ref: 8e6fe7002686d88b0c15f2c47e6cd345b1dd4cda
parent: a6c1ce4e0244ca70403dc4e795a9cee548159560
author: mia soweli <mia@soweli.net>
date: Thu Jun 12 07:31:36 EDT 2025
gui-wl: Use libdecor for window decorations This replaces the previous rudimentary window decorations with those provided by libdecor. This means a bit more of a sensible look on GNOME and no change anywhere else that is sane enough to support server side decorations.
--- a/Make.linux
+++ b/Make.linux
@@ -8,7 +8,7 @@
O=o
OS=posix
GUI=wl
-LDADD=-lwayland-client -lxkbcommon -ggdb -lm -lrt -lpipewire-0.3
+LDADD=-lwayland-client -lxkbcommon -ggdb -lm -lrt -lpipewire-0.3 -ldecor-0
LDFLAGS=$(PTHREAD)
TARG=drawterm
# AUDIO=none
--- a/gui-wl/wl-cb.c
+++ b/gui-wl/wl-cb.c
@@ -15,6 +15,7 @@
#include <wayland-client-protocol.h>
#include <linux/input-event-codes.h>
#include <xkbcommon/xkbcommon.h>
+#include <libdecor-0/libdecor.h>
#include "xdg-shell-protocol.h"
#include "xdg-decoration-protocol.h"
#include "xdg-primary-selection-protocol.h"
@@ -23,52 +24,6 @@
#include "screen.h"
#include "wl-inc.h"
-
-static void
-xdg_surface_handle_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial)
-{
- Wlwin *wl;
-
- wl = data;
- xdg_surface_ack_configure(xdg_surface, serial);
- wl_surface_commit(wl->surface);
-}
-
-const struct xdg_surface_listener xdg_surface_listener = {
- .configure = xdg_surface_handle_configure,
-};
-
-static void
-xdg_toplevel_handle_close(void *data, struct xdg_toplevel *xdg_toplevel)
-{
- wlclose(data);
-}
-
-static void
-xdg_toplevel_handle_configure(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *states)
-{
- Wlwin *wl;
- enum xdg_toplevel_state state;
- int i;
-
- wl = data;
- if(width == 0 || height == 0 || (width == wl->dx && height == wl->dy))
- return;
- wlresize(wl, width, height);
-
- wl->maximized = 0;
- for(i = 0; i < states->size; i++){
- state = ((enum xdg_toplevel_state *)states->data)[i];
- if(state == XDG_TOPLEVEL_STATE_MAXIMIZED)
- wl->maximized = 1;
- }
-}
-
-const struct xdg_toplevel_listener xdg_toplevel_listener = {
- .configure = xdg_toplevel_handle_configure,
- .close = xdg_toplevel_handle_close,
-};
-
static const struct wl_callback_listener wl_surface_frame_listener;
static void
@@ -367,31 +322,6 @@
P9Mouse3 = 4,
};
-static int
-csd_handle_mouse(Wlwin *wl, uint32_t button, uint32_t serial)
-{
- if(ptinrect(wl->mouse.xy, wl->csd_rects.button_close)){
- wlclose(wl);
- return 1;
- }
- if(ptinrect(wl->mouse.xy, wl->csd_rects.button_maximize)){
- wltogglemaximize(wl);
- return 1;
- }
- if(ptinrect(wl->mouse.xy, wl->csd_rects.button_minimize)){
- wlminimize(wl);
- return 1;
- }
- if(ptinrect(wl->mouse.xy, wl->csd_rects.bar)){
- switch (button) {
- case BTN_LEFT: wlmove(wl, serial); break;
- case BTN_RIGHT: wlmenu(wl, serial); break;
- }
- return 1;
- }
- return 0;
-}
-
static void
pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
{
@@ -412,8 +342,6 @@
wl->mouse.buttons &= ~m;
wl->mouse.msec = time;
- if(state && wl->client_side_deco && csd_handle_mouse(wl, button, serial))
- return;
absmousetrack(wl->mouse.xy.x, wl->mouse.xy.y, wl->mouse.buttons, wl->mouse.msec);
}
@@ -438,7 +366,10 @@
wl = data;
wl->pointerserial = serial;
pointer_handle_motion(data, wl_pointer, wl->mouse.msec, surface_x, surface_y);
- setcursor();
+
+ /* let libdecor handle the cursor for it's surfaces */
+ if (wl->surface == surface)
+ setcursor();
}
static void
@@ -660,22 +591,6 @@
};
static void
-zxdg_toplevel_decoration_v1_handle_configure(void *data, struct zxdg_toplevel_decoration_v1 *deco, uint32_t mode)
-{
- Wlwin *wl = data;
- int csd = mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
- if(csd == wl->client_side_deco){
- return;
- }
-
- wl->client_side_deco = csd;
-}
-
-static const struct zxdg_toplevel_decoration_v1_listener zxdg_toplevel_decoration_v1_listener = {
- .configure = zxdg_toplevel_decoration_v1_handle_configure,
-};
-
-static void
mode(void *data, struct wl_output*, uint, int x, int y, int)
{
Wlwin *wl;
@@ -722,8 +637,6 @@
xdg_wm_base_add_listener(wl->xdg_wm_base, &xdg_wm_base_listener, wl);
} else if(strcmp(interface, wl_data_device_manager_interface.name) == 0){
wl->data_device_manager = wl_registry_bind(registry, name, &wl_data_device_manager_interface, 3);
- } else if(strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0){
- wl->decoman = wl_registry_bind(registry, name, &zxdg_decoration_manager_v1_interface, 1);
} else if(strcmp(interface, zwp_primary_selection_device_manager_v1_interface.name) == 0){
wl->primsel = wl_registry_bind(registry, name, &zwp_primary_selection_device_manager_v1_interface, 1);
} else if(strcmp(interface, zwlr_virtual_pointer_manager_v1_interface.name) == 0){
@@ -741,13 +654,59 @@
.global_remove = handle_global_remove,
};
+static void
+handle_decor_error(struct libdecor *context, enum libdecor_error err, const char *errmsg)
+{
+ panic("libdecor error");
+}
+
+const struct libdecor_interface decor_interface = {
+ .error = handle_decor_error,
+};
+
+static void
+handle_decor_frame_configure(struct libdecor_frame *frame, struct libdecor_configuration *frameconfig, void *aux)
+{
+ Wlwin *wl;
+ struct libdecor_state *state;
+ int dx, dy;
+
+ wl = aux;
+ if (!libdecor_configuration_get_content_size(frameconfig, frame, &dx, &dy)) {
+ dx = 0;
+ dy = 0;
+ }
+
+ dx = (dx == 0) ? wl->dx : dx;
+ dy = (dy == 0) ? wl->dy : dy;
+
+ state = libdecor_state_new(dx, dy);
+ libdecor_frame_commit(frame, state, frameconfig);
+ libdecor_state_free(state);
+
+ if (dx != wl->dx || dy != wl->dy)
+ wlresize(wl, dx, dy);
+}
+
+static void
+handle_decor_frame_commit(struct libdecor_frame *frame, void *aux)
+{
+ Wlwin *wl;
+
+ wl = aux;
+ wl_surface_commit(wl->surface);
+}
+
+const struct libdecor_frame_interface decor_frame_interface = {
+ .configure = handle_decor_frame_configure,
+ .commit = handle_decor_frame_commit,
+};
+
void
wlsetcb(Wlwin *wl)
{
struct wl_registry *registry;
- struct xdg_surface *xdg_surface;
struct wl_callback *cb;
- struct zxdg_toplevel_decoration_v1 *deco;
//Wayland doesn't do keyboard repeat, but also may
//not tell us what the user would like, so we
@@ -770,24 +729,16 @@
wlallocbuffer(wl);
wl->surface = wl_compositor_create_surface(wl->compositor);
- xdg_surface = xdg_wm_base_get_xdg_surface(wl->xdg_wm_base, wl->surface);
- wl->xdg_toplevel = xdg_surface_get_toplevel(xdg_surface);
- xdg_surface_add_listener(xdg_surface, &xdg_surface_listener, wl);
- xdg_toplevel_add_listener(wl->xdg_toplevel, &xdg_toplevel_listener, wl);
+ wl->decor = libdecor_new(wl->display, &decor_interface);
+ wl->decor_frame = libdecor_decorate(wl->decor, wl->surface, &decor_frame_interface, wl);
+ libdecor_frame_set_app_id(wl->decor_frame, "org._9front.drawterm");
+ libdecor_frame_set_title(wl->decor_frame, "drawterm");
+ libdecor_frame_map(wl->decor_frame);
+
wl_surface_commit(wl->surface);
wl_display_roundtrip(wl->display);
- wl->client_side_deco = wl->decoman == nil;
- if(wl->decoman != nil){
- deco = zxdg_decoration_manager_v1_get_toplevel_decoration(wl->decoman, wl->xdg_toplevel);
- zxdg_toplevel_decoration_v1_add_listener(deco, &zxdg_toplevel_decoration_v1_listener, wl);
- zxdg_toplevel_decoration_v1_set_mode(deco, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
- wl_display_roundtrip(wl->display);
- }
-
- xdg_toplevel_set_app_id(wl->xdg_toplevel, "drawterm");
-
cb = wl_surface_frame(wl->surface);
wl_callback_add_listener(cb, &wl_surface_frame_listener, wl);
@@ -804,7 +755,7 @@
void
wlsettitle(Wlwin *wl, char *s)
{
- xdg_toplevel_set_title(wl->xdg_toplevel, s);
+ libdecor_frame_set_title(wl->decor_frame, s);
}
void
--- a/gui-wl/wl-inc.h
+++ b/gui-wl/wl-inc.h
@@ -1,6 +1,5 @@
typedef struct Wlwin Wlwin;
typedef struct Clipboard Clipboard;
-typedef struct Csd Csd;
/* The contents of the clipboard
* are not stored in the compositor.
@@ -33,18 +32,6 @@
Aenter2,
};
-enum CsdSizes {
- csd_bar_height = 24,
- csd_button_width = 16,
-};
-
-struct Csd {
- Rectangle bar;
- Rectangle button_close;
- Rectangle button_maximize;
- Rectangle button_minimize;
-};
-
struct Wlwin {
int dx;
int dy;
@@ -55,7 +42,6 @@
Rectangle r;
int dirty;
int alt; /* Kalt state */
- int maximized;
/* Wayland State */
int runing;
@@ -77,13 +63,14 @@
struct wl_data_device *data_device;
struct wl_pointer *pointer;
struct wl_keyboard *keyboard;
+
/* Keyboard state */
struct xkb_state *xkb_state;
struct xkb_context *xkb_context;
- struct zxdg_decoration_manager_v1 *decoman;
- int client_side_deco;
- Csd csd_rects;
+ /* Decoration state */
+ struct libdecor *decor;
+ struct libdecor_frame *decor_frame;
struct zwp_primary_selection_device_manager_v1 *primsel;
struct zwp_primary_selection_device_v1 *primsel_device;
@@ -102,7 +89,4 @@
void wlresize(Wlwin*, int, int);
void wlflush(Wlwin*);
void wlclose(Wlwin*);
-void wltogglemaximize(Wlwin*);
-void wlminimize(Wlwin*);
-void wlmove(Wlwin*, uint32_t);
-void wlmenu(Wlwin*, uint32_t);
+
--- a/gui-wl/wl-screen.c
+++ b/gui-wl/wl-screen.c
@@ -14,6 +14,7 @@
#include <wayland-client-protocol.h>
#include <linux/input-event-codes.h>
#include <xkbcommon/xkbcommon.h>
+#include <libdecor-0/libdecor.h>
#include "xdg-shell-protocol.h"
#include "screen.h"
@@ -46,77 +47,6 @@
}
void
-wltogglemaximize(Wlwin *wl)
-{
- if(wl->maximized)
- xdg_toplevel_unset_maximized(wl->xdg_toplevel);
- else
- xdg_toplevel_set_maximized(wl->xdg_toplevel);
-}
-
-void
-wlminimize(Wlwin *wl)
-{
- xdg_toplevel_set_minimized(wl->xdg_toplevel);
-}
-
-void
-wlmove(Wlwin *wl, uint32_t serial)
-{
- xdg_toplevel_move(wl->xdg_toplevel, wl->seat, serial);
-}
-
-void
-wlmenu(Wlwin *wl, uint32_t serial)
-{
- xdg_toplevel_show_window_menu(wl->xdg_toplevel, wl->seat, serial, wl->mouse.xy.x, wl->mouse.xy.y);
-}
-
-static void
-wlupdatecsdrects(Wlwin *wl)
-{
- Point offset;
- Rectangle button;
-
- if(!wl->client_side_deco){
- memset(&wl->csd_rects, 0, sizeof wl->csd_rects);
- return;
- }
-
- wl->csd_rects.bar = Rect(0, 0, wl->dx, csd_bar_height);
-
- offset = Pt(csd_button_width + 4, 0);
- button = Rect(0, 4, csd_button_width, csd_button_width + 4);
- button = rectsubpt(button, offset);
-
- wl->csd_rects.button_close = button = rectaddpt(button, Pt(wl->dx, 0));
- wl->csd_rects.button_maximize = button = rectsubpt(button, offset);
- wl->csd_rects.button_minimize = rectsubpt(button, offset);
-}
-
-static void
-wlfillrect(Wlwin *wl, Rectangle rect, uint32_t color)
-{
- Point p;
- uint32_t *data = wl->shm_data;
-
- for(p.y = rect.min.y; p.y < rect.max.y; p.y++)
- for(p.x = rect.min.x; p.x < rect.max.x; p.x++)
- data[p.y * wl->dx + p.x] = color;
-}
-
-static void
-wldrawcsd(Wlwin *wl)
-{
- if(!wl->client_side_deco)
- return;
- wlfillrect(wl, wl->csd_rects.bar, 0xAAAAAA);
- wlfillrect(wl, wl->csd_rects.button_close, DRed >> 8);
- wlfillrect(wl, wl->csd_rects.button_maximize, DGreen >> 8);
- wlfillrect(wl, wl->csd_rects.button_minimize, DYellow >> 8);
-}
-
-void
wlflush(Wlwin *wl)
{
Point p;
@@ -141,11 +71,10 @@
wl->dx = x;
wl->dy = y;
- wlupdatecsdrects(wl);
qlock(&drawlock);
wlallocbuffer(wl);
- r = Rect(0, wl->csd_rects.bar.max.y, wl->dx, wl->dy);
+ r = Rect(0, 0, wl->dx, wl->dy);
if(gscreen != nil)
freememimage(gscreen);
gscreen = allocmemimage(r, XRGB32);
@@ -157,7 +86,6 @@
qlock(&drawlock);
wl->dirty = 1;
wl->r = r;
- wldrawcsd(wl);
wlflush(wl);
qunlock(&drawlock);
}
@@ -168,7 +96,7 @@
Wlwin *wl;
wl = a;
while(wl->runing)
- wl_display_dispatch(wl->display);
+ libdecor_dispatch(wl->decor, -1);
}
static Wlwin*
@@ -185,11 +113,10 @@
memimageinit();
wlsetcb(wl);
- wlupdatecsdrects(wl);
wlflush(wl);
wlsettitle(wl, label);
- r = Rect(0, wl->csd_rects.bar.max.y, wl->dx, wl->dy);
+ r = Rect(0, 0, wl->dx, wl->dy);
gscreen = allocmemimage(r, XRGB32);
gscreen->clipr = r;
@@ -196,7 +123,7 @@
wl->runing = 1;
kproc("wldispatch", dispatchproc, wl);
qlock(&drawlock);
- wldrawcsd(wl);
+
terminit();
wlflush(wl);
qunlock(&drawlock);
--
⑨