From b9295e8cee8d3e057f92a9fea1523c379c298f03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 27 Aug 2022 16:29:23 -0500 Subject: [PATCH 01/45] sort client.h functions --- client.h | 136 +++++++++++++++++++++++++++---------------------------- 1 file changed, 66 insertions(+), 70 deletions(-) diff --git a/client.h b/client.h index c54a2f3..5988db3 100644 --- a/client.h +++ b/client.h @@ -16,16 +16,6 @@ client_is_x11(Client *c) #endif } -static inline struct wlr_surface * -client_surface(Client *c) -{ -#ifdef XWAYLAND - if (client_is_x11(c)) - return c->surface.xwayland->surface; -#endif - return c->surface.xdg->surface; -} - static inline Client * client_from_wlr_surface(struct wlr_surface *s) { @@ -48,6 +38,56 @@ client_from_wlr_surface(struct wlr_surface *s) return NULL; } +static inline Client * +client_get_parent(Client *c) +{ + Client *p; +#ifdef XWAYLAND + if (client_is_x11(c) && c->surface.xwayland->parent) + return client_from_wlr_surface(c->surface.xwayland->parent->surface); +#endif + if (c->surface.xdg->toplevel->parent) + return client_from_wlr_surface(c->surface.xdg->toplevel->parent->surface); + + return NULL; +} + +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)) { + struct wlr_xwayland_surface_size_hints *size_hints; + 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) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return c->surface.xwayland->surface; +#endif + return c->surface.xdg->surface; +} + /* The others */ static inline void client_activate_surface(struct wlr_surface *s, int activated) @@ -103,32 +143,6 @@ client_get_geometry(Client *c, struct wlr_box *geom) wlr_xdg_surface_get_geometry(c->surface.xdg, geom); } -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)) { - struct wlr_xwayland_surface_size_hints *size_hints; - 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 const char * client_get_title(Client *c) { @@ -139,19 +153,6 @@ client_get_title(Client *c) return c->surface.xdg->toplevel->title; } -static inline Client * -client_get_parent(Client *c) -{ - Client *p; -#ifdef XWAYLAND - if (client_is_x11(c) && c->surface.xwayland->parent) - return client_from_wlr_surface(c->surface.xwayland->parent->surface); -#endif - if (c->surface.xdg->toplevel->parent) - return client_from_wlr_surface(c->surface.xdg->toplevel->parent->surface); - - return NULL; -} static inline int client_is_float_type(Client *c) @@ -171,16 +172,11 @@ client_is_float_type(Client *c) || surface->window_type[i] == netatom[NetWMWindowTypeToolbar] || surface->window_type[i] == netatom[NetWMWindowTypeUtility]) return 1; - - return ((min.width > 0 || min.height > 0 || max.width > 0 || max.height > 0) - && (min.width == max.width || min.height == max.height)) - || c->surface.xwayland->parent; } #endif - return ((min.width > 0 || min.height > 0 || max.width > 0 || max.height > 0) && (min.width == max.width || min.height == max.height)) - || c->surface.xdg->toplevel->parent; + || client_get_parent(c); } static inline int @@ -193,16 +189,6 @@ client_is_mapped(Client *c) return c->surface.xdg->mapped; } -static inline int -client_wants_fullscreen(Client *c) -{ -#ifdef XWAYLAND - if (client_is_x11(c)) - return c->surface.xwayland->fullscreen; -#endif - return c->surface.xdg->toplevel->requested.fullscreen; -} - static inline int client_is_unmanaged(Client *c) { @@ -212,6 +198,17 @@ client_is_unmanaged(Client *c) return 0; } +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) { @@ -270,15 +267,14 @@ client_surface_at(Client *c, double cx, double cy, double *sx, double *sy) return wlr_xdg_surface_surface_at(c->surface.xdg, cx, cy, sx, sy); } -static inline void -client_restack_surface(Client *c) +static inline int +client_wants_fullscreen(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) - wlr_xwayland_surface_restack(c->surface.xwayland, NULL, - XCB_STACK_MODE_ABOVE); + return c->surface.xwayland->fullscreen; #endif - return; + return c->surface.xdg->toplevel->requested.fullscreen; } static inline void * From d738573e22649dfb01f70eca00cef221839c9efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 27 Aug 2022 16:05:12 -0500 Subject: [PATCH 02/45] new function to notify keyboard enter --- client.h | 10 ++++++++++ dwl.c | 15 ++------------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/client.h b/client.h index 5988db3..a881131 100644 --- a/client.h +++ b/client.h @@ -198,6 +198,16 @@ client_is_unmanaged(Client *c) return 0; } +static inline void +client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb) +{ + if (kb) + wlr_seat_keyboard_notify_enter(seat, s, kb->keycodes, + kb->num_keycodes, &kb->modifiers); + else + wlr_seat_keyboard_notify_enter(seat, s, NULL, 0, NULL); +} + static inline void client_restack_surface(Client *c) { diff --git a/dwl.c b/dwl.c index f76e30f..66aea65 100644 --- a/dwl.c +++ b/dwl.c @@ -590,7 +590,6 @@ arrangelayers(Monitor *m) ZWLR_LAYER_SHELL_V1_LAYER_TOP, }; LayerSurface *layersurface; - struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat); /* Arrange exclusive surfaces from top->bottom */ for (i = 3; i >= 0; i--) @@ -614,11 +613,7 @@ arrangelayers(Monitor *m) /* Deactivate the focused client. */ focusclient(NULL, 0); exclusive_focus = layersurface->layer_surface->surface; - if (kb) - wlr_seat_keyboard_notify_enter(seat, exclusive_focus, - kb->keycodes, kb->num_keycodes, &kb->modifiers); - else - wlr_seat_keyboard_notify_enter(seat, exclusive_focus, NULL, 0, NULL); + client_notify_enter(exclusive_focus, wlr_seat_get_keyboard(seat)); return; } } @@ -1117,7 +1112,6 @@ void focusclient(Client *c, int lift) { struct wlr_surface *old = seat->keyboard_state.focused_surface; - struct wlr_keyboard *kb; int i; /* Do not focus clients if a layer surface is focused */ if (exclusive_focus) @@ -1178,12 +1172,7 @@ focusclient(Client *c, int lift) } /* Have a client, so focus its top-level wlr_surface */ - kb = wlr_seat_get_keyboard(seat); - if (kb) - wlr_seat_keyboard_notify_enter(seat, client_surface(c), - kb->keycodes, kb->num_keycodes, &kb->modifiers); - else - wlr_seat_keyboard_notify_enter(seat, client_surface(c), NULL, 0, NULL); + client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat)); /* Activate the new client */ client_activate_surface(client_surface(c), 1); From 0e993b5fb1820189b78bed9fc2eb642230b47a58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 12 Aug 2022 23:47:34 -0500 Subject: [PATCH 03/45] conform the idle inhibitor protocol previously we disable idle tracking simply due to the fact that it exist --- dwl.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index 66aea65..a3b13b6 100644 --- a/dwl.c +++ b/dwl.c @@ -216,6 +216,7 @@ static void arrangelayers(Monitor *m); static void axisnotify(struct wl_listener *listener, void *data); 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); @@ -687,6 +688,25 @@ chvt(const Arg *arg) wlr_session_change_vt(wlr_backend_get_session(backend), arg->ui); } +void +checkidleinhibitor(struct wlr_surface *exclude) +{ + Client *c, *w; + int inhibited = 0; + struct wlr_idle_inhibitor_v1 *inhibitor; + wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { + c = client_from_wlr_surface(inhibitor->surface); + if (exclude && (!(w = client_from_wlr_surface(exclude)) || w == c)) + continue; + if (!c || VISIBLEON(c, c->mon)) { + inhibited = 1; + break; + } + } + + wlr_idle_set_enabled(idle, NULL, !inhibited); +} + void cleanup(void) { @@ -809,7 +829,7 @@ 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); - wlr_idle_set_enabled(idle, seat, 0); + checkidleinhibitor(NULL); } void @@ -1040,9 +1060,9 @@ cursorframe(struct wl_listener *listener, void *data) void destroyidleinhibitor(struct wl_listener *listener, void *data) { - /* I've been testing and at this point the inhibitor has not yet been - * removed from the list, checking if it has at least one item. */ - wlr_idle_set_enabled(idle, seat, wl_list_length(&idle_inhibit_mgr->inhibitors) <= 1); + /* `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(data); } void @@ -1163,7 +1183,7 @@ focusclient(Client *c, int lift) } printstatus(); - wlr_idle_set_enabled(idle, seat, wl_list_empty(&idle_inhibit_mgr->inhibitors)); + checkidleinhibitor(NULL); if (!c) { /* With no client, all we have left is to clear focus */ From 226051974060746d02d787ac1ef70b6267ee51b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 24 Jul 2022 17:18:44 -0500 Subject: [PATCH 04/45] various improvements to layer surface - remove various useless assignments of layersurface->mon - styles changes - do not set wlr_layer_surface->output to NULL at destroy --- dwl.c | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/dwl.c b/dwl.c index a3b13b6..8556cba 100644 --- a/dwl.c +++ b/dwl.c @@ -783,25 +783,23 @@ 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; - if (!wlr_output || !(layersurface->mon = wlr_output->data)) + if (!layersurface->mon) return; - wlr_scene_node_reparent(layersurface->scene, - layers[wlr_layer_surface->current.layer]); + if (layers[wlr_layer_surface->current.layer] != layersurface->scene) { + wlr_scene_node_reparent(layersurface->scene, + layers[wlr_layer_surface->current.layer]); + wl_list_remove(&layersurface->link); + wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->current.layer], + &layersurface->link); + } if (wlr_layer_surface->current.committed == 0 && layersurface->mapped == wlr_layer_surface->mapped) return; - layersurface->mapped = wlr_layer_surface->mapped; - if (layers[wlr_layer_surface->current.layer] != layersurface->scene) { - wl_list_remove(&layersurface->link); - wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->current.layer], - &layersurface->link); - } arrangelayers(layersurface->mon); } @@ -868,14 +866,13 @@ createlayersurface(struct wl_listener *listener, void *data) LayerSurface *layersurface; struct wlr_layer_surface_v1_state old_state; - if (!wlr_layer_surface->output) { + if (!wlr_layer_surface->output) wlr_layer_surface->output = selmon->wlr_output; - } layersurface = ecalloc(1, sizeof(LayerSurface)); layersurface->type = LayerShell; LISTEN(&wlr_layer_surface->surface->events.commit, - &layersurface->surface_commit, commitlayersurfacenotify); + &layersurface->surface_commit, commitlayersurfacenotify); LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy, destroylayersurfacenotify); LISTEN(&wlr_layer_surface->events.map, &layersurface->map, @@ -884,8 +881,8 @@ createlayersurface(struct wl_listener *listener, void *data) unmaplayersurfacenotify); layersurface->layer_surface = wlr_layer_surface; - wlr_layer_surface->data = layersurface; layersurface->mon = wlr_layer_surface->output->data; + wlr_layer_surface->data = layersurface; layersurface->scene = wlr_layer_surface->surface->data = wlr_scene_subsurface_tree_create(layers[wlr_layer_surface->pending.layer], @@ -1076,11 +1073,8 @@ 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); - if (layersurface->layer_surface->output) { - if ((layersurface->mon = layersurface->layer_surface->output->data)) - arrangelayers(layersurface->mon); - layersurface->layer_surface->output = NULL; - } + if (layersurface->mon) + arrangelayers(layersurface->mon); free(layersurface); } @@ -1380,10 +1374,8 @@ killclient(const Arg *arg) void maplayersurfacenotify(struct wl_listener *listener, void *data) { - LayerSurface *layersurface = wl_container_of(listener, layersurface, map); - layersurface->mon = layersurface->layer_surface->output->data; - wlr_surface_send_enter(layersurface->layer_surface->surface, - layersurface->mon->wlr_output); + LayerSurface *l = wl_container_of(listener, l, map); + wlr_surface_send_enter(l->layer_surface->surface, l->mon->wlr_output); motionnotify(0); } From c017916d35795cf85e5181907f5e97a1d702612a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 31 Aug 2022 16:05:19 -0500 Subject: [PATCH 05/45] Revert "various improvements to layer surface" see https://github.com/djpohly/dwl/issues/289#issuecomment-1231287114 This reverts commit 226051974060746d02d787ac1ef70b6267ee51b4. --- dwl.c | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/dwl.c b/dwl.c index 8556cba..a3b13b6 100644 --- a/dwl.c +++ b/dwl.c @@ -783,23 +783,25 @@ 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; - if (!layersurface->mon) + if (!wlr_output || !(layersurface->mon = wlr_output->data)) return; - if (layers[wlr_layer_surface->current.layer] != layersurface->scene) { - wlr_scene_node_reparent(layersurface->scene, - layers[wlr_layer_surface->current.layer]); - wl_list_remove(&layersurface->link); - wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->current.layer], - &layersurface->link); - } + wlr_scene_node_reparent(layersurface->scene, + layers[wlr_layer_surface->current.layer]); if (wlr_layer_surface->current.committed == 0 && layersurface->mapped == wlr_layer_surface->mapped) return; + layersurface->mapped = wlr_layer_surface->mapped; + if (layers[wlr_layer_surface->current.layer] != layersurface->scene) { + wl_list_remove(&layersurface->link); + wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->current.layer], + &layersurface->link); + } arrangelayers(layersurface->mon); } @@ -866,13 +868,14 @@ createlayersurface(struct wl_listener *listener, void *data) LayerSurface *layersurface; struct wlr_layer_surface_v1_state old_state; - if (!wlr_layer_surface->output) + if (!wlr_layer_surface->output) { wlr_layer_surface->output = selmon->wlr_output; + } layersurface = ecalloc(1, sizeof(LayerSurface)); layersurface->type = LayerShell; LISTEN(&wlr_layer_surface->surface->events.commit, - &layersurface->surface_commit, commitlayersurfacenotify); + &layersurface->surface_commit, commitlayersurfacenotify); LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy, destroylayersurfacenotify); LISTEN(&wlr_layer_surface->events.map, &layersurface->map, @@ -881,8 +884,8 @@ createlayersurface(struct wl_listener *listener, void *data) unmaplayersurfacenotify); layersurface->layer_surface = wlr_layer_surface; - layersurface->mon = wlr_layer_surface->output->data; wlr_layer_surface->data = layersurface; + layersurface->mon = wlr_layer_surface->output->data; layersurface->scene = wlr_layer_surface->surface->data = wlr_scene_subsurface_tree_create(layers[wlr_layer_surface->pending.layer], @@ -1073,8 +1076,11 @@ 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); - if (layersurface->mon) - arrangelayers(layersurface->mon); + if (layersurface->layer_surface->output) { + if ((layersurface->mon = layersurface->layer_surface->output->data)) + arrangelayers(layersurface->mon); + layersurface->layer_surface->output = NULL; + } free(layersurface); } @@ -1374,8 +1380,10 @@ killclient(const Arg *arg) 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); + LayerSurface *layersurface = wl_container_of(listener, layersurface, map); + layersurface->mon = layersurface->layer_surface->output->data; + wlr_surface_send_enter(layersurface->layer_surface->surface, + layersurface->mon->wlr_output); motionnotify(0); } From 40b1c0b849ee48c428f7f901afcdc67d20f3cf7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 2 Sep 2022 16:54:53 -0500 Subject: [PATCH 06/45] Revert "Revert "various improvements to layer surface"" This reverts commit c017916d35795cf85e5181907f5e97a1d702612a. --- dwl.c | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/dwl.c b/dwl.c index a3b13b6..8556cba 100644 --- a/dwl.c +++ b/dwl.c @@ -783,25 +783,23 @@ 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; - if (!wlr_output || !(layersurface->mon = wlr_output->data)) + if (!layersurface->mon) return; - wlr_scene_node_reparent(layersurface->scene, - layers[wlr_layer_surface->current.layer]); + if (layers[wlr_layer_surface->current.layer] != layersurface->scene) { + wlr_scene_node_reparent(layersurface->scene, + layers[wlr_layer_surface->current.layer]); + wl_list_remove(&layersurface->link); + wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->current.layer], + &layersurface->link); + } if (wlr_layer_surface->current.committed == 0 && layersurface->mapped == wlr_layer_surface->mapped) return; - layersurface->mapped = wlr_layer_surface->mapped; - if (layers[wlr_layer_surface->current.layer] != layersurface->scene) { - wl_list_remove(&layersurface->link); - wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->current.layer], - &layersurface->link); - } arrangelayers(layersurface->mon); } @@ -868,14 +866,13 @@ createlayersurface(struct wl_listener *listener, void *data) LayerSurface *layersurface; struct wlr_layer_surface_v1_state old_state; - if (!wlr_layer_surface->output) { + if (!wlr_layer_surface->output) wlr_layer_surface->output = selmon->wlr_output; - } layersurface = ecalloc(1, sizeof(LayerSurface)); layersurface->type = LayerShell; LISTEN(&wlr_layer_surface->surface->events.commit, - &layersurface->surface_commit, commitlayersurfacenotify); + &layersurface->surface_commit, commitlayersurfacenotify); LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy, destroylayersurfacenotify); LISTEN(&wlr_layer_surface->events.map, &layersurface->map, @@ -884,8 +881,8 @@ createlayersurface(struct wl_listener *listener, void *data) unmaplayersurfacenotify); layersurface->layer_surface = wlr_layer_surface; - wlr_layer_surface->data = layersurface; layersurface->mon = wlr_layer_surface->output->data; + wlr_layer_surface->data = layersurface; layersurface->scene = wlr_layer_surface->surface->data = wlr_scene_subsurface_tree_create(layers[wlr_layer_surface->pending.layer], @@ -1076,11 +1073,8 @@ 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); - if (layersurface->layer_surface->output) { - if ((layersurface->mon = layersurface->layer_surface->output->data)) - arrangelayers(layersurface->mon); - layersurface->layer_surface->output = NULL; - } + if (layersurface->mon) + arrangelayers(layersurface->mon); free(layersurface); } @@ -1380,10 +1374,8 @@ killclient(const Arg *arg) void maplayersurfacenotify(struct wl_listener *listener, void *data) { - LayerSurface *layersurface = wl_container_of(listener, layersurface, map); - layersurface->mon = layersurface->layer_surface->output->data; - wlr_surface_send_enter(layersurface->layer_surface->surface, - layersurface->mon->wlr_output); + LayerSurface *l = wl_container_of(listener, l, map); + wlr_surface_send_enter(l->layer_surface->surface, l->mon->wlr_output); motionnotify(0); } From 1f59b76d7726c83e8131609d806d5c78abb89356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 2 Sep 2022 17:29:41 -0500 Subject: [PATCH 07/45] prevent segfault when destroying monitors also don't count unmapped surfaces for exclusive zone and exclusive_focus is now of type `void *` --- dwl.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/dwl.c b/dwl.c index 8556cba..85db889 100644 --- a/dwl.c +++ b/dwl.c @@ -300,7 +300,7 @@ static void zoom(const Arg *arg); /* variables */ static const char broken[] = "broken"; static pid_t child_pid = -1; -static struct wlr_surface *exclusive_focus; +static void *exclusive_focus; static struct wl_display *dpy; static struct wlr_backend *backend; static struct wlr_scene *scene; @@ -522,7 +522,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; - if (exclusive != (state->exclusive_zone > 0)) + if (wlr_layer_surface->mapped && exclusive != (state->exclusive_zone > 0)) continue; bounds = state->exclusive_zone == -1 ? full_area : *usable_area; @@ -613,8 +613,8 @@ arrangelayers(Monitor *m) layersurface->layer_surface->mapped) { /* Deactivate the focused client. */ focusclient(NULL, 0); - exclusive_focus = layersurface->layer_surface->surface; - client_notify_enter(exclusive_focus, wlr_seat_get_keyboard(seat)); + exclusive_focus = layersurface; + client_notify_enter(layersurface->layer_surface->surface, wlr_seat_get_keyboard(seat)); return; } } @@ -749,6 +749,7 @@ cleanupmon(struct wl_listener *listener, void *data) wl_list_remove(&m->destroy.link); wl_list_remove(&m->frame.link); wl_list_remove(&m->link); + wlr_output->data = NULL; wlr_output_layout_remove(output_layout, m->wlr_output); wlr_scene_output_destroy(m->scene_output); @@ -783,8 +784,9 @@ 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; - if (!layersurface->mon) + if (!wlr_output || !(layersurface->mon = wlr_output->data)) return; if (layers[wlr_layer_surface->current.layer] != layersurface->scene) { @@ -1073,8 +1075,6 @@ 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); - if (layersurface->mon) - arrangelayers(layersurface->mon); free(layersurface); } @@ -2317,7 +2317,10 @@ unmaplayersurfacenotify(struct wl_listener *listener, void *data) layersurface->layer_surface->mapped = (layersurface->mapped = 0); wlr_scene_node_set_enabled(layersurface->scene, 0); - if (layersurface->layer_surface->surface == exclusive_focus) + if (layersurface->layer_surface->output + && (layersurface->mon = layersurface->layer_surface->output->data)) + arrangelayers(layersurface->mon); + if (layersurface == exclusive_focus) exclusive_focus = NULL; if (layersurface->layer_surface->surface == seat->keyboard_state.focused_surface) From 19a8a095ebe782065903b9a03670560371302206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 2 Sep 2022 18:22:15 -0500 Subject: [PATCH 08/45] call setfullscreen() in setmon() this will help when sending to another monitor a fullscreen client and also will prevent a crash when a client request fullscreen when it has no monitor --- dwl.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 85db889..f6db3c1 100644 --- a/dwl.c +++ b/dwl.c @@ -1438,9 +1438,6 @@ mapnotify(struct wl_listener *listener, void *data) } printstatus(); - if (c->isfullscreen) - setfullscreen(c, 1); - c->mon->un_map = 1; } @@ -1889,6 +1886,8 @@ void setfullscreen(Client *c, int fullscreen) { c->isfullscreen = fullscreen; + if (!c->mon) + return; c->bw = fullscreen ? 0 : borderpx; client_set_fullscreen(c, fullscreen); @@ -1968,7 +1967,7 @@ setmon(Client *c, Monitor *m, unsigned int newtags) 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 */ - arrange(m); + setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ } focusclient(focustop(selmon), 1); } From 68576799b96950dd36ed7c71ba0c4b1607a13cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 2 Sep 2022 18:49:20 -0500 Subject: [PATCH 09/45] don't arrange layers on disabled monitors --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index f6db3c1..669580a 100644 --- a/dwl.c +++ b/dwl.c @@ -591,6 +591,8 @@ arrangelayers(Monitor *m) ZWLR_LAYER_SHELL_V1_LAYER_TOP, }; LayerSurface *layersurface; + if (!m || !m->wlr_output->enabled) + return; /* Arrange exclusive surfaces from top->bottom */ for (i = 3; i >= 0; i--) From e91f71e8d6b6b29da69ec0cd8ad8f7dec2878df3 Mon Sep 17 00:00:00 2001 From: Dmitry Zakharchenko Date: Fri, 2 Sep 2022 19:57:35 +0300 Subject: [PATCH 10/45] Add direct irc link Also, move IRC section to the top so that it's more accessible. --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index 887bf29..6b12ab0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # dwl - dwm for Wayland -Join us on our [Discord server](https://discord.gg/jJxZnrGPWN)! +Join us on our [Discord server](https://discord.gg/jJxZnrGPWN) and at [#dwl](https://web.libera.chat/?channels=#dwl) on irc.libera.chat. dwl is a compact, hackable compositor for Wayland based on [wlroots](https://gitlab.freedesktop.org/wlroots/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. Like dwm, dwl is: @@ -85,10 +85,6 @@ Existing dwl-specific status bars and dwl-specific scripts for other status bars You can find a [list of Wayland applications on the sway wiki](https://github.com/swaywm/sway/wiki/i3-Migration-Guide). -## IRC channel - -dwl's IRC channel is #dwl on irc.libera.chat. - ## Acknowledgements dwl began by extending the TinyWL example provided (CC0) by the sway/wlroots 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. From a94d089c405c677ed4ae7e7c340bf52b49126d9c Mon Sep 17 00:00:00 2001 From: Dmitry Zakharchenko Date: Sun, 4 Sep 2022 12:00:00 +0300 Subject: [PATCH 11/45] Minor changes to README --- README.md | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 6b12ab0..f68290c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # dwl - dwm for Wayland -Join us on our [Discord server](https://discord.gg/jJxZnrGPWN) and at [#dwl](https://web.libera.chat/?channels=#dwl) on irc.libera.chat. +Join us on our [Discord server](https://discord.gg/jJxZnrGPWN) or at [#dwl](https://web.libera.chat/?channels=#dwl) on irc.libera.chat. dwl is a compact, hackable compositor for Wayland based on [wlroots](https://gitlab.freedesktop.org/wlroots/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. Like dwm, dwl is: @@ -73,17 +73,11 @@ If your startup command is a shell script, you can achieve the same inside the s exec <&- -Existing dwl-specific status bars and dwl-specific scripts for other status bars include: -- [somebar](https://sr.ht/~raphi/somebar/) status bar designed for dwl -- [dtaobarv2.sh](https://cdn.discordapp.com/attachments/792078050024095745/862428883423723560/dtaobarv2.sh) for use with [dtao](https://github.com/djpohly/dtao) (See "Pinned Messages" on the "customizations" channel of the [dwl Discord server](https://discord.gg/jJxZnrGPWN) for details.) -- [dwlbar.sh](https://cdn.discordapp.com/attachments/792078050024095745/810926218529472592/dwlbar.sh) for use with [waybar](https://github.com/Alexays/Waybar) (See "Pinned Messages" on the "customizations" channel of the [dwl Discord server](https://discord.gg/jJxZnrGPWN) for details.) -- [waybar-dwl](https://codeberg.org/fauxmight/waybar-dwl.git) for use with [waybar](https://github.com/Alexays/Waybar) -- [dwl-tags.sh](https://codeberg.org/novakane/yambar/src/branch/master/examples/scripts/dwl-tags.sh) for use with [yambar](https://codeberg.org/dnkl/yambar) -- [waybar-dwl.sh](https://gitee.com/guyuming76/personal/tree/dwl/gentoo/waybar-dwl) for use with [waybar](https://github.com/Alexays/Waybar) (ACCESS TO THIS SCRIPT REQUIRES gitee.com LOGIN!) +To get a list of status bars that work with dwl consult our [wiki](https://github.com/djpohly/dwl/wiki#compatible-status-bars). ## Replacements for X applications -You can find a [list of Wayland applications on the sway wiki](https://github.com/swaywm/sway/wiki/i3-Migration-Guide). +You can find a [list of useful resources on our wiki](https://github.com/djpohly/dwl/wiki#migrating-from-x). ## Acknowledgements From 14a1e3e2a2ced87d4f373c93c7caae48ccb02f27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 5 Sep 2022 16:30:23 -0500 Subject: [PATCH 12/45] set c->prev in mapnotify() Closes: #300 --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index 669580a..9a7b42e 100644 --- a/dwl.c +++ b/dwl.c @@ -1423,6 +1423,7 @@ mapnotify(struct wl_listener *listener, void *data) client_get_geometry(c, &c->geom); c->geom.width += 2 * c->bw; c->geom.height += 2 * c->bw; + c->prev = c->geom; /* Insert this client into client lists. */ wl_list_insert(&clients, &c->link); From 14c010a0d69eb8a528d63a311a94134a52cab8bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 6 Sep 2022 00:10:00 -0500 Subject: [PATCH 13/45] only enable/disable clients from the specified monitor in arrange() also fix a crash when m is null, this can only happen when selmon is NULL --- dwl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 9a7b42e..5ed534e 100644 --- a/dwl.c +++ b/dwl.c @@ -496,9 +496,10 @@ arrange(Monitor *m) { Client *c; wl_list_for_each(c, &clients, link) - wlr_scene_node_set_enabled(c->scene, VISIBLEON(c, c->mon)); + if (c->mon == m) + wlr_scene_node_set_enabled(c->scene, VISIBLEON(c, m)); - if (m->lt[m->sellt]->arrange) + if (m && m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); motionnotify(0); } From 1aacfada29657ec1104f856687400e65927e54b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 5 Sep 2022 22:48:16 -0500 Subject: [PATCH 14/45] set `c->prev` in setmon() and not in mapnotify() --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 5ed534e..41ce69f 100644 --- a/dwl.c +++ b/dwl.c @@ -1424,7 +1424,6 @@ mapnotify(struct wl_listener *listener, void *data) client_get_geometry(c, &c->geom); c->geom.width += 2 * c->bw; c->geom.height += 2 * c->bw; - c->prev = c->geom; /* Insert this client into client lists. */ wl_list_insert(&clients, &c->link); @@ -1960,6 +1959,7 @@ setmon(Client *c, Monitor *m, unsigned int newtags) if (oldmon == m) return; c->mon = m; + c->prev = c->geom; /* TODO leave/enter is not optimal but works */ if (oldmon) { From 80084839a9d9a3aaed323a267bbd2f061f37c8f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 7 Sep 2022 23:24:50 -0500 Subject: [PATCH 15/45] remove obsolete check of c->mon in fullscreennotify() since 19a8a095ebe782065903b9a03670560371302206 it's checked in setfullscreen() --- dwl.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/dwl.c b/dwl.c index 41ce69f..753ee40 100644 --- a/dwl.c +++ b/dwl.c @@ -1246,14 +1246,7 @@ void fullscreennotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, fullscreen); - int fullscreen = client_wants_fullscreen(c); - - if (!c->mon) { - /* if the client is not mapped yet, let mapnotify() call setfullscreen() */ - c->isfullscreen = fullscreen; - return; - } - setfullscreen(c, fullscreen); + setfullscreen(c, client_wants_fullscreen(c)); } void From d1496a2a9b4a336ea08f0ed3eae7fa3f155989b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 7 Sep 2022 23:54:57 -0500 Subject: [PATCH 16/45] fix condition that always evaluate to false in commitlayersurfacenotify() --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 753ee40..58dc4db 100644 --- a/dwl.c +++ b/dwl.c @@ -792,7 +792,7 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) if (!wlr_output || !(layersurface->mon = wlr_output->data)) return; - if (layers[wlr_layer_surface->current.layer] != layersurface->scene) { + if (layers[wlr_layer_surface->current.layer] != layersurface->scene->parent) { wlr_scene_node_reparent(layersurface->scene, layers[wlr_layer_surface->current.layer]); wl_list_remove(&layersurface->link); From 871463c32740d601241123770a65fea0d737fb54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 8 Sep 2022 00:10:53 -0500 Subject: [PATCH 17/45] define _POSIX_C_SOURCE through CPPFLAGS like dwm --- Makefile | 2 +- dwl.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 1bdc7d6..4afd717 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ include config.mk # flags for compiling -DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -DVERSION=\"$(VERSION)\" +DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" # Wayland utils WAYLAND_PROTOCOLS = `pkg-config --variable=pkgdatadir wayland-protocols` diff --git a/dwl.c b/dwl.c index 58dc4db..530ee4e 100644 --- a/dwl.c +++ b/dwl.c @@ -1,7 +1,6 @@ /* * See LICENSE file for copyright and license details. */ -#define _POSIX_C_SOURCE 200809L #include #include #include From 303fc72b124721ef86d1340367a2d3474716c367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 8 Sep 2022 00:13:03 -0500 Subject: [PATCH 18/45] append `-dev` to $(_VERSION) (should have added it a long time ago) --- config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.mk b/config.mk index 4638d5f..55c7262 100644 --- a/config.mk +++ b/config.mk @@ -1,4 +1,4 @@ -_VERSION = 0.3.1 +_VERSION = 0.3.1-dev VERSION = `git describe --long --tags --dirty 2>/dev/null || echo $(_VERSION)` # paths From ae42e4390b4606527b9f98148f53ae3638d1bcea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 8 Sep 2022 00:25:26 -0500 Subject: [PATCH 19/45] update link to input-protocols --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f68290c..132fb32 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ dwl is not meant to provide every feature under the sun. Instead, like dwm, it s 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/12) +- 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) Feature *non-goals* for the main codebase include: From 9bcef3d040790b5f3064e33e149891120055a377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 8 Sep 2022 16:35:55 -0500 Subject: [PATCH 20/45] resize the fullscreen background when resize the client --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index 530ee4e..912a877 100644 --- a/dwl.c +++ b/dwl.c @@ -1780,6 +1780,8 @@ resize(Client *c, struct wlr_box geo, int interact) wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw); wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw); wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw); + if (c->fullscreen_bg) + wlr_scene_rect_set_size(c->fullscreen_bg, c->geom.width, c->geom.height); /* wlroots makes this a no-op if size hasn't changed */ c->resize = client_set_size(c, c->geom.width - 2 * c->bw, From 1bb9c4583a4e5b0975ed9b57e994f1d958f04c73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 10 Sep 2022 18:41:39 -0500 Subject: [PATCH 21/45] fix exclusive zone of unmapped layer surfaces Fixes: https://github.com/djpohly/dwl/issues/302 --- dwl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 912a877..7c3855d 100644 --- a/dwl.c +++ b/dwl.c @@ -522,7 +522,8 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; - if (wlr_layer_surface->mapped && exclusive != (state->exclusive_zone > 0)) + if (!((LayerSurface *)wlr_layer_surface->data)->mapped + || exclusive != (state->exclusive_zone > 0)) continue; bounds = state->exclusive_zone == -1 ? full_area : *usable_area; @@ -901,6 +902,7 @@ createlayersurface(struct wl_listener *listener, void *data) */ 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; } @@ -2312,7 +2314,7 @@ unmaplayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *layersurface = wl_container_of(listener, layersurface, unmap); - layersurface->layer_surface->mapped = (layersurface->mapped = 0); + layersurface->mapped = 0; wlr_scene_node_set_enabled(layersurface->scene, 0); if (layersurface->layer_surface->output && (layersurface->mon = layersurface->layer_surface->output->data)) From f8f94c97f5d324c8876e88d0d82fd518eca25b1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 10 Sep 2022 22:11:06 -0500 Subject: [PATCH 22/45] fix idle inhibitor check previously we tried to get a client from the surface and then compare it with the excluded surface, if we cannot get a client from the surface (e.g: a layer surface) it just ignored all the next idle inhibitors no matter what What I have should done is just checking if the excluded surface is equal to the current idle inhibitor's surface and continue in case it is. --- dwl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 7c3855d..9420ae5 100644 --- a/dwl.c +++ b/dwl.c @@ -694,14 +694,14 @@ chvt(const Arg *arg) void checkidleinhibitor(struct wlr_surface *exclude) { - Client *c, *w; int inhibited = 0; struct wlr_idle_inhibitor_v1 *inhibitor; wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { - c = client_from_wlr_surface(inhibitor->surface); - if (exclude && (!(w = client_from_wlr_surface(exclude)) || w == c)) + Client *c; + if (exclude == inhibitor->surface) continue; - if (!c || VISIBLEON(c, c->mon)) { + if (!(c = client_from_wlr_surface(inhibitor->surface)) + || VISIBLEON(c, c->mon)) { inhibited = 1; break; } From 93de6e82a296aaf8aa15733e485fdd4ef34595d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 10 Sep 2022 22:25:46 -0500 Subject: [PATCH 23/45] inline input_device in virtualkeyboard() --- dwl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 9420ae5..27d5fae 100644 --- a/dwl.c +++ b/dwl.c @@ -2433,8 +2433,7 @@ void virtualkeyboard(struct wl_listener *listener, void *data) { struct wlr_virtual_keyboard_v1 *keyboard = data; - struct wlr_input_device *device = &keyboard->input_device; - createkeyboard(device); + createkeyboard(&keyboard->input_device); } Monitor * From c50904666334375f50e69e3c030d6a7a67bf8c87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 10 Sep 2022 23:42:58 -0500 Subject: [PATCH 24/45] add some comments --- dwl.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 27d5fae..24902bf 100644 --- a/dwl.c +++ b/dwl.c @@ -389,6 +389,8 @@ applybounds(Client *c, struct wlr_box *bbox) /* try to set size hints */ c->geom.width = MAX(min.width + (2 * c->bw), c->geom.width); c->geom.height = MAX(min.height + (2 * 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. */ 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 @@ -522,6 +524,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; + /* Unmapped surfaces shouldn't have exclusive zone */ if (!((LayerSurface *)wlr_layer_surface->data)->mapped || exclusive != (state->exclusive_zone > 0)) continue; @@ -631,6 +634,8 @@ axisnotify(struct wl_listener *listener, void *data) * for example when you move the scroll wheel. */ struct wlr_event_pointer_axis *event = data; wlr_idle_notify_activity(idle, 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. */ wlr_seat_pointer_notify_axis(seat, event->time_msec, event->orientation, event->delta, @@ -700,6 +705,8 @@ checkidleinhibitor(struct wlr_surface *exclude) Client *c; if (exclude == inhibitor->surface) continue; + /* In case we can't get a client from the surface assume that it is + * visible, for example a layer surface */ if (!(c = client_from_wlr_surface(inhibitor->surface)) || VISIBLEON(c, c->mon)) { inhibited = 1; @@ -789,6 +796,8 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; struct wlr_output *wlr_output = wlr_layer_surface->output; + /* 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; @@ -980,9 +989,14 @@ createnotify(struct wl_listener *listener, void *data) LayerSurface *l = toplevel_from_popup(xdg_surface->popup); xdg_surface->surface->data = wlr_scene_xdg_surface_create( xdg_surface->popup->parent->data, xdg_surface); + /* Raise to top layer if the inmediate parent of the popup is on + * bottom/background layer, which will cause popups appear below the + * x{dg,wayland} clients */ if (wlr_surface_is_layer_surface(xdg_surface->popup->parent) && l && l->layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) wlr_scene_node_reparent(xdg_surface->surface->data, layers[LyrTop]); + /* Probably the check of `l` is useless, the only thing that can be NULL + * is its monitor */ if (!l || !l->mon) return; box = l->type == LayerShell ? l->mon->m : l->mon->w; @@ -1158,9 +1172,7 @@ focusclient(Client *c, int lift) if (old && (!c || client_surface(c) != old)) { /* 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. - * It's probably pointless to check if old is a layer surface - * since it can't be anything else at this point. */ + * and focus it after the overlay is closed. */ if (wlr_surface_is_layer_surface(old)) { struct wlr_layer_surface_v1 *wlr_layer_surface = wlr_layer_surface_v1_from_wlr_surface(old); @@ -1233,6 +1245,9 @@ focusstack(const Arg *arg) focusclient(c, 1); } +/* We probably should change the name of this, it sounds like + * will focus the topmost client of this mon, when actually will + * only return that client */ Client * focustop(Monitor *m) { @@ -1398,14 +1413,17 @@ mapnotify(struct wl_listener *listener, void *data) } c->scene->data = c->scene_surface->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); - /* Floating */ + /* Unmanaged clients always are floating */ wlr_scene_node_reparent(c->scene, layers[LyrFloat]); wlr_scene_node_set_position(c->scene, c->geom.x + borderpx, c->geom.y + borderpx); return; } +#endif for (i = 0; i < 4; i++) { c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, bordercolor); @@ -1482,6 +1500,7 @@ 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); @@ -2533,6 +2552,7 @@ createnotifyx11(struct wl_listener *listener, void *data) { struct wlr_xwayland_surface *xwayland_surface = data; Client *c; + /* TODO: why we unset fullscreen when a xwayland client is created? */ wl_list_for_each(c, &clients, link) if (c->isfullscreen && VISIBLEON(c, c->mon)) setfullscreen(c, 0); From 77ba8e51276ce94515913091d669db21e856e8cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 10 Sep 2022 23:44:19 -0500 Subject: [PATCH 25/45] use wl_container_of() instead of data in some functions --- dwl.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index 24902bf..bcc0804 100644 --- a/dwl.c +++ b/dwl.c @@ -739,8 +739,7 @@ cleanup(void) void cleanupkeyboard(struct wl_listener *listener, void *data) { - struct wlr_input_device *device = data; - Keyboard *kb = device->data; + Keyboard *kb = wl_container_of(listener, kb, destroy); wl_list_remove(&kb->link); wl_list_remove(&kb->modifiers.link); @@ -752,14 +751,13 @@ cleanupkeyboard(struct wl_listener *listener, void *data) void cleanupmon(struct wl_listener *listener, void *data) { - struct wlr_output *wlr_output = data; - Monitor *m = wlr_output->data; + Monitor *m = wl_container_of(listener, m, destroy); int nmons, i = 0; wl_list_remove(&m->destroy.link); wl_list_remove(&m->frame.link); wl_list_remove(&m->link); - wlr_output->data = NULL; + m->wlr_output->data = NULL; wlr_output_layout_remove(output_layout, m->wlr_output); wlr_scene_output_destroy(m->scene_output); From fd67087a82d52f79cb3f02f9048ee4dd603fd8a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 10 Sep 2022 23:45:14 -0500 Subject: [PATCH 26/45] make sure the parent is mapped prior set monitor and tags --- dwl.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index bcc0804..be94832 100644 --- a/dwl.c +++ b/dwl.c @@ -1439,13 +1439,14 @@ mapnotify(struct wl_listener *listener, void *data) wl_list_insert(&clients, &c->link); wl_list_insert(&fstack, &c->flink); - /* Set initial monitor, tags, floating status, and focus */ - if ((p = client_get_parent(c))) { - /* Set the same monitor and tags than its parent */ + /* 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 */ + if ((p = client_get_parent(c)) && client_is_mapped(p)) { c->isfloating = 1; wlr_scene_node_reparent(c->scene, layers[LyrFloat]); - /* TODO recheck if !p->mon is possible with wlroots 0.16.0 */ - setmon(c, p->mon ? p->mon : selmon, p->tags); + setmon(c, p->mon, p->tags); } else { applyrules(c); } From c8a9f634515cbf5a943a982bb4b603682c0eca22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 10 Sep 2022 23:48:38 -0500 Subject: [PATCH 27/45] prior run the startup command start the backend this allow use clients like wlr-randr in the startup command --- dwl.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dwl.c b/dwl.c index be94832..09e60ec 100644 --- a/dwl.c +++ b/dwl.c @@ -1817,7 +1817,12 @@ run(char *startup_cmd) die("startup: display_add_socket_auto"); setenv("WAYLAND_DISPLAY", socket, 1); - /* Now that the socket exists, run the startup command */ + /* Start the backend. This will enumerate outputs and inputs, become the DRM + * master, etc */ + if (!wlr_backend_start(backend)) + die("startup: backend_start"); + + /* Now that the socket exists and the backend is started, run the startup command */ if (startup_cmd) { int piperw[2]; if (pipe(piperw) < 0) @@ -1839,12 +1844,7 @@ run(char *startup_cmd) signal(SIGPIPE, SIG_IGN); printstatus(); - /* Start the backend. This will enumerate outputs and inputs, become the DRM - * master, etc */ - if (!wlr_backend_start(backend)) - die("startup: backend_start"); - - /* Now that outputs are initialized, choose initial selmon based on + /* At this point the outputs are initialized, choose initial selmon based on * cursor position, and set default cursor image */ selmon = xytomon(cursor->x, cursor->y); From ba7dcb2dea2d5dc46b73b6b9194daab94a325a05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 10 Sep 2022 23:45:57 -0500 Subject: [PATCH 28/45] don't try to move outputs when its x,y hasn't change when using wlr_output_layout_move() wlroots internally change the state of the output to manually configured and when updating the layout these outputs aren't ignored by wlroots, leaving us at our own --- dwl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 09e60ec..8557540 100644 --- a/dwl.c +++ b/dwl.c @@ -1607,6 +1607,7 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) /* Then enable outputs that need to */ wl_list_for_each(config_head, &config->heads, link) { struct wlr_output *wlr_output = config_head->state.output; + Monitor *m = wlr_output->data; if (!config_head->state.enabled) continue; @@ -1619,8 +1620,11 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) config_head->state.custom_mode.height, config_head->state.custom_mode.refresh); - wlr_output_layout_move(output_layout, wlr_output, - config_head->state.x, config_head->state.y); + /* 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, + 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 bcc8ce7a40d30023eb97934419c2102c91846563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 18 Sep 2022 15:16:10 -0500 Subject: [PATCH 29/45] fix segfault when unlocking swaylock on two monitor setup wlr_*_surface_from_wlr_surface() can return NULL if the surface is being destroyed Fixes: https://github.com/djpohly/dwl/issues/305 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 8557540..4d8100d 100644 --- a/dwl.c +++ b/dwl.c @@ -1175,7 +1175,7 @@ focusclient(Client *c, int lift) struct wlr_layer_surface_v1 *wlr_layer_surface = wlr_layer_surface_v1_from_wlr_surface(old); - if (wlr_layer_surface->mapped && ( + if (wlr_layer_surface && wlr_layer_surface->mapped && ( wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP || wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY )) From bc72af6e2430cfb8db2f5fa1b9800c86f445b6d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 18 Sep 2022 15:20:00 -0500 Subject: [PATCH 30/45] fix unmanaged clients not being unlinked from the commit listener --- dwl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 4d8100d..8ed6ae3 100644 --- a/dwl.c +++ b/dwl.c @@ -2362,14 +2362,14 @@ unmapnotify(struct wl_listener *listener, void *data) if (c->mon) c->mon->un_map = 1; - if (client_is_unmanaged(c)) { - wlr_scene_node_destroy(c->scene); - return; - } + if (client_is_unmanaged(c)) + goto end; wl_list_remove(&c->link); setmon(c, NULL, 0); wl_list_remove(&c->flink); + +end: wl_list_remove(&c->commit.link); wlr_scene_node_destroy(c->scene); printstatus(); From cd96f889b8a254d4005d1f0cff71f8031d00ecd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 18 Sep 2022 15:21:19 -0500 Subject: [PATCH 31/45] fix use of loop initial declaration forbidden by the suckless style --- dwl.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index 8ed6ae3..30bafa9 100644 --- a/dwl.c +++ b/dwl.c @@ -412,6 +412,7 @@ applyexclusive(struct wlr_box *usable_area, uint32_t anchor, int32_t exclusive, int32_t margin_top, int32_t margin_right, int32_t margin_bottom, int32_t margin_left) { + size_t i; Edge edges[] = { { /* Top */ .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, @@ -450,7 +451,7 @@ applyexclusive(struct wlr_box *usable_area, .margin = margin_right, } }; - for (size_t i = 0; i < LENGTH(edges); i++) { + for (i = 0; i < LENGTH(edges); i++) { if ((anchor == edges[i].singular_anchor || anchor == edges[i].anchor_triplet) && exclusive + edges[i].margin > 0) { if (edges[i].positive_axis) @@ -612,7 +613,7 @@ arrangelayers(Monitor *m) arrangelayer(m, &m->layers[i], &usable_area, 0); /* Find topmost keyboard interactive layer, if such a layer exists */ - for (size_t i = 0; i < LENGTH(layers_above_shell); i++) { + for (i = 0; i < LENGTH(layers_above_shell); i++) { wl_list_for_each_reverse(layersurface, &m->layers[layers_above_shell[i]], link) { if (layersurface->layer_surface->current.keyboard_interactive && @@ -922,13 +923,14 @@ createmon(struct wl_listener *listener, void *data) struct wlr_output *wlr_output = data; const MonitorRule *r; Client *c; + size_t i; 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 (size_t i = 0; i < LENGTH(m->layers); i++) + for (i = 0; i < LENGTH(m->layers); i++) wl_list_init(&m->layers[i]); m->tagset[0] = m->tagset[1] = 1; for (r = monrules; r < END(monrules); r++) { From d14ee99661e420c8e3d8fcc6791429a0e08bd915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 18 Sep 2022 15:33:58 -0500 Subject: [PATCH 32/45] remove useless check of `m` in arrangelayers() it is supossed to avoid a crash when we pass m=NULL as argument however it would crash anyway and also because we should not pass m=NULL --- dwl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/dwl.c b/dwl.c index 30bafa9..798ba80 100644 --- a/dwl.c +++ b/dwl.c @@ -596,8 +596,6 @@ arrangelayers(Monitor *m) ZWLR_LAYER_SHELL_V1_LAYER_TOP, }; LayerSurface *layersurface; - if (!m || !m->wlr_output->enabled) - return; /* Arrange exclusive surfaces from top->bottom */ for (i = 3; i >= 0; i--) From 7710cf050d1a66f35fc590e0000bb300a707a5e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 18 Sep 2022 15:04:46 -0500 Subject: [PATCH 33/45] change the default term to `foot` it is closer to the suckless philosophy (foot implements things that the suckless guys would say that should be done by tmux or something else, but I have no desire to create a new terminal emulator, and the best fit is foot) also alacritty uses +100Mb of memory, more that dwl itself (~90Mb) and foot only ~20Mb --- config.def.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.def.h b/config.def.h index 29c6dbf..ec1f052 100644 --- a/config.def.h +++ b/config.def.h @@ -98,7 +98,7 @@ static const double accel_speed = 0.0; #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } /* commands */ -static const char *termcmd[] = { "alacritty", NULL }; +static const char *termcmd[] = { "foot", NULL }; static const char *menucmd[] = { "bemenu-run", NULL }; static const Key keys[] = { From a1b33826cfeb9a6764428c44cfba7d26089b40be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 18 Sep 2022 16:36:18 -0500 Subject: [PATCH 34/45] Revert "remove useless check of `m` in arrangelayers()" This partially reverts commit d14ee99661e420c8e3d8fcc6791429a0e08bd915. Checking if the output is enabled is necessary to avoid a segfault later --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index 798ba80..36d3327 100644 --- a/dwl.c +++ b/dwl.c @@ -596,6 +596,8 @@ arrangelayers(Monitor *m) ZWLR_LAYER_SHELL_V1_LAYER_TOP, }; LayerSurface *layersurface; + if (!m->wlr_output->enabled) + return; /* Arrange exclusive surfaces from top->bottom */ for (i = 3; i >= 0; i--) From 570e6e2c2763bc3a7bd270a9571cfedeb1083fef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 18 Sep 2022 16:50:29 -0500 Subject: [PATCH 35/45] fix clients not being focused after destroy a layer surface --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 36d3327..a64f4e7 100644 --- a/dwl.c +++ b/dwl.c @@ -2340,11 +2340,11 @@ unmaplayersurfacenotify(struct wl_listener *listener, void *data) layersurface->mapped = 0; wlr_scene_node_set_enabled(layersurface->scene, 0); + if (layersurface == exclusive_focus) + exclusive_focus = NULL; if (layersurface->layer_surface->output && (layersurface->mon = layersurface->layer_surface->output->data)) arrangelayers(layersurface->mon); - if (layersurface == exclusive_focus) - exclusive_focus = NULL; if (layersurface->layer_surface->surface == seat->keyboard_state.focused_surface) focusclient(selclient(), 1); From fbaeb853638a984c69045923eb662d783035762c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 18 Sep 2022 17:23:07 -0500 Subject: [PATCH 36/45] now really fix clients not being focused after unmapping a layer surface --- dwl.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index a64f4e7..c1fb9c1 100644 --- a/dwl.c +++ b/dwl.c @@ -617,7 +617,7 @@ arrangelayers(Monitor *m) wl_list_for_each_reverse(layersurface, &m->layers[layers_above_shell[i]], link) { if (layersurface->layer_surface->current.keyboard_interactive && - layersurface->layer_surface->mapped) { + layersurface->mapped) { /* Deactivate the focused client. */ focusclient(NULL, 0); exclusive_focus = layersurface; @@ -1177,10 +1177,9 @@ focusclient(Client *c, int lift) struct wlr_layer_surface_v1 *wlr_layer_surface = wlr_layer_surface_v1_from_wlr_surface(old); - if (wlr_layer_surface && wlr_layer_surface->mapped && ( - wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP || - wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY - )) + if (wlr_layer_surface && ((LayerSurface *)wlr_layer_surface->data)->mapped + && (wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP + || wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY)) return; } else { Client *w; From 1fdc65ff930a326c92b58129970026daec400862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 18 Sep 2022 17:25:12 -0500 Subject: [PATCH 37/45] make more permissive exclusive focus now you can call focusstack() while a layer surface is focused and when it gets unmapped the newly focused clients will be actually focused --- dwl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index c1fb9c1..270f8f0 100644 --- a/dwl.c +++ b/dwl.c @@ -1145,9 +1145,6 @@ focusclient(Client *c, int lift) { struct wlr_surface *old = seat->keyboard_state.focused_surface; int i; - /* Do not focus clients if a layer surface is focused */ - if (exclusive_focus) - return; /* Raise client in stacking order if requested */ if (c && lift) @@ -1164,8 +1161,11 @@ focusclient(Client *c, int lift) c->isurgent = 0; client_restack_surface(c); - for (i = 0; i < 4; i++) - wlr_scene_rect_set_color(c->border[i], focuscolor); + /* Don't change border color if there is a exclusive focus + * (at this moment it means that a layer surface is focused) */ + if (!exclusive_focus) + for (i = 0; i < 4; i++) + wlr_scene_rect_set_color(c->border[i], focuscolor); } /* Deactivate old client if focus is changing */ From 31106eff64406a004beb18c265a8b6fa0ae4f7a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 20 Sep 2022 23:34:48 -0500 Subject: [PATCH 38/45] rework Makefile - allow user to use a different pkg-config binary - restore almost all (and add other ones) warning flags (-Werror is not set) - $(XWAYLAND) is added to our CPPFLAGS - remove useless comments - don't generate idle-protocol.h (not used) --- Makefile | 31 +++++++++++-------------------- config.mk | 5 ++--- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index 4afd717..6605796 100644 --- a/Makefile +++ b/Makefile @@ -4,45 +4,38 @@ include config.mk # flags for compiling -DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" - -# Wayland utils -WAYLAND_PROTOCOLS = `pkg-config --variable=pkgdatadir wayland-protocols` -WAYLAND_SCANNER = `pkg-config --variable=wayland_scanner wayland-scanner` +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 # CFLAGS / LDFLAGS PKGS = wlroots wayland-server xkbcommon libinput $(XLIBS) -DWLCFLAGS = `pkg-config --cflags $(PKGS)` $(DWLCPPFLAGS) $(CFLAGS) $(XWAYLAND) -LDLIBS = `pkg-config --libs $(PKGS)` $(LIBS) +DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS) +LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(LIBS) -# build rules +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 +util.o: util.c util.h # wayland-scanner is a tool which generates C headers and rigging for Wayland # protocols, which are specified in XML. wlroots requires you to rig these up # to your build system yourself and provide them in the include path. -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 idle-protocol.h -util.o: util.c util.h +WAYLAND_SCANNER = `$(PKG_CONFIG) --variable=wayland_scanner wayland-scanner` +WAYLAND_PROTOCOLS = `$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols` -# wayland scanner rules to generate .h / .c files 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 $@ -idle-protocol.h: - $(WAYLAND_SCANNER) server-header \ - protocols/idle.xml $@ config.h: cp config.def.h $@ clean: rm -f dwl *.o *-protocol.h -# distribution archive dist: clean mkdir -p dwl-$(VERSION) cp -R LICENSE* Makefile README.md client.h config.def.h\ @@ -51,8 +44,6 @@ dist: clean tar -caf dwl-$(VERSION).tar.gz dwl-$(VERSION) rm -rf dwl-$(VERSION) -# install rules - install: dwl mkdir -p $(DESTDIR)$(PREFIX)/bin cp -f dwl $(DESTDIR)$(PREFIX)/bin diff --git a/config.mk b/config.mk index 55c7262..091c03a 100644 --- a/config.mk +++ b/config.mk @@ -1,13 +1,12 @@ _VERSION = 0.3.1-dev VERSION = `git describe --long --tags --dirty 2>/dev/null || echo $(_VERSION)` +PKG_CONFIG = pkg-config + # paths PREFIX = /usr/local MANDIR = $(PREFIX)/share/man -# Compile flags that can be used -#CFLAGS = -pedantic -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-unused-function -Wno-unused-variable -Wno-unused-result -Wdeclaration-after-statement - XWAYLAND = XLIBS = # Uncomment to build XWayland support From 2385d826122d24b72cab2ce531ad538d87407622 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 20 Sep 2022 23:40:35 -0500 Subject: [PATCH 39/45] remove unused variables --- client.h | 2 -- dwl.c | 1 - 2 files changed, 3 deletions(-) diff --git a/client.h b/client.h index a881131..4ecdd47 100644 --- a/client.h +++ b/client.h @@ -20,7 +20,6 @@ static inline Client * client_from_wlr_surface(struct wlr_surface *s) { struct wlr_xdg_surface *surface; - struct wlr_surface *parent; #ifdef XWAYLAND struct wlr_xwayland_surface *xsurface; @@ -41,7 +40,6 @@ client_from_wlr_surface(struct wlr_surface *s) static inline Client * client_get_parent(Client *c) { - Client *p; #ifdef XWAYLAND if (client_is_x11(c) && c->surface.xwayland->parent) return client_from_wlr_surface(c->surface.xwayland->parent->surface); diff --git a/dwl.c b/dwl.c index 270f8f0..6fbc771 100644 --- a/dwl.c +++ b/dwl.c @@ -922,7 +922,6 @@ createmon(struct wl_listener *listener, void *data) * monitor) becomes available. */ struct wlr_output *wlr_output = data; const MonitorRule *r; - Client *c; size_t i; Monitor *m = wlr_output->data = ecalloc(1, sizeof(*m)); m->wlr_output = wlr_output; From e46238b95ee3e74ee7a54e592276e8b1be2f0ea0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 22 Sep 2022 14:36:53 -0500 Subject: [PATCH 40/45] change cursor surface in internal calls of motionnotify() and call motionnotify() after unmapping a client and when focusing a client Fixes: https://github.com/djpohly/dwl/issues/308 --- dwl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 6fbc771..3538cf3 100644 --- a/dwl.c +++ b/dwl.c @@ -1199,6 +1199,9 @@ focusclient(Client *c, int lift) return; } + /* Change cursor surface */ + motionnotify(0); + /* Have a client, so focus its top-level wlr_surface */ client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat)); @@ -1521,7 +1524,7 @@ 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 && time) + if (!surface) wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor); pointerfocus(c, surface, sx, sy, time); @@ -2373,6 +2376,7 @@ end: wl_list_remove(&c->commit.link); wlr_scene_node_destroy(c->scene); printstatus(); + motionnotify(0); } void From c00faae26370682c307cfb107b12123d10d49053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 7 Sep 2022 23:04:18 -0500 Subject: [PATCH 41/45] fix various segfaults when selmon is NULL --- dwl.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/dwl.c b/dwl.c index 3538cf3..0bb551e 100644 --- a/dwl.c +++ b/dwl.c @@ -880,7 +880,10 @@ createlayersurface(struct wl_listener *listener, void *data) struct wlr_layer_surface_v1_state old_state; if (!wlr_layer_surface->output) - wlr_layer_surface->output = selmon->wlr_output; + wlr_layer_surface->output = selmon ? selmon->wlr_output : NULL; + + if (!wlr_layer_surface->output) + wlr_layer_surface_v1_destroy(wlr_layer_surface); layersurface = ecalloc(1, sizeof(LayerSurface)); layersurface->type = LayerShell; @@ -1269,6 +1272,8 @@ fullscreennotify(struct wl_listener *listener, void *data) void incnmaster(const Arg *arg) { + if (!arg || !selmon) + return; selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); arrange(selmon); } @@ -1948,6 +1953,8 @@ setfullscreen(Client *c, int fullscreen) void setlayout(const Arg *arg) { + if (!selmon) + return; if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) selmon->sellt ^= 1; if (arg && arg->v) @@ -1963,7 +1970,7 @@ setmfact(const Arg *arg) { float f; - if (!arg || !selmon->lt[selmon->sellt]->arrange) + if (!arg || !selmon || !selmon->lt[selmon->sellt]->arrange) return; f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; if (f < 0.1 || f > 0.9) @@ -2250,9 +2257,8 @@ void tagmon(const Arg *arg) { Client *sel = selclient(); - if (!sel) - return; - setmon(sel, dirtomon(arg->i), 0); + if (sel) + setmon(sel, dirtomon(arg->i), 0); } void @@ -2324,7 +2330,7 @@ toggletag(const Arg *arg) void toggleview(const Arg *arg) { - unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + unsigned int newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0; if (newtagset) { selmon->tagset[selmon->seltags] = newtagset; @@ -2445,7 +2451,7 @@ urgent(struct wl_listener *listener, void *data) void view(const Arg *arg) { - if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + if (selmon && (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) return; selmon->seltags ^= 1; /* toggle sel tagset */ if (arg->ui & TAGMASK) @@ -2507,7 +2513,7 @@ zoom(const Arg *arg) { Client *c, *sel = selclient(); - if (!sel || !selmon->lt[selmon->sellt]->arrange || sel->isfloating) + if (!sel || !selmon || !selmon->lt[selmon->sellt]->arrange || sel->isfloating) return; /* Search for the first tiled window that is not sel, marking sel as From fc8b2a8335365dbf3966f0a9bb783a4cb33fdcbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 26 Sep 2022 20:31:36 -0500 Subject: [PATCH 42/45] fix bad condition --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 0bb551e..cc08787 100644 --- a/dwl.c +++ b/dwl.c @@ -2451,7 +2451,7 @@ urgent(struct wl_listener *listener, void *data) void view(const Arg *arg) { - if (selmon && (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + if (!selmon || (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) return; selmon->seltags ^= 1; /* toggle sel tagset */ if (arg->ui & TAGMASK) From c13d948ea90fa55fb5b3180f2aa0ee4114ef6df0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 28 Sep 2022 14:15:25 -0500 Subject: [PATCH 43/45] destroy renderer and allocator in cleanup() --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index cc08787..e7571fe 100644 --- a/dwl.c +++ b/dwl.c @@ -730,6 +730,8 @@ cleanup(void) waitpid(child_pid, NULL, 0); } wlr_backend_destroy(backend); + wlr_renderer_destroy(drw); + wlr_allocator_destroy(alloc); wlr_xcursor_manager_destroy(cursor_mgr); wlr_cursor_destroy(cursor); wlr_output_layout_destroy(output_layout); From b5776e5180010ead5232efb36b2490f4fc9e1366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 28 Sep 2022 16:20:31 -0500 Subject: [PATCH 44/45] avoid setting duplicate cursor image Reference: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3436 Based on: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3595 --- dwl.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/dwl.c b/dwl.c index e7571fe..339ebe5 100644 --- a/dwl.c +++ b/dwl.c @@ -298,6 +298,7 @@ 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 void *exclusive_focus; static struct wl_display *dpy; @@ -674,10 +675,13 @@ 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 (cursor_mode != CurNormal) { - 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); @@ -1531,8 +1535,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) - wlr_xcursor_manager_set_cursor_image(cursor_mgr, "left_ptr", cursor); + if (!surface && (!cursor_image || strcmp(cursor_image, "left_ptr"))) + wlr_xcursor_manager_set_cursor_image(cursor_mgr, (cursor_image = "left_ptr"), cursor); pointerfocus(c, surface, sx, sy, time); } @@ -1567,7 +1571,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_xcursor_manager_set_cursor_image(cursor_mgr, (cursor_image = "fleur"), cursor); break; case CurResize: /* Doesn't work for X11 output - the next absolute motion event @@ -1576,7 +1580,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, - "bottom_right_corner", cursor); + (cursor_image = "bottom_right_corner"), cursor); break; } } @@ -1702,7 +1706,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 @@ -1867,7 +1870,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_xcursor_manager_set_cursor_image(cursor_mgr, cursor_image, 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 @@ -1890,10 +1893,12 @@ setcursor(struct wl_listener *listener, void *data) { /* This event is raised by the seat when a client provides a cursor image */ struct wlr_seat_pointer_request_set_cursor_event *event = data; - /* If we're "grabbing" the cursor, don't use the client's image */ - /* TODO still need to save the provided surface to restore later */ + /* If we're "grabbing" the cursor, don't use the client's image, we will + * restore it after "grabbing" sending a leave event, followed by a enter + * event, which will result in the client requesting set the cursor surface */ if (cursor_mode != CurNormal) 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 b8bc54b65d7dfaf1c7aa92de32f8ca37d8e011f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 28 Sep 2022 18:29:59 -0500 Subject: [PATCH 45/45] properly handle cursor motion when button is held Based on: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3653 --- dwl.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 339ebe5..b4fa1ef 100644 --- a/dwl.c +++ b/dwl.c @@ -66,7 +66,7 @@ #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) /* enums */ -enum { CurNormal, CurMove, CurResize }; /* cursor */ +enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ enum { XDGShell, LayerShell, X11Managed, X11Unmanaged }; /* client types */ enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrNoFocus, NUM_LAYERS }; /* scene layers */ #ifdef XWAYLAND @@ -672,10 +672,11 @@ buttonpress(struct wl_listener *listener, void *data) return; } } + cursor_mode = CurPressed; break; case WLR_BUTTON_RELEASED: /* If you released any buttons, we exit interactive move/resize mode. */ - if (cursor_mode != CurNormal) { + if (cursor_mode != CurNormal && cursor_mode != CurPressed) { 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 @@ -686,6 +687,8 @@ buttonpress(struct wl_listener *listener, void *data) selmon = xytomon(cursor->x, cursor->y); setmon(grabc, selmon, 0); return; + } else { + cursor_mode = CurNormal; } break; } @@ -1532,6 +1535,13 @@ 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) { + surface = seat->pointer_state.focused_surface; + c = client_from_wlr_surface(surface); + sx = c ? cursor->x - c->geom.x : 0; + sy = c ? cursor->y - c->geom.y : 0; + } + /* 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. */