winex11.drv: Use a separate virtual desktop display device handler.

If we want to query host monitor dimensions, we need to use XRandR
or Xinerama handler. However when in virtual desktop mode, its display
device handler overrides other handlers. So we need to separate them.
Then we can implement features that require host monitor dimensions like
checking whether the virtual desktop window is fullscreen.

Signed-off-by: Zhiyi Zhang <zzhang@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zhiyi Zhang 2019-11-05 21:04:27 +08:00 committed by Alexandre Julliard
parent 99d047724e
commit 914b5519b1
4 changed files with 127 additions and 42 deletions

View File

@ -27,6 +27,7 @@
/* avoid conflict with field names in included win32 headers */ /* avoid conflict with field names in included win32 headers */
#undef Status #undef Status
#include "wine/debug.h" #include "wine/debug.h"
#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(x11drv); WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
@ -36,6 +37,8 @@ static unsigned int dd_mode_count;
static unsigned int max_width; static unsigned int max_width;
static unsigned int max_height; static unsigned int max_height;
static unsigned int desktop_width;
static unsigned int desktop_height;
static struct screen_size { static struct screen_size {
unsigned int width; unsigned int width;
@ -146,6 +149,88 @@ static LONG X11DRV_desktop_SetCurrentMode(int mode)
return DISP_CHANGE_SUCCESSFUL; return DISP_CHANGE_SUCCESSFUL;
} }
static void query_desktop_work_area( RECT *rc_work )
{
static const WCHAR trayW[] = {'S','h','e','l','l','_','T','r','a','y','W','n','d',0};
RECT rect;
HWND hwnd = FindWindowW( trayW, NULL );
if (!hwnd || !IsWindowVisible( hwnd )) return;
if (!GetWindowRect( hwnd, &rect )) return;
if (rect.top) rc_work->bottom = rect.top;
else rc_work->top = rect.bottom;
TRACE( "found tray %p %s work area %s\n", hwnd, wine_dbgstr_rect( &rect ), wine_dbgstr_rect( rc_work ) );
}
static BOOL X11DRV_desktop_get_gpus( struct x11drv_gpu **new_gpus, int *count )
{
static const WCHAR wine_adapterW[] = {'W','i','n','e',' ','A','d','a','p','t','e','r',0};
struct x11drv_gpu *gpu;
gpu = heap_calloc( 1, sizeof(*gpu) );
if (!gpu) return FALSE;
lstrcpyW( gpu->name, wine_adapterW );
*new_gpus = gpu;
*count = 1;
return TRUE;
}
static void X11DRV_desktop_free_gpus( struct x11drv_gpu *gpus )
{
heap_free( gpus );
}
/* TODO: Support multi-head virtual desktop */
static BOOL X11DRV_desktop_get_adapters( ULONG_PTR gpu_id, struct x11drv_adapter **new_adapters, int *count )
{
struct x11drv_adapter *adapter;
adapter = heap_calloc( 1, sizeof(*adapter) );
if (!adapter) return FALSE;
adapter->state_flags = DISPLAY_DEVICE_PRIMARY_DEVICE;
if (desktop_width && desktop_height)
adapter->state_flags |= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP;
*new_adapters = adapter;
*count = 1;
return TRUE;
}
static void X11DRV_desktop_free_adapters( struct x11drv_adapter *adapters )
{
heap_free( adapters );
}
static BOOL X11DRV_desktop_get_monitors( ULONG_PTR adapter_id, struct x11drv_monitor **new_monitors, int *count )
{
static const WCHAR generic_nonpnp_monitorW[] = {
'G','e','n','e','r','i','c',' ',
'N','o','n','-','P','n','P',' ','M','o','n','i','t','o','r',0};
struct x11drv_monitor *monitor;
monitor = heap_calloc( 1, sizeof(*monitor) );
if (!monitor) return FALSE;
lstrcpyW( monitor->name, generic_nonpnp_monitorW );
SetRect( &monitor->rc_monitor, 0, 0, desktop_width, desktop_height );
SetRect( &monitor->rc_work, 0, 0, desktop_width, desktop_height );
query_desktop_work_area( &monitor->rc_work );
monitor->state_flags = DISPLAY_DEVICE_ATTACHED;
if (desktop_width && desktop_height)
monitor->state_flags |= DISPLAY_DEVICE_ACTIVE;
*new_monitors = monitor;
*count = 1;
return TRUE;
}
static void X11DRV_desktop_free_monitors( struct x11drv_monitor *monitors )
{
heap_free( monitors );
}
/*********************************************************************** /***********************************************************************
* X11DRV_init_desktop * X11DRV_init_desktop
* *
@ -157,8 +242,19 @@ void X11DRV_init_desktop( Window win, unsigned int width, unsigned int height )
root_window = win; root_window = win;
managed_mode = FALSE; /* no managed windows in desktop mode */ managed_mode = FALSE; /* no managed windows in desktop mode */
desktop_width = width;
desktop_height = height;
xinerama_init( width, height ); /* Initialize virtual desktop mode display device handler */
desktop_handler.name = "Virtual Desktop";
desktop_handler.get_gpus = X11DRV_desktop_get_gpus;
desktop_handler.get_adapters = X11DRV_desktop_get_adapters;
desktop_handler.get_monitors = X11DRV_desktop_get_monitors;
desktop_handler.free_gpus = X11DRV_desktop_free_gpus;
desktop_handler.free_adapters = X11DRV_desktop_free_adapters;
desktop_handler.free_monitors = X11DRV_desktop_free_monitors;
desktop_handler.register_event_handlers = NULL;
TRACE("Display device functions are now handled by: Virtual Desktop\n");
X11DRV_DisplayDevices_Init( TRUE ); X11DRV_DisplayDevices_Init( TRUE );
primary_rect = get_primary_monitor_rect(); primary_rect = get_primary_monitor_rect();
@ -311,8 +407,8 @@ void X11DRV_resize_desktop( unsigned int width, unsigned int height )
struct desktop_resize_data resize_data; struct desktop_resize_data resize_data;
resize_data.old_virtual_rect = get_virtual_screen_rect(); resize_data.old_virtual_rect = get_virtual_screen_rect();
desktop_width = width;
xinerama_init( width, height ); desktop_height = height;
X11DRV_DisplayDevices_Init( TRUE ); X11DRV_DisplayDevices_Init( TRUE );
resize_data.new_virtual_rect = get_virtual_screen_rect(); resize_data.new_virtual_rect = get_virtual_screen_rect();

