From ddf8bd63c7cb8fb59c8e3c50f3885ce02283bbf4 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 18 Aug 2010 03:58:32 +0200 Subject: [PATCH 01/47] Added some error handling for xcb --- i3bar/src/xcb.c | 109 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 74 insertions(+), 35 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index ae1c8278..a11a4e9a 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -184,14 +184,14 @@ void xcb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { int get_string_width(xcb_char2b_t *string, int glyph_len) { xcb_query_text_extents_cookie_t cookie; xcb_query_text_extents_reply_t *reply; - xcb_generic_error_t *error; + xcb_generic_error_t *error = NULL; int width; cookie = xcb_query_text_extents(xcb_connection, xcb_font, glyph_len, string); reply = xcb_query_text_extents_reply(xcb_connection, cookie, &error); - if (reply == NULL) { - printf("ERROR: Could not get text extents!"); - return 7; + if (error != NULL) { + printf("ERROR: Could not get text extents! XCB-errorcode: %d\n", error->error_code); + exit(EXIT_FAILURE); } width = reply->overall_width; @@ -221,17 +221,26 @@ 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); + + 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); + } /* We also need the fontheight to configure our bars accordingly */ - xcb_list_fonts_with_info_cookie_t cookie; - cookie = xcb_list_fonts_with_info(xcb_connection, - 1, - strlen(fontname), - fontname); + xcb_list_fonts_with_info_cookie_t font_info_cookie; + font_info_cookie = xcb_list_fonts_with_info(xcb_connection, + 1, + strlen(fontname), + fontname); /* The varios Watchers to communicate with xcb */ xcb_io = malloc(sizeof(ev_io)); @@ -252,7 +261,7 @@ void init_xcb(char *fontname) { /* Now we calculate the font-height */ xcb_list_fonts_with_info_reply_t *reply; reply = xcb_list_fonts_with_info_reply(xcb_connection, - cookie, + font_info_cookie, NULL); font_height = reply->font_ascent + reply->font_descent; FREE(reply); @@ -290,6 +299,10 @@ void clean_xcb() { void get_atoms() { xcb_intern_atom_reply_t *reply; #define ATOM_DO(name) reply = xcb_intern_atom_reply(xcb_connection, atom_cookies[name], NULL); \ + if (reply == NULL) { \ + printf("ERROR: Could not get atom %s\n", #name); \ + exit(EXIT_FAILURE); \ + } \ atoms[name] = reply->atom; \ free(reply); @@ -320,6 +333,9 @@ void reconfig_windows() { uint32_t mask; uint32_t values[4]; + xcb_void_cookie_t cookie; + xcb_generic_error_t *err; + i3_output *walk; SLIST_FOREACH(walk, outputs, slist) { if (!walk->active) { @@ -339,17 +355,21 @@ void reconfig_windows() { /* 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); + 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); + if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + printf("ERROR: Could not create Window. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } /* We want dock-windows (for now) */ xcb_change_property(xcb_connection, @@ -360,19 +380,33 @@ void reconfig_windows() { 32, 1, (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); + if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + printf("ERROR: Could not set dock mode. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } /* 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); + cookie = xcb_create_gc_checked(xcb_connection, + walk->bargc, + walk->bar, + mask, + values); + + if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + printf("ERROR: Could not create graphical context. XCB-errorcode: %d\n", err->error_code); + exit(EXIT_FAILURE); + } /* We finally map the bar (display it on screen) */ - xcb_map_window(xcb_connection, walk->bar); + cookie = xcb_map_window_checked(xcb_connection, walk->bar); + + if ((err = xcb_request_check(xcb_connection, 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,10 +418,15 @@ 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); + 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); + } } } } From 84d7da0acf39f4aeb79c2bd21683e5d5cf58a172 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 19 Aug 2010 22:13:40 +0200 Subject: [PATCH 02/47] Correct typo in usage-message --- i3bar/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 45a4c0dc..75f21382 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -68,7 +68,7 @@ int main(int argc, char **argv) { 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 sdtin\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"); exit(EXIT_SUCCESS); From 5015cdc4d038cc09cde906b20879cec68c556842 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 21 Aug 2010 13:09:34 +0200 Subject: [PATCH 03/47] Implement double-buffering to get rid of flickering --- i3bar/include/outputs.h | 1 + i3bar/src/xcb.c | 151 +++++++++++++++++++++++++--------------- 2 files changed, 96 insertions(+), 56 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 a11a4e9a..02e9d392 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -227,14 +227,6 @@ void init_xcb(char *fontname) { strlen(fontname), fontname); - 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); - } - /* We also need the fontheight to configure our bars accordingly */ xcb_list_fonts_with_info_cookie_t font_info_cookie; font_info_cookie = xcb_list_fonts_with_info(xcb_connection, @@ -258,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,7 +333,6 @@ void reconfig_windows() { uint32_t mask; uint32_t values[4]; - xcb_void_cookie_t cookie; xcb_generic_error_t *err; i3_output *walk; @@ -349,61 +348,77 @@ 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; - 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); - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { - printf("ERROR: Could not create Window. XCB-errorcode: %d\n", err->error_code); - exit(EXIT_FAILURE); - } + + 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]); - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { - printf("ERROR: Could not set dock mode. XCB-errorcode: %d\n", err->error_code); - exit(EXIT_FAILURE); - } + 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; - cookie = xcb_create_gc_checked(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); - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + /* We finally map the bar (display it on screen) */ + 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); } - /* We finally map the bar (display it on screen) */ - cookie = xcb_map_window_checked(xcb_connection, walk->bar); - - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + 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); } @@ -418,16 +433,31 @@ 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]); - cookie = xcb_configure_window_checked(xcb_connection, - walk->bar, - mask, - values); + xcb_void_cookie_t cfg_cookie = xcb_configure_window_checked(xcb_connection, + walk->bar, + mask, + values); - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + 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); + } + } } } @@ -454,7 +484,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); @@ -476,7 +506,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, @@ -509,7 +539,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); @@ -520,13 +550,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 14b885adf19be199a79c55bd30cbfcd8b569bc2a Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sun, 22 Aug 2010 10:24:32 +0200 Subject: [PATCH 04/47] Only copy the double-buffer on expose-events --- i3bar/include/xcb.h | 6 ++++++ i3bar/src/xcb.c | 21 ++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index af2c8933..2e4b16a8 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -48,6 +48,12 @@ void reconfig_windows(); */ void draw_bars(); +/* + * Redraw the bars, i.e. simply copy the buffer to the barwindow + * + */ +void redraw_bars(); + /* * 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 diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 02e9d392..15e11faa 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -157,7 +157,7 @@ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) { switch (event->response_type & ~0x80) { case XCB_EXPOSE: /* Expose-events happen, when the window needs to be redrawn */ - draw_bars(); + redraw_bars(); break; case XCB_BUTTON_PRESS: /* Button-press-events are mouse-buttons clicked on one of our bars */ @@ -569,3 +569,22 @@ void draw_bars() { i = 0; } } + +/* + * Redraw the bars, i.e. simply copy the buffer to the barwindow + * + */ +void redraw_bars() { + i3_output *outputs_walk; + SLIST_FOREACH(outputs_walk, outputs, slist) { + 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); + xcb_flush(xcb_connection); + } +} From bef80146e605b5d2c2d36641ff5fcd7b94087ee1 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Tue, 24 Aug 2010 14:01:48 +0200 Subject: [PATCH 05/47] Don't manually strip dzen-formats. Instead "output_format = none" should be used in the i3status-config --- i3bar/src/child.c | 35 ++--------------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 2b0fb780..9b4e9aa0 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -37,38 +37,8 @@ void cleanup() { } /* - * Since we don't use colors and stuff, we strip the dzen-formatstrings - * - */ -void strip_dzen_formats(char *buffer) { - char *src = buffer; - char *dest = buffer; - while (*src != '\0') { - /* ^ starts a format-string, ) ends it */ - if (*src == '^') { - /* We replace the seperators from i3status by pipe-symbols */ - if (!strncmp(src, "^ro", strlen("^ro"))) { - *(dest++) = ' '; - *(dest++) = '|'; - *(dest++) = ' '; - } - while (*src != ')') { - src++; - } - src++; - } else { - *dest = *src; - src++; - dest++; - } - } - /* The last character is \n, which xcb cannot display */ - *(--dest) = '\0'; -} - -/* - * Callbalk for stdin. We read a line from stdin, strip dzen-formats and store - * the result in statusline + * Callbalk for stdin. We read a line from stdin and store the result + * in statusline * */ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { @@ -105,7 +75,6 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { FREE(buffer); return; } - strip_dzen_formats(buffer); FREE(statusline); statusline = buffer; printf("%s\n", buffer); From 6034eee6474b3f906e28d16d117a149e42441bd5 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 25 Aug 2010 04:58:28 +0200 Subject: [PATCH 06/47] Remove trailing newline from stdin --- i3bar/src/child.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 9b4e9aa0..054c007f 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -52,6 +52,8 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { n = read(fd, buffer + rec, buffer_len - rec); if (n == -1) { if (errno == EAGAIN) { + /* remove trailing newline and finish up */ + buffer[rec-1] = '\0'; break; } printf("ERROR: read() failed!"); @@ -66,6 +68,8 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { buffer_len += STDIN_CHUNK_SIZE; FREE(tmp); } else { + /* remove trailing newline and finish up */ + buffer[rec-1] = '\0'; break; } } From 53ec74a4ab6eff4958938bd9aea5ab5a3120ca96 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 25 Aug 2010 16:23:30 +0200 Subject: [PATCH 07/47] 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 08/47] 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 09/47] 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 10/47] 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 11/47] 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 12/47] 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 13/47] 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; From 4e298d5a1d386da2f50c013de8fed3b666fb81c5 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sat, 4 Sep 2010 18:26:30 +0200 Subject: [PATCH 14/47] Reimplement double-buffering Due to a merge-fuckup, the double-buffer-code got lost. Know flickering should not happen anymore. --- i3bar/src/xcb.c | 132 ++++++++++++++++++++++++++++++------------------ 1 file changed, 83 insertions(+), 49 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index d5a72ae3..42a49ced 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -229,7 +229,7 @@ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) { switch (event->response_type & ~0x80) { case XCB_EXPOSE: /* Expose-events happen, when the window needs to be redrawn */ - draw_bars(); + redraw_bars(); break; case XCB_BUTTON_PRESS: /* Button-press-events are mouse-buttons clicked on one of our bars */ @@ -483,7 +483,6 @@ void reconfig_windows() { uint32_t mask; uint32_t values[5]; - xcb_void_cookie_t cookie; xcb_generic_error_t *err; i3_output *walk; @@ -499,6 +498,7 @@ 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_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK; /* Black background */ values[0] = xcb_screens->black_pixel; @@ -507,55 +507,68 @@ void reconfig_windows() { /* The events we want to receive */ values[2] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS; - 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); - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { - printf("ERROR: Could not create Window. XCB-errorcode: %d\n", err->error_code); - exit(EXIT_FAILURE); - } + 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]); - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { - printf("ERROR: Could not set dock mode. XCB-errorcode: %d\n", err->error_code); - exit(EXIT_FAILURE); - } - + 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; - cookie = xcb_create_gc_checked(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); - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + /* We finally map the bar (display it on screen) */ + 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); } - /* We finally map the bar (display it on screen) */ - cookie = xcb_map_window_checked(xcb_connection, walk->bar); - - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + 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); } @@ -572,12 +585,12 @@ void reconfig_windows() { 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, - mask, - values); + xcb_void_cookie_t cfg_cookie = xcb_configure_window_checked(xcb_connection, + walk->bar, + mask, + values); - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + 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); } @@ -608,7 +621,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); @@ -630,7 +643,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, @@ -665,7 +678,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); @@ -676,13 +689,34 @@ 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; } + redraw_bars(); + i = 0; } } + +/* + * Redraw the bars, i.e. simply copy the buffer to the barwindow + * + */ +void redraw_bars() { + i3_output *outputs_walk; + SLIST_FOREACH(outputs_walk, outputs, slist) { + 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); + xcb_flush(xcb_connection); + } +} From 4d38bf81ba6d66ce0124019082820f7bdec1659b Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Tue, 7 Sep 2010 17:28:15 +0200 Subject: [PATCH 15/47] 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 2ba839ec..97162cb4 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -142,7 +142,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 4ec3e7a61956a1b5ec81ac29fdadc4402226ad3b Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 01:16:53 +0200 Subject: [PATCH 16/47] Define Macros MAX and MIN --- i3bar/include/util.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/i3bar/include/util.h b/i3bar/include/util.h index 0f5dd3e3..7e638152 100644 --- a/i3bar/include/util.h +++ b/i3bar/include/util.h @@ -11,6 +11,10 @@ #include "queue.h" +/* Get the maximum/minimum of x and y */ +#define MAX(x,y) ((x) > (y) ? (x) : (y)) +#define MIN(x,y) ((x) < (y) ? (x) : (y)) + /* Securely free p */ #define FREE(p) do { \ if (p != NULL) { \ From 2ce9c4024f701d1e8b7d748bc99d06c904f5046c Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 01:18:50 +0200 Subject: [PATCH 17/47] Draw the statusline to a seperate buffer-pixmap --- i3bar/src/xcb.c | 177 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 152 insertions(+), 25 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 42a49ced..88f4be35 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -42,16 +42,67 @@ xcb_screen_t *xcb_screens; xcb_window_t xcb_root; xcb_font_t xcb_font; +/* We need to cache some data to speed up text-width-prediction */ +xcb_query_font_reply_t *font_info; +xcb_charinfo_t *font_table; + +/* These are only relevant for XKB, which we only need for grabbing modifiers */ Display *xkb_dpy; int xkb_event_base; int mod_pressed; +/* Because the statusline is the same on all outputs, we have + * global buffer to render it on */ +xcb_gcontext_t statusline_ctx; +xcb_pixmap_t statusline_pm; +uint32_t statusline_width; + /* Event-Watchers, to interact with the user */ ev_prepare *xcb_prep; ev_check *xcb_chk; ev_io *xcb_io; ev_io *xkb_io; +/* + * Predicts the length of text based on cached data + * + */ +uint32_t predict_text_extents(xcb_char2b_t *text, uint32_t length) { + /* If we don't have per-character data, return the maximum width */ + if (font_table == NULL) { + return (font_info->max_bounds.character_width * length); + } + + uint32_t width = 0; + uint32_t i; + + for (i = 0; i < length; i++) { + xcb_charinfo_t *info; + int row = text[i].byte1; + int col = text[i].byte2; + + if (row < font_info->min_byte1 || row > font_info->max_byte1 || + col < font_info->min_char_or_byte2 || col > font_info->max_char_or_byte2) { + continue; + } + + /* Don't you ask me, how this one works… */ + info = &font_table[((row - font_info->min_byte1) * + (font_info->max_char_or_byte2 - font_info->min_char_or_byte2 + 1)) + + (col - font_info->min_char_or_byte2)]; + + if (info->character_width != 0 || + (info->right_side_bearing | + info->left_side_bearing | + info->ascent | + info->descent) != 0) { + width += info->character_width; + } + } + + return width; +} + /* * Converts a colorstring to a colorpixel as expected from xcb_change_gc. * s is assumed to be in the format "rrggbb" @@ -67,6 +118,52 @@ uint32_t get_colorpixel(const char *s) { return (r << 16 | g << 8 | b); } +/* + * Redraws the statusline to the buffer + * + */ +void refresh_statusline() { + int glyph_count; + uint32_t root_width = xcb_screens->width_in_pixels; + if (statusline == NULL) { + return; + } + + xcb_char2b_t *text = (xcb_char2b_t*) convert_utf8_to_ucs2(statusline, &glyph_count); + statusline_width = predict_text_extents(text, glyph_count); + int crop_x = MIN(0, ((int32_t)root_width) - ((int32_t)statusline_width)); + printf("Cropping statusline with %d glyphs at x=%d\n", glyph_count, crop_x); + statusline_width = MIN((int32_t)statusline_width, (int32_t)root_width); + + xcb_free_pixmap(xcb_connection, statusline_pm); + statusline_pm = xcb_generate_id(xcb_connection); + xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection, + xcb_screens->root_depth, + statusline_pm, + xcb_root, + statusline_width, + font_height); + + xcb_void_cookie_t text_cookie = xcb_image_text_16(xcb_connection, + glyph_count, + statusline_pm, + statusline_ctx, + 0, + font_height, + text); + + xcb_generic_error_t *err; + if ((err = xcb_request_check(xcb_connection, sl_pm_cookie)) != NULL) { + printf("ERROR: Could not allocate statusline-buffer! XCB-error: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + + if ((err = xcb_request_check(xcb_connection, text_cookie)) != NULL) { + printf("ERROR: Could not draw text to buffer! XCB-error: %d\n", err->error_code); + exit(EXIT_FAILURE); + } +} + /* * Hides all bars (unmaps them) * @@ -353,6 +450,10 @@ void init_xcb(char *fontname) { strlen(fontname), fontname); + xcb_query_font_cookie_t query_font_cookie; + query_font_cookie = xcb_query_font(xcb_connection, + xcb_font); + if (config.hide_on_modifier) { int xkb_major, xkb_minor, xkb_errbase, xkb_err; xkb_major = XkbMajorVersion; @@ -392,6 +493,22 @@ void init_xcb(char *fontname) { XFlush(xkb_dpy); } + /* We draw the statusline to a seperate pixmap, because it looks the same on all bars and + * this way, we can choose to crop it */ + statusline_ctx = xcb_generate_id(xcb_connection); + uint32_t mask = XCB_GC_FOREGROUND | + XCB_GC_BACKGROUND | + XCB_GC_FONT; + uint32_t vals[3] = { xcb_screens->white_pixel, xcb_screens->black_pixel, xcb_font }; + + xcb_void_cookie_t sl_ctx_cookie = xcb_create_gc_checked(xcb_connection, + statusline_ctx, + xcb_root, + mask, + vals); + + statusline_pm = xcb_generate_id(xcb_connection); + /* The varios Watchers to communicate with xcb */ xcb_io = malloc(sizeof(ev_io)); xcb_prep = malloc(sizeof(ev_prepare)); @@ -416,7 +533,27 @@ void init_xcb(char *fontname) { font_height = reply->font_ascent + reply->font_descent; FREE(reply); + font_info = xcb_query_font_reply(xcb_connection, + query_font_cookie, + &err); + + if (err != NULL) { + printf("ERROR: Could not query font! XCB-error: %d\n", err->error_code); + exit(EXIT_FAILURE); + } + + if (xcb_query_font_char_infos_length(font_info) == 0) { + font_table = NULL; + } else { + font_table = xcb_query_font_char_infos(font_info); + } + printf("Calculated Font-height: %d\n", font_height); + + if((err = xcb_request_check(xcb_connection, sl_ctx_cookie)) != NULL) { + printf("ERROR: Could not create context for statusline! XCB-error: %d\n", err->error_code); + exit(EXIT_FAILURE); + } } /* @@ -605,6 +742,9 @@ void reconfig_windows() { void draw_bars() { printf("Drawing Bars...\n"); int i = 0; + + refresh_statusline(); + i3_output *outputs_walk; SLIST_FOREACH(outputs_walk, outputs, slist) { if (!outputs_walk->active) { @@ -627,34 +767,21 @@ void draw_bars() { &rect); if (statusline != NULL) { printf("Printing statusline!\n"); - xcb_change_gc(xcb_connection, + + xcb_void_cookie_t ca_cookie = xcb_copy_area(xcb_connection, + statusline_pm, + outputs_walk->buffer, outputs_walk->bargc, - XCB_GC_BACKGROUND, - &color); - color = get_colorpixel("FFFFFF"); - xcb_change_gc(xcb_connection, - outputs_walk->bargc, - XCB_GC_FOREGROUND, - &color); - - int glyph_count; - xcb_char2b_t *text = (xcb_char2b_t*) convert_utf8_to_ucs2(statusline, &glyph_count); - - xcb_void_cookie_t cookie; - cookie = xcb_image_text_16(xcb_connection, - glyph_count, - outputs_walk->buffer, - outputs_walk->bargc, - outputs_walk->rect.w - get_string_width(text, glyph_count) - 4, - font_height + 1, - (xcb_char2b_t*) text); - - xcb_generic_error_t *err = xcb_request_check(xcb_connection, cookie); - - if (err != NULL) { - printf("XCB-Error: %d\n", err->error_code); + 0, 0, + MAX(0, (int16_t)(outputs_walk->rect.w - statusline_width)), 1, + (uint16_t)outputs_walk->rect.w, font_height); + xcb_generic_error_t *err; + if ((err = xcb_request_check(xcb_connection, ca_cookie)) != NULL) { + printf("ERROR: Can not copy statusline-buffer! XCB-error: %d\n", err->error_code); + free(err); } } + i3_ws *ws_walk; TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) { printf("Drawing Button for WS %s at x = %d\n", ws_walk->name, i); From c5dc3d49aa42220bfef156fb9d559c677dfd7381 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 01:51:10 +0200 Subject: [PATCH 18/47] We don't need to crop at that point --- i3bar/src/xcb.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 88f4be35..43ac8beb 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -124,16 +124,13 @@ uint32_t get_colorpixel(const char *s) { */ void refresh_statusline() { int glyph_count; - uint32_t root_width = xcb_screens->width_in_pixels; + if (statusline == NULL) { return; } xcb_char2b_t *text = (xcb_char2b_t*) convert_utf8_to_ucs2(statusline, &glyph_count); statusline_width = predict_text_extents(text, glyph_count); - int crop_x = MIN(0, ((int32_t)root_width) - ((int32_t)statusline_width)); - printf("Cropping statusline with %d glyphs at x=%d\n", glyph_count, crop_x); - statusline_width = MIN((int32_t)statusline_width, (int32_t)root_width); xcb_free_pixmap(xcb_connection, statusline_pm); statusline_pm = xcb_generate_id(xcb_connection); From 0dc802c7b5a41f4e6205e2632eca8bee86276b2a Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 01:52:04 +0200 Subject: [PATCH 19/47] Write a wrapper around xcb_image_text_16() xcb_image_text_16() can only process up to 255 glyphs, so we write a wrapper around it for arbitrary long strings --- i3bar/src/xcb.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 43ac8beb..e1495e66 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -103,6 +103,31 @@ uint32_t predict_text_extents(xcb_char2b_t *text, uint32_t length) { return width; } +/* + * Draws text given in UCS-2-encoding to a given drawable and position + * + */ +void draw_text(xcb_drawable_t drawable, xcb_gcontext_t ctx, int16_t x, int16_t y, + xcb_char2b_t *text, uint32_t glyph_count) { + int offset = 0; + int16_t pos_x = x; + while (glyph_count > 0) { + uint8_t chunk_size = MIN(255, glyph_count); + uint32_t chunk_width = predict_text_extents(text + offset, chunk_size); + + xcb_image_text_16(xcb_connection, + chunk_size, + drawable, + ctx, + pos_x, y, + text + offset); + + offset += chunk_size; + pos_x += chunk_width; + glyph_count -= chunk_size; + } +} + /* * Converts a colorstring to a colorpixel as expected from xcb_change_gc. * s is assumed to be in the format "rrggbb" From 52120e3ed54000d03896d4d598760aeb28aa0f63 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 02:17:18 +0200 Subject: [PATCH 20/47] Use draw_text() to render text to the correct spot --- i3bar/src/xcb.c | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index e1495e66..453d5f46 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -111,6 +111,8 @@ void draw_text(xcb_drawable_t drawable, xcb_gcontext_t ctx, int16_t x, int16_t y xcb_char2b_t *text, uint32_t glyph_count) { int offset = 0; int16_t pos_x = x; + int16_t font_ascent = font_info->font_ascent; + while (glyph_count > 0) { uint8_t chunk_size = MIN(255, glyph_count); uint32_t chunk_width = predict_text_extents(text + offset, chunk_size); @@ -119,7 +121,7 @@ void draw_text(xcb_drawable_t drawable, xcb_gcontext_t ctx, int16_t x, int16_t y chunk_size, drawable, ctx, - pos_x, y, + pos_x, y + font_ascent, text + offset); offset += chunk_size; @@ -166,24 +168,13 @@ void refresh_statusline() { statusline_width, font_height); - xcb_void_cookie_t text_cookie = xcb_image_text_16(xcb_connection, - glyph_count, - statusline_pm, - statusline_ctx, - 0, - font_height, - text); + draw_text(statusline_pm, statusline_ctx, 0, 0, text, glyph_count); xcb_generic_error_t *err; if ((err = xcb_request_check(xcb_connection, sl_pm_cookie)) != NULL) { printf("ERROR: Could not allocate statusline-buffer! XCB-error: %d\n", err->error_code); exit(EXIT_FAILURE); } - - if ((err = xcb_request_check(xcb_connection, text_cookie)) != NULL) { - printf("ERROR: Could not draw text to buffer! XCB-error: %d\n", err->error_code); - exit(EXIT_FAILURE); - } } /* @@ -790,18 +781,13 @@ void draw_bars() { if (statusline != NULL) { printf("Printing statusline!\n"); - xcb_void_cookie_t ca_cookie = xcb_copy_area(xcb_connection, + xcb_copy_area(xcb_connection, statusline_pm, outputs_walk->buffer, outputs_walk->bargc, - 0, 0, - MAX(0, (int16_t)(outputs_walk->rect.w - statusline_width)), 1, - (uint16_t)outputs_walk->rect.w, font_height); - xcb_generic_error_t *err; - if ((err = xcb_request_check(xcb_connection, ca_cookie)) != NULL) { - printf("ERROR: Can not copy statusline-buffer! XCB-error: %d\n", err->error_code); - free(err); - } + MAX(0, (int16_t)(statusline_width - outputs_walk->rect.w + 4)), 0, + MAX(0, (int16_t)(outputs_walk->rect.w - statusline_width - 4)), 3, + MIN(outputs_walk->rect.w - 4, statusline_width), font_height); } i3_ws *ws_walk; From a702ced32249ecd9fc61339b63712fc00a0f6b14 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 02:21:09 +0200 Subject: [PATCH 21/47] Add CHANGELOG --- i3bar/CHANGELOG | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 i3bar/CHANGELOG diff --git a/i3bar/CHANGELOG b/i3bar/CHANGELOG new file mode 100644 index 00000000..0106447e --- /dev/null +++ b/i3bar/CHANGELOG @@ -0,0 +1,9 @@ +- Bugfix: Correctly render long text +- Bugfix: Don't segfault on SIGCHILD +- Implement hide-on-modifier +- Use double-buffering + + +v0.5 +===== +- Initial release From d245d14765ef0676c85a346e3bea9cf25fe44a32 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 02:28:56 +0200 Subject: [PATCH 22/47] Use realloc instead of manually reallocating --- i3bar/src/child.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 97162cb4..a4c33bcd 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -61,12 +61,8 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { } if (n == 0) { if (rec == buffer_len) { - char *tmp = buffer; - buffer = malloc(buffer_len + STDIN_CHUNK_SIZE); - memset(buffer, '\0', buffer_len); - strncpy(buffer, tmp, buffer_len); buffer_len += STDIN_CHUNK_SIZE; - FREE(tmp); + buffer = realloc(buffer, buffer_len); } else { /* remove trailing newline and finish up */ buffer[rec-1] = '\0'; From 0e4487e489ea173ae09cb31c6a48751d5287bf69 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 03:03:43 +0200 Subject: [PATCH 23/47] Move child_pid into child.c --- i3bar/include/common.h | 1 - i3bar/src/child.c | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/i3bar/include/common.h b/i3bar/include/common.h index dcb0bac3..e885ddcd 100644 --- a/i3bar/include/common.h +++ b/i3bar/include/common.h @@ -13,7 +13,6 @@ typedef struct rect_t rect; typedef int bool; struct ev_loop* main_loop; -pid_t child_pid; char *statusline; struct rect_t { diff --git a/i3bar/src/child.c b/i3bar/src/child.c index a4c33bcd..1ed429c0 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -20,6 +20,9 @@ #include "common.h" +/* Global variables for child_*() */ +pid_t child_pid; + /* stdin- and sigchild-watchers */ ev_io *stdin_io; ev_child *child_sig; From 5deb95de33a7f4665ff9a7f312babca3109b7c83 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 03:04:40 +0200 Subject: [PATCH 24/47] Make i3_default_sock_path a local variable --- i3bar/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 5afda241..07dcf5b9 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -18,7 +18,6 @@ #include "common.h" -char *i3_default_sock_path = "~/.i3/ipc.sock"; char *expand_path(char *path) { static glob_t globbuf; @@ -52,6 +51,7 @@ int main(int argc, char **argv) { char *socket_path = NULL; char *command = NULL; char *fontname = NULL; + char *i3_default_sock_path = "~/.i3/ipc.sock"; /* Definition of the standard-config */ config.hide_on_modifier = 0; From 7fda48aa9fd5c5b6174de7378fd6e6592187a065 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 03:11:49 +0200 Subject: [PATCH 25/47] We don't need get_string_width anymore --- i3bar/include/xcb.h | 6 +++--- i3bar/src/workspaces.c | 5 +++-- i3bar/src/xcb.c | 28 +++------------------------- 3 files changed, 9 insertions(+), 30 deletions(-) diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 2e4b16a8..82216f7f 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -55,11 +55,11 @@ void draw_bars(); void redraw_bars(); /* - * Calculate the rendered width of a string with the configured font. + * Predicts the length of text based on cached data. * The string has to be encoded in ucs2 and glyph_len has to be the length - * of the string (in width) + * of the string (in glyphs). * */ -int get_string_width(xcb_char2b_t *string, int glyph_len); +uint32_t predict_text_extents(xcb_char2b_t *text, uint32_t length); #endif diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index 8ba79eec..71903fb0 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -115,8 +115,9 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, unsigne xcb_char2b_t *ucs2_name = (xcb_char2b_t*) convert_utf8_to_ucs2(params->workspaces_walk->name, &ucs2_len); params->workspaces_walk->ucs2_name = ucs2_name; params->workspaces_walk->name_glyphs = ucs2_len; - params->workspaces_walk->name_width = get_string_width(params->workspaces_walk->ucs2_name, - params->workspaces_walk->name_glyphs); + params->workspaces_walk->name_width = + predict_text_extents(params->workspaces_walk->ucs2_name, + params->workspaces_walk->name_glyphs); printf("Got Workspace %s, name_width: %d, glyphs: %d\n", params->workspaces_walk->name, diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 453d5f46..e200c5e4 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -64,7 +64,9 @@ ev_io *xcb_io; ev_io *xkb_io; /* - * Predicts the length of text based on cached data + * Predicts the length of text based on cached data. + * The string has to be encoded in ucs2 and glyph_len has to be the length + * of the string (in glyphs). * */ uint32_t predict_text_extents(xcb_char2b_t *text, uint32_t length) { @@ -396,30 +398,6 @@ void xkb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { } } -/* - * 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 - * of the string (in width) - * - */ -int get_string_width(xcb_char2b_t *string, int glyph_len) { - xcb_query_text_extents_cookie_t cookie; - xcb_query_text_extents_reply_t *reply; - xcb_generic_error_t *error = NULL; - int width; - - cookie = xcb_query_text_extents(xcb_connection, xcb_font, glyph_len, string); - reply = xcb_query_text_extents_reply(xcb_connection, cookie, &error); - if (error != NULL) { - printf("ERROR: Could not get text extents! XCB-errorcode: %d\n", error->error_code); - exit(EXIT_FAILURE); - } - - width = reply->overall_width; - free(reply); - return width; -} - /* * Initialize xcb and use the specified fontname for text-rendering * From c82556f0f2ac97bf2731f3f6aed008dca946cca9 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 03:27:06 +0200 Subject: [PATCH 26/47] Use only xcb_query_font() --- i3bar/include/xcb.h | 2 -- i3bar/src/xcb.c | 18 ++++-------------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 82216f7f..75402285 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -9,8 +9,6 @@ #ifndef XCB_H_ #define XCB_H_ -int font_height; - /* * Initialize xcb and use the specified fontname for text-rendering * diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index e200c5e4..f4f064a1 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -44,6 +44,7 @@ xcb_font_t xcb_font; /* We need to cache some data to speed up text-width-prediction */ xcb_query_font_reply_t *font_info; +int font_height; xcb_charinfo_t *font_table; /* These are only relevant for XKB, which we only need for grabbing modifiers */ @@ -434,13 +435,8 @@ void init_xcb(char *fontname) { exit(EXIT_FAILURE); } - /* We also need the fontheight to configure our bars accordingly */ - xcb_list_fonts_with_info_cookie_t font_info_cookie; - font_info_cookie = xcb_list_fonts_with_info(xcb_connection, - 1, - strlen(fontname), - fontname); - + /* We need to save info about the font, because we need the fonts height and + * information about the width of characters */ xcb_query_font_cookie_t query_font_cookie; query_font_cookie = xcb_query_font(xcb_connection, xcb_font); @@ -517,16 +513,10 @@ void init_xcb(char *fontname) { get_atoms(); /* Now we calculate the font-height */ - xcb_list_fonts_with_info_reply_t *reply; - reply = xcb_list_fonts_with_info_reply(xcb_connection, - font_info_cookie, - NULL); - font_height = reply->font_ascent + reply->font_descent; - FREE(reply); - font_info = xcb_query_font_reply(xcb_connection, query_font_cookie, &err); + font_height = font_info->font_ascent + font_info->font_descent; if (err != NULL) { printf("ERROR: Could not query font! XCB-error: %d\n", err->error_code); From 93453c64f2db520416e381f2fb64cc0ca58fce79 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 05:26:31 +0200 Subject: [PATCH 27/47] Add some more comments --- i3bar/src/child.c | 3 +++ i3bar/src/ipc.c | 14 +++++++++++--- i3bar/src/main.c | 16 +++++++++++++++- i3bar/src/xcb.c | 21 ++++++++++++++++++--- 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index 1ed429c0..f57da9e1 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -114,6 +114,7 @@ void start_child(char *command) { printf("ERROR: Couldn't fork()"); exit(EXIT_FAILURE); case 0: + /* Child-process. Reroute stdout and start shell */ close(fd[0]); dup2(fd[1], STDOUT_FILENO); @@ -126,6 +127,7 @@ void start_child(char *command) { execl(shell, shell, "-c", command, (char*) NULL); return; default: + /* Parent-process. Rerout stdin */ close(fd[1]); dup2(fd[0], STDIN_FILENO); @@ -134,6 +136,7 @@ void start_child(char *command) { } } + /* We set O_NONBLOCK because blocking is evil in event-driven software */ fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); stdin_io = malloc(sizeof(ev_io)); diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 59563636..da9378f5 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -51,7 +51,7 @@ int get_ipc_fd(const char *socket_path) { * */ void got_command_reply(char *reply) { - /* FIXME: Error handling for command-replies */ + /* TODO: Error handling for command-replies */ } /* @@ -71,7 +71,7 @@ void got_workspace_reply(char *reply) { */ void got_subscribe_reply(char *reply) { printf("Got Subscribe Reply: %s\n", reply); - /* FIXME: Error handling for subscribe-commands */ + /* TODO: Error handling for subscribe-commands */ } /* @@ -134,6 +134,8 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { exit(EXIT_FAILURE); } + /* We first parse the fixed-length IPC-header, to know, how much data + * we have to expect */ uint32_t rec = 0; while (rec < header_len) { int n = read(fd, header + rec, header_len - rec); @@ -156,11 +158,13 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { exit(EXIT_FAILURE); } - /* Know we read the rest of the message */ char *walk = header + strlen(I3_IPC_MAGIC); uint32_t size = *((uint32_t*) walk); walk += sizeof(uint32_t); uint32_t type = *((uint32_t*) walk); + + /* Now that we know, what to expect, we can start read()ing the rest + * of the message */ char *buffer = malloc(size + 1); if (buffer == NULL) { printf("ERROR: Could not allocate memory!\n"); @@ -205,7 +209,11 @@ int i3_send_msg(uint32_t type, const char *payload) { len = strlen(payload); } + /* We are a wellbehaved client and send a proper header first */ uint32_t to_write = strlen (I3_IPC_MAGIC) + sizeof(uint32_t)*2 + len; + /* TODO: I'm not entirely sure if this buffer really has to contain more + * than the pure header (why not just write() the payload from *payload?), + * but we leave it for now */ char *buffer = malloc(to_write); if (buffer == NULL) { printf("ERROR: Could not allocate memory\n"); diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 07dcf5b9..118c2947 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -18,7 +18,10 @@ #include "common.h" - +/* + * Glob path, i.e. expand ~ + * + */ char *expand_path(char *path) { static glob_t globbuf; if (glob(path, GLOB_NOCHECK | GLOB_TILDE, NULL, &globbuf) < 0) { @@ -92,6 +95,9 @@ int main(int argc, char **argv) { } if (fontname == NULL) { + /* This is a very restrictive default. More sensefull would be something like + * "-misc-*-*-*-*--*-*-*-*-*-*-*-*". But since that produces very ugly results + * on my machine, let's stick with this until we have a configfile */ fontname = "-misc-fixed-medium-r-semicondensed--12-110-75-75-c-60-iso10646-1"; } @@ -108,13 +114,21 @@ int main(int argc, char **argv) { FREE(socket_path); + /* We subscribe to the i3-events we need */ subscribe_events(); + /* We initiate the main-function by requesting infos about the outputs and + * workspaces. Everything else (creating the bars, showing the right workspace- + * buttons and more) is taken care of by the event-driveniness of the code */ i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); + /* The name of this function is actually misleading. Even if no -c is specified, + * this function initiates the watchers to listen on stdin and react accordingly */ start_child(command); + /* From here on everything should run smooth for itself, just start listening for + * events. We stop simply stop the event-loop, when we are finished */ ev_loop(main_loop, 0); kill_child(); diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index f4f064a1..4939d6ab 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -441,6 +441,9 @@ void init_xcb(char *fontname) { query_font_cookie = xcb_query_font(xcb_connection, xcb_font); + /* To grab modifiers without blocking other applications from receiving key-events + * involving that modifier, we sadly have to use xkb which is not yet fully supported + * in xcb */ if (config.hide_on_modifier) { int xkb_major, xkb_minor, xkb_errbase, xkb_err; xkb_major = XkbMajorVersion; @@ -494,6 +497,8 @@ void init_xcb(char *fontname) { mask, vals); + /* We only generate an id for the pixmap, because the width of it is dependent on the + * input we get */ statusline_pm = xcb_generate_id(xcb_connection); /* The varios Watchers to communicate with xcb */ @@ -512,7 +517,7 @@ void init_xcb(char *fontname) { /* Now we get the atoms and save them in a nice data-structure */ get_atoms(); - /* Now we calculate the font-height */ + /* Now we save the font-infos */ font_info = xcb_query_font_reply(xcb_connection, query_font_cookie, &err); @@ -637,6 +642,7 @@ void reconfig_windows() { mask, values); + /* The double-buffer we use to render stuff off-screen */ xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection, xcb_screens->root_depth, walk->buffer, @@ -644,7 +650,8 @@ void reconfig_windows() { walk->rect.w, walk->rect.h); - /* We want dock-windows (for now) */ + /* We want dock-windows (for now). When override_redirect is set, i3 is ignoring + * this one */ xcb_void_cookie_t prop_cookie = xcb_change_property(xcb_connection, XCB_PROP_MODE_REPLACE, walk->bar, @@ -653,7 +660,9 @@ void reconfig_windows() { 32, 1, (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]); - /* We also want a graphics-context (the "canvas" on which we draw) */ + + /* We also want a graphics-context for the bars (it defines the properties + * with which we draw to them) */ walk->bargc = xcb_generate_id(xcb_connection); mask = XCB_GC_FONT; values[0] = xcb_font; @@ -733,8 +742,10 @@ void draw_bars() { continue; } if (outputs_walk->bar == XCB_NONE) { + /* Oh shit, an active output without an own bar. Create it now! */ reconfig_windows(); } + /* First things first: clear the backbuffer */ uint32_t color = get_colorpixel("000000"); xcb_change_gc(xcb_connection, outputs_walk->bargc, @@ -746,9 +757,13 @@ void draw_bars() { outputs_walk->bargc, 1, &rect); + if (statusline != NULL) { printf("Printing statusline!\n"); + /* Luckily we already prepared a seperate pixmap containing the rendered + * statusline, we just have to copy the relevant parts to the relevant + * position */ xcb_copy_area(xcb_connection, statusline_pm, outputs_walk->buffer, From a75cb6e785632f3baafbbb4af2d065e1c074abdc Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 05:28:22 +0200 Subject: [PATCH 28/47] Rename xcb_screens to xcb_screen, it's really just one --- i3bar/src/xcb.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 4939d6ab..cf1c8905 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -38,7 +38,7 @@ xcb_atom_t atoms[NUM_ATOMS]; /* Variables, that are the same for all functions at all times */ xcb_connection_t *xcb_connection; -xcb_screen_t *xcb_screens; +xcb_screen_t *xcb_screen; xcb_window_t xcb_root; xcb_font_t xcb_font; @@ -165,7 +165,7 @@ void refresh_statusline() { xcb_free_pixmap(xcb_connection, statusline_pm); statusline_pm = xcb_generate_id(xcb_connection); xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection, - xcb_screens->root_depth, + xcb_screen->root_depth, statusline_pm, xcb_root, statusline_width, @@ -416,8 +416,8 @@ void init_xcb(char *fontname) { #define ATOM_DO(name) atom_cookies[name] = xcb_intern_atom(xcb_connection, 0, strlen(#name), #name); #include "xcb_atoms.def" - xcb_screens = xcb_setup_roots_iterator(xcb_get_setup(xcb_connection)).data; - xcb_root = xcb_screens->root; + xcb_screen = xcb_setup_roots_iterator(xcb_get_setup(xcb_connection)).data; + xcb_root = xcb_screen->root; /* We load and allocate the font */ xcb_font = xcb_generate_id(xcb_connection); @@ -489,7 +489,7 @@ void init_xcb(char *fontname) { uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT; - uint32_t vals[3] = { xcb_screens->white_pixel, xcb_screens->black_pixel, xcb_font }; + uint32_t vals[3] = { xcb_screen->white_pixel, xcb_screen->black_pixel, xcb_font }; xcb_void_cookie_t sl_ctx_cookie = xcb_create_gc_checked(xcb_connection, statusline_ctx, @@ -624,27 +624,27 @@ void reconfig_windows() { walk->buffer = xcb_generate_id(xcb_connection); mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK; /* Black background */ - values[0] = xcb_screens->black_pixel; + values[0] = xcb_screen->black_pixel; /* 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; xcb_void_cookie_t win_cookie = xcb_create_window_checked(xcb_connection, - xcb_screens->root_depth, + xcb_screen->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, + xcb_screen->root_visual, mask, values); /* The double-buffer we use to render stuff off-screen */ xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection, - xcb_screens->root_depth, + xcb_screen->root_depth, walk->buffer, walk->bar, walk->rect.w, From 60bab3db28326206fb7c4725c64dc99c755f0e92 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 05:29:01 +0200 Subject: [PATCH 29/47] Use font_ascent instead of font_height, it's more elegant --- i3bar/src/xcb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index cf1c8905..4e116050 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -563,6 +563,7 @@ void clean_xcb() { FREE(xcb_chk); FREE(xcb_prep); FREE(xcb_io); + FREE(font_info); } /* @@ -809,7 +810,7 @@ void draw_bars() { ws_walk->name_glyphs, outputs_walk->buffer, outputs_walk->bargc, - i + 5, font_height + 1, + i + 5, font_info->font_ascent + 2, ws_walk->ucs2_name); i += 10 + ws_walk->name_width; } From ca1a2957147fafd0082d0088deb28b78f6c88c6f Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 05:55:38 +0200 Subject: [PATCH 30/47] Clean the XCB-errorhandling a little bit up --- i3bar/src/xcb.c | 68 ++++++++++++++++--------------------------------- 1 file changed, 22 insertions(+), 46 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 4e116050..87829503 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -64,6 +64,17 @@ ev_check *xcb_chk; ev_io *xcb_io; ev_io *xkb_io; +/* We define xcb_request_failed as a macro to include the relevant line-number */ +#define xcb_request_failed(cookie, err_msg) _xcb_request_failed(cookie, err_msg, __LINE__) +int _xcb_request_failed(xcb_void_cookie_t cookie, char *err_msg, int line) { + xcb_generic_error_t *err; + if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { + printf("%s:%d - %s. X Error Code: %d", __FILE__, line, err_msg, err->error_code); + return err->error_code; + } + return 0; +} + /* * Predicts the length of text based on cached data. * The string has to be encoded in ucs2 and glyph_len has to be the length @@ -173,9 +184,7 @@ void refresh_statusline() { draw_text(statusline_pm, statusline_ctx, 0, 0, text, glyph_count); - xcb_generic_error_t *err; - if ((err = xcb_request_check(xcb_connection, sl_pm_cookie)) != NULL) { - printf("ERROR: Could not allocate statusline-buffer! XCB-error: %d\n", err->error_code); + if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer")) { exit(EXIT_FAILURE); } } @@ -207,7 +216,6 @@ void unhide_bars() { i3_output *walk; xcb_void_cookie_t cookie; - xcb_generic_error_t *err; uint32_t mask; uint32_t values[5]; @@ -233,8 +241,7 @@ void unhide_bars() { mask, values); - if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { - printf("ERROR: Could not reconfigure window. XCB-errorcode: %d\n", err->error_code); + if (xcb_request_failed(cookie, "Could not reconfigure window")) { exit(EXIT_FAILURE); } xcb_map_window(xcb_connection, walk->bar); @@ -427,14 +434,6 @@ void init_xcb(char *fontname) { strlen(fontname), fontname); - 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); - } - /* We need to save info about the font, because we need the fonts height and * information about the width of characters */ xcb_query_font_cookie_t query_font_cookie; @@ -520,11 +519,10 @@ void init_xcb(char *fontname) { /* Now we save the font-infos */ font_info = xcb_query_font_reply(xcb_connection, query_font_cookie, - &err); + NULL); font_height = font_info->font_ascent + font_info->font_descent; - if (err != NULL) { - printf("ERROR: Could not query font! XCB-error: %d\n", err->error_code); + if (xcb_request_failed(open_font_cookie, "Could not open font")) { exit(EXIT_FAILURE); } @@ -536,8 +534,7 @@ void init_xcb(char *fontname) { printf("Calculated Font-height: %d\n", font_height); - if((err = xcb_request_check(xcb_connection, sl_ctx_cookie)) != NULL) { - printf("ERROR: Could not create context for statusline! XCB-error: %d\n", err->error_code); + if (xcb_request_failed(sl_ctx_cookie, "Could not create context for statusline")) { exit(EXIT_FAILURE); } } @@ -607,8 +604,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) { @@ -676,28 +671,11 @@ void reconfig_windows() { /* We finally map the bar (display it on screen) */ 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); + if (xcb_request_failed(win_cookie, "Could not create window") || + xcb_request_failed(pm_cookie, "Could not create pixmap") || + xcb_request_failed(prop_cookie, "Could not set dock mode") || + xcb_request_failed(gc_cookie, "Could not create graphical context") || + xcb_request_failed(map_cookie, "Could not map window")) { exit(EXIT_FAILURE); } } else { @@ -717,9 +695,7 @@ void reconfig_windows() { walk->bar, mask, values); - - if ((err = xcb_request_check(xcb_connection, cfg_cookie)) != NULL) { - printf("ERROR: Could not reconfigure window. XCB-errorcode: %d\n", err->error_code); + if (xcb_request_failed(cfg_cookie, "Could not reconfigure window")) { exit(EXIT_FAILURE); } } From 920721bb939a0aac67da24fd40ccd8893143034d Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 06:49:28 +0200 Subject: [PATCH 31/47] Use DLOG/ELOG-macros, provide --verbose-option --- i3bar/include/config.h | 1 + i3bar/include/util.h | 11 ++++++++ i3bar/src/child.c | 8 +++--- i3bar/src/ipc.c | 42 +++++++++++++++--------------- i3bar/src/main.c | 15 +++++++---- i3bar/src/outputs.c | 2 +- i3bar/src/workspaces.c | 12 ++++----- i3bar/src/xcb.c | 58 +++++++++++++++++++++--------------------- 8 files changed, 83 insertions(+), 66 deletions(-) diff --git a/i3bar/include/config.h b/i3bar/include/config.h index cbf158a6..0496f431 100644 --- a/i3bar/include/config.h +++ b/i3bar/include/config.h @@ -3,6 +3,7 @@ typedef struct config_t { int hide_on_modifier; + int verbose; } config_t; config_t config; diff --git a/i3bar/include/util.h b/i3bar/include/util.h index 7e638152..1952b039 100644 --- a/i3bar/include/util.h +++ b/i3bar/include/util.h @@ -44,3 +44,14 @@ walk = TAILQ_FIRST(l); \ } \ } while (0) + +/* Use cool logging-macros */ +#define DLOG(fmt, ...) do { \ + if (config.verbose) { \ + printf("[%s:%d] " fmt, __FILE__, __LINE__, ##__VA_ARGS__); \ + } \ +} while(0) + +#define ELOG(fmt, ...) do { \ + fprintf(stderr, "[%s:%d] ERROR: " fmt, __FILE__, __LINE__, ##__VA_ARGS__); \ +} while(0) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index f57da9e1..fa70f452 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -59,7 +59,7 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { buffer[rec-1] = '\0'; break; } - printf("ERROR: read() failed!"); + ELOG("read() failed!\n"); exit(EXIT_FAILURE); } if (n == 0) { @@ -80,7 +80,7 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { } FREE(statusline); statusline = buffer; - printf("%s\n", buffer); + DLOG("%s\n", buffer); draw_bars(); } @@ -91,7 +91,7 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { * */ void child_sig_cb(struct ev_loop *loop, ev_child *watcher, int revents) { - printf("Child (pid: %d) unexpectedly exited with status %d\n", + DLOG("Child (pid: %d) unexpectedly exited with status %d\n", child_pid, watcher->rstatus); cleanup(); @@ -111,7 +111,7 @@ void start_child(char *command) { child_pid = fork(); switch (child_pid) { case -1: - printf("ERROR: Couldn't fork()"); + ELOG("Couldn't fork()\n"); exit(EXIT_FAILURE); case 0: /* Child-process. Reroute stdout and start shell */ diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index da9378f5..0ddccc25 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -30,7 +30,7 @@ typedef void(*handler_t)(char*); int get_ipc_fd(const char *socket_path) { int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); if (sockfd == -1) { - printf("ERROR: Could not create Socket!\n"); + ELOG("Could not create Socket!\n"); exit(EXIT_FAILURE); } @@ -39,7 +39,7 @@ int get_ipc_fd(const char *socket_path) { addr.sun_family = AF_LOCAL; strcpy(addr.sun_path, socket_path); if (connect(sockfd, (const struct sockaddr*) &addr, sizeof(struct sockaddr_un)) < 0) { - printf("ERROR: Could not connct to i3\n"); + ELOG("Could not connct to i3!\n"); exit(EXIT_FAILURE); } return sockfd; @@ -59,7 +59,7 @@ void got_command_reply(char *reply) { * */ void got_workspace_reply(char *reply) { - printf("Got Workspace-Data!\n"); + DLOG("Got Workspace-Data!\n"); parse_workspaces_json(reply); draw_bars(); } @@ -70,7 +70,7 @@ void got_workspace_reply(char *reply) { * */ void got_subscribe_reply(char *reply) { - printf("Got Subscribe Reply: %s\n", reply); + DLOG("Got Subscribe Reply: %s\n", reply); /* TODO: Error handling for subscribe-commands */ } @@ -79,9 +79,9 @@ void got_subscribe_reply(char *reply) { * */ void got_output_reply(char *reply) { - printf("Parsing Outputs-JSON...\n"); + DLOG("Parsing Outputs-JSON...\n"); parse_outputs_json(reply); - printf("Reconfiguring Windows...\n"); + DLOG("Reconfiguring Windows...\n"); reconfig_windows(); } @@ -98,7 +98,7 @@ handler_t reply_handlers[] = { * */ void got_workspace_event(char *event) { - printf("Got Workspace Event!\n"); + DLOG("Got Workspace Event!\n"); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); } @@ -107,7 +107,7 @@ void got_workspace_event(char *event) { * */ void got_output_event(char *event) { - printf("Got Output Event!\n"); + DLOG("Got Output Event!\n"); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); } @@ -123,14 +123,14 @@ handler_t event_handlers[] = { * */ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { - printf("Got data!\n"); + DLOG("Got data!\n"); int fd = watcher->fd; /* First we only read the header, because we know it's length */ uint32_t header_len = strlen(I3_IPC_MAGIC) + sizeof(uint32_t)*2; char *header = malloc(header_len); if (header == NULL) { - printf("ERROR: Could not allocate memory!\n"); + ELOG("Could not allocate memory!\n"); exit(EXIT_FAILURE); } @@ -140,21 +140,21 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { while (rec < header_len) { int n = read(fd, header + rec, header_len - rec); if (n == -1) { - printf("ERROR: read() failed!\n"); + ELOG("read() failed!\n"); exit(EXIT_FAILURE); } if (n == 0) { - printf("ERROR: Nothing to read!\n"); + ELOG("Nothing to read!\n"); exit(EXIT_FAILURE); } rec += n; } if (strncmp(header, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC))) { - printf("ERROR: Wrong magic code: %.*s\n Expected: %s\n", - (int) strlen(I3_IPC_MAGIC), - header, - I3_IPC_MAGIC); + ELOG("Wrong magic code: %.*s\n Expected: %s\n", + (int) strlen(I3_IPC_MAGIC), + header, + I3_IPC_MAGIC); exit(EXIT_FAILURE); } @@ -167,7 +167,7 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { * of the message */ char *buffer = malloc(size + 1); if (buffer == NULL) { - printf("ERROR: Could not allocate memory!\n"); + ELOG("Could not allocate memory!\n"); exit(EXIT_FAILURE); } rec = 0; @@ -175,11 +175,11 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { while (rec < size) { int n = read(fd, buffer + rec, size - rec); if (n == -1) { - printf("ERROR: read() failed!\n"); + ELOG("read() failed!\n"); exit(EXIT_FAILURE); } if (n == 0) { - printf("ERROR: Nothing to read!\n"); + ELOG("Nothing to read!\n"); exit(EXIT_FAILURE); } rec += n; @@ -216,7 +216,7 @@ int i3_send_msg(uint32_t type, const char *payload) { * but we leave it for now */ char *buffer = malloc(to_write); if (buffer == NULL) { - printf("ERROR: Could not allocate memory\n"); + ELOG("Could not allocate memory\n"); exit(EXIT_FAILURE); } @@ -236,7 +236,7 @@ int i3_send_msg(uint32_t type, const char *payload) { while (to_write > 0) { int n = write(i3_connection->fd, buffer + written, to_write); if (n == -1) { - printf("ERROR: write() failed!\n"); + ELOG("write() failed!\n"); exit(EXIT_FAILURE); } diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 118c2947..5b6debc5 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -25,12 +25,12 @@ char *expand_path(char *path) { static glob_t globbuf; if (glob(path, GLOB_NOCHECK | GLOB_TILDE, NULL, &globbuf) < 0) { - printf("glob() failed"); + ELOG("glob() failed\n"); exit(EXIT_FAILURE); } char *result = strdup(globbuf.gl_pathc > 0 ? globbuf.gl_pathv[0] : path); if (result == NULL) { - printf("malloc() failed"); + ELOG("malloc() failed\n"); exit(EXIT_FAILURE); } globfree(&globbuf); @@ -38,13 +38,14 @@ char *expand_path(char *path) { } void print_usage(char *elf_name) { - printf("Usage: %s [-s sock_path] [-c command] [-m] [-f font] [-h]\n", elf_name); + printf("Usage: %s [-s sock_path] [-c command] [-m] [-f font] [-V] [-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("-V\t\tBe (very) verbose with the debug-output\n"); printf("-h\t\tDisplay this help-message and exit\n"); } @@ -66,10 +67,11 @@ int main(int argc, char **argv) { { "font", required_argument, 0, 'f' }, { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'v' }, + { "verbose", no_argument, 0, 'V' }, { NULL, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "s:c:mf:hv", long_opt, &option_index)) != -1) { + while ((opt = getopt_long(argc, argv, "s:c:mf:hvV", long_opt, &option_index)) != -1) { switch (opt) { case 's': socket_path = expand_path(optarg); @@ -87,6 +89,9 @@ int main(int argc, char **argv) { printf("i3bar version " I3BAR_VERSION " © 2010 Axel Wagner and contributors\n"); exit(EXIT_SUCCESS); break; + case 'V': + config.verbose = 1; + break; default: print_usage(argv[0]); exit(EXIT_SUCCESS); @@ -102,7 +107,7 @@ int main(int argc, char **argv) { } if (socket_path == NULL) { - printf("No Socket Path Specified, default to %s\n", i3_default_sock_path); + ELOG("No Socket Path Specified, default to %s\n", i3_default_sock_path); socket_path = expand_path(i3_default_sock_path); } diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index de905783..3577d82b 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -230,7 +230,7 @@ void parse_outputs_json(char *json) { case yajl_status_client_canceled: case yajl_status_insufficient_data: case yajl_status_error: - printf("ERROR: Could not parse outputs-reply!\n"); + ELOG("Could not parse outputs-reply!\n"); exit(EXIT_FAILURE); break; } diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index 71903fb0..9f8acc1b 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -119,10 +119,10 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, unsigne predict_text_extents(params->workspaces_walk->ucs2_name, params->workspaces_walk->name_glyphs); - printf("Got Workspace %s, name_width: %d, glyphs: %d\n", - params->workspaces_walk->name, - params->workspaces_walk->name_width, - params->workspaces_walk->name_glyphs); + DLOG("Got Workspace %s, name_width: %d, glyphs: %d\n", + params->workspaces_walk->name, + params->workspaces_walk->name_width, + params->workspaces_walk->name_glyphs); FREE(params->cur_key); return 1; @@ -184,7 +184,7 @@ static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, uns params->cur_key = malloc(sizeof(unsigned char) * (keyLen + 1)); if (params->cur_key == NULL) { - printf("ERROR: Could not allocate memory!\n"); + ELOG("Could not allocate memory!\n"); exit(EXIT_FAILURE); } strncpy(params->cur_key, (const char*) keyVal, keyLen); @@ -238,7 +238,7 @@ void parse_workspaces_json(char *json) { case yajl_status_client_canceled: case yajl_status_insufficient_data: case yajl_status_error: - printf("ERROR: Could not parse workspaces-reply!\n"); + ELOG("Could not parse workspaces-reply!\n"); exit(EXIT_FAILURE); break; } diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 87829503..e1669061 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -69,7 +69,7 @@ ev_io *xkb_io; int _xcb_request_failed(xcb_void_cookie_t cookie, char *err_msg, int line) { xcb_generic_error_t *err; if ((err = xcb_request_check(xcb_connection, cookie)) != NULL) { - printf("%s:%d - %s. X Error Code: %d", __FILE__, line, err_msg, err->error_code); + ELOG("%s. X Error Code: %d\n", err_msg, err->error_code); return err->error_code; } return 0; @@ -235,7 +235,7 @@ void unhide_bars() { 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]); + DLOG("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, @@ -267,11 +267,11 @@ void handle_button(xcb_button_press_event_t *event) { } if (walk == NULL) { - printf("Unknown Bar klicked!\n"); + DLOG("Unknown Bar klicked!\n"); return; } - /* TODO: Move this to exern get_ws_for_output() */ + /* TODO: Move this to extern get_ws_for_output() */ TAILQ_FOREACH(cur_ws, walk->workspaces, tailq) { if (cur_ws->visible) { break; @@ -279,20 +279,20 @@ void handle_button(xcb_button_press_event_t *event) { } if (cur_ws == NULL) { - printf("No Workspace active?\n"); + DLOG("No Workspace active?\n"); return; } int32_t x = event->event_x; - printf("Got Button %d\n", event->detail); + DLOG("Got Button %d\n", event->detail); switch (event->detail) { case 1: /* Left Mousbutton. We determine, which button was clicked * and set cur_ws accordingly */ TAILQ_FOREACH(cur_ws, walk->workspaces, tailq) { - printf("x = %d\n", x); + DLOG("x = %d\n", x); if (x < cur_ws->name_width + 10) { break; } @@ -375,18 +375,18 @@ void xkb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { XkbEvent ev; int modstate; - printf("Got XKB-Event!\n"); + DLOG("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"); + ELOG("No Xkb-Event!\n"); continue; } if (ev.any.xkb_type != XkbStateNotify) { - printf("ERROR: No State Notify!\n"); + ELOG("No State Notify!\n"); continue; } @@ -396,10 +396,10 @@ void xkb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { if (modstate != mod_pressed) { if (modstate == 0) { - printf("Mod4 got released!\n"); + DLOG("Mod4 got released!\n"); hide_bars(); } else { - printf("Mod4 got pressed!\n"); + DLOG("Mod4 got pressed!\n"); unhide_bars(); } mod_pressed = modstate; @@ -414,10 +414,10 @@ void init_xcb(char *fontname) { /* FIXME: xcb_connect leaks Memory */ xcb_connection = xcb_connect(NULL, NULL); if (xcb_connection_has_error(xcb_connection)) { - printf("Cannot open display\n"); + ELOG("Cannot open display\n"); exit(EXIT_FAILURE); } - printf("Connected to xcb\n"); + DLOG("Connected to xcb\n"); /* We have to request the atoms we need */ #define ATOM_DO(name) atom_cookies[name] = xcb_intern_atom(xcb_connection, 0, strlen(#name), #name); @@ -456,23 +456,23 @@ void init_xcb(char *fontname) { &xkb_err); if (xkb_dpy == NULL) { - printf("ERROR: No XKB!\n"); + ELOG("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"); + ELOG("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"); + ELOG("XKB not supported by X-server!\n"); exit(EXIT_FAILURE); } if (!XkbSelectEvents(xkb_dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask)) { - printf("Could not grab Key!\n"); + ELOG("Could not grab Key!\n"); exit(EXIT_FAILURE); } @@ -532,7 +532,7 @@ void init_xcb(char *fontname) { font_table = xcb_query_font_char_infos(font_info); } - printf("Calculated Font-height: %d\n", font_height); + DLOG("Calculated Font-height: %d\n", font_height); if (xcb_request_failed(sl_ctx_cookie, "Could not create context for statusline")) { exit(EXIT_FAILURE); @@ -571,14 +571,14 @@ void get_atoms() { xcb_intern_atom_reply_t *reply; #define ATOM_DO(name) reply = xcb_intern_atom_reply(xcb_connection, atom_cookies[name], NULL); \ if (reply == NULL) { \ - printf("ERROR: Could not get atom %s\n", #name); \ + ELOG("Could not get atom %s\n", #name); \ exit(EXIT_FAILURE); \ } \ atoms[name] = reply->atom; \ free(reply); #include "xcb_atoms.def" - printf("Got Atoms\n"); + DLOG("Got Atoms\n"); } /* @@ -609,12 +609,12 @@ void reconfig_windows() { if (!walk->active) { /* If an output is not active, we destroy it's bar */ /* FIXME: Maybe we rather want to unmap? */ - printf("Destroying window for output %s\n", walk->name); + DLOG("Destroying window for output %s\n", walk->name); destroy_window(walk); continue; } if (walk->bar == XCB_NONE) { - printf("Creating Window for output %s\n", walk->name); + DLOG("Creating Window for output %s\n", walk->name); walk->bar = xcb_generate_id(xcb_connection); walk->buffer = xcb_generate_id(xcb_connection); @@ -690,7 +690,7 @@ void reconfig_windows() { 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]); + DLOG("Reconfiguring Window for output %s to %d,%d\n", walk->name, values[0], values[1]); xcb_void_cookie_t cfg_cookie = xcb_configure_window_checked(xcb_connection, walk->bar, mask, @@ -707,7 +707,7 @@ void reconfig_windows() { * */ void draw_bars() { - printf("Drawing Bars...\n"); + DLOG("Drawing Bars...\n"); int i = 0; refresh_statusline(); @@ -715,7 +715,7 @@ void draw_bars() { i3_output *outputs_walk; SLIST_FOREACH(outputs_walk, outputs, slist) { if (!outputs_walk->active) { - printf("Output %s inactive, skipping...\n", outputs_walk->name); + DLOG("Output %s inactive, skipping...\n", outputs_walk->name); continue; } if (outputs_walk->bar == XCB_NONE) { @@ -736,7 +736,7 @@ void draw_bars() { &rect); if (statusline != NULL) { - printf("Printing statusline!\n"); + DLOG("Printing statusline!\n"); /* Luckily we already prepared a seperate pixmap containing the rendered * statusline, we just have to copy the relevant parts to the relevant @@ -752,13 +752,13 @@ void draw_bars() { i3_ws *ws_walk; TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) { - printf("Drawing Button for WS %s at x = %d\n", ws_walk->name, i); + DLOG("Drawing Button for WS %s at x = %d\n", ws_walk->name, i); uint32_t color = get_colorpixel("240000"); if (ws_walk->visible) { color = get_colorpixel("480000"); } if (ws_walk->urgent) { - printf("WS %s is urgent!\n", ws_walk->name); + DLOG("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(); From 27fa078159f5c4301bb594686015a1964e525ae3 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 17 Sep 2010 18:27:07 +0200 Subject: [PATCH 32/47] Adding a manpage --- i3bar/Makefile | 12 +++++++-- i3bar/doc/Makefile | 7 ++++++ i3bar/doc/i3bar.man | 61 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 i3bar/doc/Makefile create mode 100644 i3bar/doc/i3bar.man diff --git a/i3bar/Makefile b/i3bar/Makefile index 57af15e1..8f124493 100644 --- a/i3bar/Makefile +++ b/i3bar/Makefile @@ -6,10 +6,17 @@ FILES:=$(wildcard src/*.c) FILES:=$(FILES:.c=.o) HEADERS:=$(wildcard include/*.h) -all: ${FILES} +all: i3bar doc + +i3bar: ${FILES} echo "LINK" $(CC) -o i3bar ${FILES} ${LDFLAGS} +doc: + echo "" + echo "SUBDIR doc" + $(MAKE) -C doc + src/%.o: src/%.c ${HEADERS} echo "CC $<" $(CC) $(CFLAGS) -c -o $@ $< @@ -21,5 +28,6 @@ install: all clean: rm src/*.o + make -C doc clean -.PHONY: install clean +.PHONY: install clean doc diff --git a/i3bar/doc/Makefile b/i3bar/doc/Makefile new file mode 100644 index 00000000..f363207c --- /dev/null +++ b/i3bar/doc/Makefile @@ -0,0 +1,7 @@ +all: i3bar.1 + +i3bar.1: i3bar.man + echo "A2X i3bar" + a2x -f manpage i3bar.man +clean: + rm -f i3bar.xml i3bar.1 i3bar.html diff --git a/i3bar/doc/i3bar.man b/i3bar/doc/i3bar.man new file mode 100644 index 00000000..dc094ae6 --- /dev/null +++ b/i3bar/doc/i3bar.man @@ -0,0 +1,61 @@ +i3bar(1) +======== +Axel Wagner +v0.5, September 2010 + +== NAME + +i3bar - xcb-based status- and ws-bar + +== SYNOPSIS + +*i3bar* [*-s* 'sock_path'] [*-c* 'command'] [*-m*] [*-f* 'font'] [*-V*] [*-h*] + +== OPTIONS + +*-s, --socket* 'sock_path':: +Specifies the 'socketpath', via which *i3bar* connects to *i3*(1). If *i3bar* can not connect to *i3*, it will exit. Defaults to '~/.i3/ipc.sock' + +*-c, --command* 'command':: +Execute '' to get 'stdin'. You can also simply pipe into 'stdin', but starting the coomand for itself, *i3bar* is able to send 'SIGCONT' and 'SIGSTOP', when combined with *-m* + +*-m, --hide*:: +Hide the bar, when 'mod4' is not pressed. With this, dockmode will not be set, and the bar is out of the way most of the time so you have more room. +If *-c* is specified, the childprocess is sent a 'SIGSTOP' on hiding and a 'SIGCONT' on unhiding of the bars + +*-f, --font* 'font':: +Specifies a 'X-core-font' to use. You can choose one with *xfontsel*(1). Defaults to '-misc-fixed-medium-r-semicondensed--12-110-75-75-c-60-iso10646-1'. + +*-V, --verbose*:: +Be (very) verbose with the debug-output. If not set, only errors are reported to 'stderr' + +*-h, --help*:: +Display a short help-message and exit + +== DESCRIPTION + +*i3bar* is an xcb- and libev-based status- and ws-bar. It is best thought of as an replacement for the *i3-wsbar*(1) + *dzen2*(1)-combination. It creates a workspace-bar for every active output ("screen") and displays a piped in statusline rightaligned on every bar. + +It does not sample any status-information itself, so you still need a program like *i3status*(1) or *conky*(1) for that. + +i3bar does not support any color or other markups, so stdin should be plain utf8, one line at a time. If you use *i3status*(1), you therefore should specify 'output_format = none' in the general-section of it's configfile. + +Also, you should disable the internal workspace bar of *i3*(1), when using *i3bar* by specifying 'workspace_bar no' in your *i3*-configfile. + +== EXAMPLES + +To get a docked bar with some statusinformation, you use + +*i3status | i3bar* + +If you want it to hide when not needed, you should instead use + +*i3bar -c i3status -m* + +== SEE ALSO + ++i3(1)+, +i3-wsbar(1)+, +dzen2(1)+, +i3status(1)+ + +== AUTHORS + +Axel Wagner and contributors From cddda0c965e008670037b45de22828dc7ee0bcb9 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 22 Oct 2010 00:30:09 +0200 Subject: [PATCH 33/47] Remove unnecessary dependencies --- i3bar/common.mk | 1 - i3bar/src/xcb.c | 1 - 2 files changed, 2 deletions(-) diff --git a/i3bar/common.mk b/i3bar/common.mk index 1df1f6fb..3d44b028 100644 --- a/i3bar/common.mk +++ b/i3bar/common.mk @@ -14,7 +14,6 @@ CFLAGS += -DI3BAR_VERSION=\"${GIT_VERSION}\" LDFLAGS += -lev LDFLAGS += -lyajl LDFLAGS += -lxcb -LDFLAGS += -lxcb-atom LDFLAGS += -lX11 LDFLAGS += -L/usr/local/lib diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index e1669061..9ae3873f 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -10,7 +10,6 @@ */ #include #include -#include #include #include #include From 4830288c7b416bbeebf4f1d53fffaafa239587fe Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sun, 24 Oct 2010 22:56:08 +0200 Subject: [PATCH 34/47] Place bar at the bottom of the screen, when creating them --- i3bar/src/xcb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 9ae3873f..31d9771c 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -629,7 +629,7 @@ void reconfig_windows() { xcb_screen->root_depth, walk->bar, xcb_root, - walk->rect.x, walk->rect.y, + walk->rect.x, walk->rect.y + walk->rect.h - font_height - 6, walk->rect.w, font_height + 6, 1, XCB_WINDOW_CLASS_INPUT_OUTPUT, From 80172c88c5515cfd9938dcea7f0fc3e031d8689e Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Sun, 24 Oct 2010 23:03:44 +0200 Subject: [PATCH 35/47] Don't map bars on creation, if hide_on_modifier is enabled --- i3bar/src/xcb.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 31d9771c..38ee5bd9 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -667,14 +667,17 @@ void reconfig_windows() { mask, values); - /* We finally map the bar (display it on screen) */ - xcb_void_cookie_t map_cookie = xcb_map_window_checked(xcb_connection, walk->bar); + /* We finally map the bar (display it on screen), unless the modifier-switch is on */ + xcb_void_cookie_t map_cookie; + if (!config.hide_on_modifier) { + map_cookie = xcb_map_window_checked(xcb_connection, walk->bar); + } if (xcb_request_failed(win_cookie, "Could not create window") || xcb_request_failed(pm_cookie, "Could not create pixmap") || xcb_request_failed(prop_cookie, "Could not set dock mode") || xcb_request_failed(gc_cookie, "Could not create graphical context") || - xcb_request_failed(map_cookie, "Could not map window")) { + (!config.hide_on_modifier && xcb_request_failed(map_cookie, "Could not map window"))) { exit(EXIT_FAILURE); } } else { From 73728f519bd70a65aa10f73f31e22bb18f5c669e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Tarl=C3=A1=20Cardoso=20Lemos?= Date: Sun, 24 Oct 2010 01:29:54 -0200 Subject: [PATCH 36/47] Added a distclean target. --- i3bar/Makefile | 8 ++++++-- i3bar/doc/Makefile | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/i3bar/Makefile b/i3bar/Makefile index 8f124493..d4cc59b9 100644 --- a/i3bar/Makefile +++ b/i3bar/Makefile @@ -27,7 +27,11 @@ install: all $(INSTALL) -m 0755 i3bar $(DESTDIR)$(PREFIX)/bin clean: - rm src/*.o + rm -f src/*.o make -C doc clean -.PHONY: install clean doc +distclean: clean + rm -f i3bar + make -C doc distclean + +.PHONY: install clean distclean doc diff --git a/i3bar/doc/Makefile b/i3bar/doc/Makefile index f363207c..a8144cd8 100644 --- a/i3bar/doc/Makefile +++ b/i3bar/doc/Makefile @@ -5,3 +5,5 @@ i3bar.1: i3bar.man a2x -f manpage i3bar.man clean: rm -f i3bar.xml i3bar.1 i3bar.html + +distclean: clean From 6376cf99d29aa8d2fa30a3f0e3c5deea0b94bf73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Tarl=C3=A1=20Cardoso=20Lemos?= Date: Sun, 24 Oct 2010 01:24:51 -0200 Subject: [PATCH 37/47] Custom colors can be set from the command line. --- i3bar/include/xcb.h | 30 ++++++++++++++ i3bar/src/main.c | 98 ++++++++++++++++++++++++++++++++++++++++----- i3bar/src/xcb.c | 41 +++++++++++++++---- 3 files changed, 152 insertions(+), 17 deletions(-) diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 75402285..83c65a55 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -9,12 +9,42 @@ #ifndef XCB_H_ #define XCB_H_ +#include + +struct colors_t { + char *bar_fg; + char *bar_bg; + char *active_ws_fg; + char *active_ws_bg; + char *inactive_ws_fg; + char *inactive_ws_bg; + char *urgent_ws_bg; + char *urgent_ws_fg; +}; + +struct parsed_colors_t { + uint32_t bar_fg; + uint32_t bar_bg; + uint32_t active_ws_fg; + uint32_t active_ws_bg; + uint32_t inactive_ws_fg; + uint32_t inactive_ws_bg; + uint32_t urgent_ws_bg; + uint32_t urgent_ws_fg; +}; + /* * Initialize xcb and use the specified fontname for text-rendering * */ void init_xcb(); +/* + * Initialize the colors + * + */ +void init_colors(const struct colors_t *colors); + /* * Cleanup the xcb-stuff. * Called once, before the program terminates. diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 5b6debc5..e081d880 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -37,6 +37,49 @@ char *expand_path(char *path) { return result; } +static void read_color(char **color) +{ + int len = strlen(optarg); + if (len == 6 || (len == 7 && optarg[0] == '#')) { + int offset = len - 6; + int good = 1, i; + for (i = offset; good && i < 6 + offset; ++i) { + char c = optarg[i]; + if (!(c >= 'a' && c <= 'f') + && !(c >= 'A' && c <= 'F') + && !(c >= '0' && c <= '9')) { + good = 0; + break; + } + } + if (good) { + *color = strdup(optarg + offset); + return; + } + } + + fprintf(stderr, "Bad color value \"%s\"\n", optarg); + exit(EXIT_FAILURE); +} + +static void free_colors(struct colors_t *colors) +{ +#define FREE_COLOR(x) \ + do { \ + if (colors->x) \ + free(colors->x); \ + } while (0) + FREE_COLOR(bar_fg); + FREE_COLOR(bar_bg); + FREE_COLOR(active_ws_fg); + FREE_COLOR(active_ws_bg); + FREE_COLOR(inactive_ws_fg); + FREE_COLOR(inactive_ws_bg); + FREE_COLOR(urgent_ws_fg); + FREE_COLOR(urgent_ws_bg); +#undef FREE_COLOR +} + void print_usage(char *elf_name) { printf("Usage: %s [-s sock_path] [-c command] [-m] [-f font] [-V] [-h]\n", elf_name); printf("-s \tConnect to i3 via \n"); @@ -56,22 +99,31 @@ int main(int argc, char **argv) { char *command = NULL; char *fontname = NULL; char *i3_default_sock_path = "~/.i3/ipc.sock"; + struct colors_t colors = {0,}; /* 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' }, - { "verbose", no_argument, 0, 'V' }, - { NULL, 0, 0, 0} + { "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' }, + { "verbose", no_argument, 0, 'V' }, + { "color-bar-fg", required_argument, 0, 'A' }, + { "color-bar-bg", required_argument, 0, 'B' }, + { "color-active-ws-fg", required_argument, 0, 'C' }, + { "color-active-ws-bg", required_argument, 0, 'D' }, + { "color-inactive-ws-fg", required_argument, 0, 'E' }, + { "color-inactive-ws-bg", required_argument, 0, 'F' }, + { "color-urgent-ws-bg", required_argument, 0, 'G' }, + { "color-urgent-ws-fg", required_argument, 0, 'H' }, + { NULL, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "s:c:mf:hvV", long_opt, &option_index)) != -1) { + while ((opt = getopt_long(argc, argv, "s:c:mf:hvV:A:B:C:D:E:F:G:H:", long_opt, &option_index)) != -1) { switch (opt) { case 's': socket_path = expand_path(optarg); @@ -92,6 +144,30 @@ int main(int argc, char **argv) { case 'V': config.verbose = 1; break; + case 'A': + read_color(&colors.bar_fg); + break; + case 'B': + read_color(&colors.bar_bg); + break; + case 'C': + read_color(&colors.active_ws_fg); + break; + case 'D': + read_color(&colors.active_ws_bg); + break; + case 'E': + read_color(&colors.inactive_ws_fg); + break; + case 'F': + read_color(&colors.inactive_ws_bg); + break; + case 'G': + read_color(&colors.urgent_ws_fg); + break; + case 'H': + read_color(&colors.urgent_ws_bg); + break; default: print_usage(argv[0]); exit(EXIT_SUCCESS); @@ -114,6 +190,10 @@ int main(int argc, char **argv) { main_loop = ev_default_loop(0); init_xcb(fontname); + + init_colors(&colors); + free_colors(&colors); + init_outputs(); init_connection(socket_path); diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 38ee5bd9..41f221cf 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -63,6 +63,9 @@ ev_check *xcb_chk; ev_io *xcb_io; ev_io *xkb_io; +/* The parsed colors */ +struct parsed_colors_t colors; + /* We define xcb_request_failed as a macro to include the relevant line-number */ #define xcb_request_failed(cookie, err_msg) _xcb_request_failed(cookie, err_msg, __LINE__) int _xcb_request_failed(xcb_void_cookie_t cookie, char *err_msg, int line) { @@ -247,6 +250,26 @@ void unhide_bars() { } } +/* + * Parse the colors into a format that we can use + * + */ +void init_colors(const struct colors_t *new_colors) { +#define PARSE_COLOR(name, def) \ + do { \ + colors.name = get_colorpixel(new_colors->name ? new_colors->name : def); \ + } while (0) + PARSE_COLOR(bar_fg, "FFFFFF"); + PARSE_COLOR(bar_bg, "000000"); + PARSE_COLOR(active_ws_fg, "FFFFFF"); + PARSE_COLOR(active_ws_bg, "480000"); + PARSE_COLOR(inactive_ws_fg, "FFFFFF"); + PARSE_COLOR(inactive_ws_bg, "240000"); + PARSE_COLOR(urgent_ws_fg, "FFFFFF"); + PARSE_COLOR(urgent_ws_bg, "002400"); +#undef PARSE_COLOR +} + /* * 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- @@ -725,7 +748,7 @@ void draw_bars() { reconfig_windows(); } /* First things first: clear the backbuffer */ - uint32_t color = get_colorpixel("000000"); + uint32_t color = colors.bar_bg; xcb_change_gc(xcb_connection, outputs_walk->bargc, XCB_GC_FOREGROUND, @@ -755,35 +778,37 @@ void draw_bars() { i3_ws *ws_walk; TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) { DLOG("Drawing Button for WS %s at x = %d\n", ws_walk->name, i); - uint32_t color = get_colorpixel("240000"); + uint32_t fg_color = colors.inactive_ws_fg; + uint32_t bg_color = colors.inactive_ws_bg; if (ws_walk->visible) { - color = get_colorpixel("480000"); + fg_color = colors.active_ws_fg; + bg_color = colors.active_ws_bg; } if (ws_walk->urgent) { DLOG("WS %s is urgent!\n", ws_walk->name); - color = get_colorpixel("002400"); + fg_color = colors.urgent_ws_fg; + bg_color = colors.urgent_ws_bg; /* The urgent-hint should get noticed, so we unhide the bars shortly */ unhide_bars(); } xcb_change_gc(xcb_connection, outputs_walk->bargc, XCB_GC_FOREGROUND, - &color); + &bg_color); xcb_change_gc(xcb_connection, outputs_walk->bargc, XCB_GC_BACKGROUND, - &color); + &bg_color); xcb_rectangle_t rect = { i + 1, 1, ws_walk->name_width + 8, font_height + 4 }; xcb_poly_fill_rectangle(xcb_connection, outputs_walk->buffer, outputs_walk->bargc, 1, &rect); - color = get_colorpixel("FFFFFF"); xcb_change_gc(xcb_connection, outputs_walk->bargc, XCB_GC_FOREGROUND, - &color); + &fg_color); xcb_image_text_16(xcb_connection, ws_walk->name_glyphs, outputs_walk->buffer, From 992612c89d33d82eaa118e7ca7faf24735ff4a6e Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 4 Nov 2010 12:27:10 +0100 Subject: [PATCH 38/47] Some stylechanges to previous commit --- i3bar/include/common.h | 2 +- i3bar/include/config.h | 9 ++++++--- i3bar/include/xcb.h | 16 ++++------------ i3bar/src/main.c | 8 +++----- i3bar/src/xcb.c | 14 ++++++++++++-- 5 files changed, 26 insertions(+), 23 deletions(-) diff --git a/i3bar/include/common.h b/i3bar/include/common.h index e885ddcd..4ad33703 100644 --- a/i3bar/include/common.h +++ b/i3bar/include/common.h @@ -24,12 +24,12 @@ struct rect_t { #include "queue.h" #include "child.h" -#include "config.h" #include "ipc.h" #include "outputs.h" #include "util.h" #include "workspaces.h" #include "xcb.h" #include "ucs2_to_utf8.h" +#include "config.h" #endif diff --git a/i3bar/include/config.h b/i3bar/include/config.h index 0496f431..2dd0f532 100644 --- a/i3bar/include/config.h +++ b/i3bar/include/config.h @@ -1,9 +1,12 @@ #ifndef CONFIG_H_ -#define CONFIL_H_ +#define CONFIG_H_ + +#include "common.h" typedef struct config_t { - int hide_on_modifier; - int verbose; + int hide_on_modifier; + int verbose; + xcb_colors_t *colors; } config_t; config_t config; diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 83c65a55..5ace4f0b 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -10,8 +10,9 @@ #define XCB_H_ #include +//#include "outputs.h" -struct colors_t { +struct xcb_color_strings_t { char *bar_fg; char *bar_bg; char *active_ws_fg; @@ -22,16 +23,7 @@ struct colors_t { char *urgent_ws_fg; }; -struct parsed_colors_t { - uint32_t bar_fg; - uint32_t bar_bg; - uint32_t active_ws_fg; - uint32_t active_ws_bg; - uint32_t inactive_ws_fg; - uint32_t inactive_ws_bg; - uint32_t urgent_ws_bg; - uint32_t urgent_ws_fg; -}; +typedef struct xcb_colors_t xcb_colors_t; /* * Initialize xcb and use the specified fontname for text-rendering @@ -43,7 +35,7 @@ void init_xcb(); * Initialize the colors * */ -void init_colors(const struct colors_t *colors); +void init_colors(const struct xcb_color_strings_t *colors); /* * Cleanup the xcb-stuff. diff --git a/i3bar/src/main.c b/i3bar/src/main.c index e081d880..e50bcc40 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -37,8 +37,7 @@ char *expand_path(char *path) { return result; } -static void read_color(char **color) -{ +static void read_color(char **color) { int len = strlen(optarg); if (len == 6 || (len == 7 && optarg[0] == '#')) { int offset = len - 6; @@ -62,8 +61,7 @@ static void read_color(char **color) exit(EXIT_FAILURE); } -static void free_colors(struct colors_t *colors) -{ +static void free_colors(struct xcb_color_strings_t *colors) { #define FREE_COLOR(x) \ do { \ if (colors->x) \ @@ -99,7 +97,7 @@ int main(int argc, char **argv) { char *command = NULL; char *fontname = NULL; char *i3_default_sock_path = "~/.i3/ipc.sock"; - struct colors_t colors = {0,}; + struct xcb_color_strings_t colors = { NULL, }; /* Definition of the standard-config */ config.hide_on_modifier = 0; diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 41f221cf..bf679b5d 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -64,7 +64,17 @@ ev_io *xcb_io; ev_io *xkb_io; /* The parsed colors */ -struct parsed_colors_t colors; +struct xcb_colors_t { + uint32_t bar_fg; + uint32_t bar_bg; + uint32_t active_ws_fg; + uint32_t active_ws_bg; + uint32_t inactive_ws_fg; + uint32_t inactive_ws_bg; + uint32_t urgent_ws_bg; + uint32_t urgent_ws_fg; +}; +struct xcb_colors_t colors; /* We define xcb_request_failed as a macro to include the relevant line-number */ #define xcb_request_failed(cookie, err_msg) _xcb_request_failed(cookie, err_msg, __LINE__) @@ -254,7 +264,7 @@ void unhide_bars() { * Parse the colors into a format that we can use * */ -void init_colors(const struct colors_t *new_colors) { +void init_colors(const struct xcb_color_strings_t *new_colors) { #define PARSE_COLOR(name, def) \ do { \ colors.name = get_colorpixel(new_colors->name ? new_colors->name : def); \ From 214382a0307e2b2318d09d5be1c715eaf77d635b Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 4 Nov 2010 12:43:33 +0100 Subject: [PATCH 39/47] Mention the color-options in the manpage --- i3bar/.gitignore | 1 + i3bar/doc/i3bar.man | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/i3bar/.gitignore b/i3bar/.gitignore index 01e7ad61..6aad070b 100644 --- a/i3bar/.gitignore +++ b/i3bar/.gitignore @@ -1,3 +1,4 @@ i3bar *.o core +doc/i3bar.1 diff --git a/i3bar/doc/i3bar.man b/i3bar/doc/i3bar.man index dc094ae6..c41371b8 100644 --- a/i3bar/doc/i3bar.man +++ b/i3bar/doc/i3bar.man @@ -42,6 +42,18 @@ i3bar does not support any color or other markups, so stdin should be plain utf8 Also, you should disable the internal workspace bar of *i3*(1), when using *i3bar* by specifying 'workspace_bar no' in your *i3*-configfile. +== COLORS + +*i3bar* does not yet support formatting in the displayed statusline. However it does support setting colors for the bar, the workspace-buttons and the statusline. + +For now this happens with the following command-line-options: + +*--color-bar-fg, --color-bar-bg, --color-active-ws-fg, --color-active-ws-bg, --color-inactive-ws-fg, --color-inactive-ws-bg, color-urgent-ws-bg, color-urgent-ws-fg* + +For each specified option you need to give a HEX-colorcode. + +Be advised that this command-line-options are only temporary and are very likely to be removed, when we finally have a config-file. + == EXAMPLES To get a docked bar with some statusinformation, you use From 127c082e83e5622540905e56d9300cb0bf276208 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 4 Nov 2010 13:46:33 +0100 Subject: [PATCH 40/47] Call init_colors() earlier --- i3bar/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index e50bcc40..9b6f9e12 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -187,9 +187,9 @@ int main(int argc, char **argv) { main_loop = ev_default_loop(0); + init_colors(&colors); init_xcb(fontname); - init_colors(&colors); free_colors(&colors); init_outputs(); From 23b62f621dc3f3ccfe57794f67fa16b530f3e694 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 4 Nov 2010 13:46:50 +0100 Subject: [PATCH 41/47] Add support for bar_fg and bar_bg --- i3bar/src/xcb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index bf679b5d..326ca2ad 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -520,7 +520,7 @@ void init_xcb(char *fontname) { uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT; - uint32_t vals[3] = { xcb_screen->white_pixel, xcb_screen->black_pixel, xcb_font }; + uint32_t vals[3] = { colors.bar_fg, colors.bar_bg, xcb_font }; xcb_void_cookie_t sl_ctx_cookie = xcb_create_gc_checked(xcb_connection, statusline_ctx, @@ -652,7 +652,7 @@ void reconfig_windows() { walk->buffer = xcb_generate_id(xcb_connection); mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK; /* Black background */ - values[0] = xcb_screen->black_pixel; + values[0] = colors.bar_bg; /* 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 */ From eada4837658e60d9819480bcb49d5ad42cec5caa Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 10 Nov 2010 18:46:47 +0100 Subject: [PATCH 42/47] Double-fork() to avoid zombies --- i3bar/src/child.c | 51 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/i3bar/src/child.c b/i3bar/src/child.c index fa70f452..3f927b45 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -100,41 +101,67 @@ 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 + * 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 * */ void start_child(char *command) { child_pid = 0; if (command != NULL) { - int fd[2]; + int fd[2], tmp[2]; + /* This pipe will be used to communicate between e.g. i3status and i3bar */ pipe(fd); - child_pid = fork(); - switch (child_pid) { + /* We also need this temporary pipe to get back the pid of i3status */ + pipe(tmp); + switch (fork()) { case -1: ELOG("Couldn't fork()\n"); exit(EXIT_FAILURE); case 0: - /* Child-process. Reroute stdout and start shell */ - close(fd[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]); - 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; + 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); + } 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 d5e3b58d479f73cbdec4e7cb8b19e9dbead7837f Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 11 Nov 2010 02:37:50 +0100 Subject: [PATCH 43/47] -V actually does not take an argument (yet) --- i3bar/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 9b6f9e12..22c85cc0 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -121,7 +121,7 @@ int main(int argc, char **argv) { { NULL, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "s:c:mf:hvV:A:B:C:D:E:F:G:H:", long_opt, &option_index)) != -1) { + while ((opt = getopt_long(argc, argv, "s:c:mf:hvVA:B:C:D:E:F:G:H:", long_opt, &option_index)) != -1) { switch (opt) { case 's': socket_path = expand_path(optarg); From 33202881c4123084ba3eae98e33dc4378bd0fd5c Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 11 Nov 2010 02:47:30 +0100 Subject: [PATCH 44/47] Handle SIGTERM/-INT/-HUP --- i3bar/src/main.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 22c85cc0..6624f2ff 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -90,6 +90,26 @@ void print_usage(char *elf_name) { printf("-h\t\tDisplay this help-message and exit\n"); } +/* + * We watch various signals, that are there to make our application stop. + * If we get one of those, we ev_unloop() and invoke the cleanup-routines + * in main() with that + * + */ +void sig_cb(struct ev_loop *loop, ev_signal *watcher, int revents) { + switch (watcher->signum) { + case SIGTERM: + DLOG("Got a SIGTERM, stopping\n"); + break; + case SIGINT: + DLOG("Got a SIGINT, stopping\n"); + break; + case SIGHUP: + DLOG("Got a SIGHUP, stopping\n"); + } + ev_unloop(main_loop, EVUNLOOP_ALL); +} + int main(int argc, char **argv) { int opt; int option_index = 0; @@ -210,6 +230,19 @@ int main(int argc, char **argv) { * this function initiates the watchers to listen on stdin and react accordingly */ start_child(command); + /* We listen to SIGTERM/QUIT/INT and try to exit cleanly, by stopping the main-loop. + * We only need those watchers on the stack, so putting them on the stack saves us + * some calls to free() */ + ev_signal sig_term, sig_quit, sig_int, sig_hup; + + ev_signal_init(&sig_term, &sig_cb, SIGTERM); + ev_signal_init(&sig_int, &sig_cb, SIGINT); + ev_signal_init(&sig_hup, &sig_cb, SIGHUP); + + ev_signal_start(main_loop, &sig_term); + ev_signal_start(main_loop, &sig_int); + ev_signal_start(main_loop, &sig_hup); + /* From here on everything should run smooth for itself, just start listening for * events. We stop simply stop the event-loop, when we are finished */ ev_loop(main_loop, 0); From 8301d3d9f3f00a13c38eb90f91c76bb8b3adf605 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 11 Nov 2010 02:59:17 +0100 Subject: [PATCH 45/47] Send a SIGTERM instead of a SIGQUIT to exit the 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 3f927b45..08d2bed9 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -184,7 +184,7 @@ void start_child(char *command) { */ void kill_child() { if (child_pid != 0) { - kill(child_pid, SIGQUIT); + kill(child_pid, SIGTERM); } cleanup(); } From a88f7fb392828493fd1c44adbeb76a07afa49ab5 Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Thu, 11 Nov 2010 03:01:40 +0100 Subject: [PATCH 46/47] We don't need sig_quit --- i3bar/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index 6624f2ff..35ea9210 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -233,7 +233,7 @@ int main(int argc, char **argv) { /* We listen to SIGTERM/QUIT/INT and try to exit cleanly, by stopping the main-loop. * We only need those watchers on the stack, so putting them on the stack saves us * some calls to free() */ - ev_signal sig_term, sig_quit, sig_int, sig_hup; + ev_signal sig_term, sig_int, sig_hup; ev_signal_init(&sig_term, &sig_cb, SIGTERM); ev_signal_init(&sig_int, &sig_cb, SIGINT); From a3e37b059fafc5c1179bd656780935a2dded25df Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Fri, 3 Dec 2010 17:59:16 +0100 Subject: [PATCH 47/47] 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]);