From 9ae8da6bb4a8f66d55975fa0f14e5e413756d324 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Fri, 1 Nov 2019 21:19:34 +0800 Subject: [PATCH] winex11.drv: Retrieve virtual and primary monitor rectangles from SetupAPI. So that a process can still get the correct virtual and primary monitor rectangles if display devices are reinitialized in another process. Note that we can't use EnumDisplayMonitor() and GetMonitorInfo() here because they are not loaded when loading winex11.drv. Signed-off-by: Zhiyi Zhang Signed-off-by: Alexandre Julliard --- dlls/winex11.drv/display.c | 160 +++++++++++++++++++++++++------------ 1 file changed, 107 insertions(+), 53 deletions(-) diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c index 6c4097a7908..a323b795b81 100644 --- a/dlls/winex11.drv/display.c +++ b/dlls/winex11.drv/display.c @@ -104,33 +104,132 @@ static const WCHAR monitor_hardware_idW[] = { 'D','e','f','a','u','l','t','_','M','o','n','i','t','o','r',0,0}; static struct x11drv_display_device_handler handler; + +/* Cached screen information, protected by screen_section */ +static HKEY video_key; static RECT virtual_screen_rect; static RECT primary_monitor_rect; +static FILETIME last_query_screen_time; +static CRITICAL_SECTION screen_section; +static CRITICAL_SECTION_DEBUG screen_critsect_debug = +{ + 0, 0, &screen_section, + {&screen_critsect_debug.ProcessLocksList, &screen_critsect_debug.ProcessLocksList}, + 0, 0, {(DWORD_PTR)(__FILE__ ": screen_section")} +}; +static CRITICAL_SECTION screen_section = {&screen_critsect_debug, -1, 0, 0, 0, 0}; + +static HANDLE get_display_device_init_mutex(void) +{ + static const WCHAR init_mutexW[] = {'d','i','s','p','l','a','y','_','d','e','v','i','c','e','_','i','n','i','t',0}; + HANDLE mutex = CreateMutexW(NULL, FALSE, init_mutexW); + + WaitForSingleObject(mutex, INFINITE); + return mutex; +} + +static void release_display_device_init_mutex(HANDLE mutex) +{ + ReleaseMutex(mutex); + CloseHandle(mutex); +} + +/* Update screen rectangle cache from SetupAPI if it's outdated, return FALSE on failure and TRUE on success */ +static BOOL update_screen_cache(void) +{ + RECT virtual_rect = {0}, primary_rect = {0}, monitor_rect; + SP_DEVINFO_DATA device_data = {sizeof(device_data)}; + HDEVINFO devinfo = INVALID_HANDLE_VALUE; + FILETIME filetime = {0}; + HANDLE mutex = NULL; + DWORD i = 0; + INT result; + DWORD type; + BOOL ret = FALSE; + + EnterCriticalSection(&screen_section); + if ((!video_key && RegOpenKeyW(HKEY_LOCAL_MACHINE, video_keyW, &video_key)) + || RegQueryInfoKeyW(video_key, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &filetime)) + { + LeaveCriticalSection(&screen_section); + return FALSE; + } + result = CompareFileTime(&filetime, &last_query_screen_time); + LeaveCriticalSection(&screen_section); + if (result < 1) + return TRUE; + + mutex = get_display_device_init_mutex(); + + devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, displayW, NULL, DIGCF_PRESENT); + if (devinfo == INVALID_HANDLE_VALUE) + goto fail; + + while (SetupDiEnumDeviceInfo(devinfo, i++, &device_data)) + { + if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCMONITOR, &type, + (BYTE *)&monitor_rect, sizeof(monitor_rect), NULL, 0)) + goto fail; + + UnionRect(&virtual_rect, &virtual_rect, &monitor_rect); + if (i == 1) + primary_rect = monitor_rect; + } + + EnterCriticalSection(&screen_section); + virtual_screen_rect = virtual_rect; + primary_monitor_rect = primary_rect; + last_query_screen_time = filetime; + LeaveCriticalSection(&screen_section); + ret = TRUE; +fail: + SetupDiDestroyDeviceInfoList(devinfo); + release_display_device_init_mutex(mutex); + if (!ret) + WARN("Update screen cache failed!\n"); + return ret; +} POINT virtual_screen_to_root(INT x, INT y) { + RECT virtual = get_virtual_screen_rect(); POINT pt; - pt.x = x - virtual_screen_rect.left; - pt.y = y - virtual_screen_rect.top; + + pt.x = x - virtual.left; + pt.y = y - virtual.top; return pt; } POINT root_to_virtual_screen(INT x, INT y) { + RECT virtual = get_virtual_screen_rect(); POINT pt; - pt.x = x + virtual_screen_rect.left; - pt.y = y + virtual_screen_rect.top; + + pt.x = x + virtual.left; + pt.y = y + virtual.top; return pt; } RECT get_virtual_screen_rect(void) { - return virtual_screen_rect; + RECT virtual; + + update_screen_cache(); + EnterCriticalSection(&screen_section); + virtual = virtual_screen_rect; + LeaveCriticalSection(&screen_section); + return virtual; } RECT get_primary_monitor_rect(void) { - return primary_monitor_rect; + RECT primary; + + update_screen_cache(); + EnterCriticalSection(&screen_section); + primary = primary_monitor_rect; + LeaveCriticalSection(&screen_section); + return primary; } void X11DRV_DisplayDevices_SetHandler(const struct x11drv_display_device_handler *new_handler) @@ -321,9 +420,6 @@ static BOOL X11DRV_InitMonitor(HDEVINFO devinfo, const struct x11drv_monitor *mo if (!SetupDiSetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCMONITOR, DEVPROP_TYPE_BINARY, (const BYTE *)&monitor->rc_monitor, sizeof(monitor->rc_monitor), 0)) goto done; - UnionRect(&virtual_screen_rect, &virtual_screen_rect, &monitor->rc_monitor); - if (video_index == 0) - primary_monitor_rect = monitor->rc_monitor; /* RcWork */ if (!SetupDiSetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCWORK, DEVPROP_TYPE_BINARY, (const BYTE *)&monitor->rc_work, sizeof(monitor->rc_work), 0)) @@ -348,9 +444,6 @@ static void prepare_devices(HKEY video_hkey) HDEVINFO devinfo; DWORD i = 0; - SetRectEmpty(&virtual_screen_rect); - SetRectEmpty(&primary_monitor_rect); - /* Remove all monitors */ devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, displayW, NULL, 0); while (SetupDiEnumDeviceInfo(devinfo, i++, &device_data)) @@ -399,39 +492,8 @@ static void cleanup_devices(void) SetupDiDestroyDeviceInfoList(devinfo); } -/* Initialize virtual screen rect and primary monitor rect for current process */ -static void init_screen_rects(void) -{ - SP_DEVINFO_DATA device_data = {sizeof(device_data)}; - HDEVINFO devinfo; - DWORD type; - DWORD i = 0; - RECT rect; - - /* Already initialized */ - if (!IsRectEmpty(&virtual_screen_rect)) - return; - - devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, displayW, NULL, 0); - while (SetupDiEnumDeviceInfo(devinfo, i++, &device_data)) - { - if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCMONITOR, &type, (BYTE *)&rect, - sizeof(rect), NULL, 0)) - ERR("Failed to get monitor size property\n"); - - UnionRect(&virtual_screen_rect, &virtual_screen_rect, &rect); - if (i == 1) - primary_monitor_rect = rect; - } - SetupDiDestroyDeviceInfoList(devinfo); - - TRACE("virtual screen rect:%s primary monitor rect:%s\n", wine_dbgstr_rect(&virtual_screen_rect), - wine_dbgstr_rect(&primary_monitor_rect)); -} - void X11DRV_DisplayDevices_Init(BOOL force) { - static const WCHAR init_mutexW[] = {'d','i','s','p','l','a','y','_','d','e','v','i','c','e','_','i','n','i','t',0}; HANDLE mutex; struct x11drv_gpu *gpus = NULL; struct x11drv_adapter *adapters = NULL; @@ -445,8 +507,7 @@ void X11DRV_DisplayDevices_Init(BOOL force) WCHAR guidW[40]; WCHAR driverW[1024]; - mutex = CreateMutexW(NULL, FALSE, init_mutexW); - WaitForSingleObject(mutex, INFINITE); + mutex = get_display_device_init_mutex(); if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, video_keyW, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &video_hkey, &disposition)) @@ -457,10 +518,7 @@ void X11DRV_DisplayDevices_Init(BOOL force) /* Avoid unnecessary reinit */ if (!force && disposition != REG_CREATED_NEW_KEY) - { - init_screen_rects(); goto done; - } TRACE("via %s\n", wine_dbgstr_a(handler.name)); @@ -511,16 +569,12 @@ void X11DRV_DisplayDevices_Init(BOOL force) adapters = NULL; } - TRACE("virtual screen rect:%s primary monitor rect:%s\n", wine_dbgstr_rect(&virtual_screen_rect), - wine_dbgstr_rect(&primary_monitor_rect)); - done: cleanup_devices(); SetupDiDestroyDeviceInfoList(monitor_devinfo); SetupDiDestroyDeviceInfoList(gpu_devinfo); RegCloseKey(video_hkey); - ReleaseMutex(mutex); - CloseHandle(mutex); + release_display_device_init_mutex(mutex); if (gpus) handler.free_gpus(gpus); if (adapters)