View File

@ -103,7 +103,8 @@ static const WCHAR monitor_hardware_idW[] = {
'M','O','N','I','T','O','R','\\', 'M','O','N','I','T','O','R','\\',
'D','e','f','a','u','l','t','_','M','o','n','i','t','o','r',0,0}; 'D','e','f','a','u','l','t','_','M','o','n','i','t','o','r',0,0};
static struct x11drv_display_device_handler handler; static struct x11drv_display_device_handler host_handler;
struct x11drv_display_device_handler desktop_handler;
/* Cached screen information, protected by screen_section */ /* Cached screen information, protected by screen_section */
static HKEY video_key; static HKEY video_key;
@ -234,17 +235,19 @@ RECT get_primary_monitor_rect(void)
void X11DRV_DisplayDevices_SetHandler(const struct x11drv_display_device_handler *new_handler) void X11DRV_DisplayDevices_SetHandler(const struct x11drv_display_device_handler *new_handler)
{ {
if (new_handler->priority > handler.priority) if (new_handler->priority > host_handler.priority)
{ {
handler = *new_handler; host_handler = *new_handler;
TRACE("Display device functions are now handled by: %s\n", handler.name); TRACE("Display device functions are now handled by: %s\n", host_handler.name);
} }
} }
void X11DRV_DisplayDevices_RegisterEventHandlers(void) void X11DRV_DisplayDevices_RegisterEventHandlers(void)
{ {
if (handler.register_event_handlers) struct x11drv_display_device_handler *handler = is_virtual_desktop() ? &desktop_handler : &host_handler;
handler.register_event_handlers();
if (handler->register_event_handlers)
handler->register_event_handlers();
} }
/* Initialize a GPU instance and return its GUID string in guid_string and driver value in driver parameter */ /* Initialize a GPU instance and return its GUID string in guid_string and driver value in driver parameter */
@ -501,6 +504,7 @@ static void cleanup_devices(void)
void X11DRV_DisplayDevices_Init(BOOL force) void X11DRV_DisplayDevices_Init(BOOL force)
{ {
HANDLE mutex; HANDLE mutex;
struct x11drv_display_device_handler *handler = is_virtual_desktop() ? &desktop_handler : &host_handler;
struct x11drv_gpu *gpus = NULL; struct x11drv_gpu *gpus = NULL;
struct x11drv_adapter *adapters = NULL; struct x11drv_adapter *adapters = NULL;
struct x11drv_monitor *monitors = NULL; struct x11drv_monitor *monitors = NULL;
@ -526,7 +530,7 @@ void X11DRV_DisplayDevices_Init(BOOL force)
if (!force && disposition != REG_CREATED_NEW_KEY) if (!force && disposition != REG_CREATED_NEW_KEY)
goto done; goto done;
TRACE("via %s\n", wine_dbgstr_a(handler.name)); TRACE("via %s\n", wine_dbgstr_a(handler->name));
prepare_devices(video_hkey); prepare_devices(video_hkey);
@ -534,7 +538,7 @@ void X11DRV_DisplayDevices_Init(BOOL force)
monitor_devinfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_MONITOR, NULL); monitor_devinfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_MONITOR, NULL);
/* Initialize GPUs */ /* Initialize GPUs */
if (!handler.get_gpus(&gpus, &gpu_count)) if (!handler->get_gpus(&gpus, &gpu_count))
goto done; goto done;
TRACE("GPU count: %d\n", gpu_count); TRACE("GPU count: %d\n", gpu_count);
@ -544,13 +548,13 @@ void X11DRV_DisplayDevices_Init(BOOL force)
goto done; goto done;
/* Initialize adapters */ /* Initialize adapters */
if (!handler.get_adapters(gpus[gpu].id, &adapters, &adapter_count)) if (!handler->get_adapters(gpus[gpu].id, &adapters, &adapter_count))
goto done; goto done;
TRACE("GPU: %#lx %s, adapter count: %d\n", gpus[gpu].id, wine_dbgstr_w(gpus[gpu].name), adapter_count); TRACE("GPU: %#lx %s, adapter count: %d\n", gpus[gpu].id, wine_dbgstr_w(gpus[gpu].name), adapter_count);
for (adapter = 0; adapter < adapter_count; adapter++) for (adapter = 0; adapter < adapter_count; adapter++)
{ {
if (!handler.get_monitors(adapters[adapter].id, &monitors, &monitor_count)) if (!handler->get_monitors(adapters[adapter].id, &monitors, &monitor_count))
goto done; goto done;
TRACE("adapter: %#lx, monitor count: %d\n", adapters[adapter].id, monitor_count); TRACE("adapter: %#lx, monitor count: %d\n", adapters[adapter].id, monitor_count);
@ -566,12 +570,12 @@ void X11DRV_DisplayDevices_Init(BOOL force)
goto done; goto done;
} }
handler.free_monitors(monitors); handler->free_monitors(monitors);
monitors = NULL; monitors = NULL;
video_index++; video_index++;
} }
handler.free_adapters(adapters); handler->free_adapters(adapters);
adapters = NULL; adapters = NULL;
} }
@ -582,9 +586,9 @@ done:
RegCloseKey(video_hkey); RegCloseKey(video_hkey);
release_display_device_init_mutex(mutex); release_display_device_init_mutex(mutex);
if (gpus) if (gpus)
handler.free_gpus(gpus); handler->free_gpus(gpus);
if (adapters) if (adapters)
handler.free_adapters(adapters); handler->free_adapters(adapters);
if (monitors) if (monitors)
handler.free_monitors(monitors); handler->free_monitors(monitors);
} }

