1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
|
From ad18a8b8e9de138c3d89246ac0e25c0467ff5971 Mon Sep 17 00:00:00 2001
From: Nikita Ivanov <nikita.vyach.ivanov@gmail.com>
Date: Fri, 11 Oct 2024 10:50:14 +0200
Subject: [PATCH] Add per client keyboard layout and status bar info
---
config.def.h | 3 +++
dwl.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 72 insertions(+), 1 deletion(-)
diff --git a/config.def.h b/config.def.h
index 22d2171..862c104 100644
--- a/config.def.h
+++ b/config.def.h
@@ -13,6 +13,9 @@ static const float focuscolor[] = COLOR(0x005577ff);
static const float urgentcolor[] = COLOR(0xff0000ff);
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */
+/* keyboard layout change notification for status bar */
+static const char kblayout_file[] = "/tmp/dwl-keymap";
+static const char *kblayout_cmd[] = {"pkill", "-RTMIN+3", "someblocks", NULL};
/* tagging - TAGCOUNT must be no greater than 31 */
#define TAGCOUNT (9)
diff --git a/dwl.c b/dwl.c
index a2711f6..95ca3d3 100644
--- a/dwl.c
+++ b/dwl.c
@@ -14,6 +14,7 @@
#include <wayland-server-core.h>
#include <wlr/backend.h>
#include <wlr/backend/libinput.h>
+#include <wlr/interfaces/wlr_keyboard.h>
#include <wlr/render/allocator.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_alpha_modifier_v1.h>
@@ -141,6 +142,7 @@ typedef struct {
uint32_t tags;
int isfloating, isurgent, isfullscreen;
uint32_t resize; /* configure serial of a pending resize */
+ unsigned int kblayout_idx;
} Client;
typedef struct {
@@ -294,6 +296,7 @@ static void gpureset(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);
+static void kblayout(KeyboardGroup *kb);
static int keybinding(uint32_t mods, xkb_keysym_t sym);
static void keypress(struct wl_listener *listener, void *data);
static void keypressmod(struct wl_listener *listener, void *data);
@@ -413,6 +416,8 @@ static struct wlr_box sgeom;
static struct wl_list mons;
static Monitor *selmon;
+static unsigned int kblayout_idx = -1;
+
#ifdef XWAYLAND
static void activatex11(struct wl_listener *listener, void *data);
static void associatex11(struct wl_listener *listener, void *data);
@@ -879,6 +884,8 @@ createkeyboard(struct wlr_keyboard *keyboard)
/* Add the new keyboard to the group */
wlr_keyboard_group_add_keyboard(kb_group->wlr_group, keyboard);
+
+ kblayout(kb_group);
}
KeyboardGroup *
@@ -1056,11 +1063,13 @@ createnotify(struct wl_listener *listener, void *data)
/* This event is raised when a client creates a new toplevel (application window). */
struct wlr_xdg_toplevel *toplevel = data;
Client *c = NULL;
+ struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat);
/* Allocate a Client for this surface */
c = toplevel->base->data = ecalloc(1, sizeof(*c));
c->surface.xdg = toplevel->base;
c->bw = borderpx;
+ c->kblayout_idx = kb ? kb->modifiers.group : 0;
LISTEN(&toplevel->base->surface->events.commit, &c->commit, commitnotify);
LISTEN(&toplevel->base->surface->events.map, &c->map, mapnotify);
@@ -1339,10 +1348,24 @@ dirtomon(enum wlr_direction dir)
void
focusclient(Client *c, int lift)
{
+ /* Copied from wlroots/types/wlr_keyboard_group.c */
+ struct keyboard_group_device {
+ struct wlr_keyboard *keyboard;
+ struct wl_listener key;
+ struct wl_listener modifiers;
+ struct wl_listener keymap;
+ struct wl_listener repeat_info;
+ struct wl_listener destroy;
+ struct wl_list link; // wlr_keyboard_group.devices
+ };
+
struct wlr_surface *old = seat->keyboard_state.focused_surface;
int unused_lx, unused_ly, old_client_type;
Client *old_c = NULL;
LayerSurface *old_l = NULL;
+ struct keyboard_group_device *device;
+ struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat);
+ struct wlr_keyboard_group *group = kb ? wlr_keyboard_group_from_wlr_keyboard(kb) : NULL;
if (locked)
return;
@@ -1395,6 +1418,19 @@ focusclient(Client *c, int lift)
}
printstatus();
+ /* Update keyboard layout */
+ if (group) {
+ // Update the first real device, because kb or group->kb is not a real
+ // keyboard and its effective layout gets overwritten
+ device = wl_container_of(group->devices.next, device, link);
+ wlr_keyboard_notify_modifiers(device->keyboard,
+ device->keyboard->modifiers.depressed,
+ device->keyboard->modifiers.latched,
+ device->keyboard->modifiers.locked,
+ c ? c->kblayout_idx : 0
+ );
+ }
+
if (!c) {
/* With no client, all we have left is to clear focus */
wlr_seat_keyboard_notify_clear_focus(seat);
@@ -1405,7 +1441,7 @@ focusclient(Client *c, int lift)
motionnotify(0, NULL, 0, 0, 0, 0);
/* Have a client, so focus its top-level wlr_surface */
- client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat));
+ client_notify_enter(client_surface(c), kb);
/* Activate the new client */
client_activate_surface(client_surface(c), 1);
@@ -1554,6 +1590,36 @@ inputdevice(struct wl_listener *listener, void *data)
wlr_seat_set_capabilities(seat, caps);
}
+void
+kblayout(KeyboardGroup *kb)
+{
+ FILE *f;
+ Client *c;
+ unsigned int idx = kb->wlr_group->keyboard.modifiers.group;
+
+ // If layout did not change, do nothing
+ if (kblayout_idx == idx)
+ return;
+ kblayout_idx = idx;
+
+ // Update client layout
+ if ((c = focustop(selmon)))
+ c->kblayout_idx = kblayout_idx;
+
+ // Save current layout to kblayout_file
+ if (*kblayout_file && (f = fopen(kblayout_file, "w"))) {
+ fputs(xkb_keymap_layout_get_name(kb->wlr_group->keyboard.keymap,
+ idx), f);
+ fclose(f);
+ }
+
+ // Run kblayout_cmd
+ if (kblayout_cmd[0] && fork() == 0) {
+ execvp(kblayout_cmd[0], (char *const *)kblayout_cmd);
+ die("dwl: execvp %s failed:", kblayout_cmd[0]);
+ }
+}
+
int
keybinding(uint32_t mods, xkb_keysym_t sym)
{
@@ -1631,6 +1697,8 @@ keypressmod(struct wl_listener *listener, void *data)
/* Send modifiers to the client. */
wlr_seat_keyboard_notify_modifiers(seat,
&group->wlr_group->keyboard.modifiers);
+
+ kblayout(group);
}
int
--
2.46.2
|