sxhkd-rc

[fork] simple X hotkey daemon (but for the rc shell)
Log | Files | Refs | README | LICENSE

commit 3025a889cbd04b1a7fc836b49d793b24c3780ddc
parent 383e5de8f895257e809b1de6b3b0bcad04b49667
Author: Bastien Dejean <nihilhill@gmail.com>
Date:   Tue,  2 Jul 2013 22:12:42 +0200

New option: `-s`

Diffstat:
Mdoc/sxhkd.1 | 9+++++++--
Mdoc/sxhkd.1.txt | 3+++
Mparse.c | 4++++
Msxhkd.c | 240++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Msxhkd.h | 12+++++++++---
Mtypes.c | 9+++++++++
Mtypes.h | 1+
7 files changed, 166 insertions(+), 112 deletions(-)

diff --git a/doc/sxhkd.1 b/doc/sxhkd.1 @@ -2,12 +2,12 @@ .\" Title: sxhkd .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/> -.\" Date: 07/01/2013 +.\" Date: 07/02/2013 .\" Manual: Sxhkd Manual .\" Source: Sxhkd 0.4 .\" Language: English .\" -.TH "SXHKD" "1" "07/01/2013" "Sxhkd 0\&.4" "Sxhkd Manual" +.TH "SXHKD" "1" "07/02/2013" "Sxhkd 0\&.4" "Sxhkd Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -61,6 +61,11 @@ Read the main configuration from the given file\&. .RS 4 Redirect the commands output to the given file\&. .RE +.PP +\fB\-s\fR \fISTATUS_FIFO\fR +.RS 4 +Output status information to the given FIFO\&. +.RE .SH "CONFIGURATION" .sp Each line of the configuration file is interpreted as so: diff --git a/doc/sxhkd.1.txt b/doc/sxhkd.1.txt @@ -39,6 +39,9 @@ Options *-r* _REDIR_FILE_:: Redirect the commands output to the given file. +*-s* _STATUS_FIFO_:: + Output status information to the given FIFO. + Configuration ------------- diff --git a/parse.c b/parse.c @@ -2631,6 +2631,10 @@ bool parse_chain(char *string, chain_t *chain) event_type = key_to_button(event_type); chord_t *c = make_chord(keysym, button, modfield, event_type, replay_event); add_chord(chain, c); + if (status_fifo != NULL) { + strncpy(c->repr, chord, sizeof(c->repr)); + c->repr[strlen(chord)] = '\0'; + } keysym = XCB_NO_SYMBOL; button = XCB_NONE; modfield = 0; diff --git a/sxhkd.c b/sxhkd.c @@ -18,135 +18,37 @@ #include "grab.h" #include "sxhkd.h" -void hold(int sig) -{ - if (sig == SIGHUP || sig == SIGINT || sig == SIGTERM) - running = false; - else if (sig == SIGUSR1) - reload = true; - else if (sig == SIGALRM) - bell = true; -} - -void setup(void) -{ - dpy = xcb_connect(NULL, NULL); - if (xcb_connection_has_error(dpy)) - err("Can't open display.\n"); - xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(dpy)).data; - if (screen == NULL) - err("Can't acquire screen.\n"); - root = screen->root; - if ((shell = getenv(SXHKD_SHELL_ENV)) == NULL && (shell = getenv(SHELL_ENV)) == NULL) - err("The '%s' environment variable is not defined.\n", SHELL_ENV); - symbols = xcb_key_symbols_alloc(dpy); - hotkeys = hotkeys_tail = NULL; -} - -void cleanup(void) -{ - PUTS("cleanup"); - hotkey_t *hk = hotkeys; - while (hk != NULL) { - hotkey_t *tmp = hk->next; - destroy_chain(hk->chain); - free(hk); - hk = tmp; - } - hotkeys = hotkeys_tail = NULL; -} - -void reload_cmd(void) -{ - PUTS("reload"); - cleanup(); - load_config(config_file); - for (int i = 0; i < num_extra_confs; i++) - load_config(extra_confs[i]); - ungrab(); - grab(); -} - -void key_button_event(xcb_generic_event_t *evt, uint8_t event_type) -{ - xcb_keysym_t keysym = XCB_NO_SYMBOL; - xcb_button_t button = XCB_NONE; - bool replay_event = false; - uint16_t modfield = 0; - uint16_t lockfield = num_lock | caps_lock | scroll_lock; - parse_event(evt, event_type, &keysym, &button, &modfield); - modfield &= ~lockfield & MOD_STATE_FIELD; - if (keysym != XCB_NO_SYMBOL || button != XCB_NONE) { - hotkey_t *hk = find_hotkey(keysym, button, modfield, event_type, &replay_event); - if (hk != NULL) { - run(hk->command); - } - } - switch (event_type) { - case XCB_BUTTON_PRESS: - case XCB_BUTTON_RELEASE: - if (replay_event) - xcb_allow_events(dpy, XCB_ALLOW_REPLAY_POINTER, XCB_CURRENT_TIME); - else - xcb_allow_events(dpy, XCB_ALLOW_SYNC_POINTER, XCB_CURRENT_TIME); - break; - case XCB_KEY_PRESS: - case XCB_KEY_RELEASE: - if (replay_event) - xcb_allow_events(dpy, XCB_ALLOW_REPLAY_KEYBOARD, XCB_CURRENT_TIME); - else - xcb_allow_events(dpy, XCB_ALLOW_SYNC_KEYBOARD, XCB_CURRENT_TIME); - break; - } - xcb_flush(dpy); -} - -void motion_notify(xcb_generic_event_t *evt, uint8_t event_type) -{ - xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t *) evt; - /* PRINTF("motion notify %X %X %u\n", e->child, e->detail, e->state); */ - uint16_t lockfield = num_lock | caps_lock | scroll_lock; - uint16_t buttonfield = e->state >> 8; - uint16_t modfield = e->state & ~lockfield & MOD_STATE_FIELD; - xcb_button_t button = 1; - while (~buttonfield & 1 && button < 5) { - buttonfield = buttonfield >> 1; - button++; - } - hotkey_t *hk = find_hotkey(XCB_NO_SYMBOL, button, modfield, event_type, NULL); - if (hk != NULL) { - char command[MAXLEN]; - snprintf(command, sizeof(command), hk->command, e->root_x, e->root_y); - run(command); - } -} - int main(int argc, char *argv[]) { char opt; + char *fifo_path = NULL; + status_fifo = NULL; config_path = NULL; timeout = TIMEOUT; - while ((opt = getopt(argc, argv, "vht:c:r:")) != -1) { + while ((opt = getopt(argc, argv, "vht:c:r:s:")) != -1) { switch (opt) { case 'v': printf("%s\n", VERSION); exit(EXIT_SUCCESS); break; case 'h': - printf("sxhkd [-h|-v|-t TIMEOUT|-c CONFIG_FILE|-r REDIR_FILE] [EXTRA_CONFIG ...]\n"); + printf("sxhkd [-h|-v|-t TIMEOUT|-c CONFIG_FILE|-r REDIR_FILE|-s STATUS_FIFO] [EXTRA_CONFIG ...]\n"); exit(EXIT_SUCCESS); break; case 't': timeout = atoi(optarg); break; + case 'c': + config_path = optarg; + break; case 'r': redir_fd = open(optarg, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (redir_fd == -1) warn("Failed to open the command redirection file.\n"); break; - case 'c': - config_path = optarg; + case 's': + fifo_path = optarg; break; } } @@ -164,6 +66,14 @@ int main(int argc, char *argv[]) strncpy(config_file, config_path, sizeof(config_file)); } + if (fifo_path != NULL) { + int fifo_fd = open(fifo_path, O_RDWR | O_NONBLOCK); + if (fifo_fd != -1) + status_fifo = fdopen(fifo_fd, "w"); + else + warn("Couldn't open status fifo.\n"); + } + signal(SIGINT, hold); signal(SIGHUP, hold); signal(SIGTERM, hold); @@ -222,6 +132,8 @@ int main(int argc, char *argv[]) if (bell) { signal(SIGALRM, hold); abort_chain(); + if (status_fifo != NULL) + put_status(TIMEOUT_PREFIX, "Timeout reached"); bell = false; } @@ -233,9 +145,123 @@ int main(int argc, char *argv[]) if (redir_fd != -1) close(redir_fd); + if (status_fifo != NULL) + fclose(status_fifo); ungrab(); cleanup(); xcb_key_symbols_free(symbols); xcb_disconnect(dpy); return EXIT_SUCCESS; } + +void key_button_event(xcb_generic_event_t *evt, uint8_t event_type) +{ + xcb_keysym_t keysym = XCB_NO_SYMBOL; + xcb_button_t button = XCB_NONE; + bool replay_event = false; + uint16_t modfield = 0; + uint16_t lockfield = num_lock | caps_lock | scroll_lock; + parse_event(evt, event_type, &keysym, &button, &modfield); + modfield &= ~lockfield & MOD_STATE_FIELD; + if (keysym != XCB_NO_SYMBOL || button != XCB_NONE) { + hotkey_t *hk = find_hotkey(keysym, button, modfield, event_type, &replay_event); + if (hk != NULL) { + run(hk->command); + if (status_fifo != NULL) + put_status(COMMAND_PREFIX, hk->command); + } + } + switch (event_type) { + case XCB_BUTTON_PRESS: + case XCB_BUTTON_RELEASE: + if (replay_event) + xcb_allow_events(dpy, XCB_ALLOW_REPLAY_POINTER, XCB_CURRENT_TIME); + else + xcb_allow_events(dpy, XCB_ALLOW_SYNC_POINTER, XCB_CURRENT_TIME); + break; + case XCB_KEY_PRESS: + case XCB_KEY_RELEASE: + if (replay_event) + xcb_allow_events(dpy, XCB_ALLOW_REPLAY_KEYBOARD, XCB_CURRENT_TIME); + else + xcb_allow_events(dpy, XCB_ALLOW_SYNC_KEYBOARD, XCB_CURRENT_TIME); + break; + } + xcb_flush(dpy); +} + +void motion_notify(xcb_generic_event_t *evt, uint8_t event_type) +{ + xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t *) evt; + /* PRINTF("motion notify %X %X %u\n", e->child, e->detail, e->state); */ + uint16_t lockfield = num_lock | caps_lock | scroll_lock; + uint16_t buttonfield = e->state >> 8; + uint16_t modfield = e->state & ~lockfield & MOD_STATE_FIELD; + xcb_button_t button = 1; + while (~buttonfield & 1 && button < 5) { + buttonfield = buttonfield >> 1; + button++; + } + hotkey_t *hk = find_hotkey(XCB_NO_SYMBOL, button, modfield, event_type, NULL); + if (hk != NULL) { + char command[MAXLEN]; + snprintf(command, sizeof(command), hk->command, e->root_x, e->root_y); + run(command); + } +} + +void setup(void) +{ + dpy = xcb_connect(NULL, NULL); + if (xcb_connection_has_error(dpy)) + err("Can't open display.\n"); + xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(dpy)).data; + if (screen == NULL) + err("Can't acquire screen.\n"); + root = screen->root; + if ((shell = getenv(SXHKD_SHELL_ENV)) == NULL && (shell = getenv(SHELL_ENV)) == NULL) + err("The '%s' environment variable is not defined.\n", SHELL_ENV); + symbols = xcb_key_symbols_alloc(dpy); + hotkeys = hotkeys_tail = NULL; + progress[0] = '\0'; +} + +void cleanup(void) +{ + PUTS("cleanup"); + hotkey_t *hk = hotkeys; + while (hk != NULL) { + hotkey_t *tmp = hk->next; + destroy_chain(hk->chain); + free(hk); + hk = tmp; + } + hotkeys = hotkeys_tail = NULL; +} + +void reload_cmd(void) +{ + PUTS("reload"); + cleanup(); + load_config(config_file); + for (int i = 0; i < num_extra_confs; i++) + load_config(extra_confs[i]); + ungrab(); + grab(); +} + +void hold(int sig) +{ + if (sig == SIGHUP || sig == SIGINT || sig == SIGTERM) + running = false; + else if (sig == SIGUSR1) + reload = true; + else if (sig == SIGALRM) + bell = true; +} + +void put_status(char c, char *s) +{ + fprintf(status_fifo, "%c%s\n", c, s); + fflush(status_fifo); +} diff --git a/sxhkd.h b/sxhkd.h @@ -11,6 +11,9 @@ #define SXHKD_SHELL_ENV "SXHKD_SHELL" #define SHELL_ENV "SHELL" #define CONFIG_PATH "sxhkd/sxhkdrc" +#define HOTKEY_PREFIX 'H' +#define COMMAND_PREFIX 'C' +#define TIMEOUT_PREFIX 'T' #define TIMEOUT 3 xcb_connection_t *dpy; @@ -23,6 +26,8 @@ char *config_path; char **extra_confs; int num_extra_confs; int redir_fd; +FILE *status_fifo; +char progress[MAXLEN]; int timeout; hotkey_t *hotkeys, *hotkeys_tail; @@ -32,11 +37,12 @@ uint16_t num_lock; uint16_t caps_lock; uint16_t scroll_lock; -void hold(int); +void key_button_event(xcb_generic_event_t *, uint8_t); +void motion_notify(xcb_generic_event_t *, uint8_t); void setup(void); void cleanup(void); void reload_cmd(void); -void key_button_event(xcb_generic_event_t *, uint8_t); -void motion_notify(xcb_generic_event_t *, uint8_t); +void hold(int); +void put_status(char, char *); #endif diff --git a/types.c b/types.c @@ -14,6 +14,15 @@ hotkey_t *find_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfiel if (chained && c->state == c->head) continue; if (match_chord(c->state, event_type, keysym, button, modfield)) { + if (status_fifo != NULL && num_active == 0) { + if (!chained) { + strncpy(progress, c->state->repr, sizeof(progress)); + } else { + strncat(progress, LNK_SEP, sizeof(progress) - strlen(progress) - 1); + strncat(progress, c->state->repr, sizeof(progress) - strlen(progress) - 1); + } + put_status(HOTKEY_PREFIX, progress); + } if (replay_event != NULL && c->state->replay_event) *replay_event = true; if (c->state == c->tail) { diff --git a/types.h b/types.h @@ -10,6 +10,7 @@ typedef struct chord_t chord_t; struct chord_t { + char repr[MAXLEN]; xcb_keysym_t keysym; xcb_button_t button; uint16_t modfield;