projects/guix·blob python-team · refs

243 lines · 6.3 KiB

1Make kmscon listen to a FIFO in /tmp that clients can write to
2to request a keymap change.
3
4Patch by Mathieu Othacehe <[email protected]>.
5Modified by Florian Pelz <[email protected]>
6and Ludovic Courtès <[email protected]>.
7
8diff --git a/src/pty.c b/src/pty.c
9index 1443f4a..f64cb5b 100644
10--- a/src/pty.c
11+++ b/src/pty.c
12@@ -46,6 +46,8 @@
13
14 #define KMSCON_NREAD 16384
15
16+#define INPUT_KEYMAP_UPDATE_FILE "/tmp/kmscon-%d-keymap-update"
17+
18 struct kmscon_pty {
19 unsigned long ref;
20 struct ev_eloop *eloop;
21@@ -241,9 +243,22 @@ static bool pty_is_open(struct kmscon_pty *pty)
22 return pty->fd >= 0;
23 }
24
25+static int kmscon_keymap_update(pid_t pid)
26+{
27+ char *file;
28+ int ret;
29+
30+ ret = asprintf(&file, INPUT_KEYMAP_UPDATE_FILE, pid);
31+ if (ret < 0)
32+ return ret;
33+
34+ return setenv("KEYMAP_UPDATE", file, 1);
35+}
36+
37 static void __attribute__((noreturn))
38 exec_child(const char *term, const char *colorterm, char **argv,
39- const char *seat, const char *vtnr, bool env_reset)
40+ const char *seat, const char *vtnr, bool env_reset,
41+ pid_t kmscon_pid)
42 {
43 char **env;
44 char **def_argv;
45@@ -277,6 +292,8 @@ exec_child(const char *term, const char *colorterm, char **argv,
46 if (vtnr)
47 setenv("XDG_VTNR", vtnr, 1);
48
49+ kmscon_keymap_update(kmscon_pid);
50+
51 execve(argv[0], argv, environ);
52
53 log_err("failed to exec child %s: %m", argv[0]);
54@@ -383,12 +400,14 @@ static int pty_spawn(struct kmscon_pty *pty, int master,
55 unsigned short width, unsigned short height)
56 {
57 pid_t pid;
58+ pid_t kmscon_pid;
59 struct winsize ws;
60
61 memset(&ws, 0, sizeof(ws));
62 ws.ws_col = width;
63 ws.ws_row = height;
64
65+ kmscon_pid = getpid();
66 pid = fork();
67 switch (pid) {
68 case -1:
69@@ -397,7 +416,7 @@ static int pty_spawn(struct kmscon_pty *pty, int master,
70 case 0:
71 setup_child(master, &ws);
72 exec_child(pty->term, pty->colorterm, pty->argv, pty->seat,
73- pty->vtnr, pty->env_reset);
74+ pty->vtnr, pty->env_reset, kmscon_pid);
75 exit(EXIT_FAILURE);
76 default:
77 log_debug("forking child %d", pid);
78diff --git a/src/uterm_input.c b/src/uterm_input.c
79index 6fcbc4b..990a09d 100644
80--- a/src/uterm_input.c
81+++ b/src/uterm_input.c
82@@ -178,6 +178,10 @@ static void input_new_dev(struct uterm_input *input,
83 if (ret)
84 goto err_rcodepoints;
85
86+ /* Add the FIFO fd only to the first input poll loop. */
87+ if (shl_dlist_empty(&input->devices))
88+ uxkb_dev_keymap_update(dev);
89+
90 if (input->awake > 0) {
91 ret = input_wake_up_dev(dev);
92 if (ret)
93diff --git a/src/uterm_input_internal.h b/src/uterm_input_internal.h
94index 04e6cc9..ec44459 100644
95--- a/src/uterm_input_internal.h
96+++ b/src/uterm_input_internal.h
97@@ -39,6 +39,8 @@
98 #include "shl_misc.h"
99 #include "uterm_input.h"
100
101+#define INPUT_KEYMAP_UPDATE_FILE "/tmp/kmscon-%d-keymap-update"
102+
103 enum uterm_input_device_capability {
104 UTERM_DEVICE_HAS_KEYS = (1 << 0),
105 UTERM_DEVICE_HAS_LEDS = (1 << 1),
106@@ -62,6 +64,8 @@ struct uterm_input_dev {
107
108 bool repeating;
109 struct ev_timer *repeat_timer;
110+ struct ev_fd *fd_update;
111+ int rupdate_fd;
112 };
113
114 struct uterm_input {
115@@ -95,6 +99,7 @@ void uxkb_desc_destroy(struct uterm_input *input);
116
117 int uxkb_dev_init(struct uterm_input_dev *dev);
118 void uxkb_dev_destroy(struct uterm_input_dev *dev);
119+int uxkb_dev_keymap_update(struct uterm_input_dev *dev);
120 int uxkb_dev_process(struct uterm_input_dev *dev,
121 uint16_t key_state,
122 uint16_t code);
123diff --git a/src/uterm_input_uxkb.c b/src/uterm_input_uxkb.c
124index 925c755..8fe08f8 100644
125--- a/src/uterm_input_uxkb.c
126+++ b/src/uterm_input_uxkb.c
127@@ -31,6 +31,9 @@
128 #include <stdlib.h>
129 #include <string.h>
130 #include <unistd.h>
131+#include <sys/types.h>
132+#include <sys/stat.h>
133+#include <fcntl.h>
134 #include <xkbcommon/xkbcommon.h>
135 #include "shl_hook.h"
136 #include "shl_llog.h"
137@@ -178,6 +181,106 @@ static void timer_event(struct ev_timer *timer, uint64_t num, void *data)
138 shl_hook_call(dev->input->hook, dev->input, &dev->repeat_event);
139 }
140
141+static void uxkb_keymap_update_handler(struct ev_fd *fd, int mask, void *data)
142+{
143+ struct uterm_input_dev *dev = data;
144+ char in;
145+ char keymap[4][255];
146+ int pos = 0;
147+ int curr_keymap = 0;
148+ int ret;
149+ char *model, *layout, *variant, *options;
150+
151+ if (!(mask & EV_READABLE))
152+ return;
153+
154+ memset(keymap, 0, sizeof(keymap));
155+
156+ model = keymap[0];
157+ layout = keymap[1];
158+ variant = keymap[2];
159+ options = keymap[3];
160+
161+ do {
162+ ret = read(dev->rupdate_fd, &in, sizeof(in));
163+ if (ret <= 0)
164+ break;
165+
166+ keymap[curr_keymap][pos++] = in;
167+
168+ if (in == '\0') {
169+ curr_keymap++;
170+ pos = 0;
171+ }
172+ } while (1);
173+
174+ llog_info(dev->input, "HANDLER CALLED %s|%s|%s\n",
175+ model, layout, variant);
176+
177+ struct uterm_input *input = dev->input;
178+ struct shl_dlist *iter;
179+
180+ /* Apply the new layout to all the inputs. */
181+ shl_dlist_for_each(iter, &input->devices) {
182+ struct uterm_input_dev *dev;
183+ dev = shl_dlist_entry(iter,
184+ struct uterm_input_dev,
185+ list);
186+ uxkb_desc_init(dev->input, model, layout, variant, options, NULL);
187+ dev->state = xkb_state_new(dev->input->keymap);
188+ if (!dev->state) {
189+ llog_error(dev->input, "cannot create XKB state");
190+ return;
191+ }
192+ }
193+
194+ /* The client will now close the FIFO. Close it too, and re-create a
195+ * FIFO so other clients can eventually connect. */
196+ ev_eloop_rm_fd(fd);
197+ close(dev->rupdate_fd);
198+ dev->rupdate_fd = -1;
199+ uxkb_dev_keymap_update(dev);
200+
201+}
202+
203+int uxkb_dev_keymap_update(struct uterm_input_dev *dev)
204+{
205+ int ret;
206+ char *file;
207+ int pid = getpid();
208+
209+ ret = asprintf(&file, INPUT_KEYMAP_UPDATE_FILE, pid);
210+ if (ret < 0)
211+ return ret;
212+
213+ (void) unlink(file);
214+ ret = mkfifo(file, S_IRWXU);
215+ if (ret < 0) {
216+ llog_warn(dev->input, "could not open fifo");
217+ return -EFAULT;
218+ }
219+ dev->rupdate_fd = open(file, O_RDONLY | O_NONBLOCK);
220+ if (dev->rupdate_fd < 0) {
221+ llog_warn(dev->input, "cannot open file %s (%d): %m",
222+ file, errno);
223+ return -EFAULT;
224+ }
225+
226+ setenv("KEYMAP_UPDATE", file, 1);
227+
228+ ret = ev_eloop_new_fd(dev->input->eloop, &dev->fd_update,
229+ dev->rupdate_fd, EV_READABLE,
230+ uxkb_keymap_update_handler, dev);
231+ if (ret) {
232+ llog_error(dev->input, "could not init keymap update");
233+ close(dev->rupdate_fd);
234+ dev->rupdate_fd = -1;
235+ return ret;
236+ }
237+
238+ return 0;
239+}
240+
241 int uxkb_dev_init(struct uterm_input_dev *dev)
242 {
243 int ret;