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.
This commit is contained in:
lkn 2026-06-28 02:04:44 +02:00
parent 77c1687f4a
commit 00d330fe88
8 changed files with 1004 additions and 1 deletions

View File

@ -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 <stdint.h>
#include <stddef.h>
#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
* <pre>
*
* 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.
* </pre>
*/
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

View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="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.
</copyright>
<description summary="Window Maker dock application protocol">
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.
</description>
<interface name="wmaker_dockapp_manager_v1" version="1">
<description summary="manager for dock application surfaces">
Singleton global advertised by Window Maker compositors. Clients bind
to create dockapp objects for their surfaces.
</description>
<request name="destroy" type="destructor">
<description summary="release the manager">
Destroy the manager. Existing dockapp objects remain valid.
</description>
</request>
<request name="get_dockapp">
<description summary="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.
</description>
<arg name="id" type="new_id" interface="wmaker_dockapp_v1"
summary="the new dockapp object"/>
<arg name="surface" type="object" interface="wl_surface"
summary="the surface to use as dockapp content"/>
</request>
</interface>
<interface name="wmaker_dockapp_v1" version="1">
<description summary="a dock application surface">
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.
</description>
<enum name="error">
<entry name="already_configured" value="0"
summary="set_app_id called after first commit"/>
</enum>
<request name="destroy" type="destructor">
<description summary="destroy the dockapp">
Remove the dockapp from the dock and destroy this object. The
underlying wl_surface becomes inert.
</description>
</request>
<request name="set_app_id">
<description summary="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.
</description>
<arg name="app_id" type="string" summary="application identifier"/>
</request>
<event name="configure">
<description summary="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.
</description>
<arg name="width" type="uint" summary="requested width in pixels"/>
<arg name="height" type="uint" summary="requested height in pixels"/>
</event>
<event name="closed">
<description summary="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.
</description>
</event>
</interface>
</protocol>

View File

@ -8,6 +8,8 @@ WLR_PROTO_DIR = $(shell pkg-config --variable=pkgdatadir wlr-protocols 2>/dev/nu
BUILT_SOURCES = wconfig.h \ BUILT_SOURCES = wconfig.h \
wmaker-popup-v1-server-protocol.h \ wmaker-popup-v1-server-protocol.h \
wmaker-popup-v1-protocol.c \ wmaker-popup-v1-protocol.c \
wmaker-dockapp-v1-server-protocol.h \
wmaker-dockapp-v1-protocol.c \
protocols/pointer-constraints-unstable-v1-protocol.h \ protocols/pointer-constraints-unstable-v1-protocol.h \
protocols/wlr-output-power-management-unstable-v1-protocol.h \ protocols/wlr-output-power-management-unstable-v1-protocol.h \
protocols/wlr-layer-shell-unstable-v1-protocol.h \ protocols/wlr-layer-shell-unstable-v1-protocol.h \
@ -20,10 +22,14 @@ EXTRA_DIST =
nodist_wmaker_SOURCES = \ nodist_wmaker_SOURCES = \
wmaker-popup-v1-protocol.c \ 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 \ CLEANFILES = wmaker-popup-v1-server-protocol.h \
wmaker-popup-v1-protocol.c \ wmaker-popup-v1-protocol.c \
wmaker-dockapp-v1-server-protocol.h \
wmaker-dockapp-v1-protocol.c \
protocols/pointer-constraints-unstable-v1-protocol.h \ protocols/pointer-constraints-unstable-v1-protocol.h \
protocols/wlr-output-power-management-unstable-v1-protocol.h \ protocols/wlr-output-power-management-unstable-v1-protocol.h \
protocols/wlr-layer-shell-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 wmaker-popup-v1-server-protocol.h
$(WAYLAND_SCANNER) private-code $< $@ $(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 # Generate protocol headers for Wayland compositor backend
protocols/pointer-constraints-unstable-v1-protocol.h: protocols/pointer-constraints-unstable-v1-protocol.h:
@mkdir -p protocols @mkdir -p protocols
@ -238,6 +251,7 @@ wmaker_SOURCES += \
backend/wayland/wl_grab.c \ backend/wayland/wl_grab.c \
backend/wayland/wl_keyboard.c \ backend/wayland/wl_keyboard.c \
backend/wayland/wl_popup.c \ backend/wayland/wl_popup.c \
backend/wayland/wl_dockapp_proto.c \
backend/wayland/wl_text_input.c \ backend/wayland/wl_text_input.c \
backend/wayland/wl_xdg_activation.c \ backend/wayland/wl_xdg_activation.c \
backend/wayland/wl_output_mgmt.c \ backend/wayland/wl_output_mgmt.c \

View File

@ -0,0 +1,200 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <stdlib.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/util/log.h>
#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");
}

View File

@ -472,6 +472,10 @@ wl_protocols_init(void)
if (wl_state.wmaker_popup_manager) if (wl_state.wmaker_popup_manager)
wwarning("wl_backend: wmaker-popup-v1 manager created"); 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 /* advertise zxdg_decoration_manager_v1 so clients that
* support server-side decorations can negotiate; we respond with * support server-side decorations can negotiate; we respond with
* CLIENT_SIDE since the Wayland path has no X11 frame rendering. */ * CLIENT_SIDE since the Wayland path has no X11 frame rendering. */

View File

@ -169,6 +169,8 @@ struct wl_compositor_state {
struct wlr_xdg_shell *xdg_shell; struct wlr_xdg_shell *xdg_shell;
/* wmaker-popup-v1 protocol global — client-driven popup positioning */ /* wmaker-popup-v1 protocol global — client-driven popup positioning */
struct wl_global *wmaker_popup_manager; 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 */ /* Phase 64: XDG decoration manager — tell clients to use CSD */
struct wlr_xdg_decoration_manager_v1 *decoration_manager; struct wlr_xdg_decoration_manager_v1 *decoration_manager;
struct wl_listener decoration_new_listener; struct wl_listener decoration_new_listener;

View File

@ -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 <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#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,
};

View File

@ -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 <stdint.h>
#include <stddef.h>
#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
* <pre>
*
* 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.
* </pre>
*/
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