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 snprintf(buf
, sizeof(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(const RECT
*clip
, BOOL reset
)
666 TRACE("%s %u\n", wine_dbgstr_rect(clip
), reset
);
668 if (reset
) return TRUE
;
672 rect
= CGRectMake(clip
->left
, clip
->top
, max(1, clip
->right
- clip
->left
),
673 max(1, clip
->bottom
- clip
->top
));
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
)
693 ret
= macdrv_get_cursor_position(&pt
);
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
);
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
;
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;
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
);
758 pthread_mutex_lock(&cursor_cache_mutex
);
761 CFTypeRef cached_cursor
= CFDictionaryGetValue(cursor_cache
, cursor
);
764 if (CFGetTypeID(cached_cursor
) == CFStringGetTypeID())
765 cursor_name
= CFRetain(cached_cursor
);
767 cursor_frames
= CFRetain(cached_cursor
);
770 pthread_mutex_unlock(&cursor_cache_mutex
);
771 if (cursor_name
|| cursor_frames
)
774 info
.cbSize
= sizeof(info
);
775 if (!get_icon_info(cursor
, &info
))
777 WARN("GetIconInfoExW failed\n");
781 if ((cursor_name
= copy_system_cursor_name(&info
)))
783 NtGdiDeleteObjectApp(info
.hbmColor
);
784 NtGdiDeleteObjectApp(info
.hbmMask
);
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);
805 cursor_frames
= create_color_cursor(hdc
, &info
, cursor
, bm
.bmWidth
, bm
.bmHeight
);
806 NtGdiDeleteObjectApp(info
.hbmColor
);
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
);
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
);
826 cursor_name
= CFRetain(CFSTR("arrowCursor"));
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
));
844 TRACE("warped to %d,%d\n", x
, y
);
846 ERR("failed to warp to %d,%d\n", x
, y
);
851 /***********************************************************************
852 * macdrv_mouse_button
854 * Handler for MOUSE_BUTTON events.
856 void macdrv_mouse_button(HWND hwnd
, const macdrv_event
*event
)
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;
874 flags
|= MOUSEEVENTF_XDOWN
;
875 data
= 1 << (event
->mouse_button
.button
- 3);
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;
887 flags
|= MOUSEEVENTF_XUP
;
888 data
= 1 << (event
->mouse_button
.button
- 3);
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 /***********************************************************************
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());