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