mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-06 09:35:52 +00:00
winex11.drv: Support _NET_WM_FULLSCREEN_MONITORS.
Support _NET_WM_FULLSCREEN_MONITORS for fullscreen windows spanning multiple monitors. This property is used to hint window managers about which monitor a fullscreen window should cover. Window managers make a fullscreen window spanning multiple monitors cover only one monitor when this property is missing. Fix Project Cars 2/3 incorrect game window size when the triple-screen mode is on.
This commit is contained in:
parent
3dd68caab3
commit
bd8ec8f264
|
@ -9282,7 +9282,8 @@ static void test_fullscreen(void)
|
|||
flush_events(TRUE);
|
||||
|
||||
GetWindowRect(hwnd, &rc);
|
||||
todo_wine
|
||||
/* FVWM used by TestBots doesn't support _NET_WM_FULLSCREEN_MONITORS */
|
||||
todo_wine_if(!EqualRect(&rc, &virtual_rect))
|
||||
ok(EqualRect(&rc, &virtual_rect), "Expected %s, got %s.\n",
|
||||
wine_dbgstr_rect(&virtual_rect), wine_dbgstr_rect(&rc));
|
||||
DestroyWindow(hwnd);
|
||||
|
|
|
@ -533,6 +533,12 @@ void X11DRV_DisplayDevices_RegisterEventHandlers(void)
|
|||
handler->register_event_handlers();
|
||||
}
|
||||
|
||||
/* Report whether a display device handler supports detecting dynamic device changes */
|
||||
BOOL X11DRV_DisplayDevices_SupportEventHandlers(void)
|
||||
{
|
||||
return !!host_handler.register_event_handlers;
|
||||
}
|
||||
|
||||
static BOOL force_display_devices_refresh;
|
||||
|
||||
BOOL X11DRV_UpdateDisplayDevices( const struct gdi_device_manager *device_manager, BOOL force, void *param )
|
||||
|
|
|
@ -970,6 +970,46 @@ void update_user_time( Time time )
|
|||
XUnlockDisplay( gdi_display );
|
||||
}
|
||||
|
||||
/* Update _NET_WM_FULLSCREEN_MONITORS when _NET_WM_STATE_FULLSCREEN is set to support fullscreen
|
||||
* windows spanning multiple monitors */
|
||||
static void update_net_wm_fullscreen_monitors( struct x11drv_win_data *data )
|
||||
{
|
||||
long monitors[4];
|
||||
XEvent xev;
|
||||
|
||||
if (!(data->net_wm_state & (1 << NET_WM_STATE_FULLSCREEN)) || is_virtual_desktop())
|
||||
return;
|
||||
|
||||
/* If the current display device handler can not detect dynamic device changes, do not use
|
||||
* _NET_WM_FULLSCREEN_MONITORS because xinerama_get_fullscreen_monitors() may report wrong
|
||||
* indices because of stale xinerama monitor information */
|
||||
if (!X11DRV_DisplayDevices_SupportEventHandlers())
|
||||
return;
|
||||
|
||||
if (!xinerama_get_fullscreen_monitors( &data->whole_rect, monitors ))
|
||||
return;
|
||||
|
||||
if (!data->mapped)
|
||||
{
|
||||
XChangeProperty( data->display, data->whole_window, x11drv_atom(_NET_WM_FULLSCREEN_MONITORS),
|
||||
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)monitors, 4 );
|
||||
}
|
||||
else
|
||||
{
|
||||
xev.xclient.type = ClientMessage;
|
||||
xev.xclient.window = data->whole_window;
|
||||
xev.xclient.message_type = x11drv_atom(_NET_WM_FULLSCREEN_MONITORS);
|
||||
xev.xclient.serial = 0;
|
||||
xev.xclient.display = data->display;
|
||||
xev.xclient.send_event = True;
|
||||
xev.xclient.format = 32;
|
||||
xev.xclient.data.l[4] = 1;
|
||||
memcpy( xev.xclient.data.l, monitors, sizeof(monitors) );
|
||||
XSendEvent( data->display, root_window, False,
|
||||
SubstructureRedirectMask | SubstructureNotifyMask, &xev );
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* update_net_wm_states
|
||||
*/
|
||||
|
@ -1051,6 +1091,7 @@ void update_net_wm_states( struct x11drv_win_data *data )
|
|||
}
|
||||
}
|
||||
data->net_wm_state = new_state;
|
||||
update_net_wm_fullscreen_monitors( data );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -1143,6 +1184,7 @@ static void map_window( HWND hwnd, DWORD new_style )
|
|||
|
||||
data->mapped = TRUE;
|
||||
data->iconic = (new_style & WS_MINIMIZE) != 0;
|
||||
update_net_wm_fullscreen_monitors( data );
|
||||
}
|
||||
release_win_data( data );
|
||||
}
|
||||
|
|
|
@ -479,6 +479,7 @@ enum x11drv_atoms
|
|||
XATOM__NET_SYSTEM_TRAY_OPCODE,
|
||||
XATOM__NET_SYSTEM_TRAY_S0,
|
||||
XATOM__NET_SYSTEM_TRAY_VISUAL,
|
||||
XATOM__NET_WM_FULLSCREEN_MONITORS,
|
||||
XATOM__NET_WM_ICON,
|
||||
XATOM__NET_WM_MOVERESIZE,
|
||||
XATOM__NET_WM_NAME,
|
||||
|
@ -691,6 +692,7 @@ extern POINT virtual_screen_to_root( INT x, INT y ) DECLSPEC_HIDDEN;
|
|||
extern POINT root_to_virtual_screen( INT x, INT y ) DECLSPEC_HIDDEN;
|
||||
extern RECT get_host_primary_monitor_rect(void) DECLSPEC_HIDDEN;
|
||||
extern RECT get_work_area( const RECT *monitor_rect ) DECLSPEC_HIDDEN;
|
||||
extern BOOL xinerama_get_fullscreen_monitors( const RECT *rect, long *indices ) DECLSPEC_HIDDEN;
|
||||
extern void xinerama_init( unsigned int width, unsigned int height ) DECLSPEC_HIDDEN;
|
||||
extern void init_recursive_mutex( pthread_mutex_t *mutex ) DECLSPEC_HIDDEN;
|
||||
|
||||
|
@ -803,6 +805,7 @@ extern BOOL get_host_primary_gpu(struct gdi_gpu *gpu) 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_RegisterEventHandlers(void) DECLSPEC_HIDDEN;
|
||||
extern BOOL X11DRV_DisplayDevices_SupportEventHandlers(void) DECLSPEC_HIDDEN;
|
||||
/* Display device handler used in virtual desktop mode */
|
||||
extern struct x11drv_display_device_handler desktop_handler DECLSPEC_HIDDEN;
|
||||
|
||||
|
|
|
@ -162,6 +162,7 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] =
|
|||
"_NET_SYSTEM_TRAY_OPCODE",
|
||||
"_NET_SYSTEM_TRAY_S0",
|
||||
"_NET_SYSTEM_TRAY_VISUAL",
|
||||
"_NET_WM_FULLSCREEN_MONITORS",
|
||||
"_NET_WM_ICON",
|
||||
"_NET_WM_MOVERESIZE",
|
||||
"_NET_WM_NAME",
|
||||
|
|
|
@ -45,6 +45,7 @@ static MONITORINFOEXW default_monitor =
|
|||
{ '\\','\\','.','\\','D','I','S','P','L','A','Y','1',0 } /* szDevice */
|
||||
};
|
||||
|
||||
static pthread_mutex_t xinerama_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static MONITORINFOEXW *monitors;
|
||||
static int nb_monitors;
|
||||
|
||||
|
@ -122,6 +123,73 @@ static inline int query_screens(void)
|
|||
|
||||
#endif /* SONAME_LIBXINERAMA */
|
||||
|
||||
/* Get xinerama monitor indices required for _NET_WM_FULLSCREEN_MONITORS */
|
||||
BOOL xinerama_get_fullscreen_monitors( const RECT *rect, long *indices )
|
||||
{
|
||||
RECT window_rect, intersected_rect, monitor_rect;
|
||||
BOOL ret = FALSE;
|
||||
POINT offset;
|
||||
INT i;
|
||||
|
||||
pthread_mutex_lock( &xinerama_mutex );
|
||||
if (nb_monitors == 1)
|
||||
{
|
||||
memset( indices, 0, sizeof(*indices) * 4 );
|
||||
ret = TRUE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Convert window rectangle to root coordinates */
|
||||
offset = virtual_screen_to_root( rect->left, rect->top );
|
||||
window_rect.left = offset.x;
|
||||
window_rect.top = offset.y;
|
||||
window_rect.right = window_rect.left + rect->right - rect->left;
|
||||
window_rect.bottom = window_rect.top + rect->bottom - rect->top;
|
||||
|
||||
/* Compare to xinerama monitor rectangles in root coordinates */
|
||||
offset.x = INT_MAX;
|
||||
offset.y = INT_MAX;
|
||||
for (i = 0; i < nb_monitors; ++i)
|
||||
{
|
||||
offset.x = min( offset.x, monitors[i].rcMonitor.left );
|
||||
offset.y = min( offset.y, monitors[i].rcMonitor.top );
|
||||
}
|
||||
|
||||
indices[0] = -1;
|
||||
indices[1] = -1;
|
||||
indices[2] = -1;
|
||||
indices[3] = -1;
|
||||
for (i = 0; i < nb_monitors; ++i)
|
||||
{
|
||||
SetRect( &monitor_rect, monitors[i].rcMonitor.left - offset.x,
|
||||
monitors[i].rcMonitor.top - offset.y, monitors[i].rcMonitor.right - offset.x,
|
||||
monitors[i].rcMonitor.bottom - offset.y );
|
||||
intersect_rect( &intersected_rect, &window_rect, &monitor_rect );
|
||||
if (EqualRect( &intersected_rect, &monitor_rect ))
|
||||
{
|
||||
if (indices[0] == -1 || monitors[i].rcMonitor.top < monitors[indices[0]].rcMonitor.top)
|
||||
indices[0] = i;
|
||||
if (indices[1] == -1 || monitors[i].rcMonitor.bottom > monitors[indices[1]].rcMonitor.bottom)
|
||||
indices[1] = i;
|
||||
if (indices[2] == -1 || monitors[i].rcMonitor.left < monitors[indices[2]].rcMonitor.left)
|
||||
indices[2] = i;
|
||||
if (indices[3] == -1 || monitors[i].rcMonitor.right > monitors[indices[3]].rcMonitor.right)
|
||||
indices[3] = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (indices[0] == -1 || indices[1] == -1 || indices[2] == -1 || indices[3] == -1)
|
||||
ERR("Failed to get xinerama fullscreen monitor indices.\n");
|
||||
else
|
||||
ret = TRUE;
|
||||
|
||||
done:
|
||||
pthread_mutex_unlock( &xinerama_mutex );
|
||||
if (ret)
|
||||
TRACE( "fullsceen monitors: %ld,%ld,%ld,%ld.\n", indices[0], indices[1], indices[2], indices[3] );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL xinerama_get_gpus( struct gdi_gpu **new_gpus, int *count )
|
||||
{
|
||||
static const WCHAR wine_adapterW[] = {'W','i','n','e',' ','A','d','a','p','t','e','r',0};
|
||||
|
@ -157,9 +225,13 @@ static BOOL xinerama_get_adapters( ULONG_PTR gpu_id, struct gdi_adapter **new_ad
|
|||
return FALSE;
|
||||
|
||||
/* Being lazy, actual adapter count may be less */
|
||||
pthread_mutex_lock( &xinerama_mutex );
|
||||
adapters = calloc( nb_monitors, sizeof(*adapters) );
|
||||
if (!adapters)
|
||||
{
|
||||
pthread_mutex_unlock( &xinerama_mutex );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
primary_index = primary_monitor;
|
||||
if (primary_index >= nb_monitors)
|
||||
|
@ -204,6 +276,7 @@ static BOOL xinerama_get_adapters( ULONG_PTR gpu_id, struct gdi_adapter **new_ad
|
|||
|
||||
*new_adapters = adapters;
|
||||
*count = index;
|
||||
pthread_mutex_unlock( &xinerama_mutex );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -223,6 +296,8 @@ static BOOL xinerama_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **ne
|
|||
INT index = 0;
|
||||
INT i;
|
||||
|
||||
pthread_mutex_lock( &xinerama_mutex );
|
||||
|
||||
for (i = first; i < nb_monitors; i++)
|
||||
{
|
||||
if (i == first
|
||||
|
@ -233,7 +308,10 @@ static BOOL xinerama_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **ne
|
|||
|
||||
monitor = calloc( monitor_count, sizeof(*monitor) );
|
||||
if (!monitor)
|
||||
{
|
||||
pthread_mutex_unlock( &xinerama_mutex );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (i = first; i < nb_monitors; i++)
|
||||
{
|
||||
|
@ -257,6 +335,7 @@ static BOOL xinerama_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **ne
|
|||
|
||||
*new_monitors = monitor;
|
||||
*count = monitor_count;
|
||||
pthread_mutex_unlock( &xinerama_mutex );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -275,6 +354,8 @@ void xinerama_init( unsigned int width, unsigned int height )
|
|||
if (is_virtual_desktop())
|
||||
return;
|
||||
|
||||
pthread_mutex_lock( &xinerama_mutex );
|
||||
|
||||
SetRect( &rect, 0, 0, width, height );
|
||||
if (!query_screens())
|
||||
{
|
||||
|
@ -298,6 +379,8 @@ void xinerama_init( unsigned int width, unsigned int height )
|
|||
(monitors[i].dwFlags & MONITORINFOF_PRIMARY) ? " (primary)" : "" );
|
||||
}
|
||||
|
||||
pthread_mutex_unlock( &xinerama_mutex );
|
||||
|
||||
handler.name = "Xinerama";
|
||||
handler.priority = 100;
|
||||
handler.get_gpus = xinerama_get_gpus;
|
||||
|
|
|
@ -1190,6 +1190,8 @@ static void xrandr14_free_monitors( struct gdi_monitor *monitors, int count )
|
|||
|
||||
static BOOL xrandr14_device_change_handler( HWND hwnd, XEvent *event )
|
||||
{
|
||||
RECT rect;
|
||||
|
||||
xrandr14_invalidate_current_mode_cache();
|
||||
if (hwnd == NtUserGetDesktopWindow() && NtUserGetWindowThread( hwnd, NULL ) == GetCurrentThreadId())
|
||||
{
|
||||
|
@ -1197,6 +1199,9 @@ static BOOL xrandr14_device_change_handler( HWND hwnd, XEvent *event )
|
|||
init_registry_display_settings();
|
||||
X11DRV_resize_desktop();
|
||||
}
|
||||
/* Update xinerama monitors for xinerama_get_fullscreen_monitors() */
|
||||
rect = get_host_primary_monitor_rect();
|
||||
xinerama_init( rect.right - rect.left, rect.bottom - rect.top );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue