commit 3025a889cbd04b1a7fc836b49d793b24c3780ddc
parent 383e5de8f895257e809b1de6b3b0bcad04b49667
Author: Bastien Dejean <nihilhill@gmail.com>
Date: Tue, 2 Jul 2013 22:12:42 +0200
New option: `-s`
Diffstat:
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;