View File

@ -753,6 +753,8 @@ struct x11drv_display_device_handler
extern void X11DRV_DisplayDevices_SetHandler(const struct x11drv_display_device_handler *handler) DECLSPEC_HIDDEN; extern void X11DRV_DisplayDevices_SetHandler(const struct x11drv_display_device_handler *handler) DECLSPEC_HIDDEN;
extern void X11DRV_DisplayDevices_Init(BOOL force) DECLSPEC_HIDDEN; extern void X11DRV_DisplayDevices_Init(BOOL force) DECLSPEC_HIDDEN;
extern void X11DRV_DisplayDevices_RegisterEventHandlers(void) DECLSPEC_HIDDEN; extern void X11DRV_DisplayDevices_RegisterEventHandlers(void) DECLSPEC_HIDDEN;
/* Display device handler used in virtual desktop mode */
extern struct x11drv_display_device_handler desktop_handler DECLSPEC_HIDDEN;
/* XIM support */ /* XIM support */
extern BOOL X11DRV_InitXIM( const char *input_style ) DECLSPEC_HIDDEN; extern BOOL X11DRV_InitXIM( const char *input_style ) DECLSPEC_HIDDEN;

View File

@ -75,20 +75,6 @@ void query_work_area( RECT *rc_work )
} }
} }
static void query_desktop_work_area( RECT *rc_work )
{
static const WCHAR trayW[] = {'S','h','e','l','l','_','T','r','a','y','W','n','d',0};
RECT rect;
HWND hwnd = FindWindowW( trayW, NULL );
if (!hwnd || !IsWindowVisible( hwnd )) return;
if (!GetWindowRect( hwnd, &rect )) return;
if (rect.top) rc_work->bottom = rect.top;
else rc_work->top = rect.bottom;
TRACE( "found tray %p %s work area %s\n", hwnd,
wine_dbgstr_rect( &rect ), wine_dbgstr_rect( rc_work ));
}
#ifdef SONAME_LIBXINERAMA #ifdef SONAME_LIBXINERAMA
#define MAKE_FUNCPTR(f) static typeof(f) * p##f #define MAKE_FUNCPTR(f) static typeof(f) * p##f
@ -304,22 +290,19 @@ void xinerama_init( unsigned int width, unsigned int height )
{ {
struct x11drv_display_device_handler handler; struct x11drv_display_device_handler handler;
MONITORINFOEXW *primary; MONITORINFOEXW *primary;
BOOL desktop_mode = FALSE;
int i; int i;
RECT rect; RECT rect;
SetRect( &rect, 0, 0, width, height ); if (is_virtual_desktop())
return;
if (is_virtual_desktop() || !query_screens()) SetRect( &rect, 0, 0, width, height );
if (!query_screens())
{ {
default_monitor.rcWork = default_monitor.rcMonitor = rect; default_monitor.rcWork = default_monitor.rcMonitor = rect;
if (!is_virtual_desktop())
query_work_area( &default_monitor.rcWork ); query_work_area( &default_monitor.rcWork );
else
query_desktop_work_area( &default_monitor.rcWork );
nb_monitors = 1; nb_monitors = 1;
monitors = &default_monitor; monitors = &default_monitor;
desktop_mode = TRUE;
} }
primary = get_primary(); primary = get_primary();
@ -336,8 +319,8 @@ void xinerama_init( unsigned int width, unsigned int height )
(monitors[i].dwFlags & MONITORINFOF_PRIMARY) ? " (primary)" : "" ); (monitors[i].dwFlags & MONITORINFOF_PRIMARY) ? " (primary)" : "" );
} }
handler.name = desktop_mode ? "Desktop" : "Xinerama"; handler.name = "Xinerama";
handler.priority = desktop_mode ? 1000 : 100; handler.priority = 100;
handler.get_gpus = xinerama_get_gpus; handler.get_gpus = xinerama_get_gpus;
handler.get_adapters = xinerama_get_adapters; handler.get_adapters = xinerama_get_adapters;
handler.get_monitors = xinerama_get_monitors; handler.get_monitors = xinerama_get_monitors;