diff options
| author | Leonardo Hernández Hernández <leohdz172@proton.me> | 2023-12-26 16:21:28 -0600 | 
|---|---|---|
| committer | Leonardo Hernández Hernández <leohdz172@proton.me> | 2023-12-26 16:21:28 -0600 | 
| commit | bf5a6be73cf94fd6e5d1c6edd8ce08a4928fee40 (patch) | |
| tree | 8816939f751187c5309e4c28eea1cadc9bcf143b | |
| parent | 126a333354cc89ed9b635e3e30771ea15f71192e (diff) | |
| parent | 1f0afcfc286463ea95d6f84f703060af5d3b64dc (diff) | |
Merge remote-tracking branch 'upstream/main' into wlroots-next
Diffstat (limited to '')
| -rw-r--r-- | client.h | 2 | ||||
| -rw-r--r-- | dwl.c | 331 | 
2 files changed, 191 insertions, 142 deletions
@@ -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 { @@ -28,6 +28,7 @@  #include <wlr/types/wlr_idle_notify_v1.h>  #include <wlr/types/wlr_input_device.h>  #include <wlr/types/wlr_keyboard.h> +#include <wlr/types/wlr_keyboard_group.h>  #include <wlr/types/wlr_layer_shell_v1.h>  #include <wlr/types/wlr_linux_dmabuf_v1.h>  #include <wlr/types/wlr_output.h> @@ -110,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; @@ -117,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 @@ -141,7 +145,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 +154,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 +241,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); @@ -253,6 +255,7 @@ static void createnotify(struct wl_listener *listener, void *data);  static void createpointer(struct wlr_pointer *pointer);  static void createpopup(struct wl_listener *listener, void *data);  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); @@ -292,6 +295,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); @@ -369,7 +373,8 @@ 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 = {0}; +static KeyboardGroup vkb_group = {0};  static struct wlr_surface *held_grab;  static unsigned int cursor_mode;  static Client *grabc; @@ -438,9 +443,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]); @@ -477,9 +483,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); @@ -636,6 +641,11 @@ cleanup(void)  		waitpid(child_pid, NULL, 0);  	}  	wlr_xcursor_manager_destroy(cursor_mgr); + +	/* 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)  	   to avoid destroying them with an invalid scene output. */ @@ -643,19 +653,6 @@ cleanup(void)  }  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)  {  	Monitor *m = wl_container_of(listener, m, destroy); @@ -663,9 +660,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); @@ -686,10 +684,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); @@ -698,7 +696,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);  	} @@ -758,8 +756,14 @@ 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 *deco = data; +	Client *c = deco->toplevel->base->data; +	c->decoration = deco; + +	LISTEN(&deco->events.request_mode, &c->set_decoration_mode, requestdecorationmode); +	LISTEN(&deco->events.destroy, &c->destroy_decoration, destroydecoration); + +	requestdecorationmode(&c->set_decoration_mode, deco);  }  void @@ -774,35 +778,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 @@ -844,8 +825,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); @@ -961,40 +942,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);  		}  	} @@ -1037,6 +1019,15 @@ cursorframe(struct wl_listener *listener, void *data)  }  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)  {  	/* Focus enter isn't sent during drag, so refocus the focused node. */ @@ -1245,10 +1236,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);  } @@ -1285,9 +1277,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;  } @@ -1353,7 +1346,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);  } @@ -1369,8 +1362,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;  		} @@ -1383,7 +1376,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 +1384,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,24 +1397,24 @@ 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; +	wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard);  	/* 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); +			event->keycode, event->state);  }  void @@ -1429,32 +1422,27 @@ 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); + +	wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard);  	/* 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;  } @@ -1520,7 +1508,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; @@ -1547,7 +1535,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]); @@ -1559,9 +1547,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 @@ -1576,7 +1565,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);  } @@ -1784,9 +1773,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 */ @@ -1795,7 +1783,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;  	} @@ -1842,8 +1830,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); @@ -1868,9 +1856,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 @@ -1881,7 +1870,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)) @@ -1906,6 +1896,14 @@ skip:  }  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)  {  	struct wlr_seat_request_start_drag_event *event = data; @@ -2035,7 +2033,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 @@ -2159,6 +2157,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); @@ -2280,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); @@ -2323,7 +2324,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 +2334,53 @@ 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); +  	output_mgr = wlr_output_manager_v1_create(dpy);  	LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply);  	LISTEN_STATIC(&output_mgr->events.test, outputmgrtest); @@ -2345,8 +2392,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); @@ -2455,10 +2501,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; @@ -2470,9 +2513,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; @@ -2540,8 +2582,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; @@ -2609,9 +2651,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, @@ -2671,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 * @@ -2722,12 +2770,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)  | 
