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
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
;
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") },
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") },
70 static const struct system_cursors ole32_cursors
[] =
72 { 1, CFSTR("operationNotAllowedCursor") },
73 { 2, CFSTR("closedHandCursor") },
74 { 3, CFSTR("dragCopyCursor") },
75 { 4, CFSTR("dragLinkCursor") },
79 static const struct system_cursors riched20_cursors
[] =
81 { 105, CFSTR("pointingHandCursor") },
82 { 109, CFSTR("dragCopyCursor") },
83 { 110, CFSTR("closedHandCursor") },
84 { 111, CFSTR("operationNotAllowedCursor") },
90 const struct system_cursors
*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 /***********************************************************************
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
)
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
);
146 req
->rect
.right
= x
+ 1;
147 req
->rect
.bottom
= y
+ 1;
148 wine_server_call(req
);
153 input
.type
= INPUT_MOUSE
;
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
;
172 CFStringRef cursor_name
= NULL
;
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
);
186 if (info
->szResName
[0]) wcscpy(p
, info
->szResName
);
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")))
198 KEY_VALUE_PARTIAL_INFORMATION
*info
= (void *)buffer
;
201 ret
= query_reg_value(key
, name
, info
, sizeof(buffer
));
205 const WCHAR
*value
= (const WCHAR
*)info
->Data
;
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
));
215 WARN("CFStringCreateWithCharacters failed for %s\n", debugstr_w(value
));
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
]))
224 WARN("%s mapped to invalid Cocoa cursor name %s\n", debugstr_w(name
), debugstr_w(value
));
225 CFRelease(cursor_name
);
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
);
248 TRACE("%s -> %s\n", debugstr_w(name
), debugstr_cf(cursor_name
));
250 WARN("no system cursor found for %s\n", debugstr_w(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
;
265 CGColorSpaceRef colorspace
;
266 CFMutableDataRef data
;
267 CGDataProviderRef provider
;
268 CGImageRef cgimage
, cgmask
, cgmasked
;
270 CFDictionaryRef hot_spot_dict
;
271 const CFStringRef keys
[] = { CFSTR("image"), CFSTR("hotSpot") };
272 CFTypeRef values
[ARRAY_SIZE(keys
)];
273 CFDictionaryRef frame
;
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
);
294 WARN("failed to allocate and_bits\n");
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");
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 --------------------------------
320 AND | XOR | Mac image
321 ---------------------
328 ---------------------------
331 1 | 0 | don't paint (1)
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);
340 WARN("failed to create data\n");
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
);
356 WARN("failed to create colorspace\n");
362 provider
= CGDataProviderCreateWithCFData(data
);
366 WARN("failed to create data provider\n");
367 CGColorSpaceRelease(colorspace
);
372 cgimage
= CGImageCreate(width
, height
, 1, 1, width_bytes
, colorspace
,
373 kCGImageAlphaNone
| kCGBitmapByteOrderDefault
,
374 provider
, NULL
, FALSE
, kCGRenderingIntentDefault
);
375 CGDataProviderRelease(provider
);
376 CGColorSpaceRelease(colorspace
);
379 WARN("failed to create image\n");
384 /* Create data for mask. */
385 data
= CFDataCreateMutable(NULL
, info
->bmiHeader
.biSizeImage
/ 2);
388 WARN("failed to create data\n");
389 CGImageRelease(cgimage
);
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
];
402 provider
= CGDataProviderCreateWithCFData(data
);
406 WARN("failed to create data provider\n");
407 CGImageRelease(cgimage
);
411 cgmask
= CGImageMaskCreate(width
, height
, 1, 1, width_bytes
, provider
, NULL
, FALSE
);
412 CGDataProviderRelease(provider
);
415 WARN("failed to create mask image\n");
416 CGImageRelease(cgimage
);
420 cgmasked
= CGImageCreateWithMask(cgimage
, cgmask
);
421 CGImageRelease(cgimage
);
422 CGImageRelease(cgmask
);
425 WARN("failed to create masked image\n");
429 hot_spot
= CGPointMake(icon
->xHotspot
, icon
->yHotspot
);
430 hot_spot_dict
= CGPointCreateDictionaryRepresentation(hot_spot
);
433 WARN("failed to create hot spot dictionary\n");
434 CGImageRelease(cgmasked
);
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
);
447 WARN("failed to create frame dictionary\n");
451 frames
= CFArrayCreate(NULL
, (const void**)&frame
, 1, &kCFTypeArrayCallBacks
);
455 WARN("failed to create frames array\n");
463 /***********************************************************************
464 * create_cursor_frame
466 * Create a frame dictionary for a cursor from a Windows icon.
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
;
480 CFDictionaryRef hot_spot_dict
;
482 CFNumberRef duration_number
;
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
);
494 WARN("failed to allocate dictionary for frame\n");
498 hot_spot
= CGPointMake(iinfo
->xHotspot
, iinfo
->yHotspot
);
499 hot_spot_dict
= CGPointCreateDictionaryRepresentation(hot_spot
);
502 WARN("failed to create hot spot dictionary\n");
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 */
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");
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
);
534 CFDictionarySetValue(frame
, CFSTR("image"), cgimage
);
535 CGImageRelease(cgimage
);
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");
568 if (!(frames
= CFArrayCreateMutable(NULL
, nFrames
, &kCFTypeArrayCallBacks
)))
570 WARN("failed to allocate frames array\n");
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
);
592 WARN("failed to create DIB section for cursor color data\n");
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
);
611 WARN("failed to create DIB section for cursor mask data\n");
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
,
622 if (!frame
) goto cleanup
;
623 CFArrayAppendValue(frames
, frame
);
628 if (CFArrayGetCount(frames
) < nFrames
)
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
);
643 /***********************************************************************
644 * DestroyCursorIcon (MACDRV.@)
646 void macdrv_DestroyCursorIcon(HCURSOR cursor
)
648 TRACE("cursor %p\n", cursor
);
650 pthread_mutex_lock(&cursor_cache_mutex
);
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(LPCRECT clip
)
666 TRACE("%s\n", wine_dbgstr_rect(clip
));
670 rect
= CGRectMake(clip
->left
, clip
->top
, max(1, clip
->right
- clip
->left
),
671 max(1, clip
->bottom
- clip
->top
));
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
macdrv_GetCursorPos(LPPOINT pos
)
691 ret
= macdrv_get_cursor_position(&pt
);
694 TRACE("pointer at (%g,%g) server pos %d,%d\n", pt
.x
, pt
.y
, (int)pos
->x
, (int)pos
->y
);
695 pos
->x
= floor(pt
.x
);
696 pos
->y
= floor(pt
.y
);
702 /***********************************************************************
703 * SetCapture (MACDRV.@)
705 void macdrv_SetCapture(HWND hwnd
, UINT flags
)
707 struct macdrv_thread_data
*thread_data
= macdrv_thread_data();
708 HWND top
= NtUserGetAncestor(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 static BOOL
get_icon_info(HICON handle
, ICONINFOEXW
*ret
)
722 UNICODE_STRING module
, res_name
;
725 module
.Buffer
= ret
->szModName
;
726 module
.MaximumLength
= sizeof(ret
->szModName
) - sizeof(WCHAR
);
727 res_name
.Buffer
= ret
->szResName
;
728 res_name
.MaximumLength
= sizeof(ret
->szResName
) - sizeof(WCHAR
);
729 if (!NtUserGetIconInfo(handle
, &info
, &module
, &res_name
, NULL
, 0)) return FALSE
;
730 ret
->fIcon
= info
.fIcon
;
731 ret
->xHotspot
= info
.xHotspot
;
732 ret
->yHotspot
= info
.yHotspot
;
733 ret
->hbmColor
= info
.hbmColor
;
734 ret
->hbmMask
= info
.hbmMask
;
735 ret
->wResID
= res_name
.Length
? 0 : LOWORD(res_name
.Buffer
);
736 ret
->szModName
[module
.Length
] = 0;
737 ret
->szResName
[res_name
.Length
] = 0;
742 /***********************************************************************
743 * SetCursor (MACDRV.@)
745 void macdrv_SetCursor(HCURSOR cursor
)
747 CFStringRef cursor_name
= NULL
;
748 CFArrayRef cursor_frames
= NULL
;
750 TRACE("%p\n", cursor
);
756 pthread_mutex_lock(&cursor_cache_mutex
);
759 CFTypeRef cached_cursor
= CFDictionaryGetValue(cursor_cache
, cursor
);
762 if (CFGetTypeID(cached_cursor
) == CFStringGetTypeID())
763 cursor_name
= CFRetain(cached_cursor
);
765 cursor_frames
= CFRetain(cached_cursor
);
768 pthread_mutex_unlock(&cursor_cache_mutex
);
769 if (cursor_name
|| cursor_frames
)
772 info
.cbSize
= sizeof(info
);
773 if (!get_icon_info(cursor
, &info
))
775 WARN("GetIconInfoExW failed\n");
779 if ((cursor_name
= copy_system_cursor_name(&info
)))
781 NtGdiDeleteObjectApp(info
.hbmColor
);
782 NtGdiDeleteObjectApp(info
.hbmMask
);
789 NtGdiExtGetObjectW(info
.hbmMask
, sizeof(bm
), &bm
);
790 if (!info
.hbmColor
) bm
.bmHeight
= max(1, bm
.bmHeight
/ 2);
792 /* make sure hotspot is valid */
793 if (info
.xHotspot
>= bm
.bmWidth
|| info
.yHotspot
>= bm
.bmHeight
)
795 info
.xHotspot
= bm
.bmWidth
/ 2;
796 info
.yHotspot
= bm
.bmHeight
/ 2;
799 hdc
= NtGdiCreateCompatibleDC(0);
803 cursor_frames
= create_color_cursor(hdc
, &info
, cursor
, bm
.bmWidth
, bm
.bmHeight
);
804 NtGdiDeleteObjectApp(info
.hbmColor
);
807 cursor_frames
= create_monochrome_cursor(hdc
, &info
, bm
.bmWidth
, bm
.bmHeight
);
809 NtGdiDeleteObjectApp(info
.hbmMask
);
810 NtGdiDeleteObjectApp(hdc
);
813 if (cursor_name
|| cursor_frames
)
815 pthread_mutex_lock(&cursor_cache_mutex
);
817 cursor_cache
= CFDictionaryCreateMutable(NULL
, 0, NULL
,
818 &kCFTypeDictionaryValueCallBacks
);
819 CFDictionarySetValue(cursor_cache
, cursor
,
820 cursor_name
? (CFTypeRef
)cursor_name
: (CFTypeRef
)cursor_frames
);
821 pthread_mutex_unlock(&cursor_cache_mutex
);
824 cursor_name
= CFRetain(CFSTR("arrowCursor"));
828 TRACE("setting cursor with cursor_name %s cursor_frames %p\n", debugstr_cf(cursor_name
), cursor_frames
);
829 macdrv_set_cursor(cursor_name
, cursor_frames
);
830 if (cursor_name
) CFRelease(cursor_name
);
831 if (cursor_frames
) CFRelease(cursor_frames
);
835 /***********************************************************************
836 * SetCursorPos (MACDRV.@)
838 BOOL
macdrv_SetCursorPos(INT x
, INT y
)
840 BOOL ret
= macdrv_set_cursor_position(CGPointMake(x
, y
));
842 TRACE("warped to %d,%d\n", x
, y
);
844 ERR("failed to warp to %d,%d\n", x
, y
);
849 /***********************************************************************
850 * macdrv_mouse_button
852 * Handler for MOUSE_BUTTON events.
854 void macdrv_mouse_button(HWND hwnd
, const macdrv_event
*event
)
859 TRACE("win %p button %d %s at (%d,%d) time %lu (%lu ticks ago)\n", hwnd
, event
->mouse_button
.button
,
860 (event
->mouse_button
.pressed
? "pressed" : "released"),
861 event
->mouse_button
.x
, event
->mouse_button
.y
,
862 event
->mouse_button
.time_ms
, (NtGetTickCount() - event
->mouse_button
.time_ms
));
864 if (event
->mouse_button
.pressed
)
866 switch (event
->mouse_button
.button
)
868 case 0: flags
|= MOUSEEVENTF_LEFTDOWN
; break;
869 case 1: flags
|= MOUSEEVENTF_RIGHTDOWN
; break;
870 case 2: flags
|= MOUSEEVENTF_MIDDLEDOWN
; break;
872 flags
|= MOUSEEVENTF_XDOWN
;
873 data
= 1 << (event
->mouse_button
.button
- 3);
879 switch (event
->mouse_button
.button
)
881 case 0: flags
|= MOUSEEVENTF_LEFTUP
; break;
882 case 1: flags
|= MOUSEEVENTF_RIGHTUP
; break;
883 case 2: flags
|= MOUSEEVENTF_MIDDLEUP
; break;
885 flags
|= MOUSEEVENTF_XUP
;
886 data
= 1 << (event
->mouse_button
.button
- 3);
891 send_mouse_input(hwnd
, event
->window
, flags
| MOUSEEVENTF_ABSOLUTE
| MOUSEEVENTF_MOVE
,
892 event
->mouse_button
.x
, event
->mouse_button
.y
,
893 data
, FALSE
, event
->mouse_button
.time_ms
);
897 /***********************************************************************
900 * Handler for MOUSE_MOVED_RELATIVE and MOUSE_MOVED_ABSOLUTE events.
902 void macdrv_mouse_moved(HWND hwnd
, const macdrv_event
*event
)
904 UINT flags
= MOUSEEVENTF_MOVE
;
906 TRACE("win %p/%p %s (%d,%d) drag %d time %lu (%lu ticks ago)\n", hwnd
, event
->window
,
907 (event
->type
== MOUSE_MOVED_RELATIVE
) ? "relative" : "absolute",
908 event
->mouse_moved
.x
, event
->mouse_moved
.y
, event
->mouse_moved
.drag
,
909 event
->mouse_moved
.time_ms
, (NtGetTickCount() - event
->mouse_moved
.time_ms
));
911 if (event
->type
== MOUSE_MOVED_ABSOLUTE
)
912 flags
|= MOUSEEVENTF_ABSOLUTE
;
914 send_mouse_input(hwnd
, event
->window
, flags
, event
->mouse_moved
.x
, event
->mouse_moved
.y
,
915 0, event
->mouse_moved
.drag
, event
->mouse_moved
.time_ms
);
919 /***********************************************************************
920 * macdrv_mouse_scroll
922 * Handler for MOUSE_SCROLL events.
924 void macdrv_mouse_scroll(HWND hwnd
, const macdrv_event
*event
)
926 TRACE("win %p/%p scroll (%d,%d) at (%d,%d) time %lu (%lu ticks ago)\n", hwnd
,
927 event
->window
, event
->mouse_scroll
.x_scroll
, event
->mouse_scroll
.y_scroll
,
928 event
->mouse_scroll
.x
, event
->mouse_scroll
.y
,
929 event
->mouse_scroll
.time_ms
, (NtGetTickCount() - event
->mouse_scroll
.time_ms
));
931 if (event
->mouse_scroll
.y_scroll
)
932 send_mouse_input(hwnd
, event
->window
, MOUSEEVENTF_WHEEL
| MOUSEEVENTF_ABSOLUTE
| MOUSEEVENTF_MOVE
,
933 event
->mouse_scroll
.x
, event
->mouse_scroll
.y
,
934 event
->mouse_scroll
.y_scroll
, FALSE
, event
->mouse_scroll
.time_ms
);
935 if (event
->mouse_scroll
.x_scroll
)
936 send_mouse_input(hwnd
, event
->window
, MOUSEEVENTF_HWHEEL
| MOUSEEVENTF_ABSOLUTE
| MOUSEEVENTF_MOVE
,
937 event
->mouse_scroll
.x
, event
->mouse_scroll
.y
,
938 event
->mouse_scroll
.x_scroll
, FALSE
, event
->mouse_scroll
.time_ms
);
942 /***********************************************************************
943 * macdrv_release_capture
945 * Handler for RELEASE_CAPTURE events.
947 void macdrv_release_capture(HWND hwnd
, const macdrv_event
*event
)
949 struct macdrv_thread_data
*thread_data
= macdrv_thread_data();
950 HWND capture
= get_capture();
951 HWND capture_top
= NtUserGetAncestor(capture
, GA_ROOT
);
953 TRACE("win %p/%p thread_data->capture_window %p GetCapture() %p in %p\n", hwnd
,
954 event
->window
, thread_data
->capture_window
, capture
, capture_top
);
956 if (event
->window
== thread_data
->capture_window
&& hwnd
== capture_top
)
958 NtUserReleaseCapture();
959 if (!NtUserPostMessage(capture
, WM_CANCELMODE
, 0, 0))
960 WARN("failed to post WM_CANCELMODE; error 0x%08x\n", (unsigned int)RtlGetLastWin32Error());