Merge remote-tracking branch 'upstream/main' into wlroots-next

This commit is contained in:
Leonardo Hernández Hernández 2024-06-04 14:03:37 -06:00
commit f4b6b429ec
No known key found for this signature in database
GPG key ID: E538897EE11B9624
4 changed files with 91 additions and 70 deletions

View file

@ -86,7 +86,7 @@ Wayland without restarting the entire display server, so any changes will take
effect the next time dwl is executed. effect the next time dwl is executed.
As in the dwm community, we encourage users to share patches they have created. As in the dwm community, we encourage users to share patches they have created.
Check out the dwl [patches repository] and [patches wiki]! Check out the dwl [patches repository]!
## Running dwl ## Running dwl
@ -170,7 +170,6 @@ inspiration, and to the various contributors to the project, including:
[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots/ [wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots/
[wlroots-next branch]: https://codeberg.org/dwl/dwl/src/branch/wlroots-next [wlroots-next branch]: https://codeberg.org/dwl/dwl/src/branch/wlroots-next
[patches repository]: https://codeberg.org/dwl/dwl-patches [patches repository]: https://codeberg.org/dwl/dwl-patches
[patches wiki]: https://codeberg.org/dwl/dwl-patches/wiki
[s6]: https://skarnet.org/software/s6/ [s6]: https://skarnet.org/software/s6/
[anopa]: https://jjacky.com/anopa/ [anopa]: https://jjacky.com/anopa/
[runit]: http://smarden.org/runit/faq.html#userservices [runit]: http://smarden.org/runit/faq.html#userservices

View file

@ -36,6 +36,8 @@ static const Layout layouts[] = {
}; };
/* monitors */ /* 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 */ /* NOTE: ALWAYS add a fallback rule, even if you are completely sure it won't be used */
static const MonitorRule monrules[] = { static const MonitorRule monrules[] = {
/* name mfact nmaster scale layout rotate/reflect x y */ /* name mfact nmaster scale layout rotate/reflect x y */
@ -115,7 +117,7 @@ static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TA
/* commands */ /* commands */
static const char *termcmd[] = { "foot", NULL }; static const char *termcmd[] = { "foot", NULL };
static const char *menucmd[] = { "bemenu-run", NULL }; static const char *menucmd[] = { "wmenu-run", NULL };
static const Key keys[] = { static const Key keys[] = {
/* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */ /* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */

4
dwl.1
View file

@ -55,7 +55,7 @@ Move window to a single tag.
Toggle tag for window. Toggle tag for window.
.It Mod-p .It Mod-p
Spawn Spawn
.Nm bemenu-run . .Nm wmenu-run .
.It Mod-Shift-Return .It Mod-Shift-Return
Spawn Spawn
.Nm foot . .Nm foot .
@ -143,7 +143,7 @@ with s6 in the background:
.Dl dwl -s 's6-svscan <&-' .Dl dwl -s 's6-svscan <&-'
.Sh SEE ALSO .Sh SEE ALSO
.Xr foot 1 , .Xr foot 1 ,
.Xr bemenu 1 , .Xr wmenu 1 ,
.Xr dwm 1 , .Xr dwm 1 ,
.Xr xkeyboard-config 7 .Xr xkeyboard-config 7
.Sh CAVEATS .Sh CAVEATS

150
dwl.c
View file

@ -82,7 +82,7 @@
/* enums */ /* enums */
enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
enum { XDGShell, LayerShell, X11 }; /* client types */ enum { XDGShell, LayerShell, X11 }; /* client types */
enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrFS, LyrTop, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */ enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */
#ifdef XWAYLAND #ifdef XWAYLAND
enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar,
NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */
@ -160,6 +160,7 @@ typedef struct {
struct wl_listener modifiers; struct wl_listener modifiers;
struct wl_listener key; struct wl_listener key;
struct wl_listener destroy;
} KeyboardGroup; } KeyboardGroup;
typedef struct { typedef struct {
@ -260,6 +261,7 @@ static void commitpopup(struct wl_listener *listener, void *data);
static void createdecoration(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 createidleinhibitor(struct wl_listener *listener, void *data);
static void createkeyboard(struct wlr_keyboard *keyboard); static void createkeyboard(struct wlr_keyboard *keyboard);
static KeyboardGroup *createkeyboardgroup(void);
static void createlayersurface(struct wl_listener *listener, void *data); static void createlayersurface(struct wl_listener *listener, void *data);
static void createlocksurface(struct wl_listener *listener, void *data); static void createlocksurface(struct wl_listener *listener, void *data);
static void createmon(struct wl_listener *listener, void *data); static void createmon(struct wl_listener *listener, void *data);
@ -280,6 +282,7 @@ static void destroynotify(struct wl_listener *listener, void *data);
static void destroypointerconstraint(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 destroysessionlock(struct wl_listener *listener, void *data);
static void destroysessionmgr(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 Monitor *dirtomon(enum wlr_direction dir);
static void focusclient(Client *c, int lift); static void focusclient(Client *c, int lift);
static void focusmon(const Arg *arg); static void focusmon(const Arg *arg);
@ -397,8 +400,7 @@ static struct wlr_session_lock_v1 *cur_lock;
static struct wl_listener lock_listener = {.notify = locksession}; static struct wl_listener lock_listener = {.notify = locksession};
static struct wlr_seat *seat; static struct wlr_seat *seat;
static KeyboardGroup kb_group = {0}; static KeyboardGroup *kb_group;
static KeyboardGroup vkb_group = {0};
static struct wlr_surface *held_grab; static struct wlr_surface *held_grab;
static unsigned int cursor_mode; static unsigned int cursor_mode;
static Client *grabc; static Client *grabc;
@ -497,6 +499,20 @@ arrange(Monitor *m)
strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); 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) if (m->lt[m->sellt]->arrange)
m->lt[m->sellt]->arrange(m); m->lt[m->sellt]->arrange(m);
motionnotify(0, NULL, 0, 0, 0, 0); motionnotify(0, NULL, 0, 0, 0, 0);
@ -670,9 +686,7 @@ cleanup(void)
} }
wlr_xcursor_manager_destroy(cursor_mgr); wlr_xcursor_manager_destroy(cursor_mgr);
/* Remove event source that use the dpy event loop before destroying dpy */ destroykeyboardgroup(&kb_group->destroy, NULL);
wl_event_source_remove(kb_group.key_repeat_source);
wl_event_source_remove(vkb_group.key_repeat_source);
/* If it's not destroyed manually it will cause a use-after-free of wlr_seat. /* If it's not destroyed manually it will cause a use-after-free of wlr_seat.
* Destroy it until it's fixed in the wlroots side */ * Destroy it until it's fixed in the wlroots side */
@ -843,11 +857,47 @@ void
createkeyboard(struct wlr_keyboard *keyboard) createkeyboard(struct wlr_keyboard *keyboard)
{ {
/* Set the keymap to match the group keymap */ /* Set the keymap to match the group keymap */
wlr_keyboard_set_keymap(keyboard, kb_group.wlr_group->keyboard.keymap); wlr_keyboard_set_keymap(keyboard, kb_group->wlr_group->keyboard.keymap);
wlr_keyboard_set_repeat_info(keyboard, repeat_rate, repeat_delay);
/* Add the new keyboard to the group */ /* 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(event_loop, 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 void
@ -970,14 +1020,14 @@ createmon(struct wl_listener *listener, void *data)
m->fullscreen_bg = wlr_scene_rect_create(layers[LyrFS], 0, 0, fullscreen_bg); m->fullscreen_bg = wlr_scene_rect_create(layers[LyrFS], 0, 0, fullscreen_bg);
wlr_scene_node_set_enabled(&m->fullscreen_bg->node, 0); 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 * The output layout utility automatically adds a wl_output global to the
* display, which Wayland clients can see to find out information about the * display, which Wayland clients can see to find out information about the
* output (such as DPI, scale factor, manufacturer, etc). * output (such as DPI, scale factor, manufacturer, etc).
*/ */
m->scene_output = wlr_scene_output_create(scene, wlr_output); 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); wlr_output_layout_add_auto(output_layout, wlr_output);
else else
wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y); wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y);
@ -1242,6 +1292,18 @@ destroysessionmgr(struct wl_listener *listener, void *data)
wl_list_remove(&listener->link); 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 * Monitor *
dirtomon(enum wlr_direction dir) dirtomon(enum wlr_direction dir)
{ {
@ -1447,7 +1509,7 @@ inputdevice(struct wl_listener *listener, void *data)
* there are no pointer devices, so we always include that capability. */ * there are no pointer devices, so we always include that capability. */
/* TODO do we actually require a cursor? */ /* TODO do we actually require a cursor? */
caps = WL_SEAT_CAPABILITY_POINTER; 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; caps |= WL_SEAT_CAPABILITY_KEYBOARD;
wlr_seat_set_capabilities(seat, caps); wlr_seat_set_capabilities(seat, caps);
} }
@ -1908,7 +1970,7 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,
{ {
struct timespec now; struct timespec now;
if ((!active_constraint || active_constraint->surface != surface) && if (surface != seat->pointer_state.focused_surface &&
sloppyfocus && time && c && !client_is_unmanaged(c)) sloppyfocus && time && c && !client_is_unmanaged(c))
focusclient(c, 0); focusclient(c, 0);
@ -2176,7 +2238,8 @@ setfloating(Client *c, int floating)
{ {
Client *p = client_get_parent(c); Client *p = client_get_parent(c);
c->isfloating = floating; 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; return;
wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen || wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ||
(p && p->isfullscreen) ? LyrFS (p && p->isfullscreen) ? LyrFS
@ -2296,9 +2359,6 @@ setsel(struct wl_listener *listener, void *data)
void void
setup(void) setup(void)
{ {
struct xkb_context *context;
struct xkb_keymap *keymap;
int i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE}; int i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE};
struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig}; struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig};
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
@ -2484,50 +2544,8 @@ setup(void)
LISTEN_STATIC(&seat->events.request_start_drag, requeststartdrag); LISTEN_STATIC(&seat->events.request_start_drag, requeststartdrag);
LISTEN_STATIC(&seat->events.start_drag, startdrag); LISTEN_STATIC(&seat->events.start_drag, startdrag);
/* kb_group = createkeyboardgroup();
* Configures a keyboard group, which will keep track of all connected wl_list_init(&kb_group->destroy.link);
* 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(event_loop, keyrepeat, &kb_group);
vkb_group.key_repeat_source = wl_event_loop_add_timer(event_loop, keyrepeat, &vkb_group);
/* A seat can only have one keyboard, but this is a limitation of the
* Wayland protocol - not wlroots. We assign all connected keyboards to the
* 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); output_mgr = wlr_output_manager_v1_create(dpy);
LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply); LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply);
@ -2865,13 +2883,15 @@ view(const Arg *arg)
void void
virtualkeyboard(struct wl_listener *listener, void *data) 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 */ /* Set the keymap to match the group keymap */
wlr_keyboard_set_keymap(&keyboard->keyboard, vkb_group.wlr_group->keyboard.keymap); wlr_keyboard_set_keymap(&kb->keyboard, group->wlr_group->keyboard.keymap);
wlr_keyboard_set_repeat_info(&keyboard->keyboard, repeat_rate, repeat_delay); LISTEN(&kb->keyboard.base.events.destroy, &group->destroy, destroykeyboardgroup);
/* Add the new keyboard to the group */ /* 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 void