4 * Copyright 1998 Ulrich Weigand
5 * Copyright 2007 Henri Verbeet
6 * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
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.
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.
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
29 #include "wine/server.h"
30 #include "wine/unicode.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(cursor);
35 static CRITICAL_SECTION cursor_cache_section;
36 static CRITICAL_SECTION_DEBUG critsect_debug =
38 0, 0, &cursor_cache_section,
39 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
40 0, 0, { (DWORD_PTR)(__FILE__ ": cursor_cache_section") }
42 static CRITICAL_SECTION cursor_cache_section = { &critsect_debug, -1, 0, 0, 0, 0 };
44 static CFMutableDictionaryRef cursor_cache;
53 static const struct system_cursors user32_cursors[] =
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") },
65 static const struct system_cursors comctl32_cursors[] =
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") },
77 static const struct system_cursors ole32_cursors[] =
79 { 1, CFSTR("operationNotAllowedCursor") },
80 { 2, CFSTR("closedHandCursor") },
81 { 3, CFSTR("dragCopyCursor") },
82 { 4, CFSTR("dragLinkCursor") },
86 static const struct system_cursors riched20_cursors[] =
88 { 105, CFSTR("pointingHandCursor") },
89 { 109, CFSTR("dragCopyCursor") },
90 { 110, CFSTR("closedHandCursor") },
91 { 111, CFSTR("operationNotAllowedCursor") },
97 const struct system_cursors *cursors;
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} }
107 /* The names of NSCursor class methods which return cursor objects. */
108 static const CFStringRef cocoa_cursor_names[] =
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"),
131 /***********************************************************************
134 * Update the various window states on a mouse event.
136 static void send_mouse_input(HWND hwnd, UINT flags, int x, int y,
137 DWORD mouse_data, unsigned long time)
142 top_level_hwnd = GetAncestor(hwnd, GA_ROOT);
144 if ((flags & MOUSEEVENTF_MOVE) && (flags & MOUSEEVENTF_ABSOLUTE))
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);
152 SERVER_START_REQ(update_window_zorder)
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);
164 input.type = INPUT_MOUSE;
167 input.mi.mouseData = mouse_data;
168 input.mi.dwFlags = flags;
169 input.mi.time = time;
170 input.mi.dwExtraInfo = 0;
172 __wine_send_input(top_level_hwnd, &input);
176 /***********************************************************************
177 * copy_system_cursor_name
179 CFStringRef copy_system_cursor_name(ICONINFOEXW *info)
181 static const WCHAR idW[] = {'%','h','u',0};
182 const struct system_cursors *cursors;
184 CFStringRef cursor_name = NULL;
187 WCHAR *p, name[MAX_PATH * 2];
189 TRACE("info->szModName %s info->szResName %s info->wResID %hu\n", debugstr_w(info->szModName),
190 debugstr_w(info->szResName), info->wResID);
192 if (!info->szModName[0]) return NULL;
194 p = strrchrW(info->szModName, '\\');
195 strcpyW(name, p ? p + 1 : info->szModName);
196 p = name + strlenW(name);
198 if (info->szResName[0]) strcpyW(p, info->szResName);
199 else sprintfW(p, idW, info->wResID);
201 /* @@ Wine registry key: HKCU\Software\Wine\Mac Driver\Cursors */
202 if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Mac Driver\\Cursors", &key))
208 size = sizeof(value) / sizeof(WCHAR);
209 ret = RegQueryValueExW(key, name, NULL, NULL, (BYTE *)value, &size);
215 TRACE("registry forces standard cursor for %s\n", debugstr_w(name));
216 return NULL; /* force standard cursor */
219 cursor_name = CFStringCreateWithCharacters(NULL, value, strlenW(value));
222 WARN("CFStringCreateWithCharacters failed for %s\n", debugstr_w(value));
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]))
231 WARN("%s mapped to invalid Cocoa cursor name %s\n", debugstr_w(name), debugstr_w(value));
232 CFRelease(cursor_name);
237 if (info->szResName[0]) goto done; /* only integer resources are supported here */
238 if (!(module = GetModuleHandleW(info->szModName))) goto done;
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;
244 cursors = module_cursors[i].cursors;
245 for (i = 0; cursors[i].id; i++)
246 if (cursors[i].id == info->wResID)
248 cursor_name = CFRetain(cursors[i].name);
254 TRACE("%s -> %s\n", debugstr_w(name), debugstr_cf(cursor_name));
256 WARN("no system cursor found for %s\n", debugstr_w(name));
260 /***********************************************************************
261 * create_monochrome_cursor
263 CFArrayRef create_monochrome_cursor(HDC hdc, const ICONINFOEXW *icon, int width, int height)
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;
271 CGColorSpaceRef colorspace;
272 CFMutableDataRef data;
273 CGDataProviderRef provider;
274 CGImageRef cgimage, cgmask, cgmasked;
276 CFDictionaryRef hot_spot_dict;
277 const CFStringRef keys[] = { CFSTR("image"), CFSTR("hotSpot") };
278 CFTypeRef values[sizeof(keys) / sizeof(keys[0])];
279 CFDictionaryRef frame;
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);
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;
297 and_bits = HeapAlloc(GetProcessHeap(), 0, info->bmiHeader.biSizeImage);
300 WARN("failed to allocate and_bits\n");
303 xor_bits = (unsigned long*)((char*)and_bits + info->bmiHeader.biSizeImage / 2);
305 if (!GetDIBits(hdc, icon->hbmMask, 0, height * 2, and_bits, info, DIB_RGB_COLORS))
307 WARN("GetDIBits failed\n");
308 HeapFree(GetProcessHeap(), 0, and_bits);
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:
319 AND | XOR | Windows cursor pixel
320 --------------------------------
326 AND | XOR | Mac image
327 ---------------------
334 ---------------------------
337 1 | 0 | don't paint (1)
340 So, Mac image = AND ^ XOR and Mac mask = AND & ~XOR.
342 /* Create data for Mac image. */
343 data = CFDataCreateMutable(NULL, info->bmiHeader.biSizeImage / 2);
346 WARN("failed to create data\n");
347 HeapFree(GetProcessHeap(), 0, and_bits);
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];
359 colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
362 WARN("failed to create colorspace\n");
364 HeapFree(GetProcessHeap(), 0, and_bits);
368 provider = CGDataProviderCreateWithCFData(data);
372 WARN("failed to create data provider\n");
373 CGColorSpaceRelease(colorspace);
374 HeapFree(GetProcessHeap(), 0, and_bits);
378 cgimage = CGImageCreate(width, height, 1, 1, width_bytes, colorspace,
379 kCGImageAlphaNone | kCGBitmapByteOrderDefault,
380 provider, NULL, FALSE, kCGRenderingIntentDefault);
381 CGDataProviderRelease(provider);
382 CGColorSpaceRelease(colorspace);
385 WARN("failed to create image\n");
386 HeapFree(GetProcessHeap(), 0, and_bits);
390 /* Create data for mask. */
391 data = CFDataCreateMutable(NULL, info->bmiHeader.biSizeImage / 2);
394 WARN("failed to create data\n");
395 CGImageRelease(cgimage);
396 HeapFree(GetProcessHeap(), 0, and_bits);
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);
408 provider = CGDataProviderCreateWithCFData(data);
412 WARN("failed to create data provider\n");
413 CGImageRelease(cgimage);
417 cgmask = CGImageMaskCreate(width, height, 1, 1, width_bytes, provider, NULL, FALSE);
418 CGDataProviderRelease(provider);
421 WARN("failed to create mask image\n");
422 CGImageRelease(cgimage);
426 cgmasked = CGImageCreateWithMask(cgimage, cgmask);
427 CGImageRelease(cgimage);
428 CGImageRelease(cgmask);
431 WARN("failed to create masked image\n");
435 hot_spot = CGPointMake(icon->xHotspot, icon->yHotspot);
436 hot_spot_dict = CGPointCreateDictionaryRepresentation(hot_spot);
439 WARN("failed to create hot spot dictionary\n");
440 CGImageRelease(cgmasked);
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);
453 WARN("failed to create frame dictionary\n");
457 frames = CFArrayCreate(NULL, (const void**)&frame, 1, &kCFTypeArrayCallBacks);
461 WARN("failed to create frames array\n");
469 /***********************************************************************
470 * create_cgimage_from_icon
472 static CGImageRef create_cgimage_from_icon(HDC hdc, HANDLE icon, HBITMAP hbmColor,
473 unsigned char *color_bits, int color_size, HBITMAP hbmMask,
474 unsigned char *mask_bits, int mask_size, int width,
475 int height, int istep)
477 int i, has_alpha = FALSE;
479 CGBitmapInfo alpha_format;
480 CGColorSpaceRef colorspace;
482 CGDataProviderRef provider;
485 /* draw the cursor frame to a temporary buffer then create a CGImage from that */
486 memset(color_bits, 0x00, color_size);
487 SelectObject(hdc, hbmColor);
488 if (!DrawIconEx(hdc, 0, 0, icon, width, height, istep, NULL, DI_NORMAL))
490 WARN("Could not draw frame %d (walk past end of frames).\n", istep);
494 /* check if the cursor frame was drawn with an alpha channel */
495 for (i = 0, ptr = (DWORD*)color_bits; i < width * height; i++, ptr++)
496 if ((has_alpha = (*ptr & 0xff000000) != 0)) break;
499 alpha_format = kCGImageAlphaFirst;
501 alpha_format = kCGImageAlphaNoneSkipFirst;
503 colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
506 WARN("failed to create colorspace\n");
510 data = CFDataCreate(NULL, (UInt8*)color_bits, color_size);
513 WARN("failed to create data\n");
514 CGColorSpaceRelease(colorspace);
518 provider = CGDataProviderCreateWithCFData(data);
522 WARN("failed to create data provider\n");
523 CGColorSpaceRelease(colorspace);
527 cgimage = CGImageCreate(width, height, 8, 32, width * 4, colorspace,
528 alpha_format | kCGBitmapByteOrder32Little,
529 provider, NULL, FALSE, kCGRenderingIntentDefault);
530 CGDataProviderRelease(provider);
531 CGColorSpaceRelease(colorspace);
534 WARN("failed to create image\n");
538 /* if no alpha channel was drawn then generate it from the mask */
541 unsigned int width_bytes = (width + 31) / 32 * 4;
542 CGImageRef cgmask, temp;
544 /* draw the cursor mask to a temporary buffer */
545 memset(mask_bits, 0xFF, mask_size);
546 SelectObject(hdc, hbmMask);
547 if (!DrawIconEx(hdc, 0, 0, icon, width, height, istep, NULL, DI_MASK))
549 WARN("Failed to draw frame mask %d.\n", istep);
550 CGImageRelease(cgimage);
554 data = CFDataCreate(NULL, (UInt8*)mask_bits, mask_size);
557 WARN("failed to create data\n");
558 CGImageRelease(cgimage);
562 provider = CGDataProviderCreateWithCFData(data);
566 WARN("failed to create data provider\n");
567 CGImageRelease(cgimage);
571 cgmask = CGImageMaskCreate(width, height, 1, 1, width_bytes, provider, NULL, FALSE);
572 CGDataProviderRelease(provider);
575 WARN("failed to create mask\n");
576 CGImageRelease(cgimage);
580 temp = CGImageCreateWithMask(cgimage, cgmask);
581 CGImageRelease(cgmask);
582 CGImageRelease(cgimage);
585 WARN("failed to create masked image\n");
595 /***********************************************************************
596 * create_cursor_frame
598 * Create a frame dictionary for a cursor from a Windows icon.
600 * "image" a CGImage for the frame
601 * "duration" a CFNumber for the frame duration in seconds
602 * "hotSpot" a CFDictionary encoding a CGPoint for the hot spot
604 static CFDictionaryRef create_cursor_frame(HDC hdc, const ICONINFOEXW *iinfo, HANDLE icon,
605 HBITMAP hbmColor, unsigned char *color_bits, int color_size,
606 HBITMAP hbmMask, unsigned char *mask_bits, int mask_size,
607 int width, int height, int istep)
609 DWORD delay_jiffies, num_steps;
610 CFMutableDictionaryRef frame;
612 CFDictionaryRef hot_spot_dict;
614 CFNumberRef duration_number;
617 TRACE("hdc %p iinfo->xHotspot %d iinfo->yHotspot %d icon %p hbmColor %p color_bits %p color_size %d"
618 " hbmMask %p mask_bits %p mask_size %d width %d height %d istep %d\n",
619 hdc, iinfo->xHotspot, iinfo->yHotspot, icon, hbmColor, color_bits, color_size,
620 hbmMask, mask_bits, mask_size, width, height, istep);
622 frame = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks,
623 &kCFTypeDictionaryValueCallBacks);
626 WARN("failed to allocate dictionary for frame\n");
630 hot_spot = CGPointMake(iinfo->xHotspot, iinfo->yHotspot);
631 hot_spot_dict = CGPointCreateDictionaryRepresentation(hot_spot);
634 WARN("failed to create hot spot dictionary\n");
638 CFDictionarySetValue(frame, CFSTR("hotSpot"), hot_spot_dict);
639 CFRelease(hot_spot_dict);
641 if (GetCursorFrameInfo(icon, 0x0 /* unknown parameter */, istep, &delay_jiffies, &num_steps) != 0)
642 duration = delay_jiffies / 60.0; /* convert jiffies (1/60s) to seconds */
645 WARN("Failed to retrieve animated cursor frame-rate for frame %d.\n", istep);
646 duration = 0.1; /* fallback delay, 100 ms */
648 duration_number = CFNumberCreate(NULL, kCFNumberDoubleType, &duration);
649 if (!duration_number)
651 WARN("failed to create duration number\n");
655 CFDictionarySetValue(frame, CFSTR("duration"), duration_number);
656 CFRelease(duration_number);
658 cgimage = create_cgimage_from_icon(hdc, icon, hbmColor, color_bits, color_size,
659 hbmMask, mask_bits, mask_size, width, height, istep);
666 CFDictionarySetValue(frame, CFSTR("image"), cgimage);
667 CGImageRelease(cgimage);
673 /***********************************************************************
674 * create_color_cursor
676 * Create an array of color cursor frames from a Windows cursor. Each
677 * frame is represented in the array by a dictionary.
678 * Frame dictionary keys:
679 * "image" a CGImage for the frame
680 * "duration" a CFNumber for the frame duration in seconds
681 * "hotSpot" a CFDictionary encoding a CGPoint for the hot spot
683 static CFArrayRef create_color_cursor(HDC hdc, const ICONINFOEXW *iinfo, HANDLE icon, int width, int height)
685 unsigned char *color_bits, *mask_bits;
686 HBITMAP hbmColor = 0, hbmMask = 0;
687 DWORD nFrames, delay_jiffies, i;
688 int color_size, mask_size;
689 BITMAPINFO *info = NULL;
690 CFMutableArrayRef frames;
692 TRACE("hdc %p iinfo %p icon %p width %d height %d\n", hdc, iinfo, icon, width, height);
694 /* Retrieve the number of frames to render */
695 if (!GetCursorFrameInfo(icon, 0x0 /* unknown parameter */, 0, &delay_jiffies, &nFrames))
697 WARN("GetCursorFrameInfo failed\n");
700 if (!(frames = CFArrayCreateMutable(NULL, nFrames, &kCFTypeArrayCallBacks)))
702 WARN("failed to allocate frames array\n");
706 /* Allocate all of the resources necessary to obtain a cursor frame */
707 if (!(info = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(BITMAPINFO, bmiColors[256])))) goto cleanup;
708 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
709 info->bmiHeader.biWidth = width;
710 info->bmiHeader.biHeight = -height;
711 info->bmiHeader.biPlanes = 1;
712 info->bmiHeader.biCompression = BI_RGB;
713 info->bmiHeader.biXPelsPerMeter = 0;
714 info->bmiHeader.biYPelsPerMeter = 0;
715 info->bmiHeader.biClrUsed = 0;
716 info->bmiHeader.biClrImportant = 0;
717 info->bmiHeader.biBitCount = 32;
718 color_size = width * height * 4;
719 info->bmiHeader.biSizeImage = color_size;
720 hbmColor = CreateDIBSection(hdc, info, DIB_RGB_COLORS, (VOID **) &color_bits, NULL, 0);
723 WARN("failed to create DIB section for cursor color data\n");
726 info->bmiHeader.biBitCount = 1;
727 info->bmiColors[0].rgbRed = 0;
728 info->bmiColors[0].rgbGreen = 0;
729 info->bmiColors[0].rgbBlue = 0;
730 info->bmiColors[0].rgbReserved = 0;
731 info->bmiColors[1].rgbRed = 0xff;
732 info->bmiColors[1].rgbGreen = 0xff;
733 info->bmiColors[1].rgbBlue = 0xff;
734 info->bmiColors[1].rgbReserved = 0;
736 mask_size = ((width + 31) / 32 * 4) * height; /* width_bytes * height */
737 info->bmiHeader.biSizeImage = mask_size;
738 hbmMask = CreateDIBSection(hdc, info, DIB_RGB_COLORS, (VOID **) &mask_bits, NULL, 0);
741 WARN("failed to create DIB section for cursor mask data\n");
745 /* Create a CFDictionary for each frame of the cursor */
746 for (i = 0; i < nFrames; i++)
748 CFDictionaryRef frame = create_cursor_frame(hdc, iinfo, icon,
749 hbmColor, color_bits, color_size,
750 hbmMask, mask_bits, mask_size,
752 if (!frame) goto cleanup;
753 CFArrayAppendValue(frames, frame);
758 if (CFArrayGetCount(frames) < nFrames)
764 TRACE("returning cursor with %d frames\n", nFrames);
765 /* Cleanup all of the resources used to obtain the frame data */
766 if (hbmColor) DeleteObject(hbmColor);
767 if (hbmMask) DeleteObject(hbmMask);
768 HeapFree(GetProcessHeap(), 0, info);
773 /***********************************************************************
774 * DestroyCursorIcon (MACDRV.@)
776 void CDECL macdrv_DestroyCursorIcon(HCURSOR cursor)
778 TRACE("cursor %p\n", cursor);
780 EnterCriticalSection(&cursor_cache_section);
782 CFDictionaryRemoveValue(cursor_cache, cursor);
783 LeaveCriticalSection(&cursor_cache_section);
787 /***********************************************************************
788 * ClipCursor (MACDRV.@)
790 * Set the cursor clipping rectangle.
792 BOOL CDECL macdrv_ClipCursor(LPCRECT clip)
796 TRACE("%s\n", wine_dbgstr_rect(clip));
800 rect = CGRectMake(clip->left, clip->top, max(1, clip->right - clip->left),
801 max(1, clip->bottom - clip->top));
804 rect = CGRectInfinite;
806 /* FIXME: This needs to be done not just in this process but in all of the
807 ones for this WINEPREFIX. Broadcast a message to do that. */
809 return macdrv_clip_cursor(rect);
813 /***********************************************************************
814 * GetCursorPos (MACDRV.@)
816 BOOL CDECL macdrv_GetCursorPos(LPPOINT pos)
821 ret = macdrv_get_cursor_position(&pt);
824 TRACE("pointer at (%g,%g) server pos %d,%d\n", pt.x, pt.y, pos->x, pos->y);
832 /***********************************************************************
833 * SetCursor (MACDRV.@)
835 void CDECL macdrv_SetCursor(HCURSOR cursor)
837 CFStringRef cursor_name = NULL;
838 CFArrayRef cursor_frames = NULL;
840 TRACE("%p\n", cursor);
846 EnterCriticalSection(&cursor_cache_section);
849 CFTypeRef cached_cursor = CFDictionaryGetValue(cursor_cache, cursor);
852 if (CFGetTypeID(cached_cursor) == CFStringGetTypeID())
853 cursor_name = CFRetain(cached_cursor);
855 cursor_frames = CFRetain(cached_cursor);
858 LeaveCriticalSection(&cursor_cache_section);
859 if (cursor_name || cursor_frames)
862 info.cbSize = sizeof(info);
863 if (!GetIconInfoExW(cursor, &info))
865 WARN("GetIconInfoExW failed\n");
869 if ((cursor_name = copy_system_cursor_name(&info)))
871 DeleteObject(info.hbmColor);
872 DeleteObject(info.hbmMask);
879 GetObjectW(info.hbmMask, sizeof(bm), &bm);
880 if (!info.hbmColor) bm.bmHeight = max(1, bm.bmHeight / 2);
882 /* make sure hotspot is valid */
883 if (info.xHotspot >= bm.bmWidth || info.yHotspot >= bm.bmHeight)
885 info.xHotspot = bm.bmWidth / 2;
886 info.yHotspot = bm.bmHeight / 2;
889 hdc = CreateCompatibleDC(0);
893 cursor_frames = create_color_cursor(hdc, &info, cursor, bm.bmWidth, bm.bmHeight);
894 DeleteObject(info.hbmColor);
897 cursor_frames = create_monochrome_cursor(hdc, &info, bm.bmWidth, bm.bmHeight);
899 DeleteObject(info.hbmMask);
903 if (cursor_name || cursor_frames)
905 EnterCriticalSection(&cursor_cache_section);
907 cursor_cache = CFDictionaryCreateMutable(NULL, 0, NULL,
908 &kCFTypeDictionaryValueCallBacks);
909 CFDictionarySetValue(cursor_cache, cursor,
910 cursor_name ? (CFTypeRef)cursor_name : (CFTypeRef)cursor_frames);
911 LeaveCriticalSection(&cursor_cache_section);
914 cursor_name = CFRetain(CFSTR("arrowCursor"));
918 TRACE("setting cursor with cursor_name %s cursor_frames %p\n", debugstr_cf(cursor_name), cursor_frames);
919 macdrv_set_cursor(cursor_name, cursor_frames);
920 if (cursor_name) CFRelease(cursor_name);
921 if (cursor_frames) CFRelease(cursor_frames);
925 /***********************************************************************
926 * SetCursorPos (MACDRV.@)
928 BOOL CDECL macdrv_SetCursorPos(INT x, INT y)
930 BOOL ret = macdrv_set_cursor_position(CGPointMake(x, y));
932 TRACE("warped to %d,%d\n", x, y);
934 ERR("failed to warp to %d,%d\n", x, y);
939 /***********************************************************************
940 * macdrv_mouse_button
942 * Handler for MOUSE_BUTTON events.
944 void macdrv_mouse_button(HWND hwnd, const macdrv_event *event)
949 TRACE("win %p button %d %s at (%d,%d) time %lu (%lu ticks ago)\n", hwnd, event->mouse_button.button,
950 (event->mouse_button.pressed ? "pressed" : "released"),
951 event->mouse_button.x, event->mouse_button.y,
952 event->mouse_button.time_ms, (GetTickCount() - event->mouse_button.time_ms));
954 if (event->mouse_button.pressed)
956 switch (event->mouse_button.button)
958 case 0: flags |= MOUSEEVENTF_LEFTDOWN; break;
959 case 1: flags |= MOUSEEVENTF_RIGHTDOWN; break;
960 case 2: flags |= MOUSEEVENTF_MIDDLEDOWN; break;
962 flags |= MOUSEEVENTF_XDOWN;
963 data = 1 << (event->mouse_button.button - 3);
969 switch (event->mouse_button.button)
971 case 0: flags |= MOUSEEVENTF_LEFTUP; break;
972 case 1: flags |= MOUSEEVENTF_RIGHTUP; break;
973 case 2: flags |= MOUSEEVENTF_MIDDLEUP; break;
975 flags |= MOUSEEVENTF_XUP;
976 data = 1 << (event->mouse_button.button - 3);
981 send_mouse_input(hwnd, flags | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
982 event->mouse_button.x, event->mouse_button.y,
983 data, event->mouse_button.time_ms);
987 /***********************************************************************
990 * Handler for MOUSE_MOVED and MOUSE_MOVED_ABSOLUTE events.
992 void macdrv_mouse_moved(HWND hwnd, const macdrv_event *event)
994 UINT flags = MOUSEEVENTF_MOVE;
996 TRACE("win %p/%p %s (%d,%d) time %lu (%lu ticks ago)\n", hwnd, event->window,
997 (event->type == MOUSE_MOVED) ? "relative" : "absolute",
998 event->mouse_moved.x, event->mouse_moved.y,
999 event->mouse_moved.time_ms, (GetTickCount() - event->mouse_moved.time_ms));
1001 if (event->type == MOUSE_MOVED_ABSOLUTE)
1002 flags |= MOUSEEVENTF_ABSOLUTE;
1004 send_mouse_input(hwnd, flags, event->mouse_moved.x, event->mouse_moved.y,
1005 0, event->mouse_moved.time_ms);
1009 /***********************************************************************
1010 * macdrv_mouse_scroll
1012 * Handler for MOUSE_SCROLL events.
1014 void macdrv_mouse_scroll(HWND hwnd, const macdrv_event *event)
1016 TRACE("win %p/%p scroll (%d,%d) at (%d,%d) time %lu (%lu ticks ago)\n", hwnd,
1017 event->window, event->mouse_scroll.x_scroll, event->mouse_scroll.y_scroll,
1018 event->mouse_scroll.x, event->mouse_scroll.y,
1019 event->mouse_scroll.time_ms, (GetTickCount() - event->mouse_scroll.time_ms));
1021 send_mouse_input(hwnd, MOUSEEVENTF_WHEEL | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
1022 event->mouse_scroll.x, event->mouse_scroll.y,
1023 event->mouse_scroll.y_scroll, event->mouse_scroll.time_ms);
1024 send_mouse_input(hwnd, MOUSEEVENTF_HWHEEL | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
1025 event->mouse_scroll.x, event->mouse_scroll.y,
1026 event->mouse_scroll.x_scroll, event->mouse_scroll.time_ms);