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