From 53ec74a4ab6eff4958938bd9aea5ab5a3120ca96 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 25 Aug 2010 16:23:30 +0200 Subject: [PATCH 1/7] Implement hide-on-modifier --- i3bar/common.mk | 1 + i3bar/src/xcb.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+) diff --git a/i3bar/common.mk b/i3bar/common.mk index 65588314..1df1f6fb 100644 --- a/i3bar/common.mk +++ b/i3bar/common.mk @@ -15,6 +15,7 @@ LDFLAGS += -lev LDFLAGS += -lyajl LDFLAGS += -lxcb LDFLAGS += -lxcb-atom +LDFLAGS += -lX11 LDFLAGS += -L/usr/local/lib ifeq ($(DEBUG),1) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index a11a4e9a..45ed79cc 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -13,10 +13,16 @@ #include #include #include +#include +#include #include #include #include +#include +#include +#include + #include "common.h" /* We save the Atoms in an easy to access array, indexed by an enum */ @@ -36,10 +42,15 @@ xcb_screen_t *xcb_screens; xcb_window_t xcb_root; xcb_font_t xcb_font; +Display *xkb_dpy; +int xkb_event_base; +int mod_pressed; + /* Event-Watchers, to interact with the user */ ev_prepare *xcb_prep; ev_check *xcb_chk; ev_io *xcb_io; +ev_io *xkb_io; /* * Converts a colorstring to a colorpixel as expected from xcb_change_gc. @@ -56,6 +67,54 @@ uint32_t get_colorpixel(const char *s) { return (r << 16 | g << 8 | b); } +/* + * Hides all bars (unmaps them) + * + */ +void hide_bars() { + i3_output *walk; + SLIST_FOREACH(walk, outputs, slist) { + xcb_unmap_window(xcb_connection, walk->bar); + } +} + +/* + * Unhides all bars (maps them) + * + */ +void unhide_bars() { + i3_output *walk; + xcb_void_cookie_t cookie; + xcb_generic_error_t *err; + uint32_t mask; + uint32_t values[4]; + + SLIST_FOREACH(walk, outputs, slist) { + if (walk->bar == XCB_NONE) { + continue; + } + mask = XCB_CONFIG_WINDOW_X | + XCB_CONFIG_WINDOW_Y | + XCB_CONFIG_WINDOW_WIDTH | + XCB_CONFIG_WINDOW_HEIGHT; + values[0] = walk->rect.x; + values[1] = walk->rect.y + walk->rect.h - font_height - 6; + values[2] = walk->rect.w; + values[3] = font_height + 6; + printf("Reconfiguring Window for output %s to %d,%d\n", walk->name, values[0], values[1]); + cookie = xcb_configure_window_checked(xcb_connection, + walk->bar, + mask, + values); + + if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + printf("ERROR: Could not reconfigure window. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + xcb_map_window(xcb_connection, walk->bar); + } +} + /* * Handle a button-press-event (i.c. a mouse click on one of our bars). * We determine, wether the click occured on a ws-button or if the scroll- @@ -175,6 +234,45 @@ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) { void xcb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { } +/* + * We need to bind to the modifier per XKB. Sadly, XCB does not implement this + * + */ +void xkb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { + XkbEvent ev; + int modstate; + + printf("Got XKB-Event!\n"); + + while (XPending(xkb_dpy)) { + XNextEvent(xkb_dpy, (XEvent*)&ev); + + if (ev.type != xkb_event_base) { + printf("ERROR: No Xkb-Event!\n"); + continue; + } + + if (ev.any.xkb_type != XkbStateNotify) { + printf("ERROR: No State Notify!\n"); + continue; + } + + unsigned int mods = ev.state.mods; + modstate = mods & Mod4Mask; + } + + if (modstate != mod_pressed) { + if (modstate == 0) { + printf("Mod4 got released!\n"); + hide_bars(); + } else { + printf("Mod4 got pressed!\n"); + unhide_bars(); + } + mod_pressed = modstate; + } +} + /* * Calculate the rendered width of a string with the configured font. * The string has to be encoded in ucs2 and glyph_len has to be the length @@ -242,18 +340,55 @@ void init_xcb(char *fontname) { strlen(fontname), fontname); + int xkb_major, xkb_minor, xkb_errbase, xkb_err; + xkb_major = XkbMajorVersion; + xkb_minor = XkbMinorVersion; + + xkb_dpy = XkbOpenDisplay(":0", + &xkb_event_base, + &xkb_errbase, + &xkb_major, + &xkb_minor, + &xkb_err); + + if (xkb_dpy == NULL) { + printf("ERROR: No XKB!\n"); + exit(EXIT_FAILURE); + } + + if (fcntl(ConnectionNumber(xkb_dpy), F_SETFD, FD_CLOEXEC) == -1) { + fprintf(stderr, "Could not set FD_CLOEXEC on xkbdpy\n"); + exit(EXIT_FAILURE); + } + + int i1; + if (!XkbQueryExtension(xkb_dpy, &i1, &xkb_event_base, &xkb_errbase, &xkb_major, &xkb_minor)) { + printf("ERROR: XKB not supported by X-server!\n"); + exit(EXIT_FAILURE); + } + + if (!XkbSelectEvents(xkb_dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask)) { + printf("Could not grab Key!\n"); + exit(EXIT_FAILURE); + } + /* The varios Watchers to communicate with xcb */ xcb_io = malloc(sizeof(ev_io)); xcb_prep = malloc(sizeof(ev_prepare)); xcb_chk = malloc(sizeof(ev_check)); + xkb_io = malloc(sizeof(ev_io)); ev_io_init(xcb_io, &xcb_io_cb, xcb_get_file_descriptor(xcb_connection), EV_READ); ev_prepare_init(xcb_prep, &xcb_prep_cb); ev_check_init(xcb_chk, &xcb_chk_cb); + ev_io_init(xkb_io, &xkb_io_cb, ConnectionNumber(xkb_dpy), EV_READ); ev_io_start(main_loop, xcb_io); ev_prepare_start(main_loop, xcb_prep); ev_check_start(main_loop, xcb_chk); + ev_io_start(main_loop, xkb_io); + + XFlush(xkb_dpy); /* Now we get the atoms and save them in a nice data-structure */ get_atoms(); From 3c1a6384ab024d33c089219c4384633bb78daed0 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 25 Aug 2010 18:23:33 +0200 Subject: [PATCH 2/7] Define overrride-redirect The bars should not be in dockmode, when hide-on-mod is active --- i3bar/src/xcb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 45ed79cc..9494b389 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -484,11 +484,13 @@ void reconfig_windows() { printf("Creating Window for output %s\n", walk->name); walk->bar = xcb_generate_id(xcb_connection); - mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; + mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK; /* Black background */ values[0] = xcb_screens->black_pixel; + /* i3 is not supposed to manage our bar-windows */ + values[1] = 1; /* The events we want to receive */ - values[1] = XCB_EVENT_MASK_EXPOSURE | + values[2] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS; cookie = xcb_create_window_checked(xcb_connection, xcb_screens->root_depth, From a83e7699e75cad515019aa1ad5f7d59ee236a918 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 25 Aug 2010 18:31:03 +0200 Subject: [PATCH 3/7] Send the child SIGSTOPs and SIGCONTs --- i3bar/include/child.h | 12 ++++++++++++ i3bar/src/child.c | 22 +++++++++++++++++++++- i3bar/src/xcb.c | 3 +++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/i3bar/include/child.h b/i3bar/include/child.h index 0405816d..69cfc576 100644 --- a/i3bar/include/child.h +++ b/i3bar/include/child.h @@ -26,4 +26,16 @@ void start_child(char *command); */ void kill_child(); +/* + * Sends a SIGSTOP to the child-process (if existent) + * + */ +void stop_child(); + +/* + * Sends a SIGCONT to the child-process (if existent) + * + */ +void cont_child(); + #endif diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 2b0fb780..4be5d12d 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -176,7 +176,7 @@ void start_child(char *command) { } /* - * kill()s the child-prozess (if existend) and closes and + * kill()s the child-process (if existent) and closes and * free()s the stdin- and sigchild-watchers * */ @@ -186,3 +186,23 @@ void kill_child() { } cleanup(); } + +/* + * Sends a SIGSTOP to the child-process (if existent) + * + */ +void stop_child() { + if (child_pid != 0) { + kill(child_pid, SIGSTOP); + } +} + +/* + * Sends a SIGCONT to the child-process (if existent) + * + */ +void cont_child() { + if (child_pid != 0) { + kill(child_pid, SIGCONT); + } +} diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 9494b389..f5a50686 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -76,6 +76,7 @@ void hide_bars() { SLIST_FOREACH(walk, outputs, slist) { xcb_unmap_window(xcb_connection, walk->bar); } + stop_child(); } /* @@ -89,6 +90,8 @@ void unhide_bars() { uint32_t mask; uint32_t values[4]; + cont_child(); + SLIST_FOREACH(walk, outputs, slist) { if (walk->bar == XCB_NONE) { continue; From 701448c342b08b7517fb9700211cb4d53e307609 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 25 Aug 2010 21:50:01 +0200 Subject: [PATCH 4/7] Unhide on urgent-hint --- i3bar/src/xcb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index f5a50686..a974ead9 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -638,6 +638,8 @@ void draw_bars() { if (ws_walk->urgent) { printf("WS %s is urgent!\n", ws_walk->name); color = get_colorpixel("002400"); + /* The urgent-hint should get noticed, so we unhide the bars shortly */ + unhide_bars(); } xcb_change_gc(xcb_connection, outputs_walk->bargc, From c2ad6167e99c3006f8c1148bca78ec76d8e599ec Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 25 Aug 2010 23:36:25 +0200 Subject: [PATCH 5/7] Put the bars on top, when reconfiguring --- i3bar/src/xcb.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index a974ead9..7f479b4e 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -88,7 +88,7 @@ void unhide_bars() { xcb_void_cookie_t cookie; xcb_generic_error_t *err; uint32_t mask; - uint32_t values[4]; + uint32_t values[5]; cont_child(); @@ -99,11 +99,13 @@ void unhide_bars() { mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | - XCB_CONFIG_WINDOW_HEIGHT; + XCB_CONFIG_WINDOW_HEIGHT | + XCB_CONFIG_WINDOW_STACK_MODE; values[0] = walk->rect.x; values[1] = walk->rect.y + walk->rect.h - font_height - 6; values[2] = walk->rect.w; values[3] = font_height + 6; + values[4] = XCB_STACK_MODE_ABOVE; printf("Reconfiguring Window for output %s to %d,%d\n", walk->name, values[0], values[1]); cookie = xcb_configure_window_checked(xcb_connection, walk->bar, @@ -469,7 +471,7 @@ void destroy_window(i3_output *output) { */ void reconfig_windows() { uint32_t mask; - uint32_t values[4]; + uint32_t values[5]; xcb_void_cookie_t cookie; xcb_generic_error_t *err; @@ -552,11 +554,13 @@ void reconfig_windows() { mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | - XCB_CONFIG_WINDOW_HEIGHT; + XCB_CONFIG_WINDOW_HEIGHT | + XCB_CONFIG_WINDOW_STACK_MODE; values[0] = walk->rect.x; values[1] = walk->rect.y + walk->rect.h - font_height - 6; values[2] = walk->rect.w; values[3] = font_height + 6; + values[4] = XCB_STACK_MODE_ABOVE; printf("Reconfiguring Window for output %s to %d,%d\n", walk->name, values[0], values[1]); cookie = xcb_configure_window_checked(xcb_connection, walk->bar, From 386abde4df1b1fee4c933a47989c986c30856df9 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 26 Aug 2010 00:01:24 +0200 Subject: [PATCH 6/7] Put usage-message in own function --- i3bar/src/main.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 75f21382..63b60367 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -35,6 +35,17 @@ char *expand_path(char *path) { return result; } +void print_usage(char *elf_name) { + printf("Usage: %s [-s sock_path] [-c command] [-m] [-f font] [-h]\n", elf_name); + printf("-s \tConnect to i3 via \n"); + printf("-c \tExecute to get stdin\n"); + printf("-m\t\tHide the bars, when mod4 is not pressed.\n"); + printf("\t\tIf -c is specified, the childprocess is sent a SIGSTOP on hiding,\n"); + printf("\t\tand a SIGCONT on unhiding of the bars\n"); + printf("-f \tUse X-Core-Font for display\n"); + printf("-h\t\tDisplay this help-message and exit\n"); +} + int main(int argc, char **argv) { int opt; int option_index = 0; @@ -65,12 +76,9 @@ int main(int argc, char **argv) { case 'v': printf("i3bar version " I3BAR_VERSION " © 2010 Axel Wagner and contributors\n"); exit(EXIT_SUCCESS); + break; default: - printf("Usage: %s [-s socket_path] [-c command] [-f font] [-h]\n", argv[0]); - printf("-s : Connect to i3 via \n"); - printf("-c : Execute to get stdin\n"); - printf("-f : Use X-Core-Font for display\n"); - printf("-h: Display this help-message and exit\n"); + print_usage(argv[0]); exit(EXIT_SUCCESS); break; } From c4c918cb0657a0296abbc10531f402b107831ab3 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 26 Aug 2010 00:02:35 +0200 Subject: [PATCH 7/7] Make hide_on_modifier configurable --- i3bar/include/common.h | 1 + i3bar/include/config.h | 10 ++++++ i3bar/src/main.c | 9 ++++- i3bar/src/xcb.c | 74 ++++++++++++++++++++++++------------------ 4 files changed, 61 insertions(+), 33 deletions(-) create mode 100644 i3bar/include/config.h diff --git a/i3bar/include/common.h b/i3bar/include/common.h index d6b63a7e..dcb0bac3 100644 --- a/i3bar/include/common.h +++ b/i3bar/include/common.h @@ -25,6 +25,7 @@ struct rect_t { #include "queue.h" #include "child.h" +#include "config.h" #include "ipc.h" #include "outputs.h" #include "util.h" diff --git a/i3bar/include/config.h b/i3bar/include/config.h new file mode 100644 index 00000000..cbf158a6 --- /dev/null +++ b/i3bar/include/config.h @@ -0,0 +1,10 @@ +#ifndef CONFIG_H_ +#define CONFIL_H_ + +typedef struct config_t { + int hide_on_modifier; +} config_t; + +config_t config; + +#endif diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 63b60367..5afda241 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -53,16 +53,20 @@ int main(int argc, char **argv) { char *command = NULL; char *fontname = NULL; + /* Definition of the standard-config */ + config.hide_on_modifier = 0; + static struct option long_opt[] = { { "socket", required_argument, 0, 's' }, { "command", required_argument, 0, 'c' }, + { "hide", no_argument, 0, 'm' }, { "font", required_argument, 0, 'f' }, { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'v' }, { NULL, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "s:c:f:hv", long_opt, &option_index)) != -1) { + while ((opt = getopt_long(argc, argv, "s:c:mf:hv", long_opt, &option_index)) != -1) { switch (opt) { case 's': socket_path = expand_path(optarg); @@ -70,6 +74,9 @@ int main(int argc, char **argv) { case 'c': command = strdup(optarg); break; + case 'm': + config.hide_on_modifier = 1; + break; case 'f': fontname = strdup(optarg); break; diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 7f479b4e..d5a72ae3 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -72,6 +72,10 @@ uint32_t get_colorpixel(const char *s) { * */ void hide_bars() { + if (!config.hide_on_modifier) { + return; + } + i3_output *walk; SLIST_FOREACH(walk, outputs, slist) { xcb_unmap_window(xcb_connection, walk->bar); @@ -84,6 +88,10 @@ void hide_bars() { * */ void unhide_bars() { + if (!config.hide_on_modifier) { + return; + } + i3_output *walk; xcb_void_cookie_t cookie; xcb_generic_error_t *err; @@ -345,55 +353,57 @@ void init_xcb(char *fontname) { strlen(fontname), fontname); - int xkb_major, xkb_minor, xkb_errbase, xkb_err; - xkb_major = XkbMajorVersion; - xkb_minor = XkbMinorVersion; + if (config.hide_on_modifier) { + int xkb_major, xkb_minor, xkb_errbase, xkb_err; + xkb_major = XkbMajorVersion; + xkb_minor = XkbMinorVersion; - xkb_dpy = XkbOpenDisplay(":0", - &xkb_event_base, - &xkb_errbase, - &xkb_major, - &xkb_minor, - &xkb_err); + xkb_dpy = XkbOpenDisplay(":0", + &xkb_event_base, + &xkb_errbase, + &xkb_major, + &xkb_minor, + &xkb_err); - if (xkb_dpy == NULL) { - printf("ERROR: No XKB!\n"); - exit(EXIT_FAILURE); - } + if (xkb_dpy == NULL) { + printf("ERROR: No XKB!\n"); + exit(EXIT_FAILURE); + } - if (fcntl(ConnectionNumber(xkb_dpy), F_SETFD, FD_CLOEXEC) == -1) { - fprintf(stderr, "Could not set FD_CLOEXEC on xkbdpy\n"); - exit(EXIT_FAILURE); - } + if (fcntl(ConnectionNumber(xkb_dpy), F_SETFD, FD_CLOEXEC) == -1) { + fprintf(stderr, "Could not set FD_CLOEXEC on xkbdpy\n"); + exit(EXIT_FAILURE); + } - int i1; - if (!XkbQueryExtension(xkb_dpy, &i1, &xkb_event_base, &xkb_errbase, &xkb_major, &xkb_minor)) { - printf("ERROR: XKB not supported by X-server!\n"); - exit(EXIT_FAILURE); - } + int i1; + if (!XkbQueryExtension(xkb_dpy, &i1, &xkb_event_base, &xkb_errbase, &xkb_major, &xkb_minor)) { + printf("ERROR: XKB not supported by X-server!\n"); + exit(EXIT_FAILURE); + } - if (!XkbSelectEvents(xkb_dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask)) { - printf("Could not grab Key!\n"); - exit(EXIT_FAILURE); + if (!XkbSelectEvents(xkb_dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask)) { + printf("Could not grab Key!\n"); + exit(EXIT_FAILURE); + } + + xkb_io = malloc(sizeof(ev_io)); + ev_io_init(xkb_io, &xkb_io_cb, ConnectionNumber(xkb_dpy), EV_READ); + ev_io_start(main_loop, xkb_io); + XFlush(xkb_dpy); } /* The varios Watchers to communicate with xcb */ xcb_io = malloc(sizeof(ev_io)); xcb_prep = malloc(sizeof(ev_prepare)); xcb_chk = malloc(sizeof(ev_check)); - xkb_io = malloc(sizeof(ev_io)); ev_io_init(xcb_io, &xcb_io_cb, xcb_get_file_descriptor(xcb_connection), EV_READ); ev_prepare_init(xcb_prep, &xcb_prep_cb); ev_check_init(xcb_chk, &xcb_chk_cb); - ev_io_init(xkb_io, &xkb_io_cb, ConnectionNumber(xkb_dpy), EV_READ); ev_io_start(main_loop, xcb_io); ev_prepare_start(main_loop, xcb_prep); ev_check_start(main_loop, xcb_chk); - ev_io_start(main_loop, xkb_io); - - XFlush(xkb_dpy); /* Now we get the atoms and save them in a nice data-structure */ get_atoms(); @@ -492,8 +502,8 @@ void reconfig_windows() { mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK; /* Black background */ values[0] = xcb_screens->black_pixel; - /* i3 is not supposed to manage our bar-windows */ - values[1] = 1; + /* If hide_on_modifier is set, i3 is not supposed to manage our bar-windows */ + values[1] = config.hide_on_modifier; /* The events we want to receive */ values[2] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS;