The scancode Windows send for extended keys is the scancode of the
[wine] / windows / display.c
1 /*
2  * DISPLAY driver
3  *
4  * Copyright 1998 Ulrich Weigand
5  *
6  */
7
8 #include "ts_xlib.h"
9 #include "ts_xresource.h"
10 #include "ts_xutil.h"
11
12 #include <stdlib.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include "windows.h"
16 #include "win.h"
17 #include "gdi.h"
18 #include "display.h"
19 #include "callback.h"
20 #include "heap.h"
21 #include "debug.h"
22 #include "debugtools.h"
23 #include "x11drv.h"
24
25 Cursor DISPLAY_XCursor = None;    /* Current X cursor */
26
27 BOOL32 DISPLAY_DisableWarpPointer = FALSE;  /* hack; see DISPLAY_MoveCursor */
28
29
30 /***********************************************************************
31  *           DISPLAY_Inquire                    (DISPLAY.101)
32  */
33 WORD WINAPI DISPLAY_Inquire(LPCURSORINFO lpCursorInfo) 
34 {
35     lpCursorInfo->wXMickeys = 1;
36     lpCursorInfo->wYMickeys = 1;
37
38     return sizeof(CURSORINFO);
39 }
40
41 /***********************************************************************
42  *           DISPLAY_DoSetCursor
43  */
44 static BOOL32 DISPLAY_DoSetCursor( CURSORICONINFO *ptr )
45 {
46     Pixmap pixmapBits, pixmapMask, pixmapAll;
47     XColor fg, bg;
48     Cursor cursor = None;
49
50     if (!ptr)  /* Create an empty cursor */
51     {
52         static const char data[] = { 0 };
53
54         bg.red = bg.green = bg.blue = 0x0000;
55         pixmapBits = XCreateBitmapFromData( display, rootWindow, data, 1, 1 );
56         if (pixmapBits)
57         {
58             cursor = XCreatePixmapCursor( display, pixmapBits, pixmapBits,
59                                           &bg, &bg, 0, 0 );
60             XFreePixmap( display, pixmapBits );
61         }
62     }
63     else  /* Create the X cursor from the bits */
64     {
65         XImage *image;
66
67         if (ptr->bPlanes * ptr->bBitsPerPixel != 1)
68         {
69             WARN(cursor, "Cursor has more than 1 bpp!\n" );
70             return FALSE;
71         }
72
73         /* Create a pixmap and transfer all the bits to it */
74
75         /* NOTE: Following hack works, but only because XFree depth
76          *       1 images really use 1 bit/pixel (and so the same layout
77          *       as the Windows cursor data). Perhaps use a more generic
78          *       algorithm here.
79          */
80         pixmapAll = XCreatePixmap( display, rootWindow,
81                                    ptr->nWidth, ptr->nHeight * 2, 1 );
82         image = XCreateImage( display, DefaultVisualOfScreen(screen),
83                               1, ZPixmap, 0, (char *)(ptr + 1), ptr->nWidth,
84                               ptr->nHeight * 2, 16, ptr->nWidthBytes);
85         if (image)
86         {
87             image->byte_order = MSBFirst;
88             image->bitmap_bit_order = MSBFirst;
89             image->bitmap_unit = 16;
90             _XInitImageFuncPtrs(image);
91             if (pixmapAll)
92                 XPutImage( display, pixmapAll, BITMAP_monoGC, image,
93                            0, 0, 0, 0, ptr->nWidth, ptr->nHeight * 2 );
94             image->data = NULL;
95             XDestroyImage( image );
96         }
97
98         /* Now create the 2 pixmaps for bits and mask */
99
100         pixmapBits = XCreatePixmap( display, rootWindow,
101                                     ptr->nWidth, ptr->nHeight, 1 );
102         pixmapMask = XCreatePixmap( display, rootWindow,
103                                     ptr->nWidth, ptr->nHeight, 1 );
104
105         /* Make sure everything went OK so far */
106
107         if (pixmapBits && pixmapMask && pixmapAll)
108         {
109             /* We have to do some magic here, as cursors are not fully
110              * compatible between Windows and X11. Under X11, there
111              * are only 3 possible color cursor: black, white and
112              * masked. So we map the 4th Windows color (invert the
113              * bits on the screen) to black. This require some boolean
114              * arithmetic:
115              *
116              *         Windows          |          X11
117              * Xor    And      Result   |   Bits     Mask     Result
118              *  0      0     black      |    0        1     background
119              *  0      1     no change  |    X        0     no change
120              *  1      0     white      |    1        1     foreground
121              *  1      1     inverted   |    0        1     background
122              *
123              * which gives:
124              *  Bits = 'Xor' and not 'And'
125              *  Mask = 'Xor' or not 'And'
126              *
127              * FIXME: apparently some servers do support 'inverted' color.
128              * I don't know if it's correct per the X spec, but maybe
129              * we ought to take advantage of it.  -- AJ
130              */
131             XCopyArea( display, pixmapAll, pixmapBits, BITMAP_monoGC,
132                        0, 0, ptr->nWidth, ptr->nHeight, 0, 0 );
133             XCopyArea( display, pixmapAll, pixmapMask, BITMAP_monoGC,
134                        0, 0, ptr->nWidth, ptr->nHeight, 0, 0 );
135             XSetFunction( display, BITMAP_monoGC, GXandReverse );
136             XCopyArea( display, pixmapAll, pixmapBits, BITMAP_monoGC,
137                        0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 );
138             XSetFunction( display, BITMAP_monoGC, GXorReverse );
139             XCopyArea( display, pixmapAll, pixmapMask, BITMAP_monoGC,
140                        0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 );
141             XSetFunction( display, BITMAP_monoGC, GXcopy );
142             fg.red = fg.green = fg.blue = 0xffff;
143             bg.red = bg.green = bg.blue = 0x0000;
144             cursor = XCreatePixmapCursor( display, pixmapBits, pixmapMask,
145                                 &fg, &bg, ptr->ptHotSpot.x, ptr->ptHotSpot.y );
146         }
147
148         /* Now free everything */
149
150         if (pixmapAll) XFreePixmap( display, pixmapAll );
151         if (pixmapBits) XFreePixmap( display, pixmapBits );
152         if (pixmapMask) XFreePixmap( display, pixmapMask );
153     }
154
155     if (cursor == None) return FALSE;
156     if (DISPLAY_XCursor != None) XFreeCursor( display, DISPLAY_XCursor );
157     DISPLAY_XCursor = cursor;
158
159     if (rootWindow != DefaultRootWindow(display) || !WIN_GetDesktop())
160     {
161         /* Set the cursor on the desktop window */
162         XDefineCursor( display, rootWindow, cursor );
163     }
164     else
165     {
166         /* FIXME: this won't work correctly with native USER !*/
167
168         /* Set the same cursor for all top-level windows */
169         HWND32 hwnd = GetWindow32( GetDesktopWindow32(), GW_CHILD );
170         while(hwnd)
171         {
172             Window win = X11DRV_WND_GetXWindow( hwnd );
173             if (win && win!=DefaultRootWindow(display))
174                 XDefineCursor( display, win, cursor );
175             hwnd = GetWindow32( hwnd, GW_HWNDNEXT );
176         }
177     }
178     return TRUE;
179 }
180
181 /***********************************************************************
182  *           DISPLAY_SetCursor                  (DISPLAY.102)
183  */
184 VOID WINAPI DISPLAY_SetCursor( CURSORICONINFO *lpCursor )
185 {
186     EnterCriticalSection( &X11DRV_CritSection );
187     CALL_LARGE_STACK( DISPLAY_DoSetCursor, lpCursor );
188     LeaveCriticalSection( &X11DRV_CritSection );
189 }
190
191 /***********************************************************************
192  *           DISPLAY_MoveCursor                 (DISPLAY.103)
193  */
194 VOID WINAPI DISPLAY_MoveCursor( WORD wAbsX, WORD wAbsY )
195 {
196     /* 
197      * We do not want the to create MotionNotify events here, 
198      * otherwise we will get an endless recursion:
199      * XMotionEvent -> MOUSEEVENTF_MOVE -> mouse_event -> DisplayMoveCursor
200      * -> XWarpPointer -> XMotionEvent -> ...
201      *
202      * Unfortunately, the XWarpPointer call does create a MotionNotify
203      * event. So, we use a hack: before MOUSE_SendEvent calls the mouse event
204      * procedure, it sets a global flag. If this flag is set, we skip the
205      * XWarpPointer call.  If we are *not* called from within MOUSE_SendEvent,
206      * we will call XWarpPointer, which will create a MotionNotify event.
207      * Strictly speaking, this is also wrong, but that should normally not
208      * have any negative effects ...
209      *
210      * But first of all, we check whether we already are at the position
211      * are supposed to move to; if so, we don't need to do anything.
212      */
213
214     Window root, child;
215     int rootX, rootY, winX, winY;
216     unsigned int xstate;
217
218     if (DISPLAY_DisableWarpPointer) return;
219
220     if (!TSXQueryPointer( display, rootWindow, &root, &child,
221                           &rootX, &rootY, &winX, &winY, &xstate ))
222         return;
223
224     if ( winX == wAbsX && winY == wAbsY )
225         return;
226
227     TRACE( cursor, "(%d,%d): moving from (%d,%d)\n", wAbsX, wAbsY, winX, winY );
228
229     TSXWarpPointer( display, rootWindow, rootWindow, 0, 0, 0, 0, wAbsX, wAbsY );
230 }
231
232 /***********************************************************************
233  *           DISPLAY_CheckCursor                  (DISPLAY.104)
234  */
235 VOID WINAPI DISPLAY_CheckCursor()
236 {
237     FIXME( cursor, "stub\n" );
238 }
239
240 /***********************************************************************
241  *           UserRepaintDisable                 (DISPLAY.500)
242  */
243 VOID WINAPI UserRepaintDisable( BOOL16 disable )
244 {
245     TRACE( cursor, "(%d): stub\n", disable );
246 }
247