me
/
guix
Archived
1
0
Fork 0
This repository has been archived on 2024-08-07. You can view files and clone it, but cannot push or open issues/pull-requests.
guix/gnu/packages/patches/kmscon-runtime-keymap-switc...

244 lines
6.3 KiB
Diff

Make kmscon listen to a FIFO in /tmp that clients can write to
to request a keymap change.
Patch by Mathieu Othacehe <m.othacehe@gmail.com>.
Modified by Florian Pelz <pelzflorian@pelzflorian.de>
and Ludovic Courtès <ludo@gnu.org>.
diff --git a/src/pty.c b/src/pty.c
index 1443f4a..f64cb5b 100644
--- a/src/pty.c
+++ b/src/pty.c
@@ -46,6 +46,8 @@
#define KMSCON_NREAD 16384
+#define INPUT_KEYMAP_UPDATE_FILE "/tmp/kmscon-%d-keymap-update"
+
struct kmscon_pty {
unsigned long ref;
struct ev_eloop *eloop;
@@ -241,9 +243,22 @@ static bool pty_is_open(struct kmscon_pty *pty)
return pty->fd >= 0;
}
+static int kmscon_keymap_update(pid_t pid)
+{
+ char *file;
+ int ret;
+
+ ret = asprintf(&file, INPUT_KEYMAP_UPDATE_FILE, pid);
+ if (ret < 0)
+ return ret;
+
+ return setenv("KEYMAP_UPDATE", file, 1);
+}
+
static void __attribute__((noreturn))
exec_child(const char *term, const char *colorterm, char **argv,
- const char *seat, const char *vtnr, bool env_reset)
+ const char *seat, const char *vtnr, bool env_reset,
+ pid_t kmscon_pid)
{
char **env;
char **def_argv;
@@ -277,6 +292,8 @@ exec_child(const char *term, const char *colorterm, char **argv,
if (vtnr)
setenv("XDG_VTNR", vtnr, 1);
+ kmscon_keymap_update(kmscon_pid);
+
execve(argv[0], argv, environ);
log_err("failed to exec child %s: %m", argv[0]);
@@ -383,12 +400,14 @@ static int pty_spawn(struct kmscon_pty *pty, int master,
unsigned short width, unsigned short height)
{
pid_t pid;
+ pid_t kmscon_pid;
struct winsize ws;
memset(&ws, 0, sizeof(ws));
ws.ws_col = width;
ws.ws_row = height;
+ kmscon_pid = getpid();
pid = fork();
switch (pid) {
case -1:
@@ -397,7 +416,7 @@ static int pty_spawn(struct kmscon_pty *pty, int master,
case 0:
setup_child(master, &ws);
exec_child(pty->term, pty->colorterm, pty->argv, pty->seat,
- pty->vtnr, pty->env_reset);
+ pty->vtnr, pty->env_reset, kmscon_pid);
exit(EXIT_FAILURE);
default:
log_debug("forking child %d", pid);
diff --git a/src/uterm_input.c b/src/uterm_input.c
index 6fcbc4b..990a09d 100644
--- a/src/uterm_input.c
+++ b/src/uterm_input.c
@@ -178,6 +178,10 @@ static void input_new_dev(struct uterm_input *input,
if (ret)
goto err_rcodepoints;
+ /* Add the FIFO fd only to the first input poll loop. */
+ if (shl_dlist_empty(&input->devices))
+ uxkb_dev_keymap_update(dev);
+
if (input->awake > 0) {
ret = input_wake_up_dev(dev);
if (ret)
diff --git a/src/uterm_input_internal.h b/src/uterm_input_internal.h
index 04e6cc9..ec44459 100644
--- a/src/uterm_input_internal.h
+++ b/src/uterm_input_internal.h
@@ -39,6 +39,8 @@
#include "shl_misc.h"
#include "uterm_input.h"
+#define INPUT_KEYMAP_UPDATE_FILE "/tmp/kmscon-%d-keymap-update"
+
enum uterm_input_device_capability {
UTERM_DEVICE_HAS_KEYS = (1 << 0),
UTERM_DEVICE_HAS_LEDS = (1 << 1),
@@ -62,6 +64,8 @@ struct uterm_input_dev {
bool repeating;
struct ev_timer *repeat_timer;
+ struct ev_fd *fd_update;
+ int rupdate_fd;
};
struct uterm_input {
@@ -95,6 +99,7 @@ void uxkb_desc_destroy(struct uterm_input *input);
int uxkb_dev_init(struct uterm_input_dev *dev);
void uxkb_dev_destroy(struct uterm_input_dev *dev);
+int uxkb_dev_keymap_update(struct uterm_input_dev *dev);
int uxkb_dev_process(struct uterm_input_dev *dev,
uint16_t key_state,
uint16_t code);
diff --git a/src/uterm_input_uxkb.c b/src/uterm_input_uxkb.c
index 925c755..8fe08f8 100644
--- a/src/uterm_input_uxkb.c
+++ b/src/uterm_input_uxkb.c
@@ -31,6 +31,9 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#include <xkbcommon/xkbcommon.h>
#include "shl_hook.h"
#include "shl_llog.h"
@@ -178,6 +181,106 @@ static void timer_event(struct ev_timer *timer, uint64_t num, void *data)
shl_hook_call(dev->input->hook, dev->input, &dev->repeat_event);
}
+static void uxkb_keymap_update_handler(struct ev_fd *fd, int mask, void *data)
+{
+ struct uterm_input_dev *dev = data;
+ char in;
+ char keymap[4][255];
+ int pos = 0;
+ int curr_keymap = 0;
+ int ret;
+ char *model, *layout, *variant, *options;
+
+ if (!(mask & EV_READABLE))
+ return;
+
+ memset(keymap, 0, sizeof(keymap));
+
+ model = keymap[0];
+ layout = keymap[1];
+ variant = keymap[2];
+ options = keymap[3];
+
+ do {
+ ret = read(dev->rupdate_fd, &in, sizeof(in));
+ if (ret <= 0)
+ break;
+
+ keymap[curr_keymap][pos++] = in;
+
+ if (in == '\0') {
+ curr_keymap++;
+ pos = 0;
+ }
+ } while (1);
+
+ llog_info(dev->input, "HANDLER CALLED %s|%s|%s\n",
+ model, layout, variant);
+
+ struct uterm_input *input = dev->input;
+ struct shl_dlist *iter;
+
+ /* Apply the new layout to all the inputs. */
+ shl_dlist_for_each(iter, &input->devices) {
+ struct uterm_input_dev *dev;
+ dev = shl_dlist_entry(iter,
+ struct uterm_input_dev,
+ list);
+ uxkb_desc_init(dev->input, model, layout, variant, options, NULL);
+ dev->state = xkb_state_new(dev->input->keymap);
+ if (!dev->state) {
+ llog_error(dev->input, "cannot create XKB state");
+ return;
+ }
+ }
+
+ /* The client will now close the FIFO. Close it too, and re-create a
+ * FIFO so other clients can eventually connect. */
+ ev_eloop_rm_fd(fd);
+ close(dev->rupdate_fd);
+ dev->rupdate_fd = -1;
+ uxkb_dev_keymap_update(dev);
+
+}
+
+int uxkb_dev_keymap_update(struct uterm_input_dev *dev)
+{
+ int ret;
+ char *file;
+ int pid = getpid();
+
+ ret = asprintf(&file, INPUT_KEYMAP_UPDATE_FILE, pid);
+ if (ret < 0)
+ return ret;
+
+ (void) unlink(file);
+ ret = mkfifo(file, S_IRWXU);
+ if (ret < 0) {
+ llog_warn(dev->input, "could not open fifo");
+ return -EFAULT;
+ }
+ dev->rupdate_fd = open(file, O_RDONLY | O_NONBLOCK);
+ if (dev->rupdate_fd < 0) {
+ llog_warn(dev->input, "cannot open file %s (%d): %m",
+ file, errno);
+ return -EFAULT;
+ }
+
+ setenv("KEYMAP_UPDATE", file, 1);
+
+ ret = ev_eloop_new_fd(dev->input->eloop, &dev->fd_update,
+ dev->rupdate_fd, EV_READABLE,
+ uxkb_keymap_update_handler, dev);
+ if (ret) {
+ llog_error(dev->input, "could not init keymap update");
+ close(dev->rupdate_fd);
+ dev->rupdate_fd = -1;
+ return ret;
+ }
+
+ return 0;
+}
+
int uxkb_dev_init(struct uterm_input_dev *dev)
{
int ret;