Various cosmetic changes.
[wine] / dlls / x11drv / mouse.c
1 /*
2  * X11 mouse driver
3  *
4  * Copyright 1998 Ulrich Weigand
5  */
6
7 #include "config.h"
8
9 #include "ts_xlib.h"
10 #ifdef HAVE_LIBXXF86DGA2
11 #include "ts_xf86dga2.h"
12 #endif
13
14 #include "windef.h"
15 #include "wine/winuser16.h"
16
17 #include "x11drv.h"
18 #include "debugtools.h"
19
20 DEFAULT_DEBUG_CHANNEL(cursor);
21
22 /**********************************************************************/
23
24 #define NB_BUTTONS   5     /* Windows can handle 3 buttons and the wheel too */
25
26 static const UINT button_down_flags[NB_BUTTONS] =
27 {
28     MOUSEEVENTF_LEFTDOWN,
29     MOUSEEVENTF_MIDDLEDOWN,
30     MOUSEEVENTF_RIGHTDOWN,
31     MOUSEEVENTF_WHEEL,
32     MOUSEEVENTF_WHEEL
33 };
34
35 static const UINT button_up_flags[NB_BUTTONS] =
36 {
37     MOUSEEVENTF_LEFTUP,
38     MOUSEEVENTF_MIDDLEUP,
39     MOUSEEVENTF_RIGHTUP,
40     0,
41     0
42 };
43
44 static BYTE *pKeyStateTable;
45
46
47 /***********************************************************************
48  *              get_coords
49  *
50  * get the coordinates of a mouse event
51  */
52 static void get_coords( HWND *hwnd, Window window, int x, int y, POINT *pt )
53 {
54     struct x11drv_win_data *data;
55     WND *win;
56
57     if (!(win = WIN_GetPtr( *hwnd )) || win == WND_OTHER_PROCESS) return;
58     data = win->pDriverData;
59
60     if (window == data->whole_window)
61     {
62         x -= data->client_rect.left;
63         y -= data->client_rect.top;
64     }
65     WIN_ReleasePtr( win );
66
67     pt->x = x;
68     pt->y = y;
69     if (*hwnd != GetDesktopWindow())
70     {
71         ClientToScreen( *hwnd, pt );
72         *hwnd = GetAncestor( *hwnd, GA_ROOT );
73     }
74 }
75
76
77 /***********************************************************************
78  *              update_key_state
79  *
80  * Update the key state with what X provides us 
81  */
82 static void update_key_state( unsigned int state )
83 {
84     pKeyStateTable[VK_LBUTTON] = (state & Button1Mask ? 0x80 : 0);
85     pKeyStateTable[VK_MBUTTON] = (state & Button2Mask ? 0x80 : 0);
86     pKeyStateTable[VK_RBUTTON] = (state & Button3Mask ? 0x80 : 0);
87     pKeyStateTable[VK_SHIFT]   = (state & ShiftMask   ? 0x80 : 0);
88     pKeyStateTable[VK_CONTROL] = (state & ControlMask ? 0x80 : 0);
89 }
90
91
92 /***********************************************************************
93  *              send_mouse_event
94  */
95 static void send_mouse_event( HWND hwnd, DWORD flags, DWORD posX, DWORD posY,
96                               DWORD data, Time time )
97 {
98     INPUT input;
99
100     TRACE("(%04lX,%ld,%ld)\n", flags, posX, posY );
101
102     if (flags & MOUSEEVENTF_ABSOLUTE)
103     {
104         int width  = GetSystemMetrics( SM_CXSCREEN );
105         int height = GetSystemMetrics( SM_CYSCREEN );
106         /* Relative mouse movements seem not to be scaled as absolute ones */
107         posX = (((long)posX << 16) + width-1)  / width;
108         posY = (((long)posY << 16) + height-1) / height;
109     }
110
111     input.type             = WINE_INTERNAL_INPUT_MOUSE;
112     input.u.mi.dx          = posX;
113     input.u.mi.dy          = posY;
114     input.u.mi.mouseData   = data;
115     input.u.mi.dwFlags     = flags;
116     input.u.mi.time        = time - X11DRV_server_startticks;
117     input.u.mi.dwExtraInfo = (ULONG_PTR)hwnd;
118     SendInput( 1, &input, sizeof(input) );
119 }
120
121
122 /***********************************************************************
123  *              X11DRV_GetCursor
124  */
125 Cursor X11DRV_GetCursor( Display *display, CURSORICONINFO *ptr )
126 {
127     Pixmap pixmapBits, pixmapMask, pixmapMaskInv, pixmapAll;
128     XColor fg, bg;
129     Cursor cursor = None;
130
131     if (!ptr)  /* Create an empty cursor */
132     {
133         static const char data[] = { 0 };
134
135         bg.red = bg.green = bg.blue = 0x0000;
136         pixmapBits = XCreateBitmapFromData( display, root_window, data, 1, 1 );
137         if (pixmapBits)
138         {
139             cursor = XCreatePixmapCursor( display, pixmapBits, pixmapBits,
140                                           &bg, &bg, 0, 0 );
141             XFreePixmap( display, pixmapBits );
142         }
143     }
144     else  /* Create the X cursor from the bits */
145     {
146         XImage *image;
147         GC gc;
148         
149         TRACE("Bitmap %dx%d planes=%d bpp=%d bytesperline=%d\n",
150             ptr->nWidth, ptr->nHeight, ptr->bPlanes, ptr->bBitsPerPixel,
151             ptr->nWidthBytes);
152         /* Create a pixmap and transfer all the bits to it */
153
154         /* NOTE: Following hack works, but only because XFree depth
155          *       1 images really use 1 bit/pixel (and so the same layout
156          *       as the Windows cursor data). Perhaps use a more generic
157          *       algorithm here.
158          */
159         /* This pixmap will be written with two bitmaps. The first is
160          *  the mask and the second is the image.
161          */
162         if (!(pixmapAll = XCreatePixmap( display, root_window,
163                   ptr->nWidth, ptr->nHeight * 2, 1 ))) 
164             return 0;
165         if (!(image = XCreateImage( display, visual,
166                 1, ZPixmap, 0, (char *)(ptr + 1), ptr->nWidth,
167                 ptr->nHeight * 2, 16, ptr->nWidthBytes/ptr->bBitsPerPixel))) 
168         {
169             XFreePixmap( display, pixmapAll );
170             return 0;
171         }
172         gc = XCreateGC( display, pixmapAll, 0, NULL );
173         XSetGraphicsExposures( display, gc, False );
174         image->byte_order = MSBFirst;
175         image->bitmap_bit_order = MSBFirst;
176         image->bitmap_unit = 16;
177         _XInitImageFuncPtrs(image);
178         if (ptr->bPlanes * ptr->bBitsPerPixel == 1)
179         {
180             /* A plain old white on black cursor. */
181             fg.red = fg.green = fg.blue = 0xffff;
182             bg.red = bg.green = bg.blue = 0x0000;
183             XPutImage( display, pixmapAll, gc, image,
184                 0, 0, 0, 0, ptr->nWidth, ptr->nHeight * 2 );
185         }
186         else
187         {
188             int     rbits, gbits, bbits, red, green, blue;
189             int     rfg, gfg, bfg, rbg, gbg, bbg;
190             int     rscale, gscale, bscale;
191             int     x, y, xmax, ymax, bitIndex, byteIndex, xorIndex;
192             unsigned char *theMask, *theImage, theChar;
193             int     threshold, fgBits, bgBits, bitShifted;
194             BYTE    pXorBits[128];   /* Up to 32x32 icons */
195             
196             switch (ptr->bBitsPerPixel)
197             {
198             case 24:
199                 rbits = 8;
200                 gbits = 8;
201                 bbits = 8;
202                 threshold = 0x40;
203                 break;
204             default:
205                 FIXME("Currently no support for cursors with %d bits per pixel\n",
206                   ptr->bBitsPerPixel);
207                 XFreePixmap( display, pixmapAll );
208                 XFreeGC( display, gc );
209                 image->data = NULL;
210                 XDestroyImage( image );
211                 return 0;
212             }
213             /* The location of the mask. */
214             theMask = (char *)(ptr + 1);
215             /* The mask should still be 1 bit per pixel. The color image
216              * should immediately follow the mask. 
217              */
218             theImage = &theMask[ptr->nWidth/8 * ptr->nHeight];
219             rfg = gfg = bfg = rbg = gbg = bbg = 0;
220             bitIndex = 0;
221             byteIndex = 0;
222             xorIndex = 0;
223             fgBits = 0;
224             bitShifted = 0x01;
225             xmax = (ptr->nWidth > 32) ? 32 : ptr->nWidth;
226             if (ptr->nWidth > 32) {
227                 ERR("Got a %dx%d cursor. Cannot handle larger than 32x32.\n",
228                   ptr->nWidth, ptr->nHeight);
229             }
230             ymax = (ptr->nHeight > 32) ? 32 : ptr->nHeight;
231             
232             memset(pXorBits, 0, 128);
233             for (y=0; y<ymax; y++)
234             {
235                 for (x=0; x<xmax; x++)
236                 {
237                     theChar = theImage[byteIndex++];
238                     red = green = blue = 0;
239                     blue = theChar;
240                     theChar = theImage[byteIndex++];
241                     green = theChar;
242                     theChar = theImage[byteIndex++];
243                     red = theChar;
244                     if (red+green+blue > threshold)
245                     {
246                         rfg += red;
247                         gfg += green;
248                         bfg += blue;
249                         fgBits++;
250                         pXorBits[xorIndex] |= bitShifted;
251                     }
252                     else
253                     {
254                         rbg += red;
255                         gbg += green;
256                         bbg += blue;
257                     }
258                     if (x%8 == 7)
259                     {
260                         bitShifted = 0x01;
261                         xorIndex++;
262                     }
263                     else
264                         bitShifted = bitShifted << 1;
265                 }
266             }
267             rscale = 1 << (16 - rbits);
268             gscale = 1 << (16 - gbits);
269             bscale = 1 << (16 - bbits);
270             fg.red   = rfg * rscale / fgBits;
271             fg.green = gfg * gscale / fgBits;
272             fg.blue  = bfg * bscale / fgBits;
273             bgBits = xmax * ymax - fgBits;
274             bg.red   = rbg * rscale / bgBits;
275             bg.green = gbg * gscale / bgBits;
276             bg.blue  = bbg * bscale / bgBits;
277             pixmapBits = XCreateBitmapFromData( display, root_window, pXorBits, xmax, ymax );
278             if (!pixmapBits)
279             {
280                 XFreePixmap( display, pixmapAll );
281                 XFreeGC( display, gc );
282                 image->data = NULL;
283                 XDestroyImage( image );
284                 return 0;
285             }
286             
287             /* Put the mask. */
288             XPutImage( display, pixmapAll, gc, image,
289                    0, 0, 0, 0, ptr->nWidth, ptr->nHeight );
290             XSetFunction( display, gc, GXcopy );
291             /* Put the image */
292             XCopyArea( display, pixmapBits, pixmapAll, gc,
293                        0, 0, xmax, ymax, 0, ptr->nHeight );
294             XFreePixmap( display, pixmapBits );
295         }
296         image->data = NULL;
297         XDestroyImage( image );
298
299         /* Now create the 2 pixmaps for bits and mask */
300
301         pixmapBits = XCreatePixmap( display, root_window, ptr->nWidth, ptr->nHeight, 1 );
302         pixmapMask = XCreatePixmap( display, root_window, ptr->nWidth, ptr->nHeight, 1 );
303         pixmapMaskInv = XCreatePixmap( display, root_window, ptr->nWidth, ptr->nHeight, 1 );
304
305         /* Make sure everything went OK so far */
306
307         if (pixmapBits && pixmapMask && pixmapMaskInv)
308         {
309             /* We have to do some magic here, as cursors are not fully
310              * compatible between Windows and X11. Under X11, there
311              * are only 3 possible color cursor: black, white and
312              * masked. So we map the 4th Windows color (invert the
313              * bits on the screen) to black and an additional white bit on 
314              * an other place (+1,+1). This require some boolean arithmetic:
315              *
316              *         Windows          |          X11
317              * And    Xor      Result   |   Bits     Mask     Result
318              *  0      0     black      |    0        1     background
319              *  0      1     white      |    1        1     foreground
320              *  1      0     no change  |    X        0     no change
321              *  1      1     inverted   |    0        1     background
322              *
323              * which gives:
324              *  Bits = not 'And' and 'Xor' or 'And2' and 'Xor2'
325              *  Mask = not 'And' or 'Xor' or 'And2' and 'Xor2'
326              *
327              * FIXME: apparently some servers do support 'inverted' color.
328              * I don't know if it's correct per the X spec, but maybe
329              * we ought to take advantage of it.  -- AJ
330              */
331             XSetFunction( display, gc, GXcopy );
332             XCopyArea( display, pixmapAll, pixmapBits, gc,
333                        0, 0, ptr->nWidth, ptr->nHeight, 0, 0 );
334             XCopyArea( display, pixmapAll, pixmapMask, gc,
335                        0, 0, ptr->nWidth, ptr->nHeight, 0, 0 );
336             XCopyArea( display, pixmapAll, pixmapMaskInv, gc,
337                        0, 0, ptr->nWidth, ptr->nHeight, 0, 0 );
338             XSetFunction( display, gc, GXand );
339             XCopyArea( display, pixmapAll, pixmapMaskInv, gc,
340                        0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 );
341             XSetFunction( display, gc, GXandReverse );
342             XCopyArea( display, pixmapAll, pixmapBits, gc,
343                        0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 );
344             XSetFunction( display, gc, GXorReverse );
345             XCopyArea( display, pixmapAll, pixmapMask, gc,
346                        0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 );
347             /* Additional white */
348             XSetFunction( display, gc, GXor );
349             XCopyArea( display, pixmapMaskInv, pixmapMask, gc,
350                        0, 0, ptr->nWidth, ptr->nHeight, 1, 1 );
351             XCopyArea( display, pixmapMaskInv, pixmapBits, gc,
352                        0, 0, ptr->nWidth, ptr->nHeight, 1, 1 );
353             XSetFunction( display, gc, GXcopy );
354             cursor = XCreatePixmapCursor( display, pixmapBits, pixmapMask,
355                                 &fg, &bg, ptr->ptHotSpot.x, ptr->ptHotSpot.y );
356         }
357
358         /* Now free everything */
359
360         if (pixmapAll) XFreePixmap( display, pixmapAll );
361         if (pixmapBits) XFreePixmap( display, pixmapBits );
362         if (pixmapMask) XFreePixmap( display, pixmapMask );
363         if (pixmapMaskInv) XFreePixmap( display, pixmapMaskInv );
364         XFreeGC( display, gc );
365     }
366     return cursor;
367 }
368
369 /* set the cursor of a window; helper for X11DRV_SetCursor */
370 static BOOL CALLBACK set_win_cursor( HWND hwnd, LPARAM cursor )
371 {
372     Window win = X11DRV_get_whole_window( hwnd );
373     if (win) TSXDefineCursor( thread_display(), win, (Cursor)cursor );
374     return TRUE;
375 }
376
377 /***********************************************************************
378  *              SetCursor (X11DRV.@)
379  */
380 void X11DRV_SetCursor( CURSORICONINFO *lpCursor )
381 {
382     Cursor cursor;
383
384     if (root_window != DefaultRootWindow(gdi_display))
385     {
386         /* If in desktop mode, set the cursor on the desktop window */
387
388         wine_tsx11_lock();
389         cursor = X11DRV_GetCursor( gdi_display, lpCursor );
390         if (cursor)
391         {
392             XDefineCursor( gdi_display, root_window, cursor );
393             XFreeCursor( gdi_display, cursor );
394         }
395         wine_tsx11_unlock();
396     }
397     else /* set the same cursor for all top-level windows of the current thread */
398     {
399         Display *display = thread_display();
400
401         wine_tsx11_lock();
402         cursor = X11DRV_GetCursor( display, lpCursor );
403         wine_tsx11_unlock();
404         if (cursor)
405         {
406 /*            EnumThreadWindows( GetCurrentThreadId(), set_win_cursor, (LPARAM)cursor );*/
407             EnumWindows( set_win_cursor, (LPARAM)cursor );
408             TSXFreeCursor( display, cursor );
409         }
410     }
411 }
412
413 /***********************************************************************
414  *              SetCursorPos (X11DRV.@)
415  */
416 void X11DRV_SetCursorPos( INT x, INT y )
417 {
418     Display *display = thread_display();
419
420     TRACE( "warping to (%d,%d)\n", x, y );
421
422     wine_tsx11_lock();
423     XWarpPointer( display, root_window, root_window, 0, 0, 0, 0, x, y );
424     XFlush( display ); /* just in case */
425     wine_tsx11_unlock();
426 }
427
428 /***********************************************************************
429  *              GetCursorPos (X11DRV.@)
430  */
431 void X11DRV_GetCursorPos(LPPOINT pos)
432 {
433   Display *display = thread_display();
434   Window root, child;
435   int rootX, rootY, winX, winY;
436   unsigned int xstate;
437
438   if (!TSXQueryPointer( display, root_window, &root, &child,
439                         &rootX, &rootY, &winX, &winY, &xstate ))
440     return;
441
442   TRACE("pointer at (%d,%d)\n", winX, winY );
443   pos->x = winX;
444   pos->y = winY;
445 }
446
447 /***********************************************************************
448  *              InitMouse (X11DRV.@)
449  */
450 void X11DRV_InitMouse( BYTE *key_state_table )
451 {
452     Window root, child;
453     int root_x, root_y, child_x, child_y;
454     unsigned int KeyState;
455
456     pKeyStateTable = key_state_table;
457     /* Get the current mouse position and simulate an absolute mouse
458        movement to initialize the mouse global variables */
459     TSXQueryPointer( thread_display(), root_window, &root, &child,
460                      &root_x, &root_y, &child_x, &child_y, &KeyState);
461     update_key_state( KeyState );
462     send_mouse_event( 0, MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE,
463                       root_x, root_y, 0, GetTickCount() + X11DRV_server_startticks );
464 }
465
466
467 /***********************************************************************
468  *           X11DRV_ButtonPress
469  */
470 void X11DRV_ButtonPress( HWND hwnd, XButtonEvent *event )
471 {
472     int buttonNum = event->button - 1;
473     WORD wData = 0;
474     POINT pt;
475
476     if (buttonNum >= NB_BUTTONS) return;
477
478     get_coords( &hwnd, event->window, event->x, event->y, &pt );
479
480     switch (buttonNum)
481     {
482     case 3:
483         wData = WHEEL_DELTA;
484         break;
485     case 4:
486         wData = -WHEEL_DELTA;
487         break;
488     }
489     update_key_state( event->state );
490     send_mouse_event( hwnd, button_down_flags[buttonNum] | MOUSEEVENTF_ABSOLUTE,
491                       pt.x, pt.y, wData, event->time );
492 }
493
494
495 /***********************************************************************
496  *           X11DRV_ButtonRelease
497  */
498 void X11DRV_ButtonRelease( HWND hwnd, XButtonEvent *event )
499 {
500     int buttonNum = event->button - 1;
501     POINT pt;
502
503     if (buttonNum >= NB_BUTTONS || !button_up_flags[buttonNum]) return;
504
505     get_coords( &hwnd, event->window, event->x, event->y, &pt );
506     update_key_state( event->state );
507     send_mouse_event( hwnd, button_up_flags[buttonNum] | MOUSEEVENTF_ABSOLUTE,
508                       pt.x, pt.y, 0, event->time );
509 }
510
511
512 /***********************************************************************
513  *           X11DRV_MotionNotify
514  */
515 void X11DRV_MotionNotify( HWND hwnd, XMotionEvent *event )
516 {
517     POINT pt;
518
519     get_coords( &hwnd, event->window, event->x, event->y, &pt );
520     update_key_state( event->state );
521     send_mouse_event( hwnd, MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE,
522                       pt.x, pt.y, 0, event->time );
523 }
524
525
526 #ifdef HAVE_LIBXXF86DGA2
527 /**********************************************************************
528  *              X11DRV_DGAMotionEvent
529  */
530 void X11DRV_DGAMotionEvent( HWND hwnd, XDGAMotionEvent *event )
531 {
532     update_key_state( event->state );
533     send_mouse_event( hwnd, MOUSEEVENTF_MOVE, event->dx, event->dy, 0, event->time );
534 }
535
536 /**********************************************************************
537  *              X11DRV_DGAButtonPressEvent
538  */
539 void X11DRV_DGAButtonPressEvent( HWND hwnd, XDGAButtonEvent *event )
540 {
541     int buttonNum = event->button - 1;
542
543     if (buttonNum >= NB_BUTTONS) return;
544     update_key_state( event->state );
545     send_mouse_event( hwnd, button_down_flags[buttonNum], 0, 0, 0, event->time );
546 }
547
548 /**********************************************************************
549  *              X11DRV_DGAButtonReleaseEvent
550  */
551 void X11DRV_DGAButtonReleaseEvent( HWND hwnd, XDGAButtonEvent *event )
552 {
553     int buttonNum = event->button - 1;
554
555     if (buttonNum >= NB_BUTTONS) return;
556     update_key_state( event->state );
557     send_mouse_event( hwnd, button_up_flags[buttonNum], 0, 0, 0, event->time );
558 }
559 #endif /* HAVE_LIBXXF86DGA2 */