From 00d330fe8837db95e08ac8949c38514b93669f4c Mon Sep 17 00:00:00 2001 From: lkn Date: Sun, 28 Jun 2026 02:04:44 +0200 Subject: [PATCH] wayland: add wmaker-dockapp-v1 native protocol Defines a Wayland protocol for native dock applications (dockapps). Clients create a wl_surface, wrap it with wmaker_dockapp_v1, and render ARGB content at the compositor-specified tile size. The compositor places the surface in a dock slot with full transparency support, eliminating the opaque-black-background issue of XWayland. Protocol: - wmaker_dockapp_manager_v1: global, get_dockapp(surface) - wmaker_dockapp_v1: set_app_id, configure event, closed event Compositor implementation registers the global and handles surface commit by placing the dockapp in its assigned dock tile frame_buf tree. --- protocols/wmaker-dockapp-v1-client-protocol.h | 311 ++++++++++++++++++ protocols/wmaker-dockapp-v1.xml | 124 +++++++ src/Makefile.am | 16 +- src/backend/wayland/wl_dockapp_proto.c | 200 +++++++++++ src/backend/wayland/wl_extensions.c | 4 + src/backend/wayland/wl_types.h | 2 + src/wmaker-dockapp-v1-protocol.c | 77 +++++ src/wmaker-dockapp-v1-server-protocol.h | 271 +++++++++++++++ 8 files changed, 1004 insertions(+), 1 deletion(-) create mode 100644 protocols/wmaker-dockapp-v1-client-protocol.h create mode 100644 protocols/wmaker-dockapp-v1.xml create mode 100644 src/backend/wayland/wl_dockapp_proto.c create mode 100644 src/wmaker-dockapp-v1-protocol.c create mode 100644 src/wmaker-dockapp-v1-server-protocol.h diff --git a/protocols/wmaker-dockapp-v1-client-protocol.h b/protocols/wmaker-dockapp-v1-client-protocol.h new file mode 100644 index 0000000..ed8a157 --- /dev/null +++ b/protocols/wmaker-dockapp-v1-client-protocol.h @@ -0,0 +1,311 @@ +/* Generated by wayland-scanner 1.24.0 */ + +#ifndef WMAKER_DOCKAPP_V1_CLIENT_PROTOCOL_H +#define WMAKER_DOCKAPP_V1_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_wmaker_dockapp_v1 The wmaker_dockapp_v1 protocol + * Window Maker dock application protocol + * + * @section page_desc_wmaker_dockapp_v1 Description + * + * This protocol allows native Wayland clients to act as dock applications + * (dockapps) — small, tile-sized widgets that live in the Window Maker dock. + * + * Traditional X11 dockapps use the withdrawn state with an icon_window hint + * to embed a small rendering surface into the window manager's dock tile. + * This protocol provides the Wayland-native equivalent: a client creates a + * wl_surface, marks it as a dockapp via this protocol, and the compositor + * places it in a dock slot. The surface supports full ARGB transparency, + * eliminating the opaque-black-background problem of XWayland dockapps. + * + * The compositor owns the dock tile background. The dockapp surface is + * composited on top of it. The client renders only its content (clock face, + * system monitor graph, etc.) with transparent background pixels where the + * dock tile should show through. + * + * @section page_ifaces_wmaker_dockapp_v1 Interfaces + * - @subpage page_iface_wmaker_dockapp_manager_v1 - manager for dock application surfaces + * - @subpage page_iface_wmaker_dockapp_v1 - a dock application surface + * @section page_copyright_wmaker_dockapp_v1 Copyright + *
+ *
+ * Copyright © 2026 Window Maker Team
+ *
+ * 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_surface; +struct wmaker_dockapp_manager_v1; +struct wmaker_dockapp_v1; + +#ifndef WMAKER_DOCKAPP_MANAGER_V1_INTERFACE +#define WMAKER_DOCKAPP_MANAGER_V1_INTERFACE +/** + * @page page_iface_wmaker_dockapp_manager_v1 wmaker_dockapp_manager_v1 + * @section page_iface_wmaker_dockapp_manager_v1_desc Description + * + * Singleton global advertised by Window Maker compositors. Clients bind + * to create dockapp objects for their surfaces. + * @section page_iface_wmaker_dockapp_manager_v1_api API + * See @ref iface_wmaker_dockapp_manager_v1. + */ +/** + * @defgroup iface_wmaker_dockapp_manager_v1 The wmaker_dockapp_manager_v1 interface + * + * Singleton global advertised by Window Maker compositors. Clients bind + * to create dockapp objects for their surfaces. + */ +extern const struct wl_interface wmaker_dockapp_manager_v1_interface; +#endif +#ifndef WMAKER_DOCKAPP_V1_INTERFACE +#define WMAKER_DOCKAPP_V1_INTERFACE +/** + * @page page_iface_wmaker_dockapp_v1 wmaker_dockapp_v1 + * @section page_iface_wmaker_dockapp_v1_desc Description + * + * Represents a dock application. The client attaches buffers to the + * underlying wl_surface and commits them; the compositor displays the + * surface content within a dock tile. + * + * The client should render at the size indicated by the configure event. + * The surface supports ARGB — transparent pixels let the dock tile + * background show through. + * + * The compositor manages the dockapp's lifecycle: it may be undocked + * (closed event), moved between dock slots, or hidden when the dock + * is collapsed. + * @section page_iface_wmaker_dockapp_v1_api API + * See @ref iface_wmaker_dockapp_v1. + */ +/** + * @defgroup iface_wmaker_dockapp_v1 The wmaker_dockapp_v1 interface + * + * Represents a dock application. The client attaches buffers to the + * underlying wl_surface and commits them; the compositor displays the + * surface content within a dock tile. + * + * The client should render at the size indicated by the configure event. + * The surface supports ARGB — transparent pixels let the dock tile + * background show through. + * + * The compositor manages the dockapp's lifecycle: it may be undocked + * (closed event), moved between dock slots, or hidden when the dock + * is collapsed. + */ +extern const struct wl_interface wmaker_dockapp_v1_interface; +#endif + +#define WMAKER_DOCKAPP_MANAGER_V1_DESTROY 0 +#define WMAKER_DOCKAPP_MANAGER_V1_GET_DOCKAPP 1 + + +/** + * @ingroup iface_wmaker_dockapp_manager_v1 + */ +#define WMAKER_DOCKAPP_MANAGER_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wmaker_dockapp_manager_v1 + */ +#define WMAKER_DOCKAPP_MANAGER_V1_GET_DOCKAPP_SINCE_VERSION 1 + +/** @ingroup iface_wmaker_dockapp_manager_v1 */ +static inline void +wmaker_dockapp_manager_v1_set_user_data(struct wmaker_dockapp_manager_v1 *wmaker_dockapp_manager_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wmaker_dockapp_manager_v1, user_data); +} + +/** @ingroup iface_wmaker_dockapp_manager_v1 */ +static inline void * +wmaker_dockapp_manager_v1_get_user_data(struct wmaker_dockapp_manager_v1 *wmaker_dockapp_manager_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wmaker_dockapp_manager_v1); +} + +static inline uint32_t +wmaker_dockapp_manager_v1_get_version(struct wmaker_dockapp_manager_v1 *wmaker_dockapp_manager_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wmaker_dockapp_manager_v1); +} + +/** + * @ingroup iface_wmaker_dockapp_manager_v1 + * + * Destroy the manager. Existing dockapp objects remain valid. + */ +static inline void +wmaker_dockapp_manager_v1_destroy(struct wmaker_dockapp_manager_v1 *wmaker_dockapp_manager_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wmaker_dockapp_manager_v1, + WMAKER_DOCKAPP_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wmaker_dockapp_manager_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wmaker_dockapp_manager_v1 + * + * Wrap the given wl_surface as a dock application. The surface must + * not have another role (xdg_toplevel, xdg_popup, etc.) assigned. + * The compositor will place this surface in the next available dock + * slot or use the app_id for slot matching against saved state. + */ +static inline struct wmaker_dockapp_v1 * +wmaker_dockapp_manager_v1_get_dockapp(struct wmaker_dockapp_manager_v1 *wmaker_dockapp_manager_v1, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wmaker_dockapp_manager_v1, + WMAKER_DOCKAPP_MANAGER_V1_GET_DOCKAPP, &wmaker_dockapp_v1_interface, wl_proxy_get_version((struct wl_proxy *) wmaker_dockapp_manager_v1), 0, NULL, surface); + + return (struct wmaker_dockapp_v1 *) id; +} + +#ifndef WMAKER_DOCKAPP_V1_ERROR_ENUM +#define WMAKER_DOCKAPP_V1_ERROR_ENUM +enum wmaker_dockapp_v1_error { + /** + * set_app_id called after first commit + */ + WMAKER_DOCKAPP_V1_ERROR_ALREADY_CONFIGURED = 0, +}; +#endif /* WMAKER_DOCKAPP_V1_ERROR_ENUM */ + +/** + * @ingroup iface_wmaker_dockapp_v1 + * @struct wmaker_dockapp_v1_listener + */ +struct wmaker_dockapp_v1_listener { + /** + * compositor requests a size for the dockapp + * + * The compositor sends this event to tell the client what size + * to render at. The client must attach a buffer of this size on + * its next commit. Sent once after the dockapp is created, and + * again if the dock tile size changes. + * @param width requested width in pixels + * @param height requested height in pixels + */ + void (*configure)(void *data, + struct wmaker_dockapp_v1 *wmaker_dockapp_v1, + uint32_t width, + uint32_t height); + /** + * dockapp was removed from the dock + * + * The compositor removed this dockapp (user undocked it, or dock + * was destroyed). The client should destroy the dockapp object and + * may exit or create a new one. + */ + void (*closed)(void *data, + struct wmaker_dockapp_v1 *wmaker_dockapp_v1); +}; + +/** + * @ingroup iface_wmaker_dockapp_v1 + */ +static inline int +wmaker_dockapp_v1_add_listener(struct wmaker_dockapp_v1 *wmaker_dockapp_v1, + const struct wmaker_dockapp_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wmaker_dockapp_v1, + (void (**)(void)) listener, data); +} + +#define WMAKER_DOCKAPP_V1_DESTROY 0 +#define WMAKER_DOCKAPP_V1_SET_APP_ID 1 + +/** + * @ingroup iface_wmaker_dockapp_v1 + */ +#define WMAKER_DOCKAPP_V1_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_wmaker_dockapp_v1 + */ +#define WMAKER_DOCKAPP_V1_CLOSED_SINCE_VERSION 1 + +/** + * @ingroup iface_wmaker_dockapp_v1 + */ +#define WMAKER_DOCKAPP_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wmaker_dockapp_v1 + */ +#define WMAKER_DOCKAPP_V1_SET_APP_ID_SINCE_VERSION 1 + +/** @ingroup iface_wmaker_dockapp_v1 */ +static inline void +wmaker_dockapp_v1_set_user_data(struct wmaker_dockapp_v1 *wmaker_dockapp_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wmaker_dockapp_v1, user_data); +} + +/** @ingroup iface_wmaker_dockapp_v1 */ +static inline void * +wmaker_dockapp_v1_get_user_data(struct wmaker_dockapp_v1 *wmaker_dockapp_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wmaker_dockapp_v1); +} + +static inline uint32_t +wmaker_dockapp_v1_get_version(struct wmaker_dockapp_v1 *wmaker_dockapp_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wmaker_dockapp_v1); +} + +/** + * @ingroup iface_wmaker_dockapp_v1 + * + * Remove the dockapp from the dock and destroy this object. The + * underlying wl_surface becomes inert. + */ +static inline void +wmaker_dockapp_v1_destroy(struct wmaker_dockapp_v1 *wmaker_dockapp_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wmaker_dockapp_v1, + WMAKER_DOCKAPP_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wmaker_dockapp_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wmaker_dockapp_v1 + * + * Set the app_id used to match this dockapp against saved dock state + * (instance.class format, e.g. "wmclock.WMClock"). Must be called + * before the first surface commit. + */ +static inline void +wmaker_dockapp_v1_set_app_id(struct wmaker_dockapp_v1 *wmaker_dockapp_v1, const char *app_id) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wmaker_dockapp_v1, + WMAKER_DOCKAPP_V1_SET_APP_ID, NULL, wl_proxy_get_version((struct wl_proxy *) wmaker_dockapp_v1), 0, app_id); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/protocols/wmaker-dockapp-v1.xml b/protocols/wmaker-dockapp-v1.xml new file mode 100644 index 0000000..e9c7bc3 --- /dev/null +++ b/protocols/wmaker-dockapp-v1.xml @@ -0,0 +1,124 @@ + + + + Copyright © 2026 Window Maker Team + + 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. + + + + This protocol allows native Wayland clients to act as dock applications + (dockapps) — small, tile-sized widgets that live in the Window Maker dock. + + Traditional X11 dockapps use the withdrawn state with an icon_window hint + to embed a small rendering surface into the window manager's dock tile. + This protocol provides the Wayland-native equivalent: a client creates a + wl_surface, marks it as a dockapp via this protocol, and the compositor + places it in a dock slot. The surface supports full ARGB transparency, + eliminating the opaque-black-background problem of XWayland dockapps. + + The compositor owns the dock tile background. The dockapp surface is + composited on top of it. The client renders only its content (clock face, + system monitor graph, etc.) with transparent background pixels where the + dock tile should show through. + + + + + Singleton global advertised by Window Maker compositors. Clients bind + to create dockapp objects for their surfaces. + + + + + Destroy the manager. Existing dockapp objects remain valid. + + + + + + Wrap the given wl_surface as a dock application. The surface must + not have another role (xdg_toplevel, xdg_popup, etc.) assigned. + The compositor will place this surface in the next available dock + slot or use the app_id for slot matching against saved state. + + + + + + + + + Represents a dock application. The client attaches buffers to the + underlying wl_surface and commits them; the compositor displays the + surface content within a dock tile. + + The client should render at the size indicated by the configure event. + The surface supports ARGB — transparent pixels let the dock tile + background show through. + + The compositor manages the dockapp's lifecycle: it may be undocked + (closed event), moved between dock slots, or hidden when the dock + is collapsed. + + + + + + + + + Remove the dockapp from the dock and destroy this object. The + underlying wl_surface becomes inert. + + + + + + Set the app_id used to match this dockapp against saved dock state + (instance.class format, e.g. "wmclock.WMClock"). Must be called + before the first surface commit. + + + + + + + The compositor sends this event to tell the client what size to + render at. The client must attach a buffer of this size on its + next commit. Sent once after the dockapp is created, and again + if the dock tile size changes. + + + + + + + + The compositor removed this dockapp (user undocked it, or dock + was destroyed). The client should destroy the dockapp object and + may exit or create a new one. + + + + diff --git a/src/Makefile.am b/src/Makefile.am index 298aab8..d33ba00 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,6 +8,8 @@ WLR_PROTO_DIR = $(shell pkg-config --variable=pkgdatadir wlr-protocols 2>/dev/nu BUILT_SOURCES = wconfig.h \ wmaker-popup-v1-server-protocol.h \ wmaker-popup-v1-protocol.c \ + wmaker-dockapp-v1-server-protocol.h \ + wmaker-dockapp-v1-protocol.c \ protocols/pointer-constraints-unstable-v1-protocol.h \ protocols/wlr-output-power-management-unstable-v1-protocol.h \ protocols/wlr-layer-shell-unstable-v1-protocol.h \ @@ -20,10 +22,14 @@ EXTRA_DIST = nodist_wmaker_SOURCES = \ wmaker-popup-v1-protocol.c \ - wmaker-popup-v1-server-protocol.h + wmaker-popup-v1-server-protocol.h \ + wmaker-dockapp-v1-protocol.c \ + wmaker-dockapp-v1-server-protocol.h CLEANFILES = wmaker-popup-v1-server-protocol.h \ wmaker-popup-v1-protocol.c \ + wmaker-dockapp-v1-server-protocol.h \ + wmaker-dockapp-v1-protocol.c \ protocols/pointer-constraints-unstable-v1-protocol.h \ protocols/wlr-output-power-management-unstable-v1-protocol.h \ protocols/wlr-layer-shell-unstable-v1-protocol.h \ @@ -37,6 +43,13 @@ wmaker-popup-v1-protocol.c: $(top_srcdir)/protocols/wmaker-popup-v1.xml \ wmaker-popup-v1-server-protocol.h $(WAYLAND_SCANNER) private-code $< $@ +wmaker-dockapp-v1-server-protocol.h: $(top_srcdir)/protocols/wmaker-dockapp-v1.xml + $(WAYLAND_SCANNER) server-header $< $@ + +wmaker-dockapp-v1-protocol.c: $(top_srcdir)/protocols/wmaker-dockapp-v1.xml \ + wmaker-dockapp-v1-server-protocol.h + $(WAYLAND_SCANNER) private-code $< $@ + # Generate protocol headers for Wayland compositor backend protocols/pointer-constraints-unstable-v1-protocol.h: @mkdir -p protocols @@ -238,6 +251,7 @@ wmaker_SOURCES += \ backend/wayland/wl_grab.c \ backend/wayland/wl_keyboard.c \ backend/wayland/wl_popup.c \ + backend/wayland/wl_dockapp_proto.c \ backend/wayland/wl_text_input.c \ backend/wayland/wl_xdg_activation.c \ backend/wayland/wl_output_mgmt.c \ diff --git a/src/backend/wayland/wl_dockapp_proto.c b/src/backend/wayland/wl_dockapp_proto.c new file mode 100644 index 0000000..4d6b858 --- /dev/null +++ b/src/backend/wayland/wl_dockapp_proto.c @@ -0,0 +1,200 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include +#include +#include +#include +#include "wmaker-dockapp-v1-server-protocol.h" +#include "wl_types.h" +#include "../../screen.h" + +/* ------------------------------------------------------------------ */ +/* Per-dockapp state */ + +struct wl_dockapp { + struct wl_resource *resource; + struct wlr_surface *surface; + struct wlr_scene_tree *scene_node; + char *app_id; + WNativeWindow frame_id; /* dock tile frame_buf ID */ + struct wl_listener surface_commit; + struct wl_listener surface_destroy; + struct wl_list link; /* wl_state.dockapp_list */ +}; + +/* Forward declarations */ +struct wl_frame_buf *frame_buf_find(WNativeWindow id); + +/* ------------------------------------------------------------------ */ +/* wmaker_dockapp_v1 interface */ + +static void +dockapp_handle_destroy(struct wl_client *client, struct wl_resource *resource) +{ + (void)client; + wl_resource_destroy(resource); +} + +static void +dockapp_handle_set_app_id(struct wl_client *client, struct wl_resource *resource, + const char *app_id) +{ + (void)client; + struct wl_dockapp *da = wl_resource_get_user_data(resource); + if (!da) return; + free(da->app_id); + da->app_id = strdup(app_id); +} + +static const struct wmaker_dockapp_v1_interface dockapp_impl = { + .destroy = dockapp_handle_destroy, + .set_app_id = dockapp_handle_set_app_id, +}; + +/* ------------------------------------------------------------------ */ +/* Surface commit — place the dockapp in its dock tile */ + +static void +dockapp_surface_commit(struct wl_listener *listener, void *data) +{ + struct wl_dockapp *da = wl_container_of(listener, da, surface_commit); + (void)data; + + if (!da->surface || !da->surface->buffer) + return; + + /* First commit: find or assign a dock slot and create scene node */ + if (!da->scene_node && da->frame_id) { + struct wl_frame_buf *fb = frame_buf_find(da->frame_id); + if (fb && fb->tree) { + da->scene_node = wlr_scene_subsurface_tree_create(fb->tree, da->surface); + if (da->scene_node) { + wlr_scene_node_raise_to_top(&da->scene_node->node); + wlr_scene_node_set_position(&da->scene_node->node, 0, 0); + } + } + } +} + +static void +dockapp_surface_destroy(struct wl_listener *listener, void *data) +{ + struct wl_dockapp *da = wl_container_of(listener, da, surface_destroy); + (void)data; + da->surface = NULL; + if (da->scene_node) { + wlr_scene_node_destroy(&da->scene_node->node); + da->scene_node = NULL; + } +} + +static void +dockapp_resource_destroy(struct wl_resource *resource) +{ + struct wl_dockapp *da = wl_resource_get_user_data(resource); + if (!da) return; + + wl_list_remove(&da->surface_commit.link); + wl_list_remove(&da->surface_destroy.link); + wl_list_remove(&da->link); + if (da->scene_node) + wlr_scene_node_destroy(&da->scene_node->node); + free(da->app_id); + free(da); +} + +/* ------------------------------------------------------------------ */ +/* wmaker_dockapp_manager_v1 interface */ + +static void +manager_handle_destroy(struct wl_client *client, struct wl_resource *resource) +{ + (void)client; + wl_resource_destroy(resource); +} + +static void +manager_handle_get_dockapp(struct wl_client *client, + struct wl_resource *manager_resource, + uint32_t id, + struct wl_resource *surface_resource) +{ + (void)manager_resource; + struct wlr_surface *surface = wlr_surface_from_resource(surface_resource); + + struct wl_dockapp *da = calloc(1, sizeof(*da)); + if (!da) { + wl_client_post_no_memory(client); + return; + } + + struct wl_resource *resource = wl_resource_create(client, + &wmaker_dockapp_v1_interface, 1, id); + if (!resource) { + free(da); + wl_client_post_no_memory(client); + return; + } + + da->resource = resource; + da->surface = surface; + da->scene_node = NULL; + da->app_id = NULL; + da->frame_id = 0; + + wl_resource_set_implementation(resource, &dockapp_impl, da, + dockapp_resource_destroy); + + da->surface_commit.notify = dockapp_surface_commit; + wl_signal_add(&surface->events.commit, &da->surface_commit); + da->surface_destroy.notify = dockapp_surface_destroy; + wl_signal_add(&surface->events.destroy, &da->surface_destroy); + + wl_list_insert(&wl_state.dockapp_list, &da->link); + + /* Send initial configure with the dock tile size */ + int tile_sz = wPreferences.icon_size > 0 ? wPreferences.icon_size : 64; + wmaker_dockapp_v1_send_configure(resource, tile_sz, tile_sz); + + wwarning("wl_dockapp: new dockapp surface=%p", (void*)surface); +} + +static const struct wmaker_dockapp_manager_v1_interface manager_impl = { + .destroy = manager_handle_destroy, + .get_dockapp = manager_handle_get_dockapp, +}; + +/* ------------------------------------------------------------------ */ +/* Global bind */ + +static void +dockapp_manager_bind(struct wl_client *client, void *data, + uint32_t version, uint32_t id) +{ + (void)data; + struct wl_resource *resource = wl_resource_create(client, + &wmaker_dockapp_manager_v1_interface, + version > 1 ? 1 : (int)version, id); + if (!resource) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(resource, &manager_impl, NULL, NULL); +} + +void +wmaker_dockapp_manager_create(void) +{ + if (!wl_state.display) return; + + wl_list_init(&wl_state.dockapp_list); + + wl_global_create(wl_state.display, + &wmaker_dockapp_manager_v1_interface, 1, NULL, + dockapp_manager_bind); + + wwarning("wl_backend: wmaker-dockapp-v1 manager created"); +} diff --git a/src/backend/wayland/wl_extensions.c b/src/backend/wayland/wl_extensions.c index 20acd6c..d85f2eb 100644 --- a/src/backend/wayland/wl_extensions.c +++ b/src/backend/wayland/wl_extensions.c @@ -472,6 +472,10 @@ wl_protocols_init(void) if (wl_state.wmaker_popup_manager) wwarning("wl_backend: wmaker-popup-v1 manager created"); + /* Advertise wmaker-dockapp-v1 — native Wayland dock applications. */ + extern void wmaker_dockapp_manager_create(void); + wmaker_dockapp_manager_create(); + /* advertise zxdg_decoration_manager_v1 so clients that * support server-side decorations can negotiate; we respond with * CLIENT_SIDE since the Wayland path has no X11 frame rendering. */ diff --git a/src/backend/wayland/wl_types.h b/src/backend/wayland/wl_types.h index fb881d1..41ffbb8 100644 --- a/src/backend/wayland/wl_types.h +++ b/src/backend/wayland/wl_types.h @@ -169,6 +169,8 @@ struct wl_compositor_state { struct wlr_xdg_shell *xdg_shell; /* wmaker-popup-v1 protocol global — client-driven popup positioning */ struct wl_global *wmaker_popup_manager; + /* wmaker-dockapp-v1 protocol — native Wayland dock applications */ + struct wl_list dockapp_list; /* wl_dockapp.link */ /* Phase 64: XDG decoration manager — tell clients to use CSD */ struct wlr_xdg_decoration_manager_v1 *decoration_manager; struct wl_listener decoration_new_listener; diff --git a/src/wmaker-dockapp-v1-protocol.c b/src/wmaker-dockapp-v1-protocol.c new file mode 100644 index 0000000..ccdc58b --- /dev/null +++ b/src/wmaker-dockapp-v1-protocol.c @@ -0,0 +1,77 @@ +/* Generated by wayland-scanner 1.24.0 */ + +/* + * Copyright © 2026 Window Maker Team + * + * 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. + */ + +#include +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface wmaker_dockapp_v1_interface; + +static const struct wl_interface *wmaker_dockapp_v1_types[] = { + NULL, + NULL, + &wmaker_dockapp_v1_interface, + &wl_surface_interface, +}; + +static const struct wl_message wmaker_dockapp_manager_v1_requests[] = { + { "destroy", "", wmaker_dockapp_v1_types + 0 }, + { "get_dockapp", "no", wmaker_dockapp_v1_types + 2 }, +}; + +WL_PRIVATE const struct wl_interface wmaker_dockapp_manager_v1_interface = { + "wmaker_dockapp_manager_v1", 1, + 2, wmaker_dockapp_manager_v1_requests, + 0, NULL, +}; + +static const struct wl_message wmaker_dockapp_v1_requests[] = { + { "destroy", "", wmaker_dockapp_v1_types + 0 }, + { "set_app_id", "s", wmaker_dockapp_v1_types + 0 }, +}; + +static const struct wl_message wmaker_dockapp_v1_events[] = { + { "configure", "uu", wmaker_dockapp_v1_types + 0 }, + { "closed", "", wmaker_dockapp_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface wmaker_dockapp_v1_interface = { + "wmaker_dockapp_v1", 1, + 2, wmaker_dockapp_v1_requests, + 2, wmaker_dockapp_v1_events, +}; + diff --git a/src/wmaker-dockapp-v1-server-protocol.h b/src/wmaker-dockapp-v1-server-protocol.h new file mode 100644 index 0000000..a478585 --- /dev/null +++ b/src/wmaker-dockapp-v1-server-protocol.h @@ -0,0 +1,271 @@ +/* Generated by wayland-scanner 1.24.0 */ + +#ifndef WMAKER_DOCKAPP_V1_SERVER_PROTOCOL_H +#define WMAKER_DOCKAPP_V1_SERVER_PROTOCOL_H + +#include +#include +#include "wayland-server.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct wl_client; +struct wl_resource; + +/** + * @page page_wmaker_dockapp_v1 The wmaker_dockapp_v1 protocol + * Window Maker dock application protocol + * + * @section page_desc_wmaker_dockapp_v1 Description + * + * This protocol allows native Wayland clients to act as dock applications + * (dockapps) — small, tile-sized widgets that live in the Window Maker dock. + * + * Traditional X11 dockapps use the withdrawn state with an icon_window hint + * to embed a small rendering surface into the window manager's dock tile. + * This protocol provides the Wayland-native equivalent: a client creates a + * wl_surface, marks it as a dockapp via this protocol, and the compositor + * places it in a dock slot. The surface supports full ARGB transparency, + * eliminating the opaque-black-background problem of XWayland dockapps. + * + * The compositor owns the dock tile background. The dockapp surface is + * composited on top of it. The client renders only its content (clock face, + * system monitor graph, etc.) with transparent background pixels where the + * dock tile should show through. + * + * @section page_ifaces_wmaker_dockapp_v1 Interfaces + * - @subpage page_iface_wmaker_dockapp_manager_v1 - manager for dock application surfaces + * - @subpage page_iface_wmaker_dockapp_v1 - a dock application surface + * @section page_copyright_wmaker_dockapp_v1 Copyright + *
+ *
+ * Copyright © 2026 Window Maker Team
+ *
+ * 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_surface; +struct wmaker_dockapp_manager_v1; +struct wmaker_dockapp_v1; + +#ifndef WMAKER_DOCKAPP_MANAGER_V1_INTERFACE +#define WMAKER_DOCKAPP_MANAGER_V1_INTERFACE +/** + * @page page_iface_wmaker_dockapp_manager_v1 wmaker_dockapp_manager_v1 + * @section page_iface_wmaker_dockapp_manager_v1_desc Description + * + * Singleton global advertised by Window Maker compositors. Clients bind + * to create dockapp objects for their surfaces. + * @section page_iface_wmaker_dockapp_manager_v1_api API + * See @ref iface_wmaker_dockapp_manager_v1. + */ +/** + * @defgroup iface_wmaker_dockapp_manager_v1 The wmaker_dockapp_manager_v1 interface + * + * Singleton global advertised by Window Maker compositors. Clients bind + * to create dockapp objects for their surfaces. + */ +extern const struct wl_interface wmaker_dockapp_manager_v1_interface; +#endif +#ifndef WMAKER_DOCKAPP_V1_INTERFACE +#define WMAKER_DOCKAPP_V1_INTERFACE +/** + * @page page_iface_wmaker_dockapp_v1 wmaker_dockapp_v1 + * @section page_iface_wmaker_dockapp_v1_desc Description + * + * Represents a dock application. The client attaches buffers to the + * underlying wl_surface and commits them; the compositor displays the + * surface content within a dock tile. + * + * The client should render at the size indicated by the configure event. + * The surface supports ARGB — transparent pixels let the dock tile + * background show through. + * + * The compositor manages the dockapp's lifecycle: it may be undocked + * (closed event), moved between dock slots, or hidden when the dock + * is collapsed. + * @section page_iface_wmaker_dockapp_v1_api API + * See @ref iface_wmaker_dockapp_v1. + */ +/** + * @defgroup iface_wmaker_dockapp_v1 The wmaker_dockapp_v1 interface + * + * Represents a dock application. The client attaches buffers to the + * underlying wl_surface and commits them; the compositor displays the + * surface content within a dock tile. + * + * The client should render at the size indicated by the configure event. + * The surface supports ARGB — transparent pixels let the dock tile + * background show through. + * + * The compositor manages the dockapp's lifecycle: it may be undocked + * (closed event), moved between dock slots, or hidden when the dock + * is collapsed. + */ +extern const struct wl_interface wmaker_dockapp_v1_interface; +#endif + +/** + * @ingroup iface_wmaker_dockapp_manager_v1 + * @struct wmaker_dockapp_manager_v1_interface + */ +struct wmaker_dockapp_manager_v1_interface { + /** + * release the manager + * + * Destroy the manager. Existing dockapp objects remain valid. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * create a dockapp from a wl_surface + * + * Wrap the given wl_surface as a dock application. The surface + * must not have another role (xdg_toplevel, xdg_popup, etc.) + * assigned. The compositor will place this surface in the next + * available dock slot or use the app_id for slot matching against + * saved state. + * @param id the new dockapp object + * @param surface the surface to use as dockapp content + */ + void (*get_dockapp)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface); +}; + + +/** + * @ingroup iface_wmaker_dockapp_manager_v1 + */ +#define WMAKER_DOCKAPP_MANAGER_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wmaker_dockapp_manager_v1 + */ +#define WMAKER_DOCKAPP_MANAGER_V1_GET_DOCKAPP_SINCE_VERSION 1 + +#ifndef WMAKER_DOCKAPP_V1_ERROR_ENUM +#define WMAKER_DOCKAPP_V1_ERROR_ENUM +enum wmaker_dockapp_v1_error { + /** + * set_app_id called after first commit + */ + WMAKER_DOCKAPP_V1_ERROR_ALREADY_CONFIGURED = 0, +}; +#endif /* WMAKER_DOCKAPP_V1_ERROR_ENUM */ + +#ifndef WMAKER_DOCKAPP_V1_ERROR_ENUM_IS_VALID +#define WMAKER_DOCKAPP_V1_ERROR_ENUM_IS_VALID +/** + * @ingroup iface_wmaker_dockapp_v1 + * Validate a wmaker_dockapp_v1 error value. + * + * @return true on success, false on error. + * @ref wmaker_dockapp_v1_error + */ +static inline bool +wmaker_dockapp_v1_error_is_valid(uint32_t value, uint32_t version) { + switch (value) { + case WMAKER_DOCKAPP_V1_ERROR_ALREADY_CONFIGURED: + return version >= 1; + default: + return false; + } +} +#endif /* WMAKER_DOCKAPP_V1_ERROR_ENUM_IS_VALID */ + +/** + * @ingroup iface_wmaker_dockapp_v1 + * @struct wmaker_dockapp_v1_interface + */ +struct wmaker_dockapp_v1_interface { + /** + * destroy the dockapp + * + * Remove the dockapp from the dock and destroy this object. The + * underlying wl_surface becomes inert. + */ + void (*destroy)(struct wl_client *client, + struct wl_resource *resource); + /** + * set application identifier for dock state matching + * + * Set the app_id used to match this dockapp against saved dock + * state (instance.class format, e.g. "wmclock.WMClock"). Must be + * called before the first surface commit. + * @param app_id application identifier + */ + void (*set_app_id)(struct wl_client *client, + struct wl_resource *resource, + const char *app_id); +}; + +#define WMAKER_DOCKAPP_V1_CONFIGURE 0 +#define WMAKER_DOCKAPP_V1_CLOSED 1 + +/** + * @ingroup iface_wmaker_dockapp_v1 + */ +#define WMAKER_DOCKAPP_V1_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_wmaker_dockapp_v1 + */ +#define WMAKER_DOCKAPP_V1_CLOSED_SINCE_VERSION 1 + +/** + * @ingroup iface_wmaker_dockapp_v1 + */ +#define WMAKER_DOCKAPP_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wmaker_dockapp_v1 + */ +#define WMAKER_DOCKAPP_V1_SET_APP_ID_SINCE_VERSION 1 + +/** + * @ingroup iface_wmaker_dockapp_v1 + * Sends an configure event to the client owning the resource. + * @param resource_ The client's resource + * @param width requested width in pixels + * @param height requested height in pixels + */ +static inline void +wmaker_dockapp_v1_send_configure(struct wl_resource *resource_, uint32_t width, uint32_t height) +{ + wl_resource_post_event(resource_, WMAKER_DOCKAPP_V1_CONFIGURE, width, height); +} + +/** + * @ingroup iface_wmaker_dockapp_v1 + * Sends an closed event to the client owning the resource. + * @param resource_ The client's resource + */ +static inline void +wmaker_dockapp_v1_send_closed(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, WMAKER_DOCKAPP_V1_CLOSED); +} + +#ifdef __cplusplus +} +#endif + +#endif