From be3bc44d54290de677e5c5186b6f6a1836693011 Mon Sep 17 00:00:00 2001 From: elParaguayo Date: Sat, 26 Jul 2025 10:41:25 +0100 Subject: [PATCH 01/14] Add z layer manager --- libqtile/backend/base/zmanager.py | 88 + .../wlr-layer-shell-unstable-v1-protocol.h | 710 +++++ .../wayland/qw/proto/xdg-shell-protocol.h | 2327 +++++++++++++++++ 3 files changed, 3125 insertions(+) create mode 100644 libqtile/backend/base/zmanager.py create mode 100644 libqtile/backend/wayland/qw/proto/wlr-layer-shell-unstable-v1-protocol.h create mode 100644 libqtile/backend/wayland/qw/proto/xdg-shell-protocol.h diff --git a/libqtile/backend/base/zmanager.py b/libqtile/backend/base/zmanager.py new file mode 100644 index 0000000000..37af7df4af --- /dev/null +++ b/libqtile/backend/base/zmanager.py @@ -0,0 +1,88 @@ +# Copyright (c) 2025 elParaguayo +# +# 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 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. +from collections import defaultdict +from enum import Enum + + +LAYERS = ["background", "bottom", "normal", "above", "top", "overlay", "system"] + +class _ZLayer: + _index = 0 + def __init__(self, name): + self.name = name + self.index = _ZLayer._index + _ZLayer._index += 1 + self.clients = [] + +_layers = [_ZLayer(layer) for layer in LAYERS] +ZLayer = Enum("ZLayer", {layer.name.upper(): layer.index for layer in _layers}) + + +class ZManager: + def __init__(self): + self.layers = _layers + + def add_window(self, window_id, layer="normal"): + if layer not in self.layers: + raise ValueError(f"Invalid layer: {layer}") + self.layers[layer].append(window_id) + self.window_lookup[window_id] = (layer, len(self.layers[layer]) - 1) + + def remove_window(self, window_id): + layer, _ = self.window_lookup.pop(window_id) + self.layers[layer].remove(window_id) + self._reindex_layer(layer) + + def raise_window(self, window_id): + layer, _ = self.window_lookup[window_id] + self.layers[layer].remove(window_id) + self.layers[layer].append(window_id) + self._reindex_layer(layer) + + def lower_window(self, window_id): + layer, _ = self.window_lookup[window_id] + self.layers[layer].remove(window_id) + self.layers[layer].insert(0, window_id) + self._reindex_layer(layer) + + def move_window_to_layer(self, window_id, new_layer, position='top'): + old_layer, _ = self.window_lookup[window_id] + self.layers[old_layer].remove(window_id) + + if position == 'top': + self.layers[new_layer].append(window_id) + elif position == 'bottom': + self.layers[new_layer].insert(0, window_id) + else: + self.layers[new_layer].insert(position, window_id) + + self.window_lookup[window_id] = (new_layer, self.layers[new_layer].index(window_id)) + self._reindex_layer(old_layer) + self._reindex_layer(new_layer) + + def get_z_order(self): + z_order = [] + for layer in self.layer_order: + z_order.extend(self.layers[layer]) + return z_order + + def _reindex_layer(self, layer): + for idx, win_id in enumerate(self.layers[layer]): + self.window_lookup[win_id] = (layer, idx) diff --git a/libqtile/backend/wayland/qw/proto/wlr-layer-shell-unstable-v1-protocol.h b/libqtile/backend/wayland/qw/proto/wlr-layer-shell-unstable-v1-protocol.h new file mode 100644 index 0000000000..2e8962a0d6 --- /dev/null +++ b/libqtile/backend/wayland/qw/proto/wlr-layer-shell-unstable-v1-protocol.h @@ -0,0 +1,710 @@ +/* Generated by wayland-scanner 1.23.1 */ + +#ifndef WLR_LAYER_SHELL_UNSTABLE_V1_SERVER_PROTOCOL_H +#define WLR_LAYER_SHELL_UNSTABLE_V1_SERVER_PROTOCOL_H + +#include +#include +#include "wayland-server.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct wl_client; +struct wl_resource; + +/** + * @page page_wlr_layer_shell_unstable_v1 The wlr_layer_shell_unstable_v1 protocol + * @section page_ifaces_wlr_layer_shell_unstable_v1 Interfaces + * - @subpage page_iface_zwlr_layer_shell_v1 - create surfaces that are layers of the desktop + * - @subpage page_iface_zwlr_layer_surface_v1 - layer metadata interface + * @section page_copyright_wlr_layer_shell_unstable_v1 Copyright + *
+ *
+ * Copyright © 2017 Drew DeVault
+ *
+ * Permission to use, copy, modify, distribute, and sell this
+ * software and its documentation for any purpose is hereby granted
+ * without fee, provided that the above copyright notice appear in
+ * all copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * the copyright holders not be used in advertising or publicity
+ * pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ * 
+ */ +struct wl_output; +struct wl_surface; +struct xdg_popup; +struct zwlr_layer_shell_v1; +struct zwlr_layer_surface_v1; + +#ifndef ZWLR_LAYER_SHELL_V1_INTERFACE +#define ZWLR_LAYER_SHELL_V1_INTERFACE +/** + * @page page_iface_zwlr_layer_shell_v1 zwlr_layer_shell_v1 + * @section page_iface_zwlr_layer_shell_v1_desc Description + * + * Clients can use this interface to assign the surface_layer role to + * wl_surfaces. Such surfaces are assigned to a "layer" of the output and + * rendered with a defined z-depth respective to each other. They may also be + * anchored to the edges and corners of a screen and specify input handling + * semantics. This interface should be suitable for the implementation of + * many desktop shell components, and a broad number of other applications + * that interact with the desktop. + * @section page_iface_zwlr_layer_shell_v1_api API + * See @ref iface_zwlr_layer_shell_v1. + */ +/** + * @defgroup iface_zwlr_layer_shell_v1 The zwlr_layer_shell_v1 interface + * + * Clients can use this interface to assign the surface_layer role to + * wl_surfaces. Such surfaces are assigned to a "layer" of the output and + * rendered with a defined z-depth respective to each other. They may also be + * anchored to the edges and corners of a screen and specify input handling + * semantics. This interface should be suitable for the implementation of + * many desktop shell components, and a broad number of other applications + * that interact with the desktop. + */ +extern const struct wl_interface zwlr_layer_shell_v1_interface; +#endif +#ifndef ZWLR_LAYER_SURFACE_V1_INTERFACE +#define ZWLR_LAYER_SURFACE_V1_INTERFACE +/** + * @page page_iface_zwlr_layer_surface_v1 zwlr_layer_surface_v1 + * @section page_iface_zwlr_layer_surface_v1_desc Description + * + * An interface that may be implemented by a wl_surface, for surfaces that + * are designed to be rendered as a layer of a stacked desktop-like + * environment. + * + * Layer surface state (layer, size, anchor, exclusive zone, + * margin, interactivity) is double-buffered, and will be applied at the + * time wl_surface.commit of the corresponding wl_surface is called. + * + * Attaching a null buffer to a layer surface unmaps it. + * + * Unmapping a layer_surface means that the surface cannot be shown by the + * compositor until it is explicitly mapped again. The layer_surface + * returns to the state it had right after layer_shell.get_layer_surface. + * The client can re-map the surface by performing a commit without any + * buffer attached, waiting for a configure event and handling it as usual. + * @section page_iface_zwlr_layer_surface_v1_api API + * See @ref iface_zwlr_layer_surface_v1. + */ +/** + * @defgroup iface_zwlr_layer_surface_v1 The zwlr_layer_surface_v1 interface + * + * An interface that may be implemented by a wl_surface, for surfaces that + * are designed to be rendered as a layer of a stacked desktop-like + * environment. + * + * Layer surface state (layer, size, anchor, exclusive zone, + * margin, interactivity) is double-buffered, and will be applied at the + * time wl_surface.commit of the corresponding wl_surface is called. + * + * Attaching a null buffer to a layer surface unmaps it. + * + * Unmapping a layer_surface means that the surface cannot be shown by the + * compositor until it is explicitly mapped again. The layer_surface + * returns to the state it had right after layer_shell.get_layer_surface. + * The client can re-map the surface by performing a commit without any + * buffer attached, waiting for a configure event and handling it as usual. + */ +extern const struct wl_interface zwlr_layer_surface_v1_interface; +#endif + +#ifndef ZWLR_LAYER_SHELL_V1_ERROR_ENUM +#define ZWLR_LAYER_SHELL_V1_ERROR_ENUM +enum zwlr_layer_shell_v1_error { + /** + * wl_surface has another role + */ + ZWLR_LAYER_SHELL_V1_ERROR_ROLE = 0, + /** + * layer value is invalid + */ + ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER = 1, + /** + * wl_surface has a buffer attached or committed + */ + ZWLR_LAYER_SHELL_V1_ERROR_ALREADY_CONSTRUCTED = 2, +}; +/** + * @ingroup iface_zwlr_layer_shell_v1 + * Validate a zwlr_layer_shell_v1 error value. + * + * @return true on success, false on error. + * @ref zwlr_layer_shell_v1_error + */ +static inline bool +zwlr_layer_shell_v1_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case ZWLR_LAYER_SHELL_V1_ERROR_ROLE: + return version >= 1; + case ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER: + return version >= 1; + case ZWLR_LAYER_SHELL_V1_ERROR_ALREADY_CONSTRUCTED: + return version >= 1; + default: + return false; + } +} +#endif /* ZWLR_LAYER_SHELL_V1_ERROR_ENUM */ + +#ifndef ZWLR_LAYER_SHELL_V1_LAYER_ENUM +#define ZWLR_LAYER_SHELL_V1_LAYER_ENUM +/** + * @ingroup iface_zwlr_layer_shell_v1 + * available layers for surfaces + * + * These values indicate which layers a surface can be rendered in. They + * are ordered by z depth, bottom-most first. Traditional shell surfaces + * will typically be rendered between the bottom and top layers. + * Fullscreen shell surfaces are typically rendered at the top layer. + * Multiple surfaces can share a single layer, and ordering within a + * single layer is undefined. + */ +enum zwlr_layer_shell_v1_layer { + ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND = 0, + ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM = 1, + ZWLR_LAYER_SHELL_V1_LAYER_TOP = 2, + ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY = 3, +}; +/** + * @ingroup iface_zwlr_layer_shell_v1 + * Validate a zwlr_layer_shell_v1 layer value. + * + * @return true on success, false on error. + * @ref zwlr_layer_shell_v1_layer + */ +static inline bool +zwlr_layer_shell_v1_layer_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND: + return version >= 1; + case ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM: + return version >= 1; + case ZWLR_LAYER_SHELL_V1_LAYER_TOP: + return version >= 1; + case ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY: + return version >= 1; + default: + return false; + } +} +#endif /* ZWLR_LAYER_SHELL_V1_LAYER_ENUM */ + +/** + * @ingroup iface_zwlr_layer_shell_v1 + * @struct zwlr_layer_shell_v1_interface + */ +struct zwlr_layer_shell_v1_interface { + /** + * create a layer_surface from a surface + * + * Create a layer surface for an existing surface. This assigns + * the role of layer_surface, or raises a protocol error if another + * role is already assigned. + * + * Creating a layer surface from a wl_surface 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 + * layer_surface.configure call must also be treated as errors. + * + * After creating a layer_surface object and setting it up, the + * client must perform an initial commit without any buffer + * attached. The compositor will reply with a + * layer_surface.configure event. The client must acknowledge it + * and is then allowed to attach a buffer to map the surface. + * + * You may pass NULL for output to allow the compositor to decide + * which output to use. Generally this will be the one that the + * user most recently interacted with. + * + * Clients can specify a namespace that defines the purpose of the + * layer surface. + * @param layer layer to add this surface to + * @param namespace namespace for the layer surface + */ + void (*get_layer_surface)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface, + struct wl_resource *output, + uint32_t layer, + const char *namespace); + /** + * destroy the layer_shell object + * + * This request indicates that the client will not use the + * layer_shell object any more. Objects that have been created + * through this instance are not affected. + * @since 3 + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); +}; + + +/** + * @ingroup iface_zwlr_layer_shell_v1 + */ +#define ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_shell_v1 + */ +#define ZWLR_LAYER_SHELL_V1_DESTROY_SINCE_VERSION 3 + +#ifndef ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ENUM +#define ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ENUM +/** + * @ingroup iface_zwlr_layer_surface_v1 + * types of keyboard interaction possible for a layer shell surface + * + * Types of keyboard interaction possible for layer shell surfaces. The + * rationale for this is twofold: (1) some applications are not interested + * in keyboard events and not allowing them to be focused can improve the + * desktop experience; (2) some applications will want to take exclusive + * keyboard focus. + */ +enum zwlr_layer_surface_v1_keyboard_interactivity { + /** + * no keyboard focus is possible + * + * This value indicates that this surface is not interested in + * keyboard events and the compositor should never assign it the + * keyboard focus. + * + * This is the default value, set for newly created layer shell + * surfaces. + * + * This is useful for e.g. desktop widgets that display information + * or only have interaction with non-keyboard input devices. + */ + ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE = 0, + /** + * request exclusive keyboard focus + * + * Request exclusive keyboard focus if this surface is above the + * shell surface layer. + * + * For the top and overlay layers, the seat will always give + * exclusive keyboard focus to the top-most layer which has + * keyboard interactivity set to exclusive. If this layer contains + * multiple surfaces with keyboard interactivity set to exclusive, + * the compositor determines the one receiving keyboard events in + * an implementation- defined manner. In this case, no guarantee is + * made when this surface will receive keyboard focus (if ever). + * + * For the bottom and background layers, the compositor is allowed + * to use normal focus semantics. + * + * This setting is mainly intended for applications that need to + * ensure they receive all keyboard events, such as a lock screen + * or a password prompt. + */ + ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE = 1, + /** + * request regular keyboard focus semantics + * + * This requests the compositor to allow this surface to be + * focused and unfocused by the user in an implementation-defined + * manner. The user should be able to unfocus this surface even + * regardless of the layer it is on. + * + * Typically, the compositor will want to use its normal mechanism + * to manage keyboard focus between layer shell surfaces with this + * setting and regular toplevels on the desktop layer (e.g. click + * to focus). Nevertheless, it is possible for a compositor to + * require a special interaction to focus or unfocus layer shell + * surfaces (e.g. requiring a click even if focus follows the mouse + * normally, or providing a keybinding to switch focus between + * layers). + * + * This setting is mainly intended for desktop shell components + * (e.g. panels) that allow keyboard interaction. Using this option + * can allow implementing a desktop shell that can be fully usable + * without the mouse. + * @since 4 + */ + ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND = 2, +}; +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND_SINCE_VERSION 4 +/** + * @ingroup iface_zwlr_layer_surface_v1 + * Validate a zwlr_layer_surface_v1 keyboard_interactivity value. + * + * @return true on success, false on error. + * @ref zwlr_layer_surface_v1_keyboard_interactivity + */ +static inline bool +zwlr_layer_surface_v1_keyboard_interactivity_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE: + return version >= 1; + case ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE: + return version >= 1; + case ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND: + return version >= 4; + default: + return false; + } +} +#endif /* ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ENUM */ + +#ifndef ZWLR_LAYER_SURFACE_V1_ERROR_ENUM +#define ZWLR_LAYER_SURFACE_V1_ERROR_ENUM +enum zwlr_layer_surface_v1_error { + /** + * provided surface state is invalid + */ + ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SURFACE_STATE = 0, + /** + * size is invalid + */ + ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SIZE = 1, + /** + * anchor bitfield is invalid + */ + ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_ANCHOR = 2, + /** + * keyboard interactivity is invalid + */ + ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_KEYBOARD_INTERACTIVITY = 3, +}; +/** + * @ingroup iface_zwlr_layer_surface_v1 + * Validate a zwlr_layer_surface_v1 error value. + * + * @return true on success, false on error. + * @ref zwlr_layer_surface_v1_error + */ +static inline bool +zwlr_layer_surface_v1_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SURFACE_STATE: + return version >= 1; + case ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SIZE: + return version >= 1; + case ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_ANCHOR: + return version >= 1; + case ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_KEYBOARD_INTERACTIVITY: + return version >= 1; + default: + return false; + } +} +#endif /* ZWLR_LAYER_SURFACE_V1_ERROR_ENUM */ + +#ifndef ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM +#define ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM +enum zwlr_layer_surface_v1_anchor { + /** + * the top edge of the anchor rectangle + */ + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP = 1, + /** + * the bottom edge of the anchor rectangle + */ + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM = 2, + /** + * the left edge of the anchor rectangle + */ + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT = 4, + /** + * the right edge of the anchor rectangle + */ + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT = 8, +}; +/** + * @ingroup iface_zwlr_layer_surface_v1 + * Validate a zwlr_layer_surface_v1 anchor value. + * + * @return true on success, false on error. + * @ref zwlr_layer_surface_v1_anchor + */ +static inline bool +zwlr_layer_surface_v1_anchor_is_valid(uint32_t value, uint32_t version) { + uint32_t valid = 0; + if (version >= 1) + valid |= ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; + if (version >= 1) + valid |= ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; + if (version >= 1) + valid |= ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT; + if (version >= 1) + valid |= ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; + return (value & ~valid) == 0; +} +#endif /* ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM */ + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * @struct zwlr_layer_surface_v1_interface + */ +struct zwlr_layer_surface_v1_interface { + /** + * sets the size of the surface + * + * Sets the size of the surface in surface-local coordinates. The + * compositor will display the surface centered with respect to its + * anchors. + * + * If you pass 0 for either value, the compositor will assign it + * and inform you of the assignment in the configure event. You + * must set your anchor to opposite edges in the dimensions you + * omit; not doing so is a protocol error. Both values are 0 by + * default. + * + * Size is double-buffered, see wl_surface.commit. + */ + void (*set_size)(struct wl_client *client, + struct wl_resource *resource, + uint32_t width, + uint32_t height); + /** + * configures the anchor point of the surface + * + * Requests that the compositor anchor the surface to the + * specified edges and corners. If two orthogonal edges are + * specified (e.g. 'top' and 'left'), then the anchor point will be + * the intersection of the edges (e.g. the top left corner of the + * output); otherwise the anchor point will be centered on that + * edge, or in the center if none is specified. + * + * Anchor is double-buffered, see wl_surface.commit. + */ + void (*set_anchor)(struct wl_client *client, + struct wl_resource *resource, + uint32_t anchor); + /** + * configures the exclusive geometry of this surface + * + * Requests that the compositor avoids occluding an area with + * other surfaces. The compositor's use of this information is + * implementation-dependent - do not assume that this region will + * not actually be occluded. + * + * A positive value is only meaningful if the surface is anchored + * to one edge or an edge and both perpendicular edges. If the + * surface is not anchored, anchored to only two perpendicular + * edges (a corner), anchored to only two parallel edges or + * anchored to all edges, a positive value will be treated the same + * as zero. + * + * A positive zone is the distance from the edge in surface-local + * coordinates to consider exclusive. + * + * Surfaces that do not wish to have an exclusive zone may instead + * specify how they should interact with surfaces that do. If set + * to zero, the surface indicates that it would like to be moved to + * avoid occluding surfaces with a positive exclusive zone. If set + * to -1, the surface indicates that it would not like to be moved + * to accommodate for other surfaces, and the compositor should + * extend it all the way to the edges it is anchored to. + * + * For example, a panel might set its exclusive zone to 10, so that + * maximized shell surfaces are not shown on top of it. A + * notification might set its exclusive zone to 0, so that it is + * moved to avoid occluding the panel, but shell surfaces are shown + * underneath it. A wallpaper or lock screen might set their + * exclusive zone to -1, so that they stretch below or over the + * panel. + * + * The default value is 0. + * + * Exclusive zone is double-buffered, see wl_surface.commit. + */ + void (*set_exclusive_zone)(struct wl_client *client, + struct wl_resource *resource, + int32_t zone); + /** + * sets a margin from the anchor point + * + * Requests that the surface be placed some distance away from + * the anchor point on the output, in surface-local coordinates. + * Setting this value for edges you are not anchored to has no + * effect. + * + * The exclusive zone includes the margin. + * + * Margin is double-buffered, see wl_surface.commit. + */ + void (*set_margin)(struct wl_client *client, + struct wl_resource *resource, + int32_t top, + int32_t right, + int32_t bottom, + int32_t left); + /** + * requests keyboard events + * + * Set how keyboard events are delivered to this surface. By + * default, layer shell surfaces do not receive keyboard events; + * this request can be used to change this. + * + * This setting is inherited by child surfaces set by the get_popup + * request. + * + * Layer surfaces receive pointer, touch, and tablet events + * normally. If you do not want to receive them, set the input + * region on your surface to an empty region. + * + * Keyboard interactivity is double-buffered, see + * wl_surface.commit. + */ + void (*set_keyboard_interactivity)(struct wl_client *client, + struct wl_resource *resource, + uint32_t keyboard_interactivity); + /** + * assign this layer_surface as an xdg_popup parent + * + * This assigns an xdg_popup's parent to this layer_surface. This + * popup should have been created via xdg_surface::get_popup with + * the parent set to NULL, and this request must be invoked before + * committing the popup's initial state. + * + * See the documentation of xdg_popup for more details about what + * an xdg_popup is and how it is used. + */ + void (*get_popup)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *popup); + /** + * ack a configure event + * + * When a configure event is received, if a client commits the + * surface in response to the configure event, then the client must + * make an ack_configure request sometime before the commit + * request, passing along the serial of the configure event. + * + * If the client receives multiple configure events before it can + * respond to one, it only has to ack the last configure event. + * + * A client is not required to commit immediately after sending an + * ack_configure request - it may even ack_configure several times + * before its next surface commit. + * + * A client may send multiple ack_configure requests before + * committing, but only the last request sent before a commit + * indicates which configure event the client really is responding + * to. + * @param serial the serial from the configure event + */ + void (*ack_configure)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial); + /** + * destroy the layer_surface + * + * This request destroys the layer surface. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * change the layer of the surface + * + * Change the layer that the surface is rendered on. + * + * Layer is double-buffered, see wl_surface.commit. + * @param layer layer to move this surface to + * @since 2 + */ + void (*set_layer)(struct wl_client *client, + struct wl_resource *resource, + uint32_t layer); +}; + +#define ZWLR_LAYER_SURFACE_V1_CONFIGURE 0 +#define ZWLR_LAYER_SURFACE_V1_CLOSED 1 + +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_CLOSED_SINCE_VERSION 1 + +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_SET_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_SET_ANCHOR_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_SET_MARGIN_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_GET_POPUP_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_SET_LAYER_SINCE_VERSION 2 + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * Sends an configure event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +zwlr_layer_surface_v1_send_configure(struct wl_resource *resource_, uint32_t serial, uint32_t width, uint32_t height) +{ + wl_resource_post_event(resource_, ZWLR_LAYER_SURFACE_V1_CONFIGURE, serial, width, height); +} + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * Sends an closed event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +zwlr_layer_surface_v1_send_closed(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, ZWLR_LAYER_SURFACE_V1_CLOSED); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libqtile/backend/wayland/qw/proto/xdg-shell-protocol.h b/libqtile/backend/wayland/qw/proto/xdg-shell-protocol.h new file mode 100644 index 0000000000..3bd3ce5f1c --- /dev/null +++ b/libqtile/backend/wayland/qw/proto/xdg-shell-protocol.h @@ -0,0 +1,2327 @@ +/* Generated by wayland-scanner 1.23.1 */ + +#ifndef XDG_SHELL_SERVER_PROTOCOL_H +#define XDG_SHELL_SERVER_PROTOCOL_H + +#include +#include +#include "wayland-server.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct wl_client; +struct wl_resource; + +/** + * @page page_xdg_shell The xdg_shell protocol + * @section page_ifaces_xdg_shell Interfaces + * - @subpage page_iface_xdg_wm_base - create desktop-style surfaces + * - @subpage page_iface_xdg_positioner - child surface positioner + * - @subpage page_iface_xdg_surface - desktop user interface surface base interface + * - @subpage page_iface_xdg_toplevel - toplevel surface + * - @subpage page_iface_xdg_popup - short-lived, popup surfaces for menus + * @section page_copyright_xdg_shell Copyright + *
+ *
+ * Copyright © 2008-2013 Kristian Høgsberg
+ * Copyright © 2013      Rafael Antognolli
+ * Copyright © 2013      Jasper St. Pierre
+ * Copyright © 2010-2013 Intel Corporation
+ * Copyright © 2015-2017 Samsung Electronics Co., Ltd
+ * Copyright © 2015-2017 Red Hat Inc.
+ *
+ * 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.
+ * 
+ */ +struct wl_output; +struct wl_seat; +struct wl_surface; +struct xdg_popup; +struct xdg_positioner; +struct xdg_surface; +struct xdg_toplevel; +struct xdg_wm_base; + +#ifndef XDG_WM_BASE_INTERFACE +#define XDG_WM_BASE_INTERFACE +/** + * @page page_iface_xdg_wm_base xdg_wm_base + * @section page_iface_xdg_wm_base_desc Description + * + * The xdg_wm_base interface is exposed as a global object enabling clients + * to turn their wl_surfaces into windows in a desktop environment. It + * defines the basic functionality needed for clients and the compositor to + * create windows that can be dragged, resized, maximized, etc, as well as + * creating transient windows such as popup menus. + * @section page_iface_xdg_wm_base_api API + * See @ref iface_xdg_wm_base. + */ +/** + * @defgroup iface_xdg_wm_base The xdg_wm_base interface + * + * The xdg_wm_base interface is exposed as a global object enabling clients + * to turn their wl_surfaces into windows in a desktop environment. It + * defines the basic functionality needed for clients and the compositor to + * create windows that can be dragged, resized, maximized, etc, as well as + * creating transient windows such as popup menus. + */ +extern const struct wl_interface xdg_wm_base_interface; +#endif +#ifndef XDG_POSITIONER_INTERFACE +#define XDG_POSITIONER_INTERFACE +/** + * @page page_iface_xdg_positioner xdg_positioner + * @section page_iface_xdg_positioner_desc Description + * + * The xdg_positioner provides a collection of rules for the placement of a + * child surface relative to a parent surface. Rules can be defined to ensure + * the child surface remains within the visible area's borders, and to + * specify how the child surface changes its position, such as sliding along + * an axis, or flipping around a rectangle. These positioner-created rules are + * constrained by the requirement that a child surface must intersect with or + * be at least partially adjacent to its parent surface. + * + * See the various requests for details about possible rules. + * + * At the time of the request, the compositor makes a copy of the rules + * specified by the xdg_positioner. Thus, after the request is complete the + * xdg_positioner object can be destroyed or reused; further changes to the + * object will have no effect on previous usages. + * + * For an xdg_positioner object to be considered complete, it must have a + * non-zero size set by set_size, and a non-zero anchor rectangle set by + * set_anchor_rect. Passing an incomplete xdg_positioner object when + * positioning a surface raises an invalid_positioner error. + * @section page_iface_xdg_positioner_api API + * See @ref iface_xdg_positioner. + */ +/** + * @defgroup iface_xdg_positioner The xdg_positioner interface + * + * The xdg_positioner provides a collection of rules for the placement of a + * child surface relative to a parent surface. Rules can be defined to ensure + * the child surface remains within the visible area's borders, and to + * specify how the child surface changes its position, such as sliding along + * an axis, or flipping around a rectangle. These positioner-created rules are + * constrained by the requirement that a child surface must intersect with or + * be at least partially adjacent to its parent surface. + * + * See the various requests for details about possible rules. + * + * At the time of the request, the compositor makes a copy of the rules + * specified by the xdg_positioner. Thus, after the request is complete the + * xdg_positioner object can be destroyed or reused; further changes to the + * object will have no effect on previous usages. + * + * For an xdg_positioner object to be considered complete, it must have a + * non-zero size set by set_size, and a non-zero anchor rectangle set by + * set_anchor_rect. Passing an incomplete xdg_positioner object when + * positioning a surface raises an invalid_positioner error. + */ +extern const struct wl_interface xdg_positioner_interface; +#endif +#ifndef XDG_SURFACE_INTERFACE +#define XDG_SURFACE_INTERFACE +/** + * @page page_iface_xdg_surface xdg_surface + * @section page_iface_xdg_surface_desc Description + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides a base set of functionality required to construct user + * interface elements requiring management by the compositor, such as + * toplevel windows, menus, etc. The types of functionality are split into + * xdg_surface roles. + * + * Creating an xdg_surface does not set the role for a wl_surface. In order + * to map an xdg_surface, the client must create a role-specific object + * using, e.g., get_toplevel, get_popup. The wl_surface for any given + * xdg_surface can have at most one role, and may not be assigned any role + * not based on xdg_surface. + * + * A role must be assigned before any other requests are made to the + * xdg_surface object. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_surface state to take effect. + * + * Creating an xdg_surface from a wl_surface 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_surface.configure call must + * also be treated as errors. + * + * After creating a role-specific object and setting it up (e.g. by sending + * the title, app ID, size constraints, parent, etc), the client must + * perform an initial commit without any buffer attached. The compositor + * will reply with initial wl_surface state such as + * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure + * event. The client must acknowledge it and is then allowed to attach a + * buffer to map the surface. + * + * Mapping an xdg_surface-based role surface is defined as making it + * possible for the surface to be shown by the compositor. Note that + * a mapped surface is not guaranteed to be visible once it is mapped. + * + * For an xdg_surface to be mapped by the compositor, the following + * conditions must be met: + * (1) the client has assigned an xdg_surface-based role to the surface + * (2) the client has set and committed the xdg_surface state and the + * role-dependent state to the surface + * (3) the client has committed a buffer to the surface + * + * A newly-unmapped surface is considered to have met condition (1) out + * of the 3 required conditions for mapping a surface if its role surface + * has not been destroyed, i.e. the client must perform the initial commit + * again before attaching a buffer. + * @section page_iface_xdg_surface_api API + * See @ref iface_xdg_surface. + */ +/** + * @defgroup iface_xdg_surface The xdg_surface interface + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides a base set of functionality required to construct user + * interface elements requiring management by the compositor, such as + * toplevel windows, menus, etc. The types of functionality are split into + * xdg_surface roles. + * + * Creating an xdg_surface does not set the role for a wl_surface. In order + * to map an xdg_surface, the client must create a role-specific object + * using, e.g., get_toplevel, get_popup. The wl_surface for any given + * xdg_surface can have at most one role, and may not be assigned any role + * not based on xdg_surface. + * + * A role must be assigned before any other requests are made to the + * xdg_surface object. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_surface state to take effect. + * + * Creating an xdg_surface from a wl_surface 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_surface.configure call must + * also be treated as errors. + * + * After creating a role-specific object and setting it up (e.g. by sending + * the title, app ID, size constraints, parent, etc), the client must + * perform an initial commit without any buffer attached. The compositor + * will reply with initial wl_surface state such as + * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure + * event. The client must acknowledge it and is then allowed to attach a + * buffer to map the surface. + * + * Mapping an xdg_surface-based role surface is defined as making it + * possible for the surface to be shown by the compositor. Note that + * a mapped surface is not guaranteed to be visible once it is mapped. + * + * For an xdg_surface to be mapped by the compositor, the following + * conditions must be met: + * (1) the client has assigned an xdg_surface-based role to the surface + * (2) the client has set and committed the xdg_surface state and the + * role-dependent state to the surface + * (3) the client has committed a buffer to the surface + * + * A newly-unmapped surface is considered to have met condition (1) out + * of the 3 required conditions for mapping a surface if its role surface + * has not been destroyed, i.e. the client must perform the initial commit + * again before attaching a buffer. + */ +extern const struct wl_interface xdg_surface_interface; +#endif +#ifndef XDG_TOPLEVEL_INTERFACE +#define XDG_TOPLEVEL_INTERFACE +/** + * @page page_iface_xdg_toplevel xdg_toplevel + * @section page_iface_xdg_toplevel_desc Description + * + * This interface defines an xdg_surface role which allows a surface to, + * among other things, set window-like properties such as maximize, + * fullscreen, and minimize, set application-specific metadata like title and + * id, and well as trigger user interactive operations such as interactive + * resize and move. + * + * A xdg_toplevel by default is responsible for providing the full intended + * visual representation of the toplevel, which depending on the window + * state, may mean things like a title bar, window controls and drop shadow. + * + * Unmapping an xdg_toplevel means that the surface cannot be shown + * by the compositor until it is explicitly mapped again. + * All active operations (e.g., move, resize) are canceled and all + * attributes (e.g. title, state, stacking, ...) are discarded for + * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to + * the state it had right after xdg_surface.get_toplevel. The client + * can re-map the toplevel by performing a commit without any buffer + * attached, waiting for a configure event and handling it as usual (see + * xdg_surface description). + * + * Attaching a null buffer to a toplevel unmaps the surface. + * @section page_iface_xdg_toplevel_api API + * See @ref iface_xdg_toplevel. + */ +/** + * @defgroup iface_xdg_toplevel The xdg_toplevel interface + * + * This interface defines an xdg_surface role which allows a surface to, + * among other things, set window-like properties such as maximize, + * fullscreen, and minimize, set application-specific metadata like title and + * id, and well as trigger user interactive operations such as interactive + * resize and move. + * + * A xdg_toplevel by default is responsible for providing the full intended + * visual representation of the toplevel, which depending on the window + * state, may mean things like a title bar, window controls and drop shadow. + * + * Unmapping an xdg_toplevel means that the surface cannot be shown + * by the compositor until it is explicitly mapped again. + * All active operations (e.g., move, resize) are canceled and all + * attributes (e.g. title, state, stacking, ...) are discarded for + * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to + * the state it had right after xdg_surface.get_toplevel. The client + * can re-map the toplevel by performing a commit without any buffer + * attached, waiting for a configure event and handling it as usual (see + * xdg_surface description). + * + * Attaching a null buffer to a toplevel unmaps the surface. + */ +extern const struct wl_interface xdg_toplevel_interface; +#endif +#ifndef XDG_POPUP_INTERFACE +#define XDG_POPUP_INTERFACE +/** + * @page page_iface_xdg_popup xdg_popup + * @section page_iface_xdg_popup_desc Description + * + * A popup surface is a short-lived, temporary surface. It can be used to + * implement for example menus, popovers, tooltips and other similar user + * interface concepts. + * + * A popup can be made to take an explicit grab. See xdg_popup.grab for + * details. + * + * When the popup is dismissed, a popup_done event will be sent out, and at + * the same time the surface will be unmapped. See the xdg_popup.popup_done + * event for details. + * + * Explicitly destroying the xdg_popup object will also dismiss the popup and + * unmap the surface. Clients that want to dismiss the popup when another + * surface of their own is clicked should dismiss the popup using the destroy + * request. + * + * A newly created xdg_popup will be stacked on top of all previously created + * xdg_popup surfaces associated with the same xdg_toplevel. + * + * The parent of an xdg_popup must be mapped (see the xdg_surface + * description) before the xdg_popup itself. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_popup state to take effect. + * @section page_iface_xdg_popup_api API + * See @ref iface_xdg_popup. + */ +/** + * @defgroup iface_xdg_popup The xdg_popup interface + * + * A popup surface is a short-lived, temporary surface. It can be used to + * implement for example menus, popovers, tooltips and other similar user + * interface concepts. + * + * A popup can be made to take an explicit grab. See xdg_popup.grab for + * details. + * + * When the popup is dismissed, a popup_done event will be sent out, and at + * the same time the surface will be unmapped. See the xdg_popup.popup_done + * event for details. + * + * Explicitly destroying the xdg_popup object will also dismiss the popup and + * unmap the surface. Clients that want to dismiss the popup when another + * surface of their own is clicked should dismiss the popup using the destroy + * request. + * + * A newly created xdg_popup will be stacked on top of all previously created + * xdg_popup surfaces associated with the same xdg_toplevel. + * + * The parent of an xdg_popup must be mapped (see the xdg_surface + * description) before the xdg_popup itself. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_popup state to take effect. + */ +extern const struct wl_interface xdg_popup_interface; +#endif + +#ifndef XDG_WM_BASE_ERROR_ENUM +#define XDG_WM_BASE_ERROR_ENUM +enum xdg_wm_base_error { + /** + * given wl_surface has another role + */ + XDG_WM_BASE_ERROR_ROLE = 0, + /** + * xdg_wm_base was destroyed before children + */ + XDG_WM_BASE_ERROR_DEFUNCT_SURFACES = 1, + /** + * the client tried to map or destroy a non-topmost popup + */ + XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP = 2, + /** + * the client specified an invalid popup parent surface + */ + XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT = 3, + /** + * the client provided an invalid surface state + */ + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE = 4, + /** + * the client provided an invalid positioner + */ + XDG_WM_BASE_ERROR_INVALID_POSITIONER = 5, + /** + * the client didn’t respond to a ping event in time + */ + XDG_WM_BASE_ERROR_UNRESPONSIVE = 6, +}; +/** + * @ingroup iface_xdg_wm_base + * Validate a xdg_wm_base error value. + * + * @return true on success, false on error. + * @ref xdg_wm_base_error + */ +static inline bool +xdg_wm_base_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_WM_BASE_ERROR_ROLE: + return version >= 1; + case XDG_WM_BASE_ERROR_DEFUNCT_SURFACES: + return version >= 1; + case XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP: + return version >= 1; + case XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT: + return version >= 1; + case XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE: + return version >= 1; + case XDG_WM_BASE_ERROR_INVALID_POSITIONER: + return version >= 1; + case XDG_WM_BASE_ERROR_UNRESPONSIVE: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_WM_BASE_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_wm_base + * @struct xdg_wm_base_interface + */ +struct xdg_wm_base_interface { + /** + * destroy xdg_wm_base + * + * Destroy this xdg_wm_base object. + * + * Destroying a bound xdg_wm_base object while there are surfaces + * still alive created by this xdg_wm_base object instance is + * illegal and will result in a defunct_surfaces error. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * create a positioner object + * + * Create a positioner object. A positioner object is used to + * position surfaces relative to some parent surface. See the + * interface description and xdg_surface.get_popup for details. + */ + void (*create_positioner)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id); + /** + * create a shell surface from a surface + * + * This creates an xdg_surface for the given surface. While + * xdg_surface itself is not a role, the corresponding surface may + * only be assigned a role extending xdg_surface, such as + * xdg_toplevel or xdg_popup. It is illegal to create an + * xdg_surface for a wl_surface which already has an assigned role + * and this will result in a role error. + * + * This creates an xdg_surface for the given surface. An + * xdg_surface is used as basis to define a role to a given + * surface, such as xdg_toplevel or xdg_popup. It also manages + * functionality shared between xdg_surface based surface roles. + * + * See the documentation of xdg_surface for more details about what + * an xdg_surface is and how it is used. + */ + void (*get_xdg_surface)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface); + /** + * respond to a ping event + * + * A client must respond to a ping event with a pong request or + * the client may be deemed unresponsive. See xdg_wm_base.ping and + * xdg_wm_base.error.unresponsive. + * @param serial serial of the ping event + */ + void (*pong)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial); +}; + +#define XDG_WM_BASE_PING 0 + +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_PING_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_CREATE_POSITIONER_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_GET_XDG_SURFACE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_PONG_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_wm_base + * Sends an ping event to the client owning the resource. + * @param resource_ The client's resource + * @param serial pass this to the pong request + */ +static inline void +xdg_wm_base_send_ping(struct wl_resource *resource_, uint32_t serial) +{ + wl_resource_post_event(resource_, XDG_WM_BASE_PING, serial); +} + +#ifndef XDG_POSITIONER_ERROR_ENUM +#define XDG_POSITIONER_ERROR_ENUM +enum xdg_positioner_error { + /** + * invalid input provided + */ + XDG_POSITIONER_ERROR_INVALID_INPUT = 0, +}; +/** + * @ingroup iface_xdg_positioner + * Validate a xdg_positioner error value. + * + * @return true on success, false on error. + * @ref xdg_positioner_error + */ +static inline bool +xdg_positioner_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_POSITIONER_ERROR_INVALID_INPUT: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_POSITIONER_ERROR_ENUM */ + +#ifndef XDG_POSITIONER_ANCHOR_ENUM +#define XDG_POSITIONER_ANCHOR_ENUM +enum xdg_positioner_anchor { + XDG_POSITIONER_ANCHOR_NONE = 0, + XDG_POSITIONER_ANCHOR_TOP = 1, + XDG_POSITIONER_ANCHOR_BOTTOM = 2, + XDG_POSITIONER_ANCHOR_LEFT = 3, + XDG_POSITIONER_ANCHOR_RIGHT = 4, + XDG_POSITIONER_ANCHOR_TOP_LEFT = 5, + XDG_POSITIONER_ANCHOR_BOTTOM_LEFT = 6, + XDG_POSITIONER_ANCHOR_TOP_RIGHT = 7, + XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT = 8, +}; +/** + * @ingroup iface_xdg_positioner + * Validate a xdg_positioner anchor value. + * + * @return true on success, false on error. + * @ref xdg_positioner_anchor + */ +static inline bool +xdg_positioner_anchor_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_POSITIONER_ANCHOR_NONE: + return version >= 1; + case XDG_POSITIONER_ANCHOR_TOP: + return version >= 1; + case XDG_POSITIONER_ANCHOR_BOTTOM: + return version >= 1; + case XDG_POSITIONER_ANCHOR_LEFT: + return version >= 1; + case XDG_POSITIONER_ANCHOR_RIGHT: + return version >= 1; + case XDG_POSITIONER_ANCHOR_TOP_LEFT: + return version >= 1; + case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: + return version >= 1; + case XDG_POSITIONER_ANCHOR_TOP_RIGHT: + return version >= 1; + case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_POSITIONER_ANCHOR_ENUM */ + +#ifndef XDG_POSITIONER_GRAVITY_ENUM +#define XDG_POSITIONER_GRAVITY_ENUM +enum xdg_positioner_gravity { + XDG_POSITIONER_GRAVITY_NONE = 0, + XDG_POSITIONER_GRAVITY_TOP = 1, + XDG_POSITIONER_GRAVITY_BOTTOM = 2, + XDG_POSITIONER_GRAVITY_LEFT = 3, + XDG_POSITIONER_GRAVITY_RIGHT = 4, + XDG_POSITIONER_GRAVITY_TOP_LEFT = 5, + XDG_POSITIONER_GRAVITY_BOTTOM_LEFT = 6, + XDG_POSITIONER_GRAVITY_TOP_RIGHT = 7, + XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT = 8, +}; +/** + * @ingroup iface_xdg_positioner + * Validate a xdg_positioner gravity value. + * + * @return true on success, false on error. + * @ref xdg_positioner_gravity + */ +static inline bool +xdg_positioner_gravity_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_POSITIONER_GRAVITY_NONE: + return version >= 1; + case XDG_POSITIONER_GRAVITY_TOP: + return version >= 1; + case XDG_POSITIONER_GRAVITY_BOTTOM: + return version >= 1; + case XDG_POSITIONER_GRAVITY_LEFT: + return version >= 1; + case XDG_POSITIONER_GRAVITY_RIGHT: + return version >= 1; + case XDG_POSITIONER_GRAVITY_TOP_LEFT: + return version >= 1; + case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT: + return version >= 1; + case XDG_POSITIONER_GRAVITY_TOP_RIGHT: + return version >= 1; + case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_POSITIONER_GRAVITY_ENUM */ + +#ifndef XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM +#define XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM +/** + * @ingroup iface_xdg_positioner + * constraint adjustments + * + * The constraint adjustment value define ways the compositor will adjust + * the position of the surface, if the unadjusted position would result + * in the surface being partly constrained. + * + * Whether a surface is considered 'constrained' is left to the compositor + * to determine. For example, the surface may be partly outside the + * compositor's defined 'work area', thus necessitating the child surface's + * position be adjusted until it is entirely inside the work area. + * + * The adjustments can be combined, according to a defined precedence: 1) + * Flip, 2) Slide, 3) Resize. + */ +enum xdg_positioner_constraint_adjustment { + /** + * don't move the child surface when constrained + * + * Don't alter the surface position even if it is constrained on + * some axis, for example partially outside the edge of an output. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE = 0, + /** + * move along the x axis until unconstrained + * + * Slide the surface along the x axis until it is no longer + * constrained. + * + * First try to slide towards the direction of the gravity on the x + * axis until either the edge in the opposite direction of the + * gravity is unconstrained or the edge in the direction of the + * gravity is constrained. + * + * Then try to slide towards the opposite direction of the gravity + * on the x axis until either the edge in the direction of the + * gravity is unconstrained or the edge in the opposite direction + * of the gravity is constrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1, + /** + * move along the y axis until unconstrained + * + * Slide the surface along the y axis until it is no longer + * constrained. + * + * First try to slide towards the direction of the gravity on the y + * axis until either the edge in the opposite direction of the + * gravity is unconstrained or the edge in the direction of the + * gravity is constrained. + * + * Then try to slide towards the opposite direction of the gravity + * on the y axis until either the edge in the direction of the + * gravity is unconstrained or the edge in the opposite direction + * of the gravity is constrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2, + /** + * invert the anchor and gravity on the x axis + * + * Invert the anchor and gravity on the x axis if the surface is + * constrained on the x axis. For example, if the left edge of the + * surface is constrained, the gravity is 'left' and the anchor is + * 'left', change the gravity to 'right' and the anchor to 'right'. + * + * If the adjusted position also ends up being constrained, the + * resulting position of the flip_x adjustment will be the one + * before the adjustment. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X = 4, + /** + * invert the anchor and gravity on the y axis + * + * Invert the anchor and gravity on the y axis if the surface is + * constrained on the y axis. For example, if the bottom edge of + * the surface is constrained, the gravity is 'bottom' and the + * anchor is 'bottom', change the gravity to 'top' and the anchor + * to 'top'. + * + * The adjusted position is calculated given the original anchor + * rectangle and offset, but with the new flipped anchor and + * gravity values. + * + * If the adjusted position also ends up being constrained, the + * resulting position of the flip_y adjustment will be the one + * before the adjustment. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8, + /** + * horizontally resize the surface + * + * Resize the surface horizontally so that it is completely + * unconstrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16, + /** + * vertically resize the surface + * + * Resize the surface vertically so that it is completely + * unconstrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32, +}; +/** + * @ingroup iface_xdg_positioner + * Validate a xdg_positioner constraint_adjustment value. + * + * @return true on success, false on error. + * @ref xdg_positioner_constraint_adjustment + */ +static inline bool +xdg_positioner_constraint_adjustment_is_valid(uint32_t value, uint32_t version) { + uint32_t valid = 0; + if (version >= 1) + valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE; + if (version >= 1) + valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X; + if (version >= 1) + valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y; + if (version >= 1) + valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X; + if (version >= 1) + valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y; + if (version >= 1) + valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X; + if (version >= 1) + valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y; + return (value & ~valid) == 0; +} +#endif /* XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM */ + +/** + * @ingroup iface_xdg_positioner + * @struct xdg_positioner_interface + */ +struct xdg_positioner_interface { + /** + * destroy the xdg_positioner object + * + * Notify the compositor that the xdg_positioner will no longer + * be used. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * set the size of the to-be positioned rectangle + * + * Set the size of the surface that is to be positioned with the + * positioner object. The size is in surface-local coordinates and + * corresponds to the window geometry. See + * xdg_surface.set_window_geometry. + * + * If a zero or negative size is set the invalid_input error is + * raised. + * @param width width of positioned rectangle + * @param height height of positioned rectangle + */ + void (*set_size)(struct wl_client *client, + struct wl_resource *resource, + int32_t width, + int32_t height); + /** + * set the anchor rectangle within the parent surface + * + * Specify the anchor rectangle within the parent surface that + * the child surface will be placed relative to. The rectangle is + * relative to the window geometry as defined by + * xdg_surface.set_window_geometry of the parent surface. + * + * When the xdg_positioner object is used to position a child + * surface, the anchor rectangle may not extend outside the window + * geometry of the positioned child's parent surface. + * + * If a negative size is set the invalid_input error is raised. + * @param x x position of anchor rectangle + * @param y y position of anchor rectangle + * @param width width of anchor rectangle + * @param height height of anchor rectangle + */ + void (*set_anchor_rect)(struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y, + int32_t width, + int32_t height); + /** + * set anchor rectangle anchor + * + * Defines the anchor point for the anchor rectangle. The + * specified anchor is used derive an anchor point that the child + * surface will be positioned relative to. If a corner anchor is + * set (e.g. 'top_left' or 'bottom_right'), the anchor point will + * be at the specified corner; otherwise, the derived anchor point + * will be centered on the specified edge, or in the center of the + * anchor rectangle if no edge is specified. + * @param anchor anchor + */ + void (*set_anchor)(struct wl_client *client, + struct wl_resource *resource, + uint32_t anchor); + /** + * set child surface gravity + * + * Defines in what direction a surface should be positioned, + * relative to the anchor point of the parent surface. If a corner + * gravity is specified (e.g. 'bottom_right' or 'top_left'), then + * the child surface will be placed towards the specified gravity; + * otherwise, the child surface will be centered over the anchor + * point on any axis that had no gravity specified. If the gravity + * is not in the ‘gravity’ enum, an invalid_input error is + * raised. + * @param gravity gravity direction + */ + void (*set_gravity)(struct wl_client *client, + struct wl_resource *resource, + uint32_t gravity); + /** + * set the adjustment to be done when constrained + * + * Specify how the window should be positioned if the originally + * intended position caused the surface to be constrained, meaning + * at least partially outside positioning boundaries set by the + * compositor. The adjustment is set by constructing a bitmask + * describing the adjustment to be made when the surface is + * constrained on that axis. + * + * If no bit for one axis is set, the compositor will assume that + * the child surface should not change its position on that axis + * when constrained. + * + * If more than one bit for one axis is set, the order of how + * adjustments are applied is specified in the corresponding + * adjustment descriptions. + * + * The default adjustment is none. + * @param constraint_adjustment bit mask of constraint adjustments + */ + void (*set_constraint_adjustment)(struct wl_client *client, + struct wl_resource *resource, + uint32_t constraint_adjustment); + /** + * set surface position offset + * + * Specify the surface position offset relative to the position + * of the anchor on the anchor rectangle and the anchor on the + * surface. For example if the anchor of the anchor rectangle is at + * (x, y), the surface has the gravity bottom|right, and the offset + * is (ox, oy), the calculated surface position will be (x + ox, y + * + oy). The offset position of the surface is the one used for + * constraint testing. See set_constraint_adjustment. + * + * An example use case is placing a popup menu on top of a user + * interface element, while aligning the user interface element of + * the parent surface with some user interface element placed + * somewhere in the popup surface. + * @param x surface position x offset + * @param y surface position y offset + */ + void (*set_offset)(struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y); + /** + * continuously reconstrain the surface + * + * When set reactive, the surface is reconstrained if the + * conditions used for constraining changed, e.g. the parent window + * moved. + * + * If the conditions changed and the popup was reconstrained, an + * xdg_popup.configure event is sent with updated geometry, + * followed by an xdg_surface.configure event. + * @since 3 + */ + void (*set_reactive)(struct wl_client *client, + struct wl_resource *resource); + /** + * + * + * Set the parent window geometry the compositor should use when + * positioning the popup. The compositor may use this information + * to determine the future state the popup should be constrained + * using. If this doesn't match the dimension of the parent the + * popup is eventually positioned against, the behavior is + * undefined. + * + * The arguments are given in the surface-local coordinate space. + * @param parent_width future window geometry width of parent + * @param parent_height future window geometry height of parent + * @since 3 + */ + void (*set_parent_size)(struct wl_client *client, + struct wl_resource *resource, + int32_t parent_width, + int32_t parent_height); + /** + * set parent configure this is a response to + * + * Set the serial of an xdg_surface.configure event this + * positioner will be used in response to. The compositor may use + * this information together with set_parent_size to determine what + * future state the popup should be constrained using. + * @param serial serial of parent configure event + * @since 3 + */ + void (*set_parent_configure)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial); +}; + + +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_ANCHOR_RECT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_ANCHOR_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_GRAVITY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_OFFSET_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_REACTIVE_SINCE_VERSION 3 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_PARENT_SIZE_SINCE_VERSION 3 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_PARENT_CONFIGURE_SINCE_VERSION 3 + +#ifndef XDG_SURFACE_ERROR_ENUM +#define XDG_SURFACE_ERROR_ENUM +enum xdg_surface_error { + /** + * Surface was not fully constructed + */ + XDG_SURFACE_ERROR_NOT_CONSTRUCTED = 1, + /** + * Surface was already constructed + */ + XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED = 2, + /** + * Attaching a buffer to an unconfigured surface + */ + XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER = 3, + /** + * Invalid serial number when acking a configure event + */ + XDG_SURFACE_ERROR_INVALID_SERIAL = 4, + /** + * Width or height was zero or negative + */ + XDG_SURFACE_ERROR_INVALID_SIZE = 5, + /** + * Surface was destroyed before its role object + */ + XDG_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT = 6, +}; +/** + * @ingroup iface_xdg_surface + * Validate a xdg_surface error value. + * + * @return true on success, false on error. + * @ref xdg_surface_error + */ +static inline bool +xdg_surface_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_SURFACE_ERROR_NOT_CONSTRUCTED: + return version >= 1; + case XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED: + return version >= 1; + case XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER: + return version >= 1; + case XDG_SURFACE_ERROR_INVALID_SERIAL: + return version >= 1; + case XDG_SURFACE_ERROR_INVALID_SIZE: + return version >= 1; + case XDG_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_SURFACE_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_surface + * @struct xdg_surface_interface + */ +struct xdg_surface_interface { + /** + * destroy the xdg_surface + * + * Destroy the xdg_surface object. An xdg_surface must only be + * destroyed after its role object has been destroyed, otherwise a + * defunct_role_object error is raised. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * assign the xdg_toplevel surface role + * + * This creates an xdg_toplevel object for the given xdg_surface + * and gives the associated wl_surface the xdg_toplevel role. + * + * See the documentation of xdg_toplevel for more details about + * what an xdg_toplevel is and how it is used. + */ + void (*get_toplevel)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id); + /** + * assign the xdg_popup surface role + * + * This creates an xdg_popup object for the given xdg_surface and + * gives the associated wl_surface the xdg_popup role. + * + * If null is passed as a parent, a parent surface must be + * specified using some other protocol, before committing the + * initial state. + * + * See the documentation of xdg_popup for more details about what + * an xdg_popup is and how it is used. + */ + void (*get_popup)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *parent, + struct wl_resource *positioner); + /** + * set the new window geometry + * + * The window geometry of a surface is its "visible bounds" from + * the user's perspective. Client-side decorations often have + * invisible portions like drop-shadows which should be ignored for + * the purposes of aligning, placing and constraining windows. + * + * The window geometry is double-buffered state, see + * wl_surface.commit. + * + * When maintaining a position, the compositor should treat the (x, + * y) coordinate of the window geometry as the top left corner of + * the window. A client changing the (x, y) window geometry + * coordinate should in general not alter the position of the + * window. + * + * Once the window geometry of the surface is set, it is not + * possible to unset it, and it will remain the same until + * set_window_geometry is called again, even if a new subsurface or + * buffer is attached. + * + * If never set, the value is the full bounds of the surface, + * including any subsurfaces. This updates dynamically on every + * commit. This unset is meant for extremely simple clients. + * + * The arguments are given in the surface-local coordinate space of + * the wl_surface associated with this xdg_surface, and may extend + * outside of the wl_surface itself to mark parts of the subsurface + * tree as part of the window geometry. + * + * When applied, the effective window geometry will be the set + * window geometry clamped to the bounding rectangle of the + * combined geometry of the surface of the xdg_surface and the + * associated subsurfaces. + * + * The effective geometry will not be recalculated unless a new + * call to set_window_geometry is done and the new pending surface + * state is subsequently applied. + * + * The width and height of the effective window geometry must be + * greater than zero. Setting an invalid size will raise an + * invalid_size error. + */ + void (*set_window_geometry)(struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y, + int32_t width, + int32_t height); + /** + * ack a configure event + * + * When a configure event is received, if a client commits the + * surface in response to the configure event, then the client must + * make an ack_configure request sometime before the commit + * request, passing along the serial of the configure event. + * + * For instance, for toplevel surfaces the compositor might use + * this information to move a surface to the top left only when the + * client has drawn itself for the maximized or fullscreen state. + * + * If the client receives multiple configure events before it can + * respond to one, it only has to ack the last configure event. + * Acking a configure event that was never sent raises an + * invalid_serial error. + * + * A client is not required to commit immediately after sending an + * ack_configure request - it may even ack_configure several times + * before its next surface commit. + * + * A client may send multiple ack_configure requests before + * committing, but only the last request sent before a commit + * indicates which configure event the client really is responding + * to. + * + * Sending an ack_configure request consumes the serial number sent + * with the request, as well as serial numbers sent by all + * configure events sent on this xdg_surface prior to the configure + * event referenced by the committed serial. + * + * It is an error to issue multiple ack_configure requests + * referencing a serial from the same configure event, or to issue + * an ack_configure request referencing a serial from a configure + * event issued before the event identified by the last + * ack_configure request for the same xdg_surface. Doing so will + * raise an invalid_serial error. + * @param serial the serial from the configure event + */ + void (*ack_configure)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial); +}; + +#define XDG_SURFACE_CONFIGURE 0 + +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_CONFIGURE_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_GET_TOPLEVEL_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_GET_POPUP_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_SET_WINDOW_GEOMETRY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_ACK_CONFIGURE_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_surface + * Sends an configure event to the client owning the resource. + * @param resource_ The client's resource + * @param serial serial of the configure event + */ +static inline void +xdg_surface_send_configure(struct wl_resource *resource_, uint32_t serial) +{ + wl_resource_post_event(resource_, XDG_SURFACE_CONFIGURE, serial); +} + +#ifndef XDG_TOPLEVEL_ERROR_ENUM +#define XDG_TOPLEVEL_ERROR_ENUM +enum xdg_toplevel_error { + /** + * provided value is not a valid variant of the resize_edge enum + */ + XDG_TOPLEVEL_ERROR_INVALID_RESIZE_EDGE = 0, + /** + * invalid parent toplevel + */ + XDG_TOPLEVEL_ERROR_INVALID_PARENT = 1, + /** + * client provided an invalid min or max size + */ + XDG_TOPLEVEL_ERROR_INVALID_SIZE = 2, +}; +/** + * @ingroup iface_xdg_toplevel + * Validate a xdg_toplevel error value. + * + * @return true on success, false on error. + * @ref xdg_toplevel_error + */ +static inline bool +xdg_toplevel_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_TOPLEVEL_ERROR_INVALID_RESIZE_EDGE: + return version >= 1; + case XDG_TOPLEVEL_ERROR_INVALID_PARENT: + return version >= 1; + case XDG_TOPLEVEL_ERROR_INVALID_SIZE: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_TOPLEVEL_ERROR_ENUM */ + +#ifndef XDG_TOPLEVEL_RESIZE_EDGE_ENUM +#define XDG_TOPLEVEL_RESIZE_EDGE_ENUM +/** + * @ingroup iface_xdg_toplevel + * edge values for resizing + * + * These values are used to indicate which edge of a surface + * is being dragged in a resize operation. + */ +enum xdg_toplevel_resize_edge { + XDG_TOPLEVEL_RESIZE_EDGE_NONE = 0, + XDG_TOPLEVEL_RESIZE_EDGE_TOP = 1, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM = 2, + XDG_TOPLEVEL_RESIZE_EDGE_LEFT = 4, + XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT = 5, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT = 6, + XDG_TOPLEVEL_RESIZE_EDGE_RIGHT = 8, + XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT = 9, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT = 10, +}; +/** + * @ingroup iface_xdg_toplevel + * Validate a xdg_toplevel resize_edge value. + * + * @return true on success, false on error. + * @ref xdg_toplevel_resize_edge + */ +static inline bool +xdg_toplevel_resize_edge_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_TOPLEVEL_RESIZE_EDGE_NONE: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_TOP: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_LEFT: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_RIGHT: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_TOPLEVEL_RESIZE_EDGE_ENUM */ + +#ifndef XDG_TOPLEVEL_STATE_ENUM +#define XDG_TOPLEVEL_STATE_ENUM +/** + * @ingroup iface_xdg_toplevel + * types of state on the surface + * + * The different state values used on the surface. This is designed for + * state values like maximized, fullscreen. It is paired with the + * configure event to ensure that both the client and the compositor + * setting the state can be synchronized. + * + * States set in this way are double-buffered, see wl_surface.commit. + */ +enum xdg_toplevel_state { + /** + * the surface is maximized + * the surface is maximized + * + * The surface is maximized. The window geometry specified in the + * configure event must be obeyed by the client, or the + * xdg_wm_base.invalid_surface_state error is raised. + * + * The client should draw without shadow or other decoration + * outside of the window geometry. + */ + XDG_TOPLEVEL_STATE_MAXIMIZED = 1, + /** + * the surface is fullscreen + * the surface is fullscreen + * + * The surface is fullscreen. The window geometry specified in + * the configure event is a maximum; the client cannot resize + * beyond it. For a surface to cover the whole fullscreened area, + * the geometry dimensions must be obeyed by the client. For more + * details, see xdg_toplevel.set_fullscreen. + */ + XDG_TOPLEVEL_STATE_FULLSCREEN = 2, + /** + * the surface is being resized + * the surface is being resized + * + * The surface is being resized. The window geometry specified in + * the configure event is a maximum; the client cannot resize + * beyond it. Clients that have aspect ratio or cell sizing + * configuration can use a smaller size, however. + */ + XDG_TOPLEVEL_STATE_RESIZING = 3, + /** + * the surface is now activated + * the surface is now activated + * + * Client window decorations should be painted as if the window + * is active. Do not assume this means that the window actually has + * keyboard or pointer focus. + */ + XDG_TOPLEVEL_STATE_ACTIVATED = 4, + /** + * the surface’s left edge is tiled + * + * The window is currently in a tiled layout and the left edge is + * considered to be adjacent to another part of the tiling grid. + * + * The client should draw without shadow or other decoration + * outside of the window geometry on the left edge. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_LEFT = 5, + /** + * the surface’s right edge is tiled + * + * The window is currently in a tiled layout and the right edge + * is considered to be adjacent to another part of the tiling grid. + * + * The client should draw without shadow or other decoration + * outside of the window geometry on the right edge. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_RIGHT = 6, + /** + * the surface’s top edge is tiled + * + * The window is currently in a tiled layout and the top edge is + * considered to be adjacent to another part of the tiling grid. + * + * The client should draw without shadow or other decoration + * outside of the window geometry on the top edge. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_TOP = 7, + /** + * the surface’s bottom edge is tiled + * + * The window is currently in a tiled layout and the bottom edge + * is considered to be adjacent to another part of the tiling grid. + * + * The client should draw without shadow or other decoration + * outside of the window geometry on the bottom edge. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_BOTTOM = 8, + /** + * surface repaint is suspended + * + * The surface is currently not ordinarily being repainted; for + * example because its content is occluded by another window, or + * its outputs are switched off due to screen locking. + * @since 6 + */ + XDG_TOPLEVEL_STATE_SUSPENDED = 9, + /** + * the surface’s left edge is constrained + * + * The left edge of the window is currently constrained, meaning + * it shouldn't attempt to resize from that edge. It can for + * example mean it's tiled next to a monitor edge on the + * constrained side of the window. + * @since 7 + */ + XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT = 10, + /** + * the surface’s right edge is constrained + * + * The right edge of the window is currently constrained, meaning + * it shouldn't attempt to resize from that edge. It can for + * example mean it's tiled next to a monitor edge on the + * constrained side of the window. + * @since 7 + */ + XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT = 11, + /** + * the surface’s top edge is constrained + * + * The top edge of the window is currently constrained, meaning + * it shouldn't attempt to resize from that edge. It can for + * example mean it's tiled next to a monitor edge on the + * constrained side of the window. + * @since 7 + */ + XDG_TOPLEVEL_STATE_CONSTRAINED_TOP = 12, + /** + * the surface’s bottom edge is tiled + * + * The bottom edge of the window is currently constrained, + * meaning it shouldn't attempt to resize from that edge. It can + * for example mean it's tiled next to a monitor edge on the + * constrained side of the window. + * @since 7 + */ + XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM = 13, +}; +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_TOP_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_BOTTOM_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION 6 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT_SINCE_VERSION 7 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT_SINCE_VERSION 7 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_CONSTRAINED_TOP_SINCE_VERSION 7 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM_SINCE_VERSION 7 +/** + * @ingroup iface_xdg_toplevel + * Validate a xdg_toplevel state value. + * + * @return true on success, false on error. + * @ref xdg_toplevel_state + */ +static inline bool +xdg_toplevel_state_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_TOPLEVEL_STATE_MAXIMIZED: + return version >= 1; + case XDG_TOPLEVEL_STATE_FULLSCREEN: + return version >= 1; + case XDG_TOPLEVEL_STATE_RESIZING: + return version >= 1; + case XDG_TOPLEVEL_STATE_ACTIVATED: + return version >= 1; + case XDG_TOPLEVEL_STATE_TILED_LEFT: + return version >= 2; + case XDG_TOPLEVEL_STATE_TILED_RIGHT: + return version >= 2; + case XDG_TOPLEVEL_STATE_TILED_TOP: + return version >= 2; + case XDG_TOPLEVEL_STATE_TILED_BOTTOM: + return version >= 2; + case XDG_TOPLEVEL_STATE_SUSPENDED: + return version >= 6; + case XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT: + return version >= 7; + case XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT: + return version >= 7; + case XDG_TOPLEVEL_STATE_CONSTRAINED_TOP: + return version >= 7; + case XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM: + return version >= 7; + default: + return false; + } +} +#endif /* XDG_TOPLEVEL_STATE_ENUM */ + +#ifndef XDG_TOPLEVEL_WM_CAPABILITIES_ENUM +#define XDG_TOPLEVEL_WM_CAPABILITIES_ENUM +enum xdg_toplevel_wm_capabilities { + /** + * show_window_menu is available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU = 1, + /** + * set_maximized and unset_maximized are available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE = 2, + /** + * set_fullscreen and unset_fullscreen are available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN = 3, + /** + * set_minimized is available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE = 4, +}; +/** + * @ingroup iface_xdg_toplevel + * Validate a xdg_toplevel wm_capabilities value. + * + * @return true on success, false on error. + * @ref xdg_toplevel_wm_capabilities + */ +static inline bool +xdg_toplevel_wm_capabilities_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU: + return version >= 1; + case XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE: + return version >= 1; + case XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN: + return version >= 1; + case XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_TOPLEVEL_WM_CAPABILITIES_ENUM */ + +/** + * @ingroup iface_xdg_toplevel + * @struct xdg_toplevel_interface + */ +struct xdg_toplevel_interface { + /** + * destroy the xdg_toplevel + * + * This request destroys the role surface and unmaps the surface; + * see "Unmapping" behavior in interface section for details. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * set the parent of this surface + * + * Set the "parent" of this surface. This surface should be + * stacked above the parent surface and all other ancestor + * surfaces. + * + * Parent surfaces should be set on dialogs, toolboxes, or other + * "auxiliary" surfaces, so that the parent is raised when the + * dialog is raised. + * + * Setting a null parent for a child surface unsets its parent. + * Setting a null parent for a surface which currently has no + * parent is a no-op. + * + * Only mapped surfaces can have child surfaces. Setting a parent + * which is not mapped is equivalent to setting a null parent. If a + * surface becomes unmapped, its children's parent is set to the + * parent of the now-unmapped surface. If the now-unmapped surface + * has no parent, its children's parent is unset. If the + * now-unmapped surface becomes mapped again, its parent-child + * relationship is not restored. + * + * The parent toplevel must not be one of the child toplevel's + * descendants, and the parent must be different from the child + * toplevel, otherwise the invalid_parent protocol error is raised. + */ + void (*set_parent)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *parent); + /** + * set surface title + * + * Set a short title for the surface. + * + * This string may be used to identify the surface in a task bar, + * window list, or other user interface elements provided by the + * compositor. + * + * The string must be encoded in UTF-8. + */ + void (*set_title)(struct wl_client *client, + struct wl_resource *resource, + const char *title); + /** + * set application ID + * + * Set an application identifier for the surface. + * + * The app ID identifies the general class of applications to which + * the surface belongs. The compositor can use this to group + * multiple surfaces together, or to determine how to launch a new + * application. + * + * For D-Bus activatable applications, the app ID is used as the + * D-Bus service name. + * + * The compositor shell will try to group application surfaces + * together by their app ID. As a best practice, it is suggested to + * select app ID's that match the basename of the application's + * .desktop file. For example, "org.freedesktop.FooViewer" where + * the .desktop file is "org.freedesktop.FooViewer.desktop". + * + * Like other properties, a set_app_id request can be sent after + * the xdg_toplevel has been mapped to update the property. + * + * See the desktop-entry specification [0] for more details on + * application identifiers and how they relate to well-known D-Bus + * names and .desktop files. + * + * [0] https://standards.freedesktop.org/desktop-entry-spec/ + */ + void (*set_app_id)(struct wl_client *client, + struct wl_resource *resource, + const char *app_id); + /** + * show the window menu + * + * Clients implementing client-side decorations might want to + * show a context menu when right-clicking on the decorations, + * giving the user a menu that they can use to maximize or minimize + * the window. + * + * This request asks the compositor to pop up such a window menu at + * the given position, relative to the local surface coordinates of + * the parent surface. There are no guarantees as to what menu + * items the window menu contains, or even if a window menu will be + * drawn at all. + * + * This request must be used in response to some sort of user + * action like a button press, key press, or touch down event. + * @param seat the wl_seat of the user event + * @param serial the serial of the user event + * @param x the x position to pop up the window menu at + * @param y the y position to pop up the window menu at + */ + void (*show_window_menu)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat, + uint32_t serial, + int32_t x, + int32_t y); + /** + * start an interactive move + * + * Start an interactive, user-driven move of the surface. + * + * This request must be used in response to some sort of user + * action like a button press, key press, or touch down event. The + * passed serial is used to determine the type of interactive move + * (touch, pointer, etc). + * + * The server may ignore move requests depending on the state of + * the surface (e.g. fullscreen or maximized), or if the passed + * serial is no longer valid. + * + * If triggered, the surface will lose the focus of the device + * (wl_pointer, wl_touch, etc) used for the move. It is up to the + * compositor to visually indicate that the move is taking place, + * such as updating a pointer cursor, during the move. There is no + * guarantee that the device focus will return when the move is + * completed. + * @param seat the wl_seat of the user event + * @param serial the serial of the user event + */ + void (*move)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat, + uint32_t serial); + /** + * start an interactive resize + * + * Start a user-driven, interactive resize of the surface. + * + * This request must be used in response to some sort of user + * action like a button press, key press, or touch down event. The + * passed serial is used to determine the type of interactive + * resize (touch, pointer, etc). + * + * The server may ignore resize requests depending on the state of + * the surface (e.g. fullscreen or maximized). + * + * If triggered, the client will receive configure events with the + * "resize" state enum value and the expected sizes. See the + * "resize" enum value for more details about what is required. The + * client must also acknowledge configure events using + * "ack_configure". After the resize is completed, the client will + * receive another "configure" event without the resize state. + * + * If triggered, the surface also will lose the focus of the device + * (wl_pointer, wl_touch, etc) used for the resize. It is up to the + * compositor to visually indicate that the resize is taking place, + * such as updating a pointer cursor, during the resize. There is + * no guarantee that the device focus will return when the resize + * is completed. + * + * The edges parameter specifies how the surface should be resized, + * and is one of the values of the resize_edge enum. Values not + * matching a variant of the enum will cause the + * invalid_resize_edge protocol error. The compositor may use this + * information to update the surface position for example when + * dragging the top left corner. The compositor may also use this + * information to adapt its behavior, e.g. choose an appropriate + * cursor image. + * @param seat the wl_seat of the user event + * @param serial the serial of the user event + * @param edges which edge or corner is being dragged + */ + void (*resize)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat, + uint32_t serial, + uint32_t edges); + /** + * set the maximum size + * + * Set a maximum size for the window. + * + * The client can specify a maximum size so that the compositor + * does not try to configure the window beyond this size. + * + * The width and height arguments are in window geometry + * coordinates. See xdg_surface.set_window_geometry. + * + * Values set in this way are double-buffered, see + * wl_surface.commit. + * + * The compositor can use this information to allow or disallow + * different states like maximize or fullscreen and draw accurate + * animations. + * + * Similarly, a tiling window manager may use this information to + * place and resize client windows in a more effective way. + * + * The client should not rely on the compositor to obey the maximum + * size. The compositor may decide to ignore the values set by the + * client and request a larger size. + * + * If never set, or a value of zero in the request, means that the + * client has no expected maximum size in the given dimension. As a + * result, a client wishing to reset the maximum size to an + * unspecified state can use zero for width and height in the + * request. + * + * Requesting a maximum size to be smaller than the minimum size of + * a surface is illegal and will result in an invalid_size error. + * + * The width and height must be greater than or equal to zero. + * Using strictly negative values for width or height will result + * in a invalid_size error. + */ + void (*set_max_size)(struct wl_client *client, + struct wl_resource *resource, + int32_t width, + int32_t height); + /** + * set the minimum size + * + * Set a minimum size for the window. + * + * The client can specify a minimum size so that the compositor + * does not try to configure the window below this size. + * + * The width and height arguments are in window geometry + * coordinates. See xdg_surface.set_window_geometry. + * + * Values set in this way are double-buffered, see + * wl_surface.commit. + * + * The compositor can use this information to allow or disallow + * different states like maximize or fullscreen and draw accurate + * animations. + * + * Similarly, a tiling window manager may use this information to + * place and resize client windows in a more effective way. + * + * The client should not rely on the compositor to obey the minimum + * size. The compositor may decide to ignore the values set by the + * client and request a smaller size. + * + * If never set, or a value of zero in the request, means that the + * client has no expected minimum size in the given dimension. As a + * result, a client wishing to reset the minimum size to an + * unspecified state can use zero for width and height in the + * request. + * + * Requesting a minimum size to be larger than the maximum size of + * a surface is illegal and will result in an invalid_size error. + * + * The width and height must be greater than or equal to zero. + * Using strictly negative values for width and height will result + * in a invalid_size error. + */ + void (*set_min_size)(struct wl_client *client, + struct wl_resource *resource, + int32_t width, + int32_t height); + /** + * maximize the window + * + * Maximize the surface. + * + * After requesting that the surface should be maximized, the + * compositor will respond by emitting a configure event. Whether + * this configure actually sets the window maximized is subject to + * compositor policies. The client must then update its content, + * drawing in the configured state. The client must also + * acknowledge the configure when committing the new content (see + * ack_configure). + * + * It is up to the compositor to decide how and where to maximize + * the surface, for example which output and what region of the + * screen should be used. + * + * If the surface was already maximized, the compositor will still + * emit a configure event with the "maximized" state. + * + * If the surface is in a fullscreen state, this request has no + * direct effect. It may alter the state the surface is returned to + * when unmaximized unless overridden by the compositor. + */ + void (*set_maximized)(struct wl_client *client, + struct wl_resource *resource); + /** + * unmaximize the window + * + * Unmaximize the surface. + * + * After requesting that the surface should be unmaximized, the + * compositor will respond by emitting a configure event. Whether + * this actually un-maximizes the window is subject to compositor + * policies. If available and applicable, the compositor will + * include the window geometry dimensions the window had prior to + * being maximized in the configure event. The client must then + * update its content, drawing it in the configured state. The + * client must also acknowledge the configure when committing the + * new content (see ack_configure). + * + * It is up to the compositor to position the surface after it was + * unmaximized; usually the position the surface had before + * maximizing, if applicable. + * + * If the surface was already not maximized, the compositor will + * still emit a configure event without the "maximized" state. + * + * If the surface is in a fullscreen state, this request has no + * direct effect. It may alter the state the surface is returned to + * when unmaximized unless overridden by the compositor. + */ + void (*unset_maximized)(struct wl_client *client, + struct wl_resource *resource); + /** + * set the window as fullscreen on an output + * + * Make the surface fullscreen. + * + * After requesting that the surface should be fullscreened, the + * compositor will respond by emitting a configure event. Whether + * the client is actually put into a fullscreen state is subject to + * compositor policies. The client must also acknowledge the + * configure when committing the new content (see ack_configure). + * + * The output passed by the request indicates the client's + * preference as to which display it should be set fullscreen on. + * If this value is NULL, it's up to the compositor to choose which + * display will be used to map this surface. + * + * If the surface doesn't cover the whole output, the compositor + * will position the surface in the center of the output and + * compensate with with border fill covering the rest of the + * output. The content of the border fill is undefined, but should + * be assumed to be in some way that attempts to blend into the + * surrounding area (e.g. solid black). + * + * If the fullscreened surface is not opaque, the compositor must + * make sure that other screen content not part of the same surface + * tree (made up of subsurfaces, popups or similarly coupled + * surfaces) are not visible below the fullscreened surface. + */ + void (*set_fullscreen)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *output); + /** + * unset the window as fullscreen + * + * Make the surface no longer fullscreen. + * + * After requesting that the surface should be unfullscreened, the + * compositor will respond by emitting a configure event. Whether + * this actually removes the fullscreen state of the client is + * subject to compositor policies. + * + * Making a surface unfullscreen sets states for the surface based + * on the following: * the state(s) it may have had before becoming + * fullscreen * any state(s) decided by the compositor * any + * state(s) requested by the client while the surface was + * fullscreen + * + * The compositor may include the previous window geometry + * dimensions in the configure event, if applicable. + * + * The client must also acknowledge the configure when committing + * the new content (see ack_configure). + */ + void (*unset_fullscreen)(struct wl_client *client, + struct wl_resource *resource); + /** + * set the window as minimized + * + * Request that the compositor minimize your surface. There is no + * way to know if the surface is currently minimized, nor is there + * any way to unset minimization on this surface. + * + * If you are looking to throttle redrawing when minimized, please + * instead use the wl_surface.frame event for this, as this will + * also work with live previews on windows in Alt-Tab, Expose or + * similar compositor features. + */ + void (*set_minimized)(struct wl_client *client, + struct wl_resource *resource); +}; + +#define XDG_TOPLEVEL_CONFIGURE 0 +#define XDG_TOPLEVEL_CLOSE 1 +#define XDG_TOPLEVEL_CONFIGURE_BOUNDS 2 +#define XDG_TOPLEVEL_WM_CAPABILITIES 3 + +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CLOSE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION 4 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION 5 + +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_PARENT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_TITLE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_APP_ID_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SHOW_WINDOW_MENU_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_MOVE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_RESIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MAX_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MIN_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_UNSET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_UNSET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MINIMIZED_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_toplevel + * Sends an configure event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +xdg_toplevel_send_configure(struct wl_resource *resource_, int32_t width, int32_t height, struct wl_array *states) +{ + wl_resource_post_event(resource_, XDG_TOPLEVEL_CONFIGURE, width, height, states); +} + +/** + * @ingroup iface_xdg_toplevel + * Sends an close event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +xdg_toplevel_send_close(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, XDG_TOPLEVEL_CLOSE); +} + +/** + * @ingroup iface_xdg_toplevel + * Sends an configure_bounds event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +xdg_toplevel_send_configure_bounds(struct wl_resource *resource_, int32_t width, int32_t height) +{ + wl_resource_post_event(resource_, XDG_TOPLEVEL_CONFIGURE_BOUNDS, width, height); +} + +/** + * @ingroup iface_xdg_toplevel + * Sends an wm_capabilities event to the client owning the resource. + * @param resource_ The client's resource + * @param capabilities array of 32-bit capabilities + */ +static inline void +xdg_toplevel_send_wm_capabilities(struct wl_resource *resource_, struct wl_array *capabilities) +{ + wl_resource_post_event(resource_, XDG_TOPLEVEL_WM_CAPABILITIES, capabilities); +} + +#ifndef XDG_POPUP_ERROR_ENUM +#define XDG_POPUP_ERROR_ENUM +enum xdg_popup_error { + /** + * tried to grab after being mapped + */ + XDG_POPUP_ERROR_INVALID_GRAB = 0, +}; +/** + * @ingroup iface_xdg_popup + * Validate a xdg_popup error value. + * + * @return true on success, false on error. + * @ref xdg_popup_error + */ +static inline bool +xdg_popup_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_POPUP_ERROR_INVALID_GRAB: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_POPUP_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_popup + * @struct xdg_popup_interface + */ +struct xdg_popup_interface { + /** + * remove xdg_popup interface + * + * This destroys the popup. Explicitly destroying the xdg_popup + * object will also dismiss the popup, and unmap the surface. + * + * If this xdg_popup is not the "topmost" popup, the + * xdg_wm_base.not_the_topmost_popup protocol error will be sent. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * make the popup take an explicit grab + * + * This request makes the created popup take an explicit grab. An + * explicit grab will be dismissed when the user dismisses the + * popup, or when the client destroys the xdg_popup. This can be + * done by the user clicking outside the surface, using the + * keyboard, or even locking the screen through closing the lid or + * a timeout. + * + * If the compositor denies the grab, the popup will be immediately + * dismissed. + * + * This request must be used in response to some sort of user + * action like a button press, key press, or touch down event. The + * serial number of the event should be passed as 'serial'. + * + * The parent of a grabbing popup must either be an xdg_toplevel + * surface or another xdg_popup with an explicit grab. If the + * parent is another xdg_popup it means that the popups are nested, + * with this popup now being the topmost popup. + * + * Nested popups must be destroyed in the reverse order they were + * created in, e.g. the only popup you are allowed to destroy at + * all times is the topmost one. + * + * When compositors choose to dismiss a popup, they may dismiss + * every nested grabbing popup as well. When a compositor dismisses + * popups, it will follow the same dismissing order as required + * from the client. + * + * If the topmost grabbing popup is destroyed, the grab will be + * returned to the parent of the popup, if that parent previously + * had an explicit grab. + * + * If the parent is a grabbing popup which has already been + * dismissed, this popup will be immediately dismissed. If the + * parent is a popup that did not take an explicit grab, an error + * will be raised. + * + * During a popup grab, the client owning the grab will receive + * pointer and touch events for all their surfaces as normal + * (similar to an "owner-events" grab in X11 parlance), while the + * top most grabbing popup will always have keyboard focus. + * @param seat the wl_seat of the user event + * @param serial the serial of the user event + */ + void (*grab)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat, + uint32_t serial); + /** + * recalculate the popup's location + * + * Reposition an already-mapped popup. The popup will be placed + * given the details in the passed xdg_positioner object, and a + * xdg_popup.repositioned followed by xdg_popup.configure and + * xdg_surface.configure will be emitted in response. Any + * parameters set by the previous positioner will be discarded. + * + * The passed token will be sent in the corresponding + * xdg_popup.repositioned event. The new popup position will not + * take effect until the corresponding configure event is + * acknowledged by the client. See xdg_popup.repositioned for + * details. The token itself is opaque, and has no other special + * meaning. + * + * If multiple reposition requests are sent, the compositor may + * skip all but the last one. + * + * If the popup is repositioned in response to a configure event + * for its parent, the client should send an + * xdg_positioner.set_parent_configure and possibly an + * xdg_positioner.set_parent_size request to allow the compositor + * to properly constrain the popup. + * + * If the popup is repositioned together with a parent that is + * being resized, but not in response to a configure event, the + * client should send an xdg_positioner.set_parent_size request. + * @param token reposition request token + * @since 3 + */ + void (*reposition)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *positioner, + uint32_t token); +}; + +#define XDG_POPUP_CONFIGURE 0 +#define XDG_POPUP_POPUP_DONE 1 +#define XDG_POPUP_REPOSITIONED 2 + +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_POPUP_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_REPOSITIONED_SINCE_VERSION 3 + +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_GRAB_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_REPOSITION_SINCE_VERSION 3 + +/** + * @ingroup iface_xdg_popup + * Sends an configure event to the client owning the resource. + * @param resource_ The client's resource + * @param x x position relative to parent surface window geometry + * @param y y position relative to parent surface window geometry + * @param width window geometry width + * @param height window geometry height + */ +static inline void +xdg_popup_send_configure(struct wl_resource *resource_, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_resource_post_event(resource_, XDG_POPUP_CONFIGURE, x, y, width, height); +} + +/** + * @ingroup iface_xdg_popup + * Sends an popup_done event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +xdg_popup_send_popup_done(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, XDG_POPUP_POPUP_DONE); +} + +/** + * @ingroup iface_xdg_popup + * Sends an repositioned event to the client owning the resource. + * @param resource_ The client's resource + * @param token reposition request token + */ +static inline void +xdg_popup_send_repositioned(struct wl_resource *resource_, uint32_t token) +{ + wl_resource_post_event(resource_, XDG_POPUP_REPOSITIONED, token); +} + +#ifdef __cplusplus +} +#endif + +#endif From 6c3e2a5d084ed57218d9734fdf74ec5ab6d4f06e Mon Sep 17 00:00:00 2001 From: elParaguayo Date: Mon, 28 Jul 2025 18:39:41 +0100 Subject: [PATCH 02/14] More layer manager code --- libqtile/backend/base/zmanager.py | 185 +++++++++++++++++++++++------- 1 file changed, 146 insertions(+), 39 deletions(-) diff --git a/libqtile/backend/base/zmanager.py b/libqtile/backend/base/zmanager.py index 37af7df4af..bccccc1894 100644 --- a/libqtile/backend/base/zmanager.py +++ b/libqtile/backend/base/zmanager.py @@ -18,71 +18,178 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. from collections import defaultdict -from enum import Enum +from enum import IntEnum +from functools import wraps + +from libqtile.backend.base.window import _Window LAYERS = ["background", "bottom", "normal", "above", "top", "overlay", "system"] -class _ZLayer: - _index = 0 - def __init__(self, name): - self.name = name - self.index = _ZLayer._index - _ZLayer._index += 1 - self.clients = [] +# LayerGroup = Enum("LayerGroup", {layer.name.upper(): layer.index for layer in _layers}) +class LayerGroup(IntEnum): + BACKGROUND = 0 + BOTTOM = 1 + NORMAL = 2 + ABOVE = 3 + TOP = 4 + OVERLAY = 5 + SYSTEM = 6 + + +def check_window(func): + """ + Decorator that requires window to be visible and stacked before proceeding. + + The decorated method must take the window's id as the first argument. + """ + @wraps(func) + def _wrapper(self, window, *args, **kwargs): + if not self.is_stacked(window) or not window.is_visible(): + return + return func(self, window, *args, **kwargs) -_layers = [_ZLayer(layer) for layer in LAYERS] -ZLayer = Enum("ZLayer", {layer.name.upper(): layer.index for layer in _layers}) + return _wrapper class ZManager: - def __init__(self): - self.layers = _layers + def __init__(self) -> None: + self.layers: dict[LayerGroup, list[_Window]] = {l: [] for l in LayerGroup} + self.layer_map: dict[_Window, tuple(LayerGroup, int)] = {} + + def is_stacked(self, window: _Window) -> bool: + return window in self.layer_map + + def get_layer(self, window) -> LayerGroup | None: + layer, _ = self.layer_map.get(window, (None, 0)) + return layer + + @check_window + def get_window_above(self, window) -> _Window | None: + layer, idx = self.layer_map[window] + if idx < (len(self.layers[layer]) - 1): + return self.layers[layer][idx + 1] + + @check_window + def get_window_below(self, window) -> _Window | None: + layer, idx = self.layer_map[window] + if idx > 0: + return self.layers[layer][idx - 1] - def add_window(self, window_id, layer="normal"): + def add_window(self, window: _Window, layer: LayerGroup = LayerGroup.NORMAL, position="top") -> None: if layer not in self.layers: raise ValueError(f"Invalid layer: {layer}") - self.layers[layer].append(window_id) - self.window_lookup[window_id] = (layer, len(self.layers[layer]) - 1) - def remove_window(self, window_id): - layer, _ = self.window_lookup.pop(window_id) - self.layers[layer].remove(window_id) + current_layer = self.get_layer(window) + if current_layer is not None and current_layer != layer: + logger.info("Window already stacked. Moving to new layer group.") + self.layers[current_layer].remove(window) + + if position == "bottom": + self.layers[layer].insert(0, window) + else: + self.layers[layer].append(window) + + self._reindex_layer(layer) + + @check_window + def remove_window(self, window) -> None: + layer, _ = self.layer_map.pop(window) + self.layers[layer].remove(window) self._reindex_layer(layer) - def raise_window(self, window_id): - layer, _ = self.window_lookup[window_id] - self.layers[layer].remove(window_id) - self.layers[layer].append(window_id) + @check_window + def move_up(self, window) -> _Window | None: + layer, cur_idx = self.layer_map[window] + visible = [w for w in self.layers[layer] if w.is_visible() and w.group in (window.group, None)] + idx = visible.index(window) + if idx < (len(visible) - 1): + dest_idx = self.layers[layer].index(visible[idx + 1]) + win = self.layers[layer].pop(cur_idx) + self.layers[layer].insert(dest_idx, win) + self._reindex_layer(layer) - def lower_window(self, window_id): - layer, _ = self.window_lookup[window_id] - self.layers[layer].remove(window_id) - self.layers[layer].insert(0, window_id) + return self.get_window_below(window) + + @check_window + def move_down(self, window) -> _Window | None: + layer, cur_idx = self.layer_map[window] + visible = [w for w in self.layers[layer] if w.is_visible() and w.group in (window.group, None)] + idx = visible.index(window) + if idx > 0: + dest_idx = self.layers[layer].index(visible[idx - 1]) + win = self.layers[layer].pop(cur_idx) + self.layers[layer].insert(dest_idx, win) + self._reindex_layer(layer) - def move_window_to_layer(self, window_id, new_layer, position='top'): - old_layer, _ = self.window_lookup[window_id] - self.layers[old_layer].remove(window_id) + return self.get_window_above(window) - if position == 'top': - self.layers[new_layer].append(window_id) - elif position == 'bottom': - self.layers[new_layer].insert(0, window_id) + @check_window + def move_to_top(self, window) -> _Window | None: + layer, _ = self.layer_map[window] + self.layers[layer].remove(window) + self.layers[layer].append(window) + self._reindex_layer(layer) + + return self.get_window_below(window) + + @check_window + def move_to_bottom(self, window) -> _Window | None: + layer, _ = self.layer_map[window] + self.layers[layer].remove(window) + self.layers[layer].insert(0, window) + self._reindex_layer(layer) + + return self.get_window_above(window) + + @check_window + def move_window_to_layer(self, window, new_layer, position='top'): + old_layer, _ = self.layer_map[window] + self.layers[old_layer].remove(window) + + if position == 'bottom': + self.layers[new_layer].insert(0, window) else: - self.layers[new_layer].insert(position, window_id) + self.layers[new_layer].append(window) - self.window_lookup[window_id] = (new_layer, self.layers[new_layer].index(window_id)) + self.layer_map[window] = (new_layer, self.layers[new_layer].index(window)) self._reindex_layer(old_layer) self._reindex_layer(new_layer) + return self.get_window_below(window) + def get_z_order(self): z_order = [] - for layer in self.layer_order: - z_order.extend(self.layers[layer]) + for clients in self.layers.values(): + z_order.extend(clients) return z_order def _reindex_layer(self, layer): - for idx, win_id in enumerate(self.layers[layer]): - self.window_lookup[win_id] = (layer, idx) + for idx, win in enumerate(self.layers[layer]): + self.layer_map[win] = (layer, idx) + + +# Testing +class Window: + def __init__(self, name, vis, gr): + self.name = name + self.vis = vis + self.group = gr + + def is_visible(self): + return self.vis + + def __repr__(self): + return f"Window: <{self.name}>" + +A = Window("A", True, 1) +B = Window("B", True, 2) +C = Window("C", False, 1) +D = Window("D", True, 1) + +z = ZManager() + +for w in (A, B, C, D): + z.add_window(w) From 554be55eafbb88c80f957576204a83bc5c465053 Mon Sep 17 00:00:00 2001 From: elParaguayo Date: Tue, 29 Jul 2025 14:13:51 +0100 Subject: [PATCH 03/14] Adding to x11 --- libqtile/backend/base/zmanager.py | 73 ++++--- libqtile/backend/x11/core.py | 10 +- libqtile/backend/x11/window.py | 303 ++++++------------------------ libqtile/backend/x11/zmanager.py | 24 +++ libqtile/core/manager.py | 4 + 5 files changed, 139 insertions(+), 275 deletions(-) create mode 100644 libqtile/backend/x11/zmanager.py diff --git a/libqtile/backend/base/zmanager.py b/libqtile/backend/base/zmanager.py index bccccc1894..a33b12d263 100644 --- a/libqtile/backend/base/zmanager.py +++ b/libqtile/backend/base/zmanager.py @@ -18,23 +18,34 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. from collections import defaultdict +from dataclasses import dataclass from enum import IntEnum from functools import wraps from libqtile.backend.base.window import _Window -LAYERS = ["background", "bottom", "normal", "above", "top", "overlay", "system"] - -# LayerGroup = Enum("LayerGroup", {layer.name.upper(): layer.index for layer in _layers}) class LayerGroup(IntEnum): BACKGROUND = 0 BOTTOM = 1 - NORMAL = 2 - ABOVE = 3 - TOP = 4 - OVERLAY = 5 - SYSTEM = 6 + KEEP_BELOW = 2 + LAYOUT = 3 + KEEP_ABOVE = 4 + MAX = 5 + FULLSCREEN = 6 + BRING_TO_FRONT = 7 + TOP = 8 + OVERLAY = 9 + SYSTEM = 10 + + +@dataclass +class StackInfo: + sibling: _Window + above: bool + + def __post_init__(self): + self.wid = self.sibling.wid def check_window(func): @@ -65,18 +76,22 @@ def get_layer(self, window) -> LayerGroup | None: return layer @check_window - def get_window_above(self, window) -> _Window | None: - layer, idx = self.layer_map[window] - if idx < (len(self.layers[layer]) - 1): - return self.layers[layer][idx + 1] + def get_window_above(self, window) -> StackInfo | None: + stack = self.get_z_order() + idx = stack.index(window) + if idx < (len(stack) - 1): + sibling = stack[idx + 1] + return StackInfo(sibling=sibling, above=True) @check_window - def get_window_below(self, window) -> _Window | None: - layer, idx = self.layer_map[window] + def get_window_below(self, window) -> StackInfo | None: + stack = self.get_z_order() + idx = stack.index(window) if idx > 0: - return self.layers[layer][idx - 1] + sibling = stack[idx - 1] + return StackInfo(sibling=sibling, above=False) - def add_window(self, window: _Window, layer: LayerGroup = LayerGroup.NORMAL, position="top") -> None: + def add_window(self, window: _Window, layer: LayerGroup = LayerGroup.LAYOUT, position="top") -> None: if layer not in self.layers: raise ValueError(f"Invalid layer: {layer}") @@ -99,7 +114,7 @@ def remove_window(self, window) -> None: self._reindex_layer(layer) @check_window - def move_up(self, window) -> _Window | None: + def move_up(self, window) -> StackInfo | None: layer, cur_idx = self.layer_map[window] visible = [w for w in self.layers[layer] if w.is_visible() and w.group in (window.group, None)] idx = visible.index(window) @@ -113,7 +128,7 @@ def move_up(self, window) -> _Window | None: return self.get_window_below(window) @check_window - def move_down(self, window) -> _Window | None: + def move_down(self, window) -> StackInfo | None: layer, cur_idx = self.layer_map[window] visible = [w for w in self.layers[layer] if w.is_visible() and w.group in (window.group, None)] idx = visible.index(window) @@ -127,7 +142,7 @@ def move_down(self, window) -> _Window | None: return self.get_window_above(window) @check_window - def move_to_top(self, window) -> _Window | None: + def move_to_top(self, window) -> StackInfo | None: layer, _ = self.layer_map[window] self.layers[layer].remove(window) self.layers[layer].append(window) @@ -136,7 +151,7 @@ def move_to_top(self, window) -> _Window | None: return self.get_window_below(window) @check_window - def move_to_bottom(self, window) -> _Window | None: + def move_to_bottom(self, window) -> StackInfo | None: layer, _ = self.layer_map[window] self.layers[layer].remove(window) self.layers[layer].insert(0, window) @@ -145,11 +160,19 @@ def move_to_bottom(self, window) -> _Window | None: return self.get_window_above(window) @check_window - def move_window_to_layer(self, window, new_layer, position='top'): + def keep_above(self, window) -> StackInfo | None: + return self.move_window_to_layer(window, LayerGroup.KEEP_ABOVE) + + @check_window + def keep_below(self, window) -> StackInfo | None: + return self.move_window_to_layer(window, LayerGroup.KEEP_BELOW) + + @check_window + def move_window_to_layer(self, window, new_layer, position="top") -> StackInfo | None: old_layer, _ = self.layer_map[window] self.layers[old_layer].remove(window) - if position == 'bottom': + if position == "bottom": self.layers[new_layer].insert(0, window) else: self.layers[new_layer].append(window) @@ -158,15 +181,15 @@ def move_window_to_layer(self, window, new_layer, position='top'): self._reindex_layer(old_layer) self._reindex_layer(new_layer) - return self.get_window_below(window) + return self.get_window_below(window) or self.get_window_above(window) - def get_z_order(self): + def get_z_order(self) -> list[_Window]: z_order = [] for clients in self.layers.values(): z_order.extend(clients) return z_order - def _reindex_layer(self, layer): + def _reindex_layer(self, layer) -> None: for idx, win in enumerate(self.layers[layer]): self.layer_map[win] = (layer, idx) diff --git a/libqtile/backend/x11/core.py b/libqtile/backend/x11/core.py index e2715f078f..6d2eb8c942 100644 --- a/libqtile/backend/x11/core.py +++ b/libqtile/backend/x11/core.py @@ -38,6 +38,7 @@ from libqtile.backend import base from libqtile.backend.x11 import window, xcbq from libqtile.backend.x11.xkeysyms import keysyms +from libqtile.backend.x11.zmanager import ZManager from libqtile.config import ScreenRect from libqtile.log_utils import logger from libqtile.utils import QtileError @@ -170,6 +171,8 @@ def __init__(self, display_name: str | None = None) -> None: self.last_focused: base.Window | None = None + self.zmanager = ZManager() + @property def name(self): return "x11" @@ -281,7 +284,7 @@ def on_config_load(self, initial) -> None: self.qtile.manage(win) self.update_client_lists() - win.change_layer() + # win.change_layer() def warp_pointer(self, x, y): self._root.warp_pointer(x, y) @@ -771,7 +774,7 @@ def handle_MapRequest(self, event) -> None: # noqa: N802 return win.unhide() self.update_client_lists() - win.change_layer() + # win.change_layer() def handle_DestroyNotify(self, event) -> None: # noqa: N802 assert self.qtile is not None @@ -951,7 +954,8 @@ def check_stacking(self, win: base.Window) -> None: return if self.last_focused and self.last_focused.fullscreen: - self.last_focused.change_layer() + # self.last_focused.change_layer() + pass self.last_focused = win diff --git a/libqtile/backend/x11/window.py b/libqtile/backend/x11/window.py index 0082e40d05..f52d0a9e35 100644 --- a/libqtile/backend/x11/window.py +++ b/libqtile/backend/x11/window.py @@ -16,6 +16,7 @@ from libqtile import bar, hook, utils from libqtile.backend import base from libqtile.backend.base import FloatStates +from libqtile.backend.base.zmanager import LayerGroup from libqtile.backend.x11 import xcbq from libqtile.backend.x11.drawer import Drawer from libqtile.command.base import CommandError, expose_command @@ -903,14 +904,24 @@ def place( self.window.configure(x=x, y=y, width=width, height=height) if above: - self.change_layer(up=True) + self.change_layer() self.paint_borders(bordercolor, borderwidth) if send_notify: self.send_configure_notify(x, y, width, height) - def get_layering_information(self) -> tuple[bool, bool, bool, bool, bool, bool]: + def stack(self, stack_info): + if stack_info is None: + return + + xp = xcffib.xproto + self.window.configure( + stackmode=xp.StackMode.Below if stack_info.above else xp.StackMode.Above, + sibling=stack_info.wid + ) + + def get_layering_information(self) -> LayerGroup: """ Get layer-related EMWH-flags https://specifications.freedesktop.org/wm-spec/1.3/ar01s07.html#STACKINGORDER @@ -929,10 +940,19 @@ def get_layering_information(self) -> tuple[bool, bool, bool, bool, bool, bool]: Windows that are transient for another window should be kept above this window. - The window manager may choose to put some windows in different stacking positions, - for example to allow the user to bring currently a active window to the top and return - it back when the window loses focus. To this end, qtile adds an additional layer so that - scratchpad windows are placed above all others, always. + However, to provide greater flexibility for managing windows, and consistency + across the X11 and Wayland backends, qtile provides the following stacking groups: + - BACKGROUND + - BOTTOM + - KEEP_BELOW + - LAYOUT + - KEEP_ABOVE + - MAX + - FULLSCREEN + - BRINGTOFRONT + - TOP + - OVERLAY + - SYSTEM """ state = self.window.get_net_wm_state() _type = self.window.get_wm_type() or "" @@ -945,246 +965,30 @@ def get_layering_information(self) -> tuple[bool, bool, bool, bool, bool, bool]: focus = True else: focus = False - - desktop = _type == "desktop" - below = "_NET_WM_STATE_BELOW" in state - dock = _type == "dock" - above = "_NET_WM_STATE_ABOVE" in state full = ( "fullscreen" in state ) # get_net_wm_state translates this state so we don't use _NET_WM name - is_scratchpad = isinstance(self.qtile.groups_map.get(self.group), ScratchPad) - - # sort the flags from bottom to top, True meaning further below than False at each step - states = [desktop, below, above or (dock and not below), full and focus, is_scratchpad] - other = not any(states) - states.insert(2, other) - - # If we're a desktop, this should always be the lowest layer... - if desktop: - # mypy can't work out that this gives us tuple[bool, bool, bool, bool, bool, bool]... - # (True, False, False, False, False, False) - return tuple(not i for i in range(6)) # type: ignore - - # ...otherwise, we set to the highest matching layer. - # Look for the highest matching level and then set all other levels to False - highest = max(i for i, state in enumerate(states) if state) - - # mypy can't work out that this gives us tuple[bool, bool, bool, bool, bool, bool]... - return tuple(i == highest for i in range(6)) # type: ignore - - def change_layer(self, up=True, top_bottom=False): - """Raise a window above its peers or move it below them, depending on 'up'. - Raising a normal window will not lift it above pinned windows etc. - - There are a few important things to take note of when relaying windows: - 1. If a window has a defined parent, it should not be moved underneath it. - In case children are blocking, this could leave an application in an unusable state. - 2. If a window has children, they should be moved along with it. - 3. If a window has a defined parent, either move the parent or do nothing at all. - 4. EMWH-flags follow strict layering rules: - https://specifications.freedesktop.org/wm-spec/1.3/ar01s07.html#STACKINGORDER - """ - if len(self.qtile.windows_map) < 2: - return - - if self.group is None and not isinstance(self, Static): - return - - # Use the window's group or current group if this isn't set (e.g. Static windows) - group = self.group or self.qtile.current_group - - parent = self.window.get_wm_transient_for() - if parent is not None and not up: - return - - layering = self.get_layering_information() - - # Comparison of layer states: -1 if window is now in a lower state group, - # 0 if it's in the same group and 1 if it's in a higher group - moved = (self.previous_layer > layering) - (layering > self.previous_layer) - self.previous_layer = layering - - stack = list(self.qtile.core._root.query_tree()) - if self.wid not in stack or len(stack) < 2: - return - - # Get all windows for the group and add Static windows to ensure these are included - # in the stacking - group_windows = group.windows.copy() - statics = [win for win in self.qtile.windows_map.values() if isinstance(win, Static)] - group_windows.extend(statics) - - if group.screen is not None: - group_bars = [gap for gap in group.screen.gaps if isinstance(gap, bar.Bar)] - else: - group_bars = [] - - # Get list of windows that are in the stack and managed by qtile - # List of tuples (XWindow object, transient_for, layering_information) - windows = list( - map( - lambda w: ( - w.window, - w.window.get_wm_transient_for(), - w.get_layering_information(), - ), - group_windows, - ) - ) - - # Remove any windows that aren't in the server's stack - windows = list(filter(lambda w: w[0].wid in stack, windows)) - - # Sort this list to match stacking order reported by server - windows.sort(key=lambda w: stack.index(w[0].wid)) - - # Get lists of windows on lower, higher or same "layer" as window - lower = [w[0].wid for w in windows if w[2] > layering] - higher = [w[0].wid for w in windows if w[2] < layering] - same = [w[0].wid for w in windows if w[2] == layering] - - # We now need to identify the new position in the stack - - # If the window has a parent, the window should just be put above it - # If the parent isn't being managed by qtile then it may not be stacked correctly - if parent and parent in self.qtile.windows_map: - # If the window is modal then it should be placed above every other window that is in that window group - # e.g. the parent of the dialog and any other window that is also transient for the same parent. - if "_NET_WM_STATE_MODAL" in self.window.get_net_wm_state(): - window_group = [parent] - window_group.extend( - k - for k, v in self.qtile.windows_map.items() - if v.window.get_wm_transient_for() == parent - ) - window_group.sort(key=stack.index) - - # Make sure we're above the last window in that group - sibling = window_group[-1] - - else: - sibling = parent - above = True + if _type == "desktop": + return LayerGroup.BACKGROUND + + if "_NET_WM_STATE_BELOW" in state: + return LayerGroup.KEEP_BELOW - # Now we just check whether the window has changed layer. + if _type == "dock" or "_NET_WM_STATE_ABOVE" in state: + return LayerGroup.KEEP_ABOVE - # If we're forcing to top or bottom of current layer... - elif top_bottom: - # If there are no other windows in the same layer then there's nothing to do - if not same: - return - - if up: - sibling = same[-1] - above = True - else: - sibling = same[0] - above = False - - # There are no windows in the desired layer (should never happen) or - # we've moved to a new layer and are the only window in that layer - elif not same or (len(same) == 1 and moved != 0): - # Try to put it above the last window in the lower layers - if lower: - sibling = lower[-1] - above = True - - # Or below the first window in the higher layers - elif higher: - sibling = higher[0] - above = False - - # Don't think we should end up here but, if we do... - else: - # Put the window above the highest window if we're raising it - if up: - sibling = stack[-1] - above = True - - # or below the lowest window if we're lowering the window - else: - sibling = stack[0] - above = False - - else: - # Window has moved to a lower layer state - if moved < 0: - if self.kept_below: - sibling = same[0] - above = False - else: - sibling = same[-1] - above = True - - # Window is in same layer state - elif moved == 0: - try: - pos = same.index(self.wid) - except ValueError: - pos = len(same) if up else 0 - if not up: - pos = max(0, pos - 1) - else: - pos = min(pos + 1, len(same) - 1) - sibling = same[pos] - above = up - - # Window is in a higher layer - else: - if self.kept_above: - sibling = same[-1] - above = True - else: - sibling = same[0] - above = False - - # If the sibling is the current window then we just check if any windows in lower/higher layers are - # stacked incorrectly and, if so, restack them. However, we don't need to configure stacking for this - # window - if sibling == self.wid: - index = stack.index(self.wid) - - # We need to make sure the bars are included so add them now - if group_bars: - for group_bar in group_bars: - bar_layer = group_bar.window.get_layering_information() - if bar_layer > layering: - lower.append(group_bar.window.wid) - elif bar_layer < layering: - higher.append(group_bar.window.wid) - - # Sort the list to match the server's stacking order - lower.sort(key=lambda wid: stack.index(wid)) - higher.sort(key=lambda wid: stack.index(wid)) - - for wid in [w for w in lower if stack.index(w) > index]: - self.qtile.windows_map[wid].window.configure( - stackmode=xcffib.xproto.StackMode.Below, sibling=same[0] - ) + if full and focus: + return LayerGroup.FULLSCREEN - # We reverse higher as each window will be placed above the last item in the current layer - # this means the last item we stack will be just above the current layer. - for wid in [w for w in higher[::-1] if stack.index(w) < index]: - self.qtile.windows_map[wid].window.configure( - stackmode=xcffib.xproto.StackMode.Above, sibling=same[-1] - ) - - return + if isinstance(self.qtile.groups_map.get(self.group), ScratchPad): + return LayerGroup.BRING_TO_FRONT - # Window needs new stacking info. We tell the server to stack the window - # above or below a given "sibling" - self.window.configure( - stackmode=xcffib.xproto.StackMode.Above if above else xcffib.xproto.StackMode.Below, - sibling=sibling, - ) - - # Move window's children if we were moved upwards - if above: - self.raise_children(stack=stack) + return LayerGroup.LAYOUT - self.qtile.core.update_client_lists() + def change_layer(self, layer=None, up=True, top_bottom=False): + stack_info = self.qtile.core.zmanager.move_window_to_layer(self, layer or self.get_layering_information()) + self.stack(stack_info) def raise_children(self, stack=None): """Ensure any transient windows are moved up with the parent.""" @@ -1401,7 +1205,7 @@ def keep_above(self, enable: bool | None = None): else: self.kept_above = enable - self.change_layer(top_bottom=True, up=True) + self.change_layer() @expose_command() def keep_below(self, enable: bool | None = None): @@ -1410,7 +1214,7 @@ def keep_below(self, enable: bool | None = None): else: self.kept_below = enable - self.change_layer(top_bottom=True, up=False) + self.change_layer() @expose_command() def move_up(self, force=False): @@ -1419,28 +1223,32 @@ def move_up(self, force=False): with self.qtile.core.masked(): # Disable masks so that moving windows along the Z axis doesn't trigger # focus change events (i.e. due to `follow_mouse_focus`) - self.change_layer() + stack_info = self.qtile.core.zmanager.move_up(self) + self.stack(stack_info) @expose_command() def move_down(self, force=False): if self.kept_above and force: self.kept_above = False with self.qtile.core.masked(): - self.change_layer(up=False) + stack_info = self.qtile.core.zmanager.move_down(self) + self.stack(stack_info) @expose_command() def move_to_top(self, force=False): if self.kept_below and force: self.kept_below = False with self.qtile.core.masked(): - self.change_layer(top_bottom=True) + stack_info = self.qtile.core.zmanager.move_to_top(self) + self.stack(stack_info) @expose_command() def move_to_bottom(self, force=False): if self.kept_above and force: self.kept_above = False with self.qtile.core.masked(): - self.change_layer(up=False, top_bottom=True) + stack_info = self.qtile.core.zmanager.move_to_bottom(self) + self.stack(stack_info) @property def kept_above(self): @@ -1484,14 +1292,12 @@ def kept_below(self, value): if atom in reply: reply.remove(atom) self.window.set_property("_NET_WM_STATE", reply) - self.change_layer(up=False) + self.change_layer() @expose_command() def bring_to_front(self): if self.get_wm_type() != "desktop": - self.window.configure(stackmode=xcffib.xproto.StackMode.Above) - self.raise_children() - self.qtile.core.update_client_lists() + self.change_layer(layer=LayerGroup.BRING_TO_FRONT) class Internal(_Window, base.Internal): @@ -1563,6 +1369,9 @@ def info(self): id=self.window.wid, ) + def is_visible(self): + return True + @expose_command() def focus(self, warp: bool = True) -> None: """Focuses the window.""" diff --git a/libqtile/backend/x11/zmanager.py b/libqtile/backend/x11/zmanager.py new file mode 100644 index 0000000000..ad23470b66 --- /dev/null +++ b/libqtile/backend/x11/zmanager.py @@ -0,0 +1,24 @@ +# Copyright (c) 2025 elParaguayo +# +# 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 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. +from libqtile.backend.base import zmanager + + +class ZManager(zmanager.ZManager): + pass diff --git a/libqtile/core/manager.py b/libqtile/core/manager.py index 8016855c58..632ba02f62 100644 --- a/libqtile/core/manager.py +++ b/libqtile/core/manager.py @@ -728,6 +728,9 @@ def free_reserved_space( self.reserve_space(reserved_space, screen) def manage(self, win: base.WindowType) -> None: + # Add the window to our layer manager + self.core.zmanager.add_window(win) + if isinstance(win, base.Internal): self.windows_map[win.wid] = win return @@ -755,6 +758,7 @@ def unmanage(self, wid: int) -> None: # Fire the hook before removing the group from the window so hooked # functions can access it hook.fire("client_killed", c) + self.core.zmanager.remove_window(c) if isinstance(c, base.Static): if c.reserved_space: self.free_reserved_space(c.reserved_space, c.screen) From 40792384e7cb9f38e36cf49b9184ed89ffc60e36 Mon Sep 17 00:00:00 2001 From: elParaguayo Date: Tue, 29 Jul 2025 19:13:23 +0100 Subject: [PATCH 04/14] Adding to x11 contd. --- libqtile/backend/base/zmanager.py | 32 +++++-------------------------- libqtile/backend/x11/core.py | 24 ++--------------------- libqtile/backend/x11/window.py | 1 + libqtile/backend/x11/zmanager.py | 22 +++++++++++++++++++-- 4 files changed, 28 insertions(+), 51 deletions(-) diff --git a/libqtile/backend/base/zmanager.py b/libqtile/backend/base/zmanager.py index a33b12d263..f30b4ce756 100644 --- a/libqtile/backend/base/zmanager.py +++ b/libqtile/backend/base/zmanager.py @@ -48,15 +48,16 @@ def __post_init__(self): self.wid = self.sibling.wid + def check_window(func): """ - Decorator that requires window to be visible and stacked before proceeding. + Decorator that requires window to be stacked before proceeding. The decorated method must take the window's id as the first argument. """ @wraps(func) def _wrapper(self, window, *args, **kwargs): - if not self.is_stacked(window) or not window.is_visible(): + if not self.is_stacked(window): return return func(self, window, *args, **kwargs) @@ -64,7 +65,8 @@ def _wrapper(self, window, *args, **kwargs): class ZManager: - def __init__(self) -> None: + def __init__(self, core) -> None: + self.core = core self.layers: dict[LayerGroup, list[_Window]] = {l: [] for l in LayerGroup} self.layer_map: dict[_Window, tuple(LayerGroup, int)] = {} @@ -192,27 +194,3 @@ def get_z_order(self) -> list[_Window]: def _reindex_layer(self, layer) -> None: for idx, win in enumerate(self.layers[layer]): self.layer_map[win] = (layer, idx) - - -# Testing -class Window: - def __init__(self, name, vis, gr): - self.name = name - self.vis = vis - self.group = gr - - def is_visible(self): - return self.vis - - def __repr__(self): - return f"Window: <{self.name}>" - -A = Window("A", True, 1) -B = Window("B", True, 2) -C = Window("C", False, 1) -D = Window("D", True, 1) - -z = ZManager() - -for w in (A, B, C, D): - z.add_window(w) diff --git a/libqtile/backend/x11/core.py b/libqtile/backend/x11/core.py index 6d2eb8c942..70d4055f31 100644 --- a/libqtile/backend/x11/core.py +++ b/libqtile/backend/x11/core.py @@ -171,7 +171,7 @@ def __init__(self, display_name: str | None = None) -> None: self.last_focused: base.Window | None = None - self.zmanager = ZManager() + self.zmanager = ZManager(core=self) @property def name(self): @@ -452,27 +452,7 @@ def display_name(self) -> str: return self._display_name def update_client_lists(self) -> None: - """Updates the _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING properties - - This is needed for third party tasklists and drag and drop of tabs in - chrome - """ - assert self.qtile - # Regular top-level managed windows, i.e. excluding Static, Internal and Systray Icons - wids = [wid for wid, c in self.qtile.windows_map.items() if isinstance(c, window.Window)] - self._root.set_property("_NET_CLIENT_LIST", wids) - - # We rely on the stacking order from the X server - stacked_wids = [] - for wid in self._root.query_tree(): - win = self.qtile.windows_map.get(wid) - if not win: - continue - - if isinstance(win, window.Window) and win.group: - stacked_wids.append(wid) - - self._root.set_property("_NET_CLIENT_LIST_STACKING", stacked_wids) + self.zmanager.update_client_lists() def update_desktops(self, groups, index: int) -> None: """Set the current desktops of the window manager diff --git a/libqtile/backend/x11/window.py b/libqtile/backend/x11/window.py index f52d0a9e35..c345c8f48b 100644 --- a/libqtile/backend/x11/window.py +++ b/libqtile/backend/x11/window.py @@ -920,6 +920,7 @@ def stack(self, stack_info): stackmode=xp.StackMode.Below if stack_info.above else xp.StackMode.Above, sibling=stack_info.wid ) + self.qtile.core.zmanager.update_client_lists() def get_layering_information(self) -> LayerGroup: """ diff --git a/libqtile/backend/x11/zmanager.py b/libqtile/backend/x11/zmanager.py index ad23470b66..94aeac5da7 100644 --- a/libqtile/backend/x11/zmanager.py +++ b/libqtile/backend/x11/zmanager.py @@ -18,7 +18,25 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. from libqtile.backend.base import zmanager - +from libqtile.backend.base.window import _Window +from libqtile.backend.base.zmanager import LayerGroup +from libqtile.backend.x11 import window class ZManager(zmanager.ZManager): - pass + def update_client_lists(self): + """Updates the _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING properties + + This is needed for third party tasklists and drag and drop of tabs in + chrome + """ + assert self.core.qtile + z_order = self.get_z_order() + # Regular top-level managed windows, i.e. excluding Static, Internal and Systray Icons + wids = [win.wid for win in z_order if isinstance(win, window.Window)] + self.core._root.set_property("_NET_CLIENT_LIST", wids) + + self.core._root.set_property("_NET_CLIENT_LIST_STACKING", [win.wid for win in z_order]) + + def add_window(self, window: _Window, layer: LayerGroup = LayerGroup.LAYOUT, position="top") -> None: + super().add_window(window, layer, position) + window.stack(self.get_window_below(window) or self.get_window_above(window)) From 6d1e5cf9131ba613c82dab855b10c519f8c71471 Mon Sep 17 00:00:00 2001 From: elParaguayo Date: Tue, 29 Jul 2025 22:19:05 +0100 Subject: [PATCH 05/14] Make zmanager abstract --- libqtile/backend/base/zmanager.py | 136 ++++++----------------------- libqtile/backend/x11/window.py | 27 +++--- libqtile/backend/x11/zmanager.py | 138 ++++++++++++++++++++++++++++-- test/backend/x11/test_window.py | 26 +++--- 4 files changed, 186 insertions(+), 141 deletions(-) diff --git a/libqtile/backend/base/zmanager.py b/libqtile/backend/base/zmanager.py index f30b4ce756..a195e6dd34 100644 --- a/libqtile/backend/base/zmanager.py +++ b/libqtile/backend/base/zmanager.py @@ -17,7 +17,7 @@ # 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. -from collections import defaultdict +from abc import ABC, abstractmethod from dataclasses import dataclass from enum import IntEnum from functools import wraps @@ -48,7 +48,6 @@ def __post_init__(self): self.wid = self.sibling.wid - def check_window(func): """ Decorator that requires window to be stacked before proceeding. @@ -67,130 +66,47 @@ def _wrapper(self, window, *args, **kwargs): class ZManager: def __init__(self, core) -> None: self.core = core - self.layers: dict[LayerGroup, list[_Window]] = {l: [] for l in LayerGroup} - self.layer_map: dict[_Window, tuple(LayerGroup, int)] = {} + @abstractmethod def is_stacked(self, window: _Window) -> bool: - return window in self.layer_map - - def get_layer(self, window) -> LayerGroup | None: - layer, _ = self.layer_map.get(window, (None, 0)) - return layer - - @check_window - def get_window_above(self, window) -> StackInfo | None: - stack = self.get_z_order() - idx = stack.index(window) - if idx < (len(stack) - 1): - sibling = stack[idx + 1] - return StackInfo(sibling=sibling, above=True) - - @check_window - def get_window_below(self, window) -> StackInfo | None: - stack = self.get_z_order() - idx = stack.index(window) - if idx > 0: - sibling = stack[idx - 1] - return StackInfo(sibling=sibling, above=False) + pass + @abstractmethod def add_window(self, window: _Window, layer: LayerGroup = LayerGroup.LAYOUT, position="top") -> None: - if layer not in self.layers: - raise ValueError(f"Invalid layer: {layer}") - - current_layer = self.get_layer(window) - if current_layer is not None and current_layer != layer: - logger.info("Window already stacked. Moving to new layer group.") - self.layers[current_layer].remove(window) - - if position == "bottom": - self.layers[layer].insert(0, window) - else: - self.layers[layer].append(window) - - self._reindex_layer(layer) + pass - @check_window + @abstractmethod def remove_window(self, window) -> None: - layer, _ = self.layer_map.pop(window) - self.layers[layer].remove(window) - self._reindex_layer(layer) + pass - @check_window + @abstractmethod def move_up(self, window) -> StackInfo | None: - layer, cur_idx = self.layer_map[window] - visible = [w for w in self.layers[layer] if w.is_visible() and w.group in (window.group, None)] - idx = visible.index(window) - if idx < (len(visible) - 1): - dest_idx = self.layers[layer].index(visible[idx + 1]) - win = self.layers[layer].pop(cur_idx) - self.layers[layer].insert(dest_idx, win) + pass - self._reindex_layer(layer) - - return self.get_window_below(window) - - @check_window + @abstractmethod def move_down(self, window) -> StackInfo | None: - layer, cur_idx = self.layer_map[window] - visible = [w for w in self.layers[layer] if w.is_visible() and w.group in (window.group, None)] - idx = visible.index(window) - if idx > 0: - dest_idx = self.layers[layer].index(visible[idx - 1]) - win = self.layers[layer].pop(cur_idx) - self.layers[layer].insert(dest_idx, win) - - self._reindex_layer(layer) + pass - return self.get_window_above(window) - - @check_window + @abstractmethod def move_to_top(self, window) -> StackInfo | None: - layer, _ = self.layer_map[window] - self.layers[layer].remove(window) - self.layers[layer].append(window) - self._reindex_layer(layer) - - return self.get_window_below(window) + pass - @check_window + @abstractmethod def move_to_bottom(self, window) -> StackInfo | None: - layer, _ = self.layer_map[window] - self.layers[layer].remove(window) - self.layers[layer].insert(0, window) - self._reindex_layer(layer) - - return self.get_window_above(window) - - @check_window - def keep_above(self, window) -> StackInfo | None: - return self.move_window_to_layer(window, LayerGroup.KEEP_ABOVE) + pass - @check_window - def keep_below(self, window) -> StackInfo | None: - return self.move_window_to_layer(window, LayerGroup.KEEP_BELOW) - - @check_window + @abstractmethod def move_window_to_layer(self, window, new_layer, position="top") -> StackInfo | None: - old_layer, _ = self.layer_map[window] - self.layers[old_layer].remove(window) - - if position == "bottom": - self.layers[new_layer].insert(0, window) - else: - self.layers[new_layer].append(window) - - self.layer_map[window] = (new_layer, self.layers[new_layer].index(window)) - self._reindex_layer(old_layer) - self._reindex_layer(new_layer) + pass - return self.get_window_below(window) or self.get_window_above(window) + # @check_window + # def keep_above(self, window) -> StackInfo | None: + # return self.move_window_to_layer(window, LayerGroup.KEEP_ABOVE) - def get_z_order(self) -> list[_Window]: - z_order = [] - for clients in self.layers.values(): - z_order.extend(clients) - return z_order + # @check_window + # def keep_below(self, window) -> StackInfo | None: + # return self.move_window_to_layer(window, LayerGroup.KEEP_BELOW) - def _reindex_layer(self, layer) -> None: - for idx, win in enumerate(self.layers[layer]): - self.layer_map[win] = (layer, idx) + # @check_window + # def bring_to_front(self, window) -> StackInfo | None: + # return self.move_window_to_layer(window, LayerGroup.BRING_TO_FRONT) diff --git a/libqtile/backend/x11/window.py b/libqtile/backend/x11/window.py index c345c8f48b..6c02c99265 100644 --- a/libqtile/backend/x11/window.py +++ b/libqtile/backend/x11/window.py @@ -920,6 +920,7 @@ def stack(self, stack_info): stackmode=xp.StackMode.Below if stack_info.above else xp.StackMode.Above, sibling=stack_info.wid ) + self.raise_children() self.qtile.core.zmanager.update_client_lists() def get_layering_information(self) -> LayerGroup: @@ -987,25 +988,21 @@ def get_layering_information(self) -> LayerGroup: return LayerGroup.LAYOUT - def change_layer(self, layer=None, up=True, top_bottom=False): - stack_info = self.qtile.core.zmanager.move_window_to_layer(self, layer or self.get_layering_information()) + def change_layer(self, layer=None, bottom=False): + stack_info = self.qtile.core.zmanager.move_window_to_layer(self, layer or self.get_layering_information(), position="bottom" if bottom else "top") self.stack(stack_info) - def raise_children(self, stack=None): + def raise_children(self): """Ensure any transient windows are moved up with the parent.""" - children = [ - k - for k, v in self.qtile.windows_map.items() - if v.window.get_wm_transient_for() == self.window.wid - ] + query = self.window.conn.conn.core.QueryTree(self.window.wid).reply() + children = list(query.children) if children: - if stack is None: - stack = list(self.qtile.core._root.query_tree()) parent = self.window.wid - children.sort(key=stack.index) for child in children: - self.qtile.windows_map[child].window.configure( - stackmode=xcffib.xproto.StackMode.Above, sibling=parent + self.window.conn.conn.core.ConfigureWindow( + child, + xcffib.xproto.ConfigWindow.Sibling | xcffib.xproto.ConfigWindow.StackMode, + [parent, xcffib.xproto.StackMode.Above] ) parent = child @@ -1285,15 +1282,17 @@ def kept_below(self, value): atom = self.qtile.core.conn.atoms["_NET_WM_STATE_BELOW"] if value and atom not in reply: reply.append(atom) + bottom = True elif not value and atom in reply: reply.remove(atom) + bottom = False else: return atom = self.qtile.core.conn.atoms["_NET_WM_STATE_ABOVE"] if atom in reply: reply.remove(atom) self.window.set_property("_NET_WM_STATE", reply) - self.change_layer() + self.change_layer(bottom=bottom) @expose_command() def bring_to_front(self): diff --git a/libqtile/backend/x11/zmanager.py b/libqtile/backend/x11/zmanager.py index 94aeac5da7..a20ba8eec7 100644 --- a/libqtile/backend/x11/zmanager.py +++ b/libqtile/backend/x11/zmanager.py @@ -19,10 +19,140 @@ # SOFTWARE. from libqtile.backend.base import zmanager from libqtile.backend.base.window import _Window -from libqtile.backend.base.zmanager import LayerGroup +from libqtile.backend.base.zmanager import LayerGroup, StackInfo, check_window from libqtile.backend.x11 import window +from libqtile.log_utils import logger + class ZManager(zmanager.ZManager): + def __init__(self, core) -> None: + super().__init__(core) + self.layers: dict[LayerGroup, list[_Window]] = {l: [] for l in LayerGroup} + self.layer_map: dict[_Window, tuple(LayerGroup, int)] = {} + + def is_stacked(self, window: _Window) -> bool: + return window in self.layer_map + + def get_layer(self, window) -> LayerGroup | None: + layer, _ = self.layer_map.get(window, (None, 0)) + return layer + + @check_window + def get_window_above(self, window) -> StackInfo | None: + stack = self.get_z_order() + idx = stack.index(window) + if idx < (len(stack) - 1): + sibling = stack[idx + 1] + return StackInfo(sibling=sibling, above=True) + + @check_window + def get_window_below(self, window) -> StackInfo | None: + stack = self.get_z_order() + idx = stack.index(window) + if idx > 0: + sibling = stack[idx - 1] + return StackInfo(sibling=sibling, above=False) + + def add_window(self, window: _Window, layer: LayerGroup = LayerGroup.LAYOUT, position="top") -> None: + if layer not in self.layers: + raise ValueError(f"Invalid layer: {layer}") + + current_layer = self.get_layer(window) + if current_layer is not None and current_layer != layer: + logger.info("Window already stacked. Moving to new layer group.") + self.layers[current_layer].remove(window) + + if position == "bottom": + self.layers[layer].insert(0, window) + else: + self.layers[layer].append(window) + + self._reindex_layer(layer) + + window.stack(self.get_window_below(window) or self.get_window_above(window)) + + @check_window + def remove_window(self, window) -> None: + layer, _ = self.layer_map.pop(window) + self.layers[layer].remove(window) + self._reindex_layer(layer) + + @check_window + def move_up(self, window) -> StackInfo | None: + layer, cur_idx = self.layer_map[window] + visible = [w for w in self.layers[layer] if w.is_visible() and w.group in (window.group, None)] + print(layer, visible) + idx = visible.index(window) + if idx < (len(visible) - 1): + dest_idx = self.layers[layer].index(visible[idx + 1]) + win = self.layers[layer].pop(cur_idx) + self.layers[layer].insert(dest_idx, win) + + self._reindex_layer(layer) + + return self.get_window_below(window) + + @check_window + def move_down(self, window) -> StackInfo | None: + layer, cur_idx = self.layer_map[window] + visible = [w for w in self.layers[layer] if w.is_visible() and w.group in (window.group, None)] + idx = visible.index(window) + if idx > 0: + dest_idx = self.layers[layer].index(visible[idx - 1]) + win = self.layers[layer].pop(cur_idx) + self.layers[layer].insert(dest_idx, win) + + self._reindex_layer(layer) + + return self.get_window_above(window) + + @check_window + def move_to_top(self, window) -> StackInfo | None: + layer, _ = self.layer_map[window] + self.layers[layer].remove(window) + self.layers[layer].append(window) + self._reindex_layer(layer) + + return self.get_window_below(window) + + @check_window + def move_to_bottom(self, window) -> StackInfo | None: + layer, _ = self.layer_map[window] + self.layers[layer].remove(window) + self.layers[layer].insert(0, window) + self._reindex_layer(layer) + + return self.get_window_above(window) + + @check_window + def move_window_to_layer(self, window, new_layer, position="top") -> StackInfo | None: + old_layer, _ = self.layer_map[window] + if old_layer is new_layer: + return + self.layers[old_layer].remove(window) + + print(window, position) + if position == "bottom": + self.layers[new_layer].insert(0, window) + else: + self.layers[new_layer].append(window) + + self.layer_map[window] = (new_layer, self.layers[new_layer].index(window)) + self._reindex_layer(old_layer) + self._reindex_layer(new_layer) + + return self.get_window_below(window) or self.get_window_above(window) + + def get_z_order(self) -> list[_Window]: + z_order = [] + for clients in self.layers.values(): + z_order.extend(clients) + return z_order + + def _reindex_layer(self, layer) -> None: + for idx, win in enumerate(self.layers[layer]): + self.layer_map[win] = (layer, idx) + def update_client_lists(self): """Updates the _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING properties @@ -35,8 +165,4 @@ def update_client_lists(self): wids = [win.wid for win in z_order if isinstance(win, window.Window)] self.core._root.set_property("_NET_CLIENT_LIST", wids) - self.core._root.set_property("_NET_CLIENT_LIST_STACKING", [win.wid for win in z_order]) - - def add_window(self, window: _Window, layer: LayerGroup = LayerGroup.LAYOUT, position="top") -> None: - super().add_window(window, layer, position) - window.stack(self.get_window_below(window) or self.get_window_above(window)) + self.core._root.set_property("_NET_CLIENT_LIST_STACKING", [win.wid for win in z_order]) diff --git a/test/backend/x11/test_window.py b/test/backend/x11/test_window.py index b0fe5a501c..d74e6e51d7 100644 --- a/test/backend/x11/test_window.py +++ b/test/backend/x11/test_window.py @@ -24,8 +24,14 @@ from test.test_images2 import should_skip from test.test_manager import ManagerConfig + +class ManagerConfigNormalFloats(ManagerConfig): + floats_kept_above = False + + bare_config = pytest.mark.parametrize("xmanager", [BareConfig], indirect=True) manager_config = pytest.mark.parametrize("xmanager", [ManagerConfig], indirect=True) +manager_config_normal_floats = pytest.mark.parametrize("xmanager", [ManagerConfigNormalFloats], indirect=True) @manager_config @@ -851,7 +857,7 @@ def assert_state_focused(wid, has_state): xmanager.kill_window(one) -@manager_config +@manager_config_normal_floats def test_window_stacking_order(xmanager): """Test basic window stacking controls.""" conn = xcbq.Connection(xmanager.display) @@ -868,10 +874,10 @@ def _clients(): return [x[0] for x in wins] xmanager.test_window("one") - xmanager.test_window("two") - xmanager.test_window("three") - xmanager.test_window("four") - xmanager.test_window("five") + xmanager.test_window("two", floating=True) + xmanager.test_window("three", floating=True) + xmanager.test_window("four", floating=True) + xmanager.test_window("five", floating=True) # We're testing 3 "layers" # BELOW, 'everything else', ABOVE @@ -935,15 +941,13 @@ def _clients(): # BELOW: two, ABOVE: None _wnd("three").keep_below() - assert _clients() == ["two", "three", "four", "five", "one"] + assert _clients() == ["two", "four", "five", "one", "three"] _wnd("one").move_down() - assert _clients() == ["two", "three", "four", "one", "five"] - - # BELOW: None ABOVE: None - _wnd("two").keep_below() - assert _clients() == ["two", "three", "four", "one", "five"] + assert _clients() == ["two", "four", "one", "five", "three"] # BELOW: three, ABOVE: None + _wnd("two").keep_below() + _wnd("two").move_to_bottom() _wnd("three").keep_below() assert _clients() == ["three", "two", "four", "one", "five"] _wnd("two").move_down() From f6b25a03a3ed326c635d89365632392ef336f5f8 Mon Sep 17 00:00:00 2001 From: elParaguayo Date: Tue, 29 Jul 2025 22:20:29 +0100 Subject: [PATCH 06/14] Tidying up. --- .../wlr-layer-shell-unstable-v1-protocol.h | 710 ----- .../wayland/qw/proto/xdg-shell-protocol.h | 2327 ----------------- libqtile/backend/x11/zmanager.py | 2 - 3 files changed, 3039 deletions(-) delete mode 100644 libqtile/backend/wayland/qw/proto/wlr-layer-shell-unstable-v1-protocol.h delete mode 100644 libqtile/backend/wayland/qw/proto/xdg-shell-protocol.h diff --git a/libqtile/backend/wayland/qw/proto/wlr-layer-shell-unstable-v1-protocol.h b/libqtile/backend/wayland/qw/proto/wlr-layer-shell-unstable-v1-protocol.h deleted file mode 100644 index 2e8962a0d6..0000000000 --- a/libqtile/backend/wayland/qw/proto/wlr-layer-shell-unstable-v1-protocol.h +++ /dev/null @@ -1,710 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -#ifndef WLR_LAYER_SHELL_UNSTABLE_V1_SERVER_PROTOCOL_H -#define WLR_LAYER_SHELL_UNSTABLE_V1_SERVER_PROTOCOL_H - -#include -#include -#include "wayland-server.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct wl_client; -struct wl_resource; - -/** - * @page page_wlr_layer_shell_unstable_v1 The wlr_layer_shell_unstable_v1 protocol - * @section page_ifaces_wlr_layer_shell_unstable_v1 Interfaces - * - @subpage page_iface_zwlr_layer_shell_v1 - create surfaces that are layers of the desktop - * - @subpage page_iface_zwlr_layer_surface_v1 - layer metadata interface - * @section page_copyright_wlr_layer_shell_unstable_v1 Copyright - *
- *
- * Copyright © 2017 Drew DeVault
- *
- * Permission to use, copy, modify, distribute, and sell this
- * software and its documentation for any purpose is hereby granted
- * without fee, provided that the above copyright notice appear in
- * all copies and that both that copyright notice and this permission
- * notice appear in supporting documentation, and that the name of
- * the copyright holders not be used in advertising or publicity
- * pertaining to distribution of the software without specific,
- * written prior permission.  The copyright holders make no
- * representations about the suitability of this software for any
- * purpose.  It is provided "as is" without express or implied
- * warranty.
- *
- * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
- * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
- * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
- * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
- * THIS SOFTWARE.
- * 
- */ -struct wl_output; -struct wl_surface; -struct xdg_popup; -struct zwlr_layer_shell_v1; -struct zwlr_layer_surface_v1; - -#ifndef ZWLR_LAYER_SHELL_V1_INTERFACE -#define ZWLR_LAYER_SHELL_V1_INTERFACE -/** - * @page page_iface_zwlr_layer_shell_v1 zwlr_layer_shell_v1 - * @section page_iface_zwlr_layer_shell_v1_desc Description - * - * Clients can use this interface to assign the surface_layer role to - * wl_surfaces. Such surfaces are assigned to a "layer" of the output and - * rendered with a defined z-depth respective to each other. They may also be - * anchored to the edges and corners of a screen and specify input handling - * semantics. This interface should be suitable for the implementation of - * many desktop shell components, and a broad number of other applications - * that interact with the desktop. - * @section page_iface_zwlr_layer_shell_v1_api API - * See @ref iface_zwlr_layer_shell_v1. - */ -/** - * @defgroup iface_zwlr_layer_shell_v1 The zwlr_layer_shell_v1 interface - * - * Clients can use this interface to assign the surface_layer role to - * wl_surfaces. Such surfaces are assigned to a "layer" of the output and - * rendered with a defined z-depth respective to each other. They may also be - * anchored to the edges and corners of a screen and specify input handling - * semantics. This interface should be suitable for the implementation of - * many desktop shell components, and a broad number of other applications - * that interact with the desktop. - */ -extern const struct wl_interface zwlr_layer_shell_v1_interface; -#endif -#ifndef ZWLR_LAYER_SURFACE_V1_INTERFACE -#define ZWLR_LAYER_SURFACE_V1_INTERFACE -/** - * @page page_iface_zwlr_layer_surface_v1 zwlr_layer_surface_v1 - * @section page_iface_zwlr_layer_surface_v1_desc Description - * - * An interface that may be implemented by a wl_surface, for surfaces that - * are designed to be rendered as a layer of a stacked desktop-like - * environment. - * - * Layer surface state (layer, size, anchor, exclusive zone, - * margin, interactivity) is double-buffered, and will be applied at the - * time wl_surface.commit of the corresponding wl_surface is called. - * - * Attaching a null buffer to a layer surface unmaps it. - * - * Unmapping a layer_surface means that the surface cannot be shown by the - * compositor until it is explicitly mapped again. The layer_surface - * returns to the state it had right after layer_shell.get_layer_surface. - * The client can re-map the surface by performing a commit without any - * buffer attached, waiting for a configure event and handling it as usual. - * @section page_iface_zwlr_layer_surface_v1_api API - * See @ref iface_zwlr_layer_surface_v1. - */ -/** - * @defgroup iface_zwlr_layer_surface_v1 The zwlr_layer_surface_v1 interface - * - * An interface that may be implemented by a wl_surface, for surfaces that - * are designed to be rendered as a layer of a stacked desktop-like - * environment. - * - * Layer surface state (layer, size, anchor, exclusive zone, - * margin, interactivity) is double-buffered, and will be applied at the - * time wl_surface.commit of the corresponding wl_surface is called. - * - * Attaching a null buffer to a layer surface unmaps it. - * - * Unmapping a layer_surface means that the surface cannot be shown by the - * compositor until it is explicitly mapped again. The layer_surface - * returns to the state it had right after layer_shell.get_layer_surface. - * The client can re-map the surface by performing a commit without any - * buffer attached, waiting for a configure event and handling it as usual. - */ -extern const struct wl_interface zwlr_layer_surface_v1_interface; -#endif - -#ifndef ZWLR_LAYER_SHELL_V1_ERROR_ENUM -#define ZWLR_LAYER_SHELL_V1_ERROR_ENUM -enum zwlr_layer_shell_v1_error { - /** - * wl_surface has another role - */ - ZWLR_LAYER_SHELL_V1_ERROR_ROLE = 0, - /** - * layer value is invalid - */ - ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER = 1, - /** - * wl_surface has a buffer attached or committed - */ - ZWLR_LAYER_SHELL_V1_ERROR_ALREADY_CONSTRUCTED = 2, -}; -/** - * @ingroup iface_zwlr_layer_shell_v1 - * Validate a zwlr_layer_shell_v1 error value. - * - * @return true on success, false on error. - * @ref zwlr_layer_shell_v1_error - */ -static inline bool -zwlr_layer_shell_v1_error_is_valid(uint32_t value, uint32_t version) { - switch (value) { - case ZWLR_LAYER_SHELL_V1_ERROR_ROLE: - return version >= 1; - case ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER: - return version >= 1; - case ZWLR_LAYER_SHELL_V1_ERROR_ALREADY_CONSTRUCTED: - return version >= 1; - default: - return false; - } -} -#endif /* ZWLR_LAYER_SHELL_V1_ERROR_ENUM */ - -#ifndef ZWLR_LAYER_SHELL_V1_LAYER_ENUM -#define ZWLR_LAYER_SHELL_V1_LAYER_ENUM -/** - * @ingroup iface_zwlr_layer_shell_v1 - * available layers for surfaces - * - * These values indicate which layers a surface can be rendered in. They - * are ordered by z depth, bottom-most first. Traditional shell surfaces - * will typically be rendered between the bottom and top layers. - * Fullscreen shell surfaces are typically rendered at the top layer. - * Multiple surfaces can share a single layer, and ordering within a - * single layer is undefined. - */ -enum zwlr_layer_shell_v1_layer { - ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND = 0, - ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM = 1, - ZWLR_LAYER_SHELL_V1_LAYER_TOP = 2, - ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY = 3, -}; -/** - * @ingroup iface_zwlr_layer_shell_v1 - * Validate a zwlr_layer_shell_v1 layer value. - * - * @return true on success, false on error. - * @ref zwlr_layer_shell_v1_layer - */ -static inline bool -zwlr_layer_shell_v1_layer_is_valid(uint32_t value, uint32_t version) { - switch (value) { - case ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND: - return version >= 1; - case ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM: - return version >= 1; - case ZWLR_LAYER_SHELL_V1_LAYER_TOP: - return version >= 1; - case ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY: - return version >= 1; - default: - return false; - } -} -#endif /* ZWLR_LAYER_SHELL_V1_LAYER_ENUM */ - -/** - * @ingroup iface_zwlr_layer_shell_v1 - * @struct zwlr_layer_shell_v1_interface - */ -struct zwlr_layer_shell_v1_interface { - /** - * create a layer_surface from a surface - * - * Create a layer surface for an existing surface. This assigns - * the role of layer_surface, or raises a protocol error if another - * role is already assigned. - * - * Creating a layer surface from a wl_surface 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 - * layer_surface.configure call must also be treated as errors. - * - * After creating a layer_surface object and setting it up, the - * client must perform an initial commit without any buffer - * attached. The compositor will reply with a - * layer_surface.configure event. The client must acknowledge it - * and is then allowed to attach a buffer to map the surface. - * - * You may pass NULL for output to allow the compositor to decide - * which output to use. Generally this will be the one that the - * user most recently interacted with. - * - * Clients can specify a namespace that defines the purpose of the - * layer surface. - * @param layer layer to add this surface to - * @param namespace namespace for the layer surface - */ - void (*get_layer_surface)(struct wl_client *client, - struct wl_resource *resource, - uint32_t id, - struct wl_resource *surface, - struct wl_resource *output, - uint32_t layer, - const char *namespace); - /** - * destroy the layer_shell object - * - * This request indicates that the client will not use the - * layer_shell object any more. Objects that have been created - * through this instance are not affected. - * @since 3 - */ - void (*destroy)(struct wl_client *client, - struct wl_resource *resource); -}; - - -/** - * @ingroup iface_zwlr_layer_shell_v1 - */ -#define ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_layer_shell_v1 - */ -#define ZWLR_LAYER_SHELL_V1_DESTROY_SINCE_VERSION 3 - -#ifndef ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ENUM -#define ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ENUM -/** - * @ingroup iface_zwlr_layer_surface_v1 - * types of keyboard interaction possible for a layer shell surface - * - * Types of keyboard interaction possible for layer shell surfaces. The - * rationale for this is twofold: (1) some applications are not interested - * in keyboard events and not allowing them to be focused can improve the - * desktop experience; (2) some applications will want to take exclusive - * keyboard focus. - */ -enum zwlr_layer_surface_v1_keyboard_interactivity { - /** - * no keyboard focus is possible - * - * This value indicates that this surface is not interested in - * keyboard events and the compositor should never assign it the - * keyboard focus. - * - * This is the default value, set for newly created layer shell - * surfaces. - * - * This is useful for e.g. desktop widgets that display information - * or only have interaction with non-keyboard input devices. - */ - ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE = 0, - /** - * request exclusive keyboard focus - * - * Request exclusive keyboard focus if this surface is above the - * shell surface layer. - * - * For the top and overlay layers, the seat will always give - * exclusive keyboard focus to the top-most layer which has - * keyboard interactivity set to exclusive. If this layer contains - * multiple surfaces with keyboard interactivity set to exclusive, - * the compositor determines the one receiving keyboard events in - * an implementation- defined manner. In this case, no guarantee is - * made when this surface will receive keyboard focus (if ever). - * - * For the bottom and background layers, the compositor is allowed - * to use normal focus semantics. - * - * This setting is mainly intended for applications that need to - * ensure they receive all keyboard events, such as a lock screen - * or a password prompt. - */ - ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE = 1, - /** - * request regular keyboard focus semantics - * - * This requests the compositor to allow this surface to be - * focused and unfocused by the user in an implementation-defined - * manner. The user should be able to unfocus this surface even - * regardless of the layer it is on. - * - * Typically, the compositor will want to use its normal mechanism - * to manage keyboard focus between layer shell surfaces with this - * setting and regular toplevels on the desktop layer (e.g. click - * to focus). Nevertheless, it is possible for a compositor to - * require a special interaction to focus or unfocus layer shell - * surfaces (e.g. requiring a click even if focus follows the mouse - * normally, or providing a keybinding to switch focus between - * layers). - * - * This setting is mainly intended for desktop shell components - * (e.g. panels) that allow keyboard interaction. Using this option - * can allow implementing a desktop shell that can be fully usable - * without the mouse. - * @since 4 - */ - ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND = 2, -}; -/** - * @ingroup iface_zwlr_layer_surface_v1 - */ -#define ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND_SINCE_VERSION 4 -/** - * @ingroup iface_zwlr_layer_surface_v1 - * Validate a zwlr_layer_surface_v1 keyboard_interactivity value. - * - * @return true on success, false on error. - * @ref zwlr_layer_surface_v1_keyboard_interactivity - */ -static inline bool -zwlr_layer_surface_v1_keyboard_interactivity_is_valid(uint32_t value, uint32_t version) { - switch (value) { - case ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE: - return version >= 1; - case ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE: - return version >= 1; - case ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND: - return version >= 4; - default: - return false; - } -} -#endif /* ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ENUM */ - -#ifndef ZWLR_LAYER_SURFACE_V1_ERROR_ENUM -#define ZWLR_LAYER_SURFACE_V1_ERROR_ENUM -enum zwlr_layer_surface_v1_error { - /** - * provided surface state is invalid - */ - ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SURFACE_STATE = 0, - /** - * size is invalid - */ - ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SIZE = 1, - /** - * anchor bitfield is invalid - */ - ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_ANCHOR = 2, - /** - * keyboard interactivity is invalid - */ - ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_KEYBOARD_INTERACTIVITY = 3, -}; -/** - * @ingroup iface_zwlr_layer_surface_v1 - * Validate a zwlr_layer_surface_v1 error value. - * - * @return true on success, false on error. - * @ref zwlr_layer_surface_v1_error - */ -static inline bool -zwlr_layer_surface_v1_error_is_valid(uint32_t value, uint32_t version) { - switch (value) { - case ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SURFACE_STATE: - return version >= 1; - case ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SIZE: - return version >= 1; - case ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_ANCHOR: - return version >= 1; - case ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_KEYBOARD_INTERACTIVITY: - return version >= 1; - default: - return false; - } -} -#endif /* ZWLR_LAYER_SURFACE_V1_ERROR_ENUM */ - -#ifndef ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM -#define ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM -enum zwlr_layer_surface_v1_anchor { - /** - * the top edge of the anchor rectangle - */ - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP = 1, - /** - * the bottom edge of the anchor rectangle - */ - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM = 2, - /** - * the left edge of the anchor rectangle - */ - ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT = 4, - /** - * the right edge of the anchor rectangle - */ - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT = 8, -}; -/** - * @ingroup iface_zwlr_layer_surface_v1 - * Validate a zwlr_layer_surface_v1 anchor value. - * - * @return true on success, false on error. - * @ref zwlr_layer_surface_v1_anchor - */ -static inline bool -zwlr_layer_surface_v1_anchor_is_valid(uint32_t value, uint32_t version) { - uint32_t valid = 0; - if (version >= 1) - valid |= ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; - if (version >= 1) - valid |= ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; - if (version >= 1) - valid |= ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT; - if (version >= 1) - valid |= ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; - return (value & ~valid) == 0; -} -#endif /* ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM */ - -/** - * @ingroup iface_zwlr_layer_surface_v1 - * @struct zwlr_layer_surface_v1_interface - */ -struct zwlr_layer_surface_v1_interface { - /** - * sets the size of the surface - * - * Sets the size of the surface in surface-local coordinates. The - * compositor will display the surface centered with respect to its - * anchors. - * - * If you pass 0 for either value, the compositor will assign it - * and inform you of the assignment in the configure event. You - * must set your anchor to opposite edges in the dimensions you - * omit; not doing so is a protocol error. Both values are 0 by - * default. - * - * Size is double-buffered, see wl_surface.commit. - */ - void (*set_size)(struct wl_client *client, - struct wl_resource *resource, - uint32_t width, - uint32_t height); - /** - * configures the anchor point of the surface - * - * Requests that the compositor anchor the surface to the - * specified edges and corners. If two orthogonal edges are - * specified (e.g. 'top' and 'left'), then the anchor point will be - * the intersection of the edges (e.g. the top left corner of the - * output); otherwise the anchor point will be centered on that - * edge, or in the center if none is specified. - * - * Anchor is double-buffered, see wl_surface.commit. - */ - void (*set_anchor)(struct wl_client *client, - struct wl_resource *resource, - uint32_t anchor); - /** - * configures the exclusive geometry of this surface - * - * Requests that the compositor avoids occluding an area with - * other surfaces. The compositor's use of this information is - * implementation-dependent - do not assume that this region will - * not actually be occluded. - * - * A positive value is only meaningful if the surface is anchored - * to one edge or an edge and both perpendicular edges. If the - * surface is not anchored, anchored to only two perpendicular - * edges (a corner), anchored to only two parallel edges or - * anchored to all edges, a positive value will be treated the same - * as zero. - * - * A positive zone is the distance from the edge in surface-local - * coordinates to consider exclusive. - * - * Surfaces that do not wish to have an exclusive zone may instead - * specify how they should interact with surfaces that do. If set - * to zero, the surface indicates that it would like to be moved to - * avoid occluding surfaces with a positive exclusive zone. If set - * to -1, the surface indicates that it would not like to be moved - * to accommodate for other surfaces, and the compositor should - * extend it all the way to the edges it is anchored to. - * - * For example, a panel might set its exclusive zone to 10, so that - * maximized shell surfaces are not shown on top of it. A - * notification might set its exclusive zone to 0, so that it is - * moved to avoid occluding the panel, but shell surfaces are shown - * underneath it. A wallpaper or lock screen might set their - * exclusive zone to -1, so that they stretch below or over the - * panel. - * - * The default value is 0. - * - * Exclusive zone is double-buffered, see wl_surface.commit. - */ - void (*set_exclusive_zone)(struct wl_client *client, - struct wl_resource *resource, - int32_t zone); - /** - * sets a margin from the anchor point - * - * Requests that the surface be placed some distance away from - * the anchor point on the output, in surface-local coordinates. - * Setting this value for edges you are not anchored to has no - * effect. - * - * The exclusive zone includes the margin. - * - * Margin is double-buffered, see wl_surface.commit. - */ - void (*set_margin)(struct wl_client *client, - struct wl_resource *resource, - int32_t top, - int32_t right, - int32_t bottom, - int32_t left); - /** - * requests keyboard events - * - * Set how keyboard events are delivered to this surface. By - * default, layer shell surfaces do not receive keyboard events; - * this request can be used to change this. - * - * This setting is inherited by child surfaces set by the get_popup - * request. - * - * Layer surfaces receive pointer, touch, and tablet events - * normally. If you do not want to receive them, set the input - * region on your surface to an empty region. - * - * Keyboard interactivity is double-buffered, see - * wl_surface.commit. - */ - void (*set_keyboard_interactivity)(struct wl_client *client, - struct wl_resource *resource, - uint32_t keyboard_interactivity); - /** - * assign this layer_surface as an xdg_popup parent - * - * This assigns an xdg_popup's parent to this layer_surface. This - * popup should have been created via xdg_surface::get_popup with - * the parent set to NULL, and this request must be invoked before - * committing the popup's initial state. - * - * See the documentation of xdg_popup for more details about what - * an xdg_popup is and how it is used. - */ - void (*get_popup)(struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *popup); - /** - * ack a configure event - * - * When a configure event is received, if a client commits the - * surface in response to the configure event, then the client must - * make an ack_configure request sometime before the commit - * request, passing along the serial of the configure event. - * - * If the client receives multiple configure events before it can - * respond to one, it only has to ack the last configure event. - * - * A client is not required to commit immediately after sending an - * ack_configure request - it may even ack_configure several times - * before its next surface commit. - * - * A client may send multiple ack_configure requests before - * committing, but only the last request sent before a commit - * indicates which configure event the client really is responding - * to. - * @param serial the serial from the configure event - */ - void (*ack_configure)(struct wl_client *client, - struct wl_resource *resource, - uint32_t serial); - /** - * destroy the layer_surface - * - * This request destroys the layer surface. - */ - void (*destroy)(struct wl_client *client, - struct wl_resource *resource); - /** - * change the layer of the surface - * - * Change the layer that the surface is rendered on. - * - * Layer is double-buffered, see wl_surface.commit. - * @param layer layer to move this surface to - * @since 2 - */ - void (*set_layer)(struct wl_client *client, - struct wl_resource *resource, - uint32_t layer); -}; - -#define ZWLR_LAYER_SURFACE_V1_CONFIGURE 0 -#define ZWLR_LAYER_SURFACE_V1_CLOSED 1 - -/** - * @ingroup iface_zwlr_layer_surface_v1 - */ -#define ZWLR_LAYER_SURFACE_V1_CONFIGURE_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_layer_surface_v1 - */ -#define ZWLR_LAYER_SURFACE_V1_CLOSED_SINCE_VERSION 1 - -/** - * @ingroup iface_zwlr_layer_surface_v1 - */ -#define ZWLR_LAYER_SURFACE_V1_SET_SIZE_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_layer_surface_v1 - */ -#define ZWLR_LAYER_SURFACE_V1_SET_ANCHOR_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_layer_surface_v1 - */ -#define ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_layer_surface_v1 - */ -#define ZWLR_LAYER_SURFACE_V1_SET_MARGIN_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_layer_surface_v1 - */ -#define ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_layer_surface_v1 - */ -#define ZWLR_LAYER_SURFACE_V1_GET_POPUP_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_layer_surface_v1 - */ -#define ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_layer_surface_v1 - */ -#define ZWLR_LAYER_SURFACE_V1_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_layer_surface_v1 - */ -#define ZWLR_LAYER_SURFACE_V1_SET_LAYER_SINCE_VERSION 2 - -/** - * @ingroup iface_zwlr_layer_surface_v1 - * Sends an configure event to the client owning the resource. - * @param resource_ The client's resource - */ -static inline void -zwlr_layer_surface_v1_send_configure(struct wl_resource *resource_, uint32_t serial, uint32_t width, uint32_t height) -{ - wl_resource_post_event(resource_, ZWLR_LAYER_SURFACE_V1_CONFIGURE, serial, width, height); -} - -/** - * @ingroup iface_zwlr_layer_surface_v1 - * Sends an closed event to the client owning the resource. - * @param resource_ The client's resource - */ -static inline void -zwlr_layer_surface_v1_send_closed(struct wl_resource *resource_) -{ - wl_resource_post_event(resource_, ZWLR_LAYER_SURFACE_V1_CLOSED); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libqtile/backend/wayland/qw/proto/xdg-shell-protocol.h b/libqtile/backend/wayland/qw/proto/xdg-shell-protocol.h deleted file mode 100644 index 3bd3ce5f1c..0000000000 --- a/libqtile/backend/wayland/qw/proto/xdg-shell-protocol.h +++ /dev/null @@ -1,2327 +0,0 @@ -/* Generated by wayland-scanner 1.23.1 */ - -#ifndef XDG_SHELL_SERVER_PROTOCOL_H -#define XDG_SHELL_SERVER_PROTOCOL_H - -#include -#include -#include "wayland-server.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct wl_client; -struct wl_resource; - -/** - * @page page_xdg_shell The xdg_shell protocol - * @section page_ifaces_xdg_shell Interfaces - * - @subpage page_iface_xdg_wm_base - create desktop-style surfaces - * - @subpage page_iface_xdg_positioner - child surface positioner - * - @subpage page_iface_xdg_surface - desktop user interface surface base interface - * - @subpage page_iface_xdg_toplevel - toplevel surface - * - @subpage page_iface_xdg_popup - short-lived, popup surfaces for menus - * @section page_copyright_xdg_shell Copyright - *
- *
- * Copyright © 2008-2013 Kristian Høgsberg
- * Copyright © 2013      Rafael Antognolli
- * Copyright © 2013      Jasper St. Pierre
- * Copyright © 2010-2013 Intel Corporation
- * Copyright © 2015-2017 Samsung Electronics Co., Ltd
- * Copyright © 2015-2017 Red Hat Inc.
- *
- * 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.
- * 
- */ -struct wl_output; -struct wl_seat; -struct wl_surface; -struct xdg_popup; -struct xdg_positioner; -struct xdg_surface; -struct xdg_toplevel; -struct xdg_wm_base; - -#ifndef XDG_WM_BASE_INTERFACE -#define XDG_WM_BASE_INTERFACE -/** - * @page page_iface_xdg_wm_base xdg_wm_base - * @section page_iface_xdg_wm_base_desc Description - * - * The xdg_wm_base interface is exposed as a global object enabling clients - * to turn their wl_surfaces into windows in a desktop environment. It - * defines the basic functionality needed for clients and the compositor to - * create windows that can be dragged, resized, maximized, etc, as well as - * creating transient windows such as popup menus. - * @section page_iface_xdg_wm_base_api API - * See @ref iface_xdg_wm_base. - */ -/** - * @defgroup iface_xdg_wm_base The xdg_wm_base interface - * - * The xdg_wm_base interface is exposed as a global object enabling clients - * to turn their wl_surfaces into windows in a desktop environment. It - * defines the basic functionality needed for clients and the compositor to - * create windows that can be dragged, resized, maximized, etc, as well as - * creating transient windows such as popup menus. - */ -extern const struct wl_interface xdg_wm_base_interface; -#endif -#ifndef XDG_POSITIONER_INTERFACE -#define XDG_POSITIONER_INTERFACE -/** - * @page page_iface_xdg_positioner xdg_positioner - * @section page_iface_xdg_positioner_desc Description - * - * The xdg_positioner provides a collection of rules for the placement of a - * child surface relative to a parent surface. Rules can be defined to ensure - * the child surface remains within the visible area's borders, and to - * specify how the child surface changes its position, such as sliding along - * an axis, or flipping around a rectangle. These positioner-created rules are - * constrained by the requirement that a child surface must intersect with or - * be at least partially adjacent to its parent surface. - * - * See the various requests for details about possible rules. - * - * At the time of the request, the compositor makes a copy of the rules - * specified by the xdg_positioner. Thus, after the request is complete the - * xdg_positioner object can be destroyed or reused; further changes to the - * object will have no effect on previous usages. - * - * For an xdg_positioner object to be considered complete, it must have a - * non-zero size set by set_size, and a non-zero anchor rectangle set by - * set_anchor_rect. Passing an incomplete xdg_positioner object when - * positioning a surface raises an invalid_positioner error. - * @section page_iface_xdg_positioner_api API - * See @ref iface_xdg_positioner. - */ -/** - * @defgroup iface_xdg_positioner The xdg_positioner interface - * - * The xdg_positioner provides a collection of rules for the placement of a - * child surface relative to a parent surface. Rules can be defined to ensure - * the child surface remains within the visible area's borders, and to - * specify how the child surface changes its position, such as sliding along - * an axis, or flipping around a rectangle. These positioner-created rules are - * constrained by the requirement that a child surface must intersect with or - * be at least partially adjacent to its parent surface. - * - * See the various requests for details about possible rules. - * - * At the time of the request, the compositor makes a copy of the rules - * specified by the xdg_positioner. Thus, after the request is complete the - * xdg_positioner object can be destroyed or reused; further changes to the - * object will have no effect on previous usages. - * - * For an xdg_positioner object to be considered complete, it must have a - * non-zero size set by set_size, and a non-zero anchor rectangle set by - * set_anchor_rect. Passing an incomplete xdg_positioner object when - * positioning a surface raises an invalid_positioner error. - */ -extern const struct wl_interface xdg_positioner_interface; -#endif -#ifndef XDG_SURFACE_INTERFACE -#define XDG_SURFACE_INTERFACE -/** - * @page page_iface_xdg_surface xdg_surface - * @section page_iface_xdg_surface_desc Description - * - * An interface that may be implemented by a wl_surface, for - * implementations that provide a desktop-style user interface. - * - * It provides a base set of functionality required to construct user - * interface elements requiring management by the compositor, such as - * toplevel windows, menus, etc. The types of functionality are split into - * xdg_surface roles. - * - * Creating an xdg_surface does not set the role for a wl_surface. In order - * to map an xdg_surface, the client must create a role-specific object - * using, e.g., get_toplevel, get_popup. The wl_surface for any given - * xdg_surface can have at most one role, and may not be assigned any role - * not based on xdg_surface. - * - * A role must be assigned before any other requests are made to the - * xdg_surface object. - * - * The client must call wl_surface.commit on the corresponding wl_surface - * for the xdg_surface state to take effect. - * - * Creating an xdg_surface from a wl_surface 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_surface.configure call must - * also be treated as errors. - * - * After creating a role-specific object and setting it up (e.g. by sending - * the title, app ID, size constraints, parent, etc), the client must - * perform an initial commit without any buffer attached. The compositor - * will reply with initial wl_surface state such as - * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure - * event. The client must acknowledge it and is then allowed to attach a - * buffer to map the surface. - * - * Mapping an xdg_surface-based role surface is defined as making it - * possible for the surface to be shown by the compositor. Note that - * a mapped surface is not guaranteed to be visible once it is mapped. - * - * For an xdg_surface to be mapped by the compositor, the following - * conditions must be met: - * (1) the client has assigned an xdg_surface-based role to the surface - * (2) the client has set and committed the xdg_surface state and the - * role-dependent state to the surface - * (3) the client has committed a buffer to the surface - * - * A newly-unmapped surface is considered to have met condition (1) out - * of the 3 required conditions for mapping a surface if its role surface - * has not been destroyed, i.e. the client must perform the initial commit - * again before attaching a buffer. - * @section page_iface_xdg_surface_api API - * See @ref iface_xdg_surface. - */ -/** - * @defgroup iface_xdg_surface The xdg_surface interface - * - * An interface that may be implemented by a wl_surface, for - * implementations that provide a desktop-style user interface. - * - * It provides a base set of functionality required to construct user - * interface elements requiring management by the compositor, such as - * toplevel windows, menus, etc. The types of functionality are split into - * xdg_surface roles. - * - * Creating an xdg_surface does not set the role for a wl_surface. In order - * to map an xdg_surface, the client must create a role-specific object - * using, e.g., get_toplevel, get_popup. The wl_surface for any given - * xdg_surface can have at most one role, and may not be assigned any role - * not based on xdg_surface. - * - * A role must be assigned before any other requests are made to the - * xdg_surface object. - * - * The client must call wl_surface.commit on the corresponding wl_surface - * for the xdg_surface state to take effect. - * - * Creating an xdg_surface from a wl_surface 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_surface.configure call must - * also be treated as errors. - * - * After creating a role-specific object and setting it up (e.g. by sending - * the title, app ID, size constraints, parent, etc), the client must - * perform an initial commit without any buffer attached. The compositor - * will reply with initial wl_surface state such as - * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure - * event. The client must acknowledge it and is then allowed to attach a - * buffer to map the surface. - * - * Mapping an xdg_surface-based role surface is defined as making it - * possible for the surface to be shown by the compositor. Note that - * a mapped surface is not guaranteed to be visible once it is mapped. - * - * For an xdg_surface to be mapped by the compositor, the following - * conditions must be met: - * (1) the client has assigned an xdg_surface-based role to the surface - * (2) the client has set and committed the xdg_surface state and the - * role-dependent state to the surface - * (3) the client has committed a buffer to the surface - * - * A newly-unmapped surface is considered to have met condition (1) out - * of the 3 required conditions for mapping a surface if its role surface - * has not been destroyed, i.e. the client must perform the initial commit - * again before attaching a buffer. - */ -extern const struct wl_interface xdg_surface_interface; -#endif -#ifndef XDG_TOPLEVEL_INTERFACE -#define XDG_TOPLEVEL_INTERFACE -/** - * @page page_iface_xdg_toplevel xdg_toplevel - * @section page_iface_xdg_toplevel_desc Description - * - * This interface defines an xdg_surface role which allows a surface to, - * among other things, set window-like properties such as maximize, - * fullscreen, and minimize, set application-specific metadata like title and - * id, and well as trigger user interactive operations such as interactive - * resize and move. - * - * A xdg_toplevel by default is responsible for providing the full intended - * visual representation of the toplevel, which depending on the window - * state, may mean things like a title bar, window controls and drop shadow. - * - * Unmapping an xdg_toplevel means that the surface cannot be shown - * by the compositor until it is explicitly mapped again. - * All active operations (e.g., move, resize) are canceled and all - * attributes (e.g. title, state, stacking, ...) are discarded for - * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to - * the state it had right after xdg_surface.get_toplevel. The client - * can re-map the toplevel by performing a commit without any buffer - * attached, waiting for a configure event and handling it as usual (see - * xdg_surface description). - * - * Attaching a null buffer to a toplevel unmaps the surface. - * @section page_iface_xdg_toplevel_api API - * See @ref iface_xdg_toplevel. - */ -/** - * @defgroup iface_xdg_toplevel The xdg_toplevel interface - * - * This interface defines an xdg_surface role which allows a surface to, - * among other things, set window-like properties such as maximize, - * fullscreen, and minimize, set application-specific metadata like title and - * id, and well as trigger user interactive operations such as interactive - * resize and move. - * - * A xdg_toplevel by default is responsible for providing the full intended - * visual representation of the toplevel, which depending on the window - * state, may mean things like a title bar, window controls and drop shadow. - * - * Unmapping an xdg_toplevel means that the surface cannot be shown - * by the compositor until it is explicitly mapped again. - * All active operations (e.g., move, resize) are canceled and all - * attributes (e.g. title, state, stacking, ...) are discarded for - * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to - * the state it had right after xdg_surface.get_toplevel. The client - * can re-map the toplevel by performing a commit without any buffer - * attached, waiting for a configure event and handling it as usual (see - * xdg_surface description). - * - * Attaching a null buffer to a toplevel unmaps the surface. - */ -extern const struct wl_interface xdg_toplevel_interface; -#endif -#ifndef XDG_POPUP_INTERFACE -#define XDG_POPUP_INTERFACE -/** - * @page page_iface_xdg_popup xdg_popup - * @section page_iface_xdg_popup_desc Description - * - * A popup surface is a short-lived, temporary surface. It can be used to - * implement for example menus, popovers, tooltips and other similar user - * interface concepts. - * - * A popup can be made to take an explicit grab. See xdg_popup.grab for - * details. - * - * When the popup is dismissed, a popup_done event will be sent out, and at - * the same time the surface will be unmapped. See the xdg_popup.popup_done - * event for details. - * - * Explicitly destroying the xdg_popup object will also dismiss the popup and - * unmap the surface. Clients that want to dismiss the popup when another - * surface of their own is clicked should dismiss the popup using the destroy - * request. - * - * A newly created xdg_popup will be stacked on top of all previously created - * xdg_popup surfaces associated with the same xdg_toplevel. - * - * The parent of an xdg_popup must be mapped (see the xdg_surface - * description) before the xdg_popup itself. - * - * The client must call wl_surface.commit on the corresponding wl_surface - * for the xdg_popup state to take effect. - * @section page_iface_xdg_popup_api API - * See @ref iface_xdg_popup. - */ -/** - * @defgroup iface_xdg_popup The xdg_popup interface - * - * A popup surface is a short-lived, temporary surface. It can be used to - * implement for example menus, popovers, tooltips and other similar user - * interface concepts. - * - * A popup can be made to take an explicit grab. See xdg_popup.grab for - * details. - * - * When the popup is dismissed, a popup_done event will be sent out, and at - * the same time the surface will be unmapped. See the xdg_popup.popup_done - * event for details. - * - * Explicitly destroying the xdg_popup object will also dismiss the popup and - * unmap the surface. Clients that want to dismiss the popup when another - * surface of their own is clicked should dismiss the popup using the destroy - * request. - * - * A newly created xdg_popup will be stacked on top of all previously created - * xdg_popup surfaces associated with the same xdg_toplevel. - * - * The parent of an xdg_popup must be mapped (see the xdg_surface - * description) before the xdg_popup itself. - * - * The client must call wl_surface.commit on the corresponding wl_surface - * for the xdg_popup state to take effect. - */ -extern const struct wl_interface xdg_popup_interface; -#endif - -#ifndef XDG_WM_BASE_ERROR_ENUM -#define XDG_WM_BASE_ERROR_ENUM -enum xdg_wm_base_error { - /** - * given wl_surface has another role - */ - XDG_WM_BASE_ERROR_ROLE = 0, - /** - * xdg_wm_base was destroyed before children - */ - XDG_WM_BASE_ERROR_DEFUNCT_SURFACES = 1, - /** - * the client tried to map or destroy a non-topmost popup - */ - XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP = 2, - /** - * the client specified an invalid popup parent surface - */ - XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT = 3, - /** - * the client provided an invalid surface state - */ - XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE = 4, - /** - * the client provided an invalid positioner - */ - XDG_WM_BASE_ERROR_INVALID_POSITIONER = 5, - /** - * the client didn’t respond to a ping event in time - */ - XDG_WM_BASE_ERROR_UNRESPONSIVE = 6, -}; -/** - * @ingroup iface_xdg_wm_base - * Validate a xdg_wm_base error value. - * - * @return true on success, false on error. - * @ref xdg_wm_base_error - */ -static inline bool -xdg_wm_base_error_is_valid(uint32_t value, uint32_t version) { - switch (value) { - case XDG_WM_BASE_ERROR_ROLE: - return version >= 1; - case XDG_WM_BASE_ERROR_DEFUNCT_SURFACES: - return version >= 1; - case XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP: - return version >= 1; - case XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT: - return version >= 1; - case XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE: - return version >= 1; - case XDG_WM_BASE_ERROR_INVALID_POSITIONER: - return version >= 1; - case XDG_WM_BASE_ERROR_UNRESPONSIVE: - return version >= 1; - default: - return false; - } -} -#endif /* XDG_WM_BASE_ERROR_ENUM */ - -/** - * @ingroup iface_xdg_wm_base - * @struct xdg_wm_base_interface - */ -struct xdg_wm_base_interface { - /** - * destroy xdg_wm_base - * - * Destroy this xdg_wm_base object. - * - * Destroying a bound xdg_wm_base object while there are surfaces - * still alive created by this xdg_wm_base object instance is - * illegal and will result in a defunct_surfaces error. - */ - void (*destroy)(struct wl_client *client, - struct wl_resource *resource); - /** - * create a positioner object - * - * Create a positioner object. A positioner object is used to - * position surfaces relative to some parent surface. See the - * interface description and xdg_surface.get_popup for details. - */ - void (*create_positioner)(struct wl_client *client, - struct wl_resource *resource, - uint32_t id); - /** - * create a shell surface from a surface - * - * This creates an xdg_surface for the given surface. While - * xdg_surface itself is not a role, the corresponding surface may - * only be assigned a role extending xdg_surface, such as - * xdg_toplevel or xdg_popup. It is illegal to create an - * xdg_surface for a wl_surface which already has an assigned role - * and this will result in a role error. - * - * This creates an xdg_surface for the given surface. An - * xdg_surface is used as basis to define a role to a given - * surface, such as xdg_toplevel or xdg_popup. It also manages - * functionality shared between xdg_surface based surface roles. - * - * See the documentation of xdg_surface for more details about what - * an xdg_surface is and how it is used. - */ - void (*get_xdg_surface)(struct wl_client *client, - struct wl_resource *resource, - uint32_t id, - struct wl_resource *surface); - /** - * respond to a ping event - * - * A client must respond to a ping event with a pong request or - * the client may be deemed unresponsive. See xdg_wm_base.ping and - * xdg_wm_base.error.unresponsive. - * @param serial serial of the ping event - */ - void (*pong)(struct wl_client *client, - struct wl_resource *resource, - uint32_t serial); -}; - -#define XDG_WM_BASE_PING 0 - -/** - * @ingroup iface_xdg_wm_base - */ -#define XDG_WM_BASE_PING_SINCE_VERSION 1 - -/** - * @ingroup iface_xdg_wm_base - */ -#define XDG_WM_BASE_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_wm_base - */ -#define XDG_WM_BASE_CREATE_POSITIONER_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_wm_base - */ -#define XDG_WM_BASE_GET_XDG_SURFACE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_wm_base - */ -#define XDG_WM_BASE_PONG_SINCE_VERSION 1 - -/** - * @ingroup iface_xdg_wm_base - * Sends an ping event to the client owning the resource. - * @param resource_ The client's resource - * @param serial pass this to the pong request - */ -static inline void -xdg_wm_base_send_ping(struct wl_resource *resource_, uint32_t serial) -{ - wl_resource_post_event(resource_, XDG_WM_BASE_PING, serial); -} - -#ifndef XDG_POSITIONER_ERROR_ENUM -#define XDG_POSITIONER_ERROR_ENUM -enum xdg_positioner_error { - /** - * invalid input provided - */ - XDG_POSITIONER_ERROR_INVALID_INPUT = 0, -}; -/** - * @ingroup iface_xdg_positioner - * Validate a xdg_positioner error value. - * - * @return true on success, false on error. - * @ref xdg_positioner_error - */ -static inline bool -xdg_positioner_error_is_valid(uint32_t value, uint32_t version) { - switch (value) { - case XDG_POSITIONER_ERROR_INVALID_INPUT: - return version >= 1; - default: - return false; - } -} -#endif /* XDG_POSITIONER_ERROR_ENUM */ - -#ifndef XDG_POSITIONER_ANCHOR_ENUM -#define XDG_POSITIONER_ANCHOR_ENUM -enum xdg_positioner_anchor { - XDG_POSITIONER_ANCHOR_NONE = 0, - XDG_POSITIONER_ANCHOR_TOP = 1, - XDG_POSITIONER_ANCHOR_BOTTOM = 2, - XDG_POSITIONER_ANCHOR_LEFT = 3, - XDG_POSITIONER_ANCHOR_RIGHT = 4, - XDG_POSITIONER_ANCHOR_TOP_LEFT = 5, - XDG_POSITIONER_ANCHOR_BOTTOM_LEFT = 6, - XDG_POSITIONER_ANCHOR_TOP_RIGHT = 7, - XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT = 8, -}; -/** - * @ingroup iface_xdg_positioner - * Validate a xdg_positioner anchor value. - * - * @return true on success, false on error. - * @ref xdg_positioner_anchor - */ -static inline bool -xdg_positioner_anchor_is_valid(uint32_t value, uint32_t version) { - switch (value) { - case XDG_POSITIONER_ANCHOR_NONE: - return version >= 1; - case XDG_POSITIONER_ANCHOR_TOP: - return version >= 1; - case XDG_POSITIONER_ANCHOR_BOTTOM: - return version >= 1; - case XDG_POSITIONER_ANCHOR_LEFT: - return version >= 1; - case XDG_POSITIONER_ANCHOR_RIGHT: - return version >= 1; - case XDG_POSITIONER_ANCHOR_TOP_LEFT: - return version >= 1; - case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: - return version >= 1; - case XDG_POSITIONER_ANCHOR_TOP_RIGHT: - return version >= 1; - case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: - return version >= 1; - default: - return false; - } -} -#endif /* XDG_POSITIONER_ANCHOR_ENUM */ - -#ifndef XDG_POSITIONER_GRAVITY_ENUM -#define XDG_POSITIONER_GRAVITY_ENUM -enum xdg_positioner_gravity { - XDG_POSITIONER_GRAVITY_NONE = 0, - XDG_POSITIONER_GRAVITY_TOP = 1, - XDG_POSITIONER_GRAVITY_BOTTOM = 2, - XDG_POSITIONER_GRAVITY_LEFT = 3, - XDG_POSITIONER_GRAVITY_RIGHT = 4, - XDG_POSITIONER_GRAVITY_TOP_LEFT = 5, - XDG_POSITIONER_GRAVITY_BOTTOM_LEFT = 6, - XDG_POSITIONER_GRAVITY_TOP_RIGHT = 7, - XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT = 8, -}; -/** - * @ingroup iface_xdg_positioner - * Validate a xdg_positioner gravity value. - * - * @return true on success, false on error. - * @ref xdg_positioner_gravity - */ -static inline bool -xdg_positioner_gravity_is_valid(uint32_t value, uint32_t version) { - switch (value) { - case XDG_POSITIONER_GRAVITY_NONE: - return version >= 1; - case XDG_POSITIONER_GRAVITY_TOP: - return version >= 1; - case XDG_POSITIONER_GRAVITY_BOTTOM: - return version >= 1; - case XDG_POSITIONER_GRAVITY_LEFT: - return version >= 1; - case XDG_POSITIONER_GRAVITY_RIGHT: - return version >= 1; - case XDG_POSITIONER_GRAVITY_TOP_LEFT: - return version >= 1; - case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT: - return version >= 1; - case XDG_POSITIONER_GRAVITY_TOP_RIGHT: - return version >= 1; - case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT: - return version >= 1; - default: - return false; - } -} -#endif /* XDG_POSITIONER_GRAVITY_ENUM */ - -#ifndef XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM -#define XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM -/** - * @ingroup iface_xdg_positioner - * constraint adjustments - * - * The constraint adjustment value define ways the compositor will adjust - * the position of the surface, if the unadjusted position would result - * in the surface being partly constrained. - * - * Whether a surface is considered 'constrained' is left to the compositor - * to determine. For example, the surface may be partly outside the - * compositor's defined 'work area', thus necessitating the child surface's - * position be adjusted until it is entirely inside the work area. - * - * The adjustments can be combined, according to a defined precedence: 1) - * Flip, 2) Slide, 3) Resize. - */ -enum xdg_positioner_constraint_adjustment { - /** - * don't move the child surface when constrained - * - * Don't alter the surface position even if it is constrained on - * some axis, for example partially outside the edge of an output. - */ - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE = 0, - /** - * move along the x axis until unconstrained - * - * Slide the surface along the x axis until it is no longer - * constrained. - * - * First try to slide towards the direction of the gravity on the x - * axis until either the edge in the opposite direction of the - * gravity is unconstrained or the edge in the direction of the - * gravity is constrained. - * - * Then try to slide towards the opposite direction of the gravity - * on the x axis until either the edge in the direction of the - * gravity is unconstrained or the edge in the opposite direction - * of the gravity is constrained. - */ - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1, - /** - * move along the y axis until unconstrained - * - * Slide the surface along the y axis until it is no longer - * constrained. - * - * First try to slide towards the direction of the gravity on the y - * axis until either the edge in the opposite direction of the - * gravity is unconstrained or the edge in the direction of the - * gravity is constrained. - * - * Then try to slide towards the opposite direction of the gravity - * on the y axis until either the edge in the direction of the - * gravity is unconstrained or the edge in the opposite direction - * of the gravity is constrained. - */ - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2, - /** - * invert the anchor and gravity on the x axis - * - * Invert the anchor and gravity on the x axis if the surface is - * constrained on the x axis. For example, if the left edge of the - * surface is constrained, the gravity is 'left' and the anchor is - * 'left', change the gravity to 'right' and the anchor to 'right'. - * - * If the adjusted position also ends up being constrained, the - * resulting position of the flip_x adjustment will be the one - * before the adjustment. - */ - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X = 4, - /** - * invert the anchor and gravity on the y axis - * - * Invert the anchor and gravity on the y axis if the surface is - * constrained on the y axis. For example, if the bottom edge of - * the surface is constrained, the gravity is 'bottom' and the - * anchor is 'bottom', change the gravity to 'top' and the anchor - * to 'top'. - * - * The adjusted position is calculated given the original anchor - * rectangle and offset, but with the new flipped anchor and - * gravity values. - * - * If the adjusted position also ends up being constrained, the - * resulting position of the flip_y adjustment will be the one - * before the adjustment. - */ - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8, - /** - * horizontally resize the surface - * - * Resize the surface horizontally so that it is completely - * unconstrained. - */ - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16, - /** - * vertically resize the surface - * - * Resize the surface vertically so that it is completely - * unconstrained. - */ - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32, -}; -/** - * @ingroup iface_xdg_positioner - * Validate a xdg_positioner constraint_adjustment value. - * - * @return true on success, false on error. - * @ref xdg_positioner_constraint_adjustment - */ -static inline bool -xdg_positioner_constraint_adjustment_is_valid(uint32_t value, uint32_t version) { - uint32_t valid = 0; - if (version >= 1) - valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE; - if (version >= 1) - valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X; - if (version >= 1) - valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y; - if (version >= 1) - valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X; - if (version >= 1) - valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y; - if (version >= 1) - valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X; - if (version >= 1) - valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y; - return (value & ~valid) == 0; -} -#endif /* XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM */ - -/** - * @ingroup iface_xdg_positioner - * @struct xdg_positioner_interface - */ -struct xdg_positioner_interface { - /** - * destroy the xdg_positioner object - * - * Notify the compositor that the xdg_positioner will no longer - * be used. - */ - void (*destroy)(struct wl_client *client, - struct wl_resource *resource); - /** - * set the size of the to-be positioned rectangle - * - * Set the size of the surface that is to be positioned with the - * positioner object. The size is in surface-local coordinates and - * corresponds to the window geometry. See - * xdg_surface.set_window_geometry. - * - * If a zero or negative size is set the invalid_input error is - * raised. - * @param width width of positioned rectangle - * @param height height of positioned rectangle - */ - void (*set_size)(struct wl_client *client, - struct wl_resource *resource, - int32_t width, - int32_t height); - /** - * set the anchor rectangle within the parent surface - * - * Specify the anchor rectangle within the parent surface that - * the child surface will be placed relative to. The rectangle is - * relative to the window geometry as defined by - * xdg_surface.set_window_geometry of the parent surface. - * - * When the xdg_positioner object is used to position a child - * surface, the anchor rectangle may not extend outside the window - * geometry of the positioned child's parent surface. - * - * If a negative size is set the invalid_input error is raised. - * @param x x position of anchor rectangle - * @param y y position of anchor rectangle - * @param width width of anchor rectangle - * @param height height of anchor rectangle - */ - void (*set_anchor_rect)(struct wl_client *client, - struct wl_resource *resource, - int32_t x, - int32_t y, - int32_t width, - int32_t height); - /** - * set anchor rectangle anchor - * - * Defines the anchor point for the anchor rectangle. The - * specified anchor is used derive an anchor point that the child - * surface will be positioned relative to. If a corner anchor is - * set (e.g. 'top_left' or 'bottom_right'), the anchor point will - * be at the specified corner; otherwise, the derived anchor point - * will be centered on the specified edge, or in the center of the - * anchor rectangle if no edge is specified. - * @param anchor anchor - */ - void (*set_anchor)(struct wl_client *client, - struct wl_resource *resource, - uint32_t anchor); - /** - * set child surface gravity - * - * Defines in what direction a surface should be positioned, - * relative to the anchor point of the parent surface. If a corner - * gravity is specified (e.g. 'bottom_right' or 'top_left'), then - * the child surface will be placed towards the specified gravity; - * otherwise, the child surface will be centered over the anchor - * point on any axis that had no gravity specified. If the gravity - * is not in the ‘gravity’ enum, an invalid_input error is - * raised. - * @param gravity gravity direction - */ - void (*set_gravity)(struct wl_client *client, - struct wl_resource *resource, - uint32_t gravity); - /** - * set the adjustment to be done when constrained - * - * Specify how the window should be positioned if the originally - * intended position caused the surface to be constrained, meaning - * at least partially outside positioning boundaries set by the - * compositor. The adjustment is set by constructing a bitmask - * describing the adjustment to be made when the surface is - * constrained on that axis. - * - * If no bit for one axis is set, the compositor will assume that - * the child surface should not change its position on that axis - * when constrained. - * - * If more than one bit for one axis is set, the order of how - * adjustments are applied is specified in the corresponding - * adjustment descriptions. - * - * The default adjustment is none. - * @param constraint_adjustment bit mask of constraint adjustments - */ - void (*set_constraint_adjustment)(struct wl_client *client, - struct wl_resource *resource, - uint32_t constraint_adjustment); - /** - * set surface position offset - * - * Specify the surface position offset relative to the position - * of the anchor on the anchor rectangle and the anchor on the - * surface. For example if the anchor of the anchor rectangle is at - * (x, y), the surface has the gravity bottom|right, and the offset - * is (ox, oy), the calculated surface position will be (x + ox, y - * + oy). The offset position of the surface is the one used for - * constraint testing. See set_constraint_adjustment. - * - * An example use case is placing a popup menu on top of a user - * interface element, while aligning the user interface element of - * the parent surface with some user interface element placed - * somewhere in the popup surface. - * @param x surface position x offset - * @param y surface position y offset - */ - void (*set_offset)(struct wl_client *client, - struct wl_resource *resource, - int32_t x, - int32_t y); - /** - * continuously reconstrain the surface - * - * When set reactive, the surface is reconstrained if the - * conditions used for constraining changed, e.g. the parent window - * moved. - * - * If the conditions changed and the popup was reconstrained, an - * xdg_popup.configure event is sent with updated geometry, - * followed by an xdg_surface.configure event. - * @since 3 - */ - void (*set_reactive)(struct wl_client *client, - struct wl_resource *resource); - /** - * - * - * Set the parent window geometry the compositor should use when - * positioning the popup. The compositor may use this information - * to determine the future state the popup should be constrained - * using. If this doesn't match the dimension of the parent the - * popup is eventually positioned against, the behavior is - * undefined. - * - * The arguments are given in the surface-local coordinate space. - * @param parent_width future window geometry width of parent - * @param parent_height future window geometry height of parent - * @since 3 - */ - void (*set_parent_size)(struct wl_client *client, - struct wl_resource *resource, - int32_t parent_width, - int32_t parent_height); - /** - * set parent configure this is a response to - * - * Set the serial of an xdg_surface.configure event this - * positioner will be used in response to. The compositor may use - * this information together with set_parent_size to determine what - * future state the popup should be constrained using. - * @param serial serial of parent configure event - * @since 3 - */ - void (*set_parent_configure)(struct wl_client *client, - struct wl_resource *resource, - uint32_t serial); -}; - - -/** - * @ingroup iface_xdg_positioner - */ -#define XDG_POSITIONER_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_positioner - */ -#define XDG_POSITIONER_SET_SIZE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_positioner - */ -#define XDG_POSITIONER_SET_ANCHOR_RECT_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_positioner - */ -#define XDG_POSITIONER_SET_ANCHOR_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_positioner - */ -#define XDG_POSITIONER_SET_GRAVITY_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_positioner - */ -#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_positioner - */ -#define XDG_POSITIONER_SET_OFFSET_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_positioner - */ -#define XDG_POSITIONER_SET_REACTIVE_SINCE_VERSION 3 -/** - * @ingroup iface_xdg_positioner - */ -#define XDG_POSITIONER_SET_PARENT_SIZE_SINCE_VERSION 3 -/** - * @ingroup iface_xdg_positioner - */ -#define XDG_POSITIONER_SET_PARENT_CONFIGURE_SINCE_VERSION 3 - -#ifndef XDG_SURFACE_ERROR_ENUM -#define XDG_SURFACE_ERROR_ENUM -enum xdg_surface_error { - /** - * Surface was not fully constructed - */ - XDG_SURFACE_ERROR_NOT_CONSTRUCTED = 1, - /** - * Surface was already constructed - */ - XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED = 2, - /** - * Attaching a buffer to an unconfigured surface - */ - XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER = 3, - /** - * Invalid serial number when acking a configure event - */ - XDG_SURFACE_ERROR_INVALID_SERIAL = 4, - /** - * Width or height was zero or negative - */ - XDG_SURFACE_ERROR_INVALID_SIZE = 5, - /** - * Surface was destroyed before its role object - */ - XDG_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT = 6, -}; -/** - * @ingroup iface_xdg_surface - * Validate a xdg_surface error value. - * - * @return true on success, false on error. - * @ref xdg_surface_error - */ -static inline bool -xdg_surface_error_is_valid(uint32_t value, uint32_t version) { - switch (value) { - case XDG_SURFACE_ERROR_NOT_CONSTRUCTED: - return version >= 1; - case XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED: - return version >= 1; - case XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER: - return version >= 1; - case XDG_SURFACE_ERROR_INVALID_SERIAL: - return version >= 1; - case XDG_SURFACE_ERROR_INVALID_SIZE: - return version >= 1; - case XDG_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT: - return version >= 1; - default: - return false; - } -} -#endif /* XDG_SURFACE_ERROR_ENUM */ - -/** - * @ingroup iface_xdg_surface - * @struct xdg_surface_interface - */ -struct xdg_surface_interface { - /** - * destroy the xdg_surface - * - * Destroy the xdg_surface object. An xdg_surface must only be - * destroyed after its role object has been destroyed, otherwise a - * defunct_role_object error is raised. - */ - void (*destroy)(struct wl_client *client, - struct wl_resource *resource); - /** - * assign the xdg_toplevel surface role - * - * This creates an xdg_toplevel object for the given xdg_surface - * and gives the associated wl_surface the xdg_toplevel role. - * - * See the documentation of xdg_toplevel for more details about - * what an xdg_toplevel is and how it is used. - */ - void (*get_toplevel)(struct wl_client *client, - struct wl_resource *resource, - uint32_t id); - /** - * assign the xdg_popup surface role - * - * This creates an xdg_popup object for the given xdg_surface and - * gives the associated wl_surface the xdg_popup role. - * - * If null is passed as a parent, a parent surface must be - * specified using some other protocol, before committing the - * initial state. - * - * See the documentation of xdg_popup for more details about what - * an xdg_popup is and how it is used. - */ - void (*get_popup)(struct wl_client *client, - struct wl_resource *resource, - uint32_t id, - struct wl_resource *parent, - struct wl_resource *positioner); - /** - * set the new window geometry - * - * The window geometry of a surface is its "visible bounds" from - * the user's perspective. Client-side decorations often have - * invisible portions like drop-shadows which should be ignored for - * the purposes of aligning, placing and constraining windows. - * - * The window geometry is double-buffered state, see - * wl_surface.commit. - * - * When maintaining a position, the compositor should treat the (x, - * y) coordinate of the window geometry as the top left corner of - * the window. A client changing the (x, y) window geometry - * coordinate should in general not alter the position of the - * window. - * - * Once the window geometry of the surface is set, it is not - * possible to unset it, and it will remain the same until - * set_window_geometry is called again, even if a new subsurface or - * buffer is attached. - * - * If never set, the value is the full bounds of the surface, - * including any subsurfaces. This updates dynamically on every - * commit. This unset is meant for extremely simple clients. - * - * The arguments are given in the surface-local coordinate space of - * the wl_surface associated with this xdg_surface, and may extend - * outside of the wl_surface itself to mark parts of the subsurface - * tree as part of the window geometry. - * - * When applied, the effective window geometry will be the set - * window geometry clamped to the bounding rectangle of the - * combined geometry of the surface of the xdg_surface and the - * associated subsurfaces. - * - * The effective geometry will not be recalculated unless a new - * call to set_window_geometry is done and the new pending surface - * state is subsequently applied. - * - * The width and height of the effective window geometry must be - * greater than zero. Setting an invalid size will raise an - * invalid_size error. - */ - void (*set_window_geometry)(struct wl_client *client, - struct wl_resource *resource, - int32_t x, - int32_t y, - int32_t width, - int32_t height); - /** - * ack a configure event - * - * When a configure event is received, if a client commits the - * surface in response to the configure event, then the client must - * make an ack_configure request sometime before the commit - * request, passing along the serial of the configure event. - * - * For instance, for toplevel surfaces the compositor might use - * this information to move a surface to the top left only when the - * client has drawn itself for the maximized or fullscreen state. - * - * If the client receives multiple configure events before it can - * respond to one, it only has to ack the last configure event. - * Acking a configure event that was never sent raises an - * invalid_serial error. - * - * A client is not required to commit immediately after sending an - * ack_configure request - it may even ack_configure several times - * before its next surface commit. - * - * A client may send multiple ack_configure requests before - * committing, but only the last request sent before a commit - * indicates which configure event the client really is responding - * to. - * - * Sending an ack_configure request consumes the serial number sent - * with the request, as well as serial numbers sent by all - * configure events sent on this xdg_surface prior to the configure - * event referenced by the committed serial. - * - * It is an error to issue multiple ack_configure requests - * referencing a serial from the same configure event, or to issue - * an ack_configure request referencing a serial from a configure - * event issued before the event identified by the last - * ack_configure request for the same xdg_surface. Doing so will - * raise an invalid_serial error. - * @param serial the serial from the configure event - */ - void (*ack_configure)(struct wl_client *client, - struct wl_resource *resource, - uint32_t serial); -}; - -#define XDG_SURFACE_CONFIGURE 0 - -/** - * @ingroup iface_xdg_surface - */ -#define XDG_SURFACE_CONFIGURE_SINCE_VERSION 1 - -/** - * @ingroup iface_xdg_surface - */ -#define XDG_SURFACE_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_surface - */ -#define XDG_SURFACE_GET_TOPLEVEL_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_surface - */ -#define XDG_SURFACE_GET_POPUP_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_surface - */ -#define XDG_SURFACE_SET_WINDOW_GEOMETRY_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_surface - */ -#define XDG_SURFACE_ACK_CONFIGURE_SINCE_VERSION 1 - -/** - * @ingroup iface_xdg_surface - * Sends an configure event to the client owning the resource. - * @param resource_ The client's resource - * @param serial serial of the configure event - */ -static inline void -xdg_surface_send_configure(struct wl_resource *resource_, uint32_t serial) -{ - wl_resource_post_event(resource_, XDG_SURFACE_CONFIGURE, serial); -} - -#ifndef XDG_TOPLEVEL_ERROR_ENUM -#define XDG_TOPLEVEL_ERROR_ENUM -enum xdg_toplevel_error { - /** - * provided value is not a valid variant of the resize_edge enum - */ - XDG_TOPLEVEL_ERROR_INVALID_RESIZE_EDGE = 0, - /** - * invalid parent toplevel - */ - XDG_TOPLEVEL_ERROR_INVALID_PARENT = 1, - /** - * client provided an invalid min or max size - */ - XDG_TOPLEVEL_ERROR_INVALID_SIZE = 2, -}; -/** - * @ingroup iface_xdg_toplevel - * Validate a xdg_toplevel error value. - * - * @return true on success, false on error. - * @ref xdg_toplevel_error - */ -static inline bool -xdg_toplevel_error_is_valid(uint32_t value, uint32_t version) { - switch (value) { - case XDG_TOPLEVEL_ERROR_INVALID_RESIZE_EDGE: - return version >= 1; - case XDG_TOPLEVEL_ERROR_INVALID_PARENT: - return version >= 1; - case XDG_TOPLEVEL_ERROR_INVALID_SIZE: - return version >= 1; - default: - return false; - } -} -#endif /* XDG_TOPLEVEL_ERROR_ENUM */ - -#ifndef XDG_TOPLEVEL_RESIZE_EDGE_ENUM -#define XDG_TOPLEVEL_RESIZE_EDGE_ENUM -/** - * @ingroup iface_xdg_toplevel - * edge values for resizing - * - * These values are used to indicate which edge of a surface - * is being dragged in a resize operation. - */ -enum xdg_toplevel_resize_edge { - XDG_TOPLEVEL_RESIZE_EDGE_NONE = 0, - XDG_TOPLEVEL_RESIZE_EDGE_TOP = 1, - XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM = 2, - XDG_TOPLEVEL_RESIZE_EDGE_LEFT = 4, - XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT = 5, - XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT = 6, - XDG_TOPLEVEL_RESIZE_EDGE_RIGHT = 8, - XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT = 9, - XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT = 10, -}; -/** - * @ingroup iface_xdg_toplevel - * Validate a xdg_toplevel resize_edge value. - * - * @return true on success, false on error. - * @ref xdg_toplevel_resize_edge - */ -static inline bool -xdg_toplevel_resize_edge_is_valid(uint32_t value, uint32_t version) { - switch (value) { - case XDG_TOPLEVEL_RESIZE_EDGE_NONE: - return version >= 1; - case XDG_TOPLEVEL_RESIZE_EDGE_TOP: - return version >= 1; - case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM: - return version >= 1; - case XDG_TOPLEVEL_RESIZE_EDGE_LEFT: - return version >= 1; - case XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT: - return version >= 1; - case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT: - return version >= 1; - case XDG_TOPLEVEL_RESIZE_EDGE_RIGHT: - return version >= 1; - case XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT: - return version >= 1; - case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT: - return version >= 1; - default: - return false; - } -} -#endif /* XDG_TOPLEVEL_RESIZE_EDGE_ENUM */ - -#ifndef XDG_TOPLEVEL_STATE_ENUM -#define XDG_TOPLEVEL_STATE_ENUM -/** - * @ingroup iface_xdg_toplevel - * types of state on the surface - * - * The different state values used on the surface. This is designed for - * state values like maximized, fullscreen. It is paired with the - * configure event to ensure that both the client and the compositor - * setting the state can be synchronized. - * - * States set in this way are double-buffered, see wl_surface.commit. - */ -enum xdg_toplevel_state { - /** - * the surface is maximized - * the surface is maximized - * - * The surface is maximized. The window geometry specified in the - * configure event must be obeyed by the client, or the - * xdg_wm_base.invalid_surface_state error is raised. - * - * The client should draw without shadow or other decoration - * outside of the window geometry. - */ - XDG_TOPLEVEL_STATE_MAXIMIZED = 1, - /** - * the surface is fullscreen - * the surface is fullscreen - * - * The surface is fullscreen. The window geometry specified in - * the configure event is a maximum; the client cannot resize - * beyond it. For a surface to cover the whole fullscreened area, - * the geometry dimensions must be obeyed by the client. For more - * details, see xdg_toplevel.set_fullscreen. - */ - XDG_TOPLEVEL_STATE_FULLSCREEN = 2, - /** - * the surface is being resized - * the surface is being resized - * - * The surface is being resized. The window geometry specified in - * the configure event is a maximum; the client cannot resize - * beyond it. Clients that have aspect ratio or cell sizing - * configuration can use a smaller size, however. - */ - XDG_TOPLEVEL_STATE_RESIZING = 3, - /** - * the surface is now activated - * the surface is now activated - * - * Client window decorations should be painted as if the window - * is active. Do not assume this means that the window actually has - * keyboard or pointer focus. - */ - XDG_TOPLEVEL_STATE_ACTIVATED = 4, - /** - * the surface’s left edge is tiled - * - * The window is currently in a tiled layout and the left edge is - * considered to be adjacent to another part of the tiling grid. - * - * The client should draw without shadow or other decoration - * outside of the window geometry on the left edge. - * @since 2 - */ - XDG_TOPLEVEL_STATE_TILED_LEFT = 5, - /** - * the surface’s right edge is tiled - * - * The window is currently in a tiled layout and the right edge - * is considered to be adjacent to another part of the tiling grid. - * - * The client should draw without shadow or other decoration - * outside of the window geometry on the right edge. - * @since 2 - */ - XDG_TOPLEVEL_STATE_TILED_RIGHT = 6, - /** - * the surface’s top edge is tiled - * - * The window is currently in a tiled layout and the top edge is - * considered to be adjacent to another part of the tiling grid. - * - * The client should draw without shadow or other decoration - * outside of the window geometry on the top edge. - * @since 2 - */ - XDG_TOPLEVEL_STATE_TILED_TOP = 7, - /** - * the surface’s bottom edge is tiled - * - * The window is currently in a tiled layout and the bottom edge - * is considered to be adjacent to another part of the tiling grid. - * - * The client should draw without shadow or other decoration - * outside of the window geometry on the bottom edge. - * @since 2 - */ - XDG_TOPLEVEL_STATE_TILED_BOTTOM = 8, - /** - * surface repaint is suspended - * - * The surface is currently not ordinarily being repainted; for - * example because its content is occluded by another window, or - * its outputs are switched off due to screen locking. - * @since 6 - */ - XDG_TOPLEVEL_STATE_SUSPENDED = 9, - /** - * the surface’s left edge is constrained - * - * The left edge of the window is currently constrained, meaning - * it shouldn't attempt to resize from that edge. It can for - * example mean it's tiled next to a monitor edge on the - * constrained side of the window. - * @since 7 - */ - XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT = 10, - /** - * the surface’s right edge is constrained - * - * The right edge of the window is currently constrained, meaning - * it shouldn't attempt to resize from that edge. It can for - * example mean it's tiled next to a monitor edge on the - * constrained side of the window. - * @since 7 - */ - XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT = 11, - /** - * the surface’s top edge is constrained - * - * The top edge of the window is currently constrained, meaning - * it shouldn't attempt to resize from that edge. It can for - * example mean it's tiled next to a monitor edge on the - * constrained side of the window. - * @since 7 - */ - XDG_TOPLEVEL_STATE_CONSTRAINED_TOP = 12, - /** - * the surface’s bottom edge is tiled - * - * The bottom edge of the window is currently constrained, - * meaning it shouldn't attempt to resize from that edge. It can - * for example mean it's tiled next to a monitor edge on the - * constrained side of the window. - * @since 7 - */ - XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM = 13, -}; -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION 2 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION 2 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_STATE_TILED_TOP_SINCE_VERSION 2 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_STATE_TILED_BOTTOM_SINCE_VERSION 2 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION 6 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT_SINCE_VERSION 7 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT_SINCE_VERSION 7 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_STATE_CONSTRAINED_TOP_SINCE_VERSION 7 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM_SINCE_VERSION 7 -/** - * @ingroup iface_xdg_toplevel - * Validate a xdg_toplevel state value. - * - * @return true on success, false on error. - * @ref xdg_toplevel_state - */ -static inline bool -xdg_toplevel_state_is_valid(uint32_t value, uint32_t version) { - switch (value) { - case XDG_TOPLEVEL_STATE_MAXIMIZED: - return version >= 1; - case XDG_TOPLEVEL_STATE_FULLSCREEN: - return version >= 1; - case XDG_TOPLEVEL_STATE_RESIZING: - return version >= 1; - case XDG_TOPLEVEL_STATE_ACTIVATED: - return version >= 1; - case XDG_TOPLEVEL_STATE_TILED_LEFT: - return version >= 2; - case XDG_TOPLEVEL_STATE_TILED_RIGHT: - return version >= 2; - case XDG_TOPLEVEL_STATE_TILED_TOP: - return version >= 2; - case XDG_TOPLEVEL_STATE_TILED_BOTTOM: - return version >= 2; - case XDG_TOPLEVEL_STATE_SUSPENDED: - return version >= 6; - case XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT: - return version >= 7; - case XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT: - return version >= 7; - case XDG_TOPLEVEL_STATE_CONSTRAINED_TOP: - return version >= 7; - case XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM: - return version >= 7; - default: - return false; - } -} -#endif /* XDG_TOPLEVEL_STATE_ENUM */ - -#ifndef XDG_TOPLEVEL_WM_CAPABILITIES_ENUM -#define XDG_TOPLEVEL_WM_CAPABILITIES_ENUM -enum xdg_toplevel_wm_capabilities { - /** - * show_window_menu is available - */ - XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU = 1, - /** - * set_maximized and unset_maximized are available - */ - XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE = 2, - /** - * set_fullscreen and unset_fullscreen are available - */ - XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN = 3, - /** - * set_minimized is available - */ - XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE = 4, -}; -/** - * @ingroup iface_xdg_toplevel - * Validate a xdg_toplevel wm_capabilities value. - * - * @return true on success, false on error. - * @ref xdg_toplevel_wm_capabilities - */ -static inline bool -xdg_toplevel_wm_capabilities_is_valid(uint32_t value, uint32_t version) { - switch (value) { - case XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU: - return version >= 1; - case XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE: - return version >= 1; - case XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN: - return version >= 1; - case XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE: - return version >= 1; - default: - return false; - } -} -#endif /* XDG_TOPLEVEL_WM_CAPABILITIES_ENUM */ - -/** - * @ingroup iface_xdg_toplevel - * @struct xdg_toplevel_interface - */ -struct xdg_toplevel_interface { - /** - * destroy the xdg_toplevel - * - * This request destroys the role surface and unmaps the surface; - * see "Unmapping" behavior in interface section for details. - */ - void (*destroy)(struct wl_client *client, - struct wl_resource *resource); - /** - * set the parent of this surface - * - * Set the "parent" of this surface. This surface should be - * stacked above the parent surface and all other ancestor - * surfaces. - * - * Parent surfaces should be set on dialogs, toolboxes, or other - * "auxiliary" surfaces, so that the parent is raised when the - * dialog is raised. - * - * Setting a null parent for a child surface unsets its parent. - * Setting a null parent for a surface which currently has no - * parent is a no-op. - * - * Only mapped surfaces can have child surfaces. Setting a parent - * which is not mapped is equivalent to setting a null parent. If a - * surface becomes unmapped, its children's parent is set to the - * parent of the now-unmapped surface. If the now-unmapped surface - * has no parent, its children's parent is unset. If the - * now-unmapped surface becomes mapped again, its parent-child - * relationship is not restored. - * - * The parent toplevel must not be one of the child toplevel's - * descendants, and the parent must be different from the child - * toplevel, otherwise the invalid_parent protocol error is raised. - */ - void (*set_parent)(struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *parent); - /** - * set surface title - * - * Set a short title for the surface. - * - * This string may be used to identify the surface in a task bar, - * window list, or other user interface elements provided by the - * compositor. - * - * The string must be encoded in UTF-8. - */ - void (*set_title)(struct wl_client *client, - struct wl_resource *resource, - const char *title); - /** - * set application ID - * - * Set an application identifier for the surface. - * - * The app ID identifies the general class of applications to which - * the surface belongs. The compositor can use this to group - * multiple surfaces together, or to determine how to launch a new - * application. - * - * For D-Bus activatable applications, the app ID is used as the - * D-Bus service name. - * - * The compositor shell will try to group application surfaces - * together by their app ID. As a best practice, it is suggested to - * select app ID's that match the basename of the application's - * .desktop file. For example, "org.freedesktop.FooViewer" where - * the .desktop file is "org.freedesktop.FooViewer.desktop". - * - * Like other properties, a set_app_id request can be sent after - * the xdg_toplevel has been mapped to update the property. - * - * See the desktop-entry specification [0] for more details on - * application identifiers and how they relate to well-known D-Bus - * names and .desktop files. - * - * [0] https://standards.freedesktop.org/desktop-entry-spec/ - */ - void (*set_app_id)(struct wl_client *client, - struct wl_resource *resource, - const char *app_id); - /** - * show the window menu - * - * Clients implementing client-side decorations might want to - * show a context menu when right-clicking on the decorations, - * giving the user a menu that they can use to maximize or minimize - * the window. - * - * This request asks the compositor to pop up such a window menu at - * the given position, relative to the local surface coordinates of - * the parent surface. There are no guarantees as to what menu - * items the window menu contains, or even if a window menu will be - * drawn at all. - * - * This request must be used in response to some sort of user - * action like a button press, key press, or touch down event. - * @param seat the wl_seat of the user event - * @param serial the serial of the user event - * @param x the x position to pop up the window menu at - * @param y the y position to pop up the window menu at - */ - void (*show_window_menu)(struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *seat, - uint32_t serial, - int32_t x, - int32_t y); - /** - * start an interactive move - * - * Start an interactive, user-driven move of the surface. - * - * This request must be used in response to some sort of user - * action like a button press, key press, or touch down event. The - * passed serial is used to determine the type of interactive move - * (touch, pointer, etc). - * - * The server may ignore move requests depending on the state of - * the surface (e.g. fullscreen or maximized), or if the passed - * serial is no longer valid. - * - * If triggered, the surface will lose the focus of the device - * (wl_pointer, wl_touch, etc) used for the move. It is up to the - * compositor to visually indicate that the move is taking place, - * such as updating a pointer cursor, during the move. There is no - * guarantee that the device focus will return when the move is - * completed. - * @param seat the wl_seat of the user event - * @param serial the serial of the user event - */ - void (*move)(struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *seat, - uint32_t serial); - /** - * start an interactive resize - * - * Start a user-driven, interactive resize of the surface. - * - * This request must be used in response to some sort of user - * action like a button press, key press, or touch down event. The - * passed serial is used to determine the type of interactive - * resize (touch, pointer, etc). - * - * The server may ignore resize requests depending on the state of - * the surface (e.g. fullscreen or maximized). - * - * If triggered, the client will receive configure events with the - * "resize" state enum value and the expected sizes. See the - * "resize" enum value for more details about what is required. The - * client must also acknowledge configure events using - * "ack_configure". After the resize is completed, the client will - * receive another "configure" event without the resize state. - * - * If triggered, the surface also will lose the focus of the device - * (wl_pointer, wl_touch, etc) used for the resize. It is up to the - * compositor to visually indicate that the resize is taking place, - * such as updating a pointer cursor, during the resize. There is - * no guarantee that the device focus will return when the resize - * is completed. - * - * The edges parameter specifies how the surface should be resized, - * and is one of the values of the resize_edge enum. Values not - * matching a variant of the enum will cause the - * invalid_resize_edge protocol error. The compositor may use this - * information to update the surface position for example when - * dragging the top left corner. The compositor may also use this - * information to adapt its behavior, e.g. choose an appropriate - * cursor image. - * @param seat the wl_seat of the user event - * @param serial the serial of the user event - * @param edges which edge or corner is being dragged - */ - void (*resize)(struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *seat, - uint32_t serial, - uint32_t edges); - /** - * set the maximum size - * - * Set a maximum size for the window. - * - * The client can specify a maximum size so that the compositor - * does not try to configure the window beyond this size. - * - * The width and height arguments are in window geometry - * coordinates. See xdg_surface.set_window_geometry. - * - * Values set in this way are double-buffered, see - * wl_surface.commit. - * - * The compositor can use this information to allow or disallow - * different states like maximize or fullscreen and draw accurate - * animations. - * - * Similarly, a tiling window manager may use this information to - * place and resize client windows in a more effective way. - * - * The client should not rely on the compositor to obey the maximum - * size. The compositor may decide to ignore the values set by the - * client and request a larger size. - * - * If never set, or a value of zero in the request, means that the - * client has no expected maximum size in the given dimension. As a - * result, a client wishing to reset the maximum size to an - * unspecified state can use zero for width and height in the - * request. - * - * Requesting a maximum size to be smaller than the minimum size of - * a surface is illegal and will result in an invalid_size error. - * - * The width and height must be greater than or equal to zero. - * Using strictly negative values for width or height will result - * in a invalid_size error. - */ - void (*set_max_size)(struct wl_client *client, - struct wl_resource *resource, - int32_t width, - int32_t height); - /** - * set the minimum size - * - * Set a minimum size for the window. - * - * The client can specify a minimum size so that the compositor - * does not try to configure the window below this size. - * - * The width and height arguments are in window geometry - * coordinates. See xdg_surface.set_window_geometry. - * - * Values set in this way are double-buffered, see - * wl_surface.commit. - * - * The compositor can use this information to allow or disallow - * different states like maximize or fullscreen and draw accurate - * animations. - * - * Similarly, a tiling window manager may use this information to - * place and resize client windows in a more effective way. - * - * The client should not rely on the compositor to obey the minimum - * size. The compositor may decide to ignore the values set by the - * client and request a smaller size. - * - * If never set, or a value of zero in the request, means that the - * client has no expected minimum size in the given dimension. As a - * result, a client wishing to reset the minimum size to an - * unspecified state can use zero for width and height in the - * request. - * - * Requesting a minimum size to be larger than the maximum size of - * a surface is illegal and will result in an invalid_size error. - * - * The width and height must be greater than or equal to zero. - * Using strictly negative values for width and height will result - * in a invalid_size error. - */ - void (*set_min_size)(struct wl_client *client, - struct wl_resource *resource, - int32_t width, - int32_t height); - /** - * maximize the window - * - * Maximize the surface. - * - * After requesting that the surface should be maximized, the - * compositor will respond by emitting a configure event. Whether - * this configure actually sets the window maximized is subject to - * compositor policies. The client must then update its content, - * drawing in the configured state. The client must also - * acknowledge the configure when committing the new content (see - * ack_configure). - * - * It is up to the compositor to decide how and where to maximize - * the surface, for example which output and what region of the - * screen should be used. - * - * If the surface was already maximized, the compositor will still - * emit a configure event with the "maximized" state. - * - * If the surface is in a fullscreen state, this request has no - * direct effect. It may alter the state the surface is returned to - * when unmaximized unless overridden by the compositor. - */ - void (*set_maximized)(struct wl_client *client, - struct wl_resource *resource); - /** - * unmaximize the window - * - * Unmaximize the surface. - * - * After requesting that the surface should be unmaximized, the - * compositor will respond by emitting a configure event. Whether - * this actually un-maximizes the window is subject to compositor - * policies. If available and applicable, the compositor will - * include the window geometry dimensions the window had prior to - * being maximized in the configure event. The client must then - * update its content, drawing it in the configured state. The - * client must also acknowledge the configure when committing the - * new content (see ack_configure). - * - * It is up to the compositor to position the surface after it was - * unmaximized; usually the position the surface had before - * maximizing, if applicable. - * - * If the surface was already not maximized, the compositor will - * still emit a configure event without the "maximized" state. - * - * If the surface is in a fullscreen state, this request has no - * direct effect. It may alter the state the surface is returned to - * when unmaximized unless overridden by the compositor. - */ - void (*unset_maximized)(struct wl_client *client, - struct wl_resource *resource); - /** - * set the window as fullscreen on an output - * - * Make the surface fullscreen. - * - * After requesting that the surface should be fullscreened, the - * compositor will respond by emitting a configure event. Whether - * the client is actually put into a fullscreen state is subject to - * compositor policies. The client must also acknowledge the - * configure when committing the new content (see ack_configure). - * - * The output passed by the request indicates the client's - * preference as to which display it should be set fullscreen on. - * If this value is NULL, it's up to the compositor to choose which - * display will be used to map this surface. - * - * If the surface doesn't cover the whole output, the compositor - * will position the surface in the center of the output and - * compensate with with border fill covering the rest of the - * output. The content of the border fill is undefined, but should - * be assumed to be in some way that attempts to blend into the - * surrounding area (e.g. solid black). - * - * If the fullscreened surface is not opaque, the compositor must - * make sure that other screen content not part of the same surface - * tree (made up of subsurfaces, popups or similarly coupled - * surfaces) are not visible below the fullscreened surface. - */ - void (*set_fullscreen)(struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *output); - /** - * unset the window as fullscreen - * - * Make the surface no longer fullscreen. - * - * After requesting that the surface should be unfullscreened, the - * compositor will respond by emitting a configure event. Whether - * this actually removes the fullscreen state of the client is - * subject to compositor policies. - * - * Making a surface unfullscreen sets states for the surface based - * on the following: * the state(s) it may have had before becoming - * fullscreen * any state(s) decided by the compositor * any - * state(s) requested by the client while the surface was - * fullscreen - * - * The compositor may include the previous window geometry - * dimensions in the configure event, if applicable. - * - * The client must also acknowledge the configure when committing - * the new content (see ack_configure). - */ - void (*unset_fullscreen)(struct wl_client *client, - struct wl_resource *resource); - /** - * set the window as minimized - * - * Request that the compositor minimize your surface. There is no - * way to know if the surface is currently minimized, nor is there - * any way to unset minimization on this surface. - * - * If you are looking to throttle redrawing when minimized, please - * instead use the wl_surface.frame event for this, as this will - * also work with live previews on windows in Alt-Tab, Expose or - * similar compositor features. - */ - void (*set_minimized)(struct wl_client *client, - struct wl_resource *resource); -}; - -#define XDG_TOPLEVEL_CONFIGURE 0 -#define XDG_TOPLEVEL_CLOSE 1 -#define XDG_TOPLEVEL_CONFIGURE_BOUNDS 2 -#define XDG_TOPLEVEL_WM_CAPABILITIES 3 - -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_CONFIGURE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_CLOSE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION 4 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION 5 - -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_SET_PARENT_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_SET_TITLE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_SET_APP_ID_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_SHOW_WINDOW_MENU_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_MOVE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_RESIZE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_SET_MAX_SIZE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_SET_MIN_SIZE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_SET_MAXIMIZED_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_UNSET_MAXIMIZED_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_SET_FULLSCREEN_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_UNSET_FULLSCREEN_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_toplevel - */ -#define XDG_TOPLEVEL_SET_MINIMIZED_SINCE_VERSION 1 - -/** - * @ingroup iface_xdg_toplevel - * Sends an configure event to the client owning the resource. - * @param resource_ The client's resource - */ -static inline void -xdg_toplevel_send_configure(struct wl_resource *resource_, int32_t width, int32_t height, struct wl_array *states) -{ - wl_resource_post_event(resource_, XDG_TOPLEVEL_CONFIGURE, width, height, states); -} - -/** - * @ingroup iface_xdg_toplevel - * Sends an close event to the client owning the resource. - * @param resource_ The client's resource - */ -static inline void -xdg_toplevel_send_close(struct wl_resource *resource_) -{ - wl_resource_post_event(resource_, XDG_TOPLEVEL_CLOSE); -} - -/** - * @ingroup iface_xdg_toplevel - * Sends an configure_bounds event to the client owning the resource. - * @param resource_ The client's resource - */ -static inline void -xdg_toplevel_send_configure_bounds(struct wl_resource *resource_, int32_t width, int32_t height) -{ - wl_resource_post_event(resource_, XDG_TOPLEVEL_CONFIGURE_BOUNDS, width, height); -} - -/** - * @ingroup iface_xdg_toplevel - * Sends an wm_capabilities event to the client owning the resource. - * @param resource_ The client's resource - * @param capabilities array of 32-bit capabilities - */ -static inline void -xdg_toplevel_send_wm_capabilities(struct wl_resource *resource_, struct wl_array *capabilities) -{ - wl_resource_post_event(resource_, XDG_TOPLEVEL_WM_CAPABILITIES, capabilities); -} - -#ifndef XDG_POPUP_ERROR_ENUM -#define XDG_POPUP_ERROR_ENUM -enum xdg_popup_error { - /** - * tried to grab after being mapped - */ - XDG_POPUP_ERROR_INVALID_GRAB = 0, -}; -/** - * @ingroup iface_xdg_popup - * Validate a xdg_popup error value. - * - * @return true on success, false on error. - * @ref xdg_popup_error - */ -static inline bool -xdg_popup_error_is_valid(uint32_t value, uint32_t version) { - switch (value) { - case XDG_POPUP_ERROR_INVALID_GRAB: - return version >= 1; - default: - return false; - } -} -#endif /* XDG_POPUP_ERROR_ENUM */ - -/** - * @ingroup iface_xdg_popup - * @struct xdg_popup_interface - */ -struct xdg_popup_interface { - /** - * remove xdg_popup interface - * - * This destroys the popup. Explicitly destroying the xdg_popup - * object will also dismiss the popup, and unmap the surface. - * - * If this xdg_popup is not the "topmost" popup, the - * xdg_wm_base.not_the_topmost_popup protocol error will be sent. - */ - void (*destroy)(struct wl_client *client, - struct wl_resource *resource); - /** - * make the popup take an explicit grab - * - * This request makes the created popup take an explicit grab. An - * explicit grab will be dismissed when the user dismisses the - * popup, or when the client destroys the xdg_popup. This can be - * done by the user clicking outside the surface, using the - * keyboard, or even locking the screen through closing the lid or - * a timeout. - * - * If the compositor denies the grab, the popup will be immediately - * dismissed. - * - * This request must be used in response to some sort of user - * action like a button press, key press, or touch down event. The - * serial number of the event should be passed as 'serial'. - * - * The parent of a grabbing popup must either be an xdg_toplevel - * surface or another xdg_popup with an explicit grab. If the - * parent is another xdg_popup it means that the popups are nested, - * with this popup now being the topmost popup. - * - * Nested popups must be destroyed in the reverse order they were - * created in, e.g. the only popup you are allowed to destroy at - * all times is the topmost one. - * - * When compositors choose to dismiss a popup, they may dismiss - * every nested grabbing popup as well. When a compositor dismisses - * popups, it will follow the same dismissing order as required - * from the client. - * - * If the topmost grabbing popup is destroyed, the grab will be - * returned to the parent of the popup, if that parent previously - * had an explicit grab. - * - * If the parent is a grabbing popup which has already been - * dismissed, this popup will be immediately dismissed. If the - * parent is a popup that did not take an explicit grab, an error - * will be raised. - * - * During a popup grab, the client owning the grab will receive - * pointer and touch events for all their surfaces as normal - * (similar to an "owner-events" grab in X11 parlance), while the - * top most grabbing popup will always have keyboard focus. - * @param seat the wl_seat of the user event - * @param serial the serial of the user event - */ - void (*grab)(struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *seat, - uint32_t serial); - /** - * recalculate the popup's location - * - * Reposition an already-mapped popup. The popup will be placed - * given the details in the passed xdg_positioner object, and a - * xdg_popup.repositioned followed by xdg_popup.configure and - * xdg_surface.configure will be emitted in response. Any - * parameters set by the previous positioner will be discarded. - * - * The passed token will be sent in the corresponding - * xdg_popup.repositioned event. The new popup position will not - * take effect until the corresponding configure event is - * acknowledged by the client. See xdg_popup.repositioned for - * details. The token itself is opaque, and has no other special - * meaning. - * - * If multiple reposition requests are sent, the compositor may - * skip all but the last one. - * - * If the popup is repositioned in response to a configure event - * for its parent, the client should send an - * xdg_positioner.set_parent_configure and possibly an - * xdg_positioner.set_parent_size request to allow the compositor - * to properly constrain the popup. - * - * If the popup is repositioned together with a parent that is - * being resized, but not in response to a configure event, the - * client should send an xdg_positioner.set_parent_size request. - * @param token reposition request token - * @since 3 - */ - void (*reposition)(struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *positioner, - uint32_t token); -}; - -#define XDG_POPUP_CONFIGURE 0 -#define XDG_POPUP_POPUP_DONE 1 -#define XDG_POPUP_REPOSITIONED 2 - -/** - * @ingroup iface_xdg_popup - */ -#define XDG_POPUP_CONFIGURE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_popup - */ -#define XDG_POPUP_POPUP_DONE_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_popup - */ -#define XDG_POPUP_REPOSITIONED_SINCE_VERSION 3 - -/** - * @ingroup iface_xdg_popup - */ -#define XDG_POPUP_DESTROY_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_popup - */ -#define XDG_POPUP_GRAB_SINCE_VERSION 1 -/** - * @ingroup iface_xdg_popup - */ -#define XDG_POPUP_REPOSITION_SINCE_VERSION 3 - -/** - * @ingroup iface_xdg_popup - * Sends an configure event to the client owning the resource. - * @param resource_ The client's resource - * @param x x position relative to parent surface window geometry - * @param y y position relative to parent surface window geometry - * @param width window geometry width - * @param height window geometry height - */ -static inline void -xdg_popup_send_configure(struct wl_resource *resource_, int32_t x, int32_t y, int32_t width, int32_t height) -{ - wl_resource_post_event(resource_, XDG_POPUP_CONFIGURE, x, y, width, height); -} - -/** - * @ingroup iface_xdg_popup - * Sends an popup_done event to the client owning the resource. - * @param resource_ The client's resource - */ -static inline void -xdg_popup_send_popup_done(struct wl_resource *resource_) -{ - wl_resource_post_event(resource_, XDG_POPUP_POPUP_DONE); -} - -/** - * @ingroup iface_xdg_popup - * Sends an repositioned event to the client owning the resource. - * @param resource_ The client's resource - * @param token reposition request token - */ -static inline void -xdg_popup_send_repositioned(struct wl_resource *resource_, uint32_t token) -{ - wl_resource_post_event(resource_, XDG_POPUP_REPOSITIONED, token); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libqtile/backend/x11/zmanager.py b/libqtile/backend/x11/zmanager.py index a20ba8eec7..f3b92d9c61 100644 --- a/libqtile/backend/x11/zmanager.py +++ b/libqtile/backend/x11/zmanager.py @@ -81,7 +81,6 @@ def remove_window(self, window) -> None: def move_up(self, window) -> StackInfo | None: layer, cur_idx = self.layer_map[window] visible = [w for w in self.layers[layer] if w.is_visible() and w.group in (window.group, None)] - print(layer, visible) idx = visible.index(window) if idx < (len(visible) - 1): dest_idx = self.layers[layer].index(visible[idx + 1]) @@ -131,7 +130,6 @@ def move_window_to_layer(self, window, new_layer, position="top") -> StackInfo | return self.layers[old_layer].remove(window) - print(window, position) if position == "bottom": self.layers[new_layer].insert(0, window) else: From 8bf14b2bd2c9ac21f50aaf65b7f67d0ab65ca77f Mon Sep 17 00:00:00 2001 From: elParaguayo Date: Wed, 30 Jul 2025 07:11:23 +0100 Subject: [PATCH 07/14] Updates --- libqtile/backend/base/zmanager.py | 36 ++++++++++---------- libqtile/backend/wayland/zmanager.py | 51 ++++++++++++++++++++++++++++ libqtile/backend/x11/zmanager.py | 18 +++++++++- 3 files changed, 85 insertions(+), 20 deletions(-) create mode 100644 libqtile/backend/wayland/zmanager.py diff --git a/libqtile/backend/base/zmanager.py b/libqtile/backend/base/zmanager.py index a195e6dd34..e2b674f006 100644 --- a/libqtile/backend/base/zmanager.py +++ b/libqtile/backend/base/zmanager.py @@ -64,49 +64,47 @@ def _wrapper(self, window, *args, **kwargs): class ZManager: + """ + Base class for maintaining and manipulating information regarding the + window stack. + """ def __init__(self, core) -> None: self.core = core @abstractmethod def is_stacked(self, window: _Window) -> bool: - pass + """Check if window is currently in the stack.""" @abstractmethod def add_window(self, window: _Window, layer: LayerGroup = LayerGroup.LAYOUT, position="top") -> None: - pass + """ + Add window to the stack. + + Window can request specific layer group and be placed at "top" or "bottom" of + the group. + """ @abstractmethod def remove_window(self, window) -> None: + """Remove window from stack information.""" pass @abstractmethod def move_up(self, window) -> StackInfo | None: - pass + """Move window up in the stack (in its layer group).""" @abstractmethod def move_down(self, window) -> StackInfo | None: - pass + """Move window down in the stack (in its layer group).""" @abstractmethod def move_to_top(self, window) -> StackInfo | None: - pass + """Move window to top of stack (in its layer group).""" @abstractmethod def move_to_bottom(self, window) -> StackInfo | None: - pass + """Move window to bottom of stack (in its layer group).""" @abstractmethod def move_window_to_layer(self, window, new_layer, position="top") -> StackInfo | None: - pass - - # @check_window - # def keep_above(self, window) -> StackInfo | None: - # return self.move_window_to_layer(window, LayerGroup.KEEP_ABOVE) - - # @check_window - # def keep_below(self, window) -> StackInfo | None: - # return self.move_window_to_layer(window, LayerGroup.KEEP_BELOW) - - # @check_window - # def bring_to_front(self, window) -> StackInfo | None: - # return self.move_window_to_layer(window, LayerGroup.BRING_TO_FRONT) + """Move window to a new layer group.""" diff --git a/libqtile/backend/wayland/zmanager.py b/libqtile/backend/wayland/zmanager.py new file mode 100644 index 0000000000..dac0cd7fa9 --- /dev/null +++ b/libqtile/backend/wayland/zmanager.py @@ -0,0 +1,51 @@ +# Copyright (c) 2025 elParaguayo +# +# 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 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. +from libqtile.backend.base import zmanager +from libqtile.backend.base.window import _Window +from libqtile.backend.base.zmanager import LayerGroup, StackInfo + + +class ZManager(zmanager.ZManager): + def __init__(self, core) -> None: + super().__init__(c0re) + + def is_stacked(self, window: _Window) -> bool: + pass + + def add_window(self, window: _Window, layer: LayerGroup = LayerGroup.LAYOUT, position="top") -> None: + pass + + def remove_window(self, window) -> None: + pass + + def move_up(self, window) -> StackInfo | None: + pass + + def move_down(self, window) -> StackInfo | None: + pass + + def move_to_top(self, window) -> StackInfo | None: + pass + + def move_to_bottom(self, window) -> StackInfo | None: + pass + + def move_window_to_layer(self, window, new_layer, position="top") -> StackInfo | None: + pass diff --git a/libqtile/backend/x11/zmanager.py b/libqtile/backend/x11/zmanager.py index f3b92d9c61..3e03d33bdb 100644 --- a/libqtile/backend/x11/zmanager.py +++ b/libqtile/backend/x11/zmanager.py @@ -17,6 +17,7 @@ # 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. +from libqtile import hook from libqtile.backend.base import zmanager from libqtile.backend.base.window import _Window from libqtile.backend.base.zmanager import LayerGroup, StackInfo, check_window @@ -29,6 +30,7 @@ def __init__(self, core) -> None: super().__init__(core) self.layers: dict[LayerGroup, list[_Window]] = {l: [] for l in LayerGroup} self.layer_map: dict[_Window, tuple(LayerGroup, int)] = {} + hook.subscribe.client_focus(self._restack_on_focus_change) def is_stacked(self, window: _Window) -> bool: return window in self.layer_map @@ -151,8 +153,22 @@ def _reindex_layer(self, layer) -> None: for idx, win in enumerate(self.layers[layer]): self.layer_map[win] = (layer, idx) + def _restack_on_focus_change(self, window): + """ + FULLSCREEN and BRING_TO_FRONT are temporary priority layers when window + is focused. + + If windows lose focus they should be restacked. + """ + for layer in (LayerGroup.FULLSCREEN, LayerGroup.BRING_TO_FRONT): + clients = self.layers[layer] + for client in clients: + if client != window: + client.change_layer() + def update_client_lists(self): - """Updates the _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING properties + """ + Updates the _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING properties This is needed for third party tasklists and drag and drop of tabs in chrome From ca8c463443eb1df217f2fc97e9a3b08908c1df6c Mon Sep 17 00:00:00 2001 From: elParaguayo Date: Wed, 30 Jul 2025 20:06:14 +0100 Subject: [PATCH 08/14] Fix last test --- libqtile/backend/base/zmanager.py | 3 +++ libqtile/backend/x11/core.py | 5 +++++ libqtile/backend/x11/window.py | 2 +- libqtile/backend/x11/zmanager.py | 23 +++++++++++++++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/libqtile/backend/base/zmanager.py b/libqtile/backend/base/zmanager.py index e2b674f006..199f4b78a7 100644 --- a/libqtile/backend/base/zmanager.py +++ b/libqtile/backend/base/zmanager.py @@ -108,3 +108,6 @@ def move_to_bottom(self, window) -> StackInfo | None: @abstractmethod def move_window_to_layer(self, window, new_layer, position="top") -> StackInfo | None: """Move window to a new layer group.""" + + def show_stacking_order(self): + """Dump a visualisation of the stacking order to the log.""" \ No newline at end of file diff --git a/libqtile/backend/x11/core.py b/libqtile/backend/x11/core.py index 70d4055f31..8819038eae 100644 --- a/libqtile/backend/x11/core.py +++ b/libqtile/backend/x11/core.py @@ -39,6 +39,7 @@ from libqtile.backend.x11 import window, xcbq from libqtile.backend.x11.xkeysyms import keysyms from libqtile.backend.x11.zmanager import ZManager +from libqtile.command.base import expose_command from libqtile.config import ScreenRect from libqtile.log_utils import logger from libqtile.utils import QtileError @@ -943,3 +944,7 @@ def check_stacking(self, win: base.Window) -> None: def hovered_window(self) -> base.WindowType | None: _hovered_window = self.conn.conn.core.QueryPointer(self._root.wid).reply().child return self.qtile.windows_map.get(_hovered_window) + + @expose_command + def show_stacking_order(self): + self.zmanager.show_stacking_order() diff --git a/libqtile/backend/x11/window.py b/libqtile/backend/x11/window.py index 6c02c99265..5c765ab7e1 100644 --- a/libqtile/backend/x11/window.py +++ b/libqtile/backend/x11/window.py @@ -1692,7 +1692,7 @@ def static( self.group.remove(self) s = Static(self.window, self.qtile, screen, x, y, width, height) self.qtile.windows_map[self.window.wid] = s - self.qtile.core.update_client_lists() + self.qtile.core.zmanager.replace_window(self, s) hook.fire("client_managed", s) def tweak_float(self, x=None, y=None, dx=0, dy=0, w=None, h=None, dw=0, dh=0): diff --git a/libqtile/backend/x11/zmanager.py b/libqtile/backend/x11/zmanager.py index 3e03d33bdb..1dce42fd6b 100644 --- a/libqtile/backend/x11/zmanager.py +++ b/libqtile/backend/x11/zmanager.py @@ -79,6 +79,16 @@ def remove_window(self, window) -> None: self.layers[layer].remove(window) self._reindex_layer(layer) + @check_window + def replace_window(self, old_window, new_window) -> None: + layer, idx = self.layer_map[old_window] + del self.layer_map[old_window] + self.layer_map[new_window] = (layer, idx) + + assert self.layers[layer][idx] == old_window + self.layers[layer][idx] = new_window + self.update_client_lists() + @check_window def move_up(self, window) -> StackInfo | None: layer, cur_idx = self.layer_map[window] @@ -180,3 +190,16 @@ def update_client_lists(self): self.core._root.set_property("_NET_CLIENT_LIST", wids) self.core._root.set_property("_NET_CLIENT_LIST_STACKING", [win.wid for win in z_order]) + + def show_stacking_order(self): + lines = [] + + for layer in LayerGroup: + clients = self.layers[layer] + if not clients: + continue + lines.append(f"LayerGroup {layer.name}") + for client in clients: + lines.append(f"- {client} (Group: {client.group.name if client.group else "None"})") + if lines: + logger.warning("\n".join(lines)) From 3a76333d32c5018785ddfb5b563a8240209b3562 Mon Sep 17 00:00:00 2001 From: elParaguayo Date: Wed, 30 Jul 2025 20:21:59 +0100 Subject: [PATCH 09/14] Fix more tests --- libqtile/backend/base/zmanager.py | 13 ++++++++----- libqtile/backend/wayland/core.py | 2 ++ libqtile/backend/wayland/zmanager.py | 2 +- libqtile/backend/x11/window.py | 12 +++++++----- libqtile/backend/x11/zmanager.py | 22 +++++++++++++++------- 5 files changed, 33 insertions(+), 18 deletions(-) diff --git a/libqtile/backend/base/zmanager.py b/libqtile/backend/base/zmanager.py index 199f4b78a7..fc30427f33 100644 --- a/libqtile/backend/base/zmanager.py +++ b/libqtile/backend/base/zmanager.py @@ -17,7 +17,7 @@ # 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. -from abc import ABC, abstractmethod +from abc import abstractmethod from dataclasses import dataclass from enum import IntEnum from functools import wraps @@ -54,6 +54,7 @@ def check_window(func): The decorated method must take the window's id as the first argument. """ + @wraps(func) def _wrapper(self, window, *args, **kwargs): if not self.is_stacked(window): @@ -68,6 +69,7 @@ class ZManager: Base class for maintaining and manipulating information regarding the window stack. """ + def __init__(self, core) -> None: self.core = core @@ -76,10 +78,12 @@ def is_stacked(self, window: _Window) -> bool: """Check if window is currently in the stack.""" @abstractmethod - def add_window(self, window: _Window, layer: LayerGroup = LayerGroup.LAYOUT, position="top") -> None: + def add_window( + self, window: _Window, layer: LayerGroup = LayerGroup.LAYOUT, position="top" + ) -> None: """ Add window to the stack. - + Window can request specific layer group and be placed at "top" or "bottom" of the group. """ @@ -87,7 +91,6 @@ def add_window(self, window: _Window, layer: LayerGroup = LayerGroup.LAYOUT, pos @abstractmethod def remove_window(self, window) -> None: """Remove window from stack information.""" - pass @abstractmethod def move_up(self, window) -> StackInfo | None: @@ -110,4 +113,4 @@ def move_window_to_layer(self, window, new_layer, position="top") -> StackInfo | """Move window to a new layer group.""" def show_stacking_order(self): - """Dump a visualisation of the stacking order to the log.""" \ No newline at end of file + """Dump a visualisation of the stacking order to the log.""" diff --git a/libqtile/backend/wayland/core.py b/libqtile/backend/wayland/core.py index 233a52f544..e341fe775a 100644 --- a/libqtile/backend/wayland/core.py +++ b/libqtile/backend/wayland/core.py @@ -100,6 +100,7 @@ from libqtile.backend import base from libqtile.backend.wayland import inputs, layer, window, wlrq, xdgwindow, xwindow from libqtile.backend.wayland.output import Output +from libqtile.backend.wayland.zmanager import ZManager from libqtile.command.base import expose_command from libqtile.config import ScreenRect from libqtile.log_utils import logger @@ -261,6 +262,7 @@ def __init__(self) -> None: self._cursor_state = wlrq.CursorState() # Set up shell + self.zmanager = ZManager(self) self.xdg_shell = XdgShell(self.display) self.add_listener(self.xdg_shell.new_surface_event, self._on_new_xdg_surface) self.layer_shell = LayerShellV1(self.display, 4) diff --git a/libqtile/backend/wayland/zmanager.py b/libqtile/backend/wayland/zmanager.py index dac0cd7fa9..1f1c8b347a 100644 --- a/libqtile/backend/wayland/zmanager.py +++ b/libqtile/backend/wayland/zmanager.py @@ -24,7 +24,7 @@ class ZManager(zmanager.ZManager): def __init__(self, core) -> None: - super().__init__(c0re) + super().__init__(core) def is_stacked(self, window: _Window) -> bool: pass diff --git a/libqtile/backend/x11/window.py b/libqtile/backend/x11/window.py index 5c765ab7e1..3ca98149b6 100644 --- a/libqtile/backend/x11/window.py +++ b/libqtile/backend/x11/window.py @@ -13,7 +13,7 @@ from xcffib.wrappers import GContextID, PixmapID from xcffib.xproto import EventMask, SetMode -from libqtile import bar, hook, utils +from libqtile import hook, utils from libqtile.backend import base from libqtile.backend.base import FloatStates from libqtile.backend.base.zmanager import LayerGroup @@ -918,7 +918,7 @@ def stack(self, stack_info): xp = xcffib.xproto self.window.configure( stackmode=xp.StackMode.Below if stack_info.above else xp.StackMode.Above, - sibling=stack_info.wid + sibling=stack_info.wid, ) self.raise_children() self.qtile.core.zmanager.update_client_lists() @@ -973,7 +973,7 @@ def get_layering_information(self) -> LayerGroup: if _type == "desktop": return LayerGroup.BACKGROUND - + if "_NET_WM_STATE_BELOW" in state: return LayerGroup.KEEP_BELOW @@ -989,7 +989,9 @@ def get_layering_information(self) -> LayerGroup: return LayerGroup.LAYOUT def change_layer(self, layer=None, bottom=False): - stack_info = self.qtile.core.zmanager.move_window_to_layer(self, layer or self.get_layering_information(), position="bottom" if bottom else "top") + stack_info = self.qtile.core.zmanager.move_window_to_layer( + self, layer or self.get_layering_information(), position="bottom" if bottom else "top" + ) self.stack(stack_info) def raise_children(self): @@ -1002,7 +1004,7 @@ def raise_children(self): self.window.conn.conn.core.ConfigureWindow( child, xcffib.xproto.ConfigWindow.Sibling | xcffib.xproto.ConfigWindow.StackMode, - [parent, xcffib.xproto.StackMode.Above] + [parent, xcffib.xproto.StackMode.Above], ) parent = child diff --git a/libqtile/backend/x11/zmanager.py b/libqtile/backend/x11/zmanager.py index 1dce42fd6b..a01c800680 100644 --- a/libqtile/backend/x11/zmanager.py +++ b/libqtile/backend/x11/zmanager.py @@ -55,7 +55,9 @@ def get_window_below(self, window) -> StackInfo | None: sibling = stack[idx - 1] return StackInfo(sibling=sibling, above=False) - def add_window(self, window: _Window, layer: LayerGroup = LayerGroup.LAYOUT, position="top") -> None: + def add_window( + self, window: _Window, layer: LayerGroup = LayerGroup.LAYOUT, position="top" + ) -> None: if layer not in self.layers: raise ValueError(f"Invalid layer: {layer}") @@ -92,10 +94,12 @@ def replace_window(self, old_window, new_window) -> None: @check_window def move_up(self, window) -> StackInfo | None: layer, cur_idx = self.layer_map[window] - visible = [w for w in self.layers[layer] if w.is_visible() and w.group in (window.group, None)] + visible = [ + w for w in self.layers[layer] if w.is_visible() and w.group in (window.group, None) + ] idx = visible.index(window) if idx < (len(visible) - 1): - dest_idx = self.layers[layer].index(visible[idx + 1]) + dest_idx = self.layers[layer].index(visible[idx + 1]) win = self.layers[layer].pop(cur_idx) self.layers[layer].insert(dest_idx, win) @@ -106,10 +110,12 @@ def move_up(self, window) -> StackInfo | None: @check_window def move_down(self, window) -> StackInfo | None: layer, cur_idx = self.layer_map[window] - visible = [w for w in self.layers[layer] if w.is_visible() and w.group in (window.group, None)] + visible = [ + w for w in self.layers[layer] if w.is_visible() and w.group in (window.group, None) + ] idx = visible.index(window) if idx > 0: - dest_idx = self.layers[layer].index(visible[idx - 1]) + dest_idx = self.layers[layer].index(visible[idx - 1]) win = self.layers[layer].pop(cur_idx) self.layers[layer].insert(dest_idx, win) @@ -189,7 +195,7 @@ def update_client_lists(self): wids = [win.wid for win in z_order if isinstance(win, window.Window)] self.core._root.set_property("_NET_CLIENT_LIST", wids) - self.core._root.set_property("_NET_CLIENT_LIST_STACKING", [win.wid for win in z_order]) + self.core._root.set_property("_NET_CLIENT_LIST_STACKING", [win.wid for win in z_order]) def show_stacking_order(self): lines = [] @@ -200,6 +206,8 @@ def show_stacking_order(self): continue lines.append(f"LayerGroup {layer.name}") for client in clients: - lines.append(f"- {client} (Group: {client.group.name if client.group else "None"})") + lines.append( + f"- {client} (Group: {client.group.name if client.group else 'None'})" + ) if lines: logger.warning("\n".join(lines)) From 76cb3e8265470a9aec03f651ba7f511cf1f187ad Mon Sep 17 00:00:00 2001 From: elParaguayo Date: Fri, 1 Aug 2025 16:54:03 +0100 Subject: [PATCH 10/14] move stack to zmanager --- libqtile/backend/base/zmanager.py | 19 ++----- libqtile/backend/wayland/zmanager.py | 12 ++-- libqtile/backend/x11/window.py | 42 ++------------ libqtile/backend/x11/zmanager.py | 82 ++++++++++++++++++++-------- 4 files changed, 76 insertions(+), 79 deletions(-) diff --git a/libqtile/backend/base/zmanager.py b/libqtile/backend/base/zmanager.py index fc30427f33..5a80880d60 100644 --- a/libqtile/backend/base/zmanager.py +++ b/libqtile/backend/base/zmanager.py @@ -39,15 +39,6 @@ class LayerGroup(IntEnum): SYSTEM = 10 -@dataclass -class StackInfo: - sibling: _Window - above: bool - - def __post_init__(self): - self.wid = self.sibling.wid - - def check_window(func): """ Decorator that requires window to be stacked before proceeding. @@ -93,23 +84,23 @@ def remove_window(self, window) -> None: """Remove window from stack information.""" @abstractmethod - def move_up(self, window) -> StackInfo | None: + def move_up(self, window) -> None: """Move window up in the stack (in its layer group).""" @abstractmethod - def move_down(self, window) -> StackInfo | None: + def move_down(self, window) -> None: """Move window down in the stack (in its layer group).""" @abstractmethod - def move_to_top(self, window) -> StackInfo | None: + def move_to_top(self, window) -> None: """Move window to top of stack (in its layer group).""" @abstractmethod - def move_to_bottom(self, window) -> StackInfo | None: + def move_to_bottom(self, window) -> None: """Move window to bottom of stack (in its layer group).""" @abstractmethod - def move_window_to_layer(self, window, new_layer, position="top") -> StackInfo | None: + def move_window_to_layer(self, window, new_layer, position="top") -> None: """Move window to a new layer group.""" def show_stacking_order(self): diff --git a/libqtile/backend/wayland/zmanager.py b/libqtile/backend/wayland/zmanager.py index 1f1c8b347a..842a1efbe6 100644 --- a/libqtile/backend/wayland/zmanager.py +++ b/libqtile/backend/wayland/zmanager.py @@ -19,7 +19,7 @@ # SOFTWARE. from libqtile.backend.base import zmanager from libqtile.backend.base.window import _Window -from libqtile.backend.base.zmanager import LayerGroup, StackInfo +from libqtile.backend.base.zmanager import LayerGroup class ZManager(zmanager.ZManager): @@ -35,17 +35,17 @@ def add_window(self, window: _Window, layer: LayerGroup = LayerGroup.LAYOUT, pos def remove_window(self, window) -> None: pass - def move_up(self, window) -> StackInfo | None: + def move_up(self, window) -> None: pass - def move_down(self, window) -> StackInfo | None: + def move_down(self, window) -> None: pass - def move_to_top(self, window) -> StackInfo | None: + def move_to_top(self, window) -> None: pass - def move_to_bottom(self, window) -> StackInfo | None: + def move_to_bottom(self, window) -> None: pass - def move_window_to_layer(self, window, new_layer, position="top") -> StackInfo | None: + def move_window_to_layer(self, window, new_layer, position="top") -> None: pass diff --git a/libqtile/backend/x11/window.py b/libqtile/backend/x11/window.py index 3ca98149b6..52900aee26 100644 --- a/libqtile/backend/x11/window.py +++ b/libqtile/backend/x11/window.py @@ -469,6 +469,7 @@ def __init__(self, window, qtile): self.icons = {} window.set_attribute(eventmask=self._window_mask) self._group = None + self._layer_group: LayerGroup | None = None try: g = self.window.get_geometry() @@ -911,18 +912,6 @@ def place( if send_notify: self.send_configure_notify(x, y, width, height) - def stack(self, stack_info): - if stack_info is None: - return - - xp = xcffib.xproto - self.window.configure( - stackmode=xp.StackMode.Below if stack_info.above else xp.StackMode.Above, - sibling=stack_info.wid, - ) - self.raise_children() - self.qtile.core.zmanager.update_client_lists() - def get_layering_information(self) -> LayerGroup: """ Get layer-related EMWH-flags @@ -989,24 +978,9 @@ def get_layering_information(self) -> LayerGroup: return LayerGroup.LAYOUT def change_layer(self, layer=None, bottom=False): - stack_info = self.qtile.core.zmanager.move_window_to_layer( + self.qtile.core.zmanager.move_window_to_layer( self, layer or self.get_layering_information(), position="bottom" if bottom else "top" ) - self.stack(stack_info) - - def raise_children(self): - """Ensure any transient windows are moved up with the parent.""" - query = self.window.conn.conn.core.QueryTree(self.window.wid).reply() - children = list(query.children) - if children: - parent = self.window.wid - for child in children: - self.window.conn.conn.core.ConfigureWindow( - child, - xcffib.xproto.ConfigWindow.Sibling | xcffib.xproto.ConfigWindow.StackMode, - [parent, xcffib.xproto.StackMode.Above], - ) - parent = child def paint_borders(self, color, width): self.borderwidth = width @@ -1223,32 +1197,28 @@ def move_up(self, force=False): with self.qtile.core.masked(): # Disable masks so that moving windows along the Z axis doesn't trigger # focus change events (i.e. due to `follow_mouse_focus`) - stack_info = self.qtile.core.zmanager.move_up(self) - self.stack(stack_info) + self.qtile.core.zmanager.move_up(self) @expose_command() def move_down(self, force=False): if self.kept_above and force: self.kept_above = False with self.qtile.core.masked(): - stack_info = self.qtile.core.zmanager.move_down(self) - self.stack(stack_info) + self.qtile.core.zmanager.move_down(self) @expose_command() def move_to_top(self, force=False): if self.kept_below and force: self.kept_below = False with self.qtile.core.masked(): - stack_info = self.qtile.core.zmanager.move_to_top(self) - self.stack(stack_info) + self.qtile.core.zmanager.move_to_top(self) @expose_command() def move_to_bottom(self, force=False): if self.kept_above and force: self.kept_above = False with self.qtile.core.masked(): - stack_info = self.qtile.core.zmanager.move_to_bottom(self) - self.stack(stack_info) + self.qtile.core.zmanager.move_to_bottom(self) @property def kept_above(self): diff --git a/libqtile/backend/x11/zmanager.py b/libqtile/backend/x11/zmanager.py index a01c800680..1f491cc363 100644 --- a/libqtile/backend/x11/zmanager.py +++ b/libqtile/backend/x11/zmanager.py @@ -17,10 +17,12 @@ # 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. +import xcffib.xproto + from libqtile import hook from libqtile.backend.base import zmanager from libqtile.backend.base.window import _Window -from libqtile.backend.base.zmanager import LayerGroup, StackInfo, check_window +from libqtile.backend.base.zmanager import LayerGroup, check_window from libqtile.backend.x11 import window from libqtile.log_utils import logger @@ -39,21 +41,45 @@ def get_layer(self, window) -> LayerGroup | None: layer, _ = self.layer_map.get(window, (None, 0)) return layer - @check_window - def get_window_above(self, window) -> StackInfo | None: - stack = self.get_z_order() - idx = stack.index(window) - if idx < (len(stack) - 1): - sibling = stack[idx + 1] - return StackInfo(sibling=sibling, above=True) + def stack(self, window: _Window) -> None: + sibling, above = self.get_sibling(window) + + if sibling is None: + return + + window.window.configure( + stackmode=xcffib.xproto.StackMode.Above if above else xcffib.xproto.StackMode.Below, + sibling=sibling.wid, + ) + self.raise_children(window) + self.update_client_lists() + window._layer_group = self.get_window_layer(window) + + def raise_children(self, window: _Window): + """Ensure any transient windows are moved up with the parent.""" + query = window.window.conn.conn.core.QueryTree(window.window.wid).reply() + children = list(query.children) + if children: + parent = window.window.wid + for child in children: + window.window.conn.conn.core.ConfigureWindow( + child, + xcffib.xproto.ConfigWindow.Sibling | xcffib.xproto.ConfigWindow.StackMode, + [parent, xcffib.xproto.StackMode.Above], + ) + parent = child @check_window - def get_window_below(self, window) -> StackInfo | None: + def get_sibling(self, window) -> tuple[_Window | None, bool]: stack = self.get_z_order() + if len(stack) == 1: + return (None, True) + idx = stack.index(window) - if idx > 0: - sibling = stack[idx - 1] - return StackInfo(sibling=sibling, above=False) + if idx == 0: + return (stack[1], False) + else: + return (stack[idx - 1], True) def add_window( self, window: _Window, layer: LayerGroup = LayerGroup.LAYOUT, position="top" @@ -73,7 +99,7 @@ def add_window( self._reindex_layer(layer) - window.stack(self.get_window_below(window) or self.get_window_above(window)) + self.stack(window) @check_window def remove_window(self, window) -> None: @@ -92,7 +118,7 @@ def replace_window(self, old_window, new_window) -> None: self.update_client_lists() @check_window - def move_up(self, window) -> StackInfo | None: + def move_up(self, window) -> None: layer, cur_idx = self.layer_map[window] visible = [ w for w in self.layers[layer] if w.is_visible() and w.group in (window.group, None) @@ -105,11 +131,16 @@ def move_up(self, window) -> StackInfo | None: self._reindex_layer(layer) - return self.get_window_below(window) + self.stack(window) @check_window - def move_down(self, window) -> StackInfo | None: + def move_down(self, window) -> None: layer, cur_idx = self.layer_map[window] + + if layer == LayerGroup.BRING_TO_FRONT: + window.change_layer() + layer, cur_idx = self.layer_map[window] + visible = [ w for w in self.layers[layer] if w.is_visible() and w.group in (window.group, None) ] @@ -121,28 +152,28 @@ def move_down(self, window) -> StackInfo | None: self._reindex_layer(layer) - return self.get_window_above(window) + self.stack(window) @check_window - def move_to_top(self, window) -> StackInfo | None: + def move_to_top(self, window) -> None: layer, _ = self.layer_map[window] self.layers[layer].remove(window) self.layers[layer].append(window) self._reindex_layer(layer) - return self.get_window_below(window) + self.stack(window) @check_window - def move_to_bottom(self, window) -> StackInfo | None: + def move_to_bottom(self, window) -> None: layer, _ = self.layer_map[window] self.layers[layer].remove(window) self.layers[layer].insert(0, window) self._reindex_layer(layer) - return self.get_window_above(window) + self.stack(window) @check_window - def move_window_to_layer(self, window, new_layer, position="top") -> StackInfo | None: + def move_window_to_layer(self, window, new_layer, position="top") -> None: old_layer, _ = self.layer_map[window] if old_layer is new_layer: return @@ -157,7 +188,7 @@ def move_window_to_layer(self, window, new_layer, position="top") -> StackInfo | self._reindex_layer(old_layer) self._reindex_layer(new_layer) - return self.get_window_below(window) or self.get_window_above(window) + self.stack(window) def get_z_order(self) -> list[_Window]: z_order = [] @@ -165,6 +196,11 @@ def get_z_order(self) -> list[_Window]: z_order.extend(clients) return z_order + @check_window + def get_window_layer(self, window: _Window) -> LayerGroup | None: + layer, _ = self.layer_map[window] + return layer + def _reindex_layer(self, layer) -> None: for idx, win in enumerate(self.layers[layer]): self.layer_map[win] = (layer, idx) From 5f4a4c9eb7401b5cc93cf9da6b6b4933e75feda0 Mon Sep 17 00:00:00 2001 From: elParaguayo Date: Fri, 1 Aug 2025 20:30:06 +0100 Subject: [PATCH 11/14] better handling of float state --- libqtile/backend/x11/window.py | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/libqtile/backend/x11/window.py b/libqtile/backend/x11/window.py index 52900aee26..fd640ac9da 100644 --- a/libqtile/backend/x11/window.py +++ b/libqtile/backend/x11/window.py @@ -1490,9 +1490,6 @@ def floating(self): @floating.setter def floating(self, do_float): - stack = self.qtile.core._root.query_tree() - tiled = [win.window.wid for win in (self.group.tiled_windows if self.group else [])] - tiled_stack = [wid for wid in stack if wid in tiled and wid != self.window.wid] if do_float and self._float_state == FloatStates.NOT_FLOATING: if self.is_placed(): screen = self.group.screen @@ -1503,14 +1500,6 @@ def floating(self, do_float): self._float_height, ) - # Make sure floating window is placed above tiled windows - if tiled_stack and (not self.kept_above or self.qtile.config.floats_kept_above): - stack_list = list(stack) - highest_tile = tiled_stack[-1] - if stack_list.index(self.window.wid) < stack_list.index(highest_tile): - self.window.configure( - stackmode=xcffib.xproto.StackMode.Above, sibling=highest_tile - ) else: # if we are setting floating early, e.g. from a hook, we don't have a screen yet self._float_state = FloatStates.FLOATING @@ -1524,13 +1513,15 @@ def floating(self, do_float): self._float_width = self.width self._float_height = self.height self._float_state = FloatStates.NOT_FLOATING + # Put floats back into LAYOUT layer group + if self.qtile.config.floats_kept_above: + self.keep_above(enable=False) self.group.mark_floating(self, False) - if tiled_stack: - self.window.configure( - stackmode=xcffib.xproto.StackMode.Above, sibling=tiled_stack[-1] - ) hook.fire("float_change") + # Whatever we do, make sure window is at top of its layer group + self.move_to_top() + @property def wants_to_fullscreen(self): try: From 30eb97b17470cd2154795e38ac5db93752a8f9de Mon Sep 17 00:00:00 2001 From: elParaguayo Date: Sat, 2 Aug 2025 08:15:26 +0100 Subject: [PATCH 12/14] Restack unfocused windows --- libqtile/backend/x11/zmanager.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/libqtile/backend/x11/zmanager.py b/libqtile/backend/x11/zmanager.py index 1f491cc363..fd932beb7e 100644 --- a/libqtile/backend/x11/zmanager.py +++ b/libqtile/backend/x11/zmanager.py @@ -37,6 +37,18 @@ def __init__(self, core) -> None: def is_stacked(self, window: _Window) -> bool: return window in self.layer_map + def is_above(self, window: _Window, other: _Window) -> bool: + if other not in self.layer_map: + return False + + w_layer, w_idx = self.layer_map[window] + o_layer, o_idx = self.layer_map[other] + + if w_layer != o_layer: + return False + + return w_idx > o_idx + def get_layer(self, window) -> LayerGroup | None: layer, _ = self.layer_map.get(window, (None, 0)) return layer @@ -154,6 +166,14 @@ def move_down(self, window) -> None: self.stack(window) + @check_window + def move_to_index(self, window: _Window, index: int) -> None: + layer, _ = self.layer_map[window] + self.layers[layer].remove(window) + self.layers[layer].insert(index, window) + self._reindex_layer(layer) + self.stack(window) + @check_window def move_to_top(self, window) -> None: layer, _ = self.layer_map[window] @@ -217,6 +237,12 @@ def _restack_on_focus_change(self, window): for client in clients: if client != window: client.change_layer() + # We drop windows into the new layer after a new window has taken focus + # This means it will be stacked above the new window which is + # undesirable so we can move it below that window. + if self.is_above(client, window): + _, index = self.layer_map[window] + self.move_to_index(client, index) def update_client_lists(self): """ From 7ed6851e69967a1e894b9f053dd9745fc17a6d24 Mon Sep 17 00:00:00 2001 From: elParaguayo Date: Mon, 18 Aug 2025 19:06:29 +0100 Subject: [PATCH 13/14] Remove zmanager from wayland backend --- libqtile/backend/base/__init__.py | 1 + .../{wayland/zmanager.py => base/stacking.py} | 52 +- libqtile/backend/base/zmanager.py | 107 - libqtile/backend/wayland/core.py | 2 - .../wlr-layer-shell-unstable-v1-protocol.h | 710 +++++ .../wayland/qw/proto/xdg-shell-protocol.h | 2327 +++++++++++++++++ libqtile/backend/x11/window.py | 3 +- libqtile/backend/x11/zmanager.py | 25 +- 8 files changed, 3080 insertions(+), 147 deletions(-) rename libqtile/backend/{wayland/zmanager.py => base/stacking.py} (57%) delete mode 100644 libqtile/backend/base/zmanager.py create mode 100644 libqtile/backend/wayland/qw/proto/wlr-layer-shell-unstable-v1-protocol.h create mode 100644 libqtile/backend/wayland/qw/proto/xdg-shell-protocol.h diff --git a/libqtile/backend/base/__init__.py b/libqtile/backend/base/__init__.py index 739a7f736c..e0f51975db 100644 --- a/libqtile/backend/base/__init__.py +++ b/libqtile/backend/base/__init__.py @@ -1,5 +1,6 @@ from libqtile.backend.base.core import Core # noqa: F401 from libqtile.backend.base.drawer import Drawer # noqa: F401 +from libqtile.backend.base.stacking import LayerGroup # noqa: F401 from libqtile.backend.base.window import ( # noqa: F401 FloatStates, Internal, diff --git a/libqtile/backend/wayland/zmanager.py b/libqtile/backend/base/stacking.py similarity index 57% rename from libqtile/backend/wayland/zmanager.py rename to libqtile/backend/base/stacking.py index 842a1efbe6..25231b205c 100644 --- a/libqtile/backend/wayland/zmanager.py +++ b/libqtile/backend/base/stacking.py @@ -17,35 +17,23 @@ # 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. -from libqtile.backend.base import zmanager -from libqtile.backend.base.window import _Window -from libqtile.backend.base.zmanager import LayerGroup - - -class ZManager(zmanager.ZManager): - def __init__(self, core) -> None: - super().__init__(core) - - def is_stacked(self, window: _Window) -> bool: - pass - - def add_window(self, window: _Window, layer: LayerGroup = LayerGroup.LAYOUT, position="top") -> None: - pass - - def remove_window(self, window) -> None: - pass - - def move_up(self, window) -> None: - pass - - def move_down(self, window) -> None: - pass - - def move_to_top(self, window) -> None: - pass - - def move_to_bottom(self, window) -> None: - pass - - def move_window_to_layer(self, window, new_layer, position="top") -> None: - pass +from enum import IntEnum + + +class LayerGroup(IntEnum): + """ + Helper object to specify stacking layers. `LayerGroup` is backend-agnostic, + so backends will need to map behaviour accordingly. However, a common object + allows us have more common code across backends. + """ + BACKGROUND = 0 + BOTTOM = 1 + KEEP_BELOW = 2 + LAYOUT = 3 + KEEP_ABOVE = 4 + MAX = 5 + FULLSCREEN = 6 + BRING_TO_FRONT = 7 + TOP = 8 + OVERLAY = 9 + SYSTEM = 10 diff --git a/libqtile/backend/base/zmanager.py b/libqtile/backend/base/zmanager.py deleted file mode 100644 index 5a80880d60..0000000000 --- a/libqtile/backend/base/zmanager.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright (c) 2025 elParaguayo -# -# 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 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. -from abc import abstractmethod -from dataclasses import dataclass -from enum import IntEnum -from functools import wraps - -from libqtile.backend.base.window import _Window - - -class LayerGroup(IntEnum): - BACKGROUND = 0 - BOTTOM = 1 - KEEP_BELOW = 2 - LAYOUT = 3 - KEEP_ABOVE = 4 - MAX = 5 - FULLSCREEN = 6 - BRING_TO_FRONT = 7 - TOP = 8 - OVERLAY = 9 - SYSTEM = 10 - - -def check_window(func): - """ - Decorator that requires window to be stacked before proceeding. - - The decorated method must take the window's id as the first argument. - """ - - @wraps(func) - def _wrapper(self, window, *args, **kwargs): - if not self.is_stacked(window): - return - return func(self, window, *args, **kwargs) - - return _wrapper - - -class ZManager: - """ - Base class for maintaining and manipulating information regarding the - window stack. - """ - - def __init__(self, core) -> None: - self.core = core - - @abstractmethod - def is_stacked(self, window: _Window) -> bool: - """Check if window is currently in the stack.""" - - @abstractmethod - def add_window( - self, window: _Window, layer: LayerGroup = LayerGroup.LAYOUT, position="top" - ) -> None: - """ - Add window to the stack. - - Window can request specific layer group and be placed at "top" or "bottom" of - the group. - """ - - @abstractmethod - def remove_window(self, window) -> None: - """Remove window from stack information.""" - - @abstractmethod - def move_up(self, window) -> None: - """Move window up in the stack (in its layer group).""" - - @abstractmethod - def move_down(self, window) -> None: - """Move window down in the stack (in its layer group).""" - - @abstractmethod - def move_to_top(self, window) -> None: - """Move window to top of stack (in its layer group).""" - - @abstractmethod - def move_to_bottom(self, window) -> None: - """Move window to bottom of stack (in its layer group).""" - - @abstractmethod - def move_window_to_layer(self, window, new_layer, position="top") -> None: - """Move window to a new layer group.""" - - def show_stacking_order(self): - """Dump a visualisation of the stacking order to the log.""" diff --git a/libqtile/backend/wayland/core.py b/libqtile/backend/wayland/core.py index e341fe775a..233a52f544 100644 --- a/libqtile/backend/wayland/core.py +++ b/libqtile/backend/wayland/core.py @@ -100,7 +100,6 @@ from libqtile.backend import base from libqtile.backend.wayland import inputs, layer, window, wlrq, xdgwindow, xwindow from libqtile.backend.wayland.output import Output -from libqtile.backend.wayland.zmanager import ZManager from libqtile.command.base import expose_command from libqtile.config import ScreenRect from libqtile.log_utils import logger @@ -262,7 +261,6 @@ def __init__(self) -> None: self._cursor_state = wlrq.CursorState() # Set up shell - self.zmanager = ZManager(self) self.xdg_shell = XdgShell(self.display) self.add_listener(self.xdg_shell.new_surface_event, self._on_new_xdg_surface) self.layer_shell = LayerShellV1(self.display, 4) diff --git a/libqtile/backend/wayland/qw/proto/wlr-layer-shell-unstable-v1-protocol.h b/libqtile/backend/wayland/qw/proto/wlr-layer-shell-unstable-v1-protocol.h new file mode 100644 index 0000000000..2e8962a0d6 --- /dev/null +++ b/libqtile/backend/wayland/qw/proto/wlr-layer-shell-unstable-v1-protocol.h @@ -0,0 +1,710 @@ +/* Generated by wayland-scanner 1.23.1 */ + +#ifndef WLR_LAYER_SHELL_UNSTABLE_V1_SERVER_PROTOCOL_H +#define WLR_LAYER_SHELL_UNSTABLE_V1_SERVER_PROTOCOL_H + +#include +#include +#include "wayland-server.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct wl_client; +struct wl_resource; + +/** + * @page page_wlr_layer_shell_unstable_v1 The wlr_layer_shell_unstable_v1 protocol + * @section page_ifaces_wlr_layer_shell_unstable_v1 Interfaces + * - @subpage page_iface_zwlr_layer_shell_v1 - create surfaces that are layers of the desktop + * - @subpage page_iface_zwlr_layer_surface_v1 - layer metadata interface + * @section page_copyright_wlr_layer_shell_unstable_v1 Copyright + *
+ *
+ * Copyright © 2017 Drew DeVault
+ *
+ * Permission to use, copy, modify, distribute, and sell this
+ * software and its documentation for any purpose is hereby granted
+ * without fee, provided that the above copyright notice appear in
+ * all copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * the copyright holders not be used in advertising or publicity
+ * pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ * 
+ */ +struct wl_output; +struct wl_surface; +struct xdg_popup; +struct zwlr_layer_shell_v1; +struct zwlr_layer_surface_v1; + +#ifndef ZWLR_LAYER_SHELL_V1_INTERFACE +#define ZWLR_LAYER_SHELL_V1_INTERFACE +/** + * @page page_iface_zwlr_layer_shell_v1 zwlr_layer_shell_v1 + * @section page_iface_zwlr_layer_shell_v1_desc Description + * + * Clients can use this interface to assign the surface_layer role to + * wl_surfaces. Such surfaces are assigned to a "layer" of the output and + * rendered with a defined z-depth respective to each other. They may also be + * anchored to the edges and corners of a screen and specify input handling + * semantics. This interface should be suitable for the implementation of + * many desktop shell components, and a broad number of other applications + * that interact with the desktop. + * @section page_iface_zwlr_layer_shell_v1_api API + * See @ref iface_zwlr_layer_shell_v1. + */ +/** + * @defgroup iface_zwlr_layer_shell_v1 The zwlr_layer_shell_v1 interface + * + * Clients can use this interface to assign the surface_layer role to + * wl_surfaces. Such surfaces are assigned to a "layer" of the output and + * rendered with a defined z-depth respective to each other. They may also be + * anchored to the edges and corners of a screen and specify input handling + * semantics. This interface should be suitable for the implementation of + * many desktop shell components, and a broad number of other applications + * that interact with the desktop. + */ +extern const struct wl_interface zwlr_layer_shell_v1_interface; +#endif +#ifndef ZWLR_LAYER_SURFACE_V1_INTERFACE +#define ZWLR_LAYER_SURFACE_V1_INTERFACE +/** + * @page page_iface_zwlr_layer_surface_v1 zwlr_layer_surface_v1 + * @section page_iface_zwlr_layer_surface_v1_desc Description + * + * An interface that may be implemented by a wl_surface, for surfaces that + * are designed to be rendered as a layer of a stacked desktop-like + * environment. + * + * Layer surface state (layer, size, anchor, exclusive zone, + * margin, interactivity) is double-buffered, and will be applied at the + * time wl_surface.commit of the corresponding wl_surface is called. + * + * Attaching a null buffer to a layer surface unmaps it. + * + * Unmapping a layer_surface means that the surface cannot be shown by the + * compositor until it is explicitly mapped again. The layer_surface + * returns to the state it had right after layer_shell.get_layer_surface. + * The client can re-map the surface by performing a commit without any + * buffer attached, waiting for a configure event and handling it as usual. + * @section page_iface_zwlr_layer_surface_v1_api API + * See @ref iface_zwlr_layer_surface_v1. + */ +/** + * @defgroup iface_zwlr_layer_surface_v1 The zwlr_layer_surface_v1 interface + * + * An interface that may be implemented by a wl_surface, for surfaces that + * are designed to be rendered as a layer of a stacked desktop-like + * environment. + * + * Layer surface state (layer, size, anchor, exclusive zone, + * margin, interactivity) is double-buffered, and will be applied at the + * time wl_surface.commit of the corresponding wl_surface is called. + * + * Attaching a null buffer to a layer surface unmaps it. + * + * Unmapping a layer_surface means that the surface cannot be shown by the + * compositor until it is explicitly mapped again. The layer_surface + * returns to the state it had right after layer_shell.get_layer_surface. + * The client can re-map the surface by performing a commit without any + * buffer attached, waiting for a configure event and handling it as usual. + */ +extern const struct wl_interface zwlr_layer_surface_v1_interface; +#endif + +#ifndef ZWLR_LAYER_SHELL_V1_ERROR_ENUM +#define ZWLR_LAYER_SHELL_V1_ERROR_ENUM +enum zwlr_layer_shell_v1_error { + /** + * wl_surface has another role + */ + ZWLR_LAYER_SHELL_V1_ERROR_ROLE = 0, + /** + * layer value is invalid + */ + ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER = 1, + /** + * wl_surface has a buffer attached or committed + */ + ZWLR_LAYER_SHELL_V1_ERROR_ALREADY_CONSTRUCTED = 2, +}; +/** + * @ingroup iface_zwlr_layer_shell_v1 + * Validate a zwlr_layer_shell_v1 error value. + * + * @return true on success, false on error. + * @ref zwlr_layer_shell_v1_error + */ +static inline bool +zwlr_layer_shell_v1_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case ZWLR_LAYER_SHELL_V1_ERROR_ROLE: + return version >= 1; + case ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER: + return version >= 1; + case ZWLR_LAYER_SHELL_V1_ERROR_ALREADY_CONSTRUCTED: + return version >= 1; + default: + return false; + } +} +#endif /* ZWLR_LAYER_SHELL_V1_ERROR_ENUM */ + +#ifndef ZWLR_LAYER_SHELL_V1_LAYER_ENUM +#define ZWLR_LAYER_SHELL_V1_LAYER_ENUM +/** + * @ingroup iface_zwlr_layer_shell_v1 + * available layers for surfaces + * + * These values indicate which layers a surface can be rendered in. They + * are ordered by z depth, bottom-most first. Traditional shell surfaces + * will typically be rendered between the bottom and top layers. + * Fullscreen shell surfaces are typically rendered at the top layer. + * Multiple surfaces can share a single layer, and ordering within a + * single layer is undefined. + */ +enum zwlr_layer_shell_v1_layer { + ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND = 0, + ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM = 1, + ZWLR_LAYER_SHELL_V1_LAYER_TOP = 2, + ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY = 3, +}; +/** + * @ingroup iface_zwlr_layer_shell_v1 + * Validate a zwlr_layer_shell_v1 layer value. + * + * @return true on success, false on error. + * @ref zwlr_layer_shell_v1_layer + */ +static inline bool +zwlr_layer_shell_v1_layer_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND: + return version >= 1; + case ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM: + return version >= 1; + case ZWLR_LAYER_SHELL_V1_LAYER_TOP: + return version >= 1; + case ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY: + return version >= 1; + default: + return false; + } +} +#endif /* ZWLR_LAYER_SHELL_V1_LAYER_ENUM */ + +/** + * @ingroup iface_zwlr_layer_shell_v1 + * @struct zwlr_layer_shell_v1_interface + */ +struct zwlr_layer_shell_v1_interface { + /** + * create a layer_surface from a surface + * + * Create a layer surface for an existing surface. This assigns + * the role of layer_surface, or raises a protocol error if another + * role is already assigned. + * + * Creating a layer surface from a wl_surface 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 + * layer_surface.configure call must also be treated as errors. + * + * After creating a layer_surface object and setting it up, the + * client must perform an initial commit without any buffer + * attached. The compositor will reply with a + * layer_surface.configure event. The client must acknowledge it + * and is then allowed to attach a buffer to map the surface. + * + * You may pass NULL for output to allow the compositor to decide + * which output to use. Generally this will be the one that the + * user most recently interacted with. + * + * Clients can specify a namespace that defines the purpose of the + * layer surface. + * @param layer layer to add this surface to + * @param namespace namespace for the layer surface + */ + void (*get_layer_surface)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface, + struct wl_resource *output, + uint32_t layer, + const char *namespace); + /** + * destroy the layer_shell object + * + * This request indicates that the client will not use the + * layer_shell object any more. Objects that have been created + * through this instance are not affected. + * @since 3 + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); +}; + + +/** + * @ingroup iface_zwlr_layer_shell_v1 + */ +#define ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_shell_v1 + */ +#define ZWLR_LAYER_SHELL_V1_DESTROY_SINCE_VERSION 3 + +#ifndef ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ENUM +#define ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ENUM +/** + * @ingroup iface_zwlr_layer_surface_v1 + * types of keyboard interaction possible for a layer shell surface + * + * Types of keyboard interaction possible for layer shell surfaces. The + * rationale for this is twofold: (1) some applications are not interested + * in keyboard events and not allowing them to be focused can improve the + * desktop experience; (2) some applications will want to take exclusive + * keyboard focus. + */ +enum zwlr_layer_surface_v1_keyboard_interactivity { + /** + * no keyboard focus is possible + * + * This value indicates that this surface is not interested in + * keyboard events and the compositor should never assign it the + * keyboard focus. + * + * This is the default value, set for newly created layer shell + * surfaces. + * + * This is useful for e.g. desktop widgets that display information + * or only have interaction with non-keyboard input devices. + */ + ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE = 0, + /** + * request exclusive keyboard focus + * + * Request exclusive keyboard focus if this surface is above the + * shell surface layer. + * + * For the top and overlay layers, the seat will always give + * exclusive keyboard focus to the top-most layer which has + * keyboard interactivity set to exclusive. If this layer contains + * multiple surfaces with keyboard interactivity set to exclusive, + * the compositor determines the one receiving keyboard events in + * an implementation- defined manner. In this case, no guarantee is + * made when this surface will receive keyboard focus (if ever). + * + * For the bottom and background layers, the compositor is allowed + * to use normal focus semantics. + * + * This setting is mainly intended for applications that need to + * ensure they receive all keyboard events, such as a lock screen + * or a password prompt. + */ + ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE = 1, + /** + * request regular keyboard focus semantics + * + * This requests the compositor to allow this surface to be + * focused and unfocused by the user in an implementation-defined + * manner. The user should be able to unfocus this surface even + * regardless of the layer it is on. + * + * Typically, the compositor will want to use its normal mechanism + * to manage keyboard focus between layer shell surfaces with this + * setting and regular toplevels on the desktop layer (e.g. click + * to focus). Nevertheless, it is possible for a compositor to + * require a special interaction to focus or unfocus layer shell + * surfaces (e.g. requiring a click even if focus follows the mouse + * normally, or providing a keybinding to switch focus between + * layers). + * + * This setting is mainly intended for desktop shell components + * (e.g. panels) that allow keyboard interaction. Using this option + * can allow implementing a desktop shell that can be fully usable + * without the mouse. + * @since 4 + */ + ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND = 2, +}; +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND_SINCE_VERSION 4 +/** + * @ingroup iface_zwlr_layer_surface_v1 + * Validate a zwlr_layer_surface_v1 keyboard_interactivity value. + * + * @return true on success, false on error. + * @ref zwlr_layer_surface_v1_keyboard_interactivity + */ +static inline bool +zwlr_layer_surface_v1_keyboard_interactivity_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE: + return version >= 1; + case ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE: + return version >= 1; + case ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND: + return version >= 4; + default: + return false; + } +} +#endif /* ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ENUM */ + +#ifndef ZWLR_LAYER_SURFACE_V1_ERROR_ENUM +#define ZWLR_LAYER_SURFACE_V1_ERROR_ENUM +enum zwlr_layer_surface_v1_error { + /** + * provided surface state is invalid + */ + ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SURFACE_STATE = 0, + /** + * size is invalid + */ + ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SIZE = 1, + /** + * anchor bitfield is invalid + */ + ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_ANCHOR = 2, + /** + * keyboard interactivity is invalid + */ + ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_KEYBOARD_INTERACTIVITY = 3, +}; +/** + * @ingroup iface_zwlr_layer_surface_v1 + * Validate a zwlr_layer_surface_v1 error value. + * + * @return true on success, false on error. + * @ref zwlr_layer_surface_v1_error + */ +static inline bool +zwlr_layer_surface_v1_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SURFACE_STATE: + return version >= 1; + case ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SIZE: + return version >= 1; + case ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_ANCHOR: + return version >= 1; + case ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_KEYBOARD_INTERACTIVITY: + return version >= 1; + default: + return false; + } +} +#endif /* ZWLR_LAYER_SURFACE_V1_ERROR_ENUM */ + +#ifndef ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM +#define ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM +enum zwlr_layer_surface_v1_anchor { + /** + * the top edge of the anchor rectangle + */ + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP = 1, + /** + * the bottom edge of the anchor rectangle + */ + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM = 2, + /** + * the left edge of the anchor rectangle + */ + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT = 4, + /** + * the right edge of the anchor rectangle + */ + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT = 8, +}; +/** + * @ingroup iface_zwlr_layer_surface_v1 + * Validate a zwlr_layer_surface_v1 anchor value. + * + * @return true on success, false on error. + * @ref zwlr_layer_surface_v1_anchor + */ +static inline bool +zwlr_layer_surface_v1_anchor_is_valid(uint32_t value, uint32_t version) { + uint32_t valid = 0; + if (version >= 1) + valid |= ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; + if (version >= 1) + valid |= ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; + if (version >= 1) + valid |= ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT; + if (version >= 1) + valid |= ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; + return (value & ~valid) == 0; +} +#endif /* ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM */ + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * @struct zwlr_layer_surface_v1_interface + */ +struct zwlr_layer_surface_v1_interface { + /** + * sets the size of the surface + * + * Sets the size of the surface in surface-local coordinates. The + * compositor will display the surface centered with respect to its + * anchors. + * + * If you pass 0 for either value, the compositor will assign it + * and inform you of the assignment in the configure event. You + * must set your anchor to opposite edges in the dimensions you + * omit; not doing so is a protocol error. Both values are 0 by + * default. + * + * Size is double-buffered, see wl_surface.commit. + */ + void (*set_size)(struct wl_client *client, + struct wl_resource *resource, + uint32_t width, + uint32_t height); + /** + * configures the anchor point of the surface + * + * Requests that the compositor anchor the surface to the + * specified edges and corners. If two orthogonal edges are + * specified (e.g. 'top' and 'left'), then the anchor point will be + * the intersection of the edges (e.g. the top left corner of the + * output); otherwise the anchor point will be centered on that + * edge, or in the center if none is specified. + * + * Anchor is double-buffered, see wl_surface.commit. + */ + void (*set_anchor)(struct wl_client *client, + struct wl_resource *resource, + uint32_t anchor); + /** + * configures the exclusive geometry of this surface + * + * Requests that the compositor avoids occluding an area with + * other surfaces. The compositor's use of this information is + * implementation-dependent - do not assume that this region will + * not actually be occluded. + * + * A positive value is only meaningful if the surface is anchored + * to one edge or an edge and both perpendicular edges. If the + * surface is not anchored, anchored to only two perpendicular + * edges (a corner), anchored to only two parallel edges or + * anchored to all edges, a positive value will be treated the same + * as zero. + * + * A positive zone is the distance from the edge in surface-local + * coordinates to consider exclusive. + * + * Surfaces that do not wish to have an exclusive zone may instead + * specify how they should interact with surfaces that do. If set + * to zero, the surface indicates that it would like to be moved to + * avoid occluding surfaces with a positive exclusive zone. If set + * to -1, the surface indicates that it would not like to be moved + * to accommodate for other surfaces, and the compositor should + * extend it all the way to the edges it is anchored to. + * + * For example, a panel might set its exclusive zone to 10, so that + * maximized shell surfaces are not shown on top of it. A + * notification might set its exclusive zone to 0, so that it is + * moved to avoid occluding the panel, but shell surfaces are shown + * underneath it. A wallpaper or lock screen might set their + * exclusive zone to -1, so that they stretch below or over the + * panel. + * + * The default value is 0. + * + * Exclusive zone is double-buffered, see wl_surface.commit. + */ + void (*set_exclusive_zone)(struct wl_client *client, + struct wl_resource *resource, + int32_t zone); + /** + * sets a margin from the anchor point + * + * Requests that the surface be placed some distance away from + * the anchor point on the output, in surface-local coordinates. + * Setting this value for edges you are not anchored to has no + * effect. + * + * The exclusive zone includes the margin. + * + * Margin is double-buffered, see wl_surface.commit. + */ + void (*set_margin)(struct wl_client *client, + struct wl_resource *resource, + int32_t top, + int32_t right, + int32_t bottom, + int32_t left); + /** + * requests keyboard events + * + * Set how keyboard events are delivered to this surface. By + * default, layer shell surfaces do not receive keyboard events; + * this request can be used to change this. + * + * This setting is inherited by child surfaces set by the get_popup + * request. + * + * Layer surfaces receive pointer, touch, and tablet events + * normally. If you do not want to receive them, set the input + * region on your surface to an empty region. + * + * Keyboard interactivity is double-buffered, see + * wl_surface.commit. + */ + void (*set_keyboard_interactivity)(struct wl_client *client, + struct wl_resource *resource, + uint32_t keyboard_interactivity); + /** + * assign this layer_surface as an xdg_popup parent + * + * This assigns an xdg_popup's parent to this layer_surface. This + * popup should have been created via xdg_surface::get_popup with + * the parent set to NULL, and this request must be invoked before + * committing the popup's initial state. + * + * See the documentation of xdg_popup for more details about what + * an xdg_popup is and how it is used. + */ + void (*get_popup)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *popup); + /** + * ack a configure event + * + * When a configure event is received, if a client commits the + * surface in response to the configure event, then the client must + * make an ack_configure request sometime before the commit + * request, passing along the serial of the configure event. + * + * If the client receives multiple configure events before it can + * respond to one, it only has to ack the last configure event. + * + * A client is not required to commit immediately after sending an + * ack_configure request - it may even ack_configure several times + * before its next surface commit. + * + * A client may send multiple ack_configure requests before + * committing, but only the last request sent before a commit + * indicates which configure event the client really is responding + * to. + * @param serial the serial from the configure event + */ + void (*ack_configure)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial); + /** + * destroy the layer_surface + * + * This request destroys the layer surface. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * change the layer of the surface + * + * Change the layer that the surface is rendered on. + * + * Layer is double-buffered, see wl_surface.commit. + * @param layer layer to move this surface to + * @since 2 + */ + void (*set_layer)(struct wl_client *client, + struct wl_resource *resource, + uint32_t layer); +}; + +#define ZWLR_LAYER_SURFACE_V1_CONFIGURE 0 +#define ZWLR_LAYER_SURFACE_V1_CLOSED 1 + +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_CLOSED_SINCE_VERSION 1 + +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_SET_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_SET_ANCHOR_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_SET_MARGIN_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_GET_POPUP_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +#define ZWLR_LAYER_SURFACE_V1_SET_LAYER_SINCE_VERSION 2 + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * Sends an configure event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +zwlr_layer_surface_v1_send_configure(struct wl_resource *resource_, uint32_t serial, uint32_t width, uint32_t height) +{ + wl_resource_post_event(resource_, ZWLR_LAYER_SURFACE_V1_CONFIGURE, serial, width, height); +} + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * Sends an closed event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +zwlr_layer_surface_v1_send_closed(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, ZWLR_LAYER_SURFACE_V1_CLOSED); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libqtile/backend/wayland/qw/proto/xdg-shell-protocol.h b/libqtile/backend/wayland/qw/proto/xdg-shell-protocol.h new file mode 100644 index 0000000000..3bd3ce5f1c --- /dev/null +++ b/libqtile/backend/wayland/qw/proto/xdg-shell-protocol.h @@ -0,0 +1,2327 @@ +/* Generated by wayland-scanner 1.23.1 */ + +#ifndef XDG_SHELL_SERVER_PROTOCOL_H +#define XDG_SHELL_SERVER_PROTOCOL_H + +#include +#include +#include "wayland-server.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct wl_client; +struct wl_resource; + +/** + * @page page_xdg_shell The xdg_shell protocol + * @section page_ifaces_xdg_shell Interfaces + * - @subpage page_iface_xdg_wm_base - create desktop-style surfaces + * - @subpage page_iface_xdg_positioner - child surface positioner + * - @subpage page_iface_xdg_surface - desktop user interface surface base interface + * - @subpage page_iface_xdg_toplevel - toplevel surface + * - @subpage page_iface_xdg_popup - short-lived, popup surfaces for menus + * @section page_copyright_xdg_shell Copyright + *
+ *
+ * Copyright © 2008-2013 Kristian Høgsberg
+ * Copyright © 2013      Rafael Antognolli
+ * Copyright © 2013      Jasper St. Pierre
+ * Copyright © 2010-2013 Intel Corporation
+ * Copyright © 2015-2017 Samsung Electronics Co., Ltd
+ * Copyright © 2015-2017 Red Hat Inc.
+ *
+ * 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.
+ * 
+ */ +struct wl_output; +struct wl_seat; +struct wl_surface; +struct xdg_popup; +struct xdg_positioner; +struct xdg_surface; +struct xdg_toplevel; +struct xdg_wm_base; + +#ifndef XDG_WM_BASE_INTERFACE +#define XDG_WM_BASE_INTERFACE +/** + * @page page_iface_xdg_wm_base xdg_wm_base + * @section page_iface_xdg_wm_base_desc Description + * + * The xdg_wm_base interface is exposed as a global object enabling clients + * to turn their wl_surfaces into windows in a desktop environment. It + * defines the basic functionality needed for clients and the compositor to + * create windows that can be dragged, resized, maximized, etc, as well as + * creating transient windows such as popup menus. + * @section page_iface_xdg_wm_base_api API + * See @ref iface_xdg_wm_base. + */ +/** + * @defgroup iface_xdg_wm_base The xdg_wm_base interface + * + * The xdg_wm_base interface is exposed as a global object enabling clients + * to turn their wl_surfaces into windows in a desktop environment. It + * defines the basic functionality needed for clients and the compositor to + * create windows that can be dragged, resized, maximized, etc, as well as + * creating transient windows such as popup menus. + */ +extern const struct wl_interface xdg_wm_base_interface; +#endif +#ifndef XDG_POSITIONER_INTERFACE +#define XDG_POSITIONER_INTERFACE +/** + * @page page_iface_xdg_positioner xdg_positioner + * @section page_iface_xdg_positioner_desc Description + * + * The xdg_positioner provides a collection of rules for the placement of a + * child surface relative to a parent surface. Rules can be defined to ensure + * the child surface remains within the visible area's borders, and to + * specify how the child surface changes its position, such as sliding along + * an axis, or flipping around a rectangle. These positioner-created rules are + * constrained by the requirement that a child surface must intersect with or + * be at least partially adjacent to its parent surface. + * + * See the various requests for details about possible rules. + * + * At the time of the request, the compositor makes a copy of the rules + * specified by the xdg_positioner. Thus, after the request is complete the + * xdg_positioner object can be destroyed or reused; further changes to the + * object will have no effect on previous usages. + * + * For an xdg_positioner object to be considered complete, it must have a + * non-zero size set by set_size, and a non-zero anchor rectangle set by + * set_anchor_rect. Passing an incomplete xdg_positioner object when + * positioning a surface raises an invalid_positioner error. + * @section page_iface_xdg_positioner_api API + * See @ref iface_xdg_positioner. + */ +/** + * @defgroup iface_xdg_positioner The xdg_positioner interface + * + * The xdg_positioner provides a collection of rules for the placement of a + * child surface relative to a parent surface. Rules can be defined to ensure + * the child surface remains within the visible area's borders, and to + * specify how the child surface changes its position, such as sliding along + * an axis, or flipping around a rectangle. These positioner-created rules are + * constrained by the requirement that a child surface must intersect with or + * be at least partially adjacent to its parent surface. + * + * See the various requests for details about possible rules. + * + * At the time of the request, the compositor makes a copy of the rules + * specified by the xdg_positioner. Thus, after the request is complete the + * xdg_positioner object can be destroyed or reused; further changes to the + * object will have no effect on previous usages. + * + * For an xdg_positioner object to be considered complete, it must have a + * non-zero size set by set_size, and a non-zero anchor rectangle set by + * set_anchor_rect. Passing an incomplete xdg_positioner object when + * positioning a surface raises an invalid_positioner error. + */ +extern const struct wl_interface xdg_positioner_interface; +#endif +#ifndef XDG_SURFACE_INTERFACE +#define XDG_SURFACE_INTERFACE +/** + * @page page_iface_xdg_surface xdg_surface + * @section page_iface_xdg_surface_desc Description + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides a base set of functionality required to construct user + * interface elements requiring management by the compositor, such as + * toplevel windows, menus, etc. The types of functionality are split into + * xdg_surface roles. + * + * Creating an xdg_surface does not set the role for a wl_surface. In order + * to map an xdg_surface, the client must create a role-specific object + * using, e.g., get_toplevel, get_popup. The wl_surface for any given + * xdg_surface can have at most one role, and may not be assigned any role + * not based on xdg_surface. + * + * A role must be assigned before any other requests are made to the + * xdg_surface object. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_surface state to take effect. + * + * Creating an xdg_surface from a wl_surface 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_surface.configure call must + * also be treated as errors. + * + * After creating a role-specific object and setting it up (e.g. by sending + * the title, app ID, size constraints, parent, etc), the client must + * perform an initial commit without any buffer attached. The compositor + * will reply with initial wl_surface state such as + * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure + * event. The client must acknowledge it and is then allowed to attach a + * buffer to map the surface. + * + * Mapping an xdg_surface-based role surface is defined as making it + * possible for the surface to be shown by the compositor. Note that + * a mapped surface is not guaranteed to be visible once it is mapped. + * + * For an xdg_surface to be mapped by the compositor, the following + * conditions must be met: + * (1) the client has assigned an xdg_surface-based role to the surface + * (2) the client has set and committed the xdg_surface state and the + * role-dependent state to the surface + * (3) the client has committed a buffer to the surface + * + * A newly-unmapped surface is considered to have met condition (1) out + * of the 3 required conditions for mapping a surface if its role surface + * has not been destroyed, i.e. the client must perform the initial commit + * again before attaching a buffer. + * @section page_iface_xdg_surface_api API + * See @ref iface_xdg_surface. + */ +/** + * @defgroup iface_xdg_surface The xdg_surface interface + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides a base set of functionality required to construct user + * interface elements requiring management by the compositor, such as + * toplevel windows, menus, etc. The types of functionality are split into + * xdg_surface roles. + * + * Creating an xdg_surface does not set the role for a wl_surface. In order + * to map an xdg_surface, the client must create a role-specific object + * using, e.g., get_toplevel, get_popup. The wl_surface for any given + * xdg_surface can have at most one role, and may not be assigned any role + * not based on xdg_surface. + * + * A role must be assigned before any other requests are made to the + * xdg_surface object. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_surface state to take effect. + * + * Creating an xdg_surface from a wl_surface 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_surface.configure call must + * also be treated as errors. + * + * After creating a role-specific object and setting it up (e.g. by sending + * the title, app ID, size constraints, parent, etc), the client must + * perform an initial commit without any buffer attached. The compositor + * will reply with initial wl_surface state such as + * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure + * event. The client must acknowledge it and is then allowed to attach a + * buffer to map the surface. + * + * Mapping an xdg_surface-based role surface is defined as making it + * possible for the surface to be shown by the compositor. Note that + * a mapped surface is not guaranteed to be visible once it is mapped. + * + * For an xdg_surface to be mapped by the compositor, the following + * conditions must be met: + * (1) the client has assigned an xdg_surface-based role to the surface + * (2) the client has set and committed the xdg_surface state and the + * role-dependent state to the surface + * (3) the client has committed a buffer to the surface + * + * A newly-unmapped surface is considered to have met condition (1) out + * of the 3 required conditions for mapping a surface if its role surface + * has not been destroyed, i.e. the client must perform the initial commit + * again before attaching a buffer. + */ +extern const struct wl_interface xdg_surface_interface; +#endif +#ifndef XDG_TOPLEVEL_INTERFACE +#define XDG_TOPLEVEL_INTERFACE +/** + * @page page_iface_xdg_toplevel xdg_toplevel + * @section page_iface_xdg_toplevel_desc Description + * + * This interface defines an xdg_surface role which allows a surface to, + * among other things, set window-like properties such as maximize, + * fullscreen, and minimize, set application-specific metadata like title and + * id, and well as trigger user interactive operations such as interactive + * resize and move. + * + * A xdg_toplevel by default is responsible for providing the full intended + * visual representation of the toplevel, which depending on the window + * state, may mean things like a title bar, window controls and drop shadow. + * + * Unmapping an xdg_toplevel means that the surface cannot be shown + * by the compositor until it is explicitly mapped again. + * All active operations (e.g., move, resize) are canceled and all + * attributes (e.g. title, state, stacking, ...) are discarded for + * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to + * the state it had right after xdg_surface.get_toplevel. The client + * can re-map the toplevel by performing a commit without any buffer + * attached, waiting for a configure event and handling it as usual (see + * xdg_surface description). + * + * Attaching a null buffer to a toplevel unmaps the surface. + * @section page_iface_xdg_toplevel_api API + * See @ref iface_xdg_toplevel. + */ +/** + * @defgroup iface_xdg_toplevel The xdg_toplevel interface + * + * This interface defines an xdg_surface role which allows a surface to, + * among other things, set window-like properties such as maximize, + * fullscreen, and minimize, set application-specific metadata like title and + * id, and well as trigger user interactive operations such as interactive + * resize and move. + * + * A xdg_toplevel by default is responsible for providing the full intended + * visual representation of the toplevel, which depending on the window + * state, may mean things like a title bar, window controls and drop shadow. + * + * Unmapping an xdg_toplevel means that the surface cannot be shown + * by the compositor until it is explicitly mapped again. + * All active operations (e.g., move, resize) are canceled and all + * attributes (e.g. title, state, stacking, ...) are discarded for + * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to + * the state it had right after xdg_surface.get_toplevel. The client + * can re-map the toplevel by performing a commit without any buffer + * attached, waiting for a configure event and handling it as usual (see + * xdg_surface description). + * + * Attaching a null buffer to a toplevel unmaps the surface. + */ +extern const struct wl_interface xdg_toplevel_interface; +#endif +#ifndef XDG_POPUP_INTERFACE +#define XDG_POPUP_INTERFACE +/** + * @page page_iface_xdg_popup xdg_popup + * @section page_iface_xdg_popup_desc Description + * + * A popup surface is a short-lived, temporary surface. It can be used to + * implement for example menus, popovers, tooltips and other similar user + * interface concepts. + * + * A popup can be made to take an explicit grab. See xdg_popup.grab for + * details. + * + * When the popup is dismissed, a popup_done event will be sent out, and at + * the same time the surface will be unmapped. See the xdg_popup.popup_done + * event for details. + * + * Explicitly destroying the xdg_popup object will also dismiss the popup and + * unmap the surface. Clients that want to dismiss the popup when another + * surface of their own is clicked should dismiss the popup using the destroy + * request. + * + * A newly created xdg_popup will be stacked on top of all previously created + * xdg_popup surfaces associated with the same xdg_toplevel. + * + * The parent of an xdg_popup must be mapped (see the xdg_surface + * description) before the xdg_popup itself. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_popup state to take effect. + * @section page_iface_xdg_popup_api API + * See @ref iface_xdg_popup. + */ +/** + * @defgroup iface_xdg_popup The xdg_popup interface + * + * A popup surface is a short-lived, temporary surface. It can be used to + * implement for example menus, popovers, tooltips and other similar user + * interface concepts. + * + * A popup can be made to take an explicit grab. See xdg_popup.grab for + * details. + * + * When the popup is dismissed, a popup_done event will be sent out, and at + * the same time the surface will be unmapped. See the xdg_popup.popup_done + * event for details. + * + * Explicitly destroying the xdg_popup object will also dismiss the popup and + * unmap the surface. Clients that want to dismiss the popup when another + * surface of their own is clicked should dismiss the popup using the destroy + * request. + * + * A newly created xdg_popup will be stacked on top of all previously created + * xdg_popup surfaces associated with the same xdg_toplevel. + * + * The parent of an xdg_popup must be mapped (see the xdg_surface + * description) before the xdg_popup itself. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_popup state to take effect. + */ +extern const struct wl_interface xdg_popup_interface; +#endif + +#ifndef XDG_WM_BASE_ERROR_ENUM +#define XDG_WM_BASE_ERROR_ENUM +enum xdg_wm_base_error { + /** + * given wl_surface has another role + */ + XDG_WM_BASE_ERROR_ROLE = 0, + /** + * xdg_wm_base was destroyed before children + */ + XDG_WM_BASE_ERROR_DEFUNCT_SURFACES = 1, + /** + * the client tried to map or destroy a non-topmost popup + */ + XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP = 2, + /** + * the client specified an invalid popup parent surface + */ + XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT = 3, + /** + * the client provided an invalid surface state + */ + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE = 4, + /** + * the client provided an invalid positioner + */ + XDG_WM_BASE_ERROR_INVALID_POSITIONER = 5, + /** + * the client didn’t respond to a ping event in time + */ + XDG_WM_BASE_ERROR_UNRESPONSIVE = 6, +}; +/** + * @ingroup iface_xdg_wm_base + * Validate a xdg_wm_base error value. + * + * @return true on success, false on error. + * @ref xdg_wm_base_error + */ +static inline bool +xdg_wm_base_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_WM_BASE_ERROR_ROLE: + return version >= 1; + case XDG_WM_BASE_ERROR_DEFUNCT_SURFACES: + return version >= 1; + case XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP: + return version >= 1; + case XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT: + return version >= 1; + case XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE: + return version >= 1; + case XDG_WM_BASE_ERROR_INVALID_POSITIONER: + return version >= 1; + case XDG_WM_BASE_ERROR_UNRESPONSIVE: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_WM_BASE_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_wm_base + * @struct xdg_wm_base_interface + */ +struct xdg_wm_base_interface { + /** + * destroy xdg_wm_base + * + * Destroy this xdg_wm_base object. + * + * Destroying a bound xdg_wm_base object while there are surfaces + * still alive created by this xdg_wm_base object instance is + * illegal and will result in a defunct_surfaces error. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * create a positioner object + * + * Create a positioner object. A positioner object is used to + * position surfaces relative to some parent surface. See the + * interface description and xdg_surface.get_popup for details. + */ + void (*create_positioner)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id); + /** + * create a shell surface from a surface + * + * This creates an xdg_surface for the given surface. While + * xdg_surface itself is not a role, the corresponding surface may + * only be assigned a role extending xdg_surface, such as + * xdg_toplevel or xdg_popup. It is illegal to create an + * xdg_surface for a wl_surface which already has an assigned role + * and this will result in a role error. + * + * This creates an xdg_surface for the given surface. An + * xdg_surface is used as basis to define a role to a given + * surface, such as xdg_toplevel or xdg_popup. It also manages + * functionality shared between xdg_surface based surface roles. + * + * See the documentation of xdg_surface for more details about what + * an xdg_surface is and how it is used. + */ + void (*get_xdg_surface)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface); + /** + * respond to a ping event + * + * A client must respond to a ping event with a pong request or + * the client may be deemed unresponsive. See xdg_wm_base.ping and + * xdg_wm_base.error.unresponsive. + * @param serial serial of the ping event + */ + void (*pong)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial); +}; + +#define XDG_WM_BASE_PING 0 + +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_PING_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_CREATE_POSITIONER_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_GET_XDG_SURFACE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_PONG_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_wm_base + * Sends an ping event to the client owning the resource. + * @param resource_ The client's resource + * @param serial pass this to the pong request + */ +static inline void +xdg_wm_base_send_ping(struct wl_resource *resource_, uint32_t serial) +{ + wl_resource_post_event(resource_, XDG_WM_BASE_PING, serial); +} + +#ifndef XDG_POSITIONER_ERROR_ENUM +#define XDG_POSITIONER_ERROR_ENUM +enum xdg_positioner_error { + /** + * invalid input provided + */ + XDG_POSITIONER_ERROR_INVALID_INPUT = 0, +}; +/** + * @ingroup iface_xdg_positioner + * Validate a xdg_positioner error value. + * + * @return true on success, false on error. + * @ref xdg_positioner_error + */ +static inline bool +xdg_positioner_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_POSITIONER_ERROR_INVALID_INPUT: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_POSITIONER_ERROR_ENUM */ + +#ifndef XDG_POSITIONER_ANCHOR_ENUM +#define XDG_POSITIONER_ANCHOR_ENUM +enum xdg_positioner_anchor { + XDG_POSITIONER_ANCHOR_NONE = 0, + XDG_POSITIONER_ANCHOR_TOP = 1, + XDG_POSITIONER_ANCHOR_BOTTOM = 2, + XDG_POSITIONER_ANCHOR_LEFT = 3, + XDG_POSITIONER_ANCHOR_RIGHT = 4, + XDG_POSITIONER_ANCHOR_TOP_LEFT = 5, + XDG_POSITIONER_ANCHOR_BOTTOM_LEFT = 6, + XDG_POSITIONER_ANCHOR_TOP_RIGHT = 7, + XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT = 8, +}; +/** + * @ingroup iface_xdg_positioner + * Validate a xdg_positioner anchor value. + * + * @return true on success, false on error. + * @ref xdg_positioner_anchor + */ +static inline bool +xdg_positioner_anchor_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_POSITIONER_ANCHOR_NONE: + return version >= 1; + case XDG_POSITIONER_ANCHOR_TOP: + return version >= 1; + case XDG_POSITIONER_ANCHOR_BOTTOM: + return version >= 1; + case XDG_POSITIONER_ANCHOR_LEFT: + return version >= 1; + case XDG_POSITIONER_ANCHOR_RIGHT: + return version >= 1; + case XDG_POSITIONER_ANCHOR_TOP_LEFT: + return version >= 1; + case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: + return version >= 1; + case XDG_POSITIONER_ANCHOR_TOP_RIGHT: + return version >= 1; + case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_POSITIONER_ANCHOR_ENUM */ + +#ifndef XDG_POSITIONER_GRAVITY_ENUM +#define XDG_POSITIONER_GRAVITY_ENUM +enum xdg_positioner_gravity { + XDG_POSITIONER_GRAVITY_NONE = 0, + XDG_POSITIONER_GRAVITY_TOP = 1, + XDG_POSITIONER_GRAVITY_BOTTOM = 2, + XDG_POSITIONER_GRAVITY_LEFT = 3, + XDG_POSITIONER_GRAVITY_RIGHT = 4, + XDG_POSITIONER_GRAVITY_TOP_LEFT = 5, + XDG_POSITIONER_GRAVITY_BOTTOM_LEFT = 6, + XDG_POSITIONER_GRAVITY_TOP_RIGHT = 7, + XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT = 8, +}; +/** + * @ingroup iface_xdg_positioner + * Validate a xdg_positioner gravity value. + * + * @return true on success, false on error. + * @ref xdg_positioner_gravity + */ +static inline bool +xdg_positioner_gravity_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_POSITIONER_GRAVITY_NONE: + return version >= 1; + case XDG_POSITIONER_GRAVITY_TOP: + return version >= 1; + case XDG_POSITIONER_GRAVITY_BOTTOM: + return version >= 1; + case XDG_POSITIONER_GRAVITY_LEFT: + return version >= 1; + case XDG_POSITIONER_GRAVITY_RIGHT: + return version >= 1; + case XDG_POSITIONER_GRAVITY_TOP_LEFT: + return version >= 1; + case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT: + return version >= 1; + case XDG_POSITIONER_GRAVITY_TOP_RIGHT: + return version >= 1; + case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_POSITIONER_GRAVITY_ENUM */ + +#ifndef XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM +#define XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM +/** + * @ingroup iface_xdg_positioner + * constraint adjustments + * + * The constraint adjustment value define ways the compositor will adjust + * the position of the surface, if the unadjusted position would result + * in the surface being partly constrained. + * + * Whether a surface is considered 'constrained' is left to the compositor + * to determine. For example, the surface may be partly outside the + * compositor's defined 'work area', thus necessitating the child surface's + * position be adjusted until it is entirely inside the work area. + * + * The adjustments can be combined, according to a defined precedence: 1) + * Flip, 2) Slide, 3) Resize. + */ +enum xdg_positioner_constraint_adjustment { + /** + * don't move the child surface when constrained + * + * Don't alter the surface position even if it is constrained on + * some axis, for example partially outside the edge of an output. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE = 0, + /** + * move along the x axis until unconstrained + * + * Slide the surface along the x axis until it is no longer + * constrained. + * + * First try to slide towards the direction of the gravity on the x + * axis until either the edge in the opposite direction of the + * gravity is unconstrained or the edge in the direction of the + * gravity is constrained. + * + * Then try to slide towards the opposite direction of the gravity + * on the x axis until either the edge in the direction of the + * gravity is unconstrained or the edge in the opposite direction + * of the gravity is constrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1, + /** + * move along the y axis until unconstrained + * + * Slide the surface along the y axis until it is no longer + * constrained. + * + * First try to slide towards the direction of the gravity on the y + * axis until either the edge in the opposite direction of the + * gravity is unconstrained or the edge in the direction of the + * gravity is constrained. + * + * Then try to slide towards the opposite direction of the gravity + * on the y axis until either the edge in the direction of the + * gravity is unconstrained or the edge in the opposite direction + * of the gravity is constrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2, + /** + * invert the anchor and gravity on the x axis + * + * Invert the anchor and gravity on the x axis if the surface is + * constrained on the x axis. For example, if the left edge of the + * surface is constrained, the gravity is 'left' and the anchor is + * 'left', change the gravity to 'right' and the anchor to 'right'. + * + * If the adjusted position also ends up being constrained, the + * resulting position of the flip_x adjustment will be the one + * before the adjustment. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X = 4, + /** + * invert the anchor and gravity on the y axis + * + * Invert the anchor and gravity on the y axis if the surface is + * constrained on the y axis. For example, if the bottom edge of + * the surface is constrained, the gravity is 'bottom' and the + * anchor is 'bottom', change the gravity to 'top' and the anchor + * to 'top'. + * + * The adjusted position is calculated given the original anchor + * rectangle and offset, but with the new flipped anchor and + * gravity values. + * + * If the adjusted position also ends up being constrained, the + * resulting position of the flip_y adjustment will be the one + * before the adjustment. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8, + /** + * horizontally resize the surface + * + * Resize the surface horizontally so that it is completely + * unconstrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16, + /** + * vertically resize the surface + * + * Resize the surface vertically so that it is completely + * unconstrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32, +}; +/** + * @ingroup iface_xdg_positioner + * Validate a xdg_positioner constraint_adjustment value. + * + * @return true on success, false on error. + * @ref xdg_positioner_constraint_adjustment + */ +static inline bool +xdg_positioner_constraint_adjustment_is_valid(uint32_t value, uint32_t version) { + uint32_t valid = 0; + if (version >= 1) + valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE; + if (version >= 1) + valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X; + if (version >= 1) + valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y; + if (version >= 1) + valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X; + if (version >= 1) + valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y; + if (version >= 1) + valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X; + if (version >= 1) + valid |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y; + return (value & ~valid) == 0; +} +#endif /* XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM */ + +/** + * @ingroup iface_xdg_positioner + * @struct xdg_positioner_interface + */ +struct xdg_positioner_interface { + /** + * destroy the xdg_positioner object + * + * Notify the compositor that the xdg_positioner will no longer + * be used. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * set the size of the to-be positioned rectangle + * + * Set the size of the surface that is to be positioned with the + * positioner object. The size is in surface-local coordinates and + * corresponds to the window geometry. See + * xdg_surface.set_window_geometry. + * + * If a zero or negative size is set the invalid_input error is + * raised. + * @param width width of positioned rectangle + * @param height height of positioned rectangle + */ + void (*set_size)(struct wl_client *client, + struct wl_resource *resource, + int32_t width, + int32_t height); + /** + * set the anchor rectangle within the parent surface + * + * Specify the anchor rectangle within the parent surface that + * the child surface will be placed relative to. The rectangle is + * relative to the window geometry as defined by + * xdg_surface.set_window_geometry of the parent surface. + * + * When the xdg_positioner object is used to position a child + * surface, the anchor rectangle may not extend outside the window + * geometry of the positioned child's parent surface. + * + * If a negative size is set the invalid_input error is raised. + * @param x x position of anchor rectangle + * @param y y position of anchor rectangle + * @param width width of anchor rectangle + * @param height height of anchor rectangle + */ + void (*set_anchor_rect)(struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y, + int32_t width, + int32_t height); + /** + * set anchor rectangle anchor + * + * Defines the anchor point for the anchor rectangle. The + * specified anchor is used derive an anchor point that the child + * surface will be positioned relative to. If a corner anchor is + * set (e.g. 'top_left' or 'bottom_right'), the anchor point will + * be at the specified corner; otherwise, the derived anchor point + * will be centered on the specified edge, or in the center of the + * anchor rectangle if no edge is specified. + * @param anchor anchor + */ + void (*set_anchor)(struct wl_client *client, + struct wl_resource *resource, + uint32_t anchor); + /** + * set child surface gravity + * + * Defines in what direction a surface should be positioned, + * relative to the anchor point of the parent surface. If a corner + * gravity is specified (e.g. 'bottom_right' or 'top_left'), then + * the child surface will be placed towards the specified gravity; + * otherwise, the child surface will be centered over the anchor + * point on any axis that had no gravity specified. If the gravity + * is not in the ‘gravity’ enum, an invalid_input error is + * raised. + * @param gravity gravity direction + */ + void (*set_gravity)(struct wl_client *client, + struct wl_resource *resource, + uint32_t gravity); + /** + * set the adjustment to be done when constrained + * + * Specify how the window should be positioned if the originally + * intended position caused the surface to be constrained, meaning + * at least partially outside positioning boundaries set by the + * compositor. The adjustment is set by constructing a bitmask + * describing the adjustment to be made when the surface is + * constrained on that axis. + * + * If no bit for one axis is set, the compositor will assume that + * the child surface should not change its position on that axis + * when constrained. + * + * If more than one bit for one axis is set, the order of how + * adjustments are applied is specified in the corresponding + * adjustment descriptions. + * + * The default adjustment is none. + * @param constraint_adjustment bit mask of constraint adjustments + */ + void (*set_constraint_adjustment)(struct wl_client *client, + struct wl_resource *resource, + uint32_t constraint_adjustment); + /** + * set surface position offset + * + * Specify the surface position offset relative to the position + * of the anchor on the anchor rectangle and the anchor on the + * surface. For example if the anchor of the anchor rectangle is at + * (x, y), the surface has the gravity bottom|right, and the offset + * is (ox, oy), the calculated surface position will be (x + ox, y + * + oy). The offset position of the surface is the one used for + * constraint testing. See set_constraint_adjustment. + * + * An example use case is placing a popup menu on top of a user + * interface element, while aligning the user interface element of + * the parent surface with some user interface element placed + * somewhere in the popup surface. + * @param x surface position x offset + * @param y surface position y offset + */ + void (*set_offset)(struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y); + /** + * continuously reconstrain the surface + * + * When set reactive, the surface is reconstrained if the + * conditions used for constraining changed, e.g. the parent window + * moved. + * + * If the conditions changed and the popup was reconstrained, an + * xdg_popup.configure event is sent with updated geometry, + * followed by an xdg_surface.configure event. + * @since 3 + */ + void (*set_reactive)(struct wl_client *client, + struct wl_resource *resource); + /** + * + * + * Set the parent window geometry the compositor should use when + * positioning the popup. The compositor may use this information + * to determine the future state the popup should be constrained + * using. If this doesn't match the dimension of the parent the + * popup is eventually positioned against, the behavior is + * undefined. + * + * The arguments are given in the surface-local coordinate space. + * @param parent_width future window geometry width of parent + * @param parent_height future window geometry height of parent + * @since 3 + */ + void (*set_parent_size)(struct wl_client *client, + struct wl_resource *resource, + int32_t parent_width, + int32_t parent_height); + /** + * set parent configure this is a response to + * + * Set the serial of an xdg_surface.configure event this + * positioner will be used in response to. The compositor may use + * this information together with set_parent_size to determine what + * future state the popup should be constrained using. + * @param serial serial of parent configure event + * @since 3 + */ + void (*set_parent_configure)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial); +}; + + +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_ANCHOR_RECT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_ANCHOR_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_GRAVITY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_OFFSET_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_REACTIVE_SINCE_VERSION 3 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_PARENT_SIZE_SINCE_VERSION 3 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_PARENT_CONFIGURE_SINCE_VERSION 3 + +#ifndef XDG_SURFACE_ERROR_ENUM +#define XDG_SURFACE_ERROR_ENUM +enum xdg_surface_error { + /** + * Surface was not fully constructed + */ + XDG_SURFACE_ERROR_NOT_CONSTRUCTED = 1, + /** + * Surface was already constructed + */ + XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED = 2, + /** + * Attaching a buffer to an unconfigured surface + */ + XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER = 3, + /** + * Invalid serial number when acking a configure event + */ + XDG_SURFACE_ERROR_INVALID_SERIAL = 4, + /** + * Width or height was zero or negative + */ + XDG_SURFACE_ERROR_INVALID_SIZE = 5, + /** + * Surface was destroyed before its role object + */ + XDG_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT = 6, +}; +/** + * @ingroup iface_xdg_surface + * Validate a xdg_surface error value. + * + * @return true on success, false on error. + * @ref xdg_surface_error + */ +static inline bool +xdg_surface_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_SURFACE_ERROR_NOT_CONSTRUCTED: + return version >= 1; + case XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED: + return version >= 1; + case XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER: + return version >= 1; + case XDG_SURFACE_ERROR_INVALID_SERIAL: + return version >= 1; + case XDG_SURFACE_ERROR_INVALID_SIZE: + return version >= 1; + case XDG_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_SURFACE_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_surface + * @struct xdg_surface_interface + */ +struct xdg_surface_interface { + /** + * destroy the xdg_surface + * + * Destroy the xdg_surface object. An xdg_surface must only be + * destroyed after its role object has been destroyed, otherwise a + * defunct_role_object error is raised. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * assign the xdg_toplevel surface role + * + * This creates an xdg_toplevel object for the given xdg_surface + * and gives the associated wl_surface the xdg_toplevel role. + * + * See the documentation of xdg_toplevel for more details about + * what an xdg_toplevel is and how it is used. + */ + void (*get_toplevel)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id); + /** + * assign the xdg_popup surface role + * + * This creates an xdg_popup object for the given xdg_surface and + * gives the associated wl_surface the xdg_popup role. + * + * If null is passed as a parent, a parent surface must be + * specified using some other protocol, before committing the + * initial state. + * + * See the documentation of xdg_popup for more details about what + * an xdg_popup is and how it is used. + */ + void (*get_popup)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *parent, + struct wl_resource *positioner); + /** + * set the new window geometry + * + * The window geometry of a surface is its "visible bounds" from + * the user's perspective. Client-side decorations often have + * invisible portions like drop-shadows which should be ignored for + * the purposes of aligning, placing and constraining windows. + * + * The window geometry is double-buffered state, see + * wl_surface.commit. + * + * When maintaining a position, the compositor should treat the (x, + * y) coordinate of the window geometry as the top left corner of + * the window. A client changing the (x, y) window geometry + * coordinate should in general not alter the position of the + * window. + * + * Once the window geometry of the surface is set, it is not + * possible to unset it, and it will remain the same until + * set_window_geometry is called again, even if a new subsurface or + * buffer is attached. + * + * If never set, the value is the full bounds of the surface, + * including any subsurfaces. This updates dynamically on every + * commit. This unset is meant for extremely simple clients. + * + * The arguments are given in the surface-local coordinate space of + * the wl_surface associated with this xdg_surface, and may extend + * outside of the wl_surface itself to mark parts of the subsurface + * tree as part of the window geometry. + * + * When applied, the effective window geometry will be the set + * window geometry clamped to the bounding rectangle of the + * combined geometry of the surface of the xdg_surface and the + * associated subsurfaces. + * + * The effective geometry will not be recalculated unless a new + * call to set_window_geometry is done and the new pending surface + * state is subsequently applied. + * + * The width and height of the effective window geometry must be + * greater than zero. Setting an invalid size will raise an + * invalid_size error. + */ + void (*set_window_geometry)(struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y, + int32_t width, + int32_t height); + /** + * ack a configure event + * + * When a configure event is received, if a client commits the + * surface in response to the configure event, then the client must + * make an ack_configure request sometime before the commit + * request, passing along the serial of the configure event. + * + * For instance, for toplevel surfaces the compositor might use + * this information to move a surface to the top left only when the + * client has drawn itself for the maximized or fullscreen state. + * + * If the client receives multiple configure events before it can + * respond to one, it only has to ack the last configure event. + * Acking a configure event that was never sent raises an + * invalid_serial error. + * + * A client is not required to commit immediately after sending an + * ack_configure request - it may even ack_configure several times + * before its next surface commit. + * + * A client may send multiple ack_configure requests before + * committing, but only the last request sent before a commit + * indicates which configure event the client really is responding + * to. + * + * Sending an ack_configure request consumes the serial number sent + * with the request, as well as serial numbers sent by all + * configure events sent on this xdg_surface prior to the configure + * event referenced by the committed serial. + * + * It is an error to issue multiple ack_configure requests + * referencing a serial from the same configure event, or to issue + * an ack_configure request referencing a serial from a configure + * event issued before the event identified by the last + * ack_configure request for the same xdg_surface. Doing so will + * raise an invalid_serial error. + * @param serial the serial from the configure event + */ + void (*ack_configure)(struct wl_client *client, + struct wl_resource *resource, + uint32_t serial); +}; + +#define XDG_SURFACE_CONFIGURE 0 + +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_CONFIGURE_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_GET_TOPLEVEL_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_GET_POPUP_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_SET_WINDOW_GEOMETRY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_ACK_CONFIGURE_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_surface + * Sends an configure event to the client owning the resource. + * @param resource_ The client's resource + * @param serial serial of the configure event + */ +static inline void +xdg_surface_send_configure(struct wl_resource *resource_, uint32_t serial) +{ + wl_resource_post_event(resource_, XDG_SURFACE_CONFIGURE, serial); +} + +#ifndef XDG_TOPLEVEL_ERROR_ENUM +#define XDG_TOPLEVEL_ERROR_ENUM +enum xdg_toplevel_error { + /** + * provided value is not a valid variant of the resize_edge enum + */ + XDG_TOPLEVEL_ERROR_INVALID_RESIZE_EDGE = 0, + /** + * invalid parent toplevel + */ + XDG_TOPLEVEL_ERROR_INVALID_PARENT = 1, + /** + * client provided an invalid min or max size + */ + XDG_TOPLEVEL_ERROR_INVALID_SIZE = 2, +}; +/** + * @ingroup iface_xdg_toplevel + * Validate a xdg_toplevel error value. + * + * @return true on success, false on error. + * @ref xdg_toplevel_error + */ +static inline bool +xdg_toplevel_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_TOPLEVEL_ERROR_INVALID_RESIZE_EDGE: + return version >= 1; + case XDG_TOPLEVEL_ERROR_INVALID_PARENT: + return version >= 1; + case XDG_TOPLEVEL_ERROR_INVALID_SIZE: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_TOPLEVEL_ERROR_ENUM */ + +#ifndef XDG_TOPLEVEL_RESIZE_EDGE_ENUM +#define XDG_TOPLEVEL_RESIZE_EDGE_ENUM +/** + * @ingroup iface_xdg_toplevel + * edge values for resizing + * + * These values are used to indicate which edge of a surface + * is being dragged in a resize operation. + */ +enum xdg_toplevel_resize_edge { + XDG_TOPLEVEL_RESIZE_EDGE_NONE = 0, + XDG_TOPLEVEL_RESIZE_EDGE_TOP = 1, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM = 2, + XDG_TOPLEVEL_RESIZE_EDGE_LEFT = 4, + XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT = 5, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT = 6, + XDG_TOPLEVEL_RESIZE_EDGE_RIGHT = 8, + XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT = 9, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT = 10, +}; +/** + * @ingroup iface_xdg_toplevel + * Validate a xdg_toplevel resize_edge value. + * + * @return true on success, false on error. + * @ref xdg_toplevel_resize_edge + */ +static inline bool +xdg_toplevel_resize_edge_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_TOPLEVEL_RESIZE_EDGE_NONE: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_TOP: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_LEFT: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_RIGHT: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT: + return version >= 1; + case XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_TOPLEVEL_RESIZE_EDGE_ENUM */ + +#ifndef XDG_TOPLEVEL_STATE_ENUM +#define XDG_TOPLEVEL_STATE_ENUM +/** + * @ingroup iface_xdg_toplevel + * types of state on the surface + * + * The different state values used on the surface. This is designed for + * state values like maximized, fullscreen. It is paired with the + * configure event to ensure that both the client and the compositor + * setting the state can be synchronized. + * + * States set in this way are double-buffered, see wl_surface.commit. + */ +enum xdg_toplevel_state { + /** + * the surface is maximized + * the surface is maximized + * + * The surface is maximized. The window geometry specified in the + * configure event must be obeyed by the client, or the + * xdg_wm_base.invalid_surface_state error is raised. + * + * The client should draw without shadow or other decoration + * outside of the window geometry. + */ + XDG_TOPLEVEL_STATE_MAXIMIZED = 1, + /** + * the surface is fullscreen + * the surface is fullscreen + * + * The surface is fullscreen. The window geometry specified in + * the configure event is a maximum; the client cannot resize + * beyond it. For a surface to cover the whole fullscreened area, + * the geometry dimensions must be obeyed by the client. For more + * details, see xdg_toplevel.set_fullscreen. + */ + XDG_TOPLEVEL_STATE_FULLSCREEN = 2, + /** + * the surface is being resized + * the surface is being resized + * + * The surface is being resized. The window geometry specified in + * the configure event is a maximum; the client cannot resize + * beyond it. Clients that have aspect ratio or cell sizing + * configuration can use a smaller size, however. + */ + XDG_TOPLEVEL_STATE_RESIZING = 3, + /** + * the surface is now activated + * the surface is now activated + * + * Client window decorations should be painted as if the window + * is active. Do not assume this means that the window actually has + * keyboard or pointer focus. + */ + XDG_TOPLEVEL_STATE_ACTIVATED = 4, + /** + * the surface’s left edge is tiled + * + * The window is currently in a tiled layout and the left edge is + * considered to be adjacent to another part of the tiling grid. + * + * The client should draw without shadow or other decoration + * outside of the window geometry on the left edge. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_LEFT = 5, + /** + * the surface’s right edge is tiled + * + * The window is currently in a tiled layout and the right edge + * is considered to be adjacent to another part of the tiling grid. + * + * The client should draw without shadow or other decoration + * outside of the window geometry on the right edge. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_RIGHT = 6, + /** + * the surface’s top edge is tiled + * + * The window is currently in a tiled layout and the top edge is + * considered to be adjacent to another part of the tiling grid. + * + * The client should draw without shadow or other decoration + * outside of the window geometry on the top edge. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_TOP = 7, + /** + * the surface’s bottom edge is tiled + * + * The window is currently in a tiled layout and the bottom edge + * is considered to be adjacent to another part of the tiling grid. + * + * The client should draw without shadow or other decoration + * outside of the window geometry on the bottom edge. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_BOTTOM = 8, + /** + * surface repaint is suspended + * + * The surface is currently not ordinarily being repainted; for + * example because its content is occluded by another window, or + * its outputs are switched off due to screen locking. + * @since 6 + */ + XDG_TOPLEVEL_STATE_SUSPENDED = 9, + /** + * the surface’s left edge is constrained + * + * The left edge of the window is currently constrained, meaning + * it shouldn't attempt to resize from that edge. It can for + * example mean it's tiled next to a monitor edge on the + * constrained side of the window. + * @since 7 + */ + XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT = 10, + /** + * the surface’s right edge is constrained + * + * The right edge of the window is currently constrained, meaning + * it shouldn't attempt to resize from that edge. It can for + * example mean it's tiled next to a monitor edge on the + * constrained side of the window. + * @since 7 + */ + XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT = 11, + /** + * the surface’s top edge is constrained + * + * The top edge of the window is currently constrained, meaning + * it shouldn't attempt to resize from that edge. It can for + * example mean it's tiled next to a monitor edge on the + * constrained side of the window. + * @since 7 + */ + XDG_TOPLEVEL_STATE_CONSTRAINED_TOP = 12, + /** + * the surface’s bottom edge is tiled + * + * The bottom edge of the window is currently constrained, + * meaning it shouldn't attempt to resize from that edge. It can + * for example mean it's tiled next to a monitor edge on the + * constrained side of the window. + * @since 7 + */ + XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM = 13, +}; +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_TOP_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_BOTTOM_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION 6 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT_SINCE_VERSION 7 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT_SINCE_VERSION 7 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_CONSTRAINED_TOP_SINCE_VERSION 7 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM_SINCE_VERSION 7 +/** + * @ingroup iface_xdg_toplevel + * Validate a xdg_toplevel state value. + * + * @return true on success, false on error. + * @ref xdg_toplevel_state + */ +static inline bool +xdg_toplevel_state_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_TOPLEVEL_STATE_MAXIMIZED: + return version >= 1; + case XDG_TOPLEVEL_STATE_FULLSCREEN: + return version >= 1; + case XDG_TOPLEVEL_STATE_RESIZING: + return version >= 1; + case XDG_TOPLEVEL_STATE_ACTIVATED: + return version >= 1; + case XDG_TOPLEVEL_STATE_TILED_LEFT: + return version >= 2; + case XDG_TOPLEVEL_STATE_TILED_RIGHT: + return version >= 2; + case XDG_TOPLEVEL_STATE_TILED_TOP: + return version >= 2; + case XDG_TOPLEVEL_STATE_TILED_BOTTOM: + return version >= 2; + case XDG_TOPLEVEL_STATE_SUSPENDED: + return version >= 6; + case XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT: + return version >= 7; + case XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT: + return version >= 7; + case XDG_TOPLEVEL_STATE_CONSTRAINED_TOP: + return version >= 7; + case XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM: + return version >= 7; + default: + return false; + } +} +#endif /* XDG_TOPLEVEL_STATE_ENUM */ + +#ifndef XDG_TOPLEVEL_WM_CAPABILITIES_ENUM +#define XDG_TOPLEVEL_WM_CAPABILITIES_ENUM +enum xdg_toplevel_wm_capabilities { + /** + * show_window_menu is available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU = 1, + /** + * set_maximized and unset_maximized are available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE = 2, + /** + * set_fullscreen and unset_fullscreen are available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN = 3, + /** + * set_minimized is available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE = 4, +}; +/** + * @ingroup iface_xdg_toplevel + * Validate a xdg_toplevel wm_capabilities value. + * + * @return true on success, false on error. + * @ref xdg_toplevel_wm_capabilities + */ +static inline bool +xdg_toplevel_wm_capabilities_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU: + return version >= 1; + case XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE: + return version >= 1; + case XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN: + return version >= 1; + case XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_TOPLEVEL_WM_CAPABILITIES_ENUM */ + +/** + * @ingroup iface_xdg_toplevel + * @struct xdg_toplevel_interface + */ +struct xdg_toplevel_interface { + /** + * destroy the xdg_toplevel + * + * This request destroys the role surface and unmaps the surface; + * see "Unmapping" behavior in interface section for details. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * set the parent of this surface + * + * Set the "parent" of this surface. This surface should be + * stacked above the parent surface and all other ancestor + * surfaces. + * + * Parent surfaces should be set on dialogs, toolboxes, or other + * "auxiliary" surfaces, so that the parent is raised when the + * dialog is raised. + * + * Setting a null parent for a child surface unsets its parent. + * Setting a null parent for a surface which currently has no + * parent is a no-op. + * + * Only mapped surfaces can have child surfaces. Setting a parent + * which is not mapped is equivalent to setting a null parent. If a + * surface becomes unmapped, its children's parent is set to the + * parent of the now-unmapped surface. If the now-unmapped surface + * has no parent, its children's parent is unset. If the + * now-unmapped surface becomes mapped again, its parent-child + * relationship is not restored. + * + * The parent toplevel must not be one of the child toplevel's + * descendants, and the parent must be different from the child + * toplevel, otherwise the invalid_parent protocol error is raised. + */ + void (*set_parent)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *parent); + /** + * set surface title + * + * Set a short title for the surface. + * + * This string may be used to identify the surface in a task bar, + * window list, or other user interface elements provided by the + * compositor. + * + * The string must be encoded in UTF-8. + */ + void (*set_title)(struct wl_client *client, + struct wl_resource *resource, + const char *title); + /** + * set application ID + * + * Set an application identifier for the surface. + * + * The app ID identifies the general class of applications to which + * the surface belongs. The compositor can use this to group + * multiple surfaces together, or to determine how to launch a new + * application. + * + * For D-Bus activatable applications, the app ID is used as the + * D-Bus service name. + * + * The compositor shell will try to group application surfaces + * together by their app ID. As a best practice, it is suggested to + * select app ID's that match the basename of the application's + * .desktop file. For example, "org.freedesktop.FooViewer" where + * the .desktop file is "org.freedesktop.FooViewer.desktop". + * + * Like other properties, a set_app_id request can be sent after + * the xdg_toplevel has been mapped to update the property. + * + * See the desktop-entry specification [0] for more details on + * application identifiers and how they relate to well-known D-Bus + * names and .desktop files. + * + * [0] https://standards.freedesktop.org/desktop-entry-spec/ + */ + void (*set_app_id)(struct wl_client *client, + struct wl_resource *resource, + const char *app_id); + /** + * show the window menu + * + * Clients implementing client-side decorations might want to + * show a context menu when right-clicking on the decorations, + * giving the user a menu that they can use to maximize or minimize + * the window. + * + * This request asks the compositor to pop up such a window menu at + * the given position, relative to the local surface coordinates of + * the parent surface. There are no guarantees as to what menu + * items the window menu contains, or even if a window menu will be + * drawn at all. + * + * This request must be used in response to some sort of user + * action like a button press, key press, or touch down event. + * @param seat the wl_seat of the user event + * @param serial the serial of the user event + * @param x the x position to pop up the window menu at + * @param y the y position to pop up the window menu at + */ + void (*show_window_menu)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat, + uint32_t serial, + int32_t x, + int32_t y); + /** + * start an interactive move + * + * Start an interactive, user-driven move of the surface. + * + * This request must be used in response to some sort of user + * action like a button press, key press, or touch down event. The + * passed serial is used to determine the type of interactive move + * (touch, pointer, etc). + * + * The server may ignore move requests depending on the state of + * the surface (e.g. fullscreen or maximized), or if the passed + * serial is no longer valid. + * + * If triggered, the surface will lose the focus of the device + * (wl_pointer, wl_touch, etc) used for the move. It is up to the + * compositor to visually indicate that the move is taking place, + * such as updating a pointer cursor, during the move. There is no + * guarantee that the device focus will return when the move is + * completed. + * @param seat the wl_seat of the user event + * @param serial the serial of the user event + */ + void (*move)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat, + uint32_t serial); + /** + * start an interactive resize + * + * Start a user-driven, interactive resize of the surface. + * + * This request must be used in response to some sort of user + * action like a button press, key press, or touch down event. The + * passed serial is used to determine the type of interactive + * resize (touch, pointer, etc). + * + * The server may ignore resize requests depending on the state of + * the surface (e.g. fullscreen or maximized). + * + * If triggered, the client will receive configure events with the + * "resize" state enum value and the expected sizes. See the + * "resize" enum value for more details about what is required. The + * client must also acknowledge configure events using + * "ack_configure". After the resize is completed, the client will + * receive another "configure" event without the resize state. + * + * If triggered, the surface also will lose the focus of the device + * (wl_pointer, wl_touch, etc) used for the resize. It is up to the + * compositor to visually indicate that the resize is taking place, + * such as updating a pointer cursor, during the resize. There is + * no guarantee that the device focus will return when the resize + * is completed. + * + * The edges parameter specifies how the surface should be resized, + * and is one of the values of the resize_edge enum. Values not + * matching a variant of the enum will cause the + * invalid_resize_edge protocol error. The compositor may use this + * information to update the surface position for example when + * dragging the top left corner. The compositor may also use this + * information to adapt its behavior, e.g. choose an appropriate + * cursor image. + * @param seat the wl_seat of the user event + * @param serial the serial of the user event + * @param edges which edge or corner is being dragged + */ + void (*resize)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat, + uint32_t serial, + uint32_t edges); + /** + * set the maximum size + * + * Set a maximum size for the window. + * + * The client can specify a maximum size so that the compositor + * does not try to configure the window beyond this size. + * + * The width and height arguments are in window geometry + * coordinates. See xdg_surface.set_window_geometry. + * + * Values set in this way are double-buffered, see + * wl_surface.commit. + * + * The compositor can use this information to allow or disallow + * different states like maximize or fullscreen and draw accurate + * animations. + * + * Similarly, a tiling window manager may use this information to + * place and resize client windows in a more effective way. + * + * The client should not rely on the compositor to obey the maximum + * size. The compositor may decide to ignore the values set by the + * client and request a larger size. + * + * If never set, or a value of zero in the request, means that the + * client has no expected maximum size in the given dimension. As a + * result, a client wishing to reset the maximum size to an + * unspecified state can use zero for width and height in the + * request. + * + * Requesting a maximum size to be smaller than the minimum size of + * a surface is illegal and will result in an invalid_size error. + * + * The width and height must be greater than or equal to zero. + * Using strictly negative values for width or height will result + * in a invalid_size error. + */ + void (*set_max_size)(struct wl_client *client, + struct wl_resource *resource, + int32_t width, + int32_t height); + /** + * set the minimum size + * + * Set a minimum size for the window. + * + * The client can specify a minimum size so that the compositor + * does not try to configure the window below this size. + * + * The width and height arguments are in window geometry + * coordinates. See xdg_surface.set_window_geometry. + * + * Values set in this way are double-buffered, see + * wl_surface.commit. + * + * The compositor can use this information to allow or disallow + * different states like maximize or fullscreen and draw accurate + * animations. + * + * Similarly, a tiling window manager may use this information to + * place and resize client windows in a more effective way. + * + * The client should not rely on the compositor to obey the minimum + * size. The compositor may decide to ignore the values set by the + * client and request a smaller size. + * + * If never set, or a value of zero in the request, means that the + * client has no expected minimum size in the given dimension. As a + * result, a client wishing to reset the minimum size to an + * unspecified state can use zero for width and height in the + * request. + * + * Requesting a minimum size to be larger than the maximum size of + * a surface is illegal and will result in an invalid_size error. + * + * The width and height must be greater than or equal to zero. + * Using strictly negative values for width and height will result + * in a invalid_size error. + */ + void (*set_min_size)(struct wl_client *client, + struct wl_resource *resource, + int32_t width, + int32_t height); + /** + * maximize the window + * + * Maximize the surface. + * + * After requesting that the surface should be maximized, the + * compositor will respond by emitting a configure event. Whether + * this configure actually sets the window maximized is subject to + * compositor policies. The client must then update its content, + * drawing in the configured state. The client must also + * acknowledge the configure when committing the new content (see + * ack_configure). + * + * It is up to the compositor to decide how and where to maximize + * the surface, for example which output and what region of the + * screen should be used. + * + * If the surface was already maximized, the compositor will still + * emit a configure event with the "maximized" state. + * + * If the surface is in a fullscreen state, this request has no + * direct effect. It may alter the state the surface is returned to + * when unmaximized unless overridden by the compositor. + */ + void (*set_maximized)(struct wl_client *client, + struct wl_resource *resource); + /** + * unmaximize the window + * + * Unmaximize the surface. + * + * After requesting that the surface should be unmaximized, the + * compositor will respond by emitting a configure event. Whether + * this actually un-maximizes the window is subject to compositor + * policies. If available and applicable, the compositor will + * include the window geometry dimensions the window had prior to + * being maximized in the configure event. The client must then + * update its content, drawing it in the configured state. The + * client must also acknowledge the configure when committing the + * new content (see ack_configure). + * + * It is up to the compositor to position the surface after it was + * unmaximized; usually the position the surface had before + * maximizing, if applicable. + * + * If the surface was already not maximized, the compositor will + * still emit a configure event without the "maximized" state. + * + * If the surface is in a fullscreen state, this request has no + * direct effect. It may alter the state the surface is returned to + * when unmaximized unless overridden by the compositor. + */ + void (*unset_maximized)(struct wl_client *client, + struct wl_resource *resource); + /** + * set the window as fullscreen on an output + * + * Make the surface fullscreen. + * + * After requesting that the surface should be fullscreened, the + * compositor will respond by emitting a configure event. Whether + * the client is actually put into a fullscreen state is subject to + * compositor policies. The client must also acknowledge the + * configure when committing the new content (see ack_configure). + * + * The output passed by the request indicates the client's + * preference as to which display it should be set fullscreen on. + * If this value is NULL, it's up to the compositor to choose which + * display will be used to map this surface. + * + * If the surface doesn't cover the whole output, the compositor + * will position the surface in the center of the output and + * compensate with with border fill covering the rest of the + * output. The content of the border fill is undefined, but should + * be assumed to be in some way that attempts to blend into the + * surrounding area (e.g. solid black). + * + * If the fullscreened surface is not opaque, the compositor must + * make sure that other screen content not part of the same surface + * tree (made up of subsurfaces, popups or similarly coupled + * surfaces) are not visible below the fullscreened surface. + */ + void (*set_fullscreen)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *output); + /** + * unset the window as fullscreen + * + * Make the surface no longer fullscreen. + * + * After requesting that the surface should be unfullscreened, the + * compositor will respond by emitting a configure event. Whether + * this actually removes the fullscreen state of the client is + * subject to compositor policies. + * + * Making a surface unfullscreen sets states for the surface based + * on the following: * the state(s) it may have had before becoming + * fullscreen * any state(s) decided by the compositor * any + * state(s) requested by the client while the surface was + * fullscreen + * + * The compositor may include the previous window geometry + * dimensions in the configure event, if applicable. + * + * The client must also acknowledge the configure when committing + * the new content (see ack_configure). + */ + void (*unset_fullscreen)(struct wl_client *client, + struct wl_resource *resource); + /** + * set the window as minimized + * + * Request that the compositor minimize your surface. There is no + * way to know if the surface is currently minimized, nor is there + * any way to unset minimization on this surface. + * + * If you are looking to throttle redrawing when minimized, please + * instead use the wl_surface.frame event for this, as this will + * also work with live previews on windows in Alt-Tab, Expose or + * similar compositor features. + */ + void (*set_minimized)(struct wl_client *client, + struct wl_resource *resource); +}; + +#define XDG_TOPLEVEL_CONFIGURE 0 +#define XDG_TOPLEVEL_CLOSE 1 +#define XDG_TOPLEVEL_CONFIGURE_BOUNDS 2 +#define XDG_TOPLEVEL_WM_CAPABILITIES 3 + +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CLOSE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION 4 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION 5 + +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_PARENT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_TITLE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_APP_ID_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SHOW_WINDOW_MENU_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_MOVE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_RESIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MAX_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MIN_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_UNSET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_UNSET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MINIMIZED_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_toplevel + * Sends an configure event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +xdg_toplevel_send_configure(struct wl_resource *resource_, int32_t width, int32_t height, struct wl_array *states) +{ + wl_resource_post_event(resource_, XDG_TOPLEVEL_CONFIGURE, width, height, states); +} + +/** + * @ingroup iface_xdg_toplevel + * Sends an close event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +xdg_toplevel_send_close(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, XDG_TOPLEVEL_CLOSE); +} + +/** + * @ingroup iface_xdg_toplevel + * Sends an configure_bounds event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +xdg_toplevel_send_configure_bounds(struct wl_resource *resource_, int32_t width, int32_t height) +{ + wl_resource_post_event(resource_, XDG_TOPLEVEL_CONFIGURE_BOUNDS, width, height); +} + +/** + * @ingroup iface_xdg_toplevel + * Sends an wm_capabilities event to the client owning the resource. + * @param resource_ The client's resource + * @param capabilities array of 32-bit capabilities + */ +static inline void +xdg_toplevel_send_wm_capabilities(struct wl_resource *resource_, struct wl_array *capabilities) +{ + wl_resource_post_event(resource_, XDG_TOPLEVEL_WM_CAPABILITIES, capabilities); +} + +#ifndef XDG_POPUP_ERROR_ENUM +#define XDG_POPUP_ERROR_ENUM +enum xdg_popup_error { + /** + * tried to grab after being mapped + */ + XDG_POPUP_ERROR_INVALID_GRAB = 0, +}; +/** + * @ingroup iface_xdg_popup + * Validate a xdg_popup error value. + * + * @return true on success, false on error. + * @ref xdg_popup_error + */ +static inline bool +xdg_popup_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case XDG_POPUP_ERROR_INVALID_GRAB: + return version >= 1; + default: + return false; + } +} +#endif /* XDG_POPUP_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_popup + * @struct xdg_popup_interface + */ +struct xdg_popup_interface { + /** + * remove xdg_popup interface + * + * This destroys the popup. Explicitly destroying the xdg_popup + * object will also dismiss the popup, and unmap the surface. + * + * If this xdg_popup is not the "topmost" popup, the + * xdg_wm_base.not_the_topmost_popup protocol error will be sent. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * make the popup take an explicit grab + * + * This request makes the created popup take an explicit grab. An + * explicit grab will be dismissed when the user dismisses the + * popup, or when the client destroys the xdg_popup. This can be + * done by the user clicking outside the surface, using the + * keyboard, or even locking the screen through closing the lid or + * a timeout. + * + * If the compositor denies the grab, the popup will be immediately + * dismissed. + * + * This request must be used in response to some sort of user + * action like a button press, key press, or touch down event. The + * serial number of the event should be passed as 'serial'. + * + * The parent of a grabbing popup must either be an xdg_toplevel + * surface or another xdg_popup with an explicit grab. If the + * parent is another xdg_popup it means that the popups are nested, + * with this popup now being the topmost popup. + * + * Nested popups must be destroyed in the reverse order they were + * created in, e.g. the only popup you are allowed to destroy at + * all times is the topmost one. + * + * When compositors choose to dismiss a popup, they may dismiss + * every nested grabbing popup as well. When a compositor dismisses + * popups, it will follow the same dismissing order as required + * from the client. + * + * If the topmost grabbing popup is destroyed, the grab will be + * returned to the parent of the popup, if that parent previously + * had an explicit grab. + * + * If the parent is a grabbing popup which has already been + * dismissed, this popup will be immediately dismissed. If the + * parent is a popup that did not take an explicit grab, an error + * will be raised. + * + * During a popup grab, the client owning the grab will receive + * pointer and touch events for all their surfaces as normal + * (similar to an "owner-events" grab in X11 parlance), while the + * top most grabbing popup will always have keyboard focus. + * @param seat the wl_seat of the user event + * @param serial the serial of the user event + */ + void (*grab)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat, + uint32_t serial); + /** + * recalculate the popup's location + * + * Reposition an already-mapped popup. The popup will be placed + * given the details in the passed xdg_positioner object, and a + * xdg_popup.repositioned followed by xdg_popup.configure and + * xdg_surface.configure will be emitted in response. Any + * parameters set by the previous positioner will be discarded. + * + * The passed token will be sent in the corresponding + * xdg_popup.repositioned event. The new popup position will not + * take effect until the corresponding configure event is + * acknowledged by the client. See xdg_popup.repositioned for + * details. The token itself is opaque, and has no other special + * meaning. + * + * If multiple reposition requests are sent, the compositor may + * skip all but the last one. + * + * If the popup is repositioned in response to a configure event + * for its parent, the client should send an + * xdg_positioner.set_parent_configure and possibly an + * xdg_positioner.set_parent_size request to allow the compositor + * to properly constrain the popup. + * + * If the popup is repositioned together with a parent that is + * being resized, but not in response to a configure event, the + * client should send an xdg_positioner.set_parent_size request. + * @param token reposition request token + * @since 3 + */ + void (*reposition)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *positioner, + uint32_t token); +}; + +#define XDG_POPUP_CONFIGURE 0 +#define XDG_POPUP_POPUP_DONE 1 +#define XDG_POPUP_REPOSITIONED 2 + +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_POPUP_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_REPOSITIONED_SINCE_VERSION 3 + +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_GRAB_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_REPOSITION_SINCE_VERSION 3 + +/** + * @ingroup iface_xdg_popup + * Sends an configure event to the client owning the resource. + * @param resource_ The client's resource + * @param x x position relative to parent surface window geometry + * @param y y position relative to parent surface window geometry + * @param width window geometry width + * @param height window geometry height + */ +static inline void +xdg_popup_send_configure(struct wl_resource *resource_, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_resource_post_event(resource_, XDG_POPUP_CONFIGURE, x, y, width, height); +} + +/** + * @ingroup iface_xdg_popup + * Sends an popup_done event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +xdg_popup_send_popup_done(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, XDG_POPUP_POPUP_DONE); +} + +/** + * @ingroup iface_xdg_popup + * Sends an repositioned event to the client owning the resource. + * @param resource_ The client's resource + * @param token reposition request token + */ +static inline void +xdg_popup_send_repositioned(struct wl_resource *resource_, uint32_t token) +{ + wl_resource_post_event(resource_, XDG_POPUP_REPOSITIONED, token); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libqtile/backend/x11/window.py b/libqtile/backend/x11/window.py index fd640ac9da..52e2dbcb33 100644 --- a/libqtile/backend/x11/window.py +++ b/libqtile/backend/x11/window.py @@ -15,8 +15,7 @@ from libqtile import hook, utils from libqtile.backend import base -from libqtile.backend.base import FloatStates -from libqtile.backend.base.zmanager import LayerGroup +from libqtile.backend.base import FloatStates, LayerGroup from libqtile.backend.x11 import xcbq from libqtile.backend.x11.drawer import Drawer from libqtile.command.base import CommandError, expose_command diff --git a/libqtile/backend/x11/zmanager.py b/libqtile/backend/x11/zmanager.py index fd932beb7e..e37e8e431b 100644 --- a/libqtile/backend/x11/zmanager.py +++ b/libqtile/backend/x11/zmanager.py @@ -17,19 +17,36 @@ # 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. +from contextlib import wraps + import xcffib.xproto from libqtile import hook -from libqtile.backend.base import zmanager +from libqtile.backend.base import LayerGroup from libqtile.backend.base.window import _Window -from libqtile.backend.base.zmanager import LayerGroup, check_window from libqtile.backend.x11 import window from libqtile.log_utils import logger -class ZManager(zmanager.ZManager): +def check_window(func): + """ + Decorator that requires window to be stacked before proceeding. + + The decorated method must take the window's id as the first argument. + """ + + @wraps(func) + def _wrapper(self, window, *args, **kwargs): + if not self.is_stacked(window): + return + return func(self, window, *args, **kwargs) + + return _wrapper + + +class ZManager: def __init__(self, core) -> None: - super().__init__(core) + self.core = core self.layers: dict[LayerGroup, list[_Window]] = {l: [] for l in LayerGroup} self.layer_map: dict[_Window, tuple(LayerGroup, int)] = {} hook.subscribe.client_focus(self._restack_on_focus_change) From 52ccaba2a3f40135d6e742d5aeb9a1e071e276d8 Mon Sep 17 00:00:00 2001 From: elParaguayo Date: Mon, 18 Aug 2025 19:35:58 +0100 Subject: [PATCH 14/14] Fixing pre-commit check errors --- libqtile/backend/base/stacking.py | 1 + libqtile/backend/x11/window.py | 3 +++ libqtile/backend/x11/zmanager.py | 15 +++++++-------- test/backend/x11/test_window.py | 4 +++- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/libqtile/backend/base/stacking.py b/libqtile/backend/base/stacking.py index 25231b205c..0d2c305178 100644 --- a/libqtile/backend/base/stacking.py +++ b/libqtile/backend/base/stacking.py @@ -26,6 +26,7 @@ class LayerGroup(IntEnum): so backends will need to map behaviour accordingly. However, a common object allows us have more common code across backends. """ + BACKGROUND = 0 BOTTOM = 1 KEEP_BELOW = 2 diff --git a/libqtile/backend/x11/window.py b/libqtile/backend/x11/window.py index 52e2dbcb33..3292a5afad 100644 --- a/libqtile/backend/x11/window.py +++ b/libqtile/backend/x11/window.py @@ -1270,6 +1270,9 @@ def bring_to_front(self): if self.get_wm_type() != "desktop": self.change_layer(layer=LayerGroup.BRING_TO_FRONT) + def is_visible(self): + return not self.hidden + class Internal(_Window, base.Internal): """An internal window, that should not be managed by qtile""" diff --git a/libqtile/backend/x11/zmanager.py b/libqtile/backend/x11/zmanager.py index e37e8e431b..4fdbe05cc2 100644 --- a/libqtile/backend/x11/zmanager.py +++ b/libqtile/backend/x11/zmanager.py @@ -17,14 +17,13 @@ # 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. -from contextlib import wraps +from functools import wraps import xcffib.xproto from libqtile import hook from libqtile.backend.base import LayerGroup -from libqtile.backend.base.window import _Window -from libqtile.backend.x11 import window +from libqtile.backend.x11.window import Window, _Window from libqtile.log_utils import logger @@ -48,7 +47,7 @@ class ZManager: def __init__(self, core) -> None: self.core = core self.layers: dict[LayerGroup, list[_Window]] = {l: [] for l in LayerGroup} - self.layer_map: dict[_Window, tuple(LayerGroup, int)] = {} + self.layer_map: dict[_Window, tuple[LayerGroup, int]] = {} hook.subscribe.client_focus(self._restack_on_focus_change) def is_stacked(self, window: _Window) -> bool: @@ -103,7 +102,7 @@ def get_sibling(self, window) -> tuple[_Window | None, bool]: stack = self.get_z_order() if len(stack) == 1: return (None, True) - + idx = stack.index(window) if idx == 0: return (stack[1], False) @@ -147,7 +146,7 @@ def replace_window(self, old_window, new_window) -> None: self.update_client_lists() @check_window - def move_up(self, window) -> None: + def move_up(self, window: _Window) -> None: layer, cur_idx = self.layer_map[window] visible = [ w for w in self.layers[layer] if w.is_visible() and w.group in (window.group, None) @@ -168,7 +167,7 @@ def move_down(self, window) -> None: if layer == LayerGroup.BRING_TO_FRONT: window.change_layer() - layer, cur_idx = self.layer_map[window] + layer, cur_idx = self.layer_map[window] visible = [ w for w in self.layers[layer] if w.is_visible() and w.group in (window.group, None) @@ -271,7 +270,7 @@ def update_client_lists(self): assert self.core.qtile z_order = self.get_z_order() # Regular top-level managed windows, i.e. excluding Static, Internal and Systray Icons - wids = [win.wid for win in z_order if isinstance(win, window.Window)] + wids = [win.wid for win in z_order if isinstance(win, Window)] self.core._root.set_property("_NET_CLIENT_LIST", wids) self.core._root.set_property("_NET_CLIENT_LIST_STACKING", [win.wid for win in z_order]) diff --git a/test/backend/x11/test_window.py b/test/backend/x11/test_window.py index d74e6e51d7..e39843840d 100644 --- a/test/backend/x11/test_window.py +++ b/test/backend/x11/test_window.py @@ -31,7 +31,9 @@ class ManagerConfigNormalFloats(ManagerConfig): bare_config = pytest.mark.parametrize("xmanager", [BareConfig], indirect=True) manager_config = pytest.mark.parametrize("xmanager", [ManagerConfig], indirect=True) -manager_config_normal_floats = pytest.mark.parametrize("xmanager", [ManagerConfigNormalFloats], indirect=True) +manager_config_normal_floats = pytest.mark.parametrize( + "xmanager", [ManagerConfigNormalFloats], indirect=True +) @manager_config