include/msvcrt: Define more CPU control word flags.
[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 <X11/cursorfont.h>
27 #include <stdarg.h>
28
29 #ifdef SONAME_LIBXCURSOR
30 # include <X11/Xcursor/Xcursor.h>
31 static void *xcursor_handle;
32 # define MAKE_FUNCPTR(f) static typeof(f) * p##f
33 MAKE_FUNCPTR(XcursorImageCreate);
34 MAKE_FUNCPTR(XcursorImageDestroy);
35 MAKE_FUNCPTR(XcursorImageLoadCursor);
36 MAKE_FUNCPTR(XcursorImagesCreate);
37 MAKE_FUNCPTR(XcursorImagesDestroy);
38 MAKE_FUNCPTR(XcursorImagesLoadCursor);
39 MAKE_FUNCPTR(XcursorLibraryLoadCursor);
40 # undef MAKE_FUNCPTR
41 #endif /* SONAME_LIBXCURSOR */
42
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #define OEMRESOURCE
46 #include "windef.h"
47 #include "winbase.h"
48 #include "winreg.h"
49
50 #include "x11drv.h"
51 #include "wine/server.h"
52 #include "wine/library.h"
53 #include "wine/unicode.h"
54 #include "wine/debug.h"
55
56 WINE_DEFAULT_DEBUG_CHANNEL(cursor);
57
58 /**********************************************************************/
59
60 #ifndef Button6Mask
61 #define Button6Mask (1<<13)
62 #endif
63 #ifndef Button7Mask
64 #define Button7Mask (1<<14)
65 #endif
66
67 #define NB_BUTTONS   9     /* Windows can handle 5 buttons and the wheel too */
68
69 static const UINT button_down_flags[NB_BUTTONS] =
70 {
71     MOUSEEVENTF_LEFTDOWN,
72     MOUSEEVENTF_MIDDLEDOWN,
73     MOUSEEVENTF_RIGHTDOWN,
74     MOUSEEVENTF_WHEEL,
75     MOUSEEVENTF_WHEEL,
76     MOUSEEVENTF_XDOWN,  /* FIXME: horizontal wheel */
77     MOUSEEVENTF_XDOWN,
78     MOUSEEVENTF_XDOWN,
79     MOUSEEVENTF_XDOWN
80 };
81
82 static const UINT button_up_flags[NB_BUTTONS] =
83 {
84     MOUSEEVENTF_LEFTUP,
85     MOUSEEVENTF_MIDDLEUP,
86     MOUSEEVENTF_RIGHTUP,
87     0,
88     0,
89     MOUSEEVENTF_XUP,
90     MOUSEEVENTF_XUP,
91     MOUSEEVENTF_XUP,
92     MOUSEEVENTF_XUP
93 };
94
95 POINT cursor_pos;
96 static HWND cursor_window;
97 static DWORD last_time_modified;
98 static RECT cursor_clip; /* Cursor clipping rect */
99 static XContext cursor_context;
100 static Cursor create_cursor( HANDLE handle );
101
102 BOOL CDECL X11DRV_SetCursorPos( INT x, INT y );
103
104
105 /***********************************************************************
106  *              X11DRV_Xcursor_Init
107  *
108  * Load the Xcursor library for use.
109  */
110 void X11DRV_Xcursor_Init(void)
111 {
112 #ifdef SONAME_LIBXCURSOR
113     xcursor_handle = wine_dlopen(SONAME_LIBXCURSOR, RTLD_NOW, NULL, 0);
114     if (!xcursor_handle)  /* wine_dlopen failed. */
115     {
116         WARN("Xcursor failed to load.  Using fallback code.\n");
117         return;
118     }
119 #define LOAD_FUNCPTR(f) \
120         p##f = wine_dlsym(xcursor_handle, #f, NULL, 0)
121
122     LOAD_FUNCPTR(XcursorImageCreate);
123     LOAD_FUNCPTR(XcursorImageDestroy);
124     LOAD_FUNCPTR(XcursorImageLoadCursor);
125     LOAD_FUNCPTR(XcursorImagesCreate);
126     LOAD_FUNCPTR(XcursorImagesDestroy);
127     LOAD_FUNCPTR(XcursorImagesLoadCursor);
128     LOAD_FUNCPTR(XcursorLibraryLoadCursor);
129 #undef LOAD_FUNCPTR
130 #endif /* SONAME_LIBXCURSOR */
131 }
132
133
134 /***********************************************************************
135  *              clip_point_to_rect
136  *
137  * Clip point to the provided rectangle
138  */
139 static inline void clip_point_to_rect( LPCRECT rect, LPPOINT pt )
140 {
141     if      (pt->x <  rect->left)   pt->x = rect->left;
142     else if (pt->x >= rect->right)  pt->x = rect->right - 1;
143     if      (pt->y <  rect->top)    pt->y = rect->top;
144     else if (pt->y >= rect->bottom) pt->y = rect->bottom - 1;
145 }
146
147 /***********************************************************************
148  *              update_button_state
149  *
150  * Update the button state with what X provides us
151  */
152 static inline void update_button_state( unsigned int state )
153 {
154     key_state_table[VK_LBUTTON] = (state & Button1Mask ? 0x80 : 0);
155     key_state_table[VK_MBUTTON] = (state & Button2Mask ? 0x80 : 0);
156     key_state_table[VK_RBUTTON] = (state & Button3Mask ? 0x80 : 0);
157     /* X-buttons are not reported from XQueryPointer */
158 }
159
160 /***********************************************************************
161  *              get_empty_cursor
162  */
163 static Cursor get_empty_cursor(void)
164 {
165     static Cursor cursor;
166     static const char data[] = { 0 };
167
168     wine_tsx11_lock();
169     if (!cursor)
170     {
171         XColor bg;
172         Pixmap pixmap;
173
174         bg.red = bg.green = bg.blue = 0x0000;
175         pixmap = XCreateBitmapFromData( gdi_display, root_window, data, 1, 1 );
176         if (pixmap)
177         {
178             cursor = XCreatePixmapCursor( gdi_display, pixmap, pixmap, &bg, &bg, 0, 0 );
179             XFreePixmap( gdi_display, pixmap );
180         }
181     }
182     wine_tsx11_unlock();
183     return cursor;
184 }
185
186 /***********************************************************************
187  *              set_window_cursor
188  */
189 void set_window_cursor( HWND hwnd, HCURSOR handle )
190 {
191     struct x11drv_win_data *data;
192     Cursor cursor, prev;
193
194     if (!(data = X11DRV_get_win_data( hwnd ))) return;
195
196     wine_tsx11_lock();
197     if (!handle) cursor = get_empty_cursor();
198     else if (!cursor_context || XFindContext( gdi_display, (XID)handle, cursor_context, (char **)&cursor ))
199     {
200         /* try to create it */
201         wine_tsx11_unlock();
202         if (!(cursor = create_cursor( handle ))) return;
203
204         wine_tsx11_lock();
205         if (!cursor_context) cursor_context = XUniqueContext();
206         if (!XFindContext( gdi_display, (XID)handle, cursor_context, (char **)&prev ))
207         {
208             /* someone else was here first */
209             XFreeCursor( gdi_display, cursor );
210             cursor = prev;
211         }
212         else
213         {
214             XSaveContext( gdi_display, (XID)handle, cursor_context, (char *)cursor );
215             TRACE( "cursor %p created %lx\n", handle, cursor );
216         }
217     }
218
219     XDefineCursor( gdi_display, data->whole_window, cursor );
220     /* make the change take effect immediately */
221     XFlush( gdi_display );
222     data->cursor = handle;
223     wine_tsx11_unlock();
224 }
225
226 /***********************************************************************
227  *              update_mouse_state
228  *
229  * Update the various window states on a mouse event.
230  */
231 static HWND update_mouse_state( HWND hwnd, Window window, int x, int y, unsigned int state, POINT *pt )
232 {
233     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
234
235     if (!data) return 0;
236
237     if (window == data->whole_window)
238     {
239         x += data->whole_rect.left - data->client_rect.left;
240         y += data->whole_rect.top - data->client_rect.top;
241     }
242     pt->x = x;
243     pt->y = y;
244     if (GetWindowLongW( data->hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
245         pt->x = data->client_rect.right - data->client_rect.left - 1 - pt->x;
246     MapWindowPoints( hwnd, 0, pt, 1 );
247
248     cursor_window = hwnd;
249     if (hwnd != GetDesktopWindow()) hwnd = GetAncestor( hwnd, GA_ROOT );
250
251     /* update the wine server Z-order */
252
253     if (window != x11drv_thread_data()->grab_window &&
254         /* ignore event if a button is pressed, since the mouse is then grabbed too */
255         !(state & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask|Button6Mask|Button7Mask)))
256     {
257         RECT rect;
258         SetRect( &rect, pt->x, pt->y, pt->x + 1, pt->y + 1 );
259         MapWindowPoints( 0, hwnd, (POINT *)&rect, 2 );
260
261         SERVER_START_REQ( update_window_zorder )
262         {
263             req->window      = wine_server_user_handle( hwnd );
264             req->rect.left   = rect.left;
265             req->rect.top    = rect.top;
266             req->rect.right  = rect.right;
267             req->rect.bottom = rect.bottom;
268             wine_server_call( req );
269         }
270         SERVER_END_REQ;
271     }
272     return hwnd;
273 }
274
275
276 /***********************************************************************
277  *           get_key_state
278  */
279 static WORD get_key_state(void)
280 {
281     WORD ret = 0;
282
283     if (GetSystemMetrics( SM_SWAPBUTTON ))
284     {
285         if (key_state_table[VK_RBUTTON] & 0x80) ret |= MK_LBUTTON;
286         if (key_state_table[VK_LBUTTON] & 0x80) ret |= MK_RBUTTON;
287     }
288     else
289     {
290         if (key_state_table[VK_LBUTTON] & 0x80) ret |= MK_LBUTTON;
291         if (key_state_table[VK_RBUTTON] & 0x80) ret |= MK_RBUTTON;
292     }
293     if (key_state_table[VK_MBUTTON] & 0x80)  ret |= MK_MBUTTON;
294     if (key_state_table[VK_SHIFT] & 0x80)    ret |= MK_SHIFT;
295     if (key_state_table[VK_CONTROL] & 0x80)  ret |= MK_CONTROL;
296     if (key_state_table[VK_XBUTTON1] & 0x80) ret |= MK_XBUTTON1;
297     if (key_state_table[VK_XBUTTON2] & 0x80) ret |= MK_XBUTTON2;
298     return ret;
299 }
300
301
302 /***********************************************************************
303  *           queue_raw_mouse_message
304  */
305 static void queue_raw_mouse_message( UINT message, HWND top_hwnd, HWND cursor_hwnd, DWORD x, DWORD y,
306                                      DWORD data, DWORD time, DWORD extra_info, UINT injected_flags )
307 {
308     MSLLHOOKSTRUCT hook;
309     HCURSOR cursor;
310
311     hook.pt.x        = x;
312     hook.pt.y        = y;
313     hook.mouseData   = MAKELONG( 0, data );
314     hook.flags       = injected_flags;
315     hook.time        = time;
316     hook.dwExtraInfo = extra_info;
317
318     last_time_modified = GetTickCount();
319     if (HOOK_CallHooks( WH_MOUSE_LL, HC_ACTION, message, (LPARAM)&hook, TRUE ))
320         message = 0;  /* ignore it */
321
322     SERVER_START_REQ( send_hardware_message )
323     {
324         req->id       = (injected_flags & LLMHF_INJECTED) ? 0 : GetCurrentThreadId();
325         req->win      = wine_server_user_handle( top_hwnd );
326         req->msg      = message;
327         req->wparam   = MAKEWPARAM( get_key_state(), data );
328         req->lparam   = 0;
329         req->x        = x;
330         req->y        = y;
331         req->time     = time;
332         req->info     = extra_info;
333         wine_server_call( req );
334         cursor = (reply->count >= 0) ? wine_server_ptr_handle(reply->cursor) : 0;
335     }
336     SERVER_END_REQ;
337
338     if (cursor_hwnd)
339     {
340         struct x11drv_win_data *data = X11DRV_get_win_data( cursor_hwnd );
341         if (data && cursor != data->cursor) set_window_cursor( cursor_hwnd, cursor );
342     }
343 }
344
345
346 /***********************************************************************
347  *              X11DRV_send_mouse_input
348  */
349 void X11DRV_send_mouse_input( HWND top_hwnd, HWND cursor_hwnd, DWORD flags, DWORD x, DWORD y,
350                               DWORD data, DWORD time, DWORD extra_info, UINT injected_flags )
351 {
352     POINT pt;
353
354     if (!time) time = GetTickCount();
355
356     if (flags & MOUSEEVENTF_MOVE && flags & MOUSEEVENTF_ABSOLUTE)
357     {
358         if (injected_flags & LLMHF_INJECTED)
359         {
360             pt.x = (x * screen_width) >> 16;
361             pt.y = (y * screen_height) >> 16;
362         }
363         else
364         {
365             pt.x = x;
366             pt.y = y;
367             wine_tsx11_lock();
368             if (cursor_pos.x == x && cursor_pos.y == y &&
369                 (flags & ~(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE)))
370                 flags &= ~MOUSEEVENTF_MOVE;
371             wine_tsx11_unlock();
372         }
373     }
374     else if (flags & MOUSEEVENTF_MOVE)
375     {
376         int accel[3], xMult = 1, yMult = 1;
377
378         /* dx and dy can be negative numbers for relative movements */
379         SystemParametersInfoW(SPI_GETMOUSE, 0, accel, 0);
380
381         if (abs(x) > accel[0] && accel[2] != 0)
382         {
383             xMult = 2;
384             if ((abs(x) > accel[1]) && (accel[2] == 2)) xMult = 4;
385         }
386         if (abs(y) > accel[0] && accel[2] != 0)
387         {
388             yMult = 2;
389             if ((abs(y) > accel[1]) && (accel[2] == 2)) yMult = 4;
390         }
391
392         wine_tsx11_lock();
393         pt.x = cursor_pos.x + (long)x * xMult;
394         pt.y = cursor_pos.y + (long)y * yMult;
395         wine_tsx11_unlock();
396     }
397     else
398     {
399         wine_tsx11_lock();
400         pt = cursor_pos;
401         wine_tsx11_unlock();
402     }
403
404     if (flags & MOUSEEVENTF_MOVE)
405     {
406         queue_raw_mouse_message( WM_MOUSEMOVE, top_hwnd, cursor_hwnd, pt.x, pt.y, data, time,
407                                  extra_info, injected_flags );
408         if ((injected_flags & LLMHF_INJECTED) &&
409             ((flags & MOUSEEVENTF_ABSOLUTE) || x || y))  /* we have to actually move the cursor */
410         {
411             X11DRV_SetCursorPos( pt.x, pt.y );
412         }
413         else
414         {
415             wine_tsx11_lock();
416             clip_point_to_rect( &cursor_clip, &pt);
417             cursor_pos = pt;
418             wine_tsx11_unlock();
419         }
420     }
421     if (flags & MOUSEEVENTF_LEFTDOWN)
422     {
423         key_state_table[VK_LBUTTON] |= 0xc0;
424         queue_raw_mouse_message( GetSystemMetrics(SM_SWAPBUTTON) ? WM_RBUTTONDOWN : WM_LBUTTONDOWN,
425                                  top_hwnd, cursor_hwnd, pt.x, pt.y,
426                                  data, time, extra_info, injected_flags );
427     }
428     if (flags & MOUSEEVENTF_LEFTUP)
429     {
430         key_state_table[VK_LBUTTON] &= ~0x80;
431         queue_raw_mouse_message( GetSystemMetrics(SM_SWAPBUTTON) ? WM_RBUTTONUP : WM_LBUTTONUP,
432                                  top_hwnd, cursor_hwnd, pt.x, pt.y,
433                                  data, time, extra_info, injected_flags );
434     }
435     if (flags & MOUSEEVENTF_RIGHTDOWN)
436     {
437         key_state_table[VK_RBUTTON] |= 0xc0;
438         queue_raw_mouse_message( GetSystemMetrics(SM_SWAPBUTTON) ? WM_LBUTTONDOWN : WM_RBUTTONDOWN,
439                                  top_hwnd, cursor_hwnd, pt.x, pt.y,
440                                  data, time, extra_info, injected_flags );
441     }
442     if (flags & MOUSEEVENTF_RIGHTUP)
443     {
444         key_state_table[VK_RBUTTON] &= ~0x80;
445         queue_raw_mouse_message( GetSystemMetrics(SM_SWAPBUTTON) ? WM_LBUTTONUP : WM_RBUTTONUP,
446                                  top_hwnd, cursor_hwnd, pt.x, pt.y,
447                                  data, time, extra_info, injected_flags );
448     }
449     if (flags & MOUSEEVENTF_MIDDLEDOWN)
450     {
451         key_state_table[VK_MBUTTON] |= 0xc0;
452         queue_raw_mouse_message( WM_MBUTTONDOWN, top_hwnd, cursor_hwnd, pt.x, pt.y,
453                                  data, time, extra_info, injected_flags );
454     }
455     if (flags & MOUSEEVENTF_MIDDLEUP)
456     {
457         key_state_table[VK_MBUTTON] &= ~0x80;
458         queue_raw_mouse_message( WM_MBUTTONUP, top_hwnd, cursor_hwnd, pt.x, pt.y,
459                                  data, time, extra_info, injected_flags );
460     }
461     if (flags & MOUSEEVENTF_WHEEL)
462     {
463         queue_raw_mouse_message( WM_MOUSEWHEEL, top_hwnd, cursor_hwnd, pt.x, pt.y,
464                                  data, time, extra_info, injected_flags );
465     }
466     if (flags & MOUSEEVENTF_XDOWN)
467     {
468         key_state_table[VK_XBUTTON1 + data - 1] |= 0xc0;
469         queue_raw_mouse_message( WM_XBUTTONDOWN, top_hwnd, cursor_hwnd, pt.x, pt.y,
470                                  data, time, extra_info, injected_flags );
471     }
472     if (flags & MOUSEEVENTF_XUP)
473     {
474         key_state_table[VK_XBUTTON1 + data - 1] &= ~0x80;
475         queue_raw_mouse_message( WM_XBUTTONUP, top_hwnd, cursor_hwnd, pt.x, pt.y,
476                                  data, time, extra_info, injected_flags );
477     }
478 }
479
480 #ifdef SONAME_LIBXCURSOR
481
482 /***********************************************************************
483  *              create_xcursor_frame
484  *
485  * Use Xcursor to create a frame of an X cursor from a Windows one.
486  */
487 static XcursorImage *create_xcursor_frame( HDC hdc, const ICONINFOEXW *iinfo, HANDLE icon,
488                                            HBITMAP hbmColor, unsigned char *color_bits, int color_size,
489                                            HBITMAP hbmMask, unsigned char *mask_bits, int mask_size,
490                                            int width, int height, int istep )
491 {
492     XcursorImage *image, *ret = NULL;
493     int x, y, i, has_alpha;
494     XcursorPixel *ptr;
495
496     wine_tsx11_lock();
497     image = pXcursorImageCreate( width, height );
498     wine_tsx11_unlock();
499     if (!image)
500     {
501         ERR("X11 failed to produce a cursor frame!\n");
502         goto cleanup;
503     }
504
505     image->xhot = iinfo->xHotspot;
506     image->yhot = iinfo->yHotspot;
507     image->delay = 100; /* TODO: find a way to get the proper delay */
508
509     /* draw the cursor frame to a temporary buffer then copy it into the XcursorImage */
510     memset( color_bits, 0x00, color_size );
511     SelectObject( hdc, hbmColor );
512     if (!DrawIconEx( hdc, 0, 0, icon, width, height, istep, NULL, DI_NORMAL ))
513     {
514         TRACE("Could not draw frame %d (walk past end of frames).\n", istep);
515         goto cleanup;
516     }
517     memcpy( image->pixels, color_bits, color_size );
518
519     /* check if the cursor frame was drawn with an alpha channel */
520     for (i = 0, ptr = image->pixels; i < width * height; i++, ptr++)
521         if ((has_alpha = (*ptr & 0xff000000) != 0)) break;
522
523     /* if no alpha channel was drawn then generate it from the mask */
524     if (!has_alpha)
525     {
526         unsigned int width_bytes = (width + 31) / 32 * 4;
527
528         /* draw the cursor mask to a temporary buffer */
529         memset( mask_bits, 0xFF, mask_size );
530         SelectObject( hdc, hbmMask );
531         if (!DrawIconEx( hdc, 0, 0, icon, width, height, istep, NULL, DI_MASK ))
532         {
533             ERR("Failed to draw frame mask %d.\n", istep);
534             goto cleanup;
535         }
536         /* use the buffer to directly modify the XcursorImage alpha channel */
537         for (y = 0, ptr = image->pixels; y < height; y++)
538             for (x = 0; x < width; x++, ptr++)
539                 if (!((mask_bits[y * width_bytes + x / 8] << (x % 8)) & 0x80))
540                     *ptr |= 0xff000000;
541     }
542     ret = image;
543
544 cleanup:
545     if (ret == NULL) pXcursorImageDestroy( image );
546     return ret;
547 }
548
549 /***********************************************************************
550  *              create_xcursor_cursor
551  *
552  * Use Xcursor to create an X cursor from a Windows one.
553  */
554 static Cursor create_xcursor_cursor( HDC hdc, const ICONINFOEXW *iinfo, HANDLE icon, int width, int height )
555 {
556     unsigned char *color_bits, *mask_bits;
557     HBITMAP hbmColor = 0, hbmMask = 0;
558     XcursorImage **imgs, *image;
559     int color_size, mask_size;
560     BITMAPINFO *info = NULL;
561     XcursorImages *images;
562     Cursor cursor = 0;
563     int nFrames = 0;
564
565     if (!(imgs = HeapAlloc( GetProcessHeap(), 0, sizeof(XcursorImage*) ))) return 0;
566
567     /* Allocate all of the resources necessary to obtain a cursor frame */
568     if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto cleanup;
569     info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
570     info->bmiHeader.biWidth = width;
571     info->bmiHeader.biHeight = -height;
572     info->bmiHeader.biPlanes = 1;
573     info->bmiHeader.biCompression = BI_RGB;
574     info->bmiHeader.biXPelsPerMeter = 0;
575     info->bmiHeader.biYPelsPerMeter = 0;
576     info->bmiHeader.biClrUsed = 0;
577     info->bmiHeader.biClrImportant = 0;
578     info->bmiHeader.biBitCount = 32;
579     color_size = width * height * 4;
580     info->bmiHeader.biSizeImage = color_size;
581     hbmColor = CreateDIBSection( hdc, info, DIB_RGB_COLORS, (VOID **) &color_bits, NULL, 0);
582     if (!hbmColor)
583     {
584         ERR("Failed to create DIB section for cursor color data!\n");
585         goto cleanup;
586     }
587     info->bmiHeader.biBitCount = 1;
588     mask_size = ((width + 31) / 32 * 4) * height; /* width_bytes * height */
589     info->bmiHeader.biSizeImage = mask_size;
590     hbmMask = CreateDIBSection( hdc, info, DIB_RGB_COLORS, (VOID **) &mask_bits, NULL, 0);
591     if (!hbmMask)
592     {
593         ERR("Failed to create DIB section for cursor mask data!\n");
594         goto cleanup;
595     }
596
597     /* Create an XcursorImage for each frame of the cursor */
598     while (1)
599     {
600         XcursorImage **imgstmp;
601
602         image = create_xcursor_frame( hdc, iinfo, icon,
603                                       hbmColor, color_bits, color_size,
604                                       hbmMask, mask_bits, mask_size,
605                                       width, height, nFrames );
606         if (!image) break; /* no more drawable frames */
607
608         imgs[nFrames++] = image;
609         if (!(imgstmp = HeapReAlloc( GetProcessHeap(), 0, imgs, (nFrames+1)*sizeof(XcursorImage*) ))) goto cleanup;
610         imgs = imgstmp;
611     }
612
613     /* Build an X cursor out of all of the frames */
614     if (!(images = pXcursorImagesCreate( nFrames ))) goto cleanup;
615     for (images->nimage = 0; images->nimage < nFrames; images->nimage++)
616         images->images[images->nimage] = imgs[images->nimage];
617     wine_tsx11_lock();
618     cursor = pXcursorImagesLoadCursor( gdi_display, images );
619     wine_tsx11_unlock();
620     pXcursorImagesDestroy( images ); /* Note: this frees each individual frame (calls XcursorImageDestroy) */
621     HeapFree( GetProcessHeap(), 0, imgs );
622     imgs = NULL;
623
624 cleanup:
625     if (imgs)
626     {
627         /* Failed to produce a cursor, free previously allocated frames */
628         for (nFrames--; nFrames >= 0; nFrames--)
629             pXcursorImageDestroy( imgs[nFrames] );
630         HeapFree( GetProcessHeap(), 0, imgs );
631     }
632     /* Cleanup all of the resources used to obtain the frame data */
633     if (hbmColor) DeleteObject( hbmColor );
634     if (hbmMask) DeleteObject( hbmMask );
635     HeapFree( GetProcessHeap(), 0, info );
636     return cursor;
637 }
638
639
640 struct system_cursors
641 {
642     WORD id;
643     const char *name;
644 };
645
646 static const struct system_cursors user32_cursors[] =
647 {
648     { OCR_NORMAL,      "left_ptr" },
649     { OCR_IBEAM,       "xterm" },
650     { OCR_WAIT,        "watch" },
651     { OCR_CROSS,       "cross" },
652     { OCR_UP,          "center_ptr" },
653     { OCR_SIZE,        "fleur" },
654     { OCR_SIZEALL,     "fleur" },
655     { OCR_ICON,        "icon" },
656     { OCR_SIZENWSE,    "nwse-resize" },
657     { OCR_SIZENESW,    "nesw-resize" },
658     { OCR_SIZEWE,      "ew-resize" },
659     { OCR_SIZENS,      "ns-resize" },
660     { OCR_NO,          "not-allowed" },
661     { OCR_HAND,        "hand2" },
662     { OCR_APPSTARTING, "left_ptr_watch" },
663     { OCR_HELP,        "question_arrow" },
664     { 0 }
665 };
666
667 static const struct system_cursors comctl32_cursors[] =
668 {
669     { 102, "move" },
670     { 104, "copy" },
671     { 105, "left_ptr" },
672     { 106, "row-resize" },
673     { 107, "row-resize" },
674     { 108, "hand2" },
675     { 135, "col-resize" },
676     { 0 }
677 };
678
679 static const struct system_cursors ole32_cursors[] =
680 {
681     { 1, "no-drop" },
682     { 2, "move" },
683     { 3, "copy" },
684     { 4, "alias" },
685     { 0 }
686 };
687
688 static const struct system_cursors riched20_cursors[] =
689 {
690     { 105, "hand2" },
691     { 107, "right_ptr" },
692     { 109, "copy" },
693     { 110, "move" },
694     { 111, "no-drop" },
695     { 0 }
696 };
697
698 static const struct
699 {
700     const struct system_cursors *cursors;
701     WCHAR name[16];
702 } module_cursors[] =
703 {
704     { user32_cursors, {'u','s','e','r','3','2','.','d','l','l',0} },
705     { comctl32_cursors, {'c','o','m','c','t','l','3','2','.','d','l','l',0} },
706     { ole32_cursors, {'o','l','e','3','2','.','d','l','l',0} },
707     { riched20_cursors, {'r','i','c','h','e','d','2','0','.','d','l','l',0} }
708 };
709
710 /***********************************************************************
711  *              create_xcursor_system_cursor
712  *
713  * Create an X cursor for a system cursor.
714  */
715 static Cursor create_xcursor_system_cursor( const ICONINFOEXW *info )
716 {
717     static const WCHAR idW[] = {'%','h','u',0};
718     const struct system_cursors *cursors;
719     unsigned int i;
720     Cursor cursor = 0;
721     HMODULE module;
722     HKEY key;
723     WCHAR *p, name[MAX_PATH * 2], valueW[64];
724     char valueA[64];
725     DWORD size, ret;
726
727     if (!pXcursorLibraryLoadCursor) return 0;
728     if (!info->szModName[0]) return 0;
729
730     p = strrchrW( info->szModName, '\\' );
731     strcpyW( name, p ? p + 1 : info->szModName );
732     p = name + strlenW( name );
733     *p++ = ',';
734     if (info->szResName[0]) strcpyW( p, info->szResName );
735     else sprintfW( p, idW, info->wResID );
736     valueA[0] = 0;
737
738     /* @@ Wine registry key: HKCU\Software\Wine\X11 Driver\Cursors */
739     if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\X11 Driver\\Cursors", &key ))
740     {
741         size = sizeof(valueW) / sizeof(WCHAR);
742         ret = RegQueryValueExW( key, name, NULL, NULL, (BYTE *)valueW, &size );
743         RegCloseKey( key );
744         if (!ret)
745         {
746             if (!valueW[0]) return 0; /* force standard cursor */
747             if (!WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, sizeof(valueA), NULL, NULL ))
748                 valueA[0] = 0;
749             goto done;
750         }
751     }
752
753     if (info->szResName[0]) goto done;  /* only integer resources are supported here */
754     if (!(module = GetModuleHandleW( info->szModName ))) goto done;
755
756     for (i = 0; i < sizeof(module_cursors)/sizeof(module_cursors[0]); i++)
757         if (GetModuleHandleW( module_cursors[i].name ) == module) break;
758     if (i == sizeof(module_cursors)/sizeof(module_cursors[0])) goto done;
759
760     cursors = module_cursors[i].cursors;
761     for (i = 0; cursors[i].id; i++)
762         if (cursors[i].id == info->wResID)
763         {
764             strcpy( valueA, cursors[i].name );
765             break;
766         }
767
768 done:
769     if (valueA[0])
770     {
771         wine_tsx11_lock();
772         cursor = pXcursorLibraryLoadCursor( gdi_display, valueA );
773         wine_tsx11_unlock();
774         if (!cursor) WARN( "no system cursor found for %s mapped to %s\n",
775                            debugstr_w(name), debugstr_a(valueA) );
776     }
777     else WARN( "no system cursor found for %s\n", debugstr_w(name) );
778     return cursor;
779 }
780
781 #endif /* SONAME_LIBXCURSOR */
782
783
784 /***********************************************************************
785  *              create_cursor_from_bitmaps
786  *
787  * Create an X11 cursor from source bitmaps.
788  */
789 static Cursor create_cursor_from_bitmaps( HBITMAP src_xor, HBITMAP src_and, int width, int height,
790                                           int xor_y, int and_y, XColor *fg, XColor *bg,
791                                           int hotspot_x, int hotspot_y )
792 {
793     HDC src = 0, dst = 0;
794     HBITMAP bits = 0, mask = 0, mask_inv = 0;
795     Cursor cursor = 0;
796
797     if (!(src = CreateCompatibleDC( 0 ))) goto done;
798     if (!(dst = CreateCompatibleDC( 0 ))) goto done;
799
800     if (!(bits = CreateBitmap( width, height, 1, 1, NULL ))) goto done;
801     if (!(mask = CreateBitmap( width, height, 1, 1, NULL ))) goto done;
802     if (!(mask_inv = CreateBitmap( width, height, 1, 1, NULL ))) goto done;
803
804     /* We have to do some magic here, as cursors are not fully
805      * compatible between Windows and X11. Under X11, there are
806      * only 3 possible color cursor: black, white and masked. So
807      * we map the 4th Windows color (invert the bits on the screen)
808      * to black and an additional white bit on an other place
809      * (+1,+1). This require some boolean arithmetic:
810      *
811      *         Windows          |          X11
812      * And    Xor      Result   |   Bits     Mask     Result
813      *  0      0     black      |    0        1     background
814      *  0      1     white      |    1        1     foreground
815      *  1      0     no change  |    X        0     no change
816      *  1      1     inverted   |    0        1     background
817      *
818      * which gives:
819      *  Bits = not 'And' and 'Xor' or 'And2' and 'Xor2'
820      *  Mask = not 'And' or 'Xor' or 'And2' and 'Xor2'
821      */
822     SelectObject( src, src_and );
823     SelectObject( dst, bits );
824     BitBlt( dst, 0, 0, width, height, src, 0, and_y, SRCCOPY );
825     SelectObject( dst, mask );
826     BitBlt( dst, 0, 0, width, height, src, 0, and_y, SRCCOPY );
827     SelectObject( dst, mask_inv );
828     BitBlt( dst, 0, 0, width, height, src, 0, and_y, SRCCOPY );
829     SelectObject( src, src_xor );
830     BitBlt( dst, 0, 0, width, height, src, 0, xor_y, SRCAND /* src & dst */ );
831     SelectObject( dst, bits );
832     BitBlt( dst, 0, 0, width, height, src, 0, xor_y, SRCERASE /* src & ~dst */ );
833     SelectObject( dst, mask );
834     BitBlt( dst, 0, 0, width, height, src, 0, xor_y, 0xdd0228 /* src | ~dst */ );
835     /* additional white */
836     SelectObject( src, mask_inv );
837     BitBlt( dst, 1, 1, width, height, src, 0, 0, SRCPAINT /* src | dst */);
838     SelectObject( dst, bits );
839     BitBlt( dst, 1, 1, width, height, src, 0, 0, SRCPAINT /* src | dst */ );
840
841     wine_tsx11_lock();
842     cursor = XCreatePixmapCursor( gdi_display, X11DRV_get_pixmap(bits), X11DRV_get_pixmap(mask),
843                                   fg, bg, hotspot_x, hotspot_y );
844     wine_tsx11_unlock();
845
846 done:
847     DeleteDC( src );
848     DeleteDC( dst );
849     DeleteObject( bits );
850     DeleteObject( mask );
851     DeleteObject( mask_inv );
852     return cursor;
853 }
854
855 /***********************************************************************
856  *              create_xlib_cursor
857  *
858  * Create an X cursor from a Windows one.
859  */
860 static Cursor create_xlib_cursor( HDC hdc, const ICONINFOEXW *icon, int width, int height )
861 {
862     XColor fg, bg;
863     Cursor cursor = None;
864     HBITMAP xor_bitmap = 0;
865     BITMAPINFO *info;
866     unsigned int *color_bits = NULL, *ptr;
867     unsigned char *mask_bits = NULL, *xor_bits = NULL;
868     int i, x, y, has_alpha = 0;
869     int rfg, gfg, bfg, rbg, gbg, bbg, fgBits, bgBits;
870     unsigned int width_bytes = (width + 31) / 32 * 4;
871
872     if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ))))
873         return FALSE;
874     info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
875     info->bmiHeader.biWidth = width;
876     info->bmiHeader.biHeight = -height;
877     info->bmiHeader.biPlanes = 1;
878     info->bmiHeader.biBitCount = 1;
879     info->bmiHeader.biCompression = BI_RGB;
880     info->bmiHeader.biSizeImage = width_bytes * height;
881     info->bmiHeader.biXPelsPerMeter = 0;
882     info->bmiHeader.biYPelsPerMeter = 0;
883     info->bmiHeader.biClrUsed = 0;
884     info->bmiHeader.biClrImportant = 0;
885
886     if (!(mask_bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ))) goto done;
887     if (!GetDIBits( hdc, icon->hbmMask, 0, height, mask_bits, info, DIB_RGB_COLORS )) goto done;
888
889     info->bmiHeader.biBitCount = 32;
890     info->bmiHeader.biSizeImage = width * height * 4;
891     if (!(color_bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ))) goto done;
892     if (!(xor_bits = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, width_bytes * height ))) goto done;
893     GetDIBits( hdc, icon->hbmColor, 0, height, color_bits, info, DIB_RGB_COLORS );
894
895     /* compute fg/bg color and xor bitmap based on average of the color values */
896
897     if (!(xor_bitmap = CreateBitmap( width, height, 1, 1, NULL ))) goto done;
898     rfg = gfg = bfg = rbg = gbg = bbg = fgBits = 0;
899     for (y = 0, ptr = color_bits; y < height; y++)
900     {
901         for (x = 0; x < width; x++, ptr++)
902         {
903             int red   = (*ptr >> 16) & 0xff;
904             int green = (*ptr >> 8) & 0xff;
905             int blue  = (*ptr >> 0) & 0xff;
906             if (red + green + blue > 0x40)
907             {
908                 rfg += red;
909                 gfg += green;
910                 bfg += blue;
911                 fgBits++;
912                 xor_bits[y * width_bytes + x / 8] |= 0x80 >> (x % 8);
913             }
914             else
915             {
916                 rbg += red;
917                 gbg += green;
918                 bbg += blue;
919             }
920         }
921     }
922     if (fgBits)
923     {
924         fg.red   = rfg * 257 / fgBits;
925         fg.green = gfg * 257 / fgBits;
926         fg.blue  = bfg * 257 / fgBits;
927     }
928     else fg.red = fg.green = fg.blue = 0;
929     bgBits = width * height - fgBits;
930     if (bgBits)
931     {
932         bg.red   = rbg * 257 / bgBits;
933         bg.green = gbg * 257 / bgBits;
934         bg.blue  = bbg * 257 / bgBits;
935     }
936     else bg.red = bg.green = bg.blue = 0;
937
938     info->bmiHeader.biBitCount = 1;
939     info->bmiHeader.biSizeImage = width_bytes * height;
940     SetDIBits( hdc, xor_bitmap, 0, height, xor_bits, info, DIB_RGB_COLORS );
941
942     /* generate mask from the alpha channel if we have one */
943
944     for (i = 0, ptr = color_bits; i < width * height; i++, ptr++)
945         if ((has_alpha = (*ptr & 0xff000000) != 0)) break;
946
947     if (has_alpha)
948     {
949         memset( mask_bits, 0, width_bytes * height );
950         for (y = 0, ptr = color_bits; y < height; y++)
951             for (x = 0; x < width; x++, ptr++)
952                 if ((*ptr >> 24) > 25) /* more than 10% alpha */
953                     mask_bits[y * width_bytes + x / 8] |= 0x80 >> (x % 8);
954
955         info->bmiHeader.biBitCount = 1;
956         info->bmiHeader.biSizeImage = width_bytes * height;
957         SetDIBits( hdc, icon->hbmMask, 0, height, mask_bits, info, DIB_RGB_COLORS );
958
959         wine_tsx11_lock();
960         cursor = XCreatePixmapCursor( gdi_display,
961                                       X11DRV_get_pixmap(xor_bitmap),
962                                       X11DRV_get_pixmap(icon->hbmMask),
963                                       &fg, &bg, icon->xHotspot, icon->yHotspot );
964         wine_tsx11_unlock();
965     }
966     else
967     {
968         cursor = create_cursor_from_bitmaps( xor_bitmap, icon->hbmMask, width, height, 0, 0,
969                                              &fg, &bg, icon->xHotspot, icon->yHotspot );
970     }
971
972 done:
973     DeleteObject( xor_bitmap );
974     HeapFree( GetProcessHeap(), 0, info );
975     HeapFree( GetProcessHeap(), 0, color_bits );
976     HeapFree( GetProcessHeap(), 0, xor_bits );
977     HeapFree( GetProcessHeap(), 0, mask_bits );
978     return cursor;
979 }
980
981 /***********************************************************************
982  *              create_cursor
983  *
984  * Create an X cursor from a Windows one.
985  */
986 static Cursor create_cursor( HANDLE handle )
987 {
988     Cursor cursor = 0;
989     ICONINFOEXW info;
990     BITMAP bm;
991
992     if (!handle) return get_empty_cursor();
993
994     info.cbSize = sizeof(info);
995     if (!GetIconInfoExW( handle, &info )) return 0;
996
997 #ifdef SONAME_LIBXCURSOR
998     if (use_system_cursors && (cursor = create_xcursor_system_cursor( &info )))
999     {
1000         DeleteObject( info.hbmColor );
1001         DeleteObject( info.hbmMask );
1002         return cursor;
1003     }
1004 #endif
1005
1006     GetObjectW( info.hbmMask, sizeof(bm), &bm );
1007     if (!info.hbmColor) bm.bmHeight /= 2;
1008
1009     /* make sure hotspot is valid */
1010     if (info.xHotspot >= bm.bmWidth || info.yHotspot >= bm.bmHeight)
1011     {
1012         info.xHotspot = bm.bmWidth / 2;
1013         info.yHotspot = bm.bmHeight / 2;
1014     }
1015
1016     if (info.hbmColor)
1017     {
1018         HDC hdc = CreateCompatibleDC( 0 );
1019         if (hdc)
1020         {
1021 #ifdef SONAME_LIBXCURSOR
1022             if (pXcursorImagesLoadCursor)
1023                 cursor = create_xcursor_cursor( hdc, &info, handle, bm.bmWidth, bm.bmHeight );
1024 #endif
1025             if (!cursor) cursor = create_xlib_cursor( hdc, &info, bm.bmWidth, bm.bmHeight );
1026         }
1027         DeleteObject( info.hbmColor );
1028         DeleteDC( hdc );
1029     }
1030     else
1031     {
1032         XColor fg, bg;
1033         fg.red = fg.green = fg.blue = 0xffff;
1034         bg.red = bg.green = bg.blue = 0;
1035         cursor = create_cursor_from_bitmaps( info.hbmMask, info.hbmMask, bm.bmWidth, bm.bmHeight,
1036                                              bm.bmHeight, 0, &fg, &bg, info.xHotspot, info.yHotspot );
1037     }
1038
1039     DeleteObject( info.hbmMask );
1040     return cursor;
1041 }
1042
1043 /***********************************************************************
1044  *              DestroyCursorIcon (X11DRV.@)
1045  */
1046 void CDECL X11DRV_DestroyCursorIcon( HCURSOR handle )
1047 {
1048     Cursor cursor;
1049
1050     wine_tsx11_lock();
1051     if (cursor_context && !XFindContext( gdi_display, (XID)handle, cursor_context, (char **)&cursor ))
1052     {
1053         TRACE( "%p xid %lx\n", handle, cursor );
1054         XFreeCursor( gdi_display, cursor );
1055         XDeleteContext( gdi_display, (XID)handle, cursor_context );
1056     }
1057     wine_tsx11_unlock();
1058 }
1059
1060 /***********************************************************************
1061  *              SetCursor (X11DRV.@)
1062  */
1063 void CDECL X11DRV_SetCursor( HCURSOR handle )
1064 {
1065     if (cursor_window) SendNotifyMessageW( cursor_window, WM_X11DRV_SET_CURSOR, 0, (LPARAM)handle );
1066 }
1067
1068 /***********************************************************************
1069  *              SetCursorPos (X11DRV.@)
1070  */
1071 BOOL CDECL X11DRV_SetCursorPos( INT x, INT y )
1072 {
1073     Display *display = thread_init_display();
1074     POINT pt;
1075
1076     TRACE( "warping to (%d,%d)\n", x, y );
1077
1078     wine_tsx11_lock();
1079     if (cursor_pos.x == x && cursor_pos.y == y)
1080     {
1081         wine_tsx11_unlock();
1082         /* We still need to generate WM_MOUSEMOVE */
1083         queue_raw_mouse_message( WM_MOUSEMOVE, 0, 0, x, y, 0, GetCurrentTime(), 0, 0 );
1084         return TRUE;
1085     }
1086
1087     pt.x = x; pt.y = y;
1088     clip_point_to_rect( &cursor_clip, &pt);
1089     XWarpPointer( display, root_window, root_window, 0, 0, 0, 0,
1090                   pt.x - virtual_screen_rect.left, pt.y - virtual_screen_rect.top );
1091     XFlush( display ); /* avoids bad mouse lag in games that do their own mouse warping */
1092     cursor_pos = pt;
1093     wine_tsx11_unlock();
1094     return TRUE;
1095 }
1096
1097 /***********************************************************************
1098  *              GetCursorPos (X11DRV.@)
1099  */
1100 BOOL CDECL X11DRV_GetCursorPos(LPPOINT pos)
1101 {
1102     Display *display = thread_init_display();
1103     Window root, child;
1104     int rootX, rootY, winX, winY;
1105     unsigned int xstate;
1106
1107     wine_tsx11_lock();
1108     if ((GetTickCount() - last_time_modified > 100) &&
1109         XQueryPointer( display, root_window, &root, &child,
1110                        &rootX, &rootY, &winX, &winY, &xstate ))
1111     {
1112         update_button_state( xstate );
1113         winX += virtual_screen_rect.left;
1114         winY += virtual_screen_rect.top;
1115         TRACE("pointer at (%d,%d)\n", winX, winY );
1116         cursor_pos.x = winX;
1117         cursor_pos.y = winY;
1118     }
1119     *pos = cursor_pos;
1120     wine_tsx11_unlock();
1121     return TRUE;
1122 }
1123
1124
1125 /***********************************************************************
1126  *              ClipCursor (X11DRV.@)
1127  *
1128  * Set the cursor clipping rectangle.
1129  */
1130 BOOL CDECL X11DRV_ClipCursor( LPCRECT clip )
1131 {
1132     if (!IntersectRect( &cursor_clip, &virtual_screen_rect, clip ))
1133         cursor_clip = virtual_screen_rect;
1134
1135     return TRUE;
1136 }
1137
1138 /***********************************************************************
1139  *           X11DRV_ButtonPress
1140  */
1141 void X11DRV_ButtonPress( HWND hwnd, XEvent *xev )
1142 {
1143     XButtonEvent *event = &xev->xbutton;
1144     int buttonNum = event->button - 1;
1145     WORD wData = 0;
1146     POINT pt;
1147     HWND top_hwnd;
1148
1149     if (buttonNum >= NB_BUTTONS) return;
1150
1151     switch (buttonNum)
1152     {
1153     case 3:
1154         wData = WHEEL_DELTA;
1155         break;
1156     case 4:
1157         wData = -WHEEL_DELTA;
1158         break;
1159     case 5:
1160         wData = XBUTTON1;
1161         break;
1162     case 6:
1163         wData = XBUTTON2;
1164         break;
1165     case 7:
1166         wData = XBUTTON1;
1167         break;
1168     case 8:
1169         wData = XBUTTON2;
1170         break;
1171     }
1172
1173     update_user_time( event->time );
1174     top_hwnd = update_mouse_state( hwnd, event->window, event->x, event->y, event->state, &pt );
1175     if (!top_hwnd) return;
1176
1177     X11DRV_send_mouse_input( top_hwnd, hwnd,
1178                              button_down_flags[buttonNum] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
1179                              pt.x, pt.y, wData, EVENT_x11_time_to_win32_time(event->time), 0, 0 );
1180 }
1181
1182
1183 /***********************************************************************
1184  *           X11DRV_ButtonRelease
1185  */
1186 void X11DRV_ButtonRelease( HWND hwnd, XEvent *xev )
1187 {
1188     XButtonEvent *event = &xev->xbutton;
1189     int buttonNum = event->button - 1;
1190     WORD wData = 0;
1191     POINT pt;
1192     HWND top_hwnd;
1193
1194     if (buttonNum >= NB_BUTTONS || !button_up_flags[buttonNum]) return;
1195
1196     switch (buttonNum)
1197     {
1198     case 5:
1199         wData = XBUTTON1;
1200         break;
1201     case 6:
1202         wData = XBUTTON2;
1203         break;
1204     case 7:
1205         wData = XBUTTON1;
1206         break;
1207     case 8:
1208         wData = XBUTTON2;
1209         break;
1210     }
1211
1212     top_hwnd = update_mouse_state( hwnd, event->window, event->x, event->y, event->state, &pt );
1213     if (!top_hwnd) return;
1214
1215     X11DRV_send_mouse_input( top_hwnd, hwnd,
1216                              button_up_flags[buttonNum] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
1217                              pt.x, pt.y, wData, EVENT_x11_time_to_win32_time(event->time), 0, 0 );
1218 }
1219
1220
1221 /***********************************************************************
1222  *           X11DRV_MotionNotify
1223  */
1224 void X11DRV_MotionNotify( HWND hwnd, XEvent *xev )
1225 {
1226     XMotionEvent *event = &xev->xmotion;
1227     POINT pt;
1228     HWND top_hwnd;
1229
1230     TRACE("hwnd %p, event->is_hint %d\n", hwnd, event->is_hint);
1231
1232     top_hwnd = update_mouse_state( hwnd, event->window, event->x, event->y, event->state, &pt );
1233     if (!top_hwnd) return;
1234
1235     X11DRV_send_mouse_input( top_hwnd, hwnd, MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE,
1236                              pt.x, pt.y, 0, EVENT_x11_time_to_win32_time(event->time), 0, 0 );
1237 }
1238
1239
1240 /***********************************************************************
1241  *           X11DRV_EnterNotify
1242  */
1243 void X11DRV_EnterNotify( HWND hwnd, XEvent *xev )
1244 {
1245     XCrossingEvent *event = &xev->xcrossing;
1246     POINT pt;
1247     HWND top_hwnd;
1248
1249     TRACE("hwnd %p, event->detail %d\n", hwnd, event->detail);
1250
1251     if (event->detail == NotifyVirtual || event->detail == NotifyNonlinearVirtual) return;
1252     if (event->window == x11drv_thread_data()->grab_window) return;
1253
1254     /* simulate a mouse motion event */
1255     top_hwnd = update_mouse_state( hwnd, event->window, event->x, event->y, event->state, &pt );
1256     if (!top_hwnd) return;
1257
1258     X11DRV_send_mouse_input( top_hwnd, hwnd, MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE,
1259                              pt.x, pt.y, 0, EVENT_x11_time_to_win32_time(event->time), 0, 0 );
1260 }