From d04df999acc1b0c0a0bdf5fe8a737e9e0fae0a2f Mon Sep 17 00:00:00 2001
From: Stivvo <stivvo01@gmail.com>
Date: Fri, 18 Sep 2020 12:56:23 +0200
Subject: [PATCH 1/2] Switch between keyboard layouts ar runtime

setkblayout() avoids to rewrite the code necessary to set the keyboard
layout in createkeyboard() and togglekblayout()
---
 config.def.h |  6 ++++++
 dwl.c        | 38 +++++++++++++++++++++++++++++---------
 2 files changed, 35 insertions(+), 9 deletions(-)

diff --git a/config.def.h b/config.def.h
index 53021cf7..b0fb9321 100644
--- a/config.def.h
+++ b/config.def.h
@@ -44,6 +44,11 @@ static const struct xkb_rule_names xkb_rules = {
 static const int repeat_rate = 25;
 static const int repeat_delay = 600;
 
+/* gb will be set the first time togglekblayout is called, then us.. it is
+ * recommended to set the same layout in position 0 of kblayouts and in
+ * xkb_rules */
+static const char *kblayouts[] = {"us", "gb"};
+
 #define MODKEY WLR_MODIFIER_ALT
 #define TAGKEYS(KEY,SKEY,TAG) \
 	{ MODKEY,                    KEY,            view,            {.ui = 1 << TAG} }, \
@@ -81,6 +86,7 @@ static const Key keys[] = {
 	{ MODKEY,                    XKB_KEY_period,     focusmon,       {.i = +1} },
 	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less,       tagmon,         {.i = -1} },
 	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater,    tagmon,         {.i = +1} },
+	{ MODKEY,  					 XKB_KEY_w,    	 	 togglekblayout, {0} },
 	TAGKEYS(          XKB_KEY_1, XKB_KEY_exclam,                     0),
 	TAGKEYS(          XKB_KEY_2, XKB_KEY_at,                         1),
 	TAGKEYS(          XKB_KEY_3, XKB_KEY_numbersign,                 2),
diff --git a/dwl.c b/dwl.c
index 730e46a1..5256eec0 100644
--- a/dwl.c
+++ b/dwl.c
@@ -221,6 +221,7 @@ static void run(char *startup_cmd);
 static void scalebox(struct wlr_box *box, float scale);
 static Client *selclient(void);
 static void setcursor(struct wl_listener *listener, void *data);
+static void setkblayout(Keyboard *kb, const struct xkb_rule_names *newrule);
 static void setpsel(struct wl_listener *listener, void *data);
 static void setsel(struct wl_listener *listener, void *data);
 static void setfloating(Client *c, int floating);
@@ -234,6 +235,7 @@ static void tag(const Arg *arg);
 static void tagmon(const Arg *arg);
 static void tile(Monitor *m);
 static void togglefloating(const Arg *arg);
+static void togglekblayout(const Arg *arg);
 static void toggletag(const Arg *arg);
 static void toggleview(const Arg *arg);
 static void unmapnotify(struct wl_listener *listener, void *data);
@@ -261,6 +263,7 @@ static struct wlr_xcursor_manager *cursor_mgr;
 
 static struct wlr_seat *seat;
 static struct wl_list keyboards;
+static unsigned int kblayout = 0; /* index of kblayouts */
 static unsigned int cursor_mode;
 static Client *grabc;
 static int grabcx, grabcy; /* client-relative */
@@ -480,24 +483,28 @@ commitnotify(struct wl_listener *listener, void *data)
 		c->resize = 0;
 }
 
+void
+setkblayout(Keyboard *kb, const struct xkb_rule_names *newrule)
+{
+	/* Prepare an XKB keymap and assign it to the keyboard. */
+	struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+	struct xkb_keymap *keymap = xkb_map_new_from_names(context, newrule,
+			XKB_KEYMAP_COMPILE_NO_FLAGS);
+	wlr_keyboard_set_keymap(kb->device->keyboard, keymap);
+	xkb_keymap_unref(keymap);
+	xkb_context_unref(context);
+}
+
 void
 createkeyboard(struct wlr_input_device *device)
 {
-	struct xkb_context *context;
-	struct xkb_keymap *keymap;
 	Keyboard *kb;
 
 	kb = device->data = calloc(1, sizeof(*kb));
 	kb->device = device;
 
-	/* Prepare an XKB keymap and assign it to the keyboard. */
-	context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
-	keymap = xkb_map_new_from_names(context, &xkb_rules,
-		XKB_KEYMAP_COMPILE_NO_FLAGS);
+	setkblayout(kb, &xkb_rules);
 
-	wlr_keyboard_set_keymap(device->keyboard, keymap);
-	xkb_keymap_unref(keymap);
-	xkb_context_unref(context);
 	wlr_keyboard_set_repeat_info(device->keyboard, repeat_rate, repeat_delay);
 
 	/* Here we set up listeners for keyboard events. */
@@ -1675,6 +1682,19 @@ togglefloating(const Arg *arg)
 	setfloating(sel, !sel->isfloating /* || sel->isfixed */);
 }
 
