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>