Module: wine Branch: master Commit: 6e903b7924fb05806dca8c05c2c64034f953626f URL: https://gitlab.winehq.org/wine/wine/-/commit/6e903b7924fb05806dca8c05c2c6403...
Author: Alexandros Frantzis alexandros.frantzis@collabora.com Date: Wed Sep 13 11:32:20 2023 +0300
winewayland.drv: Handle xdg_toplevel configure event size hint.
Use the size hint provided by the compositor to resize the window associated with a Wayland toplevel surface.
A surface config moves through the following stages (each stage may hold a different event):
1. Pending: In the process of being populated from separate Wayland events.
2. Requested: A fully formed config which hasn't been handled yet. A new finalized Pending event will always be promoted to a Requested event (so we will skip previous events if new ones arrive quickly enough).
3. Processing: A config that is being processed. When processing is done, we mark it with `wayland_surface_config.processed = TRUE`.
4. Current: The config has been acknowledged, i.e., we are promising to respect any implied content constraints.
---
dlls/winewayland.drv/wayland_surface.c | 67 ++++++++++++++++++++++++++++++++-- dlls/winewayland.drv/waylanddrv.h | 13 ++++++- dlls/winewayland.drv/window.c | 54 +++++++++++++++++++++++++++ dlls/winewayland.drv/window_surface.c | 2 +- 4 files changed, 129 insertions(+), 7 deletions(-)
diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index 832a1081234..0004e51fe0f 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -48,9 +48,15 @@ static void xdg_surface_handle_configure(void *data, struct xdg_surface *xdg_sur * the target xdg_surface. */ if (surface->xdg_surface == xdg_surface) { - initial_configure = surface->current_serial == 0; - surface->current_serial = serial; - xdg_surface_ack_configure(xdg_surface, serial); + /* 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. */ + BOOL should_post = surface->requested.serial == 0; + initial_configure = surface->current.serial == 0; + surface->pending.serial = serial; + surface->requested = surface->pending; + memset(&surface->pending, 0, sizeof(surface->pending)); + if (should_post) NtUserPostMessage(hwnd, WM_WAYLAND_CONFIGURE, 0, 0); }
pthread_mutex_unlock(&surface->mutex); @@ -70,6 +76,20 @@ static void xdg_toplevel_handle_configure(void *data, int32_t width, int32_t height, struct wl_array *states) { + struct wayland_surface *surface; + HWND hwnd = data; + + TRACE("hwnd=%p %dx%d\n", hwnd, width, height); + + if (!(surface = wayland_surface_lock_hwnd(hwnd))) return; + + if (surface->xdg_toplevel == xdg_toplevel) + { + surface->pending.width = width; + surface->pending.height = height; + } + + pthread_mutex_unlock(&surface->mutex); }
static void xdg_toplevel_handle_close(void *data, struct xdg_toplevel *xdg_toplevel) @@ -217,7 +237,10 @@ void wayland_surface_clear_role(struct wayland_surface *surface) surface->xdg_surface = NULL; }
- surface->current_serial = 0; + memset(&surface->pending, 0, sizeof(surface->pending)); + memset(&surface->requested, 0, sizeof(surface->requested)); + memset(&surface->processing, 0, sizeof(surface->processing)); + memset(&surface->current, 0, sizeof(surface->current));
/* Ensure no buffer is attached, otherwise future role assignments may fail. */ wl_surface_attach(surface->wl_surface, NULL, 0, 0); @@ -268,6 +291,42 @@ void wayland_surface_attach_shm(struct wayland_surface *surface, } }
+/********************************************************************** + * wayland_surface_reconfigure + * + * Reconfigures the wayland surface as needed to match the latest requested + * state. + */ +BOOL wayland_surface_reconfigure(struct wayland_surface *surface) +{ + if (!surface->xdg_toplevel) return TRUE; + + TRACE("hwnd=%p\n", surface->hwnd); + + /* Acknowledge any processed config. */ + if (surface->processing.serial && surface->processing.processed) + { + 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) + { + 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) + { + return FALSE; + } + + return TRUE; +} + /********************************************************************** * wayland_shm_buffer_ref * diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 6e0b5c6fb10..5246d3ba9cb 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -53,7 +53,8 @@ extern struct wayland process_wayland DECLSPEC_HIDDEN;
enum wayland_window_message { - WM_WAYLAND_INIT_DISPLAY_DEVICES = 0x80001000 + WM_WAYLAND_INIT_DISPLAY_DEVICES = 0x80001000, + WM_WAYLAND_CONFIGURE = 0x80001001 };
struct wayland_cursor @@ -117,6 +118,13 @@ struct wayland_output struct wayland_output_state current; };
+struct wayland_surface_config +{ + int32_t width, height; + uint32_t serial; + BOOL processed; +}; + struct wayland_surface { HWND hwnd; @@ -124,7 +132,7 @@ struct wayland_surface struct xdg_surface *xdg_surface; struct xdg_toplevel *xdg_toplevel; pthread_mutex_t mutex; - uint32_t current_serial; + struct wayland_surface_config pending, requested, processing, current; struct wayland_shm_buffer *latest_window_buffer; };
@@ -167,6 +175,7 @@ void wayland_surface_attach_shm(struct wayland_surface *surface, struct wayland_shm_buffer *shm_buffer, HRGN surface_damage_region) DECLSPEC_HIDDEN; struct wayland_surface *wayland_surface_lock_hwnd(HWND hwnd) DECLSPEC_HIDDEN; +BOOL wayland_surface_reconfigure(struct wayland_surface *surface) DECLSPEC_HIDDEN;
/********************************************************************** * Wayland SHM buffer diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index 958bc5dbe68..86f4e30b136 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -192,6 +192,20 @@ out: data->wayland_surface = surface; }
+static void wayland_win_data_update_wayland_state(struct wayland_win_data *data) +{ + struct wayland_surface *surface = data->wayland_surface; + + pthread_mutex_lock(&surface->mutex); + + if (!surface->xdg_toplevel) goto out; + + if (surface->processing.serial) surface->processing.processed = TRUE; + +out: + pthread_mutex_unlock(&surface->mutex); +} + /*********************************************************************** * WAYLAND_DestroyWindow */ @@ -276,6 +290,7 @@ void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags, data->window_surface = surface;
wayland_win_data_update_wayland_surface(data); + if (data->wayland_surface) wayland_win_data_update_wayland_state(data);
wayland_win_data_release(data); } @@ -290,6 +305,42 @@ static void wayland_resize_desktop(void) SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE); }
+static void wayland_configure_window(HWND hwnd) +{ + struct wayland_surface *surface; + INT width, height; + UINT flags; + + if (!(surface = wayland_surface_lock_hwnd(hwnd))) return; + + if (!surface->xdg_toplevel) + { + TRACE("missing xdg_toplevel, returning"); + pthread_mutex_unlock(&surface->mutex); + return; + } + + if (!surface->requested.serial) + { + TRACE("requested configure event already handled, returning\n"); + pthread_mutex_unlock(&surface->mutex); + return; + } + + surface->processing = surface->requested; + memset(&surface->requested, 0, sizeof(surface->requested)); + + width = surface->processing.width; + height = surface->processing.height; + + pthread_mutex_unlock(&surface->mutex); + + flags = SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE; + if (width == 0 || height == 0) flags |= SWP_NOSIZE; + + NtUserSetWindowPos(hwnd, 0, 0, 0, width, height, flags); +} + /********************************************************************** * WAYLAND_WindowMessage */ @@ -301,6 +352,9 @@ LRESULT WAYLAND_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) wayland_init_display_devices(TRUE); wayland_resize_desktop(); return 0; + case WM_WAYLAND_CONFIGURE: + wayland_configure_window(hwnd); + return 0; default: FIXME("got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, (long)wp, lp); return 0; diff --git a/dlls/winewayland.drv/window_surface.c b/dlls/winewayland.drv/window_surface.c index baf2c12a922..67cb2fe2d0b 100644 --- a/dlls/winewayland.drv/window_surface.c +++ b/dlls/winewayland.drv/window_surface.c @@ -444,7 +444,7 @@ static void wayland_window_surface_flush(struct window_surface *window_surface) wayland_window_surface_copy_to_buffer(wws, shm_buffer, copy_from_window_region);
pthread_mutex_lock(&wws->wayland_surface->mutex); - if (wws->wayland_surface->current_serial) + if (wayland_surface_reconfigure(wws->wayland_surface)) { wayland_surface_attach_shm(wws->wayland_surface, shm_buffer, surface_damage_region);