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 1/8] 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 2/8] 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 3/8] 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 4/8] 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 5/8] 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 6/8] 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 7/8] 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 8/8] 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 *