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