1
0
Fork 0
mirror of synced 2025-03-07 03:53:26 +01:00

winewayland.drv: Handle xdg_toplevel maximized state.

A request for the maximized state has two potential origins:

1. The compositor, through an xdg_toplevel configure event. In this case
   we update the window state and size accordingly.

2. The application or Wine itself, by changing the window style. When
   we detect such a style, we make a request to the compositor to set
   the maximized state. The compositor will then eventually reply with
   a configure event, and we continue with case (1). Note that the
   compositor may deny our request, in which case we will also sync
   the window style accordingly.

An acknowledged maximized state imposes very strict constraints on the
size of surface content we can present. We are careful to not violate
these constraints, since otherwise the compositor will disconnect us.
This commit is contained in:
Alexandros Frantzis 2023-09-18 09:57:12 +03:00 committed by Alexandre Julliard
parent 6e903b7924
commit 36ecb876db
3 changed files with 121 additions and 10 deletions

View file

@ -78,8 +78,22 @@ static void xdg_toplevel_handle_configure(void *data,
{
struct wayland_surface *surface;
HWND hwnd = data;
uint32_t *state;
enum wayland_surface_config_state config_state = 0;
TRACE("hwnd=%p %dx%d\n", hwnd, width, height);
wl_array_for_each(state, states)
{
switch(*state)
{
case XDG_TOPLEVEL_STATE_MAXIMIZED:
config_state |= WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED;
break;
default:
break;
}
}
TRACE("hwnd=%p %dx%d,%#x\n", hwnd, width, height, config_state);
if (!(surface = wayland_surface_lock_hwnd(hwnd))) return;
@ -87,6 +101,7 @@ static void xdg_toplevel_handle_configure(void *data,
{
surface->pending.width = width;
surface->pending.height = height;
surface->pending.state = config_state;
}
pthread_mutex_unlock(&surface->mutex);
@ -291,6 +306,32 @@ void wayland_surface_attach_shm(struct wayland_surface *surface,
}
}
/**********************************************************************
* wayland_surface_configure_is_compatible
*
* Checks whether a wayland_surface_configure object is compatible with the
* the provided arguments.
*/
static BOOL wayland_surface_configure_is_compatible(struct wayland_surface_config *conf,
int width, int height,
enum wayland_surface_config_state state)
{
static enum wayland_surface_config_state mask =
WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED;
/* We require the same state. */
if ((state & mask) != (conf->state & mask)) return FALSE;
/* The maximized state requires the configured size. */
if ((conf->state & WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED) &&
(width != conf->width || height != conf->height))
{
return FALSE;
}
return TRUE;
}
/**********************************************************************
* wayland_surface_reconfigure
*
@ -299,27 +340,52 @@ void wayland_surface_attach_shm(struct wayland_surface *surface,
*/
BOOL wayland_surface_reconfigure(struct wayland_surface *surface)
{
RECT window_rect;
int width, height;
enum wayland_surface_config_state window_state;
if (!surface->xdg_toplevel) return TRUE;
if (!NtUserGetWindowRect(surface->hwnd, &window_rect)) return FALSE;
TRACE("hwnd=%p\n", surface->hwnd);
width = window_rect.right - window_rect.left;
height = window_rect.bottom - window_rect.top;
/* Acknowledge any processed config. */
if (surface->processing.serial && surface->processing.processed)
window_state =
(NtUserGetWindowLongW(surface->hwnd, GWL_STYLE) & WS_MAXIMIZE) ?
WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED : 0;
TRACE("hwnd=%p window=%dx%d,%#x processing=%dx%d,%#x current=%dx%d,%#x\n",
surface->hwnd, width, height, window_state,
surface->processing.width, surface->processing.height,
surface->processing.state, surface->current.width,
surface->current.height, surface->current.state);
/* Acknowledge any compatible processed config. */
if (surface->processing.serial && surface->processing.processed &&
wayland_surface_configure_is_compatible(&surface->processing,
width, height,
window_state))
{
surface->current = surface->processing;
memset(&surface->processing, 0, sizeof(surface->processing));
xdg_surface_ack_configure(surface->xdg_surface, surface->current.serial);
}
/* If this is the initial configure, and we have a requested config,
* use that, in order to draw windows that don't go through the message
* loop (e.g., some splash screens). */
else if (!surface->current.serial && surface->requested.serial)
/* If this is the initial configure, and we have a compatible requested
* config, use that, in order to draw windows that don't go through the
* message loop (e.g., some splash screens). */
else if (!surface->current.serial && surface->requested.serial &&
wayland_surface_configure_is_compatible(&surface->requested,
width, height,
window_state))
{
surface->current = surface->requested;
memset(&surface->requested, 0, sizeof(surface->requested));
xdg_surface_ack_configure(surface->xdg_surface, surface->current.serial);
}
else if (!surface->current.serial)
else if (!surface->current.serial ||
!wayland_surface_configure_is_compatible(&surface->current,
width, height,
window_state))
{
return FALSE;
}

View file

@ -57,6 +57,11 @@ enum wayland_window_message
WM_WAYLAND_CONFIGURE = 0x80001001
};
enum wayland_surface_config_state
{
WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED = (1 << 0)
};
struct wayland_cursor
{
struct wayland_shm_buffer *shm_buffer;
@ -121,6 +126,7 @@ struct wayland_output
struct wayland_surface_config
{
int32_t width, height;
enum wayland_surface_config_state state;
uint32_t serial;
BOOL processed;
};

View file

@ -195,15 +195,38 @@ out:
static void wayland_win_data_update_wayland_state(struct wayland_win_data *data)
{
struct wayland_surface *surface = data->wayland_surface;
uint32_t window_state;
struct wayland_surface_config *conf;
pthread_mutex_lock(&surface->mutex);
if (!surface->xdg_toplevel) goto out;
if (surface->processing.serial) surface->processing.processed = TRUE;
window_state =
(NtUserGetWindowLongW(surface->hwnd, GWL_STYLE) & WS_MAXIMIZE) ?
WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED : 0;
conf = surface->processing.serial ? &surface->processing : &surface->current;
TRACE("hwnd=%p window_state=%#x conf->state=%#x\n",
data->hwnd, window_state, conf->state);
if ((window_state & WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED) &&
!(conf->state & WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED))
{
xdg_toplevel_set_maximized(surface->xdg_toplevel);
}
else if (!(window_state & WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED) &&
(conf->state & WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED))
{
xdg_toplevel_unset_maximized(surface->xdg_toplevel);
}
conf->processed = TRUE;
out:
pthread_mutex_unlock(&surface->mutex);
wl_display_flush(process_wayland.wl_display);
}
/***********************************************************************
@ -310,6 +333,8 @@ static void wayland_configure_window(HWND hwnd)
struct wayland_surface *surface;
INT width, height;
UINT flags;
uint32_t state;
DWORD style;
if (!(surface = wayland_surface_lock_hwnd(hwnd))) return;
@ -332,12 +357,26 @@ static void wayland_configure_window(HWND hwnd)
width = surface->processing.width;
height = surface->processing.height;
state = surface->processing.state;
pthread_mutex_unlock(&surface->mutex);
TRACE("processing=%dx%d,%#x\n", width, height, state);
flags = SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE;
if (width == 0 || height == 0) flags |= SWP_NOSIZE;
style = NtUserGetWindowLongW(hwnd, GWL_STYLE);
if (!(state & WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED) != !(style & WS_MAXIMIZE))
{
NtUserSetWindowLong(hwnd, GWL_STYLE, style ^ WS_MAXIMIZE, FALSE);
flags |= SWP_FRAMECHANGED;
}
/* The Wayland maximized state is very strict about surface size, so don't
* let the application override it. */
if (state & WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED) flags |= SWP_NOSENDCHANGING;
NtUserSetWindowPos(hwnd, 0, 0, 0, width, height, flags);
}