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);
From: Julian Orth ju.orth@gmail.com
Doing so is a protocol error. --- dlls/winewayland.drv/wayland_surface.c | 11 +++++++---- dlls/winewayland.drv/waylanddrv.h | 1 + 2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index a18189ecfff..cf681650757 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -347,6 +347,7 @@ void wayland_surface_clear_role(struct wayland_surface *surface) surface->big_icon_buffer = NULL; surface->small_icon_buffer = NULL; surface->xdg_toplevel_icon = NULL; + surface->configured = FALSE; }
if (surface->xdg_toplevel) @@ -637,6 +638,7 @@ static BOOL wayland_surface_reconfigure_xdg(struct wayland_surface *surface, surface->current = surface->processing; surface->processing_processed = FALSE; xdg_surface_ack_configure(surface->xdg_surface, surface->current.serial); + surface->configured = TRUE; } /* 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 @@ -650,18 +652,19 @@ static BOOL wayland_surface_reconfigure_xdg(struct wayland_surface *surface, wayland_surface_config_apply_delta(&surface->processing, &surface->requested, NULL); surface->current = surface->processing; xdg_surface_ack_configure(surface->xdg_surface, surface->current.serial); + surface->configured = TRUE; } - else if (!surface->current.serial || - !wayland_surface_config_is_compatible(&surface->current, + else if (!wayland_surface_config_is_compatible(&surface->current, width, height, window->state)) { return FALSE; }
- wayland_surface_reconfigure_geometry(surface, width, height); + if (surface->configured) + wayland_surface_reconfigure_geometry(surface, width, height);
- return TRUE; + return surface->configured; }
/********************************************************************** diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index bb092000f23..d28cb406837 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -282,6 +282,7 @@ struct wayland_surface struct xdg_toplevel_icon_v1 *xdg_toplevel_icon; struct wayland_shm_buffer *small_icon_buffer; struct wayland_shm_buffer *big_icon_buffer; + BOOL configured; }; struct {
From: Julian Orth ju.orth@gmail.com
--- dlls/winewayland.drv/Makefile.in | 1 + dlls/winewayland.drv/wayland.c | 5 + dlls/winewayland.drv/wayland_surface.c | 57 ++++++- dlls/winewayland.drv/waylanddrv.h | 9 +- dlls/winewayland.drv/window.c | 18 +- .../xdg-decoration-unstable-v1.xml | 160 ++++++++++++++++++ 6 files changed, 242 insertions(+), 8 deletions(-) create mode 100644 dlls/winewayland.drv/xdg-decoration-unstable-v1.xml
diff --git a/dlls/winewayland.drv/Makefile.in b/dlls/winewayland.drv/Makefile.in index e7b1bfb90eb..3e49fcc6086 100644 --- a/dlls/winewayland.drv/Makefile.in +++ b/dlls/winewayland.drv/Makefile.in @@ -25,6 +25,7 @@ SOURCES = \ window.c \ window_surface.c \ wlr-data-control-unstable-v1.xml \ + xdg-decoration-unstable-v1.xml \ xdg-output-unstable-v1.xml \ xdg-shell.xml \ xdg-toplevel-icon-v1.xml diff --git a/dlls/winewayland.drv/wayland.c b/dlls/winewayland.drv/wayland.c index ba09d32ed89..eaaa8cb5655 100644 --- a/dlls/winewayland.drv/wayland.c +++ b/dlls/winewayland.drv/wayland.c @@ -194,6 +194,11 @@ static void registry_handle_global(void *data, struct wl_registry *registry, process_wayland.xdg_toplevel_icon_manager_v1 = wl_registry_bind(registry, id, &xdg_toplevel_icon_manager_v1_interface, 1); } + else if (strcmp(interface, "zxdg_decoration_manager_v1") == 0) + { + process_wayland.zxdg_decoration_manager_v1 = + wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1); + } }
static void registry_handle_global_remove(void *data, struct wl_registry *registry, diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index cf681650757..d96971d9c1d 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -142,6 +142,30 @@ static const struct xdg_toplevel_listener xdg_toplevel_listener = xdg_toplevel_handle_close };
+static void xdg_decoration_handle_configure(void *private, + struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, + uint32_t mode) +{ + struct wayland_surface *surface; + HWND hwnd = private; + struct wayland_win_data *data; + + if (!(data = wayland_win_data_get(hwnd))) return; + + if ((surface = data->wayland_surface) && wayland_surface_is_toplevel(surface)) + { + surface->pending.mask |= WAYLAND_SURFACE_CONFIG_DELTA_DECORATION; + surface->pending.config.decoration_mode = mode; + } + + wayland_win_data_release(data); +} + +static const struct zxdg_toplevel_decoration_v1_listener zxdg_decoration_listener = +{ + xdg_decoration_handle_configure +}; + /********************************************************************** * wayland_surface_create * @@ -259,6 +283,16 @@ void wayland_surface_make_toplevel(struct wayland_surface *surface) if (!surface->xdg_toplevel) goto err; xdg_toplevel_add_listener(surface->xdg_toplevel, &xdg_toplevel_listener, surface->hwnd);
+ if (process_wayland.zxdg_decoration_manager_v1) { + surface->zxdg_toplevel_decoration = + zxdg_decoration_manager_v1_get_toplevel_decoration(process_wayland.zxdg_decoration_manager_v1, + surface->xdg_toplevel); + if (surface->zxdg_toplevel_decoration) + zxdg_toplevel_decoration_v1_add_listener(surface->zxdg_toplevel_decoration, + &zxdg_decoration_listener, + surface->hwnd); + } + if (process_name) xdg_toplevel_set_app_id(surface->xdg_toplevel, process_name);
@@ -350,6 +384,12 @@ void wayland_surface_clear_role(struct wayland_surface *surface) surface->configured = FALSE; }
+ if (surface->zxdg_toplevel_decoration) + { + zxdg_toplevel_decoration_v1_destroy(surface->zxdg_toplevel_decoration); + surface->zxdg_toplevel_decoration = NULL; + } + if (surface->xdg_toplevel) { xdg_toplevel_destroy(surface->xdg_toplevel); @@ -459,7 +499,8 @@ void wayland_surface_attach_shm(struct wayland_surface *surface, */ BOOL wayland_surface_config_is_compatible(struct wayland_surface_config *conf, int width, int height, - enum wayland_surface_config_state state) + enum wayland_surface_config_state state, + BOOL no_decoration) { static enum wayland_surface_config_state mask = WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED; @@ -476,6 +517,12 @@ BOOL wayland_surface_config_is_compatible(struct wayland_surface_config *conf, return FALSE; }
+ if (conf->decoration_mode) { + BOOL ssd = conf->decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; + if (ssd != no_decoration) + return FALSE; + } + /* The fullscreen state requires a size smaller or equal to the configured * size. If we have a larger size, we can use surface geometry during * surface reconfiguration to provide the smaller size, so we are always @@ -633,7 +680,7 @@ static BOOL wayland_surface_reconfigure_xdg(struct wayland_surface *surface, if (surface->processing.serial && surface->processing_processed && wayland_surface_config_is_compatible(&surface->processing, width, height, - window->state)) + window->state, window->no_decoration)) { surface->current = surface->processing; surface->processing_processed = FALSE; @@ -647,7 +694,7 @@ static BOOL wayland_surface_reconfigure_xdg(struct wayland_surface *surface, (surface->requested.mask & WAYLAND_SURFACE_CONFIG_DELTA_SERIAL) && wayland_surface_config_is_compatible(&surface->requested.config, width, height, - window->state)) + window->state, window->no_decoration)) { wayland_surface_config_apply_delta(&surface->processing, &surface->requested, NULL); surface->current = surface->processing; @@ -656,7 +703,7 @@ static BOOL wayland_surface_reconfigure_xdg(struct wayland_surface *surface, } else if (!wayland_surface_config_is_compatible(&surface->current, width, height, - window->state)) + window->state, window->no_decoration)) { return FALSE; } @@ -764,6 +811,8 @@ void wayland_surface_config_apply_delta(struct wayland_surface_config *target, } if (mask & WAYLAND_SURFACE_CONFIG_DELTA_STATE) target->state = delta->config.state; + if (delta->mask & WAYLAND_SURFACE_CONFIG_DELTA_DECORATION) + target->decoration_mode = delta->config.decoration_mode; delta->mask = 0;
if (target_mask) diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index d28cb406837..2bfb56c11a1 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -37,6 +37,7 @@ #include "xdg-shell-client-protocol.h" #include "wlr-data-control-unstable-v1-client-protocol.h" #include "xdg-toplevel-icon-v1-client-protocol.h" +#include "xdg-decoration-unstable-v1-client-protocol.h"
#include "windef.h" #include "winbase.h" @@ -172,6 +173,7 @@ struct wayland struct zwlr_data_control_manager_v1 *zwlr_data_control_manager_v1; struct wl_data_device_manager *wl_data_device_manager; struct xdg_toplevel_icon_manager_v1 *xdg_toplevel_icon_manager_v1; + struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1; struct wayland_seat seat; struct wayland_keyboard keyboard; struct wayland_pointer pointer; @@ -217,6 +219,7 @@ struct wayland_surface_config int32_t width, height; enum wayland_surface_config_state state; uint32_t serial; + enum zxdg_toplevel_decoration_v1_mode decoration_mode; };
enum wayland_surface_config_delta_mask @@ -224,6 +227,7 @@ 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), + WAYLAND_SURFACE_CONFIG_DELTA_DECORATION = (1 << 3), };
struct wayland_surface_config_delta @@ -241,6 +245,7 @@ struct wayland_window_config double scale; BOOL visible; BOOL managed; + BOOL no_decoration; };
struct wayland_client_surface @@ -280,6 +285,7 @@ struct wayland_surface struct xdg_surface *xdg_surface; struct xdg_toplevel *xdg_toplevel; struct xdg_toplevel_icon_v1 *xdg_toplevel_icon; + struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration; struct wayland_shm_buffer *small_icon_buffer; struct wayland_shm_buffer *big_icon_buffer; BOOL configured; @@ -330,7 +336,8 @@ void wayland_surface_attach_shm(struct wayland_surface *surface, BOOL wayland_surface_reconfigure(struct wayland_surface *surface); BOOL wayland_surface_config_is_compatible(struct wayland_surface_config *conf, int width, int height, - enum wayland_surface_config_state state); + enum wayland_surface_config_state state, + BOOL no_decoration); void wayland_surface_coords_from_window(struct wayland_surface *surface, int window_x, int window_y, int *surface_x, int *surface_y); diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index a2a4ca5eabd..0c69a085ae2 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -177,6 +177,7 @@ static void wayland_win_data_get_config(struct wayland_win_data *data, conf->scale = NtUserGetSystemDpiForProcess(0) / 96.0; conf->visible = (style & WS_VISIBLE) == WS_VISIBLE; conf->managed = data->managed; + conf->no_decoration = (style & WS_CAPTION) == 0; }
static void reapply_cursor_clipping(void) @@ -523,7 +524,7 @@ static void wayland_configure_window(HWND hwnd) INT window_surf_width, window_surf_height; UINT flags = 0; uint32_t state; - DWORD style; + DWORD style, flip_style = 0; BOOL needs_enter_size_move = FALSE; BOOL needs_exit_size_move = FALSE; struct wayland_win_data *data; @@ -600,7 +601,8 @@ static void wayland_configure_window(HWND hwnd) if ((surface->window.state & WAYLAND_SURFACE_CONFIG_STATE_FULLSCREEN) && wayland_surface_config_is_compatible(&surface->processing, window_surf_width, window_surf_height, - surface->window.state)) + surface->window.state, + surface->window.no_decoration)) { flags |= SWP_NOSIZE; } @@ -620,7 +622,17 @@ static void wayland_configure_window(HWND hwnd)
style = NtUserGetWindowLongW(hwnd, GWL_STYLE); if (!(state & WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED) != !(style & WS_MAXIMIZE)) - NtUserSetWindowLong(hwnd, GWL_STYLE, style ^ WS_MAXIMIZE, FALSE); + flip_style |= WS_MAXIMIZE; + if (surface->processing.decoration_mode) { + if (surface->processing.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE) + flip_style |= style & WS_CAPTION; + else + flip_style |= ~style & WS_CAPTION; + } + if (flip_style & WS_CAPTION) + flags |= SWP_FRAMECHANGED; + if (flip_style) + NtUserSetWindowLong(hwnd, GWL_STYLE, style ^ flip_style, FALSE);
/* The Wayland maximized and fullscreen states are very strict about * surface size, so don't let the application override it. The tiled state diff --git a/dlls/winewayland.drv/xdg-decoration-unstable-v1.xml b/dlls/winewayland.drv/xdg-decoration-unstable-v1.xml new file mode 100644 index 00000000000..82ca247c745 --- /dev/null +++ b/dlls/winewayland.drv/xdg-decoration-unstable-v1.xml @@ -0,0 +1,160 @@ +<?xml version="1.0" encoding="UTF-8"?> +<protocol name="xdg_decoration_unstable_v1"> + <copyright> + Copyright © 2018 Simon Ser + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + </copyright> + + <interface name="zxdg_decoration_manager_v1" version="1"> + <description summary="window decoration manager"> + This interface allows a compositor to announce support for server-side + decorations. + + A window decoration is a set of window controls as deemed appropriate by + the party managing them, such as user interface components used to move, + resize and change a window's state. + + A client can use this protocol to request being decorated by a supporting + compositor. + + If compositor and client do not negotiate the use of a server-side + decoration using this protocol, clients continue to self-decorate as they + see fit. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible changes + may be added together with the corresponding interface version bump. + Backward incompatible changes are done by bumping the version number in + the protocol and interface names and resetting the interface version. + Once the protocol is to be declared stable, the 'z' prefix and the + version number in the protocol and interface names are removed and the + interface version number is reset. + </description> + + <request name="destroy" type="destructor"> + <description summary="destroy the decoration manager object"> + Destroy the decoration manager. This doesn't destroy objects created + with the manager. + </description> + </request> + + <request name="get_toplevel_decoration"> + <description summary="create a new toplevel decoration object"> + Create a new decoration object associated with the given toplevel. + + Creating an xdg_toplevel_decoration from an xdg_toplevel which has a + buffer attached or committed is a client error, and any attempts by a + client to attach or manipulate a buffer prior to the first + xdg_toplevel_decoration.configure event must also be treated as + errors. + </description> + <arg name="id" type="new_id" interface="zxdg_toplevel_decoration_v1"/> + <arg name="toplevel" type="object" interface="xdg_toplevel"/> + </request> + </interface> + + <interface name="zxdg_toplevel_decoration_v1" version="1"> + <description summary="decoration object for a toplevel surface"> + The decoration object allows the compositor to toggle server-side window + decorations for a toplevel surface. The client can request to switch to + another mode. + + The xdg_toplevel_decoration object must be destroyed before its + xdg_toplevel. + </description> + + <enum name="error"> + <entry name="unconfigured_buffer" value="0" + summary="xdg_toplevel has a buffer attached before configure"/> + <entry name="already_constructed" value="1" + summary="xdg_toplevel already has a decoration object"/> + <entry name="orphaned" value="2" + summary="xdg_toplevel destroyed before the decoration object"/> + <entry name="invalid_mode" value="3" summary="invalid mode"/> + </enum> + + <request name="destroy" type="destructor"> + <description summary="destroy the decoration object"> + Switch back to a mode without any server-side decorations at the next + commit. + </description> + </request> + + <enum name="mode"> + <description summary="window decoration modes"> + These values describe window decoration modes. + </description> + <entry name="client_side" value="1" + summary="no server-side window decoration"/> + <entry name="server_side" value="2" + summary="server-side window decoration"/> + </enum> + + <request name="set_mode"> + <description summary="set the decoration mode"> + Set the toplevel surface decoration mode. This informs the compositor + that the client prefers the provided decoration mode. + + After requesting a decoration mode, the compositor will respond by + emitting an xdg_surface.configure event. The client should then update + its content, drawing it without decorations if the received mode is + server-side decorations. The client must also acknowledge the configure + when committing the new content (see xdg_surface.ack_configure). + + The compositor can decide not to use the client's mode and enforce a + different mode instead. + + Clients whose decoration mode depend on the xdg_toplevel state may send + a set_mode request in response to an xdg_surface.configure event and wait + for the next xdg_surface.configure event to prevent unwanted state. + Such clients are responsible for preventing configure loops and must + make sure not to send multiple successive set_mode requests with the + same decoration mode. + + If an invalid mode is supplied by the client, the invalid_mode protocol + error is raised by the compositor. + </description> + <arg name="mode" type="uint" enum="mode" summary="the decoration mode"/> + </request> + + <request name="unset_mode"> + <description summary="unset the decoration mode"> + Unset the toplevel surface decoration mode. This informs the compositor + that the client doesn't prefer a particular decoration mode. + + This request has the same semantics as set_mode. + </description> + </request> + + <event name="configure"> + <description summary="notify a decoration mode change"> + The configure event configures the effective decoration mode. The + configured state should not be applied immediately. Clients must send an + ack_configure in response to this event. See xdg_surface.configure and + xdg_surface.ack_configure for details. + + A configure event can be sent at any time. The specified mode must be + obeyed by the client. + </description> + <arg name="mode" type="uint" enum="mode" summary="the decoration mode"/> + </event> + </interface> +</protocol>
Hi @mahkoh, concerning the server-side decorations part, I don't think changing the win32 window state (i.e., disabling WM_CAPTION) is the way to go, since it may have other undesirable side effects.
The way I understand recent Wine versions deal with server side decorations is by utilizing the `visible` RECT in `struct window_rects` passed in the `WindowPosChanged` driver callback. This describes the area of the window that should actually be visible on the screen. If the `window` RECT doesn't match the `visible` RECT then that's an indication that the driver should handle the decoration (e.g., https://gitlab.winehq.org/wine/wine/-/blob/ccb99cd00f55b716e3aa1a80ff4b13a6d...)
Note that in order for win32u to actually enable this mechanism a few things should be in place (https://gitlab.winehq.org/wine/wine/-/blob/ccb99cd00f55b716e3aa1a80ff4b13a6d...): 1. The "Decorated" option should be enabled (e.g., through winecfg "Allow the window manager to the decorate the windows") 2. The driver should implement the `GetWindowStyleMasks` callback.
Here is a rough list of what's missing to have server side decorations: 1. Implement `GetWindowStyleMasks` so that we get a proper `visible` RECT when the "Decorated" option is enabled. 2. Ensure we properly display only the `visible` part of surface buffers, input coordinates are translated properly etc 3. Enable the server-side decoration protocol.