[PATCH 2/3] winex11.drv: Retrieve virtual and primary monitor rectangles from SetupAPI.

Zhiyi Zhang zzhang at codeweavers.com
Tue Oct 22 05:43:23 CDT 2019


Please ignore this. It somehow could trigger a hang of window managers during
XGrabServer() and XUnGrabServer(). Sorry for the trouble.

On 10/8/19 10:42 PM, Zhiyi Zhang wrote:
> 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 <zzhang at codeweavers.com>
> ---
>  dlls/winex11.drv/display.c | 162 +++++++++++++++++++++++++------------
>  1 file changed, 109 insertions(+), 53 deletions(-)
>
> diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c
> index 6c4097a790..5b0b062ff6 100644
> --- a/dlls/winex11.drv/display.c
> +++ b/dlls/winex11.drv/display.c
> @@ -104,33 +104,134 @@ 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 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 rect 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;
> +    HKEY video_key;
> +    HANDLE mutex;
> +    DWORD i = 0;
> +    INT result;
> +    DWORD type;
> +    LSTATUS lr;
> +    BOOL ret = FALSE;
> +
> +    if (RegOpenKeyW(HKEY_LOCAL_MACHINE, video_keyW, &video_key))
> +        return FALSE;
> +    lr = RegQueryInfoKeyW(video_key, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &filetime);
> +    RegCloseKey(video_key);
> +    if (lr)
> +        return FALSE;
> +
> +    EnterCriticalSection(&screen_section);
> +    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)
> +        ERR("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 +422,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 +446,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 +494,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 +509,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 +520,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 +571,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)




More information about the wine-devel mailing list