From 3300f6c9114885160706e1599801b5000de1dd31 Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Tue, 18 Jan 2022 11:33:56 -0600 Subject: [PATCH 001/312] Upgrade for wlroots surface refactoring See [1] for details. [1]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3412 --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index 8683462..5020a78 100644 --- a/dwl.c +++ b/dwl.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -2029,6 +2030,7 @@ setup(void) wlr_gamma_control_manager_v1_create(dpy); wlr_primary_selection_v1_device_manager_create(dpy); wlr_viewporter_create(dpy); + wlr_subcompositor_create(dpy); /* Initializes the interface used to implement urgency hints */ activation = wlr_xdg_activation_v1_create(dpy); From ed44bc0c9069e0b55a4765bca10a5ad87732f019 Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Wed, 2 Feb 2022 23:18:58 -0600 Subject: [PATCH 002/312] update wlr-output-layout-get-box --- dwl.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index 8683462..ab34d56 100644 --- a/dwl.c +++ b/dwl.c @@ -863,7 +863,7 @@ createmon(struct wl_listener *listener, void *data) * output (such as DPI, scale factor, manufacturer, etc). */ wlr_output_layout_add(output_layout, wlr_output, r->x, r->y); - sgeom = *wlr_output_layout_get_box(output_layout, NULL); + wlr_output_layout_get_box(output_layout, NULL, &sgeom); /* When adding monitors, the geometries of all monitors must be updated */ wl_list_for_each(m, &mons, link) { @@ -2305,7 +2305,7 @@ updatemons(struct wl_listener *listener, void *data) struct wlr_output_configuration_v1 *config = wlr_output_configuration_v1_create(); Monitor *m; - sgeom = *wlr_output_layout_get_box(output_layout, NULL); + wlr_output_layout_get_box(output_layout, NULL, &sgeom); wl_list_for_each(m, &mons, link) { struct wlr_output_configuration_head_v1 *config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output); @@ -2314,7 +2314,8 @@ updatemons(struct wl_listener *listener, void *data) /* TODO: move focus if selmon is disabled */ /* Get the effective monitor geometry to use for surfaces */ - m->m = m->w = *wlr_output_layout_get_box(output_layout, m->wlr_output); + wlr_output_layout_get_box(output_layout, m->wlr_output, &(m->m)); + wlr_output_layout_get_box(output_layout, m->wlr_output, &(m->w)); /* Calculate the effective monitor geometry to use for clients */ arrangelayers(m); /* Don't move clients to the left output when plugging monitors */ From b8ce8d0fbb7cd1ad09ea15ded4a19dc1346e9bcd Mon Sep 17 00:00:00 2001 From: A Frederick Christensen Date: Thu, 3 Feb 2022 21:54:44 -0600 Subject: [PATCH 003/312] Account for changes expecting wlr_xdg_toplevel rather than wlr_xdg_surface --- client.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/client.h b/client.h index 4fd1863..ce41c1c 100644 --- a/client.h +++ b/client.h @@ -39,7 +39,7 @@ client_activate_surface(struct wlr_surface *s, int activated) #endif if (wlr_surface_is_xdg_surface(s)) wlr_xdg_toplevel_set_activated( - wlr_xdg_surface_from_wlr_surface(s), activated); + wlr_xdg_surface_from_wlr_surface(s)->toplevel, activated); } static inline void @@ -121,7 +121,7 @@ client_send_close(Client *c) return; } #endif - wlr_xdg_toplevel_send_close(c->surface.xdg); + wlr_xdg_toplevel_send_close(c->surface.xdg->toplevel); } static inline void @@ -133,7 +133,7 @@ client_set_fullscreen(Client *c, int fullscreen) return; } #endif - wlr_xdg_toplevel_set_fullscreen(c->surface.xdg, fullscreen); + wlr_xdg_toplevel_set_fullscreen(c->surface.xdg->toplevel, fullscreen); } static inline uint32_t @@ -146,7 +146,7 @@ client_set_size(Client *c, uint32_t width, uint32_t height) return 0; } #endif - return wlr_xdg_toplevel_set_size(c->surface.xdg, width, height); + return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, width, height); } static inline void @@ -156,7 +156,7 @@ client_set_tiled(Client *c, uint32_t edges) if (client_is_x11(c)) return; #endif - wlr_xdg_toplevel_set_tiled(c->surface.xdg, WLR_EDGE_TOP | + wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); } From 230d3432e9633da09a31ed933d8bcaff491db807 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 5 Mar 2022 21:07:25 -0600 Subject: [PATCH 004/312] wlr_virtual_keyboard_v1 now has its own wlr_keyboard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit which has its own wlr_input_device 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 ec4beb2..fcb00da 100644 --- a/dwl.c +++ b/dwl.c @@ -2375,7 +2375,7 @@ void virtualkeyboard(struct wl_listener *listener, void *data) { struct wlr_virtual_keyboard_v1 *keyboard = data; - struct wlr_input_device *device = &keyboard->input_device; + struct wlr_input_device *device = &keyboard->keyboard.base; createkeyboard(device); } From a7c4f6100a81c68aad6faf9061332f1fbacddd98 Mon Sep 17 00:00:00 2001 From: Leonardo Hernandez Hernandez Date: Sun, 13 Feb 2022 14:32:47 -0600 Subject: [PATCH 005/312] use scene layer shell helper --- dwl.c | 138 +++------------------------------------------------------- 1 file changed, 5 insertions(+), 133 deletions(-) diff --git a/dwl.c b/dwl.c index 657bf8d..4a46542 100644 --- a/dwl.c +++ b/dwl.c @@ -144,6 +144,7 @@ typedef struct { /* Must be first */ unsigned int type; /* LayerShell */ struct wlr_scene_node *scene; + struct wlr_scene_layer_surface_v1 *scene_layer; struct wl_list link; struct wlr_layer_surface_v1 *layer_surface; @@ -151,18 +152,8 @@ typedef struct { struct wl_listener map; struct wl_listener unmap; struct wl_listener surface_commit; - - struct wlr_box geo; } LayerSurface; -typedef struct { - uint32_t singular_anchor; - uint32_t anchor_triplet; - int *positive_axis; - int *negative_axis; - int margin; -} Edge; - typedef struct { const char *symbol; void (*arrange)(Monitor *); @@ -206,9 +197,6 @@ typedef struct { /* function declarations */ static void applybounds(Client *c, struct wlr_box *bbox); -static void 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); static void applyrules(Client *c); static void arrange(Monitor *m); static void arrangelayer(Monitor *m, struct wl_list *list, @@ -386,61 +374,6 @@ applybounds(Client *c, struct wlr_box *bbox) c->geom.y = bbox->y; } -void -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) { - Edge edges[] = { - { // Top - .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, - .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, - .positive_axis = &usable_area->y, - .negative_axis = &usable_area->height, - .margin = margin_top, - }, - { // Bottom - .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, - .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, - .positive_axis = NULL, - .negative_axis = &usable_area->height, - .margin = margin_bottom, - }, - { // Left - .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT, - .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, - .positive_axis = &usable_area->x, - .negative_axis = &usable_area->width, - .margin = margin_left, - }, - { // Right - .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, - .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, - .positive_axis = NULL, - .negative_axis = &usable_area->width, - .margin = margin_right, - } - }; - for (size_t 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) - *edges[i].positive_axis += exclusive + edges[i].margin; - if (edges[i].negative_axis) - *edges[i].negative_axis -= exclusive + edges[i].margin; - break; - } - } -} - void applyrules(Client *c) { @@ -492,72 +425,11 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int 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; - struct wlr_box bounds; - struct wlr_box box = { - .width = state->desired_width, - .height = state->desired_height - }; - const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT - | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; - const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP - | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; if (exclusive != (state->exclusive_zone > 0)) continue; - bounds = state->exclusive_zone == -1 ? full_area : *usable_area; - - // Horizontal axis - if ((state->anchor & both_horiz) && box.width == 0) { - box.x = bounds.x; - box.width = bounds.width; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { - box.x = bounds.x; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { - box.x = bounds.x + (bounds.width - box.width); - } else { - box.x = bounds.x + ((bounds.width / 2) - (box.width / 2)); - } - // Vertical axis - if ((state->anchor & both_vert) && box.height == 0) { - box.y = bounds.y; - box.height = bounds.height; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { - box.y = bounds.y; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { - box.y = bounds.y + (bounds.height - box.height); - } else { - box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); - } - // Margin - if ((state->anchor & both_horiz) == both_horiz) { - box.x += state->margin.left; - box.width -= state->margin.left + state->margin.right; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { - box.x += state->margin.left; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { - box.x -= state->margin.right; - } - if ((state->anchor & both_vert) == both_vert) { - box.y += state->margin.top; - box.height -= state->margin.top + state->margin.bottom; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { - box.y += state->margin.top; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { - box.y -= state->margin.bottom; - } - if (box.width < 0 || box.height < 0) { - wlr_layer_surface_v1_destroy(wlr_layer_surface); - continue; - } - layersurface->geo = box; - - if (state->exclusive_zone > 0) - applyexclusive(usable_area, state->anchor, state->exclusive_zone, - state->margin.top, state->margin.right, - state->margin.bottom, state->margin.left); - wlr_scene_node_set_position(layersurface->scene, box.x, box.y); - wlr_layer_surface_v1_configure(wlr_layer_surface, box.width, box.height); + wlr_scene_layer_surface_v1_configure(layersurface->scene_layer, &full_area, usable_area); } } @@ -916,9 +788,9 @@ createlayersurface(struct wl_listener *listener, void *data) wlr_layer_surface->data = layersurface; m = wlr_layer_surface->output->data; - layersurface->scene = wlr_scene_subsurface_tree_create( - layers[wlr_layer_surface->pending.layer], - wlr_layer_surface->surface); + layersurface->scene_layer = wlr_scene_layer_surface_v1_create( + layers[wlr_layer_surface->pending.layer], wlr_layer_surface); + layersurface->scene = layersurface->scene_layer->node; layersurface->scene->data = layersurface; wl_list_insert(&m->layers[wlr_layer_surface->pending.layer], From 98f33cd01dc452df411c07eab3b107f0172081f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 18 Mar 2022 17:20:31 -0600 Subject: [PATCH 006/312] follow up wlroots input device events renaming --- dwl.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/dwl.c b/dwl.c index fcb00da..8a1e3ea 100644 --- a/dwl.c +++ b/dwl.c @@ -619,7 +619,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_event_pointer_axis *event = data; + struct wlr_pointer_axis_event *event = data; wlr_idle_notify_activity(idle, seat); /* Notify the client with pointer focus of the axis event. */ wlr_seat_pointer_notify_axis(seat, @@ -630,7 +630,7 @@ axisnotify(struct wl_listener *listener, void *data) void buttonpress(struct wl_listener *listener, void *data) { - struct wlr_event_pointer_button *event = data; + struct wlr_pointer_button_event *event = data; struct wlr_keyboard *keyboard; uint32_t mods; Client *c; @@ -1228,7 +1228,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); - struct wlr_event_keyboard_key *event = data; + struct wlr_keyboard_key_event *event = data; /* Translate libinput keycode -> xkbcommon */ uint32_t keycode = event->keycode + 8; @@ -1340,8 +1340,8 @@ motionabsolute(struct wl_listener *listener, void *data) * 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. */ - struct wlr_event_pointer_motion_absolute *event = data; - wlr_cursor_warp_absolute(cursor, event->device, event->x, event->y); + struct wlr_pointer_motion_absolute_event *event = data; + wlr_cursor_warp_absolute(cursor, &event->pointer->base, event->x, event->y); motionnotify(event->time_msec); } @@ -1416,14 +1416,13 @@ motionrelative(struct wl_listener *listener, void *data) { /* This event is forwarded by the cursor when a pointer emits a _relative_ * pointer motion event (i.e. a delta) */ - struct wlr_event_pointer_motion *event = data; + struct wlr_pointer_motion_event *event = data; /* The cursor doesn't move unless we tell it to. The cursor automatically * handles constraining the motion to the output layout, as well as any * 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->device, - event->delta_x, event->delta_y); + wlr_cursor_move(cursor, &event->pointer->base, event->delta_x, event->delta_y); motionnotify(event->time_msec); } From 0662bc5a69cac39b92644c60534b5490d139e2c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 23 Mar 2022 09:01:01 -0600 Subject: [PATCH 007/312] wlr_seat_set_keyboard() now takes wlr_keyboard as parameter --- dwl.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dwl.c b/dwl.c index d9f2ae1..bac2e8c 100644 --- a/dwl.c +++ b/dwl.c @@ -129,7 +129,7 @@ typedef struct { typedef struct { struct wl_list link; - struct wlr_input_device *device; + struct wlr_keyboard *wlr_keyboard; struct wl_listener modifiers; struct wl_listener key; @@ -643,7 +643,7 @@ createkeyboard(struct wlr_input_device *device) Keyboard *kb = device->data = calloc(1, sizeof(*kb)); if (!kb) EBARF("createkeyboard: calloc"); - kb->device = device; + kb->wlr_keyboard = device->keyboard; /* Prepare an XKB keymap and assign it to the keyboard. */ context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); @@ -660,7 +660,7 @@ createkeyboard(struct wlr_input_device *device) LISTEN(&device->keyboard->events.key, &kb->key, keypress); LISTEN(&device->events.destroy, &kb->destroy, cleanupkeyboard); - wlr_seat_set_keyboard(seat, device); + wlr_seat_set_keyboard(seat, device->keyboard); /* And add the keyboard to our list of keyboards */ wl_list_insert(&keyboards, &kb->link); @@ -1135,10 +1135,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->device->keyboard->xkb_state, keycode, &syms); + kb->wlr_keyboard->xkb_state, keycode, &syms); int handled = 0; - uint32_t mods = wlr_keyboard_get_modifiers(kb->device->keyboard); + uint32_t mods = wlr_keyboard_get_modifiers(kb->wlr_keyboard); wlr_idle_notify_activity(idle, seat); @@ -1149,7 +1149,7 @@ keypress(struct wl_listener *listener, void *data) if (!handled) { /* Pass unhandled keycodes along to the client. */ - wlr_seat_set_keyboard(seat, kb->device); + wlr_seat_set_keyboard(seat, kb->wlr_keyboard); wlr_seat_keyboard_notify_key(seat, event->time_msec, event->keycode, event->state); } @@ -1167,10 +1167,10 @@ keypressmod(struct wl_listener *listener, void *data) * same seat. You can swap out the underlying wlr_keyboard like this and * wlr_seat handles this transparently. */ - wlr_seat_set_keyboard(seat, kb->device); + wlr_seat_set_keyboard(seat, kb->wlr_keyboard); /* Send modifiers to the client. */ wlr_seat_keyboard_notify_modifiers(seat, - &kb->device->keyboard->modifiers); + &kb->wlr_keyboard->modifiers); } void From 4276410a3d575aad3f90ff81406382824389db28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 21 Mar 2022 13:52:33 -0600 Subject: [PATCH 008/312] improve floating detection mostly copied from sway --- client.h | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/client.h b/client.h index e4a87e1..db043d2 100644 --- a/client.h +++ b/client.h @@ -91,16 +91,37 @@ client_get_title(Client *c) static inline int client_is_float_type(Client *c) { + struct wlr_xdg_toplevel *toplevel; + struct wlr_xdg_toplevel_state state; + #ifdef XWAYLAND - if (client_is_x11(c)) - for (size_t i = 0; i < c->surface.xwayland->window_type_len; i++) - if (c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeDialog] || - c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeSplash] || - c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeToolbar] || - c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeUtility]) + if (client_is_x11(c)) { + struct wlr_xwayland_surface *surface = c->surface.xwayland; + struct wlr_xwayland_surface_size_hints *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]) return 1; + + size_hints = surface->size_hints; + if (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)) + return 1; + } #endif - return 0; + + 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 From 40db9c88eaa4c32832c0bf7f7da56b8b73598519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 21 Mar 2022 13:28:44 -0600 Subject: [PATCH 009/312] remove a useless resize in mapnotify() applyrules() calls setmon() which calls resize() --- dwl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/dwl.c b/dwl.c index bac2e8c..c6b8ab9 100644 --- a/dwl.c +++ b/dwl.c @@ -1232,7 +1232,6 @@ mapnotify(struct wl_listener *listener, void *data) /* Set initial monitor, tags, floating status, and focus */ applyrules(c); - resize(c, c->geom.x, c->geom.y, c->geom.width, c->geom.height, 0); printstatus(); if (c->isfullscreen) From a7f77779078328e40eff41d3ee8102ebc6d41af2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 21 Mar 2022 21:17:58 -0600 Subject: [PATCH 010/312] only skip frames if there are visible clients that have a resize --- dwl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index c6b8ab9..222cb62 100644 --- a/dwl.c +++ b/dwl.c @@ -1497,9 +1497,11 @@ rendermon(struct wl_listener *listener, void *data) int skip = 0; struct timespec now; - /* Render if no XDG clients have an outstanding resize. */ + /* Render if no XDG clients have an outstanding resize and are visible on + * this monitor. + */ wl_list_for_each(c, &clients, link) - skip = skip || c->resize; + skip = skip || (c->resize && VISIBLEON(c, m)); if (!skip && !wlr_scene_output_commit(m->scene_output)) return; From 23af627d80d3bf42ae5d0731a79b4634ace86f9f Mon Sep 17 00:00:00 2001 From: Sevz Date: Mon, 21 Mar 2022 22:34:30 -0600 Subject: [PATCH 011/312] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 9b9eef4..64e2054 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,4 +7,16 @@ assignees: '' --- +## Info +dwl's commit: +wlroots version: +## Description + From f2be10fd43a38e0a727f679aae26737470a15a77 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Mon, 21 Mar 2022 23:03:52 +0100 Subject: [PATCH 012/312] implement drag and drop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For brevity, only a single drag icon at a time is supported. Co-authored-by: Leonardo Hernández Hernández --- dwl.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/dwl.c b/dwl.c index 222cb62..18c2d60 100644 --- a/dwl.c +++ b/dwl.c @@ -216,6 +216,7 @@ static void cursorframe(struct wl_listener *listener, void *data); static void destroylayersurfacenotify(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); static Monitor *dirtomon(enum wlr_direction dir); +static void dragicondestroy(struct wl_listener *listener, void *data); static void focusclient(Client *c, int lift); static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); @@ -243,6 +244,7 @@ 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, int x, int y, int w, int h, int interact); static void run(char *startup_cmd); static Client *selclient(void); @@ -257,6 +259,7 @@ static void setmon(Client *c, Monitor *m, unsigned int newtags); 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); static void tagmon(const Arg *arg); static void tile(Monitor *m); @@ -329,6 +332,9 @@ 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_start_drag = {.notify = requeststartdrag}; +static struct wl_listener start_drag = {.notify = startdrag}; +static struct wl_listener drag_icon_destroy = {.notify = dragicondestroy}; #ifdef XWAYLAND static void activatex11(struct wl_listener *listener, void *data); @@ -896,6 +902,16 @@ destroynotify(struct wl_listener *listener, void *data) free(c); } +void +dragicondestroy(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); +} + void togglefullscreen(const Arg *arg) { @@ -1273,11 +1289,16 @@ motionnotify(uint32_t time) /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { + struct wlr_drag_icon *icon; wlr_idle_notify_activity(idle, seat); /* Update selmon (even while dragging a window) */ if (sloppyfocus) selmon = xytomon(cursor->x, cursor->y); + + if (seat->drag && (icon = seat->drag->icon)) + wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, + cursor->y + icon->surface->sy); } /* If we are currently grabbing the mouse, handle and return */ @@ -1538,6 +1559,18 @@ resize(Client *c, int x, int y, int w, int h, int interact) c->geom.height - 2 * c->bw); } +void +requeststartdrag(struct wl_listener *listener, void *data) +{ + struct wlr_seat_request_start_drag_event *event = data; + + if (wlr_seat_validate_pointer_grab_serial(seat, event->origin, + event->serial)) + wlr_seat_start_pointer_drag(seat, event->drag, event->serial); + else + wlr_data_source_destroy(event->drag->source); +} + void run(char *startup_cmd) { @@ -1850,6 +1883,8 @@ setup(void) 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); output_mgr = wlr_output_manager_v1_create(dpy); wl_signal_add(&output_mgr->events.apply, &output_mgr_apply); @@ -1900,6 +1935,19 @@ spawn(const Arg *arg) } } +void +startdrag(struct wl_listener *listener, void *data) +{ + struct wlr_drag *drag = data; + + if (!drag->icon) + return; + + drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrTop], drag->icon->surface); + wlr_scene_node_raise_to_top(drag->icon->data); + wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); +} + void tag(const Arg *arg) { From d8ab893dab76c5f2921c30bde04fa141fb788b25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 22 Mar 2022 15:02:02 -0600 Subject: [PATCH 013/312] clients now works as expected in drag motion --- dwl.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index 18c2d60..0f742e4 100644 --- a/dwl.c +++ b/dwl.c @@ -1289,16 +1289,11 @@ motionnotify(uint32_t time) /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { - struct wlr_drag_icon *icon; wlr_idle_notify_activity(idle, seat); /* Update selmon (even while dragging a window) */ if (sloppyfocus) selmon = xytomon(cursor->x, cursor->y); - - if (seat->drag && (icon = seat->drag->icon)) - wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, - cursor->y + icon->surface->sy); } /* If we are currently grabbing the mouse, handle and return */ @@ -1437,6 +1432,7 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, { struct timespec now; int internal_call = !time; + struct wlr_drag_icon *icon; if (sloppyfocus && !internal_call && c && !client_is_unmanaged(c)) focusclient(c, 0); @@ -1458,6 +1454,13 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, wlr_seat_pointer_notify_enter(seat, surface, sx, sy); wlr_seat_pointer_notify_motion(seat, time, sx, sy); + /* If there are is a drag icon, update its position */ + /* For anyone who wants to change this function: for some reason + * (maybe a wlroots bug?, or is it intended?) if we change the node position + * before telling the seat for a motion, the clients don't recognize the drag */ + if (seat->drag && (icon = seat->drag->icon)) + wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, + cursor->y + icon->surface->sy); } void From 0db6f3c5b5f971bebfbbf8ec9bf94134f5506600 Mon Sep 17 00:00:00 2001 From: Humm Date: Wed, 5 Jan 2022 01:54:02 +0100 Subject: [PATCH 014/312] add dwl(1) Documentation is good. Man pages are documentation. A program without a man page is worthless. --- Makefile | 5 +- config.mk | 1 + dwl.1 | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 dwl.1 diff --git a/Makefile b/Makefile index 5ff69e9..536454f 100644 --- a/Makefile +++ b/Makefile @@ -15,10 +15,11 @@ clean: rm -f dwl *.o *-protocol.h *-protocol.c install: dwl - install -D dwl $(PREFIX)/bin/dwl + install -Dm755 dwl $(PREFIX)/bin/dwl + install -Dm644 dwl.1 $(MANDIR)/man1/dwl.1 uninstall: - rm -f $(PREFIX)/bin/dwl + rm -f $(PREFIX)/bin/dwl $(MANDIR)/man1/dwl.1 .PHONY: all clean install uninstall diff --git a/config.mk b/config.mk index d1b161e..960fc8a 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,6 @@ # paths PREFIX = /usr/local +MANDIR = $(PREFIX)/share/man # Default compile flags (overridable by environment) CFLAGS ?= -g -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-unused-function -Wno-unused-variable -Wno-unused-result -Wdeclaration-after-statement diff --git a/dwl.1 b/dwl.1 new file mode 100644 index 0000000..eea0f70 --- /dev/null +++ b/dwl.1 @@ -0,0 +1,144 @@ +.Dd January 8, 2021 +.Dt DWL 1 +.Os +.Sh NAME +.Nm dwl +.Nd dwm for Wayland +.Sh SYNOPSIS +.Nm +.Op Fl s Ar command +.Sh DESCRIPTION +.Nm +is a Wayland compositor based on wlroots. +It is intended to fill the same space in the Wayland world that +.Nm dwm +does for X11. +.Pp +When given the +.Fl s +option, +.Nm +starts a shell process running +.Ar command +when starting. +When stopping, it sends +.Dv SIGTERM +to the child process and waits for it to exit. +.Pp +Users are encouraged to customize +.Nm +by editing the sources, in particular +.Pa config.h . +The default key bindings are as follows: +.Bl -tag -width 20n -offset indent -compact +.It Mod-[1-9] +Show only all windows with a tag. +.It Mod-Ctrl-[1-9] +Show all windows with a tag. +.It Mod-Shift-[1-9] +Move window to a single tag. +.It Mod-Ctrl-Shift-[1-9] +Toggle tag for window. +.It Mod-p +Spawn +.Nm bemenu-run . +.It Mod-Shift-Return +Spawn +.Nm alacritty . +.It Mod-[jk] +Move focus down/up the stack. +.It Mod-[id] +Increase/decrease number of windows in master area. +.It Mod-[hl] +Decrease/increase master area. +.It Mod-Return +Move window on top of stack or switch top of stack with second window. +.It Mod-Tab +Show only all windows with previous tag. +.It Mod-Shift-c +Close window. +.It Mod-t +Switch to tabbed layout. +.It Mod-f +Switch to floating layout. +.It Mod-m +Switch to monocle layout. +.It Mod-Space +Switch to previous layout. +.It Mod-Shift-Space +Toggle floating state of window. +.It Mod-e +Toggle fullscreen state of window. +.It Mod-0 +Show all windows. +.It Mod-Shift-0 +Set all tags for window. +.It Mod-, +Move focus to previous monitor. +.It Mod-. +Move focus to next monitor. +.It Mod-Shift-, +Move window to previous monitor. +.It Mod-Shift-. +Move window to next monitor. +.It Mod-Shift-q +Quit +.Nm . +.El +These might differ depending on your keyboard layout. +.Sh ENVIRONMENT +These environment variables are used by +.Nm : +.Bl -tag -width XDG_RUNTIME_DIR +.It Ev XDG_RUNTIME_DIR +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 +libraries, including libxkbcommon. +.It Ev DISPLAY , WAYLAND_DISPLAY , WAYLAND_SOCKET +Tell how to connect to an underlying X11 or Wayland server. +.It Ev WLR_* +Various variables specific to wlroots. +.It Ev XKB_* , XLOCALEDIR , XCOMPOSEFILE +Various variables specific to libxkbcommon. +.It Ev XCURSOR_PATH +List of directories to search for XCursor themes in. +.It Ev HOME +A directory where there are always dear files there for you. +Waiting for you to clean them up. +.El +.Pp +These are set by +.Nm : +.Bl -tag -width WAYLAND_DISPLAY +.It Ev WAYLAND_DISPLAY +Tell how to connect to +.Nm . +.It Ev DISPLAY +If using +.Nm Xwayland , +tell how to connect to the +.Nm Xwayland +server. +.El +.Sh EXAMPLES +Start +.Nm +with s6 in the background: +.Dl dwl -s 's6-svscan <&-' +.Sh SEE ALSO +.Xr alacritty 1 , +.Xr bemenu 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 1a5b7e068b1bf0c02be2ae8b13aa1c85972226ab Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Tue, 3 Aug 2021 06:29:26 +0200 Subject: [PATCH 015/312] update IRC channel --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d094599..13a0000 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ You can find a [list of Wayland applications on the sway wiki](https://github.co ## IRC channel -dwl's IRC channel is #dwl on irc.freenode.net. +dwl's IRC channel is #dwl on irc.libera.chat. ## Acknowledgements From 5a1debb5f0fec4f149f8a4490828116e3b1f3b9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 22 Mar 2022 23:29:01 -0600 Subject: [PATCH 016/312] add sway LICENSE file part of the code in dwl is taken from sway, so credit it. dwm and sway are both licensed under the MIT license --- LICENSE | 2 +- LICENSE.sway | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 LICENSE.sway diff --git a/LICENSE b/LICENSE index e4bb015..658085a 100644 --- a/LICENSE +++ b/LICENSE @@ -2,7 +2,7 @@ dwl - dwm for Wayland Copyright © 2020 dwl team -See also the files LICENSE.tinywl and LICENSE.dwm. +See also the files LICENSE.tinywl, LICENSE.dwm and LICENSE.sway. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/LICENSE.sway b/LICENSE.sway new file mode 100644 index 0000000..3e0cacc --- /dev/null +++ b/LICENSE.sway @@ -0,0 +1,19 @@ +Copyright (c) 2016-2017 Drew DeVault + +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 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. From b42abeac69b08558c06611a725a997f4ad0affd8 Mon Sep 17 00:00:00 2001 From: Quentin Rameau Date: Mon, 12 Jul 2021 23:44:16 +0200 Subject: [PATCH 017/312] Add a configuration option for fullscreen locking Some people are annoyed to have this new behaviour forced for some application which use fake fullscreen. --- config.def.h | 1 + dwl.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/config.def.h b/config.def.h index 8408659..539dba6 100644 --- a/config.def.h +++ b/config.def.h @@ -1,6 +1,7 @@ /* appearance */ static const int sloppyfocus = 1; /* focus follows mouse */ static const unsigned int borderpx = 1; /* border pixel of windows */ +static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ 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}; diff --git a/dwl.c b/dwl.c index 0f742e4..cf6889e 100644 --- a/dwl.c +++ b/dwl.c @@ -1050,7 +1050,7 @@ focusstack(const Arg *arg) { /* Focus the next or previous client (in tiling order) on selmon */ Client *c, *sel = selclient(); - if (!sel) + if (!sel || (sel->isfullscreen && lockfullscreen)) return; if (arg->i > 0) { wl_list_for_each(c, &sel->link, link) { From a41d6cb00fb4729b690ffd962cc814f42fe3f28f Mon Sep 17 00:00:00 2001 From: Palanix Date: Mon, 28 Feb 2022 23:46:24 +0100 Subject: [PATCH 018/312] Fix dwl freezing when resizing --- dwl.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/dwl.c b/dwl.c index cf6889e..a198177 100644 --- a/dwl.c +++ b/dwl.c @@ -170,6 +170,7 @@ struct Monitor { unsigned int tagset[2]; double mfact; int nmaster; + int un_map; /* If a map/unmap happened on this monitor, then this should be true */ }; typedef struct { @@ -1252,6 +1253,8 @@ mapnotify(struct wl_listener *listener, void *data) if (c->isfullscreen) setfullscreen(c, 1); + + c->mon->un_map = 1; } void @@ -1521,17 +1524,27 @@ rendermon(struct wl_listener *listener, void *data) int skip = 0; struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + /* Render if no XDG clients have an outstanding resize and are visible on - * this monitor. - */ - wl_list_for_each(c, &clients, link) - skip = skip || (c->resize && VISIBLEON(c, m)); + * this monitor. */ + /* Checking m->un_map for every client is not optimal but works */ + wl_list_for_each(c, &clients, link) { + if ((c->resize && m->un_map) || (c->type == XDGShell + && (c->surface.xdg->pending.geometry.width != + c->surface.xdg->current.geometry.width + || c->surface.xdg->pending.geometry.height != + c->surface.xdg->current.geometry.height))) { + /* Lie */ + wlr_surface_send_frame_done(client_surface(c), &now); + skip = 1; + } + } if (!skip && !wlr_scene_output_commit(m->scene_output)) return; - /* Let clients know a frame has been rendered */ - clock_gettime(CLOCK_MONOTONIC, &now); wlr_scene_output_send_frame_done(m->scene_output, &now); + m->un_map = 0; } void @@ -2070,6 +2083,9 @@ unmapnotify(struct wl_listener *listener, void *data) grabc = NULL; } + if (c->mon) + c->mon->un_map = 1; + if (client_is_unmanaged(c)) { wlr_scene_node_destroy(c->scene); return; From 855e6c189806b195e7f2f851c37dd4a21d3e5366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 23 Mar 2022 14:03:07 -0600 Subject: [PATCH 019/312] add note about how to change MODKEY for windows key --- config.def.h | 1 + 1 file changed, 1 insertion(+) diff --git a/config.def.h b/config.def.h index 539dba6..9bdf8b5 100644 --- a/config.def.h +++ b/config.def.h @@ -52,6 +52,7 @@ static const int repeat_delay = 600; static const int tap_to_click = 1; static const int natural_scrolling = 0; +/* If you want to use the windows key change this to WLR_MODIFIER_LOGO */ #define MODKEY WLR_MODIFIER_ALT #define TAGKEYS(KEY,SKEY,TAG) \ { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ From 281c947e5f19b5c304baa51de9d90e69c80a5a9a Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Wed, 23 Mar 2022 22:01:04 +0100 Subject: [PATCH 020/312] inline the presentation variable This variable can be removed since with scene-graph wlr_presentation_surface_sampled_on_output no longer needs to be called. --- dwl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index a198177..2d58079 100644 --- a/dwl.c +++ b/dwl.c @@ -298,7 +298,6 @@ static struct wl_list fstack; /* focus order */ static struct wlr_idle *idle; static struct wlr_layer_shell_v1 *layer_shell; static struct wlr_output_manager_v1 *output_mgr; -static struct wlr_presentation *presentation; static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; static struct wlr_cursor *cursor; @@ -1906,8 +1905,7 @@ setup(void) wl_signal_add(&output_mgr->events.apply, &output_mgr_apply); wl_signal_add(&output_mgr->events.test, &output_mgr_test); - presentation = wlr_presentation_create(dpy, backend); - wlr_scene_set_presentation(scene, presentation); + wlr_scene_set_presentation(scene, wlr_presentation_create(dpy, backend)); #ifdef XWAYLAND /* From f353a0e759037e13419ddab6747afd6b6c736cb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 23 Mar 2022 12:13:49 -0600 Subject: [PATCH 021/312] Revert "clients now works as expected in drag motion" This reverts commit 9aec6049ecbefe3618f34002d2239cc9462c07e9. this problem is caused because xytonode() returns the surface of the drag icon --- dwl.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/dwl.c b/dwl.c index 2d58079..71996e7 100644 --- a/dwl.c +++ b/dwl.c @@ -1291,11 +1291,16 @@ motionnotify(uint32_t time) /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { + struct wlr_drag_icon *icon; wlr_idle_notify_activity(idle, seat); /* Update selmon (even while dragging a window) */ if (sloppyfocus) selmon = xytomon(cursor->x, cursor->y); + + if (seat->drag && (icon = seat->drag->icon)) + wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, + cursor->y + icon->surface->sy); } /* If we are currently grabbing the mouse, handle and return */ @@ -1434,7 +1439,6 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, { struct timespec now; int internal_call = !time; - struct wlr_drag_icon *icon; if (sloppyfocus && !internal_call && c && !client_is_unmanaged(c)) focusclient(c, 0); @@ -1456,13 +1460,6 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, wlr_seat_pointer_notify_enter(seat, surface, sx, sy); wlr_seat_pointer_notify_motion(seat, time, sx, sy); - /* If there are is a drag icon, update its position */ - /* For anyone who wants to change this function: for some reason - * (maybe a wlroots bug?, or is it intended?) if we change the node position - * before telling the seat for a motion, the clients don't recognize the drag */ - if (seat->drag && (icon = seat->drag->icon)) - wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, - cursor->y + icon->surface->sy); } void From c2899bc00b03c8a4a6d11c2b9a00a4114949f427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 23 Mar 2022 14:18:38 -0600 Subject: [PATCH 022/312] set position of the drag icon in startdrag() --- dwl.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/dwl.c b/dwl.c index 71996e7..9f72768 100644 --- a/dwl.c +++ b/dwl.c @@ -1288,21 +1288,20 @@ motionnotify(uint32_t time) double sx = 0, sy = 0; Client *c = NULL; struct wlr_surface *surface = NULL; + struct wlr_drag_icon *icon; /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { - struct wlr_drag_icon *icon; wlr_idle_notify_activity(idle, seat); /* Update selmon (even while dragging a window) */ if (sloppyfocus) selmon = xytomon(cursor->x, cursor->y); - - if (seat->drag && (icon = seat->drag->icon)) - wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, - cursor->y + icon->surface->sy); } + if (seat->drag && (icon = seat->drag->icon)) + wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, + cursor->y + icon->surface->sy); /* If we are currently grabbing the mouse, handle and return */ if (cursor_mode == CurMove) { /* Move the grabbed client to the new position. */ @@ -1955,7 +1954,7 @@ startdrag(struct wl_listener *listener, void *data) return; drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrTop], drag->icon->surface); - wlr_scene_node_raise_to_top(drag->icon->data); + motionnotify(0); wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); } From 3e79a9a5d7a7d66effaca573798f4c5b77e99773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 23 Mar 2022 13:50:08 -0600 Subject: [PATCH 023/312] fix drag icon's surface returned by xytonode --- dwl.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/dwl.c b/dwl.c index 9f72768..3f3f447 100644 --- a/dwl.c +++ b/dwl.c @@ -68,7 +68,7 @@ /* enums */ enum { CurNormal, CurMove, CurResize }; /* cursor */ enum { XDGShell, LayerShell, X11Managed, X11Unmanaged }; /* client types */ -enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, NUM_LAYERS }; /* scene layers */ +enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrNoFocus, NUM_LAYERS }; /* scene layers */ #ifdef XWAYLAND enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ @@ -1784,6 +1784,7 @@ setup(void) layers[LyrFloat] = &wlr_scene_tree_create(&scene->node)->node; layers[LyrTop] = &wlr_scene_tree_create(&scene->node)->node; layers[LyrOverlay] = &wlr_scene_tree_create(&scene->node)->node; + layers[LyrNoFocus] = &wlr_scene_tree_create(&scene->node)->node; /* Create a renderer with the default implementation */ if (!(drw = wlr_renderer_autocreate(backend))) @@ -1953,7 +1954,7 @@ startdrag(struct wl_listener *listener, void *data) if (!drag->icon) return; - drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrTop], drag->icon->surface); + drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrNoFocus], drag->icon->surface); motionnotify(0); wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); } @@ -2183,17 +2184,23 @@ xytonode(double x, double y, struct wlr_surface **psurface, struct wlr_surface *surface = NULL; Client *c = NULL; LayerSurface *l = NULL; + int i; + int focus_order[] = { LyrOverlay, LyrTop, LyrFloat, LyrTile, LyrBottom, LyrBg }; - if ((node = wlr_scene_node_at(&scene->node, x, y, nx, ny))) { - if (node->type == WLR_SCENE_NODE_SURFACE) - surface = wlr_scene_surface_from_node(node)->surface; - /* Walk the tree to find a node that knows the client */ - for (pnode = node; pnode && !c; pnode = pnode->parent) - c = pnode->data; - if (c && c->type == LayerShell) { - c = NULL; - l = pnode->data; + for (i = 0; i < LENGTH(focus_order); i++) { + if ((node = wlr_scene_node_at(layers[focus_order[i]], x, y, nx, ny))) { + if (node->type == WLR_SCENE_NODE_SURFACE) + surface = wlr_scene_surface_from_node(node)->surface; + /* Walk the tree to find a node that knows the client */ + for (pnode = node; pnode && !c; pnode = pnode->parent) + c = pnode->data; + if (c && c->type == LayerShell) { + c = NULL; + l = pnode->data; + } } + if (surface) + break; } if (psurface) *psurface = surface; From faaee90cbd42d991f6e96e516035df2a1bab8361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 20 Mar 2022 19:09:28 -0600 Subject: [PATCH 024/312] destroy scene_output in cleanupmon() --- dwl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dwl.c b/dwl.c index 3f3f447..86f8c34 100644 --- a/dwl.c +++ b/dwl.c @@ -582,6 +582,7 @@ cleanupmon(struct wl_listener *listener, void *data) wl_list_remove(&m->frame.link); wl_list_remove(&m->link); wlr_output_layout_remove(output_layout, m->wlr_output); + wlr_scene_output_destroy(m->scene_output); if ((nmons = wl_list_length(&mons))) do /* don't switch to disabled mons */ From f75e4262229e26ea159742b96f6b63aef472ed8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 23 Mar 2022 17:05:21 -0600 Subject: [PATCH 025/312] createkeyboard now takes wlr_keyboard --- dwl.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/dwl.c b/dwl.c index 86f8c34..99205c1 100644 --- a/dwl.c +++ b/dwl.c @@ -208,7 +208,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 createkeyboard(struct wlr_input_device *device); +static void createkeyboard(struct wlr_keyboard *keyboard); static void createmon(struct wl_listener *listener, void *data); static void createnotify(struct wl_listener *listener, void *data); static void createlayersurface(struct wl_listener *listener, void *data); @@ -562,7 +562,7 @@ void cleanupkeyboard(struct wl_listener *listener, void *data) { struct wlr_input_device *device = data; - Keyboard *kb = device->data; + Keyboard *kb = device->keyboard->data; wl_list_remove(&kb->link); wl_list_remove(&kb->modifiers.link); @@ -643,31 +643,31 @@ commitnotify(struct wl_listener *listener, void *data) } void -createkeyboard(struct wlr_input_device *device) +createkeyboard(struct wlr_keyboard *keyboard) { struct xkb_context *context; struct xkb_keymap *keymap; - Keyboard *kb = device->data = calloc(1, sizeof(*kb)); + Keyboard *kb = keyboard->data = calloc(1, sizeof(*kb)); if (!kb) EBARF("createkeyboard: calloc"); - kb->wlr_keyboard = device->keyboard; + 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); - wlr_keyboard_set_keymap(device->keyboard, keymap); + wlr_keyboard_set_keymap(keyboard, keymap); xkb_keymap_unref(keymap); xkb_context_unref(context); - wlr_keyboard_set_repeat_info(device->keyboard, repeat_rate, repeat_delay); + wlr_keyboard_set_repeat_info(keyboard, repeat_rate, repeat_delay); /* Here we set up listeners for keyboard events. */ - LISTEN(&device->keyboard->events.modifiers, &kb->modifiers, keypressmod); - LISTEN(&device->keyboard->events.key, &kb->key, keypress); - LISTEN(&device->events.destroy, &kb->destroy, cleanupkeyboard); + 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, device->keyboard); + wlr_seat_set_keyboard(seat, keyboard); /* And add the keyboard to our list of keyboards */ wl_list_insert(&keyboards, &kb->link); @@ -1099,7 +1099,7 @@ inputdevice(struct wl_listener *listener, void *data) switch (device->type) { case WLR_INPUT_DEVICE_KEYBOARD: - createkeyboard(device); + createkeyboard(device->keyboard); break; case WLR_INPUT_DEVICE_POINTER: createpointer(device); @@ -2174,7 +2174,7 @@ virtualkeyboard(struct wl_listener *listener, void *data) { struct wlr_virtual_keyboard_v1 *keyboard = data; struct wlr_input_device *device = &keyboard->keyboard.base; - createkeyboard(device); + createkeyboard(device->keyboard); } struct wlr_scene_node * From 7018ed9218b05e15d191adcae04167f9d6fc8bce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 23 Mar 2022 17:08:44 -0600 Subject: [PATCH 026/312] createpointer now takes wlr_pointer --- dwl.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dwl.c b/dwl.c index 99205c1..3f66be4 100644 --- a/dwl.c +++ b/dwl.c @@ -212,7 +212,7 @@ static void createkeyboard(struct wlr_keyboard *keyboard); static void createmon(struct wl_listener *listener, void *data); static void createnotify(struct wl_listener *listener, void *data); static void createlayersurface(struct wl_listener *listener, void *data); -static void createpointer(struct wlr_input_device *device); +static void createpointer(struct wlr_pointer *pointer); static void cursorframe(struct wl_listener *listener, void *data); static void destroylayersurfacenotify(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); @@ -831,11 +831,11 @@ createlayersurface(struct wl_listener *listener, void *data) } void -createpointer(struct wlr_input_device *device) +createpointer(struct wlr_pointer *pointer) { - if (wlr_input_device_is_libinput(device)) { + if (wlr_input_device_is_libinput(&pointer->base)) { struct libinput_device *libinput_device = (struct libinput_device*) - wlr_libinput_get_device_handle(device); + wlr_libinput_get_device_handle(&pointer->base); if (tap_to_click && libinput_device_config_tap_get_finger_count(libinput_device)) libinput_device_config_tap_set_enabled(libinput_device, LIBINPUT_CONFIG_TAP_ENABLED); @@ -848,7 +848,7 @@ createpointer(struct wlr_input_device *device) * is proxied through wlr_cursor. On another compositor, you might take this * opportunity to do libinput configuration on the device to set * acceleration, etc. */ - wlr_cursor_attach_input_device(cursor, device); + wlr_cursor_attach_input_device(cursor, &pointer->base); } void @@ -1102,7 +1102,7 @@ inputdevice(struct wl_listener *listener, void *data) createkeyboard(device->keyboard); break; case WLR_INPUT_DEVICE_POINTER: - createpointer(device); + createpointer(device->pointer); break; default: /* TODO handle other input device types */ From e08bd1292288f662eb265461a8c1a9d7501b0445 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Tue, 29 Mar 2022 15:55:06 -0500 Subject: [PATCH 027/312] make sure to leave XWayland process waitable On SIGCHLD, check to make sure the terminated process is not the XWayland process before reaping it, allowing wlroots to waitpid() for it successfully. Fixes #177. --- dwl.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 3f66be4..a14dc5c 100644 --- a/dwl.c +++ b/dwl.c @@ -1925,6 +1925,7 @@ setup(void) void sigchld(int unused) { + siginfo_t in; /* We should be able to remove this function in favor of a simple * signal(SIGCHLD, SIG_IGN); * but the Xwayland implementation in wlroots currently prevents us from @@ -1932,8 +1933,12 @@ sigchld(int unused) */ if (signal(SIGCHLD, sigchld) == SIG_ERR) EBARF("can't install SIGCHLD handler"); - while (0 < waitpid(-1, NULL, WNOHANG)) - ; + /* 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 + && in.si_pid != xwayland->server->pid) + waitpid(in.si_pid, NULL, 0); } void From 0ddde0c85a46370759e85f3437e3475b569d5c41 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Tue, 29 Mar 2022 16:09:29 -0500 Subject: [PATCH 028/312] move sigchld() into XWayland section --- dwl.c | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/dwl.c b/dwl.c index a14dc5c..ae5ed93 100644 --- a/dwl.c +++ b/dwl.c @@ -258,7 +258,6 @@ static void setlayout(const Arg *arg); static void setmfact(const Arg *arg); static void setmon(Client *c, Monitor *m, unsigned int newtags); 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); @@ -341,6 +340,7 @@ 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 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}; @@ -1762,7 +1762,11 @@ setup(void) dpy = wl_display_create(); /* Set up signal handlers */ +#ifdef XWAYLAND sigchld(0); +#else + signal(SIGCHLD, SIG_IGN); +#endif signal(SIGINT, quitsignal); signal(SIGTERM, quitsignal); @@ -1922,25 +1926,6 @@ setup(void) #endif } -void -sigchld(int unused) -{ - siginfo_t in; - /* We should be able to remove this function in favor of a simple - * signal(SIGCHLD, SIG_IGN); - * but the Xwayland implementation in wlroots currently prevents us from - * setting our own disposition for SIGCHLD. - */ - if (signal(SIGCHLD, sigchld) == SIG_ERR) - EBARF("can't install SIGCHLD handler"); - /* 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 - && in.si_pid != xwayland->server->pid) - waitpid(in.si_pid, NULL, 0); -} - void spawn(const Arg *arg) { @@ -2317,6 +2302,25 @@ getatom(xcb_connection_t *xc, const char *name) return atom; } +void +sigchld(int unused) +{ + siginfo_t in; + /* We should be able to remove this function in favor of a simple + * signal(SIGCHLD, SIG_IGN); + * but the Xwayland implementation in wlroots currently prevents us from + * setting our own disposition for SIGCHLD. + */ + if (signal(SIGCHLD, sigchld) == SIG_ERR) + EBARF("can't install SIGCHLD handler"); + /* 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 + && in.si_pid != xwayland->server->pid) + waitpid(in.si_pid, NULL, 0); +} + void xwaylandready(struct wl_listener *listener, void *data) { From 4a2e761914f88d4d284ec74b147104f53c394523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 12 Apr 2022 23:52:05 -0500 Subject: [PATCH 029/312] replace deleted EBARF() with die() --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index dd62956..06402c0 100644 --- a/dwl.c +++ b/dwl.c @@ -2339,7 +2339,7 @@ sigchld(int unused) * setting our own disposition for SIGCHLD. */ if (signal(SIGCHLD, sigchld) == SIG_ERR) - EBARF("can't install SIGCHLD handler"); + die("can't install SIGCHLD handler:"); /* WNOWAIT leaves the child in a waitable state, in case this is the * XWayland process */ From dc7709a00edebe323d8e192ff48f14f72f1e2142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 16 Apr 2022 15:51:13 -0500 Subject: [PATCH 030/312] schedule a configure on maximize request see maximizenotify() for more info --- dwl.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dwl.c b/dwl.c index 06402c0..f4ce462 100644 --- a/dwl.c +++ b/dwl.c @@ -104,6 +104,7 @@ typedef struct { } surface; struct wl_listener commit; struct wl_listener map; + struct wl_listener maximize; struct wl_listener unmap; struct wl_listener destroy; struct wl_listener set_title; @@ -233,6 +234,7 @@ static void keypressmod(struct wl_listener *listener, void *data); static void killclient(const Arg *arg); 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); static void motionabsolute(struct wl_listener *listener, void *data); static void motionnotify(uint32_t time); @@ -840,6 +842,8 @@ createnotify(struct wl_listener *listener, void *data) 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); c->isfullscreen = 0; } @@ -1254,6 +1258,18 @@ mapnotify(struct wl_listener *listener, void *data) c->mon->un_map = 1; } +void +maximizenotify(struct wl_listener *listener, void *data) +{ + /* This event is raised when a client would like to maximize itself, + * 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. + * 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); +} + void monocle(Monitor *m) { From 31fa6600a174d44be69d66c16dfefd80583409a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 8 May 2022 17:51:42 -0500 Subject: [PATCH 031/312] replace wlr_xwayland_surface_size_hints with xcb_size_hints_t --- client.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/client.h b/client.h index db043d2..1796ef0 100644 --- a/client.h +++ b/client.h @@ -97,7 +97,7 @@ client_is_float_type(Client *c) #ifdef XWAYLAND if (client_is_x11(c)) { struct wlr_xwayland_surface *surface = c->surface.xwayland; - struct wlr_xwayland_surface_size_hints *size_hints; + xcb_size_hints_t *size_hints; if (surface->modal) return 1; @@ -208,8 +208,7 @@ client_min_size(Client *c, int *width, int *height) 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; + xcb_size_hints_t *size_hints = c->surface.xwayland->size_hints; *width = size_hints->min_width; *height = size_hints->min_height; return; From 79a148224ffb5a55510de691f95eda2d32c6d2bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 15 May 2022 17:17:58 -0500 Subject: [PATCH 032/312] specify version in wlr_xdg_shell_create() --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 40ace0c..0acb22e 100644 --- a/dwl.c +++ b/dwl.c @@ -1896,7 +1896,7 @@ setup(void) layer_shell = wlr_layer_shell_v1_create(dpy); wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface); - xdg_shell = wlr_xdg_shell_create(dpy); + xdg_shell = wlr_xdg_shell_create(dpy, 2); wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface); input_inhibit_mgr = wlr_input_inhibit_manager_create(dpy); From 283c043b5c8cc6f2d5b8a5e72e1a5924b2c1532e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 21 May 2022 20:44:08 -0500 Subject: [PATCH 033/312] chase wlroots scene-surface refactor --- dwl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 84e5f2e..65cb97a 100644 --- a/dwl.c +++ b/dwl.c @@ -2253,8 +2253,9 @@ 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], x, y, nx, ny))) { - if (node->type == WLR_SCENE_NODE_SURFACE) - surface = wlr_scene_surface_from_node(node)->surface; + 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) c = pnode->data; From c7007b48115ac4913fad7e887c402f1c643f51bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 7 Jun 2022 00:31:58 -0500 Subject: [PATCH 034/312] chase wlroots scene-tree changes --- dwl.c | 56 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/dwl.c b/dwl.c index 65cb97a..8d08810 100644 --- a/dwl.c +++ b/dwl.c @@ -94,9 +94,9 @@ typedef struct Monitor Monitor; typedef struct { /* Must be first */ unsigned int type; /* XDGShell or X11* */ - struct wlr_scene_node *scene; + struct wlr_scene_tree *scene; struct wlr_scene_rect *border[4]; /* top, bottom, left, right */ - struct wlr_scene_node *scene_surface; + struct wlr_scene_tree *scene_surface; struct wl_list link; struct wl_list flink; union { @@ -144,7 +144,7 @@ typedef struct { /* Must be first */ unsigned int type; /* LayerShell */ int mapped; - struct wlr_scene_node *scene; + struct wlr_scene_tree *scene; struct wlr_scene_layer_surface_v1 *scene_layer; struct wl_list link; struct wlr_layer_surface_v1 *layer_surface; @@ -291,7 +291,7 @@ static const char broken[] = "broken"; static struct wl_display *dpy; static struct wlr_backend *backend; static struct wlr_scene *scene; -static struct wlr_scene_node *layers[NUM_LAYERS]; +static struct wlr_scene_tree *layers[NUM_LAYERS]; static struct wlr_renderer *drw; static struct wlr_allocator *alloc; static struct wlr_compositor *compositor; @@ -412,7 +412,7 @@ applyrules(Client *c) mon = m; } } - wlr_scene_node_reparent(c->scene, layers[c->isfloating ? LyrFloat : LyrTile]); + wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrFloat : LyrTile]); setmon(c, mon, newtags); } @@ -421,7 +421,7 @@ arrange(Monitor *m) { Client *c; wl_list_for_each(c, &clients, link) - wlr_scene_node_set_enabled(c->scene, VISIBLEON(c, c->mon)); + wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, c->mon)); if (m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); @@ -632,7 +632,7 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data) struct wlr_output *wlr_output = wlr_layer_surface->output; Monitor *m; - wlr_scene_node_reparent(layersurface->scene, + wlr_scene_node_reparent(&layersurface->scene->node, layers[wlr_layer_surface->current.layer]); if (!wlr_output || !(m = wlr_output->data)) @@ -730,9 +730,9 @@ createlayersurface(struct wl_listener *listener, void *data) layersurface->scene_layer = wlr_scene_layer_surface_v1_create( layers[wlr_layer_surface->pending.layer], wlr_layer_surface); layersurface->scene = wlr_layer_surface->surface->data = - layersurface->scene_layer->node; + &layersurface->scene_layer->tree->node; - layersurface->scene->data = layersurface; + layersurface->scene->node.data = layersurface; wl_list_insert(&m->layers[wlr_layer_surface->pending.layer], &layersurface->link); @@ -969,7 +969,7 @@ focusclient(Client *c, int lift) /* Raise client in stacking order if requested */ if (c && lift) - wlr_scene_node_raise_to_top(c->scene); + wlr_scene_node_raise_to_top(&c->scene->node); if (c && client_surface(c) == old) return; @@ -1236,17 +1236,17 @@ 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])->node; + c->scene = wlr_scene_tree_create(layers[LyrTile]); c->scene_surface = client_surface(c)->data = c->type == XDGShell ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg) : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); - c->scene_surface->data = c; + c->scene_surface->node.data = c; if (client_is_unmanaged(c)) { client_get_geometry(c, &c->geom); /* Floating */ - wlr_scene_node_reparent(c->scene, layers[LyrFloat]); - wlr_scene_node_set_position(c->scene, c->geom.x + borderpx, + 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); return; } @@ -1590,8 +1590,8 @@ resize(Client *c, int x, int y, int w, int h, int interact) applybounds(c, bbox); /* Update scene-graph, including borders */ - wlr_scene_node_set_position(c->scene, c->geom.x, c->geom.y); - wlr_scene_node_set_position(c->scene_surface, c->bw, c->bw); + wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); + wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw); wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw); wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw); wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw); @@ -1710,7 +1710,7 @@ void setfloating(Client *c, int floating) { c->isfloating = floating; - wlr_scene_node_reparent(c->scene, layers[c->isfloating ? LyrFloat : LyrTile]); + wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrFloat : LyrTile]); arrange(c->mon); printstatus(); } @@ -1836,13 +1836,13 @@ setup(void) /* Initialize the scene graph used to lay out windows */ scene = wlr_scene_create(); - layers[LyrBg] = &wlr_scene_tree_create(&scene->node)->node; - layers[LyrBottom] = &wlr_scene_tree_create(&scene->node)->node; - layers[LyrTile] = &wlr_scene_tree_create(&scene->node)->node; - layers[LyrFloat] = &wlr_scene_tree_create(&scene->node)->node; - layers[LyrTop] = &wlr_scene_tree_create(&scene->node)->node; - layers[LyrOverlay] = &wlr_scene_tree_create(&scene->node)->node; - layers[LyrNoFocus] = &wlr_scene_tree_create(&scene->node)->node; + 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[LyrTop] = wlr_scene_tree_create(&scene->tree); + layers[LyrOverlay] = wlr_scene_tree_create(&scene->tree); + layers[LyrNoFocus] = wlr_scene_tree_create(&scene->tree); /* Create a renderer with the default implementation */ if (!(drw = wlr_renderer_autocreate(backend))) @@ -2139,14 +2139,14 @@ unmapnotify(struct wl_listener *listener, void *data) c->mon->un_map = 1; if (client_is_unmanaged(c)) { - wlr_scene_node_destroy(c->scene); + wlr_scene_node_destroy(&c->scene->node); return; } wl_list_remove(&c->link); setmon(c, NULL, 0); wl_list_remove(&c->flink); - wlr_scene_node_destroy(c->scene); + wlr_scene_node_destroy(&c->scene->node); printstatus(); } @@ -2252,12 +2252,12 @@ xytonode(double x, double y, struct wlr_surface **psurface, int focus_order[] = { LyrOverlay, LyrTop, LyrFloat, LyrTile, LyrBottom, LyrBg }; for (layer = focus_order; layer < END(focus_order); layer++) { - if ((node = wlr_scene_node_at(layers[*layer], x, y, nx, ny))) { + 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) + for (pnode = node; pnode && !c; pnode = &pnode->parent->node) c = pnode->data; if (c && c->type == LayerShell) { c = NULL; From 4b890336e21edc6a69bd3463b22a4c1318a669e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 7 Jun 2022 00:55:41 -0500 Subject: [PATCH 035/312] use xdg-shell v3 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 8d08810..a71f294 100644 --- a/dwl.c +++ b/dwl.c @@ -1901,7 +1901,7 @@ setup(void) layer_shell = wlr_layer_shell_v1_create(dpy); wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface); - xdg_shell = wlr_xdg_shell_create(dpy, 2); + xdg_shell = wlr_xdg_shell_create(dpy, 3); wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface); input_inhibit_mgr = wlr_input_inhibit_manager_create(dpy); From 948fdcf709e86f380eef26ee529683d2c396e58a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 9 Jun 2022 12:45:02 -0500 Subject: [PATCH 036/312] use xdg-shell v4 --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index a71f294..852eecf 100644 --- a/dwl.c +++ b/dwl.c @@ -1901,7 +1901,7 @@ setup(void) layer_shell = wlr_layer_shell_v1_create(dpy); wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface); - xdg_shell = wlr_xdg_shell_create(dpy, 3); + 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); From a32db11f16fae3f57af3795d2463996b95e7ba1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 9 Jun 2022 12:45:42 -0500 Subject: [PATCH 037/312] set client bounds at resize --- client.h | 10 ++++++++++ dwl.c | 1 + 2 files changed, 11 insertions(+) diff --git a/client.h b/client.h index 6648c59..9431d11 100644 --- a/client.h +++ b/client.h @@ -45,6 +45,16 @@ client_activate_surface(struct wlr_surface *s, int activated) wlr_xdg_toplevel_set_activated(surface->toplevel, activated); } +static inline uint32_t +client_set_bounds(Client *c, int32_t width, int32_t height) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return 0; +#endif + return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height); +} + static inline void client_for_each_surface(Client *c, wlr_surface_iterator_func_t fn, void *data) { diff --git a/dwl.c b/dwl.c index 852eecf..b56abd7 100644 --- a/dwl.c +++ b/dwl.c @@ -1582,6 +1582,7 @@ resize(Client *c, int x, int y, int w, int h, int interact) { int min_width = 0, min_height = 0; struct wlr_box *bbox = interact ? &sgeom : &c->mon->w; + client_set_bounds(c, w, h); client_min_size(c, &min_width, &min_height); c->geom.x = x; c->geom.y = y; From 461d02d3e03a5f0dc42fbb71dd8ab728b9c7e424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 21 Jun 2022 16:25:18 -0500 Subject: [PATCH 038/312] chase wlroots input_device changes --- dwl.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/dwl.c b/dwl.c index b56abd7..beab572 100644 --- a/dwl.c +++ b/dwl.c @@ -575,8 +575,7 @@ cleanup(void) void cleanupkeyboard(struct wl_listener *listener, void *data) { - struct wlr_input_device *device = data; - Keyboard *kb = device->keyboard->data; + Keyboard *kb = wlr_keyboard_from_input_device(data)->data; wl_list_remove(&kb->link); wl_list_remove(&kb->modifiers.link); @@ -1118,10 +1117,10 @@ inputdevice(struct wl_listener *listener, void *data) switch (device->type) { case WLR_INPUT_DEVICE_KEYBOARD: - createkeyboard(device->keyboard); + createkeyboard(wlr_keyboard_from_input_device(device)); break; case WLR_INPUT_DEVICE_POINTER: - createpointer(device->pointer); + createpointer(wlr_pointer_from_input_device(device)); break; default: /* TODO handle other input device types */ @@ -2230,8 +2229,7 @@ void virtualkeyboard(struct wl_listener *listener, void *data) { struct wlr_virtual_keyboard_v1 *keyboard = data; - struct wlr_input_device *device = &keyboard->keyboard.base; - createkeyboard(device->keyboard); + createkeyboard(&keyboard->keyboard); } Monitor * From 058c699ac2552db13ea8bbef64182c59cceaf55c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 15 Jul 2022 00:27:31 -0500 Subject: [PATCH 039/312] only set bounds for clients that support it --- client.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client.h b/client.h index 9431d11..978c8e1 100644 --- a/client.h +++ b/client.h @@ -52,7 +52,10 @@ client_set_bounds(Client *c, int32_t width, int32_t height) if (client_is_x11(c)) return 0; #endif - return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height); + if (c->surface.xdg->client->shell->version >= + XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION) + return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height); + return 0; } static inline void From 83e37820d778f935af0123d3b4bc0512265fbfac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 28 Aug 2022 21:40:03 -0500 Subject: [PATCH 040/312] add support for the single pixel buffer protocol --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index f900f88..52109ee 100644 --- a/dwl.c +++ b/dwl.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -1949,6 +1950,7 @@ setup(void) 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); wlr_subcompositor_create(dpy); /* Initializes the interface used to implement urgency hints */ From dc59f7733d0315b3240b46321f3b5ae2ecc16b49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 6 Sep 2022 00:29:44 -0500 Subject: [PATCH 041/312] enable adaptive sync if supported but don't cause monitors to be ignored if it fails --- dwl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 52109ee..b80f3aa 100644 --- a/dwl.c +++ b/dwl.c @@ -803,7 +803,6 @@ createmon(struct wl_listener *listener, void *data) * 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_enable_adaptive_sync(wlr_output, 1); /* Set up event listeners */ LISTEN(&wlr_output->events.frame, &m->frame, rendermon); @@ -813,6 +812,11 @@ 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 d11358762d3693e8e268ecf01861f522a0dc96f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 18 Sep 2022 15:49:30 -0500 Subject: [PATCH 042/312] add missing library (xcb-icccm) this library is also used by wlroots, so nothing new --- config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.mk b/config.mk index 4638d5f..c7b5d16 100644 --- a/config.mk +++ b/config.mk @@ -12,4 +12,4 @@ XWAYLAND = XLIBS = # Uncomment to build XWayland support #XWAYLAND = -DXWAYLAND -#XLIBS = xcb +#XLIBS = xcb xcb-icccm From 434ed119f3427c1539aff95c57977c35921afb19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 1 Oct 2022 23:33:17 -0500 Subject: [PATCH 043/312] wlroots check map state of layersurfaces this for us --- dwl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index eb072bb..32a1650 100644 --- a/dwl.c +++ b/dwl.c @@ -456,9 +456,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; struct wlr_layer_surface_v1_state *state = &wlr_layer_surface->current; - /* Unmapped surfaces shouldn't have exclusive zone */ - if (!((LayerSurface *)wlr_layer_surface->data)->mapped - || exclusive != (state->exclusive_zone > 0)) + if (exclusive != (state->exclusive_zone > 0)) continue; wlr_scene_layer_surface_v1_configure(layersurface->scene_layer, &full_area, usable_area); From 1eeb3689d3ec5b917b5ccf730a6497e4b9fcd0a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 23 Oct 2022 12:32:57 -0500 Subject: [PATCH 044/312] add support for the ext-idle-notify-v1 protocol for now we use macros to support both KDE idle and ext-idle, wlroots will likely drop support for KDE idle in 0.17 --- dwl.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 32a1650..c29d554 100644 --- a/dwl.c +++ b/dwl.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,7 @@ #define END(A) ((A) + LENGTH(A)) #define TAGMASK ((1 << LENGTH(tags)) - 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 */ @@ -308,6 +310,7 @@ static struct wlr_xdg_activation_v1 *activation; 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_input_inhibit_manager *input_inhibit_mgr; static struct wlr_layer_shell_v1 *layer_shell; @@ -511,7 +514,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; - wlr_idle_notify_activity(idle, seat); + IDLE_NOTIFY_ACTIVITY; /* 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. */ @@ -529,7 +532,7 @@ buttonpress(struct wl_listener *listener, void *data) Client *c; const Button *b; - wlr_idle_notify_activity(idle, seat); + IDLE_NOTIFY_ACTIVITY; switch (event->state) { case WLR_BUTTON_PRESSED: @@ -599,6 +602,7 @@ checkidleinhibitor(struct wlr_surface *exclude) } wlr_idle_set_enabled(idle, NULL, !inhibited); + wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited); } void @@ -1239,7 +1243,7 @@ keypress(struct wl_listener *listener, void *data) int handled = 0; uint32_t mods = wlr_keyboard_get_modifiers(kb->wlr_keyboard); - wlr_idle_notify_activity(idle, seat); + IDLE_NOTIFY_ACTIVITY; /* On _press_ if there is no active screen locker, * attempt to process a compositor keybinding. */ @@ -1403,7 +1407,7 @@ motionnotify(uint32_t time) /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { - wlr_idle_notify_activity(idle, seat); + IDLE_NOTIFY_ACTIVITY; /* Update selmon (even while dragging a window) */ if (sloppyfocus) @@ -2029,6 +2033,7 @@ setup(void) 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); wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &idle_inhibitor_create); From 8298f20a7174eb9c70b375b92810ab3320fedf97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 29 Oct 2022 18:30:09 -0500 Subject: [PATCH 045/312] allow change adaptive sync in outputmgrapplyortest() --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index 3ba4eaf..7d41883 100644 --- a/dwl.c +++ b/dwl.c @@ -1557,6 +1557,8 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) 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, + config_head->state.adaptive_sync_enabled); apply_or_test: if (test) { From 99f062273e6a04abe4258c23284087698a8ecad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 29 Oct 2022 19:02:44 -0500 Subject: [PATCH 046/312] only destroy monitor's layer surfaces at destroy --- dwl.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index 7d41883..8b019da 100644 --- a/dwl.c +++ b/dwl.c @@ -644,12 +644,9 @@ cleanupmon(struct wl_listener *listener, void *data) LayerSurface *l, *tmp; int i; - for (i = 0; i <= ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; i++) { - wl_list_for_each_safe(l, tmp, &m->layers[i], link) { - wlr_scene_node_set_enabled(&l->scene->node, 0); + for (i = 0; i <= ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; 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); From 448a96de13042c76634c2a898c370889b33693d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 30 Oct 2022 01:03:44 -0500 Subject: [PATCH 047/312] remove now unneeded workaround in outputmgrapplyortest() --- dwl.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/dwl.c b/dwl.c index 8b019da..fa59386 100644 --- a/dwl.c +++ b/dwl.c @@ -1562,23 +1562,7 @@ apply_or_test: ok &= wlr_output_test(wlr_output); wlr_output_rollback(wlr_output); } else { - int output_ok = 1; - /* If it's a custom mode to avoid an assertion failed in wlr_output_commit() - * we test if that mode does not fail rather than just call wlr_output_commit(). - * We do not test normal modes because (at least in my hardware (@sevz17)) - * wlr_output_test() fails even if that mode can actually be set */ - if (!config_head->state.mode && config_head->state.enabled) - ok &= (output_ok = wlr_output_test(wlr_output) - && wlr_output_commit(wlr_output)); - else - ok &= wlr_output_commit(wlr_output); - - /* In custom modes we call wlr_output_test(), it it fails - * we need to rollback, and normal modes seems to does not cause - * assertions failed in wlr_output_commit() which rollback - * the output on failure */ - if (!output_ok) - wlr_output_rollback(wlr_output); + ok &= wlr_output_commit(wlr_output); } } 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 048/312] 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 049/312] 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 050/312] 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 051/312] 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 052/312] 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 88d386bfdcedb8b46d7c4c7a3ebac2476cfcf46b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sat, 12 Nov 2022 20:05:56 -0600 Subject: [PATCH 053/312] configurex11: resize floating clients and arrange tiled clients' monitor --- dwl.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 3bf5cdc..2903d9d 100644 --- a/dwl.c +++ b/dwl.c @@ -2486,8 +2486,13 @@ configurex11(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, configure); struct wlr_xwayland_surface_configure_event *event = data; - wlr_xwayland_surface_configure(c->surface.xwayland, - event->x, event->y, event->width, event->height); + if (!c->mon) + return; + if (c->isfloating || c->type == X11Unmanaged) + resize(c, (struct wlr_box){.x = event->x, .y = event->y, + .width = event->width, .height = event->height}, 0); + else + arrange(c->mon); } void From 93a911d6e93f760a5139bfe0d1c1eb90886c414f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 13 Nov 2022 16:39:17 -0600 Subject: [PATCH 054/312] simplify `if` expression in checkidleinhibitor() --- dwl.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index 2903d9d..8599764 100644 --- a/dwl.c +++ b/dwl.c @@ -588,16 +588,15 @@ chvt(const Arg *arg) void checkidleinhibitor(struct wlr_surface *exclude) { + Client *c; int inhibited = 0; struct wlr_idle_inhibitor_v1 *inhibitor; wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { - 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)) { + if (exclude != inhibitor->surface + && (!(c = client_from_wlr_surface(inhibitor->surface)) + || VISIBLEON(c, c->mon))) { inhibited = 1; break; } From 60a98b87f395618be8d35c1100e019588e255d78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 13 Nov 2022 16:46:43 -0600 Subject: [PATCH 055/312] inhibit idle if surface's node is enabled --- dwl.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/dwl.c b/dwl.c index 8599764..949f7b3 100644 --- a/dwl.c +++ b/dwl.c @@ -588,15 +588,12 @@ chvt(const Arg *arg) void checkidleinhibitor(struct wlr_surface *exclude) { - Client *c; int inhibited = 0; + struct wlr_scene_tree *tree; struct wlr_idle_inhibitor_v1 *inhibitor; wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { - /* In case we can't get a client from the surface assume that it is - * visible, for example a layer surface */ - if (exclude != inhibitor->surface - && (!(c = client_from_wlr_surface(inhibitor->surface)) - || VISIBLEON(c, c->mon))) { + if (exclude != inhibitor->surface && (tree = inhibitor->surface->data) + && tree->node.enabled) { inhibited = 1; break; } From 63d6de58669ea4ee6876e7e624fa3c3bd9e83a0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Sun, 13 Nov 2022 16:57:41 -0600 Subject: [PATCH 056/312] fix set of layersurface->popups and surface->data --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 949f7b3..3f2b261 100644 --- a/dwl.c +++ b/dwl.c @@ -804,7 +804,7 @@ createlayersurface(struct wl_listener *listener, void *data) layers[wlr_layer_surface->pending.layer], 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])->node; + wlr_scene_tree_create(layers[wlr_layer_surface->pending.layer]); layersurface->scene->node.data = layersurface; From 7eebe677879373672774c06c81c0e3eda22d03ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 15 Nov 2022 22:29:26 -0600 Subject: [PATCH 057/312] set x and y of the layersurface's geometry box --- dwl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwl.c b/dwl.c index 3f2b261..579dad1 100644 --- a/dwl.c +++ b/dwl.c @@ -466,6 +466,8 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int 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; } } From 05eca0e2d95a44a2d33959b8362a21a0f974e17a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Tue, 15 Nov 2022 22:32:20 -0600 Subject: [PATCH 058/312] rename xwayland_surface to xsurface this save us 2 lines --- dwl.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/dwl.c b/dwl.c index 579dad1..88c398f 100644 --- a/dwl.c +++ b/dwl.c @@ -2496,7 +2496,7 @@ configurex11(struct wl_listener *listener, void *data) void createnotifyx11(struct wl_listener *listener, void *data) { - struct wlr_xwayland_surface *xwayland_surface = data; + struct wlr_xwayland_surface *xsurface = data; Client *c; /* TODO: why we unset fullscreen when a xwayland client is created? */ wl_list_for_each(c, &clients, link) @@ -2504,22 +2504,20 @@ createnotifyx11(struct wl_listener *listener, void *data) setfullscreen(c, 0); /* Allocate a Client for this surface */ - c = xwayland_surface->data = ecalloc(1, sizeof(*c)); - c->surface.xwayland = xwayland_surface; - c->type = xwayland_surface->override_redirect ? X11Unmanaged : X11Managed; + c = xsurface->data = ecalloc(1, sizeof(*c)); + c->surface.xwayland = xsurface; + c->type = xsurface->override_redirect ? X11Unmanaged : X11Managed; c->bw = borderpx; /* Listen to the various events it can emit */ - LISTEN(&xwayland_surface->events.map, &c->map, mapnotify); - LISTEN(&xwayland_surface->events.unmap, &c->unmap, unmapnotify); - LISTEN(&xwayland_surface->events.request_activate, &c->activate, activatex11); - LISTEN(&xwayland_surface->events.request_configure, &c->configure, - configurex11); - LISTEN(&xwayland_surface->events.set_hints, &c->set_hints, sethints); - LISTEN(&xwayland_surface->events.set_title, &c->set_title, updatetitle); - LISTEN(&xwayland_surface->events.destroy, &c->destroy, destroynotify); - LISTEN(&xwayland_surface->events.request_fullscreen, &c->fullscreen, - fullscreennotify); + LISTEN(&xsurface->events.map, &c->map, mapnotify); + LISTEN(&xsurface->events.unmap, &c->unmap, unmapnotify); + 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); + LISTEN(&xsurface->events.set_title, &c->set_title, updatetitle); + LISTEN(&xsurface->events.destroy, &c->destroy, destroynotify); + LISTEN(&xsurface->events.request_fullscreen, &c->fullscreen, fullscreennotify); } Atom From caec566286b1bbef1758bcf0599677650017c5b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 11 Nov 2022 00:22:36 -0600 Subject: [PATCH 059/312] create a dedicated layer for fullscreen clients Bug: https://github.com/djpohly/dwl/issues/327 --- dwl.c | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/dwl.c b/dwl.c index 88c398f..aacc345 100644 --- a/dwl.c +++ b/dwl.c @@ -73,7 +73,7 @@ /* enums */ enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ enum { XDGShell, LayerShell, X11Managed, X11Unmanaged }; /* client types */ -enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrDragIcon, NUM_LAYERS }; /* scene layers */ +enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrFS, LyrDragIcon, NUM_LAYERS }; /* scene layers */ #ifdef XWAYLAND enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ @@ -102,7 +102,6 @@ typedef struct { struct wlr_scene_tree *scene; struct wlr_scene_rect *border[4]; /* top, bottom, left, right */ struct wlr_scene_tree *scene_surface; - struct wlr_scene_rect *fullscreen_bg; /* See setfullscreen() for info */ struct wl_list link; struct wl_list flink; union { @@ -171,6 +170,7 @@ struct Monitor { struct wl_list link; struct wlr_output *wlr_output; struct wlr_scene_output *scene_output; + struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */ struct wl_listener frame; struct wl_listener destroy; struct wlr_box m; /* monitor area, layout-relative */ @@ -445,6 +445,9 @@ arrange(Monitor *m) if (c->mon == m) wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m)); + wlr_scene_node_set_enabled(&m->fullscreen_bg->node, + (c = focustop(m)) && c->isfullscreen); + if (m && m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); motionnotify(0); @@ -655,6 +658,7 @@ 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); free(m); @@ -874,6 +878,18 @@ createmon(struct wl_listener *listener, void *data) wl_list_insert(&mons, &m->link); printstatus(); + /* The xdg-protocol specifies: + * + * If the fullscreened surface is not opaque, the compositor must make + * sure that other screen content not part of the same surface tree (made + * up of subsurfaces, popups or similarly coupled surfaces) are not + * visible below the fullscreened surface. + * + */ + /* updatemons() will resize and set correct position */ + 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. * * The output layout utility automatically adds a wl_output global to the @@ -1724,8 +1740,6 @@ 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, @@ -1833,32 +1847,16 @@ 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 + ? LyrFS : c->isfloating ? LyrFloat : LyrTile]); if (fullscreen) { c->prev = c->geom; resize(c, c->mon->m, 0); - /* The xdg-protocol specifies: - * - * If the fullscreened surface is not opaque, the compositor must make - * sure that other screen content not part of the same surface tree (made - * up of subsurfaces, popups or similarly coupled surfaces) are not - * visible below the fullscreened surface. - * - * For brevity we set a black background for all clients - */ - if (!c->fullscreen_bg) { - c->fullscreen_bg = wlr_scene_rect_create(c->scene, - c->geom.width, c->geom.height, fullscreen_bg); - wlr_scene_node_lower_to_bottom(&c->fullscreen_bg->node); - } } else { /* restore previous size instead of arrange for floating windows since * client positions are set by the user and cannot be recalculated */ resize(c, c->prev, 0); - if (c->fullscreen_bg) { - wlr_scene_node_destroy(&c->fullscreen_bg->node); - c->fullscreen_bg = NULL; - } } arrange(c->mon); printstatus(); @@ -1976,6 +1974,7 @@ setup(void) 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); @@ -2342,6 +2341,9 @@ updatemons(struct wl_listener *listener, void *data) /* Don't move clients to the left output when plugging monitors */ arrange(m); + wlr_scene_node_set_position(&m->fullscreen_bg->node, m->m.x, m->m.y); + wlr_scene_rect_set_size(m->fullscreen_bg, m->m.width, m->m.height); + config_head->state.enabled = 1; config_head->state.mode = m->wlr_output->current_mode; config_head->state.x = m->m.x; @@ -2411,7 +2413,7 @@ xytonode(double x, double y, struct wlr_surface **psurface, Client *c = NULL; LayerSurface *l = NULL; const int *layer; - int focus_order[] = { LyrOverlay, LyrTop, LyrFloat, LyrTile, LyrBottom, LyrBg }; + int focus_order[] = { LyrOverlay, LyrTop, LyrFS, LyrFloat, LyrTile, LyrBottom, LyrBg }; for (layer = focus_order; layer < END(focus_order); layer++) { if ((node = wlr_scene_node_at(&layers[*layer]->node, x, y, nx, ny))) { From 087373698afeab0af9257358955f1c3c772d24e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 21 Nov 2022 14:44:24 -0600 Subject: [PATCH 060/312] Revert "Add a configuration option for fullscreen locking" now all fullcreen clients are rendered above tiled and floating clients This partially reverts commit 326eee14445f8a2c08e80c30778445630c75d3bb. --- config.def.h | 1 - dwl.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/config.def.h b/config.def.h index b3caab3..0473b40 100644 --- a/config.def.h +++ b/config.def.h @@ -1,7 +1,6 @@ /* appearance */ static const int sloppyfocus = 1; /* focus follows mouse */ static const unsigned int borderpx = 1; /* border pixel of windows */ -static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ 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}; diff --git a/dwl.c b/dwl.c index aacc345..c1ff934 100644 --- a/dwl.c +++ b/dwl.c @@ -1156,7 +1156,7 @@ focusstack(const Arg *arg) { /* Focus the next or previous client (in tiling order) on selmon */ Client *c, *sel = selclient(); - if (!sel || (sel->isfullscreen && lockfullscreen)) + if (!sel || sel->isfullscreen) return; if (arg->i > 0) { wl_list_for_each(c, &sel->link, link) { From 3213088aa23e1f6cad1a5ba506dfb7318e1011c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 30 Nov 2022 17:42:58 -0600 Subject: [PATCH 061/312] do not try to set the parent's same tags and monitor for xwayland clients References: https://github.com/djpohly/dwl/pull/334#issuecomment-1330166324 --- dwl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index c1ff934..fd22c8f 100644 --- a/dwl.c +++ b/dwl.c @@ -1381,7 +1381,8 @@ 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 */ - if ((p = client_get_parent(c))) { + /* 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); From c91d21b68f436bc61dfce8b3f47beb5855bdd1a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 25 Nov 2022 12:15:55 -0600 Subject: [PATCH 062/312] do not move/resize if grabbed client is fullscreen --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index fd22c8f..4648890 100644 --- a/dwl.c +++ b/dwl.c @@ -1510,7 +1510,7 @@ moveresize(const Arg *arg) if (cursor_mode != CurNormal && cursor_mode != CurPressed) return; xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); - if (!grabc || client_is_unmanaged(grabc)) + if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen) return; /* Float the window and tell motionnotify to grab it */ From 10c56d63489506ee852f3ec18f078e60ba1885f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 30 Nov 2022 18:51:35 -0600 Subject: [PATCH 063/312] add option to allow invisible surfaces to disable idle tracking --- config.def.h | 13 +++++++------ dwl.c | 5 +++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/config.def.h b/config.def.h index 0473b40..8f01192 100644 --- a/config.def.h +++ b/config.def.h @@ -1,11 +1,12 @@ /* appearance */ -static const int sloppyfocus = 1; /* focus follows mouse */ -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}; +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 */ -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}; /* tagging */ static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; diff --git a/dwl.c b/dwl.c index 4648890..f07a867 100644 --- a/dwl.c +++ b/dwl.c @@ -597,8 +597,9 @@ checkidleinhibitor(struct wlr_surface *exclude) struct wlr_scene_tree *tree; struct wlr_idle_inhibitor_v1 *inhibitor; wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { - if (exclude != inhibitor->surface && (tree = inhibitor->surface->data) - && tree->node.enabled) { + if (bypass_surface_visibility || (exclude != inhibitor->surface + && (tree = inhibitor->surface->data) + && tree->node.enabled)) { inhibited = 1; break; } From 6df6781b437937e835d8caca14024829747bd2ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Wed, 30 Nov 2022 18:54:54 -0600 Subject: [PATCH 064/312] simplify check for surface's node state all `struct wlr_surface` should have a `wlr_scene_tree *` as data --- dwl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index f07a867..3f6db50 100644 --- a/dwl.c +++ b/dwl.c @@ -594,11 +594,10 @@ void checkidleinhibitor(struct wlr_surface *exclude) { int inhibited = 0; - struct wlr_scene_tree *tree; struct wlr_idle_inhibitor_v1 *inhibitor; wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { + struct wlr_scene_tree *tree = inhibitor->surface->data; if (bypass_surface_visibility || (exclude != inhibitor->surface - && (tree = inhibitor->surface->data) && tree->node.enabled)) { inhibited = 1; break; From b4fb1f77c768fb7bd568d3cc67c59dcfdb7cae28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Thu, 1 Dec 2022 20:49:49 -0600 Subject: [PATCH 065/312] fix xwayland clients being floating by default Fix 3213088aa23e1f6cad1a5ba506dfb7318e1011c9 References: https://github.com/djpohly/dwl/pull/334#issuecomment-1333147730 --- client.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client.h b/client.h index 3c81135..c18d01a 100644 --- a/client.h +++ b/client.h @@ -184,8 +184,7 @@ client_is_float_type(Client *c) } #endif return ((min.width > 0 || min.height > 0 || max.width > 0 || max.height > 0) - && (min.width == max.width || min.height == max.height)) - || client_get_parent(c); + && (min.width == max.width || min.height == max.height)); } static inline int From f929eaef1e15c2624de20cdcb0e348e6cab21152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Fri, 2 Dec 2022 10:07:24 -0600 Subject: [PATCH 066/312] ask for version instead of commit in bug reports --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 64e2054..6b60803 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -8,7 +8,7 @@ assignees: '' --- ## Info -dwl's commit: +dwl version: wlroots version: ## Description From f8884ffc2b7a4c0401f0a6710b679cd18b6b097d Mon Sep 17 00:00:00 2001 From: Nikita Ivanov Date: Sun, 28 May 2023 19:09:38 +0200 Subject: [PATCH 140/312] 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 141/312] 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 142/312] 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 143/312] 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 144/312] 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 145/312] 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 146/312] 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 147/312] 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 148/312] 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 149/312] 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 150/312] 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 151/312] 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 152/312] 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 153/312] 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 154/312] 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 155/312] 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 156/312] 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 157/312] 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 158/312] 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 159/312] 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 160/312] 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 161/312] 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 162/312] 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 163/312] 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 164/312] 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 165/312] 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 166/312] 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 167/312] 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 168/312] 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 169/312] 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 170/312] 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 171/312] 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 172/312] 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 173/312] 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 174/312] 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 175/312] 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 176/312] 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 177/312] 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 178/312] 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 179/312] 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 180/312] 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 181/312] 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 182/312] 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 183/312] 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 184/312] 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 185/312] 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 186/312] 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 187/312] 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 188/312] 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 189/312] 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 190/312] 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 191/312] 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 192/312] 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 193/312] 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 194/312] 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 195/312] 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 196/312] 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 197/312] 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 198/312] 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 199/312] 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 200/312] 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 201/312] 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 202/312] 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 203/312] 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 204/312] 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 205/312] 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 206/312] 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 207/312] 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 208/312] 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 209/312] 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 210/312] 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 211/312] 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 212/312] 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 213/312] 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 214/312] 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 215/312] 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 216/312] 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 217/312] 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 218/312] 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 219/312] 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 220/312] 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 221/312] 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 222/312] 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 223/312] 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 224/312] 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 225/312] 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 226/312] 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 227/312] 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 228/312] 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 229/312] 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 230/312] 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 231/312] 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 232/312] 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 233/312] 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 234/312] 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 235/312] 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 236/312] 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 237/312] 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 238/312] 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 239/312] 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 240/312] 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 241/312] 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 242/312] 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 243/312] 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 244/312] 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 245/312] 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 246/312] 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 247/312] 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 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 248/312] 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 249/312] 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 250/312] 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 251/312] 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 252/312] 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 253/312] 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 254/312] 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 255/312] 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 256/312] 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 257/312] 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 258/312] 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 259/312] 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 260/312] 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 261/312] 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 262/312] 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 263/312] 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 264/312] 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 265/312] 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 266/312] 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 267/312] 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 268/312] 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 269/312] 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 270/312] 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 271/312] 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 272/312] 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 273/312] 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 274/312] 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 275/312] 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 276/312] 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 277/312] 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 278/312] 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 279/312] 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 280/312] 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 281/312] 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 282/312] 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 283/312] 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 284/312] 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 285/312] 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 286/312] 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 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 287/312] 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 25e34e4d0c97165eef627b70b916967852ec1f5e Mon Sep 17 00:00:00 2001 From: Ben Jargowsky Date: Sat, 6 Jan 2024 17:29:39 -0800 Subject: [PATCH 288/312] 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 289/312] 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 290/312] 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 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 291/312] 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 292/312] 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 293/312] 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 294/312] 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 295/312] 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 296/312] 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 297/312] 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 298/312] 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 299/312] 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 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 300/312] 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 301/312] 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 863634a61cd953ea82d5fd1e4fa4d04e8b48a23f Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Thu, 25 Jan 2024 09:04:14 +0100 Subject: [PATCH 302/312] 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 303/312] 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 304/312] 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 305/312] 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 306/312] 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 307/312] 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 308/312] 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 309/312] 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 310/312] 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 311/312] 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 82ff3cb6e6eee15a9ad23bdc452d67598ad7187b Mon Sep 17 00:00:00 2001 From: Mahesh Asolkar Date: Sat, 17 Feb 2024 18:47:07 -0800 Subject: [PATCH 312/312] Added IPC v2 patch --- Makefile | 13 +- dwl.c | 316 ++++++++++++++-- ipc-v2-fixed.patch | 575 ++++++++++++++++++++++++++++++ protocols/dwl-ipc-unstable-v2.xml | 181 ++++++++++ 4 files changed, 1046 insertions(+), 39 deletions(-) create mode 100644 ipc-v2-fixed.patch create mode 100644 protocols/dwl-ipc-unstable-v2.xml diff --git a/Makefile b/Makefile index 0822ddc..f49a945 100644 --- a/Makefile +++ b/Makefile @@ -14,10 +14,11 @@ DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CF 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: dwl.o util.o dwl-ipc-unstable-v2-protocol.o + $(CC) dwl.o util.o dwl-ipc-unstable-v2-protocol.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-ipc-unstable-v2-protocol.h util.o: util.c util.h +dwl-ipc-unstable-v2-protocol.o: dwl-ipc-unstable-v2-protocol.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 @@ -34,6 +35,12 @@ wlr-layer-shell-unstable-v1-protocol.h: cursor-shape-v1-protocol.h: $(WAYLAND_SCANNER) server-header \ $(WAYLAND_PROTOCOLS)/staging/cursor-shape/cursor-shape-v1.xml $@ +dwl-ipc-unstable-v2-protocol.h: + $(WAYLAND_SCANNER) server-header \ + protocols/dwl-ipc-unstable-v2.xml $@ +dwl-ipc-unstable-v2-protocol.c: + $(WAYLAND_SCANNER) private-code \ + protocols/dwl-ipc-unstable-v2.xml $@ config.h: cp config.def.h $@ diff --git a/dwl.c b/dwl.c index fa76db2..c843579 100644 --- a/dwl.c +++ b/dwl.c @@ -61,6 +61,7 @@ #include #endif +#include "dwl-ipc-unstable-v2-protocol.h" #include "util.h" /* macros */ @@ -138,6 +139,12 @@ typedef struct { uint32_t resize; /* configure serial of a pending resize */ } Client; +typedef struct { + struct wl_list link; + struct wl_resource *resource; + Monitor *mon; +} DwlIpcOutput; + typedef struct { uint32_t mod; xkb_keysym_t keysym; @@ -183,6 +190,7 @@ typedef struct { struct Monitor { struct wl_list link; + struct wl_list dwl_ipc_outputs; struct wlr_output *wlr_output; struct wlr_scene_output *scene_output; struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */ @@ -266,6 +274,17 @@ 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 Monitor *dirtomon(enum wlr_direction dir); +static void dwl_ipc_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id); +static void dwl_ipc_manager_destroy(struct wl_resource *resource); +static void dwl_ipc_manager_get_output(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *output); +static void dwl_ipc_manager_release(struct wl_client *client, struct wl_resource *resource); +static void dwl_ipc_output_destroy(struct wl_resource *resource); +static void dwl_ipc_output_printstatus(Monitor *monitor); +static void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output); +static void dwl_ipc_output_set_client_tags(struct wl_client *client, struct wl_resource *resource, uint32_t and_tags, uint32_t xor_tags); +static void dwl_ipc_output_set_layout(struct wl_client *client, struct wl_resource *resource, uint32_t index); +static void dwl_ipc_output_set_tags(struct wl_client *client, struct wl_resource *resource, uint32_t tagmask, uint32_t toggle_tagset); +static void dwl_ipc_output_release(struct wl_client *client, struct wl_resource *resource); static void focusclient(Client *c, int lift); static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); @@ -317,6 +336,7 @@ static void startdrag(struct wl_listener *listener, void *data); static void tag(const Arg *arg); static void tagmon(const Arg *arg); static void tile(Monitor *m); +static void togglebar(const Arg *arg); static void togglefloating(const Arg *arg); static void togglefullscreen(const Arg *arg); static void toggletag(const Arg *arg); @@ -358,6 +378,8 @@ 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_notifier_v1 *idle_notifier; +static struct zdwl_ipc_manager_v2_interface dwl_manager_implementation = {.release = dwl_ipc_manager_release, .get_output = dwl_ipc_manager_get_output}; +static struct zdwl_ipc_output_v2_interface dwl_output_implementation = {.release = dwl_ipc_output_release, .set_tags = dwl_ipc_output_set_tags, .set_layout = dwl_ipc_output_set_layout, .set_client_tags = dwl_ipc_output_set_client_tags}; 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; @@ -667,6 +689,9 @@ cleanupmon(struct wl_listener *listener, void *data) LayerSurface *l, *tmp; size_t i; + DwlIpcOutput *ipc_output, *ipc_output_tmp; + wl_list_for_each_safe(ipc_output, ipc_output_tmp, &m->dwl_ipc_outputs, link) + wl_resource_destroy(ipc_output->resource); /* 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) @@ -891,6 +916,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); + wl_list_init(&m->dwl_ipc_outputs); + wlr_output_state_set_enabled(&state, 1); wlr_output_commit_state(wlr_output, &state); wlr_output_state_finish(&state); @@ -1159,12 +1186,219 @@ dirtomon(enum wlr_direction dir) dir, selmon->wlr_output, selmon->m.x, selmon->m.y))) return next->data; if ((next = wlr_output_layout_farthest_output(output_layout, - dir ^ (WLR_DIRECTION_LEFT|WLR_DIRECTION_RIGHT), + dir ^ (WLR_DIRECTION_UP|WLR_DIRECTION_DOWN|WLR_DIRECTION_LEFT|WLR_DIRECTION_RIGHT), selmon->wlr_output, selmon->m.x, selmon->m.y))) return next->data; return selmon; } +void +dwl_ipc_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) +{ + struct wl_resource *manager_resource = wl_resource_create(client, &zdwl_ipc_manager_v2_interface, version, id); + if (!manager_resource) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(manager_resource, &dwl_manager_implementation, NULL, dwl_ipc_manager_destroy); + + // printf("DWL::dwl_ipc_manager - EVENT Sent tagcount = %d\n", TAGCOUNT); + zdwl_ipc_manager_v2_send_tags(manager_resource, TAGCOUNT); + + for (long unsigned int i = 0; i < LENGTH(layouts); i++) { + // printf("DWL::dwl_ipc_manager - EVENT Sent layout = %s\n", layouts[i].symbol); + zdwl_ipc_manager_v2_send_layout(manager_resource, layouts[i].symbol); + } +} + +void +dwl_ipc_manager_destroy(struct wl_resource *resource) +{ + /* No state to destroy */ +} + +void +dwl_ipc_manager_get_output(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *output) +{ + DwlIpcOutput *ipc_output; + Monitor *monitor = wlr_output_from_resource(output)->data; + struct wl_resource *output_resource = wl_resource_create(client, &zdwl_ipc_output_v2_interface, wl_resource_get_version(resource), id); + if (!output_resource) + return; + + ipc_output = ecalloc(1, sizeof(*ipc_output)); + ipc_output->resource = output_resource; + ipc_output->mon = monitor; + wl_resource_set_implementation(output_resource, &dwl_output_implementation, ipc_output, dwl_ipc_output_destroy); + wl_list_insert(&monitor->dwl_ipc_outputs, &ipc_output->link); + dwl_ipc_output_printstatus_to(ipc_output); +} + +void +dwl_ipc_manager_release(struct wl_client *client, struct wl_resource *resource) +{ + // printf("DWL::dwl_ipc_manager_release - REQUEST Received\n"); + wl_resource_destroy(resource); +} + +static void +dwl_ipc_output_destroy(struct wl_resource *resource) +{ + DwlIpcOutput *ipc_output = wl_resource_get_user_data(resource); + wl_list_remove(&ipc_output->link); + free(ipc_output); +} + +void +dwl_ipc_output_printstatus(Monitor *monitor) +{ + DwlIpcOutput *ipc_output; + // printf("DWL::dwl_ipc_output_printstatus - Starting\n"); + wl_list_for_each(ipc_output, &monitor->dwl_ipc_outputs, link) { + // printf("DWL::dwl_ipc_output_printstatus - In input\n"); + dwl_ipc_output_printstatus_to(ipc_output); + } +} + +void +dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output) +{ + Monitor *monitor = ipc_output->mon; + Client *c, *focused; + int tagmask, state, numclients, focused_client, tag; + const char *title, *appid; + focused = focustop(monitor); + // printf("DWL::dwl_ipc_output - EVENT Sent active = %d\n", (monitor == selmon)); + zdwl_ipc_output_v2_send_active(ipc_output->resource, monitor == selmon); + + for (tag = 0 ; tag < TAGCOUNT; tag++) { + // printf("DWL::dwl_ipc_output_printstatus_to - tag = %d\n", tag); + numclients = state = focused_client = 0; + tagmask = 1 << tag; + if ((tagmask & monitor->tagset[monitor->seltags]) != 0) + state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_ACTIVE; + + wl_list_for_each(c, &clients, link) { + if (c->mon != monitor) + continue; + if (!(c->tags & tagmask)) + continue; + if (c == focused) + focused_client = 1; + if (c->isurgent) + state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_URGENT; + + numclients++; + } + // numclients = state = focused_client = 0; + // printf("DWL::dwl_ipc_output - EVENT Sent tag = %d, num_clients = %d\n", + // tag, numclients); + zdwl_ipc_output_v2_send_tag(ipc_output->resource, tag, state, numclients, focused_client); + // printf("DWL::dwl_ipc_output_printstatus_to - after send_tag tag = %d, num_clients = %d\n", + // tag, numclients); + } + title = focused ? client_get_title(focused) : "NF"; + appid = focused ? client_get_appid(focused) : "NF"; + + // printf("DWL::dwl_ipc_output - EVENT Sent layout = %lu\n", monitor->lt[monitor->sellt] - layouts); + zdwl_ipc_output_v2_send_layout(ipc_output->resource, monitor->lt[monitor->sellt] - layouts); + // printf("DWL::dwl_ipc_output - EVENT Sent title = %s\n", title ? title : broken); + zdwl_ipc_output_v2_send_title(ipc_output->resource, title ? title : broken); + // printf("DWL::dwl_ipc_output - EVENT Sent appid = %s\n", appid ? appid : broken); + zdwl_ipc_output_v2_send_appid(ipc_output->resource, appid ? appid : broken); + // printf("DWL::dwl_ipc_output - EVENT Sent layout_symbol = %s\n", monitor->ltsymbol); + zdwl_ipc_output_v2_send_layout_symbol(ipc_output->resource, monitor->ltsymbol); + if (wl_resource_get_version(ipc_output->resource) >= ZDWL_IPC_OUTPUT_V2_FULLSCREEN_SINCE_VERSION) { + zdwl_ipc_output_v2_send_fullscreen(ipc_output->resource, focused ? focused->isfullscreen : 0); + } + if (wl_resource_get_version(ipc_output->resource) >= ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION) { + zdwl_ipc_output_v2_send_floating(ipc_output->resource, focused ? focused->isfloating : 0); + } + // printf("DWL::dwl_ipc_output - EVENT Sent frame = done (dwl_ipc_output_printstatus_to)\n"); + zdwl_ipc_output_v2_send_frame(ipc_output->resource); +} + +void +dwl_ipc_output_set_client_tags(struct wl_client *client, struct wl_resource *resource, uint32_t and_tags, uint32_t xor_tags) +{ + DwlIpcOutput *ipc_output; + Monitor *monitor; + Client *selected_client; + unsigned int newtags = 0; + + // printf("DWL::dwl_ipc_output - REQUEST Received set_client_tags and_tags = %d, xor_tags = %d\n", and_tags, xor_tags); + ipc_output = wl_resource_get_user_data(resource); + if (!ipc_output) + return; + + monitor = ipc_output->mon; + selected_client = focustop(monitor); + if (!selected_client) + return; + + newtags = (selected_client->tags & and_tags) ^ xor_tags; + if (!newtags) + return; + + selected_client->tags = newtags; + focusclient(focustop(selmon), 1); + arrange(selmon); + printstatus(); +} + +void +dwl_ipc_output_set_layout(struct wl_client *client, struct wl_resource *resource, uint32_t index) +{ + DwlIpcOutput *ipc_output; + Monitor *monitor; + + // printf("DWL::dwl_ipc_output - REQUEST Received set_layout index = %d\n", index); + ipc_output = wl_resource_get_user_data(resource); + if (!ipc_output) + return; + + monitor = ipc_output->mon; + if (index >= LENGTH(layouts)) + return; + if (index != monitor->lt[monitor->sellt] - layouts) + monitor->sellt ^= 1; + + monitor->lt[monitor->sellt] = &layouts[index]; + arrange(monitor); + printstatus(); +} + +void +dwl_ipc_output_set_tags(struct wl_client *client, struct wl_resource *resource, uint32_t tagmask, uint32_t toggle_tagset) +{ + DwlIpcOutput *ipc_output; + Monitor *monitor; + unsigned int newtags = tagmask & TAGMASK; + + // printf("DWL::dwl_ipc_output - REQUEST Received set_tags tagmask = %d, toggle_tagset = %d\n", tagmask, toggle_tagset); + ipc_output = wl_resource_get_user_data(resource); + if (!ipc_output) + return; + monitor = ipc_output->mon; + + if (!newtags || newtags == monitor->tagset[monitor->seltags]) + return; + if (toggle_tagset) + monitor->seltags ^= 1; + + monitor->tagset[monitor->seltags] = newtags; + focusclient(focustop(monitor), 1); + arrange(monitor); + printstatus(); +} + +void +dwl_ipc_output_release(struct wl_client *client, struct wl_resource *resource) +{ + // printf("DWL::dwl_ipc_output_release - REQUEST Received\n"); + wl_resource_destroy(resource); +} + void focusclient(Client *c, int lift) { @@ -1367,15 +1601,16 @@ 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); - return 1; + handled = 1; } } - return 0; + return handled; } void @@ -1807,41 +2042,41 @@ void printstatus(void) { Monitor *m = NULL; - Client *c; - uint32_t occ, urg, sel; - const char *appid, *title; - + // printf("DWL::printstatus - Starting\n"); wl_list_for_each(m, &mons, link) { - occ = urg = 0; - wl_list_for_each(c, &clients, link) { - if (c->mon != m) - continue; - occ |= c->tags; - if (c->isurgent) - 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 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); - 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; - } + // occ = urg = 0; + // wl_list_for_each(c, &clients, link) { + // if (c->mon != m) + // continue; + // occ |= c->tags; + // if (c->isurgent) + // 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 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); + // 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; + // } - printf("%s selmon %u\n", m->wlr_output->name, m == selmon); - 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); + // printf("%s selmon %u\n", m->wlr_output->name, m == selmon); + // 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); + // printf("DWL::printstatus - In monitor\n"); + dwl_ipc_output_printstatus(m); + } } void @@ -2399,6 +2634,7 @@ setup(void) LISTEN_STATIC(&output_mgr->events.test, outputmgrtest); wlr_scene_set_presentation(scene, wlr_presentation_create(dpy, backend)); + wl_global_create(dpy, &zdwl_ipc_manager_v2_interface, 2, NULL, dwl_ipc_manager_bind); /* 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 @@ -2497,6 +2733,14 @@ tile(Monitor *m) } } +void +togglebar(const Arg *arg) { + DwlIpcOutput *ipc_output; + wl_list_for_each(ipc_output, &selmon->dwl_ipc_outputs, link) + // printf("DWL::dwl_ipc_output - EVENT Sent toggle_visibility\n"); + zdwl_ipc_output_v2_send_toggle_visibility(ipc_output->resource); +} + void togglefloating(const Arg *arg) { diff --git a/ipc-v2-fixed.patch b/ipc-v2-fixed.patch new file mode 100644 index 0000000..e82e9bb --- /dev/null +++ b/ipc-v2-fixed.patch @@ -0,0 +1,575 @@ +diff --git a/Makefile b/Makefile +index 5320e42..c13557c 100644 +--- a/Makefile ++++ b/Makefile +@@ -14,10 +14,11 @@ DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CF + 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: dwl.o util.o dwl-ipc-unstable-v2-protocol.o ++ $(CC) dwl.o util.o dwl-ipc-unstable-v2-protocol.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-ipc-unstable-v2-protocol.h + util.o: util.c util.h ++dwl-ipc-unstable-v2-protocol.o: dwl-ipc-unstable-v2-protocol.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 +@@ -31,6 +32,12 @@ xdg-shell-protocol.h: + wlr-layer-shell-unstable-v1-protocol.h: + $(WAYLAND_SCANNER) server-header \ + protocols/wlr-layer-shell-unstable-v1.xml $@ ++dwl-ipc-unstable-v2-protocol.h: ++ $(WAYLAND_SCANNER) server-header \ ++ protocols/dwl-ipc-unstable-v2.xml $@ ++dwl-ipc-unstable-v2-protocol.c: ++ $(WAYLAND_SCANNER) private-code \ ++ protocols/dwl-ipc-unstable-v2.xml $@ + + config.h: + cp config.def.h $@ +diff --git a/config.def.h b/config.def.h +index 4e30885..f285840 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -120,6 +120,7 @@ static const Key keys[] = { + /* modifier key function argument */ + { MODKEY, XKB_KEY_p, spawn, {.v = menucmd} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} }, ++ { MODKEY, XKB_KEY_b, togglebar, {0}}, + { MODKEY, XKB_KEY_j, focusstack, {.i = +1} }, + { MODKEY, XKB_KEY_k, focusstack, {.i = -1} }, + { MODKEY, XKB_KEY_i, incnmaster, {.i = +1} }, +diff --git a/dwl.c b/dwl.c +index a7d41b0..e507e31 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -58,6 +58,7 @@ + #include + #endif + ++#include "dwl-ipc-unstable-v2-protocol.h" + #include "util.h" + + /* macros */ +@@ -128,6 +129,12 @@ typedef struct { + uint32_t resize; /* configure serial of a pending resize */ + } Client; + ++typedef struct { ++ struct wl_list link; ++ struct wl_resource *resource; ++ Monitor *mon; ++} DwlIpcOutput; ++ + typedef struct { + uint32_t mod; + xkb_keysym_t keysym; +@@ -174,6 +181,7 @@ typedef struct { + + struct Monitor { + struct wl_list link; ++ struct wl_list dwl_ipc_outputs; + struct wlr_output *wlr_output; + struct wlr_scene_output *scene_output; + struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */ +@@ -255,6 +263,17 @@ 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 Monitor *dirtomon(enum wlr_direction dir); ++static void dwl_ipc_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id); ++static void dwl_ipc_manager_destroy(struct wl_resource *resource); ++static void dwl_ipc_manager_get_output(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *output); ++static void dwl_ipc_manager_release(struct wl_client *client, struct wl_resource *resource); ++static void dwl_ipc_output_destroy(struct wl_resource *resource); ++static void dwl_ipc_output_printstatus(Monitor *monitor); ++static void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output); ++static void dwl_ipc_output_set_client_tags(struct wl_client *client, struct wl_resource *resource, uint32_t and_tags, uint32_t xor_tags); ++static void dwl_ipc_output_set_layout(struct wl_client *client, struct wl_resource *resource, uint32_t index); ++static void dwl_ipc_output_set_tags(struct wl_client *client, struct wl_resource *resource, uint32_t tagmask, uint32_t toggle_tagset); ++static void dwl_ipc_output_release(struct wl_client *client, struct wl_resource *resource); + static void focusclient(Client *c, int lift); + static void focusmon(const Arg *arg); + static void focusstack(const Arg *arg); +@@ -302,6 +321,7 @@ static void startdrag(struct wl_listener *listener, void *data); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *m); ++static void togglebar(const Arg *arg); + static void togglefloating(const Arg *arg); + static void togglefullscreen(const Arg *arg); + static void toggletag(const Arg *arg); +@@ -374,6 +394,8 @@ 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 zdwl_ipc_manager_v2_interface dwl_manager_implementation = {.release = dwl_ipc_manager_release, .get_output = dwl_ipc_manager_get_output}; ++static struct zdwl_ipc_output_v2_interface dwl_output_implementation = {.release = dwl_ipc_output_release, .set_tags = dwl_ipc_output_set_tags, .set_layout = dwl_ipc_output_set_layout, .set_client_tags = dwl_ipc_output_set_client_tags}; + 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}; +@@ -691,6 +713,9 @@ cleanupmon(struct wl_listener *listener, void *data) + LayerSurface *l, *tmp; + int i; + ++ DwlIpcOutput *ipc_output, *ipc_output_tmp; ++ wl_list_for_each_safe(ipc_output, ipc_output_tmp, &m->dwl_ipc_outputs, link) ++ wl_resource_destroy(ipc_output->resource); + for (i = 0; i <= ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; i++) + wl_list_for_each_safe(l, tmp, &m->layers[i], link) + wlr_layer_surface_v1_destroy(l->layer_surface); +@@ -902,6 +927,7 @@ createmon(struct wl_listener *listener, void *data) + Monitor *m = wlr_output->data = ecalloc(1, sizeof(*m)); + m->wlr_output = wlr_output; + ++ wl_list_init(&m->dwl_ipc_outputs); + wlr_output_init_render(wlr_output, alloc, drw); + + /* Initialize monitor state using configured rules */ +@@ -1195,6 +1221,190 @@ dirtomon(enum wlr_direction dir) + return selmon; + } + ++void ++dwl_ipc_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) ++{ ++ struct wl_resource *manager_resource = wl_resource_create(client, &zdwl_ipc_manager_v2_interface, version, id); ++ if (!manager_resource) { ++ wl_client_post_no_memory(client); ++ return; ++ } ++ wl_resource_set_implementation(manager_resource, &dwl_manager_implementation, NULL, dwl_ipc_manager_destroy); ++ ++ zdwl_ipc_manager_v2_send_tags(manager_resource, TAGCOUNT); ++ ++ for (int i = 0; i < LENGTH(layouts); i++) ++ zdwl_ipc_manager_v2_send_layout(manager_resource, layouts[i].symbol); ++} ++ ++void ++dwl_ipc_manager_destroy(struct wl_resource *resource) ++{ ++ /* No state to destroy */ ++} ++ ++void ++dwl_ipc_manager_get_output(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *output) ++{ ++ DwlIpcOutput *ipc_output; ++ Monitor *monitor = wlr_output_from_resource(output)->data; ++ struct wl_resource *output_resource = wl_resource_create(client, &zdwl_ipc_output_v2_interface, wl_resource_get_version(resource), id); ++ if (!output_resource) ++ return; ++ ++ ipc_output = ecalloc(1, sizeof(*ipc_output)); ++ ipc_output->resource = output_resource; ++ ipc_output->mon = monitor; ++ wl_resource_set_implementation(output_resource, &dwl_output_implementation, ipc_output, dwl_ipc_output_destroy); ++ wl_list_insert(&monitor->dwl_ipc_outputs, &ipc_output->link); ++ dwl_ipc_output_printstatus_to(ipc_output); ++} ++ ++void ++dwl_ipc_manager_release(struct wl_client *client, struct wl_resource *resource) ++{ ++ wl_resource_destroy(resource); ++} ++ ++static void ++dwl_ipc_output_destroy(struct wl_resource *resource) ++{ ++ DwlIpcOutput *ipc_output = wl_resource_get_user_data(resource); ++ wl_list_remove(&ipc_output->link); ++ free(ipc_output); ++} ++ ++void ++dwl_ipc_output_printstatus(Monitor *monitor) ++{ ++ DwlIpcOutput *ipc_output; ++ wl_list_for_each(ipc_output, &monitor->dwl_ipc_outputs, link) ++ dwl_ipc_output_printstatus_to(ipc_output); ++} ++ ++void ++dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output) ++{ ++ Monitor *monitor = ipc_output->mon; ++ Client *c, *focused; ++ int tagmask, state, numclients, focused_client, tag; ++ const char *title, *appid; ++ focused = focustop(monitor); ++ zdwl_ipc_output_v2_send_active(ipc_output->resource, monitor == selmon); ++ ++ for (tag = 0 ; tag < TAGCOUNT; tag++) { ++ numclients = state = focused_client = 0; ++ tagmask = 1 << tag; ++ if ((tagmask & monitor->tagset[monitor->seltags]) != 0) ++ state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_ACTIVE; ++ ++ wl_list_for_each(c, &clients, link) { ++ if (c->mon != monitor) ++ continue; ++ if (!(c->tags & tagmask)) ++ continue; ++ if (c == focused) ++ focused_client = 1; ++ if (c->isurgent) ++ state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_URGENT; ++ ++ numclients++; ++ } ++ zdwl_ipc_output_v2_send_tag(ipc_output->resource, tag, state, numclients, focused_client); ++ } ++ title = focused ? client_get_title(focused) : ""; ++ appid = focused ? client_get_appid(focused) : ""; ++ ++ zdwl_ipc_output_v2_send_layout(ipc_output->resource, monitor->lt[monitor->sellt] - layouts); ++ zdwl_ipc_output_v2_send_title(ipc_output->resource, title ? title : broken); ++ zdwl_ipc_output_v2_send_appid(ipc_output->resource, appid ? appid : broken); ++ zdwl_ipc_output_v2_send_layout_symbol(ipc_output->resource, monitor->ltsymbol); ++ if (wl_resource_get_version(ipc_output->resource) >= ZDWL_IPC_OUTPUT_V2_FULLSCREEN_SINCE_VERSION) { ++ zdwl_ipc_output_v2_send_fullscreen(ipc_output->resource, focused ? focused->isfullscreen : 0); ++ } ++ if (wl_resource_get_version(ipc_output->resource) >= ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION) { ++ zdwl_ipc_output_v2_send_floating(ipc_output->resource, focused ? focused->isfloating : 0); ++ } ++ zdwl_ipc_output_v2_send_frame(ipc_output->resource); ++} ++ ++void ++dwl_ipc_output_set_client_tags(struct wl_client *client, struct wl_resource *resource, uint32_t and_tags, uint32_t xor_tags) ++{ ++ DwlIpcOutput *ipc_output; ++ Monitor *monitor; ++ Client *selected_client; ++ unsigned int newtags = 0; ++ ++ ipc_output = wl_resource_get_user_data(resource); ++ if (!ipc_output) ++ return; ++ ++ monitor = ipc_output->mon; ++ selected_client = focustop(monitor); ++ if (!selected_client) ++ return; ++ ++ newtags = (selected_client->tags & and_tags) ^ xor_tags; ++ if (!newtags) ++ return; ++ ++ selected_client->tags = newtags; ++ focusclient(focustop(selmon), 1); ++ arrange(selmon); ++ printstatus(); ++} ++ ++void ++dwl_ipc_output_set_layout(struct wl_client *client, struct wl_resource *resource, uint32_t index) ++{ ++ DwlIpcOutput *ipc_output; ++ Monitor *monitor; ++ ++ ipc_output = wl_resource_get_user_data(resource); ++ if (!ipc_output) ++ return; ++ ++ monitor = ipc_output->mon; ++ if (index >= LENGTH(layouts)) ++ return; ++ if (index != monitor->lt[monitor->sellt] - layouts) ++ monitor->sellt ^= 1; ++ ++ monitor->lt[monitor->sellt] = &layouts[index]; ++ arrange(monitor); ++ printstatus(); ++} ++ ++void ++dwl_ipc_output_set_tags(struct wl_client *client, struct wl_resource *resource, uint32_t tagmask, uint32_t toggle_tagset) ++{ ++ DwlIpcOutput *ipc_output; ++ Monitor *monitor; ++ unsigned int newtags = tagmask & TAGMASK; ++ ++ ipc_output = wl_resource_get_user_data(resource); ++ if (!ipc_output) ++ return; ++ monitor = ipc_output->mon; ++ ++ if (!newtags || newtags == monitor->tagset[monitor->seltags]) ++ return; ++ if (toggle_tagset) ++ monitor->seltags ^= 1; ++ ++ monitor->tagset[monitor->seltags] = newtags; ++ focusclient(focustop(monitor), 1); ++ arrange(monitor); ++ printstatus(); ++} ++ ++void ++dwl_ipc_output_release(struct wl_client *client, struct wl_resource *resource) ++{ ++ wl_resource_destroy(resource); ++} ++ + void + focusclient(Client *c, int lift) + { +@@ -1846,41 +2056,9 @@ void + 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; +- wl_list_for_each(c, &clients, link) { +- if (c->mon != m) +- continue; +- occ |= c->tags; +- if (c->isurgent) +- 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 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; +- } +- +- 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->ltsymbol); +- } +- fflush(stdout); ++ wl_list_for_each(m, &mons, link) ++ dwl_ipc_output_printstatus(m); + } + + void +@@ -2295,6 +2473,7 @@ setup(void) + wl_signal_add(&output_mgr->events.test, &output_mgr_test); + + wlr_scene_set_presentation(scene, wlr_presentation_create(dpy, backend)); ++ wl_global_create(dpy, &zdwl_ipc_manager_v2_interface, 2, NULL, dwl_ipc_manager_bind); + + #ifdef XWAYLAND + /* +@@ -2389,6 +2568,13 @@ tile(Monitor *m) + } + } + ++void ++togglebar(const Arg *arg) { ++ DwlIpcOutput *ipc_output; ++ wl_list_for_each(ipc_output, &selmon->dwl_ipc_outputs, link) ++ zdwl_ipc_output_v2_send_toggle_visibility(ipc_output->resource); ++} ++ + void + togglefloating(const Arg *arg) + { +diff --git a/protocols/dwl-ipc-unstable-v2.xml b/protocols/dwl-ipc-unstable-v2.xml +new file mode 100644 +index 0000000..0a6e7e5 +--- /dev/null ++++ b/protocols/dwl-ipc-unstable-v2.xml +@@ -0,0 +1,181 @@ ++ ++ ++ ++ ++ This protocol allows clients to update and get updates from dwl. ++ ++ 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 exposed as a global in wl_registry. ++ ++ Clients can use this interface to get a dwl_ipc_output. ++ After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events. ++ The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client. ++ ++ ++ ++ ++ Indicates that the client will not the dwl_ipc_manager object anymore. ++ Objects created through this instance are not affected. ++ ++ ++ ++ ++ ++ Get a dwl_ipc_outout for the specified wl_output. ++ ++ ++ ++ ++ ++ ++ ++ This event is sent after binding. ++ A roundtrip after binding guarantees the client recieved all tags. ++ ++ ++ ++ ++ ++ ++ This event is sent after binding. ++ A roundtrip after binding guarantees the client recieved all layouts. ++ ++ ++ ++ ++ ++ ++ ++ Observe and control a dwl output. ++ ++ Events are double-buffered: ++ Clients should cache events and redraw when a dwl_ipc_output.frame event is sent. ++ ++ Request are not double-buffered: ++ The compositor will update immediately upon request. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Indicates to that the client no longer needs this dwl_ipc_output. ++ ++ ++ ++ ++ ++ Indicates the client should hide or show themselves. ++ If the client is visible then hide, if hidden then show. ++ ++ ++ ++ ++ ++ Indicates if the output is active. Zero is invalid, nonzero is valid. ++ ++ ++ ++ ++ ++ ++ Indicates that a tag has been updated. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Indicates a new layout is selected. ++ ++ ++ ++ ++ ++ ++ Indicates the title has changed. ++ ++ ++ ++ ++ ++ ++ Indicates the appid has changed. ++ ++ ++ ++ ++ ++ ++ Indicates the layout has changed. Since layout symbols are dynamic. ++ As opposed to the zdwl_ipc_manager.layout event, this should take precendence when displaying. ++ You can ignore the zdwl_ipc_output.layout event. ++ ++ ++ ++ ++ ++ ++ Indicates that a sequence of status updates have finished and the client should redraw. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ The tags are updated as follows: ++ new_tags = (current_tags AND and_tags) XOR xor_tags ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Indicates if the selected client on this output is fullscreen. ++ ++ ++ ++ ++ ++ ++ Indicates if the selected client on this output is floating. ++ ++ ++ ++ ++ + diff --git a/protocols/dwl-ipc-unstable-v2.xml b/protocols/dwl-ipc-unstable-v2.xml new file mode 100644 index 0000000..0a6e7e5 --- /dev/null +++ b/protocols/dwl-ipc-unstable-v2.xml @@ -0,0 +1,181 @@ + + + + + This protocol allows clients to update and get updates from dwl. + + 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 exposed as a global in wl_registry. + + Clients can use this interface to get a dwl_ipc_output. + After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events. + The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client. + + + + + Indicates that the client will not the dwl_ipc_manager object anymore. + Objects created through this instance are not affected. + + + + + + Get a dwl_ipc_outout for the specified wl_output. + + + + + + + + This event is sent after binding. + A roundtrip after binding guarantees the client recieved all tags. + + + + + + + This event is sent after binding. + A roundtrip after binding guarantees the client recieved all layouts. + + + + + + + + Observe and control a dwl output. + + Events are double-buffered: + Clients should cache events and redraw when a dwl_ipc_output.frame event is sent. + + Request are not double-buffered: + The compositor will update immediately upon request. + + + + + + + + + + + Indicates to that the client no longer needs this dwl_ipc_output. + + + + + + Indicates the client should hide or show themselves. + If the client is visible then hide, if hidden then show. + + + + + + Indicates if the output is active. Zero is invalid, nonzero is valid. + + + + + + + Indicates that a tag has been updated. + + + + + + + + + + Indicates a new layout is selected. + + + + + + + Indicates the title has changed. + + + + + + + Indicates the appid has changed. + + + + + + + Indicates the layout has changed. Since layout symbols are dynamic. + As opposed to the zdwl_ipc_manager.layout event, this should take precendence when displaying. + You can ignore the zdwl_ipc_output.layout event. + + + + + + + Indicates that a sequence of status updates have finished and the client should redraw. + + + + + + + + + + + + The tags are updated as follows: + new_tags = (current_tags AND and_tags) XOR xor_tags + + + + + + + + + + + + + + Indicates if the selected client on this output is fullscreen. + + + + + + + Indicates if the selected client on this output is floating. + + + + +