gdi32: Printer drivers don't use the character extra spacing if lpdx is supplied.
[wine] / dlls / winemac.drv / mouse.c
1 /*
2  * MACDRV mouse driver
3  *
4  * Copyright 1998 Ulrich Weigand
5  * Copyright 2007 Henri Verbeet
6  * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24
25 #include "macdrv.h"
26 #define OEMRESOURCE
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "wine/server.h"
30 #include "wine/unicode.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(cursor);
33
34
35 static CRITICAL_SECTION cursor_cache_section;
36 static CRITICAL_SECTION_DEBUG critsect_debug =
37 {
38     0, 0, &cursor_cache_section,
39     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
40       0, 0, { (DWORD_PTR)(__FILE__ ": cursor_cache_section") }
41 };
42 static CRITICAL_SECTION cursor_cache_section = { &critsect_debug, -1, 0, 0, 0, 0 };
43
44 static CFMutableDictionaryRef cursor_cache;
45
46
47 struct system_cursors
48 {
49     WORD id;
50     CFStringRef name;
51 };
52
53 static const struct system_cursors user32_cursors[] =
54 {
55     { OCR_NORMAL,      CFSTR("arrowCursor") },
56     { OCR_IBEAM,       CFSTR("IBeamCursor") },
57     { OCR_CROSS,       CFSTR("crosshairCursor") },
58     { OCR_SIZEWE,      CFSTR("resizeLeftRightCursor") },
59     { OCR_SIZENS,      CFSTR("resizeUpDownCursor") },
60     { OCR_NO,          CFSTR("operationNotAllowedCursor") },
61     { OCR_HAND,        CFSTR("pointingHandCursor") },
62     { 0 }
63 };
64
65 static const struct system_cursors comctl32_cursors[] =
66 {
67     { 102, CFSTR("closedHandCursor") },
68     { 104, CFSTR("dragCopyCursor") },
69     { 105, CFSTR("arrowCursor") },
70     { 106, CFSTR("resizeLeftRightCursor") },
71     { 107, CFSTR("resizeLeftRightCursor") },
72     { 108, CFSTR("pointingHandCursor") },
73     { 135, CFSTR("resizeUpDownCursor") },
74     { 0 }
75 };
76
77 static const struct system_cursors ole32_cursors[] =
78 {
79     { 1, CFSTR("operationNotAllowedCursor") },
80     { 2, CFSTR("closedHandCursor") },
81     { 3, CFSTR("dragCopyCursor") },
82     { 4, CFSTR("dragLinkCursor") },
83     { 0 }
84 };
85
86 static const struct system_cursors riched20_cursors[] =
87 {
88     { 105, CFSTR("pointingHandCursor") },
89     { 109, CFSTR("dragCopyCursor") },
90     { 110, CFSTR("closedHandCursor") },
91     { 111, CFSTR("operationNotAllowedCursor") },
92     { 0 }
93 };
94
95 static const struct
96 {
97     const struct system_cursors *cursors;
98     WCHAR name[16];
99 } module_cursors[] =
100 {
101     { user32_cursors, {'u','s','e','r','3','2','.','d','l','l',0} },
102     { comctl32_cursors, {'c','o','m','c','t','l','3','2','.','d','l','l',0} },
103     { ole32_cursors, {'o','l','e','3','2','.','d','l','l',0} },
104     { riched20_cursors, {'r','i','c','h','e','d','2','0','.','d','l','l',0} }
105 };
106
107 /* The names of NSCursor class methods which return cursor objects. */
108 static const CFStringRef cocoa_cursor_names[] =
109 {
110     CFSTR("arrowCursor"),
111     CFSTR("closedHandCursor"),
112     CFSTR("contextualMenuCursor"),
113     CFSTR("crosshairCursor"),
114     CFSTR("disappearingItemCursor"),
115     CFSTR("dragCopyCursor"),
116     CFSTR("dragLinkCursor"),
117     CFSTR("IBeamCursor"),
118     CFSTR("IBeamCursorForVerticalLayout"),
119     CFSTR("openHandCursor"),
120     CFSTR("operationNotAllowedCursor"),
121     CFSTR("pointingHandCursor"),
122     CFSTR("resizeDownCursor"),
123     CFSTR("resizeLeftCursor"),
124     CFSTR("resizeLeftRightCursor"),
125     CFSTR("resizeRightCursor"),
126     CFSTR("resizeUpCursor"),
127     CFSTR("resizeUpDownCursor"),
128 };
129
130
131 /***********************************************************************
132  *              send_mouse_input
133  *
134  * Update the various window states on a mouse event.
135  */
136 static void send_mouse_input(HWND hwnd, UINT flags, int x, int y,
137                              DWORD mouse_data, unsigned long time)
138 {
139     INPUT input;
140     HWND top_level_hwnd;
141
142     top_level_hwnd = GetAncestor(hwnd, GA_ROOT);
143
144     if ((flags & MOUSEEVENTF_MOVE) && (flags & MOUSEEVENTF_ABSOLUTE))
145     {
146         RECT rect;
147
148         /* update the wine server Z-order */
149         SetRect(&rect, x, y, x + 1, y + 1);
150         MapWindowPoints(0, top_level_hwnd, (POINT *)&rect, 2);
151
152         SERVER_START_REQ(update_window_zorder)
153         {
154             req->window      = wine_server_user_handle(top_level_hwnd);
155             req->rect.left   = rect.left;
156             req->rect.top    = rect.top;
157             req->rect.right  = rect.right;
158             req->rect.bottom = rect.bottom;
159             wine_server_call(req);
160         }
161         SERVER_END_REQ;
162     }
163
164     input.type              = INPUT_MOUSE;
165     input.mi.dx             = x;
166     input.mi.dy             = y;
167     input.mi.mouseData      = mouse_data;
168     input.mi.dwFlags        = flags;
169     input.mi.time           = time;
170     input.mi.dwExtraInfo    = 0;
171
172     __wine_send_input(top_level_hwnd, &input);
173 }
174
175
176 /***********************************************************************
177  *              copy_system_cursor_name
178  */
179 CFStringRef copy_system_cursor_name(ICONINFOEXW *info)
180 {
181     static const WCHAR idW[] = {'%','h','u',0};
182     const struct system_cursors *cursors;
183     unsigned int i;
184     CFStringRef cursor_name = NULL;
185     HMODULE module;
186     HKEY key;
187     WCHAR *p, name[MAX_PATH * 2];
188
189     TRACE("info->szModName %s info->szResName %s info->wResID %hu\n", debugstr_w(info->szModName),
190           debugstr_w(info->szResName), info->wResID);
191
192     if (!info->szModName[0]) return NULL;
193
194     p = strrchrW(info->szModName, '\\');
195     strcpyW(name, p ? p + 1 : info->szModName);
196     p = name + strlenW(name);
197     *p++ = ',';
198     if (info->szResName[0]) strcpyW(p, info->szResName);
199     else sprintfW(p, idW, info->wResID);
200
201     /* @@ Wine registry key: HKCU\Software\Wine\Mac Driver\Cursors */
202     if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Mac Driver\\Cursors", &key))
203     {
204         WCHAR value[64];
205         DWORD size, ret;
206
207         value[0] = 0;
208         size = sizeof(value) / sizeof(WCHAR);
209         ret = RegQueryValueExW(key, name, NULL, NULL, (BYTE *)value, &size);
210         RegCloseKey(key);
211         if (!ret)
212         {
213             if (!value[0])
214             {
215                 TRACE("registry forces standard cursor for %s\n", debugstr_w(name));
216                 return NULL; /* force standard cursor */
217             }
218
219             cursor_name = CFStringCreateWithCharacters(NULL, value, strlenW(value));
220             if (!cursor_name)
221             {
222                 WARN("CFStringCreateWithCharacters failed for %s\n", debugstr_w(value));
223                 return NULL;
224             }
225
226             /* Make sure it's one of the appropriate NSCursor class methods. */
227             for (i = 0; i < sizeof(cocoa_cursor_names) / sizeof(cocoa_cursor_names[0]); i++)
228                 if (CFEqual(cursor_name, cocoa_cursor_names[i]))
229                     goto done;
230
231             WARN("%s mapped to invalid Cocoa cursor name %s\n", debugstr_w(name), debugstr_w(value));
232             CFRelease(cursor_name);
233             return NULL;
234         }
235     }
236
237     if (info->szResName[0]) goto done;  /* only integer resources are supported here */
238     if (!(module = GetModuleHandleW(info->szModName))) goto done;
239
240     for (i = 0; i < sizeof(module_cursors)/sizeof(module_cursors[0]); i++)
241         if (GetModuleHandleW(module_cursors[i].name) == module) break;
242     if (i == sizeof(module_cursors)/sizeof(module_cursors[0])) goto done;
243
244     cursors = module_cursors[i].cursors;
245     for (i = 0; cursors[i].id; i++)
246         if (cursors[i].id == info->wResID)
247         {
248             cursor_name = CFRetain(cursors[i].name);
249             break;
250         }
251
252 done:
253     if (cursor_name)
254         TRACE("%s -> %s\n", debugstr_w(name), debugstr_cf(cursor_name));
255     else
256         WARN("no system cursor found for %s\n", debugstr_w(name));
257     return cursor_name;
258 }
259
260 /***********************************************************************
261  *              create_monochrome_cursor
262  */
263 CFArrayRef create_monochrome_cursor(HDC hdc, const ICONINFOEXW *icon, int width, int height)
264 {
265     char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
266     BITMAPINFO *info = (BITMAPINFO *)buffer;
267     unsigned int width_bytes = (width + 31) / 32 * 4;
268     unsigned long *and_bits = NULL, *xor_bits;
269     unsigned long *data_bits;
270     int count, i;
271     CGColorSpaceRef colorspace;
272     CFMutableDataRef data;
273     CGDataProviderRef provider;
274     CGImageRef cgimage, cgmask, cgmasked;
275     CGPoint hot_spot;
276     CFDictionaryRef hot_spot_dict;
277     const CFStringRef keys[] = { CFSTR("image"), CFSTR("hotSpot") };
278     CFTypeRef values[sizeof(keys) / sizeof(keys[0])];
279     CFDictionaryRef frame;
280     CFArrayRef frames;
281
282     TRACE("hdc %p icon->hbmMask %p icon->xHotspot %d icon->yHotspot %d width %d height %d\n",
283           hdc, icon->hbmMask, icon->xHotspot, icon->yHotspot, width, height);
284
285     info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
286     info->bmiHeader.biWidth = width;
287     info->bmiHeader.biHeight = -height * 2;
288     info->bmiHeader.biPlanes = 1;
289     info->bmiHeader.biBitCount = 1;
290     info->bmiHeader.biCompression = BI_RGB;
291     info->bmiHeader.biSizeImage = width_bytes * height * 2;
292     info->bmiHeader.biXPelsPerMeter = 0;
293     info->bmiHeader.biYPelsPerMeter = 0;
294     info->bmiHeader.biClrUsed = 0;
295     info->bmiHeader.biClrImportant = 0;
296
297     and_bits = HeapAlloc(GetProcessHeap(), 0, info->bmiHeader.biSizeImage);
298     if (!and_bits)
299     {
300         WARN("failed to allocate and_bits\n");
301         return NULL;
302     }
303     xor_bits = (unsigned long*)((char*)and_bits + info->bmiHeader.biSizeImage / 2);
304
305     if (!GetDIBits(hdc, icon->hbmMask, 0, height * 2, and_bits, info, DIB_RGB_COLORS))
306     {
307         WARN("GetDIBits failed\n");
308         HeapFree(GetProcessHeap(), 0, and_bits);
309         return NULL;
310     }
311
312     /* On Windows, the pixels of a monochrome cursor can have four effects:
313        draw black, draw white, leave unchanged (transparent), or invert.  The Mac
314        only supports the first three.  It can't do pixels which invert the
315        background.  Since the background is usually white, I am arbitrarily
316        mapping "invert" to "draw black".  This entails bitwise math between the
317        cursor's AND mask and XOR mask:
318
319             AND | XOR | Windows cursor pixel
320             --------------------------------
321              0  |  0  | black
322              0  |  1  | white
323              1  |  0  | transparent
324              1  |  1  | invert
325
326             AND | XOR | Mac image
327             ---------------------
328              0  |  0  | black (0)
329              0  |  1  | white (1)
330              1  |  0  | don't care
331              1  |  1  | black (0)
332
333             AND | XOR | Mac mask
334             ---------------------------
335              0  |  0  | paint (0)
336              0  |  1  | paint (0)
337              1  |  0  | don't paint (1)
338              1  |  1  | paint (0)
339
340        So, Mac image = AND ^ XOR and Mac mask = AND & ~XOR.
341       */
342     /* Create data for Mac image. */
343     data = CFDataCreateMutable(NULL, info->bmiHeader.biSizeImage / 2);
344     if (!data)
345     {
346         WARN("failed to create data\n");
347         HeapFree(GetProcessHeap(), 0, and_bits);
348         return NULL;
349     }
350
351     /* image data = AND mask */
352     CFDataAppendBytes(data, (UInt8*)and_bits, info->bmiHeader.biSizeImage / 2);
353     /* image data ^= XOR mask */
354     data_bits = (unsigned long*)CFDataGetMutableBytePtr(data);
355     count = (info->bmiHeader.biSizeImage / 2) / sizeof(*data_bits);
356     for (i = 0; i < count; i++)
357         data_bits[i] ^= xor_bits[i];
358
359     colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
360     if (!colorspace)
361     {
362         WARN("failed to create colorspace\n");
363         CFRelease(data);
364         HeapFree(GetProcessHeap(), 0, and_bits);
365         return NULL;
366     }
367
368     provider = CGDataProviderCreateWithCFData(data);
369     CFRelease(data);
370     if (!provider)
371     {
372         WARN("failed to create data provider\n");
373         CGColorSpaceRelease(colorspace);
374         HeapFree(GetProcessHeap(), 0, and_bits);
375         return NULL;
376     }
377
378     cgimage = CGImageCreate(width, height, 1, 1, width_bytes, colorspace,
379                             kCGImageAlphaNone | kCGBitmapByteOrderDefault,
380                             provider, NULL, FALSE, kCGRenderingIntentDefault);
381     CGDataProviderRelease(provider);
382     CGColorSpaceRelease(colorspace);
383     if (!cgimage)
384     {
385         WARN("failed to create image\n");
386         HeapFree(GetProcessHeap(), 0, and_bits);
387         return NULL;
388     }
389
390     /* Create data for mask. */
391     data = CFDataCreateMutable(NULL, info->bmiHeader.biSizeImage / 2);
392     if (!data)
393     {
394         WARN("failed to create data\n");
395         CGImageRelease(cgimage);
396         HeapFree(GetProcessHeap(), 0, and_bits);
397         return NULL;
398     }
399
400     /* mask data = AND mask */
401     CFDataAppendBytes(data, (UInt8*)and_bits, info->bmiHeader.biSizeImage / 2);
402     /* mask data &= ~XOR mask */
403     data_bits = (unsigned long*)CFDataGetMutableBytePtr(data);
404     for (i = 0; i < count; i++)
405         data_bits[i] &= ~xor_bits[i];
406     HeapFree(GetProcessHeap(), 0, and_bits);
407
408     provider = CGDataProviderCreateWithCFData(data);
409     CFRelease(data);
410     if (!provider)
411     {
412         WARN("failed to create data provider\n");
413         CGImageRelease(cgimage);
414         return NULL;
415     }
416
417     cgmask = CGImageMaskCreate(width, height, 1, 1, width_bytes, provider, NULL, FALSE);
418     CGDataProviderRelease(provider);
419     if (!cgmask)
420     {
421         WARN("failed to create mask image\n");
422         CGImageRelease(cgimage);
423         return NULL;
424     }
425
426     cgmasked = CGImageCreateWithMask(cgimage, cgmask);
427     CGImageRelease(cgimage);
428     CGImageRelease(cgmask);
429     if (!cgmasked)
430     {
431         WARN("failed to create masked image\n");
432         return NULL;
433     }
434
435     hot_spot = CGPointMake(icon->xHotspot, icon->yHotspot);
436     hot_spot_dict = CGPointCreateDictionaryRepresentation(hot_spot);
437     if (!hot_spot_dict)
438     {
439         WARN("failed to create hot spot dictionary\n");
440         CGImageRelease(cgmasked);
441         return NULL;
442     }
443
444     values[0] = cgmasked;
445     values[1] = hot_spot_dict;
446     frame = CFDictionaryCreate(NULL, (const void**)keys, values, sizeof(keys) / sizeof(keys[0]),
447                                &kCFCopyStringDictionaryKeyCallBacks,
448                                &kCFTypeDictionaryValueCallBacks);
449     CFRelease(hot_spot_dict);
450     CGImageRelease(cgmasked);
451     if (!frame)
452     {
453         WARN("failed to create frame dictionary\n");
454         return NULL;
455     }
456
457     frames = CFArrayCreate(NULL, (const void**)&frame, 1, &kCFTypeArrayCallBacks);
458     CFRelease(frame);
459     if (!frames)
460     {
461         WARN("failed to create frames array\n");
462         return NULL;
463     }
464
465     return frames;
466 }
467
468
469 /***********************************************************************
470  *              create_cursor_frame
471  *
472  * Create a frame dictionary for a cursor from a Windows icon.
473  * Keys:
474  *      "image"     a CGImage for the frame
475  *      "duration"  a CFNumber for the frame duration in seconds
476  *      "hotSpot"   a CFDictionary encoding a CGPoint for the hot spot
477  */
478 static CFDictionaryRef create_cursor_frame(HDC hdc, const ICONINFOEXW *iinfo, HANDLE icon,
479                                            HBITMAP hbmColor, unsigned char *color_bits, int color_size,
480                                            HBITMAP hbmMask, unsigned char *mask_bits, int mask_size,
481                                            int width, int height, int istep)
482 {
483     DWORD delay_jiffies, num_steps;
484     CFMutableDictionaryRef frame;
485     CGPoint hot_spot;
486     CFDictionaryRef hot_spot_dict;
487     double duration;
488     CFNumberRef duration_number;
489     CGImageRef cgimage;
490
491     TRACE("hdc %p iinfo->xHotspot %d iinfo->yHotspot %d icon %p hbmColor %p color_bits %p color_size %d"
492           " hbmMask %p mask_bits %p mask_size %d width %d height %d istep %d\n",
493           hdc, iinfo->xHotspot, iinfo->yHotspot, icon, hbmColor, color_bits, color_size,
494           hbmMask, mask_bits, mask_size, width, height, istep);
495
496     frame = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks,
497                                       &kCFTypeDictionaryValueCallBacks);
498     if (!frame)
499     {
500         WARN("failed to allocate dictionary for frame\n");
501         return NULL;
502     }
503
504     hot_spot = CGPointMake(iinfo->xHotspot, iinfo->yHotspot);
505     hot_spot_dict = CGPointCreateDictionaryRepresentation(hot_spot);
506     if (!hot_spot_dict)
507     {
508         WARN("failed to create hot spot dictionary\n");
509         CFRelease(frame);
510         return NULL;
511     }
512     CFDictionarySetValue(frame, CFSTR("hotSpot"), hot_spot_dict);
513     CFRelease(hot_spot_dict);
514
515     if (GetCursorFrameInfo(icon, 0x0 /* unknown parameter */, istep, &delay_jiffies, &num_steps) != 0)
516         duration = delay_jiffies / 60.0; /* convert jiffies (1/60s) to seconds */
517     else
518     {
519         WARN("Failed to retrieve animated cursor frame-rate for frame %d.\n", istep);
520         duration = 0.1; /* fallback delay, 100 ms */
521     }
522     duration_number = CFNumberCreate(NULL, kCFNumberDoubleType, &duration);
523     if (!duration_number)
524     {
525         WARN("failed to create duration number\n");
526         CFRelease(frame);
527         return NULL;
528     }
529     CFDictionarySetValue(frame, CFSTR("duration"), duration_number);
530     CFRelease(duration_number);
531
532     cgimage = create_cgimage_from_icon_bitmaps(hdc, icon, hbmColor, color_bits, color_size,
533                                                hbmMask, mask_bits, mask_size, width, height, istep);
534     if (!cgimage)
535     {
536         CFRelease(frame);
537         return NULL;
538     }
539
540     CFDictionarySetValue(frame, CFSTR("image"), cgimage);
541     CGImageRelease(cgimage);
542
543     return frame;
544 }
545
546
547 /***********************************************************************
548  *              create_color_cursor
549  *
550  * Create an array of color cursor frames from a Windows cursor.  Each
551  * frame is represented in the array by a dictionary.
552  * Frame dictionary keys:
553  *      "image"     a CGImage for the frame
554  *      "duration"  a CFNumber for the frame duration in seconds
555  *      "hotSpot"   a CFDictionary encoding a CGPoint for the hot spot
556  */
557 static CFArrayRef create_color_cursor(HDC hdc, const ICONINFOEXW *iinfo, HANDLE icon, int width, int height)
558 {
559     unsigned char *color_bits, *mask_bits;
560     HBITMAP hbmColor = 0, hbmMask = 0;
561     DWORD nFrames, delay_jiffies, i;
562     int color_size, mask_size;
563     BITMAPINFO *info = NULL;
564     CFMutableArrayRef frames;
565
566     TRACE("hdc %p iinfo %p icon %p width %d height %d\n", hdc, iinfo, icon, width, height);
567
568     /* Retrieve the number of frames to render */
569     if (!GetCursorFrameInfo(icon, 0x0 /* unknown parameter */, 0, &delay_jiffies, &nFrames))
570     {
571         WARN("GetCursorFrameInfo failed\n");
572         return NULL;
573     }
574     if (!(frames = CFArrayCreateMutable(NULL, nFrames, &kCFTypeArrayCallBacks)))
575     {
576         WARN("failed to allocate frames array\n");
577         return NULL;
578     }
579
580     /* Allocate all of the resources necessary to obtain a cursor frame */
581     if (!(info = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(BITMAPINFO, bmiColors[256])))) goto cleanup;
582     info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
583     info->bmiHeader.biWidth = width;
584     info->bmiHeader.biHeight = -height;
585     info->bmiHeader.biPlanes = 1;
586     info->bmiHeader.biCompression = BI_RGB;
587     info->bmiHeader.biXPelsPerMeter = 0;
588     info->bmiHeader.biYPelsPerMeter = 0;
589     info->bmiHeader.biClrUsed = 0;
590     info->bmiHeader.biClrImportant = 0;
591     info->bmiHeader.biBitCount = 32;
592     color_size = width * height * 4;
593     info->bmiHeader.biSizeImage = color_size;
594     hbmColor = CreateDIBSection(hdc, info, DIB_RGB_COLORS, (VOID **) &color_bits, NULL, 0);
595     if (!hbmColor)
596     {
597         WARN("failed to create DIB section for cursor color data\n");
598         goto cleanup;
599     }
600     info->bmiHeader.biBitCount = 1;
601     info->bmiColors[0].rgbRed      = 0;
602     info->bmiColors[0].rgbGreen    = 0;
603     info->bmiColors[0].rgbBlue     = 0;
604     info->bmiColors[0].rgbReserved = 0;
605     info->bmiColors[1].rgbRed      = 0xff;
606     info->bmiColors[1].rgbGreen    = 0xff;
607     info->bmiColors[1].rgbBlue     = 0xff;
608     info->bmiColors[1].rgbReserved = 0;
609
610     mask_size = ((width + 31) / 32 * 4) * height; /* width_bytes * height */
611     info->bmiHeader.biSizeImage = mask_size;
612     hbmMask = CreateDIBSection(hdc, info, DIB_RGB_COLORS, (VOID **) &mask_bits, NULL, 0);
613     if (!hbmMask)
614     {
615         WARN("failed to create DIB section for cursor mask data\n");
616         goto cleanup;
617     }
618
619     /* Create a CFDictionary for each frame of the cursor */
620     for (i = 0; i < nFrames; i++)
621     {
622         CFDictionaryRef frame = create_cursor_frame(hdc, iinfo, icon,
623                                                     hbmColor, color_bits, color_size,
624                                                     hbmMask, mask_bits, mask_size,
625                                                     width, height, i);
626         if (!frame) goto cleanup;
627         CFArrayAppendValue(frames, frame);
628         CFRelease(frame);
629     }
630
631 cleanup:
632     if (CFArrayGetCount(frames) < nFrames)
633     {
634         CFRelease(frames);
635         frames = NULL;
636     }
637     else
638         TRACE("returning cursor with %d frames\n", nFrames);
639     /* Cleanup all of the resources used to obtain the frame data */
640     if (hbmColor) DeleteObject(hbmColor);
641     if (hbmMask) DeleteObject(hbmMask);
642     HeapFree(GetProcessHeap(), 0, info);
643     return frames;
644 }
645
646
647 /***********************************************************************
648  *              DestroyCursorIcon (MACDRV.@)
649  */
650 void CDECL macdrv_DestroyCursorIcon(HCURSOR cursor)
651 {
652     TRACE("cursor %p\n", cursor);
653
654     EnterCriticalSection(&cursor_cache_section);
655     if (cursor_cache)
656         CFDictionaryRemoveValue(cursor_cache, cursor);
657     LeaveCriticalSection(&cursor_cache_section);
658 }
659
660
661 /***********************************************************************
662  *              ClipCursor (MACDRV.@)
663  *
664  * Set the cursor clipping rectangle.
665  */
666 BOOL CDECL macdrv_ClipCursor(LPCRECT clip)
667 {
668     CGRect rect;
669
670     TRACE("%s\n", wine_dbgstr_rect(clip));
671
672     if (clip)
673     {
674         rect = CGRectMake(clip->left, clip->top, max(1, clip->right - clip->left),
675                           max(1, clip->bottom - clip->top));
676     }
677     else
678         rect = CGRectInfinite;
679
680     /* FIXME: This needs to be done not just in this process but in all of the
681        ones for this WINEPREFIX.  Broadcast a message to do that. */
682
683     return macdrv_clip_cursor(rect);
684 }
685
686
687 /***********************************************************************
688  *              GetCursorPos (MACDRV.@)
689  */
690 BOOL CDECL macdrv_GetCursorPos(LPPOINT pos)
691 {
692     CGPoint pt;
693     BOOL ret;
694
695     ret = macdrv_get_cursor_position(&pt);
696     if (ret)
697     {
698         TRACE("pointer at (%g,%g) server pos %d,%d\n", pt.x, pt.y, pos->x, pos->y);
699         pos->x = pt.x;
700         pos->y = pt.y;
701     }
702     return ret;
703 }
704
705
706 /***********************************************************************
707  *              SetCursor (MACDRV.@)
708  */
709 void CDECL macdrv_SetCursor(HCURSOR cursor)
710 {
711     CFStringRef cursor_name = NULL;
712     CFArrayRef cursor_frames = NULL;
713
714     TRACE("%p\n", cursor);
715
716     if (cursor)
717     {
718         ICONINFOEXW info;
719
720         EnterCriticalSection(&cursor_cache_section);
721         if (cursor_cache)
722         {
723             CFTypeRef cached_cursor = CFDictionaryGetValue(cursor_cache, cursor);
724             if (cached_cursor)
725             {
726                 if (CFGetTypeID(cached_cursor) == CFStringGetTypeID())
727                     cursor_name = CFRetain(cached_cursor);
728                 else
729                     cursor_frames = CFRetain(cached_cursor);
730             }
731         }
732         LeaveCriticalSection(&cursor_cache_section);
733         if (cursor_name || cursor_frames)
734             goto done;
735
736         info.cbSize = sizeof(info);
737         if (!GetIconInfoExW(cursor, &info))
738         {
739             WARN("GetIconInfoExW failed\n");
740             return;
741         }
742
743         if ((cursor_name = copy_system_cursor_name(&info)))
744         {
745             DeleteObject(info.hbmColor);
746             DeleteObject(info.hbmMask);
747         }
748         else
749         {
750             BITMAP bm;
751             HDC hdc;
752
753             GetObjectW(info.hbmMask, sizeof(bm), &bm);
754             if (!info.hbmColor) bm.bmHeight = max(1, bm.bmHeight / 2);
755
756             /* make sure hotspot is valid */
757             if (info.xHotspot >= bm.bmWidth || info.yHotspot >= bm.bmHeight)
758             {
759                 info.xHotspot = bm.bmWidth / 2;
760                 info.yHotspot = bm.bmHeight / 2;
761             }
762
763             hdc = CreateCompatibleDC(0);
764
765             if (info.hbmColor)
766             {
767                 cursor_frames = create_color_cursor(hdc, &info, cursor, bm.bmWidth, bm.bmHeight);
768                 DeleteObject(info.hbmColor);
769             }
770             else
771                 cursor_frames = create_monochrome_cursor(hdc, &info, bm.bmWidth, bm.bmHeight);
772
773             DeleteObject(info.hbmMask);
774             DeleteDC(hdc);
775         }
776
777         if (cursor_name || cursor_frames)
778         {
779             EnterCriticalSection(&cursor_cache_section);
780             if (!cursor_cache)
781                 cursor_cache = CFDictionaryCreateMutable(NULL, 0, NULL,
782                                                          &kCFTypeDictionaryValueCallBacks);
783             CFDictionarySetValue(cursor_cache, cursor,
784                                  cursor_name ? (CFTypeRef)cursor_name : (CFTypeRef)cursor_frames);
785             LeaveCriticalSection(&cursor_cache_section);
786         }
787         else
788             cursor_name = CFRetain(CFSTR("arrowCursor"));
789     }
790
791 done:
792     TRACE("setting cursor with cursor_name %s cursor_frames %p\n", debugstr_cf(cursor_name), cursor_frames);
793     macdrv_set_cursor(cursor_name, cursor_frames);
794     if (cursor_name) CFRelease(cursor_name);
795     if (cursor_frames) CFRelease(cursor_frames);
796 }
797
798
799 /***********************************************************************
800  *              SetCursorPos (MACDRV.@)
801  */
802 BOOL CDECL macdrv_SetCursorPos(INT x, INT y)
803 {
804     BOOL ret = macdrv_set_cursor_position(CGPointMake(x, y));
805     if (ret)
806         TRACE("warped to %d,%d\n", x, y);
807     else
808         ERR("failed to warp to %d,%d\n", x, y);
809     return ret;
810 }
811
812
813 /***********************************************************************
814  *              macdrv_mouse_button
815  *
816  * Handler for MOUSE_BUTTON events.
817  */
818 void macdrv_mouse_button(HWND hwnd, const macdrv_event *event)
819 {
820     UINT flags = 0;
821     WORD data = 0;
822
823     TRACE("win %p button %d %s at (%d,%d) time %lu (%lu ticks ago)\n", hwnd, event->mouse_button.button,
824           (event->mouse_button.pressed ? "pressed" : "released"),
825           event->mouse_button.x, event->mouse_button.y,
826           event->mouse_button.time_ms, (GetTickCount() - event->mouse_button.time_ms));
827
828     if (event->mouse_button.pressed)
829     {
830         switch (event->mouse_button.button)
831         {
832         case 0: flags |= MOUSEEVENTF_LEFTDOWN; break;
833         case 1: flags |= MOUSEEVENTF_RIGHTDOWN; break;
834         case 2: flags |= MOUSEEVENTF_MIDDLEDOWN; break;
835         default:
836             flags |= MOUSEEVENTF_XDOWN;
837             data = 1 << (event->mouse_button.button - 3);
838             break;
839         }
840     }
841     else
842     {
843         switch (event->mouse_button.button)
844         {
845         case 0: flags |= MOUSEEVENTF_LEFTUP; break;
846         case 1: flags |= MOUSEEVENTF_RIGHTUP; break;
847         case 2: flags |= MOUSEEVENTF_MIDDLEUP; break;
848         default:
849             flags |= MOUSEEVENTF_XUP;
850             data = 1 << (event->mouse_button.button - 3);
851             break;
852         }
853     }
854
855     send_mouse_input(hwnd, flags | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
856                      event->mouse_button.x, event->mouse_button.y,
857                      data, event->mouse_button.time_ms);
858 }
859
860
861 /***********************************************************************
862  *              macdrv_mouse_moved
863  *
864  * Handler for MOUSE_MOVED and MOUSE_MOVED_ABSOLUTE events.
865  */
866 void macdrv_mouse_moved(HWND hwnd, const macdrv_event *event)
867 {
868     UINT flags = MOUSEEVENTF_MOVE;
869
870     TRACE("win %p/%p %s (%d,%d) time %lu (%lu ticks ago)\n", hwnd, event->window,
871           (event->type == MOUSE_MOVED) ? "relative" : "absolute",
872           event->mouse_moved.x, event->mouse_moved.y,
873           event->mouse_moved.time_ms, (GetTickCount() - event->mouse_moved.time_ms));
874
875     if (event->type == MOUSE_MOVED_ABSOLUTE)
876         flags |= MOUSEEVENTF_ABSOLUTE;
877
878     send_mouse_input(hwnd, flags, event->mouse_moved.x, event->mouse_moved.y,
879                      0, event->mouse_moved.time_ms);
880 }
881
882
883 /***********************************************************************
884  *              macdrv_mouse_scroll
885  *
886  * Handler for MOUSE_SCROLL events.
887  */
888 void macdrv_mouse_scroll(HWND hwnd, const macdrv_event *event)
889 {
890     TRACE("win %p/%p scroll (%d,%d) at (%d,%d) time %lu (%lu ticks ago)\n", hwnd,
891           event->window, event->mouse_scroll.x_scroll, event->mouse_scroll.y_scroll,
892           event->mouse_scroll.x, event->mouse_scroll.y,
893           event->mouse_scroll.time_ms, (GetTickCount() - event->mouse_scroll.time_ms));
894
895     send_mouse_input(hwnd, MOUSEEVENTF_WHEEL | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
896                      event->mouse_scroll.x, event->mouse_scroll.y,
897                      event->mouse_scroll.y_scroll, event->mouse_scroll.time_ms);
898     send_mouse_input(hwnd, MOUSEEVENTF_HWHEEL | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
899                      event->mouse_scroll.x, event->mouse_scroll.y,
900                      event->mouse_scroll.x_scroll, event->mouse_scroll.time_ms);
901 }