From fe24eb748c98c8dea36dc0da5948ea118771215b Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 21 Aug 2010 13:09:34 +0200 Subject: [PATCH 1/8] Implement double-buffering to get rid of flickering --- i3bar/include/outputs.h | 1 + i3bar/src/xcb.c | 150 ++++++++++++++++++++++++++++++---------- 2 files changed, 113 insertions(+), 38 deletions(-) diff --git a/i3bar/include/outputs.h b/i3bar/include/outputs.h index 837aa50b..69a34a12 100644 --- a/i3bar/include/outputs.h +++ b/i3bar/include/outputs.h @@ -43,6 +43,7 @@ struct i3_output { rect rect; /* The rect (relative to the root-win) */ xcb_window_t bar; /* The id of the bar of the output */ + xcb_pixmap_t buffer; /* An extra pixmap for double-buffering */ xcb_gcontext_t bargc; /* The graphical context of the bar */ struct ws_head *workspaces; /* The workspaces on this output */ diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index ae1c8278..ed578700 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -221,10 +221,11 @@ void init_xcb(char *fontname) { /* We load and allocate the font */ xcb_font = xcb_generate_id(xcb_connection); - xcb_open_font(xcb_connection, - xcb_font, - strlen(fontname), - fontname); + xcb_void_cookie_t open_font_cookie; + open_font_cookie = xcb_open_font_checked(xcb_connection, + xcb_font, + strlen(fontname), + fontname); /* We also need the fontheight to configure our bars accordingly */ xcb_list_fonts_with_info_cookie_t cookie; @@ -249,6 +250,14 @@ void init_xcb(char *fontname) { /* Now we get the atoms and save them in a nice data-structure */ get_atoms(); + xcb_generic_error_t *err = xcb_request_check(xcb_connection, + open_font_cookie); + + if (err != NULL) { + printf("ERROR: Could not open font! XCB-Error-Code: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + /* Now we calculate the font-height */ xcb_list_fonts_with_info_reply_t *reply; reply = xcb_list_fonts_with_info_reply(xcb_connection, @@ -333,46 +342,81 @@ void reconfig_windows() { printf("Creating Window for output %s\n", walk->name); walk->bar = xcb_generate_id(xcb_connection); + walk->buffer = xcb_generate_id(xcb_connection); mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; /* Black background */ values[0] = xcb_screens->black_pixel; /* The events we want to receive */ values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS; - xcb_create_window(xcb_connection, - xcb_screens->root_depth, - walk->bar, - xcb_root, - walk->rect.x, walk->rect.y, - walk->rect.w, font_height + 6, - 1, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - xcb_screens->root_visual, - mask, - values); + + xcb_void_cookie_t win_cookie = xcb_create_window_checked(xcb_connection, + xcb_screens->root_depth, + walk->bar, + xcb_root, + walk->rect.x, walk->rect.y, + walk->rect.w, font_height + 6, + 1, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + xcb_screens->root_visual, + mask, + values); + + xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection, + xcb_screens->root_depth, + walk->buffer, + walk->bar, + walk->rect.w, + walk->rect.h); /* We want dock-windows (for now) */ - xcb_change_property(xcb_connection, - XCB_PROP_MODE_REPLACE, - walk->bar, - atoms[_NET_WM_WINDOW_TYPE], - atoms[ATOM], - 32, - 1, - (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); + xcb_void_cookie_t prop_cookie = xcb_change_property(xcb_connection, + XCB_PROP_MODE_REPLACE, + walk->bar, + atoms[_NET_WM_WINDOW_TYPE], + atoms[ATOM], + 32, + 1, + (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); /* We also want a graphics-context (the "canvas" on which we draw) */ walk->bargc = xcb_generate_id(xcb_connection); mask = XCB_GC_FONT; values[0] = xcb_font; - xcb_create_gc(xcb_connection, - walk->bargc, - walk->bar, - mask, - values); + + xcb_void_cookie_t gc_cookie = xcb_create_gc_checked(xcb_connection, + walk->bargc, + walk->bar, + mask, + values); /* We finally map the bar (display it on screen) */ - xcb_map_window(xcb_connection, walk->bar); + xcb_void_cookie_t map_cookie = xcb_map_window_checked(xcb_connection, walk->bar); + + if ((err = xcb_request_check(xcb_connection, win_cookie)) != NULL) { + printf("ERROR: Could not create Window. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + + if ((err = xcb_request_check(xcb_connection, pm_cookie)) != NULL) { + printf("ERROR: Could not create Pixmap. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + + if ((err = xcb_request_check(xcb_connection, prop_cookie)) != NULL) { + printf("ERROR: Could not set dock mode. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + + if ((err = xcb_request_check(xcb_connection, gc_cookie)) != NULL) { + printf("ERROR: Could not create graphical context. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + + if ((err = xcb_request_check(xcb_connection, map_cookie)) != NULL) { + printf("ERROR: Could not map window. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } } else { /* We already have a bar, so we just reconfigure it */ mask = XCB_CONFIG_WINDOW_X | @@ -384,11 +428,32 @@ void reconfig_windows() { 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]); - xcb_configure_window(xcb_connection, - walk->bar, - mask, - values); - } + + xcb_void_cookie_t cfg_cookie = xcb_configure_window_checked(xcb_connection, + walk->bar, + mask, + values); + + xcb_free_pixmap(xcb_connection, walk->buffer); + walk->buffer = xcb_generate_id(xcb_connection); + + xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection, + xcb_screens->root_depth, + walk->buffer, + walk->bar, + walk->rect.w, + walk->rect.h); + + if ((err = xcb_request_check(xcb_connection, cfg_cookie)) != NULL) { + printf("ERROR: Could not reconfigure window. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + + if ((err = xcb_request_check(xcb_connection, pm_cookie)) != NULL) { + printf("ERROR: Could not create Pixmap. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + } } } @@ -415,7 +480,7 @@ void draw_bars() { &color); xcb_rectangle_t rect = { 0, 0, outputs_walk->rect.w, font_height + 6 }; xcb_poly_fill_rectangle(xcb_connection, - outputs_walk->bar, + outputs_walk->buffer, outputs_walk->bargc, 1, &rect); @@ -437,7 +502,7 @@ void draw_bars() { xcb_void_cookie_t cookie; cookie = xcb_image_text_16(xcb_connection, glyph_count, - outputs_walk->bar, + outputs_walk->buffer, outputs_walk->bargc, outputs_walk->rect.w - get_string_width(text, glyph_count) - 4, font_height + 1, @@ -470,7 +535,7 @@ void draw_bars() { &color); xcb_rectangle_t rect = { i + 1, 1, ws_walk->name_width + 8, font_height + 4 }; xcb_poly_fill_rectangle(xcb_connection, - outputs_walk->bar, + outputs_walk->buffer, outputs_walk->bargc, 1, &rect); @@ -481,13 +546,22 @@ void draw_bars() { &color); xcb_image_text_16(xcb_connection, ws_walk->name_glyphs, - outputs_walk->bar, + outputs_walk->buffer, outputs_walk->bargc, i + 5, font_height + 1, ws_walk->ucs2_name); i += 10 + ws_walk->name_width; } + xcb_copy_area(xcb_connection, + outputs_walk->buffer, + outputs_walk->bar, + outputs_walk->bargc, + 0, 0, + 0, 0, + outputs_walk->rect.w, + outputs_walk->rect.h); + i = 0; } } From 6ad922dbd5562903e28780bb1913683b36c1427a Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 21 Aug 2010 13:29:38 +0200 Subject: [PATCH 2/8] Add declaration, accidentally lost in last commit --- i3bar/src/xcb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index ed578700..7f6379e1 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -329,6 +329,8 @@ void reconfig_windows() { uint32_t mask; uint32_t values[4]; + xcb_generic_error_t *err; + i3_output *walk; SLIST_FOREACH(walk, outputs, slist) { if (!walk->active) { From 17484d82f2b8a530badb8311341ef9e04df4f3ec Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Tue, 7 Sep 2010 17:28:15 +0200 Subject: [PATCH 3/8] Allocate the right amount of memory for ev_child --- i3bar/src/child.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 2b0fb780..c0a56661 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -169,7 +169,7 @@ void start_child(char *command) { ev_io_start(main_loop, stdin_io); /* We must cleanup, if the child unexpectedly terminates */ - child_sig = malloc(sizeof(ev_io)); + child_sig = malloc(sizeof(ev_child)); ev_child_init(child_sig, &child_sig_cb, child_pid, 0); ev_child_start(main_loop, child_sig); From a3e37b059fafc5c1179bd656780935a2dded25df Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 3 Dec 2010 17:59:16 +0100 Subject: [PATCH 4/8] Switch back ws_fg and ws_bg (Thanks julien) --- i3bar/src/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 35ea9210..ec85d324 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -181,10 +181,10 @@ int main(int argc, char **argv) { read_color(&colors.inactive_ws_bg); break; case 'G': - read_color(&colors.urgent_ws_fg); + read_color(&colors.urgent_ws_bg); break; case 'H': - read_color(&colors.urgent_ws_bg); + read_color(&colors.urgent_ws_fg); break; default: print_usage(argv[0]); From 9912d7fdbbf3cd68d836f4f22700eb583de5d5e2 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 23 Dec 2010 16:38:22 +0100 Subject: [PATCH 5/8] Update changelog and manpage --- i3bar/CHANGELOG | 11 ++++++++--- i3bar/doc/i3bar.man | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/i3bar/CHANGELOG b/i3bar/CHANGELOG index 0106447e..b8030e43 100644 --- a/i3bar/CHANGELOG +++ b/i3bar/CHANGELOG @@ -1,8 +1,13 @@ +v0.6 +===== +- Add manpage +- Implement hide-on-modifier +- Custom colors can be set from the commandline +- Use double-buffering - Bugfix: Correctly render long text - Bugfix: Don't segfault on SIGCHILD -- Implement hide-on-modifier -- Use double-buffering - +- Bugfix: Double-fork() to avoid zombies +- Some minor bugfixes v0.5 ===== diff --git a/i3bar/doc/i3bar.man b/i3bar/doc/i3bar.man index c41371b8..9ee7f7ce 100644 --- a/i3bar/doc/i3bar.man +++ b/i3bar/doc/i3bar.man @@ -1,7 +1,7 @@ i3bar(1) ======== Axel Wagner -v0.5, September 2010 +v0.6, September 2010 == NAME From a39db9ae8264b54fbb638fe358bbebcde3e4ce96 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 23 Dec 2010 16:50:48 +0100 Subject: [PATCH 6/8] Remove unnecessary declaration --- i3bar/src/xcb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 300ac859..326ca2ad 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -636,8 +636,6 @@ void reconfig_windows() { uint32_t mask; uint32_t values[5]; - xcb_generic_error_t *err; - i3_output *walk; SLIST_FOREACH(walk, outputs, slist) { if (!walk->active) { From cdf56f16bf4199379c976bcb204b65450b86808d Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sun, 26 Dec 2010 14:34:54 +0100 Subject: [PATCH 7/8] Revert "Double-fork() to avoid zombies" This reverts commit a4eafae108b63f5df76eea2958aee8cf95cb1ad6. --- i3bar/src/child.c | 51 +++++++++++------------------------------------ 1 file changed, 12 insertions(+), 39 deletions(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 08d2bed9..7cd364e0 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -101,67 +100,41 @@ void child_sig_cb(struct ev_loop *loop, ev_child *watcher, int revents) { /* * Start a child-process with the specified command and reroute stdin. * We actually start a $SHELL to execute the command so we don't have to care - * about arguments and such. - * We also double-fork() to avoid zombies and pass the pid of the child through a - * temporary pipe back to i3bar + * about arguments and such * */ void start_child(char *command) { child_pid = 0; if (command != NULL) { - int fd[2], tmp[2]; - /* This pipe will be used to communicate between e.g. i3status and i3bar */ + int fd[2]; pipe(fd); - /* We also need this temporary pipe to get back the pid of i3status */ - pipe(tmp); - switch (fork()) { + child_pid = fork(); + switch (child_pid) { case -1: ELOG("Couldn't fork()\n"); exit(EXIT_FAILURE); case 0: - /* Double-fork(), so the child gets reparented to init */ - switch(child_pid = fork()) { - case -1: - ELOG("Couldn't fork() twice\n"); - exit(EXIT_FAILURE); - case 0: - /* Child-process. Reroute stdout and start shell */ - close(fd[0]); + /* Child-process. Reroute stdout and start shell */ + close(fd[0]); - dup2(fd[1], STDOUT_FILENO); + dup2(fd[1], STDOUT_FILENO); - static const char *shell = NULL; + static const char *shell = NULL; - if ((shell = getenv("SHELL")) == NULL) - shell = "/bin/sh"; + if ((shell = getenv("SHELL")) == NULL) + shell = "/bin/sh"; - execl(shell, shell, "-c", command, (char*) NULL); - return; - default: - /* Temporary parent. We tell i3bar about the pid of i3status and exit */ - write(tmp[1], &child_pid, sizeof(int)); - close(tmp[0]); - close(tmp[1]); - exit(EXIT_SUCCESS); - } + execl(shell, shell, "-c", command, (char*) NULL); + return; default: /* Parent-process. Rerout stdin */ close(fd[1]); dup2(fd[0], STDIN_FILENO); - /* We also need to get the pid of i3status from the temporary pipe */ - size_t rec = 0; - while (rec < sizeof(int)) { - rec += read(tmp[0], &child_pid, sizeof(int) - rec); - } - /* The temporary pipe is no longer needed */ - close(tmp[0]); - close(tmp[1]); break; } } - wait(0); /* We set O_NONBLOCK because blocking is evil in event-driven software */ fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); From ff0522fe95f9ac35754ac4a73d9d78195ebe6d05 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sun, 26 Dec 2010 14:45:31 +0100 Subject: [PATCH 8/8] Bugfix: Send child a SIGCONT, so it reacts to SIGTERM (no zombies \o/) --- i3bar/src/child.c | 1 + 1 file changed, 1 insertion(+) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 7cd364e0..3092d527 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -157,6 +157,7 @@ void start_child(char *command) { */ void kill_child() { if (child_pid != 0) { + kill(child_pid, SIGCONT); kill(child_pid, SIGTERM); } cleanup();