commit - 193276b680731f03b45f7fe6d86fcfe75f573466
commit + 91009a76b6a0313a1be930d77b9c79c312d0da61
blob - 0368179e9c5d6888c5404ef0219b0d559a0c3d0a
blob + d554e22e149f851f331d3b11d8534de9a6713e81
--- bxhkd.c
+++ bxhkd.c
* See LICENSE.md and README.md for details.
*/
+/* bxhkd - basic X hotkey daemon */
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+
+#include "config.h"
+
+#define LENGTH(arr) (sizeof(arr) / sizeof(arr[0]))
+
+#define SOCKET_SUFFIX "/.local/tmp/bxwm.sock"
+
+static Display *dpy;
+static Window root;
+static volatile sig_atomic_t running = 1;
+
+static void grabkeys(void);
+static void keypress(XKeyEvent *ev);
+static void spawn(const char *cmd);
+static void send_cmd(char *cmd)
+static void sigchld(int sig);
+static void cleanup(void);
+
+static void
+grabkeys(void)
+{
+ unsigned int i, j;
+ KeyCode code;
+ unsigned int modifiers[] = { 0, LockMask, Mod2Mask, LockMask|Mod2Mask };
+
+ XUngrabKey(dpy, AnyKey, AnyModifier, root);
+ for (i = 0; i < LENGTH(keys); i++) {
+ code = XKeysymToKeycode(dpy, keys[i].keysym);
+ if (code == 0)
+ continue;
+ for (j = 0; j < LENGTH(modifiers); j++)
+ XGrabKey(dpy, code, keys[i].mod | modifiers[j],
+ root, True, GrabModeAsync, GrabModeAsync);
+ }
+}
+
+static void
+keypress(XKeyEvent *ev)
+{
+ KeySym keysym;
+ unsigned int i;
+
+ keysym = XLookupKeysym(ev, 0);
+ for (i = 0; i < LENGTH(keys); i++) {
+ if (keysym == keys[i].keysym
+ && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)) {
+ spawn(keys[i].command);
+ return;
+ }
+ }
+}
+
+static void
+spawn(const char *cmd)
+{
+ char buf[256];
+ char *argv[64];
+ char *tok;
+ int argc = 0;
+
+ strncpy(buf, cmd, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
+
+ tok = strtok(buf, " ");
+ while (tok && argc < 63) {
+ argv[argc++] = tok;
+ tok = strtok(NULL, " ");
+ }
+ argv[argc] = NULL;
+
+ if (fork() == 0) {
+ if (dpy)
+ close(ConnectionNumber(dpy));
+ setsid();
+ execvp(argv[0], argv);
+ fprintf(stderr, "bxhkd: execvp %s failed\n", argv[0]);
+ _exit(EXIT_FAILURE);
+ }
+}
+
+static void
+mappingnotify(XMappingEvent *ev)
+{
+ XRefreshKeyboardMapping(ev);
+ if (ev->request == MappingKeyboard)
+ grabkeys();
+}
+
+static void
+send_cmd(char *cmd) {
+ int sock;
+ struct sockaddr_un addr;
+ char *home = getenv("HOME");
+ char path[256];
+
+ snprintf(path, sizeof(path), "%s%s", home, "/.local/tmp/bxwm.sock");
+
+ if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) return;
+
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, path, sizeof(addr.sun_path)-1);
+
+ if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) != -1) {
+ write(sock, cmd, strlen(cmd));
+ }
+ close(sock);
+}
+
+static void
+sigchld(int sig)
+{
+ (void)sig;
+ while (waitpid(-1, NULL, WNOHANG) > 0);
+}
+
+static void
+sig_term(int sig)
+{
+ (void)sig;
+ running = 0;
+}
+
+static void
+cleanup(void)
+{
+ XUngrabKey(dpy, AnyKey, AnyModifier, root);
+ XCloseDisplay(dpy);
+}
+
+int
+main(void)
+{
+ XEvent ev;
+
+ signal(SIGCHLD, sigchld);
+ signal(SIGINT, sig_term);
+ signal(SIGTERM, sig_term);
+
+ if (!(dpy = XOpenDisplay(NULL))) {
+ fprintf(stderr, "bxhkd: cannot open display\n");
+ return EXIT_FAILURE;
+ }
+ root = DefaultRootWindow(dpy);
+
+ XSelectInput(dpy, root, KeyPressMask|StructureNotifyMask);
+ grabkeys();
+
+ while (running && XNextEvent(dpy, &ev) == 0) {
+ if (ev.type == KeyPress)
+ keypress(&ev.xkey);
+ else if (ev.type == MappingNotify)
+ mappingnotify(&ev.xmapping);
+ }
+
+ cleanup();
+ return EXIT_SUCCESS;
+}
+