wbemprox: Add a partial implementation of Win32_DiskPartition.
[wine.git] / dlls / winemac.drv / mouse.c
blobcfbb27471ac4838544e30a9f2688412702ebeb64
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, UINT flags, int x, int y,
137 DWORD mouse_data, 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))
146 RECT rect;
148 /* update the wine server Z-order */
149 SetRect(&rect, x, y, x + 1, y + 1);
150 MapWindowPoints(0, top_level_hwnd, (POINT *)&rect, 2);
152 SERVER_START_REQ(update_window_zorder)
154 req->window = wine_server_user_handle(top_level_hwnd);
155 req->rect.left = rect.left;
156 req->rect.top = rect.top;
157 req->rect.right = rect.right;
158 req->rect.bottom = rect.bottom;
159 wine_server_call(req);
161 SERVER_END_REQ;
164 input.type = INPUT_MOUSE;
165 input.mi.dx = x;
166 input.mi.dy = y;
167 input.mi.mouseData = mouse_data;
168 input.mi.dwFlags = flags;
169 input.mi.time = time;
170 input.mi.dwExtraInfo = 0;
172 __wine_send_input(top_level_hwnd, &input);
176 /***********************************************************************
177 * copy_system_cursor_name
179 CFStringRef copy_system_cursor_name(ICONINFOEXW *info)
181 static const WCHAR idW[] = {'%','h','u',0};
182 const struct system_cursors *cursors;
183 unsigned int i;
184 CFStringRef cursor_name = NULL;
185 HMODULE module;
186 HKEY key;
187 WCHAR *p, name[MAX_PATH * 2];
189 TRACE("info->szModName %s info->szResName %s info->wResID %hu\n", debugstr_w(info->szModName),
190 debugstr_w(info->szResName), info->wResID);
192 if (!info->szModName[0]) return NULL;
194 p = strrchrW(info->szModName, '\\');
195 strcpyW(name, p ? p + 1 : info->szModName);
196 p = name + strlenW(name);
197 *p++ = ',';
198 if (info->szResName[0]) strcpyW(p, info->szResName);
199 else sprintfW(p, idW, info->wResID);
201 /* @@ Wine registry key: HKCU\Software\Wine\Mac Driver\Cursors */
202 if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Mac Driver\\Cursors", &key))
204 WCHAR value[64];
205 DWORD size, ret;
207 value[0] = 0;
208 size = sizeof(value) / sizeof(WCHAR);
209 ret = RegQueryValueExW(key, name, NULL, NULL, (BYTE *)value, &size);
210 RegCloseKey(key);
211 if (!ret)
213 if (!value[0])
215 TRACE("registry forces standard cursor for %s\n", debugstr_w(name));
216 return NULL; /* force standard cursor */
219 cursor_name = CFStringCreateWithCharacters(NULL, value, strlenW(value));
220 if (!cursor_name)
222 WARN("CFStringCreateWithCharacters failed for %s\n", debugstr_w(value));
223 return NULL;
226 /* Make sure it's one of the appropriate NSCursor class methods. */
227 for (i = 0; i < sizeof(cocoa_cursor_names) / sizeof(cocoa_cursor_names[0]); i++)
228 if (CFEqual(cursor_name, cocoa_cursor_names[i]))
229 goto done;
231 WARN("%s mapped to invalid Cocoa cursor name %s\n", debugstr_w(name), debugstr_w(value));
232 CFRelease(cursor_name);
233 return NULL;
237 if (info->szResName[0]) goto done; /* only integer resources are supported here */
238 if (!(module = GetModuleHandleW(info->szModName))) goto done;
240 for (i = 0; i < sizeof(module_cursors)/sizeof(module_cursors[0]); i++)
241 if (GetModuleHandleW(module_cursors[i].name) == module) break;
242 if (i == sizeof(module_cursors)/sizeof(module_cursors[0])) goto done;
244 cursors = module_cursors[i].cursors;
245 for (i = 0; cursors[i].id; i++)
246 if (cursors[i].id == info->wResID)
248 cursor_name = CFRetain(cursors[i].name);
249 break;
252 done:
253 if (cursor_name)
254 TRACE("%s -> %s\n", debugstr_w(name), debugstr_cf(cursor_name));
255 else
256 WARN("no system cursor found for %s\n", debugstr_w(name));
257 return cursor_name;
260 /***********************************************************************
261 * release_provider_cfdata
263 * Helper for create_monochrome_cursor. A CFData is used by two
264 * different CGDataProviders, using different offsets. One of them is
265 * constructed with a pointer to the bytes, not a reference to the
266 * CFData object (because of the offset). So, the CFData is CFRetain'ed
267 * on its behalf at creation and released here.
269 void release_provider_cfdata(void *info, const void *data, size_t size)
271 CFRelease(info);
275 /***********************************************************************
276 * create_monochrome_cursor
278 CFArrayRef create_monochrome_cursor(HDC hdc, const ICONINFOEXW *icon, int width, int height)
280 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
281 BITMAPINFO *info = (BITMAPINFO *)buffer;
282 unsigned int width_bytes = (width + 31) / 32 * 4;
283 CGColorSpaceRef colorspace;
284 CFMutableDataRef data;
285 CGDataProviderRef provider;
286 CGImageRef cgimage, cgmask, cgmasked;
287 CGPoint hot_spot;
288 CFDictionaryRef hot_spot_dict;
289 const CFStringRef keys[] = { CFSTR("image"), CFSTR("hotSpot") };
290 CFTypeRef values[sizeof(keys) / sizeof(keys[0])];
291 CFDictionaryRef frame;
292 CFArrayRef frames;
294 TRACE("hdc %p icon->hbmMask %p icon->xHotspot %d icon->yHotspot %d width %d height %d\n",
295 hdc, icon->hbmMask, icon->xHotspot, icon->yHotspot, width, height);
297 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
298 info->bmiHeader.biWidth = width;
299 info->bmiHeader.biHeight = -height * 2;
300 info->bmiHeader.biPlanes = 1;
301 info->bmiHeader.biBitCount = 1;
302 info->bmiHeader.biCompression = BI_RGB;
303 info->bmiHeader.biSizeImage = width_bytes * height * 2;
304 info->bmiHeader.biXPelsPerMeter = 0;
305 info->bmiHeader.biYPelsPerMeter = 0;
306 info->bmiHeader.biClrUsed = 0;
307 info->bmiHeader.biClrImportant = 0;
309 /* This will be owned by the data provider for the mask image and released
310 when it is destroyed. */
311 data = CFDataCreateMutable(NULL, info->bmiHeader.biSizeImage);
312 if (!data)
314 WARN("failed to create data\n");
315 return NULL;
317 CFDataSetLength(data, info->bmiHeader.biSizeImage);
319 if (!GetDIBits(hdc, icon->hbmMask, 0, height * 2, CFDataGetMutableBytePtr(data), info, DIB_RGB_COLORS))
321 WARN("GetDIBits failed\n");
322 CFRelease(data);
323 return NULL;
326 colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
327 if (!colorspace)
329 WARN("failed to create colorspace\n");
330 CFRelease(data);
331 return NULL;
334 /* The data object needs to live as long as this provider, so retain it an
335 extra time and have the provider's data-release callback release it. */
336 provider = CGDataProviderCreateWithData(data, CFDataGetBytePtr(data) + width_bytes * height,
337 width_bytes * height, release_provider_cfdata);
338 if (!provider)
340 WARN("failed to create data provider\n");
341 CGColorSpaceRelease(colorspace);
342 CFRelease(data);
343 return NULL;
345 CFRetain(data);
347 cgimage = CGImageCreate(width, height, 1, 1, width_bytes, colorspace,
348 kCGImageAlphaNone | kCGBitmapByteOrderDefault,
349 provider, NULL, FALSE, kCGRenderingIntentDefault);
350 CGDataProviderRelease(provider);
351 CGColorSpaceRelease(colorspace);
352 if (!cgimage)
354 WARN("failed to create image\n");
355 CFRelease(data);
356 return NULL;
359 provider = CGDataProviderCreateWithCFData(data);
360 CFRelease(data);
361 if (!provider)
363 WARN("failed to create data provider\n");
364 CGImageRelease(cgimage);
365 return NULL;
368 cgmask = CGImageMaskCreate(width, height, 1, 1, width_bytes, provider, NULL, FALSE);
369 CGDataProviderRelease(provider);
370 if (!cgmask)
372 WARN("failed to create mask image\n");
373 CGImageRelease(cgimage);
374 return NULL;
377 cgmasked = CGImageCreateWithMask(cgimage, cgmask);
378 CGImageRelease(cgimage);
379 CGImageRelease(cgmask);
380 if (!cgmasked)
382 WARN("failed to create masked image\n");
383 return NULL;
386 hot_spot = CGPointMake(icon->xHotspot, icon->yHotspot);
387 hot_spot_dict = CGPointCreateDictionaryRepresentation(hot_spot);
388 if (!hot_spot_dict)
390 WARN("failed to create hot spot dictionary\n");
391 CGImageRelease(cgmasked);
392 return NULL;
395 values[0] = cgmasked;
396 values[1] = hot_spot_dict;
397 frame = CFDictionaryCreate(NULL, (const void**)keys, values, sizeof(keys) / sizeof(keys[0]),
398 &kCFCopyStringDictionaryKeyCallBacks,
399 &kCFTypeDictionaryValueCallBacks);
400 CFRelease(hot_spot_dict);
401 CGImageRelease(cgmasked);
402 if (!frame)
404 WARN("failed to create frame dictionary\n");
405 return NULL;
408 frames = CFArrayCreate(NULL, (const void**)&frame, 1, &kCFTypeArrayCallBacks);
409 CFRelease(frame);
410 if (!frames)
412 WARN("failed to create frames array\n");
413 return NULL;
416 return frames;
420 /***********************************************************************
421 * create_cgimage_from_icon
423 static CGImageRef create_cgimage_from_icon(HDC hdc, HANDLE icon, HBITMAP hbmColor,
424 unsigned char *color_bits, int color_size, HBITMAP hbmMask,
425 unsigned char *mask_bits, int mask_size, int width,
426 int height, int istep)
428 int i, has_alpha = FALSE;
429 DWORD *ptr;
430 CGBitmapInfo alpha_format;
431 CGColorSpaceRef colorspace;
432 CFDataRef data;
433 CGDataProviderRef provider;
434 CGImageRef cgimage;
436 /* draw the cursor frame to a temporary buffer then create a CGImage from that */
437 memset(color_bits, 0x00, color_size);
438 SelectObject(hdc, hbmColor);
439 if (!DrawIconEx(hdc, 0, 0, icon, width, height, istep, NULL, DI_NORMAL))
441 WARN("Could not draw frame %d (walk past end of frames).\n", istep);
442 return NULL;
445 /* check if the cursor frame was drawn with an alpha channel */
446 for (i = 0, ptr = (DWORD*)color_bits; i < width * height; i++, ptr++)
447 if ((has_alpha = (*ptr & 0xff000000) != 0)) break;
449 if (has_alpha)
450 alpha_format = kCGImageAlphaFirst;
451 else
452 alpha_format = kCGImageAlphaNoneSkipFirst;
454 colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
455 if (!colorspace)
457 WARN("failed to create colorspace\n");
458 return NULL;
461 data = CFDataCreate(NULL, (UInt8*)color_bits, color_size);
462 if (!data)
464 WARN("failed to create data\n");
465 CGColorSpaceRelease(colorspace);
466 return NULL;
469 provider = CGDataProviderCreateWithCFData(data);
470 CFRelease(data);
471 if (!provider)
473 WARN("failed to create data provider\n");
474 CGColorSpaceRelease(colorspace);
475 return NULL;
478 cgimage = CGImageCreate(width, height, 8, 32, width * 4, colorspace,
479 alpha_format | kCGBitmapByteOrder32Little,
480 provider, NULL, FALSE, kCGRenderingIntentDefault);
481 CGDataProviderRelease(provider);
482 CGColorSpaceRelease(colorspace);
483 if (!cgimage)
485 WARN("failed to create image\n");
486 return NULL;
489 /* if no alpha channel was drawn then generate it from the mask */
490 if (!has_alpha)
492 unsigned int width_bytes = (width + 31) / 32 * 4;
493 CGImageRef cgmask, temp;
495 /* draw the cursor mask to a temporary buffer */
496 memset(mask_bits, 0xFF, mask_size);
497 SelectObject(hdc, hbmMask);
498 if (!DrawIconEx(hdc, 0, 0, icon, width, height, istep, NULL, DI_MASK))
500 WARN("Failed to draw frame mask %d.\n", istep);
501 CGImageRelease(cgimage);
502 return NULL;
505 data = CFDataCreate(NULL, (UInt8*)mask_bits, mask_size);
506 if (!data)
508 WARN("failed to create data\n");
509 CGImageRelease(cgimage);
510 return NULL;
513 provider = CGDataProviderCreateWithCFData(data);
514 CFRelease(data);
515 if (!provider)
517 WARN("failed to create data provider\n");
518 CGImageRelease(cgimage);
519 return NULL;
522 cgmask = CGImageMaskCreate(width, height, 1, 1, width_bytes, provider, NULL, FALSE);
523 CGDataProviderRelease(provider);
524 if (!cgmask)
526 WARN("failed to create mask\n");
527 CGImageRelease(cgimage);
528 return NULL;
531 temp = CGImageCreateWithMask(cgimage, cgmask);
532 CGImageRelease(cgmask);
533 CGImageRelease(cgimage);
534 if (!temp)
536 WARN("failed to create masked image\n");
537 return NULL;
539 cgimage = temp;
542 return cgimage;
546 /***********************************************************************
547 * create_cursor_frame
549 * Create a frame dictionary for a cursor from a Windows icon.
550 * Keys:
551 * "image" a CGImage for the frame
552 * "duration" a CFNumber for the frame duration in seconds
553 * "hotSpot" a CFDictionary encoding a CGPoint for the hot spot
555 static CFDictionaryRef create_cursor_frame(HDC hdc, const ICONINFOEXW *iinfo, HANDLE icon,
556 HBITMAP hbmColor, unsigned char *color_bits, int color_size,
557 HBITMAP hbmMask, unsigned char *mask_bits, int mask_size,
558 int width, int height, int istep)
560 DWORD delay_jiffies, num_steps;
561 CFMutableDictionaryRef frame;
562 CGPoint hot_spot;
563 CFDictionaryRef hot_spot_dict;
564 double duration;
565 CFNumberRef duration_number;
566 CGImageRef cgimage;
568 TRACE("hdc %p iinfo->xHotspot %d iinfo->yHotspot %d icon %p hbmColor %p color_bits %p color_size %d"
569 " hbmMask %p mask_bits %p mask_size %d width %d height %d istep %d\n",
570 hdc, iinfo->xHotspot, iinfo->yHotspot, icon, hbmColor, color_bits, color_size,
571 hbmMask, mask_bits, mask_size, width, height, istep);
573 frame = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks,
574 &kCFTypeDictionaryValueCallBacks);
575 if (!frame)
577 WARN("failed to allocate dictionary for frame\n");
578 return NULL;
581 hot_spot = CGPointMake(iinfo->xHotspot, iinfo->yHotspot);
582 hot_spot_dict = CGPointCreateDictionaryRepresentation(hot_spot);
583 if (!hot_spot_dict)
585 WARN("failed to create hot spot dictionary\n");
586 CFRelease(frame);
587 return NULL;
589 CFDictionarySetValue(frame, CFSTR("hotSpot"), hot_spot_dict);
590 CFRelease(hot_spot_dict);
592 if (GetCursorFrameInfo(icon, 0x0 /* unknown parameter */, istep, &delay_jiffies, &num_steps) != 0)
593 duration = delay_jiffies / 60.0; /* convert jiffies (1/60s) to seconds */
594 else
596 WARN("Failed to retrieve animated cursor frame-rate for frame %d.\n", istep);
597 duration = 0.1; /* fallback delay, 100 ms */
599 duration_number = CFNumberCreate(NULL, kCFNumberDoubleType, &duration);
600 if (!duration_number)
602 WARN("failed to create duration number\n");
603 CFRelease(frame);
604 return NULL;
606 CFDictionarySetValue(frame, CFSTR("duration"), duration_number);
607 CFRelease(duration_number);
609 cgimage = create_cgimage_from_icon(hdc, icon, hbmColor, color_bits, color_size,
610 hbmMask, mask_bits, mask_size, width, height, istep);
611 if (!cgimage)
613 CFRelease(frame);
614 return NULL;
617 CFDictionarySetValue(frame, CFSTR("image"), cgimage);
618 CGImageRelease(cgimage);
620 return frame;
624 /***********************************************************************
625 * create_color_cursor
627 * Create an array of color cursor frames from a Windows cursor. Each
628 * frame is represented in the array by a dictionary.
629 * Frame dictionary keys:
630 * "image" a CGImage for the frame
631 * "duration" a CFNumber for the frame duration in seconds
632 * "hotSpot" a CFDictionary encoding a CGPoint for the hot spot
634 static CFArrayRef create_color_cursor(HDC hdc, const ICONINFOEXW *iinfo, HANDLE icon, int width, int height)
636 unsigned char *color_bits, *mask_bits;
637 HBITMAP hbmColor = 0, hbmMask = 0;
638 DWORD nFrames, delay_jiffies, i;
639 int color_size, mask_size;
640 BITMAPINFO *info = NULL;
641 CFMutableArrayRef frames;
643 TRACE("hdc %p iinfo %p icon %p width %d height %d\n", hdc, iinfo, icon, width, height);
645 /* Retrieve the number of frames to render */
646 if (!GetCursorFrameInfo(icon, 0x0 /* unknown parameter */, 0, &delay_jiffies, &nFrames))
648 WARN("GetCursorFrameInfo failed\n");
649 return NULL;
651 if (!(frames = CFArrayCreateMutable(NULL, nFrames, &kCFTypeArrayCallBacks)))
653 WARN("failed to allocate frames array\n");
654 return NULL;
657 /* Allocate all of the resources necessary to obtain a cursor frame */
658 if (!(info = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(BITMAPINFO, bmiColors[256])))) goto cleanup;
659 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
660 info->bmiHeader.biWidth = width;
661 info->bmiHeader.biHeight = -height;
662 info->bmiHeader.biPlanes = 1;
663 info->bmiHeader.biCompression = BI_RGB;
664 info->bmiHeader.biXPelsPerMeter = 0;
665 info->bmiHeader.biYPelsPerMeter = 0;
666 info->bmiHeader.biClrUsed = 0;
667 info->bmiHeader.biClrImportant = 0;
668 info->bmiHeader.biBitCount = 32;
669 color_size = width * height * 4;
670 info->bmiHeader.biSizeImage = color_size;
671 hbmColor = CreateDIBSection(hdc, info, DIB_RGB_COLORS, (VOID **) &color_bits, NULL, 0);
672 if (!hbmColor)
674 WARN("failed to create DIB section for cursor color data\n");
675 goto cleanup;
677 info->bmiHeader.biBitCount = 1;
678 info->bmiColors[0].rgbRed = 0;
679 info->bmiColors[0].rgbGreen = 0;
680 info->bmiColors[0].rgbBlue = 0;
681 info->bmiColors[0].rgbReserved = 0;
682 info->bmiColors[1].rgbRed = 0xff;
683 info->bmiColors[1].rgbGreen = 0xff;
684 info->bmiColors[1].rgbBlue = 0xff;
685 info->bmiColors[1].rgbReserved = 0;
687 mask_size = ((width + 31) / 32 * 4) * height; /* width_bytes * height */
688 info->bmiHeader.biSizeImage = mask_size;
689 hbmMask = CreateDIBSection(hdc, info, DIB_RGB_COLORS, (VOID **) &mask_bits, NULL, 0);
690 if (!hbmMask)
692 WARN("failed to create DIB section for cursor mask data\n");
693 goto cleanup;
696 /* Create a CFDictionary for each frame of the cursor */
697 for (i = 0; i < nFrames; i++)
699 CFDictionaryRef frame = create_cursor_frame(hdc, iinfo, icon,
700 hbmColor, color_bits, color_size,
701 hbmMask, mask_bits, mask_size,
702 width, height, i);
703 if (!frame) goto cleanup;
704 CFArrayAppendValue(frames, frame);
705 CFRelease(frame);
708 cleanup:
709 if (CFArrayGetCount(frames) < nFrames)
711 CFRelease(frames);
712 frames = NULL;
714 else
715 TRACE("returning cursor with %d frames\n", nFrames);
716 /* Cleanup all of the resources used to obtain the frame data */
717 if (hbmColor) DeleteObject(hbmColor);
718 if (hbmMask) DeleteObject(hbmMask);
719 HeapFree(GetProcessHeap(), 0, info);
720 return frames;
724 /***********************************************************************
725 * DestroyCursorIcon (MACDRV.@)
727 void CDECL macdrv_DestroyCursorIcon(HCURSOR cursor)
729 TRACE("cursor %p\n", cursor);
731 EnterCriticalSection(&cursor_cache_section);
732 if (cursor_cache)
733 CFDictionaryRemoveValue(cursor_cache, cursor);
734 LeaveCriticalSection(&cursor_cache_section);
738 /***********************************************************************
739 * ClipCursor (MACDRV.@)
741 * Set the cursor clipping rectangle.
743 BOOL CDECL macdrv_ClipCursor(LPCRECT clip)
745 CGRect rect;
747 TRACE("%s\n", wine_dbgstr_rect(clip));
749 if (clip)
751 rect = CGRectMake(clip->left, clip->top, max(1, clip->right - clip->left),
752 max(1, clip->bottom - clip->top));
754 else
755 rect = CGRectInfinite;
757 /* FIXME: This needs to be done not just in this process but in all of the
758 ones for this WINEPREFIX. Broadcast a message to do that. */
760 return macdrv_clip_cursor(rect);
764 /***********************************************************************
765 * GetCursorPos (MACDRV.@)
767 BOOL CDECL macdrv_GetCursorPos(LPPOINT pos)
769 CGPoint pt;
770 BOOL ret;
772 ret = macdrv_get_cursor_position(&pt);
773 if (ret)
775 TRACE("pointer at (%g,%g) server pos %d,%d\n", pt.x, pt.y, pos->x, pos->y);
776 pos->x = pt.x;
777 pos->y = pt.y;
779 return ret;
783 /***********************************************************************
784 * SetCursor (MACDRV.@)
786 void CDECL macdrv_SetCursor(HCURSOR cursor)
788 CFStringRef cursor_name = NULL;
789 CFArrayRef cursor_frames = NULL;
791 TRACE("%p\n", cursor);
793 if (cursor)
795 ICONINFOEXW info;
797 EnterCriticalSection(&cursor_cache_section);
798 if (cursor_cache)
800 CFTypeRef cached_cursor = CFDictionaryGetValue(cursor_cache, cursor);
801 if (cached_cursor)
803 if (CFGetTypeID(cached_cursor) == CFStringGetTypeID())
804 cursor_name = CFRetain(cached_cursor);
805 else
806 cursor_frames = CFRetain(cached_cursor);
809 LeaveCriticalSection(&cursor_cache_section);
810 if (cursor_name || cursor_frames)
811 goto done;
813 info.cbSize = sizeof(info);
814 if (!GetIconInfoExW(cursor, &info))
816 WARN("GetIconInfoExW failed\n");
817 return;
820 if ((cursor_name = copy_system_cursor_name(&info)))
822 DeleteObject(info.hbmColor);
823 DeleteObject(info.hbmMask);
825 else
827 BITMAP bm;
828 HDC hdc;
830 GetObjectW(info.hbmMask, sizeof(bm), &bm);
831 if (!info.hbmColor) bm.bmHeight = max(1, bm.bmHeight / 2);
833 /* make sure hotspot is valid */
834 if (info.xHotspot >= bm.bmWidth || info.yHotspot >= bm.bmHeight)
836 info.xHotspot = bm.bmWidth / 2;
837 info.yHotspot = bm.bmHeight / 2;
840 hdc = CreateCompatibleDC(0);
842 if (info.hbmColor)
844 cursor_frames = create_color_cursor(hdc, &info, cursor, bm.bmWidth, bm.bmHeight);
845 DeleteObject(info.hbmColor);
847 else
848 cursor_frames = create_monochrome_cursor(hdc, &info, bm.bmWidth, bm.bmHeight);
850 DeleteObject(info.hbmMask);
851 DeleteDC(hdc);
854 if (cursor_name || cursor_frames)
856 EnterCriticalSection(&cursor_cache_section);
857 if (!cursor_cache)
858 cursor_cache = CFDictionaryCreateMutable(NULL, 0, NULL,
859 &kCFTypeDictionaryValueCallBacks);
860 CFDictionarySetValue(cursor_cache, cursor,
861 cursor_name ? (CFTypeRef)cursor_name : (CFTypeRef)cursor_frames);
862 LeaveCriticalSection(&cursor_cache_section);
864 else
865 cursor_name = CFRetain(CFSTR("arrowCursor"));
868 done:
869 TRACE("setting cursor with cursor_name %s cursor_frames %p\n", debugstr_cf(cursor_name), cursor_frames);
870 macdrv_set_cursor(cursor_name, cursor_frames);
871 if (cursor_name) CFRelease(cursor_name);
872 if (cursor_frames) CFRelease(cursor_frames);
876 /***********************************************************************
877 * SetCursorPos (MACDRV.@)
879 BOOL CDECL macdrv_SetCursorPos(INT x, INT y)
881 BOOL ret = macdrv_set_cursor_position(CGPointMake(x, y));
882 if (ret)
883 TRACE("warped to %d,%d\n", x, y);
884 else
885 ERR("failed to warp to %d,%d\n", x, y);
886 return ret;
890 /***********************************************************************
891 * macdrv_mouse_button
893 * Handler for MOUSE_BUTTON events.
895 void macdrv_mouse_button(HWND hwnd, const macdrv_event *event)
897 UINT flags = 0;
898 WORD data = 0;
900 TRACE("win %p button %d %s at (%d,%d) time %lu (%lu ticks ago)\n", hwnd, event->mouse_button.button,
901 (event->mouse_button.pressed ? "pressed" : "released"),
902 event->mouse_button.x, event->mouse_button.y,
903 event->mouse_button.time_ms, (GetTickCount() - event->mouse_button.time_ms));
905 if (event->mouse_button.pressed)
907 switch (event->mouse_button.button)
909 case 0: flags |= MOUSEEVENTF_LEFTDOWN; break;
910 case 1: flags |= MOUSEEVENTF_RIGHTDOWN; break;
911 case 2: flags |= MOUSEEVENTF_MIDDLEDOWN; break;
912 default:
913 flags |= MOUSEEVENTF_XDOWN;
914 data = 1 << (event->mouse_button.button - 3);
915 break;
918 else
920 switch (event->mouse_button.button)
922 case 0: flags |= MOUSEEVENTF_LEFTUP; break;
923 case 1: flags |= MOUSEEVENTF_RIGHTUP; break;
924 case 2: flags |= MOUSEEVENTF_MIDDLEUP; break;
925 default:
926 flags |= MOUSEEVENTF_XUP;
927 data = 1 << (event->mouse_button.button - 3);
928 break;
932 send_mouse_input(hwnd, flags | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
933 event->mouse_button.x, event->mouse_button.y,
934 data, event->mouse_button.time_ms);
938 /***********************************************************************
939 * macdrv_mouse_moved
941 * Handler for MOUSE_MOVED and MOUSE_MOVED_ABSOLUTE events.
943 void macdrv_mouse_moved(HWND hwnd, const macdrv_event *event)
945 UINT flags = MOUSEEVENTF_MOVE;
947 TRACE("win %p/%p %s (%d,%d) time %lu (%lu ticks ago)\n", hwnd, event->window,
948 (event->type == MOUSE_MOVED) ? "relative" : "absolute",
949 event->mouse_moved.x, event->mouse_moved.y,
950 event->mouse_moved.time_ms, (GetTickCount() - event->mouse_moved.time_ms));
952 if (event->type == MOUSE_MOVED_ABSOLUTE)
953 flags |= MOUSEEVENTF_ABSOLUTE;
955 send_mouse_input(hwnd, flags, event->mouse_moved.x, event->mouse_moved.y,
956 0, event->mouse_moved.time_ms);
960 /***********************************************************************
961 * macdrv_mouse_scroll
963 * Handler for MOUSE_SCROLL events.
965 void macdrv_mouse_scroll(HWND hwnd, const macdrv_event *event)
967 TRACE("win %p/%p scroll (%d,%d) at (%d,%d) time %lu (%lu ticks ago)\n", hwnd,
968 event->window, event->mouse_scroll.x_scroll, event->mouse_scroll.y_scroll,
969 event->mouse_scroll.x, event->mouse_scroll.y,
970 event->mouse_scroll.time_ms, (GetTickCount() - event->mouse_scroll.time_ms));
972 send_mouse_input(hwnd, MOUSEEVENTF_WHEEL | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
973 event->mouse_scroll.x, event->mouse_scroll.y,
974 event->mouse_scroll.y_scroll, event->mouse_scroll.time_ms);
975 send_mouse_input(hwnd, MOUSEEVENTF_HWHEEL | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE,
976 event->mouse_scroll.x, event->mouse_scroll.y,
977 event->mouse_scroll.x_scroll, event->mouse_scroll.time_ms);