From: Julian Orth ju.orth@gmail.com
Configuration sequences completing with an xdg_surface.configure do not necessarily contain all state. For example, for a toplevel, the compositor might send xdg_surface.configure without sending an xdg_toplevel.configure.
It is up to the client to maintain the sum of all previous configuration sequences and to only modify those properties that are part of a sequence.
This commit adds a new type wayland_surface_config_delta that contains a wayland_surface_config but also a mask of all of those fields that have been modified. The new function wayland_surface_config_apply_delta takes care of transferring deltas downstream. --- dlls/winewayland.drv/wayland_surface.c | 63 ++++++++++++++++++++------ dlls/winewayland.drv/waylanddrv.h | 21 ++++++++- dlls/winewayland.drv/window.c | 14 +++--- 3 files changed, 74 insertions(+), 24 deletions(-)
diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index 99049f4e536..a18189ecfff 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -54,11 +54,13 @@ static void xdg_surface_handle_configure(void *private, struct xdg_surface *xdg_ /* If we have a previously requested config, we have already sent a * WM_WAYLAND_CONFIGURE which hasn't been handled yet. In that case, * avoid sending another message to reduce message queue traffic. */ - should_post = surface->requested.serial == 0; + should_post = !(surface->requested.mask & WAYLAND_SURFACE_CONFIG_DELTA_SERIAL); initial_configure = surface->current.serial == 0; - surface->pending.serial = serial; - surface->requested = surface->pending; - memset(&surface->pending, 0, sizeof(surface->pending)); + surface->pending.mask |= WAYLAND_SURFACE_CONFIG_DELTA_SERIAL; + surface->pending.config.serial = serial; + wayland_surface_config_apply_delta(&surface->requested.config, + &surface->pending, + &surface->requested.mask); }
wayland_win_data_release(data); @@ -119,9 +121,11 @@ static void xdg_toplevel_handle_configure(void *private,
if ((surface = data->wayland_surface) && wayland_surface_is_toplevel(surface)) { - surface->pending.width = width; - surface->pending.height = height; - surface->pending.state = config_state; + surface->pending.mask |= WAYLAND_SURFACE_CONFIG_DELTA_SIZE; + surface->pending.config.width = width; + surface->pending.config.height = height; + surface->pending.mask |= WAYLAND_SURFACE_CONFIG_DELTA_STATE; + surface->pending.config.state = config_state; }
wayland_win_data_release(data); @@ -373,6 +377,7 @@ void wayland_surface_clear_role(struct wayland_surface *surface) memset(&surface->requested, 0, sizeof(surface->requested)); memset(&surface->processing, 0, sizeof(surface->processing)); memset(&surface->current, 0, sizeof(surface->current)); + surface->processing_processed = FALSE; surface->toplevel_hwnd = 0;
/* Ensure no buffer is attached, otherwise future role assignments may fail. */ @@ -624,25 +629,26 @@ static BOOL wayland_surface_reconfigure_xdg(struct wayland_surface *surface, struct wayland_window_config *window = &surface->window;
/* Acknowledge any compatible processed config. */ - if (surface->processing.serial && surface->processing.processed && + if (surface->processing.serial && surface->processing_processed && wayland_surface_config_is_compatible(&surface->processing, width, height, window->state)) { surface->current = surface->processing; - memset(&surface->processing, 0, sizeof(surface->processing)); + surface->processing_processed = FALSE; xdg_surface_ack_configure(surface->xdg_surface, surface->current.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_config_is_compatible(&surface->requested, + else if (!surface->current.serial && + (surface->requested.mask & WAYLAND_SURFACE_CONFIG_DELTA_SERIAL) && + wayland_surface_config_is_compatible(&surface->requested.config, width, height, window->state)) { - surface->current = surface->requested; - memset(&surface->requested, 0, sizeof(surface->requested)); + wayland_surface_config_apply_delta(&surface->processing, &surface->requested, NULL); + surface->current = surface->processing; xdg_surface_ack_configure(surface->xdg_surface, surface->current.serial); } else if (!surface->current.serial || @@ -670,7 +676,7 @@ static void wayland_surface_reconfigure_subsurface(struct wayland_surface *surfa struct wayland_surface *toplevel_surface; int local_x, local_y, x, y;
- if (surface->processing.serial && surface->processing.processed && + if (surface->processing.serial && surface->processing_processed && (toplevel_data = wayland_win_data_get_nolock(surface->toplevel_hwnd)) && (toplevel_surface = toplevel_data->wayland_surface)) { @@ -688,7 +694,7 @@ static void wayland_surface_reconfigure_subsurface(struct wayland_surface *surfa wl_subsurface_place_above(surface->wl_subsurface, toplevel_surface->wl_surface); wl_surface_commit(toplevel_surface->wl_surface);
- memset(&surface->processing, 0, sizeof(surface->processing)); + surface->processing_processed = FALSE; } }
@@ -734,6 +740,33 @@ BOOL wayland_surface_reconfigure(struct wayland_surface *surface) return TRUE; }
+/********************************************************************** + * wayland_surface_config_apply_delta + * + * Applies an xdg configuration delta to a persistent configuration and + * resets the delta. If target_mask is not null, the mask of the delta + * will be OR'd into it. + */ +void wayland_surface_config_apply_delta(struct wayland_surface_config *target, + struct wayland_surface_config_delta *delta, + enum wayland_surface_config_delta_mask *target_mask) +{ + enum wayland_surface_config_delta_mask mask = delta->mask; + + if (mask & WAYLAND_SURFACE_CONFIG_DELTA_SERIAL) + target->serial = delta->config.serial; + if (mask & WAYLAND_SURFACE_CONFIG_DELTA_SIZE) { + target->width = delta->config.width; + target->height = delta->config.height; + } + if (mask & WAYLAND_SURFACE_CONFIG_DELTA_STATE) + target->state = delta->config.state; + delta->mask = 0; + + if (target_mask) + *target_mask |= mask; +} + /********************************************************************** * wayland_shm_buffer_ref * diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 24df4c66184..bb092000f23 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -217,7 +217,19 @@ struct wayland_surface_config int32_t width, height; enum wayland_surface_config_state state; uint32_t serial; - BOOL processed; +}; + +enum wayland_surface_config_delta_mask +{ + WAYLAND_SURFACE_CONFIG_DELTA_SERIAL = (1 << 0), + WAYLAND_SURFACE_CONFIG_DELTA_SIZE = (1 << 1), + WAYLAND_SURFACE_CONFIG_DELTA_STATE = (1 << 2), +}; + +struct wayland_surface_config_delta +{ + enum wayland_surface_config_delta_mask mask; + struct wayland_surface_config config; };
struct wayland_window_config @@ -278,7 +290,9 @@ struct wayland_surface }; };
- struct wayland_surface_config pending, requested, processing, current; + struct wayland_surface_config_delta pending, requested; + struct wayland_surface_config processing, current; + BOOL processing_processed; BOOL resizing; struct wayland_window_config window; int content_width, content_height; @@ -329,6 +343,9 @@ void wayland_client_surface_detach(struct wayland_client_surface *client); void wayland_surface_ensure_contents(struct wayland_surface *surface); void wayland_surface_set_title(struct wayland_surface *surface, LPCWSTR title); void wayland_surface_set_icon(struct wayland_surface *surface, UINT type, ICONINFO *ii); +void wayland_surface_config_apply_delta(struct wayland_surface_config *target, + struct wayland_surface_config_delta *delta, + enum wayland_surface_config_delta_mask *target_mask);
static inline BOOL wayland_surface_is_toplevel(struct wayland_surface *surface) { diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index ce5b6bb5143..a2a4ca5eabd 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -242,7 +242,7 @@ static BOOL wayland_win_data_create_wayland_surface(struct wayland_win_data *dat static void wayland_surface_update_state_toplevel(struct wayland_surface *surface) { BOOL processing_config = surface->processing.serial && - !surface->processing.processed; + !surface->processing_processed;
TRACE("hwnd=%p window_state=%#x %s->state=%#x\n", surface->hwnd, surface->window.state, @@ -279,7 +279,7 @@ static void wayland_surface_update_state_toplevel(struct wayland_surface *surfac } else { - surface->processing.processed = TRUE; + surface->processing_processed = TRUE; } }
@@ -300,7 +300,7 @@ static void wayland_win_data_update_wayland_state(struct wayland_win_data *data) /* Although subsurfaces don't have a dedicated surface config mechanism, * we use the config fields to mark them as updated. */ surface->processing.serial = 1; - surface->processing.processed = TRUE; + surface->processing_processed = TRUE; break; }
@@ -543,15 +543,15 @@ static void wayland_configure_window(HWND hwnd) return; }
- if (!surface->requested.serial) + if (!(surface->requested.mask & WAYLAND_SURFACE_CONFIG_DELTA_SERIAL)) { TRACE("requested configure event already handled, returning\n"); wayland_win_data_release(data); return; }
- surface->processing = surface->requested; - memset(&surface->requested, 0, sizeof(surface->requested)); + wayland_surface_config_apply_delta(&surface->processing, &surface->requested, NULL); + surface->processing_processed = FALSE;
state = surface->processing.state; /* Ignore size hints if we don't have a state that requires strict @@ -873,7 +873,7 @@ void ensure_window_surface_contents(HWND hwnd) /* Handle any processed configure request, to ensure the related * surface state is applied by the compositor. */ if (wayland_surface->processing.serial && - wayland_surface->processing.processed && + wayland_surface->processing_processed && wayland_surface_reconfigure(wayland_surface)) { wl_surface_commit(wayland_surface->wl_surface);