winex11.drv: Fix xinerama_get_fullscreen_monitors() not working correctly with non-fullscreen rects.
xinerama_get_fullscreen_monitors() was supposed to be called with fullscreen rects. Thus, we could assume the monitor indices are all zero when there is only one monitor as an optimization. However, after baf65867, xinerama_get_fullscreen_monitors() can be called with non-fullscreen rects. So we need to remove the optimization so that it works correctly for non-fullscreen rects as well.
Fix the Guild Wars 2 game window having an offset in fullscreen mode.
-- v3: winex11.drv: Fix xinerama_get_fullscreen_monitors() not working correctly with non-fullscreen rects.
From: Zhiyi Zhang zzhang@codeweavers.com
xinerama_get_fullscreen_monitors() was supposed to be called with fullscreen rects. Thus, we could assume the monitor indices are all zero when there is only one monitor as an optimization. However, after baf65867, xinerama_get_fullscreen_monitors() can be called with non-fullscreen rects. So we need to remove the optimization so that it works correctly for non-fullscreen rects as well.
Fix the Guild Wars 2 game window having an offset in fullscreen mode. --- dlls/winex11.drv/window.c | 7 ++++--- dlls/winex11.drv/x11drv.h | 2 +- dlls/winex11.drv/xinerama.c | 17 +++++++---------- 3 files changed, 12 insertions(+), 14 deletions(-)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 546d2583639..0eddc40da0c 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1685,9 +1685,10 @@ static UINT window_update_client_config( struct x11drv_win_data *data ) * window rect will be repeatedly changed by the WM and the application, causing a flickering effect */ if (data->is_fullscreen) { - xinerama_get_fullscreen_monitors( &data->rects.visible, &old_generation, old_monitors ); - xinerama_get_fullscreen_monitors( &data->current_state.rect, &generation, monitors ); - if (!memcmp( old_monitors, monitors, sizeof(monitors) )) return 0; + if (xinerama_get_fullscreen_monitors( &data->rects.visible, &old_generation, old_monitors ) + && xinerama_get_fullscreen_monitors( &data->current_state.rect, &generation, monitors ) + && !memcmp( old_monitors, monitors, sizeof(monitors) )) + return 0; }
flags = SWP_NOACTIVATE | SWP_NOZORDER; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 431c8e750bd..309632d2c3b 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -746,7 +746,7 @@ extern POINT virtual_screen_to_root( INT x, INT y ); extern POINT root_to_virtual_screen( INT x, INT y ); extern RECT get_host_primary_monitor_rect(void); extern RECT get_work_area( const RECT *monitor_rect ); -extern void xinerama_get_fullscreen_monitors( const RECT *rect, unsigned int *generation, long *indices ); +extern BOOL xinerama_get_fullscreen_monitors( const RECT *rect, unsigned int *generation, long *indices ); extern void xinerama_init( unsigned int width, unsigned int height ); extern void init_recursive_mutex( pthread_mutex_t *mutex ); extern void init_icm_profile(void); diff --git a/dlls/winex11.drv/xinerama.c b/dlls/winex11.drv/xinerama.c index 5086f3ee766..99c0080464f 100644 --- a/dlls/winex11.drv/xinerama.c +++ b/dlls/winex11.drv/xinerama.c @@ -124,20 +124,16 @@ static inline int query_screens(void)
#endif /* SONAME_LIBXINERAMA */
-/* Get xinerama monitor indices required for _NET_WM_FULLSCREEN_MONITORS */ -void xinerama_get_fullscreen_monitors( const RECT *rect, unsigned int *generation, long *indices ) +/* Get xinerama monitor indices required for _NET_WM_FULLSCREEN_MONITORS. Return FALSE if rect is + * not fullscreen */ +BOOL xinerama_get_fullscreen_monitors( const RECT *rect, unsigned int *generation, 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 ); - *generation = xinerama_generation; - goto done; - }
/* Convert window rectangle to root coordinates */ offset = virtual_screen_to_root( rect->left, rect->top ); @@ -173,10 +169,11 @@ void xinerama_get_fullscreen_monitors( const RECT *rect, unsigned int *generatio } }
- if (indices[0] == -1) WARN("Failed to get xinerama fullscreen monitor indices.\n"); + if (indices[0] != -1) + ret = TRUE;
-done: pthread_mutex_unlock( &xinerama_mutex ); + return ret; }
static BOOL xinerama_get_gpus( struct x11drv_gpu **new_gpus, int *count, BOOL get_properties )
On Thu Nov 13 09:16:10 2025 +0000, Rémi Bernon wrote:
I think checking only the first one is enough, they either all -1 or are all initialized at once.
Right. Thanks.
Actually I'm wondering whether we really should add a return value there. If rect is not fullscreen the indices should be set to -1, and would be different if it is.
If data->is_fullscreen I would expect that either one of current_state.rect or rects.visible to be a fullscreen rect. Do you know which one is not and why it causes some problems?
Actually I'm wondering whether we really should add a return value there. If rect is not fullscreen the indices should be set to -1, and would be different if it is.
Yes. But I think having a return value would be more intuitive.
If data->is_fullscreen I would expect that either one of current_state.rect or rects.visible to be a fullscreen rect. Do you know which one is not and why it causes some problems?
current_state.rect might not be fullscreen because sometimes the WM might not respect the fullscreen request.
Yes. But I think having a return value would be more intuitive.
Hmm, I think it duplicates the information and actually changes the logic a bit here: if neither current_state.rect nor rects.visible are fullscreen, the memcmp was supposed to return 0 before [^1]. ie: both rects are similar fullscreen-wise, both not fullscreen.
In practice it doesn't make a difference as because of data->is_fullscreen, one of the two rects has to be fullscreen, so I don't really mind but still IMO unnecessary.
[^1]: Ignoring the issue this MR is fixing.
This merge request was approved by Rémi Bernon.