+void
+togglekblayout(const Arg *arg)
+{
+	Keyboard *kb;
+	struct xkb_rule_names newrule = xkb_rules;
+
+	kblayout = (kblayout + 1) % LENGTH(kblayouts);
+	newrule.layout = kblayouts[kblayout];
+	wl_list_for_each(kb, &keyboards, link) {
+		setkblayout(kb, &newrule);
+	}
+}
+
 void
 toggletag(const Arg *arg)
 {

From 382ec6b9cddbde9e66a08bc11d4836327b8f084a Mon Sep 17 00:00:00 2001
From: Stivvo <stivvo01@gmail.com>
Date: Mon, 8 Mar 2021 17:19:18 +0100
Subject: [PATCH 2/2] Don't interfere with the dwl codebase

Removing setkblayout duplicates a few lines of code to avoid touch the
codebase
---
 dwl.c | 34 ++++++++++++++++++----------------
 1 file changed, 18 insertions(+), 16 deletions(-)

diff --git a/dwl.c b/dwl.c
index 83dc16d0..4749936f 100644
--- a/dwl.c
+++ b/dwl.c
@@ -270,7 +270,6 @@ static void run(char *startup_cmd);
 static void scalebox(struct wlr_box *box, float scale);
 static Client *selclient(void);
 static void setcursor(struct wl_listener *listener, void *data);
-static void setkblayout(Keyboard *kb, const struct xkb_rule_names *newrule);
 static void setpsel(struct wl_listener *listener, void *data);
 static void setsel(struct wl_listener *listener, void *data);
 static void setfloating(Client *c, int floating);
@@ -784,25 +783,22 @@ commitnotify(struct wl_listener *listener, void *data)
 		c->resize = 0;
 }
 
-void
-setkblayout(Keyboard *kb, const struct xkb_rule_names *newrule)
-{
-	/* Prepare an XKB keymap and assign it to the keyboard. */
-	struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
-	struct xkb_keymap *keymap = xkb_map_new_from_names(context, newrule,
-			XKB_KEYMAP_COMPILE_NO_FLAGS);
-	wlr_keyboard_set_keymap(kb->device->keyboard, keymap);
-	xkb_keymap_unref(keymap);
-	xkb_context_unref(context);
-}
-
 void
 createkeyboard(struct wlr_input_device *device)
 {
+	struct xkb_context *context;
+	struct xkb_keymap *keymap;
 	Keyboard *kb = device->data = calloc(1, sizeof(*kb));
 	kb->device = device;
 
-	setkblayout(kb, &xkb_rules);
+	/* Prepare an XKB keymap and assign it to the keyboard. */
+	context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+	keymap = xkb_map_new_from_names(context, &xkb_rules,
+		XKB_KEYMAP_COMPILE_NO_FLAGS);
+
+	wlr_keyboard_set_keymap(device->keyboard, keymap);
+	xkb_keymap_unref(keymap);
+	xkb_context_unref(context);
 	wlr_keyboard_set_repeat_info(device->keyboard, repeat_rate, repeat_delay);
 
 	/* Here we set up listeners for keyboard events. */
@@ -2234,8 +2230,14 @@ togglekblayout(const Arg *arg)
 
 	kblayout = (kblayout + 1) % LENGTH(kblayouts);
 	newrule.layout = kblayouts[kblayout];
-	wl_list_for_each(kb, &keyboards, link)
-		setkblayout(kb, &newrule);
+	wl_list_for_each(kb, &keyboards, link) {
+		struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+		struct xkb_keymap *keymap = xkb_map_new_from_names(context, &newrule,
+				XKB_KEYMAP_COMPILE_NO_FLAGS);
+		wlr_keyboard_set_keymap(kb->device->keyboard, keymap);
+		xkb_keymap_unref(keymap);
+		xkb_context_unref(context);
+	}
 }
 
 void
