Request server-side decorations from the host compositor

The nested window is an xdg_toplevel client inside labwc, but tabbed-
wlroots never bound xdg-decoration-unstable-v1, so labwc added no title
bar. Generate the client protocol (wayland-scanner), register it in the
Makefile, and after creating the host toplevel request SERVER_SIDE mode
so labwc draws a real host title bar above the nested content. Adds an
informational configure listener that reports the effective mode.
This commit is contained in:
Andrew Hamilton 2026-08-07 10:32:11 +10:00
parent b7faf9ec91
commit ec3ec08e11
4 changed files with 495 additions and 1 deletions

View file

@ -32,6 +32,7 @@
#include <wayland-egl.h>
#include <wayland-server.h>
#include "xdg-decoration-client.h"
#include "xdg-shell-client.h"
#include <EGL/egl.h>
@ -120,6 +121,8 @@ struct tabbed_host {
struct xdg_wm_base *wm_base;
struct xdg_surface *xdg_surface;
struct xdg_toplevel *toplevel;
struct zxdg_decoration_manager_v1 *decoration;
struct zxdg_toplevel_decoration_v1 *decoration_obj;
struct wl_seat *seat;
struct wl_keyboard *keyboard;
struct wl_pointer *pointer;
@ -578,6 +581,9 @@ static void host_registry_global(void *data, struct wl_registry *registry,
} else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
host.wm_base = wl_registry_bind(registry, name,
&xdg_wm_base_interface, version < 1 ? version : 1);
} else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) {
host.decoration = wl_registry_bind(registry, name,
&zxdg_decoration_manager_v1_interface, 1);
} else if (strcmp(interface, wl_seat_interface.name) == 0) {
host.seat = wl_registry_bind(registry, name,
&wl_seat_interface, version < 5 ? version : 5);
@ -651,6 +657,20 @@ static const struct xdg_toplevel_listener host_xdg_toplevel_listener = {
.close = host_xdg_toplevel_close,
};
static void host_decoration_configure(void *data,
struct zxdg_toplevel_decoration_v1 *dec,
uint32_t mode)
{
(void)data; (void)dec;
fprintf(stderr, "tabbed-wlroots: host decoration mode=%u (%s)\n", mode,
mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE
? "server-side" : "client-side");
}
static const struct zxdg_toplevel_decoration_v1_listener host_decoration_listener = {
.configure = host_decoration_configure,
};
/* ---------- host keyboard ---------- */
static void host_kbd_keymap(void *data, struct wl_keyboard *kbd, uint32_t format,
@ -892,6 +912,17 @@ static bool host_init(void) {
host.xdg_surface = xdg_wm_base_get_xdg_surface(host.wm_base, host.surface);
host.toplevel = xdg_surface_get_toplevel(host.xdg_surface);
xdg_toplevel_set_title(host.toplevel, "tabbed-wlroots");
if (host.decoration) {
/* Ask the host compositor (labwc) for a server-side title bar, so
the nested window always has a host-drawn decoration above our
own tab content (including full-bleed clients like the test). */
host.decoration_obj = zxdg_decoration_manager_v1_get_toplevel_decoration(
host.decoration, host.toplevel);
zxdg_toplevel_decoration_v1_add_listener(host.decoration_obj,
&host_decoration_listener, NULL);
zxdg_toplevel_decoration_v1_set_mode(host.decoration_obj,
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
}
xdg_surface_add_listener(host.xdg_surface, &host_xdg_surface_listener, NULL);
xdg_toplevel_add_listener(host.toplevel, &host_xdg_toplevel_listener, NULL);
xdg_wm_base_add_listener(host.wm_base, &host_xdg_wm_listener, NULL);