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