From 7b87b268e34c84b379a5bc390af4286b0cad76be Mon Sep 17 00:00:00 2001 From: Riccardo Canalicchio Date: Mon, 25 Oct 2021 03:12:56 -0400 Subject: [PATCH] wayland backend: layer shell --- Headers/wayland/WaylandServer.h | 7 +- .../wayland/wlr-layer-shell-client-protocol.h | 597 ++++++++++++++++++ Headers/wayland/xdg-shell-client-protocol.h | 154 ++++- Source/cairo/WaylandCairoSurface.m | 2 +- Source/wayland/GNUmakefile | 1 + Source/wayland/WaylandServer.m | 368 +++++++---- .../protocols/wlr-layer-shell-unstable-v1.xml | 311 +++++++++ Source/wayland/wlr-layer-shell-protocol.c | 83 +++ Source/wayland/xdg-shell-protocol.c | 103 +-- 9 files changed, 1427 insertions(+), 199 deletions(-) create mode 100644 Headers/wayland/wlr-layer-shell-client-protocol.h create mode 100644 Source/wayland/protocols/wlr-layer-shell-unstable-v1.xml create mode 100644 Source/wayland/wlr-layer-shell-protocol.c diff --git a/Headers/wayland/WaylandServer.h b/Headers/wayland/WaylandServer.h index 5feb217..a74eb4b 100644 --- a/Headers/wayland/WaylandServer.h +++ b/Headers/wayland/WaylandServer.h @@ -38,6 +38,7 @@ #include "cairo/WaylandCairoSurface.h" #include "wayland/xdg-shell-client-protocol.h" +#include "wayland/wlr-layer-shell-client-protocol.h" struct pointer { struct wl_pointer *wlpointer; @@ -61,6 +62,7 @@ typedef struct _WaylandConfig { struct wl_seat *seat; struct wl_keyboard *keyboard; struct xdg_wm_base *wm_base; + struct zwlr_layer_shell_v1 *layer_shell; struct wl_list output_list; int output_count; @@ -116,13 +118,16 @@ struct window { float saved_pos_x; float saved_pos_y; int is_out; + int level; unsigned char *data; struct wl_buffer *buffer; struct wl_surface *surface; struct xdg_surface *xdg_surface; struct xdg_toplevel *toplevel; - + struct xdg_popup *popup; + struct xdg_positioner *positioner; + struct zwlr_layer_surface_v1 *layer_surface; struct output *output; WaylandCairoSurface *wcs; }; diff --git a/Headers/wayland/wlr-layer-shell-client-protocol.h b/Headers/wayland/wlr-layer-shell-client-protocol.h new file mode 100644 index 0000000..a3be2fd --- /dev/null +++ b/Headers/wayland/wlr-layer-shell-client-protocol.h @@ -0,0 +1,597 @@ +/* Generated by wayland-scanner 1.18.0 */ + +#ifndef WLR_LAYER_SHELL_UNSTABLE_V1_CLIENT_PROTOCOL_H +#define WLR_LAYER_SHELL_UNSTABLE_V1_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @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; + +/** + * @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; +/** + * @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. + * @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. + */ +extern const struct wl_interface zwlr_layer_surface_v1_interface; + +#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, +}; +#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, +}; +#endif /* ZWLR_LAYER_SHELL_V1_LAYER_ENUM */ + +#define ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE 0 +#define ZWLR_LAYER_SHELL_V1_DESTROY 1 + + +/** + * @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 + +/** @ingroup iface_zwlr_layer_shell_v1 */ +static inline void +zwlr_layer_shell_v1_set_user_data(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwlr_layer_shell_v1, user_data); +} + +/** @ingroup iface_zwlr_layer_shell_v1 */ +static inline void * +zwlr_layer_shell_v1_get_user_data(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwlr_layer_shell_v1); +} + +static inline uint32_t +zwlr_layer_shell_v1_get_version(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zwlr_layer_shell_v1); +} + +/** + * @ingroup iface_zwlr_layer_shell_v1 + * + * 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. + * + * 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. + */ +static inline struct zwlr_layer_surface_v1 * +zwlr_layer_shell_v1_get_layer_surface(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1, struct wl_surface *surface, struct wl_output *output, uint32_t layer, const char *namespace) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) zwlr_layer_shell_v1, + ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE, &zwlr_layer_surface_v1_interface, NULL, surface, output, layer, namespace); + + return (struct zwlr_layer_surface_v1 *) id; +} + +/** + * @ingroup iface_zwlr_layer_shell_v1 + * + * 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. + */ +static inline void +zwlr_layer_shell_v1_destroy(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1) +{ + wl_proxy_marshal((struct wl_proxy *) zwlr_layer_shell_v1, + ZWLR_LAYER_SHELL_V1_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) zwlr_layer_shell_v1); +} + +#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, +}; +#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, +}; +#endif /* ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM */ + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * @struct zwlr_layer_surface_v1_listener + */ +struct zwlr_layer_surface_v1_listener { + /** + * suggest a surface change + * + * The configure event asks the client to resize its surface. + * + * Clients should arrange their surface for the new states, and + * then send an ack_configure request with the serial sent in this + * configure event at some point before committing the new surface. + * + * The client is free to dismiss all but the last configure event + * it received. + * + * The width and height arguments specify the size of the window in + * surface-local coordinates. + * + * The size is a hint, in the sense that the client is free to + * ignore it if it doesn't resize, pick a smaller size (to satisfy + * aspect ratio or resize in steps of NxM pixels). If the client + * picks a smaller size and is anchored to two opposite anchors + * (e.g. 'top' and 'bottom'), the surface will be centered on this + * axis. + * + * If the width or height arguments are zero, it means the client + * should decide its own window dimension. + */ + void (*configure)(void *data, + struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, + uint32_t serial, + uint32_t width, + uint32_t height); + /** + * surface should be closed + * + * The closed event is sent by the compositor when the surface + * will no longer be shown. The output may have been destroyed or + * the user may have asked for it to be removed. Further changes to + * the surface will be ignored. The client should destroy the + * resource after receiving this event, and create a new surface if + * they so choose. + */ + void (*closed)(void *data, + struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1); +}; + +/** + * @ingroup iface_zwlr_layer_surface_v1 + */ +static inline int +zwlr_layer_surface_v1_add_listener(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, + const struct zwlr_layer_surface_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwlr_layer_surface_v1, + (void (**)(void)) listener, data); +} + +#define ZWLR_LAYER_SURFACE_V1_SET_SIZE 0 +#define ZWLR_LAYER_SURFACE_V1_SET_ANCHOR 1 +#define ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE 2 +#define ZWLR_LAYER_SURFACE_V1_SET_MARGIN 3 +#define ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY 4 +#define ZWLR_LAYER_SURFACE_V1_GET_POPUP 5 +#define ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE 6 +#define ZWLR_LAYER_SURFACE_V1_DESTROY 7 +#define ZWLR_LAYER_SURFACE_V1_SET_LAYER 8 + +/** + * @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 */ +static inline void +zwlr_layer_surface_v1_set_user_data(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwlr_layer_surface_v1, user_data); +} + +/** @ingroup iface_zwlr_layer_surface_v1 */ +static inline void * +zwlr_layer_surface_v1_get_user_data(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwlr_layer_surface_v1); +} + +static inline uint32_t +zwlr_layer_surface_v1_get_version(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1); +} + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * + * 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. + */ +static inline void +zwlr_layer_surface_v1_set_size(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t width, uint32_t height) +{ + wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1, + ZWLR_LAYER_SURFACE_V1_SET_SIZE, width, height); +} + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * + * 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. + */ +static inline void +zwlr_layer_surface_v1_set_anchor(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t anchor) +{ + wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1, + ZWLR_LAYER_SURFACE_V1_SET_ANCHOR, anchor); +} + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * + * 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. + */ +static inline void +zwlr_layer_surface_v1_set_exclusive_zone(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, int32_t zone) +{ + wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1, + ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE, zone); +} + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * + * 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. + */ +static inline void +zwlr_layer_surface_v1_set_margin(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, int32_t top, int32_t right, int32_t bottom, int32_t left) +{ + wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1, + ZWLR_LAYER_SURFACE_V1_SET_MARGIN, top, right, bottom, left); +} + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * + * Set to 1 to request that the seat send keyboard events to this layer + * surface. For layers below the shell surface layer, the seat will use + * normal focus semantics. For layers above the shell surface layers, the + * seat will always give exclusive keyboard focus to the top-most layer + * which has keyboard interactivity set to true. + * + * 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. + * + * Events is double-buffered, see wl_surface.commit. + */ +static inline void +zwlr_layer_surface_v1_set_keyboard_interactivity(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t keyboard_interactivity) +{ + wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1, + ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY, keyboard_interactivity); +} + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * + * 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. + */ +static inline void +zwlr_layer_surface_v1_get_popup(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, struct xdg_popup *popup) +{ + wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1, + ZWLR_LAYER_SURFACE_V1_GET_POPUP, popup); +} + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * + * 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. + */ +static inline void +zwlr_layer_surface_v1_ack_configure(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t serial) +{ + wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1, + ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE, serial); +} + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * + * This request destroys the layer surface. + */ +static inline void +zwlr_layer_surface_v1_destroy(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1) +{ + wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1, + ZWLR_LAYER_SURFACE_V1_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) zwlr_layer_surface_v1); +} + +/** + * @ingroup iface_zwlr_layer_surface_v1 + * + * Change the layer that the surface is rendered on. + * + * Layer is double-buffered, see wl_surface.commit. + */ +static inline void +zwlr_layer_surface_v1_set_layer(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t layer) +{ + wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1, + ZWLR_LAYER_SURFACE_V1_SET_LAYER, layer); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Headers/wayland/xdg-shell-client-protocol.h b/Headers/wayland/xdg-shell-client-protocol.h index 1f4bfb5..6e80367 100644 --- a/Headers/wayland/xdg-shell-client-protocol.h +++ b/Headers/wayland/xdg-shell-client-protocol.h @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.17.0 */ +/* Generated by wayland-scanner 1.18.0 */ #ifndef XDG_SHELL_CLIENT_PROTOCOL_H #define XDG_SHELL_CLIENT_PROTOCOL_H @@ -284,12 +284,6 @@ extern const struct wl_interface xdg_toplevel_interface; * The parent of an xdg_popup must be mapped (see the xdg_surface * description) before the xdg_popup itself. * - * The x and y arguments passed when creating the popup object specify - * where the top left of the popup should be placed, relative to the - * local surface coordinates of the parent surface. See - * xdg_surface.get_popup. An xdg_popup must intersect with or be at least - * partially adjacent to its parent surface. - * * 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 @@ -320,12 +314,6 @@ extern const struct wl_interface xdg_toplevel_interface; * The parent of an xdg_popup must be mapped (see the xdg_surface * description) before the xdg_popup itself. * - * The x and y arguments passed when creating the popup object specify - * where the top left of the popup should be placed, relative to the - * local surface coordinates of the parent surface. See - * xdg_surface.get_popup. An xdg_popup must intersect with or be at least - * partially adjacent to its parent surface. - * * The client must call wl_surface.commit on the corresponding wl_surface * for the xdg_popup state to take effect. */ @@ -587,6 +575,9 @@ enum xdg_positioner_constraint_adjustment { #define XDG_POSITIONER_SET_GRAVITY 4 #define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT 5 #define XDG_POSITIONER_SET_OFFSET 6 +#define XDG_POSITIONER_SET_REACTIVE 7 +#define XDG_POSITIONER_SET_PARENT_SIZE 8 +#define XDG_POSITIONER_SET_PARENT_CONFIGURE 9 /** @@ -617,6 +608,18 @@ enum xdg_positioner_constraint_adjustment { * @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 /** @ingroup iface_xdg_positioner */ static inline void @@ -769,6 +772,56 @@ xdg_positioner_set_offset(struct xdg_positioner *xdg_positioner, int32_t x, int3 XDG_POSITIONER_SET_OFFSET, x, y); } +/** + * @ingroup iface_xdg_positioner + * + * 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. + */ +static inline void +xdg_positioner_set_reactive(struct xdg_positioner *xdg_positioner) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_REACTIVE); +} + +/** + * @ingroup iface_xdg_positioner + * + * 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. + */ +static inline void +xdg_positioner_set_parent_size(struct xdg_positioner *xdg_positioner, int32_t parent_width, int32_t parent_height) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_PARENT_SIZE, parent_width, parent_height); +} + +/** + * @ingroup iface_xdg_positioner + * + * Set the serial of a 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. + */ +static inline void +xdg_positioner_set_parent_configure(struct xdg_positioner *xdg_positioner, uint32_t serial) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_PARENT_CONFIGURE, serial); +} + #ifndef XDG_SURFACE_ERROR_ENUM #define XDG_SURFACE_ERROR_ENUM enum xdg_surface_error { @@ -1691,6 +1744,12 @@ struct xdg_popup_listener { * The x and y arguments represent the position the popup was * placed at given the xdg_positioner rule, relative to the upper * left corner of the window geometry of the parent surface. + * + * For version 2 or older, the configure event for an xdg_popup is + * only ever sent once for the initial configuration. Starting with + * version 3, it may be sent again if the popup is setup with an + * xdg_positioner with set_reactive requested, or in response to + * xdg_popup.reposition requests. * @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 @@ -1711,6 +1770,32 @@ struct xdg_popup_listener { */ void (*popup_done)(void *data, struct xdg_popup *xdg_popup); + /** + * signal the completion of a repositioned request + * + * The repositioned event is sent as part of a popup + * configuration sequence, together with xdg_popup.configure and + * lastly xdg_surface.configure to notify the completion of a + * reposition request. + * + * The repositioned event is to notify about the completion of a + * xdg_popup.reposition request. The token argument is the token + * passed in the xdg_popup.reposition request. + * + * Immediately after this event is emitted, xdg_popup.configure and + * xdg_surface.configure will be sent with the updated size and + * position, as well as a new configure serial. + * + * The client should optionally update the content of the popup, + * but must acknowledge the new popup configuration for the new + * position to take effect. See xdg_surface.ack_configure for + * details. + * @param token reposition request token + * @since 3 + */ + void (*repositioned)(void *data, + struct xdg_popup *xdg_popup, + uint32_t token); }; /** @@ -1726,6 +1811,7 @@ xdg_popup_add_listener(struct xdg_popup *xdg_popup, #define XDG_POPUP_DESTROY 0 #define XDG_POPUP_GRAB 1 +#define XDG_POPUP_REPOSITION 2 /** * @ingroup iface_xdg_popup @@ -1735,6 +1821,10 @@ xdg_popup_add_listener(struct xdg_popup *xdg_popup, * @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 @@ -1744,6 +1834,10 @@ xdg_popup_add_listener(struct xdg_popup *xdg_popup, * @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 */ static inline void @@ -1835,6 +1929,40 @@ xdg_popup_grab(struct xdg_popup *xdg_popup, struct wl_seat *seat, uint32_t seria XDG_POPUP_GRAB, seat, serial); } +/** + * @ingroup iface_xdg_popup + * + * 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 a 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 a xdg_positioner.set_parent_size request. + */ +static inline void +xdg_popup_reposition(struct xdg_popup *xdg_popup, struct xdg_positioner *positioner, uint32_t token) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_popup, + XDG_POPUP_REPOSITION, positioner, token); +} + #ifdef __cplusplus } #endif diff --git a/Source/cairo/WaylandCairoSurface.m b/Source/cairo/WaylandCairoSurface.m index f8d709e..a7122b1 100644 --- a/Source/cairo/WaylandCairoSurface.m +++ b/Source/cairo/WaylandCairoSurface.m @@ -147,7 +147,7 @@ create_shm_buffer(struct window *window) return 0; } - if(window->toplevel != NULL && window->configured) { + if(window->configured) { // if the window has a toplevel then it should appear on screen // we can attach a buffer only if the xdg surface is configured NSDebugLog(@"wl_surface_attach: win=%d toplevel_surface", window->window_id); diff --git a/Source/wayland/GNUmakefile b/Source/wayland/GNUmakefile index 237e13c..b84fd24 100644 --- a/Source/wayland/GNUmakefile +++ b/Source/wayland/GNUmakefile @@ -40,6 +40,7 @@ wayland_LOCALIZED_RESOURCE_FILES = \ # The C source files to be compiled wayland_C_FILES = \ xdg-shell-protocol.c \ +wlr-layer-shell-protocol.c \ # The Objective-C source files to be compiled wayland_OBJC_FILES = \ diff --git a/Source/wayland/WaylandServer.m b/Source/wayland/WaylandServer.m index 7fe4c6a..a5ce15e 100644 --- a/Source/wayland/WaylandServer.m +++ b/Source/wayland/WaylandServer.m @@ -183,6 +183,7 @@ pointer_handle_leave(void *data, struct wl_pointer *pointer, // FIXME: Send NSMouseExited event. } +// triggered when the cursor is over a surface static void pointer_handle_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w) @@ -673,7 +674,6 @@ struct wl_shm_listener shm_listener = { #define XDG_SHELL -#ifdef XDG_SHELL static void xdg_surface_on_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial) @@ -767,34 +767,64 @@ static const struct xdg_wm_base_listener wm_base_listener = { .ping = wm_base_handle_ping, }; +static void layer_surface_configure(void *data, + struct zwlr_layer_surface_v1 *surface, + uint32_t serial, uint32_t w, uint32_t h) { + + NSDebugLog(@"configure layer"); + struct window *window = data; + WaylandConfig *wlconfig = window->wlconfig; + zwlr_layer_surface_v1_ack_configure(surface, serial); + window->configured = YES; + if(window->buffer_needs_attach) { + NSDebugLog(@"attach: win=%d layer", window->window_id); + wl_surface_attach(window->surface, window->buffer, 0, 0); + wl_surface_commit(window->surface); + } -#else -static void -wl_shell_surface_on_ping(void *data, struct wl_shell_surface *shell_surface, - uint32_t serial) -{ - wl_shell_surface_pong(shell_surface, serial); } -static void -wl_shell_surface_on_configure(void *data, - struct wl_shell_surface *shell_surface, - uint32_t edges, int32_t width, int32_t height) -{ +static void layer_surface_closed(void *data, + struct zwlr_layer_surface_v1 *surface) { + struct window *window = data; + WaylandConfig *wlconfig = window->wlconfig; + NSDebugLog(@"layer_surface_closed %d", window->window_id); + //zwlr_layer_surface_v1_destroy(surface); + wl_surface_destroy(window->surface); + window->surface = NULL; + window->configured = NO; + window->layer_surface = NULL; } -static void -wl_shell_surface_on_popup_done(void *data, - struct wl_shell_surface *shell_surface) -{ -} - -static const struct wl_shell_surface_listener shell_surface_listener = { - wl_shell_surface_on_ping, - wl_shell_surface_on_configure, - wl_shell_surface_on_popup_done, +struct zwlr_layer_surface_v1_listener layer_surface_listener = { + .configure = layer_surface_configure, + .closed = layer_surface_closed, }; -#endif + +static void xdg_popup_configure(void *data, struct xdg_popup *xdg_popup, + int32_t x, int32_t y, int32_t width, int32_t height) { + struct window *window = data; + WaylandConfig *wlconfig = window->wlconfig; + + window->width = width; + window->height = height; + + +} + +static void xdg_popup_done(void *data, struct xdg_popup *xdg_popup) { + struct window *window = data; + WaylandConfig *wlconfig = window->wlconfig; + xdg_popup_destroy(xdg_popup); + + wl_surface_destroy(window->surface); +} + +static const struct xdg_popup_listener xdg_popup_listener = { + .configure = xdg_popup_configure, + .popup_done = xdg_popup_done, +}; + static void handle_global(void *data, struct wl_registry *registry, @@ -804,23 +834,27 @@ handle_global(void *data, struct wl_registry *registry, NSDebugLog(@"wayland: registering interface '%s'", interface); if (strcmp(interface, xdg_wm_base_interface.name) == 0) { - wlconfig->wm_base = wl_registry_bind(registry, name, + wlconfig->wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); - xdg_wm_base_add_listener(wlconfig->wm_base, &wm_base_listener, NULL); + xdg_wm_base_add_listener(wlconfig->wm_base, &wm_base_listener, NULL); NSDebugLog(@"wayland: found wm_base interface"); } else if (strcmp(interface, wl_shell_interface.name) == 0) { - wlconfig->shell = wl_registry_bind(registry, name, + wlconfig->shell = wl_registry_bind(registry, name, &wl_shell_interface, 1); NSDebugLog(@"wayland: found shell interface"); } else if (strcmp(interface, wl_compositor_interface.name) == 0) { - wlconfig->compositor = wl_registry_bind(registry, name, + wlconfig->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1); NSDebugLog(@"wayland: found compositor interface"); } else if (strcmp(interface, wl_shm_interface.name) == 0) { - wlconfig->shm = wl_registry_bind(registry, name, + wlconfig->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); NSDebugLog(@"wayland: found shm interface"); - wl_shm_add_listener(wlconfig->shm, &shm_listener, wlconfig); + wl_shm_add_listener(wlconfig->shm, &shm_listener, wlconfig); + } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { + wlconfig->layer_shell = wl_registry_bind(registry, name, + &zwlr_layer_shell_v1_interface, 1); + NSDebugLog(@"wayland: found wlr-layer_shell interface"); } else if (strcmp(interface, wl_output_interface.name) == 0) { struct output *output = (struct output *)malloc(sizeof(struct output)); memset(output, 0, sizeof(struct output)); @@ -1148,56 +1182,51 @@ int NSToWayland(struct window *window, int ns_y) return window->window_id; } -- (void) makeWindowTopLevel: (int) win +- (void) makeWindowTopLevelIfNeeded: (int) win { - NSDebugLog(@"makeWindowTopLevel"); - + NSDebugLog(@"makeWindowTopLevelIfNeeded"); struct window *window = get_window_with_id(wlconfig, win); - window->surface = wl_compositor_create_surface(wlconfig->compositor); - if (!window->surface) { - NSDebugLog(@"can't create wayland surface"); - free(window); - return; + if(window->toplevel != NULL || window->layer_surface != NULL) { + return; } - wl_surface_set_user_data(window->surface, window); - window->xdg_surface = - xdg_wm_base_get_xdg_surface(wlconfig->wm_base, window->surface); - window->toplevel = xdg_surface_get_toplevel(window->xdg_surface); - xdg_surface_add_listener(window->xdg_surface, - &xdg_surface_listener, window); + if(window->surface == NULL) { + window->surface = wl_compositor_create_surface(wlconfig->compositor); + if (!window->surface) { + NSDebugLog(@"can't create wayland surface"); + free(window); + return; + } + wl_surface_set_user_data(window->surface, window); + } + if(window->xdg_surface == NULL) { + window->xdg_surface = + xdg_wm_base_get_xdg_surface(wlconfig->wm_base, window->surface); + window->toplevel = xdg_surface_get_toplevel(window->xdg_surface); - xdg_surface_set_window_geometry(window->xdg_surface, - window->pos_x, - window->pos_y, - window->width, - window->height); + xdg_surface_add_listener(window->xdg_surface, + &xdg_surface_listener, window); - NSDebugLog(@"wl_surface_commit: win=%d toplevel", window->window_id); + xdg_surface_set_window_geometry(window->xdg_surface, + window->pos_x, + window->pos_y, + window->width, + window->height); + } + //NSDebugLog(@"wl_surface_commit: win=%d toplevel", window->window_id); wl_surface_commit(window->surface); wl_display_dispatch_pending(window->wlconfig->display); wl_display_flush(window->wlconfig->display); - return; - -#if 0 - // TODO: xdg_shell_get_xdg_surface_special() no longer exists, - // so we need to find another way, see *get_popup for menus - if (style & NSMainMenuWindowMask) { - NSDebugLog(@"window id=%d will be a panel", window->window_id); - } else if (style & NSBackgroundWindowMask) { - NSDebugLog(@"window id=%d will be a ?", window->window_id); - } else { - NSDebugLog(@"window id=%d will be ordinary", window->window_id); - } -#endif - } - (void) termwindow: (int) win { NSDebugLog(@"termwindow: win=%d", win); struct window *window = get_window_with_id(wlconfig, win); - xdg_surface_destroy(window->xdg_surface); + if(window->xdg_surface) { + //destroy_xdg_surface(window->xdg_surface); + } + wl_surface_destroy(window->surface); wl_buffer_destroy(window->buffer); wl_list_remove(&window->link); @@ -1234,8 +1263,9 @@ int NSToWayland(struct window *window, int ns_y) struct window *window = get_window_with_id(wlconfig, win); const char *cString = [window_title UTF8String]; - if(window->toplevel) + if(window->toplevel) { xdg_toplevel_set_title(window->toplevel, cString); + } } - (void) miniwindow: (int) win @@ -1264,35 +1294,34 @@ int NSToWayland(struct window *window, int ns_y) struct window *window = get_window_with_id(wlconfig, win); if (op == NSWindowOut) { - NSDebugLog(@"orderwindow: NSWindowOut"); - window->is_out = 1; - if(window->xdg_surface) { - xdg_surface_set_window_geometry(window->xdg_surface, - window->pos_x + 32000, - window->pos_y + 32000, - window->width, - window->height); - } - NSRect rect = NSMakeRect(0, 0, - window->width, window->height); - [window->instance flushwindowrect:rect :window->window_id]; - if(window->toplevel != NULL) { - xdg_toplevel_set_minimized(window->toplevel); - } + NSDebugLog(@"orderwindow: NSWindowOut"); + if(window->layer_surface) { + zwlr_layer_surface_v1_destroy(window->layer_surface); + wl_surface_destroy(window->surface); + window->surface = NULL; + window->layer_surface = NULL; + window->configured = NO; + window->is_out = 1; + } + if(window->xdg_surface) { + xdg_surface_set_window_geometry(window->xdg_surface, + window->pos_x + 32000, + window->pos_y + 32000, + window->width, + window->height); + } + NSRect rect = NSMakeRect(0, 0, + window->width, window->height); + [window->instance flushwindowrect:rect :window->window_id]; + if(window->toplevel != NULL) { + xdg_toplevel_set_minimized(window->toplevel); + } - - wl_display_dispatch_pending(window->wlconfig->display); - wl_display_flush(window->wlconfig->display); + wl_display_dispatch_pending(window->wlconfig->display); + wl_display_flush(window->wlconfig->display); } else /*if (window->is_out)*/ { - if(window->toplevel == NULL) { - [self makeWindowTopLevel: win]; - } - NSDebugLog(@"orderwindow: %d restoring to %fx%f", win, window->pos_x, window->pos_y); - xdg_surface_set_window_geometry(window->xdg_surface, - window->pos_x, - window->pos_y, - window->width, - window->height); + NSDebugLog(@"orderwindow: %d restoring to %fx%f", win, window->pos_x, window->pos_y); + [self makeWindowShell: win]; NSRect rect = NSMakeRect(0, 0, window->width, window->height); [window->instance flushwindowrect:rect :window->window_id]; @@ -1332,50 +1361,8 @@ int NSToWayland(struct window *window, int ns_y) struct window *window = get_window_with_id(wlconfig, win); WaylandConfig *config = window->wlconfig; - if (0 && config->pointer.serial && config->pointer.focus && - config->pointer.focus->window_id == win) { - // FIXME: remove dead branch - NSEvent *event; - NSEventType eventType; - NSPoint eventLocation; - NSGraphicsContext *gcontext; - unsigned int eventFlags; - float deltaX = 0.0; - float deltaY = 0.0; - int tick; - - gcontext = GSCurrentContext(); - eventLocation = NSMakePoint(config->pointer.x, - window->height - config->pointer.y); - eventFlags = 0; - eventType = NSLeftMouseUp; - - tick = 0; - - NSDebugLog(@"sending pointer event at: %fx%f, window=%d", config->pointer.x, config->pointer.y, window->window_id); - - event = [NSEvent mouseEventWithType: eventType - location: eventLocation - modifierFlags: eventFlags - timestamp: (NSTimeInterval) 0 - windowNumber: (int)window->window_id - context: gcontext - eventNumber: tick - clickCount: 1 - pressure: 1.0 - buttonNumber: 0 /* FIXME */ - deltaX: deltaX - deltaY: deltaY - deltaZ: 0.]; - - [GSCurrentServer() postEvent: event atStart: NO]; - - //xdg_toplevel_move(window->toplevel, - // config->seat, - // config->pointer.serial); - } else { - if(window->toplevel == NULL) { - [self makeWindowTopLevel: win]; + if(window->toplevel == NULL && !window->layer_surface) { + [self makeWindowTopLevelIfNeeded: win]; } NSDebugLog(@"placewindow: oldpos=%fx%f", window->pos_x, window->pos_y); NSDebugLog(@"placewindow: oldsize=%fx%f", window->width, window->height); @@ -1413,6 +1400,7 @@ int NSToWayland(struct window *window, int ns_y) window->pos_y, window->width, window->height); + wl_surface_commit(window->surface); /* NSRect flushRect = NSMakeRect(0, 0, window->width, window->height); @@ -1466,9 +1454,117 @@ int NSToWayland(struct window *window, int ns_y) window->width, window->height); } +- (void) makeMainMenu: (int) win +{ + struct window *window = get_window_with_id(wlconfig, win); + char *namespace = "wlroots"; + if(!wlconfig->layer_shell) { + return; + } + if(window->surface == NULL) { + window->surface = wl_compositor_create_surface(wlconfig->compositor); + wl_surface_set_user_data(window->surface, window); + } + + if(window->layer_surface == NULL) { + window->layer_surface = zwlr_layer_shell_v1_get_layer_surface( + wlconfig->layer_shell, + window->surface, + window->output->output, + ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, + namespace); + assert(window->layer_surface); + zwlr_layer_surface_v1_set_size(window->layer_surface, + window->width, window->height); + zwlr_layer_surface_v1_set_anchor(window->layer_surface, + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP); + zwlr_layer_surface_v1_set_exclusive_zone(window->layer_surface, 1); + zwlr_layer_surface_v1_set_margin(window->layer_surface, + 0, 0, 0, 0); + zwlr_layer_surface_v1_add_listener(window->layer_surface, + &layer_surface_listener, window); + } + wl_surface_commit(window->surface); + wl_display_roundtrip(wlconfig->display); +} +- (void) makeSubMenu: (int) win +{ + struct window *window = get_window_with_id(wlconfig, win); + if(!wlconfig->layer_shell) { + return; + } + char *namespace = "wlroots"; + if(window->surface == NULL) { + window->surface = wl_compositor_create_surface(wlconfig->compositor); + wl_surface_set_user_data(window->surface, window); + } + if(window->layer_surface == NULL) { + window->layer_surface = zwlr_layer_shell_v1_get_layer_surface( + wlconfig->layer_shell, + window->surface, + window->output->output, + ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, + namespace); + + zwlr_layer_surface_v1_set_size(window->layer_surface, + window->width, window->height); + zwlr_layer_surface_v1_set_anchor(window->layer_surface, + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT); + zwlr_layer_surface_v1_set_exclusive_zone(window->layer_surface, 1); + zwlr_layer_surface_v1_set_margin(window->layer_surface, + window->pos_y, 0, 0, window->pos_x); + + zwlr_layer_surface_v1_add_listener(window->layer_surface, + &layer_surface_listener, window); + } + + wl_surface_commit(window->surface); + wl_display_roundtrip(wlconfig->display); +} + +- (void) makeWindowShell: (int) win +{ + struct window *window = get_window_with_id(wlconfig, win); + switch(window->level) { + case NSMainMenuWindowLevel: + NSDebugLog(@"NSMainMenuWindowLevel win=%d", win); + [self makeMainMenu: win]; + break; + case NSSubmenuWindowLevel: + NSDebugLog(@"NSSubmenuWindowLevel win=%d", win); + [self makeSubMenu: win]; + break; + case NSDesktopWindowLevel: + NSDebugLog(@"NSDesktopWindowLevel win=%d", win); + break; + case NSStatusWindowLevel: + NSDebugLog(@"NSStatusWindowLevel win=%d", win); + break; + case NSPopUpMenuWindowLevel: + NSDebugLog(@"NSPopUpMenuWindowLevel win=%d", win); + break; + case NSScreenSaverWindowLevel: + NSDebugLog(@"NSScreenSaverWindowLevel win=%d", win); + break; + case NSFloatingWindowLevel: + NSDebugLog(@"NSFloatingWindowLevel win=%d", win); + case NSModalPanelWindowLevel: + NSDebugLog(@"NSModalPanelWindowLevel win=%d", win); + case NSNormalWindowLevel: + NSDebugLog(@"NSNormalWindowLevel win=%d", win); + [self makeWindowTopLevelIfNeeded: win]; + + break; + } +} + - (void) setwindowlevel: (int) level : (int) win { + struct window *window = get_window_with_id(wlconfig, win); + window->level = level; + NSDebugLog(@"setwindowlevel: level=%d win=%d", level, win); + [self makeWindowShell: win]; } - (int) windowlevel: (int) win diff --git a/Source/wayland/protocols/wlr-layer-shell-unstable-v1.xml b/Source/wayland/protocols/wlr-layer-shell-unstable-v1.xml new file mode 100644 index 0000000..fa67001 --- /dev/null +++ b/Source/wayland/protocols/wlr-layer-shell-unstable-v1.xml @@ -0,0 +1,311 @@ + + + + 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. + + + + + 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. + + + + + 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. + + 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. + + + + + + + + + + + + + + + + + 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. + + + + + + + + + + + + + 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. + + + + + + + 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. + + + + + 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. + + + + + + + + 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. + + + + + + + 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. + + + + + + + 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. + + + + + + + + + + Set to 1 to request that the seat send keyboard events to this layer + surface. For layers below the shell surface layer, the seat will use + normal focus semantics. For layers above the shell surface layers, the + seat will always give exclusive keyboard focus to the top-most layer + which has keyboard interactivity set to true. + + 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. + + Events is double-buffered, see wl_surface.commit. + + + + + + + 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. + + + + + + + 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. + + + + + + + This request destroys the layer surface. + + + + + + The configure event asks the client to resize its surface. + + Clients should arrange their surface for the new states, and then send + an ack_configure request with the serial sent in this configure event at + some point before committing the new surface. + + The client is free to dismiss all but the last configure event it + received. + + The width and height arguments specify the size of the window in + surface-local coordinates. + + The size is a hint, in the sense that the client is free to ignore it if + it doesn't resize, pick a smaller size (to satisfy aspect ratio or + resize in steps of NxM pixels). If the client picks a smaller size and + is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the + surface will be centered on this axis. + + If the width or height arguments are zero, it means the client should + decide its own window dimension. + + + + + + + + + The closed event is sent by the compositor when the surface will no + longer be shown. The output may have been destroyed or the user may + have asked for it to be removed. Further changes to the surface will be + ignored. The client should destroy the resource after receiving this + event, and create a new surface if they so choose. + + + + + + + + + + + + + + + + + + + + + Change the layer that the surface is rendered on. + + Layer is double-buffered, see wl_surface.commit. + + + + + diff --git a/Source/wayland/wlr-layer-shell-protocol.c b/Source/wayland/wlr-layer-shell-protocol.c new file mode 100644 index 0000000..f5a9603 --- /dev/null +++ b/Source/wayland/wlr-layer-shell-protocol.c @@ -0,0 +1,83 @@ +/* Generated by wayland-scanner 1.18.0 */ + +/* + * 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. + */ + +#include +#include +#include "wayland-util.h" + +extern const struct wl_interface wl_output_interface; +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface xdg_popup_interface; +extern const struct wl_interface zwlr_layer_surface_v1_interface; + +static const struct wl_interface *wlr_layer_shell_unstable_v1_types[] = { + NULL, + NULL, + NULL, + NULL, + &zwlr_layer_surface_v1_interface, + &wl_surface_interface, + &wl_output_interface, + NULL, + NULL, + &xdg_popup_interface, +}; + +static const struct wl_message zwlr_layer_shell_v1_requests[] = { + { "get_layer_surface", "no?ous", wlr_layer_shell_unstable_v1_types + 4 }, + { "destroy", "3", wlr_layer_shell_unstable_v1_types + 0 }, +}; + +WL_EXPORT const struct wl_interface zwlr_layer_shell_v1_interface = { + "zwlr_layer_shell_v1", 3, + 2, zwlr_layer_shell_v1_requests, + 0, NULL, +}; + +static const struct wl_message zwlr_layer_surface_v1_requests[] = { + { "set_size", "uu", wlr_layer_shell_unstable_v1_types + 0 }, + { "set_anchor", "u", wlr_layer_shell_unstable_v1_types + 0 }, + { "set_exclusive_zone", "i", wlr_layer_shell_unstable_v1_types + 0 }, + { "set_margin", "iiii", wlr_layer_shell_unstable_v1_types + 0 }, + { "set_keyboard_interactivity", "u", wlr_layer_shell_unstable_v1_types + 0 }, + { "get_popup", "o", wlr_layer_shell_unstable_v1_types + 9 }, + { "ack_configure", "u", wlr_layer_shell_unstable_v1_types + 0 }, + { "destroy", "", wlr_layer_shell_unstable_v1_types + 0 }, + { "set_layer", "2u", wlr_layer_shell_unstable_v1_types + 0 }, +}; + +static const struct wl_message zwlr_layer_surface_v1_events[] = { + { "configure", "uuu", wlr_layer_shell_unstable_v1_types + 0 }, + { "closed", "", wlr_layer_shell_unstable_v1_types + 0 }, +}; + +WL_EXPORT const struct wl_interface zwlr_layer_surface_v1_interface = { + "zwlr_layer_surface_v1", 3, + 9, zwlr_layer_surface_v1_requests, + 2, zwlr_layer_surface_v1_events, +}; + diff --git a/Source/wayland/xdg-shell-protocol.c b/Source/wayland/xdg-shell-protocol.c index a50fb44..058ba76 100644 --- a/Source/wayland/xdg-shell-protocol.c +++ b/Source/wayland/xdg-shell-protocol.c @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.17.0 */ +/* Generated by wayland-scanner 1.18.0 */ /* * Copyright © 2008-2013 Kristian Høgsberg @@ -40,7 +40,7 @@ extern const struct wl_interface xdg_positioner_interface; extern const struct wl_interface xdg_surface_interface; extern const struct wl_interface xdg_toplevel_interface; -static const struct wl_interface *types[] = { +static const struct wl_interface *xdg_shell_types[] = { NULL, NULL, NULL, @@ -65,100 +65,107 @@ static const struct wl_interface *types[] = { &wl_output_interface, &wl_seat_interface, NULL, + &xdg_positioner_interface, + NULL, }; static const struct wl_message xdg_wm_base_requests[] = { - { "destroy", "", types + 0 }, - { "create_positioner", "n", types + 4 }, - { "get_xdg_surface", "no", types + 5 }, - { "pong", "u", types + 0 }, + { "destroy", "", xdg_shell_types + 0 }, + { "create_positioner", "n", xdg_shell_types + 4 }, + { "get_xdg_surface", "no", xdg_shell_types + 5 }, + { "pong", "u", xdg_shell_types + 0 }, }; static const struct wl_message xdg_wm_base_events[] = { - { "ping", "u", types + 0 }, + { "ping", "u", xdg_shell_types + 0 }, }; WL_EXPORT const struct wl_interface xdg_wm_base_interface = { - "xdg_wm_base", 2, + "xdg_wm_base", 3, 4, xdg_wm_base_requests, 1, xdg_wm_base_events, }; static const struct wl_message xdg_positioner_requests[] = { - { "destroy", "", types + 0 }, - { "set_size", "ii", types + 0 }, - { "set_anchor_rect", "iiii", types + 0 }, - { "set_anchor", "u", types + 0 }, - { "set_gravity", "u", types + 0 }, - { "set_constraint_adjustment", "u", types + 0 }, - { "set_offset", "ii", types + 0 }, + { "destroy", "", xdg_shell_types + 0 }, + { "set_size", "ii", xdg_shell_types + 0 }, + { "set_anchor_rect", "iiii", xdg_shell_types + 0 }, + { "set_anchor", "u", xdg_shell_types + 0 }, + { "set_gravity", "u", xdg_shell_types + 0 }, + { "set_constraint_adjustment", "u", xdg_shell_types + 0 }, + { "set_offset", "ii", xdg_shell_types + 0 }, + { "set_reactive", "3", xdg_shell_types + 0 }, + { "set_parent_size", "3ii", xdg_shell_types + 0 }, + { "set_parent_configure", "3u", xdg_shell_types + 0 }, }; WL_EXPORT const struct wl_interface xdg_positioner_interface = { - "xdg_positioner", 2, - 7, xdg_positioner_requests, + "xdg_positioner", 3, + 10, xdg_positioner_requests, 0, NULL, }; static const struct wl_message xdg_surface_requests[] = { - { "destroy", "", types + 0 }, - { "get_toplevel", "n", types + 7 }, - { "get_popup", "n?oo", types + 8 }, - { "set_window_geometry", "iiii", types + 0 }, - { "ack_configure", "u", types + 0 }, + { "destroy", "", xdg_shell_types + 0 }, + { "get_toplevel", "n", xdg_shell_types + 7 }, + { "get_popup", "n?oo", xdg_shell_types + 8 }, + { "set_window_geometry", "iiii", xdg_shell_types + 0 }, + { "ack_configure", "u", xdg_shell_types + 0 }, }; static const struct wl_message xdg_surface_events[] = { - { "configure", "u", types + 0 }, + { "configure", "u", xdg_shell_types + 0 }, }; WL_EXPORT const struct wl_interface xdg_surface_interface = { - "xdg_surface", 2, + "xdg_surface", 3, 5, xdg_surface_requests, 1, xdg_surface_events, }; static const struct wl_message xdg_toplevel_requests[] = { - { "destroy", "", types + 0 }, - { "set_parent", "?o", types + 11 }, - { "set_title", "s", types + 0 }, - { "set_app_id", "s", types + 0 }, - { "show_window_menu", "ouii", types + 12 }, - { "move", "ou", types + 16 }, - { "resize", "ouu", types + 18 }, - { "set_max_size", "ii", types + 0 }, - { "set_min_size", "ii", types + 0 }, - { "set_maximized", "", types + 0 }, - { "unset_maximized", "", types + 0 }, - { "set_fullscreen", "?o", types + 21 }, - { "unset_fullscreen", "", types + 0 }, - { "set_minimized", "", types + 0 }, + { "destroy", "", xdg_shell_types + 0 }, + { "set_parent", "?o", xdg_shell_types + 11 }, + { "set_title", "s", xdg_shell_types + 0 }, + { "set_app_id", "s", xdg_shell_types + 0 }, + { "show_window_menu", "ouii", xdg_shell_types + 12 }, + { "move", "ou", xdg_shell_types + 16 }, + { "resize", "ouu", xdg_shell_types + 18 }, + { "set_max_size", "ii", xdg_shell_types + 0 }, + { "set_min_size", "ii", xdg_shell_types + 0 }, + { "set_maximized", "", xdg_shell_types + 0 }, + { "unset_maximized", "", xdg_shell_types + 0 }, + { "set_fullscreen", "?o", xdg_shell_types + 21 }, + { "unset_fullscreen", "", xdg_shell_types + 0 }, + { "set_minimized", "", xdg_shell_types + 0 }, }; static const struct wl_message xdg_toplevel_events[] = { - { "configure", "iia", types + 0 }, - { "close", "", types + 0 }, + { "configure", "iia", xdg_shell_types + 0 }, + { "close", "", xdg_shell_types + 0 }, }; WL_EXPORT const struct wl_interface xdg_toplevel_interface = { - "xdg_toplevel", 2, + "xdg_toplevel", 3, 14, xdg_toplevel_requests, 2, xdg_toplevel_events, }; static const struct wl_message xdg_popup_requests[] = { - { "destroy", "", types + 0 }, - { "grab", "ou", types + 22 }, + { "destroy", "", xdg_shell_types + 0 }, + { "grab", "ou", xdg_shell_types + 22 }, + { "reposition", "3ou", xdg_shell_types + 24 }, }; static const struct wl_message xdg_popup_events[] = { - { "configure", "iiii", types + 0 }, - { "popup_done", "", types + 0 }, + { "configure", "iiii", xdg_shell_types + 0 }, + { "popup_done", "", xdg_shell_types + 0 }, + { "repositioned", "3u", xdg_shell_types + 0 }, }; WL_EXPORT const struct wl_interface xdg_popup_interface = { - "xdg_popup", 2, - 2, xdg_popup_requests, - 2, xdg_popup_events, + "xdg_popup", 3, + 3, xdg_popup_requests, + 3, xdg_popup_events, };