quartz/tests: Make testpin_{AddRef,Release}() static.
[wine.git] / dlls / winemac.drv / mouse.c
blobdd6443fe1ba2ca0768aeee2b8f11b54a9803c09b
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 /* update the wine server Z-order */
148 SERVER_START_REQ(update_window_zorder)
150 req->window = wine_server_user_handle(top_level_hwnd);
151 req->rect.left = x;
152 req->rect.top = y;
153 req->rect.right = x + 1;
154 req->rect.bottom = y + 1;
155 wine_server_call(req);
157 SERVER_END_REQ;
160 input.type = INPUT_MOUSE;
161 input.mi.dx = x;
162 input.mi.dy = y;
163 input.mi.mouseData = mouse_data;
164 input.mi.dwFlags = flags;
165 input.mi.time = time;
166 input.mi.dwExtraInfo = 0;
168 __wine_send_input(top_level_hwnd, &input);
172 /***********************************************************************
173 * copy_system_cursor_name
175 CFStringRef copy_system_cursor_name(ICONINFOEXW *info)
177 static const WCHAR idW[] = {'%','h','u',0};
178 const struct system_cursors *cursors;
179 unsigned int i;
180 CFStringRef cursor_name = NULL;
181 HMODULE module;
182 HKEY key;
183 WCHAR *p, name[MAX_PATH * 2];
185 TRACE("info->szModName %s info->szResName %s info->wResID %hu\n", debugstr_w(info->szModName),
186 debugstr_w(info->szResName), info->wResID);
188 if (!info->szModName[0]) return NULL;
190 p = strrchrW(info->szModName, '\\');
191 strcpyW(name, p ? p + 1 : info->szModName);
192 p = name + strlenW(name);
193 *p++ = ',';
194 if (info->szResName[0]) strcpyW(p, info->szResName);
195 else sprintfW(p, idW, info->wResID);
197 /* @@ Wine registry key: HKCU\Software\Wine\Mac Driver\Cursors */
198 if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Mac Driver\\Cursors", &key))
200 WCHAR value[64];
201 DWORD size, ret;
203 value[0] = 0;
204 size = sizeof(value);
205 ret = RegQueryValueExW(key, name, NULL, NULL, (BYTE *)value, &size);
206 RegCloseKey(key);
207 if (!ret)
209 if (!value[0])
211 TRACE("registry forces standard cursor for %s\n", debugstr_w(name));
212 return NULL; /* force standard cursor */
215 cursor_name = CFStringCreateWithCharacters(NULL, value, strlenW(value));
216 if (!cursor_name)
218 WARN("CFStringCreateWithCharacters failed for %s\n", debugstr_w(value));
219 return NULL;
222 /* Make sure it's one of the appropriate NSCursor class methods. */
223 for (i = 0; i < ARRAY_SIZE(cocoa_cursor_names); i++)
224 if (CFEqual(cursor_name, cocoa_cursor_names[i]))
225 goto done;
227 WARN("%s mapped to invalid Cocoa cursor name %s\n", debugstr_w(name), debugstr_w(value));
228 CFRelease(cursor_name);
229 return NULL;
233 if (info->szResName[0]) goto done; /* only integer resources are supported here */
234 if (!(module = GetModuleHandleW(info->szModName))) goto done;
236 for (i = 0; i < ARRAY_SIZE(module_cursors); i++)
237 if (GetModuleHandleW(module_cursors[i].name) == module) break;
238 if (i == ARRAY_SIZE(module_cursors)) goto done;
240 cursors = module_cursors[i].cursors;
241 for (i = 0; cursors[i].id; i++)
242 if (cursors[i].id == info->wResID)
244 cursor_name = CFRetain(cursors[i].name);
245 break;
248 done:
249 if (cursor_name)
250 TRACE("%s -> %s\n", debugstr_w(name), debugstr_cf(cursor_name));
251 else
252 WARN("no system cursor found for %s\n", debugstr_w(name));
253 return cursor_name;
256 /***********************************************************************
257 * create_monochrome_cursor
259 CFArrayRef create_monochrome_cursor(HDC hdc, const ICONINFOEXW *icon, int width, int height)
261 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
262 BITMAPINFO *info = (BITMAPINFO *)buffer;
263 unsigned int width_bytes = (width + 31) / 32 * 4;
264 unsigned long *and_bits = NULL, *xor_bits;
265 unsigned long *data_bits;
266 int count, i;
267 CGColorSpaceRef colorspace;
268 CFMutableDataRef data;
269 CGDataProviderRef provider;
270 CGImageRef cgimage, cgmask, cgmasked;
271 CGPoint hot_spot;
272 CFDictionaryRef hot_spot_dict;
273 const CFStringRef keys[] = { CFSTR("image"), CFSTR("hotSpot") };
274 CFTypeRef values[ARRAY_SIZE(keys)];
275 CFDictionaryRef frame;
276 CFArrayRef frames;
278 TRACE("hdc %p icon->hbmMask %p icon->xHotspot %d icon->yHotspot %d width %d height %d\n",
279 hdc, icon->hbmMask, icon->xHotspot, icon->yHotspot, width, height);
281 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
282 info->bmiHeader.biWidth = width;
283 info->bmiHeader.biHeight = -height * 2;
284 info->bmiHeader.biPlanes = 1;
285 info->bmiHeader.biBitCount = 1;
286 info->bmiHeader.biCompression = BI_RGB;
287 info->bmiHeader.biSizeImage = width_bytes * height * 2;
288 info->bmiHeader.biXPelsPerMeter = 0;
289 info->bmiHeader.biYPelsPerMeter = 0;
290 info->bmiHeader.biClrUsed = 0;
291 info->bmiHeader.biClrImportant = 0;
293 and_bits = HeapAlloc(GetProcessHeap(), 0, info->bmiHeader.biSizeImage);
294 if (!and_bits)
296 WARN("failed to allocate and_bits\n");
297 return NULL;
299 xor_bits = (unsigned long*)((char*)and_bits + info->bmiHeader.biSizeImage / 2);
301 if (!GetDIBits(hdc, icon->hbmMask, 0, height * 2, and_bits, info, DIB_RGB_COLORS))
303 WARN("GetDIBits failed\n");
304 HeapFree(GetProcessHeap(), 0, and_bits);
305 return NULL;
308 /* On Windows, the pixels of a monochrome cursor can have four effects:
309 draw black, draw white, leave unchanged (transparent), or invert. The Mac
310 only supports the first three. It can't do pixels which invert the
311 background. Since the background is usually white, I am arbitrarily
312 mapping "invert" to "draw black". This entails bitwise math between the
313 cursor's AND mask and XOR mask:
315 AND | XOR | Windows cursor pixel
316 --------------------------------
317 0 | 0 | black
318 0 | 1 | white
319 1 | 0 | transparent
320 1 | 1 | invert
322 AND | XOR | Mac image
323 ---------------------
324 0 | 0 | black (0)
325 0 | 1 | white (1)
326 1 | 0 | don't care
327 1 | 1 | black (0)
329 AND | XOR | Mac mask
330 ---------------------------
331 0 | 0 | paint (0)
332 0 | 1 | paint (0)
333 1 | 0 | don't paint (1)
334 1 | 1 | paint (0)
336 So, Mac image = AND ^ XOR and Mac mask = AND & ~XOR.
338 /* Create data for Mac image. */
339 data = CFDataCreateMutable(NULL, info->bmiHeader.biSizeImage / 2);
340 if (!data)
342 WARN("failed to create data\n");
343 HeapFree(GetProcessHeap(), 0, and_bits);
344 return NULL;
347 /* image data = AND mask */
348 CFDataAppendBytes(data, (UInt8*)and_bits, info->bmiHeader.biSizeImage / 2);
349 /* image data ^= XOR mask */
350 data_bits = (unsigned long*)CFDataGetMutableBytePtr(data);
351 count = (info->bmiHeader.biSizeImage / 2) / sizeof(*data_bits);
352 for (i = 0; i < count; i++)
353 data_bits[i] ^= xor_bits[i];
355 colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGrayGamma2_2);
356 if (!colorspace)
358 WARN("failed to create colorspace\n");
359 CFRelease(data);
360 HeapFree(GetProcessHeap(), 0, and_bits);
361 return NULL;
364 provider = CGDataProviderCreateWithCFData(data);
365 CFRelease(data);
366 if (!provider)
368 WARN("failed to create data provider\n");
369 CGColorSpaceRelease(colorspace);
370 HeapFree(GetProcessHeap(), 0, and_bits);
371 return NULL;
374 cgimage = CGImageCreate(width, height, 1, 1, width_bytes, colorspace,
375 kCGImageAlphaNone | kCGBitmapByteOrderDefault,
376 provider, NULL, FALSE, kCGRenderingIntentDefault);
377 CGDataProviderRelease(provider);
378 CGColorSpaceRelease(colorspace);
379 if (!cgimage)
381 WARN("failed to create image\n");
382 HeapFree(GetProcessHeap(), 0, and_bits);
383 return NULL;
386 /* Create data for mask. */
387 data = CFDataCreateMutable(NULL, info->bmiHeader.biSizeImage / 2);
388 if (!data)
390 WARN("failed to create data\n");
391 CGImageRelease(cgimage);
392 HeapFree(GetProcessHeap(), 0, and_bits);
393 return NULL;
396 /* mask data = AND mask */
397 CFDataAppendBytes(data, (UInt8*)and_bits, info->bmiHeader.biSizeImage / 2);
398 /* mask data &= ~XOR mask */
399 data_bits = (unsigned long*)CFDataGetMutableBytePtr(data);
400 for (i = 0; i < count; i++)
401 data_bits[i] &= ~xor_bits[i];
402 HeapFree(GetProcessHeap(), 0, and_bits);
404 provider = CGDataProviderCreateWithCFData(data);
405 CFRelease(data);
406 if (!provider)
408 WARN("failed to create data provider\n");
409 CGImageRelease(cgimage);
410 return NULL;
413 cgmask = CGImageMaskCreate(width, height, 1, 1, width_bytes, provider, NULL, FALSE);
414 CGDataProviderRelease(provider);
415 if (!cgmask)
417 WARN("failed to create mask image\n");
418 CGImageRelease(cgimage);
419 return NULL;
422 cgmasked = CGImageCreateWithMask(cgimage, cgmask);
423 CGImageRelease(cgimage);
424 CGImageRelease(cgmask);
425 if (!cgmasked)
427 WARN("failed to create masked image\n");
428 return NULL;
431 hot_spot = CGPointMake(icon->xHotspot, icon->yHotspot);
432 hot_spot_dict = CGPointCreateDictionaryRepresentation(hot_spot);
433 if (!hot_spot_dict)
435 WARN("failed to create hot spot dictionary\n");
436 CGImageRelease(cgmasked);
437 return NULL;
440 values[0] = cgmasked;
441 values[1] = hot_spot_dict;
442 frame = CFDictionaryCreate(NULL, (const void**)keys, values, ARRAY_SIZE(keys),
443 &kCFCopyStringDictionaryKeyCallBacks,
444 &kCFTypeDictionaryValueCallBacks);
445 CFRelease(hot_spot_dict);
446 CGImageRelease(cgmasked);
447 if (!frame)
449 WARN("failed to create frame dictionary\n");
450 return NULL;
453 frames = CFArrayCreate(NULL, (const void**)&frame, 1, &kCFTypeArrayCallBacks);
454 CFRelease(frame);
455 if (!frames)
457 WARN("failed to create frames array\n");
458 return NULL;
461 return frames;
465 /***********************************************************************
466 * create_cursor_frame
468 * Create a frame dictionary for a cursor from a Windows icon.
469 * Keys:
470 * "image" a CGImage for the frame
471 * "duration" a CFNumber for the frame duration in seconds
472 * "hotSpot" a CFDictionary encoding a CGPoint for the hot spot
474 static CFDictionaryRef create_cursor_frame(HDC hdc, const ICONINFOEXW *iinfo, HANDLE icon,
475 HBITMAP hbmColor, unsigned char *color_bits, int color_size,
476 HBITMAP hbmMask, unsigned char *mask_bits, int mask_size,
477 int width, int height, int istep)
479 DWORD delay_jiffies, num_steps;
480 CFMutableDictionaryRef frame;
481 CGPoint hot_spot;
482 CFDictionaryRef hot_spot_dict;
483 double duration;
484 CFNumberRef duration_number;
485 CGImageRef cgimage;
487 TRACE("hdc %p iinfo->xHotspot %d iinfo->yHotspot %d icon %p hbmColor %p color_bits %p color_size %d"
488 " hbmMask %p mask_bits %p mask_size %d width %d height %d istep %d\n",
489 hdc, iinfo->xHotspot, iinfo->yHotspot, icon, hbmColor, color_bits, color_size,
490 hbmMask, mask_bits, mask_size, width, height, istep);
492 frame = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks,
493 &kCFTypeDictionaryValueCallBacks);
494 if (!frame)
496 WARN("failed to allocate dictionary for frame\n");
497 return NULL;
500 hot_spot = CGPointMake(iinfo->xHotspot, iinfo->yHotspot);
501 hot_spot_dict = CGPointCreateDictionaryRepresentation(hot_spot);
502 if (!hot_spot_dict)
504 WARN("failed to create hot spot dictionary\n");
505 CFRelease(frame);
506 return NULL;
508 CFDictionarySetValue(frame, CFSTR("hotSpot"), hot_spot_dict);
509 CFRelease(hot_spot_dict);
511 if (GetCursorFrameInfo(icon, 0x0 /* unknown parameter */, istep, &delay_jiffies, &num_steps) != 0)
512 duration = delay_jiffies / 60.0; /* convert jiffies (1/60s) to seconds */
513 else
515 WARN("Failed to retrieve animated cursor frame-rate for frame %d.\n", istep);
516 duration = 0.1; /* fallback delay, 100 ms */
518 duration_number = CFNumberCreate(NULL, kCFNumberDoubleType, &duration);
519 if (!duration_number)
521 WARN("failed to create duration number\n");
522 CFRelease(frame);
523 return NULL;
525 CFDictionarySetValue(frame, CFSTR("duration"), duration_number);
526 CFRelease(duration_number);
528 cgimage = create_cgimage_from_icon_bitmaps(hdc, icon, hbmColor, color_bits, color_size,
529 hbmMask, mask_bits, mask_size, width, height, istep);
530 if (!cgimage)
532 CFRelease(frame);
533 return NULL;
536 CFDictionarySetValue(frame, CFSTR("image"), cgimage);
537 CGImageRelease(cgimage);
539 return frame;
543 /***********************************************************************
544 * create_color_cursor
546 * Create an array of color cursor frames from a Windows cursor. Each
547 * frame is represented in the array by a dictionary.
548 * Frame dictionary keys:
549 * "image" a CGImage for the frame
550 * "duration" a CFNumber for the frame duration in seconds
551 * "hotSpot" a CFDictionary encoding a CGPoint for the hot spot
553 static CFArrayRef create_color_cursor(HDC hdc, const ICONINFOEXW *iinfo, HANDLE icon, int width, int height)
555 unsigned char *color_bits, *mask_bits;
556 HBITMAP hbmColor = 0, hbmMask = 0;
557 DWORD nFrames, delay_jiffies, i;
558 int color_size, mask_size;
559 BITMAPINFO *info = NULL;
560 CFMutableArrayRef frames;
562 TRACE("hdc %p iinfo %p icon %p width %d height %d\n", hdc, iinfo, icon, width, height);
564 /* Retrieve the number of frames to render */
565 if (!GetCursorFrameInfo(icon, 0x0 /* unknown parameter */, 0, &delay_jiffies, &nFrames))
567 WARN("GetCursorFrameInfo failed\n");
568 return NULL;
570 if (!(frames = CFArrayCreateMutable(NULL, nFrames, &kCFTypeArrayCallBacks)))
572 WARN("failed to allocate frames array\n");
573 return NULL;
576 /* Allocate all of the resources necessary to obtain a cursor frame */
577 if (!(info = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(BITMAPINFO, bmiColors[256])))) goto cleanup;
578 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
579 info->bmiHeader.biWidth = width;
580 info->bmiHeader.biHeight = -height;
581 info->bmiHeader.biPlanes = 1;
582 info->bmiHeader.biCompression = BI_RGB;
583 info->bmiHeader.biXPelsPerMeter = 0;
584 info->bmiHeader.biYPelsPerMeter = 0;
585 info->bmiHeader.biClrUsed = 0;
586 info->bmiHeader.biClrImportant = 0;
587 info->bmiHeader.biBitCount = 32;
588 color_size = width * height * 4;
589 info->bmiHeader.biSizeImage = color_size;
590 hbmColor = CreateDIBSection(hdc, info, DIB_RGB_COLORS, (VOID **) &color_bits, NULL, 0);
591 if (!hbmColor)
593 WARN("failed to create DIB section for cursor color data\n");
594 goto cleanup;
596 info->bmiHeader.biBitCount = 1;
597 info->bmiColors[0].rgbRed = 0;
598 info->bmiColors[0].rgbGreen = 0;
599 info->bmiColors[0].rgbBlue = 0;
600 info->bmiColors[0].rgbReserved = 0;
601 info->bmiColors[1].rgbRed = 0xff;
602 info->bmiColors[1].rgbGreen = 0xff;
603 info->bmiColors[1].rgbBlue = 0xff;
604 info->bmiColors[1].rgbReserved = 0;
606 mask_size = ((width + 31) / 32 * 4) * height; /* width_bytes * height */
607 info->bmiHeader.biSizeImage = mask_size;
608 hbmMask = CreateDIBSection(hdc, info, DIB_RGB_COLORS, (VOID **) &mask_bits, NULL, 0);
609 if (!hbmMask)
611 WARN("failed to create DIB section for cursor mask data\n");
612 goto cleanup;
615 /* Create a CFDictionary for each frame of the cursor */
616 for (i = 0; i < nFrames; i++)
618 CFDictionaryRef frame = create_cursor_frame(hdc, iinfo, icon,
619 hbmColor, color_bits, color_size,
620 hbmMask, mask_bits, mask_size,
621 width, height, i);
622 if (!frame) goto cleanup;
623 CFArrayAppendValue(frames, frame);
624 CFRelease(frame);
627 cleanup:
628 if (CFArrayGetCount(frames) < nFrames)
630 CFRelease(frames);
631 frames = NULL;
633 else
634 TRACE("returning cursor with %d frames\n", nFrames);
635 /* Cleanup all of the resources used to obtain the frame data */
636 if (hbmColor) DeleteObject(hbmColor);
637 if (hbmMask) DeleteObject(hbmMask);
638 HeapFree(GetProcessHeap(), 0, info);
639 return frames;
643 /***********************************************************************
644 * DestroyCursorIcon (MACDRV.@)
646 void CDECL macdrv_DestroyCursorIcon(HCURSOR cursor)
648 TRACE("cursor %p\n", cursor);
650 EnterCriticalSection(&cursor_cache_section);
651 if (cursor_cache)
652 CFDictionaryRemoveValue(cursor_cache, cursor);
653 LeaveCriticalSection(&cursor_cache_section);
657 /***********************************************************************
658 * ClipCursor (MACDRV.@)
660 * Set the cursor clipping rectangle.
662 BOOL CDECL macdrv_ClipCursor(LPCRECT clip)
664 CGRect rect;
666 TRACE("%s\n", wine_dbgstr_rect(clip));
668 if (clip)
670 rect = CGRectMake(clip->left, clip->top, max(1, clip->right - clip->left),
671 max(1, clip->bottom - clip->top));
673 else
674 rect = CGRectInfinite;
676 /* FIXME: This needs to be done not just in this process but in all of the
677 ones for this WINEPREFIX. Broadcast a message to do that. */
679 return macdrv_clip_cursor(rect);
683 /***********************************************************************
684 * GetCursorPos (MACDRV.@)
686 BOOL CDECL macdrv_GetCursorPos(LPPOINT pos)
688 CGPoint pt;
689 BOOL ret;
691 ret = macdrv_get_cursor_position(&pt);
692 if (ret)
694 TRACE("pointer at (%g,%g) server pos %d,%d\n", pt.x, pt.y, pos->x, pos->y);
695 pos->x = floor(pt.x);
696 pos->y = floor(pt.y);
698 return ret;
702 /***********************************************************************
703 * SetCapture (MACDRV.@)
705 void CDECL macdrv_SetCapture(HWND hwnd, UINT flags)
707 struct macdrv_thread_data *thread_data = macdrv_thread_data();
708 HWND top = GetAncestor(hwnd, GA_ROOT);
709 macdrv_window cocoa_window = macdrv_get_cocoa_window(top, FALSE);
711 TRACE("hwnd %p top %p/%p flags 0x%08x\n", hwnd, top, cocoa_window, flags);
713 if (!thread_data) return;
715 thread_data->capture_window = cocoa_window;
716 macdrv_set_mouse_capture_window(cocoa_window);
720 /***********************************************************************
721 * SetCursor (MACDRV.@)
723 void CDECL macdrv_SetCursor(HCURSOR cursor)
725 CFStringRef cursor_name = NULL;
726 CFArrayRef cursor_frames = NULL;
728 TRACE("%p\n", cursor);
730 if (cursor)
732 ICONINFOEXW info;
734 EnterCriticalSection(&cursor_cache_section);
735 if (cursor_cache)
737 CFTypeRef cached_cursor = CFDictionaryGetValue(cursor_cache, cursor);
738 if (cached_cursor)
740 if (CFGetTypeID(cached_cursor) == CFStringGetTypeID())
741 cursor_name = CFRetain(cached_cursor);
742 else
743 cursor_frames = CFRetain(cached_cursor);
746 LeaveCriticalSection(&cursor_cache_section);
747 if (cursor_name || cursor_frames)
748 goto done;
750 info.cbSize = sizeof(info);
751 if (!GetIconInfoExW(cursor, &info))
753 WARN("GetIconInfoExW failed\n");
754 return;
757 if ((cursor_name = copy_system_cursor_name(&info)))
759 DeleteObject(info.hbmColor);
760 DeleteObject(info.hbmMask);
762 else
764 BITMAP bm;
765 HDC hdc;
767 GetObjectW(info.hbmMask, sizeof(bm), &bm);
768 if (!info.hbmColor) bm.bmHeight = max(1, bm.bmHeight / 2);
770 /* make sure hotspot is valid */
771 if (info.xHotspot >= bm.bmWidth || info.yHotspot >= bm.bmHeight)
773 info.xHotspot = bm.bmWidth / 2;
774 info.yHotspot = bm.bmHeight / 2;
777 hdc = CreateCompatibleDC(0);
779 if (info.hbmColor)
781 cursor_frames = create_color_cursor(hdc, &info, cursor, bm.bmWidth, bm.bmHeight);
782 DeleteObject(info.hbmColor);
784 else
785 cursor_frames = create_monochrome_cursor(hdc, &info, bm.bmWidth, bm.bmHeight);
787 DeleteObject(info.hbmMask);
788 DeleteDC(hdc);
791 if (cursor_name || cursor_frames)
793 EnterCriticalSection(&cursor_cache_section);
794 if (!cursor_cache)
795 cursor_cache = CFDictionaryCreateMutable(NULL, 0, NULL,
796 &kCFTypeDictionaryValueCallBacks);
797 CFDictionarySetValue(cursor_cache, cursor,
798 cursor_name ? (CFTypeRef)cursor_name : (CFTypeRef)cursor_frames);
799 LeaveCriticalSection(&cursor_cache_section);
801 else
802 cursor_name = CFRetain(CFSTR("arrowCursor"));
805 done:
806 TRACE("setting cursor with cursor_name %s cursor_frames %p\n", debugstr_cf(cursor_name), cursor_frames);
807 macdrv_set_cursor(cursor_name, cursor_frames);
808 if (cursor_name) CFRelease(cursor_name);
809 if (cursor_frames) CFRelease(cursor_frames);
813 /***********************************************************************
814 * SetCursorPos (MACDRV.@)
816 BOOL CDECL macdrv_SetCursorPos(INT x, INT y)
818 BOOL ret = macdrv_set_cursor_position(CGPointMake(x, y));
819 if (ret)
820 TRACE("warped to %d,%d\n", x, y);
821 else
822 ERR("failed to warp to %d,%d\n", x, y);
823 return ret;
827 /***********************************************************************
828 * macdrv_mouse_button
830 * Handler for MOUSE_BUTTON events.
832 void macdrv_mouse_button(HWND hwnd, const macdrv_event *event)
834 UINT flags = 0;
835 WORD data = 0;
837 TRACE("win %p button %d %s at (%d,%d) time %lu (%lu ticks ago)\n", hwnd, event->mouse_button.button,
838 (event->mouse_button.pressed ? "pressed" : "released"),
839 event->mouse_button.x, event->mouse_button.y,
840 event->mouse_button.time_ms, (GetTickCount() - event->mouse_button.time_ms));
842 if (event->mouse_button.pressed)
844 switch (event->mouse_button.button)
846 case 0: flags |= MOUSEEVENTF_LEFTDOWN; break;
847 case 1: flags |= MOUSEEVENTF_RIGHTDOWN; break;
848 case 2: flags |= MOUSEEVENTF_MIDDLEDOWN; break;
849 default:
850 flags |= MOUSEEVENTF_XDOWN;
851 data = 1 << (event->mouse_button.button - 3);
852 break;
855 else
857 switch (event->mouse_button.button)
859 case 0: flags |= MOUSEEVENTF_LEFTUP; break;
860 case 1: flags |= MOUSEEVENTF_RIGHTUP; break;
861 case 2: flags |= MOUSEEVENTF_MIDDLEUP; break;
862 default:
863 flags |= MOUSEEVENTF_XUP;
864 data = 1 << (event->mouse_button.button - 3);
865 break;
869 send_mouse_input(hwnd, event->window, flags | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
870 event->mouse_button.x, event->mouse_button.y,
871 data, FALSE, event->mouse_button.time_ms);
875 /***********************************************************************
876 * macdrv_mouse_moved
878 * Handler for MOUSE_MOVED and MOUSE_MOVED_ABSOLUTE events.
880 void macdrv_mouse_moved(HWND hwnd, const macdrv_event *event)
882 UINT flags = MOUSEEVENTF_MOVE;
884 TRACE("win %p/%p %s (%d,%d) drag %d time %lu (%lu ticks ago)\n", hwnd, event->window,
885 (event->type == MOUSE_MOVED) ? "relative" : "absolute",
886 event->mouse_moved.x, event->mouse_moved.y, event->mouse_moved.drag,
887 event->mouse_moved.time_ms, (GetTickCount() - event->mouse_moved.time_ms));
889 if (event->type == MOUSE_MOVED_ABSOLUTE)
890 flags |= MOUSEEVENTF_ABSOLUTE;
892 send_mouse_input(hwnd, event->window, flags, event->mouse_moved.x, event->mouse_moved.y,
893 0, event->mouse_moved.drag, event->mouse_moved.time_ms);
897 /***********************************************************************
898 * macdrv_mouse_scroll
900 * Handler for MOUSE_SCROLL events.
902 void macdrv_mouse_scroll(HWND hwnd, const macdrv_event *event)
904 TRACE("win %p/%p scroll (%d,%d) at (%d,%d) time %lu (%lu ticks ago)\n", hwnd,
905 event->window, event->mouse_scroll.x_scroll, event->mouse_scroll.y_scroll,
906 event->mouse_scroll.x, event->mouse_scroll.y,
907 event->mouse_scroll.time_ms, (GetTickCount() - event->mouse_scroll.time_ms));
909 if (event->mouse_scroll.y_scroll)
910 send_mouse_input(hwnd, event->window, MOUSEEVENTF_WHEEL | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
911 event->mouse_scroll.x, event->mouse_scroll.y,
912 event->mouse_scroll.y_scroll, FALSE, event->mouse_scroll.time_ms);
913 if (event->mouse_scroll.x_scroll)
914 send_mouse_input(hwnd, event->window, MOUSEEVENTF_HWHEEL | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
915 event->mouse_scroll.x, event->mouse_scroll.y,
916 event->mouse_scroll.x_scroll, FALSE, event->mouse_scroll.time_ms);
920 /***********************************************************************
921 * macdrv_release_capture
923 * Handler for RELEASE_CAPTURE events.
925 void macdrv_release_capture(HWND hwnd, const macdrv_event *event)
927 struct macdrv_thread_data *thread_data = macdrv_thread_data();
928 HWND capture = GetCapture();
929 HWND capture_top = GetAncestor(capture, GA_ROOT);
931 TRACE("win %p/%p thread_data->capture_window %p GetCapture() %p in %p\n", hwnd,
932 event->window, thread_data->capture_window, capture, capture_top);
934 if (event->window == thread_data->capture_window && hwnd == capture_top)
936 ReleaseCapture();
937 if (!PostMessageW(capture, WM_CANCELMODE, 0, 0))
938 WARN("failed to post WM_CANCELMODE; error 0x%08x\n", GetLastError());