xaudio2/tests: Fix memory leaks.
[wine.git] / dlls / winemac.drv / display.c
blobe1357d8942242eabc752eaab4312f0aa0edcfe22
1 /*
2 * MACDRV display settings
4 * Copyright 2003 Alexander James Pasadyn
5 * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
24 #include "macdrv.h"
25 #include "winuser.h"
26 #include "winreg.h"
27 #include "ddrawi.h"
28 #include "wine/unicode.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(display);
33 struct display_mode_descriptor
35 DWORD width;
36 DWORD height;
37 DWORD pixel_width;
38 DWORD pixel_height;
39 DWORD io_flags;
40 double refresh;
41 CFStringRef pixel_encoding;
45 BOOL CDECL macdrv_EnumDisplaySettingsEx(LPCWSTR devname, DWORD mode, LPDEVMODEW devmode, DWORD flags);
48 static const char initial_mode_key[] = "Initial Display Mode";
49 static const WCHAR pixelencodingW[] = {'P','i','x','e','l','E','n','c','o','d','i','n','g',0};
52 static CFArrayRef modes;
53 static BOOL modes_has_8bpp, modes_has_16bpp;
54 static int default_mode_bpp;
55 static CRITICAL_SECTION modes_section;
56 static CRITICAL_SECTION_DEBUG critsect_debug =
58 0, 0, &modes_section,
59 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
60 0, 0, { (DWORD_PTR)(__FILE__ ": modes_section") }
62 static CRITICAL_SECTION modes_section = { &critsect_debug, -1, 0, 0, 0, 0 };
64 static BOOL inited_original_display_mode;
67 static inline HMONITOR display_id_to_monitor(CGDirectDisplayID display_id)
69 return (HMONITOR)(UINT_PTR)display_id;
72 static inline CGDirectDisplayID monitor_to_display_id(HMONITOR handle)
74 return (CGDirectDisplayID)(UINT_PTR)handle;
78 static BOOL get_display_device_reg_key(char *key, unsigned len)
80 static const char display_device_guid_prop[] = "__wine_display_device_guid";
81 static const char video_path[] = "System\\CurrentControlSet\\Control\\Video\\{";
82 static const char display0[] = "}\\0000";
83 ATOM guid_atom;
85 assert(len >= sizeof(video_path) + sizeof(display0) + 40);
87 guid_atom = HandleToULong(GetPropA(GetDesktopWindow(), display_device_guid_prop));
88 if (!guid_atom) return FALSE;
90 memcpy(key, video_path, sizeof(video_path));
92 if (!GlobalGetAtomNameA(guid_atom, key + strlen(key), 40))
93 return FALSE;
95 strcat(key, display0);
97 TRACE("display device key %s\n", wine_dbgstr_a(key));
98 return TRUE;
102 static BOOL read_registry_settings(DEVMODEW *dm)
104 char wine_mac_reg_key[128];
105 HKEY hkey;
106 DWORD type, size;
107 BOOL ret = TRUE;
109 dm->dmFields = 0;
111 if (!get_display_device_reg_key(wine_mac_reg_key, sizeof(wine_mac_reg_key)))
112 return FALSE;
114 if (RegOpenKeyExA(HKEY_CURRENT_CONFIG, wine_mac_reg_key, 0, KEY_READ, &hkey))
115 return FALSE;
117 #define query_value(name, data) \
118 size = sizeof(DWORD); \
119 if (RegQueryValueExA(hkey, name, 0, &type, (LPBYTE)(data), &size) || \
120 type != REG_DWORD || size != sizeof(DWORD)) \
121 ret = FALSE
123 query_value("DefaultSettings.BitsPerPel", &dm->dmBitsPerPel);
124 dm->dmFields |= DM_BITSPERPEL;
125 query_value("DefaultSettings.XResolution", &dm->dmPelsWidth);
126 dm->dmFields |= DM_PELSWIDTH;
127 query_value("DefaultSettings.YResolution", &dm->dmPelsHeight);
128 dm->dmFields |= DM_PELSHEIGHT;
129 query_value("DefaultSettings.VRefresh", &dm->dmDisplayFrequency);
130 dm->dmFields |= DM_DISPLAYFREQUENCY;
131 query_value("DefaultSettings.Flags", &dm->dmDisplayFlags);
132 dm->dmFields |= DM_DISPLAYFLAGS;
133 query_value("DefaultSettings.XPanning", &dm->dmPosition.x);
134 query_value("DefaultSettings.YPanning", &dm->dmPosition.y);
135 query_value("DefaultSettings.Orientation", &dm->dmDisplayOrientation);
136 query_value("DefaultSettings.FixedOutput", &dm->dmDisplayFixedOutput);
138 #undef query_value
140 RegCloseKey(hkey);
141 return ret;
145 static BOOL write_registry_settings(const DEVMODEW *dm)
147 char wine_mac_reg_key[128];
148 HKEY hkey;
149 BOOL ret = TRUE;
151 if (!get_display_device_reg_key(wine_mac_reg_key, sizeof(wine_mac_reg_key)))
152 return FALSE;
154 if (RegCreateKeyExA(HKEY_CURRENT_CONFIG, wine_mac_reg_key, 0, NULL,
155 REG_OPTION_VOLATILE, KEY_WRITE, NULL, &hkey, NULL))
156 return FALSE;
158 #define set_value(name, data) \
159 if (RegSetValueExA(hkey, name, 0, REG_DWORD, (const BYTE*)(data), sizeof(DWORD))) \
160 ret = FALSE
162 set_value("DefaultSettings.BitsPerPel", &dm->dmBitsPerPel);
163 set_value("DefaultSettings.XResolution", &dm->dmPelsWidth);
164 set_value("DefaultSettings.YResolution", &dm->dmPelsHeight);
165 set_value("DefaultSettings.VRefresh", &dm->dmDisplayFrequency);
166 set_value("DefaultSettings.Flags", &dm->dmDisplayFlags);
167 set_value("DefaultSettings.XPanning", &dm->dmPosition.x);
168 set_value("DefaultSettings.YPanning", &dm->dmPosition.y);
169 set_value("DefaultSettings.Orientation", &dm->dmDisplayOrientation);
170 set_value("DefaultSettings.FixedOutput", &dm->dmDisplayFixedOutput);
172 #undef set_value
174 RegCloseKey(hkey);
175 return ret;
179 static BOOL write_display_settings(HKEY parent_hkey, CGDirectDisplayID displayID)
181 BOOL ret = FALSE;
182 char display_key_name[19];
183 HKEY display_hkey;
184 CGDisplayModeRef display_mode;
185 DWORD val;
186 CFStringRef pixel_encoding;
187 size_t len;
188 WCHAR* buf = NULL;
190 snprintf(display_key_name, sizeof(display_key_name), "Display 0x%08x", displayID);
191 /* @@ Wine registry key: HKLM\Software\Wine\Mac Driver\Initial Display Mode\Display 0xnnnnnnnn */
192 if (RegCreateKeyExA(parent_hkey, display_key_name, 0, NULL,
193 REG_OPTION_VOLATILE, KEY_WRITE, NULL, &display_hkey, NULL))
194 return FALSE;
196 display_mode = CGDisplayCopyDisplayMode(displayID);
197 if (!display_mode)
198 goto fail;
200 val = CGDisplayModeGetWidth(display_mode);
201 if (RegSetValueExA(display_hkey, "Width", 0, REG_DWORD, (const BYTE*)&val, sizeof(val)))
202 goto fail;
203 val = CGDisplayModeGetHeight(display_mode);
204 if (RegSetValueExA(display_hkey, "Height", 0, REG_DWORD, (const BYTE*)&val, sizeof(val)))
205 goto fail;
206 val = CGDisplayModeGetRefreshRate(display_mode) * 100;
207 if (RegSetValueExA(display_hkey, "RefreshRateTimes100", 0, REG_DWORD, (const BYTE*)&val, sizeof(val)))
208 goto fail;
209 val = CGDisplayModeGetIOFlags(display_mode);
210 if (RegSetValueExA(display_hkey, "IOFlags", 0, REG_DWORD, (const BYTE*)&val, sizeof(val)))
211 goto fail;
213 #if defined(MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
214 if (CGDisplayModeGetPixelWidth != NULL && CGDisplayModeGetPixelHeight != NULL)
216 val = CGDisplayModeGetPixelWidth(display_mode);
217 if (RegSetValueExA(display_hkey, "PixelWidth", 0, REG_DWORD, (const BYTE*)&val, sizeof(val)))
218 goto fail;
219 val = CGDisplayModeGetPixelHeight(display_mode);
220 if (RegSetValueExA(display_hkey, "PixelHeight", 0, REG_DWORD, (const BYTE*)&val, sizeof(val)))
221 goto fail;
223 #endif
225 pixel_encoding = CGDisplayModeCopyPixelEncoding(display_mode);
226 len = CFStringGetLength(pixel_encoding);
227 buf = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
228 CFStringGetCharacters(pixel_encoding, CFRangeMake(0, len), (UniChar*)buf);
229 buf[len] = 0;
230 CFRelease(pixel_encoding);
231 if (RegSetValueExW(display_hkey, pixelencodingW, 0, REG_SZ, (const BYTE*)buf, (len + 1) * sizeof(WCHAR)))
232 goto fail;
234 ret = TRUE;
236 fail:
237 HeapFree(GetProcessHeap(), 0, buf);
238 if (display_mode) CGDisplayModeRelease(display_mode);
239 RegCloseKey(display_hkey);
240 if (!ret)
241 RegDeleteKeyA(parent_hkey, display_key_name);
242 return ret;
246 static void init_original_display_mode(void)
248 BOOL success = FALSE;
249 HKEY mac_driver_hkey, parent_hkey;
250 DWORD disposition;
251 struct macdrv_display *displays = NULL;
252 int num_displays, i;
254 if (inited_original_display_mode)
255 return;
257 /* @@ Wine registry key: HKLM\Software\Wine\Mac Driver */
258 if (RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Mac Driver", 0, NULL,
259 0, KEY_ALL_ACCESS, NULL, &mac_driver_hkey, NULL))
260 return;
262 /* @@ Wine registry key: HKLM\Software\Wine\Mac Driver\Initial Display Mode */
263 if (RegCreateKeyExA(mac_driver_hkey, initial_mode_key, 0, NULL,
264 REG_OPTION_VOLATILE, KEY_WRITE, NULL, &parent_hkey, &disposition))
266 parent_hkey = NULL;
267 goto fail;
270 /* If we didn't create a new key, then it already existed. Something already stored
271 the initial display mode since Wine was started. We don't want to overwrite it. */
272 if (disposition != REG_CREATED_NEW_KEY)
273 goto done;
275 if (macdrv_get_displays(&displays, &num_displays))
276 goto fail;
278 for (i = 0; i < num_displays; i++)
280 if (!write_display_settings(parent_hkey, displays[i].displayID))
281 goto fail;
284 done:
285 success = TRUE;
287 fail:
288 macdrv_free_displays(displays);
289 RegCloseKey(parent_hkey);
290 if (!success && parent_hkey)
291 RegDeleteTreeA(mac_driver_hkey, initial_mode_key);
292 RegCloseKey(mac_driver_hkey);
293 if (success)
294 inited_original_display_mode = TRUE;
298 static BOOL read_dword(HKEY hkey, const char* name, DWORD* val)
300 DWORD type, size = sizeof(*val);
301 if (RegQueryValueExA(hkey, name, 0, &type, (BYTE*)val, &size) || type != REG_DWORD || size != sizeof(*val))
302 return FALSE;
303 return TRUE;
307 static void free_display_mode_descriptor(struct display_mode_descriptor* desc)
309 if (desc)
311 if (desc->pixel_encoding)
312 CFRelease(desc->pixel_encoding);
313 HeapFree(GetProcessHeap(), 0, desc);
318 static struct display_mode_descriptor* create_original_display_mode_descriptor(CGDirectDisplayID displayID)
320 static const char display_key_format[] = "Software\\Wine\\Mac Driver\\Initial Display Mode\\Display 0x%08x";
321 struct display_mode_descriptor* ret = NULL;
322 struct display_mode_descriptor* desc;
323 char display_key[sizeof(display_key_format) + 10];
324 HKEY hkey;
325 DWORD type, size;
326 DWORD refresh100;
327 WCHAR* pixel_encoding = NULL, *end;
329 init_original_display_mode();
331 snprintf(display_key, sizeof(display_key), display_key_format, displayID);
332 /* @@ Wine registry key: HKLM\Software\Wine\Mac Driver\Initial Display Mode\Display 0xnnnnnnnn */
333 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, display_key, 0, KEY_READ, &hkey))
334 return NULL;
336 desc = HeapAlloc(GetProcessHeap(), 0, sizeof(*desc));
337 desc->pixel_encoding = NULL;
339 if (!read_dword(hkey, "Width", &desc->width) ||
340 !read_dword(hkey, "Height", &desc->height) ||
341 !read_dword(hkey, "RefreshRateTimes100", &refresh100) ||
342 !read_dword(hkey, "IOFlags", &desc->io_flags))
343 goto done;
344 if (refresh100)
345 desc->refresh = refresh100 / 100.0;
346 else
347 desc->refresh = 60;
349 if (!read_dword(hkey, "PixelWidth", &desc->pixel_width) ||
350 !read_dword(hkey, "PixelHeight", &desc->pixel_height))
352 desc->pixel_width = desc->width;
353 desc->pixel_height = desc->height;
356 size = 0;
357 if (RegQueryValueExW(hkey, pixelencodingW, 0, &type, NULL, &size) || type != REG_SZ)
358 goto done;
359 pixel_encoding = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
360 if (RegQueryValueExW(hkey, pixelencodingW, 0, &type, (BYTE*)pixel_encoding, &size) || type != REG_SZ)
361 goto done;
362 if ((end = memchrW(pixel_encoding, 0, size)))
363 size = end - pixel_encoding;
364 desc->pixel_encoding = CFStringCreateWithCharacters(NULL, (const UniChar*)pixel_encoding, size);
366 ret = desc;
368 done:
369 if (!ret)
370 free_display_mode_descriptor(desc);
371 HeapFree(GetProcessHeap(), 0, pixel_encoding);
372 RegCloseKey(hkey);
373 return ret;
377 static BOOL display_mode_matches_descriptor(CGDisplayModeRef mode, const struct display_mode_descriptor* desc)
379 DWORD mode_io_flags;
380 double mode_refresh;
381 CFStringRef mode_pixel_encoding;
383 if (!desc)
384 return FALSE;
386 if (CGDisplayModeGetWidth(mode) != desc->width ||
387 CGDisplayModeGetHeight(mode) != desc->height)
388 return FALSE;
390 mode_io_flags = CGDisplayModeGetIOFlags(mode);
391 if ((desc->io_flags ^ mode_io_flags) & (kDisplayModeValidFlag | kDisplayModeSafeFlag | kDisplayModeStretchedFlag |
392 kDisplayModeInterlacedFlag | kDisplayModeTelevisionFlag))
393 return FALSE;
395 mode_refresh = CGDisplayModeGetRefreshRate(mode);
396 if (!mode_refresh)
397 mode_refresh = 60;
398 if (fabs(desc->refresh - mode_refresh) > 0.1)
399 return FALSE;
401 #if defined(MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
402 if (CGDisplayModeGetPixelWidth != NULL && CGDisplayModeGetPixelHeight != NULL)
404 if (CGDisplayModeGetPixelWidth(mode) != desc->pixel_width ||
405 CGDisplayModeGetPixelHeight(mode) != desc->pixel_height)
406 return FALSE;
408 else
409 #endif
410 if (CGDisplayModeGetWidth(mode) != desc->pixel_width ||
411 CGDisplayModeGetHeight(mode) != desc->pixel_height)
412 return FALSE;
414 mode_pixel_encoding = CGDisplayModeCopyPixelEncoding(mode);
415 if (!CFEqual(mode_pixel_encoding, desc->pixel_encoding))
417 CFRelease(mode_pixel_encoding);
418 return FALSE;
420 CFRelease(mode_pixel_encoding);
422 return TRUE;
426 static int display_mode_bits_per_pixel(CGDisplayModeRef display_mode)
428 CFStringRef pixel_encoding;
429 int bits_per_pixel = 0;
431 pixel_encoding = CGDisplayModeCopyPixelEncoding(display_mode);
432 if (pixel_encoding)
434 if (CFEqual(pixel_encoding, CFSTR(kIO32BitFloatPixels)))
435 bits_per_pixel = 128;
436 else if (CFEqual(pixel_encoding, CFSTR(kIO16BitFloatPixels)))
437 bits_per_pixel = 64;
438 else if (CFEqual(pixel_encoding, CFSTR(kIO64BitDirectPixels)))
439 bits_per_pixel = 64;
440 else if (CFEqual(pixel_encoding, CFSTR(kIO30BitDirectPixels)))
441 bits_per_pixel = 30;
442 else if (CFEqual(pixel_encoding, CFSTR(IO32BitDirectPixels)))
443 bits_per_pixel = 32;
444 else if (CFEqual(pixel_encoding, CFSTR(IO16BitDirectPixels)))
445 bits_per_pixel = 16;
446 else if (CFEqual(pixel_encoding, CFSTR(IO8BitIndexedPixels)))
447 bits_per_pixel = 8;
448 else if (CFEqual(pixel_encoding, CFSTR(IO4BitIndexedPixels)))
449 bits_per_pixel = 4;
450 else if (CFEqual(pixel_encoding, CFSTR(IO2BitIndexedPixels)))
451 bits_per_pixel = 2;
452 else if (CFEqual(pixel_encoding, CFSTR(IO1BitIndexedPixels)))
453 bits_per_pixel = 1;
455 CFRelease(pixel_encoding);
458 return bits_per_pixel;
462 static int get_default_bpp(void)
464 int ret;
466 EnterCriticalSection(&modes_section);
468 if (!default_mode_bpp)
470 CGDisplayModeRef mode = CGDisplayCopyDisplayMode(kCGDirectMainDisplay);
471 if (mode)
473 default_mode_bpp = display_mode_bits_per_pixel(mode);
474 CFRelease(mode);
477 if (!default_mode_bpp)
478 default_mode_bpp = 32;
481 ret = default_mode_bpp;
483 LeaveCriticalSection(&modes_section);
485 TRACE(" -> %d\n", ret);
486 return ret;
490 #if defined(MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
491 static CFDictionaryRef create_mode_dict(CGDisplayModeRef display_mode)
493 CFDictionaryRef ret;
494 SInt32 io_flags = CGDisplayModeGetIOFlags(display_mode);
495 SInt64 width = CGDisplayModeGetWidth(display_mode);
496 SInt64 height = CGDisplayModeGetHeight(display_mode);
497 double refresh_rate = CGDisplayModeGetRefreshRate(display_mode);
498 CFStringRef pixel_encoding = CGDisplayModeCopyPixelEncoding(display_mode);
499 CFNumberRef cf_io_flags, cf_width, cf_height, cf_refresh;
501 io_flags &= kDisplayModeValidFlag | kDisplayModeSafeFlag | kDisplayModeInterlacedFlag |
502 kDisplayModeStretchedFlag | kDisplayModeTelevisionFlag;
503 cf_io_flags = CFNumberCreate(NULL, kCFNumberSInt32Type, &io_flags);
504 cf_width = CFNumberCreate(NULL, kCFNumberSInt64Type, &width);
505 cf_height = CFNumberCreate(NULL, kCFNumberSInt64Type, &height);
506 cf_refresh = CFNumberCreate(NULL, kCFNumberDoubleType, &refresh_rate);
509 static const CFStringRef keys[] = {
510 CFSTR("io_flags"),
511 CFSTR("width"),
512 CFSTR("height"),
513 CFSTR("pixel_encoding"),
514 CFSTR("refresh_rate"),
516 const void* values[sizeof(keys) / sizeof(keys[0])] = {
517 cf_io_flags,
518 cf_width,
519 cf_height,
520 pixel_encoding,
521 cf_refresh,
524 ret = CFDictionaryCreate(NULL, (const void**)keys, (const void**)values, sizeof(keys) / sizeof(keys[0]),
525 &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
528 CFRelease(pixel_encoding);
529 CFRelease(cf_io_flags);
530 CFRelease(cf_width);
531 CFRelease(cf_height);
532 CFRelease(cf_refresh);
534 return ret;
536 #endif
539 /***********************************************************************
540 * copy_display_modes
542 * Wrapper around CGDisplayCopyAllDisplayModes() to include additional
543 * modes on Retina-capable systems, but filter those which would confuse
544 * Windows apps (basically duplicates at different DPIs).
546 * For example, some Retina Macs support a 1920x1200 mode, but it's not
547 * returned from CGDisplayCopyAllDisplayModes() without special options.
548 * This is especially bad if that's the user's default mode, since then
549 * no "available" mode matches the initial settings.
551 static CFArrayRef copy_display_modes(CGDirectDisplayID display)
553 CFArrayRef modes = NULL;
555 #if defined(MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
556 if (&kCGDisplayShowDuplicateLowResolutionModes != NULL &&
557 CGDisplayModeGetPixelWidth != NULL && CGDisplayModeGetPixelHeight != NULL)
559 CFDictionaryRef options;
560 struct display_mode_descriptor* desc;
561 CFMutableDictionaryRef modes_by_size;
562 CFIndex i, count;
563 CGDisplayModeRef* mode_array;
565 options = CFDictionaryCreate(NULL, (const void**)&kCGDisplayShowDuplicateLowResolutionModes,
566 (const void**)&kCFBooleanTrue, 1, &kCFTypeDictionaryKeyCallBacks,
567 &kCFTypeDictionaryValueCallBacks);
569 modes = CGDisplayCopyAllDisplayModes(display, options);
570 if (options)
571 CFRelease(options);
572 if (!modes)
573 return NULL;
575 desc = create_original_display_mode_descriptor(display);
577 modes_by_size = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
578 count = CFArrayGetCount(modes);
579 for (i = 0; i < count; i++)
581 BOOL better = TRUE;
582 CGDisplayModeRef new_mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i);
583 BOOL new_is_original = display_mode_matches_descriptor(new_mode, desc);
584 CFDictionaryRef key = create_mode_dict(new_mode);
586 /* If a given mode is the user's default, then always list it in preference to any similar
587 modes that may exist. */
588 if (new_is_original)
589 better = TRUE;
590 else
592 CFStringRef pixel_encoding = CGDisplayModeCopyPixelEncoding(new_mode);
593 CGDisplayModeRef old_mode;
595 if (pixel_encoding)
597 BOOL bpp30 = CFEqual(pixel_encoding, CFSTR(kIO30BitDirectPixels));
598 CFRelease(pixel_encoding);
599 if (bpp30)
601 /* This is an odd pixel encoding. It seems it's only returned
602 when using kCGDisplayShowDuplicateLowResolutionModes. It's
603 32bpp in terms of the actual raster layout, but it's 10
604 bits per component. I think that no Windows program is
605 likely to need it and they will probably be confused by it.
606 Skip it. */
607 CFRelease(key);
608 continue;
612 old_mode = (CGDisplayModeRef)CFDictionaryGetValue(modes_by_size, key);
613 if (old_mode)
615 BOOL old_is_original = display_mode_matches_descriptor(old_mode, desc);
617 if (old_is_original)
618 better = FALSE;
619 else
621 /* Otherwise, prefer a mode whose pixel size equals its point size over one which
622 is scaled. */
623 size_t width_points = CGDisplayModeGetWidth(new_mode);
624 size_t height_points = CGDisplayModeGetHeight(new_mode);
625 size_t new_width_pixels = CGDisplayModeGetPixelWidth(new_mode);
626 size_t new_height_pixels = CGDisplayModeGetPixelHeight(new_mode);
627 size_t old_width_pixels = CGDisplayModeGetPixelWidth(old_mode);
628 size_t old_height_pixels = CGDisplayModeGetPixelHeight(old_mode);
629 BOOL new_size_same = (new_width_pixels == width_points && new_height_pixels == height_points);
630 BOOL old_size_same = (old_width_pixels == width_points && old_height_pixels == height_points);
632 if (new_size_same && !old_size_same)
633 better = TRUE;
634 else if (!new_size_same && old_size_same)
635 better = FALSE;
636 else
638 /* Otherwise, prefer the mode with the smaller pixel size. */
639 if (old_width_pixels < new_width_pixels || old_height_pixels < new_height_pixels)
640 better = FALSE;
646 if (better)
647 CFDictionarySetValue(modes_by_size, key, new_mode);
649 CFRelease(key);
652 free_display_mode_descriptor(desc);
653 CFRelease(modes);
655 count = CFDictionaryGetCount(modes_by_size);
656 mode_array = HeapAlloc(GetProcessHeap(), 0, count * sizeof(mode_array[0]));
657 CFDictionaryGetKeysAndValues(modes_by_size, NULL, (const void **)mode_array);
658 modes = CFArrayCreate(NULL, (const void **)mode_array, count, &kCFTypeArrayCallBacks);
659 HeapFree(GetProcessHeap(), 0, mode_array);
660 CFRelease(modes_by_size);
662 else
663 #endif
664 modes = CGDisplayCopyAllDisplayModes(display, NULL);
666 return modes;
670 /***********************************************************************
671 * ChangeDisplaySettingsEx (MACDRV.@)
674 LONG CDECL macdrv_ChangeDisplaySettingsEx(LPCWSTR devname, LPDEVMODEW devmode,
675 HWND hwnd, DWORD flags, LPVOID lpvoid)
677 LONG ret = DISP_CHANGE_BADMODE;
678 int bpp;
679 DEVMODEW dm;
680 BOOL def_mode = TRUE;
681 struct macdrv_display *displays;
682 int num_displays;
683 CFArrayRef display_modes;
684 CFIndex count, i, safe, best;
685 CGDisplayModeRef best_display_mode;
686 uint32_t best_io_flags;
688 TRACE("%s %p %p 0x%08x %p\n", debugstr_w(devname), devmode, hwnd, flags, lpvoid);
690 init_original_display_mode();
692 if (devmode)
694 /* this is the minimal dmSize that XP accepts */
695 if (devmode->dmSize < FIELD_OFFSET(DEVMODEW, dmFields))
696 return DISP_CHANGE_FAILED;
698 if (devmode->dmSize >= FIELD_OFFSET(DEVMODEW, dmFields) + sizeof(devmode->dmFields))
700 if (((devmode->dmFields & DM_BITSPERPEL) && devmode->dmBitsPerPel) ||
701 ((devmode->dmFields & DM_PELSWIDTH) && devmode->dmPelsWidth) ||
702 ((devmode->dmFields & DM_PELSHEIGHT) && devmode->dmPelsHeight) ||
703 ((devmode->dmFields & DM_DISPLAYFREQUENCY) && devmode->dmDisplayFrequency))
704 def_mode = FALSE;
708 if (def_mode)
710 if (!macdrv_EnumDisplaySettingsEx(devname, ENUM_REGISTRY_SETTINGS, &dm, 0))
712 ERR("Default mode not found!\n");
713 return DISP_CHANGE_BADMODE;
716 TRACE("Return to original display mode\n");
717 devmode = &dm;
720 if ((devmode->dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != (DM_PELSWIDTH | DM_PELSHEIGHT))
722 WARN("devmode doesn't specify the resolution: %04x\n", devmode->dmFields);
723 return DISP_CHANGE_BADMODE;
726 if (macdrv_get_displays(&displays, &num_displays))
727 return DISP_CHANGE_FAILED;
729 display_modes = copy_display_modes(displays[0].displayID);
730 if (!display_modes)
732 macdrv_free_displays(displays);
733 return DISP_CHANGE_FAILED;
736 bpp = get_default_bpp();
737 if ((devmode->dmFields & DM_BITSPERPEL) && devmode->dmBitsPerPel != bpp)
738 TRACE("using default %d bpp instead of caller's request %d bpp\n", bpp, devmode->dmBitsPerPel);
740 TRACE("looking for %dx%dx%dbpp @%d Hz",
741 (devmode->dmFields & DM_PELSWIDTH ? devmode->dmPelsWidth : 0),
742 (devmode->dmFields & DM_PELSHEIGHT ? devmode->dmPelsHeight : 0),
743 bpp,
744 (devmode->dmFields & DM_DISPLAYFREQUENCY ? devmode->dmDisplayFrequency : 0));
745 if (devmode->dmFields & DM_DISPLAYFIXEDOUTPUT)
746 TRACE(" %sstretched", devmode->dmDisplayFixedOutput == DMDFO_STRETCH ? "" : "un");
747 if (devmode->dmFields & DM_DISPLAYFLAGS)
748 TRACE(" %sinterlaced", devmode->dmDisplayFlags & DM_INTERLACED ? "" : "non-");
749 TRACE("\n");
751 safe = -1;
752 best_display_mode = NULL;
753 count = CFArrayGetCount(display_modes);
754 for (i = 0; i < count; i++)
756 CGDisplayModeRef display_mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(display_modes, i);
757 uint32_t io_flags = CGDisplayModeGetIOFlags(display_mode);
758 int mode_bpp = display_mode_bits_per_pixel(display_mode);
759 size_t width = CGDisplayModeGetWidth(display_mode);
760 size_t height = CGDisplayModeGetHeight(display_mode);
762 if (!(io_flags & kDisplayModeValidFlag) || !(io_flags & kDisplayModeSafeFlag))
763 continue;
765 safe++;
767 if (bpp != mode_bpp)
768 continue;
770 if (devmode->dmFields & DM_PELSWIDTH)
772 if (devmode->dmPelsWidth != width)
773 continue;
775 if (devmode->dmFields & DM_PELSHEIGHT)
777 if (devmode->dmPelsHeight != height)
778 continue;
780 if ((devmode->dmFields & DM_DISPLAYFREQUENCY) && devmode->dmDisplayFrequency != 0)
782 double refresh_rate = CGDisplayModeGetRefreshRate(display_mode);
783 if (!refresh_rate)
784 refresh_rate = 60;
785 if (devmode->dmDisplayFrequency != (DWORD)refresh_rate)
786 continue;
788 if (devmode->dmFields & DM_DISPLAYFLAGS)
790 if (!(devmode->dmDisplayFlags & DM_INTERLACED) != !(io_flags & kDisplayModeInterlacedFlag))
791 continue;
793 else if (best_display_mode)
795 if (io_flags & kDisplayModeInterlacedFlag && !(best_io_flags & kDisplayModeInterlacedFlag))
796 continue;
797 else if (!(io_flags & kDisplayModeInterlacedFlag) && best_io_flags & kDisplayModeInterlacedFlag)
798 goto better;
800 if (devmode->dmFields & DM_DISPLAYFIXEDOUTPUT)
802 if (!(devmode->dmDisplayFixedOutput == DMDFO_STRETCH) != !(io_flags & kDisplayModeStretchedFlag))
803 continue;
805 else if (best_display_mode)
807 if (io_flags & kDisplayModeStretchedFlag && !(best_io_flags & kDisplayModeStretchedFlag))
808 continue;
809 else if (!(io_flags & kDisplayModeStretchedFlag) && best_io_flags & kDisplayModeStretchedFlag)
810 goto better;
813 if (best_display_mode)
814 continue;
816 better:
817 best_display_mode = display_mode;
818 best = safe;
819 best_io_flags = io_flags;
822 if (best_display_mode)
824 /* we have a valid mode */
825 TRACE("Requested display settings match mode %ld\n", best);
827 if ((flags & CDS_UPDATEREGISTRY) && !write_registry_settings(devmode))
829 WARN("Failed to update registry\n");
830 ret = DISP_CHANGE_NOTUPDATED;
832 else if (flags & (CDS_TEST | CDS_NORESET))
833 ret = DISP_CHANGE_SUCCESSFUL;
834 else if (macdrv_set_display_mode(&displays[0], best_display_mode))
836 int mode_bpp = display_mode_bits_per_pixel(best_display_mode);
837 size_t width = CGDisplayModeGetWidth(best_display_mode);
838 size_t height = CGDisplayModeGetHeight(best_display_mode);
840 SendMessageW(GetDesktopWindow(), WM_MACDRV_UPDATE_DESKTOP_RECT, mode_bpp,
841 MAKELPARAM(width, height));
842 ret = DISP_CHANGE_SUCCESSFUL;
844 else
846 WARN("Failed to set display mode\n");
847 ret = DISP_CHANGE_FAILED;
850 else
852 /* no valid modes found */
853 ERR("No matching mode found %ux%ux%d @%u!\n", devmode->dmPelsWidth, devmode->dmPelsHeight,
854 bpp, devmode->dmDisplayFrequency);
857 CFRelease(display_modes);
858 macdrv_free_displays(displays);
860 return ret;
864 /***********************************************************************
865 * EnumDisplayMonitors (MACDRV.@)
867 BOOL CDECL macdrv_EnumDisplayMonitors(HDC hdc, LPRECT rect, MONITORENUMPROC proc, LPARAM lparam)
869 struct macdrv_display *displays;
870 int num_displays;
871 int i;
872 BOOL ret = TRUE;
874 TRACE("%p, %s, %p, %#lx\n", hdc, wine_dbgstr_rect(rect), proc, lparam);
876 if (hdc)
878 POINT origin;
879 RECT limit;
881 if (!GetDCOrgEx(hdc, &origin)) return FALSE;
882 if (GetClipBox(hdc, &limit) == ERROR) return FALSE;
884 if (rect && !IntersectRect(&limit, &limit, rect)) return TRUE;
886 if (macdrv_get_displays(&displays, &num_displays))
887 return FALSE;
889 for (i = 0; i < num_displays; i++)
891 RECT monrect = rect_from_cgrect(displays[i].frame);
892 OffsetRect(&monrect, -origin.x, -origin.y);
893 if (IntersectRect(&monrect, &monrect, &limit))
895 HMONITOR monitor = display_id_to_monitor(displays[i].displayID);
896 TRACE("monitor %d handle %p @ %s\n", i, monitor, wine_dbgstr_rect(&monrect));
897 if (!proc(monitor, hdc, &monrect, lparam))
899 ret = FALSE;
900 break;
905 else
907 if (macdrv_get_displays(&displays, &num_displays))
908 return FALSE;
910 for (i = 0; i < num_displays; i++)
912 RECT monrect = rect_from_cgrect(displays[i].frame);
913 RECT unused;
914 if (!rect || IntersectRect(&unused, &monrect, rect))
916 HMONITOR monitor = display_id_to_monitor(displays[i].displayID);
917 TRACE("monitor %d handle %p @ %s\n", i, monitor, wine_dbgstr_rect(&monrect));
918 if (!proc(monitor, 0, &monrect, lparam))
920 ret = FALSE;
921 break;
927 macdrv_free_displays(displays);
929 return ret;
933 /***********************************************************************
934 * EnumDisplaySettingsEx (MACDRV.@)
937 BOOL CDECL macdrv_EnumDisplaySettingsEx(LPCWSTR devname, DWORD mode,
938 LPDEVMODEW devmode, DWORD flags)
940 static const WCHAR dev_name[CCHDEVICENAME] =
941 { 'W','i','n','e',' ','M','a','c',' ','d','r','i','v','e','r',0 };
942 struct macdrv_display *displays = NULL;
943 int num_displays;
944 CGDisplayModeRef display_mode;
945 int display_mode_bpp;
946 BOOL synthesized = FALSE;
947 double rotation;
948 uint32_t io_flags;
950 TRACE("%s, %u, %p + %hu, %08x\n", debugstr_w(devname), mode, devmode, devmode->dmSize, flags);
952 init_original_display_mode();
954 memcpy(devmode->dmDeviceName, dev_name, sizeof(dev_name));
955 devmode->dmSpecVersion = DM_SPECVERSION;
956 devmode->dmDriverVersion = DM_SPECVERSION;
957 devmode->dmSize = FIELD_OFFSET(DEVMODEW, dmICMMethod);
958 devmode->dmDriverExtra = 0;
959 memset(&devmode->dmFields, 0, devmode->dmSize - FIELD_OFFSET(DEVMODEW, dmFields));
961 if (mode == ENUM_REGISTRY_SETTINGS)
963 TRACE("mode %d (registry) -- getting default mode\n", mode);
964 return read_registry_settings(devmode);
967 if (macdrv_get_displays(&displays, &num_displays))
968 goto failed;
970 if (mode == ENUM_CURRENT_SETTINGS)
972 TRACE("mode %d (current) -- getting current mode\n", mode);
973 display_mode = CGDisplayCopyDisplayMode(displays[0].displayID);
974 display_mode_bpp = display_mode_bits_per_pixel(display_mode);
976 else
978 DWORD count, i;
980 EnterCriticalSection(&modes_section);
982 if (mode == 0 || !modes)
984 if (modes) CFRelease(modes);
985 modes = copy_display_modes(displays[0].displayID);
986 modes_has_8bpp = modes_has_16bpp = FALSE;
988 if (modes)
990 count = CFArrayGetCount(modes);
991 for (i = 0; i < count && !(modes_has_8bpp && modes_has_16bpp); i++)
993 CGDisplayModeRef mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i);
994 int bpp = display_mode_bits_per_pixel(mode);
995 if (bpp == 8)
996 modes_has_8bpp = TRUE;
997 else if (bpp == 16)
998 modes_has_16bpp = TRUE;
1003 display_mode = NULL;
1004 if (modes)
1006 int default_bpp = get_default_bpp();
1007 DWORD seen_modes = 0;
1009 count = CFArrayGetCount(modes);
1010 for (i = 0; i < count; i++)
1012 CGDisplayModeRef candidate = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i);
1014 io_flags = CGDisplayModeGetIOFlags(candidate);
1015 if (!(flags & EDS_RAWMODE) &&
1016 (!(io_flags & kDisplayModeValidFlag) || !(io_flags & kDisplayModeSafeFlag)))
1017 continue;
1019 seen_modes++;
1020 if (seen_modes > mode)
1022 display_mode = (CGDisplayModeRef)CFRetain(candidate);
1023 display_mode_bpp = display_mode_bits_per_pixel(display_mode);
1024 break;
1027 /* We only synthesize modes from those having the default bpp. */
1028 if (display_mode_bits_per_pixel(candidate) != default_bpp)
1029 continue;
1031 if (!modes_has_8bpp)
1033 seen_modes++;
1034 if (seen_modes > mode)
1036 display_mode = (CGDisplayModeRef)CFRetain(candidate);
1037 display_mode_bpp = 8;
1038 synthesized = TRUE;
1039 break;
1043 if (!modes_has_16bpp)
1045 seen_modes++;
1046 if (seen_modes > mode)
1048 display_mode = (CGDisplayModeRef)CFRetain(candidate);
1049 display_mode_bpp = 16;
1050 synthesized = TRUE;
1051 break;
1057 LeaveCriticalSection(&modes_section);
1060 if (!display_mode)
1061 goto failed;
1063 /* We currently only report modes for the primary display, so it's at (0, 0). */
1064 devmode->dmPosition.x = 0;
1065 devmode->dmPosition.y = 0;
1066 devmode->dmFields |= DM_POSITION;
1068 rotation = CGDisplayRotation(displays[0].displayID);
1069 devmode->dmDisplayOrientation = ((int)((rotation / 90) + 0.5)) % 4;
1070 devmode->dmFields |= DM_DISPLAYORIENTATION;
1072 io_flags = CGDisplayModeGetIOFlags(display_mode);
1073 if (io_flags & kDisplayModeStretchedFlag)
1074 devmode->dmDisplayFixedOutput = DMDFO_STRETCH;
1075 else
1076 devmode->dmDisplayFixedOutput = DMDFO_CENTER;
1077 devmode->dmFields |= DM_DISPLAYFIXEDOUTPUT;
1079 devmode->dmBitsPerPel = display_mode_bpp;
1080 if (devmode->dmBitsPerPel)
1081 devmode->dmFields |= DM_BITSPERPEL;
1083 devmode->dmPelsWidth = CGDisplayModeGetWidth(display_mode);
1084 devmode->dmPelsHeight = CGDisplayModeGetHeight(display_mode);
1085 devmode->dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
1087 devmode->dmDisplayFlags = 0;
1088 if (io_flags & kDisplayModeInterlacedFlag)
1089 devmode->dmDisplayFlags |= DM_INTERLACED;
1090 devmode->dmFields |= DM_DISPLAYFLAGS;
1092 devmode->dmDisplayFrequency = CGDisplayModeGetRefreshRate(display_mode);
1093 if (!devmode->dmDisplayFrequency)
1094 devmode->dmDisplayFrequency = 60;
1095 devmode->dmFields |= DM_DISPLAYFREQUENCY;
1097 CFRelease(display_mode);
1098 macdrv_free_displays(displays);
1100 TRACE("mode %d -- %dx%dx%dbpp @%d Hz", mode,
1101 devmode->dmPelsWidth, devmode->dmPelsHeight, devmode->dmBitsPerPel,
1102 devmode->dmDisplayFrequency);
1103 if (devmode->dmDisplayOrientation)
1104 TRACE(" rotated %u degrees", devmode->dmDisplayOrientation * 90);
1105 if (devmode->dmDisplayFixedOutput == DMDFO_STRETCH)
1106 TRACE(" stretched");
1107 if (devmode->dmDisplayFlags & DM_INTERLACED)
1108 TRACE(" interlaced");
1109 if (synthesized)
1110 TRACE(" (synthesized)");
1111 TRACE("\n");
1113 return TRUE;
1115 failed:
1116 TRACE("mode %d -- not present\n", mode);
1117 if (displays) macdrv_free_displays(displays);
1118 SetLastError(ERROR_NO_MORE_FILES);
1119 return FALSE;
1123 /***********************************************************************
1124 * GetDeviceGammaRamp (MACDRV.@)
1126 BOOL macdrv_GetDeviceGammaRamp(PHYSDEV dev, LPVOID ramp)
1128 BOOL ret = FALSE;
1129 DDGAMMARAMP *r = ramp;
1130 struct macdrv_display *displays;
1131 int num_displays;
1132 uint32_t mac_entries;
1133 int win_entries = sizeof(r->red) / sizeof(r->red[0]);
1134 CGGammaValue *red, *green, *blue;
1135 CGError err;
1136 int win_entry;
1138 TRACE("dev %p ramp %p\n", dev, ramp);
1140 if (macdrv_get_displays(&displays, &num_displays))
1142 WARN("failed to get Mac displays\n");
1143 return FALSE;
1146 mac_entries = CGDisplayGammaTableCapacity(displays[0].displayID);
1147 red = HeapAlloc(GetProcessHeap(), 0, mac_entries * sizeof(red[0]) * 3);
1148 if (!red)
1149 goto done;
1150 green = red + mac_entries;
1151 blue = green + mac_entries;
1153 err = CGGetDisplayTransferByTable(displays[0].displayID, mac_entries, red, green,
1154 blue, &mac_entries);
1155 if (err != kCGErrorSuccess)
1157 WARN("failed to get Mac gamma table: %d\n", err);
1158 goto done;
1161 if (mac_entries == win_entries)
1163 for (win_entry = 0; win_entry < win_entries; win_entry++)
1165 r->red[win_entry] = red[win_entry] * 65535 + 0.5;
1166 r->green[win_entry] = green[win_entry] * 65535 + 0.5;
1167 r->blue[win_entry] = blue[win_entry] * 65535 + 0.5;
1170 else
1172 for (win_entry = 0; win_entry < win_entries; win_entry++)
1174 double mac_pos = win_entry * (mac_entries - 1) / (double)(win_entries - 1);
1175 int mac_entry = mac_pos;
1176 double red_value, green_value, blue_value;
1178 if (mac_entry == mac_entries - 1)
1180 red_value = red[mac_entry];
1181 green_value = green[mac_entry];
1182 blue_value = blue[mac_entry];
1184 else
1186 double distance = mac_pos - mac_entry;
1188 red_value = red[mac_entry] * (1 - distance) + red[mac_entry + 1] * distance;
1189 green_value = green[mac_entry] * (1 - distance) + green[mac_entry + 1] * distance;
1190 blue_value = blue[mac_entry] * (1 - distance) + blue[mac_entry + 1] * distance;
1193 r->red[win_entry] = red_value * 65535 + 0.5;
1194 r->green[win_entry] = green_value * 65535 + 0.5;
1195 r->blue[win_entry] = blue_value * 65535 + 0.5;
1199 ret = TRUE;
1201 done:
1202 HeapFree(GetProcessHeap(), 0, red);
1203 macdrv_free_displays(displays);
1204 return ret;
1208 /***********************************************************************
1209 * GetMonitorInfo (MACDRV.@)
1211 BOOL CDECL macdrv_GetMonitorInfo(HMONITOR monitor, LPMONITORINFO info)
1213 static const WCHAR adapter_name[] = { '\\','\\','.','\\','D','I','S','P','L','A','Y','1',0 };
1214 struct macdrv_display *displays;
1215 int num_displays;
1216 CGDirectDisplayID display_id;
1217 int i;
1219 TRACE("%p, %p\n", monitor, info);
1221 if (macdrv_get_displays(&displays, &num_displays))
1223 ERR("couldn't get display list\n");
1224 SetLastError(ERROR_GEN_FAILURE);
1225 return FALSE;
1228 display_id = monitor_to_display_id(monitor);
1229 for (i = 0; i < num_displays; i++)
1231 if (displays[i].displayID == display_id)
1232 break;
1235 if (i < num_displays)
1237 info->rcMonitor = rect_from_cgrect(displays[i].frame);
1238 info->rcWork = rect_from_cgrect(displays[i].work_frame);
1240 info->dwFlags = (i == 0) ? MONITORINFOF_PRIMARY : 0;
1242 if (info->cbSize >= sizeof(MONITORINFOEXW))
1243 lstrcpyW(((MONITORINFOEXW*)info)->szDevice, adapter_name);
1245 TRACE(" -> rcMonitor %s rcWork %s dwFlags %08x\n", wine_dbgstr_rect(&info->rcMonitor),
1246 wine_dbgstr_rect(&info->rcWork), info->dwFlags);
1248 else
1250 ERR("invalid monitor handle\n");
1251 SetLastError(ERROR_INVALID_HANDLE);
1254 macdrv_free_displays(displays);
1255 return (i < num_displays);
1259 /***********************************************************************
1260 * SetDeviceGammaRamp (MACDRV.@)
1262 BOOL macdrv_SetDeviceGammaRamp(PHYSDEV dev, LPVOID ramp)
1264 DDGAMMARAMP *r = ramp;
1265 struct macdrv_display *displays;
1266 int num_displays;
1267 int win_entries = sizeof(r->red) / sizeof(r->red[0]);
1268 CGGammaValue *red, *green, *blue;
1269 int i;
1270 CGError err = kCGErrorFailure;
1272 TRACE("dev %p ramp %p\n", dev, ramp);
1274 if (!allow_set_gamma)
1276 TRACE("disallowed by registry setting\n");
1277 return FALSE;
1280 if (macdrv_get_displays(&displays, &num_displays))
1282 WARN("failed to get Mac displays\n");
1283 return FALSE;
1286 red = HeapAlloc(GetProcessHeap(), 0, win_entries * sizeof(red[0]) * 3);
1287 if (!red)
1288 goto done;
1289 green = red + win_entries;
1290 blue = green + win_entries;
1292 for (i = 0; i < win_entries; i++)
1294 red[i] = r->red[i] / 65535.0;
1295 green[i] = r->green[i] / 65535.0;
1296 blue[i] = r->blue[i] / 65535.0;
1299 err = CGSetDisplayTransferByTable(displays[0].displayID, win_entries, red, green, blue);
1300 if (err != kCGErrorSuccess)
1301 WARN("failed to set display gamma table: %d\n", err);
1303 done:
1304 HeapFree(GetProcessHeap(), 0, red);
1305 macdrv_free_displays(displays);
1306 return (err == kCGErrorSuccess);
1310 /***********************************************************************
1311 * macdrv_displays_changed
1313 * Handler for DISPLAYS_CHANGED events.
1315 void macdrv_displays_changed(const macdrv_event *event)
1317 HWND hwnd = GetDesktopWindow();
1319 /* A system display change will get delivered to all GUI-attached threads,
1320 so the desktop-window-owning thread will get it and all others should
1321 ignore it. A synthesized display change event due to activation
1322 will only get delivered to the activated process. So, it needs to
1323 process it (by sending it to the desktop window). */
1324 if (event->displays_changed.activating ||
1325 GetWindowThreadProcessId(hwnd, NULL) == GetCurrentThreadId())
1327 CGDirectDisplayID mainDisplay = CGMainDisplayID();
1328 CGDisplayModeRef mode = CGDisplayCopyDisplayMode(mainDisplay);
1329 size_t width = CGDisplayModeGetWidth(mode);
1330 size_t height = CGDisplayModeGetHeight(mode);
1331 int mode_bpp = display_mode_bits_per_pixel(mode);
1333 CGDisplayModeRelease(mode);
1334 SendMessageW(hwnd, WM_MACDRV_UPDATE_DESKTOP_RECT, mode_bpp,
1335 MAKELPARAM(width, height));