Release 950727
[wine] / windows / cursor.c
1 /*
2  *    WINE
3 static char Copyright[] = "Copyright  Martin Ayotte, 1993";
4 */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include <unistd.h>
13 #include <X11/cursorfont.h>
14 #include <X11/Xlib.h>
15 #include "windows.h"
16 #include "win.h"
17 #include "gdi.h"
18 #include "neexe.h"
19 #include "wine.h"
20 #include "cursor.h"
21 #include "resource.h"
22 #include "stddebug.h"
23 #include "debug.h"
24 #include "arch.h"
25
26 static int ShowCursCount = 0;
27 static HCURSOR hActiveCursor;
28 static HCURSOR hEmptyCursor = 0;
29 RECT    ClipCursorRect;
30
31 static struct { SEGPTR name; HCURSOR cursor; } system_cursor[] =
32 {
33     { IDC_ARROW, 0 },
34     { IDC_IBEAM, 0 },
35     { IDC_WAIT, 0 },
36     { IDC_CROSS, 0 },
37     { IDC_UPARROW, 0 },
38     { IDC_SIZE, 0 },
39     { IDC_ICON, 0 },
40     { IDC_SIZENWSE, 0 },
41     { IDC_SIZENESW, 0 },
42     { IDC_SIZEWE, 0 },
43     { IDC_SIZENS, 0 }
44 };
45
46 #define NB_SYS_CURSORS  (sizeof(system_cursor)/sizeof(system_cursor[0]))
47
48
49 /**********************************************************************
50  *                      LoadCursor [USER.173]
51  */
52 HCURSOR LoadCursor(HANDLE instance, SEGPTR cursor_name)
53 {
54     HCURSOR     hCursor;
55     HRSRC       hRsrc;
56     HANDLE      rsc_mem;
57     WORD        *lp;
58     LONG        *lpl,size;
59     CURSORDESCRIP *lpcurdesc;
60     CURSORALLOC   *lpcur;
61     HDC         hdc;
62     int i;
63     unsigned char *cp1,*cp2;
64     dprintf_resource(stddeb,"LoadCursor: instance = %04x, name = %08lx\n",
65            instance, cursor_name);
66     if (!instance)
67     {
68         for (i = 0; i < NB_SYS_CURSORS; i++)
69             if (system_cursor[i].name == cursor_name)
70             {
71                 if (system_cursor[i].cursor) return system_cursor[i].cursor;
72                 else break;
73             }
74         if (i == NB_SYS_CURSORS) return 0;
75     }
76     hCursor = GlobalAlloc(GMEM_MOVEABLE, sizeof(CURSORALLOC) + 1024L); 
77     if (hCursor == (HCURSOR)NULL) return 0;
78     if (!instance) system_cursor[i].cursor = hCursor;
79
80     dprintf_cursor(stddeb,"LoadCursor Alloc hCursor=%X\n", hCursor);
81     lpcur = (CURSORALLOC *)GlobalLock(hCursor);
82     memset(lpcur, 0, sizeof(CURSORALLOC));
83     if (instance == (HANDLE)NULL) {
84         switch((LONG)cursor_name) {
85             case IDC_ARROW:
86                 lpcur->xcursor = XCreateFontCursor(display, XC_top_left_arrow);
87                 GlobalUnlock(hCursor);
88                 return hCursor;
89             case IDC_CROSS:
90                 lpcur->xcursor = XCreateFontCursor(display, XC_crosshair);
91                 GlobalUnlock(hCursor);
92                 return hCursor;
93             case IDC_IBEAM:
94                 lpcur->xcursor = XCreateFontCursor(display, XC_xterm);
95                 GlobalUnlock(hCursor);
96                 return hCursor;
97             case IDC_WAIT:
98                 lpcur->xcursor = XCreateFontCursor(display, XC_watch);
99                 GlobalUnlock(hCursor);
100                 return hCursor;
101             case IDC_SIZENS:
102                 lpcur->xcursor = XCreateFontCursor(display, XC_sb_v_double_arrow);
103                 GlobalUnlock(hCursor);
104                 return hCursor;
105             case IDC_SIZEWE:
106                 lpcur->xcursor = XCreateFontCursor(display, XC_sb_h_double_arrow);
107                 GlobalUnlock(hCursor);
108                 return hCursor;
109             case IDC_SIZENWSE:
110             case IDC_SIZENESW:
111                 lpcur->xcursor = XCreateFontCursor(display, XC_fleur);
112                 GlobalUnlock(hCursor);
113                 return hCursor;
114             default:
115                 break;
116             }
117         }
118
119 #if 0
120     /* this code replaces all bitmap cursors with the default cursor */
121     lpcur->xcursor = XCreateFontCursor(display, XC_top_left_arrow);
122     GlobalUnlock(hCursor);
123     return hCursor;
124 #endif
125
126     if (!(hdc = GetDC(0))) return 0;
127     if (!(hRsrc = FindResource( instance, cursor_name, RT_GROUP_CURSOR )))
128     {
129         ReleaseDC(0, hdc); 
130         return 0;
131     }
132     rsc_mem = LoadResource(instance, hRsrc );
133     if (rsc_mem == (HANDLE)NULL) {
134     fprintf(stderr,"LoadCursor / Cursor %08lx not Found !\n", cursor_name);
135         ReleaseDC(0, hdc); 
136         return 0;
137         }
138     lp = (WORD *)LockResource(rsc_mem);
139     if (lp == NULL) {
140         FreeResource( rsc_mem );
141         ReleaseDC(0, hdc); 
142         return 0;
143         }
144     lpcurdesc = (CURSORDESCRIP *)(lp + 3);
145 #if 0
146     dprintf_cursor(stddeb,"LoadCursor / curReserved=%X\n", *lp);
147     dprintf_cursor(stddeb,"LoadCursor / curResourceType=%X\n", *(lp + 1));
148     dprintf_cursor(stddeb,"LoadCursor / curResourceCount=%X\n", *(lp + 2));
149     dprintf_cursor(stddeb,"LoadCursor / cursor Width=%d\n", 
150                 (int)lpcurdesc->Width);
151     dprintf_cursor(stddeb,"LoadCursor / cursor Height=%d\n", 
152                 (int)lpcurdesc->Height);
153     dprintf_cursor(stddeb,"LoadCursor / cursor curXHotspot=%d\n", 
154                 (int)lpcurdesc->curXHotspot);
155     dprintf_cursor(stddeb,"LoadCursor / cursor curYHotspot=%d\n", 
156                 (int)lpcurdesc->curYHotspot);
157     dprintf_cursor(stddeb,"LoadCursor / cursor curDIBSize=%lX\n", 
158                 (DWORD)lpcurdesc->curDIBSize);
159     dprintf_cursor(stddeb,"LoadCursor / cursor curDIBOffset=%lX\n", 
160                 (DWORD)lpcurdesc->curDIBOffset);
161 #endif
162     lpcur->descriptor = *lpcurdesc;
163     FreeResource( rsc_mem );
164     if (!(hRsrc = FindResource( instance,
165                                 MAKEINTRESOURCE(lpcurdesc->curDIBOffset), 
166                                 RT_CURSOR )))
167     {
168         ReleaseDC(0, hdc); 
169         return 0;
170     }
171     rsc_mem = LoadResource(instance, hRsrc );
172     if (rsc_mem == (HANDLE)NULL) {
173         fprintf(stderr,
174                 "LoadCursor / Cursor %08lx Bitmap not Found !\n", cursor_name);
175         ReleaseDC(0, hdc); 
176         return 0;
177         }
178     lpl = (LONG *)LockResource(rsc_mem);
179     lpl++;
180     size = CONV_LONG (*lpl);
181     if (size == sizeof(BITMAPCOREHEADER)){
182         CONV_BITMAPCOREHEADER (lpl);
183         ((BITMAPINFOHEADER *)lpl)->biHeight /= 2;
184         lpcur->hBitmap = ConvertCoreBitmap( hdc, (BITMAPCOREHEADER *) lpl );
185     } else if (size == sizeof(BITMAPINFOHEADER)){
186         CONV_BITMAPINFO (lpl);
187         ((BITMAPINFOHEADER *)lpl)->biHeight /= 2;
188         lpcur->hBitmap = ConvertInfoBitmap( hdc, (BITMAPINFO *) lpl );
189     } else  {
190       fprintf(stderr,"No bitmap for cursor?\n");
191       lpcur->hBitmap = 0;
192     }
193     lpl = (LONG *)((char *)lpl + size + 8);
194   /* This is rather strange! The data is stored *BACKWARDS* and       */
195   /* mirrored! But why?? FIXME: the image must be flipped at the Y    */
196   /* axis, either here or in CreateCusor(); */
197     size = lpcur->descriptor.Height/2 * ((lpcur->descriptor.Width+7)/8);
198 #if 0
199     dprintf_cursor(stddeb,"Before:\n");
200     for(i=0;i<2*size;i++)  {
201       dprintf_cursor(stddeb,"%02x ",((unsigned char *)lpl)[i]);
202       if ((i & 7) == 7) dprintf_cursor(stddeb,"\n");
203     }
204 #endif
205     cp1 = (char *)lpl;
206     cp2 = cp1+2*size;
207     for(i = 0; i < size; i++)  {
208       char tmp=*--cp2;
209       *cp2 = *cp1;
210       *cp1++ = tmp;
211     }
212 #if 0
213     dprintf_cursor(stddeb,"After:\n");
214     for(i=0;i<2*size;i++)  {
215       dprintf_cursor(stddeb,"%02x ",((unsigned char *)lpl)[i]);
216       if ((i & 7) == 7) dprintf_cursor(stddeb,"\n");
217     }
218 #endif
219     hCursor = CreateCursor(instance, lpcur->descriptor.curXHotspot, 
220         lpcur->descriptor.curYHotspot, lpcur->descriptor.Width,
221         lpcur->descriptor.Height/2,
222         (LPSTR)lpl, ((LPSTR)lpl)+size);
223
224     FreeResource( rsc_mem );
225     GlobalUnlock(hCursor);
226     ReleaseDC(0,hdc);
227     return hCursor;
228 }
229
230
231
232 /***********************************************************************
233  *           CreateCursorIconIndirect           (USER.408)
234  *
235  * Returns handle to either an icon or a cursor. Used by CreateCursor
236  * and CreateIcon in  Windoze, but will use same in this version.
237  */
238 HANDLE CreateCursorIconIndirect(HANDLE hInstance, LPCURSORICONINFO lpInfo,
239                                 LPSTR lpANDBits, /* bitmap data */
240                                 LPSTR lpXORBits /* masking data */)
241 {
242         return CreateIcon(hInstance,
243                 lpInfo->nWidth, lpInfo->nHeight,
244                 lpInfo->byPlanes, lpInfo->byBitsPix,
245                 lpANDBits, lpXORBits);
246 }
247
248
249 /**********************************************************************
250  *                      CreateCursor [USER.406]
251  */
252 HCURSOR CreateCursor(HANDLE instance, short nXhotspot, short nYhotspot, 
253         short nWidth, short nHeight, LPSTR lpANDbitPlane, LPSTR lpXORbitPlane)
254 {
255     HCURSOR     hCursor;
256     CURSORALLOC   *lpcur;
257     HDC         hdc;
258     int         bpllen = (nWidth + 7)/8 * nHeight;
259     char        *tmpbpl = malloc(bpllen);
260     int         i;
261   
262     XColor bkcolor,fgcolor;
263     Colormap cmap = XDefaultColormap(display,XDefaultScreen(display));
264     
265     dprintf_resource(stddeb,"CreateCursor: inst=%04x nXhotspot=%d  nYhotspot=%d nWidth=%d nHeight=%d\n",  
266        instance, nXhotspot, nYhotspot, nWidth, nHeight);
267     dprintf_resource(stddeb,"CreateCursor: inst=%04x lpANDbitPlane=%p lpXORbitPlane=%p\n",
268         instance, lpANDbitPlane, lpXORbitPlane);
269
270     if (!(hdc = GetDC(GetDesktopWindow()))) return 0;
271     hCursor = GlobalAlloc(GMEM_MOVEABLE, sizeof(CURSORALLOC) + 1024L); 
272     if (hCursor == (HCURSOR)NULL) {
273         ReleaseDC(GetDesktopWindow(), hdc); 
274         return 0;
275         }
276     dprintf_cursor(stddeb,"CreateCursor Alloc hCursor=%X\n", hCursor);
277     lpcur = (CURSORALLOC *)GlobalLock(hCursor);
278     memset(lpcur, 0, sizeof(CURSORALLOC));
279     lpcur->descriptor.curXHotspot = nXhotspot;
280     lpcur->descriptor.curYHotspot = nYhotspot;
281     for(i=0; i<bpllen; i++) tmpbpl[i] = ~lpANDbitPlane[i];
282     lpcur->pixmask = XCreatePixmapFromBitmapData(
283         display, DefaultRootWindow(display), 
284         tmpbpl, nWidth, nHeight, 1, 0, 1);
285     for(i=0; i<bpllen; i++) tmpbpl[i] ^= lpXORbitPlane[i];
286     lpcur->pixshape = XCreatePixmapFromBitmapData(
287         display, DefaultRootWindow(display),
288         tmpbpl, nWidth, nHeight, 1, 0, 1);
289     XParseColor(display,cmap,"#000000",&fgcolor);
290     XParseColor(display,cmap,"#ffffff",&bkcolor);
291     lpcur->xcursor = XCreatePixmapCursor(display,
292         lpcur->pixshape, lpcur->pixmask, 
293         &fgcolor, &bkcolor, lpcur->descriptor.curXHotspot, 
294         lpcur->descriptor.curYHotspot);
295     free(tmpbpl);
296     XFreePixmap(display, lpcur->pixshape);
297     XFreePixmap(display, lpcur->pixmask);
298     ReleaseDC(GetDesktopWindow(), hdc); 
299     GlobalUnlock(hCursor);
300     return hCursor;
301 }
302
303
304
305 /**********************************************************************
306  *                      DestroyCursor [USER.458]
307  */
308 BOOL DestroyCursor(HCURSOR hCursor)
309 {
310     int i;
311     CURSORALLOC *lpcur;
312     
313     if (hCursor == 0) return FALSE;
314     for (i = 0; i < NB_SYS_CURSORS; i++) {
315         if (system_cursor[i].cursor == hCursor) return TRUE;
316     }
317     lpcur = (CURSORALLOC *)GlobalLock(hCursor);
318     if (lpcur->hBitmap != (HBITMAP)NULL) DeleteObject(lpcur->hBitmap);
319     GlobalUnlock(hCursor);
320     GlobalFree(hCursor);
321     return TRUE;
322 }
323
324
325 /**********************************************************************
326  *         CURSOR_SetCursor
327  *
328  * Internal helper function for SetCursor() and ShowCursor().
329  */
330 static void CURSOR_SetCursor( HCURSOR hCursor )
331 {
332     CURSORALLOC *lpcur;
333
334     if (!(lpcur = (CURSORALLOC *)GlobalLock(hCursor))) return;
335     if (rootWindow != DefaultRootWindow(display))
336     {
337         XDefineCursor( display, rootWindow, lpcur->xcursor );
338     }
339     else
340     {
341         HWND hwnd = GetWindow( GetDesktopWindow(), GW_CHILD );
342         while(hwnd)
343         {
344             Window win = WIN_GetXWindow( hwnd );
345             if (win) XDefineCursor( display, win, lpcur->xcursor );
346             hwnd = GetWindow( hwnd, GW_HWNDNEXT );
347         }
348     }
349     GlobalUnlock( hCursor );
350 }
351
352 /**********************************************************************
353  *                      SetCursor [USER.69]
354  */
355 HCURSOR SetCursor(HCURSOR hCursor)
356 {
357     HCURSOR hOldCursor;
358
359     dprintf_cursor(stddeb,"SetCursor / hCursor=%04X !\n", hCursor);
360     hOldCursor = hActiveCursor;
361     hActiveCursor = hCursor;
362     if ((hCursor != hOldCursor) || (ShowCursCount < 0))
363     {
364         CURSOR_SetCursor( hCursor );
365     }
366     ShowCursCount = 0;
367     return hOldCursor;
368 }
369
370
371 /**********************************************************************
372  *                      GetCursor [USER.247]
373  */
374 HCURSOR GetCursor(void)
375 {
376     return hActiveCursor;
377 }
378
379
380 /**********************************************************************
381  *                        SetCursorPos [USER.70]
382  */
383 void SetCursorPos(short x, short y)
384 {
385     dprintf_cursor(stddeb,"SetCursorPos // x=%d y=%d\n", x, y);
386     XWarpPointer( display, None, rootWindow, 0, 0, 0, 0, x, y );
387 }
388
389
390 /**********************************************************************
391  *                        GetCursorPos [USER.17]
392  */
393 void GetCursorPos(LPPOINT lpRetPoint)
394 {
395     Window      root, child;
396     int         rootX, rootY;
397     int         childX, childY;
398     unsigned int mousebut;
399
400     if (!lpRetPoint) return;
401     if (!XQueryPointer( display, rootWindow, &root, &child,
402                         &rootX, &rootY, &childX, &childY, &mousebut ))
403         lpRetPoint->x = lpRetPoint->y = 0;
404     else
405     {
406         lpRetPoint->x = rootX + desktopX;
407         lpRetPoint->y = rootY + desktopY;
408     }
409     dprintf_cursor(stddeb,
410                 "GetCursorPos // x=%d y=%d\n", lpRetPoint->x, lpRetPoint->y);
411 }
412
413
414 /**********************************************************************
415  *                      ShowCursor [USER.71]
416  */
417 int ShowCursor(BOOL bShow)
418 {
419     dprintf_cursor(stddeb, "ShowCursor(%d), count=%d\n", bShow, ShowCursCount);
420
421     if (bShow)
422     {
423         if (++ShowCursCount == 0)  /* Time to show it */
424             CURSOR_SetCursor( hActiveCursor );
425     }
426     else  /* Hide it */
427     {
428         if (--ShowCursCount == -1)  /* Time to hide it */
429         {
430             if (!hEmptyCursor)
431                 hEmptyCursor = CreateCursor( 0, 1, 1, 1, 1,
432                                              "\xFF\xFF", "\xFF\xFF" );
433             CURSOR_SetCursor( hEmptyCursor );
434         }
435     }
436     return 0;
437 }
438
439
440 /**********************************************************************
441  *                        ClipCursor [USER.16]
442  */
443 void ClipCursor(LPRECT lpNewClipRect)
444 {
445     if (!lpNewClipRect) SetRectEmpty( &ClipCursorRect );
446     else CopyRect( &ClipCursorRect, lpNewClipRect );
447 }
448
449
450 /**********************************************************************
451  *                        GetClipCursor [USER.309]
452  */
453 void GetClipCursor(LPRECT lpRetClipRect)
454 {
455     if (lpRetClipRect != NULL)
456         CopyRect(lpRetClipRect, &ClipCursorRect);
457 }