From 25dfdcc4337a8b6ca40a5848ef1d49160105f568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 15 Nov 2022 23:04:02 -0600 Subject: [PATCH 001/347] specify layer shell version --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 6d44c52..bfac6b5 100644 --- a/dwl.c +++ b/dwl.c @@ -2038,7 +2038,7 @@ setup(void) idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &idle_inhibitor_create); - layer_shell = wlr_layer_shell_v1_create(dpy); + layer_shell = wlr_layer_shell_v1_create(dpy, 3); wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface); xdg_shell = wlr_xdg_shell_create(dpy, 4); From 359e7edc52c38a0eb1bbc33aa238561efaf28d58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 15 Nov 2022 23:04:39 -0600 Subject: [PATCH 002/347] update for wlroots!3814 References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3814 --- dwl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index bfac6b5..5d484dc 100644 --- a/dwl.c +++ b/dwl.c @@ -305,6 +305,7 @@ static struct wlr_scene_tree *layers[NUM_LAYERS]; static struct wlr_renderer *drw; static struct wlr_allocator *alloc; static struct wlr_compositor *compositor; +static struct wlr_session *session; static struct wlr_xdg_shell *xdg_shell; static struct wlr_xdg_activation_v1 *activation; @@ -582,7 +583,8 @@ buttonpress(struct wl_listener *listener, void *data) void chvt(const Arg *arg) { - wlr_session_change_vt(wlr_backend_get_session(backend), arg->ui); + if (session) + wlr_session_change_vt(session, arg->ui); } void @@ -1969,7 +1971,7 @@ setup(void) * backend uses the renderer, for example, to fall back to software cursors * if the backend does not support hardware cursors (some older GPUs * don't). */ - if (!(backend = wlr_backend_autocreate(dpy))) + if (!(backend = wlr_backend_autocreate(dpy, &session))) die("couldn't create backend"); /* Initialize the scene graph used to lay out windows */ From 5eb352927575bd45c75d6d7f5e3f7a6e3499a85f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 15 Nov 2022 23:07:21 -0600 Subject: [PATCH 003/347] use the new scene helper for drag icons --- dwl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index 5d484dc..d8cee36 100644 --- a/dwl.c +++ b/dwl.c @@ -990,8 +990,6 @@ cursorframe(struct wl_listener *listener, void *data) void destroydragicon(struct wl_listener *listener, void *data) { - struct wlr_drag_icon *icon = data; - wlr_scene_node_destroy(icon->data); /* Focus enter isn't sent during drag, so refocus the focused node. */ focusclient(selclient(), 1); motionnotify(0); @@ -2148,7 +2146,7 @@ startdrag(struct wl_listener *listener, void *data) if (!drag->icon) return; - drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrDragIcon], drag->icon->surface); + drag->icon->data = wlr_scene_drag_icon_create(layers[LyrDragIcon], drag->icon); motionnotify(0); wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); } From dae00caaddee6d14cb566ee750c976543788d5fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 15 Nov 2022 23:07:45 -0600 Subject: [PATCH 004/347] update for wlroots!3861 References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3861 --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index d8cee36..386763a 100644 --- a/dwl.c +++ b/dwl.c @@ -1439,8 +1439,8 @@ motionnotify(uint32_t time) /* Update drag icon's position if any */ if (seat->drag && (icon = seat->drag->icon)) - wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, - cursor->y + icon->surface->sy); + wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->current.dx, + cursor->y + icon->surface->current.dy); /* If we are currently grabbing the mouse, handle and return */ if (cursor_mode == CurMove) { /* Move the grabbed client to the new position. */ From 21ef004886be1092becba61abb71e9fd86b85c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 15 Nov 2022 23:52:21 -0600 Subject: [PATCH 005/347] listen to the output request_state event; References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/2693 --- dwl.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dwl.c b/dwl.c index 386763a..d630d06 100644 --- a/dwl.c +++ b/dwl.c @@ -173,6 +173,7 @@ struct Monitor { struct wlr_scene_output *scene_output; struct wl_listener frame; struct wl_listener destroy; + struct wl_listener request_state; struct wlr_box m; /* monitor area, layout-relative */ struct wlr_box w; /* window area, layout-relative */ struct wl_list layers[4]; /* LayerSurface::link */ @@ -260,6 +261,7 @@ static void quit(const Arg *arg); static void quitsignal(int signo); static void rendermon(struct wl_listener *listener, void *data); static void requeststartdrag(struct wl_listener *listener, void *data); +static void requestmonstate(struct wl_listener *listener, void *data); static void resize(Client *c, struct wlr_box geo, int interact); static void run(char *startup_cmd); static Client *selclient(void); @@ -865,6 +867,7 @@ createmon(struct wl_listener *listener, void *data) /* Set up event listeners */ LISTEN(&wlr_output->events.frame, &m->frame, rendermon); LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon); + LISTEN(&wlr_output->events.request_state, &m->request_state, requestmonstate); wlr_output_enable(wlr_output, 1); if (!wlr_output_commit(wlr_output)) @@ -1708,6 +1711,13 @@ requeststartdrag(struct wl_listener *listener, void *data) wlr_data_source_destroy(event->drag->source); } +void +requestmonstate(struct wl_listener *listener, void *data) +{ + struct wlr_output_event_request_state *event = data; + wlr_output_commit_state(event->output, event->state); +} + void resize(Client *c, struct wlr_box geo, int interact) { From 27ab9cf1b1230e6e839a6a10eb85c670c59d6f9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 2 Dec 2022 23:17:05 -0600 Subject: [PATCH 006/347] call updatemons() in requestmonstate() This way we make sure that the Monitor's boxes are updated correctly --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index 255a334..c9d79d9 100644 --- a/dwl.c +++ b/dwl.c @@ -1738,6 +1738,7 @@ requestmonstate(struct wl_listener *listener, void *data) { struct wlr_output_event_request_state *event = data; wlr_output_commit_state(event->output, event->state); + updatemons(NULL, NULL); } void From 02c257e0b163430401c87fc62937a454e883359b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 5 Dec 2022 20:21:38 -0600 Subject: [PATCH 007/347] update for wlroots!3627 References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3627 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index c9d79d9..0408951 100644 --- a/dwl.c +++ b/dwl.c @@ -1580,7 +1580,7 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) /* Don't move monitors if position wouldn't change, this to avoid * wlroots marking the output as manually configured */ if (m->m.x != config_head->state.x || m->m.y != config_head->state.y) - wlr_output_layout_move(output_layout, wlr_output, + wlr_output_layout_add(output_layout, wlr_output, config_head->state.x, config_head->state.y); wlr_output_set_transform(wlr_output, config_head->state.transform); wlr_output_set_scale(wlr_output, config_head->state.scale); From f7d6a34cd98e3c090956c8a263a44972c3ffa05e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 28 Sep 2022 00:54:48 -0500 Subject: [PATCH 008/347] use sigaction(2) for signal handling References: http://git.suckless.org/dwm/commit/712d6639ff8e863560328131bbb92b248dc9cde7.html --- dwl.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/dwl.c b/dwl.c index 19bb6ce..c2273ba 100644 --- a/dwl.c +++ b/dwl.c @@ -1885,6 +1885,8 @@ run(char *startup_cmd) { /* Add a Unix socket to the Wayland display. */ const char *socket = wl_display_add_socket_auto(dpy); + struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = SIG_IGN}; + sigemptyset(&sa.sa_mask); if (!socket) die("startup: display_add_socket_auto"); setenv("WAYLAND_DISPLAY", socket, 1); @@ -1913,7 +1915,7 @@ run(char *startup_cmd) close(piperw[0]); } /* If nobody is reading the status output, don't terminate */ - signal(SIGPIPE, SIG_IGN); + sigaction(SIGPIPE, &sa, NULL); printstatus(); /* At this point the outputs are initialized, choose initial selmon based on @@ -2066,18 +2068,26 @@ setsel(struct wl_listener *listener, void *data) void setup(void) { + struct sigaction sa_term = {.sa_flags = SA_RESTART, .sa_handler = quitsignal}; + struct sigaction sa_sigchld = { +#ifdef XWAYLAND + .sa_flags = SA_RESTART, + .sa_handler = sigchld, +#else + .sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART, + .sa_handler = SIG_IGN, +#endif + }; + sigemptyset(&sa_term.sa_mask); + sigemptyset(&sa_sigchld.sa_mask); /* The Wayland display is managed by libwayland. It handles accepting * clients from the Unix socket, manging Wayland globals, and so on. */ dpy = wl_display_create(); /* Set up signal handlers */ -#ifdef XWAYLAND - sigchld(0); -#else - signal(SIGCHLD, SIG_IGN); -#endif - signal(SIGINT, quitsignal); - signal(SIGTERM, quitsignal); + sigaction(SIGCHLD, &sa_sigchld, NULL); + sigaction(SIGINT, &sa_term, NULL); + sigaction(SIGTERM, &sa_term, NULL); /* The backend is a wlroots feature which abstracts the underlying input and * output hardware. The autocreate option will choose the most suitable @@ -2699,12 +2709,11 @@ sigchld(int unused) { siginfo_t in; /* We should be able to remove this function in favor of a simple - * signal(SIGCHLD, SIG_IGN); + * struct sigaction sa = {.sa_handler = SIG_IGN}; + * sigaction(SIGCHLD, &sa, NULL); * but the Xwayland implementation in wlroots currently prevents us from * setting our own disposition for SIGCHLD. */ - if (signal(SIGCHLD, sigchld) == SIG_ERR) - die("can't install SIGCHLD handler:"); /* WNOWAIT leaves the child in a waitable state, in case this is the * XWayland process */ From 7ae5039b4f35c6f5fd09f2d650c62dc7304ce6fe Mon Sep 17 00:00:00 2001 From: Job79 Date: Wed, 1 Feb 2023 20:09:45 +0100 Subject: [PATCH 009/347] follow upstream xwayland_surface changes wlroots removed the `wlr_surface_is_xwayland_surface` function, and renamed `wlr_xwayland_surface_from_wlr_surface` to `wlr_xwayland_surface_try_from_wlr_surface`. related commit: https://gitlab.freedesktop.org/wlroots/wlroots/-/commit/fbf5982e3838ee28b5345e98832f6956c402b225 --- client.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/client.h b/client.h index 5a45edc..558dd03 100644 --- a/client.h +++ b/client.h @@ -69,8 +69,7 @@ toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl) root_surface = wlr_surface_get_root_surface(s); #ifdef XWAYLAND - if (wlr_surface_is_xwayland_surface(root_surface) - && (xsurface = wlr_xwayland_surface_from_wlr_surface(root_surface))) { + if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(root_surface))) { c = xsurface->data; type = c->type; goto end; @@ -121,8 +120,7 @@ client_activate_surface(struct wlr_surface *s, int activated) struct wlr_xdg_surface *surface; #ifdef XWAYLAND struct wlr_xwayland_surface *xsurface; - if (wlr_surface_is_xwayland_surface(s) - && (xsurface = wlr_xwayland_surface_from_wlr_surface(s))) { + if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(s))) { wlr_xwayland_surface_activate(xsurface, activated); return; } From e7f736ccc9435138d9921ba1f3ba5ebed142523b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 2 Feb 2023 10:30:24 -0600 Subject: [PATCH 010/347] chase wlroots!3391 References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3991 --- client.h | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/client.h b/client.h index 558dd03..5fe31b1 100644 --- a/client.h +++ b/client.h @@ -76,24 +76,22 @@ toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl) } #endif - if (wlr_surface_is_layer_surface(root_surface) - && (layer_surface = wlr_layer_surface_v1_from_wlr_surface(root_surface))) { + if ((layer_surface = wlr_layer_surface_v1_try_from_wlr_surface(root_surface))) { l = layer_surface->data; type = LayerShell; goto end; } - if (wlr_surface_is_xdg_surface(root_surface) - && (xdg_surface = wlr_xdg_surface_from_wlr_surface(root_surface))) { + if ((xdg_surface = wlr_xdg_surface_try_from_wlr_surface(root_surface))) { while (1) { switch (xdg_surface->role) { case WLR_XDG_SURFACE_ROLE_POPUP: if (!xdg_surface->popup->parent) return -1; - else if (!wlr_surface_is_xdg_surface(xdg_surface->popup->parent)) + else if (!wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent)) return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc, pl); - xdg_surface = wlr_xdg_surface_from_wlr_surface(xdg_surface->popup->parent); + xdg_surface = wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent); break; case WLR_XDG_SURFACE_ROLE_TOPLEVEL: c = xdg_surface->data; @@ -125,8 +123,7 @@ client_activate_surface(struct wlr_surface *s, int activated) return; } #endif - if (wlr_surface_is_xdg_surface(s) - && (surface = wlr_xdg_surface_from_wlr_surface(s)) + if ((surface = wlr_xdg_surface_try_from_wlr_surface(s)) && surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) wlr_xdg_toplevel_set_activated(surface->toplevel, activated); } From fbe89a929f8465a288630ebe27bd656cd9ce8282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 5 Feb 2023 10:03:09 -0600 Subject: [PATCH 011/347] chase wlroots!4000 References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4000 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 360708f..42086af 100644 --- a/dwl.c +++ b/dwl.c @@ -2582,7 +2582,7 @@ xytonode(double x, double y, struct wlr_surface **psurface, for (layer = focus_order; layer < END(focus_order); layer++) { if ((node = wlr_scene_node_at(&layers[*layer]->node, x, y, nx, ny))) { if (node->type == WLR_SCENE_NODE_BUFFER) - surface = wlr_scene_surface_from_buffer( + surface = wlr_scene_surface_try_from_buffer( wlr_scene_buffer_from_node(node))->surface; /* Walk the tree to find a node that knows the client */ for (pnode = node; pnode && !c; pnode = &pnode->parent->node) From 04fdf1a29545641a23e5c586d6b3dfa3a0103d97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 8 Feb 2023 22:25:41 -0600 Subject: [PATCH 012/347] add support for wp-fractional-scale-v1 References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3511 --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index 42086af..0eb11c2 100644 --- a/dwl.c +++ b/dwl.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -2137,6 +2138,7 @@ setup(void) wlr_primary_selection_v1_device_manager_create(dpy); wlr_viewporter_create(dpy); wlr_single_pixel_buffer_manager_v1_create(dpy); + wlr_fractional_scale_manager_v1_create(dpy, 1); wlr_subcompositor_create(dpy); /* Initializes the interface used to implement urgency hints */ From 23ede80f741d8452dbf223226974476ef8860541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 8 Sep 2022 12:24:13 -0500 Subject: [PATCH 013/347] allow configure x and y of outputs --- config.def.h | 6 +++--- dwl.c | 8 +++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/config.def.h b/config.def.h index a4f7c13..419e6ef 100644 --- a/config.def.h +++ b/config.def.h @@ -29,12 +29,12 @@ static const Layout layouts[] = { /* monitors */ static const MonitorRule monrules[] = { - /* name mfact nmaster scale layout rotate/reflect */ + /* name mfact nmaster scale layout rotate/reflect x y */ /* example of a HiDPI laptop monitor: - { "eDP-1", 0.5, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL }, + { "eDP-1", 0.5, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL -1, -1 }, */ /* defaults */ - { NULL, 0.55, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL }, + { NULL, 0.55, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, }; /* keyboard */ diff --git a/dwl.c b/dwl.c index c2273ba..57870fe 100644 --- a/dwl.c +++ b/dwl.c @@ -194,6 +194,7 @@ typedef struct { float scale; const Layout *lt; enum wl_output_transform rr; + int x, y; } MonitorRule; typedef struct { @@ -908,6 +909,8 @@ createmon(struct wl_listener *listener, void *data) wlr_xcursor_manager_load(cursor_mgr, r->scale); m->lt[0] = m->lt[1] = r->lt; wlr_output_set_transform(wlr_output, r->rr); + m->m.x = r->x; + m->m.y = r->y; break; } } @@ -953,7 +956,10 @@ createmon(struct wl_listener *listener, void *data) * output (such as DPI, scale factor, manufacturer, etc). */ m->scene_output = wlr_scene_output_create(scene, wlr_output); - wlr_output_layout_add_auto(output_layout, wlr_output); + if (m->m.x < 0 || m->m.y < 0) + wlr_output_layout_add_auto(output_layout, wlr_output); + else + wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y); } void From ab8334bd8a85c5c63a2d06bc68bf0b5f5e1c2923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 26 Dec 2022 16:45:38 -0600 Subject: [PATCH 014/347] implement repeatable keybindings --- dwl.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/dwl.c b/dwl.c index 57870fe..ac741d2 100644 --- a/dwl.c +++ b/dwl.c @@ -139,6 +139,11 @@ typedef struct { struct wl_list link; struct wlr_keyboard *wlr_keyboard; + int nsyms; + const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */ + uint32_t mods; /* invalid if nsyms == 0 */ + struct wl_event_source *key_repeat_source; + struct wl_listener modifiers; struct wl_listener key; struct wl_listener destroy; @@ -259,6 +264,7 @@ static void inputdevice(struct wl_listener *listener, void *data); static int keybinding(uint32_t mods, xkb_keysym_t sym); static void keypress(struct wl_listener *listener, void *data); static void keypressmod(struct wl_listener *listener, void *data); +static int keyrepeat(void *data); static void killclient(const Arg *arg); static void locksession(struct wl_listener *listener, void *data); static void maplayersurfacenotify(struct wl_listener *listener, void *data); @@ -667,6 +673,7 @@ cleanupkeyboard(struct wl_listener *listener, void *data) { Keyboard *kb = wl_container_of(listener, kb, destroy); + wl_event_source_remove(kb->key_repeat_source); wl_list_remove(&kb->link); wl_list_remove(&kb->modifiers.link); wl_list_remove(&kb->key.link); @@ -812,6 +819,9 @@ createkeyboard(struct wlr_keyboard *keyboard) wlr_seat_set_keyboard(seat, keyboard); + kb->key_repeat_source = wl_event_loop_add_timer( + wl_display_get_event_loop(dpy), keyrepeat, kb); + /* And add the keyboard to our list of keyboards */ wl_list_insert(&keyboards, &kb->link); } @@ -1400,6 +1410,17 @@ keypress(struct wl_listener *listener, void *data) for (i = 0; i < nsyms; i++) handled = keybinding(mods, syms[i]) || handled; + if (handled && kb->wlr_keyboard->repeat_info.delay > 0) { + kb->mods = mods; + kb->keysyms = syms; + kb->nsyms = nsyms; + wl_event_source_timer_update(kb->key_repeat_source, + kb->wlr_keyboard->repeat_info.delay); + } else { + kb->nsyms = 0; + wl_event_source_timer_update(kb->key_repeat_source, 0); + } + if (!handled) { /* Pass unhandled keycodes along to the client. */ wlr_seat_set_keyboard(seat, kb->wlr_keyboard); @@ -1426,6 +1447,22 @@ keypressmod(struct wl_listener *listener, void *data) &kb->wlr_keyboard->modifiers); } +int +keyrepeat(void *data) +{ + Keyboard *kb = data; + int i; + if (kb->nsyms && kb->wlr_keyboard->repeat_info.rate > 0) { + wl_event_source_timer_update(kb->key_repeat_source, + 1000 / kb->wlr_keyboard->repeat_info.rate); + + for (i = 0; i < kb->nsyms; i++) + keybinding(kb->mods, kb->keysyms[i]); + } + + return 0; +} + void killclient(const Arg *arg) { From 7f9a21247613a0d8ba6575869220e29071a40c64 Mon Sep 17 00:00:00 2001 From: Ben Collerson Date: Wed, 23 Nov 2022 21:55:04 +1000 Subject: [PATCH 015/347] Add appid field to printstatus() output Adds an appid field to printstatus which can be used to monitor the currently active application. --- dwl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index ac741d2..efd6977 100644 --- a/dwl.c +++ b/dwl.c @@ -1823,6 +1823,7 @@ printstatus(void) Monitor *m = NULL; Client *c; unsigned int occ, urg, sel; + const char *appid, *title; wl_list_for_each(m, &mons, link) { occ = urg = 0; @@ -1834,12 +1835,16 @@ printstatus(void) urg |= c->tags; } if ((c = focustop(m))) { - printf("%s title %s\n", m->wlr_output->name, client_get_title(c)); + title = client_get_title(c); + appid = client_get_appid(c); + printf("%s title %s\n", m->wlr_output->name, title ? title : broken); + printf("%s appid %s\n", m->wlr_output->name, appid ? appid : broken); printf("%s fullscreen %u\n", m->wlr_output->name, c->isfullscreen); printf("%s floating %u\n", m->wlr_output->name, c->isfloating); sel = c->tags; } else { printf("%s title \n", m->wlr_output->name); + printf("%s appid \n", m->wlr_output->name); printf("%s fullscreen \n", m->wlr_output->name); printf("%s floating \n", m->wlr_output->name); sel = 0; From f8373ccf2581fa481602bbb7528ba8871f6d5c85 Mon Sep 17 00:00:00 2001 From: pino-desktop Date: Sun, 8 Jan 2023 17:37:24 +0100 Subject: [PATCH 016/347] Fixed 'unused variable' compiler warning. --- dwl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/dwl.c b/dwl.c index efd6977..27d051f 100644 --- a/dwl.c +++ b/dwl.c @@ -1526,7 +1526,6 @@ mapnotify(struct wl_listener *listener, void *data) } c->scene->node.data = c->scene_surface->node.data = c; -#ifdef XWAYLAND /* Handle unmanaged clients first so we can return prior create borders */ if (client_is_unmanaged(c)) { client_get_geometry(c, &c->geom); @@ -1540,7 +1539,6 @@ mapnotify(struct wl_listener *listener, void *data) } goto unset_fullscreen; } -#endif for (i = 0; i < 4; i++) { c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, bordercolor); From 737688a6b1da09c4276d3e26989305f287389505 Mon Sep 17 00:00:00 2001 From: godalming123 Date: Fri, 17 Feb 2023 19:33:44 +0000 Subject: [PATCH 017/347] fix spelling --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 27d051f..ac262b2 100644 --- a/dwl.c +++ b/dwl.c @@ -423,8 +423,8 @@ applybounds(Client *c, struct wlr_box *bbox) /* try to set size hints */ c->geom.width = MAX(min.width + (2 * (int)c->bw), c->geom.width); c->geom.height = MAX(min.height + (2 * (int)c->bw), c->geom.height); - /* Some clients set them max size to INT_MAX, which does not violates - * the protocol but its innecesary, they can set them max size to zero. */ + /* Some clients set their max size to INT_MAX, which does not violate the + * protocol but its unnecesary, as they can set their max size to zero. */ if (max.width > 0 && !(2 * c->bw > INT_MAX - max.width)) /* Checks for overflow */ c->geom.width = MIN(max.width + (2 * c->bw), c->geom.width); if (max.height > 0 && !(2 * c->bw > INT_MAX - max.height)) /* Checks for overflow */ From c69a2bec3ff417fbc4ea8fec0a49096773e01e7d Mon Sep 17 00:00:00 2001 From: godalming123 Date: Sat, 18 Feb 2023 16:15:07 +0000 Subject: [PATCH 018/347] Fix spacing and replace it with tabs --- dwl.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/dwl.c b/dwl.c index ac262b2..8043bf9 100644 --- a/dwl.c +++ b/dwl.c @@ -98,7 +98,7 @@ typedef struct Monitor Monitor; typedef struct { /* Must keep these three elements in this order */ unsigned int type; /* XDGShell or X11* */ - struct wlr_box geom; /* layout-relative, includes border */ + struct wlr_box geom; /* layout-relative, includes border */ Monitor *mon; struct wlr_scene_tree *scene; struct wlr_scene_rect *border[4]; /* top, bottom, left, right */ @@ -116,7 +116,7 @@ typedef struct { struct wl_listener destroy; struct wl_listener set_title; struct wl_listener fullscreen; - struct wlr_box prev; /* layout-relative, includes border */ + struct wlr_box prev; /* layout-relative, includes border */ #ifdef XWAYLAND struct wl_listener activate; struct wl_listener configure; @@ -181,8 +181,8 @@ struct Monitor { struct wl_listener destroy; struct wl_listener destroy_lock_surface; struct wlr_session_lock_surface_v1 *lock_surface; - struct wlr_box m; /* monitor area, layout-relative */ - struct wlr_box w; /* window area, layout-relative */ + struct wlr_box m; /* monitor area, layout-relative */ + struct wlr_box w; /* window area, layout-relative */ struct wl_list layers[4]; /* LayerSurface::link */ const Layout *lt[2]; unsigned int seltags; @@ -423,8 +423,8 @@ applybounds(Client *c, struct wlr_box *bbox) /* try to set size hints */ c->geom.width = MAX(min.width + (2 * (int)c->bw), c->geom.width); c->geom.height = MAX(min.height + (2 * (int)c->bw), c->geom.height); - /* Some clients set their max size to INT_MAX, which does not violate the - * protocol but its unnecesary, as they can set their max size to zero. */ + /* Some clients set their max size to INT_MAX, which does not violate the + * protocol but its unnecesary, as they can set their max size to zero. */ if (max.width > 0 && !(2 * c->bw > INT_MAX - max.width)) /* Checks for overflow */ c->geom.width = MIN(max.width + (2 * c->bw), c->geom.width); if (max.height > 0 && !(2 * c->bw > INT_MAX - max.height)) /* Checks for overflow */ @@ -1020,7 +1020,7 @@ void createpointer(struct wlr_pointer *pointer) { if (wlr_input_device_is_libinput(&pointer->base)) { - struct libinput_device *libinput_device = (struct libinput_device*) + struct libinput_device *libinput_device = (struct libinput_device*) wlr_libinput_get_device_handle(&pointer->base); if (libinput_device_config_tap_get_finger_count(libinput_device)) { @@ -1288,16 +1288,16 @@ focusstack(const Arg *arg) if (arg->i > 0) { wl_list_for_each(c, &sel->link, link) { if (&c->link == &clients) - continue; /* wrap past the sentinel node */ + continue; /* wrap past the sentinel node */ if (VISIBLEON(c, selmon)) - break; /* found it */ + break; /* found it */ } } else { wl_list_for_each_reverse(c, &sel->link, link) { if (&c->link == &clients) - continue; /* wrap past the sentinel node */ + continue; /* wrap past the sentinel node */ if (VISIBLEON(c, selmon)) - break; /* found it */ + break; /* found it */ } } /* If only one client is visible on selmon, then c == sel */ @@ -1729,7 +1729,7 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) { /* * Called when a client such as wlr-randr requests a change in output - * configuration. This is only one way that the layout can be changed, + * configuration. This is only one way that the layout can be changed, * so any Monitor information should be updated by updatemons() after an * output_layout.change event, not here. */ @@ -1969,7 +1969,7 @@ run(char *startup_cmd) selmon = xytomon(cursor->x, cursor->y); /* TODO hack to get cursor to display in its initial location (100, 100) - * instead of (0, 0) and then jumping. still may not be fully + * instead of (0, 0) and then jumping. still may not be fully * initialized, as the image/coordinates are not transformed for the * monitor when displayed here */ wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y); @@ -2487,7 +2487,7 @@ updatemons(struct wl_listener *listener, void *data) { /* * Called whenever the output layout changes: adding or removing a - * monitor, changing an output's mode or position, etc. This is where + * monitor, changing an output's mode or position, etc. This is where * the change officially happens and we update geometry, window * positions, focus, and the stored configuration in wlroots' * output-manager implementation. @@ -2755,8 +2755,8 @@ sigchld(int unused) { siginfo_t in; /* We should be able to remove this function in favor of a simple - * struct sigaction sa = {.sa_handler = SIG_IGN}; - * sigaction(SIGCHLD, &sa, NULL); + * struct sigaction sa = {.sa_handler = SIG_IGN}; + * sigaction(SIGCHLD, &sa, NULL); * but the Xwayland implementation in wlroots currently prevents us from * setting our own disposition for SIGCHLD. */ @@ -2779,7 +2779,7 @@ xwaylandready(struct wl_listener *listener, void *data) return; } - /* Collect atoms we are interested in. If getatom returns 0, we will + /* Collect atoms we are interested in. If getatom returns 0, we will * not detect that window type. */ netatom[NetWMWindowTypeDialog] = getatom(xc, "_NET_WM_WINDOW_TYPE_DIALOG"); netatom[NetWMWindowTypeSplash] = getatom(xc, "_NET_WM_WINDOW_TYPE_SPLASH"); From d1b36925c9e08aa26f72c4199c4046b0800c2266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 20 Feb 2023 21:24:18 -0600 Subject: [PATCH 019/347] add support for linux-dmabuf-unstable-v1 References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3726 References: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/main/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml --- dwl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dwl.c b/dwl.c index 0e02530..d028b95 100644 --- a/dwl.c +++ b/dwl.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -2302,6 +2303,9 @@ setup(void) wl_signal_add(&output_mgr->events.test, &output_mgr_test); wlr_scene_set_presentation(scene, wlr_presentation_create(dpy, backend)); + wlr_scene_set_linux_dmabuf_v1(scene, + wlr_linux_dmabuf_v1_create_with_renderer(dpy, 4, drw)); + #ifdef XWAYLAND /* From e4921fad28081f36fa0daa61b4bef7022a21b340 Mon Sep 17 00:00:00 2001 From: gan-of-culture <53971163+gan-of-culture@users.noreply.github.com> Date: Sat, 25 Feb 2023 22:59:23 +0100 Subject: [PATCH 020/347] add missing comma in "MonitorRule" add a missing comma for the example --- config.def.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.def.h b/config.def.h index 419e6ef..a1a6795 100644 --- a/config.def.h +++ b/config.def.h @@ -31,7 +31,7 @@ static const Layout layouts[] = { static const MonitorRule monrules[] = { /* name mfact nmaster scale layout rotate/reflect x y */ /* example of a HiDPI laptop monitor: - { "eDP-1", 0.5, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL -1, -1 }, + { "eDP-1", 0.5, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, */ /* defaults */ { NULL, 0.55, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, From eaf6dd2cd2f8c25a8cbce0e57221f73168a2bdc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 7 Mar 2023 22:04:32 -0600 Subject: [PATCH 021/347] do not call dmabuf_create twice it is called automatically by `wlr_renderer_init_wl_display()` but since we need a pointer to wlr_linux_dmabuf_v1 to integrate it with scene API we need to recreate that function. Bug: https://github.com/emersion/xdg-desktop-portal-wlr/issues/216 Fixes: https://github.com/djpohly/dwl/issues/398 --- dwl.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index d028b95..935babe 100644 --- a/dwl.c +++ b/dwl.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -2174,7 +2175,19 @@ setup(void) /* Create a renderer with the default implementation */ if (!(drw = wlr_renderer_autocreate(backend))) die("couldn't create renderer"); - wlr_renderer_init_wl_display(drw, dpy); + + /* Create shm, drm and linux_dmabuf interfaces by ourselves. + * The simplest way is call: + * wlr_renderer_init_wl_display(drw); + * but we need to create manually the linux_dmabuf interface to integrate it + * with wlr_scene. */ + wlr_renderer_init_wl_shm(drw, dpy); + + if (wlr_renderer_get_dmabuf_texture_formats(drw)) { + wlr_drm_create(dpy, drw); + wlr_scene_set_linux_dmabuf_v1(scene, + wlr_linux_dmabuf_v1_create_with_renderer(dpy, 4, drw)); + } /* Create a default allocator */ if (!(alloc = wlr_allocator_autocreate(backend, drw))) @@ -2303,9 +2316,6 @@ setup(void) wl_signal_add(&output_mgr->events.test, &output_mgr_test); wlr_scene_set_presentation(scene, wlr_presentation_create(dpy, backend)); - wlr_scene_set_linux_dmabuf_v1(scene, - wlr_linux_dmabuf_v1_create_with_renderer(dpy, 4, drw)); - #ifdef XWAYLAND /* From 6722a8953243387545a6bab23514b84cffd6a3bf Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Tue, 28 Feb 2023 21:32:35 -0600 Subject: [PATCH 022/347] Missing apostrophe --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 8043bf9..fbe4c24 100644 --- a/dwl.c +++ b/dwl.c @@ -424,7 +424,7 @@ applybounds(Client *c, struct wlr_box *bbox) c->geom.width = MAX(min.width + (2 * (int)c->bw), c->geom.width); c->geom.height = MAX(min.height + (2 * (int)c->bw), c->geom.height); /* Some clients set their max size to INT_MAX, which does not violate the - * protocol but its unnecesary, as they can set their max size to zero. */ + * protocol but it's unnecesary, as they can set their max size to zero. */ if (max.width > 0 && !(2 * c->bw > INT_MAX - max.width)) /* Checks for overflow */ c->geom.width = MIN(max.width + (2 * c->bw), c->geom.width); if (max.height > 0 && !(2 * c->bw > INT_MAX - max.height)) /* Checks for overflow */ From 21930621eec5bc4acc3ae5c42cffd6a9422dc615 Mon Sep 17 00:00:00 2001 From: Palanix Date: Mon, 13 Mar 2023 12:00:46 +0100 Subject: [PATCH 023/347] Remove rootcolor --- config.def.h | 1 - 1 file changed, 1 deletion(-) diff --git a/config.def.h b/config.def.h index a1a6795..f98eab2 100644 --- a/config.def.h +++ b/config.def.h @@ -2,7 +2,6 @@ static const int sloppyfocus = 1; /* focus follows mouse */ static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */ static const unsigned int borderpx = 1; /* border pixel of windows */ -static const float rootcolor[] = {0.3, 0.3, 0.3, 1.0}; static const float bordercolor[] = {0.5, 0.5, 0.5, 1.0}; static const float focuscolor[] = {1.0, 0.0, 0.0, 1.0}; /* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */ From bbdf2a913b72e7a308ee0dfde6518a4285d4a775 Mon Sep 17 00:00:00 2001 From: Yves Zoundi Date: Tue, 21 Feb 2023 13:00:10 -0500 Subject: [PATCH 024/347] display clients count in monocle symbol - Replicate missing functionality from dwl to display the client count in monocle mode - Add ltsymbol field to Monitor struct - Display client count in monocle mode when greater than zero - Tested with somebar and dwlb --- dwl.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index fbe4c24..1b59c21 100644 --- a/dwl.c +++ b/dwl.c @@ -190,6 +190,7 @@ struct Monitor { unsigned int tagset[2]; double mfact; int nmaster; + char ltsymbol[16]; }; typedef struct { @@ -482,6 +483,8 @@ arrange(Monitor *m) wlr_scene_node_set_enabled(&m->fullscreen_bg->node, (c = focustop(m)) && c->isfullscreen); + if (m) + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); if (m && m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); motionnotify(0); @@ -970,6 +973,7 @@ createmon(struct wl_listener *listener, void *data) wlr_output_layout_add_auto(output_layout, wlr_output); else wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y); + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); } void @@ -1592,12 +1596,16 @@ void monocle(Monitor *m) { Client *c; + int n = 0; wl_list_for_each(c, &clients, link) { if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) continue; resize(c, m->w, 0); + n++; } + if (n) + snprintf(m->ltsymbol, LENGTH(m->ltsymbol), "[%d]", n); if ((c = focustop(m))) wlr_scene_node_raise_to_top(&c->scene->node); } @@ -1851,7 +1859,7 @@ printstatus(void) printf("%s selmon %u\n", m->wlr_output->name, m == selmon); printf("%s tags %u %u %u %u\n", m->wlr_output->name, occ, m->tagset[m->seltags], sel, urg); - printf("%s layout %s\n", m->wlr_output->name, m->lt[m->sellt]->symbol); + printf("%s layout %s\n", m->wlr_output->name, m->ltsymbol); } fflush(stdout); } @@ -2044,7 +2052,7 @@ setlayout(const Arg *arg) selmon->sellt ^= 1; if (arg && arg->v) selmon->lt[selmon->sellt] = (Layout *)arg->v; - /* TODO change layout symbol? */ + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, LENGTH(selmon->ltsymbol)); arrange(selmon); printstatus(); } From 9d68554c59a886b641d27a364884fb461af2d4f1 Mon Sep 17 00:00:00 2001 From: Ben Collerson Date: Thu, 23 Mar 2023 09:38:48 +1000 Subject: [PATCH 025/347] remove tag labels from dwl Tag labels are not used in dwl. Only the number of tags is important. Tag labels should be defined for each tag in whatever status bar is used. --- config.def.h | 4 ++-- dwl.c | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/config.def.h b/config.def.h index f98eab2..c6a4950 100644 --- a/config.def.h +++ b/config.def.h @@ -7,8 +7,8 @@ static const float focuscolor[] = {1.0, 0.0, 0.0, 1.0}; /* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */ static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; -/* tagging */ -static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; +/* tagging - tagcount must be no greater than 31 */ +static const int tagcount = 9; static const Rule rules[] = { /* app_id title tags mask isfloating monitor */ diff --git a/dwl.c b/dwl.c index 1b59c21..fbdf096 100644 --- a/dwl.c +++ b/dwl.c @@ -67,7 +67,7 @@ #define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) #define LENGTH(X) (sizeof X / sizeof X[0]) #define END(A) ((A) + LENGTH(A)) -#define TAGMASK ((1 << LENGTH(tags)) - 1) +#define TAGMASK ((1u << tagcount) - 1) #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) #define IDLE_NOTIFY_ACTIVITY wlr_idle_notify_activity(idle, seat), wlr_idle_notifier_v1_notify_activity(idle_notifier, seat) @@ -411,9 +411,6 @@ static Atom netatom[NetLast]; /* attempt to encapsulate suck into one file */ #include "client.h" -/* compile-time check if all tags fit into an unsigned int bit array. */ -struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; - /* function implementations */ void applybounds(Client *c, struct wlr_box *bbox) From 20f61a59afeb4634dbdccfcbead95ec5852ef456 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 8 Apr 2023 11:29:18 -0600 Subject: [PATCH 026/347] use fixed-size type for client tags while the size of `int` in most compilers is 32-bits, the size of int and all other integer types are implementation defined, so make sure we can use up to 32-bits --- dwl.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/dwl.c b/dwl.c index fbdf096..6c34e32 100644 --- a/dwl.c +++ b/dwl.c @@ -123,7 +123,7 @@ typedef struct { struct wl_listener set_hints; #endif unsigned int bw; - unsigned int tags; + uint32_t tags; int isfloating, isurgent, isfullscreen; uint32_t resize; /* configure serial of a pending resize */ } Client; @@ -187,7 +187,7 @@ struct Monitor { const Layout *lt[2]; unsigned int seltags; unsigned int sellt; - unsigned int tagset[2]; + uint32_t tagset[2]; double mfact; int nmaster; char ltsymbol[16]; @@ -206,7 +206,7 @@ typedef struct { typedef struct { const char *id; const char *title; - unsigned int tags; + uint32_t tags; int isfloating; int monitor; } Rule; @@ -293,7 +293,7 @@ static void setfloating(Client *c, int floating); static void setfullscreen(Client *c, int fullscreen); static void setlayout(const Arg *arg); static void setmfact(const Arg *arg); -static void setmon(Client *c, Monitor *m, unsigned int newtags); +static void setmon(Client *c, Monitor *m, uint32_t newtags); static void setpsel(struct wl_listener *listener, void *data); static void setsel(struct wl_listener *listener, void *data); static void setup(void); @@ -444,7 +444,7 @@ applyrules(Client *c) { /* rule matching */ const char *appid, *title; - unsigned int i, newtags = 0; + uint32_t i, newtags = 0; const Rule *r; Monitor *mon = selmon, *m; @@ -1825,7 +1825,7 @@ printstatus(void) { Monitor *m = NULL; Client *c; - unsigned int occ, urg, sel; + uint32_t occ, urg, sel; const char *appid, *title; wl_list_for_each(m, &mons, link) { @@ -2070,7 +2070,7 @@ setmfact(const Arg *arg) } void -setmon(Client *c, Monitor *m, unsigned int newtags) +setmon(Client *c, Monitor *m, uint32_t newtags) { Monitor *oldmon = c->mon; @@ -2409,7 +2409,7 @@ togglefullscreen(const Arg *arg) void toggletag(const Arg *arg) { - unsigned int newtags; + uint32_t newtags; Client *sel = focustop(selmon); if (!sel) return; @@ -2425,7 +2425,7 @@ toggletag(const Arg *arg) void toggleview(const Arg *arg) { - unsigned int newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0; + uint32_t newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0; if (newtagset) { selmon->tagset[selmon->seltags] = newtagset; From da77e34ee55ef4d2f92f632fea880610e8fc7fda Mon Sep 17 00:00:00 2001 From: Ben Collerson Date: Sun, 9 Apr 2023 14:48:55 +1000 Subject: [PATCH 027/347] Use uint32_t for ui Arg --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 6c34e32..e59eae4 100644 --- a/dwl.c +++ b/dwl.c @@ -82,7 +82,7 @@ enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, typedef union { int i; - unsigned int ui; + uint32_t ui; float f; const void *v; } Arg; From 3c760bcd4ae640ec27229da8c75e9539bfd0d5cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 12 Apr 2023 19:31:55 -0600 Subject: [PATCH 028/347] remove unneeded check of `m` in arrange() arrange must never be called with a NULL argument --- dwl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index e59eae4..3442dcb 100644 --- a/dwl.c +++ b/dwl.c @@ -480,9 +480,9 @@ arrange(Monitor *m) wlr_scene_node_set_enabled(&m->fullscreen_bg->node, (c = focustop(m)) && c->isfullscreen); - if (m) - strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); - if (m && m->lt[m->sellt]->arrange) + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); + + if (m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); motionnotify(0); checkidleinhibitor(NULL); From 797e0c74b2cbf4a49f83c9269abec06f3293d00c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 12 Apr 2023 21:37:19 -0600 Subject: [PATCH 029/347] correctly check if a scene node is enabled checking only wlr_scene_node.enabled may result in a false positive because it does not consider if its ancestors are enabled as well. --- dwl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 3442dcb..b7436bb 100644 --- a/dwl.c +++ b/dwl.c @@ -631,13 +631,13 @@ chvt(const Arg *arg) void checkidleinhibitor(struct wlr_surface *exclude) { - int inhibited = 0; + int inhibited = 0, unused_lx, unused_ly; struct wlr_idle_inhibitor_v1 *inhibitor; wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { struct wlr_surface *surface = wlr_surface_get_root_surface(inhibitor->surface); struct wlr_scene_tree *tree = surface->data; if (exclude != surface && (bypass_surface_visibility || (!tree - || tree->node.enabled))) { + || wlr_scene_node_coords(&tree->node, &unused_lx, &unused_ly)))) { inhibited = 1; break; } @@ -1201,7 +1201,7 @@ void focusclient(Client *c, int lift) { struct wlr_surface *old = seat->keyboard_state.focused_surface; - int i; + int i, unused_lx, unused_ly; if (locked) return; @@ -1236,7 +1236,7 @@ focusclient(Client *c, int lift) Client *w = NULL; LayerSurface *l = NULL; int type = toplevel_from_wlr_surface(old, &w, &l); - if (type == LayerShell && l->scene->node.enabled + if (type == LayerShell && wlr_scene_node_coords(&l->scene->node, &unused_lx, &unused_ly) && l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) { return; } else if (w && w == exclusive_focus && client_wants_focus(w)) { From 2d1a40caf27d15f809b301fb2e597a0937e6d298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 14 Apr 2023 12:14:11 -0600 Subject: [PATCH 030/347] pass version to wlr_compositor_create() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3696 Signed-off-by: Leonardo Hernández Hernández --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index f94059a..e481930 100644 --- a/dwl.c +++ b/dwl.c @@ -2204,7 +2204,7 @@ setup(void) * to dig your fingers in and play with their behavior if you want. Note that * the clients cannot set the selection directly without compositor approval, * see the setsel() function. */ - compositor = wlr_compositor_create(dpy, drw); + compositor = wlr_compositor_create(dpy, 5, drw); wlr_export_dmabuf_manager_v1_create(dpy); wlr_screencopy_manager_v1_create(dpy); wlr_data_control_manager_v1_create(dpy); From 0729f18dce85cb79b8aaac325a43dba0c5e96ab3 Mon Sep 17 00:00:00 2001 From: Micah Gorrell Date: Wed, 24 May 2023 10:20:30 -0600 Subject: [PATCH 031/347] Prevent using a wlr_layer_surface after destroying it, due to no available outputs --- dwl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index b7436bb..1ad3d05 100644 --- a/dwl.c +++ b/dwl.c @@ -836,8 +836,10 @@ createlayersurface(struct wl_listener *listener, void *data) if (!wlr_layer_surface->output) wlr_layer_surface->output = selmon ? selmon->wlr_output : NULL; - if (!wlr_layer_surface->output) + if (!wlr_layer_surface->output) { wlr_layer_surface_v1_destroy(wlr_layer_surface); + return; + } layersurface = ecalloc(1, sizeof(LayerSurface)); layersurface->type = LayerShell; From 72adab621f27f9daed87ea1b0068679e39fb3f8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 8 Apr 2023 14:44:34 -0600 Subject: [PATCH 032/347] destroy old client popups when focusing another client Closes: https://github.com/djpohly/dwl/issues/408 --- dwl.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/dwl.c b/dwl.c index 1ad3d05..aec7427 100644 --- a/dwl.c +++ b/dwl.c @@ -1203,7 +1203,9 @@ void focusclient(Client *c, int lift) { struct wlr_surface *old = seat->keyboard_state.focused_surface; - int i, unused_lx, unused_ly; + int i, unused_lx, unused_ly, old_client_type; + Client *old_c = NULL; + LayerSurface *old_l = NULL; if (locked) return; @@ -1215,6 +1217,12 @@ focusclient(Client *c, int lift) if (c && client_surface(c) == old) return; + if ((old_client_type = toplevel_from_wlr_surface(old, &old_c, &old_l)) == XDGShell) { + struct wlr_xdg_popup *popup, *tmp; + wl_list_for_each_safe(popup, tmp, &old_c->surface.xdg->popups, link) + wlr_xdg_popup_destroy(popup); + } + /* Put the new client atop the focus stack and select its monitor */ if (c && !client_is_unmanaged(c)) { wl_list_remove(&c->flink); @@ -1235,19 +1243,17 @@ focusclient(Client *c, int lift) /* If an overlay is focused, don't focus or activate the client, * but only update its position in fstack to render its border with focuscolor * and focus it after the overlay is closed. */ - Client *w = NULL; - LayerSurface *l = NULL; - int type = toplevel_from_wlr_surface(old, &w, &l); - if (type == LayerShell && wlr_scene_node_coords(&l->scene->node, &unused_lx, &unused_ly) - && l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) { + if (old_client_type == LayerShell && wlr_scene_node_coords( + &old_l->scene->node, &unused_lx, &unused_ly) + && old_l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) { return; - } else if (w && w == exclusive_focus && client_wants_focus(w)) { + } else if (old_c && old_c == exclusive_focus && client_wants_focus(old_c)) { return; /* Don't deactivate old client if the new one wants focus, as this causes issues with winecfg * and probably other clients */ - } else if (w && !client_is_unmanaged(w) && (!c || !client_wants_focus(c))) { + } else if (old_c && !client_is_unmanaged(old_c) && (!c || !client_wants_focus(c))) { for (i = 0; i < 4; i++) - wlr_scene_rect_set_color(w->border[i], bordercolor); + wlr_scene_rect_set_color(old_c->border[i], bordercolor); client_activate_surface(old, 0); } From a5e45924edeaeb9b763cdc75fd4ec413b2ec2ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 28 May 2023 00:20:20 -0600 Subject: [PATCH 033/347] remove note about contact me for patch issues I am no longer able to spend much time developing dwl let alone maintaining other's patches :) --- .github/ISSUE_TEMPLATE/bug_report.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 6b60803..cd9bd8d 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -14,9 +14,4 @@ wlroots version: From f8884ffc2b7a4c0401f0a6710b679cd18b6b097d Mon Sep 17 00:00:00 2001 From: Nikita Ivanov Date: Sun, 28 May 2023 19:09:38 +0200 Subject: [PATCH 034/347] Set XCURSOR_SIZE --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index aec7427..cd27c7c 100644 --- a/dwl.c +++ b/dwl.c @@ -2260,6 +2260,7 @@ setup(void) * images are available at all scale factors on the screen (necessary for * HiDPI support). Scaled cursors will be loaded with each output. */ cursor_mgr = wlr_xcursor_manager_create(NULL, 24); + setenv("XCURSOR_SIZE", "24", 1); /* * wlr_cursor *only* displays an image on screen. It does not move around From 3d98907b98e2ff978cc30614b739f1f4b8f7f8c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 25 May 2023 22:19:29 -0600 Subject: [PATCH 035/347] send frame done even if output commit fails Bug: https://github.com/djpohly/dwl/issues/420 Fixes: https://github.com/djpohly/dwl/issues/353 --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index cd27c7c..02c761c 100644 --- a/dwl.c +++ b/dwl.c @@ -1895,8 +1895,8 @@ rendermon(struct wl_listener *listener, void *data) wl_list_for_each(c, &clients, link) if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && !client_is_stopped(c)) goto skip; - if (!wlr_scene_output_commit(m->scene_output)) - return; + wlr_scene_output_commit(m->scene_output); + skip: /* Let clients know a frame has been rendered */ clock_gettime(CLOCK_MONOTONIC, &now); From 9b9b79b35ebaed7a5897f748c51b2d5c4ec1ddfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 25 May 2023 22:20:12 -0600 Subject: [PATCH 036/347] activate lock surface in updatemons Fixes an issue when swaylock does not receive input after turn off and then turn on the outputs --- dwl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 02c761c..918852e 100644 --- a/dwl.c +++ b/dwl.c @@ -2572,9 +2572,12 @@ updatemons(struct wl_listener *listener, void *data) wl_list_for_each(c, &clients, link) if (!c->mon && client_is_mapped(c)) setmon(c, selmon, c->tags); - if (selmon->lock_surface) + focusclient(focustop(selmon), 1); + if (selmon->lock_surface) { client_notify_enter(selmon->lock_surface->surface, wlr_seat_get_keyboard(seat)); + client_activate_surface(selmon->lock_surface->surface, 1); + } } wlr_output_manager_v1_set_configuration(output_mgr, config); From 06bc65549f42bcfa2f0b119149eacb7e5adc9073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 2 Jun 2023 21:34:22 -0600 Subject: [PATCH 037/347] chase wlroots map logic unification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Leonardo Hernández Hernández --- client.h | 10 ---------- dwl.c | 55 ++++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 40 insertions(+), 25 deletions(-) diff --git a/client.h b/client.h index 5fe31b1..ef56ee6 100644 --- a/client.h +++ b/client.h @@ -225,16 +225,6 @@ client_is_float_type(Client *c) && (min.width == max.width || min.height == max.height)); } -static inline int -client_is_mapped(Client *c) -{ -#ifdef XWAYLAND - if (client_is_x11(c)) - return c->surface.xwayland->mapped; -#endif - return c->surface.xdg->mapped; -} - static inline int client_is_rendered_on_mon(Client *c, Monitor *m) { diff --git a/dwl.c b/dwl.c index fd93ec5..c28ce42 100644 --- a/dwl.c +++ b/dwl.c @@ -122,6 +122,8 @@ typedef struct { struct wlr_box prev; /* layout-relative, includes border */ #ifdef XWAYLAND struct wl_listener activate; + struct wl_listener associate; + struct wl_listener dissociate; struct wl_listener configure; struct wl_listener set_hints; #endif @@ -399,8 +401,10 @@ static struct wl_listener session_lock_mgr_destroy = {.notify = destroysessionmg #ifdef XWAYLAND static void activatex11(struct wl_listener *listener, void *data); +static void associatex11(struct wl_listener *listener, void *data); static void configurex11(struct wl_listener *listener, void *data); static void createnotifyx11(struct wl_listener *listener, void *data); +static void dissociatex11(struct wl_listener *listener, void *data); static Atom getatom(xcb_connection_t *xc, const char *name); static void sethints(struct wl_listener *listener, void *data); static void sigchld(int unused); @@ -762,9 +766,9 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) wlr_scene_node_reparent(&layersurface->popups->node, layers[LyrTop]); if (wlr_layer_surface->current.committed == 0 - && layersurface->mapped == wlr_layer_surface->mapped) + && layersurface->mapped == wlr_layer_surface->surface->mapped) return; - layersurface->mapped = wlr_layer_surface->mapped; + layersurface->mapped = wlr_layer_surface->surface->mapped; arrangelayers(layersurface->mon); } @@ -854,9 +858,9 @@ createlayersurface(struct wl_listener *listener, void *data) &layersurface->surface_commit, commitlayersurfacenotify); LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy, destroylayersurfacenotify); - LISTEN(&wlr_layer_surface->events.map, &layersurface->map, + LISTEN(&wlr_layer_surface->surface->events.map, &layersurface->map, maplayersurfacenotify); - LISTEN(&wlr_layer_surface->events.unmap, &layersurface->unmap, + LISTEN(&wlr_layer_surface->surface->events.unmap, &layersurface->unmap, unmaplayersurfacenotify); layersurface->layer_surface = wlr_layer_surface; @@ -1017,8 +1021,8 @@ createnotify(struct wl_listener *listener, void *data) c->surface.xdg = xdg_surface; c->bw = borderpx; - LISTEN(&xdg_surface->events.map, &c->map, mapnotify); - LISTEN(&xdg_surface->events.unmap, &c->unmap, unmapnotify); + LISTEN(&xdg_surface->surface->events.map, &c->map, mapnotify); + LISTEN(&xdg_surface->surface->events.unmap, &c->unmap, unmapnotify); LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify); LISTEN(&xdg_surface->toplevel->events.set_title, &c->set_title, updatetitle); LISTEN(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen, @@ -1055,7 +1059,7 @@ createpointer(struct wlr_pointer *pointer) if (libinput_device_config_scroll_get_methods(libinput_device) != LIBINPUT_CONFIG_SCROLL_NO_SCROLL) libinput_device_config_scroll_set_method (libinput_device, scroll_method); - + if (libinput_device_config_click_get_methods(libinput_device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE) libinput_device_config_click_set_method (libinput_device, click_method); @@ -1160,18 +1164,22 @@ destroynotify(struct wl_listener *listener, void *data) { /* Called when the surface is destroyed and should never be shown again. */ Client *c = wl_container_of(listener, c, destroy); - wl_list_remove(&c->map.link); - wl_list_remove(&c->unmap.link); wl_list_remove(&c->destroy.link); wl_list_remove(&c->set_title.link); wl_list_remove(&c->fullscreen.link); #ifdef XWAYLAND if (c->type != XDGShell) { - wl_list_remove(&c->configure.link); - wl_list_remove(&c->set_hints.link); wl_list_remove(&c->activate.link); - } + wl_list_remove(&c->associate.link); + wl_list_remove(&c->configure.link); + wl_list_remove(&c->dissociate.link); + wl_list_remove(&c->set_hints.link); + } else #endif + { + wl_list_remove(&c->map.link); + wl_list_remove(&c->unmap.link); + } free(c); } @@ -2597,7 +2605,7 @@ updatemons(struct wl_listener *listener, void *data) if (selmon && selmon->wlr_output->enabled) { wl_list_for_each(c, &clients, link) - if (!c->mon && client_is_mapped(c)) + if (!c->mon && client_surface(c)->mapped) setmon(c, selmon, c->tags); focusclient(focustop(selmon), 1); if (selmon->lock_surface) { @@ -2734,6 +2742,15 @@ activatex11(struct wl_listener *listener, void *data) wlr_xwayland_surface_activate(c->surface.xwayland, 1); } +void +associatex11(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, associate); + + LISTEN(&client_surface(c)->events.map, &c->map, mapnotify); + LISTEN(&client_surface(c)->events.unmap, &c->unmap, unmapnotify); +} + void configurex11(struct wl_listener *listener, void *data) { @@ -2761,8 +2778,8 @@ createnotifyx11(struct wl_listener *listener, void *data) c->bw = borderpx; /* Listen to the various events it can emit */ - LISTEN(&xsurface->events.map, &c->map, mapnotify); - LISTEN(&xsurface->events.unmap, &c->unmap, unmapnotify); + LISTEN(&xsurface->events.associate, &c->associate, associatex11); + LISTEN(&xsurface->events.dissociate, &c->dissociate, dissociatex11); LISTEN(&xsurface->events.request_activate, &c->activate, activatex11); LISTEN(&xsurface->events.request_configure, &c->configure, configurex11); LISTEN(&xsurface->events.set_hints, &c->set_hints, sethints); @@ -2771,6 +2788,14 @@ createnotifyx11(struct wl_listener *listener, void *data) LISTEN(&xsurface->events.request_fullscreen, &c->fullscreen, fullscreennotify); } +void +dissociatex11(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, dissociate); + wl_list_remove(&c->map.link); + wl_list_remove(&c->unmap.link); +} + Atom getatom(xcb_connection_t *xc, const char *name) { From f3d017077a1328e7d327304772cf186f2e7ae0de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 2 Jun 2023 22:08:17 -0600 Subject: [PATCH 038/347] use the new {a,di}ssociate events to handle xwayland commit listener --- dwl.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/dwl.c b/dwl.c index c28ce42..5edb12c 100644 --- a/dwl.c +++ b/dwl.c @@ -1021,6 +1021,7 @@ createnotify(struct wl_listener *listener, void *data) c->surface.xdg = xdg_surface; c->bw = borderpx; + LISTEN(&xdg_surface->surface->events.commit, &c->commit, commitnotify); LISTEN(&xdg_surface->surface->events.map, &c->map, mapnotify); LISTEN(&xdg_surface->surface->events.unmap, &c->unmap, unmapnotify); LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify); @@ -1177,6 +1178,7 @@ destroynotify(struct wl_listener *listener, void *data) } else #endif { + wl_list_remove(&c->commit.link); wl_list_remove(&c->map.link); wl_list_remove(&c->unmap.link); } @@ -1541,12 +1543,7 @@ mapnotify(struct wl_listener *listener, void *data) c->scene_surface = c->type == XDGShell ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg) : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); - if (client_surface(c)) { - client_surface(c)->data = c->scene; - /* Ideally we should do this in createnotify{,x11} but at that moment - * wlr_xwayland_surface doesn't have wlr_surface yet. */ - LISTEN(&client_surface(c)->events.commit, &c->commit, commitnotify); - } + client_surface(c)->data = c->scene; c->scene->node.data = c->scene_surface->node.data = c; /* Handle unmanaged clients first so we can return prior create borders */ @@ -2525,7 +2522,6 @@ unmapnotify(struct wl_listener *listener, void *data) wl_list_remove(&c->flink); } - wl_list_remove(&c->commit.link); wlr_scene_node_destroy(&c->scene->node); printstatus(); motionnotify(0); @@ -2747,6 +2743,7 @@ associatex11(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, associate); + LISTEN(&client_surface(c)->events.commit, &c->commit, commitnotify); LISTEN(&client_surface(c)->events.map, &c->map, mapnotify); LISTEN(&client_surface(c)->events.unmap, &c->unmap, unmapnotify); } @@ -2792,6 +2789,7 @@ void dissociatex11(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, dissociate); + wl_list_remove(&c->commit.link); wl_list_remove(&c->map.link); wl_list_remove(&c->unmap.link); } From 5215712cabce273f76a5381de244c58a7d1f54f9 Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Wed, 7 Jun 2023 16:24:28 -0500 Subject: [PATCH 039/347] Stray whitespace fixes --- config.def.h | 6 +++--- dwl.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config.def.h b/config.def.h index c6a4950..447ba00 100644 --- a/config.def.h +++ b/config.def.h @@ -65,9 +65,9 @@ LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN static const enum libinput_config_scroll_method scroll_method = LIBINPUT_CONFIG_SCROLL_2FG; /* You can choose between: -LIBINPUT_CONFIG_CLICK_METHOD_NONE -LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS -LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER +LIBINPUT_CONFIG_CLICK_METHOD_NONE +LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS +LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER */ static const enum libinput_config_click_method click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; diff --git a/dwl.c b/dwl.c index 918852e..d741cbd 100644 --- a/dwl.c +++ b/dwl.c @@ -1047,7 +1047,7 @@ createpointer(struct wlr_pointer *pointer) if (libinput_device_config_scroll_get_methods(libinput_device) != LIBINPUT_CONFIG_SCROLL_NO_SCROLL) libinput_device_config_scroll_set_method (libinput_device, scroll_method); - + if (libinput_device_config_click_get_methods(libinput_device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE) libinput_device_config_click_set_method (libinput_device, click_method); From 24a337e6ec4711d28789abc90cb42ce3e7277309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 8 Jun 2023 23:35:46 -0600 Subject: [PATCH 040/347] handle gamma-control-v1 set_gamma event References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4046 --- dwl.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 5edb12c..1c6de4e 100644 --- a/dwl.c +++ b/dwl.c @@ -298,6 +298,7 @@ static void run(char *startup_cmd); static void setcursor(struct wl_listener *listener, void *data); static void setfloating(Client *c, int floating); static void setfullscreen(Client *c, int fullscreen); +static void setgamma(struct wl_listener *listener, void *data); static void setlayout(const Arg *arg); static void setmfact(const Arg *arg); static void setmon(Client *c, Monitor *m, uint32_t newtags); @@ -352,6 +353,7 @@ static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr; static struct wlr_input_inhibit_manager *input_inhibit_mgr; static struct wlr_layer_shell_v1 *layer_shell; static struct wlr_output_manager_v1 *output_mgr; +static struct wlr_gamma_control_manager_v1 *gamma_control_mgr; static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; static struct wlr_cursor *cursor; @@ -392,6 +394,7 @@ static struct wl_listener output_mgr_apply = {.notify = outputmgrapply}; static struct wl_listener output_mgr_test = {.notify = outputmgrtest}; static struct wl_listener request_activate = {.notify = urgent}; static struct wl_listener request_cursor = {.notify = setcursor}; +static struct wl_listener request_gamma = {.notify = setgamma}; static struct wl_listener request_set_psel = {.notify = setpsel}; static struct wl_listener request_set_sel = {.notify = setsel}; static struct wl_listener request_start_drag = {.notify = requeststartdrag}; @@ -2067,6 +2070,21 @@ setfullscreen(Client *c, int fullscreen) printstatus(); } +void +setgamma(struct wl_listener *listener, void *data) +{ + struct wlr_gamma_control_manager_v1_set_gamma_event *event = data; + if (!wlr_gamma_control_v1_apply(event->control, &event->output->pending)) + return; + + if (!wlr_output_test(event->output)) { + wlr_output_rollback(event->output); + wlr_gamma_control_v1_send_failed_and_destroy(event->control); + } + + wlr_output_schedule_frame(event->output); +} + void setlayout(const Arg *arg) { @@ -2222,7 +2240,6 @@ setup(void) wlr_screencopy_manager_v1_create(dpy); wlr_data_control_manager_v1_create(dpy); wlr_data_device_manager_create(dpy); - wlr_gamma_control_manager_v1_create(dpy); wlr_primary_selection_v1_device_manager_create(dpy); wlr_viewporter_create(dpy); wlr_single_pixel_buffer_manager_v1_create(dpy); @@ -2233,6 +2250,9 @@ setup(void) activation = wlr_xdg_activation_v1_create(dpy); wl_signal_add(&activation->events.request_activate, &request_activate); + gamma_control_mgr = wlr_gamma_control_manager_v1_create(dpy); + wl_signal_add(&gamma_control_mgr->events.set_gamma, &request_gamma); + /* Creates an output layout, which a wlroots utility for working with an * arrangement of screens in a physical layout. */ output_layout = wlr_output_layout_create(); From 1eb8a82ac4d3a0fa76affff591c6a6667cb12cae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 7 May 2023 14:59:48 -0600 Subject: [PATCH 041/347] Revert "avoid setting duplicate cursor image" This reverts commit b5776e5180010ead5232efb36b2490f4fc9e1366. See next commit for details --- dwl.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/dwl.c b/dwl.c index 1c6de4e..c73ce2a 100644 --- a/dwl.c +++ b/dwl.c @@ -329,7 +329,6 @@ static void zoom(const Arg *arg); /* variables */ static const char broken[] = "broken"; -static const char *cursor_image = "left_ptr"; static pid_t child_pid = -1; static int locked; static void *exclusive_focus; @@ -613,13 +612,10 @@ buttonpress(struct wl_listener *listener, void *data) break; case WLR_BUTTON_RELEASED: /* If you released any buttons, we exit interactive move/resize mode. */ + /* TODO should reset to the pointer focus's current setcursor */ if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { + wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor); cursor_mode = CurNormal; - /* Clear the pointer focus, this way if the cursor is over a surface - * we will send an enter event after which the client will provide us - * a cursor surface */ - wlr_seat_pointer_clear_focus(seat); - motionnotify(0); /* Drop the window off on its new monitor */ selmon = xytomon(cursor->x, cursor->y); setmon(grabc, selmon, 0); @@ -1694,8 +1690,8 @@ motionnotify(uint32_t time) /* If there's no client surface under the cursor, set the cursor image to a * default. This is what makes the cursor image appear when you move it * off of a client or over its border. */ - if (!surface && !seat->drag && (!cursor_image || strcmp(cursor_image, "left_ptr"))) - wlr_xcursor_manager_set_cursor_image(cursor_mgr, (cursor_image = "left_ptr"), cursor); + if (!surface && !seat->drag) + wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor); pointerfocus(c, surface, sx, sy, time); } @@ -1730,7 +1726,7 @@ moveresize(const Arg *arg) case CurMove: grabcx = cursor->x - grabc->geom.x; grabcy = cursor->y - grabc->geom.y; - wlr_xcursor_manager_set_cursor_image(cursor_mgr, (cursor_image = "fleur"), cursor); + wlr_xcursor_manager_set_cursor_image(cursor_mgr, "fleur", cursor); break; case CurResize: /* Doesn't work for X11 output - the next absolute motion event @@ -1739,7 +1735,7 @@ moveresize(const Arg *arg) grabc->geom.x + grabc->geom.width, grabc->geom.y + grabc->geom.height); wlr_xcursor_manager_set_cursor_image(cursor_mgr, - (cursor_image = "bottom_right_corner"), cursor); + "bottom_right_corner", cursor); break; } } @@ -1840,6 +1836,7 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, * wlroots makes this a no-op if surface is already focused */ wlr_seat_pointer_notify_enter(seat, surface, sx, sy); wlr_seat_pointer_notify_motion(seat, time, sx, sy); + } void @@ -2008,7 +2005,7 @@ run(char *startup_cmd) * initialized, as the image/coordinates are not transformed for the * monitor when displayed here */ wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y); - wlr_xcursor_manager_set_cursor_image(cursor_mgr, cursor_image, cursor); + wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor); /* Run the Wayland event loop. This does not return until you exit the * compositor. Starting the backend rigged up all of the necessary event @@ -2027,7 +2024,6 @@ setcursor(struct wl_listener *listener, void *data) * event, which will result in the client requesting set the cursor surface */ if (cursor_mode != CurNormal && cursor_mode != CurPressed) return; - cursor_image = NULL; /* This can be sent by any client, so we check to make sure this one is * actually has pointer focus first. If so, we can tell the cursor to * use the provided surface as the cursor image. It will set the From 96ab92cdb16dfbae724e96eea6fb72d1bec20021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 15 Jun 2023 12:12:22 -0600 Subject: [PATCH 042/347] use wlr_cursor_set_xcursor() This avoids re-upload the cursor image in each motion event Managing the scale is done by the function itself References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4170 --- dwl.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/dwl.c b/dwl.c index c73ce2a..1538ed7 100644 --- a/dwl.c +++ b/dwl.c @@ -614,7 +614,7 @@ buttonpress(struct wl_listener *listener, void *data) /* If you released any buttons, we exit interactive move/resize mode. */ /* TODO should reset to the pointer focus's current setcursor */ if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { - wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "left_ptr"); cursor_mode = CurNormal; /* Drop the window off on its new monitor */ selmon = xytomon(cursor->x, cursor->y); @@ -928,7 +928,6 @@ createmon(struct wl_listener *listener, void *data) m->mfact = r->mfact; m->nmaster = r->nmaster; wlr_output_set_scale(wlr_output, r->scale); - wlr_xcursor_manager_load(cursor_mgr, r->scale); m->lt[0] = m->lt[1] = r->lt; wlr_output_set_transform(wlr_output, r->rr); m->m.x = r->x; @@ -1691,7 +1690,7 @@ motionnotify(uint32_t time) * default. This is what makes the cursor image appear when you move it * off of a client or over its border. */ if (!surface && !seat->drag) - wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "left_ptr"); pointerfocus(c, surface, sx, sy, time); } @@ -1726,7 +1725,7 @@ moveresize(const Arg *arg) case CurMove: grabcx = cursor->x - grabc->geom.x; grabcy = cursor->y - grabc->geom.y; - wlr_xcursor_manager_set_cursor_image(cursor_mgr, "fleur", cursor); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur"); break; case CurResize: /* Doesn't work for X11 output - the next absolute motion event @@ -1734,8 +1733,7 @@ moveresize(const Arg *arg) wlr_cursor_warp_closest(cursor, NULL, grabc->geom.x + grabc->geom.width, grabc->geom.y + grabc->geom.height); - wlr_xcursor_manager_set_cursor_image(cursor_mgr, - "bottom_right_corner", cursor); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "bottom_right_corner"); break; } } @@ -2005,7 +2003,7 @@ run(char *startup_cmd) * initialized, as the image/coordinates are not transformed for the * monitor when displayed here */ wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y); - wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "left_ptr"); /* Run the Wayland event loop. This does not return until you exit the * compositor. Starting the backend rigged up all of the necessary event From 65f68e76437275a0c1c25279af646f726e213b6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 12 Jun 2023 22:46:39 -0600 Subject: [PATCH 043/347] use wlr_scene_output_build_state() to set gamma --- dwl.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 1538ed7..1b2027c 100644 --- a/dwl.c +++ b/dwl.c @@ -2068,15 +2068,26 @@ void setgamma(struct wl_listener *listener, void *data) { struct wlr_gamma_control_manager_v1_set_gamma_event *event = data; - if (!wlr_gamma_control_v1_apply(event->control, &event->output->pending)) + Monitor *m = event->output->data; + struct wlr_output_state pending = {0}; + if (!m) return; - if (!wlr_output_test(event->output)) { - wlr_output_rollback(event->output); + if (!wlr_scene_output_build_state(m->scene_output, &pending)) + return; + + if (!wlr_gamma_control_v1_apply(event->control, &pending)) + goto out; + + if (!wlr_output_commit_state(m->wlr_output, &pending)) { wlr_gamma_control_v1_send_failed_and_destroy(event->control); + goto out; } - wlr_output_schedule_frame(event->output); + wlr_damage_ring_rotate(&m->scene_output->damage_ring); + +out: + wlr_output_state_finish(&pending); } void From dfb6b97159ab8780674be9bea103227e68505c7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 9 Jun 2023 13:36:56 -0600 Subject: [PATCH 044/347] drop support for wlr-input-inhibitor-unstable-v1 deprecated in favor of ext-session-lock-v1 References: https://gitlab.freedesktop.org/wlroots/wlr-protocols/-/commit/4aa366e3ddf5e9b67950a94b9fb299bbfe05eef8 References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3848 --- dwl.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index 1b2027c..77303d2 100644 --- a/dwl.c +++ b/dwl.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -349,7 +348,6 @@ static struct wl_list fstack; /* focus order */ static struct wlr_idle *idle; static struct wlr_idle_notifier_v1 *idle_notifier; static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr; -static struct wlr_input_inhibit_manager *input_inhibit_mgr; static struct wlr_layer_shell_v1 *layer_shell; static struct wlr_output_manager_v1 *output_mgr; static struct wlr_gamma_control_manager_v1 *gamma_control_mgr; @@ -1428,8 +1426,7 @@ keypress(struct wl_listener *listener, void *data) /* On _press_ if there is no active screen locker, * attempt to process a compositor keybinding. */ - if (!locked && !input_inhibit_mgr->active_inhibitor - && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) + if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) for (i = 0; i < nsyms; i++) handled = keybinding(mods, syms[i]) || handled; @@ -2290,7 +2287,6 @@ setup(void) xdg_shell = wlr_xdg_shell_create(dpy, 4); wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface); - input_inhibit_mgr = wlr_input_inhibit_manager_create(dpy); session_lock_mgr = wlr_session_lock_manager_v1_create(dpy); wl_signal_add(&session_lock_mgr->events.new_lock, &session_lock_create_lock); wl_signal_add(&session_lock_mgr->events.destroy, &session_lock_mgr_destroy); From 1e1811f95368c0848ba13137452153e01862c301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 9 Jun 2023 13:45:40 -0600 Subject: [PATCH 045/347] drop KDE idle support use ext-idle-notify-v1 instead --- dwl.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/dwl.c b/dwl.c index 77303d2..3c2f2f6 100644 --- a/dwl.c +++ b/dwl.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -71,7 +70,6 @@ #define END(A) ((A) + LENGTH(A)) #define TAGMASK ((1u << tagcount) - 1) #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) -#define IDLE_NOTIFY_ACTIVITY wlr_idle_notify_activity(idle, seat), wlr_idle_notifier_v1_notify_activity(idle_notifier, seat) /* enums */ enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ @@ -345,7 +343,6 @@ static struct wlr_xdg_activation_v1 *activation; static struct wlr_xdg_decoration_manager_v1 *xdg_decoration_mgr; static struct wl_list clients; /* tiling order */ static struct wl_list fstack; /* focus order */ -static struct wlr_idle *idle; static struct wlr_idle_notifier_v1 *idle_notifier; static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr; static struct wlr_layer_shell_v1 *layer_shell; @@ -567,7 +564,7 @@ axisnotify(struct wl_listener *listener, void *data) /* This event is forwarded by the cursor when a pointer emits an axis event, * for example when you move the scroll wheel. */ struct wlr_pointer_axis_event *event = data; - IDLE_NOTIFY_ACTIVITY; + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); /* TODO: allow usage of scroll whell for mousebindings, it can be implemented * checking the event's orientation and the delta of the event */ /* Notify the client with pointer focus of the axis event. */ @@ -585,7 +582,7 @@ buttonpress(struct wl_listener *listener, void *data) Client *c; const Button *b; - IDLE_NOTIFY_ACTIVITY; + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); switch (event->state) { case WLR_BUTTON_PRESSED: @@ -651,7 +648,6 @@ checkidleinhibitor(struct wlr_surface *exclude) } } - wlr_idle_set_enabled(idle, NULL, !inhibited); wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited); } @@ -1422,7 +1418,7 @@ keypress(struct wl_listener *listener, void *data) int handled = 0; uint32_t mods = wlr_keyboard_get_modifiers(kb->wlr_keyboard); - IDLE_NOTIFY_ACTIVITY; + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); /* On _press_ if there is no active screen locker, * attempt to process a compositor keybinding. */ @@ -1647,7 +1643,7 @@ motionnotify(uint32_t time) /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { - IDLE_NOTIFY_ACTIVITY; + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); /* Update selmon (even while dragging a window) */ if (sloppyfocus) @@ -2275,7 +2271,6 @@ setup(void) wl_list_init(&clients); wl_list_init(&fstack); - idle = wlr_idle_create(dpy); idle_notifier = wlr_idle_notifier_v1_create(dpy); idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); From df11b7a7864b416bba52e00d6ad7997d9a7c19b0 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Thu, 15 Jun 2023 15:42:54 -0500 Subject: [PATCH 046/347] fix startup_cmd SIGCHLD handler Ignored handlers are not reset by exec() calls --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index d741cbd..19adafe 100644 --- a/dwl.c +++ b/dwl.c @@ -1963,6 +1963,8 @@ run(char *startup_cmd) if ((child_pid = fork()) < 0) die("startup: fork:"); if (child_pid == 0) { + sa.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &sa, NULL); dup2(piperw[0], STDIN_FILENO); close(piperw[0]); close(piperw[1]); From 9c592da01f7648ff1efb69e851ced554b3231096 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Thu, 15 Jun 2023 23:57:16 -0500 Subject: [PATCH 047/347] Reset ignored signal handler in spawn() as well --- dwl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dwl.c b/dwl.c index 19adafe..9402935 100644 --- a/dwl.c +++ b/dwl.c @@ -2327,6 +2327,9 @@ void spawn(const Arg *arg) { if (fork() == 0) { + struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = SIG_DFL}; + sigemptyset(&sa.sa_mask); + sigaction(SIGCHLD, &sa, NULL); dup2(STDERR_FILENO, STDOUT_FILENO); setsid(); execvp(((char **)arg->v)[0], (char **)arg->v); From 68a17f962e05895603d0f409fb8da4493cbe52aa Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Fri, 16 Jun 2023 00:22:11 -0500 Subject: [PATCH 048/347] Don't bother with ignoring SIGCHLD It added complexity, especially with the differences in behavior between handled and ignored signals across an exec(). --- dwl.c | 73 ++++++++++++++++++++++++++--------------------------------- 1 file changed, 32 insertions(+), 41 deletions(-) diff --git a/dwl.c b/dwl.c index 9402935..da3a516 100644 --- a/dwl.c +++ b/dwl.c @@ -297,6 +297,7 @@ static void setmon(Client *c, Monitor *m, uint32_t newtags); static void setpsel(struct wl_listener *listener, void *data); static void setsel(struct wl_listener *listener, void *data); static void setup(void); +static void sigchld(int unused); static void spawn(const Arg *arg); static void startdrag(struct wl_listener *listener, void *data); static void tag(const Arg *arg); @@ -397,7 +398,6 @@ static void configurex11(struct wl_listener *listener, void *data); static void createnotifyx11(struct wl_listener *listener, void *data); static Atom getatom(xcb_connection_t *xc, const char *name); static void sethints(struct wl_listener *listener, void *data); -static void sigchld(int unused); static void xwaylandready(struct wl_listener *listener, void *data); static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11}; static struct wl_listener xwayland_ready = {.notify = xwaylandready}; @@ -1963,8 +1963,6 @@ run(char *startup_cmd) if ((child_pid = fork()) < 0) die("startup: fork:"); if (child_pid == 0) { - sa.sa_handler = SIG_DFL; - sigaction(SIGCHLD, &sa, NULL); dup2(piperw[0], STDIN_FILENO); close(piperw[0]); close(piperw[1]); @@ -2129,27 +2127,19 @@ setsel(struct wl_listener *listener, void *data) void setup(void) { - struct sigaction sa_term = {.sa_flags = SA_RESTART, .sa_handler = quitsignal}; - struct sigaction sa_sigchld = { -#ifdef XWAYLAND - .sa_flags = SA_RESTART, - .sa_handler = sigchld, -#else - .sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART, - .sa_handler = SIG_IGN, -#endif - }; - sigemptyset(&sa_term.sa_mask); - sigemptyset(&sa_sigchld.sa_mask); + /* Set up signal handlers */ + struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = sigchld}; + sigemptyset(&sa.sa_mask); + sigaction(SIGCHLD, &sa, NULL); + + sa.sa_handler = quitsignal; + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + /* The Wayland display is managed by libwayland. It handles accepting * clients from the Unix socket, manging Wayland globals, and so on. */ dpy = wl_display_create(); - /* Set up signal handlers */ - sigaction(SIGCHLD, &sa_sigchld, NULL); - sigaction(SIGINT, &sa_term, NULL); - sigaction(SIGTERM, &sa_term, NULL); - /* The backend is a wlroots feature which abstracts the underlying input and * output hardware. The autocreate option will choose the most suitable * backend based on the current environment, such as opening an X11 window @@ -2323,13 +2313,32 @@ setup(void) #endif } +void +sigchld(int unused) +{ +#ifdef XWAYLAND + siginfo_t in; + /* We should be able to remove this function in favor of a simple + * struct sigaction sa = {.sa_handler = SIG_IGN}; + * sigaction(SIGCHLD, &sa, NULL); + * but the Xwayland implementation in wlroots currently prevents us from + * setting our own disposition for SIGCHLD. + */ + /* WNOWAIT leaves the child in a waitable state, in case this is the + * XWayland process + */ + while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid + && (!xwayland || in.si_pid != xwayland->server->pid)) + waitpid(in.si_pid, NULL, 0); +#else + while (waitpid(-1, NULL, WNOHANG) > 0); +#endif +} + void spawn(const Arg *arg) { if (fork() == 0) { - struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = SIG_DFL}; - sigemptyset(&sa.sa_mask); - sigaction(SIGCHLD, &sa, NULL); dup2(STDERR_FILENO, STDOUT_FILENO); setsid(); execvp(((char **)arg->v)[0], (char **)arg->v); @@ -2772,24 +2781,6 @@ sethints(struct wl_listener *listener, void *data) } } -void -sigchld(int unused) -{ - siginfo_t in; - /* We should be able to remove this function in favor of a simple - * struct sigaction sa = {.sa_handler = SIG_IGN}; - * sigaction(SIGCHLD, &sa, NULL); - * but the Xwayland implementation in wlroots currently prevents us from - * setting our own disposition for SIGCHLD. - */ - /* WNOWAIT leaves the child in a waitable state, in case this is the - * XWayland process - */ - while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid - && (!xwayland || in.si_pid != xwayland->server->pid)) - waitpid(in.si_pid, NULL, 0); -} - void xwaylandready(struct wl_listener *listener, void *data) { From 6095ff84d2f8141f5bcedb41af75c95109e24fdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 23 Jun 2023 13:30:43 -0600 Subject: [PATCH 049/347] Revert "use wlr_scene_output_build_state() to set gamma" This reverts commit 65f68e76437275a0c1c25279af646f726e213b6d. --- dwl.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/dwl.c b/dwl.c index 3c2f2f6..2a16ef7 100644 --- a/dwl.c +++ b/dwl.c @@ -2061,26 +2061,15 @@ void setgamma(struct wl_listener *listener, void *data) { struct wlr_gamma_control_manager_v1_set_gamma_event *event = data; - Monitor *m = event->output->data; - struct wlr_output_state pending = {0}; - if (!m) + if (!wlr_gamma_control_v1_apply(event->control, &event->output->pending)) return; - if (!wlr_scene_output_build_state(m->scene_output, &pending)) - return; - - if (!wlr_gamma_control_v1_apply(event->control, &pending)) - goto out; - - if (!wlr_output_commit_state(m->wlr_output, &pending)) { + if (!wlr_output_test(event->output)) { + wlr_output_rollback(event->output); wlr_gamma_control_v1_send_failed_and_destroy(event->control); - goto out; } - wlr_damage_ring_rotate(&m->scene_output->damage_ring); - -out: - wlr_output_state_finish(&pending); + wlr_output_schedule_frame(event->output); } void From fdb66ccfa3a035202369bb366a401d49bcce22a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 23 Jun 2023 13:42:44 -0600 Subject: [PATCH 050/347] use detached output states to set gamma --- dwl.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/dwl.c b/dwl.c index 2a16ef7..4ebceab 100644 --- a/dwl.c +++ b/dwl.c @@ -2061,15 +2061,20 @@ void setgamma(struct wl_listener *listener, void *data) { struct wlr_gamma_control_manager_v1_set_gamma_event *event = data; - if (!wlr_gamma_control_v1_apply(event->control, &event->output->pending)) + struct wlr_output_state state; + wlr_output_state_init(&state); + if (!wlr_gamma_control_v1_apply(event->control, &state)) { + wlr_output_state_finish(&state); return; - - if (!wlr_output_test(event->output)) { - wlr_output_rollback(event->output); - wlr_gamma_control_v1_send_failed_and_destroy(event->control); } - wlr_output_schedule_frame(event->output); + if (!wlr_output_test_state(event->output, &state)) { + wlr_gamma_control_v1_send_failed_and_destroy(event->control); + wlr_output_state_finish(&state); + return; + } + + wlr_output_commit_state(event->output, &state); } void From 733114f0ca5a09b471514d54dbced4a9a6068e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 24 Jun 2023 10:09:49 -0600 Subject: [PATCH 051/347] schedule a frame after commmiting gamma not doing it, may freeze the output or do not actually change the gamma until creating a client --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index 4ebceab..8cdcd49 100644 --- a/dwl.c +++ b/dwl.c @@ -2075,6 +2075,7 @@ setgamma(struct wl_listener *listener, void *data) } wlr_output_commit_state(event->output, &state); + wlr_output_schedule_frame(event->output); } void From eda0613cc4c657a4d4f0165aa8ccd75108545981 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sun, 25 Jun 2023 17:44:00 -0500 Subject: [PATCH 052/347] Separate drag icon from layers array and Lyr enum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we treat the drag icon as distinct from other layers (it doesn't have contents that are interactive, focusable, etc.), then we can iterate over layers meaningfully with a simple for loop. ΔSLOC: -8 --- dwl.c | 67 +++++++++++++++++++++++++++-------------------------------- 1 file changed, 31 insertions(+), 36 deletions(-) diff --git a/dwl.c b/dwl.c index da3a516..5a1b1b5 100644 --- a/dwl.c +++ b/dwl.c @@ -74,7 +74,7 @@ /* enums */ enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ enum { XDGShell, LayerShell, X11Managed, X11Unmanaged }; /* client types */ -enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrFS, LyrDragIcon, LyrBlock, NUM_LAYERS }; /* scene layers */ +enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrFS, LyrTop, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */ #ifdef XWAYLAND enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ @@ -330,6 +330,8 @@ static struct wl_display *dpy; static struct wlr_backend *backend; static struct wlr_scene *scene; static struct wlr_scene_tree *layers[NUM_LAYERS]; +/* Map from ZWLR_LAYER_SHELL_* constants to Lyr* enum */ +static const int layermap[] = { LyrBg, LyrBottom, LyrTop, LyrOverlay }; static struct wlr_renderer *drw; static struct wlr_allocator *alloc; static struct wlr_compositor *compositor; @@ -736,17 +738,16 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) LayerSurface *layersurface = wl_container_of(listener, layersurface, surface_commit); struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; struct wlr_output *wlr_output = wlr_layer_surface->output; + struct wlr_scene_tree *layer = layers[layermap[wlr_layer_surface->current.layer]]; /* For some reason this layersurface have no monitor, this can be because * its monitor has just been destroyed */ if (!wlr_output || !(layersurface->mon = wlr_output->data)) return; - if (layers[wlr_layer_surface->current.layer] != layersurface->scene->node.parent) { - wlr_scene_node_reparent(&layersurface->scene->node, - layers[wlr_layer_surface->current.layer]); - wlr_scene_node_reparent(&layersurface->popups->node, - layers[wlr_layer_surface->current.layer]); + if (layer != layersurface->scene->node.parent) { + wlr_scene_node_reparent(&layersurface->scene->node, layer); + wlr_scene_node_reparent(&layersurface->popups->node, layer); wl_list_remove(&layersurface->link); wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->current.layer], &layersurface->link); @@ -832,6 +833,7 @@ createlayersurface(struct wl_listener *listener, void *data) struct wlr_layer_surface_v1 *wlr_layer_surface = data; LayerSurface *layersurface; struct wlr_layer_surface_v1_state old_state; + struct wlr_scene_tree *l = layers[layermap[wlr_layer_surface->pending.layer]]; if (!wlr_layer_surface->output) wlr_layer_surface->output = selmon ? selmon->wlr_output : NULL; @@ -856,11 +858,9 @@ createlayersurface(struct wl_listener *listener, void *data) layersurface->mon = wlr_layer_surface->output->data; wlr_layer_surface->data = layersurface; - layersurface->scene_layer = wlr_scene_layer_surface_v1_create( - layers[wlr_layer_surface->pending.layer], wlr_layer_surface); + layersurface->scene_layer = wlr_scene_layer_surface_v1_create(l, wlr_layer_surface); layersurface->scene = layersurface->scene_layer->tree; - layersurface->popups = wlr_layer_surface->surface->data = - wlr_scene_tree_create(layers[wlr_layer_surface->pending.layer]); + layersurface->popups = wlr_layer_surface->surface->data = wlr_scene_tree_create(l); layersurface->scene->node.data = layersurface; @@ -2127,6 +2127,8 @@ setsel(struct wl_listener *listener, void *data) void setup(void) { + int layer; + /* Set up signal handlers */ struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = sigchld}; sigemptyset(&sa.sa_mask); @@ -2153,15 +2155,8 @@ setup(void) /* Initialize the scene graph used to lay out windows */ scene = wlr_scene_create(); - layers[LyrBg] = wlr_scene_tree_create(&scene->tree); - layers[LyrBottom] = wlr_scene_tree_create(&scene->tree); - layers[LyrTile] = wlr_scene_tree_create(&scene->tree); - layers[LyrFloat] = wlr_scene_tree_create(&scene->tree); - layers[LyrFS] = wlr_scene_tree_create(&scene->tree); - layers[LyrTop] = wlr_scene_tree_create(&scene->tree); - layers[LyrOverlay] = wlr_scene_tree_create(&scene->tree); - layers[LyrDragIcon] = wlr_scene_tree_create(&scene->tree); - layers[LyrBlock] = wlr_scene_tree_create(&scene->tree); + for (layer = 0; layer < NUM_LAYERS; layer++) + layers[layer] = wlr_scene_tree_create(&scene->tree); /* Create a renderer with the default implementation */ if (!(drw = wlr_renderer_autocreate(backend))) @@ -2350,11 +2345,13 @@ void startdrag(struct wl_listener *listener, void *data) { struct wlr_drag *drag = data; + struct wlr_scene_tree *icon; if (!drag->icon) return; - drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrDragIcon], drag->icon->surface); + drag->icon->data = icon = wlr_scene_subsurface_tree_create(&scene->tree, drag->icon->surface); + wlr_scene_node_place_below(&icon->node, &layers[LyrBlock]->node); motionnotify(0); wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); } @@ -2652,24 +2649,22 @@ xytonode(double x, double y, struct wlr_surface **psurface, struct wlr_surface *surface = NULL; Client *c = NULL; LayerSurface *l = NULL; - const int *layer; - int focus_order[] = { LyrBlock, LyrOverlay, LyrTop, LyrFS, LyrFloat, LyrTile, LyrBottom, LyrBg }; + int layer; - for (layer = focus_order; layer < END(focus_order); layer++) { - if ((node = wlr_scene_node_at(&layers[*layer]->node, x, y, nx, ny))) { - if (node->type == WLR_SCENE_NODE_BUFFER) - surface = wlr_scene_surface_from_buffer( - wlr_scene_buffer_from_node(node))->surface; - /* Walk the tree to find a node that knows the client */ - for (pnode = node; pnode && !c; pnode = &pnode->parent->node) - c = pnode->data; - if (c && c->type == LayerShell) { - c = NULL; - l = pnode->data; - } + for (layer = NUM_LAYERS - 1; !surface && layer >= 0; layer--) { + if (!(node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny))) + continue; + + if (node->type == WLR_SCENE_NODE_BUFFER) + surface = wlr_scene_surface_from_buffer( + wlr_scene_buffer_from_node(node))->surface; + /* Walk the tree to find a node that knows the client */ + for (pnode = node; pnode && !c; pnode = &pnode->parent->node) + c = pnode->data; + if (c && c->type == LayerShell) { + c = NULL; + l = pnode->data; } - if (surface) - break; } if (psurface) *psurface = surface; From a01e402c5dc2e9fe6af58e4921a1c28179e253b7 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Mon, 3 Jul 2023 17:48:45 -0500 Subject: [PATCH 053/347] Line saver: follow "local = wlr->data = obj" pattern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There were still a couple of places where we could use this handy multiple assignment to save a line. ΔSLOC = -3 --- dwl.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/dwl.c b/dwl.c index 740e543..0c08bfd 100644 --- a/dwl.c +++ b/dwl.c @@ -847,7 +847,7 @@ createlayersurface(struct wl_listener *listener, void *data) return; } - layersurface = ecalloc(1, sizeof(LayerSurface)); + layersurface = wlr_layer_surface->data = ecalloc(1, sizeof(LayerSurface)); layersurface->type = LayerShell; LISTEN(&wlr_layer_surface->surface->events.commit, &layersurface->surface_commit, commitlayersurfacenotify); @@ -860,8 +860,6 @@ createlayersurface(struct wl_listener *listener, void *data) layersurface->layer_surface = wlr_layer_surface; layersurface->mon = wlr_layer_surface->output->data; - wlr_layer_surface->data = layersurface; - layersurface->scene_layer = wlr_scene_layer_surface_v1_create(l, wlr_layer_surface); layersurface->scene = layersurface->scene_layer->tree; layersurface->popups = wlr_layer_surface->surface->data = wlr_scene_tree_create(l); @@ -1497,13 +1495,12 @@ locksession(struct wl_listener *listener, void *data) wlr_session_lock_v1_destroy(session_lock); return; } - lock = ecalloc(1, sizeof(*lock)); + lock = session_lock->data = ecalloc(1, sizeof(*lock)); focusclient(NULL, 0); lock->scene = wlr_scene_tree_create(layers[LyrBlock]); cur_lock = lock->lock = session_lock; locked = 1; - session_lock->data = lock; LISTEN(&session_lock->events.new_surface, &lock->new_surface, createlocksurface); LISTEN(&session_lock->events.destroy, &lock->destroy, destroysessionlock); @@ -1529,12 +1526,11 @@ mapnotify(struct wl_listener *listener, void *data) int i; /* Create scene tree for this client and its border */ - c->scene = wlr_scene_tree_create(layers[LyrTile]); + c->scene = client_surface(c)->data = wlr_scene_tree_create(layers[LyrTile]); wlr_scene_node_set_enabled(&c->scene->node, c->type != XDGShell); c->scene_surface = c->type == XDGShell ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg) : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); - client_surface(c)->data = c->scene; c->scene->node.data = c->scene_surface->node.data = c; /* Handle unmanaged clients first so we can return prior create borders */ @@ -2393,7 +2389,7 @@ startdrag(struct wl_listener *listener, void *data) if (!drag->icon) return; - drag->icon->data = icon = wlr_scene_drag_icon_create(&scene->tree, drag->icon); + icon = drag->icon->data = wlr_scene_drag_icon_create(&scene->tree, drag->icon); wlr_scene_node_place_below(&icon->node, &layers[LyrBlock]->node); motionnotify(0); wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); From fbd84aca4a2cbaa4e7daaa9d1a546d2248be8fec Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Mon, 3 Jul 2023 14:51:09 -0500 Subject: [PATCH 054/347] Unify signal handling under wl_event_loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merge our signal handlers into a single function and let Wayland deal with all the struct sigaction stuff. ΔSLOC: -3 --- dwl.c | 83 +++++++++++++++++++++++++---------------------------------- 1 file changed, 35 insertions(+), 48 deletions(-) diff --git a/dwl.c b/dwl.c index 5a1b1b5..b5e146d 100644 --- a/dwl.c +++ b/dwl.c @@ -260,6 +260,7 @@ static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); static Client *focustop(Monitor *m); static void fullscreennotify(struct wl_listener *listener, void *data); +static int handlesig(int signo, void *data); static void incnmaster(const Arg *arg); static void inputdevice(struct wl_listener *listener, void *data); static int keybinding(uint32_t mods, xkb_keysym_t sym); @@ -283,7 +284,6 @@ static void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, uint32_t time); static void printstatus(void); static void quit(const Arg *arg); -static void quitsignal(int signo); static void rendermon(struct wl_listener *listener, void *data); static void requeststartdrag(struct wl_listener *listener, void *data); static void resize(Client *c, struct wlr_box geo, int interact); @@ -297,7 +297,6 @@ static void setmon(Client *c, Monitor *m, uint32_t newtags); static void setpsel(struct wl_listener *listener, void *data); static void setsel(struct wl_listener *listener, void *data); static void setup(void); -static void sigchld(int unused); static void spawn(const Arg *arg); static void startdrag(struct wl_listener *listener, void *data); static void tag(const Arg *arg); @@ -327,6 +326,8 @@ static pid_t child_pid = -1; static int locked; static void *exclusive_focus; static struct wl_display *dpy; +static struct wl_event_loop *eventloop; +static struct wl_event_source *sighandler[4]; static struct wlr_backend *backend; static struct wlr_scene *scene; static struct wlr_scene_tree *layers[NUM_LAYERS]; @@ -652,6 +653,7 @@ checkidleinhibitor(struct wlr_surface *exclude) void cleanup(void) { + int i; #ifdef XWAYLAND wlr_xwayland_destroy(xwayland); #endif @@ -667,6 +669,8 @@ cleanup(void) wlr_cursor_destroy(cursor); wlr_output_layout_destroy(output_layout); wlr_seat_destroy(seat); + for (i = 0; i < LENGTH(sighandler); i++) + wl_event_source_remove(sighandler[i]); wl_display_destroy(dpy); } @@ -820,8 +824,7 @@ createkeyboard(struct wlr_keyboard *keyboard) wlr_seat_set_keyboard(seat, keyboard); - kb->key_repeat_source = wl_event_loop_add_timer( - wl_display_get_event_loop(dpy), keyrepeat, kb); + kb->key_repeat_source = wl_event_loop_add_timer(eventloop, keyrepeat, kb); /* And add the keyboard to our list of keyboards */ wl_list_insert(&keyboards, &kb->link); @@ -1333,6 +1336,28 @@ fullscreennotify(struct wl_listener *listener, void *data) setfullscreen(c, client_wants_fullscreen(c)); } +int +handlesig(int signo, void *data) +{ + if (signo == SIGCHLD) { +#ifdef XWAYLAND + siginfo_t in; + /* wlroots expects to reap the XWayland process itself, so we + * use WNOWAIT to keep the child waitable until we know it's not + * XWayland. + */ + while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid + && (!xwayland || in.si_pid != xwayland->server->pid)) + waitpid(in.si_pid, NULL, 0); +#else + while (waitpid(-1, NULL, WNOHANG) > 0); +#endif + } else if (signo == SIGINT || signo == SIGTERM) { + quit(NULL); + } + return 0; +} + void incnmaster(const Arg *arg) { @@ -1875,12 +1900,6 @@ quit(const Arg *arg) wl_display_terminate(dpy); } -void -quitsignal(int signo) -{ - quit(NULL); -} - void rendermon(struct wl_listener *listener, void *data) { @@ -1944,8 +1963,6 @@ run(char *startup_cmd) { /* Add a Unix socket to the Wayland display. */ const char *socket = wl_display_add_socket_auto(dpy); - struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = SIG_IGN}; - sigemptyset(&sa.sa_mask); if (!socket) die("startup: display_add_socket_auto"); setenv("WAYLAND_DISPLAY", socket, 1); @@ -1973,8 +1990,6 @@ run(char *startup_cmd) close(piperw[1]); close(piperw[0]); } - /* If nobody is reading the status output, don't terminate */ - sigaction(SIGPIPE, &sa, NULL); printstatus(); /* At this point the outputs are initialized, choose initial selmon based on @@ -2127,20 +2142,14 @@ setsel(struct wl_listener *listener, void *data) void setup(void) { - int layer; - - /* Set up signal handlers */ - struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = sigchld}; - sigemptyset(&sa.sa_mask); - sigaction(SIGCHLD, &sa, NULL); - - sa.sa_handler = quitsignal; - sigaction(SIGINT, &sa, NULL); - sigaction(SIGTERM, &sa, NULL); + int i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE}; /* The Wayland display is managed by libwayland. It handles accepting * clients from the Unix socket, manging Wayland globals, and so on. */ dpy = wl_display_create(); + eventloop = wl_display_get_event_loop(dpy); + for (i = 0; i < LENGTH(sighandler); i++) + sighandler[i] = wl_event_loop_add_signal(eventloop, sig[i], handlesig, NULL); /* The backend is a wlroots feature which abstracts the underlying input and * output hardware. The autocreate option will choose the most suitable @@ -2155,8 +2164,8 @@ setup(void) /* Initialize the scene graph used to lay out windows */ scene = wlr_scene_create(); - for (layer = 0; layer < NUM_LAYERS; layer++) - layers[layer] = wlr_scene_tree_create(&scene->tree); + for (i = 0; i < NUM_LAYERS; i++) + layers[i] = wlr_scene_tree_create(&scene->tree); /* Create a renderer with the default implementation */ if (!(drw = wlr_renderer_autocreate(backend))) @@ -2308,28 +2317,6 @@ setup(void) #endif } -void -sigchld(int unused) -{ -#ifdef XWAYLAND - siginfo_t in; - /* We should be able to remove this function in favor of a simple - * struct sigaction sa = {.sa_handler = SIG_IGN}; - * sigaction(SIGCHLD, &sa, NULL); - * but the Xwayland implementation in wlroots currently prevents us from - * setting our own disposition for SIGCHLD. - */ - /* WNOWAIT leaves the child in a waitable state, in case this is the - * XWayland process - */ - while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid - && (!xwayland || in.si_pid != xwayland->server->pid)) - waitpid(in.si_pid, NULL, 0); -#else - while (waitpid(-1, NULL, WNOHANG) > 0); -#endif -} - void spawn(const Arg *arg) { From 33bcd2e4ca892bb0b558660c99ed63a3dfdd9011 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Mon, 3 Jul 2023 17:35:44 -0500 Subject: [PATCH 055/347] Line saver: LISTEN_STATIC macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This parallels the LISTEN macro for statically allocated listeners, and it allows us to remove almost all of the global wl_listener declarations. This also fixes a bug with the axisnotify listener, which was declared with a compound literal. At block scope, these have automatic storage duration [1], so the listener was no longer valid after setup() returned. (The option to declare it static explicitly was standardized in C23, if that ever gains suckless traction.) ΔSLOC: -27 [1]: https://en.cppreference.com/w/c/language/compound_literal#Explanation --- dwl.c | 93 ++++++++++++++++++++--------------------------------------- 1 file changed, 32 insertions(+), 61 deletions(-) diff --git a/dwl.c b/dwl.c index 0c08bfd..0e788a4 100644 --- a/dwl.c +++ b/dwl.c @@ -70,6 +70,7 @@ #define END(A) ((A) + LENGTH(A)) #define TAGMASK ((1u << tagcount) - 1) #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) +#define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0) /* enums */ enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ @@ -359,6 +360,7 @@ static struct wlr_xcursor_manager *cursor_mgr; static struct wlr_session_lock_manager_v1 *session_lock_mgr; static struct wlr_scene_rect *locked_bg; static struct wlr_session_lock_v1 *cur_lock; +static struct wl_listener lock_listener = {.notify = locksession}; static struct wlr_seat *seat; static struct wl_list keyboards; @@ -371,34 +373,6 @@ static struct wlr_box sgeom; static struct wl_list mons; static Monitor *selmon; -/* global event handlers */ -static struct wl_listener cursor_axis = {.notify = axisnotify}; -static struct wl_listener cursor_button = {.notify = buttonpress}; -static struct wl_listener cursor_frame = {.notify = cursorframe}; -static struct wl_listener cursor_motion = {.notify = motionrelative}; -static struct wl_listener cursor_motion_absolute = {.notify = motionabsolute}; -static struct wl_listener drag_icon_destroy = {.notify = destroydragicon}; -static struct wl_listener idle_inhibitor_create = {.notify = createidleinhibitor}; -static struct wl_listener idle_inhibitor_destroy = {.notify = destroyidleinhibitor}; -static struct wl_listener layout_change = {.notify = updatemons}; -static struct wl_listener new_input = {.notify = inputdevice}; -static struct wl_listener new_virtual_keyboard = {.notify = virtualkeyboard}; -static struct wl_listener new_output = {.notify = createmon}; -static struct wl_listener new_xdg_surface = {.notify = createnotify}; -static struct wl_listener new_xdg_decoration = {.notify = createdecoration}; -static struct wl_listener new_layer_shell_surface = {.notify = createlayersurface}; -static struct wl_listener output_mgr_apply = {.notify = outputmgrapply}; -static struct wl_listener output_mgr_test = {.notify = outputmgrtest}; -static struct wl_listener request_activate = {.notify = urgent}; -static struct wl_listener request_cursor = {.notify = setcursor}; -static struct wl_listener request_gamma = {.notify = setgamma}; -static struct wl_listener request_set_psel = {.notify = setpsel}; -static struct wl_listener request_set_sel = {.notify = setsel}; -static struct wl_listener request_start_drag = {.notify = requeststartdrag}; -static struct wl_listener start_drag = {.notify = startdrag}; -static struct wl_listener session_lock_create_lock = {.notify = locksession}; -static struct wl_listener session_lock_mgr_destroy = {.notify = destroysessionmgr}; - #ifdef XWAYLAND static void activatex11(struct wl_listener *listener, void *data); static void associatex11(struct wl_listener *listener, void *data); @@ -408,8 +382,6 @@ static void dissociatex11(struct wl_listener *listener, void *data); static Atom getatom(xcb_connection_t *xc, const char *name); static void sethints(struct wl_listener *listener, void *data); static void xwaylandready(struct wl_listener *listener, void *data); -static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11}; -static struct wl_listener xwayland_ready = {.notify = xwaylandready}; static struct wlr_xwayland *xwayland; static Atom netatom[NetLast]; #endif @@ -794,7 +766,7 @@ void createidleinhibitor(struct wl_listener *listener, void *data) { struct wlr_idle_inhibitor_v1 *idle_inhibitor = data; - wl_signal_add(&idle_inhibitor->events.destroy, &idle_inhibitor_destroy); + LISTEN_STATIC(&idle_inhibitor->events.destroy, destroyidleinhibitor); checkidleinhibitor(NULL); } @@ -1185,8 +1157,8 @@ destroysessionlock(struct wl_listener *listener, void *data) void destroysessionmgr(struct wl_listener *listener, void *data) { - wl_list_remove(&session_lock_create_lock.link); - wl_list_remove(&session_lock_mgr_destroy.link); + wl_list_remove(&lock_listener.link); + wl_list_remove(&listener->link); } Monitor * @@ -2224,21 +2196,21 @@ setup(void) /* Initializes the interface used to implement urgency hints */ activation = wlr_xdg_activation_v1_create(dpy); - wl_signal_add(&activation->events.request_activate, &request_activate); + LISTEN_STATIC(&activation->events.request_activate, urgent); gamma_control_mgr = wlr_gamma_control_manager_v1_create(dpy); - wl_signal_add(&gamma_control_mgr->events.set_gamma, &request_gamma); + LISTEN_STATIC(&gamma_control_mgr->events.set_gamma, setgamma); /* Creates an output layout, which a wlroots utility for working with an * arrangement of screens in a physical layout. */ output_layout = wlr_output_layout_create(); - wl_signal_add(&output_layout->events.change, &layout_change); + LISTEN_STATIC(&output_layout->events.change, updatemons); wlr_xdg_output_manager_v1_create(dpy, output_layout); /* Configure a listener to be notified when new outputs are available on the * backend. */ wl_list_init(&mons); - wl_signal_add(&backend->events.new_output, &new_output); + LISTEN_STATIC(&backend->events.new_output, createmon); /* Set up our client lists and the xdg-shell. The xdg-shell is a * Wayland protocol which is used for application windows. For more @@ -2252,17 +2224,17 @@ setup(void) idle_notifier = wlr_idle_notifier_v1_create(dpy); idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); - wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &idle_inhibitor_create); + LISTEN_STATIC(&idle_inhibit_mgr->events.new_inhibitor, createidleinhibitor); layer_shell = wlr_layer_shell_v1_create(dpy, 3); - wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface); + LISTEN_STATIC(&layer_shell->events.new_surface, createlayersurface); xdg_shell = wlr_xdg_shell_create(dpy, 4); - wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface); + LISTEN_STATIC(&xdg_shell->events.new_surface, createnotify); session_lock_mgr = wlr_session_lock_manager_v1_create(dpy); - wl_signal_add(&session_lock_mgr->events.new_lock, &session_lock_create_lock); - wl_signal_add(&session_lock_mgr->events.destroy, &session_lock_mgr_destroy); + wl_signal_add(&session_lock_mgr->events.new_lock, &lock_listener); + LISTEN_STATIC(&session_lock_mgr->events.destroy, destroysessionmgr); locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height, (float [4]){0.1, 0.1, 0.1, 1.0}); wlr_scene_node_set_enabled(&locked_bg->node, 0); @@ -2272,7 +2244,7 @@ setup(void) wlr_server_decoration_manager_create(dpy), WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy); - wl_signal_add(&xdg_decoration_mgr->events.new_toplevel_decoration, &new_xdg_decoration); + LISTEN_STATIC(&xdg_decoration_mgr->events.new_toplevel_decoration, createdecoration); /* * Creates a cursor, which is a wlroots utility for tracking the cursor @@ -2300,11 +2272,11 @@ setup(void) * * And more comments are sprinkled throughout the notify functions above. */ - wl_signal_add(&cursor->events.motion, &cursor_motion); - wl_signal_add(&cursor->events.motion_absolute, &cursor_motion_absolute); - wl_signal_add(&cursor->events.button, &cursor_button); - wl_signal_add(&cursor->events.axis, &cursor_axis); - wl_signal_add(&cursor->events.frame, &cursor_frame); + LISTEN_STATIC(&cursor->events.motion, motionrelative); + LISTEN_STATIC(&cursor->events.motion_absolute, motionabsolute); + LISTEN_STATIC(&cursor->events.button, buttonpress); + LISTEN_STATIC(&cursor->events.axis, axisnotify); + LISTEN_STATIC(&cursor->events.frame, cursorframe); /* * Configures a seat, which is a single "seat" at which a user sits and @@ -2313,20 +2285,19 @@ setup(void) * let us know when new input devices are available on the backend. */ wl_list_init(&keyboards); - wl_signal_add(&backend->events.new_input, &new_input); + LISTEN_STATIC(&backend->events.new_input, inputdevice); virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy); - wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard, - &new_virtual_keyboard); + LISTEN_STATIC(&virtual_keyboard_mgr->events.new_virtual_keyboard, virtualkeyboard); seat = wlr_seat_create(dpy, "seat0"); - wl_signal_add(&seat->events.request_set_cursor, &request_cursor); - wl_signal_add(&seat->events.request_set_selection, &request_set_sel); - wl_signal_add(&seat->events.request_set_primary_selection, &request_set_psel); - wl_signal_add(&seat->events.request_start_drag, &request_start_drag); - wl_signal_add(&seat->events.start_drag, &start_drag); + LISTEN_STATIC(&seat->events.request_set_cursor, setcursor); + LISTEN_STATIC(&seat->events.request_set_selection, setsel); + LISTEN_STATIC(&seat->events.request_set_primary_selection, setpsel); + LISTEN_STATIC(&seat->events.request_start_drag, requeststartdrag); + LISTEN_STATIC(&seat->events.start_drag, startdrag); output_mgr = wlr_output_manager_v1_create(dpy); - wl_signal_add(&output_mgr->events.apply, &output_mgr_apply); - wl_signal_add(&output_mgr->events.test, &output_mgr_test); + LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply); + LISTEN_STATIC(&output_mgr->events.test, outputmgrtest); wlr_scene_set_presentation(scene, wlr_presentation_create(dpy, backend)); @@ -2337,8 +2308,8 @@ setup(void) */ xwayland = wlr_xwayland_create(dpy, compositor, 1); if (xwayland) { - wl_signal_add(&xwayland->events.ready, &xwayland_ready); - wl_signal_add(&xwayland->events.new_surface, &new_xwayland_surface); + LISTEN_STATIC(&xwayland->events.ready, xwaylandready); + LISTEN_STATIC(&xwayland->events.new_surface, createnotifyx11); setenv("DISPLAY", xwayland->display_name, 1); } else { @@ -2392,7 +2363,7 @@ startdrag(struct wl_listener *listener, void *data) icon = drag->icon->data = wlr_scene_drag_icon_create(&scene->tree, drag->icon); wlr_scene_node_place_below(&icon->node, &layers[LyrBlock]->node); motionnotify(0); - wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); + LISTEN_STATIC(&drag->icon->events.destroy, destroydragicon); } void From ff7c0e9508a380bb271886c2780e6f21679da1ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 10 Jul 2023 11:23:19 -0600 Subject: [PATCH 056/347] chase wlroots!4220 References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4220 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 0e788a4..7a2c323 100644 --- a/dwl.c +++ b/dwl.c @@ -1865,7 +1865,7 @@ rendermon(struct wl_listener *listener, void *data) wl_list_for_each(c, &clients, link) if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && !client_is_stopped(c)) goto skip; - wlr_scene_output_commit(m->scene_output); + wlr_scene_output_commit(m->scene_output, NULL); skip: /* Let clients know a frame has been rendered */ From 18415278718bf8e162b0fbf5d3551134d1eb705a Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Thu, 13 Jul 2023 16:20:51 -0500 Subject: [PATCH 057/347] properly destroy scene MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ΔSLOC: +1 --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index b5e146d..76ba33d 100644 --- a/dwl.c +++ b/dwl.c @@ -663,6 +663,7 @@ cleanup(void) waitpid(child_pid, NULL, 0); } wlr_backend_destroy(backend); + wlr_scene_node_destroy(&scene->tree.node); wlr_renderer_destroy(drw); wlr_allocator_destroy(alloc); wlr_xcursor_manager_destroy(cursor_mgr); From 831fc36bc91ac595340300ec5cef5e81f263c3b3 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Thu, 13 Jul 2023 16:22:50 -0500 Subject: [PATCH 058/347] Make drag_icon a persistent scene node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If there is no current drag icon, this node will be empty, but we now have `drag_icon != NULL` as an invariant. This allows us to eliminate a conditional, since there's no harm in moving an empty node's coordinates around with the pointer. ΔSLOC: -1 --- dwl.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dwl.c b/dwl.c index 76ba33d..190601e 100644 --- a/dwl.c +++ b/dwl.c @@ -331,6 +331,7 @@ static struct wl_event_source *sighandler[4]; static struct wlr_backend *backend; static struct wlr_scene *scene; static struct wlr_scene_tree *layers[NUM_LAYERS]; +static struct wlr_scene_tree *drag_icon; /* Map from ZWLR_LAYER_SHELL_* constants to Lyr* enum */ static const int layermap[] = { LyrBg, LyrBottom, LyrTop, LyrOverlay }; static struct wlr_renderer *drw; @@ -1663,7 +1664,6 @@ motionnotify(uint32_t time) LayerSurface *l = NULL; int type; struct wlr_surface *surface = NULL; - struct wlr_drag_icon *icon; /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { @@ -1674,10 +1674,9 @@ motionnotify(uint32_t time) selmon = xytomon(cursor->x, cursor->y); } - /* Update drag icon's position if any */ - if (seat->drag && (icon = seat->drag->icon)) - wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, - cursor->y + icon->surface->sy); + /* Update drag icon's position */ + wlr_scene_node_set_position(&drag_icon->node, cursor->x, cursor->y); + /* If we are currently grabbing the mouse, handle and return */ if (cursor_mode == CurMove) { /* Move the grabbed client to the new position. */ @@ -2167,6 +2166,8 @@ setup(void) scene = wlr_scene_create(); for (i = 0; i < NUM_LAYERS; i++) layers[i] = wlr_scene_tree_create(&scene->tree); + drag_icon = wlr_scene_tree_create(&scene->tree); + wlr_scene_node_place_below(&drag_icon->node, &layers[LyrBlock]->node); /* Create a renderer with the default implementation */ if (!(drw = wlr_renderer_autocreate(backend))) @@ -2338,8 +2339,7 @@ startdrag(struct wl_listener *listener, void *data) if (!drag->icon) return; - drag->icon->data = icon = wlr_scene_subsurface_tree_create(&scene->tree, drag->icon->surface); - wlr_scene_node_place_below(&icon->node, &layers[LyrBlock]->node); + drag->icon->data = icon = wlr_scene_subsurface_tree_create(drag_icon, drag->icon->surface); motionnotify(0); wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); } From 4b15bbeb33ba5409bc436ca44200b5605a73b344 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Fri, 14 Jul 2023 00:02:39 -0400 Subject: [PATCH 059/347] Remove unused icon variable --- dwl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index 190601e..96ffb64 100644 --- a/dwl.c +++ b/dwl.c @@ -2334,12 +2334,10 @@ void startdrag(struct wl_listener *listener, void *data) { struct wlr_drag *drag = data; - struct wlr_scene_tree *icon; - if (!drag->icon) return; - drag->icon->data = icon = wlr_scene_subsurface_tree_create(drag_icon, drag->icon->surface); + drag->icon->data = &wlr_scene_subsurface_tree_create(drag_icon, drag->icon->surface)->node; motionnotify(0); wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); } From 76ba2cdab04a952d8cd0503a5f2afc7a18f53538 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Fri, 14 Jul 2023 00:02:54 -0400 Subject: [PATCH 060/347] Remove now-unneeded call to motionnotify This appears to have been here for the side effect of updating the drag icon's position. --- dwl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/dwl.c b/dwl.c index 96ffb64..f323d1b 100644 --- a/dwl.c +++ b/dwl.c @@ -2338,7 +2338,6 @@ startdrag(struct wl_listener *listener, void *data) return; drag->icon->data = &wlr_scene_subsurface_tree_create(drag_icon, drag->icon->surface)->node; - motionnotify(0); wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); } From ca4a97b9335296c40f558baa1ead14578b166d70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 13 Jul 2023 19:36:26 -0600 Subject: [PATCH 061/347] do not use wl_event_loop for signal handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ΔSLOC: -4 Fixes: https://github.com/djpohly/dwl/issues/456 Fixes: https://github.com/djpohly/dwl/issues/459 --- dwl.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/dwl.c b/dwl.c index f323d1b..93f66ef 100644 --- a/dwl.c +++ b/dwl.c @@ -260,7 +260,7 @@ static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); static Client *focustop(Monitor *m); static void fullscreennotify(struct wl_listener *listener, void *data); -static int handlesig(int signo, void *data); +static void handlesig(int signo); static void incnmaster(const Arg *arg); static void inputdevice(struct wl_listener *listener, void *data); static int keybinding(uint32_t mods, xkb_keysym_t sym); @@ -326,8 +326,6 @@ static pid_t child_pid = -1; static int locked; static void *exclusive_focus; static struct wl_display *dpy; -static struct wl_event_loop *eventloop; -static struct wl_event_source *sighandler[4]; static struct wlr_backend *backend; static struct wlr_scene *scene; static struct wlr_scene_tree *layers[NUM_LAYERS]; @@ -654,7 +652,6 @@ checkidleinhibitor(struct wlr_surface *exclude) void cleanup(void) { - int i; #ifdef XWAYLAND wlr_xwayland_destroy(xwayland); #endif @@ -671,8 +668,6 @@ cleanup(void) wlr_cursor_destroy(cursor); wlr_output_layout_destroy(output_layout); wlr_seat_destroy(seat); - for (i = 0; i < LENGTH(sighandler); i++) - wl_event_source_remove(sighandler[i]); wl_display_destroy(dpy); } @@ -826,7 +821,8 @@ createkeyboard(struct wlr_keyboard *keyboard) wlr_seat_set_keyboard(seat, keyboard); - kb->key_repeat_source = wl_event_loop_add_timer(eventloop, keyrepeat, kb); + kb->key_repeat_source = wl_event_loop_add_timer( + wl_display_get_event_loop(dpy), keyrepeat, kb); /* And add the keyboard to our list of keyboards */ wl_list_insert(&keyboards, &kb->link); @@ -1338,8 +1334,8 @@ fullscreennotify(struct wl_listener *listener, void *data) setfullscreen(c, client_wants_fullscreen(c)); } -int -handlesig(int signo, void *data) +void +handlesig(int signo) { if (signo == SIGCHLD) { #ifdef XWAYLAND @@ -1357,7 +1353,6 @@ handlesig(int signo, void *data) } else if (signo == SIGINT || signo == SIGTERM) { quit(NULL); } - return 0; } void @@ -2143,13 +2138,15 @@ void setup(void) { int i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE}; + struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig}; + sigemptyset(&sa.sa_mask); + + for (i = 0; i < LENGTH(sig); i++) + sigaction(sig[i], &sa, NULL); /* The Wayland display is managed by libwayland. It handles accepting * clients from the Unix socket, manging Wayland globals, and so on. */ dpy = wl_display_create(); - eventloop = wl_display_get_event_loop(dpy); - for (i = 0; i < LENGTH(sighandler); i++) - sighandler[i] = wl_event_loop_add_signal(eventloop, sig[i], handlesig, NULL); /* The backend is a wlroots feature which abstracts the underlying input and * output hardware. The autocreate option will choose the most suitable From 0bb1a1cc5c31b8375d3c64a50e7ada57994fd2a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 15 Jul 2023 10:11:47 -0600 Subject: [PATCH 062/347] increase wl_compositor version Now scene will handle sending the preferred buffer scale References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4269 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 11bc510..fcd3612 100644 --- a/dwl.c +++ b/dwl.c @@ -2191,7 +2191,7 @@ setup(void) * to dig your fingers in and play with their behavior if you want. Note that * the clients cannot set the selection directly without compositor approval, * see the setsel() function. */ - compositor = wlr_compositor_create(dpy, 5, drw); + compositor = wlr_compositor_create(dpy, 6, drw); wlr_export_dmabuf_manager_v1_create(dpy); wlr_screencopy_manager_v1_create(dpy); wlr_data_control_manager_v1_create(dpy); From 0e5405610ea2c7f07675c7d22bf6991a0d947803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 27 Jun 2023 18:21:58 -0600 Subject: [PATCH 063/347] add support for cursor-shape-v1 References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4106 --- Makefile | 5 ++++- dwl.c | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ccca079..63b52f0 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(LIBS) all: dwl dwl: dwl.o util.o $(CC) dwl.o util.o $(LDLIBS) $(LDFLAGS) $(DWLCFLAGS) -o $@ -dwl.o: dwl.c config.mk config.h client.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h +dwl.o: dwl.c config.mk config.h client.h cursor-shape-v1-protocol.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h util.o: util.c util.h # wayland-scanner is a tool which generates C headers and rigging for Wayland @@ -31,6 +31,9 @@ xdg-shell-protocol.h: wlr-layer-shell-unstable-v1-protocol.h: $(WAYLAND_SCANNER) server-header \ protocols/wlr-layer-shell-unstable-v1.xml $@ +cursor-shape-v1-protocol.h: + $(WAYLAND_SCANNER) server-header \ + $(WAYLAND_PROTOCOLS)/staging/cursor-shape/cursor-shape-v1.xml $@ config.h: cp config.def.h $@ diff --git a/dwl.c b/dwl.c index fcd3612..456648b 100644 --- a/dwl.c +++ b/dwl.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -294,6 +295,7 @@ static void requestmonstate(struct wl_listener *listener, void *data); static void resize(Client *c, struct wlr_box geo, int interact); static void run(char *startup_cmd); static void setcursor(struct wl_listener *listener, void *data); +static void setcursorshape(struct wl_listener *listener, void *data); static void setfloating(Client *c, int floating); static void setfullscreen(Client *c, int fullscreen); static void setgamma(struct wl_listener *listener, void *data); @@ -353,6 +355,7 @@ static struct wlr_layer_shell_v1 *layer_shell; static struct wlr_output_manager_v1 *output_mgr; static struct wlr_gamma_control_manager_v1 *gamma_control_mgr; static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; +static struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr; static struct wlr_cursor *cursor; static struct wlr_xcursor_manager *cursor_mgr; @@ -2003,6 +2006,20 @@ setcursor(struct wl_listener *listener, void *data) event->hotspot_x, event->hotspot_y); } +void +setcursorshape(struct wl_listener *listener, void *data) +{ + struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data; + if (cursor_mode != CurNormal && cursor_mode != CurPressed) + return; + /* This can be sent by any client, so we check to make sure this one is + * actually has pointer focus first. If so, we can tell the cursor to + * use the provided cursor shape. */ + if (event->seat_client == seat->pointer_state.focused_client) + wlr_cursor_set_xcursor(cursor, cursor_mgr, + wlr_cursor_shape_v1_name(event->shape)); +} + void setfloating(Client *c, int floating) { @@ -2286,6 +2303,9 @@ setup(void) LISTEN_STATIC(&cursor->events.axis, axisnotify); LISTEN_STATIC(&cursor->events.frame, cursorframe); + cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1); + LISTEN_STATIC(&cursor_shape_mgr->events.request_set_shape, setcursorshape); + /* * Configures a seat, which is a single "seat" at which a user sits and * operates the computer. This conceptually includes up to one keyboard, From ce997c4a21e96716982f491718eef08f95425ab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 23 Jul 2023 19:07:21 -0600 Subject: [PATCH 064/347] update to xdg-shell v5 --- dwl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 456648b..436d082 100644 --- a/dwl.c +++ b/dwl.c @@ -987,6 +987,9 @@ createnotify(struct wl_listener *listener, void *data) c->surface.xdg = xdg_surface; c->bw = borderpx; + wlr_xdg_toplevel_set_wm_capabilities(xdg_surface->toplevel, + WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); + LISTEN(&xdg_surface->surface->events.commit, &c->commit, commitnotify); LISTEN(&xdg_surface->surface->events.map, &c->map, mapnotify); LISTEN(&xdg_surface->surface->events.unmap, &c->unmap, unmapnotify); @@ -2254,7 +2257,7 @@ setup(void) layer_shell = wlr_layer_shell_v1_create(dpy, 3); LISTEN_STATIC(&layer_shell->events.new_surface, createlayersurface); - xdg_shell = wlr_xdg_shell_create(dpy, 4); + xdg_shell = wlr_xdg_shell_create(dpy, 5); LISTEN_STATIC(&xdg_shell->events.new_surface, createnotify); session_lock_mgr = wlr_session_lock_manager_v1_create(dpy); From 78cf88670f3410782f5c90895c3c4586d3485a67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 23 Jul 2023 20:59:29 -0600 Subject: [PATCH 065/347] add support for xdg-shell v6 --- client.h | 11 +++++++++++ dwl.c | 9 ++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/client.h b/client.h index ef56ee6..fc999f1 100644 --- a/client.h +++ b/client.h @@ -346,6 +346,17 @@ client_set_tiled(Client *c, uint32_t edges) wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges); } +static inline void +client_set_suspended(Client *c, int suspended) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return; +#endif + + wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended); +} + static inline struct wlr_surface * client_surface_at(Client *c, double cx, double cy, double *sx, double *sy) { diff --git a/dwl.c b/dwl.c index 436d082..91abe11 100644 --- a/dwl.c +++ b/dwl.c @@ -457,9 +457,12 @@ void arrange(Monitor *m) { Client *c; - wl_list_for_each(c, &clients, link) - if (c->mon == m) + wl_list_for_each(c, &clients, link) { + if (c->mon == m) { wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m)); + client_set_suspended(c, !VISIBLEON(c, m)); + } + } wlr_scene_node_set_enabled(&m->fullscreen_bg->node, (c = focustop(m)) && c->isfullscreen); @@ -2257,7 +2260,7 @@ setup(void) layer_shell = wlr_layer_shell_v1_create(dpy, 3); LISTEN_STATIC(&layer_shell->events.new_surface, createlayersurface); - xdg_shell = wlr_xdg_shell_create(dpy, 5); + xdg_shell = wlr_xdg_shell_create(dpy, 6); LISTEN_STATIC(&xdg_shell->events.new_surface, createnotify); session_lock_mgr = wlr_session_lock_manager_v1_create(dpy); From 25db04539216fa6bf05ad39cdeeeca6df6b69e60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 25 Jul 2023 19:45:18 -0600 Subject: [PATCH 066/347] set withdrawn state for xwayland invisible clients --- client.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client.h b/client.h index fc999f1..6a46151 100644 --- a/client.h +++ b/client.h @@ -350,8 +350,10 @@ static inline void client_set_suspended(Client *c, int suspended) { #ifdef XWAYLAND - if (client_is_x11(c)) + if (client_is_x11(c)) { + wlr_xwayland_surface_set_withdrawn(c->surface.xwayland, suspended); return; + } #endif wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended); From 4567979b16b0509bb80b6102ecb9b601b3cf6fa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 18 Aug 2023 21:37:22 -0600 Subject: [PATCH 067/347] don't resize clients on commit It creates an infinite commit-resize loop when scale != 1 --- dwl.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/dwl.c b/dwl.c index 93f66ef..655ded0 100644 --- a/dwl.c +++ b/dwl.c @@ -768,12 +768,6 @@ void commitnotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, commit); - struct wlr_box box = {0}; - client_get_geometry(c, &box); - - if (c->mon && !wlr_box_empty(&box) && (box.width != c->geom.width - 2 * c->bw - || box.height != c->geom.height - 2 * c->bw)) - c->isfloating ? resize(c, c->geom, 1) : arrange(c->mon); /* mark a pending resize as completed */ if (c->resize && c->resize <= c->surface.xdg->current.configure_serial) From d4f2c6bfd638d45736512691f06081cf314370bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 21 Aug 2023 17:53:24 -0600 Subject: [PATCH 068/347] chase wlroots!4288 References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4288 --- client.h | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/client.h b/client.h index 6a46151..80152cc 100644 --- a/client.h +++ b/client.h @@ -54,7 +54,7 @@ client_surface(Client *c) static inline int toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl) { - struct wlr_xdg_surface *xdg_surface; + struct wlr_xdg_surface *xdg_surface, *tmp_xdg_surface; struct wlr_surface *root_surface; struct wlr_layer_surface_v1 *layer_surface; Client *c = NULL; @@ -82,24 +82,27 @@ toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl) goto end; } - if ((xdg_surface = wlr_xdg_surface_try_from_wlr_surface(root_surface))) { - while (1) { - switch (xdg_surface->role) { - case WLR_XDG_SURFACE_ROLE_POPUP: - if (!xdg_surface->popup->parent) - return -1; - else if (!wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent)) - return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc, pl); - - xdg_surface = wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent); - break; - case WLR_XDG_SURFACE_ROLE_TOPLEVEL: - c = xdg_surface->data; - type = c->type; - goto end; - case WLR_XDG_SURFACE_ROLE_NONE: + xdg_surface = wlr_xdg_surface_try_from_wlr_surface(root_surface); + while (xdg_surface) { + tmp_xdg_surface = NULL; + switch (xdg_surface->role) { + case WLR_XDG_SURFACE_ROLE_POPUP: + if (!xdg_surface->popup || !xdg_surface->popup->parent) return -1; - } + + tmp_xdg_surface = wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent); + + if (!tmp_xdg_surface) + return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc, pl); + + xdg_surface = tmp_xdg_surface; + break; + case WLR_XDG_SURFACE_ROLE_TOPLEVEL: + c = xdg_surface->data; + type = c->type; + goto end; + case WLR_XDG_SURFACE_ROLE_NONE: + return -1; } } From 4eb54b55f36e770a42e9fc6a4701911b6aaac441 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Fri, 21 Jul 2023 20:13:38 -0400 Subject: [PATCH 069/347] No need to send surface.leave/enter events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The scene graph implementation sends these for us, and it does so more accurately than our overly-simplified approach. Layer shell surfaces don't appear to receive these events at all, according to my WAYLAND_DEBUG experiments with bemenu and dtao. ΔSLOC: -4 --- dwl.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/dwl.c b/dwl.c index 655ded0..ddf7cad 100644 --- a/dwl.c +++ b/dwl.c @@ -1525,7 +1525,6 @@ void maplayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *l = wl_container_of(listener, l, map); - wlr_surface_send_enter(l->layer_surface->surface, l->mon->wlr_output); motionnotify(0); } @@ -2091,15 +2090,12 @@ setmon(Client *c, Monitor *m, uint32_t newtags) c->mon = m; c->prev = c->geom; - /* TODO leave/enter is not optimal but works */ - if (oldmon) { - wlr_surface_send_leave(client_surface(c), oldmon->wlr_output); + /* Scene graph sends surface leave/enter events on move and resize */ + if (oldmon) arrange(oldmon); - } if (m) { /* Make sure window actually overlaps with the monitor */ resize(c, c->geom, 0); - wlr_surface_send_enter(client_surface(c), m->wlr_output); c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */ setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ } From d7569870b62233099af65ce6a048e2ec50d92b7b Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Fri, 21 Jul 2023 20:28:12 -0400 Subject: [PATCH 070/347] Style: use early-return to clarify code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use an early return to avoid indenting the main logic instead of wrapping the tail of a function in an if statement. No functional change, except for a handful of places where printstatus() was being called spuriously (tag, toggletag, toggleview). ΔSLOC: 0 --- dwl.c | 96 ++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/dwl.c b/dwl.c index ddf7cad..7f1e471 100644 --- a/dwl.c +++ b/dwl.c @@ -1132,15 +1132,16 @@ destroylocksurface(struct wl_listener *listener, void *data) m->lock_surface = NULL; wl_list_remove(&m->destroy_lock_surface.link); - if (lock_surface->surface == seat->keyboard_state.focused_surface) { - if (locked && cur_lock && !wl_list_empty(&cur_lock->surfaces)) { - surface = wl_container_of(cur_lock->surfaces.next, surface, link); - client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat)); - } else if (!locked) { - focusclient(focustop(selmon), 1); - } else { - wlr_seat_keyboard_clear_focus(seat); - } + if (lock_surface->surface != seat->keyboard_state.focused_surface) + return; + + if (locked && cur_lock && !wl_list_empty(&cur_lock->surfaces)) { + surface = wl_container_of(cur_lock->surfaces.next, surface, link); + client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat)); + } else if (!locked) { + focusclient(focustop(selmon), 1); + } else { + wlr_seat_keyboard_clear_focus(seat); } } @@ -1446,12 +1447,13 @@ keypress(struct wl_listener *listener, void *data) wl_event_source_timer_update(kb->key_repeat_source, 0); } - if (!handled) { - /* Pass unhandled keycodes along to the client. */ - wlr_seat_set_keyboard(seat, kb->wlr_keyboard); - wlr_seat_keyboard_notify_key(seat, event->time_msec, - event->keycode, event->state); - } + if (handled) + return; + + /* Pass unhandled keycodes along to the client. */ + wlr_seat_set_keyboard(seat, kb->wlr_keyboard); + wlr_seat_keyboard_notify_key(seat, event->time_msec, + event->keycode, event->state); } void @@ -1477,13 +1479,14 @@ keyrepeat(void *data) { Keyboard *kb = data; int i; - if (kb->nsyms && kb->wlr_keyboard->repeat_info.rate > 0) { - wl_event_source_timer_update(kb->key_repeat_source, - 1000 / kb->wlr_keyboard->repeat_info.rate); + if (!kb->nsyms || kb->wlr_keyboard->repeat_info.rate <= 0) + return 0; - for (i = 0; i < kb->nsyms; i++) - keybinding(kb->mods, kb->keysyms[i]); - } + wl_event_source_timer_update(kb->key_repeat_source, + 1000 / kb->wlr_keyboard->repeat_info.rate); + + for (i = 0; i < kb->nsyms; i++) + keybinding(kb->mods, kb->keysyms[i]); return 0; } @@ -2332,11 +2335,12 @@ void tag(const Arg *arg) { Client *sel = focustop(selmon); - if (sel && arg->ui & TAGMASK) { - sel->tags = arg->ui & TAGMASK; - focusclient(focustop(selmon), 1); - arrange(selmon); - } + if (!sel || (arg->ui & TAGMASK) == 0) + return; + + sel->tags = arg->ui & TAGMASK; + focusclient(focustop(selmon), 1); + arrange(selmon); printstatus(); } @@ -2406,11 +2410,12 @@ toggletag(const Arg *arg) if (!sel) return; newtags = sel->tags ^ (arg->ui & TAGMASK); - if (newtags) { - sel->tags = newtags; - focusclient(focustop(selmon), 1); - arrange(selmon); - } + if (!newtags) + return; + + sel->tags = newtags; + focusclient(focustop(selmon), 1); + arrange(selmon); printstatus(); } @@ -2419,11 +2424,12 @@ toggleview(const Arg *arg) { uint32_t newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0; - if (newtagset) { - selmon->tagset[selmon->seltags] = newtagset; - focusclient(focustop(selmon), 1); - arrange(selmon); - } + if (!newtagset) + return; + + selmon->tagset[selmon->seltags] = newtagset; + focusclient(focustop(selmon), 1); + arrange(selmon); printstatus(); } @@ -2580,10 +2586,11 @@ urgent(struct wl_listener *listener, void *data) struct wlr_xdg_activation_v1_request_activate_event *event = data; Client *c = NULL; toplevel_from_wlr_surface(event->surface, &c, NULL); - if (c && c != focustop(selmon)) { - c->isurgent = 1; - printstatus(); - } + if (!c || c == focustop(selmon)) + return; + + c->isurgent = 1; + printstatus(); } void @@ -2742,10 +2749,11 @@ void sethints(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, set_hints); - if (c != focustop(selmon)) { - c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints); - printstatus(); - } + if (c == focustop(selmon)) + return; + + c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints); + printstatus(); } void From 4b8c1bf31e9619db58eadf593617ba060d62418d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 22 Aug 2023 14:48:29 -0600 Subject: [PATCH 071/347] return nothing in xytonode() we do not use the node --- dwl.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index 7f1e471..4ff5c37 100644 --- a/dwl.c +++ b/dwl.c @@ -315,7 +315,7 @@ static void urgent(struct wl_listener *listener, void *data); static void view(const Arg *arg); static void virtualkeyboard(struct wl_listener *listener, void *data); static Monitor *xytomon(double x, double y); -static struct wlr_scene_node *xytonode(double x, double y, struct wlr_surface **psurface, +static void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, LayerSurface **pl, double *nx, double *ny); static void zoom(const Arg *arg); @@ -2620,7 +2620,7 @@ xytomon(double x, double y) return o ? o->data : NULL; } -struct wlr_scene_node * +void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, LayerSurface **pl, double *nx, double *ny) { @@ -2649,7 +2649,6 @@ xytonode(double x, double y, struct wlr_surface **psurface, if (psurface) *psurface = surface; if (pc) *pc = c; if (pl) *pl = l; - return node; } void From 9be85c11174e0d3e8e122039142af45f87c1151d Mon Sep 17 00:00:00 2001 From: Ben Collerson Date: Wed, 28 Jun 2023 15:53:15 +1000 Subject: [PATCH 072/347] tagcount should have been a #define --- config.def.h | 4 ++-- dwl.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config.def.h b/config.def.h index 447ba00..d3795fb 100644 --- a/config.def.h +++ b/config.def.h @@ -7,8 +7,8 @@ static const float focuscolor[] = {1.0, 0.0, 0.0, 1.0}; /* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */ static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; -/* tagging - tagcount must be no greater than 31 */ -static const int tagcount = 9; +/* tagging - TAGCOUNT must be no greater than 31 */ +#define TAGCOUNT (9) static const Rule rules[] = { /* app_id title tags mask isfloating monitor */ diff --git a/dwl.c b/dwl.c index 4ff5c37..170fa29 100644 --- a/dwl.c +++ b/dwl.c @@ -67,7 +67,7 @@ #define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) #define LENGTH(X) (sizeof X / sizeof X[0]) #define END(A) ((A) + LENGTH(A)) -#define TAGMASK ((1u << tagcount) - 1) +#define TAGMASK ((1u << TAGCOUNT) - 1) #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) #define IDLE_NOTIFY_ACTIVITY wlr_idle_notify_activity(idle, seat), wlr_idle_notifier_v1_notify_activity(idle_notifier, seat) From e5367753bb90add013ee5d170a110064298ac2c4 Mon Sep 17 00:00:00 2001 From: Ben Collerson Date: Wed, 23 Aug 2023 14:16:24 +1000 Subject: [PATCH 073/347] just add define --- config.def.h | 3 ++- dwl.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/config.def.h b/config.def.h index d3795fb..1677f6f 100644 --- a/config.def.h +++ b/config.def.h @@ -7,8 +7,9 @@ static const float focuscolor[] = {1.0, 0.0, 0.0, 1.0}; /* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */ static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; -/* tagging - TAGCOUNT must be no greater than 31 */ +/* tagging - tagcount must be no greater than 31 */ #define TAGCOUNT (9) +static const int tagcount = TAGCOUNT; static const Rule rules[] = { /* app_id title tags mask isfloating monitor */ diff --git a/dwl.c b/dwl.c index 170fa29..4ff5c37 100644 --- a/dwl.c +++ b/dwl.c @@ -67,7 +67,7 @@ #define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) #define LENGTH(X) (sizeof X / sizeof X[0]) #define END(A) ((A) + LENGTH(A)) -#define TAGMASK ((1u << TAGCOUNT) - 1) +#define TAGMASK ((1u << tagcount) - 1) #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) #define IDLE_NOTIFY_ACTIVITY wlr_idle_notify_activity(idle, seat), wlr_idle_notifier_v1_notify_activity(idle_notifier, seat) From c1d8b77f7fb4f082b7eb43474a788e9b5fe04e29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 23 Aug 2023 00:16:21 -0600 Subject: [PATCH 074/347] prefer IRC over Discord I regularly check the discord server, but it is much more likely that I will be online on IRC, and djpohly does not seem to be active on either. --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 05f149c..1ac5b4b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # dwl - dwm for Wayland -Join us on our [Discord server] or at [#dwl] on irc.libera.chat. +Join us on our IRC channel: [#dwl on Libera Chat] +Or on our [Discord server]. dwl is a compact, hackable compositor for [Wayland] based on [wlroots]. It is intended to fill the same space in the Wayland world that dwm does in X11, @@ -143,7 +144,7 @@ inspiration, and to the various contributors to the project, including: [Discord server]: https://discord.gg/jJxZnrGPWN -[#dwl]: https://web.libera.chat/?channels=#dwl +[#dwl on Libera Chat]: https://web.libera.chat/?channels=#dwl [Wayland]: https://wayland.freedesktop.org/ [wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots/ [wlroots-next branch]: https://github.com/djpohly/dwl/tree/wlroots-next From aea8dd6ae122bdc99e104afe019479d45755f239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 3 Sep 2023 11:44:30 -0600 Subject: [PATCH 075/347] return early if the client doesn't have monitor in setfloating there is still a bug, but for now this prevents a segfault Bug: https://github.com/djpohly/dwl/issues/472 --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index 4ff5c37..edea5b1 100644 --- a/dwl.c +++ b/dwl.c @@ -2026,6 +2026,8 @@ void setfloating(Client *c, int floating) { c->isfloating = floating; + if (!c->mon) + return; wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrFloat : LyrTile]); arrange(c->mon); printstatus(); From 960c32a7d83703a64ec0a363d8a11f3c1c51bf20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 3 Sep 2023 20:39:33 -0600 Subject: [PATCH 076/347] call setfloating in setmon since in the previous commit we may not applying floating in clients this is to make sure we do --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index edea5b1..4118fd8 100644 --- a/dwl.c +++ b/dwl.c @@ -2103,6 +2103,7 @@ setmon(Client *c, Monitor *m, uint32_t newtags) resize(c, c->geom, 0); c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */ setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ + setfloating(c, c->isfloating); } focusclient(focustop(selmon), 1); } From 755fcae2afbed51f38c167bdc56a5437cda8137a Mon Sep 17 00:00:00 2001 From: Angelo Antony <83206032+alterego-blip@users.noreply.github.com> Date: Sun, 10 Sep 2023 21:05:37 +0530 Subject: [PATCH 077/347] fix typo --- dwl.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.1 b/dwl.1 index cae1036..6f164e6 100644 --- a/dwl.1 +++ b/dwl.1 @@ -101,7 +101,7 @@ These environment variables are used by A directory where temporary user files, such as the Wayland socket, are stored. .It Ev XDG_CONFIG_DIR -A directory containung configuration of various programs and +A directory containing configuration of various programs and libraries, including libxkbcommon. .It Ev DISPLAY , WAYLAND_DISPLAY , WAYLAND_SOCKET Tell how to connect to an underlying X11 or Wayland server. From 773bd04764f8407f90bf5bd10d62cd1712594892 Mon Sep 17 00:00:00 2001 From: Weiseguy Date: Fri, 22 Sep 2023 06:50:35 -0500 Subject: [PATCH 078/347] Add desktop entry file --- Makefile | 5 ++++- dwl.desktop | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 dwl.desktop diff --git a/Makefile b/Makefile index ccca079..09c2c53 100644 --- a/Makefile +++ b/Makefile @@ -52,8 +52,11 @@ install: dwl mkdir -p $(DESTDIR)$(MANDIR)/man1 cp -f dwl.1 $(DESTDIR)$(MANDIR)/man1 chmod 644 $(DESTDIR)$(MANDIR)/man1/dwl.1 + mkdir -p $(DESTDIR)$(PREFIX)/share/wayland-sessions + cp -f dwl.desktop $(DESTDIR)$(PREFIX)/share/wayland-sessions/dwl.desktop + chmod 644 $(DESTDIR)$(PREFIX)/share/wayland-sessions/dwl.desktop uninstall: - rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 + rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 $(DESTDIR)$(PREFIX)/share/wayland-sessions/dwl.desktop .SUFFIXES: .c .o .c.o: diff --git a/dwl.desktop b/dwl.desktop new file mode 100644 index 0000000..e1380f7 --- /dev/null +++ b/dwl.desktop @@ -0,0 +1,5 @@ +[Desktop Entry] +Name=dwl +Comment=dwm for Wayland +Exec=dwl +Type=Application From 5baf195523934519d7659ae34ad287ca60a5654c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 24 Sep 2023 11:24:39 -0600 Subject: [PATCH 079/347] allow specify DATADIR (to install desktop file) --- Makefile | 8 ++++---- config.mk | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 09c2c53..ff6e518 100644 --- a/Makefile +++ b/Makefile @@ -52,11 +52,11 @@ install: dwl mkdir -p $(DESTDIR)$(MANDIR)/man1 cp -f dwl.1 $(DESTDIR)$(MANDIR)/man1 chmod 644 $(DESTDIR)$(MANDIR)/man1/dwl.1 - mkdir -p $(DESTDIR)$(PREFIX)/share/wayland-sessions - cp -f dwl.desktop $(DESTDIR)$(PREFIX)/share/wayland-sessions/dwl.desktop - chmod 644 $(DESTDIR)$(PREFIX)/share/wayland-sessions/dwl.desktop + mkdir -p $(DESTDIR)$(DATADIR)/wayland-sessions + cp -f dwl.desktop $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop + chmod 644 $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop uninstall: - rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 $(DESTDIR)$(PREFIX)/share/wayland-sessions/dwl.desktop + rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop .SUFFIXES: .c .o .c.o: diff --git a/config.mk b/config.mk index f50156f..4bc9b9d 100644 --- a/config.mk +++ b/config.mk @@ -6,6 +6,7 @@ PKG_CONFIG = pkg-config # paths PREFIX = /usr/local MANDIR = $(PREFIX)/share/man +DATADIR = $(PREFIX)/share XWAYLAND = XLIBS = From 342850487acf4fc7383429786b9cb05a6a4cdf4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 24 Sep 2023 14:41:13 -0600 Subject: [PATCH 080/347] include dwl.desktop in the tarbal --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ff6e518..5320e42 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ clean: dist: clean mkdir -p dwl-$(VERSION) cp -R LICENSE* Makefile README.md client.h config.def.h\ - config.mk protocols dwl.1 dwl.c util.c util.h\ + config.mk protocols dwl.1 dwl.c util.c util.h dwl.desktop\ dwl-$(VERSION) tar -caf dwl-$(VERSION).tar.gz dwl-$(VERSION) rm -rf dwl-$(VERSION) From aec21eca1fedbb8d924cd3dfaf4503e3c19fc873 Mon Sep 17 00:00:00 2001 From: Forrest Bushstone Date: Fri, 29 Sep 2023 14:45:22 -0400 Subject: [PATCH 081/347] make sure that fullscreen clients are on the correct screen when isfloating is true Bug: https://github.com/djpohly/dwl/issues/487 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 4118fd8..2cedede 100644 --- a/dwl.c +++ b/dwl.c @@ -2102,8 +2102,8 @@ setmon(Client *c, Monitor *m, uint32_t newtags) /* Make sure window actually overlaps with the monitor */ resize(c, c->geom, 0); c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */ - setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ setfloating(c, c->isfloating); + setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ } focusclient(focustop(selmon), 1); } From f695674361d15a312eed2234e8d21a5e03719559 Mon Sep 17 00:00:00 2001 From: Forrest Bushstone Date: Fri, 29 Sep 2023 18:16:42 -0400 Subject: [PATCH 082/347] Check if c is fullscreen before reparenting it to LyrFloating Closes: https://github.com/djpohly/dwl/issues/487 --- dwl.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index 2cedede..b51614d 100644 --- a/dwl.c +++ b/dwl.c @@ -2028,7 +2028,8 @@ setfloating(Client *c, int floating) c->isfloating = floating; if (!c->mon) return; - wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrFloat : LyrTile]); + wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen + ? LyrFS : c->isfloating ? LyrFloat : LyrTile]); arrange(c->mon); printstatus(); } @@ -2041,7 +2042,7 @@ setfullscreen(Client *c, int fullscreen) return; c->bw = fullscreen ? 0 : borderpx; client_set_fullscreen(c, fullscreen); - wlr_scene_node_reparent(&c->scene->node, layers[fullscreen + wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ? LyrFS : c->isfloating ? LyrFloat : LyrTile]); if (fullscreen) { @@ -2102,8 +2103,8 @@ setmon(Client *c, Monitor *m, uint32_t newtags) /* Make sure window actually overlaps with the monitor */ resize(c, c->geom, 0); c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */ - setfloating(c, c->isfloating); setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ + setfloating(c, c->isfloating); } focusclient(focustop(selmon), 1); } From 0ab1ed6530a3891cbf1d9d2943b20f386e0e4a98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 5 Oct 2023 22:03:59 -0600 Subject: [PATCH 083/347] add macro to configure colors Closes: https://github.com/djpohly/dwl/issues/466 --- config.def.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/config.def.h b/config.def.h index 1677f6f..9e0c293 100644 --- a/config.def.h +++ b/config.def.h @@ -1,11 +1,15 @@ +#define COLOR(hex) { ((hex >> 24) & 0xFF) / 255.0f, \ + ((hex >> 16) & 0xFF) / 255.0f, \ + ((hex >> 8) & 0xFF) / 255.0f, \ + (hex & 0xFF) / 255.0f } /* appearance */ static const int sloppyfocus = 1; /* focus follows mouse */ static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */ static const unsigned int borderpx = 1; /* border pixel of windows */ -static const float bordercolor[] = {0.5, 0.5, 0.5, 1.0}; -static const float focuscolor[] = {1.0, 0.0, 0.0, 1.0}; +static const float bordercolor[] = COLOR(0x808080ff); +static const float focuscolor[] = COLOR(0xff0000ff); /* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */ -static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; +static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; /* You can also use glsl colors */ /* tagging - tagcount must be no greater than 31 */ #define TAGCOUNT (9) From f4031590cd506f7afe5aa62ae58b9ef4bac99af5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 5 Oct 2023 22:06:30 -0600 Subject: [PATCH 084/347] add missing url about the COLOR macro --- config.def.h | 1 + 1 file changed, 1 insertion(+) diff --git a/config.def.h b/config.def.h index 9e0c293..0a08aea 100644 --- a/config.def.h +++ b/config.def.h @@ -1,3 +1,4 @@ +/* Taken from https://github.com/djpohly/dwl/issues/466 */ #define COLOR(hex) { ((hex >> 24) & 0xFF) / 255.0f, \ ((hex >> 16) & 0xFF) / 255.0f, \ ((hex >> 8) & 0xFF) / 255.0f, \ From d63f4078c51c484a47b1c463912dc6038e787426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 5 Oct 2023 22:09:08 -0600 Subject: [PATCH 085/347] use the same border colors as dwm --- config.def.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.def.h b/config.def.h index 0a08aea..f4c3cae 100644 --- a/config.def.h +++ b/config.def.h @@ -7,8 +7,8 @@ static const int sloppyfocus = 1; /* focus follows mouse */ static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */ static const unsigned int borderpx = 1; /* border pixel of windows */ -static const float bordercolor[] = COLOR(0x808080ff); -static const float focuscolor[] = COLOR(0xff0000ff); +static const float bordercolor[] = COLOR(0x444444ff); +static const float focuscolor[] = COLOR(0x005577ff); /* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */ static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; /* You can also use glsl colors */ From 72a7d78a1a7926a207539eb50f44b2e1eb089d49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 5 Oct 2023 22:13:56 -0600 Subject: [PATCH 086/347] make the borders red borders for urgent clients iirc this is the same behavior of dwm --- config.def.h | 1 + dwl.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/config.def.h b/config.def.h index f4c3cae..895284f 100644 --- a/config.def.h +++ b/config.def.h @@ -9,6 +9,7 @@ static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will static const unsigned int borderpx = 1; /* border pixel of windows */ static const float bordercolor[] = COLOR(0x444444ff); static const float focuscolor[] = COLOR(0x005577ff); +static const float urgentcolor[] = COLOR(0xff0000ff); /* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */ static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; /* You can also use glsl colors */ diff --git a/dwl.c b/dwl.c index b51614d..87f0636 100644 --- a/dwl.c +++ b/dwl.c @@ -2589,10 +2589,14 @@ urgent(struct wl_listener *listener, void *data) { struct wlr_xdg_activation_v1_request_activate_event *event = data; Client *c = NULL; + int i; toplevel_from_wlr_surface(event->surface, &c, NULL); if (!c || c == focustop(selmon)) return; + for (i = 0; i < 4; i++) + wlr_scene_rect_set_color(c->border[i], urgentcolor); + c->isurgent = 1; printstatus(); } @@ -2752,9 +2756,13 @@ void sethints(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, set_hints); + int i; if (c == focustop(selmon)) return; + for (i = 0; i < 4; i++) + wlr_scene_rect_set_color(c->border[i], urgentcolor); + c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints); printstatus(); } From a18c52830010675cc794984c86db6c39776f914a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 5 Oct 2023 22:20:08 -0600 Subject: [PATCH 087/347] simplify setting the border color of clients --- client.h | 8 ++++++++ dwl.c | 18 +++++------------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/client.h b/client.h index 5a45edc..cf1ed85 100644 --- a/client.h +++ b/client.h @@ -323,6 +323,14 @@ client_send_close(Client *c) wlr_xdg_toplevel_send_close(c->surface.xdg->toplevel); } +static inline void +client_set_border_color(Client *c, const float color[static 4]) +{ + int i; + for (i = 0; i < 4; i++) + wlr_scene_rect_set_color(c->border[i], color); +} + static inline void client_set_fullscreen(Client *c, int fullscreen) { diff --git a/dwl.c b/dwl.c index 87f0636..33b370c 100644 --- a/dwl.c +++ b/dwl.c @@ -1199,7 +1199,7 @@ void focusclient(Client *c, int lift) { struct wlr_surface *old = seat->keyboard_state.focused_surface; - int i, unused_lx, unused_ly, old_client_type; + int unused_lx, unused_ly, old_client_type; Client *old_c = NULL; LayerSurface *old_l = NULL; @@ -1230,8 +1230,7 @@ focusclient(Client *c, int lift) /* Don't change border color if there is an exclusive focus or we are * handling a drag operation */ if (!exclusive_focus && !seat->drag) - for (i = 0; i < 4; i++) - wlr_scene_rect_set_color(c->border[i], focuscolor); + client_set_border_color(c, focuscolor); } /* Deactivate old client if focus is changing */ @@ -1248,8 +1247,7 @@ focusclient(Client *c, int lift) /* Don't deactivate old client if the new one wants focus, as this causes issues with winecfg * and probably other clients */ } else if (old_c && !client_is_unmanaged(old_c) && (!c || !client_wants_focus(c))) { - for (i = 0; i < 4; i++) - wlr_scene_rect_set_color(old_c->border[i], bordercolor); + client_set_border_color(old_c, bordercolor); client_activate_surface(old, 0); } @@ -2589,14 +2587,11 @@ urgent(struct wl_listener *listener, void *data) { struct wlr_xdg_activation_v1_request_activate_event *event = data; Client *c = NULL; - int i; toplevel_from_wlr_surface(event->surface, &c, NULL); if (!c || c == focustop(selmon)) return; - for (i = 0; i < 4; i++) - wlr_scene_rect_set_color(c->border[i], urgentcolor); - + client_set_border_color(c, urgentcolor); c->isurgent = 1; printstatus(); } @@ -2756,13 +2751,10 @@ void sethints(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, set_hints); - int i; if (c == focustop(selmon)) return; - for (i = 0; i < 4; i++) - wlr_scene_rect_set_color(c->border[i], urgentcolor); - + client_set_border_color(c, urgentcolor); c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints); printstatus(); } From 935b852dc5b7e042f3eaf446e69048631b8101be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 9 Oct 2023 10:56:05 -0600 Subject: [PATCH 088/347] add [-d] flag to enable debug logging --- config.def.h | 3 +++ dwl.1 | 7 +++++++ dwl.c | 8 ++++++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/config.def.h b/config.def.h index 895284f..9365505 100644 --- a/config.def.h +++ b/config.def.h @@ -17,6 +17,9 @@ static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; /* You can al #define TAGCOUNT (9) static const int tagcount = TAGCOUNT; +/* logging */ +static int log_level = WLR_ERROR; + static const Rule rules[] = { /* app_id title tags mask isfloating monitor */ /* examples: diff --git a/dwl.1 b/dwl.1 index 6f164e6..ce1acf9 100644 --- a/dwl.1 +++ b/dwl.1 @@ -7,6 +7,7 @@ .Sh SYNOPSIS .Nm .Op Fl v +.Op Fl d .Op Fl s Ar startup command .Sh DESCRIPTION .Nm @@ -22,6 +23,12 @@ option, writes its name and version to standard error and exits unsuccessfully. .Pp When given the +.Fl d +option, +.Nm +enables full wlroots logging, including debug information. +.Pp +When given the .Fl s option, .Nm diff --git a/dwl.c b/dwl.c index 33b370c..7fe1559 100644 --- a/dwl.c +++ b/dwl.c @@ -2139,6 +2139,8 @@ setup(void) for (i = 0; i < LENGTH(sig); i++) sigaction(sig[i], &sa, NULL); + wlr_log_init(log_level, NULL); + /* The Wayland display is managed by libwayland. It handles accepting * clients from the Unix socket, manging Wayland globals, and so on. */ dpy = wl_display_create(); @@ -2797,9 +2799,11 @@ main(int argc, char *argv[]) char *startup_cmd = NULL; int c; - while ((c = getopt(argc, argv, "s:hv")) != -1) { + while ((c = getopt(argc, argv, "s:hdv")) != -1) { if (c == 's') startup_cmd = optarg; + else if (c == 'd') + log_level = WLR_DEBUG; else if (c == 'v') die("dwl " VERSION); else @@ -2817,5 +2821,5 @@ main(int argc, char *argv[]) return EXIT_SUCCESS; usage: - die("Usage: %s [-v] [-s startup command]", argv[0]); + die("Usage: %s [-v] [-d] [-s startup command]", argv[0]); } From 6d9a915fb60d38ebf0ae897fbd6affde39ed8d77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 9 Oct 2023 11:12:24 -0600 Subject: [PATCH 089/347] Revert "just add define" I'm going to make some changes in the config file anyway This reverts commit e5367753bb90add013ee5d170a110064298ac2c4. --- config.def.h | 3 +-- dwl.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/config.def.h b/config.def.h index 9365505..4e30885 100644 --- a/config.def.h +++ b/config.def.h @@ -13,9 +13,8 @@ static const float urgentcolor[] = COLOR(0xff0000ff); /* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */ static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; /* You can also use glsl colors */ -/* tagging - tagcount must be no greater than 31 */ +/* tagging - TAGCOUNT must be no greater than 31 */ #define TAGCOUNT (9) -static const int tagcount = TAGCOUNT; /* logging */ static int log_level = WLR_ERROR; diff --git a/dwl.c b/dwl.c index 7fe1559..e07560e 100644 --- a/dwl.c +++ b/dwl.c @@ -67,7 +67,7 @@ #define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) #define LENGTH(X) (sizeof X / sizeof X[0]) #define END(A) ((A) + LENGTH(A)) -#define TAGMASK ((1u << tagcount) - 1) +#define TAGMASK ((1u << TAGCOUNT) - 1) #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) #define IDLE_NOTIFY_ACTIVITY wlr_idle_notify_activity(idle, seat), wlr_idle_notifier_v1_notify_activity(idle_notifier, seat) From 887fde65a3010905aa10f373cfcfe540cfc1781e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 9 Oct 2023 22:16:52 -0600 Subject: [PATCH 090/347] only set border color for urgent *and* mapped X11 clients this fixes a segfault when the client emits .set_hints but it's not mapped Fixes: 72a7d78a1a7926a207539eb50f44b2e1eb089d49 --- dwl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index e07560e..edc7337 100644 --- a/dwl.c +++ b/dwl.c @@ -2756,8 +2756,11 @@ sethints(struct wl_listener *listener, void *data) if (c == focustop(selmon)) return; - client_set_border_color(c, urgentcolor); c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints); + + if (c->isurgent && client_is_mapped(c)) + client_set_border_color(c, urgentcolor); + printstatus(); } From df131cdb78c6e3e79c3fafa522f0e4f6b43d2ab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 9 Oct 2023 21:35:49 -0600 Subject: [PATCH 091/347] use instead of --- dwl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index edc7337..4cfa4db 100644 --- a/dwl.c +++ b/dwl.c @@ -54,7 +54,7 @@ #include #ifdef XWAYLAND #include -#include +#include #include #endif @@ -398,13 +398,13 @@ static struct wl_listener session_lock_mgr_destroy = {.notify = destroysessionmg static void activatex11(struct wl_listener *listener, void *data); static void configurex11(struct wl_listener *listener, void *data); static void createnotifyx11(struct wl_listener *listener, void *data); -static Atom getatom(xcb_connection_t *xc, const char *name); +static xcb_atom_t getatom(xcb_connection_t *xc, const char *name); static void sethints(struct wl_listener *listener, void *data); static void xwaylandready(struct wl_listener *listener, void *data); static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11}; static struct wl_listener xwayland_ready = {.notify = xwaylandready}; static struct wlr_xwayland *xwayland; -static Atom netatom[NetLast]; +static xcb_atom_t netatom[NetLast]; #endif /* configuration, allows nested code to access above variables */ @@ -2736,10 +2736,10 @@ createnotifyx11(struct wl_listener *listener, void *data) LISTEN(&xsurface->events.request_fullscreen, &c->fullscreen, fullscreennotify); } -Atom +xcb_atom_t getatom(xcb_connection_t *xc, const char *name) { - Atom atom = 0; + xcb_atom_t atom = 0; xcb_intern_atom_reply_t *reply; xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xc, 0, strlen(name), name); if ((reply = xcb_intern_atom_reply(xc, cookie, NULL))) From 8c79f8dc155ba696572be30ee8c2ddfc577ae418 Mon Sep 17 00:00:00 2001 From: Ben Collerson Date: Tue, 10 Oct 2023 16:42:46 +1000 Subject: [PATCH 092/347] check client is mapped before setting border color For some reason brave configured for as a wayland client triggers this code on startup and segfaults. Checking if the client is mapped fixes this, like with the previous fix for urgent border colour. References: 887fde65a3010905aa10f373cfcfe540cfc1781e Fixes: 72a7d78a1a7926a207539eb50f44b2e1eb089d49 --- dwl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 4cfa4db..a7d41b0 100644 --- a/dwl.c +++ b/dwl.c @@ -2593,7 +2593,8 @@ urgent(struct wl_listener *listener, void *data) if (!c || c == focustop(selmon)) return; - client_set_border_color(c, urgentcolor); + if (client_is_mapped(c)) + client_set_border_color(c, urgentcolor); c->isurgent = 1; printstatus(); } From 7085057f6d75a259a399e6e0e65291804d7ceb18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 11 Oct 2023 19:58:18 -0600 Subject: [PATCH 093/347] update README.md these things were changed in the code but not in the readme --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1ac5b4b..aa4591b 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ given the base on which it is built. Implemented default features are: monitoring - Provide information to external status bars via stdout/stdin - Urgency hints via xdg-activate protocol -- Support screen lockers via input-inhibitor protocol +- Support screen lockers via ext-session-lock-v1 protocol - Various Wayland protocols - XWayland support as provided by wlroots (can be enabled in `config.mk`) - Zero flickering - Wayland users naturally expect that "every frame is perfect" @@ -83,6 +83,7 @@ When dwl is run with no arguments, it will launch the server and begin handling any shortcuts configured in `config.h`. There is no status bar or other decoration initially; these are instead clients that can be run within the Wayland session. +Do note that the background color is black. If you would like to run a script or command automatically at startup, you can specify the command using the `-s` option. This command will be executed as a @@ -106,7 +107,7 @@ automatically, you will need to configure it prior to launching `dwl`, e.g.: ### Status information -Information about selected layouts, current window title, and +Information about selected layouts, current window title, app-id, and selected/occupied/urgent tags is written to the stdin of the `-s` command (see the `printstatus()` function for details). This information can be used to populate an external status bar with a script that parses the information. From ab87410023a139c124bccb2817e567a7fa4fabab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 11 Oct 2023 19:52:26 -0600 Subject: [PATCH 094/347] clarify the dependencies needed by dwl Note that previous df131cdb78c6e3e79c3fafa522f0e4f6b43d2ab4 libX11 headers were also required for building (but not for runtime) Also, I want to apologize to the packagers for do not list *all* the required dependencies before. --- README.md | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index aa4591b..62ae872 100644 --- a/README.md +++ b/README.md @@ -50,14 +50,28 @@ Feature *non-goals* for the main codebase include: ## Building dwl -dwl has only two dependencies: `wlroots` and `wayland-protocols`. +dwl has the following dependencies: +``` +libinput +wayland +wlroots (compiled with the libinput backend) +xkbcommon +wayland-protocols (compile-time only) +pkg-config (compile-time only) +``` +If you enable X11 support: +``` +libxcb +libxcb-wm +wlroots (compiled with X11 support) +Xwayland (runtime only) +``` Simply install these (and their `-devel` versions if your distro has separate development packages) and run `make`. If you wish to build against a Git version of wlroots, check out the [wlroots-next branch]. -To enable XWayland, you should also install xorg-xwayland and uncomment its flag -in `config.mk`. +To enable XWayland, you should uncomment its flags in `config.mk`. ## Configuration From e5e74acfce05502181a0eaa6e252140e1572d925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 1 Nov 2023 12:04:59 -0600 Subject: [PATCH 095/347] send maximized if tiled isn't supported (XDG shell) wlroots doesn't do it automatically anymore References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4409 --- client.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client.h b/client.h index 6fc7c93..b49032e 100644 --- a/client.h +++ b/client.h @@ -354,7 +354,12 @@ client_set_tiled(Client *c, uint32_t edges) if (client_is_x11(c)) return; #endif - wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges); + if (wl_resource_get_version(c->surface.xdg->resource) + >= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) { + wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges); + } else { + wlr_xdg_toplevel_set_maximized(c->surface.xdg->toplevel, edges != 0); + } } static inline void From e45ded7eea0c77db8ff13148a51a910bac13b48a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 1 Nov 2023 12:16:02 -0600 Subject: [PATCH 096/347] ignore maximize events for clients using xdg-shell v5 and newer --- dwl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 6db82d6..cde99fe 100644 --- a/dwl.c +++ b/dwl.c @@ -1587,9 +1587,14 @@ maximizenotify(struct wl_listener *listener, void *data) * typically because the user clicked on the maximize button on * client-side decorations. dwl doesn't support maximization, but * to conform to xdg-shell protocol we still must send a configure. + * Since xdg-shell protocol v5 we should ignore request of unsupported + * capabilities, just schedule a empty configure when the client uses <5 + * protocol version * wlr_xdg_surface_schedule_configure() is used to send an empty reply. */ Client *c = wl_container_of(listener, c, maximize); - wlr_xdg_surface_schedule_configure(c->surface.xdg); + if (wl_resource_get_version(c->surface.xdg->resource) + < XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) + wlr_xdg_surface_schedule_configure(c->surface.xdg); } void From a4a83e95e69afd45ff1770149810d79de39b8467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 1 Nov 2023 12:28:19 -0600 Subject: [PATCH 097/347] use newer cursor naming spec References: https://www.freedesktop.org/wiki/Specifications/cursor-spec/ References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4416 --- dwl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index cde99fe..5d3c63d 100644 --- a/dwl.c +++ b/dwl.c @@ -589,7 +589,7 @@ buttonpress(struct wl_listener *listener, void *data) /* If you released any buttons, we exit interactive move/resize mode. */ /* TODO should reset to the pointer focus's current setcursor */ if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { - wlr_cursor_set_xcursor(cursor, cursor_mgr, "left_ptr"); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); cursor_mode = CurNormal; /* Drop the window off on its new monitor */ selmon = xytomon(cursor->x, cursor->y); @@ -1679,7 +1679,7 @@ motionnotify(uint32_t time) * default. This is what makes the cursor image appear when you move it * off of a client or over its border. */ if (!surface && !seat->drag) - wlr_cursor_set_xcursor(cursor, cursor_mgr, "left_ptr"); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); pointerfocus(c, surface, sx, sy, time); } @@ -1722,7 +1722,7 @@ moveresize(const Arg *arg) wlr_cursor_warp_closest(cursor, NULL, grabc->geom.x + grabc->geom.width, grabc->geom.y + grabc->geom.height); - wlr_cursor_set_xcursor(cursor, cursor_mgr, "bottom_right_corner"); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize"); break; } } @@ -1982,7 +1982,7 @@ run(char *startup_cmd) * initialized, as the image/coordinates are not transformed for the * monitor when displayed here */ wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y); - wlr_cursor_set_xcursor(cursor, cursor_mgr, "left_ptr"); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); /* Run the Wayland event loop. This does not return until you exit the * compositor. Starting the backend rigged up all of the necessary event @@ -2847,7 +2847,7 @@ xwaylandready(struct wl_listener *listener, void *data) wlr_xwayland_set_seat(xwayland, seat); /* Set the default XWayland cursor to match the rest of dwl. */ - if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "left_ptr", 1))) + if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "default", 1))) wlr_xwayland_set_cursor(xwayland, xcursor->images[0]->buffer, xcursor->images[0]->width * 4, xcursor->images[0]->width, xcursor->images[0]->height, From d6fabe3a150d2e464078c3269410d56e8bbeb54f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 5 Oct 2023 21:36:14 -0600 Subject: [PATCH 098/347] add a comment about chvt keybindings Closes: https://github.com/djpohly/dwl/issues/427 --- config.def.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config.def.h b/config.def.h index 4e30885..db0babc 100644 --- a/config.def.h +++ b/config.def.h @@ -154,6 +154,9 @@ static const Key keys[] = { /* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */ { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_Terminate_Server, quit, {0} }, + /* Ctrl-Alt-Fx is used to switch to another VT, if you don't know what a VT is + * do not remove them. + */ #define CHVT(n) { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_XF86Switch_VT_##n, chvt, {.ui = (n)} } CHVT(1), CHVT(2), CHVT(3), CHVT(4), CHVT(5), CHVT(6), CHVT(7), CHVT(8), CHVT(9), CHVT(10), CHVT(11), CHVT(12), From 31bf1cbaf6418a6fb39e41b21cadc5c20826a663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 8 Jul 2023 20:07:27 -0600 Subject: [PATCH 099/347] Revert "respect size hints" This reverts commit 72e0a560d9836c5e8658003f548203bcd722e565. --- client.h | 53 +++++++++++++++++++---------------------------------- dwl.c | 16 +++------------- 2 files changed, 22 insertions(+), 47 deletions(-) diff --git a/client.h b/client.h index b49032e..6a870b4 100644 --- a/client.h +++ b/client.h @@ -16,31 +16,6 @@ client_is_x11(Client *c) #endif } -static inline void -client_get_size_hints(Client *c, struct wlr_box *max, struct wlr_box *min) -{ - struct wlr_xdg_toplevel *toplevel; - struct wlr_xdg_toplevel_state *state; -#ifdef XWAYLAND - if (client_is_x11(c)) { - xcb_size_hints_t *size_hints = c->surface.xwayland->size_hints; - if (size_hints) { - max->width = size_hints->max_width; - max->height = size_hints->max_height; - min->width = size_hints->min_width; - min->height = size_hints->min_height; - } - return; - } -#endif - toplevel = c->surface.xdg->toplevel; - state = &toplevel->current; - max->width = state->max_width; - max->height = state->max_height; - min->width = state->min_width; - min->height = state->min_height; -} - static inline struct wlr_surface * client_surface(Client *c) { @@ -190,7 +165,6 @@ client_get_parent(Client *c) #endif if (c->surface.xdg->toplevel->parent) toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL); - return p; } @@ -207,25 +181,36 @@ client_get_title(Client *c) static inline int client_is_float_type(Client *c) { - struct wlr_box min = {0}, max = {0}; - client_get_size_hints(c, &max, &min); + struct wlr_xdg_toplevel *toplevel; + struct wlr_xdg_toplevel_state state; #ifdef XWAYLAND if (client_is_x11(c)) { struct wlr_xwayland_surface *surface = c->surface.xwayland; + xcb_size_hints_t *size_hints; if (surface->modal) return 1; for (size_t i = 0; i < surface->window_type_len; i++) - if (surface->window_type[i] == netatom[NetWMWindowTypeDialog] - || surface->window_type[i] == netatom[NetWMWindowTypeSplash] - || surface->window_type[i] == netatom[NetWMWindowTypeToolbar] - || surface->window_type[i] == netatom[NetWMWindowTypeUtility]) + if (surface->window_type[i] == netatom[NetWMWindowTypeDialog] || + surface->window_type[i] == netatom[NetWMWindowTypeSplash] || + surface->window_type[i] == netatom[NetWMWindowTypeToolbar] || + surface->window_type[i] == netatom[NetWMWindowTypeUtility]) return 1; + + size_hints = surface->size_hints; + return size_hints && size_hints->min_width > 0 && size_hints->min_height > 0 + && (size_hints->max_width == size_hints->min_width + || size_hints->max_height == size_hints->min_height); } #endif - return ((min.width > 0 || min.height > 0 || max.width > 0 || max.height > 0) - && (min.width == max.width || min.height == max.height)); + + toplevel = c->surface.xdg->toplevel; + state = toplevel->current; + return (state.min_width != 0 && state.min_height != 0 + && (state.min_width == state.max_width + || state.min_height == state.max_height)) + || toplevel->parent; } static inline int diff --git a/dwl.c b/dwl.c index 5d3c63d..b379305 100644 --- a/dwl.c +++ b/dwl.c @@ -399,19 +399,9 @@ static xcb_atom_t netatom[NetLast]; void applybounds(Client *c, struct wlr_box *bbox) { - if (!c->isfullscreen) { - struct wlr_box min = {0}, max = {0}; - client_get_size_hints(c, &max, &min); - /* try to set size hints */ - c->geom.width = MAX(min.width + (2 * (int)c->bw), c->geom.width); - c->geom.height = MAX(min.height + (2 * (int)c->bw), c->geom.height); - /* Some clients set their max size to INT_MAX, which does not violate the - * protocol but it's unnecesary, as they can set their max size to zero. */ - if (max.width > 0 && !(2 * c->bw > INT_MAX - max.width)) /* Checks for overflow */ - c->geom.width = MIN(max.width + (2 * c->bw), c->geom.width); - if (max.height > 0 && !(2 * c->bw > INT_MAX - max.height)) /* Checks for overflow */ - c->geom.height = MIN(max.height + (2 * c->bw), c->geom.height); - } + /* set minimum possible */ + c->geom.width = MAX(1, c->geom.width); + c->geom.height = MAX(1, c->geom.height); if (c->geom.x >= bbox->x + bbox->width) c->geom.x = bbox->x + bbox->width - c->geom.width; From e1f3983bf8a548f0357a92d9023c90aa4c273f64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 8 Jul 2023 20:08:45 -0600 Subject: [PATCH 100/347] use wlr_scene_subsurface_tree_set_clip References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4131 Closes: https://github.com/djpohly/dwl/issues/411 --- client.h | 22 ++++++++++++++++++++++ dwl.c | 3 +++ 2 files changed, 25 insertions(+) diff --git a/client.h b/client.h index 6a870b4..012ba74 100644 --- a/client.h +++ b/client.h @@ -140,6 +140,28 @@ client_get_appid(Client *c) return c->surface.xdg->toplevel->app_id; } +static inline void +client_get_clip(Client *c, struct wlr_box *clip) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) { + *clip = (struct wlr_box){ + .x = 0, + .y = 0, + .width = c->geom.width - c->bw, + .height = c->geom.height - c->bw}; + return; + } +#endif + + *clip = (struct wlr_box){ + .x = c->surface.xdg->pending.geometry.x, + .y = c->surface.xdg->pending.geometry.y, + .width = c->geom.width - c->bw, + .height = c->geom.height - c->bw}; + +} + static inline void client_get_geometry(Client *c, struct wlr_box *geom) { diff --git a/dwl.c b/dwl.c index b379305..00d22e8 100644 --- a/dwl.c +++ b/dwl.c @@ -1909,6 +1909,7 @@ void resize(Client *c, struct wlr_box geo, int interact) { struct wlr_box *bbox = interact ? &sgeom : &c->mon->w; + struct wlr_box clip; client_set_bounds(c, geo.width, geo.height); c->geom = geo; applybounds(c, bbox); @@ -1927,6 +1928,8 @@ resize(Client *c, struct wlr_box geo, int interact) /* this is a no-op if size hasn't changed */ c->resize = client_set_size(c, c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw); + client_get_clip(c, &clip); + wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip); } void From 6f8a3f93749aae35b863946d333043d4779d2b54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Nov 2023 20:58:45 -0600 Subject: [PATCH 101/347] fix screen artifacts when setting gamma the artifacts were caused because we tried to set the gamma right after receiving the event, this resulted in two pending page-flips, which not always play well together. This also seems to fix a screen freeze when turning on a monitor that has gamma. Additionally the current method won't work once [0] is merged [0]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4423 --- dwl.c | 47 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/dwl.c b/dwl.c index 00d22e8..e6d7914 100644 --- a/dwl.c +++ b/dwl.c @@ -194,6 +194,7 @@ struct Monitor { unsigned int sellt; uint32_t tagset[2]; double mfact; + int gamma_lut_changed; int nmaster; char ltsymbol[16]; }; @@ -1870,6 +1871,8 @@ rendermon(struct wl_listener *listener, void *data) * generally at the output's refresh rate (e.g. 60Hz). */ Monitor *m = wl_container_of(listener, m, frame); Client *c; + struct wlr_output_state pending = {0}; + struct wlr_gamma_control_v1 *gamma_control; struct timespec now; /* Render if no XDG clients have an outstanding resize and are visible on @@ -1877,12 +1880,38 @@ rendermon(struct wl_listener *listener, void *data) wl_list_for_each(c, &clients, link) if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && !client_is_stopped(c)) goto skip; + + /* + * HACK: The "correct" way to set the gamma is to commit it together with + * the rest of the state in one go, but to do that we would need to rewrite + * wlr_scene_output_commit() in order to add the gamma to the pending + * state before committing, instead try to commit the gamma in one frame, + * and commit the rest of the state in the next one (or in the same frame if + * the gamma can not be committed). + */ + if (m->gamma_lut_changed) { + gamma_control = wlr_gamma_control_manager_v1_get_control(gamma_control_mgr, m->wlr_output); + m->gamma_lut_changed = 0; + + if (!wlr_gamma_control_v1_apply(gamma_control, &pending)) + goto commit; + + if (!wlr_output_test_state(m->wlr_output, &pending)) { + wlr_gamma_control_v1_send_failed_and_destroy(gamma_control); + goto commit; + } + wlr_output_commit_state(m->wlr_output, &pending); + wlr_output_schedule_frame(m->wlr_output); + } else { +commit: wlr_scene_output_commit(m->scene_output, NULL); + } skip: /* Let clients know a frame has been rendered */ clock_gettime(CLOCK_MONOTONIC, &now); wlr_scene_output_send_frame_done(m->scene_output, &now); + wlr_output_state_finish(&pending); } void @@ -2057,21 +2086,9 @@ void setgamma(struct wl_listener *listener, void *data) { struct wlr_gamma_control_manager_v1_set_gamma_event *event = data; - struct wlr_output_state state; - wlr_output_state_init(&state); - if (!wlr_gamma_control_v1_apply(event->control, &state)) { - wlr_output_state_finish(&state); - return; - } - - if (!wlr_output_test_state(event->output, &state)) { - wlr_gamma_control_v1_send_failed_and_destroy(event->control); - wlr_output_state_finish(&state); - return; - } - - wlr_output_commit_state(event->output, &state); - wlr_output_schedule_frame(event->output); + Monitor *m = event->output->data; + m->gamma_lut_changed = 1; + wlr_output_schedule_frame(m->wlr_output); } void From 2212363225510d11988f5ddc49bf9454f4455fe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Nov 2023 20:47:29 -0600 Subject: [PATCH 102/347] make sure fullscreen clients have the right size --- dwl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dwl.c b/dwl.c index e6d7914..eca0860 100644 --- a/dwl.c +++ b/dwl.c @@ -2604,6 +2604,9 @@ updatemons(struct wl_listener *listener, void *data) arrangelayers(m); /* Don't move clients to the left output when plugging monitors */ arrange(m); + /* make sure fullscreen clients have the right size */ + if ((c = focustop(m)) && c->isfullscreen) + resize(c, m->m, 0); config_head->state.enabled = 1; config_head->state.mode = m->wlr_output->current_mode; From 8e3f5364d366fcabc16e142fbb09b0d9c376f3f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Nov 2023 20:47:59 -0600 Subject: [PATCH 103/347] do not compute layout box twice --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index eca0860..37dc27f 100644 --- a/dwl.c +++ b/dwl.c @@ -2586,8 +2586,8 @@ updatemons(struct wl_listener *listener, void *data) config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output); /* Get the effective monitor geometry to use for surfaces */ - wlr_output_layout_get_box(output_layout, m->wlr_output, &(m->m)); - wlr_output_layout_get_box(output_layout, m->wlr_output, &(m->w)); + wlr_output_layout_get_box(output_layout, m->wlr_output, &m->m); + m->w = m->m; wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y); wlr_scene_node_set_position(&m->fullscreen_bg->node, m->m.x, m->m.y); From 4f4c540bb9ec47c77ff30e1a7ddd7d00d63c67b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Nov 2023 21:00:16 -0600 Subject: [PATCH 104/347] prevent a use-after-free at exit --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index 37dc27f..82b7248 100644 --- a/dwl.c +++ b/dwl.c @@ -627,6 +627,7 @@ cleanup(void) { #ifdef XWAYLAND wlr_xwayland_destroy(xwayland); + xwayland = NULL; #endif wl_display_destroy_clients(dpy); if (child_pid > 0) { From 6d0ec595d3f3ba6977ea117681861713fbc1de5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Nov 2023 21:12:50 -0600 Subject: [PATCH 105/347] simplify client_get_clip the clips for xwayland and xdg clients are pretty similar, after all we only need to adjust x and y for xdg clients --- client.h | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/client.h b/client.h index 012ba74..2ffb92c 100644 --- a/client.h +++ b/client.h @@ -143,23 +143,22 @@ client_get_appid(Client *c) static inline void client_get_clip(Client *c, struct wlr_box *clip) { + struct wlr_box xdg_geom = {0}; + *clip = (struct wlr_box){ + .x = 0, + .y = 0, + .width = c->geom.width - c->bw, + .height = c->geom.height - c->bw, + }; + #ifdef XWAYLAND - if (client_is_x11(c)) { - *clip = (struct wlr_box){ - .x = 0, - .y = 0, - .width = c->geom.width - c->bw, - .height = c->geom.height - c->bw}; + if (client_is_x11(c)) return; - } #endif - *clip = (struct wlr_box){ - .x = c->surface.xdg->pending.geometry.x, - .y = c->surface.xdg->pending.geometry.y, - .width = c->geom.width - c->bw, - .height = c->geom.height - c->bw}; - + wlr_xdg_surface_get_geometry(c->surface.xdg, &xdg_geom); + clip->x = xdg_geom.x; + clip->y = xdg_geom.y; } static inline void From 0e897608a151da10f4ddcd2a528c618e5f60d9cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Nov 2023 21:17:39 -0600 Subject: [PATCH 106/347] do not use magical numbers to check edges the interface is declared stable, which means we could just use 0 anyway --- client.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.h b/client.h index 2ffb92c..0fdd774 100644 --- a/client.h +++ b/client.h @@ -364,7 +364,7 @@ client_set_tiled(Client *c, uint32_t edges) >= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) { wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges); } else { - wlr_xdg_toplevel_set_maximized(c->surface.xdg->toplevel, edges != 0); + wlr_xdg_toplevel_set_maximized(c->surface.xdg->toplevel, edges != WLR_EDGE_NONE); } } From d6c102d9db2a2f3dc9d1da96d87e306129237a8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Nov 2023 21:21:40 -0600 Subject: [PATCH 107/347] correctly check if the scene node is enabled in client_is_rendered_on_mon --- client.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client.h b/client.h index 0fdd774..a5bec71 100644 --- a/client.h +++ b/client.h @@ -241,7 +241,8 @@ client_is_rendered_on_mon(Client *c, Monitor *m) * but rather actual displaying of the pixels. * Usually VISIBLEON suffices and is also faster. */ struct wlr_surface_output *s; - if (!c->scene->node.enabled) + int unused_lx, unused_ly; + if (!wlr_scene_node_coords(&c->scene->node, &unused_lx, &unused_ly)) return 0; wl_list_for_each(s, &client_surface(c)->current_outputs, link) if (s->output == m->wlr_output) From 22d21676b016a03fe3f2d988618d0c2acca48de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Nov 2023 21:27:49 -0600 Subject: [PATCH 108/347] style fixes in client_is_float_type --- client.h | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/client.h b/client.h index a5bec71..7d9ff8c 100644 --- a/client.h +++ b/client.h @@ -208,18 +208,18 @@ client_is_float_type(Client *c) #ifdef XWAYLAND if (client_is_x11(c)) { struct wlr_xwayland_surface *surface = c->surface.xwayland; - xcb_size_hints_t *size_hints; + xcb_size_hints_t *size_hints = surface->size_hints; + size_t i; if (surface->modal) return 1; - for (size_t i = 0; i < surface->window_type_len; i++) - if (surface->window_type[i] == netatom[NetWMWindowTypeDialog] || - surface->window_type[i] == netatom[NetWMWindowTypeSplash] || - surface->window_type[i] == netatom[NetWMWindowTypeToolbar] || - surface->window_type[i] == netatom[NetWMWindowTypeUtility]) + for (i = 0; i < surface->window_type_len; i++) + if (surface->window_type[i] == netatom[NetWMWindowTypeDialog] + || surface->window_type[i] == netatom[NetWMWindowTypeSplash] + || surface->window_type[i] == netatom[NetWMWindowTypeToolbar] + || surface->window_type[i] == netatom[NetWMWindowTypeUtility]) return 1; - size_hints = surface->size_hints; return size_hints && size_hints->min_width > 0 && size_hints->min_height > 0 && (size_hints->max_width == size_hints->min_width || size_hints->max_height == size_hints->min_height); @@ -228,10 +228,9 @@ client_is_float_type(Client *c) toplevel = c->surface.xdg->toplevel; state = toplevel->current; - return (state.min_width != 0 && state.min_height != 0 + return toplevel->parent || (state.min_width != 0 && state.min_height != 0 && (state.min_width == state.max_width - || state.min_height == state.max_height)) - || toplevel->parent; + || state.min_height == state.max_height)); } static inline int From 0067c76caba464c0636183a8318fee6d63cd2b35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Nov 2023 21:43:31 -0600 Subject: [PATCH 109/347] delete unused functions --- client.h | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/client.h b/client.h index 7d9ff8c..186c23d 100644 --- a/client.h +++ b/client.h @@ -119,17 +119,6 @@ client_set_bounds(Client *c, int32_t width, int32_t height) return 0; } -static inline void -client_for_each_surface(Client *c, wlr_surface_iterator_func_t fn, void *data) -{ - wlr_surface_for_each_surface(client_surface(c), fn, data); -#ifdef XWAYLAND - if (client_is_x11(c)) - return; -#endif - wlr_xdg_surface_for_each_popup_surface(c->surface.xdg, fn, data); -} - static inline const char * client_get_appid(Client *c) { @@ -381,17 +370,6 @@ client_set_suspended(Client *c, int suspended) wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended); } -static inline struct wlr_surface * -client_surface_at(Client *c, double cx, double cy, double *sx, double *sy) -{ -#ifdef XWAYLAND - if (client_is_x11(c)) - return wlr_surface_surface_at(c->surface.xwayland->surface, - cx, cy, sx, sy); -#endif - return wlr_xdg_surface_surface_at(c->surface.xdg, cx, cy, sx, sy); -} - static inline int client_wants_focus(Client *c) { From b1740056d5e9f81888fc9cb3e016bdb8eff054c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Nov 2023 21:45:08 -0600 Subject: [PATCH 110/347] do not use #ifdef -> #else -> #endif in client_is_x11 all other funcions use #ifdef -> #endif --- client.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client.h b/client.h index 186c23d..efb3e0d 100644 --- a/client.h +++ b/client.h @@ -11,9 +11,8 @@ client_is_x11(Client *c) { #ifdef XWAYLAND return c->type == X11Managed || c->type == X11Unmanaged; -#else - return 0; #endif + return 0; } static inline struct wlr_surface * From caac2d664db998beddeeececd7253a11a665c162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Nov 2023 21:46:46 -0600 Subject: [PATCH 111/347] explicitly return -1 in the first check in toplevel_from_wlr_surface --- client.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.h b/client.h index efb3e0d..9a9f0e0 100644 --- a/client.h +++ b/client.h @@ -39,7 +39,7 @@ toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl) #endif if (!s) - return type; + return -1; root_surface = wlr_surface_get_root_surface(s); #ifdef XWAYLAND From dd25cdb56e00586281b6d8e79f3af91db2f747ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Nov 2023 21:47:29 -0600 Subject: [PATCH 112/347] use the new wlroots function to get a toplevel from a wlr_surface References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4419 --- client.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/client.h b/client.h index 9a9f0e0..7a77df0 100644 --- a/client.h +++ b/client.h @@ -92,7 +92,7 @@ end: static inline void client_activate_surface(struct wlr_surface *s, int activated) { - struct wlr_xdg_surface *surface; + struct wlr_xdg_toplevel *toplevel; #ifdef XWAYLAND struct wlr_xwayland_surface *xsurface; if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(s))) { @@ -100,9 +100,8 @@ client_activate_surface(struct wlr_surface *s, int activated) return; } #endif - if ((surface = wlr_xdg_surface_try_from_wlr_surface(s)) - && surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) - wlr_xdg_toplevel_set_activated(surface->toplevel, activated); + if ((toplevel = wlr_xdg_toplevel_try_from_wlr_surface(s))) + wlr_xdg_toplevel_set_activated(toplevel, activated); } static inline uint32_t From 7bdbab04000c23638afeb8dbeddd628c4f15117c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Nov 2023 21:48:56 -0600 Subject: [PATCH 113/347] check toplevel resource instead of client's xdg_shell to set bounds --- client.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.h b/client.h index 7a77df0..b0f2900 100644 --- a/client.h +++ b/client.h @@ -111,7 +111,7 @@ client_set_bounds(Client *c, int32_t width, int32_t height) if (client_is_x11(c)) return 0; #endif - if (c->surface.xdg->client->shell->version >= + if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >= XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION && width >= 0 && height >= 0) return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height); return 0; From bca1b779aae29437e920e64562da14eff3bc80c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Nov 2023 22:23:26 -0600 Subject: [PATCH 114/347] fix destroynotify() docs References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4421 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 82b7248..b6f9389 100644 --- a/dwl.c +++ b/dwl.c @@ -1122,7 +1122,7 @@ destroylocksurface(struct wl_listener *listener, void *data) void destroynotify(struct wl_listener *listener, void *data) { - /* Called when the surface is destroyed and should never be shown again. */ + /* Called when the xdg_toplevel is destroyed. */ Client *c = wl_container_of(listener, c, destroy); wl_list_remove(&c->destroy.link); wl_list_remove(&c->set_title.link); From e95f14541a55c6e71881faebd1a7197b6d9bf20a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Nov 2023 23:05:18 -0600 Subject: [PATCH 115/347] fix docs copied from tinywl --- dwl.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/dwl.c b/dwl.c index b6f9389..3fcdf07 100644 --- a/dwl.c +++ b/dwl.c @@ -2185,11 +2185,7 @@ setup(void) /* The backend is a wlroots feature which abstracts the underlying input and * output hardware. The autocreate option will choose the most suitable * backend based on the current environment, such as opening an X11 window - * if an X11 server is running. The NULL argument here optionally allows you - * to pass in a custom renderer if wlr_renderer doesn't meet your needs. The - * backend uses the renderer, for example, to fall back to software cursors - * if the backend does not support hardware cursors (some older GPUs - * don't). */ + * if an X11 server is running. */ if (!(backend = wlr_backend_autocreate(dpy, &session))) die("couldn't create backend"); @@ -2200,7 +2196,10 @@ setup(void) drag_icon = wlr_scene_tree_create(&scene->tree); wlr_scene_node_place_below(&drag_icon->node, &layers[LyrBlock]->node); - /* Create a renderer with the default implementation */ + /* Autocreates a renderer, either Pixman, GLES2 or Vulkan for us. The user + * can also specify a renderer using the WLR_RENDERER env var. + * The renderer is responsible for defining the various pixel formats it + * supports for shared memory, this configures that for clients. */ if (!(drw = wlr_renderer_autocreate(backend))) die("couldn't create renderer"); @@ -2217,7 +2216,10 @@ setup(void) wlr_linux_dmabuf_v1_create_with_renderer(dpy, 4, drw)); } - /* Create a default allocator */ + /* Autocreates an allocator for us. + * The allocator is the bridge between the renderer and the backend. It + * handles the buffer creation, allowing wlroots to render onto the + * screen */ if (!(alloc = wlr_allocator_autocreate(backend, drw))) die("couldn't create allocator"); @@ -2228,15 +2230,15 @@ setup(void) * the clients cannot set the selection directly without compositor approval, * see the setsel() function. */ compositor = wlr_compositor_create(dpy, 6, drw); + wlr_subcompositor_create(dpy); + wlr_data_device_manager_create(dpy); wlr_export_dmabuf_manager_v1_create(dpy); wlr_screencopy_manager_v1_create(dpy); wlr_data_control_manager_v1_create(dpy); - wlr_data_device_manager_create(dpy); wlr_primary_selection_v1_device_manager_create(dpy); wlr_viewporter_create(dpy); wlr_single_pixel_buffer_manager_v1_create(dpy); wlr_fractional_scale_manager_v1_create(dpy, 1); - wlr_subcompositor_create(dpy); /* Initializes the interface used to implement urgency hints */ activation = wlr_xdg_activation_v1_create(dpy); @@ -2256,7 +2258,7 @@ setup(void) wl_list_init(&mons); LISTEN_STATIC(&backend->events.new_output, createmon); - /* Set up our client lists and the xdg-shell. The xdg-shell is a + /* Set up our client lists, the xdg-shell and the layer-shell. The xdg-shell is a * Wayland protocol which is used for application windows. For more * detail on shells, refer to the article: * @@ -2265,16 +2267,16 @@ setup(void) wl_list_init(&clients); wl_list_init(&fstack); - idle_notifier = wlr_idle_notifier_v1_create(dpy); - - idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); - LISTEN_STATIC(&idle_inhibit_mgr->events.new_inhibitor, createidleinhibitor); + xdg_shell = wlr_xdg_shell_create(dpy, 6); + LISTEN_STATIC(&xdg_shell->events.new_surface, createnotify); layer_shell = wlr_layer_shell_v1_create(dpy, 3); LISTEN_STATIC(&layer_shell->events.new_surface, createlayersurface); - xdg_shell = wlr_xdg_shell_create(dpy, 6); - LISTEN_STATIC(&xdg_shell->events.new_surface, createnotify); + idle_notifier = wlr_idle_notifier_v1_create(dpy); + + idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); + LISTEN_STATIC(&idle_inhibit_mgr->events.new_inhibitor, createidleinhibitor); session_lock_mgr = wlr_session_lock_manager_v1_create(dpy); wl_signal_add(&session_lock_mgr->events.new_lock, &lock_listener); @@ -2309,9 +2311,7 @@ setup(void) * when the pointer moves. However, we can attach input devices to it, and * it will generate aggregate events for all of them. In these events, we * can choose how we want to process them, forwarding them to clients and - * moving the cursor around. More detail on this process is described in my - * input handling blog post: - * + * moving the cursor around. More detail on this process is described in * https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html * * And more comments are sprinkled throughout the notify functions above. From 7611dc91d7f5211071fe1ecca3179a9ca6be9f2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Nov 2023 23:06:21 -0600 Subject: [PATCH 116/347] enable debug symbols by default they does not affect performance and the size's increase is negligible --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d7082fd..6cde460 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ include config.mk # flags for compiling DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XWAYLAND) -DWLDEVCFLAGS = -pedantic -Wall -Wextra -Wdeclaration-after-statement -Wno-unused-parameter -Wno-sign-compare -Wshadow -Wunused-macros\ +DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement -Wno-unused-parameter -Wno-sign-compare -Wshadow -Wunused-macros\ -Werror=strict-prototypes -Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types # CFLAGS / LDFLAGS From 6bcd5d8d87a972f72e23f37b94cc59d77d76c4cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Nov 2023 23:23:08 -0600 Subject: [PATCH 117/347] do not explicitly destroy some wlroots interfaces they are destroyed when the wayland display is destroyed --- dwl.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/dwl.c b/dwl.c index 3fcdf07..5347af6 100644 --- a/dwl.c +++ b/dwl.c @@ -634,15 +634,12 @@ cleanup(void) kill(child_pid, SIGTERM); waitpid(child_pid, NULL, 0); } - wlr_backend_destroy(backend); - wlr_scene_node_destroy(&scene->tree.node); - wlr_renderer_destroy(drw); - wlr_allocator_destroy(alloc); wlr_xcursor_manager_destroy(cursor_mgr); - wlr_cursor_destroy(cursor); wlr_output_layout_destroy(output_layout); - wlr_seat_destroy(seat); wl_display_destroy(dpy); + /* Destroy after the wayland display (when the monitors are already destroyed) + to avoid destroying them with an invalid scene output. */ + wlr_scene_node_destroy(&scene->tree.node); } void From 1044a21555776969d9e3d72bbb2fff2bc0f90eb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Nov 2023 23:29:40 -0600 Subject: [PATCH 118/347] do not check if `session` is non-NULL wlr_session_change_vt() is a no-op if session == NULL --- dwl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 5347af6..443c2c4 100644 --- a/dwl.c +++ b/dwl.c @@ -600,8 +600,7 @@ buttonpress(struct wl_listener *listener, void *data) void chvt(const Arg *arg) { - if (session) - wlr_session_change_vt(session, arg->ui); + wlr_session_change_vt(session, arg->ui); } void From b8e933b9a9bcbdb9c1f07f077d12cfec03cd5b28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 17 Nov 2023 00:11:53 -0600 Subject: [PATCH 119/347] remove unused #include --- dwl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/dwl.c b/dwl.c index 443c2c4..60a2c7c 100644 --- a/dwl.c +++ b/dwl.c @@ -3,7 +3,6 @@ */ #include #include -#include #include #include #include From fcf324be6c661617a835ee504cb160c7d415d2e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 17 Nov 2023 19:03:23 -0600 Subject: [PATCH 120/347] fix the position of the cursor image after turning all the monitors on --- dwl.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dwl.c b/dwl.c index 60a2c7c..11ecc42 100644 --- a/dwl.c +++ b/dwl.c @@ -2622,6 +2622,13 @@ updatemons(struct wl_listener *listener, void *data) } } + /* FIXME: figure out why the cursor image is at 0,0 after turning all + * the monitors on. + * Move the cursor image where it used to be. It does not generate a + * wl_pointer.motion event for the clients, it's only the image what it's + * at the wrong position after all. */ + wlr_cursor_move(cursor, NULL, 0, 0); + wlr_output_manager_v1_set_configuration(output_mgr, config); } From 2751a6195d5b659c8538b2b16fa157e7b920c8c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 18 Nov 2023 11:20:56 -0600 Subject: [PATCH 121/347] do not try to enable adaptive sync --- dwl.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/dwl.c b/dwl.c index 11ecc42..51ada7d 100644 --- a/dwl.c +++ b/dwl.c @@ -903,11 +903,6 @@ createmon(struct wl_listener *listener, void *data) if (!wlr_output_commit(wlr_output)) return; - /* Try to enable adaptive sync, note that not all monitors support it. - * wlr_output_commit() will deactivate it in case it cannot be enabled */ - wlr_output_enable_adaptive_sync(wlr_output, 1); - wlr_output_commit(wlr_output); - wl_list_insert(&mons, &m->link); printstatus(); From b4da97446aafba04ac10062b16f343ac95a81e90 Mon Sep 17 00:00:00 2001 From: link2xt Date: Sun, 19 Nov 2023 06:53:02 +0000 Subject: [PATCH 122/347] createkeyboard: do not segfault if xkb_keymap_new_from_names returns NULL Passing NULL to wlr_keyboard_set_keymap results in a segfault. Example: Thread 1 "dwl" received signal SIGSEGV, Segmentation fault. 0x00007ffff7e49b64 in xkb_keymap_ref () from /usr/lib/libxkbcommon.so.0 (gdb) bt #0 0x00007ffff7e49b64 in xkb_keymap_ref () at /usr/lib/libxkbcommon.so.0 #1 0x00007ffff7f06389 in wlr_keyboard_set_keymap () at /usr/lib/libwlroots.so.11 #2 0x000055555555bc54 in createkeyboard () #3 0x000055555555c283 in inputdevice () #4 0x00007ffff7e8101e in wl_signal_emit_mutable () at /usr/lib/libwayland-server.so.0 #5 0x00007ffff7e8101e in wl_signal_emit_mutable () at /usr/lib/libwayland-server.so.0 #6 0x00007ffff7edb52c in () at /usr/lib/libwlroots.so.11 #7 0x00007ffff7ee44b6 in () at /usr/lib/libwlroots.so.11 #8 0x000055555555fe66 in main () --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index a7d41b0..b78ed02 100644 --- a/dwl.c +++ b/dwl.c @@ -802,6 +802,8 @@ createkeyboard(struct wlr_keyboard *keyboard) context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); keymap = xkb_keymap_new_from_names(context, &xkb_rules, XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) + die("createkeyboard: failed to compile keymap"); wlr_keyboard_set_keymap(keyboard, keymap); xkb_keymap_unref(keymap); From 32e66f45827cc8016ca2cef65ba61840f43fcc85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 21 Nov 2023 19:20:49 -0600 Subject: [PATCH 123/347] resize clients on commit Fixes: https://github.com/djpohly/dwl/issues/515 This reverts commit 4567979b16b0509bb80b6102ecb9b601b3cf6fa1. --- dwl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dwl.c b/dwl.c index 51ada7d..517062a 100644 --- a/dwl.c +++ b/dwl.c @@ -738,6 +738,9 @@ commitnotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, commit); + if (client_surface(c)->mapped) + resize(c, c->geom, (c->isfloating && !c->isfullscreen)); + /* mark a pending resize as completed */ if (c->resize && c->resize <= c->surface.xdg->current.configure_serial) c->resize = 0; From a0e79d81452049aaad2d3081d9c689fb9f4253a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 21 Nov 2023 20:08:20 -0600 Subject: [PATCH 124/347] Do not send repeated xdg_toplevel.configure_bounds Fixes: 32e66f45827cc8016ca2cef65ba61840f43fcc85 --- client.h | 6 +++++- dwl.c | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/client.h b/client.h index b0f2900..71c7d76 100644 --- a/client.h +++ b/client.h @@ -112,8 +112,12 @@ client_set_bounds(Client *c, int32_t width, int32_t height) return 0; #endif if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >= - XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION && width >= 0 && height >= 0) + XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION && width >= 0 && height >= 0 + && (c->bounds.width != width || c->bounds.height != height)) { + c->bounds.width = width; + c->bounds.height = height; return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height); + } return 0; } diff --git a/dwl.c b/dwl.c index 517062a..9e870cc 100644 --- a/dwl.c +++ b/dwl.c @@ -118,6 +118,7 @@ typedef struct { struct wl_listener set_title; struct wl_listener fullscreen; struct wlr_box prev; /* layout-relative, includes border */ + struct wlr_box bounds; #ifdef XWAYLAND struct wl_listener activate; struct wl_listener associate; From d2dd2f49862dfc4c2f7164026e7421bf91d2325e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 21 Nov 2023 20:11:06 -0600 Subject: [PATCH 125/347] ignore wl_surface.commit for xwayland clients This is no longer needed --- dwl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/dwl.c b/dwl.c index 9e870cc..4eac1fd 100644 --- a/dwl.c +++ b/dwl.c @@ -2760,7 +2760,6 @@ associatex11(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, associate); - LISTEN(&client_surface(c)->events.commit, &c->commit, commitnotify); LISTEN(&client_surface(c)->events.map, &c->map, mapnotify); LISTEN(&client_surface(c)->events.unmap, &c->unmap, unmapnotify); } @@ -2806,7 +2805,6 @@ void dissociatex11(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, dissociate); - wl_list_remove(&c->commit.link); wl_list_remove(&c->map.link); wl_list_remove(&c->unmap.link); } From 6838f909bd58e6f9775dcc463566c2c3ad3d4279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 21 Nov 2023 20:38:07 -0600 Subject: [PATCH 126/347] try to apply gamma LUT in updatemons this in the case the output was re-enabled --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 4eac1fd..762f147 100644 --- a/dwl.c +++ b/dwl.c @@ -2567,7 +2567,6 @@ updatemons(struct wl_listener *listener, void *data) if (m->wlr_output->enabled && !wlr_output_layout_get(output_layout, m->wlr_output)) wlr_output_layout_add_auto(output_layout, m->wlr_output); - /* Now that we update the output layout we can get its box */ wlr_output_layout_get_box(output_layout, NULL, &sgeom); @@ -2603,6 +2602,7 @@ updatemons(struct wl_listener *listener, void *data) if ((c = focustop(m)) && c->isfullscreen) resize(c, m->m, 0); + m->gamma_lut_changed = 1; config_head->state.enabled = 1; config_head->state.mode = m->wlr_output->current_mode; config_head->state.x = m->m.x; From 24576f1fdf56bc8879203bb2d7e7cd116d4bba42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 16 Oct 2023 00:33:09 -0600 Subject: [PATCH 127/347] add CHANGELOG.md --- CHANGELOG.md | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..f378693 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,99 @@ +# Changelog + +* [Unreleased](#unreleased) + +## Unreleased +### Added + +* Allow configure x and y position of outputs ([#301][301]) +* Implement repeatable keybindings ([#368][368]) +* Print app id in printstatus() output ([#381][381]) +* Display client count in monocle symbol ([#387][387]) +* Export XCURSOR_SIZE to fix apps using an older version of Qt ([#425][425]) +* Support for wp-fractional-scale-v1 (through wlr_scene: [wlroots!3511][wlroots!3511]) +* dwl now sends `wl_surface.preferred_buffer_scale` (through wlr_scene: [wlroots!4269][wlroots!4269]) +* Add support for xdg-shell v6 ([#465][465]) +* Add support for wp-cursor-shape-v1 ([#444][444]) +* Add desktop file ([#484][484]) +* Add macro to easily configure colors ([#466][466]) +* Color of urgent clients are now red ([#494][494]) +* New flag `-d` and option `log_level` to change the wlroots debug level +* Add CHANGELOG.md ([#501][501]) + +[301]: https://github.com/djpohly/dwl/pull/301 +[368]: https://github.com/djpohly/dwl/pull/368 +[381]: https://github.com/djpohly/dwl/pull/381 +[387]: https://github.com/djpohly/dwl/issues/387 +[425]: https://github.com/djpohly/dwl/pull/425 +[wlroots!4269]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4269 +[wlroots!3511]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3511 +[465]: https://github.com/djpohly/dwl/pull/465 +[444]: https://github.com/djpohly/dwl/pull/444 +[484]: https://github.com/djpohly/dwl/pull/484 +[466]: https://github.com/djpohly/dwl/issues/466 +[494]: https://github.com/djpohly/dwl/pull/494 +[501]: https://github.com/djpohly/dwl/pull/501 + + +### Changed + +* Replace `tags` with `TAGCOUNT` in config.def.h ([#403][403]) +* Pop ups are now destroyed when focusing another client ([#408][408]) +* dwl does not longer respect size hints, instead clip windows if they are + larger than they should be ([#455][455]) +* The version of wlr-layer-shell-unstable-v1 was lowered to 3 (from 4) +* Use the same border color as dwm ([#494][494]) + +[403]: https://github.com/djpohly/dwl/pull/403 +[408]: https://github.com/djpohly/dwl/pull/409 +[455]: https://github.com/djpohly/dwl/pull/455 +[494]: https://github.com/djpohly/dwl/pull/494 + + +### Deprecated +### Removed + +* Remove unused `rootcolor` option ([#401][401]) +* Remove support for wlr-input-inhibitor-unstable-v1 ([#430][430]) +* Remove support for KDE idle protocol ([#431][431]) + +[401]: https://github.com/djpohly/dwl/pull/401 +[430]: https://github.com/djpohly/dwl/pull/430 +[431]: https://github.com/djpohly/dwl/pull/431 + + +### Fixed + +* Fix crash when creating a layer surface with all outputs disabled + ([#421][421]) +* Fix other clients being shown as focused if the focused client have pop ups + open ([#408][408]) +* Resize fullscreen clients when updating monitor mode +* dwl no longer crash at exit like sometimes did +* Fullscreen background appearing above clients ([#487][487]) +* Fix a segfault when user provides invalid xkb_rules ([#518][518]) + +[421]: https://github.com/djpohly/dwl/pull/421 +[408]: https://github.com/djpohly/dwl/issues/408 +[487]: https://github.com/djpohly/dwl/issues/487 +[518]: https://github.com/djpohly/dwl/pull/518 + + +### Security +### Contributors + +* A Frederick Christensen +* Angelo Antony +* Ben Collerson +* Devin J. Pohly +* Forrest Bushstone +* gan-of-culture +* godalming123 +* Job79 +* link2xt +* Micah Gorrell +* Nikita Ivanov +* Palanix +* pino-desktop +* Weiseguy +* Yves Zoundi From f579dd86688c72d701cee70c428e2f2ccceba21c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 25 Nov 2023 00:28:11 -0600 Subject: [PATCH 128/347] bump version to 0.5 --- CHANGELOG.md | 7 +++---- config.mk | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f378693..ac0f3f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,9 @@ # Changelog -* [Unreleased](#unreleased) +* [0.5](#0.5) + +## 0.5 -## Unreleased ### Added * Allow configure x and y position of outputs ([#301][301]) @@ -50,7 +51,6 @@ [494]: https://github.com/djpohly/dwl/pull/494 -### Deprecated ### Removed * Remove unused `rootcolor` option ([#401][401]) @@ -79,7 +79,6 @@ [518]: https://github.com/djpohly/dwl/pull/518 -### Security ### Contributors * A Frederick Christensen diff --git a/config.mk b/config.mk index 4bc9b9d..906f403 100644 --- a/config.mk +++ b/config.mk @@ -1,4 +1,4 @@ -_VERSION = 0.4 +_VERSION = 0.5 VERSION = `git describe --tags --dirty 2>/dev/null || echo $(_VERSION)` PKG_CONFIG = pkg-config From d08e6a3a7e9ccf47720b2e63f298c97292f85ebf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 25 Nov 2023 01:22:48 -0600 Subject: [PATCH 129/347] include CHANGELOG.md in the tarball Fixes: 24576f1fdf56bc8879203bb2d7e7cd116d4bba42 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6cde460..f0ff805 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ clean: dist: clean mkdir -p dwl-$(VERSION) - cp -R LICENSE* Makefile README.md client.h config.def.h\ + cp -R LICENSE* Makefile CHANGELOG.md README.md client.h config.def.h\ config.mk protocols dwl.1 dwl.c util.c util.h dwl.desktop\ dwl-$(VERSION) tar -caf dwl-$(VERSION).tar.gz dwl-$(VERSION) From 66ef4ecfec46eb95cc8db8d9d66502b3578d723c Mon Sep 17 00:00:00 2001 From: Squibid Date: Sat, 25 Nov 2023 03:42:27 -0500 Subject: [PATCH 130/347] Change github links to codeberg links in README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 62ae872..820828f 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Features under consideration (possibly as patches) are: - Protocols made trivial by wlroots - Implement the text-input and input-method protocols to support IME once ibus implements input-method v2 (see https://github.com/ibus/ibus/pull/2256 and - https://github.com/djpohly/dwl/pull/235) + https://codeberg.org/dwl/dwl/pulls/235) Feature *non-goals* for the main codebase include: @@ -162,12 +162,12 @@ inspiration, and to the various contributors to the project, including: [#dwl on Libera Chat]: https://web.libera.chat/?channels=#dwl [Wayland]: https://wayland.freedesktop.org/ [wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots/ -[wlroots-next branch]: https://github.com/djpohly/dwl/tree/wlroots-next -[patches page on our wiki]: https://github.com/djpohly/dwl/wiki/Patches +[wlroots-next branch]: https://codeberg.org/dwl/dwl/src/branch/wlroots-next +[patches page on our wiki]: https://codeberg.org/dwl/dwl/wiki/Patches [s6]: https://skarnet.org/software/s6/ [anopa]: https://jjacky.com/anopa/ [runit]: http://smarden.org/runit/faq.html#userservices [`systemd --user`]: https://wiki.archlinux.org/title/Systemd/User -[wiki]: https://github.com/djpohly/dwl/wiki#compatible-status-bars +[wiki]: https://codeberg.org/dwl/dwl/wiki/Home#compatible-status-bars [list of useful resources on our wiki]: - https://github.com/djpohly/dwl/wiki#migrating-from-x + https://codeberg.org/dwl/dwl/wiki/Home#migrating-from-x From 2783e82bf847e9f3e46f9d09037799a31d12c9ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 25 Nov 2023 18:50:42 -0600 Subject: [PATCH 131/347] make sure to unlink Monitor.request_state listener --- dwl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index ef27a1d..5725bf1 100644 --- a/dwl.c +++ b/dwl.c @@ -661,13 +661,15 @@ cleanupmon(struct wl_listener *listener, void *data) LayerSurface *l, *tmp; int i; - for (i = 0; i <= ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; i++) + /* m->layers[i] are intentionally not unlinked */ + for (i = 0; i < LENGTH(m->layers); i++) wl_list_for_each_safe(l, tmp, &m->layers[i], link) wlr_layer_surface_v1_destroy(l->layer_surface); wl_list_remove(&m->destroy.link); wl_list_remove(&m->frame.link); wl_list_remove(&m->link); + wl_list_remove(&m->request_state.link); m->wlr_output->data = NULL; wlr_output_layout_remove(output_layout, m->wlr_output); wlr_scene_output_destroy(m->scene_output); From 922e117fc5fd03faebd8f23e127fb75d21b83f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 25 Nov 2023 19:04:08 -0600 Subject: [PATCH 132/347] add new 'unreleased' section --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac0f3f2..366728d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,19 @@ # Changelog +* [Unreleased](#unreleased) * [0.5](#0.5) + +## Unreleased +### Added +### Changed +### Deprecated +### Removed +### Fixed +### Security +### Contributors + + ## 0.5 ### Added From 1f10e69b4ccaf5ba335b4584db3c42190b45ffe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 25 Nov 2023 12:40:13 -0600 Subject: [PATCH 133/347] use sizeof(*pointer) instead of sizeof(struct) --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 5725bf1..c0c5c08 100644 --- a/dwl.c +++ b/dwl.c @@ -815,7 +815,7 @@ createlayersurface(struct wl_listener *listener, void *data) return; } - layersurface = wlr_layer_surface->data = ecalloc(1, sizeof(LayerSurface)); + layersurface = wlr_layer_surface->data = ecalloc(1, sizeof(*layersurface)); layersurface->type = LayerShell; LISTEN(&wlr_layer_surface->surface->events.commit, &layersurface->surface_commit, commitlayersurfacenotify); From 66ec028b0056b834442a7ede6544eae8709946c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 25 Nov 2023 12:39:16 -0600 Subject: [PATCH 134/347] simplify check for wlr_layer_surface.output --- dwl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index c0c5c08..ea0a791 100644 --- a/dwl.c +++ b/dwl.c @@ -807,10 +807,8 @@ createlayersurface(struct wl_listener *listener, void *data) struct wlr_layer_surface_v1_state old_state; struct wlr_scene_tree *l = layers[layermap[wlr_layer_surface->pending.layer]]; - if (!wlr_layer_surface->output) - wlr_layer_surface->output = selmon ? selmon->wlr_output : NULL; - - if (!wlr_layer_surface->output) { + if (!wlr_layer_surface->output + && !(wlr_layer_surface->output = selmon ? selmon->wlr_output : NULL)) { wlr_layer_surface_v1_destroy(wlr_layer_surface); return; } From a353eee2cac0378a4201e408a3417aa107a7f647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 25 Nov 2023 12:48:54 -0600 Subject: [PATCH 135/347] simplify settings popups scene tree parent --- dwl.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index ea0a791..8500f2b 100644 --- a/dwl.c +++ b/dwl.c @@ -720,13 +720,12 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) if (layer != layersurface->scene->node.parent) { wlr_scene_node_reparent(&layersurface->scene->node, layer); - wlr_scene_node_reparent(&layersurface->popups->node, layer); wl_list_remove(&layersurface->link); wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->current.layer], &layersurface->link); + wlr_scene_node_reparent(&layersurface->popups->node, (wlr_layer_surface->current.layer + < ZWLR_LAYER_SHELL_V1_LAYER_TOP ? layers[LyrTop] : layer)); } - if (wlr_layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) - wlr_scene_node_reparent(&layersurface->popups->node, layers[LyrTop]); if (wlr_layer_surface->current.committed == 0 && layersurface->mapped == wlr_layer_surface->surface->mapped) From 39f4ee564b153966b0219004293d16900d2356d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 25 Nov 2023 12:35:38 -0600 Subject: [PATCH 136/347] use wlr_box_equal() instead of memcmp --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 8500f2b..b589378 100644 --- a/dwl.c +++ b/dwl.c @@ -504,7 +504,7 @@ arrangelayers(Monitor *m) for (i = 3; i >= 0; i--) arrangelayer(m, &m->layers[i], &usable_area, 1); - if (memcmp(&usable_area, &m->w, sizeof(struct wlr_box))) { + if (!wlr_box_equal(&usable_area, &m->w)) { m->w = usable_area; arrange(m); } From a5e068b20a04357b4fc709b1c6f3b698b4dc7094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 25 Nov 2023 13:30:56 -0600 Subject: [PATCH 137/347] destroy the layer-suface's scene tree for popups --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index b589378..6a96179 100644 --- a/dwl.c +++ b/dwl.c @@ -1067,6 +1067,7 @@ destroylayersurfacenotify(struct wl_listener *listener, void *data) wl_list_remove(&layersurface->unmap.link); wl_list_remove(&layersurface->surface_commit.link); wlr_scene_node_destroy(&layersurface->scene->node); + wlr_scene_node_destroy(&layersurface->popups->node); free(layersurface); } From 01a237bd5c96da5c4294b20e5093881008401b66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 25 Nov 2023 12:42:38 -0600 Subject: [PATCH 138/347] send wl_surface.enter before initial commit It's not necessary but it'll help clients to render a perfect first frame --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index 6a96179..09d3ea0 100644 --- a/dwl.c +++ b/dwl.c @@ -833,6 +833,7 @@ createlayersurface(struct wl_listener *listener, void *data) wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->pending.layer], &layersurface->link); + wlr_surface_send_enter(wlr_layer_surface->surface, wlr_layer_surface->output); /* Temporarily set the layer's current state to pending * so that we can easily arrange it From 9cb1ece6ccecaa49462160816afb24cbbb43e87b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 25 Nov 2023 12:46:39 -0600 Subject: [PATCH 139/347] do not check if a layer surface has monitor on commit We do not allow creating them w/o monitor and they are destroyed when destroying their monitor --- dwl.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/dwl.c b/dwl.c index 09d3ea0..c187df2 100644 --- a/dwl.c +++ b/dwl.c @@ -710,14 +710,8 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *layersurface = wl_container_of(listener, layersurface, surface_commit); struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; - struct wlr_output *wlr_output = wlr_layer_surface->output; struct wlr_scene_tree *layer = layers[layermap[wlr_layer_surface->current.layer]]; - /* For some reason this layersurface have no monitor, this can be because - * its monitor has just been destroyed */ - if (!wlr_output || !(layersurface->mon = wlr_output->data)) - return; - if (layer != layersurface->scene->node.parent) { wlr_scene_node_reparent(&layersurface->scene->node, layer); wl_list_remove(&layersurface->link); From b100b446b8c82bc2dcdbb40856ab87ed4a4ad594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 25 Nov 2023 12:49:52 -0600 Subject: [PATCH 140/347] return early if a layersurface didn't commit something --- dwl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index c187df2..8d5f599 100644 --- a/dwl.c +++ b/dwl.c @@ -712,6 +712,11 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; struct wlr_scene_tree *layer = layers[layermap[wlr_layer_surface->current.layer]]; + if (wlr_layer_surface->current.committed == 0 + && layersurface->mapped == wlr_layer_surface->surface->mapped) + return; + layersurface->mapped = wlr_layer_surface->surface->mapped; + if (layer != layersurface->scene->node.parent) { wlr_scene_node_reparent(&layersurface->scene->node, layer); wl_list_remove(&layersurface->link); @@ -721,11 +726,6 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) < ZWLR_LAYER_SHELL_V1_LAYER_TOP ? layers[LyrTop] : layer)); } - if (wlr_layer_surface->current.committed == 0 - && layersurface->mapped == wlr_layer_surface->surface->mapped) - return; - layersurface->mapped = wlr_layer_surface->surface->mapped; - arrangelayers(layersurface->mon); } From 2e4fdc1664e094b38814d760b4c933c3c3450a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 25 Nov 2023 13:01:54 -0600 Subject: [PATCH 141/347] use `l` instead of `layersurface` `layer_surface` instead of `wlr_layer_surface` and `scene_layer` whenever a wlr_scene_tree is related to layer surfaces --- dwl.c | 146 +++++++++++++++++++++++++++------------------------------- 1 file changed, 68 insertions(+), 78 deletions(-) diff --git a/dwl.c b/dwl.c index 8d5f599..69da91d 100644 --- a/dwl.c +++ b/dwl.c @@ -469,21 +469,20 @@ arrange(Monitor *m) void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int exclusive) { - LayerSurface *layersurface; + LayerSurface *l; struct wlr_box full_area = m->m; - wl_list_for_each(layersurface, list, link) { - struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; - struct wlr_layer_surface_v1_state *state = &wlr_layer_surface->current; + wl_list_for_each(l, list, link) { + struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; + struct wlr_layer_surface_v1_state *state = &layer_surface->current; if (exclusive != (state->exclusive_zone > 0)) continue; - wlr_scene_layer_surface_v1_configure(layersurface->scene_layer, &full_area, usable_area); - wlr_scene_node_set_position(&layersurface->popups->node, - layersurface->scene->node.x, layersurface->scene->node.y); - layersurface->geom.x = layersurface->scene->node.x; - layersurface->geom.y = layersurface->scene->node.y; + wlr_scene_layer_surface_v1_configure(l->scene_layer, &full_area, usable_area); + wlr_scene_node_set_position(&l->popups->node, l->scene->node.x, l->scene->node.y); + l->geom.x = l->scene->node.x; + l->geom.y = l->scene->node.y; } } @@ -492,11 +491,11 @@ arrangelayers(Monitor *m) { int i; struct wlr_box usable_area = m->m; + LayerSurface *l; uint32_t layers_above_shell[] = { ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, ZWLR_LAYER_SHELL_V1_LAYER_TOP, }; - LayerSurface *layersurface; if (!m->wlr_output->enabled) return; @@ -515,14 +514,12 @@ arrangelayers(Monitor *m) /* Find topmost keyboard interactive layer, if such a layer exists */ for (i = 0; i < LENGTH(layers_above_shell); i++) { - wl_list_for_each_reverse(layersurface, - &m->layers[layers_above_shell[i]], link) { - if (!locked && layersurface->layer_surface->current.keyboard_interactive - && layersurface->mapped) { + wl_list_for_each_reverse(l, &m->layers[layers_above_shell[i]], link) { + if (!locked && l->layer_surface->current.keyboard_interactive && l->mapped) { /* Deactivate the focused client. */ focusclient(NULL, 0); - exclusive_focus = layersurface; - client_notify_enter(layersurface->layer_surface->surface, wlr_seat_get_keyboard(seat)); + exclusive_focus = l; + client_notify_enter(l->layer_surface->surface, wlr_seat_get_keyboard(seat)); return; } } @@ -708,25 +705,24 @@ closemon(Monitor *m) void commitlayersurfacenotify(struct wl_listener *listener, void *data) { - LayerSurface *layersurface = wl_container_of(listener, layersurface, surface_commit); - struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; - struct wlr_scene_tree *layer = layers[layermap[wlr_layer_surface->current.layer]]; + LayerSurface *l = wl_container_of(listener, l, surface_commit); + struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; + struct wlr_scene_tree *scene_layer = layers[layermap[layer_surface->current.layer]]; - if (wlr_layer_surface->current.committed == 0 - && layersurface->mapped == wlr_layer_surface->surface->mapped) + + if (layer_surface->current.committed == 0 && l->mapped == layer_surface->surface->mapped) return; - layersurface->mapped = wlr_layer_surface->surface->mapped; + l->mapped = layer_surface->surface->mapped; - if (layer != layersurface->scene->node.parent) { - wlr_scene_node_reparent(&layersurface->scene->node, layer); - wl_list_remove(&layersurface->link); - wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->current.layer], - &layersurface->link); - wlr_scene_node_reparent(&layersurface->popups->node, (wlr_layer_surface->current.layer - < ZWLR_LAYER_SHELL_V1_LAYER_TOP ? layers[LyrTop] : layer)); + if (scene_layer != l->scene->node.parent) { + wlr_scene_node_reparent(&l->scene->node, scene_layer); + wl_list_remove(&l->link); + wl_list_insert(&l->mon->layers[layer_surface->current.layer], &l->link); + wlr_scene_node_reparent(&l->popups->node, (layer_surface->current.layer + < ZWLR_LAYER_SHELL_V1_LAYER_TOP ? layers[LyrTop] : scene_layer)); } - arrangelayers(layersurface->mon); + arrangelayers(l->mon); } void @@ -795,48 +791,44 @@ createkeyboard(struct wlr_keyboard *keyboard) void createlayersurface(struct wl_listener *listener, void *data) { - struct wlr_layer_surface_v1 *wlr_layer_surface = data; - LayerSurface *layersurface; + struct wlr_layer_surface_v1 *layer_surface = data; + LayerSurface *l; + struct wlr_surface *surface = layer_surface->surface; + struct wlr_scene_tree *scene_layer = layers[layermap[layer_surface->pending.layer]]; struct wlr_layer_surface_v1_state old_state; - struct wlr_scene_tree *l = layers[layermap[wlr_layer_surface->pending.layer]]; - if (!wlr_layer_surface->output - && !(wlr_layer_surface->output = selmon ? selmon->wlr_output : NULL)) { - wlr_layer_surface_v1_destroy(wlr_layer_surface); + if (!layer_surface->output + && !(layer_surface->output = selmon ? selmon->wlr_output : NULL)) { + wlr_layer_surface_v1_destroy(layer_surface); return; } - layersurface = wlr_layer_surface->data = ecalloc(1, sizeof(*layersurface)); - layersurface->type = LayerShell; - LISTEN(&wlr_layer_surface->surface->events.commit, - &layersurface->surface_commit, commitlayersurfacenotify); - LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy, - destroylayersurfacenotify); - LISTEN(&wlr_layer_surface->surface->events.map, &layersurface->map, - maplayersurfacenotify); - LISTEN(&wlr_layer_surface->surface->events.unmap, &layersurface->unmap, - unmaplayersurfacenotify); + l = layer_surface->data = ecalloc(1, sizeof(*l)); + l->type = LayerShell; + LISTEN(&surface->events.commit, &l->surface_commit, commitlayersurfacenotify); + LISTEN(&surface->events.map, &l->map, maplayersurfacenotify); + LISTEN(&surface->events.unmap, &l->unmap, unmaplayersurfacenotify); + LISTEN(&layer_surface->events.destroy, &l->destroy, destroylayersurfacenotify); - layersurface->layer_surface = wlr_layer_surface; - layersurface->mon = wlr_layer_surface->output->data; - layersurface->scene_layer = wlr_scene_layer_surface_v1_create(l, wlr_layer_surface); - layersurface->scene = layersurface->scene_layer->tree; - layersurface->popups = wlr_layer_surface->surface->data = wlr_scene_tree_create(l); + l->layer_surface = layer_surface; + l->mon = layer_surface->output->data; + l->scene_layer = wlr_scene_layer_surface_v1_create(scene_layer, layer_surface); + l->scene = l->scene_layer->tree; + l->popups = surface->data = wlr_scene_tree_create(scene_layer); + l->scene->node.data = l; - layersurface->scene->node.data = layersurface; - wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->pending.layer], - &layersurface->link); - wlr_surface_send_enter(wlr_layer_surface->surface, wlr_layer_surface->output); + wl_list_insert(&l->mon->layers[layer_surface->pending.layer],&l->link); + wlr_surface_send_enter(surface, layer_surface->output); /* Temporarily set the layer's current state to pending * so that we can easily arrange it */ - old_state = wlr_layer_surface->current; - wlr_layer_surface->current = wlr_layer_surface->pending; - layersurface->mapped = 1; - arrangelayers(layersurface->mon); - wlr_layer_surface->current = old_state; + old_state = layer_surface->current; + layer_surface->current = layer_surface->pending; + l->mapped = 1; + arrangelayers(l->mon); + layer_surface->current = old_state; } void @@ -1054,16 +1046,16 @@ destroyidleinhibitor(struct wl_listener *listener, void *data) void destroylayersurfacenotify(struct wl_listener *listener, void *data) { - LayerSurface *layersurface = wl_container_of(listener, layersurface, destroy); + LayerSurface *l = wl_container_of(listener, l, destroy); - wl_list_remove(&layersurface->link); - wl_list_remove(&layersurface->destroy.link); - wl_list_remove(&layersurface->map.link); - wl_list_remove(&layersurface->unmap.link); - wl_list_remove(&layersurface->surface_commit.link); - wlr_scene_node_destroy(&layersurface->scene->node); - wlr_scene_node_destroy(&layersurface->popups->node); - free(layersurface); + wl_list_remove(&l->link); + wl_list_remove(&l->destroy.link); + wl_list_remove(&l->map.link); + wl_list_remove(&l->unmap.link); + wl_list_remove(&l->surface_commit.link); + wlr_scene_node_destroy(&l->scene->node); + wlr_scene_node_destroy(&l->popups->node); + free(l); } void @@ -2490,17 +2482,15 @@ unlocksession(struct wl_listener *listener, void *data) void unmaplayersurfacenotify(struct wl_listener *listener, void *data) { - LayerSurface *layersurface = wl_container_of(listener, layersurface, unmap); + LayerSurface *l = wl_container_of(listener, l, unmap); - layersurface->mapped = 0; - wlr_scene_node_set_enabled(&layersurface->scene->node, 0); - if (layersurface == exclusive_focus) + l->mapped = 0; + wlr_scene_node_set_enabled(&l->scene->node, 0); + if (l == exclusive_focus) exclusive_focus = NULL; - if (layersurface->layer_surface->output - && (layersurface->mon = layersurface->layer_surface->output->data)) - arrangelayers(layersurface->mon); - if (layersurface->layer_surface->surface == - seat->keyboard_state.focused_surface) + if (l->layer_surface->output && (l->mon = l->layer_surface->output->data)) + arrangelayers(l->mon); + if (l->layer_surface->surface == seat->keyboard_state.focused_surface) focusclient(focustop(selmon), 1); motionnotify(0); } From 057d50af8cd54647933021ae20e975a54ecf4408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 23 Nov 2023 10:56:01 -0600 Subject: [PATCH 142/347] pass wl_display to wlr_output_layout_create (wlroots!4310) References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4310 --- dwl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 69da91d..de336b7 100644 --- a/dwl.c +++ b/dwl.c @@ -631,7 +631,6 @@ cleanup(void) waitpid(child_pid, NULL, 0); } wlr_xcursor_manager_destroy(cursor_mgr); - wlr_output_layout_destroy(output_layout); wl_display_destroy(dpy); /* Destroy after the wayland display (when the monitors are already destroyed) to avoid destroying them with an invalid scene output. */ @@ -2232,7 +2231,7 @@ setup(void) /* Creates an output layout, which a wlroots utility for working with an * arrangement of screens in a physical layout. */ - output_layout = wlr_output_layout_create(); + output_layout = wlr_output_layout_create(dpy); LISTEN_STATIC(&output_layout->events.change, updatemons); wlr_xdg_output_manager_v1_create(dpy, output_layout); From 3fe3581a5986be10e0736ea6c8ded59c7f44db5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 23 Nov 2023 14:19:10 -0600 Subject: [PATCH 143/347] chase wlr_layer_shell_v1.new_surface changes (wlroots!4265) References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4265 --- dwl.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/dwl.c b/dwl.c index de336b7..7b13087 100644 --- a/dwl.c +++ b/dwl.c @@ -707,7 +707,17 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) LayerSurface *l = wl_container_of(listener, l, surface_commit); struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; struct wlr_scene_tree *scene_layer = layers[layermap[layer_surface->current.layer]]; + struct wlr_layer_surface_v1_state old_state; + if (l->layer_surface->initial_commit) { + /* Temporarily set the layer's current state to pending + * so that we can easily arrange it */ + old_state = l->layer_surface->current; + l->layer_surface->current = l->layer_surface->pending; + arrangelayers(l->mon); + l->layer_surface->current = old_state; + return; + } if (layer_surface->current.committed == 0 && l->mapped == layer_surface->surface->mapped) return; @@ -794,7 +804,6 @@ createlayersurface(struct wl_listener *listener, void *data) LayerSurface *l; struct wlr_surface *surface = layer_surface->surface; struct wlr_scene_tree *scene_layer = layers[layermap[layer_surface->pending.layer]]; - struct wlr_layer_surface_v1_state old_state; if (!layer_surface->output && !(layer_surface->output = selmon ? selmon->wlr_output : NULL)) { @@ -819,15 +828,6 @@ createlayersurface(struct wl_listener *listener, void *data) wl_list_insert(&l->mon->layers[layer_surface->pending.layer],&l->link); wlr_surface_send_enter(surface, layer_surface->output); - - /* Temporarily set the layer's current state to pending - * so that we can easily arrange it - */ - old_state = layer_surface->current; - layer_surface->current = layer_surface->pending; - l->mapped = 1; - arrangelayers(l->mon); - layer_surface->current = old_state; } void @@ -1484,7 +1484,6 @@ locksession(struct wl_listener *listener, void *data) void maplayersurfacenotify(struct wl_listener *listener, void *data) { - LayerSurface *l = wl_container_of(listener, l, map); motionnotify(0); } From 70c5fcc23d3702544c978e81b8f067de596f06d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 23 Nov 2023 14:06:45 -0600 Subject: [PATCH 144/347] chase xdg-shell events update (wlroots!4345) References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4345 --- dwl.c | 80 ++++++++++++++++++++++++++++++----------------------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/dwl.c b/dwl.c index 7b13087..aa3f1b9 100644 --- a/dwl.c +++ b/dwl.c @@ -251,6 +251,7 @@ static void createlocksurface(struct wl_listener *listener, void *data); static void createmon(struct wl_listener *listener, void *data); static void createnotify(struct wl_listener *listener, void *data); static void createpointer(struct wlr_pointer *pointer); +static void createpopup(struct wl_listener *listener, void *data); static void cursorframe(struct wl_listener *listener, void *data); static void destroydragicon(struct wl_listener *listener, void *data); static void destroyidleinhibitor(struct wl_listener *listener, void *data); @@ -739,6 +740,9 @@ commitnotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, commit); + if (c->surface.xdg->initial_commit) + wlr_xdg_toplevel_set_wm_capabilities(c->surface.xdg->toplevel, WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); + if (client_surface(c)->mapped) resize(c, c->geom, (c->isfloating && !c->isfullscreen)); @@ -926,49 +930,22 @@ createmon(struct wl_listener *listener, void *data) void createnotify(struct wl_listener *listener, void *data) { - /* This event is raised when wlr_xdg_shell receives a new xdg surface from a - * client, either a toplevel (application window) or popup, - * or when wlr_layer_shell receives a new popup from a layer. - * If you want to do something tricky with popups you should check if - * its parent is wlr_xdg_shell or wlr_layer_shell */ - struct wlr_xdg_surface *xdg_surface = data; + /* This event is raised when a client creates a new toplevel (application window). */ + struct wlr_xdg_toplevel *toplevel = data; Client *c = NULL; - LayerSurface *l = NULL; - - if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { - struct wlr_box box; - int type = toplevel_from_wlr_surface(xdg_surface->surface, &c, &l); - if (!xdg_surface->popup->parent || type < 0) - return; - xdg_surface->surface->data = wlr_scene_xdg_surface_create( - xdg_surface->popup->parent->data, xdg_surface); - if ((l && !l->mon) || (c && !c->mon)) - return; - box = type == LayerShell ? l->mon->m : c->mon->w; - box.x -= (type == LayerShell ? l->geom.x : c->geom.x); - box.y -= (type == LayerShell ? l->geom.y : c->geom.y); - wlr_xdg_popup_unconstrain_from_box(xdg_surface->popup, &box); - return; - } else if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_NONE) - return; /* Allocate a Client for this surface */ - c = xdg_surface->data = ecalloc(1, sizeof(*c)); - c->surface.xdg = xdg_surface; + c = toplevel->base->data = ecalloc(1, sizeof(*c)); + c->surface.xdg = toplevel->base; c->bw = borderpx; - wlr_xdg_toplevel_set_wm_capabilities(xdg_surface->toplevel, - WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); - - LISTEN(&xdg_surface->surface->events.commit, &c->commit, commitnotify); - LISTEN(&xdg_surface->surface->events.map, &c->map, mapnotify); - LISTEN(&xdg_surface->surface->events.unmap, &c->unmap, unmapnotify); - LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify); - LISTEN(&xdg_surface->toplevel->events.set_title, &c->set_title, updatetitle); - LISTEN(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen, - fullscreennotify); - LISTEN(&xdg_surface->toplevel->events.request_maximize, &c->maximize, - maximizenotify); + LISTEN(&toplevel->base->surface->events.commit, &c->commit, commitnotify); + LISTEN(&toplevel->base->surface->events.map, &c->map, mapnotify); + LISTEN(&toplevel->base->surface->events.unmap, &c->unmap, unmapnotify); + LISTEN(&toplevel->events.destroy, &c->destroy, destroynotify); + LISTEN(&toplevel->events.request_fullscreen, &c->fullscreen, fullscreennotify); + LISTEN(&toplevel->events.request_maximize, &c->maximize, maximizenotify); + LISTEN(&toplevel->events.set_title, &c->set_title, updatetitle); } void @@ -1015,6 +992,30 @@ createpointer(struct wlr_pointer *pointer) wlr_cursor_attach_input_device(cursor, &pointer->base); } +void +createpopup(struct wl_listener *listener, void *data) +{ + /* This event is raised when a client (either xdg-shell or layer-shell) + * creates a new popup. */ + struct wlr_xdg_popup *popup = data; + LayerSurface *l = NULL; + Client *c = NULL; + struct wlr_box box; + + int type = toplevel_from_wlr_surface(popup->base->surface, &c, &l); + if (!popup->parent || type < 0) + return; + popup->base->surface->data = wlr_scene_xdg_surface_create( + popup->parent->data, popup->base); + if ((l && !l->mon) || (c && !c->mon)) + return; + box = type == LayerShell ? l->mon->m : c->mon->w; + box.x -= (type == LayerShell ? l->geom.x : c->geom.x); + box.y -= (type == LayerShell ? l->geom.y : c->geom.y); + /* FIXME: this send a configure event to a uninitialized wlr_xdg_surface */ + wlr_xdg_popup_unconstrain_from_box(popup, &box); +} + void cursorframe(struct wl_listener *listener, void *data) { @@ -2249,7 +2250,8 @@ setup(void) wl_list_init(&fstack); xdg_shell = wlr_xdg_shell_create(dpy, 6); - LISTEN_STATIC(&xdg_shell->events.new_surface, createnotify); + LISTEN_STATIC(&xdg_shell->events.new_toplevel, createnotify); + LISTEN_STATIC(&xdg_shell->events.new_popup, createpopup); layer_shell = wlr_layer_shell_v1_create(dpy, 3); LISTEN_STATIC(&layer_shell->events.new_surface, createlayersurface); From ff39cac355e79b21049ba0ad181c098aebefc313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 28 Nov 2023 20:44:30 -0600 Subject: [PATCH 145/347] convert issue templates to yaml also move the templates to .gitea to reflect the migration to Codeberg --- .gitea/issue_template/bug_report.yml | 27 ++++++++++++++++++++++ .gitea/issue_template/enhancement-idea.yml | 9 ++++++++ .github/ISSUE_TEMPLATE/bug_report.md | 17 -------------- .github/ISSUE_TEMPLATE/enhancement-idea.md | 10 -------- 4 files changed, 36 insertions(+), 27 deletions(-) create mode 100644 .gitea/issue_template/bug_report.yml create mode 100644 .gitea/issue_template/enhancement-idea.yml delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md delete mode 100644 .github/ISSUE_TEMPLATE/enhancement-idea.md diff --git a/.gitea/issue_template/bug_report.yml b/.gitea/issue_template/bug_report.yml new file mode 100644 index 0000000..1ec1cf0 --- /dev/null +++ b/.gitea/issue_template/bug_report.yml @@ -0,0 +1,27 @@ +name: Bug Report +about: Something in dwl isn't working correctly +title: +labels: + - 'Kind/Bug' +body: + - type: markdown + attributes: + value: | + Only report bugs that can be reproduced on the main (or wlroots-next) branch + Report patch issues to their respective authors + - type: input + id: dwl_version + attributes: + label: dwl version + placeholder: '`dwl -v`' + validations: + required: true + - type: input + id: wlroots_version + attributes: + label: wlroots version + validations: + required: true + - type: textarea + attributes: + label: Description diff --git a/.gitea/issue_template/enhancement-idea.yml b/.gitea/issue_template/enhancement-idea.yml new file mode 100644 index 0000000..be1bbf2 --- /dev/null +++ b/.gitea/issue_template/enhancement-idea.yml @@ -0,0 +1,9 @@ +name: Enhancement idea +about: Suggest a feature or improvement +title: +labels: + - 'Kind/Feature' +body: + - type: textarea + attributes: + label: Description diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index cd9bd8d..0000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -name: Bug report -about: Something in dwl isn't working correctly -title: '' -labels: 'A: bug' -assignees: '' - ---- - -## Info -dwl version: -wlroots version: -## Description - diff --git a/.github/ISSUE_TEMPLATE/enhancement-idea.md b/.github/ISSUE_TEMPLATE/enhancement-idea.md deleted file mode 100644 index 0ac096d..0000000 --- a/.github/ISSUE_TEMPLATE/enhancement-idea.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: Enhancement idea -about: Suggest a feature or improvement -title: '' -labels: 'A: enhancement' -assignees: '' - ---- - - From 43f31b8f1be327bf4d29e1efc2ea51178ac64481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 28 Nov 2023 22:50:40 -0600 Subject: [PATCH 146/347] improve the bug report template Fixes: https://codeberg.org/dwl/dwl/issues/498 --- .gitea/issue_template/bug_report.yml | 43 +++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/.gitea/issue_template/bug_report.yml b/.gitea/issue_template/bug_report.yml index 1ec1cf0..56f4a3e 100644 --- a/.gitea/issue_template/bug_report.yml +++ b/.gitea/issue_template/bug_report.yml @@ -7,21 +7,56 @@ body: - type: markdown attributes: value: | - Only report bugs that can be reproduced on the main (or wlroots-next) branch - Report patch issues to their respective authors + - Only report bugs that can be reproduced on the main (or wlroots-next) branch without patches. + - Proprietary graphics drivers, including nvidia, are not supported. Please use the open source equivalents, such as nouveau, if you would like to use dwl. + - Report patch issues to their respective authors. + - type: input id: dwl_version attributes: - label: dwl version + label: 'dwl version:' placeholder: '`dwl -v`' validations: required: true + - type: input id: wlroots_version attributes: - label: wlroots version + label: 'wlroots version:' validations: required: true + + - type: input + id: distro + attributes: + label: What distro (and version) are you using? + validations: + required: false + + - type: textarea + id: debug_log + attributes: + label: Debug Log + value: | + Run `dwl -d 2> ~/dwl.log` from a TTY and attach the **full** (do not truncate it) file here, or upload it to a pastebin. + Please try to keep the reproduction as brief as possible and exit dwl. + validations: + required: false + + - type: textarea + id: backtrace + attributes: + label: Stack Trace + value: | + - Only required if dwl crashes. + - If the lines mentioning dwl or wlroots have `??`. Please compile both dwl and wlroots from source (enabling debug symbols) and try to reproduce. + validations: + required: false + - type: textarea attributes: label: Description + value: | + The steps you took to reproduce the problem. + validations: + required: false From 2e29189b92c581345eb6b40a98e81c0e692fe8a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 30 Nov 2023 21:10:21 -0600 Subject: [PATCH 147/347] use a detached output state in outputmgrapplyortest() wlr_output.pending might be removed in wlroots 0.18 --- dwl.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/dwl.c b/dwl.c index 69da91d..0ef6bfe 100644 --- a/dwl.c +++ b/dwl.c @@ -1724,14 +1724,17 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) wl_list_for_each(config_head, &config->heads, link) { struct wlr_output *wlr_output = config_head->state.output; Monitor *m = wlr_output->data; + struct wlr_output_state state; - wlr_output_enable(wlr_output, config_head->state.enabled); + wlr_output_state_init(&state); + wlr_output_state_set_enabled(&state, config_head->state.enabled); if (!config_head->state.enabled) goto apply_or_test; + if (config_head->state.mode) - wlr_output_set_mode(wlr_output, config_head->state.mode); + wlr_output_state_set_mode(&state, config_head->state.mode); else - wlr_output_set_custom_mode(wlr_output, + wlr_output_state_set_custom_mode(&state, config_head->state.custom_mode.width, config_head->state.custom_mode.height, config_head->state.custom_mode.refresh); @@ -1741,18 +1744,16 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) if (m->m.x != config_head->state.x || m->m.y != config_head->state.y) wlr_output_layout_add(output_layout, wlr_output, config_head->state.x, config_head->state.y); - wlr_output_set_transform(wlr_output, config_head->state.transform); - wlr_output_set_scale(wlr_output, config_head->state.scale); - wlr_output_enable_adaptive_sync(wlr_output, + wlr_output_state_set_transform(&state, config_head->state.transform); + wlr_output_state_set_scale(&state, config_head->state.scale); + wlr_output_state_set_adaptive_sync_enabled(&state, config_head->state.adaptive_sync_enabled); apply_or_test: - if (test) { - ok &= wlr_output_test(wlr_output); - wlr_output_rollback(wlr_output); - } else { - ok &= wlr_output_commit(wlr_output); - } + ok &= test ? wlr_output_test_state(wlr_output, &state) + : wlr_output_commit_state(wlr_output, &state); + + wlr_output_state_finish(&state); } if (ok) From 00e867d5365a7d98b1094386f8a0b88839eb9d86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 30 Nov 2023 21:12:31 -0600 Subject: [PATCH 148/347] use detached output state in createmon() see previous commit for motivation --- dwl.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/dwl.c b/dwl.c index 0ef6bfe..6d74a3f 100644 --- a/dwl.c +++ b/dwl.c @@ -858,22 +858,25 @@ createmon(struct wl_listener *listener, void *data) struct wlr_output *wlr_output = data; const MonitorRule *r; size_t i; + struct wlr_output_state state; Monitor *m = wlr_output->data = ecalloc(1, sizeof(*m)); m->wlr_output = wlr_output; wlr_output_init_render(wlr_output, alloc, drw); - /* Initialize monitor state using configured rules */ for (i = 0; i < LENGTH(m->layers); i++) wl_list_init(&m->layers[i]); + + wlr_output_state_init(&state); + /* Initialize monitor state using configured rules */ m->tagset[0] = m->tagset[1] = 1; for (r = monrules; r < END(monrules); r++) { if (!r->name || strstr(wlr_output->name, r->name)) { m->mfact = r->mfact; m->nmaster = r->nmaster; - wlr_output_set_scale(wlr_output, r->scale); + wlr_output_state_set_scale(&state, r->scale); m->lt[0] = m->lt[1] = r->lt; - wlr_output_set_transform(wlr_output, r->rr); + wlr_output_state_set_transform(&state, r->rr); m->m.x = r->x; m->m.y = r->y; break; @@ -884,16 +887,19 @@ createmon(struct wl_listener *listener, void *data) * monitor supports only a specific set of modes. We just pick the * monitor's preferred mode; a more sophisticated compositor would let * the user configure it. */ - wlr_output_set_mode(wlr_output, wlr_output_preferred_mode(wlr_output)); + wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output)); /* Set up event listeners */ LISTEN(&wlr_output->events.frame, &m->frame, rendermon); LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon); LISTEN(&wlr_output->events.request_state, &m->request_state, requestmonstate); - wlr_output_enable(wlr_output, 1); - if (!wlr_output_commit(wlr_output)) + wlr_output_state_set_enabled(&state, 1); + if (!wlr_output_commit_state(wlr_output, &state)) { + wlr_output_state_finish(&state); return; + } + wlr_output_state_finish(&state); wl_list_insert(&mons, &m->link); printstatus(); From 901d2e2d9d54ab6c6a66d0877402bab04a60093e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 30 Nov 2023 22:17:30 -0600 Subject: [PATCH 149/347] check failure of wlr_output_init_render --- dwl.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index 6d74a3f..1eee591 100644 --- a/dwl.c +++ b/dwl.c @@ -859,10 +859,13 @@ createmon(struct wl_listener *listener, void *data) const MonitorRule *r; size_t i; struct wlr_output_state state; - Monitor *m = wlr_output->data = ecalloc(1, sizeof(*m)); - m->wlr_output = wlr_output; + Monitor *m; - wlr_output_init_render(wlr_output, alloc, drw); + if (!wlr_output_init_render(wlr_output, alloc, drw)) + return; + + m = wlr_output->data = ecalloc(1, sizeof(*m)); + m->wlr_output = wlr_output; for (i = 0; i < LENGTH(m->layers); i++) wl_list_init(&m->layers[i]); From 5f7d396996ce67bce4f2a35c936e9879576b5aa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 30 Nov 2023 22:22:21 -0600 Subject: [PATCH 150/347] don't return early if the first output commit fails --- dwl.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 1eee591..1bfe8cf 100644 --- a/dwl.c +++ b/dwl.c @@ -898,10 +898,7 @@ createmon(struct wl_listener *listener, void *data) LISTEN(&wlr_output->events.request_state, &m->request_state, requestmonstate); wlr_output_state_set_enabled(&state, 1); - if (!wlr_output_commit_state(wlr_output, &state)) { - wlr_output_state_finish(&state); - return; - } + wlr_output_commit_state(wlr_output, &state); wlr_output_state_finish(&state); wl_list_insert(&mons, &m->link); From 2b3504e439f3064700c4aed002caf56a1a7d21ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 1 Dec 2023 21:35:50 -0600 Subject: [PATCH 151/347] sort #includes --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 1bfe8cf..bbb27e4 100644 --- a/dwl.c +++ b/dwl.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -30,6 +29,7 @@ #include #include #include +#include #include #include #include From 28ec843aee3d339ef0b5b95685cdd7c2bcacdb16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 7 Dec 2023 14:09:10 -0600 Subject: [PATCH 152/347] make sure popups of a layer surface are in the correct layer previously it worked because we checked in every commit the layer in a353eee2cac0378a4201e408a3417aa107a7f647 and b100b446b8c82bc2dcdbb40856ab87ed4a4ad594 we changed the way it's handled and now if the layer surface does not change the layer we don't it either. meaning that if it was created in the bottom layer and did not change the layer the popups would show behind xdg clients --- dwl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index bbb27e4..e9b7d84 100644 --- a/dwl.c +++ b/dwl.c @@ -814,7 +814,8 @@ createlayersurface(struct wl_listener *listener, void *data) l->mon = layer_surface->output->data; l->scene_layer = wlr_scene_layer_surface_v1_create(scene_layer, layer_surface); l->scene = l->scene_layer->tree; - l->popups = surface->data = wlr_scene_tree_create(scene_layer); + l->popups = surface->data = wlr_scene_tree_create(layer_surface->current.layer + < ZWLR_LAYER_SHELL_V1_LAYER_TOP ? layers[LyrTop] : scene_layer); l->scene->node.data = l; From 393078d80c330be0313ac84c9de2de132f785d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 7 Dec 2023 14:18:03 -0600 Subject: [PATCH 153/347] store the layersurface pointer in l->popups->node.data as well --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index e9b7d84..edba265 100644 --- a/dwl.c +++ b/dwl.c @@ -816,7 +816,7 @@ createlayersurface(struct wl_listener *listener, void *data) l->scene = l->scene_layer->tree; l->popups = surface->data = wlr_scene_tree_create(layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP ? layers[LyrTop] : scene_layer); - l->scene->node.data = l; + l->scene->node.data = l->popups->node.data = l; wl_list_insert(&l->mon->layers[layer_surface->pending.layer],&l->link); From be2a1dea26f04bc8161d2e7cfb28e8e19b949944 Mon Sep 17 00:00:00 2001 From: fictitiousexistence Date: Thu, 30 Nov 2023 05:30:22 +0000 Subject: [PATCH 154/347] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 820828f..1aa5195 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ shell command using `/bin/sh -c`. It serves a similar function to `.xinitrc`, but differs in that the display server will not shut down when this process terminates. Instead, dwl will send this process a SIGTERM at shutdown and wait for it to terminate (if it hasn't already). This makes it ideal for execing into -a user service manager like [s6], [anopa], [runit], or [`systemd --user`]. +a user service manager like [s6], [anopa], [runit], [dinit], or [`systemd --user`]. Note: The `-s` command is run as a *child process* of dwl, which means that it does not have the ability to affect the environment of dwl or of any processes @@ -167,6 +167,7 @@ inspiration, and to the various contributors to the project, including: [s6]: https://skarnet.org/software/s6/ [anopa]: https://jjacky.com/anopa/ [runit]: http://smarden.org/runit/faq.html#userservices +[dinit]: https://davmac.org/projects/dinit/ [`systemd --user`]: https://wiki.archlinux.org/title/Systemd/User [wiki]: https://codeberg.org/dwl/dwl/wiki/Home#compatible-status-bars [list of useful resources on our wiki]: From 7341d047da511a457a54ec342703d6fc6cdd5240 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 30 Nov 2023 22:30:03 -0600 Subject: [PATCH 155/347] add a note about not removing the default rule Closes: https://codeberg.org/dwl/dwl/issues/527 --- config.def.h | 1 + 1 file changed, 1 insertion(+) diff --git a/config.def.h b/config.def.h index db0babc..5375eb5 100644 --- a/config.def.h +++ b/config.def.h @@ -36,6 +36,7 @@ static const Layout layouts[] = { }; /* monitors */ +/* NOTE: ALWAYS add a fallback rule, even if you are completely sure it won't be used */ static const MonitorRule monrules[] = { /* name mfact nmaster scale layout rotate/reflect x y */ /* example of a HiDPI laptop monitor: From 80c9ad12ba81ab54ac6aad8b413a158d1de52705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 7 Dec 2023 21:43:48 -0600 Subject: [PATCH 156/347] reduce calls to client_get_geometry --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index edba265..670e95f 100644 --- a/dwl.c +++ b/dwl.c @@ -1512,9 +1512,10 @@ mapnotify(struct wl_listener *listener, void *data) : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); c->scene->node.data = c->scene_surface->node.data = c; + client_get_geometry(c, &c->geom); + /* Handle unmanaged clients first so we can return prior create borders */ if (client_is_unmanaged(c)) { - client_get_geometry(c, &c->geom); /* Unmanaged clients always are floating */ wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]); wlr_scene_node_set_position(&c->scene->node, c->geom.x + borderpx, @@ -1533,7 +1534,6 @@ mapnotify(struct wl_listener *listener, void *data) /* Initialize client geometry with room for border */ client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); - client_get_geometry(c, &c->geom); c->geom.width += 2 * c->bw; c->geom.height += 2 * c->bw; From a760757b82eb10ce09a890e0a5ea1c76de22b144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 7 Dec 2023 21:44:53 -0600 Subject: [PATCH 157/347] set the correct border color when mapping a client --- dwl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 670e95f..b4d91b6 100644 --- a/dwl.c +++ b/dwl.c @@ -1528,7 +1528,8 @@ mapnotify(struct wl_listener *listener, void *data) } for (i = 0; i < 4; i++) { - c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, bordercolor); + c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, + c->isurgent ? urgentcolor : bordercolor); c->border[i]->node.data = c; } From 472a31b5a4c0165c796fe6497160106bd73a6b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 7 Dec 2023 21:48:56 -0600 Subject: [PATCH 158/347] LayerSurface::link -> LayerSurface.link --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index b4d91b6..004da40 100644 --- a/dwl.c +++ b/dwl.c @@ -188,7 +188,7 @@ struct Monitor { struct wlr_session_lock_surface_v1 *lock_surface; struct wlr_box m; /* monitor area, layout-relative */ struct wlr_box w; /* window area, layout-relative */ - struct wl_list layers[4]; /* LayerSurface::link */ + struct wl_list layers[4]; /* LayerSurface.link */ const Layout *lt[2]; unsigned int seltags; unsigned int sellt; From 50ea84c5f6beb814faa2a0fc50149e51192bf97b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 7 Dec 2023 21:49:26 -0600 Subject: [PATCH 159/347] remove extra blank line --- dwl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/dwl.c b/dwl.c index 004da40..d7db9b5 100644 --- a/dwl.c +++ b/dwl.c @@ -818,7 +818,6 @@ createlayersurface(struct wl_listener *listener, void *data) < ZWLR_LAYER_SHELL_V1_LAYER_TOP ? layers[LyrTop] : scene_layer); l->scene->node.data = l->popups->node.data = l; - wl_list_insert(&l->mon->layers[layer_surface->pending.layer],&l->link); wlr_surface_send_enter(surface, layer_surface->output); From bdbfb45d6687c69a83f2387b278e2ca97ef61a36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 7 Dec 2023 21:51:24 -0600 Subject: [PATCH 160/347] copy layout symbol when matching a MonitorRule --- dwl.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dwl.c b/dwl.c index d7db9b5..d149a22 100644 --- a/dwl.c +++ b/dwl.c @@ -875,13 +875,14 @@ createmon(struct wl_listener *listener, void *data) m->tagset[0] = m->tagset[1] = 1; for (r = monrules; r < END(monrules); r++) { if (!r->name || strstr(wlr_output->name, r->name)) { - m->mfact = r->mfact; - m->nmaster = r->nmaster; - wlr_output_state_set_scale(&state, r->scale); - m->lt[0] = m->lt[1] = r->lt; - wlr_output_state_set_transform(&state, r->rr); m->m.x = r->x; m->m.y = r->y; + m->mfact = r->mfact; + m->nmaster = r->nmaster; + m->lt[0] = m->lt[1] = r->lt; + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); + wlr_output_state_set_scale(&state, r->scale); + wlr_output_state_set_transform(&state, r->rr); break; } } @@ -927,7 +928,6 @@ createmon(struct wl_listener *listener, void *data) wlr_output_layout_add_auto(output_layout, wlr_output); else wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y); - strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); } void From e5e2d1c28f816c3f9188ebca77ecf3abcdd89acc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 7 Dec 2023 22:04:24 -0600 Subject: [PATCH 161/347] use (struct wlr_box){0} to empty the Monitor areas --- dwl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index d149a22..eb30215 100644 --- a/dwl.c +++ b/dwl.c @@ -2554,8 +2554,7 @@ updatemons(struct wl_listener *listener, void *data) /* Remove this output from the layout to avoid cursor enter inside it */ wlr_output_layout_remove(output_layout, m->wlr_output); closemon(m); - memset(&m->m, 0, sizeof(m->m)); - memset(&m->w, 0, sizeof(m->w)); + m->m = m->w = (struct wlr_box){0}; } /* Insert outputs that need to */ wl_list_for_each(m, &mons, link) From 6a151677540b858f90a891b2a0f616ea1abb2427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 7 Dec 2023 22:15:42 -0600 Subject: [PATCH 162/347] add a blank line to improve readability --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index eb30215..0fc0f72 100644 --- a/dwl.c +++ b/dwl.c @@ -2561,6 +2561,7 @@ updatemons(struct wl_listener *listener, void *data) if (m->wlr_output->enabled && !wlr_output_layout_get(output_layout, m->wlr_output)) wlr_output_layout_add_auto(output_layout, m->wlr_output); + /* Now that we update the output layout we can get its box */ wlr_output_layout_get_box(output_layout, NULL, &sgeom); From 9694477b2ffe84a83207c16b805eccf0a9f6aa34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 7 Dec 2023 22:16:13 -0600 Subject: [PATCH 163/347] relax a bit the line length limit --- dwl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 0fc0f72..007d4d6 100644 --- a/dwl.c +++ b/dwl.c @@ -2585,8 +2585,7 @@ updatemons(struct wl_listener *listener, void *data) if (m->lock_surface) { struct wlr_scene_tree *scene_tree = m->lock_surface->surface->data; wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y); - wlr_session_lock_surface_v1_configure(m->lock_surface, m->m.width, - m->m.height); + wlr_session_lock_surface_v1_configure(m->lock_surface, m->m.width, m->m.height); } /* Calculate the effective monitor geometry to use for clients */ From e7e84b10837424ea6d969afa239944ea53d16b14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 7 Dec 2023 22:17:48 -0600 Subject: [PATCH 164/347] add explanation about why we try to re-apply the gamma LUT on output changes --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index 007d4d6..d8969ba 100644 --- a/dwl.c +++ b/dwl.c @@ -2596,6 +2596,8 @@ updatemons(struct wl_listener *listener, void *data) if ((c = focustop(m)) && c->isfullscreen) resize(c, m->m, 0); + /* Try to re-set the gamma LUT when updating monitors, + * it's only really needed when enabling a disabled output, but meh. */ m->gamma_lut_changed = 1; config_head->state.enabled = 1; config_head->state.mode = m->wlr_output->current_mode; From e03896b4d61ae99eec16f3ed0408d5499c0494b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 7 Dec 2023 22:18:49 -0600 Subject: [PATCH 165/347] avoid duplication of lines the output state is copied when creating a output configuration head --- dwl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index d8969ba..3148072 100644 --- a/dwl.c +++ b/dwl.c @@ -2599,8 +2599,7 @@ updatemons(struct wl_listener *listener, void *data) /* Try to re-set the gamma LUT when updating monitors, * it's only really needed when enabling a disabled output, but meh. */ m->gamma_lut_changed = 1; - config_head->state.enabled = 1; - config_head->state.mode = m->wlr_output->current_mode; + config_head->state.x = m->m.x; config_head->state.y = m->m.y; } From f5d839844d1c1f9369ca55e058e91161da6929f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 7 Dec 2023 22:37:00 -0600 Subject: [PATCH 166/347] remove an unneeded cast in createpointer() --- dwl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 3148072..9219af5 100644 --- a/dwl.c +++ b/dwl.c @@ -982,8 +982,7 @@ void createpointer(struct wlr_pointer *pointer) { if (wlr_input_device_is_libinput(&pointer->base)) { - struct libinput_device *libinput_device = (struct libinput_device*) - wlr_libinput_get_device_handle(&pointer->base); + struct libinput_device *libinput_device = wlr_libinput_get_device_handle(&pointer->base); if (libinput_device_config_tap_get_finger_count(libinput_device)) { libinput_device_config_tap_set_enabled(libinput_device, tap_to_click); From 79c51a45841a15be9c65fd01b34b2a23e48eb423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 7 Dec 2023 22:37:35 -0600 Subject: [PATCH 167/347] use the same style for urgent() and sethints() --- dwl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 9219af5..ecb8a4b 100644 --- a/dwl.c +++ b/dwl.c @@ -2642,10 +2642,11 @@ urgent(struct wl_listener *listener, void *data) if (!c || c == focustop(selmon)) return; - if (client_surface(c)->mapped) - client_set_border_color(c, urgentcolor); c->isurgent = 1; printstatus(); + + if (client_surface(c)->mapped) + client_set_border_color(c, urgentcolor); } void @@ -2825,11 +2826,10 @@ sethints(struct wl_listener *listener, void *data) return; c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints); + printstatus(); if (c->isurgent && surface && surface->mapped) client_set_border_color(c, urgentcolor); - - printstatus(); } void From 1884a076460797b42d4670cb62bacd3871740c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 7 Dec 2023 22:40:59 -0600 Subject: [PATCH 168/347] sort LISTEN calls in createnotify{,x11} --- dwl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index ecb8a4b..6aa2cf3 100644 --- a/dwl.c +++ b/dwl.c @@ -967,15 +967,15 @@ createnotify(struct wl_listener *listener, void *data) wlr_xdg_toplevel_set_wm_capabilities(xdg_surface->toplevel, WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); + LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify); LISTEN(&xdg_surface->surface->events.commit, &c->commit, commitnotify); LISTEN(&xdg_surface->surface->events.map, &c->map, mapnotify); LISTEN(&xdg_surface->surface->events.unmap, &c->unmap, unmapnotify); - LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify); - LISTEN(&xdg_surface->toplevel->events.set_title, &c->set_title, updatetitle); LISTEN(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen, fullscreennotify); LISTEN(&xdg_surface->toplevel->events.request_maximize, &c->maximize, maximizenotify); + LISTEN(&xdg_surface->toplevel->events.set_title, &c->set_title, updatetitle); } void @@ -2787,13 +2787,13 @@ createnotifyx11(struct wl_listener *listener, void *data) /* Listen to the various events it can emit */ LISTEN(&xsurface->events.associate, &c->associate, associatex11); + LISTEN(&xsurface->events.destroy, &c->destroy, destroynotify); LISTEN(&xsurface->events.dissociate, &c->dissociate, dissociatex11); LISTEN(&xsurface->events.request_activate, &c->activate, activatex11); LISTEN(&xsurface->events.request_configure, &c->configure, configurex11); + LISTEN(&xsurface->events.request_fullscreen, &c->fullscreen, fullscreennotify); LISTEN(&xsurface->events.set_hints, &c->set_hints, sethints); LISTEN(&xsurface->events.set_title, &c->set_title, updatetitle); - LISTEN(&xsurface->events.destroy, &c->destroy, destroynotify); - LISTEN(&xsurface->events.request_fullscreen, &c->fullscreen, fullscreennotify); } void From 9c5bdcfbe86a58134af5d54f07d67524697f2a47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 10 Dec 2023 16:53:56 -0600 Subject: [PATCH 169/347] do not blindly try to send motion events when pointer button is pressed we don't have to do this if the surface is the same --- dwl.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/dwl.c b/dwl.c index 6aa2cf3..c4fb703 100644 --- a/dwl.c +++ b/dwl.c @@ -368,6 +368,7 @@ static struct wl_listener lock_listener = {.notify = locksession}; static struct wlr_seat *seat; static struct wl_list keyboards; +static struct wlr_surface *held_grab; static unsigned int cursor_mode; static Client *grabc; static int grabcx, grabcy; /* client-relative */ @@ -555,6 +556,7 @@ buttonpress(struct wl_listener *listener, void *data) switch (event->state) { case WLR_BUTTON_PRESSED: cursor_mode = CurPressed; + held_grab = seat->pointer_state.focused_surface; if (locked) break; @@ -574,6 +576,7 @@ buttonpress(struct wl_listener *listener, void *data) } break; case WLR_BUTTON_RELEASED: + held_grab = NULL; /* If you released any buttons, we exit interactive move/resize mode. */ /* TODO should reset to the pointer focus's current setcursor */ if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { @@ -1616,7 +1619,6 @@ motionnotify(uint32_t time) double sx = 0, sy = 0; Client *c = NULL, *w = NULL; LayerSurface *l = NULL; - int type; struct wlr_surface *surface = NULL; /* time is 0 in internal calls meant to restore pointer focus. */ @@ -1646,14 +1648,12 @@ motionnotify(uint32_t time) /* Find the client under the pointer and send the event along. */ xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy); - if (cursor_mode == CurPressed && !seat->drag) { - if ((type = toplevel_from_wlr_surface( - seat->pointer_state.focused_surface, &w, &l)) >= 0) { - c = w; - surface = seat->pointer_state.focused_surface; - sx = cursor->x - (type == LayerShell ? l->geom.x : w->geom.x); - sy = cursor->y - (type == LayerShell ? l->geom.y : w->geom.y); - } + if (cursor_mode == CurPressed && !seat->drag && surface != held_grab + && toplevel_from_wlr_surface(held_grab, &w, &l) >= 0) { + c = w; + surface = held_grab; + sx = cursor->x - (l ? l->geom.x : w->geom.x); + sy = cursor->y - (l ? l->geom.y : w->geom.y); } /* If there's no client surface under the cursor, set the cursor image to a From c88960751d7e422ad7eca1672c00ee09515e5095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 10 Dec 2023 23:42:35 -0600 Subject: [PATCH 170/347] check if a client is unmanaged checking the o-r flag it may change at any moment and I don't really want to add a listener for it --- client.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client.h b/client.h index 71c7d76..68e7534 100644 --- a/client.h +++ b/client.h @@ -270,7 +270,8 @@ static inline int client_is_unmanaged(Client *c) { #ifdef XWAYLAND - return c->type == X11Unmanaged; + if (client_is_x11(c)) + return c->surface.xwayland->override_redirect; #endif return 0; } From 49bfe927030b4747deded43656b4fe417c157123 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 10 Dec 2023 23:44:33 -0600 Subject: [PATCH 171/347] merge X11Managed and X11Unmanaged into X11 now that client_is_unmanaged() checks the wlr struct we don't need to keep track of it ourselves --- client.h | 2 +- dwl.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client.h b/client.h index 68e7534..dded687 100644 --- a/client.h +++ b/client.h @@ -10,7 +10,7 @@ static inline int client_is_x11(Client *c) { #ifdef XWAYLAND - return c->type == X11Managed || c->type == X11Unmanaged; + return c->type == X11; #endif return 0; } diff --git a/dwl.c b/dwl.c index c4fb703..8b58a86 100644 --- a/dwl.c +++ b/dwl.c @@ -74,7 +74,7 @@ /* enums */ enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ -enum { XDGShell, LayerShell, X11Managed, X11Unmanaged }; /* client types */ +enum { XDGShell, LayerShell, X11 }; /* client types */ enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrFS, LyrTop, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */ #ifdef XWAYLAND enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, @@ -2746,7 +2746,7 @@ activatex11(struct wl_listener *listener, void *data) Client *c = wl_container_of(listener, c, activate); /* Only "managed" windows can be activated */ - if (c->type == X11Managed) + if (!client_is_unmanaged(c)) wlr_xwayland_surface_activate(c->surface.xwayland, 1); } @@ -2766,7 +2766,7 @@ configurex11(struct wl_listener *listener, void *data) struct wlr_xwayland_surface_configure_event *event = data; if (!c->mon) return; - if (c->isfloating || c->type == X11Unmanaged) + if (c->isfloating || client_is_unmanaged(c)) resize(c, (struct wlr_box){.x = event->x, .y = event->y, .width = event->width, .height = event->height}, 0); else @@ -2782,7 +2782,7 @@ createnotifyx11(struct wl_listener *listener, void *data) /* Allocate a Client for this surface */ c = xsurface->data = ecalloc(1, sizeof(*c)); c->surface.xwayland = xsurface; - c->type = xsurface->override_redirect ? X11Unmanaged : X11Managed; + c->type = X11; c->bw = borderpx; /* Listen to the various events it can emit */ From 9a84789ff1ba5cac059e536d57a849917ab360b6 Mon Sep 17 00:00:00 2001 From: Dima Krasner Date: Fri, 8 Dec 2023 08:22:57 +0200 Subject: [PATCH 172/347] restore and respect rootcolor --- config.def.h | 1 + dwl.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/config.def.h b/config.def.h index 5375eb5..a8ed61d 100644 --- a/config.def.h +++ b/config.def.h @@ -7,6 +7,7 @@ static const int sloppyfocus = 1; /* focus follows mouse */ static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */ static const unsigned int borderpx = 1; /* border pixel of windows */ +static const float rootcolor[] = COLOR(0x222222ff); static const float bordercolor[] = COLOR(0x444444ff); static const float focuscolor[] = COLOR(0x005577ff); static const float urgentcolor[] = COLOR(0xff0000ff); diff --git a/dwl.c b/dwl.c index 8b58a86..73e0c54 100644 --- a/dwl.c +++ b/dwl.c @@ -361,6 +361,7 @@ static struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr; static struct wlr_cursor *cursor; static struct wlr_xcursor_manager *cursor_mgr; +static struct wlr_scene_rect *root_bg; static struct wlr_session_lock_manager_v1 *session_lock_mgr; static struct wlr_scene_rect *locked_bg; static struct wlr_session_lock_v1 *cur_lock; @@ -2181,6 +2182,7 @@ setup(void) /* Initialize the scene graph used to lay out windows */ scene = wlr_scene_create(); + root_bg = wlr_scene_rect_create(&scene->tree, 0, 0, rootcolor); for (i = 0; i < NUM_LAYERS; i++) layers[i] = wlr_scene_tree_create(&scene->tree); drag_icon = wlr_scene_tree_create(&scene->tree); @@ -2564,6 +2566,9 @@ updatemons(struct wl_listener *listener, void *data) /* Now that we update the output layout we can get its box */ wlr_output_layout_get_box(output_layout, NULL, &sgeom); + wlr_scene_node_set_position(&root_bg->node, sgeom.x, sgeom.y); + wlr_scene_rect_set_size(root_bg, sgeom.width, sgeom.height); + /* Make sure the clients are hidden when dwl is locked */ wlr_scene_node_set_position(&locked_bg->node, sgeom.x, sgeom.y); wlr_scene_rect_set_size(locked_bg, sgeom.width, sgeom.height); From fa660fb61e9c883901c43afaf3056af9a8b4736e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 12 Dec 2023 22:17:57 -0600 Subject: [PATCH 173/347] check toplevel resources it's just a aesthetic change --- client.h | 2 +- dwl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client.h b/client.h index dded687..1dae434 100644 --- a/client.h +++ b/client.h @@ -352,7 +352,7 @@ client_set_tiled(Client *c, uint32_t edges) if (client_is_x11(c)) return; #endif - if (wl_resource_get_version(c->surface.xdg->resource) + if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) { wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges); } else { diff --git a/dwl.c b/dwl.c index 73e0c54..4436285 100644 --- a/dwl.c +++ b/dwl.c @@ -1577,7 +1577,7 @@ maximizenotify(struct wl_listener *listener, void *data) * protocol version * wlr_xdg_surface_schedule_configure() is used to send an empty reply. */ Client *c = wl_container_of(listener, c, maximize); - if (wl_resource_get_version(c->surface.xdg->resource) + if (wl_resource_get_version(c->surface.xdg->toplevel->resource) < XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) wlr_xdg_surface_schedule_configure(c->surface.xdg); } From 023efce6eb26a7a1be974dfc6c932834bfc260e2 Mon Sep 17 00:00:00 2001 From: David Donahue Date: Tue, 12 Dec 2023 18:04:38 -0700 Subject: [PATCH 174/347] use wlr_keyboard_group to manage all keyboards --- dwl.c | 145 ++++++++++++++++++++++++++++------------------------------ 1 file changed, 71 insertions(+), 74 deletions(-) diff --git a/dwl.c b/dwl.c index 4436285..5469d4d 100644 --- a/dwl.c +++ b/dwl.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -141,7 +142,7 @@ typedef struct { typedef struct { struct wl_list link; - struct wlr_keyboard *wlr_keyboard; + struct wlr_keyboard_group *wlr_group; int nsyms; const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */ @@ -150,8 +151,7 @@ typedef struct { struct wl_listener modifiers; struct wl_listener key; - struct wl_listener destroy; -} Keyboard; +} KeyboardGroup; typedef struct { /* Must keep these three elements in this order */ @@ -238,7 +238,6 @@ static void buttonpress(struct wl_listener *listener, void *data); static void chvt(const Arg *arg); static void checkidleinhibitor(struct wlr_surface *exclude); static void cleanup(void); -static void cleanupkeyboard(struct wl_listener *listener, void *data); static void cleanupmon(struct wl_listener *listener, void *data); static void closemon(Monitor *m); static void commitlayersurfacenotify(struct wl_listener *listener, void *data); @@ -368,7 +367,7 @@ static struct wlr_session_lock_v1 *cur_lock; static struct wl_listener lock_listener = {.notify = locksession}; static struct wlr_seat *seat; -static struct wl_list keyboards; +static KeyboardGroup kb_group; static struct wlr_surface *held_grab; static unsigned int cursor_mode; static Client *grabc; @@ -636,25 +635,16 @@ cleanup(void) } wlr_xcursor_manager_destroy(cursor_mgr); wlr_output_layout_destroy(output_layout); + + /* Remove event source that use the dpy event loop before destroying dpy */ + wl_event_source_remove(kb_group.key_repeat_source); + wl_display_destroy(dpy); /* Destroy after the wayland display (when the monitors are already destroyed) to avoid destroying them with an invalid scene output. */ wlr_scene_node_destroy(&scene->tree.node); } -void -cleanupkeyboard(struct wl_listener *listener, void *data) -{ - Keyboard *kb = wl_container_of(listener, kb, destroy); - - wl_event_source_remove(kb->key_repeat_source); - wl_list_remove(&kb->link); - wl_list_remove(&kb->modifiers.link); - wl_list_remove(&kb->key.link); - wl_list_remove(&kb->destroy.link); - free(kb); -} - void cleanupmon(struct wl_listener *listener, void *data) { @@ -761,35 +751,12 @@ createidleinhibitor(struct wl_listener *listener, void *data) void createkeyboard(struct wlr_keyboard *keyboard) { - struct xkb_context *context; - struct xkb_keymap *keymap; - Keyboard *kb = keyboard->data = ecalloc(1, sizeof(*kb)); - kb->wlr_keyboard = keyboard; - - /* Prepare an XKB keymap and assign it to the keyboard. */ - context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - keymap = xkb_keymap_new_from_names(context, &xkb_rules, - XKB_KEYMAP_COMPILE_NO_FLAGS); - if (!keymap) - die("createkeyboard: failed to compile keymap"); - - wlr_keyboard_set_keymap(keyboard, keymap); - xkb_keymap_unref(keymap); - xkb_context_unref(context); + /* Set the keymap to match the group keymap */ + wlr_keyboard_set_keymap(keyboard, kb_group.wlr_group->keyboard.keymap); wlr_keyboard_set_repeat_info(keyboard, repeat_rate, repeat_delay); - /* Here we set up listeners for keyboard events. */ - LISTEN(&keyboard->events.modifiers, &kb->modifiers, keypressmod); - LISTEN(&keyboard->events.key, &kb->key, keypress); - LISTEN(&keyboard->base.events.destroy, &kb->destroy, cleanupkeyboard); - - wlr_seat_set_keyboard(seat, keyboard); - - kb->key_repeat_source = wl_event_loop_add_timer( - wl_display_get_event_loop(dpy), keyrepeat, kb); - - /* And add the keyboard to our list of keyboards */ - wl_list_insert(&keyboards, &kb->link); + /* Add the new keyboard to the group */ + wlr_keyboard_group_add_keyboard(kb_group.wlr_group, keyboard); } void @@ -1353,7 +1320,7 @@ inputdevice(struct wl_listener *listener, void *data) * there are no pointer devices, so we always include that capability. */ /* TODO do we actually require a cursor? */ caps = WL_SEAT_CAPABILITY_POINTER; - if (!wl_list_empty(&keyboards)) + if (!wl_list_empty(&kb_group.wlr_group->devices)) caps |= WL_SEAT_CAPABILITY_KEYBOARD; wlr_seat_set_capabilities(seat, caps); } @@ -1383,7 +1350,7 @@ keypress(struct wl_listener *listener, void *data) { int i; /* This event is raised when a key is pressed or released. */ - Keyboard *kb = wl_container_of(listener, kb, key); + KeyboardGroup *group = wl_container_of(listener, group, key); struct wlr_keyboard_key_event *event = data; /* Translate libinput keycode -> xkbcommon */ @@ -1391,10 +1358,10 @@ keypress(struct wl_listener *listener, void *data) /* Get a list of keysyms based on the keymap for this keyboard */ const xkb_keysym_t *syms; int nsyms = xkb_state_key_get_syms( - kb->wlr_keyboard->xkb_state, keycode, &syms); + group->wlr_group->keyboard.xkb_state, keycode, &syms); int handled = 0; - uint32_t mods = wlr_keyboard_get_modifiers(kb->wlr_keyboard); + uint32_t mods = wlr_keyboard_get_modifiers(&group->wlr_group->keyboard); wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); @@ -1404,22 +1371,21 @@ keypress(struct wl_listener *listener, void *data) for (i = 0; i < nsyms; i++) handled = keybinding(mods, syms[i]) || handled; - if (handled && kb->wlr_keyboard->repeat_info.delay > 0) { - kb->mods = mods; - kb->keysyms = syms; - kb->nsyms = nsyms; - wl_event_source_timer_update(kb->key_repeat_source, - kb->wlr_keyboard->repeat_info.delay); + if (handled && group->wlr_group->keyboard.repeat_info.delay > 0) { + group->mods = mods; + group->keysyms = syms; + group->nsyms = nsyms; + wl_event_source_timer_update(group->key_repeat_source, + group->wlr_group->keyboard.repeat_info.delay); } else { - kb->nsyms = 0; - wl_event_source_timer_update(kb->key_repeat_source, 0); + group->nsyms = 0; + wl_event_source_timer_update(group->key_repeat_source, 0); } if (handled) return; /* Pass unhandled keycodes along to the client. */ - wlr_seat_set_keyboard(seat, kb->wlr_keyboard); wlr_seat_keyboard_notify_key(seat, event->time_msec, event->keycode, event->state); } @@ -1429,32 +1395,26 @@ keypressmod(struct wl_listener *listener, void *data) { /* This event is raised when a modifier key, such as shift or alt, is * pressed. We simply communicate this to the client. */ - Keyboard *kb = wl_container_of(listener, kb, modifiers); - /* - * A seat can only have one keyboard, but this is a limitation of the - * Wayland protocol - not wlroots. We assign all connected keyboards to the - * same seat. You can swap out the underlying wlr_keyboard like this and - * wlr_seat handles this transparently. - */ - wlr_seat_set_keyboard(seat, kb->wlr_keyboard); + KeyboardGroup *group = wl_container_of(listener, group, modifiers); + /* Send modifiers to the client. */ wlr_seat_keyboard_notify_modifiers(seat, - &kb->wlr_keyboard->modifiers); + &group->wlr_group->keyboard.modifiers); } int keyrepeat(void *data) { - Keyboard *kb = data; + KeyboardGroup *group = data; int i; - if (!kb->nsyms || kb->wlr_keyboard->repeat_info.rate <= 0) + if (!group->nsyms || group->wlr_group->keyboard.repeat_info.rate <= 0) return 0; - wl_event_source_timer_update(kb->key_repeat_source, - 1000 / kb->wlr_keyboard->repeat_info.rate); + wl_event_source_timer_update(group->key_repeat_source, + 1000 / group->wlr_group->keyboard.repeat_info.rate); - for (i = 0; i < kb->nsyms; i++) - keybinding(kb->mods, kb->keysyms[i]); + for (i = 0; i < group->nsyms; i++) + keybinding(group->mods, group->keysyms[i]); return 0; } @@ -2160,6 +2120,9 @@ setsel(struct wl_listener *listener, void *data) void setup(void) { + struct xkb_context *context; + struct xkb_keymap *keymap; + int i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE}; struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig}; sigemptyset(&sa.sa_mask); @@ -2323,7 +2286,6 @@ setup(void) * pointer, touch, and drawing tablet device. We also rig up a listener to * let us know when new input devices are available on the backend. */ - wl_list_init(&keyboards); LISTEN_STATIC(&backend->events.new_input, inputdevice); virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy); LISTEN_STATIC(&virtual_keyboard_mgr->events.new_virtual_keyboard, virtualkeyboard); @@ -2334,6 +2296,41 @@ setup(void) LISTEN_STATIC(&seat->events.request_start_drag, requeststartdrag); LISTEN_STATIC(&seat->events.start_drag, startdrag); + /* + * Configures a keyboard group, which will keep track of all connected + * keyboards, keep their modifier and LED states in sync, and handle + * keypresses + */ + kb_group.wlr_group = wlr_keyboard_group_create(); + kb_group.wlr_group->data = &kb_group; + + /* Prepare an XKB keymap and assign it to the keyboard group. */ + context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + keymap = xkb_keymap_new_from_names(context, &xkb_rules, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) + die("failed to compile keymap"); + + wlr_keyboard_set_keymap(&kb_group.wlr_group->keyboard, keymap); + xkb_keymap_unref(keymap); + xkb_context_unref(context); + + wlr_keyboard_set_repeat_info(&kb_group.wlr_group->keyboard, repeat_rate, repeat_delay); + + /* Set up listeners for keyboard events */ + LISTEN(&kb_group.wlr_group->keyboard.events.key, &kb_group.key, keypress); + LISTEN(&kb_group.wlr_group->keyboard.events.modifiers, &kb_group.modifiers, keypressmod); + + kb_group.key_repeat_source = wl_event_loop_add_timer( + wl_display_get_event_loop(dpy), keyrepeat, &kb_group); + + /* A seat can only have one keyboard, but this is a limitation of the + * Wayland protocol - not wlroots. We assign all connected keyboards to the + * same wlr_keyboard_group, which provides a single wlr_keyboard interface for + * all of them. Set this combined wlr_keyboard as the seat keyboard. + */ + wlr_seat_set_keyboard(seat, &kb_group.wlr_group->keyboard); + output_mgr = wlr_output_manager_v1_create(dpy); LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply); LISTEN_STATIC(&output_mgr->events.test, outputmgrtest); From 7afdc191fe4e9b3d16604b7f0c96f9741247e2d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 17 Dec 2023 15:21:32 -0600 Subject: [PATCH 175/347] style fixes --- dwl.c | 152 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 77 insertions(+), 75 deletions(-) diff --git a/dwl.c b/dwl.c index 5469d4d..3d82fa6 100644 --- a/dwl.c +++ b/dwl.c @@ -436,9 +436,10 @@ applyrules(Client *c) c->isfloating = r->isfloating; newtags |= r->tags; i = 0; - wl_list_for_each(m, &mons, link) + wl_list_for_each(m, &mons, link) { if (r->monitor == i++) mon = m; + } } } wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrFloat : LyrTile]); @@ -475,9 +476,8 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int wl_list_for_each(l, list, link) { struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; - struct wlr_layer_surface_v1_state *state = &layer_surface->current; - if (exclusive != (state->exclusive_zone > 0)) + if (exclusive != (layer_surface->current.exclusive_zone > 0)) continue; wlr_scene_layer_surface_v1_configure(l->scene_layer, &full_area, usable_area); @@ -653,9 +653,10 @@ cleanupmon(struct wl_listener *listener, void *data) int i; /* m->layers[i] are intentionally not unlinked */ - for (i = 0; i < LENGTH(m->layers); i++) + for (i = 0; i < LENGTH(m->layers); i++) { wl_list_for_each_safe(l, tmp, &m->layers[i], link) wlr_layer_surface_v1_destroy(l->layer_surface); + } wl_list_remove(&m->destroy.link); wl_list_remove(&m->frame.link); @@ -676,10 +677,10 @@ closemon(Monitor *m) /* update selmon if needed and * move closed monitor's clients to the focused one */ Client *c; - if (wl_list_empty(&mons)) { + int i = 0, nmons = wl_list_length(&mons); + if (!nmons) { selmon = NULL; } else if (m == selmon) { - int nmons = wl_list_length(&mons), i = 0; do /* don't switch to disabled mons */ selmon = wl_container_of(mons.next, selmon, link); while (!selmon->wlr_output->enabled && i++ < nmons); @@ -688,7 +689,7 @@ closemon(Monitor *m) wl_list_for_each(c, &clients, link) { if (c->isfloating && c->geom.x > m->m.width) resize(c, (struct wlr_box){.x = c->geom.x - m->w.width, .y = c->geom.y, - .width = c->geom.width, .height = c->geom.height}, 0); + .width = c->geom.width, .height = c->geom.height}, 0); if (c->mon == m) setmon(c, selmon, c->tags); } @@ -808,8 +809,8 @@ createlocksurface(struct wl_listener *listener, void *data) SessionLock *lock = wl_container_of(listener, lock, new_surface); struct wlr_session_lock_surface_v1 *lock_surface = data; Monitor *m = lock_surface->output->data; - struct wlr_scene_tree *scene_tree = lock_surface->surface->data = - wlr_scene_subsurface_tree_create(lock->scene, lock_surface->surface); + struct wlr_scene_tree *scene_tree = lock_surface->surface->data + = wlr_scene_subsurface_tree_create(lock->scene, lock_surface->surface); m->lock_surface = lock_surface; wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y); @@ -914,18 +915,18 @@ createnotify(struct wl_listener *listener, void *data) LayerSurface *l = NULL; if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { + struct wlr_xdg_popup *popup = xdg_surface->popup; struct wlr_box box; - int type = toplevel_from_wlr_surface(xdg_surface->surface, &c, &l); - if (!xdg_surface->popup->parent || type < 0) + if (toplevel_from_wlr_surface(popup->base->surface, &c, &l) < 0) return; - xdg_surface->surface->data = wlr_scene_xdg_surface_create( - xdg_surface->popup->parent->data, xdg_surface); + popup->base->surface->data = wlr_scene_xdg_surface_create( + popup->parent->data, popup->base); if ((l && !l->mon) || (c && !c->mon)) return; - box = type == LayerShell ? l->mon->m : c->mon->w; - box.x -= (type == LayerShell ? l->geom.x : c->geom.x); - box.y -= (type == LayerShell ? l->geom.y : c->geom.y); - wlr_xdg_popup_unconstrain_from_box(xdg_surface->popup, &box); + box = l ? l->mon->m : c->mon->w; + box.x -= (l ? l->geom.x : c->geom.x); + box.y -= (l ? l->geom.y : c->geom.y); + wlr_xdg_popup_unconstrain_from_box(popup, &box); return; } else if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_NONE) return; @@ -952,40 +953,41 @@ createnotify(struct wl_listener *listener, void *data) void createpointer(struct wlr_pointer *pointer) { - if (wlr_input_device_is_libinput(&pointer->base)) { - struct libinput_device *libinput_device = wlr_libinput_get_device_handle(&pointer->base); + struct libinput_device *device; + if (wlr_input_device_is_libinput(&pointer->base) + && (device = wlr_libinput_get_device_handle(&pointer->base))) { - if (libinput_device_config_tap_get_finger_count(libinput_device)) { - libinput_device_config_tap_set_enabled(libinput_device, tap_to_click); - libinput_device_config_tap_set_drag_enabled(libinput_device, tap_and_drag); - libinput_device_config_tap_set_drag_lock_enabled(libinput_device, drag_lock); - libinput_device_config_tap_set_button_map(libinput_device, button_map); + if (libinput_device_config_tap_get_finger_count(device)) { + libinput_device_config_tap_set_enabled(device, tap_to_click); + libinput_device_config_tap_set_drag_enabled(device, tap_and_drag); + libinput_device_config_tap_set_drag_lock_enabled(device, drag_lock); + libinput_device_config_tap_set_button_map(device, button_map); } - if (libinput_device_config_scroll_has_natural_scroll(libinput_device)) - libinput_device_config_scroll_set_natural_scroll_enabled(libinput_device, natural_scrolling); + if (libinput_device_config_scroll_has_natural_scroll(device)) + libinput_device_config_scroll_set_natural_scroll_enabled(device, natural_scrolling); - if (libinput_device_config_dwt_is_available(libinput_device)) - libinput_device_config_dwt_set_enabled(libinput_device, disable_while_typing); + if (libinput_device_config_dwt_is_available(device)) + libinput_device_config_dwt_set_enabled(device, disable_while_typing); - if (libinput_device_config_left_handed_is_available(libinput_device)) - libinput_device_config_left_handed_set(libinput_device, left_handed); + if (libinput_device_config_left_handed_is_available(device)) + libinput_device_config_left_handed_set(device, left_handed); - if (libinput_device_config_middle_emulation_is_available(libinput_device)) - libinput_device_config_middle_emulation_set_enabled(libinput_device, middle_button_emulation); + if (libinput_device_config_middle_emulation_is_available(device)) + libinput_device_config_middle_emulation_set_enabled(device, middle_button_emulation); - if (libinput_device_config_scroll_get_methods(libinput_device) != LIBINPUT_CONFIG_SCROLL_NO_SCROLL) - libinput_device_config_scroll_set_method (libinput_device, scroll_method); + if (libinput_device_config_scroll_get_methods(device) != LIBINPUT_CONFIG_SCROLL_NO_SCROLL) + libinput_device_config_scroll_set_method (device, scroll_method); - if (libinput_device_config_click_get_methods(libinput_device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE) - libinput_device_config_click_set_method (libinput_device, click_method); + if (libinput_device_config_click_get_methods(device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE) + libinput_device_config_click_set_method (device, click_method); - if (libinput_device_config_send_events_get_modes(libinput_device)) - libinput_device_config_send_events_set_mode(libinput_device, send_events_mode); + if (libinput_device_config_send_events_get_modes(device)) + libinput_device_config_send_events_set_mode(device, send_events_mode); - if (libinput_device_config_accel_is_available(libinput_device)) { - libinput_device_config_accel_set_profile(libinput_device, accel_profile); - libinput_device_config_accel_set_speed(libinput_device, accel_speed); + if (libinput_device_config_accel_is_available(device)) { + libinput_device_config_accel_set_profile(device, accel_profile); + libinput_device_config_accel_set_speed(device, accel_speed); } } @@ -1212,10 +1214,11 @@ void focusmon(const Arg *arg) { int i = 0, nmons = wl_list_length(&mons); - if (nmons) + if (nmons) { do /* don't switch to disabled mons */ selmon = dirtomon(arg->i); while (!selmon->wlr_output->enabled && i++ < nmons); + } focusclient(focustop(selmon), 1); } @@ -1252,9 +1255,10 @@ Client * focustop(Monitor *m) { Client *c; - wl_list_for_each(c, &fstack, flink) + wl_list_for_each(c, &fstack, flink) { if (VISIBLEON(c, m)) return c; + } return NULL; } @@ -1336,8 +1340,8 @@ keybinding(uint32_t mods, xkb_keysym_t sym) int handled = 0; const Key *k; for (k = keys; k < END(keys); k++) { - if (CLEANMASK(mods) == CLEANMASK(k->mod) && - sym == k->keysym && k->func) { + if (CLEANMASK(mods) == CLEANMASK(k->mod) + && sym == k->keysym && k->func) { k->func(&k->arg); handled = 1; } @@ -1387,7 +1391,7 @@ keypress(struct wl_listener *listener, void *data) /* Pass unhandled keycodes along to the client. */ wlr_seat_keyboard_notify_key(seat, event->time_msec, - event->keycode, event->state); + event->keycode, event->state); } void @@ -1399,7 +1403,7 @@ keypressmod(struct wl_listener *listener, void *data) /* Send modifiers to the client. */ wlr_seat_keyboard_notify_modifiers(seat, - &group->wlr_group->keyboard.modifiers); + &group->wlr_group->keyboard.modifiers); } int @@ -1481,7 +1485,7 @@ mapnotify(struct wl_listener *listener, void *data) /* Unmanaged clients always are floating */ wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]); wlr_scene_node_set_position(&c->scene->node, c->geom.x + borderpx, - c->geom.y + borderpx); + c->geom.y + borderpx); if (client_wants_focus(c)) { focusclient(c, 1); exclusive_focus = c; @@ -1508,7 +1512,7 @@ mapnotify(struct wl_listener *listener, void *data) * we always consider floating, clients that have parent and thus * we set the same tags and monitor than its parent, if not * try to apply rules for them */ - /* TODO: https://github.com/djpohly/dwl/pull/334#issuecomment-1330166324 */ + /* TODO: https://github.com/djpohly/dwl/pull/334#issuecomment-1330166324 */ if (c->type == XDGShell && (p = client_get_parent(c))) { c->isfloating = 1; wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]); @@ -1520,9 +1524,10 @@ mapnotify(struct wl_listener *listener, void *data) unset_fullscreen: m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y); - wl_list_for_each(w, &clients, link) + wl_list_for_each(w, &clients, link) { if (w != c && w->isfullscreen && m == w->mon && (w->tags & c->tags)) setfullscreen(w, 0); + } } void @@ -1745,9 +1750,8 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, uint32_t time) { struct timespec now; - int internal_call = !time; - if (sloppyfocus && !internal_call && c && !client_is_unmanaged(c)) + if (sloppyfocus && time && c && !client_is_unmanaged(c)) focusclient(c, 0); /* If surface is NULL, clear pointer focus */ @@ -1756,7 +1760,7 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, return; } - if (internal_call) { + if (!time) { clock_gettime(CLOCK_MONOTONIC, &now); time = now.tv_sec * 1000 + now.tv_nsec / 1000000; } @@ -1803,8 +1807,8 @@ printstatus(void) } printf("%s selmon %u\n", m->wlr_output->name, m == selmon); - printf("%s tags %u %u %u %u\n", m->wlr_output->name, occ, m->tagset[m->seltags], - sel, urg); + printf("%s tags %u %u %u %u\n", m->wlr_output->name, occ, + m->tagset[m->seltags], sel, urg); printf("%s layout %s\n", m->wlr_output->name, m->ltsymbol); } fflush(stdout); @@ -1829,9 +1833,10 @@ rendermon(struct wl_listener *listener, void *data) /* Render if no XDG clients have an outstanding resize and are visible on * this monitor. */ - wl_list_for_each(c, &clients, link) + wl_list_for_each(c, &clients, link) { if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && !client_is_stopped(c)) goto skip; + } /* * HACK: The "correct" way to set the gamma is to commit it together with @@ -1842,7 +1847,8 @@ rendermon(struct wl_listener *listener, void *data) * the gamma can not be committed). */ if (m->gamma_lut_changed) { - gamma_control = wlr_gamma_control_manager_v1_get_control(gamma_control_mgr, m->wlr_output); + gamma_control + = wlr_gamma_control_manager_v1_get_control(gamma_control_mgr, m->wlr_output); m->gamma_lut_changed = 0; if (!wlr_gamma_control_v1_apply(gamma_control, &pending)) @@ -1996,7 +2002,7 @@ setcursorshape(struct wl_listener *listener, void *data) * use the provided cursor shape. */ if (event->seat_client == seat->pointer_state.focused_client) wlr_cursor_set_xcursor(cursor, cursor_mgr, - wlr_cursor_shape_v1_name(event->shape)); + wlr_cursor_shape_v1_name(event->shape)); } void @@ -2243,7 +2249,7 @@ setup(void) /* Use decoration protocols to negotiate server-side decorations */ wlr_server_decoration_manager_set_default_mode( wlr_server_decoration_manager_create(dpy), - WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); + WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy); LISTEN_STATIC(&xdg_decoration_mgr->events.new_toplevel_decoration, createdecoration); @@ -2306,9 +2312,8 @@ setup(void) /* Prepare an XKB keymap and assign it to the keyboard group. */ context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - keymap = xkb_keymap_new_from_names(context, &xkb_rules, - XKB_KEYMAP_COMPILE_NO_FLAGS); - if (!keymap) + if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules, + XKB_KEYMAP_COMPILE_NO_FLAGS))) die("failed to compile keymap"); wlr_keyboard_set_keymap(&kb_group.wlr_group->keyboard, keymap); @@ -2342,8 +2347,7 @@ setup(void) * Initialise the XWayland X server. * It will be started when the first X client is started. */ - xwayland = wlr_xwayland_create(dpy, compositor, 1); - if (xwayland) { + if (!(xwayland = wlr_xwayland_create(dpy, compositor, 1))) { LISTEN_STATIC(&xwayland->events.ready, xwaylandready); LISTEN_STATIC(&xwayland->events.new_surface, createnotifyx11); @@ -2452,10 +2456,7 @@ toggletag(const Arg *arg) { uint32_t newtags; Client *sel = focustop(selmon); - if (!sel) - return; - newtags = sel->tags ^ (arg->ui & TAGMASK); - if (!newtags) + if (!sel || !(newtags = sel->tags ^ (arg->ui & TAGMASK))) return; sel->tags = newtags; @@ -2467,9 +2468,8 @@ toggletag(const Arg *arg) void toggleview(const Arg *arg) { - uint32_t newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0; - - if (!newtagset) + uint32_t newtagset; + if (!(newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0)) return; selmon->tagset[selmon->seltags] = newtagset; @@ -2537,8 +2537,8 @@ updatemons(struct wl_listener *listener, void *data) * positions, focus, and the stored configuration in wlroots' * output-manager implementation. */ - struct wlr_output_configuration_v1 *config = - wlr_output_configuration_v1_create(); + struct wlr_output_configuration_v1 *config + = wlr_output_configuration_v1_create(); Client *c; struct wlr_output_configuration_head_v1 *config_head; Monitor *m; @@ -2606,9 +2606,10 @@ updatemons(struct wl_listener *listener, void *data) } if (selmon && selmon->wlr_output->enabled) { - wl_list_for_each(c, &clients, link) + wl_list_for_each(c, &clients, link) { if (!c->mon && client_surface(c)->mapped) setmon(c, selmon, c->tags); + } focusclient(focustop(selmon), 1); if (selmon->lock_surface) { client_notify_enter(selmon->lock_surface->surface, @@ -2719,12 +2720,13 @@ zoom(const Arg *arg) /* Search for the first tiled window that is not sel, marking sel as * NULL if we pass it along the way */ - wl_list_for_each(c, &clients, link) + wl_list_for_each(c, &clients, link) { if (VISIBLEON(c, selmon) && !c->isfloating) { if (c != sel) break; sel = NULL; } + } /* Return if no other tiled window was found */ if (&c->link == &clients) From a71b368483909ab030fe3ccbbbf8d320b2d5f2dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 8 Dec 2023 12:52:56 -0600 Subject: [PATCH 176/347] Revert "remove typedef `Decoration`" This reverts commit d1ff1e6f75d9c53c953957b5c0a64e0bcb40008b. --- dwl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dwl.c b/dwl.c index 3d82fa6..32a4df8 100644 --- a/dwl.c +++ b/dwl.c @@ -133,6 +133,11 @@ typedef struct { uint32_t resize; /* configure serial of a pending resize */ } Client; +typedef struct { + struct wl_listener request_mode; + struct wl_listener destroy; +} Decoration; + typedef struct { uint32_t mod; xkb_keysym_t keysym; From 396840cdf215b4affea28ac39f10f0011da94ed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 8 Dec 2023 12:52:46 -0600 Subject: [PATCH 177/347] Revert "nuke CSDs, hopefully for good!" The compositor must respond to the client requesting a change to the decoration mode, it does not matter if the compositor chooses a different mode. This reverts commit 9071ce6c848ce214939fb84f85ae77de86de88d7. --- dwl.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 32a4df8..bb83168 100644 --- a/dwl.c +++ b/dwl.c @@ -264,12 +264,14 @@ static void destroylocksurface(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); static void destroysessionlock(struct wl_listener *listener, void *data); static void destroysessionmgr(struct wl_listener *listener, void *data); +static void destroyxdeco(struct wl_listener *listener, void *data); static Monitor *dirtomon(enum wlr_direction dir); static void focusclient(Client *c, int lift); static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); static Client *focustop(Monitor *m); static void fullscreennotify(struct wl_listener *listener, void *data); +static void getxdecomode(struct wl_listener *listener, void *data); static void handlesig(int signo); static void incnmaster(const Arg *arg); static void inputdevice(struct wl_listener *listener, void *data); @@ -741,8 +743,13 @@ commitnotify(struct wl_listener *listener, void *data) void createdecoration(struct wl_listener *listener, void *data) { - struct wlr_xdg_toplevel_decoration_v1 *dec = data; - wlr_xdg_toplevel_decoration_v1_set_mode(dec, WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + struct wlr_xdg_toplevel_decoration_v1 *wlr_deco = data; + Decoration *d = wlr_deco->data = calloc(1, sizeof(*d)); + + LISTEN(&wlr_deco->events.request_mode, &d->request_mode, getxdecomode); + LISTEN(&wlr_deco->events.destroy, &d->destroy, destroyxdeco); + + getxdecomode(&d->request_mode, wlr_deco); } void @@ -1124,6 +1131,17 @@ destroysessionmgr(struct wl_listener *listener, void *data) wl_list_remove(&listener->link); } +void +destroyxdeco(struct wl_listener *listener, void *data) +{ + struct wlr_xdg_toplevel_decoration_v1 *wlr_deco = data; + Decoration *d = wlr_deco->data; + + wl_list_remove(&d->destroy.link); + wl_list_remove(&d->request_mode.link); + free(d); +} + Monitor * dirtomon(enum wlr_direction dir) { @@ -1274,6 +1292,14 @@ fullscreennotify(struct wl_listener *listener, void *data) setfullscreen(c, client_wants_fullscreen(c)); } +void +getxdecomode(struct wl_listener *listener, void *data) +{ + struct wlr_xdg_toplevel_decoration_v1 *wlr_deco = data; + wlr_xdg_toplevel_decoration_v1_set_mode(wlr_deco, + WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); +} + void handlesig(int signo) { From e39d931430fdca12bf9cad28dfea3f2c938dd3fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 8 Dec 2023 13:44:28 -0600 Subject: [PATCH 178/347] tie xdg_toplevel_decorations to Client a xdg_toplevel can only have one xdg_toplevel_decoration so there is no need to have a new struct for decorations --- dwl.c | 59 ++++++++++++++++++++++++++++------------------------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/dwl.c b/dwl.c index bb83168..d52c908 100644 --- a/dwl.c +++ b/dwl.c @@ -111,6 +111,7 @@ typedef struct { struct wlr_xdg_surface *xdg; struct wlr_xwayland_surface *xwayland; } surface; + struct wlr_xdg_toplevel_decoration_v1 *decoration; struct wl_listener commit; struct wl_listener map; struct wl_listener maximize; @@ -118,6 +119,8 @@ typedef struct { struct wl_listener destroy; struct wl_listener set_title; struct wl_listener fullscreen; + struct wl_listener set_decoration_mode; + struct wl_listener destroy_decoration; struct wlr_box prev; /* layout-relative, includes border */ struct wlr_box bounds; #ifdef XWAYLAND @@ -133,11 +136,6 @@ typedef struct { uint32_t resize; /* configure serial of a pending resize */ } Client; -typedef struct { - struct wl_listener request_mode; - struct wl_listener destroy; -} Decoration; - typedef struct { uint32_t mod; xkb_keysym_t keysym; @@ -256,6 +254,7 @@ static void createmon(struct wl_listener *listener, void *data); static void createnotify(struct wl_listener *listener, void *data); static void createpointer(struct wlr_pointer *pointer); static void cursorframe(struct wl_listener *listener, void *data); +static void destroydecoration(struct wl_listener *listener, void *data); static void destroydragicon(struct wl_listener *listener, void *data); static void destroyidleinhibitor(struct wl_listener *listener, void *data); static void destroylayersurfacenotify(struct wl_listener *listener, void *data); @@ -264,14 +263,12 @@ static void destroylocksurface(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); static void destroysessionlock(struct wl_listener *listener, void *data); static void destroysessionmgr(struct wl_listener *listener, void *data); -static void destroyxdeco(struct wl_listener *listener, void *data); static Monitor *dirtomon(enum wlr_direction dir); static void focusclient(Client *c, int lift); static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); static Client *focustop(Monitor *m); static void fullscreennotify(struct wl_listener *listener, void *data); -static void getxdecomode(struct wl_listener *listener, void *data); static void handlesig(int signo); static void incnmaster(const Arg *arg); static void inputdevice(struct wl_listener *listener, void *data); @@ -297,6 +294,7 @@ static void pointerfocus(Client *c, struct wlr_surface *surface, static void printstatus(void); static void quit(const Arg *arg); static void rendermon(struct wl_listener *listener, void *data); +static void requestdecorationmode(struct wl_listener *listener, void *data); static void requeststartdrag(struct wl_listener *listener, void *data); static void requestmonstate(struct wl_listener *listener, void *data); static void resize(Client *c, struct wlr_box geo, int interact); @@ -743,13 +741,14 @@ commitnotify(struct wl_listener *listener, void *data) void createdecoration(struct wl_listener *listener, void *data) { - struct wlr_xdg_toplevel_decoration_v1 *wlr_deco = data; - Decoration *d = wlr_deco->data = calloc(1, sizeof(*d)); + struct wlr_xdg_toplevel_decoration_v1 *deco = data; + Client *c = deco->toplevel->base->data; + c->decoration = deco; - LISTEN(&wlr_deco->events.request_mode, &d->request_mode, getxdecomode); - LISTEN(&wlr_deco->events.destroy, &d->destroy, destroyxdeco); + LISTEN(&deco->events.request_mode, &c->set_decoration_mode, requestdecorationmode); + LISTEN(&deco->events.destroy, &c->destroy_decoration, destroydecoration); - getxdecomode(&d->request_mode, wlr_deco); + requestdecorationmode(&c->set_decoration_mode, deco); } void @@ -1017,6 +1016,15 @@ cursorframe(struct wl_listener *listener, void *data) wlr_seat_pointer_notify_frame(seat); } +void +destroydecoration(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, destroy_decoration); + + wl_list_remove(&c->destroy_decoration.link); + wl_list_remove(&c->set_decoration_mode.link); +} + void destroydragicon(struct wl_listener *listener, void *data) { @@ -1131,17 +1139,6 @@ destroysessionmgr(struct wl_listener *listener, void *data) wl_list_remove(&listener->link); } -void -destroyxdeco(struct wl_listener *listener, void *data) -{ - struct wlr_xdg_toplevel_decoration_v1 *wlr_deco = data; - Decoration *d = wlr_deco->data; - - wl_list_remove(&d->destroy.link); - wl_list_remove(&d->request_mode.link); - free(d); -} - Monitor * dirtomon(enum wlr_direction dir) { @@ -1292,14 +1289,6 @@ fullscreennotify(struct wl_listener *listener, void *data) setfullscreen(c, client_wants_fullscreen(c)); } -void -getxdecomode(struct wl_listener *listener, void *data) -{ - struct wlr_xdg_toplevel_decoration_v1 *wlr_deco = data; - wlr_xdg_toplevel_decoration_v1_set_mode(wlr_deco, - WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); -} - void handlesig(int signo) { @@ -1903,6 +1892,14 @@ skip: wlr_output_state_finish(&pending); } +void +requestdecorationmode(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, set_decoration_mode); + wlr_xdg_toplevel_decoration_v1_set_mode(c->decoration, + WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); +} + void requeststartdrag(struct wl_listener *listener, void *data) { From 23fd312409f86848da5b163ae5c19c8e50e09d7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 18 Dec 2023 14:08:09 -0600 Subject: [PATCH 179/347] fix typo Fixes: 7afdc191fe4e9b3d16604b7f0c96f9741247e2d2 Thanks to: David Donahue --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index d52c908..76c2e38 100644 --- a/dwl.c +++ b/dwl.c @@ -2375,7 +2375,7 @@ setup(void) * Initialise the XWayland X server. * It will be started when the first X client is started. */ - if (!(xwayland = wlr_xwayland_create(dpy, compositor, 1))) { + if ((xwayland = wlr_xwayland_create(dpy, compositor, 1))) { LISTEN_STATIC(&xwayland->events.ready, xwaylandready); LISTEN_STATIC(&xwayland->events.new_surface, createnotifyx11); From 1f0afcfc286463ea95d6f84f703060af5d3b64dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 25 Dec 2023 11:18:42 -0600 Subject: [PATCH 180/347] create a wlr_keyboard_group for virtual keyboards Fixes: https://codeberg.org/dwl/dwl/issues/554 --- dwl.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 76c2e38..edf0cf1 100644 --- a/dwl.c +++ b/dwl.c @@ -372,7 +372,8 @@ static struct wlr_session_lock_v1 *cur_lock; static struct wl_listener lock_listener = {.notify = locksession}; static struct wlr_seat *seat; -static KeyboardGroup kb_group; +static KeyboardGroup kb_group = {0}; +static KeyboardGroup vkb_group = {0}; static struct wlr_surface *held_grab; static unsigned int cursor_mode; static Client *grabc; @@ -643,6 +644,7 @@ cleanup(void) /* Remove event source that use the dpy event loop before destroying dpy */ wl_event_source_remove(kb_group.key_repeat_source); + wl_event_source_remove(vkb_group.key_repeat_source); wl_display_destroy(dpy); /* Destroy after the wayland display (when the monitors are already destroyed) @@ -1409,6 +1411,7 @@ keypress(struct wl_listener *listener, void *data) if (handled) return; + wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); /* Pass unhandled keycodes along to the client. */ wlr_seat_keyboard_notify_key(seat, event->time_msec, event->keycode, event->state); @@ -1421,6 +1424,7 @@ keypressmod(struct wl_listener *listener, void *data) * pressed. We simply communicate this to the client. */ KeyboardGroup *group = wl_container_of(listener, group, modifiers); + wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); /* Send modifiers to the client. */ wlr_seat_keyboard_notify_modifiers(seat, &group->wlr_group->keyboard.modifiers); @@ -2338,6 +2342,13 @@ setup(void) kb_group.wlr_group = wlr_keyboard_group_create(); kb_group.wlr_group->data = &kb_group; + /* + * Virtual keyboards need to be in a different group + * https://codeberg.org/dwl/dwl/issues/554 + */ + vkb_group.wlr_group = wlr_keyboard_group_create(); + vkb_group.wlr_group->data = &vkb_group; + /* Prepare an XKB keymap and assign it to the keyboard group. */ context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules, @@ -2345,17 +2356,23 @@ setup(void) die("failed to compile keymap"); wlr_keyboard_set_keymap(&kb_group.wlr_group->keyboard, keymap); + wlr_keyboard_set_keymap(&vkb_group.wlr_group->keyboard, keymap); xkb_keymap_unref(keymap); xkb_context_unref(context); wlr_keyboard_set_repeat_info(&kb_group.wlr_group->keyboard, repeat_rate, repeat_delay); + wlr_keyboard_set_repeat_info(&vkb_group.wlr_group->keyboard, repeat_rate, repeat_delay); /* Set up listeners for keyboard events */ LISTEN(&kb_group.wlr_group->keyboard.events.key, &kb_group.key, keypress); LISTEN(&kb_group.wlr_group->keyboard.events.modifiers, &kb_group.modifiers, keypressmod); + LISTEN(&vkb_group.wlr_group->keyboard.events.key, &vkb_group.key, keypress); + LISTEN(&vkb_group.wlr_group->keyboard.events.modifiers, &vkb_group.modifiers, keypressmod); kb_group.key_repeat_source = wl_event_loop_add_timer( wl_display_get_event_loop(dpy), keyrepeat, &kb_group); + vkb_group.key_repeat_source = wl_event_loop_add_timer( + wl_display_get_event_loop(dpy), keyrepeat, &vkb_group); /* A seat can only have one keyboard, but this is a limitation of the * Wayland protocol - not wlroots. We assign all connected keyboards to the @@ -2697,7 +2714,12 @@ void virtualkeyboard(struct wl_listener *listener, void *data) { struct wlr_virtual_keyboard_v1 *keyboard = data; - createkeyboard(&keyboard->keyboard); + /* Set the keymap to match the group keymap */ + wlr_keyboard_set_keymap(&keyboard->keyboard, vkb_group.wlr_group->keyboard.keymap); + wlr_keyboard_set_repeat_info(&keyboard->keyboard, repeat_rate, repeat_delay); + + /* Add the new keyboard to the group */ + wlr_keyboard_group_add_keyboard(vkb_group.wlr_group, &keyboard->keyboard); } Monitor * From e277d84c51942605ca69d426e1fb87a25b64237a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 27 Dec 2023 11:17:52 -0600 Subject: [PATCH 181/347] more style fixes missed from the previous iteration --- dwl.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/dwl.c b/dwl.c index edf0cf1..f9788d2 100644 --- a/dwl.c +++ b/dwl.c @@ -522,13 +522,13 @@ arrangelayers(Monitor *m) /* Find topmost keyboard interactive layer, if such a layer exists */ for (i = 0; i < LENGTH(layers_above_shell); i++) { wl_list_for_each_reverse(l, &m->layers[layers_above_shell[i]], link) { - if (!locked && l->layer_surface->current.keyboard_interactive && l->mapped) { - /* Deactivate the focused client. */ - focusclient(NULL, 0); - exclusive_focus = l; - client_notify_enter(l->layer_surface->surface, wlr_seat_get_keyboard(seat)); - return; - } + if (locked || !l->layer_surface->current.keyboard_interactive || !l->mapped) + continue; + /* Deactivate the focused client. */ + focusclient(NULL, 0); + exclusive_focus = l; + client_notify_enter(l->layer_surface->surface, wlr_seat_get_keyboard(seat)); + return; } } } @@ -711,7 +711,6 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; struct wlr_scene_tree *scene_layer = layers[layermap[layer_surface->current.layer]]; - if (layer_surface->current.committed == 0 && l->mapped == layer_surface->surface->mapped) return; l->mapped = layer_surface->surface->mapped; @@ -1393,9 +1392,10 @@ keypress(struct wl_listener *listener, void *data) /* On _press_ if there is no active screen locker, * attempt to process a compositor keybinding. */ - if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) + if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { for (i = 0; i < nsyms; i++) handled = keybinding(mods, syms[i]) || handled; + } if (handled && group->wlr_group->keyboard.repeat_info.delay > 0) { group->mods = mods; @@ -2281,7 +2281,7 @@ setup(void) /* Use decoration protocols to negotiate server-side decorations */ wlr_server_decoration_manager_set_default_mode( wlr_server_decoration_manager_create(dpy), - WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); + WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy); LISTEN_STATIC(&xdg_decoration_mgr->events.new_toplevel_decoration, createdecoration); @@ -2557,10 +2557,10 @@ unmapnotify(struct wl_listener *listener, void *data) } if (client_is_unmanaged(c)) { - if (c == exclusive_focus) + if (c == exclusive_focus) { exclusive_focus = NULL; - if (client_surface(c) == seat->keyboard_state.focused_surface) focusclient(focustop(selmon), 1); + } } else { wl_list_remove(&c->link); setmon(c, NULL, 0); @@ -2600,10 +2600,11 @@ updatemons(struct wl_listener *listener, void *data) m->m = m->w = (struct wlr_box){0}; } /* Insert outputs that need to */ - wl_list_for_each(m, &mons, link) + wl_list_for_each(m, &mons, link) { if (m->wlr_output->enabled && !wlr_output_layout_get(output_layout, m->wlr_output)) wlr_output_layout_add_auto(output_layout, m->wlr_output); + } /* Now that we update the output layout we can get its box */ wlr_output_layout_get_box(output_layout, NULL, &sgeom); From d13015381b5761bbc52cebae042edacecd739a2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 27 Dec 2023 11:18:24 -0600 Subject: [PATCH 182/347] only execute the first keybinding --- dwl.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index f9788d2..14ef091 100644 --- a/dwl.c +++ b/dwl.c @@ -1358,16 +1358,15 @@ keybinding(uint32_t mods, xkb_keysym_t sym) * processing keys, rather than passing them on to the client for its own * processing. */ - int handled = 0; const Key *k; for (k = keys; k < END(keys); k++) { if (CLEANMASK(mods) == CLEANMASK(k->mod) && sym == k->keysym && k->func) { k->func(&k->arg); - handled = 1; + return 1; } } - return handled; + return 0; } void From 6cbf8e9b80d8be140bd4a71268b483ac1b5c9d5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 27 Dec 2023 11:19:03 -0600 Subject: [PATCH 183/347] unset DISPLAY before setting up xwayland --- dwl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dwl.c b/dwl.c index 14ef091..10d5a5b 100644 --- a/dwl.c +++ b/dwl.c @@ -2386,6 +2386,10 @@ setup(void) wlr_scene_set_presentation(scene, wlr_presentation_create(dpy, backend)); + /* Make sure XWayland clients don't connect to the parent X server, + * e.g when running in the x11 backend or the wayland backend and the + * compositor has Xwayland support */ + unsetenv("DISPLAY"); #ifdef XWAYLAND /* * Initialise the XWayland X server. From 05c263de45f9f4ab2262e6bba111e7b95c153556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 27 Dec 2023 11:45:36 -0600 Subject: [PATCH 184/347] only create wlr_presentation (wlroots!4482) References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4482 --- dwl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index ec2b1c1..d0ac38a 100644 --- a/dwl.c +++ b/dwl.c @@ -2231,6 +2231,7 @@ setup(void) wlr_viewporter_create(dpy); wlr_single_pixel_buffer_manager_v1_create(dpy); wlr_fractional_scale_manager_v1_create(dpy, 1); + wlr_presentation_create(dpy, backend); /* Initializes the interface used to implement urgency hints */ activation = wlr_xdg_activation_v1_create(dpy); @@ -2385,8 +2386,6 @@ setup(void) LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply); LISTEN_STATIC(&output_mgr->events.test, outputmgrtest); - wlr_scene_set_presentation(scene, wlr_presentation_create(dpy, backend)); - /* Make sure XWayland clients don't connect to the parent X server, * e.g when running in the x11 backend or the wayland backend and the * compositor has Xwayland support */ From f3c4f723147b40fb1284083f3d7dac988c52d162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 1 Jan 2024 00:51:01 -0600 Subject: [PATCH 185/347] fix posible NULL-dereference in wl_surface.commit handler --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 10d5a5b..4d19357 100644 --- a/dwl.c +++ b/dwl.c @@ -731,7 +731,7 @@ commitnotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, commit); - if (client_surface(c)->mapped) + if (client_surface(c)->mapped && c->mon) resize(c, c->geom, (c->isfloating && !c->isfullscreen)); /* mark a pending resize as completed */ From c222468887b25fa21c34c02ae605d002de218d1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 5 Jan 2024 10:01:16 -0600 Subject: [PATCH 186/347] don't send configure events to uninitialized xdg-popups --- dwl.c | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/dwl.c b/dwl.c index d0ac38a..5ab5a0a 100644 --- a/dwl.c +++ b/dwl.c @@ -245,6 +245,7 @@ static void cleanupmon(struct wl_listener *listener, void *data); static void closemon(Monitor *m); static void commitlayersurfacenotify(struct wl_listener *listener, void *data); static void commitnotify(struct wl_listener *listener, void *data); +static void commitpopup(struct wl_listener *listener, void *data); static void createdecoration(struct wl_listener *listener, void *data); static void createidleinhibitor(struct wl_listener *listener, void *data); static void createkeyboard(struct wlr_keyboard *keyboard); @@ -753,6 +754,33 @@ commitnotify(struct wl_listener *listener, void *data) c->resize = 0; } +void +commitpopup(struct wl_listener *listener, void *data) +{ + struct wlr_surface *surface = data; + struct wlr_xdg_popup *popup = wlr_xdg_popup_try_from_wlr_surface(surface); + LayerSurface *l = NULL; + Client *c = NULL; + struct wlr_box box; + int type = -1; + + if (!popup->base->initial_commit) + return; + + type = toplevel_from_wlr_surface(popup->base->surface, &c, &l); + if (!popup->parent || type < 0) + return; + popup->base->surface->data = wlr_scene_xdg_surface_create( + popup->parent->data, popup->base); + if ((l && !l->mon) || (c && !c->mon)) + return; + box = type == LayerShell ? l->mon->m : c->mon->w; + box.x -= (type == LayerShell ? l->geom.x : c->geom.x); + box.y -= (type == LayerShell ? l->geom.y : c->geom.y); + wlr_xdg_popup_unconstrain_from_box(popup, &box); + wl_list_remove(&listener->link); +} + void createdecoration(struct wl_listener *listener, void *data) { @@ -989,22 +1017,7 @@ createpopup(struct wl_listener *listener, void *data) /* This event is raised when a client (either xdg-shell or layer-shell) * creates a new popup. */ struct wlr_xdg_popup *popup = data; - LayerSurface *l = NULL; - Client *c = NULL; - struct wlr_box box; - - int type = toplevel_from_wlr_surface(popup->base->surface, &c, &l); - if (!popup->parent || type < 0) - return; - popup->base->surface->data = wlr_scene_xdg_surface_create( - popup->parent->data, popup->base); - if ((l && !l->mon) || (c && !c->mon)) - return; - box = type == LayerShell ? l->mon->m : c->mon->w; - box.x -= (type == LayerShell ? l->geom.x : c->geom.x); - box.y -= (type == LayerShell ? l->geom.y : c->geom.y); - /* FIXME: this send a configure event to a uninitialized wlr_xdg_surface */ - wlr_xdg_popup_unconstrain_from_box(popup, &box); + LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup); } void From 668022bc906fc7ba4d2092d260fbd10304fec29f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 5 Jan 2024 11:12:34 -0600 Subject: [PATCH 187/347] don't send configure events to uninitialized xdg-toplevels --- dwl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 5ab5a0a..7fb1b88 100644 --- a/dwl.c +++ b/dwl.c @@ -1578,8 +1578,9 @@ maximizenotify(struct wl_listener *listener, void *data) * protocol version * wlr_xdg_surface_schedule_configure() is used to send an empty reply. */ Client *c = wl_container_of(listener, c, maximize); - if (wl_resource_get_version(c->surface.xdg->toplevel->resource) - < XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) + if (c->surface.xdg->initialized + && wl_resource_get_version(c->surface.xdg->toplevel->resource) + < XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) wlr_xdg_surface_schedule_configure(c->surface.xdg); } From 25e34e4d0c97165eef627b70b916967852ec1f5e Mon Sep 17 00:00:00 2001 From: Ben Jargowsky Date: Sat, 6 Jan 2024 17:29:39 -0800 Subject: [PATCH 188/347] Destroy fullscreen node after moving clients off mon --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 4d19357..632dabf 100644 --- a/dwl.c +++ b/dwl.c @@ -672,9 +672,9 @@ cleanupmon(struct wl_listener *listener, void *data) m->wlr_output->data = NULL; wlr_output_layout_remove(output_layout, m->wlr_output); wlr_scene_output_destroy(m->scene_output); - wlr_scene_node_destroy(&m->fullscreen_bg->node); closemon(m); + wlr_scene_node_destroy(&m->fullscreen_bg->node); free(m); } From 6340989c8e1a178637996d293481d9366205cfc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 10 Jan 2024 00:10:39 -0600 Subject: [PATCH 189/347] add acknowledgment to djpohly --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1aa5195..3b5dd0f 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,7 @@ Many thanks to suckless.org and the dwm developers and community for the inspiration, and to the various contributors to the project, including: - Alexander Courtis for the XWayland implementation +- Devin J. Pohly for creating and nurturing the fledgling project - Guido Cella for the layer-shell protocol implementation, patch maintenance, and for helping to keep the project running - Stivvo for output management and fullscreen support, and patch maintenance From f5b046ce9e907a6211b9f7f5061b4d5ecac43294 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 11 Oct 2023 23:26:59 -0600 Subject: [PATCH 190/347] prefer functionality over philosophy --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3b5dd0f..c9652d1 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Or on our [Discord server]. dwl is a compact, hackable compositor for [Wayland] based on [wlroots]. It is intended to fill the same space in the Wayland world that dwm does in X11, -primarily in terms of philosophy, and secondarily in terms of functionality. +primarily in terms of functionality, and secondarily in terms of philosophy. Like dwm, dwl is: - Easy to understand, hack on, and extend with patches From facbe57fcbe74d27809eefdfe6aaac5150fbb954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 5 Jan 2024 11:16:16 -0600 Subject: [PATCH 191/347] drop wl_drm (wlroots!4397) References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4397 --- dwl.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 7fb1b88..c992cbf 100644 --- a/dwl.c +++ b/dwl.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -2216,11 +2215,9 @@ setup(void) * with wlr_scene. */ wlr_renderer_init_wl_shm(drw, dpy); - if (wlr_renderer_get_dmabuf_texture_formats(drw)) { - wlr_drm_create(dpy, drw); + if (wlr_renderer_get_dmabuf_texture_formats(drw)) wlr_scene_set_linux_dmabuf_v1(scene, wlr_linux_dmabuf_v1_create_with_renderer(dpy, 4, drw)); - } /* Autocreates an allocator for us. * The allocator is the bridge between the renderer and the backend. It From a73afc66abdffe2668ea27130f447ae05efb04f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 11 Oct 2023 23:40:16 -0600 Subject: [PATCH 192/347] drop SLOC limit --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c9652d1..60b4845 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,6 @@ Like dwm, dwl is: - Easy to understand, hack on, and extend with patches - One C source file (or a very small number) configurable via `config.h` -- Limited to 2200 SLOC to promote hackability - Tied to as few external dependencies as possible dwl is not meant to provide every feature under the sun. Instead, like dwm, it @@ -34,6 +33,10 @@ given the base on which it is built. Implemented default features are: - Layer shell popups (used by Waybar) - Damage tracking provided by scenegraph API +Given the Wayland architecture, dwl has to implement features from dwm **and** +the xorg-server. Because of this, it is impossible to maintain the original project goal of 2000 +SLOC and have a reasonably complete compositor with features comparable to dwm. + Features under consideration (possibly as patches) are: - Protocols made trivial by wlroots From fd263041a00deb648c2e27daac942e86621b2855 Mon Sep 17 00:00:00 2001 From: choc Date: Wed, 10 Jan 2024 22:27:04 +0800 Subject: [PATCH 193/347] check if monitor is null before setting gamma fixes segfault on monitor disconnect when using wlsunset --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index 632dabf..a20c607 100644 --- a/dwl.c +++ b/dwl.c @@ -2076,6 +2076,8 @@ setgamma(struct wl_listener *listener, void *data) { struct wlr_gamma_control_manager_v1_set_gamma_event *event = data; Monitor *m = event->output->data; + if (!m) + return; m->gamma_lut_changed = 1; wlr_output_schedule_frame(m->wlr_output); } From ec557f253b33f156720ae8950889519ed6425685 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 12 Jan 2024 22:34:09 -0600 Subject: [PATCH 194/347] clarify the code will be kept as small as possible --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 60b4845..6af019e 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,10 @@ given the base on which it is built. Implemented default features are: - Damage tracking provided by scenegraph API Given the Wayland architecture, dwl has to implement features from dwm **and** -the xorg-server. Because of this, it is impossible to maintain the original project goal of 2000 -SLOC and have a reasonably complete compositor with features comparable to dwm. +the xorg-server. Because of this, it is impossible to maintain the original +project goal of 2000 SLOC and have a reasonably complete compositor with +features comparable to dwm. However, this does not mean that the code will grow +indiscriminately. We will try to keep the code as small as possible. Features under consideration (possibly as patches) are: From 337d6ba3fbec3379162a1a287028fce363488197 Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Sun, 14 Jan 2024 09:01:49 -0600 Subject: [PATCH 195/347] acknowledgements refactoring --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6af019e..3d22cf3 100644 --- a/README.md +++ b/README.md @@ -157,8 +157,8 @@ possible. Many thanks to suckless.org and the dwm developers and community for the inspiration, and to the various contributors to the project, including: +- **Devin J. Pohly for creating and nurturing the fledgling project** - Alexander Courtis for the XWayland implementation -- Devin J. Pohly for creating and nurturing the fledgling project - Guido Cella for the layer-shell protocol implementation, patch maintenance, and for helping to keep the project running - Stivvo for output management and fullscreen support, and patch maintenance From 0151bd48ddef6c7679b1fd6fcce9db6340ab80d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 11 Jan 2023 12:13:53 -0600 Subject: [PATCH 196/347] turn on -Wsign-compare --- Makefile | 2 +- client.h | 6 +++--- dwl.c | 16 +++++++++------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index f0ff805..e0a601d 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ include config.mk # flags for compiling DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XWAYLAND) -DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement -Wno-unused-parameter -Wno-sign-compare -Wshadow -Wunused-macros\ +DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement -Wno-unused-parameter -Wshadow -Wunused-macros\ -Werror=strict-prototypes -Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types # CFLAGS / LDFLAGS diff --git a/client.h b/client.h index 1dae434..0753da8 100644 --- a/client.h +++ b/client.h @@ -339,10 +339,10 @@ client_set_size(Client *c, uint32_t width, uint32_t height) return 0; } #endif - if (width == c->surface.xdg->toplevel->current.width - && height ==c->surface.xdg->toplevel->current.height) + if ((int32_t)width == c->surface.xdg->toplevel->current.width + && (int32_t)height == c->surface.xdg->toplevel->current.height) return 0; - return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, width, height); + return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, (int32_t)width, (int32_t)height); } static inline void diff --git a/dwl.c b/dwl.c index a20c607..77583ee 100644 --- a/dwl.c +++ b/dwl.c @@ -415,9 +415,9 @@ applybounds(Client *c, struct wlr_box *bbox) c->geom.x = bbox->x + bbox->width - c->geom.width; if (c->geom.y >= bbox->y + bbox->height) c->geom.y = bbox->y + bbox->height - c->geom.height; - if (c->geom.x + c->geom.width + 2 * c->bw <= bbox->x) + if (c->geom.x + c->geom.width + 2 * (int)c->bw <= bbox->x) c->geom.x = bbox->x; - if (c->geom.y + c->geom.height + 2 * c->bw <= bbox->y) + if (c->geom.y + c->geom.height + 2 * (int)c->bw <= bbox->y) c->geom.y = bbox->y; } @@ -426,7 +426,8 @@ applyrules(Client *c) { /* rule matching */ const char *appid, *title; - uint32_t i, newtags = 0; + uint32_t newtags = 0; + int i; const Rule *r; Monitor *mon = selmon, *m; @@ -520,7 +521,7 @@ arrangelayers(Monitor *m) arrangelayer(m, &m->layers[i], &usable_area, 0); /* Find topmost keyboard interactive layer, if such a layer exists */ - for (i = 0; i < LENGTH(layers_above_shell); i++) { + for (i = 0; i < (int)LENGTH(layers_above_shell); i++) { wl_list_for_each_reverse(l, &m->layers[layers_above_shell[i]], link) { if (locked || !l->layer_surface->current.keyboard_interactive || !l->mapped) continue; @@ -657,7 +658,7 @@ cleanupmon(struct wl_listener *listener, void *data) { Monitor *m = wl_container_of(listener, m, destroy); LayerSurface *l, *tmp; - int i; + size_t i; /* m->layers[i] are intentionally not unlinked */ for (i = 0; i < LENGTH(m->layers); i++) { @@ -2166,7 +2167,7 @@ setup(void) struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig}; sigemptyset(&sa.sa_mask); - for (i = 0; i < LENGTH(sig); i++) + for (i = 0; i < (int)LENGTH(sig); i++) sigaction(sig[i], &sa, NULL); wlr_log_init(log_level, NULL); @@ -2454,7 +2455,8 @@ tagmon(const Arg *arg) void tile(Monitor *m) { - unsigned int i, n = 0, mw, my, ty; + unsigned int mw, my, ty; + int i, n = 0; Client *c; wl_list_for_each(c, &clients, link) From a1f3e25c350db7907b584aba30bf2567ca10610e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 1 Feb 2023 14:02:29 -0600 Subject: [PATCH 197/347] turn on -Wfloat-conversion --- Makefile | 2 +- config.def.h | 12 ++++++------ dwl.c | 19 ++++++++++--------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index e0a601d..0822ddc 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ include config.mk # flags for compiling DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XWAYLAND) DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement -Wno-unused-parameter -Wshadow -Wunused-macros\ - -Werror=strict-prototypes -Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types + -Werror=strict-prototypes -Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types -Wfloat-conversion # CFLAGS / LDFLAGS PKGS = wlroots wayland-server xkbcommon libinput $(XLIBS) diff --git a/config.def.h b/config.def.h index a8ed61d..9009517 100644 --- a/config.def.h +++ b/config.def.h @@ -12,7 +12,7 @@ static const float bordercolor[] = COLOR(0x444444ff); static const float focuscolor[] = COLOR(0x005577ff); static const float urgentcolor[] = COLOR(0xff0000ff); /* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */ -static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; /* You can also use glsl colors */ +static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */ /* tagging - TAGCOUNT must be no greater than 31 */ #define TAGCOUNT (9) @@ -39,12 +39,12 @@ static const Layout layouts[] = { /* monitors */ /* NOTE: ALWAYS add a fallback rule, even if you are completely sure it won't be used */ static const MonitorRule monrules[] = { - /* name mfact nmaster scale layout rotate/reflect x y */ + /* name mfact nmaster scale layout rotate/reflect x y */ /* example of a HiDPI laptop monitor: - { "eDP-1", 0.5, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, + { "eDP-1", 0.5f, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, */ /* defaults */ - { NULL, 0.55, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, + { NULL, 0.55f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, }; /* keyboard */ @@ -126,8 +126,8 @@ static const Key keys[] = { { MODKEY, XKB_KEY_k, focusstack, {.i = -1} }, { MODKEY, XKB_KEY_i, incnmaster, {.i = +1} }, { MODKEY, XKB_KEY_d, incnmaster, {.i = -1} }, - { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05} }, - { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05} }, + { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} }, + { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05f} }, { MODKEY, XKB_KEY_Return, zoom, {0} }, { MODKEY, XKB_KEY_Tab, view, {0} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, {0} }, diff --git a/dwl.c b/dwl.c index 77583ee..449913d 100644 --- a/dwl.c +++ b/dwl.c @@ -65,6 +65,7 @@ /* macros */ #define MAX(A, B) ((A) > (B) ? (A) : (B)) #define MIN(A, B) ((A) < (B) ? (A) : (B)) +#define ROUND(X) ((int)((X < 0) ? (X - 0.5) : (X + 0.5))) #define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS) #define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) #define LENGTH(X) (sizeof X / sizeof X[0]) @@ -196,7 +197,7 @@ struct Monitor { unsigned int seltags; unsigned int sellt; uint32_t tagset[2]; - double mfact; + float mfact; int gamma_lut_changed; int nmaster; char ltsymbol[16]; @@ -1621,17 +1622,17 @@ motionnotify(uint32_t time) } /* Update drag icon's position */ - wlr_scene_node_set_position(&drag_icon->node, cursor->x, cursor->y); + wlr_scene_node_set_position(&drag_icon->node, ROUND(cursor->x), ROUND(cursor->y)); /* If we are currently grabbing the mouse, handle and return */ if (cursor_mode == CurMove) { /* Move the grabbed client to the new position. */ - resize(grabc, (struct wlr_box){.x = cursor->x - grabcx, .y = cursor->y - grabcy, + resize(grabc, (struct wlr_box){.x = ROUND(cursor->x) - grabcx, .y = ROUND(cursor->y) - grabcy, .width = grabc->geom.width, .height = grabc->geom.height}, 1); return; } else if (cursor_mode == CurResize) { resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y, - .width = cursor->x - grabc->geom.x, .height = cursor->y - grabc->geom.y}, 1); + .width = ROUND(cursor->x) - grabc->geom.x, .height = ROUND(cursor->y) - grabc->geom.y}, 1); return; } @@ -1683,8 +1684,8 @@ moveresize(const Arg *arg) setfloating(grabc, 1); switch (cursor_mode = arg->ui) { case CurMove: - grabcx = cursor->x - grabc->geom.x; - grabcy = cursor->y - grabc->geom.y; + grabcx = ROUND(cursor->x) - grabc->geom.x; + grabcy = ROUND(cursor->y) - grabc->geom.y; wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur"); break; case CurResize: @@ -2105,7 +2106,7 @@ setmfact(const Arg *arg) if (!arg || !selmon || !selmon->lt[selmon->sellt]->arrange) return; - f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + f = arg->f < 1.0f ? arg->f + selmon->mfact : arg->f - 1.0f; if (f < 0.1 || f > 0.9) return; selmon->mfact = f; @@ -2277,7 +2278,7 @@ setup(void) wl_signal_add(&session_lock_mgr->events.new_lock, &lock_listener); LISTEN_STATIC(&session_lock_mgr->events.destroy, destroysessionmgr); locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height, - (float [4]){0.1, 0.1, 0.1, 1.0}); + (float [4]){0.1f, 0.1f, 0.1f, 1.0f}); wlr_scene_node_set_enabled(&locked_bg->node, 0); /* Use decoration protocols to negotiate server-side decorations */ @@ -2466,7 +2467,7 @@ tile(Monitor *m) return; if (n > m->nmaster) - mw = m->nmaster ? m->w.width * m->mfact : 0; + mw = m->nmaster ? ROUND(m->w.width * m->mfact) : 0; else mw = m->w.width; i = my = ty = 0; From 417e37f98877975ad19b13c9c09f0837684668e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 15 Jan 2024 02:15:54 +0000 Subject: [PATCH 198/347] request description before logs --- .gitea/issue_template/bug_report.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.gitea/issue_template/bug_report.yml b/.gitea/issue_template/bug_report.yml index 56f4a3e..77ce108 100644 --- a/.gitea/issue_template/bug_report.yml +++ b/.gitea/issue_template/bug_report.yml @@ -33,6 +33,14 @@ body: validations: required: false + - type: textarea + attributes: + label: Description + value: | + The steps you took to reproduce the problem. + validations: + required: false + - type: textarea id: debug_log attributes: @@ -52,11 +60,3 @@ body: - If the lines mentioning dwl or wlroots have `??`. Please compile both dwl and wlroots from source (enabling debug symbols) and try to reproduce. validations: required: false - - - type: textarea - attributes: - label: Description - value: | - The steps you took to reproduce the problem. - validations: - required: false From 6c8be38ec49273cc22faa4849295aaff5e39bfba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 15 Jan 2024 02:19:02 +0000 Subject: [PATCH 199/347] drop unused variable --- dwl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/dwl.c b/dwl.c index 449913d..f25ac2f 100644 --- a/dwl.c +++ b/dwl.c @@ -1483,7 +1483,6 @@ locksession(struct wl_listener *listener, void *data) void maplayersurfacenotify(struct wl_listener *listener, void *data) { - LayerSurface *l = wl_container_of(listener, l, map); motionnotify(0); } From 26d7c9689f6e7eb699f2a63c2093c2a27e411ea3 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Fri, 21 Jul 2023 20:17:41 -0400 Subject: [PATCH 200/347] No need to call updatemons ourselves MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The output manager in wlroots emits an output_layout.change event when anything changes, so updatemons will be called anyway. ΔSLOC: -1 --- dwl.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/dwl.c b/dwl.c index f25ac2f..bf02a6d 100644 --- a/dwl.c +++ b/dwl.c @@ -1757,9 +1757,6 @@ apply_or_test: else wlr_output_configuration_v1_send_failed(config); wlr_output_configuration_v1_destroy(config); - - /* TODO: use a wrapper function? */ - updatemons(NULL, NULL); } void From f136aa088ab0f439c151b34fb1465abd85ca97ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 24 Jan 2024 12:09:55 -0600 Subject: [PATCH 201/347] Revert "drop wl_drm (wlroots!4397)" There still a lot software that uses this protocol This reverts commit facbe57fcbe74d27809eefdfe6aaac5150fbb954. --- dwl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index b899dbb..6d29ec0 100644 --- a/dwl.c +++ b/dwl.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -2216,9 +2217,11 @@ setup(void) * with wlr_scene. */ wlr_renderer_init_wl_shm(drw, dpy); - if (wlr_renderer_get_dmabuf_texture_formats(drw)) + if (wlr_renderer_get_dmabuf_texture_formats(drw)) { + wlr_drm_create(dpy, drw); wlr_scene_set_linux_dmabuf_v1(scene, wlr_linux_dmabuf_v1_create_with_renderer(dpy, 4, drw)); + } /* Autocreates an allocator for us. * The allocator is the bridge between the renderer and the backend. It From b3f33e91479d795436b2c6937d58754eaf18192e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 24 Jan 2024 12:10:54 -0600 Subject: [PATCH 202/347] add support for axis_relative_direction event (wlroots!4003) References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4003 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 6d29ec0..a4e4983 100644 --- a/dwl.c +++ b/dwl.c @@ -549,7 +549,7 @@ axisnotify(struct wl_listener *listener, void *data) /* Notify the client with pointer focus of the axis event. */ wlr_seat_pointer_notify_axis(seat, event->time_msec, event->orientation, event->delta, - event->delta_discrete, event->source); + event->delta_discrete, event->source, event->relative_direction); } void From 4043fc3093a73174cb63653ba9e742b4738f2ee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 24 Jan 2024 12:12:09 -0600 Subject: [PATCH 203/347] do not arrange monitor if it's disabled (wlroots!4520) This causes us to send negative values to xdg-configures (e.g a bug in our end) References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4520 --- dwl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dwl.c b/dwl.c index a4e4983..b70d818 100644 --- a/dwl.c +++ b/dwl.c @@ -460,6 +460,10 @@ void arrange(Monitor *m) { Client *c; + + if (!m->wlr_output->enabled) + return; + wl_list_for_each(c, &clients, link) { if (c->mon == m) { wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m)); From 433385f7f18abb607c4feff6d6c7fa817071a710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 24 Jan 2024 12:12:09 -0600 Subject: [PATCH 204/347] do not arrange monitor if it's disabled (wlroots!4520) This causes us to send negative values to xdg-configures (e.g a bug in our end) References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4520 (cherry picked from commit 4043fc3093a73174cb63653ba9e742b4738f2ee5) --- dwl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dwl.c b/dwl.c index bf02a6d..239f7d7 100644 --- a/dwl.c +++ b/dwl.c @@ -458,6 +458,10 @@ void arrange(Monitor *m) { Client *c; + + if (!m->wlr_output->enabled) + return; + wl_list_for_each(c, &clients, link) { if (c->mon == m) { wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m)); From ac6074f4fdb8cc263c877f08e16a5805d3bb22d2 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Wed, 24 Jan 2024 22:47:50 +0100 Subject: [PATCH 205/347] implement the virtual pointer protocol This is used by programs like warpd. --- dwl.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dwl.c b/dwl.c index 239f7d7..76ed8aa 100644 --- a/dwl.c +++ b/dwl.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -328,6 +329,7 @@ static void updatetitle(struct wl_listener *listener, void *data); static void urgent(struct wl_listener *listener, void *data); static void view(const Arg *arg); static void virtualkeyboard(struct wl_listener *listener, void *data); +static void virtualpointer(struct wl_listener *listener, void *data); static Monitor *xytomon(double x, double y); static void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, LayerSurface **pl, double *nx, double *ny); @@ -361,6 +363,7 @@ static struct wlr_layer_shell_v1 *layer_shell; static struct wlr_output_manager_v1 *output_mgr; static struct wlr_gamma_control_manager_v1 *gamma_control_mgr; static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; +static struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr; static struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr; static struct wlr_cursor *cursor; @@ -2330,6 +2333,9 @@ setup(void) LISTEN_STATIC(&backend->events.new_input, inputdevice); virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy); LISTEN_STATIC(&virtual_keyboard_mgr->events.new_virtual_keyboard, virtualkeyboard); + virtual_pointer_mgr = wlr_virtual_pointer_manager_v1_create(dpy); + LISTEN_STATIC(&virtual_pointer_mgr->events.new_virtual_pointer, virtualpointer); + seat = wlr_seat_create(dpy, "seat0"); LISTEN_STATIC(&seat->events.request_set_cursor, setcursor); LISTEN_STATIC(&seat->events.request_set_selection, setsel); @@ -2731,6 +2737,17 @@ virtualkeyboard(struct wl_listener *listener, void *data) wlr_keyboard_group_add_keyboard(vkb_group.wlr_group, &keyboard->keyboard); } +void +virtualpointer(struct wl_listener *listener, void *data) +{ + struct wlr_virtual_pointer_v1_new_pointer_event *event = data; + struct wlr_pointer pointer = event->new_pointer->pointer; + + wlr_cursor_attach_input_device(cursor, &pointer.base); + if (event->suggested_output) + wlr_cursor_map_input_to_output(cursor, &pointer.base, event->suggested_output); +} + Monitor * xytomon(double x, double y) { From 5fec98b17ac398070ca05ba12fab7c22ea56a753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 25 Jan 2024 11:11:40 -0600 Subject: [PATCH 206/347] pass wl_event_loop to wlr_backend_autocreate (wlroots!4443) References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4443 --- dwl.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index b70d818..95a6e82 100644 --- a/dwl.c +++ b/dwl.c @@ -341,6 +341,7 @@ static pid_t child_pid = -1; static int locked; static void *exclusive_focus; static struct wl_display *dpy; +static struct wl_event_loop *event_loop; static struct wlr_backend *backend; static struct wlr_scene *scene; static struct wlr_scene_tree *layers[NUM_LAYERS]; @@ -653,6 +654,10 @@ cleanup(void) wl_event_source_remove(kb_group.key_repeat_source); wl_event_source_remove(vkb_group.key_repeat_source); + /* If it's not destroyed manually it will cause a use-after-free of wlr_seat. + * Destroy it until it's fixed in the wlroots side */ + wlr_backend_destroy(backend); + wl_display_destroy(dpy); /* Destroy after the wayland display (when the monitors are already destroyed) to avoid destroying them with an invalid scene output. */ @@ -2191,12 +2196,13 @@ setup(void) /* The Wayland display is managed by libwayland. It handles accepting * clients from the Unix socket, manging Wayland globals, and so on. */ dpy = wl_display_create(); + event_loop = wl_display_get_event_loop(dpy); /* The backend is a wlroots feature which abstracts the underlying input and * output hardware. The autocreate option will choose the most suitable * backend based on the current environment, such as opening an X11 window * if an X11 server is running. */ - if (!(backend = wlr_backend_autocreate(dpy, &session))) + if (!(backend = wlr_backend_autocreate(event_loop, &session))) die("couldn't create backend"); /* Initialize the scene graph used to lay out windows */ @@ -2389,10 +2395,8 @@ setup(void) LISTEN(&vkb_group.wlr_group->keyboard.events.key, &vkb_group.key, keypress); LISTEN(&vkb_group.wlr_group->keyboard.events.modifiers, &vkb_group.modifiers, keypressmod); - kb_group.key_repeat_source = wl_event_loop_add_timer( - wl_display_get_event_loop(dpy), keyrepeat, &kb_group); - vkb_group.key_repeat_source = wl_event_loop_add_timer( - wl_display_get_event_loop(dpy), keyrepeat, &vkb_group); + kb_group.key_repeat_source = wl_event_loop_add_timer(event_loop, keyrepeat, &kb_group); + vkb_group.key_repeat_source = wl_event_loop_add_timer(event_loop, keyrepeat, &vkb_group); /* A seat can only have one keyboard, but this is a limitation of the * Wayland protocol - not wlroots. We assign all connected keyboards to the From 863634a61cd953ea82d5fd1e4fa4d04e8b48a23f Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Thu, 25 Jan 2024 09:04:14 +0100 Subject: [PATCH 207/347] configure xwayland surfaces without monitors For wine clients often configurex11() is called before mapnotify() and therefore c->mon is NULL. configurex11 just returns early in that case, letting these clients stay in the wrong size. For example only the top left part of winecfg and wine uninstaller is drawn, or confirmation dialogs like when closing wine notepad are too big. Fix this by configuring their surfaces like before 88d386b. --- dwl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 76ed8aa..c8283b7 100644 --- a/dwl.c +++ b/dwl.c @@ -2844,8 +2844,12 @@ configurex11(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, configure); struct wlr_xwayland_surface_configure_event *event = data; - if (!c->mon) + /* TODO: figure out if there is another way to do this */ + if (!c->mon) { + wlr_xwayland_surface_configure(c->surface.xwayland, + event->x, event->y, event->width, event->height); return; + } if (c->isfloating || client_is_unmanaged(c)) resize(c, (struct wlr_box){.x = event->x, .y = event->y, .width = event->width, .height = event->height}, 0); From 9830a991ff3d310223fb8389d108423b914afb67 Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Fri, 26 Jan 2024 08:54:53 -0600 Subject: [PATCH 208/347] Correct specifier-data_type mismatches --- dwl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index c8283b7..3fac808 100644 --- a/dwl.c +++ b/dwl.c @@ -1823,8 +1823,8 @@ printstatus(void) appid = client_get_appid(c); printf("%s title %s\n", m->wlr_output->name, title ? title : broken); printf("%s appid %s\n", m->wlr_output->name, appid ? appid : broken); - printf("%s fullscreen %u\n", m->wlr_output->name, c->isfullscreen); - printf("%s floating %u\n", m->wlr_output->name, c->isfloating); + printf("%s fullscreen %d\n", m->wlr_output->name, c->isfullscreen); + printf("%s floating %d\n", m->wlr_output->name, c->isfloating); sel = c->tags; } else { printf("%s title \n", m->wlr_output->name); @@ -1835,8 +1835,8 @@ printstatus(void) } printf("%s selmon %u\n", m->wlr_output->name, m == selmon); - printf("%s tags %u %u %u %u\n", m->wlr_output->name, occ, - m->tagset[m->seltags], sel, urg); + printf("%s tags %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32"\n", + m->wlr_output->name, occ, m->tagset[m->seltags], sel, urg); printf("%s layout %s\n", m->wlr_output->name, m->ltsymbol); } fflush(stdout); From 5c936efc427f2d326dab3f8d22cb34159b8292b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 30 Jan 2024 22:54:54 -0600 Subject: [PATCH 209/347] Revert "No need to call updatemons ourselves" Fixes: https://codeberg.org/dwl/dwl/issues/577 This reverts commit 26d7c9689f6e7eb699f2a63c2093c2a27e411ea3. --- dwl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dwl.c b/dwl.c index 3fac808..ae8df11 100644 --- a/dwl.c +++ b/dwl.c @@ -1764,6 +1764,9 @@ apply_or_test: else wlr_output_configuration_v1_send_failed(config); wlr_output_configuration_v1_destroy(config); + + /* TODO: use a wrapper function? */ + updatemons(NULL, NULL); } void From 45e3694fc8e91642cf970bd1586bd1a16dbc8a31 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Sun, 28 Jan 2024 09:01:09 +0100 Subject: [PATCH 210/347] remove useless wlr_scene_node_reparent() calls These don't do anything because wlr_scene_node_reparent() is immediately called again by setfloating() through setmon(). They are also a source of confusion because if you change the wlr_scene_node_reparent() call in applyrules() it takes a while to understand why it doesn't work. --- dwl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/dwl.c b/dwl.c index ae8df11..f407477 100644 --- a/dwl.c +++ b/dwl.c @@ -453,7 +453,6 @@ applyrules(Client *c) } } } - wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrFloat : LyrTile]); setmon(c, mon, newtags); } @@ -1546,7 +1545,6 @@ mapnotify(struct wl_listener *listener, void *data) /* TODO: https://github.com/djpohly/dwl/pull/334#issuecomment-1330166324 */ if (c->type == XDGShell && (p = client_get_parent(c))) { c->isfloating = 1; - wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]); setmon(c, p->mon, p->tags); } else { applyrules(c); From 17c5cbbf7b6c3a5373f46e6fb6e88daada325479 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Sun, 28 Jan 2024 09:06:20 +0100 Subject: [PATCH 211/347] make XWayland clients inherit tags and monitors Revert 3213088 because the linked bug can no longer be reproduced with wlroots 0.17, and update client_get_parent() so it doesn't segfault with XWayland surfaces. This also allows reusing the p variable in the next commit. --- client.h | 7 +++++-- dwl.c | 3 +-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/client.h b/client.h index 0753da8..8a379d0 100644 --- a/client.h +++ b/client.h @@ -172,8 +172,11 @@ client_get_parent(Client *c) { Client *p = NULL; #ifdef XWAYLAND - if (client_is_x11(c) && c->surface.xwayland->parent) - toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL); + if (client_is_x11(c)) { + if (c->surface.xwayland->parent) + toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL); + return p; + } #endif if (c->surface.xdg->toplevel->parent) toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL); diff --git a/dwl.c b/dwl.c index f407477..b04b66a 100644 --- a/dwl.c +++ b/dwl.c @@ -1542,8 +1542,7 @@ mapnotify(struct wl_listener *listener, void *data) * we always consider floating, clients that have parent and thus * we set the same tags and monitor than its parent, if not * try to apply rules for them */ - /* TODO: https://github.com/djpohly/dwl/pull/334#issuecomment-1330166324 */ - if (c->type == XDGShell && (p = client_get_parent(c))) { + if ((p = client_get_parent(c))) { c->isfloating = 1; setmon(c, p->mon, p->tags); } else { From 298949bbc4eae8cedb9cdd11cfc9ebd139ac5d5f Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Sun, 28 Jan 2024 18:30:36 +0100 Subject: [PATCH 212/347] place child clients above fullscreen clients When a child window of a fullscreen client is mapped, the fullscreen is disabled, and if the previously fullscreen client is floating the child window is rendered below it and cannot be seen, causing confusion, though it is still focused and interactable. Fix this by putting children of fullscreen clients in LyrFS instead of LyrFloat, and by returning before the unset_fullscreen code is called when they are mapped. focusstack() now lets you switch focus from a fullscreen client to its child windows, otherwise if you switch focus from the child window to the fullscreen client you could not focus the child window again and the fullscreen client would stay unresponsive. Child clients are not reparented to LyrFloat after leaving fullscreen, so you could spawn a child window, focus back the fullscreen client, unfullscreen it, and the child window would still be drawn above other floating clients. Avoid dealing with this edge case to keep the line count low. These cases can be tested by pressing Ctrl+o in applications with an open file dialog. --- client.h | 12 ++++++++++++ dwl.c | 13 ++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/client.h b/client.h index 8a379d0..fe9dffc 100644 --- a/client.h +++ b/client.h @@ -183,6 +183,18 @@ client_get_parent(Client *c) return p; } +static inline int +client_has_children(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return !wl_list_empty(&c->surface.xwayland->children); +#endif + /* surface.xdg->link is never empty because it always contains at least the + * surface itself. */ + return wl_list_length(&c->surface.xdg->link) > 1; +} + static inline const char * client_get_title(Client *c) { diff --git a/dwl.c b/dwl.c index b04b66a..95ebee8 100644 --- a/dwl.c +++ b/dwl.c @@ -1256,7 +1256,7 @@ focusstack(const Arg *arg) { /* Focus the next or previous client (in tiling order) on selmon */ Client *c, *sel = focustop(selmon); - if (!sel || sel->isfullscreen) + if (!sel || (sel->isfullscreen && !client_has_children(sel))) return; if (arg->i > 0) { wl_list_for_each(c, &sel->link, link) { @@ -1496,7 +1496,8 @@ void mapnotify(struct wl_listener *listener, void *data) { /* Called when the surface is mapped, or ready to display on-screen. */ - Client *p, *w, *c = wl_container_of(listener, c, map); + Client *p = NULL; + Client *w, *c = wl_container_of(listener, c, map); Monitor *m; int i; @@ -1553,7 +1554,7 @@ mapnotify(struct wl_listener *listener, void *data) unset_fullscreen: m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y); wl_list_for_each(w, &clients, link) { - if (w != c && w->isfullscreen && m == w->mon && (w->tags & c->tags)) + if (w != c && w != p && w->isfullscreen && m == w->mon && (w->tags & c->tags)) setfullscreen(w, 0); } } @@ -2044,11 +2045,13 @@ setcursorshape(struct wl_listener *listener, void *data) void setfloating(Client *c, int floating) { + Client *p = client_get_parent(c); c->isfloating = floating; if (!c->mon) return; - wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen - ? LyrFS : c->isfloating ? LyrFloat : LyrTile]); + wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen || + (p && p->isfullscreen) ? LyrFS + : c->isfloating ? LyrFloat : LyrTile]); arrange(c->mon); printstatus(); } From 3c98c4c24de39dea298bbf289b8fd8e7942a6901 Mon Sep 17 00:00:00 2001 From: Benjamin Chausse Date: Tue, 6 Feb 2024 00:39:01 +0000 Subject: [PATCH 213/347] Fix link to patches website Signed-off-by: Benjamin Chausse --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3d22cf3..09233c7 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ Wayland without restarting the entire display server, so any changes will take effect the next time dwl is executed. As in the dwm community, we encourage users to share patches they have created. -Check out the [patches page on our wiki]! +Check out the [patches repository]! ## Running dwl @@ -169,6 +169,7 @@ inspiration, and to the various contributors to the project, including: [Wayland]: https://wayland.freedesktop.org/ [wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots/ [wlroots-next branch]: https://codeberg.org/dwl/dwl/src/branch/wlroots-next +[patches repository]: https://codeberg.org/dwl/dwl-patches [patches page on our wiki]: https://codeberg.org/dwl/dwl/wiki/Patches [s6]: https://skarnet.org/software/s6/ [anopa]: https://jjacky.com/anopa/ From 089480e0b674156928e63a1db7888c312eeea68b Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Tue, 6 Feb 2024 01:25:56 +0000 Subject: [PATCH 214/347] Update and correct patches/patches-wiki links MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Leonardo Hernández Hernández --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 09233c7..5b3d4f6 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ Wayland without restarting the entire display server, so any changes will take effect the next time dwl is executed. As in the dwm community, we encourage users to share patches they have created. -Check out the [patches repository]! +Check out the dwl [patches repository] and [patches wiki]! ## Running dwl @@ -170,7 +170,7 @@ inspiration, and to the various contributors to the project, including: [wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots/ [wlroots-next branch]: https://codeberg.org/dwl/dwl/src/branch/wlroots-next [patches repository]: https://codeberg.org/dwl/dwl-patches -[patches page on our wiki]: https://codeberg.org/dwl/dwl/wiki/Patches +[patches wiki]: https://codeberg.org/dwl/dwl-patches/wiki [s6]: https://skarnet.org/software/s6/ [anopa]: https://jjacky.com/anopa/ [runit]: http://smarden.org/runit/faq.html#userservices From 5ae245beedd587a2c9748168ef494abd5a92469c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 7 Feb 2024 02:21:26 +0000 Subject: [PATCH 215/347] fix minimum size continuation of 4043fc3093a73174cb63653ba9e742b4738f2ee5 --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 95ebee8..e999923 100644 --- a/dwl.c +++ b/dwl.c @@ -412,8 +412,8 @@ void applybounds(Client *c, struct wlr_box *bbox) { /* set minimum possible */ - c->geom.width = MAX(1, c->geom.width); - c->geom.height = MAX(1, c->geom.height); + c->geom.width = MAX(1 + 2 * (int)c->bw, c->geom.width); + c->geom.height = MAX(1 + 2 * (int)c->bw, c->geom.height); if (c->geom.x >= bbox->x + bbox->width) c->geom.x = bbox->x + bbox->width - c->geom.width; From 8006e7920085947673517c3e296a1e308f935f75 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Tue, 16 Jan 2024 19:11:18 +0100 Subject: [PATCH 216/347] allow toggling the layout before selecting a different one --- dwl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index e999923..fa76db2 100644 --- a/dwl.c +++ b/dwl.c @@ -871,7 +871,8 @@ createmon(struct wl_listener *listener, void *data) m->m.y = r->y; m->mfact = r->mfact; m->nmaster = r->nmaster; - m->lt[0] = m->lt[1] = r->lt; + m->lt[0] = r->lt; + m->lt[1] = &layouts[LENGTH(layouts) > 1 && r->lt != &layouts[1]]; strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); wlr_output_state_set_scale(&state, r->scale); wlr_output_state_set_transform(&state, r->rr); From c215e8a3e1dae6c3f4789dd404d6266c39d9d2dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 6 Feb 2024 20:30:40 -0600 Subject: [PATCH 217/347] send initial configure to xdg-toplevels (wlroots!4396) We still need to fix xdg-popups References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4396 --- dwl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index e9cf506..ac5b19d 100644 --- a/dwl.c +++ b/dwl.c @@ -756,8 +756,11 @@ commitnotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, commit); - if (c->surface.xdg->initial_commit) + if (c->surface.xdg->initial_commit) { wlr_xdg_toplevel_set_wm_capabilities(c->surface.xdg->toplevel, WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); + wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, 0, 0); + return; + } if (client_surface(c)->mapped && c->mon) resize(c, c->geom, (c->isfloating && !c->isfullscreen)); From 7b3eb7050186d477889b78afa36079fdb7a8ea3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 6 Feb 2024 20:37:36 -0600 Subject: [PATCH 218/347] misc fixes to xdg-toplevel-decoration --- dwl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index ac5b19d..e8557ce 100644 --- a/dwl.c +++ b/dwl.c @@ -759,6 +759,8 @@ commitnotify(struct wl_listener *listener, void *data) if (c->surface.xdg->initial_commit) { wlr_xdg_toplevel_set_wm_capabilities(c->surface.xdg->toplevel, WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, 0, 0); + if (c->decoration) + requestdecorationmode(&c->set_decoration_mode, c->decoration); return; } @@ -1052,6 +1054,7 @@ void destroydecoration(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, destroy_decoration); + c->decoration = NULL; wl_list_remove(&c->destroy_decoration.link); wl_list_remove(&c->set_decoration_mode.link); @@ -1929,8 +1932,9 @@ void requestdecorationmode(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, set_decoration_mode); - wlr_xdg_toplevel_decoration_v1_set_mode(c->decoration, - WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + if (c->surface.xdg->initialized) + wlr_xdg_toplevel_decoration_v1_set_mode(c->decoration, + WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); } void From a0117eea76ce5ca5e6660f5a6f0057e29f268d41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 29 Feb 2024 14:05:09 -0600 Subject: [PATCH 219/347] use enums from the wayland protocol (wlroots!4575) References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4575 --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index e8557ce..dfb3a27 100644 --- a/dwl.c +++ b/dwl.c @@ -571,7 +571,7 @@ buttonpress(struct wl_listener *listener, void *data) wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); switch (event->state) { - case WLR_BUTTON_PRESSED: + case WL_POINTER_BUTTON_STATE_PRESSED: cursor_mode = CurPressed; held_grab = seat->pointer_state.focused_surface; if (locked) @@ -592,7 +592,7 @@ buttonpress(struct wl_listener *listener, void *data) } } break; - case WLR_BUTTON_RELEASED: + case WL_POINTER_BUTTON_STATE_RELEASED: held_grab = NULL; /* If you released any buttons, we exit interactive move/resize mode. */ /* TODO should reset to the pointer focus's current setcursor */ From ea33ce9ae68e41a22a2fca3b6d17e071b9325a69 Mon Sep 17 00:00:00 2001 From: Forrest Bushstone Date: Mon, 26 Feb 2024 16:43:01 -0500 Subject: [PATCH 220/347] Support pointer constraints and relative pointer protocols Fixes: https://codeberg.org/dwl/dwl/issues/489 FIxes: https://codeberg.org/dwl/dwl/issues/317 --- Makefile | 17 ++++--- dwl.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 129 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index 0822ddc..a67fdd3 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(LIBS) all: dwl dwl: dwl.o util.o $(CC) dwl.o util.o $(LDLIBS) $(LDFLAGS) $(DWLCFLAGS) -o $@ -dwl.o: dwl.c config.mk config.h client.h cursor-shape-v1-protocol.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h +dwl.o: dwl.c config.mk config.h client.h cursor-shape-v1-protocol.h pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h xdg-shell-protocol.h util.o: util.c util.h # wayland-scanner is a tool which generates C headers and rigging for Wayland @@ -25,15 +25,18 @@ util.o: util.c util.h WAYLAND_SCANNER = `$(PKG_CONFIG) --variable=wayland_scanner wayland-scanner` WAYLAND_PROTOCOLS = `$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols` -xdg-shell-protocol.h: - $(WAYLAND_SCANNER) server-header \ - $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ -wlr-layer-shell-unstable-v1-protocol.h: - $(WAYLAND_SCANNER) server-header \ - protocols/wlr-layer-shell-unstable-v1.xml $@ cursor-shape-v1-protocol.h: $(WAYLAND_SCANNER) server-header \ $(WAYLAND_PROTOCOLS)/staging/cursor-shape/cursor-shape-v1.xml $@ +pointer-constraints-unstable-v1-protocol.h: + $(WAYLAND_SCANNER) server-header \ + $(WAYLAND_PROTOCOLS)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@ +wlr-layer-shell-unstable-v1-protocol.h: + $(WAYLAND_SCANNER) server-header \ + protocols/wlr-layer-shell-unstable-v1.xml $@ +xdg-shell-protocol.h: + $(WAYLAND_SCANNER) server-header \ + $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ config.h: cp config.def.h $@ diff --git a/dwl.c b/dwl.c index fa76db2..d508d79 100644 --- a/dwl.c +++ b/dwl.c @@ -35,9 +35,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -54,6 +56,7 @@ #include #include #include +#include #include #ifdef XWAYLAND #include @@ -214,6 +217,11 @@ typedef struct { int x, y; } MonitorRule; +typedef struct { + struct wlr_pointer_constraint_v1 *constraint; + struct wl_listener destroy; +} PointerConstraint; + typedef struct { const char *id; const char *title; @@ -255,7 +263,10 @@ static void createlocksurface(struct wl_listener *listener, void *data); static void createmon(struct wl_listener *listener, void *data); static void createnotify(struct wl_listener *listener, void *data); static void createpointer(struct wlr_pointer *pointer); +static void createpointerconstraint(struct wl_listener *listener, void *data); +static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint); static void cursorframe(struct wl_listener *listener, void *data); +static void cursorwarptohint(void); static void destroydecoration(struct wl_listener *listener, void *data); static void destroydragicon(struct wl_listener *listener, void *data); static void destroyidleinhibitor(struct wl_listener *listener, void *data); @@ -263,6 +274,7 @@ static void destroylayersurfacenotify(struct wl_listener *listener, void *data); static void destroylock(SessionLock *lock, int unlocked); static void destroylocksurface(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); +static void destroypointerconstraint(struct wl_listener *listener, void *data); static void destroysessionlock(struct wl_listener *listener, void *data); static void destroysessionmgr(struct wl_listener *listener, void *data); static Monitor *dirtomon(enum wlr_direction dir); @@ -285,7 +297,8 @@ static void mapnotify(struct wl_listener *listener, void *data); static void maximizenotify(struct wl_listener *listener, void *data); static void monocle(Monitor *m); static void motionabsolute(struct wl_listener *listener, void *data); -static void motionnotify(uint32_t time); +static void motionnotify(uint32_t time, struct wlr_input_device *device, double sx, + double sy, double sx_unaccel, double sy_unaccel); static void motionrelative(struct wl_listener *listener, void *data); static void moveresize(const Arg *arg); static void outputmgrapply(struct wl_listener *listener, void *data); @@ -366,6 +379,10 @@ static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; static struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr; static struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr; +static struct wlr_pointer_constraints_v1 *pointer_constraints; +static struct wlr_relative_pointer_manager_v1 *relative_pointer_mgr; +static struct wlr_pointer_constraint_v1 *active_constraint; + static struct wlr_cursor *cursor; static struct wlr_xcursor_manager *cursor_mgr; @@ -478,7 +495,7 @@ arrange(Monitor *m) if (m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); - motionnotify(0); + motionnotify(0, NULL, 0, 0, 0, 0); checkidleinhibitor(NULL); } @@ -1015,6 +1032,28 @@ createpointer(struct wlr_pointer *pointer) wlr_cursor_attach_input_device(cursor, &pointer->base); } +void +createpointerconstraint(struct wl_listener *listener, void *data) +{ + PointerConstraint *pointer_constraint = ecalloc(1, sizeof(*pointer_constraint)); + pointer_constraint->constraint = data; + LISTEN(&pointer_constraint->constraint->events.destroy, + &pointer_constraint->destroy, destroypointerconstraint); +} + +void +cursorconstrain(struct wlr_pointer_constraint_v1 *constraint) +{ + if (active_constraint == constraint) + return; + + if (active_constraint) + wlr_pointer_constraint_v1_send_deactivated(active_constraint); + + active_constraint = constraint; + wlr_pointer_constraint_v1_send_activated(constraint); +} + void cursorframe(struct wl_listener *listener, void *data) { @@ -1026,6 +1065,21 @@ cursorframe(struct wl_listener *listener, void *data) wlr_seat_pointer_notify_frame(seat); } +void +cursorwarptohint(void) +{ + Client *c = NULL; + double sx = active_constraint->current.cursor_hint.x; + double sy = active_constraint->current.cursor_hint.y; + + toplevel_from_wlr_surface(active_constraint->surface, &c, NULL); + /* TODO: wlroots 0.18: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4478 */ + if (c && (active_constraint->current.committed & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT )) { + wlr_cursor_warp(cursor, NULL, sx + c->geom.x + c->bw, sy + c->geom.y + c->bw); + wlr_seat_pointer_warp(active_constraint->seat, sx, sy); + } +} + void destroydecoration(struct wl_listener *listener, void *data) { @@ -1040,7 +1094,7 @@ destroydragicon(struct wl_listener *listener, void *data) { /* Focus enter isn't sent during drag, so refocus the focused node. */ focusclient(focustop(selmon), 1); - motionnotify(0); + motionnotify(0, NULL, 0, 0, 0, 0); } void @@ -1076,7 +1130,7 @@ destroylock(SessionLock *lock, int unlock) wlr_scene_node_set_enabled(&locked_bg->node, 0); focusclient(focustop(selmon), 0); - motionnotify(0); + motionnotify(0, NULL, 0, 0, 0, 0); destroy: wl_list_remove(&lock->new_surface.link); @@ -1135,6 +1189,20 @@ destroynotify(struct wl_listener *listener, void *data) free(c); } +void +destroypointerconstraint(struct wl_listener *listener, void *data) +{ + PointerConstraint *pointer_constraint = wl_container_of(listener, pointer_constraint, destroy); + + if (active_constraint == pointer_constraint->constraint) { + cursorwarptohint(); + active_constraint = NULL; + } + + wl_list_remove(&pointer_constraint->destroy.link); + free(pointer_constraint); +} + void destroysessionlock(struct wl_listener *listener, void *data) { @@ -1231,7 +1299,7 @@ focusclient(Client *c, int lift) } /* Change cursor surface */ - motionnotify(0); + motionnotify(0, NULL, 0, 0, 0, 0); /* Have a client, so focus its top-level wlr_surface */ client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat)); @@ -1490,7 +1558,7 @@ locksession(struct wl_listener *listener, void *data) void maplayersurfacenotify(struct wl_listener *listener, void *data) { - motionnotify(0); + motionnotify(0, NULL, 0, 0, 0, 0); } void @@ -1605,20 +1673,50 @@ motionabsolute(struct wl_listener *listener, void *data) * so we have to warp the mouse there. There is also some hardware which * emits these events. */ struct wlr_pointer_motion_absolute_event *event = data; - wlr_cursor_warp_absolute(cursor, &event->pointer->base, event->x, event->y); - motionnotify(event->time_msec); + double lx, ly, dx, dy; + + wlr_cursor_absolute_to_layout_coords(cursor, &event->pointer->base, event->x, event->y, &lx, &ly); + dx = lx - cursor->x; + dy = ly - cursor->y; + motionnotify(event->time_msec, &event->pointer->base, dx, dy, dx, dy); } void -motionnotify(uint32_t time) +motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy, + double dx_unaccel, double dy_unaccel) { - double sx = 0, sy = 0; + double sx = 0, sy = 0, sx_confined, sy_confined; Client *c = NULL, *w = NULL; LayerSurface *l = NULL; struct wlr_surface *surface = NULL; + struct wlr_pointer_constraint_v1 *constraint; /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { + wlr_relative_pointer_manager_v1_send_relative_motion( + relative_pointer_mgr, seat, (uint64_t)time * 1000, + dx, dy, dx_unaccel, dy_unaccel); + + wl_list_for_each(constraint, &pointer_constraints->constraints, link) + cursorconstrain(constraint); + + if (active_constraint && cursor_mode != CurResize && cursor_mode != CurMove) { + toplevel_from_wlr_surface(active_constraint->surface, &c, NULL); + if (c && active_constraint->surface == seat->pointer_state.focused_surface) { + sx = cursor->x - c->geom.x - c->bw; + sy = cursor->y - c->geom.y - c->bw; + if (wlr_region_confine(&active_constraint->region, sx, sy, + sx + dx, sy + dy, &sx_confined, &sy_confined)) { + dx = sx_confined - sx; + dy = sy_confined - sy; + } + + if (active_constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED) + return; + } + } + + wlr_cursor_move(cursor, device, dx, dy); wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); /* Update selmon (even while dragging a window) */ @@ -1672,8 +1770,8 @@ motionrelative(struct wl_listener *listener, void *data) * special configuration applied for the specific input device which * generated the event. You can pass NULL for the device if you want to move * the cursor around without any input. */ - wlr_cursor_move(cursor, &event->pointer->base, event->delta_x, event->delta_y); - motionnotify(event->time_msec); + motionnotify(event->time_msec, &event->pointer->base, event->delta_x, event->delta_y, + event->unaccel_dx, event->unaccel_dy); } void @@ -1781,7 +1879,8 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, { struct timespec now; - if (sloppyfocus && time && c && !client_is_unmanaged(c)) + if ((!active_constraint || active_constraint->surface != surface) && + sloppyfocus && time && c && !client_is_unmanaged(c)) focusclient(c, 0); /* If surface is NULL, clear pointer focus */ @@ -1800,7 +1899,6 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, * wlroots makes this a no-op if surface is already focused */ wlr_seat_pointer_notify_enter(seat, surface, sx, sy); wlr_seat_pointer_notify_motion(seat, time, sx, sy); - } void @@ -2295,6 +2393,11 @@ setup(void) xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy); LISTEN_STATIC(&xdg_decoration_mgr->events.new_toplevel_decoration, createdecoration); + pointer_constraints = wlr_pointer_constraints_v1_create(dpy); + LISTEN_STATIC(&pointer_constraints->events.new_constraint, createpointerconstraint); + + relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy); + /* * Creates a cursor, which is a wlroots utility for tracking the cursor * image shown on screen. @@ -2561,7 +2664,7 @@ unmaplayersurfacenotify(struct wl_listener *listener, void *data) arrangelayers(l->mon); if (l->layer_surface->surface == seat->keyboard_state.focused_surface) focusclient(focustop(selmon), 1); - motionnotify(0); + motionnotify(0, NULL, 0, 0, 0, 0); } void @@ -2587,7 +2690,7 @@ unmapnotify(struct wl_listener *listener, void *data) wlr_scene_node_destroy(&c->scene->node); printstatus(); - motionnotify(0); + motionnotify(0, NULL, 0, 0, 0, 0); } void From 2b171fd5010379a8674afa012245fea5a590e472 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Mon, 11 Mar 2024 19:01:13 +0100 Subject: [PATCH 221/347] fix virtual pointers When motionabsolute() is called from warpd, event->time_msec is 0, so motionnotify() doesn't call wlr_cursor_move(). Fix this by explicitly warping the cursor in this case, like it was done before implementing pointer constraints. I don't know if this is a bug in warpd or time_msec is always 0 with virtual pointers, since the only other software that uses the virtual pointer protocol I know of is wl-kbptr, and I can't get that to work with dwl at all. --- dwl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dwl.c b/dwl.c index d508d79..5867b0c 100644 --- a/dwl.c +++ b/dwl.c @@ -1675,6 +1675,9 @@ motionabsolute(struct wl_listener *listener, void *data) struct wlr_pointer_motion_absolute_event *event = data; double lx, ly, dx, dy; + if (!event->time_msec) /* this is 0 with virtual pointers */ + wlr_cursor_warp_absolute(cursor, &event->pointer->base, event->x, event->y); + wlr_cursor_absolute_to_layout_coords(cursor, &event->pointer->base, event->x, event->y, &lx, &ly); dx = lx - cursor->x; dy = ly - cursor->y; From 3a95d4ed03bb506658382f1c5dc4e3d002a90464 Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Tue, 26 Mar 2024 20:00:46 -0500 Subject: [PATCH 222/347] Fix rule examples; minimize newbie surprises Make example rules be actual EXAMPLES. Now newcomers should not have to ask, "When I start firefox, nothing happens. What is going on?" Also clarified a minor typo and a consistency in spacing. --- config.def.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/config.def.h b/config.def.h index 9009517..8847e58 100644 --- a/config.def.h +++ b/config.def.h @@ -11,7 +11,7 @@ static const float rootcolor[] = COLOR(0x222222ff); static const float bordercolor[] = COLOR(0x444444ff); static const float focuscolor[] = COLOR(0x005577ff); static const float urgentcolor[] = COLOR(0xff0000ff); -/* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */ +/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */ static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */ /* tagging - TAGCOUNT must be no greater than 31 */ @@ -21,11 +21,10 @@ static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You ca static int log_level = WLR_ERROR; static const Rule rules[] = { - /* app_id title tags mask isfloating monitor */ - /* examples: - { "Gimp", NULL, 0, 1, -1 }, - */ - { "firefox", NULL, 1 << 8, 0, -1 }, + /* app_id title tags mask isfloating monitor */ + /* examples: */ + { "Gimp_EXAMPLE", NULL, 0, 1, -1 }, /* Start on currently visible tags floating, not tiled */ + { "firefox_EXAMPLE", NULL, 1 << 8, 0, -1 }, /* Start on ONLY tag "9" */ }; /* layout(s) */ @@ -95,6 +94,7 @@ LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE */ static const enum libinput_config_accel_profile accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE; static const double accel_speed = 0.0; + /* You can choose between: LIBINPUT_CONFIG_TAP_MAP_LRM -- 1/2/3 finger tap maps to left/right/middle LIBINPUT_CONFIG_TAP_MAP_LMR -- 1/2/3 finger tap maps to left/middle/right From f7154d539d09b4aa5b92371c296d9aa7a045bac0 Mon Sep 17 00:00:00 2001 From: korei999 Date: Sun, 24 Mar 2024 12:54:32 +0200 Subject: [PATCH 223/347] properly resize on configurex11 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 5867b0c..39ce68c 100644 --- a/dwl.c +++ b/dwl.c @@ -2962,7 +2962,7 @@ configurex11(struct wl_listener *listener, void *data) } if (c->isfloating || client_is_unmanaged(c)) resize(c, (struct wlr_box){.x = event->x, .y = event->y, - .width = event->width, .height = event->height}, 0); + .width = event->width + c->bw * 2, .height = event->height + c->bw * 2}, 0); else arrange(c->mon); } From dd00d994ce4c53829d0b871622dc05e90a6f58c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 31 Mar 2024 21:41:12 -0600 Subject: [PATCH 224/347] do not set withdrawn state for xwayland clients Closes: https://codeberg.org/dwl/dwl/issues/573 --- client.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/client.h b/client.h index fe9dffc..800b867 100644 --- a/client.h +++ b/client.h @@ -379,10 +379,8 @@ static inline void client_set_suspended(Client *c, int suspended) { #ifdef XWAYLAND - if (client_is_x11(c)) { - wlr_xwayland_surface_set_withdrawn(c->surface.xwayland, suspended); + if (client_is_x11(c)) return; - } #endif wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended); From 577d8da6d17dad5f847795582ebf813f3c5c04a7 Mon Sep 17 00:00:00 2001 From: choc Date: Thu, 4 Apr 2024 18:48:16 +0800 Subject: [PATCH 225/347] put wlr_layer_shell top layer below fullscreen fixes wlr_layer_shell top clients showing over fullscreen clients --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 39ce68c..bf763df 100644 --- a/dwl.c +++ b/dwl.c @@ -81,7 +81,7 @@ /* enums */ enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ enum { XDGShell, LayerShell, X11 }; /* client types */ -enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrFS, LyrTop, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */ +enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */ #ifdef XWAYLAND enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ From bb734816627b3bad7ea231bfb454777a1c5177ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 21 Apr 2024 15:53:59 -0600 Subject: [PATCH 226/347] use wlr_renderer_get_texture_formats (wlroots!4644) References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4644 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 1ebc3d4..589b187 100644 --- a/dwl.c +++ b/dwl.c @@ -2341,7 +2341,7 @@ setup(void) * with wlr_scene. */ wlr_renderer_init_wl_shm(drw, dpy); - if (wlr_renderer_get_dmabuf_texture_formats(drw)) { + if (wlr_renderer_get_texture_formats(drw, WLR_BUFFER_CAP_DMABUF)) { wlr_drm_create(dpy, drw); wlr_scene_set_linux_dmabuf_v1(scene, wlr_linux_dmabuf_v1_create_with_renderer(dpy, 4, drw)); From 3b1f0a8a88d0b535c76d2f0e919fd68e3a4c3b89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 30 Apr 2024 12:36:10 -0600 Subject: [PATCH 227/347] add support for alpha-modifier-v1 (wlroots!4616) References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4616 --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index 589b187..06db9f4 100644 --- a/dwl.c +++ b/dwl.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -2371,6 +2372,7 @@ setup(void) wlr_single_pixel_buffer_manager_v1_create(dpy); wlr_fractional_scale_manager_v1_create(dpy, 1); wlr_presentation_create(dpy, backend); + wlr_alpha_modifier_v1_create(dpy); /* Initializes the interface used to implement urgency hints */ activation = wlr_xdg_activation_v1_create(dpy); From 5c19e23146b6163e6508765f0062cde9a1718be7 Mon Sep 17 00:00:00 2001 From: sewn Date: Wed, 21 Feb 2024 20:41:29 +0300 Subject: [PATCH 228/347] switch to wmenu bemenu is very bloated, turning itself into a library, which makes it 7489 SLOC. wmenu on the other hand, looks suckless by default, and is only 2000 SLOC, which i also find alot nicer to use, since bemenu does nothing to replicate the original dmenu feel. --- config.def.h | 2 +- dwl.1 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config.def.h b/config.def.h index 8847e58..57acd39 100644 --- a/config.def.h +++ b/config.def.h @@ -115,7 +115,7 @@ static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TA /* commands */ static const char *termcmd[] = { "foot", NULL }; -static const char *menucmd[] = { "bemenu-run", NULL }; +static const char *menucmd[] = { "wmenu_run", NULL }; static const Key keys[] = { /* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */ diff --git a/dwl.1 b/dwl.1 index ce1acf9..e64a71b 100644 --- a/dwl.1 +++ b/dwl.1 @@ -55,7 +55,7 @@ Move window to a single tag. Toggle tag for window. .It Mod-p Spawn -.Nm bemenu-run . +.Nm wmenu_run . .It Mod-Shift-Return Spawn .Nm foot . @@ -143,7 +143,7 @@ with s6 in the background: .Dl dwl -s 's6-svscan <&-' .Sh SEE ALSO .Xr foot 1 , -.Xr bemenu 1 , +.Xr wmenu 1 , .Xr dwm 1 , .Xr xkeyboard-config 7 .Sh CAVEATS From 34b7a5721134d63f8241af2f008c2e0d9f836dd5 Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Sun, 5 May 2024 13:52:25 -0500 Subject: [PATCH 229/347] Update wmenu-run name --- config.def.h | 2 +- dwl.1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config.def.h b/config.def.h index 57acd39..8f498d2 100644 --- a/config.def.h +++ b/config.def.h @@ -115,7 +115,7 @@ static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TA /* commands */ static const char *termcmd[] = { "foot", NULL }; -static const char *menucmd[] = { "wmenu_run", NULL }; +static const char *menucmd[] = { "wmenu-run", NULL }; static const Key keys[] = { /* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */ diff --git a/dwl.1 b/dwl.1 index e64a71b..387bcc9 100644 --- a/dwl.1 +++ b/dwl.1 @@ -55,7 +55,7 @@ Move window to a single tag. Toggle tag for window. .It Mod-p Spawn -.Nm wmenu_run . +.Nm wmenu-run . .It Mod-Shift-Return Spawn .Nm foot . From 9825c26cdd5dfed34022b77a8936c5d8f485e134 Mon Sep 17 00:00:00 2001 From: fauxmight Date: Fri, 10 May 2024 05:08:54 +0000 Subject: [PATCH 230/347] dwl-patches overhaul - doc changes --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 5b3d4f6..9d91923 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ Wayland without restarting the entire display server, so any changes will take effect the next time dwl is executed. As in the dwm community, we encourage users to share patches they have created. -Check out the dwl [patches repository] and [patches wiki]! +Check out the dwl [patches repository]! ## Running dwl @@ -170,7 +170,6 @@ inspiration, and to the various contributors to the project, including: [wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots/ [wlroots-next branch]: https://codeberg.org/dwl/dwl/src/branch/wlroots-next [patches repository]: https://codeberg.org/dwl/dwl-patches -[patches wiki]: https://codeberg.org/dwl/dwl-patches/wiki [s6]: https://skarnet.org/software/s6/ [anopa]: https://jjacky.com/anopa/ [runit]: http://smarden.org/runit/faq.html#userservices From bf81a128ecddaa63a904c2b08b80ed03619e0eb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 27 May 2024 23:10:40 -0600 Subject: [PATCH 231/347] wlroots now allows parallel installs --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a67fdd3..82f23b3 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement -Wno-unu -Werror=strict-prototypes -Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types -Wfloat-conversion # CFLAGS / LDFLAGS -PKGS = wlroots wayland-server xkbcommon libinput $(XLIBS) +PKGS = wlroots-0.18 wayland-server xkbcommon libinput $(XLIBS) DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS) LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(LIBS) From 0047ff740a4f8da430cecdb19084f626bf535b21 Mon Sep 17 00:00:00 2001 From: Forrest Bushstone Date: Fri, 5 Apr 2024 21:54:54 -0400 Subject: [PATCH 232/347] Replicate dwm behavior for sloppyfocus --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index bf763df..52bfbc8 100644 --- a/dwl.c +++ b/dwl.c @@ -1882,7 +1882,7 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, { struct timespec now; - if ((!active_constraint || active_constraint->surface != surface) && + if (surface != seat->pointer_state.focused_surface && sloppyfocus && time && c && !client_is_unmanaged(c)) focusclient(c, 0); From bca077b9279f28c12cced63f0a556c0556f7169c Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Sun, 2 Jun 2024 14:19:24 -0500 Subject: [PATCH 233/347] Allow negative coordinates in MonitorRules Monitor/output position (-1, -1) remains as a single indicator value for autoconfigure layout. Additionally, one minor comment typo is corrected. --- config.def.h | 2 ++ dwl.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/config.def.h b/config.def.h index 8f498d2..a784eb4 100644 --- a/config.def.h +++ b/config.def.h @@ -36,6 +36,8 @@ static const Layout layouts[] = { }; /* monitors */ +/* (x=-1, y=-1) is reserved as an "autoconfigure" monitor position indicator */ +/* WARNING: negative values other than (-1, -1) cause problems with xwayland clients' menus */ /* NOTE: ALWAYS add a fallback rule, even if you are completely sure it won't be used */ static const MonitorRule monrules[] = { /* name mfact nmaster scale layout rotate/reflect x y */ diff --git a/dwl.c b/dwl.c index 52bfbc8..1ea7f2a 100644 --- a/dwl.c +++ b/dwl.c @@ -927,14 +927,14 @@ createmon(struct wl_listener *listener, void *data) m->fullscreen_bg = wlr_scene_rect_create(layers[LyrFS], 0, 0, fullscreen_bg); wlr_scene_node_set_enabled(&m->fullscreen_bg->node, 0); - /* Adds this to the output layout in the order it was configured in. + /* Adds this to the output layout in the order it was configured. * * The output layout utility automatically adds a wl_output global to the * display, which Wayland clients can see to find out information about the * output (such as DPI, scale factor, manufacturer, etc). */ m->scene_output = wlr_scene_output_create(scene, wlr_output); - if (m->m.x < 0 || m->m.y < 0) + if (m->m.x == -1 && m->m.y == -1) wlr_output_layout_add_auto(output_layout, wlr_output); else wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y); From 8f6fca35d0710b347836dcaf3543e85e58783e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 30 Jan 2024 13:16:16 -0600 Subject: [PATCH 234/347] create a keyboard group for each virtual keyboard --- dwl.c | 128 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 66 insertions(+), 62 deletions(-) diff --git a/dwl.c b/dwl.c index 1ea7f2a..356b913 100644 --- a/dwl.c +++ b/dwl.c @@ -159,6 +159,7 @@ typedef struct { struct wl_listener modifiers; struct wl_listener key; + struct wl_listener destroy; } KeyboardGroup; typedef struct { @@ -258,6 +259,7 @@ static void commitnotify(struct wl_listener *listener, void *data); static void createdecoration(struct wl_listener *listener, void *data); static void createidleinhibitor(struct wl_listener *listener, void *data); static void createkeyboard(struct wlr_keyboard *keyboard); +static KeyboardGroup *createkeyboardgroup(void); static void createlayersurface(struct wl_listener *listener, void *data); static void createlocksurface(struct wl_listener *listener, void *data); static void createmon(struct wl_listener *listener, void *data); @@ -277,6 +279,7 @@ static void destroynotify(struct wl_listener *listener, void *data); static void destroypointerconstraint(struct wl_listener *listener, void *data); static void destroysessionlock(struct wl_listener *listener, void *data); static void destroysessionmgr(struct wl_listener *listener, void *data); +static void destroykeyboardgroup(struct wl_listener *listener, void *data); static Monitor *dirtomon(enum wlr_direction dir); static void focusclient(Client *c, int lift); static void focusmon(const Arg *arg); @@ -393,8 +396,7 @@ static struct wlr_session_lock_v1 *cur_lock; static struct wl_listener lock_listener = {.notify = locksession}; static struct wlr_seat *seat; -static KeyboardGroup kb_group = {0}; -static KeyboardGroup vkb_group = {0}; +static KeyboardGroup *kb_group; static struct wlr_surface *held_grab; static unsigned int cursor_mode; static Client *grabc; @@ -667,9 +669,7 @@ cleanup(void) wlr_xcursor_manager_destroy(cursor_mgr); wlr_output_layout_destroy(output_layout); - /* Remove event source that use the dpy event loop before destroying dpy */ - wl_event_source_remove(kb_group.key_repeat_source); - wl_event_source_remove(vkb_group.key_repeat_source); + destroykeyboardgroup(&kb_group->destroy, NULL); wl_display_destroy(dpy); /* Destroy after the wayland display (when the monitors are already destroyed) @@ -790,11 +790,48 @@ void createkeyboard(struct wlr_keyboard *keyboard) { /* Set the keymap to match the group keymap */ - wlr_keyboard_set_keymap(keyboard, kb_group.wlr_group->keyboard.keymap); - wlr_keyboard_set_repeat_info(keyboard, repeat_rate, repeat_delay); + wlr_keyboard_set_keymap(keyboard, kb_group->wlr_group->keyboard.keymap); /* Add the new keyboard to the group */ - wlr_keyboard_group_add_keyboard(kb_group.wlr_group, keyboard); + wlr_keyboard_group_add_keyboard(kb_group->wlr_group, keyboard); +} + +KeyboardGroup * +createkeyboardgroup(void) +{ + KeyboardGroup *group = ecalloc(1, sizeof(*group)); + struct xkb_context *context; + struct xkb_keymap *keymap; + + group->wlr_group = wlr_keyboard_group_create(); + group->wlr_group->data = group; + + /* Prepare an XKB keymap and assign it to the keyboard group. */ + context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules, + XKB_KEYMAP_COMPILE_NO_FLAGS))) + die("failed to compile keymap"); + + wlr_keyboard_set_keymap(&group->wlr_group->keyboard, keymap); + xkb_keymap_unref(keymap); + xkb_context_unref(context); + + wlr_keyboard_set_repeat_info(&group->wlr_group->keyboard, repeat_rate, repeat_delay); + + /* Set up listeners for keyboard events */ + LISTEN(&group->wlr_group->keyboard.events.key, &group->key, keypress); + LISTEN(&group->wlr_group->keyboard.events.modifiers, &group->modifiers, keypressmod); + + group->key_repeat_source = wl_event_loop_add_timer( + wl_display_get_event_loop(dpy), keyrepeat, group); + + /* A seat can only have one keyboard, but this is a limitation of the + * Wayland protocol - not wlroots. We assign all connected keyboards to the + * same wlr_keyboard_group, which provides a single wlr_keyboard interface for + * all of them. Set this combined wlr_keyboard as the seat keyboard. + */ + wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); + return group; } void @@ -1217,6 +1254,18 @@ destroysessionmgr(struct wl_listener *listener, void *data) wl_list_remove(&listener->link); } +void +destroykeyboardgroup(struct wl_listener *listener, void *data) +{ + KeyboardGroup *group = wl_container_of(listener, group, destroy); + wl_event_source_remove(group->key_repeat_source); + wlr_keyboard_group_destroy(group->wlr_group); + wl_list_remove(&group->key.link); + wl_list_remove(&group->modifiers.link); + wl_list_remove(&group->destroy.link); + free(group); +} + Monitor * dirtomon(enum wlr_direction dir) { @@ -1422,7 +1471,7 @@ inputdevice(struct wl_listener *listener, void *data) * there are no pointer devices, so we always include that capability. */ /* TODO do we actually require a cursor? */ caps = WL_SEAT_CAPABILITY_POINTER; - if (!wl_list_empty(&kb_group.wlr_group->devices)) + if (!wl_list_empty(&kb_group->wlr_group->devices)) caps |= WL_SEAT_CAPABILITY_KEYBOARD; wlr_seat_set_capabilities(seat, caps); } @@ -2269,9 +2318,6 @@ setsel(struct wl_listener *listener, void *data) void setup(void) { - struct xkb_context *context; - struct xkb_keymap *keymap; - int i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE}; struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig}; sigemptyset(&sa.sa_mask); @@ -2453,52 +2499,8 @@ setup(void) LISTEN_STATIC(&seat->events.request_start_drag, requeststartdrag); LISTEN_STATIC(&seat->events.start_drag, startdrag); - /* - * Configures a keyboard group, which will keep track of all connected - * keyboards, keep their modifier and LED states in sync, and handle - * keypresses - */ - kb_group.wlr_group = wlr_keyboard_group_create(); - kb_group.wlr_group->data = &kb_group; - - /* - * Virtual keyboards need to be in a different group - * https://codeberg.org/dwl/dwl/issues/554 - */ - vkb_group.wlr_group = wlr_keyboard_group_create(); - vkb_group.wlr_group->data = &vkb_group; - - /* Prepare an XKB keymap and assign it to the keyboard group. */ - context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules, - XKB_KEYMAP_COMPILE_NO_FLAGS))) - die("failed to compile keymap"); - - wlr_keyboard_set_keymap(&kb_group.wlr_group->keyboard, keymap); - wlr_keyboard_set_keymap(&vkb_group.wlr_group->keyboard, keymap); - xkb_keymap_unref(keymap); - xkb_context_unref(context); - - wlr_keyboard_set_repeat_info(&kb_group.wlr_group->keyboard, repeat_rate, repeat_delay); - wlr_keyboard_set_repeat_info(&vkb_group.wlr_group->keyboard, repeat_rate, repeat_delay); - - /* Set up listeners for keyboard events */ - LISTEN(&kb_group.wlr_group->keyboard.events.key, &kb_group.key, keypress); - LISTEN(&kb_group.wlr_group->keyboard.events.modifiers, &kb_group.modifiers, keypressmod); - LISTEN(&vkb_group.wlr_group->keyboard.events.key, &vkb_group.key, keypress); - LISTEN(&vkb_group.wlr_group->keyboard.events.modifiers, &vkb_group.modifiers, keypressmod); - - kb_group.key_repeat_source = wl_event_loop_add_timer( - wl_display_get_event_loop(dpy), keyrepeat, &kb_group); - vkb_group.key_repeat_source = wl_event_loop_add_timer( - wl_display_get_event_loop(dpy), keyrepeat, &vkb_group); - - /* A seat can only have one keyboard, but this is a limitation of the - * Wayland protocol - not wlroots. We assign all connected keyboards to the - * same wlr_keyboard_group, which provides a single wlr_keyboard interface for - * all of them. Set this combined wlr_keyboard as the seat keyboard. - */ - wlr_seat_set_keyboard(seat, &kb_group.wlr_group->keyboard); + kb_group = createkeyboardgroup(); + wl_list_init(&kb_group->destroy.link); output_mgr = wlr_output_manager_v1_create(dpy); LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply); @@ -2838,13 +2840,15 @@ view(const Arg *arg) void virtualkeyboard(struct wl_listener *listener, void *data) { - struct wlr_virtual_keyboard_v1 *keyboard = data; + struct wlr_virtual_keyboard_v1 *kb = data; + /* virtual keyboards shouldn't share keyboard group */ + KeyboardGroup *group = createkeyboardgroup(); /* Set the keymap to match the group keymap */ - wlr_keyboard_set_keymap(&keyboard->keyboard, vkb_group.wlr_group->keyboard.keymap); - wlr_keyboard_set_repeat_info(&keyboard->keyboard, repeat_rate, repeat_delay); + wlr_keyboard_set_keymap(&kb->keyboard, group->wlr_group->keyboard.keymap); + LISTEN(&kb->keyboard.base.events.destroy, &group->destroy, destroykeyboardgroup); /* Add the new keyboard to the group */ - wlr_keyboard_group_add_keyboard(vkb_group.wlr_group, &keyboard->keyboard); + wlr_keyboard_group_add_keyboard(group->wlr_group, &kb->keyboard); } void From 21205f2f404ee2ae0680becbe914e6deb04df2ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 30 May 2024 17:48:01 -0600 Subject: [PATCH 235/347] make sure clients share the same layer on floating layout --- dwl.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 356b913..6f041a0 100644 --- a/dwl.c +++ b/dwl.c @@ -495,6 +495,20 @@ arrange(Monitor *m) strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); + /* We move all clients (except fullscreen and unmanaged) to LyrTile while + * in floating layout to avoid "real" floating clients be always on top */ + wl_list_for_each(c, &clients, link) { + if (c->mon != m || c->isfullscreen) + continue; + + wlr_scene_node_reparent(&c->scene->node, + (!m->lt[m->sellt]->arrange && c->isfloating) + ? layers[LyrTile] + : (m->lt[m->sellt]->arrange && c->isfloating) + ? layers[LyrFloat] + : c->scene->node.parent); + } + if (m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); motionnotify(0, NULL, 0, 0, 0, 0); @@ -2198,7 +2212,8 @@ setfloating(Client *c, int floating) { Client *p = client_get_parent(c); c->isfloating = floating; - if (!c->mon) + /* If in floating layout do not change the client's layer */ + if (!c->mon || !c->mon->lt[c->mon->sellt]->arrange) return; wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen || (p && p->isfullscreen) ? LyrFS From 57b5e41063d27087d3a651b28f1ae6c7d9e2a6da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 30 May 2024 15:00:05 -0600 Subject: [PATCH 236/347] use enum headers when possible --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 82f23b3..29f24b4 100644 --- a/Makefile +++ b/Makefile @@ -26,13 +26,13 @@ WAYLAND_SCANNER = `$(PKG_CONFIG) --variable=wayland_scanner wayland-scanner` WAYLAND_PROTOCOLS = `$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols` cursor-shape-v1-protocol.h: - $(WAYLAND_SCANNER) server-header \ + $(WAYLAND_SCANNER) enum-header \ $(WAYLAND_PROTOCOLS)/staging/cursor-shape/cursor-shape-v1.xml $@ pointer-constraints-unstable-v1-protocol.h: - $(WAYLAND_SCANNER) server-header \ + $(WAYLAND_SCANNER) enum-header \ $(WAYLAND_PROTOCOLS)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@ wlr-layer-shell-unstable-v1-protocol.h: - $(WAYLAND_SCANNER) server-header \ + $(WAYLAND_SCANNER) enum-header \ protocols/wlr-layer-shell-unstable-v1.xml $@ xdg-shell-protocol.h: $(WAYLAND_SCANNER) server-header \ From e5a57fb155c0238c46336795902c6bfdf4c6d00b Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Wed, 12 Jun 2024 21:05:32 +0200 Subject: [PATCH 237/347] use tabs in client.h Fixes 298949bbc4eae8cedb9cdd11cfc9ebd139ac5d5f. --- client.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/client.h b/client.h index 800b867..19861b9 100644 --- a/client.h +++ b/client.h @@ -172,11 +172,11 @@ client_get_parent(Client *c) { Client *p = NULL; #ifdef XWAYLAND - if (client_is_x11(c)) { - if (c->surface.xwayland->parent) - toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL); - return p; - } + if (client_is_x11(c)) { + if (c->surface.xwayland->parent) + toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL); + return p; + } #endif if (c->surface.xdg->toplevel->parent) toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL); @@ -187,12 +187,12 @@ static inline int client_has_children(Client *c) { #ifdef XWAYLAND - if (client_is_x11(c)) - return !wl_list_empty(&c->surface.xwayland->children); + if (client_is_x11(c)) + return !wl_list_empty(&c->surface.xwayland->children); #endif - /* surface.xdg->link is never empty because it always contains at least the - * surface itself. */ - return wl_list_length(&c->surface.xdg->link) > 1; + /* surface.xdg->link is never empty because it always contains at least the + * surface itself. */ + return wl_list_length(&c->surface.xdg->link) > 1; } static inline const char * From 7570dc0a41c4b2a1952f7275327d7168e45129fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 13 Jun 2024 14:23:51 -0600 Subject: [PATCH 238/347] minor adjustments in Makefile --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index a67fdd3..e3e6426 100644 --- a/Makefile +++ b/Makefile @@ -15,8 +15,8 @@ LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(LIBS) all: dwl dwl: dwl.o util.o - $(CC) dwl.o util.o $(LDLIBS) $(LDFLAGS) $(DWLCFLAGS) -o $@ -dwl.o: dwl.c config.mk config.h client.h cursor-shape-v1-protocol.h pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h xdg-shell-protocol.h + $(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ +dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h xdg-shell-protocol.h util.o: util.c util.h # wayland-scanner is a tool which generates C headers and rigging for Wayland @@ -66,4 +66,4 @@ uninstall: .SUFFIXES: .c .o .c.o: - $(CC) $(CPPFLAGS) $(DWLCFLAGS) -c $< + $(CC) $(CPPFLAGS) $(DWLCFLAGS) -o $@ -c $< From c2e7350f2ef4f07810c8fa49bed3e8db37faa058 Mon Sep 17 00:00:00 2001 From: Forrest Bushstone Date: Wed, 12 Jun 2024 14:04:43 -0400 Subject: [PATCH 239/347] Make sure toplevel_from_wlr_surface is called with a valid surface pointer --- dwl.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/dwl.c b/dwl.c index 6f041a0..5a31aee 100644 --- a/dwl.c +++ b/dwl.c @@ -397,7 +397,6 @@ static struct wl_listener lock_listener = {.notify = locksession}; static struct wlr_seat *seat; static KeyboardGroup *kb_group; -static struct wlr_surface *held_grab; static unsigned int cursor_mode; static Client *grabc; static int grabcx, grabcy; /* client-relative */ @@ -603,7 +602,6 @@ buttonpress(struct wl_listener *listener, void *data) switch (event->state) { case WLR_BUTTON_PRESSED: cursor_mode = CurPressed; - held_grab = seat->pointer_state.focused_surface; if (locked) break; @@ -623,7 +621,6 @@ buttonpress(struct wl_listener *listener, void *data) } break; case WLR_BUTTON_RELEASED: - held_grab = NULL; /* If you released any buttons, we exit interactive move/resize mode. */ /* TODO should reset to the pointer focus's current setcursor */ if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { @@ -1757,6 +1754,18 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d struct wlr_surface *surface = NULL; struct wlr_pointer_constraint_v1 *constraint; + /* Find the client under the pointer and send the event along. */ + xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy); + + if (cursor_mode == CurPressed && !seat->drag + && surface != seat->pointer_state.focused_surface + && toplevel_from_wlr_surface(seat->pointer_state.focused_surface, &w, &l) >= 0) { + c = w; + surface = seat->pointer_state.focused_surface; + sx = cursor->x - (l ? l->geom.x : w->geom.x); + sy = cursor->y - (l ? l->geom.y : w->geom.y); + } + /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { wlr_relative_pointer_manager_v1_send_relative_motion( @@ -1805,17 +1814,6 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d return; } - /* Find the client under the pointer and send the event along. */ - xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy); - - if (cursor_mode == CurPressed && !seat->drag && surface != held_grab - && toplevel_from_wlr_surface(held_grab, &w, &l) >= 0) { - c = w; - surface = held_grab; - sx = cursor->x - (l ? l->geom.x : w->geom.x); - sy = cursor->y - (l ? l->geom.y : w->geom.y); - } - /* If there's no client surface under the cursor, set the cursor image to a * default. This is what makes the cursor image appear when you move it * off of a client or over its border. */ From 7a46fccdba35b46d91226d10c1c9b90e43418c09 Mon Sep 17 00:00:00 2001 From: Peter Hofmann Date: Tue, 18 Jun 2024 19:09:32 +0200 Subject: [PATCH 240/347] Run startup_cmd in new session and kill the entire group When a user's startup_cmd is a little more complex, e.g. a shell script, and forks off several processes, then killing only the main child pid might leave unwanted processes behind on exit. Not all children will notice when their parent or the compositor has quit. To fix this, put startup_cmd into its own session and process group, and kill the entire group on exit. --- dwl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 5a31aee..79ccb34 100644 --- a/dwl.c +++ b/dwl.c @@ -674,7 +674,7 @@ cleanup(void) #endif wl_display_destroy_clients(dpy); if (child_pid > 0) { - kill(child_pid, SIGTERM); + kill(-child_pid, SIGTERM); waitpid(child_pid, NULL, 0); } wlr_xcursor_manager_destroy(cursor_mgr); @@ -2141,6 +2141,7 @@ run(char *startup_cmd) if ((child_pid = fork()) < 0) die("startup: fork:"); if (child_pid == 0) { + setsid(); dup2(piperw[0], STDIN_FILENO); close(piperw[0]); close(piperw[1]); From a8403d7b4d54e30699424586784cc0265b29d08d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 3 May 2024 11:03:18 -0600 Subject: [PATCH 241/347] handle gpu resets Fixes: https://codeberg.org/dwl/dwl/issues/601 --- dwl.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/dwl.c b/dwl.c index 9890a6c..7b61ba2 100644 --- a/dwl.c +++ b/dwl.c @@ -289,6 +289,7 @@ static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); static Client *focustop(Monitor *m); static void fullscreennotify(struct wl_listener *listener, void *data); +static void gpureset(struct wl_listener *listener, void *data); static void handlesig(int signo); static void incnmaster(const Arg *arg); static void inputdevice(struct wl_listener *listener, void *data); @@ -1454,6 +1455,30 @@ fullscreennotify(struct wl_listener *listener, void *data) setfullscreen(c, client_wants_fullscreen(c)); } +void +gpureset(struct wl_listener *listener, void *data) +{ + struct wlr_renderer *old_drw = drw; + struct wlr_allocator *old_alloc = alloc; + struct Monitor *m; + if (!(drw = wlr_renderer_autocreate(backend))) + die("couldn't recreate renderer"); + + if (!(alloc = wlr_allocator_autocreate(backend, drw))) + die("couldn't recreate allocator"); + + LISTEN_STATIC(&drw->events.lost, gpureset); + + wlr_compositor_set_renderer(compositor, drw); + + wl_list_for_each(m, &mons, link) { + wlr_output_init_render(m->wlr_output, alloc, drw); + } + + wlr_allocator_destroy(old_alloc); + wlr_renderer_destroy(old_drw); +} + void handlesig(int signo) { @@ -2394,6 +2419,7 @@ setup(void) * supports for shared memory, this configures that for clients. */ if (!(drw = wlr_renderer_autocreate(backend))) die("couldn't create renderer"); + LISTEN_STATIC(&drw->events.lost, gpureset); /* Create shm, drm and linux_dmabuf interfaces by ourselves. * The simplest way is call: From 16076ec5a40ed708b99f27100036a4a92b4fdd59 Mon Sep 17 00:00:00 2001 From: Rutherther Date: Sat, 4 May 2024 20:59:51 +0200 Subject: [PATCH 242/347] fix: make sure selmon doesn't get set to disabled mon --- dwl.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dwl.c b/dwl.c index 79ccb34..83bdbe4 100644 --- a/dwl.c +++ b/dwl.c @@ -727,6 +727,9 @@ closemon(Monitor *m) do /* don't switch to disabled mons */ selmon = wl_container_of(mons.next, selmon, link); while (!selmon->wlr_output->enabled && i++ < nmons); + + if (!selmon->wlr_output->enabled) + selmon = NULL; } wl_list_for_each(c, &clients, link) { @@ -2789,6 +2792,10 @@ updatemons(struct wl_listener *listener, void *data) config_head->state.x = m->m.x; config_head->state.y = m->m.y; + + if (!selmon) { + selmon = m; + } } if (selmon && selmon->wlr_output->enabled) { From 11baacbec0b75dff34abf52d5172687e4ae2cc4f Mon Sep 17 00:00:00 2001 From: Rutherther Date: Tue, 14 May 2024 17:57:59 +0200 Subject: [PATCH 243/347] Add output to layout after enabled state is committed --- dwl.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index 83bdbe4..60b74ae 100644 --- a/dwl.c +++ b/dwl.c @@ -1906,11 +1906,6 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) config_head->state.custom_mode.height, config_head->state.custom_mode.refresh); - /* Don't move monitors if position wouldn't change, this to avoid - * wlroots marking the output as manually configured */ - if (m->m.x != config_head->state.x || m->m.y != config_head->state.y) - wlr_output_layout_add(output_layout, wlr_output, - config_head->state.x, config_head->state.y); wlr_output_state_set_transform(&state, config_head->state.transform); wlr_output_state_set_scale(&state, config_head->state.scale); wlr_output_state_set_adaptive_sync_enabled(&state, @@ -1920,6 +1915,13 @@ apply_or_test: ok &= test ? wlr_output_test_state(wlr_output, &state) : wlr_output_commit_state(wlr_output, &state); + /* Don't move monitors if position wouldn't change, this to avoid + * wlroots marking the output as manually configured. + * wlr_output_layout_add does not like disabled outputs */ + if (!test && wlr_output->enabled && (m->m.x != config_head->state.x || m->m.y != config_head->state.y)) + wlr_output_layout_add(output_layout, wlr_output, + config_head->state.x, config_head->state.y); + wlr_output_state_finish(&state); } From 784b047b3825b0c784de85034e9b215134250e3c Mon Sep 17 00:00:00 2001 From: Rutherther Date: Fri, 31 May 2024 16:00:50 +0200 Subject: [PATCH 244/347] Check for null monitor in resize function --- dwl.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 60b74ae..3dba2bf 100644 --- a/dwl.c +++ b/dwl.c @@ -2100,8 +2100,14 @@ requestmonstate(struct wl_listener *listener, void *data) void resize(Client *c, struct wlr_box geo, int interact) { - struct wlr_box *bbox = interact ? &sgeom : &c->mon->w; + struct wlr_box *bbox; struct wlr_box clip; + + if (!c->mon) + return; + + bbox = interact ? &sgeom : &c->mon->w; + client_set_bounds(c, geo.width, geo.height); c->geom = geo; applybounds(c, bbox); From 92d1c286b8041bcdf5c335a63f5c060460e2a0e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 20 Jun 2024 18:38:59 -0600 Subject: [PATCH 245/347] default CC to gcc posix c99 does not accept `-pedantic` Fixes: https://codeberg.org/dwl/dwl/issues/584 --- config.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config.mk b/config.mk index 906f403..259bd0f 100644 --- a/config.mk +++ b/config.mk @@ -13,3 +13,5 @@ XLIBS = # Uncomment to build XWayland support #XWAYLAND = -DXWAYLAND #XLIBS = xcb xcb-icccm + +CC = gcc From 9b1f35e42bf435b212dfcdcc510439ef8b4f2e31 Mon Sep 17 00:00:00 2001 From: Emil Miler Date: Wed, 17 Jan 2024 09:45:03 +0100 Subject: [PATCH 246/347] Implement support for output power management This patch is based on the original stale patch by Guido Cella @guidocella. It has been modified to apply cleanly to the latest v5.0 tag. Since the SLOC limit is now lifted, this core feature should be merged into dwl upstream. Thanks to Dima Krasner @dimkr for the cherry-pick. Closes: #559, #525 --- Makefile | 5 +- dwl.c | 14 ++ ...lr-output-power-management-unstable-v1.xml | 128 ++++++++++++++++++ 3 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 protocols/wlr-output-power-management-unstable-v1.xml diff --git a/Makefile b/Makefile index e3e6426..8375772 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(LIBS) all: dwl dwl: dwl.o util.o $(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ -dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h xdg-shell-protocol.h +dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h xdg-shell-protocol.h wlr-output-power-management-unstable-v1-protocol.h util.o: util.c util.h # wayland-scanner is a tool which generates C headers and rigging for Wayland @@ -37,6 +37,9 @@ wlr-layer-shell-unstable-v1-protocol.h: xdg-shell-protocol.h: $(WAYLAND_SCANNER) server-header \ $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ +wlr-output-power-management-unstable-v1-protocol.h: + $(WAYLAND_SCANNER) server-header \ + protocols/wlr-output-power-management-unstable-v1.xml $@ config.h: cp config.def.h $@ diff --git a/dwl.c b/dwl.c index 3dba2bf..7a2920e 100644 --- a/dwl.c +++ b/dwl.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -310,6 +311,7 @@ static void outputmgrtest(struct wl_listener *listener, void *data); static void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, uint32_t time); static void printstatus(void); +static void powermgrsetmodenotify(struct wl_listener *listener, void *data); static void quit(const Arg *arg); static void rendermon(struct wl_listener *listener, void *data); static void requestdecorationmode(struct wl_listener *listener, void *data); @@ -381,6 +383,7 @@ static struct wlr_gamma_control_manager_v1 *gamma_control_mgr; static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; static struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr; static struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr; +static struct wlr_output_power_manager_v1 *power_mgr; static struct wlr_pointer_constraints_v1 *pointer_constraints; static struct wlr_relative_pointer_manager_v1 *relative_pointer_mgr; @@ -2011,6 +2014,14 @@ printstatus(void) fflush(stdout); } +void +powermgrsetmodenotify(struct wl_listener *listener, void *data) +{ + struct wlr_output_power_v1_set_mode_event *event = data; + wlr_output_enable(event->output, event->mode); + wlr_output_commit(event->output); +} + void quit(const Arg *arg) { @@ -2422,6 +2433,9 @@ setup(void) gamma_control_mgr = wlr_gamma_control_manager_v1_create(dpy); LISTEN_STATIC(&gamma_control_mgr->events.set_gamma, setgamma); + power_mgr = wlr_output_power_manager_v1_create(dpy); + LISTEN_STATIC(&power_mgr->events.set_mode, powermgrsetmodenotify); + /* Creates an output layout, which a wlroots utility for working with an * arrangement of screens in a physical layout. */ output_layout = wlr_output_layout_create(); diff --git a/protocols/wlr-output-power-management-unstable-v1.xml b/protocols/wlr-output-power-management-unstable-v1.xml new file mode 100644 index 0000000..a977839 --- /dev/null +++ b/protocols/wlr-output-power-management-unstable-v1.xml @@ -0,0 +1,128 @@ + + + + Copyright © 2019 Purism SPC + + 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 clients to control power management modes + of outputs that are currently part of the compositor space. The + intent is to allow special clients like desktop shells to power + down outputs when the system is idle. + + To modify outputs not currently part of the compositor space see + wlr-output-management. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible changes + may be added together with the corresponding interface version bump. + Backward incompatible changes are done by bumping the version number in + the protocol and interface names and resetting the interface version. + Once the protocol is to be declared stable, the 'z' prefix and the + version number in the protocol and interface names are removed and the + interface version number is reset. + + + + + This interface is a manager that allows creating per-output power + management mode controls. + + + + + Create a output power management mode control that can be used to + adjust the power management mode for a given output. + + + + + + + + All objects created by the manager will still remain valid, until their + appropriate destroy request has been called. + + + + + + + This object offers requests to set the power management mode of + an output. + + + + + + + + + + + + + + Set an output's power save mode to the given mode. The mode change + is effective immediately. If the output does not support the given + mode a failed event is sent. + + + + + + + Report the power management mode change of an output. + + The mode event is sent after an output changed its power + management mode. The reason can be a client using set_mode or the + compositor deciding to change an output's mode. + This event is also sent immediately when the object is created + so the client is informed about the current power management mode. + + + + + + + This event indicates that the output power management mode control + is no longer valid. This can happen for a number of reasons, + including: + - The output doesn't support power management + - Another client already has exclusive power management mode control + for this output + - The output disappeared + + Upon receiving this event, the client should destroy this object. + + + + + + Destroys the output power management mode control object. + + + + From 2902df94d6e3da04b7abc92f846b0da7d40ff4ea Mon Sep 17 00:00:00 2001 From: David Donahue Date: Sat, 6 Apr 2024 11:29:14 -0600 Subject: [PATCH 247/347] Prevent updatemons() from removing monitors that have been put to sleep from the layout --- dwl.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 7a2920e..4867760 100644 --- a/dwl.c +++ b/dwl.c @@ -207,6 +207,7 @@ struct Monitor { int gamma_lut_changed; int nmaster; char ltsymbol[16]; + int asleep; }; typedef struct { @@ -962,6 +963,8 @@ createmon(struct wl_listener *listener, void *data) LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon); LISTEN(&wlr_output->events.request_state, &m->request_state, requestmonstate); + m->asleep = 0; + wlr_output_state_set_enabled(&state, 1); wlr_output_commit_state(wlr_output, &state); wlr_output_state_finish(&state); @@ -2018,8 +2021,11 @@ void powermgrsetmodenotify(struct wl_listener *listener, void *data) { struct wlr_output_power_v1_set_mode_event *event = data; + wlr_output_enable(event->output, event->mode); wlr_output_commit(event->output); + + ((Monitor *)(event->output->data))->asleep = !event->mode; } void @@ -2755,7 +2761,7 @@ updatemons(struct wl_listener *listener, void *data) /* First remove from the layout the disabled monitors */ wl_list_for_each(m, &mons, link) { - if (m->wlr_output->enabled) + if (m->wlr_output->enabled || m->asleep) continue; config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output); config_head->state.enabled = 0; From 650a918010ac5769787d461812392cff786e4d3b Mon Sep 17 00:00:00 2001 From: thanatos Date: Thu, 20 Jun 2024 18:48:47 -0600 Subject: [PATCH 248/347] Updated power management handling to address issues raised in the PR --- Makefile | 8 ++++---- dwl.c | 20 +++++++++++++------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 8375772..fdc581a 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(LIBS) all: dwl dwl: dwl.o util.o $(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ -dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h xdg-shell-protocol.h wlr-output-power-management-unstable-v1-protocol.h +dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h util.o: util.c util.h # wayland-scanner is a tool which generates C headers and rigging for Wayland @@ -34,12 +34,12 @@ pointer-constraints-unstable-v1-protocol.h: wlr-layer-shell-unstable-v1-protocol.h: $(WAYLAND_SCANNER) server-header \ protocols/wlr-layer-shell-unstable-v1.xml $@ -xdg-shell-protocol.h: - $(WAYLAND_SCANNER) server-header \ - $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ wlr-output-power-management-unstable-v1-protocol.h: $(WAYLAND_SCANNER) server-header \ protocols/wlr-output-power-management-unstable-v1.xml $@ +xdg-shell-protocol.h: + $(WAYLAND_SCANNER) server-header \ + $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ config.h: cp config.def.h $@ diff --git a/dwl.c b/dwl.c index 4867760..2cdc819 100644 --- a/dwl.c +++ b/dwl.c @@ -312,7 +312,7 @@ static void outputmgrtest(struct wl_listener *listener, void *data); static void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, uint32_t time); static void printstatus(void); -static void powermgrsetmodenotify(struct wl_listener *listener, void *data); +static void powermgrsetmode(struct wl_listener *listener, void *data); static void quit(const Arg *arg); static void rendermon(struct wl_listener *listener, void *data); static void requestdecorationmode(struct wl_listener *listener, void *data); @@ -963,8 +963,6 @@ createmon(struct wl_listener *listener, void *data) LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon); LISTEN(&wlr_output->events.request_state, &m->request_state, requestmonstate); - m->asleep = 0; - wlr_output_state_set_enabled(&state, 1); wlr_output_commit_state(wlr_output, &state); wlr_output_state_finish(&state); @@ -1899,6 +1897,10 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) Monitor *m = wlr_output->data; struct wlr_output_state state; + /* Ensure displays previously disabled by wlr-output-power-management-v1 + * are properly handled*/ + m->asleep = 0; + wlr_output_state_init(&state); wlr_output_state_set_enabled(&state, config_head->state.enabled); if (!config_head->state.enabled) @@ -2018,12 +2020,16 @@ printstatus(void) } void -powermgrsetmodenotify(struct wl_listener *listener, void *data) +powermgrsetmode(struct wl_listener *listener, void *data) { struct wlr_output_power_v1_set_mode_event *event = data; + struct wlr_output_state state = {0}; - wlr_output_enable(event->output, event->mode); - wlr_output_commit(event->output); + if (!event->output->data) + return; + + wlr_output_state_set_enabled(&state, event->mode); + wlr_output_commit_state(event->output, &state); ((Monitor *)(event->output->data))->asleep = !event->mode; } @@ -2440,7 +2446,7 @@ setup(void) LISTEN_STATIC(&gamma_control_mgr->events.set_gamma, setgamma); power_mgr = wlr_output_power_manager_v1_create(dpy); - LISTEN_STATIC(&power_mgr->events.set_mode, powermgrsetmodenotify); + LISTEN_STATIC(&power_mgr->events.set_mode, powermgrsetmode); /* Creates an output layout, which a wlroots utility for working with an * arrangement of screens in a physical layout. */ From 9cdce1b8ff6e50affd0c20696b2dd8048e45b3bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 20 Jun 2024 23:09:03 -0600 Subject: [PATCH 249/347] try to limit (79 characters) the line lenght in the Makefile --- Makefile | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index fdc581a..9308656 100644 --- a/Makefile +++ b/Makefile @@ -4,9 +4,12 @@ include config.mk # flags for compiling -DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XWAYLAND) -DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement -Wno-unused-parameter -Wshadow -Wunused-macros\ - -Werror=strict-prototypes -Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types -Wfloat-conversion +DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L \ + -DVERSION=\"$(VERSION)\" $(XWAYLAND) +DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement \ + -Wno-unused-parameter -Wshadow -Wunused-macros -Werror=strict-prototypes \ + -Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types \ + -Wfloat-conversion # CFLAGS / LDFLAGS PKGS = wlroots wayland-server xkbcommon libinput $(XLIBS) @@ -16,7 +19,9 @@ LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(LIBS) all: dwl dwl: dwl.o util.o $(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ -dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h +dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \ + pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \ + wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h util.o: util.c util.h # wayland-scanner is a tool which generates C headers and rigging for Wayland @@ -48,8 +53,8 @@ clean: dist: clean mkdir -p dwl-$(VERSION) - cp -R LICENSE* Makefile CHANGELOG.md README.md client.h config.def.h\ - config.mk protocols dwl.1 dwl.c util.c util.h dwl.desktop\ + cp -R LICENSE* Makefile CHANGELOG.md README.md client.h config.def.h \ + config.mk protocols dwl.1 dwl.c util.c util.h dwl.desktop \ dwl-$(VERSION) tar -caf dwl-$(VERSION).tar.gz dwl-$(VERSION) rm -rf dwl-$(VERSION) @@ -65,7 +70,8 @@ install: dwl cp -f dwl.desktop $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop chmod 644 $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop uninstall: - rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop + rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 \ + $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop .SUFFIXES: .c .o .c.o: From 845d3c47bd5dc8c7c7966e835579f10e69c5d92e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 20 Jun 2024 23:28:14 -0600 Subject: [PATCH 250/347] Reapply gamma LUT when re-enabling an output using wlr-output-power-management --- dwl.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index 2cdc819..d48bf40 100644 --- a/dwl.c +++ b/dwl.c @@ -2024,14 +2024,16 @@ powermgrsetmode(struct wl_listener *listener, void *data) { struct wlr_output_power_v1_set_mode_event *event = data; struct wlr_output_state state = {0}; + Monitor *m = event->output->data; - if (!event->output->data) + if (!m) return; + m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the ouput */ wlr_output_state_set_enabled(&state, event->mode); - wlr_output_commit_state(event->output, &state); + wlr_output_commit_state(m->wlr_output, &state); - ((Monitor *)(event->output->data))->asleep = !event->mode; + m->asleep = !event->mode; } void From 4a7d1bebf5c706109c92bd0415ab62825a7556ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 22 Jun 2024 00:21:17 -0600 Subject: [PATCH 251/347] add bugref for negative x,y monitor position and xwayland --- config.def.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config.def.h b/config.def.h index a784eb4..646a3d6 100644 --- a/config.def.h +++ b/config.def.h @@ -36,8 +36,10 @@ static const Layout layouts[] = { }; /* monitors */ -/* (x=-1, y=-1) is reserved as an "autoconfigure" monitor position indicator */ -/* WARNING: negative values other than (-1, -1) cause problems with xwayland clients' menus */ +/* (x=-1, y=-1) is reserved as an "autoconfigure" monitor position indicator + * WARNING: negative values other than (-1, -1) cause problems with Xwayland clients + * https://gitlab.freedesktop.org/xorg/xserver/-/issues/899 +*/ /* NOTE: ALWAYS add a fallback rule, even if you are completely sure it won't be used */ static const MonitorRule monrules[] = { /* name mfact nmaster scale layout rotate/reflect x y */ From 13925eb1da8af2c1d23ee9d01efd03c3626081b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 23 Jun 2024 14:42:50 -0600 Subject: [PATCH 252/347] correctly report position to xwayland clients Previously we didn't take into account their borders requiring us to add `borderpx` to override_redirect clients. Fixes: https://codeberg.org/dwl/dwl/issues/651 --- client.h | 2 +- dwl.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/client.h b/client.h index 19861b9..42f225f 100644 --- a/client.h +++ b/client.h @@ -350,7 +350,7 @@ client_set_size(Client *c, uint32_t width, uint32_t height) #ifdef XWAYLAND if (client_is_x11(c)) { wlr_xwayland_surface_configure(c->surface.xwayland, - c->geom.x, c->geom.y, width, height); + c->geom.x + c->bw, c->geom.y + c->bw, width, height); return 0; } #endif diff --git a/dwl.c b/dwl.c index d48bf40..00e9cc1 100644 --- a/dwl.c +++ b/dwl.c @@ -1651,8 +1651,7 @@ mapnotify(struct wl_listener *listener, void *data) if (client_is_unmanaged(c)) { /* Unmanaged clients always are floating */ wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]); - wlr_scene_node_set_position(&c->scene->node, c->geom.x + borderpx, - c->geom.y + borderpx); + wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); if (client_wants_focus(c)) { focusclient(c, 1); exclusive_focus = c; @@ -3038,7 +3037,7 @@ createnotifyx11(struct wl_listener *listener, void *data) c = xsurface->data = ecalloc(1, sizeof(*c)); c->surface.xwayland = xsurface; c->type = X11; - c->bw = borderpx; + c->bw = client_is_unmanaged(c) ? 0 : borderpx; /* Listen to the various events it can emit */ LISTEN(&xsurface->events.associate, &c->associate, associatex11); From 46ae075430017ccd4a58d63a166fe1e696d3f379 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 5 Jun 2024 00:42:43 -0600 Subject: [PATCH 253/347] set preferred scale on creation (LayerShell) --- dwl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dwl.c b/dwl.c index 00e9cc1..521b07a 100644 --- a/dwl.c +++ b/dwl.c @@ -71,6 +71,7 @@ #define MAX(A, B) ((A) > (B) ? (A) : (B)) #define MIN(A, B) ((A) < (B) ? (A) : (B)) #define ROUND(X) ((int)((X < 0) ? (X - 0.5) : (X + 0.5))) +#define CEIL(X) ((int)((X < 0) ? (X) : ((int)X == X) ? (X) : ((int)X + 1))) #define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS) #define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) #define LENGTH(X) (sizeof X / sizeof X[0]) @@ -884,6 +885,8 @@ createlayersurface(struct wl_listener *listener, void *data) wl_list_insert(&l->mon->layers[layer_surface->pending.layer],&l->link); wlr_surface_send_enter(surface, layer_surface->output); + wlr_fractional_scale_v1_notify_scale(surface, l->mon->wlr_output->scale); + wlr_surface_set_preferred_buffer_scale(surface, CEIL(l->mon->wlr_output->scale)); /* Temporarily set the layer's current state to pending * so that we can easily arrange it From 1002ea04fa45fba46755478044bc4828f8e19b20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 25 Jun 2024 22:22:43 -0600 Subject: [PATCH 254/347] add bugref about why we call updatemons in outputmgrapplyortest --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 521b07a..9fb50a7 100644 --- a/dwl.c +++ b/dwl.c @@ -1941,7 +1941,7 @@ apply_or_test: wlr_output_configuration_v1_send_failed(config); wlr_output_configuration_v1_destroy(config); - /* TODO: use a wrapper function? */ + /* https://codeberg.org/dwl/dwl/issues/577 */ updatemons(NULL, NULL); } From 2b4893a0ad57fb5234c48615a2e531401efcf69c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 29 Jun 2024 18:31:01 -0600 Subject: [PATCH 255/347] add a note about having at least a dummy rule for `rules[]` Closes: https://codeberg.org/dwl/dwl/issues/656 --- config.def.h | 1 + 1 file changed, 1 insertion(+) diff --git a/config.def.h b/config.def.h index 646a3d6..22d2171 100644 --- a/config.def.h +++ b/config.def.h @@ -20,6 +20,7 @@ static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You ca /* logging */ static int log_level = WLR_ERROR; +/* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */ static const Rule rules[] = { /* app_id title tags mask isfloating monitor */ /* examples: */ From 71f11e6cf63289d51f152469a0da81a85fe2608c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 27 Jun 2024 13:19:16 -0600 Subject: [PATCH 256/347] set O_NONBLOCK flag to stdout --- dwl.c | 6 ++++++ util.c | 16 ++++++++++++++++ util.h | 1 + 3 files changed, 23 insertions(+) diff --git a/dwl.c b/dwl.c index 9fb50a7..3175e79 100644 --- a/dwl.c +++ b/dwl.c @@ -2190,6 +2190,12 @@ run(char *startup_cmd) close(piperw[1]); close(piperw[0]); } + + /* Mark stdout as non-blocking to avoid people who does not close stdin + * nor consumes it in their startup script getting dwl frozen */ + if (fd_set_nonblock(STDOUT_FILENO) < 0) + close(STDOUT_FILENO); + printstatus(); /* At this point the outputs are initialized, choose initial selmon based on diff --git a/util.c b/util.c index cca7c19..51130af 100644 --- a/util.c +++ b/util.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "util.h" @@ -33,3 +34,18 @@ ecalloc(size_t nmemb, size_t size) die("calloc:"); return p; } + +int +fd_set_nonblock(int fd) { + int flags = fcntl(fd, F_GETFL); + if (flags < 0) { + perror("fcntl(F_GETFL):"); + return -1; + } + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { + perror("fcntl(F_SETFL):"); + return -1; + } + + return 0; +} diff --git a/util.h b/util.h index 4c94117..226980d 100644 --- a/util.h +++ b/util.h @@ -2,3 +2,4 @@ void die(const char *fmt, ...); void *ecalloc(size_t nmemb, size_t size); +int fd_set_nonblock(int fd); From b4638fef296cc7fa7ce51fa8ac07ecad17985226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 3 Jul 2024 13:20:51 -0600 Subject: [PATCH 257/347] drop useless maplayersurfacenotify() --- dwl.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/dwl.c b/dwl.c index 3175e79..a0f26bf 100644 --- a/dwl.c +++ b/dwl.c @@ -177,7 +177,6 @@ typedef struct { struct wlr_layer_surface_v1 *layer_surface; struct wl_listener destroy; - struct wl_listener map; struct wl_listener unmap; struct wl_listener surface_commit; } LayerSurface; @@ -298,7 +297,6 @@ static void keypressmod(struct wl_listener *listener, void *data); static int keyrepeat(void *data); static void killclient(const Arg *arg); static void locksession(struct wl_listener *listener, void *data); -static void maplayersurfacenotify(struct wl_listener *listener, void *data); static void mapnotify(struct wl_listener *listener, void *data); static void maximizenotify(struct wl_listener *listener, void *data); static void monocle(Monitor *m); @@ -871,7 +869,6 @@ createlayersurface(struct wl_listener *listener, void *data) l = layer_surface->data = ecalloc(1, sizeof(*l)); l->type = LayerShell; LISTEN(&surface->events.commit, &l->surface_commit, commitlayersurfacenotify); - LISTEN(&surface->events.map, &l->map, maplayersurfacenotify); LISTEN(&surface->events.unmap, &l->unmap, unmaplayersurfacenotify); LISTEN(&layer_surface->events.destroy, &l->destroy, destroylayersurfacenotify); @@ -1170,7 +1167,6 @@ destroylayersurfacenotify(struct wl_listener *listener, void *data) wl_list_remove(&l->link); wl_list_remove(&l->destroy.link); - wl_list_remove(&l->map.link); wl_list_remove(&l->unmap.link); wl_list_remove(&l->surface_commit.link); wlr_scene_node_destroy(&l->scene->node); @@ -1625,12 +1621,6 @@ locksession(struct wl_listener *listener, void *data) wlr_session_lock_v1_send_locked(session_lock); } -void -maplayersurfacenotify(struct wl_listener *listener, void *data) -{ - motionnotify(0, NULL, 0, 0, 0, 0); -} - void mapnotify(struct wl_listener *listener, void *data) { From ab5c554d096ebca8446b7b1354c49be014b8b747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 5 Jun 2024 00:43:14 -0600 Subject: [PATCH 258/347] set preferred scale after the first commit (XDGshell) --- dwl.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index a0f26bf..ee24044 100644 --- a/dwl.c +++ b/dwl.c @@ -773,6 +773,19 @@ commitnotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, commit); + if (c->surface.xdg->initial_commit) { + /* + * Get the monitor this client will be rendered on + * Note that if the user set a rule in which the client is placed on + * a different monitor based on its title this will likely select + * a wrong monitor. + */ + applyrules(c); + wlr_surface_set_preferred_buffer_scale(client_surface(c), CEIL(c->mon->wlr_output->scale)); + wlr_fractional_scale_v1_notify_scale(client_surface(c), c->mon->wlr_output->scale); + setmon(c, NULL, 0); /* Make sure to reapply rules in mapnotify() */ + } + if (client_surface(c)->mapped && c->mon) resize(c, c->geom, (c->isfloating && !c->isfullscreen)); @@ -2120,7 +2133,7 @@ resize(Client *c, struct wlr_box geo, int interact) struct wlr_box *bbox; struct wlr_box clip; - if (!c->mon) + if (!c->mon || !c->scene) return; bbox = interact ? &sgeom : &c->mon->w; @@ -2246,7 +2259,7 @@ setfloating(Client *c, int floating) Client *p = client_get_parent(c); c->isfloating = floating; /* If in floating layout do not change the client's layer */ - if (!c->mon || !c->mon->lt[c->mon->sellt]->arrange) + if (!c->mon || !client_surface(c)->mapped || !c->mon->lt[c->mon->sellt]->arrange) return; wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen || (p && p->isfullscreen) ? LyrFS @@ -2259,7 +2272,7 @@ void setfullscreen(Client *c, int fullscreen) { c->isfullscreen = fullscreen; - if (!c->mon) + if (!c->mon || !client_surface(c)->mapped) return; c->bw = fullscreen ? 0 : borderpx; client_set_fullscreen(c, fullscreen); From 2db0a2e8ef57acceeb3331a312dc3388a1710b29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 25 Jun 2024 11:38:01 -0600 Subject: [PATCH 259/347] use round(3) and ceilf(3) from the math library MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ΔSLOC: -1 --- Makefile | 2 +- dwl.c | 19 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 9308656..0d651e7 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement \ # CFLAGS / LDFLAGS PKGS = wlroots wayland-server xkbcommon libinput $(XLIBS) DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS) -LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(LIBS) +LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` -lm $(LIBS) all: dwl dwl: dwl.o util.o diff --git a/dwl.c b/dwl.c index ee24044..9d8317e 100644 --- a/dwl.c +++ b/dwl.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -70,8 +71,6 @@ /* macros */ #define MAX(A, B) ((A) > (B) ? (A) : (B)) #define MIN(A, B) ((A) < (B) ? (A) : (B)) -#define ROUND(X) ((int)((X < 0) ? (X - 0.5) : (X + 0.5))) -#define CEIL(X) ((int)((X < 0) ? (X) : ((int)X == X) ? (X) : ((int)X + 1))) #define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS) #define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) #define LENGTH(X) (sizeof X / sizeof X[0]) @@ -781,7 +780,7 @@ commitnotify(struct wl_listener *listener, void *data) * a wrong monitor. */ applyrules(c); - wlr_surface_set_preferred_buffer_scale(client_surface(c), CEIL(c->mon->wlr_output->scale)); + wlr_surface_set_preferred_buffer_scale(client_surface(c), (int)ceilf(c->mon->wlr_output->scale)); wlr_fractional_scale_v1_notify_scale(client_surface(c), c->mon->wlr_output->scale); setmon(c, NULL, 0); /* Make sure to reapply rules in mapnotify() */ } @@ -896,7 +895,7 @@ createlayersurface(struct wl_listener *listener, void *data) wl_list_insert(&l->mon->layers[layer_surface->pending.layer],&l->link); wlr_surface_send_enter(surface, layer_surface->output); wlr_fractional_scale_v1_notify_scale(surface, l->mon->wlr_output->scale); - wlr_surface_set_preferred_buffer_scale(surface, CEIL(l->mon->wlr_output->scale)); + wlr_surface_set_preferred_buffer_scale(surface, (int32_t)ceilf(l->mon->wlr_output->scale)); /* Temporarily set the layer's current state to pending * so that we can easily arrange it @@ -1812,17 +1811,17 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d } /* Update drag icon's position */ - wlr_scene_node_set_position(&drag_icon->node, ROUND(cursor->x), ROUND(cursor->y)); + wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y)); /* If we are currently grabbing the mouse, handle and return */ if (cursor_mode == CurMove) { /* Move the grabbed client to the new position. */ - resize(grabc, (struct wlr_box){.x = ROUND(cursor->x) - grabcx, .y = ROUND(cursor->y) - grabcy, + resize(grabc, (struct wlr_box){.x = (int)round(cursor->x) - grabcx, .y = (int)round(cursor->y) - grabcy, .width = grabc->geom.width, .height = grabc->geom.height}, 1); return; } else if (cursor_mode == CurResize) { resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y, - .width = ROUND(cursor->x) - grabc->geom.x, .height = ROUND(cursor->y) - grabc->geom.y}, 1); + .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1); return; } @@ -1863,8 +1862,8 @@ moveresize(const Arg *arg) setfloating(grabc, 1); switch (cursor_mode = arg->ui) { case CurMove: - grabcx = ROUND(cursor->x) - grabc->geom.x; - grabcy = ROUND(cursor->y) - grabc->geom.y; + grabcx = (int)round(cursor->x) - grabc->geom.x; + grabcy = (int)round(cursor->y) - grabc->geom.y; wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur"); break; case CurResize: @@ -2649,7 +2648,7 @@ tile(Monitor *m) return; if (n > m->nmaster) - mw = m->nmaster ? ROUND(m->w.width * m->mfact) : 0; + mw = m->nmaster ? (int)roundf(m->w.width * m->mfact) : 0; else mw = m->w.width; i = my = ty = 0; From 7d8c3ea3695de248aa1975def5839b0ffd34d198 Mon Sep 17 00:00:00 2001 From: Rutherther Date: Tue, 7 May 2024 19:14:32 +0200 Subject: [PATCH 260/347] feat: focus empty monitor when clicked --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index 9d8317e..e2fd223 100644 --- a/dwl.c +++ b/dwl.c @@ -604,6 +604,7 @@ buttonpress(struct wl_listener *listener, void *data) switch (event->state) { case WLR_BUTTON_PRESSED: cursor_mode = CurPressed; + selmon = xytomon(cursor->x, cursor->y); if (locked) break; From aede3b294b1b78afb1ceaf2214b8cc024a775974 Mon Sep 17 00:00:00 2001 From: Rutherther Date: Sun, 30 Jun 2024 21:42:05 +0200 Subject: [PATCH 261/347] Fix applybounds Applybounds doesn't move client when it overlays only with border with monitor to the right. Apparently, c->geom.width already includes the border as well. --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index e2fd223..dc0437e 100644 --- a/dwl.c +++ b/dwl.c @@ -439,9 +439,9 @@ applybounds(Client *c, struct wlr_box *bbox) c->geom.x = bbox->x + bbox->width - c->geom.width; if (c->geom.y >= bbox->y + bbox->height) c->geom.y = bbox->y + bbox->height - c->geom.height; - if (c->geom.x + c->geom.width + 2 * (int)c->bw <= bbox->x) + if (c->geom.x + c->geom.width <= bbox->x) c->geom.x = bbox->x; - if (c->geom.y + c->geom.height + 2 * (int)c->bw <= bbox->y) + if (c->geom.y + c->geom.height <= bbox->y) c->geom.y = bbox->y; } From 043ab3ac1335d7a1cd84fe0f9cea8056977211a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 12 Jul 2024 21:08:48 -0600 Subject: [PATCH 262/347] Revert "place child clients above fullscreen clients" This does not work as intended. Lets revert it temporarily and add it back after the release. This reverts commit 298949bbc4eae8cedb9cdd11cfc9ebd139ac5d5f. --- client.h | 12 ------------ dwl.c | 13 +++++-------- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/client.h b/client.h index 42f225f..f0e5445 100644 --- a/client.h +++ b/client.h @@ -183,18 +183,6 @@ client_get_parent(Client *c) return p; } -static inline int -client_has_children(Client *c) -{ -#ifdef XWAYLAND - if (client_is_x11(c)) - return !wl_list_empty(&c->surface.xwayland->children); -#endif - /* surface.xdg->link is never empty because it always contains at least the - * surface itself. */ - return wl_list_length(&c->surface.xdg->link) > 1; -} - static inline const char * client_get_title(Client *c) { diff --git a/dwl.c b/dwl.c index dc0437e..145fd01 100644 --- a/dwl.c +++ b/dwl.c @@ -1404,7 +1404,7 @@ focusstack(const Arg *arg) { /* Focus the next or previous client (in tiling order) on selmon */ Client *c, *sel = focustop(selmon); - if (!sel || (sel->isfullscreen && !client_has_children(sel))) + if (!sel || sel->isfullscreen) return; if (arg->i > 0) { wl_list_for_each(c, &sel->link, link) { @@ -1638,8 +1638,7 @@ void mapnotify(struct wl_listener *listener, void *data) { /* Called when the surface is mapped, or ready to display on-screen. */ - Client *p = NULL; - Client *w, *c = wl_container_of(listener, c, map); + Client *p, *w, *c = wl_container_of(listener, c, map); Monitor *m; int i; @@ -1695,7 +1694,7 @@ mapnotify(struct wl_listener *listener, void *data) unset_fullscreen: m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y); wl_list_for_each(w, &clients, link) { - if (w != c && w != p && w->isfullscreen && m == w->mon && (w->tags & c->tags)) + if (w != c && w->isfullscreen && m == w->mon && (w->tags & c->tags)) setfullscreen(w, 0); } } @@ -2256,14 +2255,12 @@ setcursorshape(struct wl_listener *listener, void *data) void setfloating(Client *c, int floating) { - Client *p = client_get_parent(c); c->isfloating = floating; /* If in floating layout do not change the client's layer */ if (!c->mon || !client_surface(c)->mapped || !c->mon->lt[c->mon->sellt]->arrange) return; - wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen || - (p && p->isfullscreen) ? LyrFS - : c->isfloating ? LyrFloat : LyrTile]); + wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen + ? LyrFS : c->isfloating ? LyrFloat : LyrTile]); arrange(c->mon); printstatus(); } From bd5001b7801b694b8bfb13215848e56113708917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 13 Jul 2024 01:14:26 -0600 Subject: [PATCH 263/347] prepare CHANGELOG.md for 0.6 --- CHANGELOG.md | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 366728d..89de0ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,14 +5,79 @@ ## Unreleased + ### Added + +* Add `rootcolor` to change the default background color ([#544][544]). +* Implement the wlr-virtual-pointer-unstable-v1 protocol ([#574][574]). +* Implement the pointer-constraints and relative-pointer protocols ([#317][317]) +* Implement the wlr-output-power-management protocol ([#599][599]) + +[544]: https://codeberg.org/dwl/dwl/pulls/544 +[574]: https://codeberg.org/dwl/dwl/pulls/574 +[317]: https://codeberg.org/dwl/dwl/issues/317 +[599]: https://codeberg.org/dwl/dwl/issues/559 + + ### Changed -### Deprecated + +* Keyboards are now managed through keyboard groups ([#549][549]). +* Only the first matched keybinding is executed. +* Allow toggling the layout before selecting a different one ([#570][570]). +* Fullscreen clients are now rendered above wlr_layer_surfaces in the top layer + ([#609][609]). +* The default menu was changed from `bemenu-run` to `wmenu-run` ([#553][553]). +* The option `sloppyfocus` now replicates the dwm behavior ([#599][599]). +* Allow configure position of monitors with negative values. (-1, -1) is + used to auto-configure them ([#635][635]). +* dwl now kills the entire process group of `startup_cmd` +* The O_NONBLOCK flag is set for stdout. + +[549]: https://codeberg.org/dwl/dwl/pulls/549 +[570]: https://codeberg.org/dwl/dwl/pulls/570 +[609]: https://codeberg.org/dwl/dwl/pulls/609 +[553]: https://codeberg.org/dwl/dwl/issues/553 +[599]: https://codeberg.org/dwl/dwl/pulls/599 +[635]: https://codeberg.org/dwl/dwl/pulls/635 + + ### Removed + +* The SLOC limit is now removed ([#497][497]). + +[497]: https://codeberg.org/dwl/dwl/pulls/497 + + ### Fixed -### Security + +* Clients not having the correct border color when mapping. +* Compliance with the xdg-decoration-unstable-v1 ([#546][546]). +* dwl no longer sends negative values in xdg_toplevel.configure events. +* Crashes with disabled monitors ([#472][472]). + +[546]: https://codeberg.org/dwl/dwl/pulls/546 +[472]: https://codeberg.org/dwl/dwl/issues/472 + + ### Contributors +Ben Jargowsky +Benjamin Chausse +David Donahue +Devin J. Pohly +Dima Krasner +Emil Miler +Forrest Bushstone +Guido Cella +Peter Hofmann +Rutherther +Squibid +choc +fictitiousexistence +korei999 +sewn +thanatos + ## 0.5 From 5a4839b1c8e1b171441a86a379ef30ddfb687421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 13 Jul 2024 16:34:01 -0600 Subject: [PATCH 264/347] bump version to 0.6 --- CHANGELOG.md | 2 +- config.mk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89de0ca..6ef3d96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -* [Unreleased](#unreleased) +* [0.6](#0.6) * [0.5](#0.5) diff --git a/config.mk b/config.mk index 259bd0f..6fb4fb3 100644 --- a/config.mk +++ b/config.mk @@ -1,4 +1,4 @@ -_VERSION = 0.5 +_VERSION = 0.6 VERSION = `git describe --tags --dirty 2>/dev/null || echo $(_VERSION)` PKG_CONFIG = pkg-config From 12b44421c84367a67461f81cacf13297ae673c20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 13 Jul 2024 20:23:04 -0600 Subject: [PATCH 265/347] bump to linux-dmabuf version 5 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 39b2d31..70d99ca 100644 --- a/dwl.c +++ b/dwl.c @@ -2468,7 +2468,7 @@ setup(void) if (wlr_renderer_get_texture_formats(drw, WLR_BUFFER_CAP_DMABUF)) { wlr_drm_create(dpy, drw); wlr_scene_set_linux_dmabuf_v1(scene, - wlr_linux_dmabuf_v1_create_with_renderer(dpy, 4, drw)); + wlr_linux_dmabuf_v1_create_with_renderer(dpy, 5, drw)); } /* Autocreates an allocator for us. From 9a962ce136536689b289ac126a0ad3525a13f682 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 14 Jul 2024 21:01:36 -0600 Subject: [PATCH 266/347] Reapply "place child clients above fullscreen clients" This reverts commit 043ab3ac1335d7a1cd84fe0f9cea8056977211a4. --- client.h | 12 ++++++++++++ dwl.c | 13 ++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/client.h b/client.h index f0e5445..42f225f 100644 --- a/client.h +++ b/client.h @@ -183,6 +183,18 @@ client_get_parent(Client *c) return p; } +static inline int +client_has_children(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return !wl_list_empty(&c->surface.xwayland->children); +#endif + /* surface.xdg->link is never empty because it always contains at least the + * surface itself. */ + return wl_list_length(&c->surface.xdg->link) > 1; +} + static inline const char * client_get_title(Client *c) { diff --git a/dwl.c b/dwl.c index 4a1267b..2dbc5da 100644 --- a/dwl.c +++ b/dwl.c @@ -1427,7 +1427,7 @@ focusstack(const Arg *arg) { /* Focus the next or previous client (in tiling order) on selmon */ Client *c, *sel = focustop(selmon); - if (!sel || sel->isfullscreen) + if (!sel || (sel->isfullscreen && !client_has_children(sel))) return; if (arg->i > 0) { wl_list_for_each(c, &sel->link, link) { @@ -1685,7 +1685,8 @@ void mapnotify(struct wl_listener *listener, void *data) { /* Called when the surface is mapped, or ready to display on-screen. */ - Client *p, *w, *c = wl_container_of(listener, c, map); + Client *p = NULL; + Client *w, *c = wl_container_of(listener, c, map); Monitor *m; int i; @@ -1741,7 +1742,7 @@ mapnotify(struct wl_listener *listener, void *data) unset_fullscreen: m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y); wl_list_for_each(w, &clients, link) { - if (w != c && w->isfullscreen && m == w->mon && (w->tags & c->tags)) + if (w != c && w != p && w->isfullscreen && m == w->mon && (w->tags & c->tags)) setfullscreen(w, 0); } } @@ -2304,12 +2305,14 @@ setcursorshape(struct wl_listener *listener, void *data) void setfloating(Client *c, int floating) { + Client *p = client_get_parent(c); c->isfloating = floating; /* If in floating layout do not change the client's layer */ if (!c->mon || !client_surface(c)->mapped || !c->mon->lt[c->mon->sellt]->arrange) return; - wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen - ? LyrFS : c->isfloating ? LyrFloat : LyrTile]); + wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen || + (p && p->isfullscreen) ? LyrFS + : c->isfloating ? LyrFloat : LyrTile]); arrange(c->mon); printstatus(); } From efe10ea655de409d76e08b21913bf7cab72d4fec Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Sun, 14 Jul 2024 21:02:45 -0600 Subject: [PATCH 267/347] use the parent scene node to determine if move clients out of LyrFloat [sevz: commit message is mine] --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 2dbc5da..5bf995e 100644 --- a/dwl.c +++ b/dwl.c @@ -504,7 +504,7 @@ arrange(Monitor *m) /* We move all clients (except fullscreen and unmanaged) to LyrTile while * in floating layout to avoid "real" floating clients be always on top */ wl_list_for_each(c, &clients, link) { - if (c->mon != m || c->isfullscreen) + if (c->mon != m || c->scene->node.parent == layers[LyrFS]) continue; wlr_scene_node_reparent(&c->scene->node, From c709b09e10ad6b4ccb63e7f75b17f0fdd488d4da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 14 Jul 2024 21:13:20 -0600 Subject: [PATCH 268/347] changelog: add new 'unreleased' section --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ef3d96..62cccc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,21 @@ # Changelog +* [Unreleased](#unreleased) * [0.6](#0.6) * [0.5](#0.5) ## Unreleased +### Added +### Changed +### Deprecated +### Removed +### Fixed +### Security +### Contributors + + +## 0.6 ### Added From 0060e1922d600f7f2378b82477ec053654560267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 14 Jul 2024 21:16:25 -0600 Subject: [PATCH 269/347] prepare CHANGELOG.md for 0.7 --- CHANGELOG.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62cccc6..c8e7a19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,14 +6,22 @@ ## Unreleased + +This version is just 0.6 with wlroots 0.18 compatibility. + ### Added -### Changed -### Deprecated -### Removed -### Fixed -### Security + +* Add support for the alpha-modifier-v1 protocol ([wlroots!4616][wlroots!4616]). +* dwl now will survive GPU resets ([#601][601]). + +[wlroots!4616]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4616 +[601]: https://codeberg.org/dwl/dwl/issues/601 + + ### Contributors +Guido Cella + ## 0.6 From bd59573f07f27fff7870a1e1a70e72493bb42453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 14 Jul 2024 21:22:08 -0600 Subject: [PATCH 270/347] bump version to 0.7-rc1 --- CHANGELOG.md | 4 ++-- config.mk | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8e7a19..cc3edb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,11 @@ # Changelog -* [Unreleased](#unreleased) +* [0.7](#0.7) * [0.6](#0.6) * [0.5](#0.5) -## Unreleased +## 0.7 This version is just 0.6 with wlroots 0.18 compatibility. diff --git a/config.mk b/config.mk index 6fb4fb3..c5e3b4c 100644 --- a/config.mk +++ b/config.mk @@ -1,4 +1,4 @@ -_VERSION = 0.6 +_VERSION = 0.7-rc1 VERSION = `git describe --tags --dirty 2>/dev/null || echo $(_VERSION)` PKG_CONFIG = pkg-config From 7328e5691cb09c5a6937c9beea239743aed9ffdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 14 Jul 2024 21:33:37 -0600 Subject: [PATCH 271/347] changelog: add new 'unreleased' section --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc3edb5..3aefd6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,21 @@ # Changelog +* [Unreleased](#unreleased) * [0.7](#0.7) * [0.6](#0.6) * [0.5](#0.5) +## Unreleased +### Added +### Changed +### Deprecated +### Removed +### Fixed +### Security +### Contributors + + ## 0.7 This version is just 0.6 with wlroots 0.18 compatibility. From 51881da27bc95f303ec249ccc51eb9a8e0ee6ca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 14 Jul 2024 21:34:28 -0600 Subject: [PATCH 272/347] bump version to 0.8-dev --- config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.mk b/config.mk index c5e3b4c..1d5ac38 100644 --- a/config.mk +++ b/config.mk @@ -1,4 +1,4 @@ -_VERSION = 0.7-rc1 +_VERSION = 0.8-dev VERSION = `git describe --tags --dirty 2>/dev/null || echo $(_VERSION)` PKG_CONFIG = pkg-config From 2553111aa39445f0d5e50963ab689ef677a3ad81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 14 Jul 2024 21:34:44 -0600 Subject: [PATCH 273/347] bump wlroots version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3358bae..f955e7b 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement \ -Wfloat-conversion # CFLAGS / LDFLAGS -PKGS = wlroots-0.18 wayland-server xkbcommon libinput $(XLIBS) +PKGS = wlroots-0.19 wayland-server xkbcommon libinput $(XLIBS) DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS) LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` -lm $(LIBS) From da6de7c4d7a2858d463945dc185abc5ae7796960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 14 Jul 2024 21:37:03 -0600 Subject: [PATCH 274/347] update wlr_xwayland_surface names (wlroots!2434) References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/2434 --- client.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client.h b/client.h index 42f225f..c43dbfd 100644 --- a/client.h +++ b/client.h @@ -391,8 +391,8 @@ client_wants_focus(Client *c) { #ifdef XWAYLAND return client_is_unmanaged(c) - && wlr_xwayland_or_surface_wants_focus(c->surface.xwayland) - && wlr_xwayland_icccm_input_model(c->surface.xwayland) != WLR_ICCCM_INPUT_MODEL_NONE; + && wlr_xwayland_surface_override_redirect_wants_focus(c->surface.xwayland) + && wlr_xwayland_surface_icccm_input_model(c->surface.xwayland) != WLR_ICCCM_INPUT_MODEL_NONE; #endif return 0; } From 452a314faa18573fe100a03a154fdd0a0ad54ba2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 14 Jul 2024 21:55:58 -0600 Subject: [PATCH 275/347] update README.md to mention the main branch now requires wlroots-git Closes: https://codeberg.org/dwl/dwl/issues/646 --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9d91923..6161a53 100644 --- a/README.md +++ b/README.md @@ -73,8 +73,9 @@ Xwayland (runtime only) ``` Simply install these (and their `-devel` versions if your distro has separate -development packages) and run `make`. If you wish to build against a Git -version of wlroots, check out the [wlroots-next branch]. +development packages) and run `make`. You need to use the Git version of +wlroots to build the `main` branch. If you wish to build against a released +version of wlroots, use a release or a [0.x branch]. To enable XWayland, you should uncomment its flags in `config.mk`. @@ -168,7 +169,7 @@ inspiration, and to the various contributors to the project, including: [#dwl on Libera Chat]: https://web.libera.chat/?channels=#dwl [Wayland]: https://wayland.freedesktop.org/ [wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots/ -[wlroots-next branch]: https://codeberg.org/dwl/dwl/src/branch/wlroots-next +[0.x branch]: https://codeberg.org/dwl/dwl/branches [patches repository]: https://codeberg.org/dwl/dwl-patches [s6]: https://skarnet.org/software/s6/ [anopa]: https://jjacky.com/anopa/ From ad30ca910b9da45835523af5c24ac353b7d13e9f Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Tue, 16 Jul 2024 23:02:22 -0500 Subject: [PATCH 276/347] Documentation restructuring Modified documentation to make clear the change in development (main) branch versus releases. --- README.md | 236 +++++++++++++++++++++++++++++------------------------- 1 file changed, 125 insertions(+), 111 deletions(-) diff --git a/README.md b/README.md index 6161a53..cec84f5 100644 --- a/README.md +++ b/README.md @@ -5,21 +5,132 @@ Or on our [Discord server]. dwl is a compact, hackable compositor for [Wayland] based on [wlroots]. It is intended to fill the same space in the Wayland world that dwm does in X11, -primarily in terms of functionality, and secondarily in terms of philosophy. -Like dwm, dwl is: +primarily in terms of functionality, and secondarily in terms of +philosophy. Like dwm, dwl is: - Easy to understand, hack on, and extend with patches - One C source file (or a very small number) configurable via `config.h` - Tied to as few external dependencies as possible +## Getting Started: + +### Latest semi-stable [release] +This is probably where you want to start. This builds against the dependent +packages' versions currently shipping in major distributions. If your +distribution's wlroots version is older, use an earlier dwl [release] or [0.x +branch]. + +### Development branch [main] +Active development progresses on the `main` branch. The `main` branch is built +against a late (and often changing) git commit of wlroots. While the adventurous +are welcome to use `main`, it is a rocky road. Using `main` requires that the +user be willing to chase git commits of wlroots. Testing development pull +requests may involve merging unmerged pull requests in [wlroots]' git repository +and/or git commits of wayland. + +### Building dwl +dwl has the following dependencies: +- libinput +- wayland +- wlroots (compiled with the libinput backend) +- xkbcommon +- wayland-protocols (compile-time only) +- pkg-config (compile-time only) + +dwl has the following additional dependencies if XWayland support is enabled: +- libxcb +- libxcb-wm +- wlroots (compiled with X11 support) +- Xwayland (runtime only) + +Install these (and their `-devel` versions if your distro has separate +development packages) and run `make`. If you wish to build against a released +version of wlroots (*you probably do*), use a [release] or a [0.x branch]. If +you want to use the unstable development `main` branch, you need to use the git +version of [wlroots]. + +To enable XWayland, you should uncomment its flags in `config.mk`. + +## Configuration + +All configuration is done by editing `config.h` and recompiling, in the same +manner as dwm. There is no way to separately restart the window manager in +Wayland without restarting the entire display server, so any changes will take +effect the next time dwl is executed. + +As in the dwm community, we encourage users to share patches they have +created. Check out the [dwl-patches] repository! + +## Running dwl + +dwl can be run on any of the backends supported by wlroots. This means you can +run it as a separate window inside either an X11 or Wayland session, as well as +directly from a VT console. Depending on your distro's setup, you may need to +add your user to the `video` and `input` groups before you can run dwl on a +VT. If you are using `elogind` or `systemd-logind` you need to install polkit; +otherwise you need to add yourself in the `seat` group and enable/start the +seatd daemon. + +When dwl is run with no arguments, it will launch the server and begin handling +any shortcuts configured in `config.h`. There is no status bar or other +decoration initially; these are instead clients that can be run within the +Wayland session. Do note that the default background color is black. This can be +modified in `config.h`. + +If you would like to run a script or command automatically at startup, you can +specify the command using the `-s` option. This command will be executed as a +shell command using `/bin/sh -c`. It serves a similar function to `.xinitrc`, +but differs in that the display server will not shut down when this process +terminates. Instead, dwl will send this process a SIGTERM at shutdown and wait +for it to terminate (if it hasn't already). This makes it ideal for execing into +a user service manager like [s6], [anopa], [runit], [dinit], or [`systemd +--user`]. + +Note: The `-s` command is run as a *child process* of dwl, which means that it +does not have the ability to affect the environment of dwl or of any processes +that it spawns. If you need to set environment variables that affect the entire +dwl session, these must be set prior to running dwl. For example, Wayland +requires a valid `XDG_RUNTIME_DIR`, which is usually set up by a session manager +such as `elogind` or `systemd-logind`. If your system doesn't do this +automatically, you will need to configure it prior to launching `dwl`, e.g.: + + export XDG_RUNTIME_DIR=/tmp/xdg-runtime-$(id -u) + mkdir -p $XDG_RUNTIME_DIR + dwl + +### Status information + +Information about selected layouts, current window title, app-id, and +selected/occupied/urgent tags is written to the stdin of the `-s` command (see +the `printstatus()` function for details). This information can be used to +populate an external status bar with a script that parses the +information. Failing to read this information will cause dwl to block, so if you +do want to run a startup command that does not consume the status information, +you can close standard input with the `<&-` shell redirection, for example: + + dwl -s 'foot --server <&-' + +If your startup command is a shell script, you can achieve the same inside the +script with the line + + exec <&- + +To get a list of status bars that work with dwl consult our [wiki]. + +## Replacements for X applications + +You can find a [list of useful resources on our wiki]. + +## Background + dwl is not meant to provide every feature under the sun. Instead, like dwm, it sticks to features which are necessary, simple, and straightforward to implement given the base on which it is built. Implemented default features are: - Any features provided by dwm/Xlib: simple window borders, tags, keybindings, client rules, mouse move/resize. Providing a built-in status bar is an - exception to this goal, to avoid dependencies on font rendering and/or - drawing libraries when an external bar could work well. + exception to this goal, to avoid dependencies on font rendering and/or drawing + libraries when an external bar could work well. - Configurable multi-monitor layout support, including position and rotation - Configurable HiDPI/multi-DPI support - Idle-inhibit protocol which lets applications such as mpv disable idle @@ -53,101 +164,6 @@ Feature *non-goals* for the main codebase include: be done through the compositor - Animations and visual effects -## Building dwl - -dwl has the following dependencies: -``` -libinput -wayland -wlroots (compiled with the libinput backend) -xkbcommon -wayland-protocols (compile-time only) -pkg-config (compile-time only) -``` -If you enable X11 support: -``` -libxcb -libxcb-wm -wlroots (compiled with X11 support) -Xwayland (runtime only) -``` - -Simply install these (and their `-devel` versions if your distro has separate -development packages) and run `make`. You need to use the Git version of -wlroots to build the `main` branch. If you wish to build against a released -version of wlroots, use a release or a [0.x branch]. - -To enable XWayland, you should uncomment its flags in `config.mk`. - -## Configuration - -All configuration is done by editing `config.h` and recompiling, in the same -manner as dwm. There is no way to separately restart the window manager in -Wayland without restarting the entire display server, so any changes will take -effect the next time dwl is executed. - -As in the dwm community, we encourage users to share patches they have created. -Check out the dwl [patches repository]! - -## Running dwl - -dwl can be run on any of the backends supported by wlroots. This means you can -run it as a separate window inside either an X11 or Wayland session, as well -as directly from a VT console. Depending on your distro's setup, you may need -to add your user to the `video` and `input` groups before you can run dwl on -a VT. If you are using `elogind` or `systemd-logind` you need to install -polkit; otherwise you need to add yourself in the `seat` group and -enable/start the seatd daemon. - -When dwl is run with no arguments, it will launch the server and begin handling -any shortcuts configured in `config.h`. There is no status bar or other -decoration initially; these are instead clients that can be run within -the Wayland session. -Do note that the background color is black. - -If you would like to run a script or command automatically at startup, you can -specify the command using the `-s` option. This command will be executed as a -shell command using `/bin/sh -c`. It serves a similar function to `.xinitrc`, -but differs in that the display server will not shut down when this process -terminates. Instead, dwl will send this process a SIGTERM at shutdown and wait -for it to terminate (if it hasn't already). This makes it ideal for execing into -a user service manager like [s6], [anopa], [runit], [dinit], or [`systemd --user`]. - -Note: The `-s` command is run as a *child process* of dwl, which means that it -does not have the ability to affect the environment of dwl or of any processes -that it spawns. If you need to set environment variables that affect the entire -dwl session, these must be set prior to running dwl. For example, Wayland -requires a valid `XDG_RUNTIME_DIR`, which is usually set up by a session manager -such as `elogind` or `systemd-logind`. If your system doesn't do this -automatically, you will need to configure it prior to launching `dwl`, e.g.: - - export XDG_RUNTIME_DIR=/tmp/xdg-runtime-$(id -u) - mkdir -p $XDG_RUNTIME_DIR - dwl - -### Status information - -Information about selected layouts, current window title, app-id, and -selected/occupied/urgent tags is written to the stdin of the `-s` command (see -the `printstatus()` function for details). This information can be used to -populate an external status bar with a script that parses the information. -Failing to read this information will cause dwl to block, so if you do want to -run a startup command that does not consume the status information, you can -close standard input with the `<&-` shell redirection, for example: - - dwl -s 'foot --server <&-' - -If your startup command is a shell script, you can achieve the same inside the -script with the line - - exec <&- - -To get a list of status bars that work with dwl consult our [wiki]. - -## Replacements for X applications - -You can find a [list of useful resources on our wiki]. - ## Acknowledgements dwl began by extending the TinyWL example provided (CC0) by the sway/wlroots @@ -165,17 +181,15 @@ inspiration, and to the various contributors to the project, including: - Stivvo for output management and fullscreen support, and patch maintenance -[Discord server]: https://discord.gg/jJxZnrGPWN -[#dwl on Libera Chat]: https://web.libera.chat/?channels=#dwl -[Wayland]: https://wayland.freedesktop.org/ -[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots/ -[0.x branch]: https://codeberg.org/dwl/dwl/branches -[patches repository]: https://codeberg.org/dwl/dwl-patches -[s6]: https://skarnet.org/software/s6/ +[`systemd --user`]: https://wiki.archlinux.org/title/Systemd/User [#dwl on Libera Chat]: https://web.libera.chat/?channels=#dwl +[0.7-rc1]: https://codeberg.org/dwl/dwl/releases/tag/v0.7-rc1 [0.x branch]: https://codeberg.org/dwl/dwl/branches [anopa]: https://jjacky.com/anopa/ -[runit]: http://smarden.org/runit/faq.html#userservices [dinit]: https://davmac.org/projects/dinit/ -[`systemd --user`]: https://wiki.archlinux.org/title/Systemd/User -[wiki]: https://codeberg.org/dwl/dwl/wiki/Home#compatible-status-bars -[list of useful resources on our wiki]: - https://codeberg.org/dwl/dwl/wiki/Home#migrating-from-x +[dwl-patches]: https://codeberg.org/dwl/dwl-patches [list of useful resources on our wiki]: https://codeberg.org/dwl/dwl/wiki/Home#migrating-from-x +[main]: https://codeberg.org/dwl/dwl/src/branch/main +[release]: https://codeberg.org/dwl/dwl/releases +[runit]: http://smarden.org/runit/faq.html#userservices +[s6]: https://skarnet.org/software/s6/ +[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots/ +[wiki]: https://codeberg.org/dwl/dwl/wiki/Home#compatible-status-bars [Discord server]: https://discord.gg/jJxZnrGPWN +[Wayland]: https://wayland.freedesktop.org/ From ea6a4501213e73119c4f17c05d7122fcbb9bfd0d Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Sun, 21 Jul 2024 14:28:08 -0500 Subject: [PATCH 277/347] README.md Fix links formatting issue after re-flow text to 80 columns --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index cec84f5..90222e6 100644 --- a/README.md +++ b/README.md @@ -181,15 +181,19 @@ inspiration, and to the various contributors to the project, including: - Stivvo for output management and fullscreen support, and patch maintenance -[`systemd --user`]: https://wiki.archlinux.org/title/Systemd/User [#dwl on Libera Chat]: https://web.libera.chat/?channels=#dwl -[0.7-rc1]: https://codeberg.org/dwl/dwl/releases/tag/v0.7-rc1 [0.x branch]: https://codeberg.org/dwl/dwl/branches +[`systemd --user`]: https://wiki.archlinux.org/title/Systemd/User +[#dwl on Libera Chat]: https://web.libera.chat/?channels=#dwl +[0.7-rc1]: https://codeberg.org/dwl/dwl/releases/tag/v0.7-rc1 +[0.x branch]: https://codeberg.org/dwl/dwl/branches [anopa]: https://jjacky.com/anopa/ [dinit]: https://davmac.org/projects/dinit/ -[dwl-patches]: https://codeberg.org/dwl/dwl-patches [list of useful resources on our wiki]: https://codeberg.org/dwl/dwl/wiki/Home#migrating-from-x +[dwl-patches]: https://codeberg.org/dwl/dwl-patches +[list of useful resources on our wiki]: https://codeberg.org/dwl/dwl/wiki/Home#migrating-from-x [main]: https://codeberg.org/dwl/dwl/src/branch/main [release]: https://codeberg.org/dwl/dwl/releases [runit]: http://smarden.org/runit/faq.html#userservices [s6]: https://skarnet.org/software/s6/ [wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots/ -[wiki]: https://codeberg.org/dwl/dwl/wiki/Home#compatible-status-bars [Discord server]: https://discord.gg/jJxZnrGPWN +[wiki]: https://codeberg.org/dwl/dwl/wiki/Home#compatible-status-bars +[Discord server]: https://discord.gg/jJxZnrGPWN [Wayland]: https://wayland.freedesktop.org/ From 4bbbb4907ec3e239353aa6ba8685ab1aa4a5fea5 Mon Sep 17 00:00:00 2001 From: Lennart Jablonka Date: Tue, 23 Jul 2024 20:12:00 +0200 Subject: [PATCH 278/347] add myself to .mailmap --- .mailmap | 1 + 1 file changed, 1 insertion(+) create mode 100644 .mailmap diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..911248c --- /dev/null +++ b/.mailmap @@ -0,0 +1 @@ +Lennart Jablonka From f2c5023a3a6b9abd45c81e7547b111fb5ab119bf Mon Sep 17 00:00:00 2001 From: Lennart Jablonka Date: Tue, 23 Jul 2024 20:14:51 +0200 Subject: [PATCH 279/347] dwl(1): use correct special characters for - and ' The hyphen-minus <-> and apostrophe-quote <'> are interpreted by troff as hyphen and right single quotation mark. See groff_char(7). Fixes: 0db6f3c5b5f9 ("add dwl(1)") --- dwl.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.1 b/dwl.1 index 387bcc9..780c78f 100644 --- a/dwl.1 +++ b/dwl.1 @@ -140,7 +140,7 @@ server. Start .Nm with s6 in the background: -.Dl dwl -s 's6-svscan <&-' +.Dl dwl \-s \(aqs6\-svscan <&\-\(aq .Sh SEE ALSO .Xr foot 1 , .Xr wmenu 1 , From cd216908a7c26f547b7e10a389aea6b754afb6d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 23 Jul 2024 16:16:19 -0600 Subject: [PATCH 280/347] send scale on initial commit to layer surfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Leonardo Hernández Hernández --- dwl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 5bf995e..5f9491b 100644 --- a/dwl.c +++ b/dwl.c @@ -763,6 +763,9 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) struct wlr_layer_surface_v1_state old_state; if (l->layer_surface->initial_commit) { + wlr_fractional_scale_v1_notify_scale(layer_surface->surface, l->mon->wlr_output->scale); + wlr_surface_set_preferred_buffer_scale(layer_surface->surface, (int32_t)ceilf(l->mon->wlr_output->scale)); + /* Temporarily set the layer's current state to pending * so that we can easily arrange it */ old_state = l->layer_surface->current; @@ -945,8 +948,6 @@ createlayersurface(struct wl_listener *listener, void *data) wl_list_insert(&l->mon->layers[layer_surface->pending.layer],&l->link); wlr_surface_send_enter(surface, layer_surface->output); - wlr_fractional_scale_v1_notify_scale(surface, l->mon->wlr_output->scale); - wlr_surface_set_preferred_buffer_scale(surface, (int32_t)ceilf(l->mon->wlr_output->scale)); } void From 487abc28ba6879bf3a2492ef766f0420ae6f904b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 24 Jul 2024 15:51:49 -0600 Subject: [PATCH 281/347] add myself to .mailmap --- .mailmap | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.mailmap b/.mailmap index 911248c..1778cb9 100644 --- a/.mailmap +++ b/.mailmap @@ -1 +1,3 @@ Lennart Jablonka +Leonardo Hernández Hernández +Leonardo Hernández Hernández From 986beef5be32a2bead22ca85d19f4d6d7e5c0ce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 27 Jul 2024 00:40:24 -0600 Subject: [PATCH 282/347] replace spaces with tabs Fixes: 71f11e6cf63289d51f152469a0da81a85fe2608c --- util.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/util.c b/util.c index 51130af..b925987 100644 --- a/util.c +++ b/util.c @@ -38,14 +38,14 @@ ecalloc(size_t nmemb, size_t size) int fd_set_nonblock(int fd) { int flags = fcntl(fd, F_GETFL); - if (flags < 0) { + if (flags < 0) { perror("fcntl(F_GETFL):"); - return -1; - } - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { + return -1; + } + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { perror("fcntl(F_SETFL):"); return -1; - } + } return 0; } From b5abbc37d8161c7ac8d05010e0effbc6af81718b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 27 Jul 2024 21:34:18 -0600 Subject: [PATCH 283/347] fix crash when re-mapping a client Fixes: ab5c554d096ebca8446b7b1354c49be014b8b747 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 5f9491b..2db3c15 100644 --- a/dwl.c +++ b/dwl.c @@ -2183,7 +2183,7 @@ resize(Client *c, struct wlr_box geo, int interact) struct wlr_box *bbox; struct wlr_box clip; - if (!c->mon || !c->scene) + if (!c->mon || !client_surface(c)->mapped) return; bbox = interact ? &sgeom : &c->mon->w; From 672b4c405d5207cadc572190affbe41e653e7a8c Mon Sep 17 00:00:00 2001 From: Sivecano Date: Sat, 27 Jul 2024 14:46:54 +0200 Subject: [PATCH 284/347] fix maximize callback not getting deregisterd --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index 2db3c15..ac9c36b 100644 --- a/dwl.c +++ b/dwl.c @@ -1276,6 +1276,7 @@ destroynotify(struct wl_listener *listener, void *data) wl_list_remove(&c->commit.link); wl_list_remove(&c->map.link); wl_list_remove(&c->unmap.link); + wl_list_remove(&c->maximize.link); } free(c); } From d136dadf456250f9a4cef23abd1fdf21518a31ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 1 Aug 2024 20:38:57 -0600 Subject: [PATCH 285/347] `-pedantic` -> `-Wpedantic` Bug: https://codeberg.org/dwl/dwl/issues/584 --- Makefile | 2 +- config.mk | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index f955e7b..f3e1f10 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ include config.mk # flags for compiling DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L \ -DVERSION=\"$(VERSION)\" $(XWAYLAND) -DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement \ +DWLDEVCFLAGS = -g -Wpedantic -Wall -Wextra -Wdeclaration-after-statement \ -Wno-unused-parameter -Wshadow -Wunused-macros -Werror=strict-prototypes \ -Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types \ -Wfloat-conversion diff --git a/config.mk b/config.mk index 1d5ac38..99ccc63 100644 --- a/config.mk +++ b/config.mk @@ -14,4 +14,7 @@ XLIBS = #XWAYLAND = -DXWAYLAND #XLIBS = xcb xcb-icccm -CC = gcc +# dwl itself only uses C99 features, but wlroots' headers use anonymous unions (C11). +# To avoid warnings about them, we do not use -std=c99 and instead of using the +# gmake default 'CC=c99', we use cc. +CC = cc From a634e3f527001cd2e2b7bc21bb14c1b7351f60bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 5 Aug 2024 12:11:42 -0600 Subject: [PATCH 286/347] fix crash when a virtual pointer is destroyed Fixes: https://codeberg.org/dwl/dwl/issues/680 --- dwl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index ac9c36b..8e0d28b 100644 --- a/dwl.c +++ b/dwl.c @@ -2977,11 +2977,11 @@ void virtualpointer(struct wl_listener *listener, void *data) { struct wlr_virtual_pointer_v1_new_pointer_event *event = data; - struct wlr_pointer pointer = event->new_pointer->pointer; + struct wlr_input_device *device = &event->new_pointer->pointer.base; - wlr_cursor_attach_input_device(cursor, &pointer.base); + wlr_cursor_attach_input_device(cursor, device); if (event->suggested_output) - wlr_cursor_map_input_to_output(cursor, &pointer.base, event->suggested_output); + wlr_cursor_map_input_to_output(cursor, device, event->suggested_output); } Monitor * From 35951a8d7eb3bcf2c7d618e156fd7b163e64d976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 11 Jun 2024 11:32:50 -0600 Subject: [PATCH 287/347] add support for linux-drm-syncobj-v1 (wlroots!4715) References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4262 References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4715 --- CHANGELOG.md | 7 +++++++ dwl.c | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3aefd6f..b7d67dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,13 @@ ## Unreleased ### Added + +* Support for the linux-drm-syncobj-v1 protocol ([wlroots!4715][wlroots!4715], [#685][685]) + +[wlroots!4715]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4715 +[685]: https://codeberg.org/dwl/dwl/pulls/685 + + ### Changed ### Deprecated ### Removed diff --git a/dwl.c b/dwl.c index 8e0d28b..72892d9 100644 --- a/dwl.c +++ b/dwl.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -2430,7 +2431,7 @@ setsel(struct wl_listener *listener, void *data) void setup(void) { - int i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE}; + int drm_fd, i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE}; struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig}; sigemptyset(&sa.sa_mask); @@ -2480,6 +2481,9 @@ setup(void) wlr_linux_dmabuf_v1_create_with_renderer(dpy, 5, drw)); } + if ((drm_fd = wlr_renderer_get_drm_fd(drw)) >= 0 && drw->features.timeline) + wlr_linux_drm_syncobj_manager_v1_create(dpy, 1, drm_fd); + /* Autocreates an allocator for us. * The allocator is the bridge between the renderer and the backend. It * handles the buffer creation, allowing wlroots to render onto the From a4fa9546166c9af277616dd6dcd80e61ee024eb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 3 Aug 2024 12:09:18 -0600 Subject: [PATCH 288/347] do not restack xwayland surfaces (wlroots!4756) References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4756 --- client.h | 11 ----------- dwl.c | 1 - 2 files changed, 12 deletions(-) diff --git a/client.h b/client.h index c43dbfd..3dc1050 100644 --- a/client.h +++ b/client.h @@ -301,17 +301,6 @@ client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb) wlr_seat_keyboard_notify_enter(seat, s, NULL, 0, NULL); } -static inline void -client_restack_surface(Client *c) -{ -#ifdef XWAYLAND - if (client_is_x11(c)) - wlr_xwayland_surface_restack(c->surface.xwayland, NULL, - XCB_STACK_MODE_ABOVE); -#endif - return; -} - static inline void client_send_close(Client *c) { diff --git a/dwl.c b/dwl.c index 72892d9..7e2d510 100644 --- a/dwl.c +++ b/dwl.c @@ -1368,7 +1368,6 @@ focusclient(Client *c, int lift) wl_list_insert(&fstack, &c->flink); selmon = c->mon; c->isurgent = 0; - client_restack_surface(c); /* Don't change border color if there is an exclusive focus or we are * handling a drag operation */ From b25717c9396d2fc040b8c3df75288b3de72971ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 8 Aug 2024 14:19:39 -0600 Subject: [PATCH 289/347] drop a useless check in configurex11() --- dwl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 7e2d510..3a3188c 100644 --- a/dwl.c +++ b/dwl.c @@ -3083,13 +3083,14 @@ configurex11(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, configure); struct wlr_xwayland_surface_configure_event *event = data; - /* TODO: figure out if there is another way to do this */ + /* This also handles "unmanaged" clients (because we do not assign + * them a monitor) */ if (!c->mon) { wlr_xwayland_surface_configure(c->surface.xwayland, event->x, event->y, event->width, event->height); return; } - if (c->isfloating || client_is_unmanaged(c)) + if (c->isfloating) resize(c, (struct wlr_box){.x = event->x, .y = event->y, .width = event->width + c->bw * 2, .height = event->height + c->bw * 2}, 0); else From bb21ecda30e041fb957eca42947e093758cdf75a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 8 Aug 2024 14:33:03 -0600 Subject: [PATCH 290/347] improve checking in configurex11() this avoids a client resizing itself when the user is interactively resizing the client --- dwl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 3a3188c..1500ceb 100644 --- a/dwl.c +++ b/dwl.c @@ -638,6 +638,7 @@ buttonpress(struct wl_listener *listener, void *data) /* Drop the window off on its new monitor */ selmon = xytomon(cursor->x, cursor->y); setmon(grabc, selmon, 0); + grabc = NULL; return; } else { cursor_mode = CurNormal; @@ -3090,7 +3091,7 @@ configurex11(struct wl_listener *listener, void *data) event->x, event->y, event->width, event->height); return; } - if (c->isfloating) + if ((c->isfloating && c != grabc) || !c->mon->lt[c->mon->sellt]->arrange) resize(c, (struct wlr_box){.x = event->x, .y = event->y, .width = event->width + c->bw * 2, .height = event->height + c->bw * 2}, 0); else From 94f4ead7dad89433e6087dc19950738c64bbed05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 8 Aug 2024 14:38:43 -0600 Subject: [PATCH 291/347] actually move unmanaged clients in configurex11() only calling wlr_xwayland_surface_configure() may be not enough because we also need to move the scene node in order to make effective the configure --- dwl.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 1500ceb..f1ab64b 100644 --- a/dwl.c +++ b/dwl.c @@ -3084,14 +3084,13 @@ configurex11(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, configure); struct wlr_xwayland_surface_configure_event *event = data; - /* This also handles "unmanaged" clients (because we do not assign - * them a monitor) */ - if (!c->mon) { + if (!client_surface(c) || !client_surface(c)->mapped) { wlr_xwayland_surface_configure(c->surface.xwayland, event->x, event->y, event->width, event->height); return; } - if ((c->isfloating && c != grabc) || !c->mon->lt[c->mon->sellt]->arrange) + if ((c->isfloating && c != grabc) + || client_is_unmanaged(c) || !c->mon->lt[c->mon->sellt]->arrange) resize(c, (struct wlr_box){.x = event->x, .y = event->y, .width = event->width + c->bw * 2, .height = event->height + c->bw * 2}, 0); else From 1b805ddd38aeb03dbf64886fb9a153f76f4eb8e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 8 Aug 2024 14:42:16 -0600 Subject: [PATCH 292/347] account border width in configurex11() Fixes: 13925eb1da8af2c1d23ee9d01efd03c3626081b2 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index f1ab64b..82a01d8 100644 --- a/dwl.c +++ b/dwl.c @@ -3091,7 +3091,7 @@ configurex11(struct wl_listener *listener, void *data) } if ((c->isfloating && c != grabc) || client_is_unmanaged(c) || !c->mon->lt[c->mon->sellt]->arrange) - resize(c, (struct wlr_box){.x = event->x, .y = event->y, + resize(c, (struct wlr_box){.x = event->x - c->bw, .y = event->y - c->bw, .width = event->width + c->bw * 2, .height = event->height + c->bw * 2}, 0); else arrange(c->mon); From 334bbe6f0f5e4f77789b42ac9e5607d5076aef1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 10 Aug 2024 10:39:25 -0600 Subject: [PATCH 293/347] fix potential crash in configurex11() We can't call resize() on unmanaged clients because they don't have borders and resize() requires them. Fixes: 94f4ead7dad89433e6087dc19950738c64bbed05 --- dwl.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 82a01d8..d28e9f1 100644 --- a/dwl.c +++ b/dwl.c @@ -3089,8 +3089,13 @@ configurex11(struct wl_listener *listener, void *data) event->x, event->y, event->width, event->height); return; } - if ((c->isfloating && c != grabc) - || client_is_unmanaged(c) || !c->mon->lt[c->mon->sellt]->arrange) + if (client_is_unmanaged(c)) { + wlr_scene_node_set_position(&c->scene->node, event->x, event->y); + wlr_xwayland_surface_configure(c->surface.xwayland, + event->x, event->y, event->width, event->height); + return; + } + if ((c->isfloating && c != grabc) || !c->mon->lt[c->mon->sellt]->arrange) resize(c, (struct wlr_box){.x = event->x - c->bw, .y = event->y - c->bw, .width = event->width + c->bw * 2, .height = event->height + c->bw * 2}, 0); else From e454f7ae812ca5ceac372223d42ffea252ff012a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 20 Jun 2024 12:36:56 -0600 Subject: [PATCH 294/347] allow the use of non-system wlroots library References: https://codeberg.org/dwl/dwl/issues/646#issuecomment-2032644 --- Makefile | 6 +++--- config.mk | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index f3e1f10..8db7409 100644 --- a/Makefile +++ b/Makefile @@ -12,9 +12,9 @@ DWLDEVCFLAGS = -g -Wpedantic -Wall -Wextra -Wdeclaration-after-statement \ -Wfloat-conversion # CFLAGS / LDFLAGS -PKGS = wlroots-0.19 wayland-server xkbcommon libinput $(XLIBS) -DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS) -LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` -lm $(LIBS) +PKGS = wayland-server xkbcommon libinput $(XLIBS) +DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(WLR_INCS) $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS) +LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(WLR_LIBS) -lm $(LIBS) all: dwl dwl: dwl.o util.o diff --git a/config.mk b/config.mk index 99ccc63..e374ccb 100644 --- a/config.mk +++ b/config.mk @@ -8,6 +8,22 @@ PREFIX = /usr/local MANDIR = $(PREFIX)/share/man DATADIR = $(PREFIX)/share +# Allow using an alternative wlroots installations +# This has to have all the includes required by wlroots, e.g: +# Assuming wlroots git repo is "${PWD}/wlroots" and you only ran "meson setup build && ninja -C build" +#WLR_INCS = -I/usr/include/pixman-1 -I/usr/include/elogind -I/usr/include/libdrm \ +# -I$(PWD)/wlroots/include +# Set -rpath to avoid using the wrong library. +#WLR_LIBS = -Wl,-rpath,$(PWD)/wlroots/build -L$(PWD)/wlroots/build -lwlroots-0.19 + +# Assuming you ran "meson setup --prefix ${PWD}/0.19 build && ninja -C build install" +#WLR_INCS = -I/usr/include/pixman-1 -I/usr/include/elogind -I/usr/include/libdrm \ +# -I$(PWD)/wlroots/0.19/include/wlroots-0.19 +#WLR_LIBS = -Wl,-rpath,$(PWD)/wlroots/0.19/lib64 -L$(PWD)/wlroots/0.19/lib64 -lwlroots-0.19 + +WLR_INCS = `$(PKG_CONFIG) --cflags wlroots-0.19` +WLR_LIBS = `$(PKG_CONFIG) --libs wlroots-0.19` + XWAYLAND = XLIBS = # Uncomment to build XWayland support From 07aeef1f7ee2e5c48846fcdbd651fc8162c02c57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 9 Aug 2024 21:34:02 -0600 Subject: [PATCH 295/347] guarantee client_get_{title,appid} never return NULL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ΔSLOC: -6 --- client.h | 8 ++++---- dwl.c | 14 ++++---------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/client.h b/client.h index 3dc1050..e0c45fd 100644 --- a/client.h +++ b/client.h @@ -126,9 +126,9 @@ client_get_appid(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) - return c->surface.xwayland->class; + return c->surface.xwayland->class ? c->surface.xwayland->class : "broken"; #endif - return c->surface.xdg->toplevel->app_id; + return c->surface.xdg->toplevel->app_id ? c->surface.xdg->toplevel->app_id : "broken"; } static inline void @@ -200,9 +200,9 @@ client_get_title(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) - return c->surface.xwayland->title; + return c->surface.xwayland->title ? c->surface.xwayland->title : "broken"; #endif - return c->surface.xdg->toplevel->title; + return c->surface.xdg->toplevel->title ? c->surface.xdg->toplevel->title : "broken"; } static inline int diff --git a/dwl.c b/dwl.c index d28e9f1..b88d7b1 100644 --- a/dwl.c +++ b/dwl.c @@ -358,7 +358,6 @@ static void xytonode(double x, double y, struct wlr_surface **psurface, static void zoom(const Arg *arg); /* variables */ -static const char broken[] = "broken"; static pid_t child_pid = -1; static int locked; static void *exclusive_focus; @@ -462,10 +461,8 @@ applyrules(Client *c) Monitor *mon = selmon, *m; c->isfloating = client_is_float_type(c); - if (!(appid = client_get_appid(c))) - appid = broken; - if (!(title = client_get_title(c))) - title = broken; + appid = client_get_appid(c); + title = client_get_title(c); for (r = rules; r < END(rules); r++) { if ((!r->title || strstr(title, r->title)) @@ -2040,7 +2037,6 @@ printstatus(void) Monitor *m = NULL; Client *c; uint32_t occ, urg, sel; - const char *appid, *title; wl_list_for_each(m, &mons, link) { occ = urg = 0; @@ -2052,10 +2048,8 @@ printstatus(void) urg |= c->tags; } if ((c = focustop(m))) { - title = client_get_title(c); - appid = client_get_appid(c); - printf("%s title %s\n", m->wlr_output->name, title ? title : broken); - printf("%s appid %s\n", m->wlr_output->name, appid ? appid : broken); + printf("%s title %s\n", m->wlr_output->name, client_get_title(c)); + printf("%s appid %s\n", m->wlr_output->name, client_get_appid(c)); printf("%s fullscreen %d\n", m->wlr_output->name, c->isfullscreen); printf("%s floating %d\n", m->wlr_output->name, c->isfloating); sel = c->tags; From 0caa6582765492cff5a6470626137adaebaa575e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 14 Aug 2024 11:47:29 -0600 Subject: [PATCH 296/347] use wlr_scene_set_gamma_control_manager_v1() (wlroots!4192) References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4192 --- dwl.c | 44 ++------------------------------------------ 1 file changed, 2 insertions(+), 42 deletions(-) diff --git a/dwl.c b/dwl.c index b88d7b1..8a587d1 100644 --- a/dwl.c +++ b/dwl.c @@ -327,7 +327,6 @@ static void setcursor(struct wl_listener *listener, void *data); static void setcursorshape(struct wl_listener *listener, void *data); static void setfloating(Client *c, int floating); static void setfullscreen(Client *c, int fullscreen); -static void setgamma(struct wl_listener *listener, void *data); static void setlayout(const Arg *arg); static void setmfact(const Arg *arg); static void setmon(Client *c, Monitor *m, uint32_t newtags); @@ -383,7 +382,6 @@ static struct wlr_idle_notifier_v1 *idle_notifier; static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr; static struct wlr_layer_shell_v1 *layer_shell; static struct wlr_output_manager_v1 *output_mgr; -static struct wlr_gamma_control_manager_v1 *gamma_control_mgr; static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; static struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr; static struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr; @@ -2100,7 +2098,6 @@ rendermon(struct wl_listener *listener, void *data) Monitor *m = wl_container_of(listener, m, frame); Client *c; struct wlr_output_state pending = {0}; - struct wlr_gamma_control_v1 *gamma_control; struct timespec now; /* Render if no XDG clients have an outstanding resize and are visible on @@ -2110,32 +2107,7 @@ rendermon(struct wl_listener *listener, void *data) goto skip; } - /* - * HACK: The "correct" way to set the gamma is to commit it together with - * the rest of the state in one go, but to do that we would need to rewrite - * wlr_scene_output_commit() in order to add the gamma to the pending - * state before committing, instead try to commit the gamma in one frame, - * and commit the rest of the state in the next one (or in the same frame if - * the gamma can not be committed). - */ - if (m->gamma_lut_changed) { - gamma_control - = wlr_gamma_control_manager_v1_get_control(gamma_control_mgr, m->wlr_output); - m->gamma_lut_changed = 0; - - if (!wlr_gamma_control_v1_apply(gamma_control, &pending)) - goto commit; - - if (!wlr_output_test_state(m->wlr_output, &pending)) { - wlr_gamma_control_v1_send_failed_and_destroy(gamma_control); - goto commit; - } - wlr_output_commit_state(m->wlr_output, &pending); - wlr_output_schedule_frame(m->wlr_output); - } else { -commit: - wlr_scene_output_commit(m->scene_output, NULL); - } + wlr_scene_output_commit(m->scene_output, NULL); skip: /* Let clients know a frame has been rendered */ @@ -2337,17 +2309,6 @@ setfullscreen(Client *c, int fullscreen) printstatus(); } -void -setgamma(struct wl_listener *listener, void *data) -{ - struct wlr_gamma_control_manager_v1_set_gamma_event *event = data; - Monitor *m = event->output->data; - if (!m) - return; - m->gamma_lut_changed = 1; - wlr_output_schedule_frame(m->wlr_output); -} - void setlayout(const Arg *arg) { @@ -2508,8 +2469,7 @@ setup(void) activation = wlr_xdg_activation_v1_create(dpy); LISTEN_STATIC(&activation->events.request_activate, urgent); - gamma_control_mgr = wlr_gamma_control_manager_v1_create(dpy); - LISTEN_STATIC(&gamma_control_mgr->events.set_gamma, setgamma); + wlr_scene_set_gamma_control_manager_v1(scene, wlr_gamma_control_manager_v1_create(dpy)); power_mgr = wlr_output_power_manager_v1_create(dpy); LISTEN_STATIC(&power_mgr->events.set_mode, powermgrsetmode); From 554754c9a2c03a263ac7d14092d6f67f3a211cdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 14 Aug 2024 13:37:14 -0600 Subject: [PATCH 297/347] chase xdg_surface geometry changes (wlroots!4788) References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4788 --- client.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/client.h b/client.h index e0c45fd..81946db 100644 --- a/client.h +++ b/client.h @@ -134,7 +134,6 @@ client_get_appid(Client *c) static inline void client_get_clip(Client *c, struct wlr_box *clip) { - struct wlr_box xdg_geom = {0}; *clip = (struct wlr_box){ .x = 0, .y = 0, @@ -147,9 +146,8 @@ client_get_clip(Client *c, struct wlr_box *clip) return; #endif - wlr_xdg_surface_get_geometry(c->surface.xdg, &xdg_geom); - clip->x = xdg_geom.x; - clip->y = xdg_geom.y; + clip->x = c->surface.xdg->geometry.x; + clip->y = c->surface.xdg->geometry.y; } static inline void @@ -164,7 +162,7 @@ client_get_geometry(Client *c, struct wlr_box *geom) return; } #endif - wlr_xdg_surface_get_geometry(c->surface.xdg, geom); + *geom = c->surface.xdg->geometry; } static inline Client * From 2c0b889f86bec0bb43a53bea8835b0418fa887ed Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Sat, 17 Aug 2024 09:46:20 -0500 Subject: [PATCH 298/347] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7d67dc..f59ba5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,9 +10,11 @@ ### Added * Support for the linux-drm-syncobj-v1 protocol ([wlroots!4715][wlroots!4715], [#685][685]) +* Allow the use of non-system wlroots library ([#646][646]) [wlroots!4715]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4715 [685]: https://codeberg.org/dwl/dwl/pulls/685 +[646]: https://codeberg.org/dwl/dwl/pulls/646 ### Changed From c5275ca571b0824d81f49c156b33217deceb9eed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 17 Aug 2024 21:15:17 -0600 Subject: [PATCH 299/347] state that the Discord server is community-maintained Previously I regularly checked the server but it has been quite a long time since I was able to do it. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 90222e6..1bcc36e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # dwl - dwm for Wayland Join us on our IRC channel: [#dwl on Libera Chat] -Or on our [Discord server]. +Or on the community-maintained [Discord server]. dwl is a compact, hackable compositor for [Wayland] based on [wlroots]. It is intended to fill the same space in the Wayland world that dwm does in X11, From 8ec5e52e061cfefab0bfed354a8b98ea2f4fb775 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 25 Aug 2024 11:33:54 -0600 Subject: [PATCH 300/347] fix crash when a client is created while all outputs are disabled --- CHANGELOG.md | 3 +++ dwl.c | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f59ba5b..07c9ee4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,9 @@ ### Deprecated ### Removed ### Fixed + +* Crash when a client is created while all outputs are disabled. + ### Security ### Contributors diff --git a/dwl.c b/dwl.c index 8a587d1..3171123 100644 --- a/dwl.c +++ b/dwl.c @@ -800,8 +800,10 @@ commitnotify(struct wl_listener *listener, void *data) * a wrong monitor. */ applyrules(c); - wlr_surface_set_preferred_buffer_scale(client_surface(c), (int)ceilf(c->mon->wlr_output->scale)); - wlr_fractional_scale_v1_notify_scale(client_surface(c), c->mon->wlr_output->scale); + if (c->mon) { + wlr_surface_set_preferred_buffer_scale(client_surface(c), (int)ceilf(c->mon->wlr_output->scale)); + wlr_fractional_scale_v1_notify_scale(client_surface(c), c->mon->wlr_output->scale); + } setmon(c, NULL, 0); /* Make sure to reapply rules in mapnotify() */ wlr_xdg_toplevel_set_wm_capabilities(c->surface.xdg->toplevel, WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); From 5db05e82bd7d1f6bf3cb0ce1ddd07952f06e57f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 9 Aug 2024 20:51:33 -0600 Subject: [PATCH 301/347] fix style in configurex11() --- dwl.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 3171123..78cf341 100644 --- a/dwl.c +++ b/dwl.c @@ -3051,11 +3051,13 @@ configurex11(struct wl_listener *listener, void *data) event->x, event->y, event->width, event->height); return; } - if ((c->isfloating && c != grabc) || !c->mon->lt[c->mon->sellt]->arrange) - resize(c, (struct wlr_box){.x = event->x - c->bw, .y = event->y - c->bw, - .width = event->width + c->bw * 2, .height = event->height + c->bw * 2}, 0); - else + if ((c->isfloating && c != grabc) || !c->mon->lt[c->mon->sellt]->arrange) { + resize(c, (struct wlr_box){.x = event->x - c->bw, + .y = event->y - c->bw, .width = event->width + c->bw * 2, + .height = event->height + c->bw * 2}, 0); + } else { arrange(c->mon); + } } void From d4ad37354e9ae8d475f8de9300903f8dd19e0f9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 9 Aug 2024 21:35:21 -0600 Subject: [PATCH 302/347] update comment about first fields of Client and LayerSurface order --- dwl.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/dwl.c b/dwl.c index 78cf341..bef92e2 100644 --- a/dwl.c +++ b/dwl.c @@ -106,15 +106,18 @@ typedef struct { typedef struct Monitor Monitor; typedef struct { - /* Must keep these three elements in this order */ + /* Must keep this field first */ unsigned int type; /* XDGShell or X11* */ - struct wlr_box geom; /* layout-relative, includes border */ + Monitor *mon; struct wlr_scene_tree *scene; struct wlr_scene_rect *border[4]; /* top, bottom, left, right */ struct wlr_scene_tree *scene_surface; struct wl_list link; struct wl_list flink; + struct wlr_box geom; /* layout-relative, includes border */ + struct wlr_box prev; /* layout-relative, includes border */ + struct wlr_box bounds; /* only width and height are used */ union { struct wlr_xdg_surface *xdg; struct wlr_xwayland_surface *xwayland; @@ -129,8 +132,6 @@ typedef struct { struct wl_listener fullscreen; struct wl_listener set_decoration_mode; struct wl_listener destroy_decoration; - struct wlr_box prev; /* layout-relative, includes border */ - struct wlr_box bounds; #ifdef XWAYLAND struct wl_listener activate; struct wl_listener associate; @@ -166,10 +167,11 @@ typedef struct { } KeyboardGroup; typedef struct { - /* Must keep these three elements in this order */ + /* Must keep this field first */ unsigned int type; /* LayerShell */ - struct wlr_box geom; + Monitor *mon; + struct wlr_box geom; struct wlr_scene_tree *scene; struct wlr_scene_tree *popups; struct wlr_scene_layer_surface_v1 *scene_layer; From b616476c856d893e0d7bd1e35b74cc996ec7f4b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 14 Aug 2024 13:09:09 -0600 Subject: [PATCH 303/347] remove unnecessary LayerShell.geom We only used geom.x and geom.y. We can access those variables directly from the scene node. --- dwl.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/dwl.c b/dwl.c index bef92e2..1aec267 100644 --- a/dwl.c +++ b/dwl.c @@ -171,7 +171,6 @@ typedef struct { unsigned int type; /* LayerShell */ Monitor *mon; - struct wlr_box geom; struct wlr_scene_tree *scene; struct wlr_scene_tree *popups; struct wlr_scene_layer_surface_v1 *scene_layer; @@ -533,8 +532,6 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int wlr_scene_layer_surface_v1_configure(l->scene_layer, &full_area, usable_area); wlr_scene_node_set_position(&l->popups->node, l->scene->node.x, l->scene->node.y); - l->geom.x = l->scene->node.x; - l->geom.y = l->scene->node.y; } } @@ -844,8 +841,8 @@ commitpopup(struct wl_listener *listener, void *data) if ((l && !l->mon) || (c && !c->mon)) return; box = type == LayerShell ? l->mon->m : c->mon->w; - box.x -= (type == LayerShell ? l->geom.x : c->geom.x); - box.y -= (type == LayerShell ? l->geom.y : c->geom.y); + box.x -= (type == LayerShell ? l->scene->node.x : c->geom.x); + box.y -= (type == LayerShell ? l->scene->node.y : c->geom.y); wlr_xdg_popup_unconstrain_from_box(popup, &box); wl_list_remove(&listener->link); } @@ -1824,8 +1821,8 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d && toplevel_from_wlr_surface(seat->pointer_state.focused_surface, &w, &l) >= 0) { c = w; surface = seat->pointer_state.focused_surface; - sx = cursor->x - (l ? l->geom.x : w->geom.x); - sy = cursor->y - (l ? l->geom.y : w->geom.y); + sx = cursor->x - (l ? l->scene->node.x : w->geom.x); + sy = cursor->y - (l ? l->scene->node.y : w->geom.y); } /* time is 0 in internal calls meant to restore pointer focus. */ From 43016bdad80fcd2efe557a43e8db2345ead9b5f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 9 Aug 2024 22:05:04 -0600 Subject: [PATCH 304/347] introduce client_set_scale() --- client.h | 6 ++++++ dwl.c | 6 ++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/client.h b/client.h index 81946db..9c2cff3 100644 --- a/client.h +++ b/client.h @@ -331,6 +331,12 @@ client_set_fullscreen(Client *c, int fullscreen) wlr_xdg_toplevel_set_fullscreen(c->surface.xdg->toplevel, fullscreen); } +static inline void +client_set_scale(struct wlr_surface *s, float scale) { + wlr_fractional_scale_v1_notify_scale(s, scale); + wlr_surface_set_preferred_buffer_scale(s, (int32_t)ceilf(scale)); +} + static inline uint32_t client_set_size(Client *c, uint32_t width, uint32_t height) { diff --git a/dwl.c b/dwl.c index 1aec267..457bea7 100644 --- a/dwl.c +++ b/dwl.c @@ -759,8 +759,7 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) struct wlr_layer_surface_v1_state old_state; if (l->layer_surface->initial_commit) { - wlr_fractional_scale_v1_notify_scale(layer_surface->surface, l->mon->wlr_output->scale); - wlr_surface_set_preferred_buffer_scale(layer_surface->surface, (int32_t)ceilf(l->mon->wlr_output->scale)); + client_set_scale(layer_surface->surface, l->mon->wlr_output->scale); /* Temporarily set the layer's current state to pending * so that we can easily arrange it */ @@ -800,8 +799,7 @@ commitnotify(struct wl_listener *listener, void *data) */ applyrules(c); if (c->mon) { - wlr_surface_set_preferred_buffer_scale(client_surface(c), (int)ceilf(c->mon->wlr_output->scale)); - wlr_fractional_scale_v1_notify_scale(client_surface(c), c->mon->wlr_output->scale); + client_set_scale(client_surface(c), c->mon->wlr_output->scale); } setmon(c, NULL, 0); /* Make sure to reapply rules in mapnotify() */ From 54b546121b3221e02d31a2af0bb0ce859376ab93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 9 Aug 2024 22:27:51 -0600 Subject: [PATCH 305/347] avoid using a else block --- dwl.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index 457bea7..76d3fca 100644 --- a/dwl.c +++ b/dwl.c @@ -625,7 +625,7 @@ buttonpress(struct wl_listener *listener, void *data) break; case WL_POINTER_BUTTON_STATE_RELEASED: /* If you released any buttons, we exit interactive move/resize mode. */ - /* TODO should reset to the pointer focus's current setcursor */ + /* TODO: should reset to the pointer focus's current setcursor */ if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); cursor_mode = CurNormal; @@ -634,9 +634,8 @@ buttonpress(struct wl_listener *listener, void *data) setmon(grabc, selmon, 0); grabc = NULL; return; - } else { - cursor_mode = CurNormal; } + cursor_mode = CurNormal; break; } /* If the event wasn't handled by the compositor, notify the client with From bbc00d88a45df249009c9946dfd88285eecac0c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 14 Aug 2024 13:10:14 -0600 Subject: [PATCH 306/347] remove a redundant check resize() now does the same check --- dwl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 76d3fca..4a11657 100644 --- a/dwl.c +++ b/dwl.c @@ -809,8 +809,7 @@ commitnotify(struct wl_listener *listener, void *data) return; } - if (client_surface(c)->mapped && c->mon) - resize(c, c->geom, (c->isfloating && !c->isfullscreen)); + resize(c, c->geom, (c->isfloating && !c->isfullscreen)); /* mark a pending resize as completed */ if (c->resize && c->resize <= c->surface.xdg->current.configure_serial) From 6de87121e2cf05119ddbfb501c87766912aa4d0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 14 Aug 2024 13:10:58 -0600 Subject: [PATCH 307/347] destroy popups when we can't get it's parent or they don't have monitor --- dwl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 4a11657..94e01b0 100644 --- a/dwl.c +++ b/dwl.c @@ -834,8 +834,10 @@ commitpopup(struct wl_listener *listener, void *data) return; popup->base->surface->data = wlr_scene_xdg_surface_create( popup->parent->data, popup->base); - if ((l && !l->mon) || (c && !c->mon)) + if ((l && !l->mon) || (c && !c->mon)) { + wlr_xdg_popup_destroy(popup); return; + } box = type == LayerShell ? l->mon->m : c->mon->w; box.x -= (type == LayerShell ? l->scene->node.x : c->geom.x); box.y -= (type == LayerShell ? l->scene->node.y : c->geom.y); From 0312720ae8599904e847eed377cc5ee222905835 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 14 Aug 2024 13:12:09 -0600 Subject: [PATCH 308/347] remove a space before parenthesis in function calls --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 94e01b0..85e7f36 100644 --- a/dwl.c +++ b/dwl.c @@ -1094,10 +1094,10 @@ createpointer(struct wlr_pointer *pointer) libinput_device_config_middle_emulation_set_enabled(device, middle_button_emulation); if (libinput_device_config_scroll_get_methods(device) != LIBINPUT_CONFIG_SCROLL_NO_SCROLL) - libinput_device_config_scroll_set_method (device, scroll_method); + libinput_device_config_scroll_set_method(device, scroll_method); if (libinput_device_config_click_get_methods(device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE) - libinput_device_config_click_set_method (device, click_method); + libinput_device_config_click_set_method(device, click_method); if (libinput_device_config_send_events_get_modes(device)) libinput_device_config_send_events_set_mode(device, send_events_mode); From cc72df11d690346ed1924593d283a7453986deab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 14 Aug 2024 13:14:15 -0600 Subject: [PATCH 309/347] configure xdg_toplevels after configuring it's decoration --- dwl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 85e7f36..dd9bd7d 100644 --- a/dwl.c +++ b/dwl.c @@ -802,10 +802,11 @@ commitnotify(struct wl_listener *listener, void *data) } setmon(c, NULL, 0); /* Make sure to reapply rules in mapnotify() */ - wlr_xdg_toplevel_set_wm_capabilities(c->surface.xdg->toplevel, WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); - wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, 0, 0); + wlr_xdg_toplevel_set_wm_capabilities(c->surface.xdg->toplevel, + WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); if (c->decoration) requestdecorationmode(&c->set_decoration_mode, c->decoration); + wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, 0, 0); return; } From f89906096537b1ec69a1db3216268ef7b4a1b7b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 14 Aug 2024 13:15:48 -0600 Subject: [PATCH 310/347] send a configure to unmanaged clients when mapping --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index dd9bd7d..e6bbf04 100644 --- a/dwl.c +++ b/dwl.c @@ -1703,6 +1703,7 @@ mapnotify(struct wl_listener *listener, void *data) /* Unmanaged clients always are floating */ wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]); wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); + client_set_size(c, c->geom.width, c->geom.height); if (client_wants_focus(c)) { focusclient(c, 1); exclusive_focus = c; From c49312f0841aaa11e9354d9cc239953b7c50ae83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 14 Aug 2024 13:18:04 -0600 Subject: [PATCH 311/347] disable scene node unless it is unmanaged --- dwl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index e6bbf04..1f8df42 100644 --- a/dwl.c +++ b/dwl.c @@ -1690,7 +1690,8 @@ mapnotify(struct wl_listener *listener, void *data) /* Create scene tree for this client and its border */ c->scene = client_surface(c)->data = wlr_scene_tree_create(layers[LyrTile]); - wlr_scene_node_set_enabled(&c->scene->node, c->type != XDGShell); + /* Enabled later by a call to arrange() */ + wlr_scene_node_set_enabled(&c->scene->node, client_is_unmanaged(c)); c->scene_surface = c->type == XDGShell ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg) : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); From d34be5d545f598bb4f07f9a07c4618e480705ca6 Mon Sep 17 00:00:00 2001 From: choc Date: Mon, 26 Aug 2024 21:40:27 +0800 Subject: [PATCH 312/347] remove unused link member from KeyboardGroup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit unnecessary since grouping Keyboard wl_list to use wlr_keyboard_group in 023efce ΔSLOC: -1 --- dwl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/dwl.c b/dwl.c index 1f8df42..9021e44 100644 --- a/dwl.c +++ b/dwl.c @@ -153,7 +153,6 @@ typedef struct { } Key; typedef struct { - struct wl_list link; struct wlr_keyboard_group *wlr_group; int nsyms; From 9c05b9622c7aa3a0874c49231249cf1859e2d031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 30 Aug 2024 18:19:18 -0600 Subject: [PATCH 313/347] fix style for client_set_scale() --- client.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client.h b/client.h index 9c2cff3..dabea35 100644 --- a/client.h +++ b/client.h @@ -332,7 +332,8 @@ client_set_fullscreen(Client *c, int fullscreen) } static inline void -client_set_scale(struct wlr_surface *s, float scale) { +client_set_scale(struct wlr_surface *s, float scale) +{ wlr_fractional_scale_v1_notify_scale(s, scale); wlr_surface_set_preferred_buffer_scale(s, (int32_t)ceilf(scale)); } From 54f207839f686a44918cfc581b15ff153215ee9c Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Sun, 8 Sep 2024 20:51:41 +0200 Subject: [PATCH 314/347] reorder config.mk variables By placing the default WLR_INCS and WLR_LIBS before the ones for an alternative wlroots, they don't need to be commented to enable the alternative ones. --- config.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config.mk b/config.mk index e374ccb..e2f1816 100644 --- a/config.mk +++ b/config.mk @@ -8,6 +8,9 @@ PREFIX = /usr/local MANDIR = $(PREFIX)/share/man DATADIR = $(PREFIX)/share +WLR_INCS = `$(PKG_CONFIG) --cflags wlroots-0.19` +WLR_LIBS = `$(PKG_CONFIG) --libs wlroots-0.19` + # Allow using an alternative wlroots installations # This has to have all the includes required by wlroots, e.g: # Assuming wlroots git repo is "${PWD}/wlroots" and you only ran "meson setup build && ninja -C build" @@ -21,9 +24,6 @@ DATADIR = $(PREFIX)/share # -I$(PWD)/wlroots/0.19/include/wlroots-0.19 #WLR_LIBS = -Wl,-rpath,$(PWD)/wlroots/0.19/lib64 -L$(PWD)/wlroots/0.19/lib64 -lwlroots-0.19 -WLR_INCS = `$(PKG_CONFIG) --cflags wlroots-0.19` -WLR_LIBS = `$(PKG_CONFIG) --libs wlroots-0.19` - XWAYLAND = XLIBS = # Uncomment to build XWayland support From 8206cc8889994b3e9ce3c50abefc19367cf49a8e Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Sat, 7 Sep 2024 21:22:40 +0200 Subject: [PATCH 315/347] fix a use after free This line makes dwl crash after closing mpv with the switchtotag patch. --- dwl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/dwl.c b/dwl.c index 9021e44..dc0c861 100644 --- a/dwl.c +++ b/dwl.c @@ -1171,7 +1171,6 @@ void destroydecoration(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, destroy_decoration); - c->decoration = NULL; wl_list_remove(&c->destroy_decoration.link); wl_list_remove(&c->set_decoration_mode.link); From 002c7d22043da56a54511b5d234c2e3bd997d119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 25 Aug 2024 13:02:34 -0600 Subject: [PATCH 316/347] tell xwayland clients they're maximized like we do to xdg clients when tiled state is not supported. --- client.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client.h b/client.h index dabea35..389b4f0 100644 --- a/client.h +++ b/client.h @@ -358,8 +358,11 @@ static inline void client_set_tiled(Client *c, uint32_t edges) { #ifdef XWAYLAND - if (client_is_x11(c)) + if (client_is_x11(c)) { + wlr_xwayland_surface_set_maximized(c->surface.xwayland, + edges != WLR_EDGE_NONE, edges != WLR_EDGE_NONE); return; + } #endif if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) { From 6ca87210d49424b457a319ae037d8a0658346af9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 27 Oct 2024 20:26:55 -0600 Subject: [PATCH 317/347] check if the backend supports explicit sync before creating the object (wlroots!4848) References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4848 --- dwl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index dc0c861..19eaf71 100644 --- a/dwl.c +++ b/dwl.c @@ -2436,7 +2436,8 @@ setup(void) wlr_linux_dmabuf_v1_create_with_renderer(dpy, 5, drw)); } - if ((drm_fd = wlr_renderer_get_drm_fd(drw)) >= 0 && drw->features.timeline) + if ((drm_fd = wlr_renderer_get_drm_fd(drw)) >= 0 && drw->features.timeline + && backend->features.timeline) wlr_linux_drm_syncobj_manager_v1_create(dpy, 1, drm_fd); /* Autocreates an allocator for us. From 84245764e28e6c841946ef706c704139e97d1bd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 27 Oct 2024 20:08:02 -0600 Subject: [PATCH 318/347] specify version for presentation-time (wlroots!4858) References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4858 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 19eaf71..9acb898 100644 --- a/dwl.c +++ b/dwl.c @@ -2463,7 +2463,7 @@ setup(void) wlr_viewporter_create(dpy); wlr_single_pixel_buffer_manager_v1_create(dpy); wlr_fractional_scale_manager_v1_create(dpy, 1); - wlr_presentation_create(dpy, backend); + wlr_presentation_create(dpy, backend, 2); wlr_alpha_modifier_v1_create(dpy); /* Initializes the interface used to implement urgency hints */ From 1d08ade13225343890e3476f7c4003ab87dc266c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 15 Nov 2024 00:17:43 -0600 Subject: [PATCH 319/347] remove binary before copying to destination Since Linux 6.11 is possible overwrite a running executable, possibly making it crash. Thanks to: movq42rax Fixes: https://codeberg.org/dwl/dwl/issues/709 References: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=2a010c412853 References: https://lore.kernel.org/stable/CACKH++YAtEMYu2nTLUyfmxZoGO37fqogKMDkBpddmNaz5HE6ng@mail.gmail.com/T/#u --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 8db7409..578194f 100644 --- a/Makefile +++ b/Makefile @@ -61,6 +61,7 @@ dist: clean install: dwl mkdir -p $(DESTDIR)$(PREFIX)/bin + rm -f $(DESTDIR)$(PREFIX)/bin/dwl cp -f dwl $(DESTDIR)$(PREFIX)/bin chmod 755 $(DESTDIR)$(PREFIX)/bin/dwl mkdir -p $(DESTDIR)$(MANDIR)/man1 From 30f5063474a70835d0178ffc12521a3e0fb1ef8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 10 Dec 2024 22:32:21 -0600 Subject: [PATCH 320/347] manually call updatemons in powermgrsetmode() Fixes: https://codeberg.org/dwl/dwl/issues/713 --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index 9acb898..0eba3e9 100644 --- a/dwl.c +++ b/dwl.c @@ -2082,6 +2082,7 @@ powermgrsetmode(struct wl_listener *listener, void *data) wlr_output_commit_state(m->wlr_output, &state); m->asleep = !event->mode; + updatemons(NULL, NULL); } void From 6f34a6d3a6f6604af2c4c257343a31064983651f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 10 Aug 2024 11:25:41 -0600 Subject: [PATCH 321/347] use wlr_xwayland_surface_has_window_type() (wlroots!4553) References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4553 --- client.h | 13 ++++++------- dwl.c | 34 ---------------------------------- 2 files changed, 6 insertions(+), 41 deletions(-) diff --git a/client.h b/client.h index 389b4f0..f1e2ab5 100644 --- a/client.h +++ b/client.h @@ -213,16 +213,15 @@ client_is_float_type(Client *c) if (client_is_x11(c)) { struct wlr_xwayland_surface *surface = c->surface.xwayland; xcb_size_hints_t *size_hints = surface->size_hints; - size_t i; if (surface->modal) return 1; - for (i = 0; i < surface->window_type_len; i++) - if (surface->window_type[i] == netatom[NetWMWindowTypeDialog] - || surface->window_type[i] == netatom[NetWMWindowTypeSplash] - || surface->window_type[i] == netatom[NetWMWindowTypeToolbar] - || surface->window_type[i] == netatom[NetWMWindowTypeUtility]) - return 1; + if (wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_DIALOG) + || wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_SPLASH) + || wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_TOOLBAR) + || wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_UTILITY)) { + return 1; + } return size_hints && size_hints->min_width > 0 && size_hints->min_height > 0 && (size_hints->max_width == size_hints->min_width diff --git a/dwl.c b/dwl.c index 0eba3e9..05e1975 100644 --- a/dwl.c +++ b/dwl.c @@ -85,10 +85,6 @@ enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ enum { XDGShell, LayerShell, X11 }; /* client types */ enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */ -#ifdef XWAYLAND -enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, - NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ -#endif typedef union { int i; @@ -417,11 +413,9 @@ static void associatex11(struct wl_listener *listener, void *data); static void configurex11(struct wl_listener *listener, void *data); static void createnotifyx11(struct wl_listener *listener, void *data); static void dissociatex11(struct wl_listener *listener, void *data); -static xcb_atom_t getatom(xcb_connection_t *xc, const char *name); static void sethints(struct wl_listener *listener, void *data); static void xwaylandready(struct wl_listener *listener, void *data); static struct wlr_xwayland *xwayland; -static xcb_atom_t netatom[NetLast]; #endif /* configuration, allows nested code to access above variables */ @@ -3091,19 +3085,6 @@ dissociatex11(struct wl_listener *listener, void *data) wl_list_remove(&c->unmap.link); } -xcb_atom_t -getatom(xcb_connection_t *xc, const char *name) -{ - xcb_atom_t atom = 0; - xcb_intern_atom_reply_t *reply; - xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xc, 0, strlen(name), name); - if ((reply = xcb_intern_atom_reply(xc, cookie, NULL))) - atom = reply->atom; - free(reply); - - return atom; -} - void sethints(struct wl_listener *listener, void *data) { @@ -3123,19 +3104,6 @@ void xwaylandready(struct wl_listener *listener, void *data) { struct wlr_xcursor *xcursor; - xcb_connection_t *xc = xcb_connect(xwayland->display_name, NULL); - int err = xcb_connection_has_error(xc); - if (err) { - fprintf(stderr, "xcb_connect to X server failed with code %d\n. Continuing with degraded functionality.\n", err); - return; - } - - /* Collect atoms we are interested in. If getatom returns 0, we will - * not detect that window type. */ - netatom[NetWMWindowTypeDialog] = getatom(xc, "_NET_WM_WINDOW_TYPE_DIALOG"); - netatom[NetWMWindowTypeSplash] = getatom(xc, "_NET_WM_WINDOW_TYPE_SPLASH"); - netatom[NetWMWindowTypeToolbar] = getatom(xc, "_NET_WM_WINDOW_TYPE_TOOLBAR"); - netatom[NetWMWindowTypeUtility] = getatom(xc, "_NET_WM_WINDOW_TYPE_UTILITY"); /* assign the one and only seat */ wlr_xwayland_set_seat(xwayland, seat); @@ -3146,8 +3114,6 @@ xwaylandready(struct wl_listener *listener, void *data) xcursor->images[0]->buffer, xcursor->images[0]->width * 4, xcursor->images[0]->width, xcursor->images[0]->height, xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y); - - xcb_disconnect(xc); } #endif From 26504f9a6f93e5b14819d5ed84dd27d3fbb41f3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 26 Dec 2024 20:18:51 -0600 Subject: [PATCH 322/347] do not call waitid(2) in the signal handler when Xwayland is enabled waitid(2) is not a async-signal-safe function acording to signal-safety(7) We can stop doing this because wlroots!4926 allows compositors to install signal handlers for SIGCHLD. References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4926 --- dwl.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/dwl.c b/dwl.c index 05e1975..ea66483 100644 --- a/dwl.c +++ b/dwl.c @@ -1486,22 +1486,10 @@ gpureset(struct wl_listener *listener, void *data) void handlesig(int signo) { - if (signo == SIGCHLD) { -#ifdef XWAYLAND - siginfo_t in; - /* wlroots expects to reap the XWayland process itself, so we - * use WNOWAIT to keep the child waitable until we know it's not - * XWayland. - */ - while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid - && (!xwayland || in.si_pid != xwayland->server->pid)) - waitpid(in.si_pid, NULL, 0); -#else + if (signo == SIGCHLD) while (waitpid(-1, NULL, WNOHANG) > 0); -#endif - } else if (signo == SIGINT || signo == SIGTERM) { + else if (signo == SIGINT || signo == SIGTERM) quit(NULL); - } } void From 0925fe956aeddb983875f0fd892e9049e2d8cb76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 16 Jan 2025 19:02:02 -0600 Subject: [PATCH 323/347] unlink some destroy listeners Recently wlroots was updated to assert that signals do not have listeners attached on destroy. This is just a preliminar work to fix dwl. At the moment dwl will trigger the assertions at exit. References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4918 --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index ea66483..d9d9f95 100644 --- a/dwl.c +++ b/dwl.c @@ -1176,6 +1176,7 @@ destroydragicon(struct wl_listener *listener, void *data) /* Focus enter isn't sent during drag, so refocus the focused node. */ focusclient(focustop(selmon), 1); motionnotify(0, NULL, 0, 0, 0, 0); + wl_list_remove(&listener->link); } void @@ -1184,6 +1185,7 @@ destroyidleinhibitor(struct wl_listener *listener, void *data) /* `data` is the wlr_surface of the idle inhibitor being destroyed, * at this point the idle inhibitor is still in the list of the manager */ checkidleinhibitor(wlr_surface_get_root_surface(data)); + wl_list_remove(&listener->link); } void From 4e7e2999d42fdb6d4796d88e355138fa6ae61252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 19 Jan 2025 13:43:51 -0600 Subject: [PATCH 324/347] Partially revert "Line saver: LISTEN_STATIC macro" This reverts commit 33bcd2e4ca892bb0b558660c99ed63a3dfdd9011. We keep LISTEN_STATIC for three instances where we use it. We use simple listeners for the rest of signals. This is the continuation of 0925fe956aeddb983875f0fd892e9049e2d8cb76 --- dwl.c | 108 ++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 72 insertions(+), 36 deletions(-) diff --git a/dwl.c b/dwl.c index d9d9f95..cfe7772 100644 --- a/dwl.c +++ b/dwl.c @@ -394,7 +394,6 @@ static struct wlr_scene_rect *root_bg; static struct wlr_session_lock_manager_v1 *session_lock_mgr; static struct wlr_scene_rect *locked_bg; static struct wlr_session_lock_v1 *cur_lock; -static struct wl_listener lock_listener = {.notify = locksession}; static struct wlr_seat *seat; static KeyboardGroup *kb_group; @@ -407,6 +406,37 @@ static struct wlr_box sgeom; static struct wl_list mons; static Monitor *selmon; +/* global event handlers */ +static struct wl_listener cursor_axis = {.notify = axisnotify}; +static struct wl_listener cursor_button = {.notify = buttonpress}; +static struct wl_listener cursor_frame = {.notify = cursorframe}; +static struct wl_listener cursor_motion = {.notify = motionrelative}; +static struct wl_listener cursor_motion_absolute = {.notify = motionabsolute}; +static struct wl_listener gpu_reset = {.notify = gpureset}; +static struct wl_listener idle_inhibitor_create = {.notify = createidleinhibitor}; +static struct wl_listener layout_change = {.notify = updatemons}; +static struct wl_listener new_input = {.notify = inputdevice}; +static struct wl_listener new_virtual_keyboard = {.notify = virtualkeyboard}; +static struct wl_listener new_virtual_pointer = {.notify = virtualpointer}; +static struct wl_listener new_pointer_constraint = {.notify = createpointerconstraint}; +static struct wl_listener new_output = {.notify = createmon}; +static struct wl_listener new_xdg_surface = {.notify = createnotify}; +static struct wl_listener new_xdg_popup = {.notify = createpopup}; +static struct wl_listener new_xdg_decoration = {.notify = createdecoration}; +static struct wl_listener new_layer_shell_surface = {.notify = createlayersurface}; +static struct wl_listener output_mgr_apply = {.notify = outputmgrapply}; +static struct wl_listener output_mgr_test = {.notify = outputmgrtest}; +static struct wl_listener output_power_mgr_set_mode = {.notify = powermgrsetmode}; +static struct wl_listener request_activate = {.notify = urgent}; +static struct wl_listener request_cursor = {.notify = setcursor}; +static struct wl_listener request_set_psel = {.notify = setpsel}; +static struct wl_listener request_set_sel = {.notify = setsel}; +static struct wl_listener request_set_shape = {.notify = setcursorshape}; +static struct wl_listener request_start_drag = {.notify = requeststartdrag}; +static struct wl_listener start_drag = {.notify = startdrag}; +static struct wl_listener session_lock_create_lock = {.notify = locksession}; +static struct wl_listener session_lock_mgr_destroy = {.notify = destroysessionmgr}; + #ifdef XWAYLAND static void activatex11(struct wl_listener *listener, void *data); static void associatex11(struct wl_listener *listener, void *data); @@ -415,6 +445,8 @@ static void createnotifyx11(struct wl_listener *listener, void *data); static void dissociatex11(struct wl_listener *listener, void *data); static void sethints(struct wl_listener *listener, void *data); static void xwaylandready(struct wl_listener *listener, void *data); +static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11}; +static struct wl_listener xwayland_ready = {.notify = xwaylandready}; static struct wlr_xwayland *xwayland; #endif @@ -1296,8 +1328,8 @@ destroysessionlock(struct wl_listener *listener, void *data) void destroysessionmgr(struct wl_listener *listener, void *data) { - wl_list_remove(&lock_listener.link); - wl_list_remove(&listener->link); + wl_list_remove(&session_lock_create_lock.link); + wl_list_remove(&session_lock_mgr_destroy.link); } void @@ -1473,7 +1505,8 @@ gpureset(struct wl_listener *listener, void *data) if (!(alloc = wlr_allocator_autocreate(backend, drw))) die("couldn't recreate allocator"); - LISTEN_STATIC(&drw->events.lost, gpureset); + wl_list_remove(&gpu_reset.link); + wl_signal_add(&drw->events.lost, &gpu_reset); wlr_compositor_set_renderer(compositor, drw); @@ -2406,7 +2439,7 @@ setup(void) * supports for shared memory, this configures that for clients. */ if (!(drw = wlr_renderer_autocreate(backend))) die("couldn't create renderer"); - LISTEN_STATIC(&drw->events.lost, gpureset); + wl_signal_add(&drw->events.lost, &gpu_reset); /* Create shm, drm and linux_dmabuf interfaces by ourselves. * The simplest way is call: @@ -2453,23 +2486,24 @@ setup(void) /* Initializes the interface used to implement urgency hints */ activation = wlr_xdg_activation_v1_create(dpy); - LISTEN_STATIC(&activation->events.request_activate, urgent); + wl_signal_add(&activation->events.request_activate, &request_activate); wlr_scene_set_gamma_control_manager_v1(scene, wlr_gamma_control_manager_v1_create(dpy)); power_mgr = wlr_output_power_manager_v1_create(dpy); - LISTEN_STATIC(&power_mgr->events.set_mode, powermgrsetmode); + wl_signal_add(&power_mgr->events.set_mode, &output_power_mgr_set_mode); /* Creates an output layout, which a wlroots utility for working with an * arrangement of screens in a physical layout. */ output_layout = wlr_output_layout_create(dpy); - LISTEN_STATIC(&output_layout->events.change, updatemons); - wlr_xdg_output_manager_v1_create(dpy, output_layout); + wl_signal_add(&output_layout->events.change, &layout_change); + + wlr_xdg_output_manager_v1_create(dpy, output_layout); /* Configure a listener to be notified when new outputs are available on the * backend. */ wl_list_init(&mons); - LISTEN_STATIC(&backend->events.new_output, createmon); + wl_signal_add(&backend->events.new_output, &new_output); /* Set up our client lists, the xdg-shell and the layer-shell. The xdg-shell is a * Wayland protocol which is used for application windows. For more @@ -2481,20 +2515,20 @@ setup(void) wl_list_init(&fstack); xdg_shell = wlr_xdg_shell_create(dpy, 6); - LISTEN_STATIC(&xdg_shell->events.new_toplevel, createnotify); - LISTEN_STATIC(&xdg_shell->events.new_popup, createpopup); + wl_signal_add(&xdg_shell->events.new_toplevel, &new_xdg_surface); + wl_signal_add(&xdg_shell->events.new_popup, &new_xdg_popup); layer_shell = wlr_layer_shell_v1_create(dpy, 3); - LISTEN_STATIC(&layer_shell->events.new_surface, createlayersurface); + wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface); idle_notifier = wlr_idle_notifier_v1_create(dpy); idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); - LISTEN_STATIC(&idle_inhibit_mgr->events.new_inhibitor, createidleinhibitor); + wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &idle_inhibitor_create); session_lock_mgr = wlr_session_lock_manager_v1_create(dpy); - wl_signal_add(&session_lock_mgr->events.new_lock, &lock_listener); - LISTEN_STATIC(&session_lock_mgr->events.destroy, destroysessionmgr); + wl_signal_add(&session_lock_mgr->events.new_lock, &session_lock_create_lock); + wl_signal_add(&session_lock_mgr->events.destroy, &session_lock_mgr_destroy); locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height, (float [4]){0.1f, 0.1f, 0.1f, 1.0f}); wlr_scene_node_set_enabled(&locked_bg->node, 0); @@ -2504,10 +2538,10 @@ setup(void) wlr_server_decoration_manager_create(dpy), WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy); - LISTEN_STATIC(&xdg_decoration_mgr->events.new_toplevel_decoration, createdecoration); + wl_signal_add(&xdg_decoration_mgr->events.new_toplevel_decoration, &new_xdg_decoration); pointer_constraints = wlr_pointer_constraints_v1_create(dpy); - LISTEN_STATIC(&pointer_constraints->events.new_constraint, createpointerconstraint); + wl_signal_add(&pointer_constraints->events.new_constraint, &new_pointer_constraint); relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy); @@ -2535,14 +2569,14 @@ setup(void) * * And more comments are sprinkled throughout the notify functions above. */ - LISTEN_STATIC(&cursor->events.motion, motionrelative); - LISTEN_STATIC(&cursor->events.motion_absolute, motionabsolute); - LISTEN_STATIC(&cursor->events.button, buttonpress); - LISTEN_STATIC(&cursor->events.axis, axisnotify); - LISTEN_STATIC(&cursor->events.frame, cursorframe); + wl_signal_add(&cursor->events.motion, &cursor_motion); + wl_signal_add(&cursor->events.motion_absolute, &cursor_motion_absolute); + wl_signal_add(&cursor->events.button, &cursor_button); + wl_signal_add(&cursor->events.axis, &cursor_axis); + wl_signal_add(&cursor->events.frame, &cursor_frame); cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1); - LISTEN_STATIC(&cursor_shape_mgr->events.request_set_shape, setcursorshape); + wl_signal_add(&cursor_shape_mgr->events.request_set_shape, &request_set_shape); /* * Configures a seat, which is a single "seat" at which a user sits and @@ -2550,25 +2584,27 @@ setup(void) * pointer, touch, and drawing tablet device. We also rig up a listener to * let us know when new input devices are available on the backend. */ - LISTEN_STATIC(&backend->events.new_input, inputdevice); + wl_signal_add(&backend->events.new_input, &new_input); virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy); - LISTEN_STATIC(&virtual_keyboard_mgr->events.new_virtual_keyboard, virtualkeyboard); + wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard, + &new_virtual_keyboard); virtual_pointer_mgr = wlr_virtual_pointer_manager_v1_create(dpy); - LISTEN_STATIC(&virtual_pointer_mgr->events.new_virtual_pointer, virtualpointer); + wl_signal_add(&virtual_pointer_mgr->events.new_virtual_pointer, + &new_virtual_pointer); seat = wlr_seat_create(dpy, "seat0"); - LISTEN_STATIC(&seat->events.request_set_cursor, setcursor); - LISTEN_STATIC(&seat->events.request_set_selection, setsel); - LISTEN_STATIC(&seat->events.request_set_primary_selection, setpsel); - LISTEN_STATIC(&seat->events.request_start_drag, requeststartdrag); - LISTEN_STATIC(&seat->events.start_drag, startdrag); + wl_signal_add(&seat->events.request_set_cursor, &request_cursor); + wl_signal_add(&seat->events.request_set_selection, &request_set_sel); + wl_signal_add(&seat->events.request_set_primary_selection, &request_set_psel); + wl_signal_add(&seat->events.request_start_drag, &request_start_drag); + wl_signal_add(&seat->events.start_drag, &start_drag); kb_group = createkeyboardgroup(); wl_list_init(&kb_group->destroy.link); output_mgr = wlr_output_manager_v1_create(dpy); - LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply); - LISTEN_STATIC(&output_mgr->events.test, outputmgrtest); + wl_signal_add(&output_mgr->events.apply, &output_mgr_apply); + wl_signal_add(&output_mgr->events.test, &output_mgr_test); /* Make sure XWayland clients don't connect to the parent X server, * e.g when running in the x11 backend or the wayland backend and the @@ -2580,8 +2616,8 @@ setup(void) * It will be started when the first X client is started. */ if ((xwayland = wlr_xwayland_create(dpy, compositor, 1))) { - LISTEN_STATIC(&xwayland->events.ready, xwaylandready); - LISTEN_STATIC(&xwayland->events.new_surface, createnotifyx11); + wl_signal_add(&xwayland->events.ready, &xwayland_ready); + wl_signal_add(&xwayland->events.new_surface, &new_xwayland_surface); setenv("DISPLAY", xwayland->display_name, 1); } else { From 9a9f67db1c9a1b05d4edbaa310d78a76f3831b54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 19 Jan 2025 14:04:03 -0600 Subject: [PATCH 325/347] unlink global listeners on destroy Continuation of 0925fe956aeddb983875f0fd892e9049e2d8cb76 --- dwl.c | 49 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/dwl.c b/dwl.c index cfe7772..f7ae6fb 100644 --- a/dwl.c +++ b/dwl.c @@ -252,6 +252,7 @@ static void chvt(const Arg *arg); static void checkidleinhibitor(struct wlr_surface *exclude); static void cleanup(void); static void cleanupmon(struct wl_listener *listener, void *data); +static void cleanuplisteners(void); static void closemon(Monitor *m); static void commitlayersurfacenotify(struct wl_listener *listener, void *data); static void commitnotify(struct wl_listener *listener, void *data); @@ -279,7 +280,6 @@ static void destroylocksurface(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); static void destroypointerconstraint(struct wl_listener *listener, void *data); static void destroysessionlock(struct wl_listener *listener, void *data); -static void destroysessionmgr(struct wl_listener *listener, void *data); static void destroykeyboardgroup(struct wl_listener *listener, void *data); static Monitor *dirtomon(enum wlr_direction dir); static void focusclient(Client *c, int lift); @@ -435,7 +435,6 @@ static struct wl_listener request_set_shape = {.notify = setcursorshape}; static struct wl_listener request_start_drag = {.notify = requeststartdrag}; static struct wl_listener start_drag = {.notify = startdrag}; static struct wl_listener session_lock_create_lock = {.notify = locksession}; -static struct wl_listener session_lock_mgr_destroy = {.notify = destroysessionmgr}; #ifdef XWAYLAND static void activatex11(struct wl_listener *listener, void *data); @@ -696,6 +695,7 @@ checkidleinhibitor(struct wlr_surface *exclude) void cleanup(void) { + cleanuplisteners(); #ifdef XWAYLAND wlr_xwayland_destroy(xwayland); xwayland = NULL; @@ -745,6 +745,43 @@ cleanupmon(struct wl_listener *listener, void *data) free(m); } +void +cleanuplisteners(void) +{ + wl_list_remove(&cursor_axis.link); + wl_list_remove(&cursor_button.link); + wl_list_remove(&cursor_frame.link); + wl_list_remove(&cursor_motion.link); + wl_list_remove(&cursor_motion_absolute.link); + wl_list_remove(&gpu_reset.link); + wl_list_remove(&idle_inhibitor_create.link); + wl_list_remove(&layout_change.link); + wl_list_remove(&new_input.link); + wl_list_remove(&new_virtual_keyboard.link); + wl_list_remove(&new_virtual_pointer.link); + wl_list_remove(&new_pointer_constraint.link); + wl_list_remove(&new_output.link); + wl_list_remove(&new_xdg_surface.link); + wl_list_remove(&new_xdg_decoration.link); + wl_list_remove(&new_xdg_popup.link); + wl_list_remove(&new_layer_shell_surface.link); + wl_list_remove(&output_mgr_apply.link); + wl_list_remove(&output_mgr_test.link); + wl_list_remove(&output_power_mgr_set_mode.link); + wl_list_remove(&request_activate.link); + wl_list_remove(&request_cursor.link); + wl_list_remove(&request_set_psel.link); + wl_list_remove(&request_set_sel.link); + wl_list_remove(&request_set_shape.link); + wl_list_remove(&request_start_drag.link); + wl_list_remove(&start_drag.link); + wl_list_remove(&session_lock_create_lock.link); +#ifdef XWAYLAND + wl_list_remove(&new_xwayland_surface.link); + wl_list_remove(&xwayland_ready.link); +#endif +} + void closemon(Monitor *m) { @@ -1325,13 +1362,6 @@ destroysessionlock(struct wl_listener *listener, void *data) destroylock(lock, 0); } -void -destroysessionmgr(struct wl_listener *listener, void *data) -{ - wl_list_remove(&session_lock_create_lock.link); - wl_list_remove(&session_lock_mgr_destroy.link); -} - void destroykeyboardgroup(struct wl_listener *listener, void *data) { @@ -2528,7 +2558,6 @@ setup(void) session_lock_mgr = wlr_session_lock_manager_v1_create(dpy); wl_signal_add(&session_lock_mgr->events.new_lock, &session_lock_create_lock); - wl_signal_add(&session_lock_mgr->events.destroy, &session_lock_mgr_destroy); locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height, (float [4]){0.1f, 0.1f, 0.1f, 1.0f}); wlr_scene_node_set_enabled(&locked_bg->node, 0); From da13a9568312ccfdb1c5e527abf773d7512f3f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 19 Jan 2025 14:05:54 -0600 Subject: [PATCH 326/347] destroy keyboard group after unlinking listeners Last commit addressing the issue mentioned in 0925fe956aeddb983875f0fd892e9049e2d8cb76 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index f7ae6fb..1ff1167 100644 --- a/dwl.c +++ b/dwl.c @@ -1367,10 +1367,10 @@ destroykeyboardgroup(struct wl_listener *listener, void *data) { KeyboardGroup *group = wl_container_of(listener, group, destroy); wl_event_source_remove(group->key_repeat_source); - wlr_keyboard_group_destroy(group->wlr_group); wl_list_remove(&group->key.link); wl_list_remove(&group->modifiers.link); wl_list_remove(&group->destroy.link); + wlr_keyboard_group_destroy(group->wlr_group); free(group); } From d1c2f434983562bd7d2ace15ab0c05155be603bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 19 Jan 2025 17:24:01 -0600 Subject: [PATCH 327/347] rename some listeners To keep consistency with the rest of listeners --- dwl.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/dwl.c b/dwl.c index 1ff1167..ad21e1b 100644 --- a/dwl.c +++ b/dwl.c @@ -413,17 +413,17 @@ static struct wl_listener cursor_frame = {.notify = cursorframe}; static struct wl_listener cursor_motion = {.notify = motionrelative}; static struct wl_listener cursor_motion_absolute = {.notify = motionabsolute}; static struct wl_listener gpu_reset = {.notify = gpureset}; -static struct wl_listener idle_inhibitor_create = {.notify = createidleinhibitor}; static struct wl_listener layout_change = {.notify = updatemons}; -static struct wl_listener new_input = {.notify = inputdevice}; +static struct wl_listener new_idle_inhibitor = {.notify = createidleinhibitor}; +static struct wl_listener new_input_device = {.notify = inputdevice}; static struct wl_listener new_virtual_keyboard = {.notify = virtualkeyboard}; static struct wl_listener new_virtual_pointer = {.notify = virtualpointer}; static struct wl_listener new_pointer_constraint = {.notify = createpointerconstraint}; static struct wl_listener new_output = {.notify = createmon}; -static struct wl_listener new_xdg_surface = {.notify = createnotify}; +static struct wl_listener new_xdg_toplevel = {.notify = createnotify}; static struct wl_listener new_xdg_popup = {.notify = createpopup}; static struct wl_listener new_xdg_decoration = {.notify = createdecoration}; -static struct wl_listener new_layer_shell_surface = {.notify = createlayersurface}; +static struct wl_listener new_layer_surface = {.notify = createlayersurface}; static struct wl_listener output_mgr_apply = {.notify = outputmgrapply}; static struct wl_listener output_mgr_test = {.notify = outputmgrtest}; static struct wl_listener output_power_mgr_set_mode = {.notify = powermgrsetmode}; @@ -431,10 +431,10 @@ static struct wl_listener request_activate = {.notify = urgent}; static struct wl_listener request_cursor = {.notify = setcursor}; static struct wl_listener request_set_psel = {.notify = setpsel}; static struct wl_listener request_set_sel = {.notify = setsel}; -static struct wl_listener request_set_shape = {.notify = setcursorshape}; +static struct wl_listener request_set_cursor_shape = {.notify = setcursorshape}; static struct wl_listener request_start_drag = {.notify = requeststartdrag}; static struct wl_listener start_drag = {.notify = startdrag}; -static struct wl_listener session_lock_create_lock = {.notify = locksession}; +static struct wl_listener new_session_lock = {.notify = locksession}; #ifdef XWAYLAND static void activatex11(struct wl_listener *listener, void *data); @@ -754,17 +754,17 @@ cleanuplisteners(void) wl_list_remove(&cursor_motion.link); wl_list_remove(&cursor_motion_absolute.link); wl_list_remove(&gpu_reset.link); - wl_list_remove(&idle_inhibitor_create.link); + wl_list_remove(&new_idle_inhibitor.link); wl_list_remove(&layout_change.link); - wl_list_remove(&new_input.link); + wl_list_remove(&new_input_device.link); wl_list_remove(&new_virtual_keyboard.link); wl_list_remove(&new_virtual_pointer.link); wl_list_remove(&new_pointer_constraint.link); wl_list_remove(&new_output.link); - wl_list_remove(&new_xdg_surface.link); + wl_list_remove(&new_xdg_toplevel.link); wl_list_remove(&new_xdg_decoration.link); wl_list_remove(&new_xdg_popup.link); - wl_list_remove(&new_layer_shell_surface.link); + wl_list_remove(&new_layer_surface.link); wl_list_remove(&output_mgr_apply.link); wl_list_remove(&output_mgr_test.link); wl_list_remove(&output_power_mgr_set_mode.link); @@ -772,10 +772,10 @@ cleanuplisteners(void) wl_list_remove(&request_cursor.link); wl_list_remove(&request_set_psel.link); wl_list_remove(&request_set_sel.link); - wl_list_remove(&request_set_shape.link); + wl_list_remove(&request_set_cursor_shape.link); wl_list_remove(&request_start_drag.link); wl_list_remove(&start_drag.link); - wl_list_remove(&session_lock_create_lock.link); + wl_list_remove(&new_session_lock.link); #ifdef XWAYLAND wl_list_remove(&new_xwayland_surface.link); wl_list_remove(&xwayland_ready.link); @@ -2545,19 +2545,19 @@ setup(void) wl_list_init(&fstack); xdg_shell = wlr_xdg_shell_create(dpy, 6); - wl_signal_add(&xdg_shell->events.new_toplevel, &new_xdg_surface); + wl_signal_add(&xdg_shell->events.new_toplevel, &new_xdg_toplevel); wl_signal_add(&xdg_shell->events.new_popup, &new_xdg_popup); layer_shell = wlr_layer_shell_v1_create(dpy, 3); - wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface); + wl_signal_add(&layer_shell->events.new_surface, &new_layer_surface); idle_notifier = wlr_idle_notifier_v1_create(dpy); idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); - wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &idle_inhibitor_create); + wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &new_idle_inhibitor); session_lock_mgr = wlr_session_lock_manager_v1_create(dpy); - wl_signal_add(&session_lock_mgr->events.new_lock, &session_lock_create_lock); + wl_signal_add(&session_lock_mgr->events.new_lock, &new_session_lock); locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height, (float [4]){0.1f, 0.1f, 0.1f, 1.0f}); wlr_scene_node_set_enabled(&locked_bg->node, 0); @@ -2605,7 +2605,7 @@ setup(void) wl_signal_add(&cursor->events.frame, &cursor_frame); cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1); - wl_signal_add(&cursor_shape_mgr->events.request_set_shape, &request_set_shape); + wl_signal_add(&cursor_shape_mgr->events.request_set_shape, &request_set_cursor_shape); /* * Configures a seat, which is a single "seat" at which a user sits and @@ -2613,7 +2613,7 @@ setup(void) * pointer, touch, and drawing tablet device. We also rig up a listener to * let us know when new input devices are available on the backend. */ - wl_signal_add(&backend->events.new_input, &new_input); + wl_signal_add(&backend->events.new_input, &new_input_device); virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy); wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard, &new_virtual_keyboard); From aa69ed81b558f74e470e69cdcd442f9048ee624c Mon Sep 17 00:00:00 2001 From: korei999 Date: Sun, 2 Feb 2025 01:38:47 +0200 Subject: [PATCH 328/347] allocate with LISTEN_STATIC Fixes: https://codeberg.org/dwl/dwl/issues/723 Supersedes: https://codeberg.org/dwl/dwl/pulls/724 --- dwl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index ad21e1b..ec4ca86 100644 --- a/dwl.c +++ b/dwl.c @@ -79,7 +79,7 @@ #define END(A) ((A) + LENGTH(A)) #define TAGMASK ((1u << TAGCOUNT) - 1) #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) -#define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0) +#define LISTEN_STATIC(E, H) do { struct wl_listener *_l = ecalloc(1, sizeof(*_l)); _l->notify = (H); wl_signal_add((E), _l); } while (0) /* enums */ enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ @@ -906,6 +906,7 @@ commitpopup(struct wl_listener *listener, void *data) box.y -= (type == LayerShell ? l->scene->node.y : c->geom.y); wlr_xdg_popup_unconstrain_from_box(popup, &box); wl_list_remove(&listener->link); + free(listener); } void @@ -1246,6 +1247,7 @@ destroydragicon(struct wl_listener *listener, void *data) focusclient(focustop(selmon), 1); motionnotify(0, NULL, 0, 0, 0, 0); wl_list_remove(&listener->link); + free(listener); } void @@ -1255,6 +1257,7 @@ destroyidleinhibitor(struct wl_listener *listener, void *data) * at this point the idle inhibitor is still in the list of the manager */ checkidleinhibitor(wlr_surface_get_root_surface(data)); wl_list_remove(&listener->link); + free(listener); } void From e0f531d5087cbd1223577c77262ec7476c157088 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 12 Mar 2025 16:27:47 +0800 Subject: [PATCH 329/347] fix: crash when open some x11 app --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index ec4ca86..395b81d 100644 --- a/dwl.c +++ b/dwl.c @@ -3148,7 +3148,7 @@ sethints(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, set_hints); struct wlr_surface *surface = client_surface(c); - if (c == focustop(selmon)) + if (c == focustop(selmon) || !c->surface.xwayland->hints) return; c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints); From 4456f4536a483c127909151a84d7b62da4f40e8b Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 12 Mar 2025 16:17:44 +0800 Subject: [PATCH 330/347] fix: shouldn't configure uninitialized layer_surface --- dwl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dwl.c b/dwl.c index 395b81d..4816159 100644 --- a/dwl.c +++ b/dwl.c @@ -551,6 +551,9 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int wl_list_for_each(l, list, link) { struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; + if (!layer_surface->initialized) + continue; + if (exclusive != (layer_surface->current.exclusive_zone > 0)) continue; From faa56cc9b9718e1b195a02682836fe040963eb7d Mon Sep 17 00:00:00 2001 From: fauxmight Date: Thu, 24 Apr 2025 04:28:44 +0000 Subject: [PATCH 331/347] Update README.md --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1bcc36e..b8e3a3a 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,11 @@ philosophy. Like dwm, dwl is: ## Getting Started: ### Latest semi-stable [release] -This is probably where you want to start. This builds against the dependent -packages' versions currently shipping in major distributions. If your -distribution's wlroots version is older, use an earlier dwl [release] or [0.x -branch]. +This is probably where you want to start. This builds against the [wlroots] +versions currently shipping in major distributions. If your +distribution's `wlroots` version is older, use an earlier dwl [release]. +The `wlroots` version against which a given `dwl` release builds is specified +with each release on the [release] page ### Development branch [main] Active development progresses on the `main` branch. The `main` branch is built @@ -181,6 +182,7 @@ inspiration, and to the various contributors to the project, including: - Stivvo for output management and fullscreen support, and patch maintenance +[wlroots]: https://gitlab.freedesktop.org/wlroots [`systemd --user`]: https://wiki.archlinux.org/title/Systemd/User [#dwl on Libera Chat]: https://web.libera.chat/?channels=#dwl [0.7-rc1]: https://codeberg.org/dwl/dwl/releases/tag/v0.7-rc1 From de57f6c315f0ad70b68e083ae9a1822e43f01586 Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Sat, 7 Jun 2025 00:25:30 -0500 Subject: [PATCH 332/347] Cleanup comments --- client.h | 4 ++-- config.mk | 2 +- dwl.c | 49 +++++++++++++++++++++++++------------------------ 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/client.h b/client.h index f1e2ab5..d9f90bb 100644 --- a/client.h +++ b/client.h @@ -264,8 +264,8 @@ client_is_stopped(Client *c) wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); if (waitid(P_PID, pid, &in, WNOHANG|WCONTINUED|WSTOPPED|WNOWAIT) < 0) { - /* This process is not our child process, while is very unluckely that - * it is stopped, in order to do not skip frames assume that it is. */ + /* This process is not our child process, while is very unlikely that + * it is stopped, in order to do not skip frames, assume that it is. */ if (errno == ECHILD) return 1; } else if (in.si_pid) { diff --git a/config.mk b/config.mk index e2f1816..eb08a05 100644 --- a/config.mk +++ b/config.mk @@ -11,7 +11,7 @@ DATADIR = $(PREFIX)/share WLR_INCS = `$(PKG_CONFIG) --cflags wlroots-0.19` WLR_LIBS = `$(PKG_CONFIG) --libs wlroots-0.19` -# Allow using an alternative wlroots installations +# Allow using an alternative wlroots installation # This has to have all the includes required by wlroots, e.g: # Assuming wlroots git repo is "${PWD}/wlroots" and you only ran "meson setup build && ninja -C build" #WLR_INCS = -I/usr/include/pixman-1 -I/usr/include/elogind -I/usr/include/libdrm \ diff --git a/dwl.c b/dwl.c index 4816159..775dadf 100644 --- a/dwl.c +++ b/dwl.c @@ -609,8 +609,8 @@ axisnotify(struct wl_listener *listener, void *data) * for example when you move the scroll wheel. */ struct wlr_pointer_axis_event *event = data; wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); - /* TODO: allow usage of scroll whell for mousebindings, it can be implemented - * checking the event's orientation and the delta of the event */ + /* TODO: allow usage of scroll wheel for mousebindings, it can be implemented + * by checking the event's orientation and the delta of the event */ /* Notify the client with pointer focus of the axis event. */ wlr_seat_pointer_notify_axis(seat, event->time_msec, event->orientation, event->delta, @@ -712,8 +712,8 @@ cleanup(void) destroykeyboardgroup(&kb_group->destroy, NULL); - /* If it's not destroyed manually it will cause a use-after-free of wlr_seat. - * Destroy it until it's fixed in the wlroots side */ + /* If it's not destroyed manually, it will cause a use-after-free of wlr_seat. + * Destroy it until it's fixed on the wlroots side */ wlr_backend_destroy(backend); wl_display_destroy(dpy); @@ -858,7 +858,7 @@ commitnotify(struct wl_listener *listener, void *data) /* * Get the monitor this client will be rendered on * Note that if the user set a rule in which the client is placed on - * a different monitor based on its title this will likely select + * a different monitor based on its title, this will likely select * a wrong monitor. */ applyrules(c); @@ -1212,7 +1212,7 @@ cursorconstrain(struct wlr_pointer_constraint_v1 *constraint) void cursorframe(struct wl_listener *listener, void *data) { - /* This event is forwarded by the cursor when a pointer emits an frame + /* This event is forwarded by the cursor when a pointer emits a frame * event. Frame events are sent after regular pointer events to group * multiple events together. For instance, two axis events may happen at the * same time, in which case a frame event won't be sent in between. */ @@ -1508,7 +1508,7 @@ focusstack(const Arg *arg) focusclient(c, 1); } -/* We probably should change the name of this, it sounds like +/* We probably should change the name of this: it sounds like it * will focus the topmost client of this mon, when actually will * only return that client */ Client * @@ -1780,8 +1780,8 @@ mapnotify(struct wl_listener *listener, void *data) /* Set initial monitor, tags, floating status, and focus: * we always consider floating, clients that have parent and thus - * we set the same tags and monitor than its parent, if not - * try to apply rules for them */ + * we set the same tags and monitor as its parent. + * If there is no parent, apply rules */ if ((p = client_get_parent(c))) { c->isfloating = 1; setmon(c, p->mon, p->tags); @@ -1841,8 +1841,7 @@ motionabsolute(struct wl_listener *listener, void *data) * motion event, from 0..1 on each axis. This happens, for example, when * wlroots is running under a Wayland window rather than KMS+DRM, and you * move the mouse over the window. You could enter the window from any edge, - * so we have to warp the mouse there. There is also some hardware which - * emits these events. */ + * so we have to warp the mouse there. Also, some hardware emits these events. */ struct wlr_pointer_motion_absolute_event *event = data; double lx, ly, dx, dy; @@ -2027,9 +2026,9 @@ apply_or_test: ok &= test ? wlr_output_test_state(wlr_output, &state) : wlr_output_commit_state(wlr_output, &state); - /* Don't move monitors if position wouldn't change, this to avoid - * wlroots marking the output as manually configured. - * wlr_output_layout_add does not like disabled outputs */ + /* Don't move monitors if position wouldn't change. This avoids + * wlroots marking the output as manually configured. + * wlr_output_layout_add does not like disabled outputs */ if (!test && wlr_output->enabled && (m->m.x != config_head->state.x || m->m.y != config_head->state.y)) wlr_output_layout_add(output_layout, wlr_output, config_head->state.x, config_head->state.y); @@ -2266,8 +2265,10 @@ run(char *startup_cmd) close(piperw[0]); } - /* Mark stdout as non-blocking to avoid people who does not close stdin - * nor consumes it in their startup script getting dwl frozen */ + /* Mark stdout as non-blocking to avoid the startup script + * causing dwl to freeze when a user neither closes stdin + * nor consumes standard input in his startup script */ + if (fd_set_nonblock(STDOUT_FILENO) < 0) close(STDOUT_FILENO); @@ -2278,7 +2279,7 @@ run(char *startup_cmd) selmon = xytomon(cursor->x, cursor->y); /* TODO hack to get cursor to display in its initial location (100, 100) - * instead of (0, 0) and then jumping. still may not be fully + * instead of (0, 0) and then jumping. Still may not be fully * initialized, as the image/coordinates are not transformed for the * monitor when displayed here */ wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y); @@ -2301,7 +2302,7 @@ setcursor(struct wl_listener *listener, void *data) * event, which will result in the client requesting set the cursor surface */ if (cursor_mode != CurNormal && cursor_mode != CurPressed) return; - /* This can be sent by any client, so we check to make sure this one is + /* This can be sent by any client, so we check to make sure this one * actually has pointer focus first. If so, we can tell the cursor to * use the provided surface as the cursor image. It will set the * hardware cursor on the output that it's currently on and continue to @@ -2317,7 +2318,7 @@ setcursorshape(struct wl_listener *listener, void *data) struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data; if (cursor_mode != CurNormal && cursor_mode != CurPressed) return; - /* This can be sent by any client, so we check to make sure this one is + /* This can be sent by any client, so we check to make sure this one * actually has pointer focus first. If so, we can tell the cursor to * use the provided cursor shape. */ if (event->seat_client == seat->pointer_state.focused_client) @@ -2420,7 +2421,7 @@ setpsel(struct wl_listener *listener, void *data) { /* This event is raised by the seat when a client wants to set the selection, * usually when the user copies something. wlroots allows compositors to - * ignore such requests if they so choose, but in dwl we always honor + * ignore such requests if they so choose, but in dwl we always honor them */ struct wlr_seat_request_set_primary_selection_event *event = data; wlr_seat_set_primary_selection(seat, event->source, event->serial); @@ -2431,7 +2432,7 @@ setsel(struct wl_listener *listener, void *data) { /* This event is raised by the seat when a client wants to set the selection, * usually when the user copies something. wlroots allows compositors to - * ignore such requests if they so choose, but in dwl we always honor + * ignore such requests if they so choose, but in dwl we always honor them */ struct wlr_seat_request_set_selection_event *event = data; wlr_seat_set_selection(seat, event->source, event->serial); @@ -2478,9 +2479,9 @@ setup(void) wl_signal_add(&drw->events.lost, &gpu_reset); /* Create shm, drm and linux_dmabuf interfaces by ourselves. - * The simplest way is call: + * The simplest way is to call: * wlr_renderer_init_wl_display(drw); - * but we need to create manually the linux_dmabuf interface to integrate it + * but we need to create the linux_dmabuf interface manually to integrate it * with wlr_scene. */ wlr_renderer_init_wl_shm(drw, dpy); @@ -2529,7 +2530,7 @@ setup(void) power_mgr = wlr_output_power_manager_v1_create(dpy); wl_signal_add(&power_mgr->events.set_mode, &output_power_mgr_set_mode); - /* Creates an output layout, which a wlroots utility for working with an + /* Creates an output layout, which is a wlroots utility for working with an * arrangement of screens in a physical layout. */ output_layout = wlr_output_layout_create(dpy); wl_signal_add(&output_layout->events.change, &layout_change); From 7d2415bfe854cccc2bcf2709fecc1eaacddbe903 Mon Sep 17 00:00:00 2001 From: mcsimw Date: Fri, 16 May 2025 06:24:58 +0000 Subject: [PATCH 333/347] Update config.mk compiles and works fine on wlroots-0.20 --- config.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.mk b/config.mk index eb08a05..f641d04 100644 --- a/config.mk +++ b/config.mk @@ -8,8 +8,8 @@ PREFIX = /usr/local MANDIR = $(PREFIX)/share/man DATADIR = $(PREFIX)/share -WLR_INCS = `$(PKG_CONFIG) --cflags wlroots-0.19` -WLR_LIBS = `$(PKG_CONFIG) --libs wlroots-0.19` +WLR_INCS = `$(PKG_CONFIG) --cflags wlroots-0.20` +WLR_LIBS = `$(PKG_CONFIG) --libs wlroots-0.20` # Allow using an alternative wlroots installation # This has to have all the includes required by wlroots, e.g: From 78e75a83a4541d0fd4c5b0be56057380a5fb639e Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Mon, 9 Jun 2025 00:18:17 -0500 Subject: [PATCH 334/347] Revert "Update config.mk" This reverts commit 7d2415bfe854cccc2bcf2709fecc1eaacddbe903. Will stick with wlroots 0.19 for now. --- config.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.mk b/config.mk index f641d04..eb08a05 100644 --- a/config.mk +++ b/config.mk @@ -8,8 +8,8 @@ PREFIX = /usr/local MANDIR = $(PREFIX)/share/man DATADIR = $(PREFIX)/share -WLR_INCS = `$(PKG_CONFIG) --cflags wlroots-0.20` -WLR_LIBS = `$(PKG_CONFIG) --libs wlroots-0.20` +WLR_INCS = `$(PKG_CONFIG) --cflags wlroots-0.19` +WLR_LIBS = `$(PKG_CONFIG) --libs wlroots-0.19` # Allow using an alternative wlroots installation # This has to have all the includes required by wlroots, e.g: From d1880b44223701c91b51b319fc69a0f63044f861 Mon Sep 17 00:00:00 2001 From: Nikita Ivanov Date: Tue, 4 Feb 2025 20:51:06 +0100 Subject: [PATCH 335/347] Fix crash disabling monitor with locked surface --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index 775dadf..5beef8b 100644 --- a/dwl.c +++ b/dwl.c @@ -739,6 +739,8 @@ cleanupmon(struct wl_listener *listener, void *data) wl_list_remove(&m->frame.link); wl_list_remove(&m->link); wl_list_remove(&m->request_state.link); + if (m->lock_surface) + destroylocksurface(&m->destroy_lock_surface, NULL); m->wlr_output->data = NULL; wlr_output_layout_remove(output_layout, m->wlr_output); wlr_scene_output_destroy(m->scene_output); From 02f8744a486713bfac41661e7c5590ec11ec8989 Mon Sep 17 00:00:00 2001 From: kilpilainen <> Date: Thu, 27 Mar 2025 16:07:45 +0200 Subject: [PATCH 336/347] Use `all-scroll` instead of `fleur` xcursor shape for window dragging When there are no xcursor themes available, Wayland uses its own built-in shapes [1]. Wayland (and thus to extend wlroots) is based on the XDG's cursor spec [2], which itself is based on CSS' [3][4], neither of which define `fleur` shape. So dwl, without any external themes, falls back to `default` shape when dragging a window. There is `all-scroll` shape that is being symlinked to (or vice versa) by `move`, `dnd-move`, `grabbed` and `fleur` shapes by various themes. Since `all-scroll` is being symlinked to anyway, and has been part of all relevant specs as the shape for this use case for a very long time now, use it instead. [1] https://gitlab.freedesktop.org/wayland/wayland/-/blob/main/cursor/cursor-data.h#L559 [2] https://www.freedesktop.org/wiki/Specifications/cursor-spec [3] https://drafts.csswg.org/css-ui/#cursor [4] https://developer.mozilla.org/en-US/docs/Web/CSS/cursor --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 5beef8b..76b7755 100644 --- a/dwl.c +++ b/dwl.c @@ -1965,7 +1965,7 @@ moveresize(const Arg *arg) case CurMove: grabcx = (int)round(cursor->x) - grabc->geom.x; grabcy = (int)round(cursor->y) - grabc->geom.y; - wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur"); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "all-scroll"); break; case CurResize: /* Doesn't work for X11 output - the next absolute motion event From 59c99308b0cad19f48fa0586aca40eaec58695a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 28 Jul 2024 12:28:31 -0600 Subject: [PATCH 337/347] drop CAVEATS section from the man page Since 71f11e6cf63289d51f152469a0da81a85fe2608c it is not longer the case --- dwl.1 | 8 -------- 1 file changed, 8 deletions(-) diff --git a/dwl.1 b/dwl.1 index 780c78f..f254096 100644 --- a/dwl.1 +++ b/dwl.1 @@ -146,13 +146,5 @@ with s6 in the background: .Xr wmenu 1 , .Xr dwm 1 , .Xr xkeyboard-config 7 -.Sh CAVEATS -The child process's standard input is connected with a pipe to -.Nm . -If the child process neither reads from the pipe nor closes its -standard input, -.Nm -will freeze after a while due to it blocking when writing to the full -pipe buffer. .Sh BUGS All of them. From 9dbce43a69988b62430f6060f30049fb6ab036f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 27 Sep 2024 21:18:47 -0600 Subject: [PATCH 338/347] document mouse button actions [sevz: commit message is mine. The content was written by scottro11 and shared in https://codeberg.org/dwl/dwl/issues/697] Closes: https://codeberg.org/dwl/dwl/issues/697 --- dwl.1 | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dwl.1 b/dwl.1 index f254096..65648f4 100644 --- a/dwl.1 +++ b/dwl.1 @@ -100,6 +100,16 @@ Quit .Nm . .El These might differ depending on your keyboard layout. +.Sh Mouse commands +.Bl -tag -width 20n -offset indent -compact +.It Mod-Button1 +Move focused window while dragging. Tiled windows will be toggled to the floating state. +.It Mod-Button2 +Toggles focused window between floating and tiled state. +.It Mod-Button3 +Resize focused window while dragging. Tiled windows will be toggled to +the +floating state. .Sh ENVIRONMENT These environment variables are used by .Nm : From 661e1ee38ceeb6e8e41b32ea13dc2eec591afba8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 27 Sep 2024 22:20:16 -0600 Subject: [PATCH 339/347] Use a subsection for mouse commands also add missing ".El", s/Toggles/Toggle/ in second command and add newlines after a full stop --- dwl.1 | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/dwl.1 b/dwl.1 index 65648f4..fccf569 100644 --- a/dwl.1 +++ b/dwl.1 @@ -100,16 +100,17 @@ Quit .Nm . .El These might differ depending on your keyboard layout. -.Sh Mouse commands +.Ss Mouse commands .Bl -tag -width 20n -offset indent -compact .It Mod-Button1 -Move focused window while dragging. Tiled windows will be toggled to the floating state. +Move focused window while dragging. +Tiled windows will be toggled to the floating state. .It Mod-Button2 -Toggles focused window between floating and tiled state. +Toggle focused window between floating and tiled state. .It Mod-Button3 -Resize focused window while dragging. Tiled windows will be toggled to -the -floating state. +Resize focused window while dragging. +Tiled windows will be toggled to the floating state. +.El .Sh ENVIRONMENT These environment variables are used by .Nm : From 67ff29eb953b135d95371b462fc8f14e89d839f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 26 Dec 2024 21:10:36 -0600 Subject: [PATCH 340/347] document status output --- README.md | 2 +- dwl.1 | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 102 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b8e3a3a..b876fdb 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ automatically, you will need to configure it prior to launching `dwl`, e.g.: Information about selected layouts, current window title, app-id, and selected/occupied/urgent tags is written to the stdin of the `-s` command (see -the `printstatus()` function for details). This information can be used to +the `STATUS INFORMATION` section in `_dwl_(1)`). This information can be used to populate an external status bar with a script that parses the information. Failing to read this information will cause dwl to block, so if you do want to run a startup command that does not consume the status information, diff --git a/dwl.1 b/dwl.1 index fccf569..7fee870 100644 --- a/dwl.1 +++ b/dwl.1 @@ -37,7 +37,7 @@ starts a shell process running when starting. When stopping, it sends .Dv SIGTERM -to the child process and waits for it to exit. +to the child process group and waits for it to exit. .Pp Users are encouraged to customize .Nm @@ -55,10 +55,10 @@ Move window to a single tag. Toggle tag for window. .It Mod-p Spawn -.Nm wmenu-run . +.Xr wmenu-run 1 . .It Mod-Shift-Return Spawn -.Nm foot . +.Xr foot 1 . .It Mod-[jk] Move focus down/up the stack. .It Mod-[id] @@ -111,6 +111,103 @@ Toggle focused window between floating and tiled state. Resize focused window while dragging. Tiled windows will be toggled to the floating state. .El +.Sh STATUS INFORMATION +.Nm +writes its status information to standard output. +If the +.Fl s +option is given, the status information is written to the standard input of the +child process instead. +.Pp +Said information has the following format: +.Bd -ragged -offset indent +.Ar +.Ar +.Ar +.Ed +.Pp +.Bl -tag -width 11n -offset 0 -compact +.It Ar +is the name given to the output. +.It Ar +is one of (in order) +.Em title , +.Em appid , +.Em fullscreen , +.Em floating , +.Em selmon , +.Em tags , +.Em layout . +.It Ar +changes depending on +.Ar . +.Bl -tag -width 10n -compact +.It Em title +The title of the focused window on +.Ar +or nothing if there is no focused window. +.It Em appid +The app_id of the focused window on +.Ar +or nothing if there is no focused window. +.It Em fullscreen +Prints 1 if the focused window on +.Ar +is in fullscreen state, otherwise prints 0. If there is no focused +window it prints nothing. +.It Em floating +Prints 1 if the focused window on +.Ar +is in floating state, otherwise prints 0. If there is no focused +window it prints nothing. +.It Em selmon +Prints 1 if +.Ar +is the selected monitor, otherwise prints 0. +.It Em tags +Prints four bitmasks in the following order: +.Bl -bullet -width 2n -compact +.It +Occupied tags of +.Ar . +.It +Selected tags of +.Ar . +.It +Tags of the focused window on +.Ar . +.It +Tags where a window on +.Ar +requested activation or has urgency hints. +.El +The bitmasks are 32-bit unsigned decimal integers. +.It Em layout +Prints the symbol of the current layout. +.El +.El +.Ss Examples +When there is a selected window: +.Bd -literal -offset indent +HDMI\-A\-1 title \(ti/source/repos/dwl > man \-l dwl.1 +HDMI\-A\-1 appid footclient +HDMI\-A\-1 fullscreen 0 +HDMI\-A\-1 floating 0 +HDMI\-A\-1 selmon 1 +HDMI\-A\-1 tags 271 4 4 0 +HDMI\-A\-1 layout [T] +.Ed +.Pp +When there is no selected window: +.Bd -literal -offset indent +HDMI\-A\-1 title +HDMI\-A\-1 appid +HDMI\-A\-1 fullscreen +HDMI\-A\-1 floating +HDMI\-A\-1 selmon 1 +HDMI\-A\-1 tags 271 512 0 0 +HDMI\-A\-1 layout [T] +.Ed .Sh ENVIRONMENT These environment variables are used by .Nm : @@ -153,9 +250,9 @@ Start with s6 in the background: .Dl dwl \-s \(aqs6\-svscan <&\-\(aq .Sh SEE ALSO +.Xr dwm 1 , .Xr foot 1 , .Xr wmenu 1 , -.Xr dwm 1 , .Xr xkeyboard-config 7 .Sh BUGS All of them. From ea263a0ed50d62033ca305fe7a4c5c36fddb4755 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Sat, 14 Jun 2025 22:27:25 +0200 Subject: [PATCH 341/347] float sub-windows matching a rule Currently when a rule that doesn't make windows floating matches, even sub-windows of float type get tiled rather than just the main window. This is inconsistent with dwm and other compositors. Fix this by making these windows floating after applying rules. Fixes #1142. --- dwl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 76b7755..12f441e 100644 --- a/dwl.c +++ b/dwl.c @@ -483,7 +483,6 @@ applyrules(Client *c) const Rule *r; Monitor *mon = selmon, *m; - c->isfloating = client_is_float_type(c); appid = client_get_appid(c); title = client_get_title(c); @@ -499,6 +498,8 @@ applyrules(Client *c) } } } + + c->isfloating |= client_is_float_type(c); setmon(c, mon, newtags); } From 90b8371707a136a2c8f2f20a3fa9d3dd7bd3ed5c Mon Sep 17 00:00:00 2001 From: fauxmight Date: Wed, 18 Jun 2025 14:52:15 +0200 Subject: [PATCH 342/347] Update README.md Correct description of default background color --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b876fdb..364e3ca 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ seatd daemon. When dwl is run with no arguments, it will launch the server and begin handling any shortcuts configured in `config.h`. There is no status bar or other decoration initially; these are instead clients that can be run within the -Wayland session. Do note that the default background color is black. This can be +Wayland session. Do note that the default background color is grey. This can be modified in `config.h`. If you would like to run a script or command automatically at startup, you can From 15bfffd87a6f9da0bc551db95c7c2a9a069b3708 Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Wed, 18 Jun 2025 23:41:14 -0500 Subject: [PATCH 343/347] fullscreen_bg defaults to black Per conversation at PR #1147 with @kilpilainen --- config.def.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.def.h b/config.def.h index 22d2171..95c2afa 100644 --- a/config.def.h +++ b/config.def.h @@ -12,7 +12,7 @@ static const float bordercolor[] = COLOR(0x444444ff); static const float focuscolor[] = COLOR(0x005577ff); static const float urgentcolor[] = COLOR(0xff0000ff); /* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */ -static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */ +static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */ /* tagging - TAGCOUNT must be no greater than 31 */ #define TAGCOUNT (9) From b28674e0ca4a9ecc92cb0607498e3db2df3d4c00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 14 Jan 2025 12:34:20 -0600 Subject: [PATCH 344/347] add support for ext-image-copy-capture-v1 and ext-image-capture-source-v1 (wlroots!4545) References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4545 --- Makefile | 4 ++++ dwl.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Makefile b/Makefile index 578194f..3981fbb 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ all: dwl dwl: dwl.o util.o $(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \ + ext-image-copy-capture-v1-protocol.h \ pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \ wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h util.o: util.c util.h @@ -33,6 +34,9 @@ WAYLAND_PROTOCOLS = `$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols` cursor-shape-v1-protocol.h: $(WAYLAND_SCANNER) enum-header \ $(WAYLAND_PROTOCOLS)/staging/cursor-shape/cursor-shape-v1.xml $@ +ext-image-copy-capture-v1-protocol.h: + $(WAYLAND_SCANNER) enum-header \ + $(WAYLAND_PROTOCOLS)/staging/ext-image-copy-capture/ext-image-copy-capture-v1.xml $@ pointer-constraints-unstable-v1-protocol.h: $(WAYLAND_SCANNER) enum-header \ $(WAYLAND_PROTOCOLS)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@ diff --git a/dwl.c b/dwl.c index 12f441e..1dad6ac 100644 --- a/dwl.c +++ b/dwl.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include #include @@ -2516,6 +2518,8 @@ setup(void) wlr_data_device_manager_create(dpy); wlr_export_dmabuf_manager_v1_create(dpy); wlr_screencopy_manager_v1_create(dpy); + wlr_ext_image_copy_capture_manager_v1_create(dpy, 1); + wlr_ext_output_image_capture_source_manager_v1_create(dpy, 1); wlr_data_control_manager_v1_create(dpy); wlr_primary_selection_v1_device_manager_create(dpy); wlr_viewporter_create(dpy); From ab4cb6e28365cf8754d6d3bdd293c05abfc27e26 Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Mon, 4 Aug 2025 16:27:34 -0500 Subject: [PATCH 345/347] Revert "add support for ext-image-copy-capture-v1 and ext-image-capture-source-v1 (wlroots!4545)" This reverts commit b28674e0ca4a9ecc92cb0607498e3db2df3d4c00. This PR is not yet finalized. (Screen freezes). --- Makefile | 4 ---- dwl.c | 4 ---- 2 files changed, 8 deletions(-) diff --git a/Makefile b/Makefile index 3981fbb..578194f 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,6 @@ all: dwl dwl: dwl.o util.o $(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \ - ext-image-copy-capture-v1-protocol.h \ pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \ wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h util.o: util.c util.h @@ -34,9 +33,6 @@ WAYLAND_PROTOCOLS = `$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols` cursor-shape-v1-protocol.h: $(WAYLAND_SCANNER) enum-header \ $(WAYLAND_PROTOCOLS)/staging/cursor-shape/cursor-shape-v1.xml $@ -ext-image-copy-capture-v1-protocol.h: - $(WAYLAND_SCANNER) enum-header \ - $(WAYLAND_PROTOCOLS)/staging/ext-image-copy-capture/ext-image-copy-capture-v1.xml $@ pointer-constraints-unstable-v1-protocol.h: $(WAYLAND_SCANNER) enum-header \ $(WAYLAND_PROTOCOLS)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@ diff --git a/dwl.c b/dwl.c index 1dad6ac..12f441e 100644 --- a/dwl.c +++ b/dwl.c @@ -24,8 +24,6 @@ #include #include #include -#include -#include #include #include #include @@ -2518,8 +2516,6 @@ setup(void) wlr_data_device_manager_create(dpy); wlr_export_dmabuf_manager_v1_create(dpy); wlr_screencopy_manager_v1_create(dpy); - wlr_ext_image_copy_capture_manager_v1_create(dpy, 1); - wlr_ext_output_image_capture_source_manager_v1_create(dpy, 1); wlr_data_control_manager_v1_create(dpy); wlr_primary_selection_v1_device_manager_create(dpy); wlr_viewporter_create(dpy); From ed2e1efda8470d4c7971f5d75d50bb1c8e627316 Mon Sep 17 00:00:00 2001 From: fauxmight Date: Mon, 29 Sep 2025 05:39:54 +0200 Subject: [PATCH 346/347] Update README.md Make "dwl" references in README.md links to dwm main site. Closes #1168 --- README.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 364e3ca..d131bb0 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ Join us on our IRC channel: [#dwl on Libera Chat] Or on the community-maintained [Discord server]. dwl is a compact, hackable compositor for [Wayland] based on [wlroots]. It is -intended to fill the same space in the Wayland world that dwm does in X11, +intended to fill the same space in the Wayland world that [dwm] does in X11, primarily in terms of functionality, and secondarily in terms of -philosophy. Like dwm, dwl is: +philosophy. Like [dwm], dwl is: - Easy to understand, hack on, and extend with patches - One C source file (or a very small number) configurable via `config.h` @@ -55,11 +55,11 @@ To enable XWayland, you should uncomment its flags in `config.mk`. ## Configuration All configuration is done by editing `config.h` and recompiling, in the same -manner as dwm. There is no way to separately restart the window manager in +manner as [dwm]. There is no way to separately restart the window manager in Wayland without restarting the entire display server, so any changes will take effect the next time dwl is executed. -As in the dwm community, we encourage users to share patches they have +As in the [dwm] community, we encourage users to share patches they have created. Check out the [dwl-patches] repository! ## Running dwl @@ -124,11 +124,11 @@ You can find a [list of useful resources on our wiki]. ## Background -dwl is not meant to provide every feature under the sun. Instead, like dwm, it +dwl is not meant to provide every feature under the sun. Instead, like [dwm], it sticks to features which are necessary, simple, and straightforward to implement given the base on which it is built. Implemented default features are: -- Any features provided by dwm/Xlib: simple window borders, tags, keybindings, +- Any features provided by [dwm]/Xlib: simple window borders, tags, keybindings, client rules, mouse move/resize. Providing a built-in status bar is an exception to this goal, to avoid dependencies on font rendering and/or drawing libraries when an external bar could work well. @@ -145,10 +145,10 @@ given the base on which it is built. Implemented default features are: - Layer shell popups (used by Waybar) - Damage tracking provided by scenegraph API -Given the Wayland architecture, dwl has to implement features from dwm **and** +Given the Wayland architecture, dwl has to implement features from [dwm] **and** the xorg-server. Because of this, it is impossible to maintain the original project goal of 2000 SLOC and have a reasonably complete compositor with -features comparable to dwm. However, this does not mean that the code will grow +features comparable to [dwm]. However, this does not mean that the code will grow indiscriminately. We will try to keep the code as small as possible. Features under consideration (possibly as patches) are: @@ -172,7 +172,7 @@ developers. This was made possible in many cases by looking at how sway accomplished something, then trying to do the same in as suckless a way as possible. -Many thanks to suckless.org and the dwm developers and community for the +Many thanks to suckless.org and the [dwm] developers and community for the inspiration, and to the various contributors to the project, including: - **Devin J. Pohly for creating and nurturing the fledgling project** @@ -183,6 +183,7 @@ inspiration, and to the various contributors to the project, including: [wlroots]: https://gitlab.freedesktop.org/wlroots +[dwm]: https://dwm.suckless.org/ [`systemd --user`]: https://wiki.archlinux.org/title/Systemd/User [#dwl on Libera Chat]: https://web.libera.chat/?channels=#dwl [0.7-rc1]: https://codeberg.org/dwl/dwl/releases/tag/v0.7-rc1 From 6cd26568d5b8be2252ac0def36cd194b4fb2d7c3 Mon Sep 17 00:00:00 2001 From: fauxmight Date: Mon, 29 Sep 2025 05:56:22 +0200 Subject: [PATCH 347/347] Update README.md Document Java nonreparenting WM issue Closes #722 --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index d131bb0..390788d 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,15 @@ script with the line To get a list of status bars that work with dwl consult our [wiki]. +### (Known) Java nonreparenting WM issue +Certain IDEs don't display correctly unless an environmental variable for Java AWT +indicates that the WM is nonreparenting. + +For some Java AWT-based IDEs, such as Xilinx Vivado and Microchip MPLAB X, the +following environment variable needs to be set before running the IDE or dwl: + + export _JAVA_AWT_WM_NONREPARENTING=1 + ## Replacements for X applications You can find a [list of useful resources on our wiki].