/*********************************************************************** * macdrv_displays_changed * * Handler for DISPLAYS_CHANGED events. */ void macdrv_displays_changed(const macdrv_event *event) { HWND hwnd = GetDesktopWindow(); /* A system display change will get delivered to all GUI-attached threads, so the desktop-window-owning thread will get it and all others should ignore it. A synthesized display change event due to activation will only get delivered to the activated process. So, it needs to process it (by sending it to the desktop window). */ if (event->displays_changed.activating || GetWindowThreadProcessId(hwnd, NULL) == GetCurrentThreadId()) { CGDirectDisplayID mainDisplay = CGMainDisplayID(); CGDisplayModeRef mode = CGDisplayCopyDisplayMode(mainDisplay); size_t width = CGDisplayModeGetWidth(mode); size_t height = CGDisplayModeGetHeight(mode); int mode_bpp = display_mode_bits_per_pixel(mode); struct display_mode_descriptor* desc = create_original_display_mode_descriptor(mainDisplay); BOOL is_original = display_mode_matches_descriptor(mode, desc); free_display_mode_descriptor(desc); CGDisplayModeRelease(mode); if (is_original && retina_enabled) { width *= 2; height *= 2; } SendMessageW(hwnd, WM_MACDRV_UPDATE_DESKTOP_RECT, mode_bpp, MAKELPARAM(width, height)); } }
void check_retina_status(void) { if (retina_enabled) { struct display_mode_descriptor* desc = create_original_display_mode_descriptor(kCGDirectMainDisplay); CGDisplayModeRef mode = CGDisplayCopyDisplayMode(kCGDirectMainDisplay); BOOL new_value = display_mode_matches_descriptor(mode, desc); CGDisplayModeRelease(mode); free_display_mode_descriptor(desc); if (new_value != retina_on) macdrv_set_cocoa_retina_mode(new_value); } }
/*********************************************************************** * copy_display_modes * * Wrapper around CGDisplayCopyAllDisplayModes() to include additional * modes on Retina-capable systems, but filter those which would confuse * Windows apps (basically duplicates at different DPIs). * * For example, some Retina Macs support a 1920x1200 mode, but it's not * returned from CGDisplayCopyAllDisplayModes() without special options. * This is especially bad if that's the user's default mode, since then * no "available" mode matches the initial settings. */ static CFArrayRef copy_display_modes(CGDirectDisplayID display) { CFArrayRef modes = NULL; #if defined(MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 if (&kCGDisplayShowDuplicateLowResolutionModes != NULL && CGDisplayModeGetPixelWidth != NULL && CGDisplayModeGetPixelHeight != NULL) { CFDictionaryRef options; struct display_mode_descriptor* desc; CFMutableDictionaryRef modes_by_size; CFIndex i, count; CGDisplayModeRef* mode_array; options = CFDictionaryCreate(NULL, (const void**)&kCGDisplayShowDuplicateLowResolutionModes, (const void**)&kCFBooleanTrue, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); modes = CGDisplayCopyAllDisplayModes(display, options); if (options) CFRelease(options); if (!modes) return NULL; desc = create_original_display_mode_descriptor(display); modes_by_size = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); count = CFArrayGetCount(modes); for (i = 0; i < count; i++) { BOOL better = TRUE; CGDisplayModeRef new_mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i); BOOL new_is_original = display_mode_matches_descriptor(new_mode, desc); CFDictionaryRef key = create_mode_dict(new_mode); /* If a given mode is the user's default, then always list it in preference to any similar modes that may exist. */ if (new_is_original) better = TRUE; else { CFStringRef pixel_encoding = CGDisplayModeCopyPixelEncoding(new_mode); CGDisplayModeRef old_mode; if (pixel_encoding) { BOOL bpp30 = CFEqual(pixel_encoding, CFSTR(kIO30BitDirectPixels)); CFRelease(pixel_encoding); if (bpp30) { /* This is an odd pixel encoding. It seems it's only returned when using kCGDisplayShowDuplicateLowResolutionModes. It's 32bpp in terms of the actual raster layout, but it's 10 bits per component. I think that no Windows program is likely to need it and they will probably be confused by it. Skip it. */ CFRelease(key); continue; } } old_mode = (CGDisplayModeRef)CFDictionaryGetValue(modes_by_size, key); if (old_mode) { BOOL old_is_original = display_mode_matches_descriptor(old_mode, desc); if (old_is_original) better = FALSE; else { /* Otherwise, prefer a mode whose pixel size equals its point size over one which is scaled. */ size_t width_points = CGDisplayModeGetWidth(new_mode); size_t height_points = CGDisplayModeGetHeight(new_mode); size_t new_width_pixels = CGDisplayModeGetPixelWidth(new_mode); size_t new_height_pixels = CGDisplayModeGetPixelHeight(new_mode); size_t old_width_pixels = CGDisplayModeGetPixelWidth(old_mode); size_t old_height_pixels = CGDisplayModeGetPixelHeight(old_mode); BOOL new_size_same = (new_width_pixels == width_points && new_height_pixels == height_points); BOOL old_size_same = (old_width_pixels == width_points && old_height_pixels == height_points); if (new_size_same && !old_size_same) better = TRUE; else if (!new_size_same && old_size_same) better = FALSE; else { /* Otherwise, prefer the mode with the smaller pixel size. */ if (old_width_pixels < new_width_pixels || old_height_pixels < new_height_pixels) better = FALSE; } } } } if (better) CFDictionarySetValue(modes_by_size, key, new_mode); CFRelease(key); } free_display_mode_descriptor(desc); CFRelease(modes); count = CFDictionaryGetCount(modes_by_size); mode_array = HeapAlloc(GetProcessHeap(), 0, count * sizeof(mode_array[0])); CFDictionaryGetKeysAndValues(modes_by_size, NULL, (const void **)mode_array); modes = CFArrayCreate(NULL, (const void **)mode_array, count, &kCFTypeArrayCallBacks); HeapFree(GetProcessHeap(), 0, mode_array); CFRelease(modes_by_size); } else #endif modes = CGDisplayCopyAllDisplayModes(display, NULL); return modes; }
/*********************************************************************** * EnumDisplaySettingsEx (MACDRV.@) * */ BOOL CDECL macdrv_EnumDisplaySettingsEx(LPCWSTR devname, DWORD mode, LPDEVMODEW devmode, DWORD flags) { static const WCHAR dev_name[CCHDEVICENAME] = { 'W','i','n','e',' ','M','a','c',' ','d','r','i','v','e','r',0 }; struct macdrv_display *displays = NULL; int num_displays; CGDisplayModeRef display_mode; int display_mode_bpp; BOOL synthesized = FALSE; double rotation; uint32_t io_flags; TRACE("%s, %u, %p + %hu, %08x\n", debugstr_w(devname), mode, devmode, devmode->dmSize, flags); init_original_display_mode(); memcpy(devmode->dmDeviceName, dev_name, sizeof(dev_name)); devmode->dmSpecVersion = DM_SPECVERSION; devmode->dmDriverVersion = DM_SPECVERSION; devmode->dmSize = FIELD_OFFSET(DEVMODEW, dmICMMethod); devmode->dmDriverExtra = 0; memset(&devmode->dmFields, 0, devmode->dmSize - FIELD_OFFSET(DEVMODEW, dmFields)); if (mode == ENUM_REGISTRY_SETTINGS) { TRACE("mode %d (registry) -- getting default mode\n", mode); return read_registry_settings(devmode); } if (macdrv_get_displays(&displays, &num_displays)) goto failed; if (mode == ENUM_CURRENT_SETTINGS) { TRACE("mode %d (current) -- getting current mode\n", mode); display_mode = CGDisplayCopyDisplayMode(displays[0].displayID); display_mode_bpp = display_mode_bits_per_pixel(display_mode); } else { DWORD count, i; EnterCriticalSection(&modes_section); if (mode == 0 || !modes) { if (modes) CFRelease(modes); modes = copy_display_modes(displays[0].displayID); modes_has_8bpp = modes_has_16bpp = FALSE; if (modes) { count = CFArrayGetCount(modes); for (i = 0; i < count && !(modes_has_8bpp && modes_has_16bpp); i++) { CGDisplayModeRef mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i); int bpp = display_mode_bits_per_pixel(mode); if (bpp == 8) modes_has_8bpp = TRUE; else if (bpp == 16) modes_has_16bpp = TRUE; } } } display_mode = NULL; if (modes) { int default_bpp = get_default_bpp(); DWORD seen_modes = 0; count = CFArrayGetCount(modes); for (i = 0; i < count; i++) { CGDisplayModeRef candidate = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i); io_flags = CGDisplayModeGetIOFlags(candidate); if (!(flags & EDS_RAWMODE) && (!(io_flags & kDisplayModeValidFlag) || !(io_flags & kDisplayModeSafeFlag))) continue; seen_modes++; if (seen_modes > mode) { display_mode = (CGDisplayModeRef)CFRetain(candidate); display_mode_bpp = display_mode_bits_per_pixel(display_mode); break; } /* We only synthesize modes from those having the default bpp. */ if (display_mode_bits_per_pixel(candidate) != default_bpp) continue; if (!modes_has_8bpp) { seen_modes++; if (seen_modes > mode) { display_mode = (CGDisplayModeRef)CFRetain(candidate); display_mode_bpp = 8; synthesized = TRUE; break; } } if (!modes_has_16bpp) { seen_modes++; if (seen_modes > mode) { display_mode = (CGDisplayModeRef)CFRetain(candidate); display_mode_bpp = 16; synthesized = TRUE; break; } } } } LeaveCriticalSection(&modes_section); } if (!display_mode) goto failed; /* We currently only report modes for the primary display, so it's at (0, 0). */ devmode->dmPosition.x = 0; devmode->dmPosition.y = 0; devmode->dmFields |= DM_POSITION; rotation = CGDisplayRotation(displays[0].displayID); devmode->dmDisplayOrientation = ((int)((rotation / 90) + 0.5)) % 4; devmode->dmFields |= DM_DISPLAYORIENTATION; io_flags = CGDisplayModeGetIOFlags(display_mode); if (io_flags & kDisplayModeStretchedFlag) devmode->dmDisplayFixedOutput = DMDFO_STRETCH; else devmode->dmDisplayFixedOutput = DMDFO_CENTER; devmode->dmFields |= DM_DISPLAYFIXEDOUTPUT; devmode->dmBitsPerPel = display_mode_bpp; if (devmode->dmBitsPerPel) devmode->dmFields |= DM_BITSPERPEL; devmode->dmPelsWidth = CGDisplayModeGetWidth(display_mode); devmode->dmPelsHeight = CGDisplayModeGetHeight(display_mode); if (retina_enabled) { struct display_mode_descriptor* desc = create_original_display_mode_descriptor(displays[0].displayID); if (display_mode_matches_descriptor(display_mode, desc)) { devmode->dmPelsWidth *= 2; devmode->dmPelsHeight *= 2; } free_display_mode_descriptor(desc); } devmode->dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT; devmode->dmDisplayFlags = 0; if (io_flags & kDisplayModeInterlacedFlag) devmode->dmDisplayFlags |= DM_INTERLACED; devmode->dmFields |= DM_DISPLAYFLAGS; devmode->dmDisplayFrequency = CGDisplayModeGetRefreshRate(display_mode); if (!devmode->dmDisplayFrequency) devmode->dmDisplayFrequency = 60; devmode->dmFields |= DM_DISPLAYFREQUENCY; CFRelease(display_mode); macdrv_free_displays(displays); TRACE("mode %d -- %dx%dx%dbpp @%d Hz", mode, devmode->dmPelsWidth, devmode->dmPelsHeight, devmode->dmBitsPerPel, devmode->dmDisplayFrequency); if (devmode->dmDisplayOrientation) TRACE(" rotated %u degrees", devmode->dmDisplayOrientation * 90); if (devmode->dmDisplayFixedOutput == DMDFO_STRETCH) TRACE(" stretched"); if (devmode->dmDisplayFlags & DM_INTERLACED) TRACE(" interlaced"); if (synthesized) TRACE(" (synthesized)"); TRACE("\n"); return TRUE; failed: TRACE("mode %d -- not present\n", mode); if (displays) macdrv_free_displays(displays); SetLastError(ERROR_NO_MORE_FILES); return FALSE; }
/*********************************************************************** * ChangeDisplaySettingsEx (MACDRV.@) * */ LONG CDECL macdrv_ChangeDisplaySettingsEx(LPCWSTR devname, LPDEVMODEW devmode, HWND hwnd, DWORD flags, LPVOID lpvoid) { LONG ret = DISP_CHANGE_BADMODE; int bpp; DEVMODEW dm; BOOL def_mode = TRUE; struct macdrv_display *displays; int num_displays; CFArrayRef display_modes; struct display_mode_descriptor* desc; CFIndex count, i, safe, best; CGDisplayModeRef best_display_mode; uint32_t best_io_flags; BOOL best_is_original; TRACE("%s %p %p 0x%08x %p\n", debugstr_w(devname), devmode, hwnd, flags, lpvoid); init_original_display_mode(); if (devmode) { /* this is the minimal dmSize that XP accepts */ if (devmode->dmSize < FIELD_OFFSET(DEVMODEW, dmFields)) return DISP_CHANGE_FAILED; if (devmode->dmSize >= FIELD_OFFSET(DEVMODEW, dmFields) + sizeof(devmode->dmFields)) { if (((devmode->dmFields & DM_BITSPERPEL) && devmode->dmBitsPerPel) || ((devmode->dmFields & DM_PELSWIDTH) && devmode->dmPelsWidth) || ((devmode->dmFields & DM_PELSHEIGHT) && devmode->dmPelsHeight) || ((devmode->dmFields & DM_DISPLAYFREQUENCY) && devmode->dmDisplayFrequency)) def_mode = FALSE; } } if (def_mode) { if (!macdrv_EnumDisplaySettingsEx(devname, ENUM_REGISTRY_SETTINGS, &dm, 0)) { ERR("Default mode not found!\n"); return DISP_CHANGE_BADMODE; } TRACE("Return to original display mode\n"); devmode = &dm; } if ((devmode->dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != (DM_PELSWIDTH | DM_PELSHEIGHT)) { WARN("devmode doesn't specify the resolution: %04x\n", devmode->dmFields); return DISP_CHANGE_BADMODE; } if (macdrv_get_displays(&displays, &num_displays)) return DISP_CHANGE_FAILED; display_modes = copy_display_modes(displays[0].displayID); if (!display_modes) { macdrv_free_displays(displays); return DISP_CHANGE_FAILED; } bpp = get_default_bpp(); if ((devmode->dmFields & DM_BITSPERPEL) && devmode->dmBitsPerPel != bpp) TRACE("using default %d bpp instead of caller's request %d bpp\n", bpp, devmode->dmBitsPerPel); TRACE("looking for %dx%dx%dbpp @%d Hz", (devmode->dmFields & DM_PELSWIDTH ? devmode->dmPelsWidth : 0), (devmode->dmFields & DM_PELSHEIGHT ? devmode->dmPelsHeight : 0), bpp, (devmode->dmFields & DM_DISPLAYFREQUENCY ? devmode->dmDisplayFrequency : 0)); if (devmode->dmFields & DM_DISPLAYFIXEDOUTPUT) TRACE(" %sstretched", devmode->dmDisplayFixedOutput == DMDFO_STRETCH ? "" : "un"); if (devmode->dmFields & DM_DISPLAYFLAGS) TRACE(" %sinterlaced", devmode->dmDisplayFlags & DM_INTERLACED ? "" : "non-"); TRACE("\n"); desc = create_original_display_mode_descriptor(displays[0].displayID); safe = -1; best_display_mode = NULL; count = CFArrayGetCount(display_modes); for (i = 0; i < count; i++) { CGDisplayModeRef display_mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(display_modes, i); BOOL is_original = display_mode_matches_descriptor(display_mode, desc); uint32_t io_flags = CGDisplayModeGetIOFlags(display_mode); int mode_bpp = display_mode_bits_per_pixel(display_mode); size_t width = CGDisplayModeGetWidth(display_mode); size_t height = CGDisplayModeGetHeight(display_mode); if (is_original && retina_enabled) { width *= 2; height *= 2; } if (!(io_flags & kDisplayModeValidFlag) || !(io_flags & kDisplayModeSafeFlag)) continue; safe++; if (bpp != mode_bpp) continue; if (devmode->dmFields & DM_PELSWIDTH) { if (devmode->dmPelsWidth != width) continue; } if (devmode->dmFields & DM_PELSHEIGHT) { if (devmode->dmPelsHeight != height) continue; } if ((devmode->dmFields & DM_DISPLAYFREQUENCY) && devmode->dmDisplayFrequency != 0) { double refresh_rate = CGDisplayModeGetRefreshRate(display_mode); if (!refresh_rate) refresh_rate = 60; if (devmode->dmDisplayFrequency != (DWORD)refresh_rate) continue; } if (devmode->dmFields & DM_DISPLAYFLAGS) { if (!(devmode->dmDisplayFlags & DM_INTERLACED) != !(io_flags & kDisplayModeInterlacedFlag)) continue; } else if (best_display_mode) { if (io_flags & kDisplayModeInterlacedFlag && !(best_io_flags & kDisplayModeInterlacedFlag)) continue; else if (!(io_flags & kDisplayModeInterlacedFlag) && best_io_flags & kDisplayModeInterlacedFlag) goto better; } if (devmode->dmFields & DM_DISPLAYFIXEDOUTPUT) { if (!(devmode->dmDisplayFixedOutput == DMDFO_STRETCH) != !(io_flags & kDisplayModeStretchedFlag)) continue; } else if (best_display_mode) { if (io_flags & kDisplayModeStretchedFlag && !(best_io_flags & kDisplayModeStretchedFlag)) continue; else if (!(io_flags & kDisplayModeStretchedFlag) && best_io_flags & kDisplayModeStretchedFlag) goto better; } if (best_display_mode) continue; better: best_display_mode = display_mode; best = safe; best_io_flags = io_flags; best_is_original = is_original; } if (best_display_mode) { /* we have a valid mode */ TRACE("Requested display settings match mode %ld\n", best); if ((flags & CDS_UPDATEREGISTRY) && !write_registry_settings(devmode)) { WARN("Failed to update registry\n"); ret = DISP_CHANGE_NOTUPDATED; } else if (flags & (CDS_TEST | CDS_NORESET)) ret = DISP_CHANGE_SUCCESSFUL; else if (macdrv_set_display_mode(&displays[0], best_display_mode)) { int mode_bpp = display_mode_bits_per_pixel(best_display_mode); size_t width = CGDisplayModeGetWidth(best_display_mode); size_t height = CGDisplayModeGetHeight(best_display_mode); if (best_is_original && retina_enabled) { width *= 2; height *= 2; } SendMessageW(GetDesktopWindow(), WM_MACDRV_UPDATE_DESKTOP_RECT, mode_bpp, MAKELPARAM(width, height)); ret = DISP_CHANGE_SUCCESSFUL; } else { WARN("Failed to set display mode\n"); ret = DISP_CHANGE_FAILED; } } else { /* no valid modes found */ ERR("No matching mode found %ux%ux%d @%u!\n", devmode->dmPelsWidth, devmode->dmPelsHeight, bpp, devmode->dmDisplayFrequency); } free_display_mode_descriptor(desc); CFRelease(display_modes); macdrv_free_displays(displays); return ret; }