wineoss.drv: Move a function wide variable down to the block it is used in.
[wine] / dlls / winex11.drv / mouse.c
1 /*
2  * X11 mouse driver
3  *
4  * Copyright 1998 Ulrich Weigand
5  * Copyright 2007 Henri Verbeet
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <X11/Xlib.h>
26 #include <stdarg.h>
27
28 #ifdef SONAME_LIBXCURSOR
29 # include <X11/Xcursor/Xcursor.h>
30 static void *xcursor_handle;
31 # define MAKE_FUNCPTR(f) static typeof(f) * p##f
32 MAKE_FUNCPTR(XcursorImageCreate);
33 MAKE_FUNCPTR(XcursorImageDestroy);
34 MAKE_FUNCPTR(XcursorImageLoadCursor);
35 # undef MAKE_FUNCPTR
36 #endif /* SONAME_LIBXCURSOR */
37
38 #define NONAMELESSUNION
39 #define NONAMELESSSTRUCT
40 #include "windef.h"
41 #include "winbase.h"
42 #include "wine/winuser16.h"
43
44 #include "win.h"
45 #include "x11drv.h"
46 #include "wine/server.h"
47 #include "wine/library.h"
48 #include "wine/debug.h"
49
50 WINE_DEFAULT_DEBUG_CHANNEL(cursor);
51
52 /**********************************************************************/
53
54 #ifndef Button6Mask
55 #define Button6Mask (1<<13)
56 #endif
57 #ifndef Button7Mask
58 #define Button7Mask (1<<14)
59 #endif
60
61 #define NB_BUTTONS   7     /* Windows can handle 5 buttons and the wheel too */
62
63 static const UINT button_down_flags[NB_BUTTONS] =
64 {
65     MOUSEEVENTF_LEFTDOWN,
66     MOUSEEVENTF_MIDDLEDOWN,
67     MOUSEEVENTF_RIGHTDOWN,
68     MOUSEEVENTF_WHEEL,
69     MOUSEEVENTF_WHEEL,
70     MOUSEEVENTF_XDOWN,
71     MOUSEEVENTF_XDOWN
72 };
73
74 static const UINT button_up_flags[NB_BUTTONS] =
75 {
76     MOUSEEVENTF_LEFTUP,
77     MOUSEEVENTF_MIDDLEUP,
78     MOUSEEVENTF_RIGHTUP,
79     0,
80     0,
81     MOUSEEVENTF_XUP,
82     MOUSEEVENTF_XUP
83 };
84
85 POINT cursor_pos;
86 static DWORD last_time_modified;
87 static RECT cursor_clip; /* Cursor clipping rect */
88
89 BOOL X11DRV_SetCursorPos( INT x, INT y );
90
91
92 /***********************************************************************
93  *              X11DRV_Xcursor_Init
94  *
95  * Load the Xcursor library for use.
96  */
97 void X11DRV_Xcursor_Init(void)
98 {
99 #ifdef SONAME_LIBXCURSOR
100     xcursor_handle = wine_dlopen(SONAME_LIBXCURSOR, RTLD_NOW, NULL, 0);
101     if (!xcursor_handle)  /* wine_dlopen failed. */
102     {
103         WARN("Xcursor failed to load.  Using fallback code.\n");
104         return;
105     }
106 #define LOAD_FUNCPTR(f) \
107         p##f = wine_dlsym(xcursor_handle, #f, NULL, 0)
108
109     LOAD_FUNCPTR(XcursorImageCreate);
110     LOAD_FUNCPTR(XcursorImageDestroy);
111     LOAD_FUNCPTR(XcursorImageLoadCursor);
112 #undef LOAD_FUNCPTR
113 #endif /* SONAME_LIBXCURSOR */
114 }
115
116
117 /***********************************************************************
118  *              get_coords
119  *
120  * get the coordinates of a mouse event
121  */
122 static inline void get_coords( HWND hwnd, int x, int y, POINT *pt )
123 {
124     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
125
126     if (!data) return;
127
128     pt->x = x + data->whole_rect.left;
129     pt->y = y + data->whole_rect.top;
130 }
131
132 /***********************************************************************
133  *              clip_point_to_rect
134  *
135  * Clip point to the provided rectangle
136  */
137 static inline void clip_point_to_rect( LPCRECT rect, LPPOINT pt )
138 {
139     if      (pt->x <  rect->left)   pt->x = rect->left;
140     else if (pt->x >= rect->right)  pt->x = rect->right - 1;
141     if      (pt->y <  rect->top)    pt->y = rect->top;
142     else if (pt->y >= rect->bottom) pt->y = rect->bottom - 1;
143 }
144
145 /***********************************************************************
146  *              update_button_state
147  *
148  * Update the button state with what X provides us
149  */
150 static inline void update_button_state( unsigned int state )
151 {
152     key_state_table[VK_LBUTTON] = (state & Button1Mask ? 0x80 : 0);
153     key_state_table[VK_MBUTTON] = (state & Button2Mask ? 0x80 : 0);
154     key_state_table[VK_RBUTTON] = (state & Button3Mask ? 0x80 : 0);
155     /* X-buttons are not reported from XQueryPointer */
156 }
157
158
159 /***********************************************************************
160  *              update_mouse_state
161  *
162  * Update the various window states on a mouse event.
163  */
164 static void update_mouse_state( HWND hwnd, Window window, int x, int y, unsigned int state, POINT *pt )
165 {
166     struct x11drv_thread_data *data = x11drv_thread_data();
167
168     if (window == root_window)
169     {
170         x += virtual_screen_rect.left;
171         y += virtual_screen_rect.top;
172     }
173     get_coords( hwnd, x, y, pt );
174
175     /* update the cursor */
176
177     if (data->cursor_window != window)
178     {
179         data->cursor_window = window;
180         wine_tsx11_lock();
181         if (data->cursor) XDefineCursor( data->display, window, data->cursor );
182         wine_tsx11_unlock();
183     }
184
185     /* update the wine server Z-order */
186
187     if (window != data->grab_window &&
188         /* ignore event if a button is pressed, since the mouse is then grabbed too */
189         !(state & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask|Button6Mask|Button7Mask)))
190     {
191         SERVER_START_REQ( update_window_zorder )
192         {
193             req->window      = hwnd;
194             req->rect.left   = pt->x;
195             req->rect.top    = pt->y;
196             req->rect.right  = pt->x + 1;
197             req->rect.bottom = pt->y + 1;
198             wine_server_call( req );
199         }
200         SERVER_END_REQ;
201     }
202 }
203
204
205 /***********************************************************************
206  *           get_key_state
207  */
208 static WORD get_key_state(void)
209 {
210     WORD ret = 0;
211
212     if (GetSystemMetrics( SM_SWAPBUTTON ))
213     {
214         if (key_state_table[VK_RBUTTON] & 0x80) ret |= MK_LBUTTON;
215         if (key_state_table[VK_LBUTTON] & 0x80) ret |= MK_RBUTTON;
216     }
217     else
218     {
219         if (key_state_table[VK_LBUTTON] & 0x80) ret |= MK_LBUTTON;
220         if (key_state_table[VK_RBUTTON] & 0x80) ret |= MK_RBUTTON;
221     }
222     if (key_state_table[VK_MBUTTON] & 0x80)  ret |= MK_MBUTTON;
223     if (key_state_table[VK_SHIFT] & 0x80)    ret |= MK_SHIFT;
224     if (key_state_table[VK_CONTROL] & 0x80)  ret |= MK_CONTROL;
225     if (key_state_table[VK_XBUTTON1] & 0x80) ret |= MK_XBUTTON1;
226     if (key_state_table[VK_XBUTTON2] & 0x80) ret |= MK_XBUTTON2;
227     return ret;
228 }
229
230
231 /***********************************************************************
232  *           queue_raw_mouse_message
233  */
234 static void queue_raw_mouse_message( UINT message, HWND hwnd, DWORD x, DWORD y,
235                                      DWORD data, DWORD time, DWORD extra_info, UINT injected_flags )
236 {
237     MSLLHOOKSTRUCT hook;
238
239     hook.pt.x        = x;
240     hook.pt.y        = y;
241     hook.mouseData   = MAKELONG( 0, data );
242     hook.flags       = injected_flags;
243     hook.time        = time;
244     hook.dwExtraInfo = extra_info;
245
246     last_time_modified = GetTickCount();
247     if (HOOK_CallHooks( WH_MOUSE_LL, HC_ACTION, message, (LPARAM)&hook, TRUE )) return;
248
249     SERVER_START_REQ( send_hardware_message )
250     {
251         req->id       = (injected_flags & LLMHF_INJECTED) ? 0 : GetCurrentThreadId();
252         req->win      = hwnd;
253         req->msg      = message;
254         req->wparam   = MAKEWPARAM( get_key_state(), data );
255         req->lparam   = 0;
256         req->x        = x;
257         req->y        = y;
258         req->time     = time;
259         req->info     = extra_info;
260         wine_server_call( req );
261     }
262     SERVER_END_REQ;
263
264 }
265
266
267 /***********************************************************************
268  *              X11DRV_send_mouse_input
269  */
270 void X11DRV_send_mouse_input( HWND hwnd, DWORD flags, DWORD x, DWORD y,
271                               DWORD data, DWORD time, DWORD extra_info, UINT injected_flags )
272 {
273     POINT pt;
274
275     if (flags & MOUSEEVENTF_MOVE && flags & MOUSEEVENTF_ABSOLUTE)
276     {
277         if (injected_flags & LLMHF_INJECTED)
278         {
279             pt.x = (x * screen_width) >> 16;
280             pt.y = (y * screen_height) >> 16;
281         }
282         else
283         {
284             pt.x = x;
285             pt.y = y;
286             wine_tsx11_lock();
287             if (cursor_pos.x == x && cursor_pos.y == y &&
288                 (flags & ~(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE)))
289                 flags &= ~MOUSEEVENTF_MOVE;
290             wine_tsx11_unlock();
291         }
292     }
293     else if (flags & MOUSEEVENTF_MOVE)
294     {
295         int accel[3], xMult = 1, yMult = 1;
296
297         /* dx and dy can be negative numbers for relative movements */
298         SystemParametersInfoW(SPI_GETMOUSE, 0, accel, 0);
299
300         if (abs(x) > accel[0] && accel[2] != 0)
301         {
302             xMult = 2;
303             if ((abs(x) > accel[1]) && (accel[2] == 2)) xMult = 4;
304         }
305         if (abs(y) > accel[0] && accel[2] != 0)
306         {
307             yMult = 2;
308             if ((abs(y) > accel[1]) && (accel[2] == 2)) yMult = 4;
309         }
310
311         wine_tsx11_lock();
312         pt.x = cursor_pos.x + (long)x * xMult;
313         pt.y = cursor_pos.y + (long)y * yMult;
314         wine_tsx11_unlock();
315     }
316     else
317     {
318         wine_tsx11_lock();
319         pt = cursor_pos;
320         wine_tsx11_unlock();
321     }
322
323     if (flags & MOUSEEVENTF_MOVE)
324     {
325         queue_raw_mouse_message( WM_MOUSEMOVE, hwnd, pt.x, pt.y, data, time,
326                                  extra_info, injected_flags );
327         if ((injected_flags & LLMHF_INJECTED) &&
328             ((flags & MOUSEEVENTF_ABSOLUTE) || x || y))  /* we have to actually move the cursor */
329         {
330             X11DRV_SetCursorPos( pt.x, pt.y );
331         }
332         else
333         {
334             wine_tsx11_lock();
335             clip_point_to_rect( &cursor_clip, &pt);
336             cursor_pos = pt;
337             wine_tsx11_unlock();
338         }
339     }
340     if (flags & MOUSEEVENTF_LEFTDOWN)
341     {
342         key_state_table[VK_LBUTTON] |= 0xc0;
343         queue_raw_mouse_message( GetSystemMetrics(SM_SWAPBUTTON) ? WM_RBUTTONDOWN : WM_LBUTTONDOWN,
344                                  hwnd, pt.x, pt.y, data, time, extra_info, injected_flags );
345     }
346     if (flags & MOUSEEVENTF_LEFTUP)
347     {
348         key_state_table[VK_LBUTTON] &= ~0x80;
349         queue_raw_mouse_message( GetSystemMetrics(SM_SWAPBUTTON) ? WM_RBUTTONUP : WM_LBUTTONUP,
350                                  hwnd, pt.x, pt.y, data, time, extra_info, injected_flags );
351     }
352     if (flags & MOUSEEVENTF_RIGHTDOWN)
353     {
354         key_state_table[VK_RBUTTON] |= 0xc0;
355         queue_raw_mouse_message( GetSystemMetrics(SM_SWAPBUTTON) ? WM_LBUTTONDOWN : WM_RBUTTONDOWN,
356                                  hwnd, pt.x, pt.y, data, time, extra_info, injected_flags );
357     }
358     if (flags & MOUSEEVENTF_RIGHTUP)
359     {
360         key_state_table[VK_RBUTTON] &= ~0x80;
361         queue_raw_mouse_message( GetSystemMetrics(SM_SWAPBUTTON) ? WM_LBUTTONUP : WM_RBUTTONUP,
362                                  hwnd, pt.x, pt.y, data, time, extra_info, injected_flags );
363     }
364     if (flags & MOUSEEVENTF_MIDDLEDOWN)
365     {
366         key_state_table[VK_MBUTTON] |= 0xc0;
367         queue_raw_mouse_message( WM_MBUTTONDOWN, hwnd, pt.x, pt.y, data, time,
368                                  extra_info, injected_flags );
369     }
370     if (flags & MOUSEEVENTF_MIDDLEUP)
371     {
372         key_state_table[VK_MBUTTON] &= ~0x80;
373         queue_raw_mouse_message( WM_MBUTTONUP, hwnd, pt.x, pt.y, data, time,
374                                  extra_info, injected_flags );
375     }
376     if (flags & MOUSEEVENTF_WHEEL)
377     {
378         queue_raw_mouse_message( WM_MOUSEWHEEL, hwnd, pt.x, pt.y, data, time,
379                                  extra_info, injected_flags );
380     }
381     if (flags & MOUSEEVENTF_XDOWN)
382     {
383         key_state_table[VK_XBUTTON1 + data - 1] |= 0xc0;
384         queue_raw_mouse_message( WM_XBUTTONDOWN, hwnd, pt.x, pt.y, data, time,
385                                  extra_info, injected_flags );
386     }
387     if (flags & MOUSEEVENTF_XUP)
388     {
389         key_state_table[VK_XBUTTON1 + data - 1] &= ~0x80;
390         queue_raw_mouse_message( WM_XBUTTONUP, hwnd, pt.x, pt.y, data, time,
391                                  extra_info, injected_flags );
392     }
393 }
394
395
396 #ifdef SONAME_LIBXCURSOR
397
398 /***********************************************************************
399  *              create_cursor_image
400  *
401  * Create an XcursorImage from a CURSORICONINFO
402  */
403 static XcursorImage *create_cursor_image( CURSORICONINFO *ptr )
404 {
405     int x, xmax;
406     int y, ymax;
407     int and_size, xor_size;
408     unsigned char *and_bits, *and_ptr, *xor_bits, *xor_ptr;
409     int and_width_bytes, xor_width_bytes;
410     XcursorPixel *pixel_ptr;
411     XcursorImage *image;
412
413     ymax = (ptr->nHeight > 32) ? 32 : ptr->nHeight;
414     xmax = (ptr->nWidth > 32) ? 32 : ptr->nWidth;
415
416     and_width_bytes = xmax / 8;
417     xor_width_bytes = and_width_bytes * ptr->bBitsPerPixel;
418
419     and_size = ptr->nWidth * ptr->nHeight / 8;
420     and_ptr = and_bits = (unsigned char *)(ptr + 1);
421
422     xor_size = xor_width_bytes * ptr->nHeight;
423     xor_ptr = xor_bits = and_ptr + and_size;
424
425     image = pXcursorImageCreate( xmax, ymax );
426     pixel_ptr = image->pixels;
427
428     /* On windows, to calculate the color for a pixel, first an AND is done
429      * with the background and the "and" bitmap, then an XOR with the "xor"
430      * bitmap. This means that when the data in the "and" bitmap is 0, the
431      * pixel will get the color as specified in the "xor" bitmap.
432      * However, if the data in the "and" bitmap is 1, the result will be the
433      * background XOR'ed with the value in the "xor" bitmap. In case the "xor"
434      * data is completely black (0x000000) the pixel will become transparent,
435      * in case it's white (0xffffff) the pixel will become the inverse of the
436      * background color.
437      *
438      * Since we can't support inverting colors, we map the grayscale value of
439      * the "xor" data to the alpha channel, and xor the color with either
440      * black or white.
441      */
442     for (y = 0; y < ymax; ++y)
443     {
444         and_ptr = and_bits + (y * and_width_bytes);
445         xor_ptr = xor_bits + (y * xor_width_bytes);
446
447         for (x = 0; x < xmax; ++x)
448         {
449             /* Xcursor pixel data is in ARGB format, with A in the high byte */
450             switch (ptr->bBitsPerPixel)
451             {
452                 case 32:
453                     /* BGRA, 8 bits each */
454                     *pixel_ptr = *xor_ptr++;
455                     *pixel_ptr |= *xor_ptr++ << 8;
456                     *pixel_ptr |= *xor_ptr++ << 16;
457                     *pixel_ptr |= *xor_ptr++ << 24;
458                     break;
459
460                 case 24:
461                     /* BGR, 8 bits each */
462                     *pixel_ptr = *xor_ptr++;
463                     *pixel_ptr |= *xor_ptr++ << 8;
464                     *pixel_ptr |= *xor_ptr++ << 16;
465                     break;
466
467                 case 16:
468                     /* BGR, 5 red, 6 green, 5 blue */
469                     *pixel_ptr = *xor_ptr * 0x1f;
470                     *pixel_ptr |= (*xor_ptr & 0xe0) << 3;
471                     ++xor_ptr;
472                     *pixel_ptr |= (*xor_ptr & 0x07) << 11;
473                     *pixel_ptr |= (*xor_ptr & 0xf8) << 13;
474                     break;
475
476                 case 1:
477                     if (*xor_ptr & (1 << (7 - (x & 7)))) *pixel_ptr = 0xffffff;
478                     else *pixel_ptr = 0;
479                     if ((x & 7) == 7) ++xor_ptr;
480                     break;
481
482                 default:
483                     FIXME("Currently no support for cursors with %d bits per pixel\n", ptr->bBitsPerPixel);
484                     return 0;
485             }
486
487             if (ptr->bBitsPerPixel != 32)
488             {
489                 /* Alpha channel */
490                 if (~*and_ptr & (1 << (7 - (x & 7)))) *pixel_ptr |= 0xff << 24;
491                 else if (*pixel_ptr)
492                 {
493                     int alpha = (*pixel_ptr & 0xff) * 0.30f
494                             + ((*pixel_ptr & 0xff00) >> 8) * 0.55f
495                             + ((*pixel_ptr & 0xff0000) >> 16) * 0.15f;
496                     *pixel_ptr ^= ((x + y) % 2) ? 0xffffff : 0x000000;
497                     *pixel_ptr |= alpha << 24;
498                 }
499                 if ((x & 7) == 7) ++and_ptr;
500             }
501             ++pixel_ptr;
502         }
503     }
504
505     return image;
506 }
507
508
509 /***********************************************************************
510  *              create_xcursor_cursor
511  *
512  * Use Xcursor to create an X cursor from a Windows one.
513  */
514 static Cursor create_xcursor_cursor( Display *display, CURSORICONINFO *ptr )
515 {
516     Cursor cursor;
517     XcursorImage *image;
518
519     if (!ptr) /* Create an empty cursor */
520     {
521         image = pXcursorImageCreate( 1, 1 );
522         image->xhot = 0;
523         image->yhot = 0;
524         *(image->pixels) = 0;
525         cursor = pXcursorImageLoadCursor( display, image );
526         pXcursorImageDestroy( image );
527
528         return cursor;
529     }
530
531     image = create_cursor_image( ptr );
532     if (!image) return 0;
533
534     /* Make sure hotspot is valid */
535     image->xhot = ptr->ptHotSpot.x;
536     image->yhot = ptr->ptHotSpot.y;
537     if (image->xhot < 0 || image->xhot >= image->width ||
538         image->yhot < 0 || image->yhot >= image->height)
539     {
540         image->xhot = image->width / 2;
541         image->yhot = image->height / 2;
542     }
543
544     image->delay = 0;
545
546     cursor = pXcursorImageLoadCursor( display, image );
547     pXcursorImageDestroy( image );
548
549     return cursor;
550 }
551
552 #endif /* SONAME_LIBXCURSOR */
553
554
555 /***********************************************************************
556  *              create_cursor
557  *
558  * Create an X cursor from a Windows one.
559  */
560 static Cursor create_cursor( Display *display, CURSORICONINFO *ptr )
561 {
562     Pixmap pixmapBits, pixmapMask, pixmapMaskInv = 0, pixmapAll;
563     XColor fg, bg;
564     Cursor cursor = None;
565     POINT hotspot;
566     char *bitMask32 = NULL;
567
568 #ifdef SONAME_LIBXCURSOR
569     if (pXcursorImageLoadCursor) return create_xcursor_cursor( display, ptr );
570 #endif
571
572     if (!ptr)  /* Create an empty cursor */
573     {
574         static const char data[] = { 0 };
575
576         bg.red = bg.green = bg.blue = 0x0000;
577         pixmapBits = XCreateBitmapFromData( display, root_window, data, 1, 1 );
578         if (pixmapBits)
579         {
580             cursor = XCreatePixmapCursor( display, pixmapBits, pixmapBits,
581                                           &bg, &bg, 0, 0 );
582             XFreePixmap( display, pixmapBits );
583         }
584     }
585     else  /* Create the X cursor from the bits */
586     {
587         XImage *image;
588         GC gc;
589
590         TRACE("Bitmap %dx%d planes=%d bpp=%d bytesperline=%d\n",
591             ptr->nWidth, ptr->nHeight, ptr->bPlanes, ptr->bBitsPerPixel,
592             ptr->nWidthBytes);
593
594         /* Create a pixmap and transfer all the bits to it */
595
596         /* NOTE: Following hack works, but only because XFree depth
597          *       1 images really use 1 bit/pixel (and so the same layout
598          *       as the Windows cursor data). Perhaps use a more generic
599          *       algorithm here.
600          */
601         /* This pixmap will be written with two bitmaps. The first is
602          *  the mask and the second is the image.
603          */
604         if (!(pixmapAll = XCreatePixmap( display, root_window,
605                   ptr->nWidth, ptr->nHeight * 2, 1 )))
606             return 0;
607         if (!(image = XCreateImage( display, visual,
608                 1, ZPixmap, 0, (char *)(ptr + 1), ptr->nWidth,
609                 ptr->nHeight * 2, 16, ptr->nWidthBytes/ptr->bBitsPerPixel)))
610         {
611             XFreePixmap( display, pixmapAll );
612             return 0;
613         }
614         gc = XCreateGC( display, pixmapAll, 0, NULL );
615         XSetGraphicsExposures( display, gc, False );
616         image->byte_order = MSBFirst;
617         image->bitmap_bit_order = MSBFirst;
618         image->bitmap_unit = 16;
619         _XInitImageFuncPtrs(image);
620         if (ptr->bPlanes * ptr->bBitsPerPixel == 1)
621         {
622             /* A plain old white on black cursor. */
623             fg.red = fg.green = fg.blue = 0xffff;
624             bg.red = bg.green = bg.blue = 0x0000;
625             XPutImage( display, pixmapAll, gc, image,
626                 0, 0, 0, 0, ptr->nWidth, ptr->nHeight * 2 );
627         }
628         else
629         {
630             int     rbits, gbits, bbits, red, green, blue;
631             int     rfg, gfg, bfg, rbg, gbg, bbg;
632             int     rscale, gscale, bscale;
633             int     x, y, xmax, ymax, bitIndex, byteIndex, xorIndex;
634             unsigned char *theMask, *theImage, theChar;
635             int     threshold, fgBits, bgBits, bitShifted;
636             BYTE    pXorBits[128];   /* Up to 32x32 icons */
637
638             switch (ptr->bBitsPerPixel)
639             {
640             case 32:
641                 bitMask32 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
642                                        ptr->nWidth * ptr->nHeight / 8 );
643                 /* Fallthrough */
644             case 24:
645                 rbits = 8;
646                 gbits = 8;
647                 bbits = 8;
648                 threshold = 0x40;
649                 break;
650             case 16:
651                 rbits = 5;
652                 gbits = 6;
653                 bbits = 5;
654                 threshold = 0x40;
655                 break;
656             default:
657                 FIXME("Currently no support for cursors with %d bits per pixel\n",
658                   ptr->bBitsPerPixel);
659                 XFreePixmap( display, pixmapAll );
660                 XFreeGC( display, gc );
661                 image->data = NULL;
662                 XDestroyImage( image );
663                 return 0;
664             }
665             /* The location of the mask. */
666             theMask = (unsigned char *)(ptr + 1);
667             /* The mask should still be 1 bit per pixel. The color image
668              * should immediately follow the mask.
669              */
670             theImage = &theMask[ptr->nWidth/8 * ptr->nHeight];
671             rfg = gfg = bfg = rbg = gbg = bbg = 0;
672             bitIndex = 0;
673             byteIndex = 0;
674             xorIndex = 0;
675             fgBits = 0;
676             bitShifted = 0x01;
677             xmax = (ptr->nWidth > 32) ? 32 : ptr->nWidth;
678             if (ptr->nWidth > 32) {
679                 ERR("Got a %dx%d cursor. Cannot handle larger than 32x32.\n",
680                   ptr->nWidth, ptr->nHeight);
681             }
682             ymax = (ptr->nHeight > 32) ? 32 : ptr->nHeight;
683
684             memset(pXorBits, 0, 128);
685             for (y=0; y<ymax; y++)
686             {
687                 for (x=0; x<xmax; x++)
688                 {
689                         red = green = blue = 0;
690                         switch (ptr->bBitsPerPixel)
691                         {
692                         case 32:
693                             theChar = theImage[byteIndex++];
694                             blue = theChar;
695                             theChar = theImage[byteIndex++];
696                             green = theChar;
697                             theChar = theImage[byteIndex++];
698                             red = theChar;
699                             theChar = theImage[byteIndex++];
700                             /* If the alpha channel is >5% transparent,
701                              * assume that we can add it to the bitMask32.
702                              */
703                             if (theChar > 0x0D)
704                                 *(bitMask32 + (y*xmax+x)/8) |= 1 << (x & 7);
705                             break;
706                         case 24:
707                             theChar = theImage[byteIndex++];
708                             blue = theChar;
709                             theChar = theImage[byteIndex++];
710                             green = theChar;
711                             theChar = theImage[byteIndex++];
712                             red = theChar;
713                             break;
714                         case 16:
715                             theChar = theImage[byteIndex++];
716                             blue = theChar & 0x1F;
717                             green = (theChar & 0xE0) >> 5;
718                             theChar = theImage[byteIndex++];
719                             green |= (theChar & 0x07) << 3;
720                             red = (theChar & 0xF8) >> 3;
721                             break;
722                         }
723
724                     if (red+green+blue > threshold)
725                     {
726                         rfg += red;
727                         gfg += green;
728                         bfg += blue;
729                         fgBits++;
730                         pXorBits[xorIndex] |= bitShifted;
731                     }
732                     else
733                     {
734                         rbg += red;
735                         gbg += green;
736                         bbg += blue;
737                     }
738                     if (x%8 == 7)
739                     {
740                         bitShifted = 0x01;
741                         xorIndex++;
742                     }
743                     else
744                         bitShifted = bitShifted << 1;
745                 }
746             }
747             rscale = 1 << (16 - rbits);
748             gscale = 1 << (16 - gbits);
749             bscale = 1 << (16 - bbits);
750             if (fgBits)
751             {
752                 fg.red   = rfg * rscale / fgBits;
753                 fg.green = gfg * gscale / fgBits;
754                 fg.blue  = bfg * bscale / fgBits;
755             }
756             else fg.red = fg.green = fg.blue = 0;
757             bgBits = xmax * ymax - fgBits;
758             if (bgBits)
759             {
760                 bg.red   = rbg * rscale / bgBits;
761                 bg.green = gbg * gscale / bgBits;
762                 bg.blue  = bbg * bscale / bgBits;
763             }
764             else bg.red = bg.green = bg.blue = 0;
765             pixmapBits = XCreateBitmapFromData( display, root_window, (char *)pXorBits, xmax, ymax );
766             if (!pixmapBits)
767             {
768                 HeapFree( GetProcessHeap(), 0, bitMask32 );
769                 XFreePixmap( display, pixmapAll );
770                 XFreeGC( display, gc );
771                 image->data = NULL;
772                 XDestroyImage( image );
773                 return 0;
774             }
775
776             /* Put the mask. */
777             XPutImage( display, pixmapAll, gc, image,
778                    0, 0, 0, 0, ptr->nWidth, ptr->nHeight );
779             XSetFunction( display, gc, GXcopy );
780             /* Put the image */
781             XCopyArea( display, pixmapBits, pixmapAll, gc,
782                        0, 0, xmax, ymax, 0, ptr->nHeight );
783             XFreePixmap( display, pixmapBits );
784         }
785         image->data = NULL;
786         XDestroyImage( image );
787
788         /* Now create the 2 pixmaps for bits and mask */
789
790         pixmapBits = XCreatePixmap( display, root_window, ptr->nWidth, ptr->nHeight, 1 );
791         if (ptr->bBitsPerPixel != 32)
792         {
793             pixmapMaskInv = XCreatePixmap( display, root_window, ptr->nWidth, ptr->nHeight, 1 );
794             pixmapMask = XCreatePixmap( display, root_window, ptr->nWidth, ptr->nHeight, 1 );
795
796             /* Make sure everything went OK so far */
797             if (pixmapBits && pixmapMask && pixmapMaskInv)
798             {
799                 /* We have to do some magic here, as cursors are not fully
800                  * compatible between Windows and X11. Under X11, there are
801                  * only 3 possible color cursor: black, white and masked. So
802                  * we map the 4th Windows color (invert the bits on the screen)
803                  * to black and an additional white bit on an other place
804                  * (+1,+1). This require some boolean arithmetic:
805                  *
806                  *         Windows          |          X11
807                  * And    Xor      Result   |   Bits     Mask     Result
808                  *  0      0     black      |    0        1     background
809                  *  0      1     white      |    1        1     foreground
810                  *  1      0     no change  |    X        0     no change
811                  *  1      1     inverted   |    0        1     background
812                  *
813                  * which gives:
814                  *  Bits = not 'And' and 'Xor' or 'And2' and 'Xor2'
815                  *  Mask = not 'And' or 'Xor' or 'And2' and 'Xor2'
816                  *
817                  * FIXME: apparently some servers do support 'inverted' color.
818                  * I don't know if it's correct per the X spec, but maybe we
819                  * ought to take advantage of it.  -- AJ
820                  */
821                 XSetFunction( display, gc, GXcopy );
822                 XCopyArea( display, pixmapAll, pixmapBits, gc,
823                            0, 0, ptr->nWidth, ptr->nHeight, 0, 0 );
824                 XCopyArea( display, pixmapAll, pixmapMask, gc,
825                            0, 0, ptr->nWidth, ptr->nHeight, 0, 0 );
826                 XCopyArea( display, pixmapAll, pixmapMaskInv, gc,
827                            0, 0, ptr->nWidth, ptr->nHeight, 0, 0 );
828                 XSetFunction( display, gc, GXand );
829                 XCopyArea( display, pixmapAll, pixmapMaskInv, gc,
830                            0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 );
831                 XSetFunction( display, gc, GXandReverse );
832                 XCopyArea( display, pixmapAll, pixmapBits, gc,
833                            0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 );
834                 XSetFunction( display, gc, GXorReverse );
835                 XCopyArea( display, pixmapAll, pixmapMask, gc,
836                            0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 );
837                 /* Additional white */
838                 XSetFunction( display, gc, GXor );
839                 XCopyArea( display, pixmapMaskInv, pixmapMask, gc,
840                            0, 0, ptr->nWidth, ptr->nHeight, 1, 1 );
841                 XCopyArea( display, pixmapMaskInv, pixmapBits, gc,
842                            0, 0, ptr->nWidth, ptr->nHeight, 1, 1 );
843                 XSetFunction( display, gc, GXcopy );
844             }
845         }
846         else
847         {
848             pixmapMask = XCreateBitmapFromData( display, root_window,
849                                                 bitMask32, ptr->nWidth,
850                                                 ptr->nHeight );
851             HeapFree( GetProcessHeap(), 0, bitMask32 );
852         }
853
854         /* Make sure hotspot is valid */
855         hotspot.x = ptr->ptHotSpot.x;
856         hotspot.y = ptr->ptHotSpot.y;
857         if (hotspot.x < 0 || hotspot.x >= ptr->nWidth ||
858             hotspot.y < 0 || hotspot.y >= ptr->nHeight)
859         {
860             hotspot.x = ptr->nWidth / 2;
861             hotspot.y = ptr->nHeight / 2;
862         }
863
864         if (pixmapBits && pixmapMask)
865             cursor = XCreatePixmapCursor( display, pixmapBits, pixmapMask,
866                                           &fg, &bg, hotspot.x, hotspot.y );
867
868         /* Now free everything */
869
870         if (pixmapAll) XFreePixmap( display, pixmapAll );
871         if (pixmapBits) XFreePixmap( display, pixmapBits );
872         if (pixmapMask) XFreePixmap( display, pixmapMask );
873         if (pixmapMaskInv) XFreePixmap( display, pixmapMaskInv );
874         XFreeGC( display, gc );
875     }
876     return cursor;
877 }
878
879
880 /***********************************************************************
881  *              SetCursor (X11DRV.@)
882  */
883 void X11DRV_SetCursor( CURSORICONINFO *lpCursor )
884 {
885     struct x11drv_thread_data *data = x11drv_thread_data();
886     Cursor cursor;
887
888     if (lpCursor)
889         TRACE("%ux%u, planes %u, bpp %u\n",
890               lpCursor->nWidth, lpCursor->nHeight, lpCursor->bPlanes, lpCursor->bBitsPerPixel);
891     else
892         TRACE("NULL\n");
893
894     /* set the same cursor for all top-level windows of the current thread */
895
896     wine_tsx11_lock();
897     cursor = create_cursor( data->display, lpCursor );
898     if (cursor)
899     {
900         if (data->cursor) XFreeCursor( data->display, data->cursor );
901         data->cursor = cursor;
902         if (data->cursor_window)
903         {
904             XDefineCursor( data->display, data->cursor_window, cursor );
905             /* Make the change take effect immediately */
906             XFlush( data->display );
907         }
908     }
909     wine_tsx11_unlock();
910 }
911
912 /***********************************************************************
913  *              SetCursorPos (X11DRV.@)
914  */
915 BOOL X11DRV_SetCursorPos( INT x, INT y )
916 {
917     Display *display = thread_display();
918     POINT pt;
919
920     TRACE( "warping to (%d,%d)\n", x, y );
921
922     wine_tsx11_lock();
923     if (cursor_pos.x == x && cursor_pos.y == y)
924     {
925         wine_tsx11_unlock();
926         /* We still need to generate WM_MOUSEMOVE */
927         queue_raw_mouse_message( WM_MOUSEMOVE, NULL, x, y, 0, GetCurrentTime(), 0, 0 );
928         return TRUE;
929     }
930
931     pt.x = x; pt.y = y;
932     clip_point_to_rect( &cursor_clip, &pt);
933     XWarpPointer( display, root_window, root_window, 0, 0, 0, 0,
934                   pt.x - virtual_screen_rect.left, pt.y - virtual_screen_rect.top );
935     XFlush( display ); /* avoids bad mouse lag in games that do their own mouse warping */
936     cursor_pos = pt;
937     wine_tsx11_unlock();
938     return TRUE;
939 }
940
941 /***********************************************************************
942  *              GetCursorPos (X11DRV.@)
943  */
944 BOOL X11DRV_GetCursorPos(LPPOINT pos)
945 {
946     Display *display = thread_display();
947     Window root, child;
948     int rootX, rootY, winX, winY;
949     unsigned int xstate;
950
951     wine_tsx11_lock();
952     if ((GetTickCount() - last_time_modified > 100) &&
953         XQueryPointer( display, root_window, &root, &child,
954                        &rootX, &rootY, &winX, &winY, &xstate ))
955     {
956         update_button_state( xstate );
957         winX += virtual_screen_rect.left;
958         winY += virtual_screen_rect.top;
959         TRACE("pointer at (%d,%d)\n", winX, winY );
960         cursor_pos.x = winX;
961         cursor_pos.y = winY;
962     }
963     *pos = cursor_pos;
964     wine_tsx11_unlock();
965     return TRUE;
966 }
967
968
969 /***********************************************************************
970  *              ClipCursor (X11DRV.@)
971  *
972  * Set the cursor clipping rectangle.
973  */
974 BOOL X11DRV_ClipCursor( LPCRECT clip )
975 {
976     if (!IntersectRect( &cursor_clip, &virtual_screen_rect, clip ))
977         cursor_clip = virtual_screen_rect;
978
979     return TRUE;
980 }
981
982 /***********************************************************************
983  *           X11DRV_ButtonPress
984  */
985 void X11DRV_ButtonPress( HWND hwnd, XEvent *xev )
986 {
987     XButtonEvent *event = &xev->xbutton;
988     int buttonNum = event->button - 1;
989     WORD wData = 0;
990     POINT pt;
991
992     if (buttonNum >= NB_BUTTONS) return;
993     if (!hwnd) return;
994
995     switch (buttonNum)
996     {
997     case 3:
998         wData = WHEEL_DELTA;
999         break;
1000     case 4:
1001         wData = -WHEEL_DELTA;
1002         break;
1003     case 5:
1004         wData = XBUTTON1;
1005         break;
1006     case 6:
1007         wData = XBUTTON2;
1008         break;
1009     }
1010
1011     update_mouse_state( hwnd, event->window, event->x, event->y, event->state, &pt );
1012
1013     X11DRV_send_mouse_input( hwnd, button_down_flags[buttonNum] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
1014                              pt.x, pt.y, wData, EVENT_x11_time_to_win32_time(event->time), 0, 0 );
1015 }
1016
1017
1018 /***********************************************************************
1019  *           X11DRV_ButtonRelease
1020  */
1021 void X11DRV_ButtonRelease( HWND hwnd, XEvent *xev )
1022 {
1023     XButtonEvent *event = &xev->xbutton;
1024     int buttonNum = event->button - 1;
1025     WORD wData = 0;
1026     POINT pt;
1027
1028     if (buttonNum >= NB_BUTTONS || !button_up_flags[buttonNum]) return;
1029     if (!hwnd) return;
1030
1031     switch (buttonNum)
1032     {
1033     case 5:
1034         wData = XBUTTON1;
1035         break;
1036     case 6:
1037         wData = XBUTTON2;
1038         break;
1039     }
1040
1041     update_mouse_state( hwnd, event->window, event->x, event->y, event->state, &pt );
1042
1043     X11DRV_send_mouse_input( hwnd, button_up_flags[buttonNum] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
1044                              pt.x, pt.y, wData, EVENT_x11_time_to_win32_time(event->time), 0, 0 );
1045 }
1046
1047
1048 /***********************************************************************
1049  *           X11DRV_MotionNotify
1050  */
1051 void X11DRV_MotionNotify( HWND hwnd, XEvent *xev )
1052 {
1053     XMotionEvent *event = &xev->xmotion;
1054     POINT pt;
1055
1056     TRACE("hwnd %p, event->is_hint %d\n", hwnd, event->is_hint);
1057
1058     if (!hwnd) return;
1059
1060     update_mouse_state( hwnd, event->window, event->x, event->y, event->state, &pt );
1061
1062     X11DRV_send_mouse_input( hwnd, MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE,
1063                              pt.x, pt.y, 0, EVENT_x11_time_to_win32_time(event->time), 0, 0 );
1064 }
1065
1066
1067 /***********************************************************************
1068  *           X11DRV_EnterNotify
1069  */
1070 void X11DRV_EnterNotify( HWND hwnd, XEvent *xev )
1071 {
1072     XCrossingEvent *event = &xev->xcrossing;
1073     POINT pt;
1074
1075     TRACE("hwnd %p, event->detail %d\n", hwnd, event->detail);
1076
1077     if (!hwnd) return;
1078     if (event->detail == NotifyVirtual || event->detail == NotifyNonlinearVirtual) return;
1079
1080     /* simulate a mouse motion event */
1081     update_mouse_state( hwnd, event->window, event->x, event->y, event->state, &pt );
1082
1083     X11DRV_send_mouse_input( hwnd, MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE,
1084                              pt.x, pt.y, 0, EVENT_x11_time_to_win32_time(event->time), 0, 0 );
1085 }