diff --git a/config.def.h b/config.def.h index 8f498d2..a784eb4 100644 --- a/config.def.h +++ b/config.def.h @@ -36,6 +36,8 @@ static const Layout layouts[] = { }; /* monitors */ +/* (x=-1, y=-1) is reserved as an "autoconfigure" monitor position indicator */ +/* WARNING: negative values other than (-1, -1) cause problems with xwayland clients' menus */ /* NOTE: ALWAYS add a fallback rule, even if you are completely sure it won't be used */ static const MonitorRule monrules[] = { /* name mfact nmaster scale layout rotate/reflect x y */ diff --git a/dwl.c b/dwl.c index 23277e2..a60647c 100644 --- a/dwl.c +++ b/dwl.c @@ -166,6 +166,7 @@ typedef struct { struct wl_listener modifiers; struct wl_listener key; + struct wl_listener destroy; } KeyboardGroup; typedef struct { @@ -266,6 +267,7 @@ static void commitnotify(struct wl_listener *listener, void *data); static void createdecoration(struct wl_listener *listener, void *data); static void createidleinhibitor(struct wl_listener *listener, void *data); static void createkeyboard(struct wlr_keyboard *keyboard); +static KeyboardGroup *createkeyboardgroup(void); static void createlayersurface(struct wl_listener *listener, void *data); static void createlocksurface(struct wl_listener *listener, void *data); static void createmon(struct wl_listener *listener, void *data); @@ -285,6 +287,7 @@ static void destroynotify(struct wl_listener *listener, void *data); static void destroypointerconstraint(struct wl_listener *listener, void *data); static void destroysessionlock(struct wl_listener *listener, void *data); static void destroysessionmgr(struct wl_listener *listener, void *data); +static void destroykeyboardgroup(struct wl_listener *listener, void *data); static Monitor *dirtomon(enum wlr_direction dir); static void 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); @@ -415,8 +418,7 @@ static struct wlr_session_lock_v1 *cur_lock; static struct wl_listener lock_listener = {.notify = locksession}; static struct wlr_seat *seat; -static KeyboardGroup kb_group = {0}; -static KeyboardGroup vkb_group = {0}; +static KeyboardGroup *kb_group; static struct wlr_surface *held_grab; static unsigned int cursor_mode; static Client *grabc; @@ -515,6 +517,20 @@ arrange(Monitor *m) strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); + /* We move all clients (except fullscreen and unmanaged) to LyrTile while + * in floating layout to avoid "real" floating clients be always on top */ + wl_list_for_each(c, &clients, link) { + if (c->mon != m || c->isfullscreen) + continue; + + wlr_scene_node_reparent(&c->scene->node, + (!m->lt[m->sellt]->arrange && c->isfloating) + ? layers[LyrTile] + : (m->lt[m->sellt]->arrange && c->isfloating) + ? layers[LyrFloat] + : c->scene->node.parent); + } + if (m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); motionnotify(0, NULL, 0, 0, 0, 0); @@ -689,9 +705,7 @@ cleanup(void) wlr_xcursor_manager_destroy(cursor_mgr); wlr_output_layout_destroy(output_layout); - /* Remove event source that use the dpy event loop before destroying dpy */ - wl_event_source_remove(kb_group.key_repeat_source); - wl_event_source_remove(vkb_group.key_repeat_source); + destroykeyboardgroup(&kb_group->destroy, NULL); wl_display_destroy(dpy); /* Destroy after the wayland display (when the monitors are already destroyed) @@ -815,11 +829,48 @@ void createkeyboard(struct wlr_keyboard *keyboard) { /* Set the keymap to match the group keymap */ - wlr_keyboard_set_keymap(keyboard, kb_group.wlr_group->keyboard.keymap); - wlr_keyboard_set_repeat_info(keyboard, repeat_rate, repeat_delay); + wlr_keyboard_set_keymap(keyboard, kb_group->wlr_group->keyboard.keymap); /* Add the new keyboard to the group */ - wlr_keyboard_group_add_keyboard(kb_group.wlr_group, keyboard); + wlr_keyboard_group_add_keyboard(kb_group->wlr_group, keyboard); +} + +KeyboardGroup * +createkeyboardgroup(void) +{ + KeyboardGroup *group = ecalloc(1, sizeof(*group)); + struct xkb_context *context; + struct xkb_keymap *keymap; + + group->wlr_group = wlr_keyboard_group_create(); + group->wlr_group->data = group; + + /* Prepare an XKB keymap and assign it to the keyboard group. */ + context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules, + XKB_KEYMAP_COMPILE_NO_FLAGS))) + die("failed to compile keymap"); + + wlr_keyboard_set_keymap(&group->wlr_group->keyboard, keymap); + xkb_keymap_unref(keymap); + xkb_context_unref(context); + + wlr_keyboard_set_repeat_info(&group->wlr_group->keyboard, repeat_rate, repeat_delay); + + /* Set up listeners for keyboard events */ + LISTEN(&group->wlr_group->keyboard.events.key, &group->key, keypress); + LISTEN(&group->wlr_group->keyboard.events.modifiers, &group->modifiers, keypressmod); + + group->key_repeat_source = wl_event_loop_add_timer( + wl_display_get_event_loop(dpy), keyrepeat, group); + + /* A seat can only have one keyboard, but this is a limitation of the + * Wayland protocol - not wlroots. We assign all connected keyboards to the + * same wlr_keyboard_group, which provides a single wlr_keyboard interface for + * all of them. Set this combined wlr_keyboard as the seat keyboard. + */ + wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); + return group; } void @@ -954,14 +1005,14 @@ createmon(struct wl_listener *listener, void *data) m->fullscreen_bg = wlr_scene_rect_create(layers[LyrFS], 0, 0, fullscreen_bg); wlr_scene_node_set_enabled(&m->fullscreen_bg->node, 0); - /* Adds this to the output layout in the order it was configured in. + /* Adds this to the output layout in the order it was configured. * * The output layout utility automatically adds a wl_output global to the * display, which Wayland clients can see to find out information about the * output (such as DPI, scale factor, manufacturer, etc). */ m->scene_output = wlr_scene_output_create(scene, wlr_output); - if (m->m.x < 0 || m->m.y < 0) + if (m->m.x == -1 && m->m.y == -1) wlr_output_layout_add_auto(output_layout, wlr_output); else wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y); @@ -1244,6 +1295,18 @@ destroysessionmgr(struct wl_listener *listener, void *data) wl_list_remove(&listener->link); } +void +destroykeyboardgroup(struct wl_listener *listener, void *data) +{ + KeyboardGroup *group = wl_container_of(listener, group, destroy); + wl_event_source_remove(group->key_repeat_source); + wlr_keyboard_group_destroy(group->wlr_group); + wl_list_remove(&group->key.link); + wl_list_remove(&group->modifiers.link); + wl_list_remove(&group->destroy.link); + free(group); +} + Monitor * dirtomon(enum wlr_direction dir) { @@ -1656,7 +1719,7 @@ inputdevice(struct wl_listener *listener, void *data) * there are no pointer devices, so we always include that capability. */ /* TODO do we actually require a cursor? */ caps = WL_SEAT_CAPABILITY_POINTER; - if (!wl_list_empty(&kb_group.wlr_group->devices)) + if (!wl_list_empty(&kb_group->wlr_group->devices)) caps |= WL_SEAT_CAPABILITY_KEYBOARD; wlr_seat_set_capabilities(seat, caps); } @@ -2117,7 +2180,7 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, { struct timespec now; - if ((!active_constraint || active_constraint->surface != surface) && + if (surface != seat->pointer_state.focused_surface && sloppyfocus && time && c && !client_is_unmanaged(c)) focusclient(c, 0); @@ -2384,7 +2447,8 @@ setfloating(Client *c, int floating) { Client *p = client_get_parent(c); c->isfloating = floating; - if (!c->mon) + /* If in floating layout do not change the client's layer */ + if (!c->mon || !c->mon->lt[c->mon->sellt]->arrange) return; wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen || (p && p->isfullscreen) ? LyrFS @@ -2504,9 +2568,6 @@ setsel(struct wl_listener *listener, void *data) void setup(void) { - struct xkb_context *context; - struct xkb_keymap *keymap; - int i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE}; struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig}; sigemptyset(&sa.sa_mask); @@ -2688,52 +2749,8 @@ setup(void) LISTEN_STATIC(&seat->events.request_start_drag, requeststartdrag); LISTEN_STATIC(&seat->events.start_drag, startdrag); - /* - * Configures a keyboard group, which will keep track of all connected - * keyboards, keep their modifier and LED states in sync, and handle - * keypresses - */ - kb_group.wlr_group = wlr_keyboard_group_create(); - kb_group.wlr_group->data = &kb_group; - - /* - * Virtual keyboards need to be in a different group - * https://codeberg.org/dwl/dwl/issues/554 - */ - vkb_group.wlr_group = wlr_keyboard_group_create(); - vkb_group.wlr_group->data = &vkb_group; - - /* Prepare an XKB keymap and assign it to the keyboard group. */ - context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules, - XKB_KEYMAP_COMPILE_NO_FLAGS))) - die("failed to compile keymap"); - - wlr_keyboard_set_keymap(&kb_group.wlr_group->keyboard, keymap); - wlr_keyboard_set_keymap(&vkb_group.wlr_group->keyboard, keymap); - xkb_keymap_unref(keymap); - xkb_context_unref(context); - - wlr_keyboard_set_repeat_info(&kb_group.wlr_group->keyboard, repeat_rate, repeat_delay); - wlr_keyboard_set_repeat_info(&vkb_group.wlr_group->keyboard, repeat_rate, repeat_delay); - - /* Set up listeners for keyboard events */ - LISTEN(&kb_group.wlr_group->keyboard.events.key, &kb_group.key, keypress); - LISTEN(&kb_group.wlr_group->keyboard.events.modifiers, &kb_group.modifiers, keypressmod); - LISTEN(&vkb_group.wlr_group->keyboard.events.key, &vkb_group.key, keypress); - LISTEN(&vkb_group.wlr_group->keyboard.events.modifiers, &vkb_group.modifiers, keypressmod); - - kb_group.key_repeat_source = wl_event_loop_add_timer( - wl_display_get_event_loop(dpy), keyrepeat, &kb_group); - vkb_group.key_repeat_source = wl_event_loop_add_timer( - wl_display_get_event_loop(dpy), keyrepeat, &vkb_group); - - /* A seat can only have one keyboard, but this is a limitation of the - * Wayland protocol - not wlroots. We assign all connected keyboards to the - * same wlr_keyboard_group, which provides a single wlr_keyboard interface for - * all of them. Set this combined wlr_keyboard as the seat keyboard. - */ - wlr_seat_set_keyboard(seat, &kb_group.wlr_group->keyboard); + kb_group = createkeyboardgroup(); + wl_list_init(&kb_group->destroy.link); output_mgr = wlr_output_manager_v1_create(dpy); LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply); @@ -3082,13 +3099,15 @@ view(const Arg *arg) void virtualkeyboard(struct wl_listener *listener, void *data) { - struct wlr_virtual_keyboard_v1 *keyboard = data; + struct wlr_virtual_keyboard_v1 *kb = data; + /* virtual keyboards shouldn't share keyboard group */ + KeyboardGroup *group = createkeyboardgroup(); /* Set the keymap to match the group keymap */ - wlr_keyboard_set_keymap(&keyboard->keyboard, vkb_group.wlr_group->keyboard.keymap); - wlr_keyboard_set_repeat_info(&keyboard->keyboard, repeat_rate, repeat_delay); + wlr_keyboard_set_keymap(&kb->keyboard, group->wlr_group->keyboard.keymap); + LISTEN(&kb->keyboard.base.events.destroy, &group->destroy, destroykeyboardgroup); /* Add the new keyboard to the group */ - wlr_keyboard_group_add_keyboard(vkb_group.wlr_group, &keyboard->keyboard); + wlr_keyboard_group_add_keyboard(group->wlr_group, &kb->keyboard); } void