From 4f4ac0cafcf0a1db61939bd146d8f6d077b3be7b Mon Sep 17 00:00:00 2001 From: Ken Thomases Date: Sun, 17 Feb 2013 19:28:42 -0600 Subject: [PATCH] winemac: Implement EnumDisplaySettingsEx(). --- dlls/winemac.drv/display.c | 221 ++++++++++++++++++++++++++++++ dlls/winemac.drv/winemac.drv.spec | 1 + 2 files changed, 222 insertions(+) diff --git a/dlls/winemac.drv/display.c b/dlls/winemac.drv/display.c index 2a966311f53..afa0646d6aa 100644 --- a/dlls/winemac.drv/display.c +++ b/dlls/winemac.drv/display.c @@ -23,10 +23,22 @@ #include "macdrv.h" #include "winuser.h" +#include "winreg.h" WINE_DEFAULT_DEBUG_CHANNEL(display); +static CFArrayRef modes; +static CRITICAL_SECTION modes_section; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &modes_section, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": modes_section") } +}; +static CRITICAL_SECTION modes_section = { &critsect_debug, -1, 0, 0, 0, 0 }; + + static inline HMONITOR display_id_to_monitor(CGDirectDisplayID display_id) { return (HMONITOR)(UINT_PTR)display_id; @@ -38,6 +50,73 @@ static inline CGDirectDisplayID monitor_to_display_id(HMONITOR handle) } +static BOOL get_display_device_reg_key(char *key, unsigned len) +{ + static const char display_device_guid_prop[] = "__wine_display_device_guid"; + static const char video_path[] = "System\\CurrentControlSet\\Control\\Video\\{"; + static const char display0[] = "}\\0000"; + ATOM guid_atom; + + assert(len >= sizeof(video_path) + sizeof(display0) + 40); + + guid_atom = HandleToULong(GetPropA(GetDesktopWindow(), display_device_guid_prop)); + if (!guid_atom) return FALSE; + + memcpy(key, video_path, sizeof(video_path)); + + if (!GlobalGetAtomNameA(guid_atom, key + strlen(key), 40)) + return FALSE; + + strcat(key, display0); + + TRACE("display device key %s\n", wine_dbgstr_a(key)); + return TRUE; +} + + +static BOOL read_registry_settings(DEVMODEW *dm) +{ + char wine_mac_reg_key[128]; + HKEY hkey; + DWORD type, size; + BOOL ret = TRUE; + + dm->dmFields = 0; + + if (!get_display_device_reg_key(wine_mac_reg_key, sizeof(wine_mac_reg_key))) + return FALSE; + + if (RegOpenKeyExA(HKEY_CURRENT_CONFIG, wine_mac_reg_key, 0, KEY_READ, &hkey)) + return FALSE; + +#define query_value(name, data) \ + size = sizeof(DWORD); \ + if (RegQueryValueExA(hkey, name, 0, &type, (LPBYTE)(data), &size) || \ + type != REG_DWORD || size != sizeof(DWORD)) \ + ret = FALSE + + query_value("DefaultSettings.BitsPerPel", &dm->dmBitsPerPel); + dm->dmFields |= DM_BITSPERPEL; + query_value("DefaultSettings.XResolution", &dm->dmPelsWidth); + dm->dmFields |= DM_PELSWIDTH; + query_value("DefaultSettings.YResolution", &dm->dmPelsHeight); + dm->dmFields |= DM_PELSHEIGHT; + query_value("DefaultSettings.VRefresh", &dm->dmDisplayFrequency); + dm->dmFields |= DM_DISPLAYFREQUENCY; + query_value("DefaultSettings.Flags", &dm->dmDisplayFlags); + dm->dmFields |= DM_DISPLAYFLAGS; + query_value("DefaultSettings.XPanning", &dm->dmPosition.x); + query_value("DefaultSettings.YPanning", &dm->dmPosition.y); + query_value("DefaultSettings.Orientation", &dm->dmDisplayOrientation); + query_value("DefaultSettings.FixedOutput", &dm->dmDisplayFixedOutput); + +#undef query_value + + RegCloseKey(hkey); + return ret; +} + + static int display_mode_bits_per_pixel(CGDisplayModeRef display_mode) { CFStringRef pixel_encoding; @@ -143,6 +222,148 @@ BOOL CDECL macdrv_EnumDisplayMonitors(HDC hdc, LPRECT rect, MONITORENUMPROC proc } +/*********************************************************************** + * 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; + double rotation; + uint32_t io_flags; + + TRACE("%s, %u, %p + %hu, %08x\n", debugstr_w(devname), mode, devmode, devmode->dmSize, flags); + + 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); + } + else + { + EnterCriticalSection(&modes_section); + + if (mode == 0 || !modes) + { + if (modes) CFRelease(modes); + modes = CGDisplayCopyAllDisplayModes(displays[0].displayID, NULL); + } + + display_mode = NULL; + if (modes) + { + if (flags & EDS_RAWMODE) + { + if (mode < CFArrayGetCount(modes)) + display_mode = (CGDisplayModeRef)CFRetain(CFArrayGetValueAtIndex(modes, mode)); + } + else + { + DWORD count, i, safe_modes = 0; + count = CFArrayGetCount(modes); + for (i = 0; i < count; i++) + { + CGDisplayModeRef candidate = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i); + io_flags = CGDisplayModeGetIOFlags(candidate); + if ((io_flags & kDisplayModeValidFlag) && + (io_flags & kDisplayModeSafeFlag)) + { + safe_modes++; + if (safe_modes > mode) + { + display_mode = (CGDisplayModeRef)CFRetain(candidate); + 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_bits_per_pixel(display_mode); + if (devmode->dmBitsPerPel) + devmode->dmFields |= DM_BITSPERPEL; + + devmode->dmPelsWidth = CGDisplayModeGetWidth(display_mode); + devmode->dmPelsHeight = CGDisplayModeGetHeight(display_mode); + 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"); + 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; +} + + /*********************************************************************** * GetMonitorInfo (MACDRV.@) */ diff --git a/dlls/winemac.drv/winemac.drv.spec b/dlls/winemac.drv/winemac.drv.spec index 57b1e5a74c4..d8412836ef2 100644 --- a/dlls/winemac.drv/winemac.drv.spec +++ b/dlls/winemac.drv/winemac.drv.spec @@ -10,6 +10,7 @@ @ cdecl CreateWindow(long) macdrv_CreateWindow @ cdecl DestroyWindow(long) macdrv_DestroyWindow @ cdecl EnumDisplayMonitors(long ptr ptr long) macdrv_EnumDisplayMonitors +@ cdecl EnumDisplaySettingsEx(ptr long ptr long) macdrv_EnumDisplaySettingsEx @ cdecl GetKeyboardLayout(long) macdrv_GetKeyboardLayout @ cdecl GetKeyboardLayoutName(ptr) macdrv_GetKeyboardLayoutName @ cdecl GetKeyNameText(long ptr long) macdrv_GetKeyNameText