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