dxdiagn: Remove DECLSPEC_HIDDEN usage.
[wine.git] / dlls / winemac.drv / mouse.c
blob5c04c71e1dc9c1934a5adc84b058a72bea91c58e
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 #if 0
24 #pragma makedep unix
25 #endif
27 #include "config.h"
29 #define OEMRESOURCE
30 #include "macdrv.h"
31 #include "wine/server.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(cursor);
36 static pthread_mutex_t cursor_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
37 static CFMutableDictionaryRef cursor_cache;
40 struct system_cursors
42 WORD id;
43 CFStringRef name;
46 static const struct system_cursors user32_cursors[] =
48 { OCR_NORMAL, CFSTR("arrowCursor") },
49 { OCR_IBEAM, CFSTR("IBeamCursor") },
50 { OCR_CROSS, CFSTR("crosshairCursor") },
51 { OCR_SIZEWE, CFSTR("resizeLeftRightCursor") },
52 { OCR_SIZENS, CFSTR("resizeUpDownCursor") },
53 { OCR_NO, CFSTR("operationNotAllowedCursor") },
54 { OCR_HAND, CFSTR("pointingHandCursor") },
55 { 0 }
58 static const struct system_cursors comctl32_cursors[] =
60 { 102, CFSTR("closedHandCursor") },
61 { 104, CFSTR("dragCopyCursor") },
62 { 105, CFSTR("arrowCursor") },
63 { 106, CFSTR("resizeLeftRightCursor") },
64 { 107, CFSTR("resizeLeftRightCursor") },
65 { 108, CFSTR("pointingHandCursor") },
66 { 135, CFSTR("resizeUpDownCursor") },
67 { 0 }
70 static const struct system_cursors ole32_cursors[] =
72 { 1, CFSTR("operationNotAllowedCursor") },
73 { 2, CFSTR("closedHandCursor") },
74 { 3, CFSTR("dragCopyCursor") },
75 { 4, CFSTR("dragLinkCursor") },
76 { 0 }
79 static const struct system_cursors riched20_cursors[] =
81 { 105, CFSTR("pointingHandCursor") },
82 { 109, CFSTR("dragCopyCursor") },
83 { 110, CFSTR("closedHandCursor") },
84 { 111, CFSTR("operationNotAllowedCursor") },
85 { 0 }
88 static const struct
90 const struct system_cursors *cursors;
91 WCHAR name[16];
92 } module_cursors[] =
94 { user32_cursors, {'u','s','e','r','3','2','.','d','l','l',0} },
95 { comctl32_cursors, {'c','o','m','c','t','l','3','2','.','d','l','l',0} },
96 { ole32_cursors, {'o','l','e','3','2','.','d','l','l',0} },
97 { riched20_cursors, {'r','i','c','h','e','d','2','0','.','d','l','l',0} }
100 /* The names of NSCursor class methods which return cursor objects. */
101 static const CFStringRef cocoa_cursor_names[] =
103 CFSTR("arrowCursor"),
104 CFSTR("closedHandCursor"),
105 CFSTR("contextualMenuCursor"),
106 CFSTR("crosshairCursor"),
107 CFSTR("disappearingItemCursor"),
108 CFSTR("dragCopyCursor"),
109 CFSTR("dragLinkCursor"),
110 CFSTR("IBeamCursor"),
111 CFSTR("IBeamCursorForVerticalLayout"),
112 CFSTR("openHandCursor"),
113 CFSTR("operationNotAllowedCursor"),
114 CFSTR("pointingHandCursor"),
115 CFSTR("resizeDownCursor"),
116 CFSTR("resizeLeftCursor"),
117 CFSTR("resizeLeftRightCursor"),
118 CFSTR("resizeRightCursor"),
119 CFSTR("resizeUpCursor"),
120 CFSTR("resizeUpDownCursor"),
124 /***********************************************************************
125 * send_mouse_input
127 * Update the various window states on a mouse event.
129 static void send_mouse_input(HWND hwnd, macdrv_window cocoa_window, UINT flags, int x, int y,
130 DWORD mouse_data, BOOL drag, unsigned long time)
132 INPUT input;
133 HWND top_level_hwnd;
135 top_level_hwnd = NtUserGetAncestor(hwnd, GA_ROOT);
137 if ((flags & MOUSEEVENTF_MOVE) && (flags & MOUSEEVENTF_ABSOLUTE) && !drag &&
138 cocoa_window != macdrv_thread_data()->capture_window)
140 /* update the wine server Z-order */
141 SERVER_START_REQ(update_window_zorder)
143 req->window = wine_server_user_handle(top_level_hwnd);
144 req->rect.left = x;
145 req->rect.top = y;
146 req->rect.right = x + 1;
147 req->rect.bottom = y + 1;
148 wine_server_call(req);
150 SERVER_END_REQ;
153 input.type = INPUT_MOUSE;
154 input.mi.dx = x;
155 input.mi.dy = y;
156 input.mi.mouseData = mouse_data;
157 input.mi.dwFlags = flags;
158 input.mi.time = time;
159 input.mi.dwExtraInfo = 0;
161 __wine_send_input(top_level_hwnd, &input, NULL);
165 /***********************************************************************
166 * copy_system_cursor_name
168 CFStringRef copy_system_cursor_name(ICONINFOEXW *info)
170 const struct system_cursors *cursors;
171 unsigned int i;
172 CFStringRef cursor_name = NULL;
173 const WCHAR *module;
174 HKEY key;
175 WCHAR *p, name[MAX_PATH * 2];
177 TRACE("info->szModName %s info->szResName %s info->wResID %hu\n", debugstr_w(info->szModName),
178 debugstr_w(info->szResName), info->wResID);
180 if (!info->szModName[0]) return NULL;
182 p = wcsrchr(info->szModName, '\\');
183 wcscpy(name, p ? p + 1 : info->szModName);
184 p = name + wcslen(name);
185 *p++ = ',';
186 if (info->szResName[0]) wcscpy(p, info->szResName);
187 else
189 char buf[16];
190 sprintf(buf, "%hu", info->wResID);
191 asciiz_to_unicode(p, buf);
194 /* @@ Wine registry key: HKCU\Software\Wine\Mac Driver\Cursors */
195 if (!(key = open_hkcu_key("Software\\Wine\\Mac Driver\\Cursors")))
197 char buffer[2048];
198 KEY_VALUE_PARTIAL_INFORMATION *info = (void *)buffer;
199 DWORD ret;
201 ret = query_reg_value(key, name, info, sizeof(buffer));
202 NtClose(key);
203 if (ret)
205 const WCHAR *value = (const WCHAR *)info->Data;
206 if (!value[0])
208 TRACE("registry forces standard cursor for %s\n", debugstr_w(name));
209 return NULL; /* force standard cursor */
212 cursor_name = CFStringCreateWithCharacters(NULL, value, wcslen(value));
213 if (!cursor_name)
215 WARN("CFStringCreateWithCharacters failed for %s\n", debugstr_w(value));
216 return NULL;
219 /* Make sure it's one of the appropriate NSCursor class methods. */
220 for (i = 0; i < ARRAY_SIZE(cocoa_cursor_names); i++)
221 if (CFEqual(cursor_name, cocoa_cursor_names[i]))
222 goto done;
224 WARN("%s mapped to invalid Cocoa cursor name %s\n", debugstr_w(name), debugstr_w(value));
225 CFRelease(cursor_name);
226 return NULL;
230 if (info->szResName[0]) goto done; /* only integer resources are supported here */
232 if ((module = wcsrchr(info->szModName, '\\'))) module++;
233 else module = info->szModName;
234 for (i = 0; i < ARRAY_SIZE( module_cursors ); i++)
235 if (!wcsicmp(module, module_cursors[i].name)) break;
236 if (i == ARRAY_SIZE(module_cursors)) goto done;
238 cursors = module_cursors[i].cursors;
239 for (i = 0; cursors[i].id; i++)
240 if (cursors[i].id == info->wResID)
242 cursor_name = CFRetain(cursors[i].name);
243 break;
246 done:
247 if (cursor_name)
248 TRACE("%s -> %s\n", debugstr_w(name), debugstr_cf(cursor_name));
249 else
250 WARN("no system cursor found for %s\n", debugstr_w(name));
251 return cursor_name;
254 /***********************************************************************
255 * create_monochrome_cursor
257 CFArrayRef create_monochrome_cursor(HDC hdc, const ICONINFOEXW *icon, int width, int height)
259 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
260 BITMAPINFO *info = (BITMAPINFO *)buffer;
261 unsigned int width_bytes = (width + 31) / 32 * 4;
262 unsigned long *and_bits = NULL, *xor_bits;
263 unsigned long *data_bits;
264 int count, i;
265 CGColorSpaceRef colorspace;
266 CFMutableDataRef data;
267 CGDataProviderRef provider;
268 CGImageRef cgimage, cgmask, cgmasked;
269 CGPoint hot_spot;
270 CFDictionaryRef hot_spot_dict;
271 const CFStringRef keys[] = { CFSTR("image"), CFSTR("hotSpot") };
272 CFTypeRef values[ARRAY_SIZE(keys)];
273 CFDictionaryRef frame;
274 CFArrayRef frames;
276 TRACE("hdc %p icon->hbmMask %p icon->xHotspot %d icon->yHotspot %d width %d height %d\n",
277 hdc, icon->hbmMask, (int)icon->xHotspot, (int)icon->yHotspot, width, height);
279 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
280 info->bmiHeader.biWidth = width;
281 info->bmiHeader.biHeight = -height * 2;
282 info->bmiHeader.biPlanes = 1;
283 info->bmiHeader.biBitCount = 1;
284 info->bmiHeader.biCompression = BI_RGB;
285 info->bmiHeader.biSizeImage = width_bytes * height * 2;
286 info->bmiHeader.biXPelsPerMeter = 0;
287 info->bmiHeader.biYPelsPerMeter = 0;
288 info->bmiHeader.biClrUsed = 0;
289 info->bmiHeader.biClrImportant = 0;
291 and_bits = malloc(info->bmiHeader.biSizeImage);
292 if (!and_bits)
294 WARN("failed to allocate and_bits\n");
295 return NULL;
297 xor_bits = (unsigned long*)((char*)and_bits + info->bmiHeader.biSizeImage / 2);
299 if (!NtGdiGetDIBitsInternal(hdc, icon->hbmMask, 0, height * 2, and_bits, info, DIB_RGB_COLORS, 0, 0))
301 WARN("GetDIBits failed\n");
302 free(and_bits);
303 return NULL;
306 /* On Windows, the pixels of a monochrome cursor can have four effects:
307 draw black, draw white, leave unchanged (transparent), or invert. The Mac
308 only supports the first three. It can't do pixels which invert the
309 background. Since the background is usually white, I am arbitrarily
310 mapping "invert" to "draw black". This entails bitwise math between the
311 cursor's AND mask and XOR mask:
313 AND | XOR | Windows cursor pixel
314 --------------------------------
315 0 | 0 | black
316 0 | 1 | white
317 1 | 0 | transparent
318 1 | 1 | invert
320 AND | XOR | Mac image
321 ---------------------
322 0 | 0 | black (0)
323 0 | 1 | white (1)
324 1 | 0 | don't care
325 1 | 1 | black (0)
327 AND | XOR | Mac mask
328 ---------------------------
329 0 | 0 | paint (0)
330 0 | 1 | paint (0)
331 1 | 0 | don't paint (1)
332 1 | 1 | paint (0)
334 So, Mac image = AND ^ XOR and Mac mask = AND & ~XOR.
336 /* Create data for Mac image. */
337 data = CFDataCreateMutable(NULL, info->bmiHeader.biSizeImage / 2);
338 if (!data)
340 WARN("failed to create data\n");
341 free(and_bits);
342 return NULL;
345 /* image data = AND mask */
346 CFDataAppendBytes(data, (UInt8*)and_bits, info->bmiHeader.biSizeImage / 2);
347 /* image data ^= XOR mask */
348 data_bits = (unsigned long*)CFDataGetMutableBytePtr(data);
349 count = (info->bmiHeader.biSizeImage / 2) / sizeof(*data_bits);
350 for (i = 0; i < count; i++)
351 data_bits[i] ^= xor_bits[i];
353 colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGrayGamma2_2);
354 if (!colorspace)
356 WARN("failed to create colorspace\n");
357 CFRelease(data);
358 free(and_bits);
359 return NULL;
362 provider = CGDataProviderCreateWithCFData(data);
363 CFRelease(data);
364 if (!provider)
366 WARN("failed to create data provider\n");
367 CGColorSpaceRelease(colorspace);
368 free(and_bits);
369 return NULL;
372 cgimage = CGImageCreate(width, height, 1, 1, width_bytes, colorspace,
373 kCGImageAlphaNone | kCGBitmapByteOrderDefault,
374 provider, NULL, FALSE, kCGRenderingIntentDefault);
375 CGDataProviderRelease(provider);
376 CGColorSpaceRelease(colorspace);
377 if (!cgimage)
379 WARN("failed to create image\n");
380 free(and_bits);
381 return NULL;
384 /* Create data for mask. */
385 data = CFDataCreateMutable(NULL, info->bmiHeader.biSizeImage / 2);
386 if (!data)
388 WARN("failed to create data\n");
389 CGImageRelease(cgimage);
390 free(and_bits);
391 return NULL;
394 /* mask data = AND mask */
395 CFDataAppendBytes(data, (UInt8*)and_bits, info->bmiHeader.biSizeImage / 2);
396 /* mask data &= ~XOR mask */
397 data_bits = (unsigned long*)CFDataGetMutableBytePtr(data);
398 for (i = 0; i < count; i++)
399 data_bits[i] &= ~xor_bits[i];
400 free(and_bits);
402 provider = CGDataProviderCreateWithCFData(data);
403 CFRelease(data);
404 if (!provider)
406 WARN("failed to create data provider\n");
407 CGImageRelease(cgimage);
408 return NULL;
411 cgmask = CGImageMaskCreate(width, height, 1, 1, width_bytes, provider, NULL, FALSE);
412 CGDataProviderRelease(provider);
413 if (!cgmask)
415 WARN("failed to create mask image\n");
416 CGImageRelease(cgimage);
417 return NULL;
420 cgmasked = CGImageCreateWithMask(cgimage, cgmask);
421 CGImageRelease(cgimage);
422 CGImageRelease(cgmask);
423 if (!cgmasked)
425 WARN("failed to create masked image\n");
426 return NULL;
429 hot_spot = CGPointMake(icon->xHotspot, icon->yHotspot);
430 hot_spot_dict = CGPointCreateDictionaryRepresentation(hot_spot);
431 if (!hot_spot_dict)
433 WARN("failed to create hot spot dictionary\n");
434 CGImageRelease(cgmasked);
435 return NULL;
438 values[0] = cgmasked;
439 values[1] = hot_spot_dict;
440 frame = CFDictionaryCreate(NULL, (const void**)keys, values, ARRAY_SIZE(keys),
441 &kCFCopyStringDictionaryKeyCallBacks,
442 &kCFTypeDictionaryValueCallBacks);
443 CFRelease(hot_spot_dict);
444 CGImageRelease(cgmasked);
445 if (!frame)
447 WARN("failed to create frame dictionary\n");
448 return NULL;
451 frames = CFArrayCreate(NULL, (const void**)&frame, 1, &kCFTypeArrayCallBacks);
452 CFRelease(frame);
453 if (!frames)
455 WARN("failed to create frames array\n");
456 return NULL;
459 return frames;
463 /***********************************************************************
464 * create_cursor_frame
466 * Create a frame dictionary for a cursor from a Windows icon.
467 * Keys:
468 * "image" a CGImage for the frame
469 * "duration" a CFNumber for the frame duration in seconds
470 * "hotSpot" a CFDictionary encoding a CGPoint for the hot spot
472 static CFDictionaryRef create_cursor_frame(HDC hdc, const ICONINFOEXW *iinfo, HANDLE icon,
473 HBITMAP hbmColor, unsigned char *color_bits, int color_size,
474 HBITMAP hbmMask, unsigned char *mask_bits, int mask_size,
475 int width, int height, int istep)
477 DWORD delay_jiffies, num_steps;
478 CFMutableDictionaryRef frame;
479 CGPoint hot_spot;
480 CFDictionaryRef hot_spot_dict;
481 double duration;
482 CFNumberRef duration_number;
483 CGImageRef cgimage;
485 TRACE("hdc %p iinfo->xHotspot %d iinfo->yHotspot %d icon %p hbmColor %p color_bits %p color_size %d"
486 " hbmMask %p mask_bits %p mask_size %d width %d height %d istep %d\n",
487 hdc, (int)iinfo->xHotspot, (int)iinfo->yHotspot, icon, hbmColor, color_bits, color_size,
488 hbmMask, mask_bits, mask_size, width, height, istep);
490 frame = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks,
491 &kCFTypeDictionaryValueCallBacks);
492 if (!frame)
494 WARN("failed to allocate dictionary for frame\n");
495 return NULL;
498 hot_spot = CGPointMake(iinfo->xHotspot, iinfo->yHotspot);
499 hot_spot_dict = CGPointCreateDictionaryRepresentation(hot_spot);
500 if (!hot_spot_dict)
502 WARN("failed to create hot spot dictionary\n");
503 CFRelease(frame);
504 return NULL;
506 CFDictionarySetValue(frame, CFSTR("hotSpot"), hot_spot_dict);
507 CFRelease(hot_spot_dict);
509 if (NtUserGetCursorFrameInfo(icon, istep, &delay_jiffies, &num_steps) != 0)
510 duration = delay_jiffies / 60.0; /* convert jiffies (1/60s) to seconds */
511 else
513 WARN("Failed to retrieve animated cursor frame-rate for frame %d.\n", istep);
514 duration = 0.1; /* fallback delay, 100 ms */
516 duration_number = CFNumberCreate(NULL, kCFNumberDoubleType, &duration);
517 if (!duration_number)
519 WARN("failed to create duration number\n");
520 CFRelease(frame);
521 return NULL;
523 CFDictionarySetValue(frame, CFSTR("duration"), duration_number);
524 CFRelease(duration_number);
526 cgimage = create_cgimage_from_icon_bitmaps(hdc, icon, hbmColor, color_bits, color_size,
527 hbmMask, mask_bits, mask_size, width, height, istep);
528 if (!cgimage)
530 CFRelease(frame);
531 return NULL;
534 CFDictionarySetValue(frame, CFSTR("image"), cgimage);
535 CGImageRelease(cgimage);
537 return frame;
541 /***********************************************************************
542 * create_color_cursor
544 * Create an array of color cursor frames from a Windows cursor. Each
545 * frame is represented in the array by a dictionary.
546 * Frame dictionary keys:
547 * "image" a CGImage for the frame
548 * "duration" a CFNumber for the frame duration in seconds
549 * "hotSpot" a CFDictionary encoding a CGPoint for the hot spot
551 static CFArrayRef create_color_cursor(HDC hdc, const ICONINFOEXW *iinfo, HANDLE icon, int width, int height)
553 unsigned char *color_bits, *mask_bits;
554 HBITMAP hbmColor = 0, hbmMask = 0;
555 DWORD nFrames, delay_jiffies, i;
556 int color_size, mask_size;
557 BITMAPINFO *info = NULL;
558 CFMutableArrayRef frames;
560 TRACE("hdc %p iinfo %p icon %p width %d height %d\n", hdc, iinfo, icon, width, height);
562 /* Retrieve the number of frames to render */
563 if (!NtUserGetCursorFrameInfo(icon, 0, &delay_jiffies, &nFrames))
565 WARN("GetCursorFrameInfo failed\n");
566 return NULL;
568 if (!(frames = CFArrayCreateMutable(NULL, nFrames, &kCFTypeArrayCallBacks)))
570 WARN("failed to allocate frames array\n");
571 return NULL;
574 /* Allocate all of the resources necessary to obtain a cursor frame */
575 if (!(info = malloc(FIELD_OFFSET(BITMAPINFO, bmiColors[256])))) goto cleanup;
576 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
577 info->bmiHeader.biWidth = width;
578 info->bmiHeader.biHeight = -height;
579 info->bmiHeader.biPlanes = 1;
580 info->bmiHeader.biCompression = BI_RGB;
581 info->bmiHeader.biXPelsPerMeter = 0;
582 info->bmiHeader.biYPelsPerMeter = 0;
583 info->bmiHeader.biClrUsed = 0;
584 info->bmiHeader.biClrImportant = 0;
585 info->bmiHeader.biBitCount = 32;
586 color_size = width * height * 4;
587 info->bmiHeader.biSizeImage = color_size;
588 hbmColor = NtGdiCreateDIBSection(hdc, NULL, 0, info, DIB_RGB_COLORS,
589 0, 0, 0, (void **)&color_bits);
590 if (!hbmColor)
592 WARN("failed to create DIB section for cursor color data\n");
593 goto cleanup;
595 info->bmiHeader.biBitCount = 1;
596 info->bmiColors[0].rgbRed = 0;
597 info->bmiColors[0].rgbGreen = 0;
598 info->bmiColors[0].rgbBlue = 0;
599 info->bmiColors[0].rgbReserved = 0;
600 info->bmiColors[1].rgbRed = 0xff;
601 info->bmiColors[1].rgbGreen = 0xff;
602 info->bmiColors[1].rgbBlue = 0xff;
603 info->bmiColors[1].rgbReserved = 0;
605 mask_size = ((width + 31) / 32 * 4) * height; /* width_bytes * height */
606 info->bmiHeader.biSizeImage = mask_size;
607 hbmMask = NtGdiCreateDIBSection(hdc, NULL, 0, info, DIB_RGB_COLORS,
608 0, 0, 0, (void **)&mask_bits);
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", (int)nFrames);
635 /* Cleanup all of the resources used to obtain the frame data */
636 if (hbmColor) NtGdiDeleteObjectApp(hbmColor);
637 if (hbmMask) NtGdiDeleteObjectApp(hbmMask);
638 free(info);
639 return frames;
643 /***********************************************************************
644 * DestroyCursorIcon (MACDRV.@)
646 void macdrv_DestroyCursorIcon(HCURSOR cursor)
648 TRACE("cursor %p\n", cursor);
650 pthread_mutex_lock(&cursor_cache_mutex);
651 if (cursor_cache)
652 CFDictionaryRemoveValue(cursor_cache, cursor);
653 pthread_mutex_unlock(&cursor_cache_mutex);
657 /***********************************************************************
658 * ClipCursor (MACDRV.@)
660 * Set the cursor clipping rectangle.
662 BOOL macdrv_ClipCursor(const RECT *clip, BOOL reset)
664 CGRect rect;
666 TRACE("%s %u\n", wine_dbgstr_rect(clip), reset);
668 if (reset) return TRUE;
670 if (clip)
672 rect = CGRectMake(clip->left, clip->top, max(1, clip->right - clip->left),
673 max(1, clip->bottom - clip->top));
675 else
676 rect = CGRectInfinite;
678 /* FIXME: This needs to be done not just in this process but in all of the
679 ones for this WINEPREFIX. Broadcast a message to do that. */
681 return macdrv_clip_cursor(rect);
685 /***********************************************************************
686 * GetCursorPos (MACDRV.@)
688 BOOL macdrv_GetCursorPos(LPPOINT pos)
690 CGPoint pt;
691 BOOL ret;
693 ret = macdrv_get_cursor_position(&pt);
694 if (ret)
696 TRACE("pointer at (%g,%g) server pos %d,%d\n", pt.x, pt.y, (int)pos->x, (int)pos->y);
697 pos->x = floor(pt.x);
698 pos->y = floor(pt.y);
700 return ret;
704 /***********************************************************************
705 * SetCapture (MACDRV.@)
707 void macdrv_SetCapture(HWND hwnd, UINT flags)
709 struct macdrv_thread_data *thread_data = macdrv_thread_data();
710 HWND top = NtUserGetAncestor(hwnd, GA_ROOT);
711 macdrv_window cocoa_window = macdrv_get_cocoa_window(top, FALSE);
713 TRACE("hwnd %p top %p/%p flags 0x%08x\n", hwnd, top, cocoa_window, flags);
715 if (!thread_data) return;
717 thread_data->capture_window = cocoa_window;
718 macdrv_set_mouse_capture_window(cocoa_window);
722 static BOOL get_icon_info(HICON handle, ICONINFOEXW *ret)
724 UNICODE_STRING module, res_name;
725 ICONINFO info;
727 module.Buffer = ret->szModName;
728 module.MaximumLength = sizeof(ret->szModName) - sizeof(WCHAR);
729 res_name.Buffer = ret->szResName;
730 res_name.MaximumLength = sizeof(ret->szResName) - sizeof(WCHAR);
731 if (!NtUserGetIconInfo(handle, &info, &module, &res_name, NULL, 0)) return FALSE;
732 ret->fIcon = info.fIcon;
733 ret->xHotspot = info.xHotspot;
734 ret->yHotspot = info.yHotspot;
735 ret->hbmColor = info.hbmColor;
736 ret->hbmMask = info.hbmMask;
737 ret->wResID = res_name.Length ? 0 : LOWORD(res_name.Buffer);
738 ret->szModName[module.Length] = 0;
739 ret->szResName[res_name.Length] = 0;
740 return TRUE;
744 /***********************************************************************
745 * SetCursor (MACDRV.@)
747 void macdrv_SetCursor(HWND hwnd, HCURSOR cursor)
749 CFStringRef cursor_name = NULL;
750 CFArrayRef cursor_frames = NULL;
752 TRACE("%p %p\n", hwnd, cursor);
754 if (cursor)
756 ICONINFOEXW info;
758 pthread_mutex_lock(&cursor_cache_mutex);
759 if (cursor_cache)
761 CFTypeRef cached_cursor = CFDictionaryGetValue(cursor_cache, cursor);
762 if (cached_cursor)
764 if (CFGetTypeID(cached_cursor) == CFStringGetTypeID())
765 cursor_name = CFRetain(cached_cursor);
766 else
767 cursor_frames = CFRetain(cached_cursor);
770 pthread_mutex_unlock(&cursor_cache_mutex);
771 if (cursor_name || cursor_frames)
772 goto done;
774 info.cbSize = sizeof(info);
775 if (!get_icon_info(cursor, &info))
777 WARN("GetIconInfoExW failed\n");
778 return;
781 if ((cursor_name = copy_system_cursor_name(&info)))
783 NtGdiDeleteObjectApp(info.hbmColor);
784 NtGdiDeleteObjectApp(info.hbmMask);
786 else
788 BITMAP bm;
789 HDC hdc;
791 NtGdiExtGetObjectW(info.hbmMask, sizeof(bm), &bm);
792 if (!info.hbmColor) bm.bmHeight = max(1, bm.bmHeight / 2);
794 /* make sure hotspot is valid */
795 if (info.xHotspot >= bm.bmWidth || info.yHotspot >= bm.bmHeight)
797 info.xHotspot = bm.bmWidth / 2;
798 info.yHotspot = bm.bmHeight / 2;
801 hdc = NtGdiCreateCompatibleDC(0);
803 if (info.hbmColor)
805 cursor_frames = create_color_cursor(hdc, &info, cursor, bm.bmWidth, bm.bmHeight);
806 NtGdiDeleteObjectApp(info.hbmColor);
808 else
809 cursor_frames = create_monochrome_cursor(hdc, &info, bm.bmWidth, bm.bmHeight);
811 NtGdiDeleteObjectApp(info.hbmMask);
812 NtGdiDeleteObjectApp(hdc);
815 if (cursor_name || cursor_frames)
817 pthread_mutex_lock(&cursor_cache_mutex);
818 if (!cursor_cache)
819 cursor_cache = CFDictionaryCreateMutable(NULL, 0, NULL,
820 &kCFTypeDictionaryValueCallBacks);
821 CFDictionarySetValue(cursor_cache, cursor,
822 cursor_name ? (CFTypeRef)cursor_name : (CFTypeRef)cursor_frames);
823 pthread_mutex_unlock(&cursor_cache_mutex);
825 else
826 cursor_name = CFRetain(CFSTR("arrowCursor"));
829 done:
830 TRACE("setting cursor with cursor_name %s cursor_frames %p\n", debugstr_cf(cursor_name), cursor_frames);
831 macdrv_set_cursor(cursor_name, cursor_frames);
832 if (cursor_name) CFRelease(cursor_name);
833 if (cursor_frames) CFRelease(cursor_frames);
837 /***********************************************************************
838 * SetCursorPos (MACDRV.@)
840 BOOL macdrv_SetCursorPos(INT x, INT y)
842 BOOL ret = macdrv_set_cursor_position(CGPointMake(x, y));
843 if (ret)
844 TRACE("warped to %d,%d\n", x, y);
845 else
846 ERR("failed to warp to %d,%d\n", x, y);
847 return ret;
851 /***********************************************************************
852 * macdrv_mouse_button
854 * Handler for MOUSE_BUTTON events.
856 void macdrv_mouse_button(HWND hwnd, const macdrv_event *event)
858 UINT flags = 0;
859 WORD data = 0;
861 TRACE("win %p button %d %s at (%d,%d) time %lu (%lu ticks ago)\n", hwnd, event->mouse_button.button,
862 (event->mouse_button.pressed ? "pressed" : "released"),
863 event->mouse_button.x, event->mouse_button.y,
864 event->mouse_button.time_ms, (NtGetTickCount() - event->mouse_button.time_ms));
866 if (event->mouse_button.pressed)
868 switch (event->mouse_button.button)
870 case 0: flags |= MOUSEEVENTF_LEFTDOWN; break;
871 case 1: flags |= MOUSEEVENTF_RIGHTDOWN; break;
872 case 2: flags |= MOUSEEVENTF_MIDDLEDOWN; break;
873 default:
874 flags |= MOUSEEVENTF_XDOWN;
875 data = 1 << (event->mouse_button.button - 3);
876 break;
879 else
881 switch (event->mouse_button.button)
883 case 0: flags |= MOUSEEVENTF_LEFTUP; break;
884 case 1: flags |= MOUSEEVENTF_RIGHTUP; break;
885 case 2: flags |= MOUSEEVENTF_MIDDLEUP; break;
886 default:
887 flags |= MOUSEEVENTF_XUP;
888 data = 1 << (event->mouse_button.button - 3);
889 break;
893 send_mouse_input(hwnd, event->window, flags | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
894 event->mouse_button.x, event->mouse_button.y,
895 data, FALSE, event->mouse_button.time_ms);
899 /***********************************************************************
900 * macdrv_mouse_moved
902 * Handler for MOUSE_MOVED_RELATIVE and MOUSE_MOVED_ABSOLUTE events.
904 void macdrv_mouse_moved(HWND hwnd, const macdrv_event *event)
906 UINT flags = MOUSEEVENTF_MOVE;
908 TRACE("win %p/%p %s (%d,%d) drag %d time %lu (%lu ticks ago)\n", hwnd, event->window,
909 (event->type == MOUSE_MOVED_RELATIVE) ? "relative" : "absolute",
910 event->mouse_moved.x, event->mouse_moved.y, event->mouse_moved.drag,
911 event->mouse_moved.time_ms, (NtGetTickCount() - event->mouse_moved.time_ms));
913 if (event->type == MOUSE_MOVED_ABSOLUTE)
914 flags |= MOUSEEVENTF_ABSOLUTE;
916 send_mouse_input(hwnd, event->window, flags, event->mouse_moved.x, event->mouse_moved.y,
917 0, event->mouse_moved.drag, event->mouse_moved.time_ms);
921 /***********************************************************************
922 * macdrv_mouse_scroll
924 * Handler for MOUSE_SCROLL events.
926 void macdrv_mouse_scroll(HWND hwnd, const macdrv_event *event)
928 TRACE("win %p/%p scroll (%d,%d) at (%d,%d) time %lu (%lu ticks ago)\n", hwnd,
929 event->window, event->mouse_scroll.x_scroll, event->mouse_scroll.y_scroll,
930 event->mouse_scroll.x, event->mouse_scroll.y,
931 event->mouse_scroll.time_ms, (NtGetTickCount() - event->mouse_scroll.time_ms));
933 if (event->mouse_scroll.y_scroll)
934 send_mouse_input(hwnd, event->window, MOUSEEVENTF_WHEEL | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
935 event->mouse_scroll.x, event->mouse_scroll.y,
936 event->mouse_scroll.y_scroll, FALSE, event->mouse_scroll.time_ms);
937 if (event->mouse_scroll.x_scroll)
938 send_mouse_input(hwnd, event->window, MOUSEEVENTF_HWHEEL | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
939 event->mouse_scroll.x, event->mouse_scroll.y,
940 event->mouse_scroll.x_scroll, FALSE, event->mouse_scroll.time_ms);
944 /***********************************************************************
945 * macdrv_release_capture
947 * Handler for RELEASE_CAPTURE events.
949 void macdrv_release_capture(HWND hwnd, const macdrv_event *event)
951 struct macdrv_thread_data *thread_data = macdrv_thread_data();
952 HWND capture = get_capture();
953 HWND capture_top = NtUserGetAncestor(capture, GA_ROOT);
955 TRACE("win %p/%p thread_data->capture_window %p GetCapture() %p in %p\n", hwnd,
956 event->window, thread_data->capture_window, capture, capture_top);
958 if (event->window == thread_data->capture_window && hwnd == capture_top)
960 NtUserReleaseCapture();
961 if (!NtUserPostMessage(capture, WM_CANCELMODE, 0, 0))
962 WARN("failed to post WM_CANCELMODE; error 0x%08x\n", (unsigned int)RtlGetLastWin32Error());