oleaut32/tests: Use common wine_dbgstr_guid implementation from test.h.
[wine.git] / dlls / winemac.drv / mouse.c
blobf9130c00e6e1e9ceafc2f7451fb9064ced0c66e9
1 /*
2 * MACDRV mouse driver
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
23 #include "config.h"
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"
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;
47 struct system_cursors
49 WORD id;
50 CFStringRef name;
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") },
62 { 0 }
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") },
74 { 0 }
77 static const struct system_cursors ole32_cursors[] =
79 { 1, CFSTR("operationNotAllowedCursor") },
80 { 2, CFSTR("closedHandCursor") },
81 { 3, CFSTR("dragCopyCursor") },
82 { 4, CFSTR("dragLinkCursor") },
83 { 0 }
86 static const struct system_cursors riched20_cursors[] =
88 { 105, CFSTR("pointingHandCursor") },
89 { 109, CFSTR("dragCopyCursor") },
90 { 110, CFSTR("closedHandCursor") },
91 { 111, CFSTR("operationNotAllowedCursor") },
92 { 0 }
95 static const struct
97 const struct system_cursors *cursors;
98 WCHAR name[16];
99 } module_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 /***********************************************************************
132 * send_mouse_input
134 * Update the various window states on a mouse event.
136 static void send_mouse_input(HWND hwnd, macdrv_window cocoa_window, UINT flags, int x, int y,
137 DWORD mouse_data, BOOL drag, unsigned long time)
139 INPUT input;
140 HWND top_level_hwnd;
142 top_level_hwnd = GetAncestor(hwnd, GA_ROOT);
144 if ((flags & MOUSEEVENTF_MOVE) && (flags & MOUSEEVENTF_ABSOLUTE) && !drag &&
145 cocoa_window != macdrv_thread_data()->capture_window)
147 RECT rect;
149 /* update the wine server Z-order */
150 SetRect(&rect, x, y, x + 1, y + 1);
151 MapWindowPoints(0, top_level_hwnd, (POINT *)&rect, 2);
153 SERVER_START_REQ(update_window_zorder)
155 req->window = wine_server_user_handle(top_level_hwnd);
156 req->rect.left = rect.left;
157 req->rect.top = rect.top;
158 req->rect.right = rect.right;
159 req->rect.bottom = rect.bottom;
160 wine_server_call(req);
162 SERVER_END_REQ;
165 input.type = INPUT_MOUSE;
166 input.mi.dx = x;
167 input.mi.dy = y;
168 input.mi.mouseData = mouse_data;
169 input.mi.dwFlags = flags;
170 input.mi.time = time;
171 input.mi.dwExtraInfo = 0;
173 __wine_send_input(top_level_hwnd, &input);
177 /***********************************************************************
178 * copy_system_cursor_name
180 CFStringRef copy_system_cursor_name(ICONINFOEXW *info)
182 static const WCHAR idW[] = {'%','h','u',0};
183 const struct system_cursors *cursors;
184 unsigned int i;
185 CFStringRef cursor_name = NULL;
186 HMODULE module;
187 HKEY key;
188 WCHAR *p, name[MAX_PATH * 2];
190 TRACE("info->szModName %s info->szResName %s info->wResID %hu\n", debugstr_w(info->szModName),
191 debugstr_w(info->szResName), info->wResID);
193 if (!info->szModName[0]) return NULL;
195 p = strrchrW(info->szModName, '\\');
196 strcpyW(name, p ? p + 1 : info->szModName);
197 p = name + strlenW(name);
198 *p++ = ',';
199 if (info->szResName[0]) strcpyW(p, info->szResName);
200 else sprintfW(p, idW, info->wResID);
202 /* @@ Wine registry key: HKCU\Software\Wine\Mac Driver\Cursors */
203 if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Mac Driver\\Cursors", &key))
205 WCHAR value[64];
206 DWORD size, ret;
208 value[0] = 0;
209 size = sizeof(value) / sizeof(WCHAR);
210 ret = RegQueryValueExW(key, name, NULL, NULL, (BYTE *)value, &size);
211 RegCloseKey(key);
212 if (!ret)
214 if (!value[0])
216 TRACE("registry forces standard cursor for %s\n", debugstr_w(name));
217 return NULL; /* force standard cursor */
220 cursor_name = CFStringCreateWithCharacters(NULL, value, strlenW(value));
221 if (!cursor_name)
223 WARN("CFStringCreateWithCharacters failed for %s\n", debugstr_w(value));
224 return NULL;
227 /* Make sure it's one of the appropriate NSCursor class methods. */
228 for (i = 0; i < sizeof(cocoa_cursor_names) / sizeof(cocoa_cursor_names[0]); i++)
229 if (CFEqual(cursor_name, cocoa_cursor_names[i]))
230 goto done;
232 WARN("%s mapped to invalid Cocoa cursor name %s\n", debugstr_w(name), debugstr_w(value));
233 CFRelease(cursor_name);
234 return NULL;
238 if (info->szResName[0]) goto done; /* only integer resources are supported here */
239 if (!(module = GetModuleHandleW(info->szModName))) goto done;
241 for (i = 0; i < sizeof(module_cursors)/sizeof(module_cursors[0]); i++)
242 if (GetModuleHandleW(module_cursors[i].name) == module) break;
243 if (i == sizeof(module_cursors)/sizeof(module_cursors[0])) goto done;
245 cursors = module_cursors[i].cursors;
246 for (i = 0; cursors[i].id; i++)
247 if (cursors[i].id == info->wResID)
249 cursor_name = CFRetain(cursors[i].name);
250 break;
253 done:
254 if (cursor_name)
255 TRACE("%s -> %s\n", debugstr_w(name), debugstr_cf(cursor_name));
256 else
257 WARN("no system cursor found for %s\n", debugstr_w(name));
258 return cursor_name;
261 /***********************************************************************
262 * create_monochrome_cursor
264 CFArrayRef create_monochrome_cursor(HDC hdc, const ICONINFOEXW *icon, int width, int height)
266 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
267 BITMAPINFO *info = (BITMAPINFO *)buffer;
268 unsigned int width_bytes = (width + 31) / 32 * 4;
269 unsigned long *and_bits = NULL, *xor_bits;
270 unsigned long *data_bits;
271 int count, i;
272 CGColorSpaceRef colorspace;
273 CFMutableDataRef data;
274 CGDataProviderRef provider;
275 CGImageRef cgimage, cgmask, cgmasked;
276 CGPoint hot_spot;
277 CFDictionaryRef hot_spot_dict;
278 const CFStringRef keys[] = { CFSTR("image"), CFSTR("hotSpot") };
279 CFTypeRef values[sizeof(keys) / sizeof(keys[0])];
280 CFDictionaryRef frame;
281 CFArrayRef frames;
283 TRACE("hdc %p icon->hbmMask %p icon->xHotspot %d icon->yHotspot %d width %d height %d\n",
284 hdc, icon->hbmMask, icon->xHotspot, icon->yHotspot, width, height);
286 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
287 info->bmiHeader.biWidth = width;
288 info->bmiHeader.biHeight = -height * 2;
289 info->bmiHeader.biPlanes = 1;
290 info->bmiHeader.biBitCount = 1;
291 info->bmiHeader.biCompression = BI_RGB;
292 info->bmiHeader.biSizeImage = width_bytes * height * 2;
293 info->bmiHeader.biXPelsPerMeter = 0;
294 info->bmiHeader.biYPelsPerMeter = 0;
295 info->bmiHeader.biClrUsed = 0;
296 info->bmiHeader.biClrImportant = 0;
298 and_bits = HeapAlloc(GetProcessHeap(), 0, info->bmiHeader.biSizeImage);
299 if (!and_bits)
301 WARN("failed to allocate and_bits\n");
302 return NULL;
304 xor_bits = (unsigned long*)((char*)and_bits + info->bmiHeader.biSizeImage / 2);
306 if (!GetDIBits(hdc, icon->hbmMask, 0, height * 2, and_bits, info, DIB_RGB_COLORS))
308 WARN("GetDIBits failed\n");
309 HeapFree(GetProcessHeap(), 0, and_bits);
310 return NULL;
313 /* On Windows, the pixels of a monochrome cursor can have four effects:
314 draw black, draw white, leave unchanged (transparent), or invert. The Mac
315 only supports the first three. It can't do pixels which invert the
316 background. Since the background is usually white, I am arbitrarily
317 mapping "invert" to "draw black". This entails bitwise math between the
318 cursor's AND mask and XOR mask:
320 AND | XOR | Windows cursor pixel
321 --------------------------------
322 0 | 0 | black
323 0 | 1 | white
324 1 | 0 | transparent
325 1 | 1 | invert
327 AND | XOR | Mac image
328 ---------------------
329 0 | 0 | black (0)
330 0 | 1 | white (1)
331 1 | 0 | don't care
332 1 | 1 | black (0)
334 AND | XOR | Mac mask
335 ---------------------------
336 0 | 0 | paint (0)
337 0 | 1 | paint (0)
338 1 | 0 | don't paint (1)
339 1 | 1 | paint (0)
341 So, Mac image = AND ^ XOR and Mac mask = AND & ~XOR.
343 /* Create data for Mac image. */
344 data = CFDataCreateMutable(NULL, info->bmiHeader.biSizeImage / 2);
345 if (!data)
347 WARN("failed to create data\n");
348 HeapFree(GetProcessHeap(), 0, and_bits);
349 return NULL;
352 /* image data = AND mask */
353 CFDataAppendBytes(data, (UInt8*)and_bits, info->bmiHeader.biSizeImage / 2);
354 /* image data ^= XOR mask */
355 data_bits = (unsigned long*)CFDataGetMutableBytePtr(data);
356 count = (info->bmiHeader.biSizeImage / 2) / sizeof(*data_bits);
357 for (i = 0; i < count; i++)
358 data_bits[i] ^= xor_bits[i];
360 colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
361 if (!colorspace)
363 WARN("failed to create colorspace\n");
364 CFRelease(data);
365 HeapFree(GetProcessHeap(), 0, and_bits);
366 return NULL;
369 provider = CGDataProviderCreateWithCFData(data);
370 CFRelease(data);
371 if (!provider)
373 WARN("failed to create data provider\n");
374 CGColorSpaceRelease(colorspace);
375 HeapFree(GetProcessHeap(), 0, and_bits);
376 return NULL;
379 cgimage = CGImageCreate(width, height, 1, 1, width_bytes, colorspace,
380 kCGImageAlphaNone | kCGBitmapByteOrderDefault,
381 provider, NULL, FALSE, kCGRenderingIntentDefault);
382 CGDataProviderRelease(provider);
383 CGColorSpaceRelease(colorspace);
384 if (!cgimage)
386 WARN("failed to create image\n");
387 HeapFree(GetProcessHeap(), 0, and_bits);
388 return NULL;
391 /* Create data for mask. */
392 data = CFDataCreateMutable(NULL, info->bmiHeader.biSizeImage / 2);
393 if (!data)
395 WARN("failed to create data\n");
396 CGImageRelease(cgimage);
397 HeapFree(GetProcessHeap(), 0, and_bits);
398 return NULL;
401 /* mask data = AND mask */
402 CFDataAppendBytes(data, (UInt8*)and_bits, info->bmiHeader.biSizeImage / 2);
403 /* mask data &= ~XOR mask */
404 data_bits = (unsigned long*)CFDataGetMutableBytePtr(data);
405 for (i = 0; i < count; i++)
406 data_bits[i] &= ~xor_bits[i];
407 HeapFree(GetProcessHeap(), 0, and_bits);
409 provider = CGDataProviderCreateWithCFData(data);
410 CFRelease(data);
411 if (!provider)
413 WARN("failed to create data provider\n");
414 CGImageRelease(cgimage);
415 return NULL;
418 cgmask = CGImageMaskCreate(width, height, 1, 1, width_bytes, provider, NULL, FALSE);
419 CGDataProviderRelease(provider);
420 if (!cgmask)
422 WARN("failed to create mask image\n");
423 CGImageRelease(cgimage);
424 return NULL;
427 cgmasked = CGImageCreateWithMask(cgimage, cgmask);
428 CGImageRelease(cgimage);
429 CGImageRelease(cgmask);
430 if (!cgmasked)
432 WARN("failed to create masked image\n");
433 return NULL;
436 hot_spot = CGPointMake(icon->xHotspot, icon->yHotspot);
437 hot_spot_dict = CGPointCreateDictionaryRepresentation(hot_spot);
438 if (!hot_spot_dict)
440 WARN("failed to create hot spot dictionary\n");
441 CGImageRelease(cgmasked);
442 return NULL;
445 values[0] = cgmasked;
446 values[1] = hot_spot_dict;
447 frame = CFDictionaryCreate(NULL, (const void**)keys, values, sizeof(keys) / sizeof(keys[0]),
448 &kCFCopyStringDictionaryKeyCallBacks,
449 &kCFTypeDictionaryValueCallBacks);
450 CFRelease(hot_spot_dict);
451 CGImageRelease(cgmasked);
452 if (!frame)
454 WARN("failed to create frame dictionary\n");
455 return NULL;
458 frames = CFArrayCreate(NULL, (const void**)&frame, 1, &kCFTypeArrayCallBacks);
459 CFRelease(frame);
460 if (!frames)
462 WARN("failed to create frames array\n");
463 return NULL;
466 return frames;
470 /***********************************************************************
471 * create_cursor_frame
473 * Create a frame dictionary for a cursor from a Windows icon.
474 * Keys:
475 * "image" a CGImage for the frame
476 * "duration" a CFNumber for the frame duration in seconds
477 * "hotSpot" a CFDictionary encoding a CGPoint for the hot spot
479 static CFDictionaryRef create_cursor_frame(HDC hdc, const ICONINFOEXW *iinfo, HANDLE icon,
480 HBITMAP hbmColor, unsigned char *color_bits, int color_size,
481 HBITMAP hbmMask, unsigned char *mask_bits, int mask_size,
482 int width, int height, int istep)
484 DWORD delay_jiffies, num_steps;
485 CFMutableDictionaryRef frame;
486 CGPoint hot_spot;
487 CFDictionaryRef hot_spot_dict;
488 double duration;
489 CFNumberRef duration_number;
490 CGImageRef cgimage;
492 TRACE("hdc %p iinfo->xHotspot %d iinfo->yHotspot %d icon %p hbmColor %p color_bits %p color_size %d"
493 " hbmMask %p mask_bits %p mask_size %d width %d height %d istep %d\n",
494 hdc, iinfo->xHotspot, iinfo->yHotspot, icon, hbmColor, color_bits, color_size,
495 hbmMask, mask_bits, mask_size, width, height, istep);
497 frame = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks,
498 &kCFTypeDictionaryValueCallBacks);
499 if (!frame)
501 WARN("failed to allocate dictionary for frame\n");
502 return NULL;
505 hot_spot = CGPointMake(iinfo->xHotspot, iinfo->yHotspot);
506 hot_spot_dict = CGPointCreateDictionaryRepresentation(hot_spot);
507 if (!hot_spot_dict)
509 WARN("failed to create hot spot dictionary\n");
510 CFRelease(frame);
511 return NULL;
513 CFDictionarySetValue(frame, CFSTR("hotSpot"), hot_spot_dict);
514 CFRelease(hot_spot_dict);
516 if (GetCursorFrameInfo(icon, 0x0 /* unknown parameter */, istep, &delay_jiffies, &num_steps) != 0)
517 duration = delay_jiffies / 60.0; /* convert jiffies (1/60s) to seconds */
518 else
520 WARN("Failed to retrieve animated cursor frame-rate for frame %d.\n", istep);
521 duration = 0.1; /* fallback delay, 100 ms */
523 duration_number = CFNumberCreate(NULL, kCFNumberDoubleType, &duration);
524 if (!duration_number)
526 WARN("failed to create duration number\n");
527 CFRelease(frame);
528 return NULL;
530 CFDictionarySetValue(frame, CFSTR("duration"), duration_number);
531 CFRelease(duration_number);
533 cgimage = create_cgimage_from_icon_bitmaps(hdc, icon, hbmColor, color_bits, color_size,
534 hbmMask, mask_bits, mask_size, width, height, istep);
535 if (!cgimage)
537 CFRelease(frame);
538 return NULL;
541 CFDictionarySetValue(frame, CFSTR("image"), cgimage);
542 CGImageRelease(cgimage);
544 return frame;
548 /***********************************************************************
549 * create_color_cursor
551 * Create an array of color cursor frames from a Windows cursor. Each
552 * frame is represented in the array by a dictionary.
553 * Frame dictionary keys:
554 * "image" a CGImage for the frame
555 * "duration" a CFNumber for the frame duration in seconds
556 * "hotSpot" a CFDictionary encoding a CGPoint for the hot spot
558 static CFArrayRef create_color_cursor(HDC hdc, const ICONINFOEXW *iinfo, HANDLE icon, int width, int height)
560 unsigned char *color_bits, *mask_bits;
561 HBITMAP hbmColor = 0, hbmMask = 0;
562 DWORD nFrames, delay_jiffies, i;
563 int color_size, mask_size;
564 BITMAPINFO *info = NULL;
565 CFMutableArrayRef frames;
567 TRACE("hdc %p iinfo %p icon %p width %d height %d\n", hdc, iinfo, icon, width, height);
569 /* Retrieve the number of frames to render */
570 if (!GetCursorFrameInfo(icon, 0x0 /* unknown parameter */, 0, &delay_jiffies, &nFrames))
572 WARN("GetCursorFrameInfo failed\n");
573 return NULL;
575 if (!(frames = CFArrayCreateMutable(NULL, nFrames, &kCFTypeArrayCallBacks)))
577 WARN("failed to allocate frames array\n");
578 return NULL;
581 /* Allocate all of the resources necessary to obtain a cursor frame */
582 if (!(info = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(BITMAPINFO, bmiColors[256])))) goto cleanup;
583 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
584 info->bmiHeader.biWidth = width;
585 info->bmiHeader.biHeight = -height;
586 info->bmiHeader.biPlanes = 1;
587 info->bmiHeader.biCompression = BI_RGB;
588 info->bmiHeader.biXPelsPerMeter = 0;
589 info->bmiHeader.biYPelsPerMeter = 0;
590 info->bmiHeader.biClrUsed = 0;
591 info->bmiHeader.biClrImportant = 0;
592 info->bmiHeader.biBitCount = 32;
593 color_size = width * height * 4;
594 info->bmiHeader.biSizeImage = color_size;
595 hbmColor = CreateDIBSection(hdc, info, DIB_RGB_COLORS, (VOID **) &color_bits, NULL, 0);
596 if (!hbmColor)
598 WARN("failed to create DIB section for cursor color data\n");
599 goto cleanup;
601 info->bmiHeader.biBitCount = 1;
602 info->bmiColors[0].rgbRed = 0;
603 info->bmiColors[0].rgbGreen = 0;
604 info->bmiColors[0].rgbBlue = 0;
605 info->bmiColors[0].rgbReserved = 0;
606 info->bmiColors[1].rgbRed = 0xff;
607 info->bmiColors[1].rgbGreen = 0xff;
608 info->bmiColors[1].rgbBlue = 0xff;
609 info->bmiColors[1].rgbReserved = 0;
611 mask_size = ((width + 31) / 32 * 4) * height; /* width_bytes * height */
612 info->bmiHeader.biSizeImage = mask_size;
613 hbmMask = CreateDIBSection(hdc, info, DIB_RGB_COLORS, (VOID **) &mask_bits, NULL, 0);
614 if (!hbmMask)
616 WARN("failed to create DIB section for cursor mask data\n");
617 goto cleanup;
620 /* Create a CFDictionary for each frame of the cursor */
621 for (i = 0; i < nFrames; i++)
623 CFDictionaryRef frame = create_cursor_frame(hdc, iinfo, icon,
624 hbmColor, color_bits, color_size,
625 hbmMask, mask_bits, mask_size,
626 width, height, i);
627 if (!frame) goto cleanup;
628 CFArrayAppendValue(frames, frame);
629 CFRelease(frame);
632 cleanup:
633 if (CFArrayGetCount(frames) < nFrames)
635 CFRelease(frames);
636 frames = NULL;
638 else
639 TRACE("returning cursor with %d frames\n", nFrames);
640 /* Cleanup all of the resources used to obtain the frame data */
641 if (hbmColor) DeleteObject(hbmColor);
642 if (hbmMask) DeleteObject(hbmMask);
643 HeapFree(GetProcessHeap(), 0, info);
644 return frames;
648 /***********************************************************************
649 * DestroyCursorIcon (MACDRV.@)
651 void CDECL macdrv_DestroyCursorIcon(HCURSOR cursor)
653 TRACE("cursor %p\n", cursor);
655 EnterCriticalSection(&cursor_cache_section);
656 if (cursor_cache)
657 CFDictionaryRemoveValue(cursor_cache, cursor);
658 LeaveCriticalSection(&cursor_cache_section);
662 /***********************************************************************
663 * ClipCursor (MACDRV.@)
665 * Set the cursor clipping rectangle.
667 BOOL CDECL macdrv_ClipCursor(LPCRECT clip)
669 CGRect rect;
671 TRACE("%s\n", wine_dbgstr_rect(clip));
673 if (clip)
675 rect = CGRectMake(clip->left, clip->top, max(1, clip->right - clip->left),
676 max(1, clip->bottom - clip->top));
678 else
679 rect = CGRectInfinite;
681 /* FIXME: This needs to be done not just in this process but in all of the
682 ones for this WINEPREFIX. Broadcast a message to do that. */
684 return macdrv_clip_cursor(rect);
688 /***********************************************************************
689 * GetCursorPos (MACDRV.@)
691 BOOL CDECL macdrv_GetCursorPos(LPPOINT pos)
693 CGPoint pt;
694 BOOL ret;
696 ret = macdrv_get_cursor_position(&pt);
697 if (ret)
699 TRACE("pointer at (%g,%g) server pos %d,%d\n", pt.x, pt.y, pos->x, pos->y);
700 pos->x = pt.x;
701 pos->y = pt.y;
703 return ret;
707 /***********************************************************************
708 * SetCapture (MACDRV.@)
710 void CDECL macdrv_SetCapture(HWND hwnd, UINT flags)
712 struct macdrv_thread_data *thread_data = macdrv_thread_data();
713 HWND top = GetAncestor(hwnd, GA_ROOT);
714 macdrv_window cocoa_window = macdrv_get_cocoa_window(top, FALSE);
716 TRACE("hwnd %p top %p/%p flags 0x%08x\n", hwnd, top, cocoa_window, flags);
718 if (!thread_data) return;
720 thread_data->capture_window = cocoa_window;
721 macdrv_set_mouse_capture_window(cocoa_window);
725 /***********************************************************************
726 * SetCursor (MACDRV.@)
728 void CDECL macdrv_SetCursor(HCURSOR cursor)
730 CFStringRef cursor_name = NULL;
731 CFArrayRef cursor_frames = NULL;
733 TRACE("%p\n", cursor);
735 if (cursor)
737 ICONINFOEXW info;
739 EnterCriticalSection(&cursor_cache_section);
740 if (cursor_cache)
742 CFTypeRef cached_cursor = CFDictionaryGetValue(cursor_cache, cursor);
743 if (cached_cursor)
745 if (CFGetTypeID(cached_cursor) == CFStringGetTypeID())
746 cursor_name = CFRetain(cached_cursor);
747 else
748 cursor_frames = CFRetain(cached_cursor);
751 LeaveCriticalSection(&cursor_cache_section);
752 if (cursor_name || cursor_frames)
753 goto done;
755 info.cbSize = sizeof(info);
756 if (!GetIconInfoExW(cursor, &info))
758 WARN("GetIconInfoExW failed\n");
759 return;
762 if ((cursor_name = copy_system_cursor_name(&info)))
764 DeleteObject(info.hbmColor);
765 DeleteObject(info.hbmMask);
767 else
769 BITMAP bm;
770 HDC hdc;
772 GetObjectW(info.hbmMask, sizeof(bm), &bm);
773 if (!info.hbmColor) bm.bmHeight = max(1, bm.bmHeight / 2);
775 /* make sure hotspot is valid */
776 if (info.xHotspot >= bm.bmWidth || info.yHotspot >= bm.bmHeight)
778 info.xHotspot = bm.bmWidth / 2;
779 info.yHotspot = bm.bmHeight / 2;
782 hdc = CreateCompatibleDC(0);
784 if (info.hbmColor)
786 cursor_frames = create_color_cursor(hdc, &info, cursor, bm.bmWidth, bm.bmHeight);
787 DeleteObject(info.hbmColor);
789 else
790 cursor_frames = create_monochrome_cursor(hdc, &info, bm.bmWidth, bm.bmHeight);
792 DeleteObject(info.hbmMask);
793 DeleteDC(hdc);
796 if (cursor_name || cursor_frames)
798 EnterCriticalSection(&cursor_cache_section);
799 if (!cursor_cache)
800 cursor_cache = CFDictionaryCreateMutable(NULL, 0, NULL,
801 &kCFTypeDictionaryValueCallBacks);
802 CFDictionarySetValue(cursor_cache, cursor,
803 cursor_name ? (CFTypeRef)cursor_name : (CFTypeRef)cursor_frames);
804 LeaveCriticalSection(&cursor_cache_section);
806 else
807 cursor_name = CFRetain(CFSTR("arrowCursor"));
810 done:
811 TRACE("setting cursor with cursor_name %s cursor_frames %p\n", debugstr_cf(cursor_name), cursor_frames);
812 macdrv_set_cursor(cursor_name, cursor_frames);
813 if (cursor_name) CFRelease(cursor_name);
814 if (cursor_frames) CFRelease(cursor_frames);
818 /***********************************************************************
819 * SetCursorPos (MACDRV.@)
821 BOOL CDECL macdrv_SetCursorPos(INT x, INT y)
823 BOOL ret = macdrv_set_cursor_position(CGPointMake(x, y));
824 if (ret)
825 TRACE("warped to %d,%d\n", x, y);
826 else
827 ERR("failed to warp to %d,%d\n", x, y);
828 return ret;
832 /***********************************************************************
833 * macdrv_mouse_button
835 * Handler for MOUSE_BUTTON events.
837 void macdrv_mouse_button(HWND hwnd, const macdrv_event *event)
839 UINT flags = 0;
840 WORD data = 0;
842 TRACE("win %p button %d %s at (%d,%d) time %lu (%lu ticks ago)\n", hwnd, event->mouse_button.button,
843 (event->mouse_button.pressed ? "pressed" : "released"),
844 event->mouse_button.x, event->mouse_button.y,
845 event->mouse_button.time_ms, (GetTickCount() - event->mouse_button.time_ms));
847 if (event->mouse_button.pressed)
849 switch (event->mouse_button.button)
851 case 0: flags |= MOUSEEVENTF_LEFTDOWN; break;
852 case 1: flags |= MOUSEEVENTF_RIGHTDOWN; break;
853 case 2: flags |= MOUSEEVENTF_MIDDLEDOWN; break;
854 default:
855 flags |= MOUSEEVENTF_XDOWN;
856 data = 1 << (event->mouse_button.button - 3);
857 break;
860 else
862 switch (event->mouse_button.button)
864 case 0: flags |= MOUSEEVENTF_LEFTUP; break;
865 case 1: flags |= MOUSEEVENTF_RIGHTUP; break;
866 case 2: flags |= MOUSEEVENTF_MIDDLEUP; break;
867 default:
868 flags |= MOUSEEVENTF_XUP;
869 data = 1 << (event->mouse_button.button - 3);
870 break;
874 send_mouse_input(hwnd, event->window, flags | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
875 event->mouse_button.x, event->mouse_button.y,
876 data, FALSE, event->mouse_button.time_ms);
880 /***********************************************************************
881 * macdrv_mouse_moved
883 * Handler for MOUSE_MOVED and MOUSE_MOVED_ABSOLUTE events.
885 void macdrv_mouse_moved(HWND hwnd, const macdrv_event *event)
887 UINT flags = MOUSEEVENTF_MOVE;
889 TRACE("win %p/%p %s (%d,%d) drag %d time %lu (%lu ticks ago)\n", hwnd, event->window,
890 (event->type == MOUSE_MOVED) ? "relative" : "absolute",
891 event->mouse_moved.x, event->mouse_moved.y, event->mouse_moved.drag,
892 event->mouse_moved.time_ms, (GetTickCount() - event->mouse_moved.time_ms));
894 if (event->type == MOUSE_MOVED_ABSOLUTE)
895 flags |= MOUSEEVENTF_ABSOLUTE;
897 send_mouse_input(hwnd, event->window, flags, event->mouse_moved.x, event->mouse_moved.y,
898 0, event->mouse_moved.drag, event->mouse_moved.time_ms);
902 /***********************************************************************
903 * macdrv_mouse_scroll
905 * Handler for MOUSE_SCROLL events.
907 void macdrv_mouse_scroll(HWND hwnd, const macdrv_event *event)
909 TRACE("win %p/%p scroll (%d,%d) at (%d,%d) time %lu (%lu ticks ago)\n", hwnd,
910 event->window, event->mouse_scroll.x_scroll, event->mouse_scroll.y_scroll,
911 event->mouse_scroll.x, event->mouse_scroll.y,
912 event->mouse_scroll.time_ms, (GetTickCount() - event->mouse_scroll.time_ms));
914 if (event->mouse_scroll.y_scroll)
915 send_mouse_input(hwnd, event->window, MOUSEEVENTF_WHEEL | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
916 event->mouse_scroll.x, event->mouse_scroll.y,
917 event->mouse_scroll.y_scroll, FALSE, event->mouse_scroll.time_ms);
918 if (event->mouse_scroll.x_scroll)
919 send_mouse_input(hwnd, event->window, MOUSEEVENTF_HWHEEL | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
920 event->mouse_scroll.x, event->mouse_scroll.y,
921 event->mouse_scroll.x_scroll, FALSE, event->mouse_scroll.time_ms);
925 /***********************************************************************
926 * macdrv_release_capture
928 * Handler for RELEASE_CAPTURE events.
930 void macdrv_release_capture(HWND hwnd, const macdrv_event *event)
932 struct macdrv_thread_data *thread_data = macdrv_thread_data();
933 HWND capture = GetCapture();
934 HWND capture_top = GetAncestor(capture, GA_ROOT);
936 TRACE("win %p/%p thread_data->capture_window %p GetCapture() %p in %p\n", hwnd,
937 event->window, thread_data->capture_window, capture, capture_top);
939 if (event->window == thread_data->capture_window && hwnd == capture_top)
941 ReleaseCapture();
942 if (!PostMessageW(capture, WM_CANCELMODE, 0, 0))
943 WARN("failed to post WM_CANCELMODE; error 0x%08x\n", GetLastError());