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
32 #define WIN32_NO_STATUS
35 WINE_DEFAULT_DEBUG_CHANNEL(display
);
38 struct display_mode_descriptor
46 CFStringRef pixel_encoding
;
50 BOOL
macdrv_EnumDisplaySettingsEx(LPCWSTR devname
, DWORD mode
, LPDEVMODEW devmode
, DWORD flags
);
52 static const WCHAR initial_mode_keyW
[] = {'I','n','i','t','i','a','l',' ','D','i','s','p','l','a','y',
54 static const WCHAR pixelencodingW
[] = {'P','i','x','e','l','E','n','c','o','d','i','n','g',0};
56 static CFArrayRef modes
;
57 static BOOL modes_has_8bpp
, modes_has_16bpp
;
58 static int default_mode_bpp
;
59 static pthread_mutex_t modes_mutex
= PTHREAD_MUTEX_INITIALIZER
;
61 static BOOL inited_original_display_mode
;
64 static int display_mode_bits_per_pixel(CGDisplayModeRef display_mode
)
66 CFStringRef pixel_encoding
;
67 int bits_per_pixel
= 0;
69 pixel_encoding
= CGDisplayModeCopyPixelEncoding(display_mode
);
72 if (CFEqual(pixel_encoding
, CFSTR(kIO32BitFloatPixels
)))
74 else if (CFEqual(pixel_encoding
, CFSTR(kIO16BitFloatPixels
)))
76 else if (CFEqual(pixel_encoding
, CFSTR(kIO64BitDirectPixels
)))
78 else if (CFEqual(pixel_encoding
, CFSTR(kIO30BitDirectPixels
)))
80 else if (CFEqual(pixel_encoding
, CFSTR(IO32BitDirectPixels
)))
82 else if (CFEqual(pixel_encoding
, CFSTR(IO16BitDirectPixels
)))
84 else if (CFEqual(pixel_encoding
, CFSTR(IO8BitIndexedPixels
)))
86 else if (CFEqual(pixel_encoding
, CFSTR(IO4BitIndexedPixels
)))
88 else if (CFEqual(pixel_encoding
, CFSTR(IO2BitIndexedPixels
)))
90 else if (CFEqual(pixel_encoding
, CFSTR(IO1BitIndexedPixels
)))
93 CFRelease(pixel_encoding
);
96 return bits_per_pixel
;
100 static void display_mode_to_devmode(CGDirectDisplayID display_id
, CGDisplayModeRef display_mode
, DEVMODEW
*devmode
)
105 rotation
= CGDisplayRotation(display_id
);
106 devmode
->dmDisplayOrientation
= ((int)((rotation
/ 90) + 0.5)) % 4;
107 devmode
->dmFields
|= DM_DISPLAYORIENTATION
;
109 io_flags
= CGDisplayModeGetIOFlags(display_mode
);
110 if (io_flags
& kDisplayModeStretchedFlag
)
111 devmode
->dmDisplayFixedOutput
= DMDFO_STRETCH
;
113 devmode
->dmDisplayFixedOutput
= DMDFO_CENTER
;
114 devmode
->dmFields
|= DM_DISPLAYFIXEDOUTPUT
;
116 devmode
->dmBitsPerPel
= display_mode_bits_per_pixel(display_mode
);
117 if (devmode
->dmBitsPerPel
)
118 devmode
->dmFields
|= DM_BITSPERPEL
;
120 devmode
->dmPelsWidth
= CGDisplayModeGetWidth(display_mode
);
121 devmode
->dmPelsHeight
= CGDisplayModeGetHeight(display_mode
);
122 devmode
->dmFields
|= DM_PELSWIDTH
| DM_PELSHEIGHT
;
124 devmode
->dmDisplayFlags
= 0;
125 if (io_flags
& kDisplayModeInterlacedFlag
)
126 devmode
->dmDisplayFlags
|= DM_INTERLACED
;
127 devmode
->dmFields
|= DM_DISPLAYFLAGS
;
129 devmode
->dmDisplayFrequency
= CGDisplayModeGetRefreshRate(display_mode
);
130 if (!devmode
->dmDisplayFrequency
)
131 devmode
->dmDisplayFrequency
= 60;
132 devmode
->dmFields
|= DM_DISPLAYFREQUENCY
;
136 static BOOL
set_setting_value(HKEY hkey
, const char *name
, DWORD val
)
139 UNICODE_STRING str
= { asciiz_to_unicode(nameW
, name
) - sizeof(WCHAR
), sizeof(nameW
), nameW
};
140 return !NtSetValueKey(hkey
, &str
, 0, REG_DWORD
, &val
, sizeof(val
));
144 static BOOL
write_display_settings(HKEY parent_hkey
, CGDirectDisplayID displayID
)
147 char display_key_name
[19];
149 CGDisplayModeRef display_mode
;
152 CFStringRef pixel_encoding
;
156 snprintf(display_key_name
, sizeof(display_key_name
), "Display 0x%08x", CGDisplayUnitNumber(displayID
));
157 /* @@ Wine registry key: HKLM\Software\Wine\Mac Driver\Initial Display Mode\Display 0xnnnnnnnn */
158 if (!(display_hkey
= reg_create_ascii_key(parent_hkey
, display_key_name
, REG_OPTION_VOLATILE
, NULL
)))
161 display_mode
= CGDisplayCopyDisplayMode(displayID
);
165 val
= CGDisplayModeGetWidth(display_mode
);
166 if (!set_setting_value(display_hkey
, "Width", val
))
168 val
= CGDisplayModeGetHeight(display_mode
);
169 if (!set_setting_value(display_hkey
, "Height", val
))
171 val
= CGDisplayModeGetRefreshRate(display_mode
) * 100;
172 if (!set_setting_value(display_hkey
, "RefreshRateTimes100", val
))
174 val
= CGDisplayModeGetIOFlags(display_mode
);
175 if (!set_setting_value(display_hkey
, "IOFlags", val
))
178 #if defined(MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
179 if (&CGDisplayModeGetPixelWidth
!= NULL
&& &CGDisplayModeGetPixelHeight
!= NULL
)
181 val
= CGDisplayModeGetPixelWidth(display_mode
);
182 if (!set_setting_value(display_hkey
, "PixelWidth", val
))
184 val
= CGDisplayModeGetPixelHeight(display_mode
);
185 if (!set_setting_value(display_hkey
, "PixelHeight", val
))
190 pixel_encoding
= CGDisplayModeCopyPixelEncoding(display_mode
);
191 len
= CFStringGetLength(pixel_encoding
);
192 buf
= malloc((len
+ 1) * sizeof(WCHAR
));
193 CFStringGetCharacters(pixel_encoding
, CFRangeMake(0, len
), (UniChar
*)buf
);
195 CFRelease(pixel_encoding
);
196 RtlInitUnicodeString(&str
, pixelencodingW
);
197 if (NtSetValueKey(display_hkey
, &str
, 0, REG_SZ
, (const BYTE
*)buf
, (len
+ 1) * sizeof(WCHAR
)))
204 if (display_mode
) CGDisplayModeRelease(display_mode
);
205 NtClose(display_hkey
);
209 reg_delete_tree(parent_hkey
, nameW
, asciiz_to_unicode(nameW
, display_key_name
) - sizeof(WCHAR
));
215 static void init_original_display_mode(void)
217 BOOL success
= FALSE
;
218 HKEY mac_driver_hkey
, parent_hkey
;
220 struct macdrv_display
*displays
= NULL
;
223 if (inited_original_display_mode
)
226 /* @@ Wine registry key: HKLM\Software\Wine\Mac Driver */
227 mac_driver_hkey
= reg_create_ascii_key(NULL
, "\\Registry\\Machine\\Software\\Wine\\Mac Driver",
229 if (!mac_driver_hkey
)
232 /* @@ Wine registry key: HKLM\Software\Wine\Mac Driver\Initial Display Mode */
233 if (!(parent_hkey
= reg_create_key(mac_driver_hkey
, initial_mode_keyW
, sizeof(initial_mode_keyW
),
234 REG_OPTION_VOLATILE
, &disposition
)))
240 /* If we didn't create a new key, then it already existed. Something already stored
241 the initial display mode since Wine was started. We don't want to overwrite it. */
242 if (disposition
!= REG_CREATED_NEW_KEY
)
245 if (macdrv_get_displays(&displays
, &num_displays
))
248 for (i
= 0; i
< num_displays
; i
++)
250 if (!write_display_settings(parent_hkey
, displays
[i
].displayID
))
258 macdrv_free_displays(displays
);
259 NtClose(parent_hkey
);
260 if (!success
&& parent_hkey
)
261 reg_delete_tree(mac_driver_hkey
, initial_mode_keyW
, sizeof(initial_mode_keyW
));
262 NtClose(mac_driver_hkey
);
264 inited_original_display_mode
= TRUE
;
268 static BOOL
read_dword(HKEY hkey
, const char* name
, DWORD
* val
)
270 char buffer
[offsetof(KEY_VALUE_PARTIAL_INFORMATION
, Data
[sizeof(*val
)])];
271 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
273 asciiz_to_unicode(nameW
, name
);
274 if (query_reg_value(hkey
, nameW
, value
, sizeof(buffer
)) != sizeof(*val
) || value
->Type
!= REG_DWORD
)
276 *val
= *(DWORD
*)value
->Data
;
281 static void free_display_mode_descriptor(struct display_mode_descriptor
* desc
)
285 if (desc
->pixel_encoding
)
286 CFRelease(desc
->pixel_encoding
);
292 static struct display_mode_descriptor
* create_original_display_mode_descriptor(CGDirectDisplayID displayID
)
294 static const char display_key_format
[] =
295 "\\Registry\\Machine\\Software\\Wine\\Mac Driver\\Initial Display Mode\\Display 0x%08x";
296 struct display_mode_descriptor
* ret
= NULL
;
297 struct display_mode_descriptor
* desc
;
298 char display_key
[sizeof(display_key_format
) + 10];
299 WCHAR nameW
[ARRAYSIZE(display_key
)];
301 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
305 init_original_display_mode();
307 snprintf(display_key
, sizeof(display_key
), display_key_format
, CGDisplayUnitNumber(displayID
));
308 /* @@ Wine registry key: HKLM\Software\Wine\Mac Driver\Initial Display Mode\Display 0xnnnnnnnn */
309 if (!(hkey
= reg_open_key(NULL
, nameW
, asciiz_to_unicode(nameW
, display_key
))))
312 desc
= malloc(sizeof(*desc
));
313 desc
->pixel_encoding
= NULL
;
315 if (!read_dword(hkey
, "Width", &desc
->width
) ||
316 !read_dword(hkey
, "Height", &desc
->height
) ||
317 !read_dword(hkey
, "RefreshRateTimes100", &refresh100
) ||
318 !read_dword(hkey
, "IOFlags", &desc
->io_flags
))
321 desc
->refresh
= refresh100
/ 100.0;
325 if (!read_dword(hkey
, "PixelWidth", &desc
->pixel_width
) ||
326 !read_dword(hkey
, "PixelHeight", &desc
->pixel_height
))
328 desc
->pixel_width
= desc
->width
;
329 desc
->pixel_height
= desc
->height
;
332 if (!query_reg_value(hkey
, pixelencodingW
, value
, sizeof(buffer
)) || value
->Type
!= REG_SZ
)
334 desc
->pixel_encoding
= CFStringCreateWithCharacters(NULL
, (const UniChar
*)value
->Data
,
335 lstrlenW((const WCHAR
*)value
->Data
));
341 free_display_mode_descriptor(desc
);
347 static BOOL
display_mode_matches_descriptor(CGDisplayModeRef mode
, const struct display_mode_descriptor
* desc
)
351 CFStringRef mode_pixel_encoding
;
356 if (CGDisplayModeGetWidth(mode
) != desc
->width
||
357 CGDisplayModeGetHeight(mode
) != desc
->height
)
360 mode_io_flags
= CGDisplayModeGetIOFlags(mode
);
361 if ((desc
->io_flags
^ mode_io_flags
) & (kDisplayModeValidFlag
| kDisplayModeSafeFlag
| kDisplayModeStretchedFlag
|
362 kDisplayModeInterlacedFlag
| kDisplayModeTelevisionFlag
))
365 mode_refresh
= CGDisplayModeGetRefreshRate(mode
);
368 if (fabs(desc
->refresh
- mode_refresh
) > 0.1)
371 #if defined(MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
372 if (&CGDisplayModeGetPixelWidth
!= NULL
&& &CGDisplayModeGetPixelHeight
!= NULL
)
374 if (CGDisplayModeGetPixelWidth(mode
) != desc
->pixel_width
||
375 CGDisplayModeGetPixelHeight(mode
) != desc
->pixel_height
)
380 if (CGDisplayModeGetWidth(mode
) != desc
->pixel_width
||
381 CGDisplayModeGetHeight(mode
) != desc
->pixel_height
)
384 mode_pixel_encoding
= CGDisplayModeCopyPixelEncoding(mode
);
385 if (!CFEqual(mode_pixel_encoding
, desc
->pixel_encoding
))
387 CFRelease(mode_pixel_encoding
);
390 CFRelease(mode_pixel_encoding
);
396 static int get_default_bpp(void)
400 if (!default_mode_bpp
)
402 CGDisplayModeRef mode
= CGDisplayCopyDisplayMode(kCGDirectMainDisplay
);
405 default_mode_bpp
= display_mode_bits_per_pixel(mode
);
409 if (!default_mode_bpp
)
410 default_mode_bpp
= 32;
413 ret
= default_mode_bpp
;
415 TRACE(" -> %d\n", ret
);
420 static BOOL
display_mode_is_supported(CGDisplayModeRef display_mode
)
422 uint32_t io_flags
= CGDisplayModeGetIOFlags(display_mode
);
423 return (io_flags
& kDisplayModeValidFlag
) && (io_flags
& kDisplayModeSafeFlag
);
427 #if defined(MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
428 static CFDictionaryRef
create_mode_dict(CGDisplayModeRef display_mode
, BOOL is_original
)
431 SInt32 io_flags
= CGDisplayModeGetIOFlags(display_mode
);
432 SInt64 width
= CGDisplayModeGetWidth(display_mode
);
433 SInt64 height
= CGDisplayModeGetHeight(display_mode
);
434 double refresh_rate
= CGDisplayModeGetRefreshRate(display_mode
);
435 CFStringRef pixel_encoding
= CGDisplayModeCopyPixelEncoding(display_mode
);
436 CFNumberRef cf_io_flags
, cf_width
, cf_height
, cf_refresh
;
438 if (retina_enabled
&& is_original
)
444 io_flags
&= kDisplayModeValidFlag
| kDisplayModeSafeFlag
| kDisplayModeInterlacedFlag
|
445 kDisplayModeStretchedFlag
| kDisplayModeTelevisionFlag
;
446 cf_io_flags
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &io_flags
);
447 cf_width
= CFNumberCreate(NULL
, kCFNumberSInt64Type
, &width
);
448 cf_height
= CFNumberCreate(NULL
, kCFNumberSInt64Type
, &height
);
449 cf_refresh
= CFNumberCreate(NULL
, kCFNumberDoubleType
, &refresh_rate
);
452 static const CFStringRef keys
[] = {
456 CFSTR("pixel_encoding"),
457 CFSTR("refresh_rate"),
459 const void* values
[ARRAY_SIZE(keys
)] = {
467 ret
= CFDictionaryCreate(NULL
, (const void**)keys
, (const void**)values
, ARRAY_SIZE(keys
),
468 &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
471 CFRelease(pixel_encoding
);
472 CFRelease(cf_io_flags
);
474 CFRelease(cf_height
);
475 CFRelease(cf_refresh
);
481 static BOOL
mode_is_preferred(CGDisplayModeRef new_mode
, CGDisplayModeRef old_mode
,
482 struct display_mode_descriptor
*original_mode_desc
,
483 BOOL include_unsupported
)
485 BOOL new_is_supported
;
486 CFStringRef pixel_encoding
;
487 size_t width_points
, height_points
;
488 size_t old_width_pixels
, old_height_pixels
, new_width_pixels
, new_height_pixels
;
489 BOOL old_size_same
, new_size_same
;
491 /* If a given mode is the user's default, then always list it in preference to any similar
492 modes that may exist. */
493 if (display_mode_matches_descriptor(new_mode
, original_mode_desc
))
496 /* Skip unsupported modes unless told to do otherwise. */
497 new_is_supported
= display_mode_is_supported(new_mode
);
498 if (!new_is_supported
&& !include_unsupported
)
501 pixel_encoding
= CGDisplayModeCopyPixelEncoding(new_mode
);
504 BOOL bpp30
= CFEqual(pixel_encoding
, CFSTR(kIO30BitDirectPixels
));
505 CFRelease(pixel_encoding
);
508 /* This is an odd pixel encoding. It seems it's only returned
509 when using kCGDisplayShowDuplicateLowResolutionModes. It's
510 32bpp in terms of the actual raster layout, but it's 10
511 bits per component. I think that no Windows program is
512 likely to need it and they will probably be confused by it.
521 /* Prefer the original mode over any similar mode. */
522 if (display_mode_matches_descriptor(old_mode
, original_mode_desc
))
525 /* Prefer supported modes over similar unsupported ones. */
526 if (!new_is_supported
&& display_mode_is_supported(old_mode
))
529 /* Otherwise, prefer a mode whose pixel size equals its point size over one which
531 width_points
= CGDisplayModeGetWidth(new_mode
);
532 height_points
= CGDisplayModeGetHeight(new_mode
);
533 new_width_pixels
= CGDisplayModeGetPixelWidth(new_mode
);
534 new_height_pixels
= CGDisplayModeGetPixelHeight(new_mode
);
535 old_width_pixels
= CGDisplayModeGetPixelWidth(old_mode
);
536 old_height_pixels
= CGDisplayModeGetPixelHeight(old_mode
);
537 new_size_same
= (new_width_pixels
== width_points
&& new_height_pixels
== height_points
);
538 old_size_same
= (old_width_pixels
== width_points
&& old_height_pixels
== height_points
);
540 if (new_size_same
&& !old_size_same
)
543 if (!new_size_same
&& old_size_same
)
546 /* Otherwise, prefer the mode with the smaller pixel size. */
547 return new_width_pixels
< old_width_pixels
&& new_height_pixels
< old_height_pixels
;
552 static CFComparisonResult
mode_compare(const void *p1
, const void *p2
, void *context
)
554 CGDisplayModeRef a
= (CGDisplayModeRef
)p1
, b
= (CGDisplayModeRef
)p2
;
556 double a_refresh_rate
, b_refresh_rate
;
558 /* Sort by bpp descending, */
559 a_val
= display_mode_bits_per_pixel(a
);
560 b_val
= display_mode_bits_per_pixel(b
);
562 return kCFCompareGreaterThan
;
563 else if (a_val
> b_val
)
564 return kCFCompareLessThan
;
566 /* then width ascending, */
567 a_val
= CGDisplayModeGetWidth(a
);
568 b_val
= CGDisplayModeGetWidth(b
);
570 return kCFCompareLessThan
;
571 else if (a_val
> b_val
)
572 return kCFCompareGreaterThan
;
574 /* then height ascending, */
575 a_val
= CGDisplayModeGetHeight(a
);
576 b_val
= CGDisplayModeGetHeight(b
);
578 return kCFCompareLessThan
;
579 else if (a_val
> b_val
)
580 return kCFCompareGreaterThan
;
582 /* then refresh rate descending. */
583 a_refresh_rate
= CGDisplayModeGetRefreshRate(a
);
584 b_refresh_rate
= CGDisplayModeGetRefreshRate(b
);
585 if (a_refresh_rate
< b_refresh_rate
)
586 return kCFCompareGreaterThan
;
587 else if (a_refresh_rate
> b_refresh_rate
)
588 return kCFCompareLessThan
;
590 return kCFCompareEqualTo
;
594 /***********************************************************************
597 * Wrapper around CGDisplayCopyAllDisplayModes() to include additional
598 * modes on Retina-capable systems, but filter those which would confuse
599 * Windows apps (basically duplicates at different DPIs).
601 * For example, some Retina Macs support a 1920x1200 mode, but it's not
602 * returned from CGDisplayCopyAllDisplayModes() without special options.
603 * This is especially bad if that's the user's default mode, since then
604 * no "available" mode matches the initial settings.
606 * If include_unsupported is FALSE, display modes with IO flags that
607 * indicate that they are invalid or unsafe are filtered.
609 static CFArrayRef
copy_display_modes(CGDirectDisplayID display
, BOOL include_unsupported
)
611 CFArrayRef modes
= NULL
;
613 #if defined(MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
614 if (&CGDisplayModeGetPixelWidth
!= NULL
&& &CGDisplayModeGetPixelHeight
!= NULL
)
616 CFDictionaryRef options
;
617 struct display_mode_descriptor
* desc
;
618 CFMutableDictionaryRef modes_by_size
;
620 CGDisplayModeRef
* mode_array
;
622 options
= CFDictionaryCreate(NULL
, (const void**)&kCGDisplayShowDuplicateLowResolutionModes
,
623 (const void**)&kCFBooleanTrue
, 1, &kCFTypeDictionaryKeyCallBacks
,
624 &kCFTypeDictionaryValueCallBacks
);
626 modes
= CGDisplayCopyAllDisplayModes(display
, options
);
632 desc
= create_original_display_mode_descriptor(display
);
634 modes_by_size
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
635 count
= CFArrayGetCount(modes
);
636 for (i
= 0; i
< count
; i
++)
638 CGDisplayModeRef new_mode
= (CGDisplayModeRef
)CFArrayGetValueAtIndex(modes
, i
);
639 BOOL new_is_original
= display_mode_matches_descriptor(new_mode
, desc
);
640 CFDictionaryRef key
= create_mode_dict(new_mode
, new_is_original
);
641 CGDisplayModeRef old_mode
= (CGDisplayModeRef
)CFDictionaryGetValue(modes_by_size
, key
);
643 if (mode_is_preferred(new_mode
, old_mode
, desc
, include_unsupported
))
644 CFDictionarySetValue(modes_by_size
, key
, new_mode
);
649 free_display_mode_descriptor(desc
);
652 count
= CFDictionaryGetCount(modes_by_size
);
653 mode_array
= malloc(count
* sizeof(mode_array
[0]));
654 CFDictionaryGetKeysAndValues(modes_by_size
, NULL
, (const void **)mode_array
);
655 modes
= CFArrayCreate(NULL
, (const void **)mode_array
, count
, &kCFTypeArrayCallBacks
);
657 CFRelease(modes_by_size
);
661 modes
= CGDisplayCopyAllDisplayModes(display
, NULL
);
665 CFIndex count
= CFArrayGetCount(modes
);
666 CFMutableArrayRef sorted_modes
= CFArrayCreateMutableCopy(NULL
, count
, modes
);
668 CFArraySortValues(sorted_modes
, CFRangeMake(0, count
), mode_compare
, NULL
);
676 void check_retina_status(void)
680 struct display_mode_descriptor
* desc
= create_original_display_mode_descriptor(kCGDirectMainDisplay
);
681 CGDisplayModeRef mode
= CGDisplayCopyDisplayMode(kCGDirectMainDisplay
);
682 BOOL new_value
= display_mode_matches_descriptor(mode
, desc
);
684 CGDisplayModeRelease(mode
);
685 free_display_mode_descriptor(desc
);
687 if (new_value
!= retina_on
)
688 macdrv_set_cocoa_retina_mode(new_value
);
692 static BOOL
get_primary_adapter(WCHAR
*name
)
698 for (i
= 0; !NtUserEnumDisplayDevices(NULL
, i
, &dd
, 0); ++i
)
700 if (dd
.StateFlags
& DISPLAY_DEVICE_PRIMARY_DEVICE
)
702 lstrcpyW(name
, dd
.DeviceName
);
710 static BOOL
is_detached_mode(const DEVMODEW
*mode
)
712 return mode
->dmFields
& DM_POSITION
&&
713 mode
->dmFields
& DM_PELSWIDTH
&&
714 mode
->dmFields
& DM_PELSHEIGHT
&&
715 mode
->dmPelsWidth
== 0 &&
716 mode
->dmPelsHeight
== 0;
719 static CGDisplayModeRef
find_best_display_mode(DEVMODEW
*devmode
, CFArrayRef display_modes
, int bpp
, struct display_mode_descriptor
*desc
)
721 CFIndex count
, i
, best
;
722 CGDisplayModeRef best_display_mode
;
723 uint32_t best_io_flags
;
725 best_display_mode
= NULL
;
727 count
= CFArrayGetCount(display_modes
);
728 for (i
= 0; i
< count
; i
++)
730 CGDisplayModeRef display_mode
= (CGDisplayModeRef
)CFArrayGetValueAtIndex(display_modes
, i
);
731 BOOL is_original
= display_mode_matches_descriptor(display_mode
, desc
);
732 uint32_t io_flags
= CGDisplayModeGetIOFlags(display_mode
);
733 int mode_bpp
= display_mode_bits_per_pixel(display_mode
);
734 size_t width
= CGDisplayModeGetWidth(display_mode
);
735 size_t height
= CGDisplayModeGetHeight(display_mode
);
737 if (is_original
&& retina_enabled
)
746 if (devmode
->dmFields
& DM_PELSWIDTH
)
748 if (devmode
->dmPelsWidth
!= width
)
751 if (devmode
->dmFields
& DM_PELSHEIGHT
)
753 if (devmode
->dmPelsHeight
!= height
)
756 if ((devmode
->dmFields
& DM_DISPLAYFREQUENCY
) &&
757 devmode
->dmDisplayFrequency
!= 0 &&
758 devmode
->dmDisplayFrequency
!= 1)
760 double refresh_rate
= CGDisplayModeGetRefreshRate(display_mode
);
763 if (devmode
->dmDisplayFrequency
!= (DWORD
)refresh_rate
)
766 if (devmode
->dmFields
& DM_DISPLAYFLAGS
)
768 if (!(devmode
->dmDisplayFlags
& DM_INTERLACED
) != !(io_flags
& kDisplayModeInterlacedFlag
))
771 else if (best_display_mode
)
773 if (io_flags
& kDisplayModeInterlacedFlag
&& !(best_io_flags
& kDisplayModeInterlacedFlag
))
775 else if (!(io_flags
& kDisplayModeInterlacedFlag
) && best_io_flags
& kDisplayModeInterlacedFlag
)
778 if (devmode
->dmFields
& DM_DISPLAYFIXEDOUTPUT
)
780 if (!(devmode
->dmDisplayFixedOutput
== DMDFO_STRETCH
) != !(io_flags
& kDisplayModeStretchedFlag
))
783 else if (best_display_mode
)
785 if (io_flags
& kDisplayModeStretchedFlag
&& !(best_io_flags
& kDisplayModeStretchedFlag
))
787 else if (!(io_flags
& kDisplayModeStretchedFlag
) && best_io_flags
& kDisplayModeStretchedFlag
)
791 if (best_display_mode
)
795 best_display_mode
= display_mode
;
797 best_io_flags
= io_flags
;
800 if (best_display_mode
)
801 TRACE("Requested display settings match mode %ld\n", best
);
803 return best_display_mode
;
806 /***********************************************************************
807 * ChangeDisplaySettingsEx (MACDRV.@)
810 LONG
macdrv_ChangeDisplaySettingsEx(LPCWSTR devname
, LPDEVMODEW devmode
,
811 HWND hwnd
, DWORD flags
, LPVOID lpvoid
)
813 WCHAR primary_adapter
[CCHDEVICENAME
];
814 LONG ret
= DISP_CHANGE_BADMODE
;
815 DEVMODEW default_mode
;
817 struct macdrv_display
*displays
;
819 CFArrayRef display_modes
;
820 struct display_mode_descriptor
*desc
;
821 CGDisplayModeRef best_display_mode
;
823 TRACE("%s %p %p 0x%08x %p\n", debugstr_w(devname
), devmode
, hwnd
, flags
, lpvoid
);
825 init_original_display_mode();
827 if (!get_primary_adapter(primary_adapter
))
828 return DISP_CHANGE_FAILED
;
830 if (!devname
&& !devmode
)
833 memset(&default_mode
, 0, sizeof(default_mode
));
834 default_mode
.dmSize
= sizeof(default_mode
);
835 RtlInitUnicodeString(&str
, primary_adapter
);
836 if (!NtUserEnumDisplaySettings(&str
, ENUM_REGISTRY_SETTINGS
, &default_mode
, 0))
838 ERR("Default mode not found for %s!\n", wine_dbgstr_w(primary_adapter
));
839 return DISP_CHANGE_BADMODE
;
842 devname
= primary_adapter
;
843 devmode
= &default_mode
;
846 if (is_detached_mode(devmode
))
848 FIXME("Detaching adapters is currently unsupported.\n");
849 return DISP_CHANGE_SUCCESSFUL
;
852 if (macdrv_get_displays(&displays
, &num_displays
))
853 return DISP_CHANGE_FAILED
;
855 display_modes
= copy_display_modes(displays
[0].displayID
, FALSE
);
858 macdrv_free_displays(displays
);
859 return DISP_CHANGE_FAILED
;
862 pthread_mutex_lock(&modes_mutex
);
863 bpp
= get_default_bpp();
864 pthread_mutex_unlock(&modes_mutex
);
865 if ((devmode
->dmFields
& DM_BITSPERPEL
) && devmode
->dmBitsPerPel
!= bpp
)
866 TRACE("using default %d bpp instead of caller's request %d bpp\n", bpp
, devmode
->dmBitsPerPel
);
868 TRACE("looking for %dx%dx%dbpp @%d Hz",
869 (devmode
->dmFields
& DM_PELSWIDTH
? devmode
->dmPelsWidth
: 0),
870 (devmode
->dmFields
& DM_PELSHEIGHT
? devmode
->dmPelsHeight
: 0),
872 (devmode
->dmFields
& DM_DISPLAYFREQUENCY
? devmode
->dmDisplayFrequency
: 0));
873 if (devmode
->dmFields
& DM_DISPLAYFIXEDOUTPUT
)
874 TRACE(" %sstretched", devmode
->dmDisplayFixedOutput
== DMDFO_STRETCH
? "" : "un");
875 if (devmode
->dmFields
& DM_DISPLAYFLAGS
)
876 TRACE(" %sinterlaced", devmode
->dmDisplayFlags
& DM_INTERLACED
? "" : "non-");
879 desc
= create_original_display_mode_descriptor(displays
[0].displayID
);
880 best_display_mode
= find_best_display_mode(devmode
, display_modes
, bpp
, desc
);
882 if (best_display_mode
)
884 if (flags
& (CDS_TEST
| CDS_NORESET
)) ret
= DISP_CHANGE_SUCCESSFUL
;
885 else if (wcsicmp(primary_adapter
, devname
))
887 FIXME("Changing non-primary adapter settings is currently unsupported.\n");
888 ret
= DISP_CHANGE_SUCCESSFUL
;
890 else if (macdrv_set_display_mode(&displays
[0], best_display_mode
))
892 int mode_bpp
= display_mode_bits_per_pixel(best_display_mode
);
893 size_t width
= CGDisplayModeGetWidth(best_display_mode
);
894 size_t height
= CGDisplayModeGetHeight(best_display_mode
);
896 macdrv_init_display_devices(TRUE
);
898 if (retina_enabled
&& display_mode_matches_descriptor(best_display_mode
, desc
))
904 send_message(NtUserGetDesktopWindow(), WM_MACDRV_UPDATE_DESKTOP_RECT
, mode_bpp
,
905 MAKELPARAM(width
, height
));
906 ret
= DISP_CHANGE_SUCCESSFUL
;
910 WARN("Failed to set display mode\n");
911 ret
= DISP_CHANGE_FAILED
;
916 /* no valid modes found */
917 ERR("No matching mode found %ux%ux%d @%u!\n", devmode
->dmPelsWidth
, devmode
->dmPelsHeight
,
918 bpp
, devmode
->dmDisplayFrequency
);
921 free_display_mode_descriptor(desc
);
922 CFRelease(display_modes
);
923 macdrv_free_displays(displays
);
929 static DEVMODEW
*display_get_modes(CGDirectDisplayID display_id
, int *modes_count
)
931 int default_bpp
= get_default_bpp(), synth_count
= 0, count
, i
;
932 BOOL modes_has_8bpp
= FALSE
, modes_has_16bpp
= FALSE
;
933 struct display_mode_descriptor
*desc
;
937 modes
= copy_display_modes(display_id
, TRUE
);
941 count
= CFArrayGetCount(modes
);
942 for (i
= 0; i
< count
&& !(modes_has_8bpp
&& modes_has_16bpp
); i
++)
944 CGDisplayModeRef mode
= (CGDisplayModeRef
)CFArrayGetValueAtIndex(modes
, i
);
945 int bpp
= display_mode_bits_per_pixel(mode
);
947 modes_has_8bpp
= TRUE
;
949 modes_has_16bpp
= TRUE
;
952 if (!(devmodes
= calloc(count
* 3, sizeof(DEVMODEW
))))
958 desc
= create_original_display_mode_descriptor(display_id
);
959 for (i
= 0; i
< count
; i
++)
961 CGDisplayModeRef mode
= (CGDisplayModeRef
)CFArrayGetValueAtIndex(modes
, i
);
962 display_mode_to_devmode(display_id
, mode
, devmodes
+ i
);
964 if (retina_enabled
&& display_mode_matches_descriptor(mode
, desc
))
966 devmodes
[i
].dmPelsWidth
*= 2;
967 devmodes
[i
].dmPelsHeight
*= 2;
970 free_display_mode_descriptor(desc
);
972 for (i
= 0; !modes_has_16bpp
&& i
< count
; i
++)
974 /* We only synthesize modes from those having the default bpp. */
975 if (devmodes
[i
].dmBitsPerPel
!= default_bpp
) continue;
976 devmodes
[count
+ synth_count
] = devmodes
[i
];
977 devmodes
[count
+ synth_count
].dmBitsPerPel
= 16;
981 for (i
= 0; !modes_has_8bpp
&& i
< count
; i
++)
983 /* We only synthesize modes from those having the default bpp. */
984 if (devmodes
[i
].dmBitsPerPel
!= default_bpp
) continue;
985 devmodes
[count
+ synth_count
] = devmodes
[i
];
986 devmodes
[count
+ synth_count
].dmBitsPerPel
= 8;
991 *modes_count
= count
+ synth_count
;
995 /***********************************************************************
996 * EnumDisplaySettingsEx (MACDRV.@)
999 BOOL
macdrv_EnumDisplaySettingsEx(LPCWSTR devname
, DWORD mode
, LPDEVMODEW devmode
, DWORD flags
)
1001 struct macdrv_display
*displays
= NULL
;
1003 CGDisplayModeRef display_mode
;
1004 int display_mode_bpp
;
1005 BOOL synthesized
= FALSE
;
1008 TRACE("%s, %u, %p + %hu, %08x\n", debugstr_w(devname
), mode
, devmode
, devmode
->dmSize
, flags
);
1010 init_original_display_mode();
1012 if (macdrv_get_displays(&displays
, &num_displays
))
1015 pthread_mutex_lock(&modes_mutex
);
1017 if (mode
== 0 || !modes
)
1019 if (modes
) CFRelease(modes
);
1020 modes
= copy_display_modes(displays
[0].displayID
, (flags
& EDS_RAWMODE
) != 0);
1021 modes_has_8bpp
= modes_has_16bpp
= FALSE
;
1025 count
= CFArrayGetCount(modes
);
1026 for (i
= 0; i
< count
&& !(modes_has_8bpp
&& modes_has_16bpp
); i
++)
1028 CGDisplayModeRef mode
= (CGDisplayModeRef
)CFArrayGetValueAtIndex(modes
, i
);
1029 int bpp
= display_mode_bits_per_pixel(mode
);
1031 modes_has_8bpp
= TRUE
;
1033 modes_has_16bpp
= TRUE
;
1038 display_mode
= NULL
;
1042 DWORD seen_modes
= 0;
1044 count
= CFArrayGetCount(modes
);
1045 for (i
= 0; i
< count
; i
++)
1047 CGDisplayModeRef candidate
= (CGDisplayModeRef
)CFArrayGetValueAtIndex(modes
, i
);
1050 if (seen_modes
> mode
)
1052 display_mode
= (CGDisplayModeRef
)CFRetain(candidate
);
1053 display_mode_bpp
= display_mode_bits_per_pixel(display_mode
);
1058 default_bpp
= get_default_bpp();
1060 /* If all the real modes are exhausted, synthesize lower bpp modes. */
1061 if (!display_mode
&& (!modes_has_16bpp
|| !modes_has_8bpp
))
1063 /* We want to synthesize higher depths first. */
1064 int synth_bpps
[] = { modes_has_16bpp
? 0 : 16, modes_has_8bpp
? 0 : 8 };
1065 size_t synth_bpp_idx
;
1066 for (synth_bpp_idx
= 0; synth_bpp_idx
< 2; synth_bpp_idx
++)
1068 int synth_bpp
= synth_bpps
[synth_bpp_idx
];
1072 for (i
= 0; i
< count
; i
++)
1074 CGDisplayModeRef candidate
= (CGDisplayModeRef
)CFArrayGetValueAtIndex(modes
, i
);
1075 /* We only synthesize modes from those having the default bpp. */
1076 if (display_mode_bits_per_pixel(candidate
) != default_bpp
)
1080 if (seen_modes
> mode
)
1082 display_mode
= (CGDisplayModeRef
)CFRetain(candidate
);
1083 display_mode_bpp
= synth_bpp
;
1095 pthread_mutex_unlock(&modes_mutex
);
1100 display_mode_to_devmode(displays
[0].displayID
, display_mode
, devmode
);
1101 devmode
->dmBitsPerPel
= display_mode_bpp
;
1102 if (devmode
->dmBitsPerPel
)
1103 devmode
->dmFields
|= DM_BITSPERPEL
;
1106 struct display_mode_descriptor
* desc
= create_original_display_mode_descriptor(displays
[0].displayID
);
1107 if (display_mode_matches_descriptor(display_mode
, desc
))
1109 devmode
->dmPelsWidth
*= 2;
1110 devmode
->dmPelsHeight
*= 2;
1112 free_display_mode_descriptor(desc
);
1115 CFRelease(display_mode
);
1116 macdrv_free_displays(displays
);
1118 TRACE("mode %d -- %dx%dx%dbpp @%d Hz", mode
,
1119 devmode
->dmPelsWidth
, devmode
->dmPelsHeight
, devmode
->dmBitsPerPel
,
1120 devmode
->dmDisplayFrequency
);
1121 if (devmode
->dmDisplayOrientation
)
1122 TRACE(" rotated %u degrees", devmode
->dmDisplayOrientation
* 90);
1123 if (devmode
->dmDisplayFixedOutput
== DMDFO_STRETCH
)
1124 TRACE(" stretched");
1125 if (devmode
->dmDisplayFlags
& DM_INTERLACED
)
1126 TRACE(" interlaced");
1128 TRACE(" (synthesized)");
1134 TRACE("mode %d -- not present\n", mode
);
1135 if (displays
) macdrv_free_displays(displays
);
1136 RtlSetLastWin32Error(ERROR_NO_MORE_FILES
);
1140 /***********************************************************************
1141 * GetCurrentDisplaySettings (MACDRV.@)
1144 BOOL
macdrv_GetCurrentDisplaySettings(LPCWSTR devname
, LPDEVMODEW devmode
)
1146 struct macdrv_display
*displays
= NULL
;
1148 CGDisplayModeRef display_mode
;
1150 TRACE("%s, %p + %hu\n", debugstr_w(devname
), devmode
, devmode
->dmSize
);
1152 init_original_display_mode();
1154 if (macdrv_get_displays(&displays
, &num_displays
))
1157 display_mode
= CGDisplayCopyDisplayMode(displays
[0].displayID
);
1159 /* We currently only report modes for the primary display, so it's at (0, 0). */
1160 devmode
->dmPosition
.x
= 0;
1161 devmode
->dmPosition
.y
= 0;
1162 devmode
->dmFields
|= DM_POSITION
;
1164 display_mode_to_devmode(displays
[0].displayID
, display_mode
, devmode
);
1167 struct display_mode_descriptor
*desc
= create_original_display_mode_descriptor(displays
[0].displayID
);
1168 if (display_mode_matches_descriptor(display_mode
, desc
))
1170 devmode
->dmPelsWidth
*= 2;
1171 devmode
->dmPelsHeight
*= 2;
1173 free_display_mode_descriptor(desc
);
1176 CFRelease(display_mode
);
1177 macdrv_free_displays(displays
);
1179 TRACE("current mode -- %dx%dx%dbpp @%d Hz",
1180 devmode
->dmPelsWidth
, devmode
->dmPelsHeight
, devmode
->dmBitsPerPel
,
1181 devmode
->dmDisplayFrequency
);
1182 if (devmode
->dmDisplayOrientation
)
1183 TRACE(" rotated %u degrees", devmode
->dmDisplayOrientation
* 90);
1184 if (devmode
->dmDisplayFixedOutput
== DMDFO_STRETCH
)
1185 TRACE(" stretched");
1186 if (devmode
->dmDisplayFlags
& DM_INTERLACED
)
1187 TRACE(" interlaced");
1194 /***********************************************************************
1195 * GetDeviceGammaRamp (MACDRV.@)
1197 BOOL
macdrv_GetDeviceGammaRamp(PHYSDEV dev
, LPVOID ramp
)
1200 DDGAMMARAMP
*r
= ramp
;
1201 struct macdrv_display
*displays
;
1203 uint32_t mac_entries
;
1204 int win_entries
= ARRAY_SIZE(r
->red
);
1205 CGGammaValue
*red
, *green
, *blue
;
1209 TRACE("dev %p ramp %p\n", dev
, ramp
);
1211 if (macdrv_get_displays(&displays
, &num_displays
))
1213 WARN("failed to get Mac displays\n");
1217 mac_entries
= CGDisplayGammaTableCapacity(displays
[0].displayID
);
1218 red
= malloc(mac_entries
* sizeof(red
[0]) * 3);
1221 green
= red
+ mac_entries
;
1222 blue
= green
+ mac_entries
;
1224 err
= CGGetDisplayTransferByTable(displays
[0].displayID
, mac_entries
, red
, green
,
1225 blue
, &mac_entries
);
1226 if (err
!= kCGErrorSuccess
)
1228 WARN("failed to get Mac gamma table: %d\n", err
);
1232 if (mac_entries
== win_entries
)
1234 for (win_entry
= 0; win_entry
< win_entries
; win_entry
++)
1236 r
->red
[win_entry
] = red
[win_entry
] * 65535 + 0.5;
1237 r
->green
[win_entry
] = green
[win_entry
] * 65535 + 0.5;
1238 r
->blue
[win_entry
] = blue
[win_entry
] * 65535 + 0.5;
1243 for (win_entry
= 0; win_entry
< win_entries
; win_entry
++)
1245 double mac_pos
= win_entry
* (mac_entries
- 1) / (double)(win_entries
- 1);
1246 int mac_entry
= mac_pos
;
1247 double red_value
, green_value
, blue_value
;
1249 if (mac_entry
== mac_entries
- 1)
1251 red_value
= red
[mac_entry
];
1252 green_value
= green
[mac_entry
];
1253 blue_value
= blue
[mac_entry
];
1257 double distance
= mac_pos
- mac_entry
;
1259 red_value
= red
[mac_entry
] * (1 - distance
) + red
[mac_entry
+ 1] * distance
;
1260 green_value
= green
[mac_entry
] * (1 - distance
) + green
[mac_entry
+ 1] * distance
;
1261 blue_value
= blue
[mac_entry
] * (1 - distance
) + blue
[mac_entry
+ 1] * distance
;
1264 r
->red
[win_entry
] = red_value
* 65535 + 0.5;
1265 r
->green
[win_entry
] = green_value
* 65535 + 0.5;
1266 r
->blue
[win_entry
] = blue_value
* 65535 + 0.5;
1274 macdrv_free_displays(displays
);
1278 /***********************************************************************
1279 * SetDeviceGammaRamp (MACDRV.@)
1281 BOOL
macdrv_SetDeviceGammaRamp(PHYSDEV dev
, LPVOID ramp
)
1283 DDGAMMARAMP
*r
= ramp
;
1284 struct macdrv_display
*displays
;
1286 int win_entries
= ARRAY_SIZE(r
->red
);
1287 CGGammaValue
*red
, *green
, *blue
;
1289 CGError err
= kCGErrorFailure
;
1291 TRACE("dev %p ramp %p\n", dev
, ramp
);
1293 if (!allow_set_gamma
)
1295 TRACE("disallowed by registry setting\n");
1299 if (macdrv_get_displays(&displays
, &num_displays
))
1301 WARN("failed to get Mac displays\n");
1305 red
= malloc(win_entries
* sizeof(red
[0]) * 3);
1308 green
= red
+ win_entries
;
1309 blue
= green
+ win_entries
;
1311 for (i
= 0; i
< win_entries
; i
++)
1313 red
[i
] = r
->red
[i
] / 65535.0;
1314 green
[i
] = r
->green
[i
] / 65535.0;
1315 blue
[i
] = r
->blue
[i
] / 65535.0;
1318 err
= CGSetDisplayTransferByTable(displays
[0].displayID
, win_entries
, red
, green
, blue
);
1319 if (err
!= kCGErrorSuccess
)
1320 WARN("failed to set display gamma table: %d\n", err
);
1324 macdrv_free_displays(displays
);
1325 return (err
== kCGErrorSuccess
);
1328 /***********************************************************************
1329 * init_registry_display_settings
1331 * Initialize registry display settings when new display devices are added.
1333 static void init_registry_display_settings(void)
1335 DEVMODEW dm
= {.dmSize
= sizeof(dm
)};
1336 DISPLAY_DEVICEW dd
= {sizeof(dd
)};
1341 while (!NtUserEnumDisplayDevices(NULL
, i
++, &dd
, 0))
1343 RtlInitUnicodeString(&str
, dd
.DeviceName
);
1345 /* Skip if the device already has registry display settings */
1346 if (NtUserEnumDisplaySettings(&str
, ENUM_REGISTRY_SETTINGS
, &dm
, 0))
1349 if (!NtUserEnumDisplaySettings(&str
, ENUM_CURRENT_SETTINGS
, &dm
, 0))
1351 ERR("Failed to query current display settings for %s.\n", wine_dbgstr_w(dd
.DeviceName
));
1355 TRACE("Device %s current display mode %ux%u %ubits %uHz at %d,%d.\n",
1356 wine_dbgstr_w(dd
.DeviceName
), dm
.dmPelsWidth
, dm
.dmPelsHeight
, dm
.dmBitsPerPel
,
1357 dm
.dmDisplayFrequency
, dm
.dmPosition
.x
, dm
.dmPosition
.y
);
1359 ret
= NtUserChangeDisplaySettings(&str
, &dm
, NULL
,
1360 CDS_GLOBAL
| CDS_NORESET
| CDS_UPDATEREGISTRY
, NULL
);
1361 if (ret
!= DISP_CHANGE_SUCCESSFUL
)
1362 ERR("Failed to save registry display settings for %s, returned %d.\n",
1363 wine_dbgstr_w(dd
.DeviceName
), ret
);
1367 /***********************************************************************
1368 * macdrv_displays_changed
1370 * Handler for DISPLAYS_CHANGED events.
1372 void macdrv_displays_changed(const macdrv_event
*event
)
1374 HWND hwnd
= NtUserGetDesktopWindow();
1376 /* A system display change will get delivered to all GUI-attached threads,
1377 so the desktop-window-owning thread will get it and all others should
1378 ignore it. A synthesized display change event due to activation
1379 will only get delivered to the activated process. So, it needs to
1380 process it (by sending it to the desktop window). */
1381 if (event
->displays_changed
.activating
||
1382 NtUserGetWindowThread(hwnd
, NULL
) == GetCurrentThreadId())
1384 CGDirectDisplayID mainDisplay
= CGMainDisplayID();
1385 CGDisplayModeRef mode
= CGDisplayCopyDisplayMode(mainDisplay
);
1386 size_t width
= CGDisplayModeGetWidth(mode
);
1387 size_t height
= CGDisplayModeGetHeight(mode
);
1388 int mode_bpp
= display_mode_bits_per_pixel(mode
);
1389 struct display_mode_descriptor
* desc
= create_original_display_mode_descriptor(mainDisplay
);
1390 BOOL is_original
= display_mode_matches_descriptor(mode
, desc
);
1392 free_display_mode_descriptor(desc
);
1393 CGDisplayModeRelease(mode
);
1395 macdrv_init_display_devices(TRUE
);
1396 init_registry_display_settings();
1398 if (is_original
&& retina_enabled
)
1404 send_message(hwnd
, WM_MACDRV_UPDATE_DESKTOP_RECT
, mode_bpp
,
1405 MAKELPARAM(width
, height
));
1409 static BOOL force_display_devices_refresh
;
1411 BOOL
macdrv_UpdateDisplayDevices( const struct gdi_device_manager
*device_manager
, BOOL force
, void *param
)
1413 struct macdrv_adapter
*adapters
, *adapter
;
1414 struct macdrv_monitor
*monitors
, *monitor
;
1415 struct macdrv_gpu
*gpus
, *gpu
;
1416 INT gpu_count
, adapter_count
, monitor_count
, mode_count
;
1417 DEVMODEW
*mode
, *modes
;
1420 if (!force
&& !force_display_devices_refresh
) return TRUE
;
1421 force_display_devices_refresh
= FALSE
;
1423 /* Initialize GPUs */
1424 if (macdrv_get_gpus(&gpus
, &gpu_count
))
1426 ERR("could not get GPUs\n");
1429 TRACE("GPU count: %d\n", gpu_count
);
1431 for (gpu
= gpus
; gpu
< gpus
+ gpu_count
; gpu
++)
1433 struct gdi_gpu gdi_gpu
=
1436 .vendor_id
= gpu
->vendor_id
,
1437 .device_id
= gpu
->device_id
,
1438 .subsys_id
= gpu
->subsys_id
,
1439 .revision_id
= gpu
->revision_id
,
1441 RtlUTF8ToUnicodeN(gdi_gpu
.name
, sizeof(gdi_gpu
.name
), &len
, gpu
->name
, strlen(gpu
->name
));
1442 device_manager
->add_gpu(&gdi_gpu
, param
);
1444 /* Initialize adapters */
1445 if (macdrv_get_adapters(gpu
->id
, &adapters
, &adapter_count
)) break;
1446 TRACE("GPU: %llx %s, adapter count: %d\n", gpu
->id
, debugstr_a(gpu
->name
), adapter_count
);
1448 for (adapter
= adapters
; adapter
< adapters
+ adapter_count
; adapter
++)
1450 struct gdi_adapter gdi_adapter
=
1453 .state_flags
= adapter
->state_flags
,
1455 device_manager
->add_adapter( &gdi_adapter
, param
);
1457 if (macdrv_get_monitors(adapter
->id
, &monitors
, &monitor_count
)) break;
1458 TRACE("adapter: %#x, monitor count: %d\n", adapter
->id
, monitor_count
);
1460 /* Initialize monitors */
1461 for (monitor
= monitors
; monitor
< monitors
+ monitor_count
; monitor
++)
1463 struct gdi_monitor gdi_monitor
=
1465 .rc_monitor
= rect_from_cgrect(monitor
->rc_monitor
),
1466 .rc_work
= rect_from_cgrect(monitor
->rc_work
),
1467 .state_flags
= monitor
->state_flags
,
1469 RtlUTF8ToUnicodeN(gdi_monitor
.name
, sizeof(gdi_monitor
.name
), &len
,
1470 monitor
->name
, strlen(monitor
->name
));
1471 TRACE("monitor: %s\n", debugstr_a(monitor
->name
));
1472 device_manager
->add_monitor( &gdi_monitor
, param
);
1475 if (!(modes
= display_get_modes(adapter
->id
, &mode_count
))) break;
1476 TRACE("adapter: %#x, mode count: %d\n", adapter
->id
, mode_count
);
1478 /* Initialize modes */
1479 for (mode
= modes
; mode
< modes
+ mode_count
; mode
++)
1481 TRACE("mode: %dx%dx%dbpp @%d Hz, %sstretched %sinterlaced\n", mode
->dmPelsWidth
, mode
->dmPelsHeight
,
1482 mode
->dmBitsPerPel
, mode
->dmDisplayFrequency
,
1483 mode
->dmDisplayFixedOutput
== DMDFO_STRETCH
? "" : "un",
1484 mode
->dmDisplayFlags
& DM_INTERLACED
? "" : "non-");
1485 device_manager
->add_mode( mode
, param
);
1488 macdrv_free_monitors(monitors
);
1491 macdrv_free_adapters(adapters
);
1494 macdrv_free_gpus(gpus
);
1498 /***********************************************************************
1499 * macdrv_init_display_devices
1501 * Initialize display device registry data.
1503 void macdrv_init_display_devices(BOOL force
)
1505 UINT32 num_path
, num_mode
;
1507 if (force
) force_display_devices_refresh
= TRUE
;
1508 /* trigger refresh in win32u */
1509 NtUserGetDisplayConfigBufferSizes( QDC_ONLY_ACTIVE_PATHS
, &num_path
, &num_mode
);