From f26a344dfa00d3b53a92e374612833e31ff11705 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Wed, 12 Oct 2011 22:29:39 +0100 Subject: [PATCH 01/45] reformat include/config.h --- include/config.h | 172 +++++++++++++++++++++++------------------------ 1 file changed, 86 insertions(+), 86 deletions(-) diff --git a/include/config.h b/include/config.h index 337db8fb..24754751 100644 --- a/include/config.h +++ b/include/config.h @@ -1,5 +1,5 @@ /* - * vim:ts=8:expandtab + * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager * @@ -32,17 +32,17 @@ extern SLIST_HEAD(modes_head, Mode) modes; * */ struct context { - bool has_errors; + bool has_errors; - int line_number; - char *line_copy; - const char *filename; + int line_number; + char *line_copy; + const char *filename; - char *compact_error; + char *compact_error; - /* These are the same as in YYLTYPE */ - int first_column; - int last_column; + /* These are the same as in YYLTYPE */ + int first_column; + int last_column; }; /** @@ -51,9 +51,9 @@ struct context { * */ struct Colortriple { - uint32_t border; - uint32_t background; - uint32_t text; + uint32_t border; + uint32_t background; + uint32_t text; }; /** @@ -62,11 +62,11 @@ struct Colortriple { * */ struct Variable { - char *key; - char *value; - char *next_match; + char *key; + char *value; + char *next_match; - SLIST_ENTRY(Variable) variables; + SLIST_ENTRY(Variable) variables; }; /** @@ -76,10 +76,10 @@ struct Variable { * */ struct Mode { - char *name; - struct bindings_head *bindings; + char *name; + struct bindings_head *bindings; - SLIST_ENTRY(Mode) modes; + SLIST_ENTRY(Mode) modes; }; /** @@ -88,86 +88,86 @@ struct Mode { * */ struct Config { - const char *terminal; - i3Font font; + const char *terminal; + i3Font font; - char *ipc_socket_path; - const char *restart_state_path; + char *ipc_socket_path; + const char *restart_state_path; - int default_layout; - int container_stack_limit; - int container_stack_limit_value; + int default_layout; + int container_stack_limit; + int container_stack_limit_value; - /** Default orientation for new containers */ - int default_orientation; + /** Default orientation for new containers */ + int default_orientation; - /** By default, focus follows mouse. If the user explicitly wants to - * turn this off (and instead rely only on the keyboard for changing - * focus), we allow him to do this with this relatively special option. - * It is not planned to add any different focus models. */ - bool disable_focus_follows_mouse; + /** By default, focus follows mouse. If the user explicitly wants to + * turn this off (and instead rely only on the keyboard for changing + * focus), we allow him to do this with this relatively special option. + * It is not planned to add any different focus models. */ + bool disable_focus_follows_mouse; - /** By default, a workspace bar is drawn at the bottom of the screen. - * If you want to have a more fancy bar, it is recommended to replace - * the whole bar by dzen2, for example using the i3-wsbar script which - * comes with i3. Thus, you can turn it off entirely. */ - bool disable_workspace_bar; + /** By default, a workspace bar is drawn at the bottom of the screen. + * If you want to have a more fancy bar, it is recommended to replace + * the whole bar by dzen2, for example using the i3-wsbar script which + * comes with i3. Thus, you can turn it off entirely. */ + bool disable_workspace_bar; - /** Think of the following layout: Horizontal workspace with a tabbed - * con on the left of the screen and a terminal on the right of the - * screen. You are in the second container in the tabbed container and - * focus to the right. By default, i3 will set focus to the terminal on - * the right. If you are in the first container in the tabbed container - * however, focusing to the left will wrap. This option forces i3 to - * always wrap, which will result in you having to use "focus parent" - * more often. */ - bool force_focus_wrapping; + /** Think of the following layout: Horizontal workspace with a tabbed + * con on the left of the screen and a terminal on the right of the + * screen. You are in the second container in the tabbed container and + * focus to the right. By default, i3 will set focus to the terminal on + * the right. If you are in the first container in the tabbed container + * however, focusing to the left will wrap. This option forces i3 to + * always wrap, which will result in you having to use "focus parent" + * more often. */ + bool force_focus_wrapping; - /** By default, use the RandR API for multi-monitor setups. - * Unfortunately, the nVidia binary graphics driver doesn't support - * this API. Instead, it only support the less powerful Xinerama API, - * which can be enabled by this option. - * - * Note: this option takes only effect on the initial startup (eg. - * reconfiguration is not possible). On startup, the list of screens - * is fetched once and never updated. */ - bool force_xinerama; + /** By default, use the RandR API for multi-monitor setups. + * Unfortunately, the nVidia binary graphics driver doesn't support + * this API. Instead, it only support the less powerful Xinerama API, + * which can be enabled by this option. + * + * Note: this option takes only effect on the initial startup (eg. + * reconfiguration is not possible). On startup, the list of screens + * is fetched once and never updated. */ + bool force_xinerama; - /** Automatic workspace back and forth switching. If this is set, a - * switch to the currently active workspace will switch to the - * previously focused one instead, making it possible to fast toggle - * between two workspaces. */ - bool workspace_auto_back_and_forth; + /** Automatic workspace back and forth switching. If this is set, a + * switch to the currently active workspace will switch to the + * previously focused one instead, making it possible to fast toggle + * between two workspaces. */ + bool workspace_auto_back_and_forth; - /** The default border style for new windows. */ - border_style_t default_border; + /** The default border style for new windows. */ + border_style_t default_border; - /** The default border style for new floating windows. */ - border_style_t default_floating_border; + /** The default border style for new floating windows. */ + border_style_t default_floating_border; - /** The modifier which needs to be pressed in combination with your mouse - * buttons to do things with floating windows (move, resize) */ - uint32_t floating_modifier; + /** The modifier which needs to be pressed in combination with your mouse + * buttons to do things with floating windows (move, resize) */ + uint32_t floating_modifier; - /* Color codes are stored here */ - struct config_client { - uint32_t background; - struct Colortriple focused; - struct Colortriple focused_inactive; - struct Colortriple unfocused; - struct Colortriple urgent; - } client; - struct config_bar { - struct Colortriple focused; - struct Colortriple unfocused; - struct Colortriple urgent; - } bar; + /* Color codes are stored here */ + struct config_client { + uint32_t background; + struct Colortriple focused; + struct Colortriple focused_inactive; + struct Colortriple unfocused; + struct Colortriple urgent; + } client; + struct config_bar { + struct Colortriple focused; + struct Colortriple unfocused; + struct Colortriple urgent; + } bar; - /** What should happen when a new popup is opened during fullscreen mode */ - enum { - PDF_LEAVE_FULLSCREEN = 0, - PDF_IGNORE = 1 - } popup_during_fullscreen; + /** What should happen when a new popup is opened during fullscreen mode */ + enum { + PDF_LEAVE_FULLSCREEN = 0, + PDF_IGNORE = 1 + } popup_during_fullscreen; }; /** From 4898f78e5e3bd786e55a290ade1afe75db0bb31f Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Wed, 12 Oct 2011 22:52:55 +0100 Subject: [PATCH 02/45] add a data structure for 'bar' configuration --- include/config.h | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ src/config.c | 1 + 2 files changed, 69 insertions(+) diff --git a/include/config.h b/include/config.h index 24754751..200d393f 100644 --- a/include/config.h +++ b/include/config.h @@ -22,9 +22,11 @@ #include "i3.h" typedef struct Config Config; +typedef struct Barconfig Barconfig; extern char *current_configpath; extern Config config; extern SLIST_HEAD(modes_head, Mode) modes; +extern SLIST_HEAD(barconfig_head, Barconfig) barconfigs; /** * Used during the config file lexing/parsing to keep the state of the lexer @@ -170,6 +172,72 @@ struct Config { } popup_during_fullscreen; }; +/** + * Holds the status bar configuration (i3bar). One of these structures is + * created for each 'bar' block in the config. + * + */ +struct Barconfig { + /** Automatically generated ID for this bar config. Used by the bar process + * to request a specific configuration. */ + char *id; + + /** Number of outputs in the outputs array */ + int num_outputs; + /** Outputs on which this bar should show up on. We use an array for + * simplicity (since we store just strings). */ + char **outputs; + + /** Output on which the tray should be shown. The special value of 'no' + * disables the tray (it’s enabled by default). */ + char *tray_output; + + /** Path to the i3 IPC socket. This option is discouraged since programs + * can find out the path by looking for the I3_SOCKET_PATH property on the + * root window! */ + char *socket_path; + + /** Bar display mode (hide unless modifier is pressed or show in dock mode) */ + enum { M_HIDE = 0, M_DOCK = 1 } mode; + + /** Bar position (bottom by default). */ + enum { P_BOTTOM = 0, P_TOP = 1 } position; + + /** Command that should be run to get a statusline, for example 'i3status'. + * Will be passed to the shell. */ + char *status_command; + + /** Font specification for all text rendered on the bar. */ + char *font; + + /** Hide workspace buttons? Configuration option is 'workspace_buttons no' + * but we invert the bool to get the correct default when initializing with + * zero. */ + bool hide_workspace_buttons; + + /** Enable verbose mode? Useful for debugging purposes. */ + bool verbose; + + struct bar_colors { + char *background; + char *statusline; + + char *focused_workspace_text; + char *focused_workspace_bg; + + char *active_workspace_text; + char *active_workspace_bg; + + char *inactive_workspace_text; + char *inactive_workspace_bg; + + char *urgent_workspace_text; + char *urgent_workspace_bg; + } colors; + + SLIST_ENTRY(Barconfig) configs; +}; + /** * Reads the configuration from ~/.i3/config or /etc/i3/config if not found. * diff --git a/src/config.c b/src/config.c index c979d8cd..3ea18258 100644 --- a/src/config.c +++ b/src/config.c @@ -21,6 +21,7 @@ char *current_configpath = NULL; Config config; struct modes_head modes; +struct barconfig_head barconfigs; /** * Ungrabs all keys, to be called before re-grabbing the keys because of a From 24ede1c8341be5c2e50925b68107d1384cb78b4e Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Wed, 12 Oct 2011 23:23:09 +0100 Subject: [PATCH 03/45] add an IPC request to get the bar configuration (by ID) --- i3-msg/main.c | 4 +- include/i3/ipc.h | 8 +++- src/ipc.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 127 insertions(+), 4 deletions(-) diff --git a/i3-msg/main.c b/i3-msg/main.c index 5bc35b88..13cf0ccb 100644 --- a/i3-msg/main.c +++ b/i3-msg/main.c @@ -74,9 +74,11 @@ int main(int argc, char *argv[]) { message_type = I3_IPC_MESSAGE_TYPE_GET_TREE; else if (strcasecmp(optarg, "get_marks") == 0) message_type = I3_IPC_MESSAGE_TYPE_GET_MARKS; + else if (strcasecmp(optarg, "get_bar_config") == 0) + message_type = I3_IPC_MESSAGE_TYPE_GET_BAR_CONFIG; else { printf("Unknown message type\n"); - printf("Known types: command, get_workspaces, get_outputs, get_tree, get_marks\n"); + printf("Known types: command, get_workspaces, get_outputs, get_tree, get_marks, get_bar_config\n"); exit(EXIT_FAILURE); } } else if (o == 'q') { diff --git a/include/i3/ipc.h b/include/i3/ipc.h index 30b2d304..a12d5cd7 100644 --- a/include/i3/ipc.h +++ b/include/i3/ipc.h @@ -41,6 +41,9 @@ /** Request the current defined marks from i3 */ #define I3_IPC_MESSAGE_TYPE_GET_MARKS 5 +/** Request the configuration for a specific 'bar' */ +#define I3_IPC_MESSAGE_TYPE_GET_BAR_CONFIG 6 + /* * Messages from i3 to clients * @@ -61,9 +64,12 @@ /** Tree reply type */ #define I3_IPC_REPLY_TYPE_TREE 4 -/** Marks reply type*/ +/** Marks reply type */ #define I3_IPC_REPLY_TYPE_MARKS 5 +/** Bar config reply type */ +#define I3_IPC_REPLY_TYPE_BAR_CONFIG 6 + /* * Events from i3 to clients. Events have the first bit set high. * diff --git a/src/ipc.c b/src/ipc.c index eba778cd..60f55966 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -475,6 +475,120 @@ IPC_HANDLER(get_marks) { y(free); } +/* + * Formats the reply message for a GET_BAR_CONFIG request and sends it to the + * client. + * + */ +IPC_HANDLER(get_bar_config) { + /* To get a properly terminated buffer, we copy + * message_size bytes out of the buffer */ + char *bar_id = scalloc(message_size + 1); + strncpy(bar_id, (const char*)message, message_size); + LOG("IPC: looking for config for bar ID \"%s\"\n", bar_id); + Barconfig *current, *config = NULL; + SLIST_FOREACH(current, &barconfigs, configs) { + if (strcmp(current->id, bar_id) != 0) + continue; + + config = current; + break; + } + +#if YAJL_MAJOR >= 2 + yajl_gen gen = yajl_gen_alloc(NULL); +#else + yajl_gen gen = yajl_gen_alloc(NULL, NULL); +#endif + + y(map_open); + + if (!config) { + /* If we did not find a config for the given ID, the reply will contain + * a null 'id' field. */ + ystr("id"); + y(null); + } else { + ystr("id"); + ystr(config->id); + + if (config->num_outputs > 0) { + ystr("outputs"); + y(array_open); + for (int c = 0; c < config->num_outputs; c++) + ystr(config->outputs[c]); + y(array_close); + } + +#define YSTR_IF_SET(name) \ + do { \ + if (config->name) { \ + ystr( # name); \ + ystr(config->name); \ + } \ + } while (0) + + YSTR_IF_SET(tray_output); + YSTR_IF_SET(socket_path); + + ystr("mode"); + if (config->mode == M_HIDE) + ystr("hide"); + else ystr("dock"); + + ystr("position"); + if (config->position == P_BOTTOM) + ystr("bottom"); + else ystr("top"); + + YSTR_IF_SET(status_command); + YSTR_IF_SET(font); + + ystr("workspace_buttons"); + y(bool, !config->hide_workspace_buttons); + + ystr("verbose"); + y(bool, config->verbose); + +#undef YSTR_IF_SET +#define YSTR_IF_SET(name) \ + do { \ + if (config->colors.name) { \ + ystr( # name); \ + ystr(config->colors.name); \ + } \ + } while (0) + + ystr("colors"); + y(map_open); + YSTR_IF_SET(background); + YSTR_IF_SET(statusline); + YSTR_IF_SET(focused_workspace_text); + YSTR_IF_SET(focused_workspace_bg); + YSTR_IF_SET(active_workspace_text); + YSTR_IF_SET(active_workspace_bg); + YSTR_IF_SET(inactive_workspace_text); + YSTR_IF_SET(inactive_workspace_bg); + YSTR_IF_SET(urgent_workspace_text); + YSTR_IF_SET(urgent_workspace_bg); + +#undef YSTR_IF_SET + } + + y(map_close); + + const unsigned char *payload; +#if YAJL_MAJOR >= 2 + size_t length; +#else + unsigned int length; +#endif + y(get_buf, &payload, &length); + + ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_BAR_CONFIG, payload); + y(free); +} + /* * Callback for the YAJL parser (will be called when a string is parsed). * @@ -560,13 +674,14 @@ IPC_HANDLER(subscribe) { /* The index of each callback function corresponds to the numeric * value of the message type (see include/i3/ipc.h) */ -handler_t handlers[6] = { +handler_t handlers[7] = { handle_command, handle_get_workspaces, handle_subscribe, handle_get_outputs, handle_tree, - handle_get_marks + handle_get_marks, + handle_get_bar_config }; /* From c2c6ca25d5d14f7c9c280ad3b74577ff6b1569fa Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 18 Oct 2011 22:11:27 +0100 Subject: [PATCH 04/45] Make the barconfig list a TAILQ --- include/config.h | 4 ++-- src/config.c | 2 +- src/ipc.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/config.h b/include/config.h index 200d393f..a4a274cf 100644 --- a/include/config.h +++ b/include/config.h @@ -26,7 +26,7 @@ typedef struct Barconfig Barconfig; extern char *current_configpath; extern Config config; extern SLIST_HEAD(modes_head, Mode) modes; -extern SLIST_HEAD(barconfig_head, Barconfig) barconfigs; +extern TAILQ_HEAD(barconfig_head, Barconfig) barconfigs; /** * Used during the config file lexing/parsing to keep the state of the lexer @@ -235,7 +235,7 @@ struct Barconfig { char *urgent_workspace_bg; } colors; - SLIST_ENTRY(Barconfig) configs; + TAILQ_ENTRY(Barconfig) configs; }; /** diff --git a/src/config.c b/src/config.c index 3ea18258..d39a5761 100644 --- a/src/config.c +++ b/src/config.c @@ -21,7 +21,7 @@ char *current_configpath = NULL; Config config; struct modes_head modes; -struct barconfig_head barconfigs; +struct barconfig_head barconfigs = TAILQ_HEAD_INITIALIZER(barconfigs); /** * Ungrabs all keys, to be called before re-grabbing the keys because of a diff --git a/src/ipc.c b/src/ipc.c index 60f55966..1ae6bb0a 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -487,7 +487,7 @@ IPC_HANDLER(get_bar_config) { strncpy(bar_id, (const char*)message, message_size); LOG("IPC: looking for config for bar ID \"%s\"\n", bar_id); Barconfig *current, *config = NULL; - SLIST_FOREACH(current, &barconfigs, configs) { + TAILQ_FOREACH(current, &barconfigs, configs) { if (strcmp(current->id, bar_id) != 0) continue; From e3cbdea1fce139eb43b0149f28cb9e8cc61559f5 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 18 Oct 2011 22:11:44 +0100 Subject: [PATCH 05/45] Bugfix: Correctly close the colors map in the IPC bar config reply --- src/ipc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ipc.c b/src/ipc.c index 1ae6bb0a..1660096b 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -571,6 +571,7 @@ IPC_HANDLER(get_bar_config) { YSTR_IF_SET(inactive_workspace_bg); YSTR_IF_SET(urgent_workspace_text); YSTR_IF_SET(urgent_workspace_bg); + y(map_close); #undef YSTR_IF_SET } From 149b05aacfab6d94d79081b0a2ffa8f44f5720cd Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 18 Oct 2011 22:12:46 +0100 Subject: [PATCH 06/45] ipc: when requesting the bar config without a payload, return an array of available bar IDs --- src/ipc.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/ipc.c b/src/ipc.c index 1660096b..97937c05 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -481,6 +481,34 @@ IPC_HANDLER(get_marks) { * */ IPC_HANDLER(get_bar_config) { +#if YAJL_MAJOR >= 2 + yajl_gen gen = yajl_gen_alloc(NULL); +#else + yajl_gen gen = yajl_gen_alloc(NULL, NULL); +#endif + + /* If no ID was passed, we return a JSON array with all IDs */ + if (message_size == 0) { + y(array_open); + Barconfig *current; + TAILQ_FOREACH(current, &barconfigs, configs) { + ystr(current->id); + } + y(array_close); + + const unsigned char *payload; +#if YAJL_MAJOR >= 2 + size_t length; +#else + unsigned int length; +#endif + y(get_buf, &payload, &length); + + ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_BAR_CONFIG, payload); + y(free); + return; + } + /* To get a properly terminated buffer, we copy * message_size bytes out of the buffer */ char *bar_id = scalloc(message_size + 1); @@ -495,12 +523,6 @@ IPC_HANDLER(get_bar_config) { break; } -#if YAJL_MAJOR >= 2 - yajl_gen gen = yajl_gen_alloc(NULL); -#else - yajl_gen gen = yajl_gen_alloc(NULL, NULL); -#endif - y(map_open); if (!config) { From d9f3a31cb7bc1de1c5b1d684e0a34ed4a6de00b6 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 18 Oct 2011 22:15:48 +0100 Subject: [PATCH 07/45] tests: add a test to check that bar configs are parsed correctly --- testcases/t/177-bar-config.t | 130 +++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 testcases/t/177-bar-config.t diff --git a/testcases/t/177-bar-config.t b/testcases/t/177-bar-config.t new file mode 100644 index 00000000..98eb4edd --- /dev/null +++ b/testcases/t/177-bar-config.t @@ -0,0 +1,130 @@ +#!perl +# vim:ts=4:sw=4:expandtab +# !NO_I3_INSTANCE! will prevent complete-run.pl from starting i3 +# +# Checks that the bar config is parsed correctly. +# + +use i3test; + +##################################################################### +# test a config without any bars +##################################################################### + +my $config = <get_bar_config()->recv; +is(@$bars, 0, 'no bars configured'); + +exit_gracefully($pid); + +##################################################################### +# now provide a simple bar configuration +##################################################################### + +$config = <get_bar_config()->recv; +is(@$bars, 1, 'one bar configured'); + +my $bar_id = shift @$bars; + +my $bar_config = $i3->get_bar_config($bar_id)->recv; +is($bar_config->{status_command}, 'i3status --foo', 'status_command correct'); +ok(!$bar_config->{verbose}, 'verbose off by default'); +ok($bar_config->{workspace_buttons}, 'workspace buttons enabled per default'); +is($bar_config->{mode}, 'hide', 'hide mode by default'); +is($bar_config->{position}, 'bottom', 'position bottom by default'); + +exit_gracefully($pid); + +##################################################################### +# validate a more complex configuration +##################################################################### + +$config = <get_bar_config()->recv; +is(@$bars, 1, 'one bar configured'); + +my $bar_id = shift @$bars; + +my $bar_config = $i3->get_bar_config($bar_id)->recv; +is($bar_config->{status_command}, 'i3status --bar', 'status_command correct'); +ok($bar_config->{verbose}, 'verbose on'); +ok(!$bar_config->{workspace_buttons}, 'workspace buttons disabled'); +is($bar_config->{mode}, 'dock', 'dock mode'); +is($bar_config->{position}, 'top', 'position top'); +is_deeply($bar_config->{outputs}, [ 'HDMI1', 'HDMI2' ], 'outputs ok'); +is($bar_config->{tray_output}, 'HDMI2', 'tray_output ok'); +is($bar_config->{font}, 'Terminus', 'font ok'); +is($bar_config->{socket_path}, '/tmp/foobar', 'socket_path ok'); +is_deeply($bar_config->{colors}, + { + background => 'ff0000', + statusline => '00ff00', + focused_workspace_text => 'ffffff', + focused_workspace_bg => '285577', + active_workspace_text => '888888', + active_workspace_bg => '222222', + inactive_workspace_text => '888888', + inactive_workspace_bg => '222222', + urgent_workspace_text => 'ffffff', + urgent_workspace_bg => '900000', + }, 'colors ok'); + +exit_gracefully($pid); + +done_testing; From 063b124e358705f24c1972bec7d15f52a5f56a86 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 18 Oct 2011 22:16:04 +0100 Subject: [PATCH 08/45] Implement parsing bar {} config blocks --- src/cfgparse.l | 48 ++++++++++- src/cfgparse.y | 221 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 266 insertions(+), 3 deletions(-) diff --git a/src/cfgparse.l b/src/cfgparse.l index 622a133b..2278a81e 100644 --- a/src/cfgparse.l +++ b/src/cfgparse.l @@ -37,6 +37,11 @@ int yycolumn = 1; yy_push_state(EAT_WHITESPACE); \ } while (0) +#define BAR_DOUBLE_COLOR do { \ + yy_push_state(BAR_COLOR); \ + yy_push_state(BAR_COLOR); \ +} while (0) + %} EOL (\r?\n) @@ -50,7 +55,13 @@ EOL (\r?\n) %s OUTPUT_COND %s FOR_WINDOW_COND %s EAT_WHITESPACE + %x BUFFER_LINE +%x BAR +%x BAR_MODE +%x BAR_POSITION +%x BAR_COLORS +%x BAR_COLOR %% @@ -74,6 +85,37 @@ EOL (\r?\n) yycolumn = 1; } + /* This part of the lexer handles the bar {} blocks */ +[ \t]+ { /* ignore whitespace */ ; } +"{" { return '{'; } +"}" { yy_pop_state(); return '}'; } +^[ \t]*#[^\n]* { return TOKCOMMENT; } +output { WS_STRING; return TOK_BAR_OUTPUT; } +tray_output { WS_STRING; return TOK_BAR_TRAY_OUTPUT; } +socket_path { WS_STRING; return TOK_BAR_SOCKET_PATH; } +mode { yy_push_state(BAR_MODE); return TOK_BAR_MODE; } +hide { yy_pop_state(); return TOK_BAR_HIDE; } +dock { yy_pop_state(); return TOK_BAR_DOCK; } +position { yy_push_state(BAR_POSITION); return TOK_BAR_POSITION; } +bottom { yy_pop_state(); return TOK_BAR_BOTTOM; } +top { yy_pop_state(); return TOK_BAR_TOP; } +status_command { WS_STRING; return TOK_BAR_STATUS_COMMAND; } +font { WS_STRING; return TOK_BAR_FONT; } +workspace_buttons { return TOK_BAR_WORKSPACE_BUTTONS; } +verbose { return TOK_BAR_VERBOSE; } +colors { yy_push_state(BAR_COLORS); return TOK_BAR_COLORS; } +"{" { return '{'; } +"}" { yy_pop_state(); return '}'; } +background { yy_push_state(BAR_COLOR); return TOK_BAR_COLOR_BACKGROUND; } +statusline { yy_push_state(BAR_COLOR); return TOK_BAR_COLOR_STATUSLINE; } +focused_workspace { BAR_DOUBLE_COLOR; return TOK_BAR_COLOR_FOCUSED_WORKSPACE; } +active_workspace { BAR_DOUBLE_COLOR; return TOK_BAR_COLOR_ACTIVE_WORKSPACE; } +inactive_workspace { BAR_DOUBLE_COLOR; return TOK_BAR_COLOR_INACTIVE_WORKSPACE; } +urgent_workspace { BAR_DOUBLE_COLOR; return TOK_BAR_COLOR_URGENT_WORKSPACE; } +#[0-9a-fA-F]+ { yy_pop_state(); yylval.string = sstrdup(yytext+1); return HEXCOLOR; } +[a-zA-Z]+ { yylval.string = sstrdup(yytext); return WORD; } + + "]" { yy_pop_state(); return ']'; } "[" { @@ -93,13 +135,14 @@ EOL (\r?\n) yylval.string = copy; return STR; } -[^\n]+ { BEGIN(INITIAL); yylval.string = sstrdup(yytext); return STR; } +[^\n]+ { yy_pop_state(); yylval.string = sstrdup(yytext); return STR; } [a-zA-Z0-9_-]+ { yylval.string = sstrdup(yytext); return OUTPUT; } ^[ \t]*#[^\n]* { return TOKCOMMENT; } [0-9a-fA-F]+ { yylval.string = sstrdup(yytext); return HEX; } [ \t]*→[ \t]* { BEGIN(WANT_STRING); } [ \t]+ { BEGIN(WANT_STRING); } [0-9]+ { yylval.number = atoi(yytext); return NUMBER; } +bar { yy_push_state(BAR); return TOK_BAR; } mode { return TOKMODE; } bind { yy_push_state(WANT_STRING); yy_push_state(EAT_WHITESPACE); yy_push_state(EAT_WHITESPACE); return TOKBINDCODE; } bindcode { yy_push_state(WANT_STRING); yy_push_state(EAT_WHITESPACE); yy_push_state(EAT_WHITESPACE); return TOKBINDCODE; } @@ -179,10 +222,9 @@ con_id { yy_push_state(WANT_QSTRING); return TOK_CON_ID con_mark { yy_push_state(WANT_QSTRING); return TOK_MARK; } title { yy_push_state(WANT_QSTRING); return TOK_TITLE; } -{EOL} { +<*>{EOL} { FREE(context->line_copy); context->line_number++; - BEGIN(INITIAL); yy_push_state(BUFFER_LINE); } [ \t]+ { BEGIN(WANT_STRING); } diff --git a/src/cfgparse.y b/src/cfgparse.y index 6869eee7..6e59c87c 100644 --- a/src/cfgparse.y +++ b/src/cfgparse.y @@ -14,6 +14,7 @@ static pid_t configerror_pid = -1; static Match current_match; +static Barconfig current_bar; typedef struct yy_buffer_state *YY_BUFFER_STATE; extern int yylex(struct context *context); @@ -587,6 +588,7 @@ void parse_file(const char *f) { %token STR "" %token STR_NG "" %token HEX "" +%token HEXCOLOR "#" %token OUTPUT "" %token TOKBINDCODE %token TOKTERMINAL @@ -610,6 +612,7 @@ void parse_file(const char *f) { %token TOKCOLOR %token TOKARROW "→" %token TOKMODE "mode" +%token TOK_BAR "bar" %token TOK_ORIENTATION "default_orientation" %token TOK_HORIZ "horizontal" %token TOK_VERT "vertical" @@ -634,6 +637,27 @@ void parse_file(const char *f) { %token TOK_LEAVE_FULLSCREEN "leave_fullscreen" %token TOK_FOR_WINDOW "for_window" +%token TOK_BAR_OUTPUT "output (bar)" +%token TOK_BAR_TRAY_OUTPUT "tray_output" +%token TOK_BAR_SOCKET_PATH "socket_path" +%token TOK_BAR_MODE "mode" +%token TOK_BAR_HIDE "hide" +%token TOK_BAR_DOCK "dock" +%token TOK_BAR_POSITION "position" +%token TOK_BAR_BOTTOM "bottom" +%token TOK_BAR_TOP "top" +%token TOK_BAR_STATUS_COMMAND "status_command" +%token TOK_BAR_FONT "font" +%token TOK_BAR_WORKSPACE_BUTTONS "workspace_buttons" +%token TOK_BAR_VERBOSE "verbose" +%token TOK_BAR_COLORS "colors" +%token TOK_BAR_COLOR_BACKGROUND "background" +%token TOK_BAR_COLOR_STATUSLINE "statusline" +%token TOK_BAR_COLOR_FOCUSED_WORKSPACE "focused_workspace" +%token TOK_BAR_COLOR_ACTIVE_WORKSPACE "active_workspace" +%token TOK_BAR_COLOR_INACTIVE_WORKSPACE "inactive_workspace" +%token TOK_BAR_COLOR_URGENT_WORKSPACE "urgent_workspace" + %token TOK_MARK "mark" %token TOK_CLASS "class" %token TOK_INSTANCE "instance" @@ -655,6 +679,8 @@ void parse_file(const char *f) { %type colorpixel %type bool %type popup_setting +%type bar_position_position +%type bar_mode_mode %type command %type word_or_number %type optional_workspace_name @@ -672,6 +698,7 @@ line: bindline | for_window | mode + | bar | floating_modifier | orientation | workspace_layout @@ -902,6 +929,200 @@ modeline: } ; +bar: + TOK_BAR '{' barlines '}' + { + printf("\t new bar configuration finished, saving.\n"); + /* Generate a unique ID for this bar */ + current_bar.id = sstrdup("foo"); /* TODO */ + + /* Copy the current (static) structure into a dynamically allocated + * one, then cleanup our static one. */ + Barconfig *bar_config = scalloc(sizeof(Barconfig)); + memcpy(bar_config, ¤t_bar, sizeof(Barconfig)); + TAILQ_INSERT_TAIL(&barconfigs, bar_config, configs); + + memset(¤t_bar, '\0', sizeof(Barconfig)); + } + ; + +barlines: + /* empty */ + | barlines barline + ; + +barline: + comment + | bar_status_command + | bar_output + | bar_tray_output + | bar_position + | bar_mode + | bar_font + | bar_workspace_buttons + | bar_verbose + | bar_socket_path + | bar_colors + | bar_color_background + | bar_color_statusline + | bar_color_focused_workspace + | bar_color_active_workspace + | bar_color_inactive_workspace + | bar_color_urgent_workspace + ; + +bar_status_command: + TOK_BAR_STATUS_COMMAND STR + { + DLOG("should add status command %s\n", $2); + FREE(current_bar.status_command); + current_bar.status_command = $2; + } + ; + +bar_output: + TOK_BAR_OUTPUT STR + { + DLOG("bar output %s\n", $2); + int new_outputs = current_bar.num_outputs + 1; + current_bar.outputs = srealloc(current_bar.outputs, sizeof(char*) * new_outputs); + current_bar.outputs[current_bar.num_outputs] = $2; + current_bar.num_outputs = new_outputs; + } + ; + +bar_tray_output: + TOK_BAR_TRAY_OUTPUT STR + { + DLOG("tray %s\n", $2); + FREE(current_bar.tray_output); + current_bar.tray_output = $2; + } + ; + +bar_position: + TOK_BAR_POSITION bar_position_position + { + DLOG("position %d\n", $2); + current_bar.position = $2; + } + ; + +bar_position_position: + TOK_BAR_TOP { $$ = P_TOP; } + | TOK_BAR_BOTTOM { $$ = P_BOTTOM; } + ; + +bar_mode: + TOK_BAR_MODE bar_mode_mode + { + DLOG("mode %d\n", $2); + current_bar.mode = $2; + } + ; + +bar_mode_mode: + TOK_BAR_HIDE { $$ = M_HIDE; } + | TOK_BAR_DOCK { $$ = M_DOCK; } + ; + +bar_font: + TOK_BAR_FONT STR + { + DLOG("font %s\n", $2); + FREE(current_bar.font); + current_bar.font = $2; + } + ; + +bar_workspace_buttons: + TOK_BAR_WORKSPACE_BUTTONS bool + { + DLOG("workspace_buttons = %d\n", $2); + /* We store this inverted to make the default setting right when + * initializing the struct with zero. */ + current_bar.hide_workspace_buttons = !($2); + } + ; + +bar_verbose: + TOK_BAR_VERBOSE bool + { + DLOG("verbose = %d\n", $2); + current_bar.verbose = $2; + } + ; + +bar_socket_path: + TOK_BAR_SOCKET_PATH STR + { + DLOG("socket_path = %s\n", $2); + FREE(current_bar.socket_path); + current_bar.socket_path = $2; + } + ; + +bar_colors: + TOK_BAR_COLORS '{' barlines '}' + { + /* At the moment, the TOK_BAR_COLORS token is only to make the config + * friendlier for humans. We might change this in the future if it gets + * more complex. */ + } + ; + +bar_color_background: + TOK_BAR_COLOR_BACKGROUND HEXCOLOR + { + DLOG("background = %s\n", $2); + current_bar.colors.background = $2; + } + ; + +bar_color_statusline: + TOK_BAR_COLOR_STATUSLINE HEXCOLOR + { + DLOG("statusline = %s\n", $2); + current_bar.colors.statusline = $2; + } + ; + +bar_color_focused_workspace: + TOK_BAR_COLOR_FOCUSED_WORKSPACE HEXCOLOR HEXCOLOR + { + DLOG("focused_ws = %s and %s\n", $2, $3); + current_bar.colors.focused_workspace_text = $2; + current_bar.colors.focused_workspace_bg = $3; + } + ; + +bar_color_active_workspace: + TOK_BAR_COLOR_ACTIVE_WORKSPACE HEXCOLOR HEXCOLOR + { + DLOG("active_ws = %s and %s\n", $2, $3); + current_bar.colors.active_workspace_text = $2; + current_bar.colors.active_workspace_bg = $3; + } + ; + +bar_color_inactive_workspace: + TOK_BAR_COLOR_INACTIVE_WORKSPACE HEXCOLOR HEXCOLOR + { + DLOG("inactive_ws = %s and %s\n", $2, $3); + current_bar.colors.inactive_workspace_text = $2; + current_bar.colors.inactive_workspace_bg = $3; + } + ; + +bar_color_urgent_workspace: + TOK_BAR_COLOR_URGENT_WORKSPACE HEXCOLOR HEXCOLOR + { + DLOG("urgent_ws = %s and %s\n", $2, $3); + current_bar.colors.urgent_workspace_text = $2; + current_bar.colors.urgent_workspace_bg = $3; + } + ; + floating_modifier: TOKFLOATING_MODIFIER binding_modifiers { From 15bface10d2ebaac3f0a7b01da2c7be285a61807 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Wed, 19 Oct 2011 19:57:39 +0100 Subject: [PATCH 09/45] Create different IDs for each bar (+test) --- src/cfgparse.y | 9 ++++++++- src/main.c | 2 ++ testcases/t/177-bar-config.t | 39 ++++++++++++++++++++++++++++++++++-- 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/cfgparse.y b/src/cfgparse.y index 6e59c87c..2c796af1 100644 --- a/src/cfgparse.y +++ b/src/cfgparse.y @@ -934,7 +934,14 @@ bar: { printf("\t new bar configuration finished, saving.\n"); /* Generate a unique ID for this bar */ - current_bar.id = sstrdup("foo"); /* TODO */ + current_bar.id = sstrdup("bar-XXXXXX"); + /* This works similar to mktemp in that it replaces the last six X with + * random letters, but without the restriction that the given buffer + * has to contain a valid path name. */ + char *x = current_bar.id + strlen("bar-"); + while (*x != '\0') { + *(x++) = (rand() % 26) + 'a'; + } /* Copy the current (static) structure into a dynamically allocated * one, then cleanup our static one. */ diff --git a/src/main.c b/src/main.c index ffdc1fd3..832d7f1b 100644 --- a/src/main.c +++ b/src/main.c @@ -217,6 +217,8 @@ int main(int argc, char *argv[]) { if (!isatty(fileno(stdout))) setbuf(stdout, NULL); + srand(time(NULL)); + init_logging(); start_argv = argv; diff --git a/testcases/t/177-bar-config.t b/testcases/t/177-bar-config.t index 98eb4edd..c7cf2843 100644 --- a/testcases/t/177-bar-config.t +++ b/testcases/t/177-bar-config.t @@ -99,9 +99,9 @@ $i3 = i3(get_socket_path(0)); $bars = $i3->get_bar_config()->recv; is(@$bars, 1, 'one bar configured'); -my $bar_id = shift @$bars; +$bar_id = shift @$bars; -my $bar_config = $i3->get_bar_config($bar_id)->recv; +$bar_config = $i3->get_bar_config($bar_id)->recv; is($bar_config->{status_command}, 'i3status --bar', 'status_command correct'); ok($bar_config->{verbose}, 'verbose on'); ok(!$bar_config->{workspace_buttons}, 'workspace buttons disabled'); @@ -127,4 +127,39 @@ is_deeply($bar_config->{colors}, exit_gracefully($pid); +##################################################################### +# ensure that multiple bars get different IDs +##################################################################### + +$config = <get_bar_config()->recv; +is(@$bars, 2, 'two bars configured'); +isnt($bars->[0], $bars->[1], 'bar IDs are different'); + +my $bar1_config = $i3->get_bar_config($bars->[0])->recv; +my $bar2_config = $i3->get_bar_config($bars->[1])->recv; + +isnt($bar1_config->{outputs}, $bar2_config->{outputs}, 'outputs different'); + +exit_gracefully($pid); + done_testing; From a5be27cb79f63b6303b65c70a79bddf44c1017d4 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Wed, 19 Oct 2011 22:58:19 +0100 Subject: [PATCH 10/45] Make i3bar get its config from i3 via IPC In order to not duplicate configuration options and make stuff confusing, we dropped the commandline flags (except for socket_path and bar_id). This means that you *have to* specify bar_id when starting i3bar. The best way is to let i3 start i3bar, which it will do automatically for every bar {} configuration block it finds. --- i3bar/include/config.h | 17 +++- i3bar/include/xcb.h | 12 ++- i3bar/src/config.c | 214 +++++++++++++++++++++++++++++++++++++++++ i3bar/src/ipc.c | 38 +++++++- i3bar/src/main.c | 188 ++++-------------------------------- i3bar/src/xcb.c | 159 +++++++++++++++++------------- 6 files changed, 388 insertions(+), 240 deletions(-) create mode 100644 i3bar/src/config.c diff --git a/i3bar/include/config.h b/i3bar/include/config.h index b3473917..19b246dc 100644 --- a/i3bar/include/config.h +++ b/i3bar/include/config.h @@ -13,10 +13,25 @@ typedef struct config_t { int hide_on_modifier; dockpos_t dockpos; int verbose; - xcb_colors_t *colors; + struct xcb_color_strings_t colors; int disable_ws; + char *bar_id; + char *command; + char *fontname; } config_t; config_t config; +/** + * Start parsing the received bar configuration json-string + * + */ +void parse_config_json(char *json); + +/** + * free()s the color strings as soon as they are not needed anymore. + * + */ +void free_colors(struct xcb_color_strings_t *colors); + #endif diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index c1b7cc14..51da5d3e 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -40,10 +40,18 @@ struct xcb_color_strings_t { typedef struct xcb_colors_t xcb_colors_t; /* - * Initialize xcb and use the specified fontname for text-rendering + * Early initialization of the connection to X11: Everything which does not + * depend on 'config'. * */ -char *init_xcb(char *fontname); +char *init_xcb_early(); + +/** + * Initialization which depends on 'config' being usable. Called after the + * configuration has arrived. + * + */ +void init_xcb_late(char *fontname); /* * Initialize the colors diff --git a/i3bar/src/config.c b/i3bar/src/config.c new file mode 100644 index 00000000..23c5e122 --- /dev/null +++ b/i3bar/src/config.c @@ -0,0 +1,214 @@ +/* + * vim:ts=4:sw=4:expandtab + * + * i3bar - an xcb-based status- and ws-bar for i3 + * + * © 2010-2011 Axel Wagner and contributors + * + * See file LICENSE for license information + * + * src/outputs.c: Maintaining the output-list + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +static char *cur_key; + +/* + * Parse a key. + * + * Essentially we just save it in cur_key. + * + */ +#if YAJL_MAJOR >= 2 +static int config_map_key_cb(void *params_, const unsigned char *keyVal, size_t keyLen) { +#else +static int config_map_key_cb(void *params_, const unsigned char *keyVal, unsigned keyLen) { +#endif + FREE(cur_key); + + cur_key = malloc(sizeof(unsigned char) * (keyLen + 1)); + strncpy(cur_key, (const char*) keyVal, keyLen); + cur_key[keyLen] = '\0'; + + return 1; +} + +/* + * Parse a string + * + */ +#if YAJL_MAJOR >= 2 +static int config_string_cb(void *params_, const unsigned char *val, size_t len) { +#else +static int config_string_cb(void *params_, const unsigned char *val, unsigned int len) { +#endif + /* The id is ignored, we already have it in config.bar_id */ + if (!strcmp(cur_key, "id")) + return 1; + + if (!strcmp(cur_key, "mode")) { + DLOG("mode = %.*s, len = %d\n", len, val, len); + config.hide_on_modifier = (len == 4 && !strncmp((const char*)val, "hide", strlen("hide"))); + return 1; + } + + if (!strcmp(cur_key, "position")) { + DLOG("position = %.*s\n", len, val); + config.dockpos = (len == 3 && !strncmp((const char*)val, "top", strlen("top")) ? DOCKPOS_TOP : DOCKPOS_BOT); + return 1; + } + + if (!strcmp(cur_key, "status_command")) { + /* We cannot directly start the child here, because start_child() also + * needs to be run when no command was specified (to setup stdin). + * Therefore we save the command in 'config' and access it later in + * got_bar_config() */ + DLOG("command = %.*s\n", len, val); + asprintf(&config.command, "%.*s", len, val); + return 1; + } + + if (!strcmp(cur_key, "font")) { + DLOG("font = %.*s\n", len, val); + asprintf(&config.fontname, "%.*s", len, val); + return 1; + } + + if (!strcmp(cur_key, "outputs")) { + printf("+output %.*s\n", len, val); + /* XXX: these are not implemented yet */ + return 1; + } + + if (!strcmp(cur_key, "tray_output")) { + printf("tray_output %.*s\n", len, val); + /* XXX: these are not implemented yet */ + return 1; + } + +#define COLOR(json_name, struct_name) \ + do { \ + if (!strcmp(cur_key, #json_name)) { \ + DLOG(#json_name " = " #struct_name " = %.*s\n", len, val); \ + asprintf(&(config.colors.struct_name), "%.*s", len, val); \ + return 1; \ + } \ + } while (0) + + COLOR(statusline, bar_fg); + COLOR(background, bar_bg); + COLOR(focused_workspace_text, focus_ws_fg); + COLOR(focused_workspace_bg, focus_ws_bg); + COLOR(active_workspace_text, active_ws_fg); + COLOR(active_workspace_bg, active_ws_bg); + COLOR(inactive_workspace_text, inactive_ws_fg); + COLOR(inactive_workspace_bg, inactive_ws_bg); + COLOR(urgent_workspace_text, urgent_ws_fg); + COLOR(urgent_workspace_bg, urgent_ws_bg); + + printf("got unexpected string %.*s for cur_key = %s\n", len, val, cur_key); + + return 0; +} + +/* + * Parse a boolean value + * + */ +static int config_boolean_cb(void *params_, int val) { + if (!strcmp(cur_key, "workspace_buttons")) { + DLOG("workspace_buttons = %d\n", val); + config.disable_ws = !val; + return 1; + } + + if (!strcmp(cur_key, "verbose")) { + DLOG("verbose = %d\n", val); + config.verbose = val; + return 1; + } + + return 0; +} + +/* A datastructure to pass all these callbacks to yajl */ +static yajl_callbacks outputs_callbacks = { + NULL, + &config_boolean_cb, + NULL, + NULL, + NULL, + &config_string_cb, + NULL, + &config_map_key_cb, + NULL, + NULL, + NULL +}; + +/* + * Start parsing the received bar configuration json-string + * + */ +void parse_config_json(char *json) { + yajl_handle handle; + yajl_status state; +#if YAJL_MAJOR < 2 + yajl_parser_config parse_conf = { 0, 0 }; + + handle = yajl_alloc(&outputs_callbacks, &parse_conf, NULL, NULL); +#else + handle = yajl_alloc(&outputs_callbacks, NULL, NULL); +#endif + + state = yajl_parse(handle, (const unsigned char*) json, strlen(json)); + + /* FIXME: Proper errorhandling for JSON-parsing */ + switch (state) { + case yajl_status_ok: + break; + case yajl_status_client_canceled: +#if YAJL_MAJOR < 2 + case yajl_status_insufficient_data: +#endif + case yajl_status_error: + ELOG("Could not parse config-reply!\n"); + exit(EXIT_FAILURE); + break; + } + + yajl_free(handle); +} + +/* + * free()s the color strings as soon as they are not needed anymore. + * + */ +void free_colors(struct xcb_color_strings_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); + FREE_COLOR(focus_ws_fg); + FREE_COLOR(focus_ws_bg); +#undef FREE_COLOR +} + diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index e31de333..5969e5d6 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -114,12 +114,47 @@ void got_output_reply(char *reply) { reconfig_windows(); } +/* + * Called when we get the configuration for our bar instance + * + */ +void got_bar_config(char *reply) { + DLOG("Received bar config \"%s\"\n", reply); + /* 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-drivenness of the code */ + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); + parse_config_json(reply); + + /* Now we can actually use 'config', so let's subscribe to the appropriate + * events and request the workspaces if necessary. */ + subscribe_events(); + if (!config.disable_ws) + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); + + /* Initialize the rest of XCB */ + init_xcb_late(config.fontname); + + /* Resolve color strings to colorpixels and save them, then free the strings. */ + init_colors(&(config.colors)); + free_colors(&(config.colors)); + + /* The name of this function is actually misleading. Even if no command is + * specified, this function initiates the watchers to listen on stdin and + * react accordingly */ + start_child(config.command); + FREE(config.command); +} + /* Data-structure to easily call the reply-handlers later */ handler_t reply_handlers[] = { &got_command_reply, &got_workspace_reply, &got_subscribe_reply, &got_output_reply, + NULL, + NULL, + &got_bar_config, }; /* @@ -232,7 +267,8 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { type ^= 1 << 31; event_handlers[type](buffer); } else { - reply_handlers[type](buffer); + if (reply_handlers[type]) + reply_handlers[type](buffer); } FREE(header); diff --git a/i3bar/src/main.c b/i3bar/src/main.c index bfccb8ed..ea489941 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -19,6 +19,7 @@ #include #include "common.h" +#include "libi3.h" /* * Glob path, i.e. expand ~ @@ -39,61 +40,11 @@ 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 xcb_color_strings_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); - FREE_COLOR(focus_ws_fg); - FREE_COLOR(focus_ws_bg); -#undef FREE_COLOR -} - void print_usage(char *elf_name) { - printf("Usage: %s [-s sock_path] [-c command] [-m|-d[pos]] [-f font] [-V] [-h]\n", elf_name); + printf("Usage: %s [-s sock_path] [-h] [-v]\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("-d[]\tEnable dockmode. is \"top\" or \"bottom\". Default is bottom\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("-w\t\tDisable workspace-buttons\n"); - printf("-V\t\tBe (very) verbose with the debug-output\n"); printf("-h\t\tDisplay this help-message and exit\n"); + printf("-v\t\tDisplay version number and exit\n"); } /* @@ -120,107 +71,33 @@ int main(int argc, char **argv) { int opt; int option_index = 0; char *socket_path = getenv("I3SOCK"); - char *command = NULL; - char *fontname = NULL; char *i3_default_sock_path = "/tmp/i3-ipc.sock"; - struct xcb_color_strings_t colors = { NULL, }; - /* Definition of the standard-config */ - config.hide_on_modifier = 0; - config.dockpos = DOCKPOS_NONE; - config.disable_ws = 0; + /* Initialize the standard config to use 0 as default */ + memset(&config, '\0', sizeof(config_t)); static struct option long_opt[] = { { "socket", required_argument, 0, 's' }, - { "command", required_argument, 0, 'c' }, - { "hide", no_argument, 0, 'm' }, - { "dock", optional_argument, 0, 'd' }, - { "font", required_argument, 0, 'f' }, - { "nows", no_argument, 0, 'w' }, + { "bar_id", required_argument, 0, 0 }, { "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' }, - { "color-focus-ws-bg", required_argument, 0, 'I' }, - { "color-focus-ws-fg", required_argument, 0, 'J' }, { NULL, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "s:c:d::mf:whvVA:B:C:D:E:F:G:H:I:J:", long_opt, &option_index)) != -1) { + while ((opt = getopt_long(argc, argv, "s:hv", long_opt, &option_index)) != -1) { switch (opt) { case 's': socket_path = expand_path(optarg); break; - case 'c': - command = strdup(optarg); - break; - case 'm': - config.hide_on_modifier = 1; - break; - case 'd': - config.hide_on_modifier = 0; - if (optarg == NULL) { - config.dockpos = DOCKPOS_BOT; - break; - } - if (!strcmp(optarg, "top")) { - config.dockpos = DOCKPOS_TOP; - } else if (!strcmp(optarg, "bottom")) { - config.dockpos = DOCKPOS_BOT; - } else { - print_usage(argv[0]); - exit(EXIT_FAILURE); - } - break; - case 'f': - fontname = strdup(optarg); - break; - case 'w': - config.disable_ws = 1; - break; case 'v': printf("i3bar version " I3_VERSION " © 2010-2011 Axel Wagner and contributors\n"); exit(EXIT_SUCCESS); break; - 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_bg); - break; - case 'H': - read_color(&colors.urgent_ws_fg); - break; - case 'I': - read_color(&colors.focus_ws_bg); - break; - case 'J': - read_color(&colors.focus_ws_fg); + case 0: + if (!strcmp(long_opt[option_index].name, "bar_id")) { + FREE(config.bar_id); + config.bar_id = sstrdup(optarg); + } break; default: print_usage(argv[0]); @@ -229,26 +106,16 @@ 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"; - } - - if (config.dockpos != DOCKPOS_NONE) { - if (config.hide_on_modifier) { - ELOG("--dock and --hide are mutually exclusive!\n"); - exit(EXIT_FAILURE); - } - } else { - config.hide_on_modifier = 1; + if (!config.bar_id) { + /* TODO: maybe we want -f which will automatically ask i3 for the first + * configured bar (and error out if there are too many)? */ + ELOG("No bar_id passed. Please let i3 start i3bar or specify --bar_id\n"); + exit(EXIT_FAILURE); } main_loop = ev_default_loop(0); - init_colors(&colors); - char *atom_sock_path = init_xcb(fontname); + char *atom_sock_path = init_xcb_early(); if (socket_path == NULL) { socket_path = atom_sock_path; @@ -259,27 +126,12 @@ int main(int argc, char **argv) { socket_path = expand_path(i3_default_sock_path); } - free_colors(&colors); - init_outputs(); if (init_connection(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); - if (!config.disable_ws) { - i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); - } + /* Request the bar configuration. When it arrives, we fill the config array. */ + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_BAR_CONFIG, config.bar_id); } - /* 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); - FREE(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() */ diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 4bbc8da7..471209c7 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -790,10 +790,11 @@ void xkb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { } /* - * Initialize xcb and use the specified fontname for text-rendering + * Early initialization of the connection to X11: Everything which does not + * depend on 'config'. * */ -char *init_xcb(char *fontname) { +char *init_xcb_early() { /* FIXME: xcb_connect leaks Memory */ xcb_connection = xcb_connect(NULL, &screen); if (xcb_connection_has_error(xcb_connection)) { @@ -809,66 +810,10 @@ char *init_xcb(char *fontname) { 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); - xcb_void_cookie_t open_font_cookie; - open_font_cookie = xcb_open_font_checked(xcb_connection, - xcb_font, - strlen(fontname), - fontname); - - /* We need to save info about the font, because we need the font's 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); - - /* 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; - xkb_minor = XkbMinorVersion; - - xkb_dpy = XkbOpenDisplay(NULL, - &xkb_event_base, - &xkb_errbase, - &xkb_major, - &xkb_minor, - &xkb_err); - - if (xkb_dpy == NULL) { - ELOG("No XKB!\n"); - exit(EXIT_FAILURE); - } - - if (fcntl(ConnectionNumber(xkb_dpy), F_SETFD, FD_CLOEXEC) == -1) { - ELOG("Could not set FD_CLOEXEC on xkbdpy: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - - int i1; - if (!XkbQueryExtension(xkb_dpy, &i1, &xkb_event_base, &xkb_errbase, &xkb_major, &xkb_minor)) { - ELOG("XKB not supported by X-server!\n"); - exit(EXIT_FAILURE); - } - - if (!XkbSelectEvents(xkb_dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask)) { - ELOG("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); - } - /* 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 */ uint32_t mask = XCB_GC_FOREGROUND; - uint32_t vals[3] = { colors.bar_bg, colors.bar_bg, xcb_font }; + uint32_t vals[] = { colors.bar_bg, colors.bar_bg }; statusline_clear = xcb_generate_id(xcb_connection); xcb_void_cookie_t clear_ctx_cookie = xcb_create_gc_checked(xcb_connection, @@ -877,7 +822,7 @@ char *init_xcb(char *fontname) { mask, vals); - mask |= XCB_GC_BACKGROUND | XCB_GC_FONT; + mask |= XCB_GC_BACKGROUND; vals[0] = colors.bar_fg; statusline_ctx = xcb_generate_id(xcb_connection); xcb_void_cookie_t sl_ctx_cookie = xcb_create_gc_checked(xcb_connection, @@ -931,6 +876,92 @@ char *init_xcb(char *fontname) { } } + + if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer") || + xcb_request_failed(clear_ctx_cookie, "Could not allocate statusline-buffer-clearcontext") || + xcb_request_failed(sl_ctx_cookie, "Could not allocate statusline-buffer-context")) { + exit(EXIT_FAILURE); + } + + return path; +} + +/* + * Initialization which depends on 'config' being usable. Called after the + * configuration has arrived. + * + */ +void init_xcb_late(char *fontname) { + 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"; + } + + /* We load and allocate the font */ + xcb_font = xcb_generate_id(xcb_connection); + xcb_void_cookie_t open_font_cookie; + open_font_cookie = xcb_open_font_checked(xcb_connection, + xcb_font, + strlen(fontname), + fontname); + + /* We need to save info about the font, because we need the font's 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); + + xcb_change_gc(xcb_connection, + statusline_ctx, + XCB_GC_FONT, + (uint32_t[]){ xcb_font }); + + xcb_flush(xcb_connection); + + /* 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; + xkb_minor = XkbMinorVersion; + + xkb_dpy = XkbOpenDisplay(NULL, + &xkb_event_base, + &xkb_errbase, + &xkb_major, + &xkb_minor, + &xkb_err); + + if (xkb_dpy == NULL) { + ELOG("No XKB!\n"); + exit(EXIT_FAILURE); + } + + if (fcntl(ConnectionNumber(xkb_dpy), F_SETFD, FD_CLOEXEC) == -1) { + ELOG("Could not set FD_CLOEXEC on xkbdpy: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + int i1; + if (!XkbQueryExtension(xkb_dpy, &i1, &xkb_event_base, &xkb_errbase, &xkb_major, &xkb_minor)) { + ELOG("XKB not supported by X-server!\n"); + exit(EXIT_FAILURE); + } + + if (!XkbSelectEvents(xkb_dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask)) { + ELOG("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); + } + /* Now we save the font-infos */ font_info = xcb_query_font_reply(xcb_connection, query_font_cookie, @@ -949,14 +980,6 @@ char *init_xcb(char *fontname) { } DLOG("Calculated Font-height: %d\n", font_height); - - if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer") || - xcb_request_failed(clear_ctx_cookie, "Could not allocate statusline-buffer-clearcontext") || - xcb_request_failed(sl_ctx_cookie, "Could not allocate statusline-buffer-context")) { - exit(EXIT_FAILURE); - } - - return path; } /* From ad0f13a0a987c60094d207e8fc43bac4b525f4d1 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 20 Oct 2011 18:47:09 +0100 Subject: [PATCH 11/45] Clean bars before reloading the config (+test) While the configuration gets updated in i3, the i3bar processes will not pick up these changes. We have to think about a good way to do that. --- src/config.c | 26 ++++++++++++++++++++++++++ testcases/t/177-bar-config.t | 8 ++++++++ 2 files changed, 34 insertions(+) diff --git a/src/config.c b/src/config.c index d39a5761..0830add8 100644 --- a/src/config.c +++ b/src/config.c @@ -295,6 +295,32 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath, FREE(assign); } + /* Clear bar configs */ + Barconfig *barconfig; + while (!TAILQ_EMPTY(&barconfigs)) { + barconfig = TAILQ_FIRST(&barconfigs); + FREE(barconfig->id); + for (int c = 0; c < barconfig->num_outputs; c++) + free(barconfig->outputs[c]); + FREE(barconfig->outputs); + FREE(barconfig->tray_output); + FREE(barconfig->socket_path); + FREE(barconfig->status_command); + FREE(barconfig->font); + FREE(barconfig->colors.background); + FREE(barconfig->colors.statusline); + FREE(barconfig->colors.focused_workspace_text); + FREE(barconfig->colors.focused_workspace_bg); + FREE(barconfig->colors.active_workspace_text); + FREE(barconfig->colors.active_workspace_bg); + FREE(barconfig->colors.inactive_workspace_text); + FREE(barconfig->colors.inactive_workspace_bg); + FREE(barconfig->colors.urgent_workspace_text); + FREE(barconfig->colors.urgent_workspace_bg); + TAILQ_REMOVE(&barconfigs, barconfig, configs); + FREE(barconfig); + } + /* Clear workspace names */ #if 0 Workspace *ws; diff --git a/testcases/t/177-bar-config.t b/testcases/t/177-bar-config.t index c7cf2843..761dbf21 100644 --- a/testcases/t/177-bar-config.t +++ b/testcases/t/177-bar-config.t @@ -54,6 +54,14 @@ ok($bar_config->{workspace_buttons}, 'workspace buttons enabled per default'); is($bar_config->{mode}, 'hide', 'hide mode by default'); is($bar_config->{position}, 'bottom', 'position bottom by default'); +##################################################################### +# ensure that reloading cleans up the old bar configs +##################################################################### + +cmd 'reload'; +$bars = $i3->get_bar_config()->recv; +is(@$bars, 1, 'still one bar configured'); + exit_gracefully($pid); ##################################################################### From ab2d96ba48cb903c7654a679ad045da621ead31b Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 20 Oct 2011 19:02:08 +0100 Subject: [PATCH 12/45] tests: modify $PATH so that it prefers the compiled versions of everything in ../ --- testcases/lib/SocketActivation.pm | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/testcases/lib/SocketActivation.pm b/testcases/lib/SocketActivation.pm index ef182012..11a672e3 100644 --- a/testcases/lib/SocketActivation.pm +++ b/testcases/lib/SocketActivation.pm @@ -54,6 +54,14 @@ sub activate_i3 { $ENV{LISTEN_PID} = $$; $ENV{LISTEN_FDS} = 1; $ENV{DISPLAY} = $args{display}; + $ENV{PATH} = join(':', + '../i3-nagbar', + '../i3-msg', + '../i3-config-wizard', + '../i3bar', + '..', + $ENV{PATH} + ); # Only pass file descriptors 0 (stdin), 1 (stdout), 2 (stderr) and # 3 (socket) to the child. $^F = 3; From 230b238870c742eb4c55de62c04d022bb6c12682 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 20 Oct 2011 19:03:40 +0100 Subject: [PATCH 13/45] Actually start i3bar instances for each configured bar --- src/main.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main.c b/src/main.c index 832d7f1b..50ebaa34 100644 --- a/src/main.c +++ b/src/main.c @@ -633,6 +633,17 @@ int main(int argc, char *argv[]) { start_application(exec_always->command); } + /* Start i3bar processes for all configured bars */ + Barconfig *barconfig; + TAILQ_FOREACH(barconfig, &barconfigs, configs) { + char *command = NULL; + asprintf(&command, "i3bar --bar_id=%s --socket=\"%s\"", + barconfig->id, current_socketpath); + LOG("Starting bar process: %s\n", command); + start_application(command); + free(command); + } + /* Make sure to destroy the event loop to invoke the cleeanup callbacks * when calling exit() */ atexit(i3_exit); From c5caa9682cac0a480e0e9c27767f467000adbf20 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 20 Oct 2011 19:08:41 +0100 Subject: [PATCH 14/45] =?UTF-8?q?i3bar:=20don=E2=80=99t=20reconnect,=20but?= =?UTF-8?q?=20exit(0)=20on=20EOF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since i3 starts i3bar instances as necessary, EOF is considered a signal to either shutdown because i3 exited or because it is restarting. --- i3bar/src/ipc.c | 67 +++++++------------------------------------------ 1 file changed, 9 insertions(+), 58 deletions(-) diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 5969e5d6..db60a362 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -24,55 +24,11 @@ #include "common.h" ev_io *i3_connection; -ev_timer *reconn = NULL; const char *sock_path; typedef void(*handler_t)(char*); -/* - * Retry to connect. - * - */ -void retry_connection(struct ev_loop *loop, ev_timer *w, int events) { - static int retries = 8; - if (init_connection(sock_path) == 0) { - if (retries == 0) { - ELOG("Retried 8 times - connection failed!\n"); - exit(EXIT_FAILURE); - } - retries--; - return; - } - retries = 8; - ev_timer_stop(loop, w); - subscribe_events(); - - /* We get the current outputs and workspaces, to - * reconfigure all bars with the current configuration */ - i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); - if (!config.disable_ws) { - i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); - } -} - -/* - * Schedule a reconnect - * - */ -void reconnect() { - if (reconn == NULL) { - if ((reconn = malloc(sizeof(ev_timer))) == NULL) { - ELOG("malloc() failed: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - } else { - ev_timer_stop(main_loop, reconn); - } - ev_timer_init(reconn, retry_connection, 0.25, 0.25); - ev_timer_start(main_loop, reconn); -} - /* * Called, when we get a reply to a command from i3. * Since i3 does not give us much feedback on commands, we do not much @@ -210,12 +166,10 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { exit(EXIT_FAILURE); } if (n == 0) { - /* EOF received. We try to recover a few times, because most likely - * i3 just restarted */ - ELOG("EOF received, try to recover...\n"); - destroy_connection(); - reconnect(); - return; + /* EOF received. Since i3 will restart i3bar instances as appropriate, + * we exit here. */ + DLOG("EOF received, exiting...\n"); + exit(EXIT_SUCCESS); } rec += n; } @@ -239,12 +193,10 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { * of the message */ char *buffer = malloc(size + 1); if (buffer == NULL) { - /* EOF received. We try to recover a few times, because most likely - * i3 just restarted */ - ELOG("EOF received, try to recover...\n"); - destroy_connection(); - reconnect(); - return; + /* EOF received. Since i3 will restart i3bar instances as appropriate, + * we exit here. */ + DLOG("EOF received, exiting...\n"); + exit(EXIT_SUCCESS); } rec = 0; @@ -346,8 +298,7 @@ int init_connection(const char *socket_path) { strcpy(addr.sun_path, sock_path); if (connect(sockfd, (const struct sockaddr*) &addr, sizeof(struct sockaddr_un)) < 0) { ELOG("Could not connect to i3! %s: %s\n", sock_path, strerror(errno)); - reconnect(); - return 0; + exit(EXIT_FAILURE); } i3_connection = malloc(sizeof(ev_io)); From a33c720ce86ab05d85885e4a015a2dd36b3417ba Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 20 Oct 2011 19:46:57 +0100 Subject: [PATCH 15/45] docs/ipc: document i3 --get-socketpath --- docs/ipc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/ipc b/docs/ipc index 4093ffce..12523d12 100644 --- a/docs/ipc +++ b/docs/ipc @@ -1,7 +1,7 @@ IPC interface (interprocess communication) ========================================== Michael Stapelberg -March 2010 +October 2011 This document describes how to interface with i3 from a separate process. This is useful for example to remote-control i3 (to write test cases for example) or @@ -12,7 +12,7 @@ The method of choice for IPC in our case is a unix socket because it has very little overhead on both sides and is usually available without headaches in most languages. In the default configuration file, the ipc-socket gets created in +/tmp/i3-%u/ipc-socket.%p+ where +%u+ is your UNIX username and +%p+ is the -PID of i3. +PID of i3. You can get the socketpath from i3 by calling +i3 --get-socketpath+. All i3 utilities, like +i3-msg+ and +i3-input+ will read the +I3_SOCKET_PATH+ X11 property, stored on the X11 root window. @@ -24,7 +24,8 @@ snippet illustrates this in Perl: ------------------------------------------------------------- use IO::Socket::UNIX; -my $sock = IO::Socket::UNIX->new(Peer => '/tmp/i3-ipc.sock'); +chomp(my $path = qx(i3 --get-socketpath)); +my $sock = IO::Socket::UNIX->new(Peer => $path); ------------------------------------------------------------- == Sending messages to i3 From 2bda05d1b8b442943d278d011bcd4327542f5e4a Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 20 Oct 2011 19:51:01 +0100 Subject: [PATCH 16/45] docs/ipc: fix example end --- docs/ipc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/ipc b/docs/ipc index 12523d12..76643573 100644 --- a/docs/ipc +++ b/docs/ipc @@ -423,7 +423,7 @@ JSON dump: } ] } - +------------------------ === GET_MARKS reply @@ -433,7 +433,6 @@ same mark, it will be represented multiple times in the reply (the array contents are not unique). If no window has a mark the response will be the empty array []. ------------------------- == Events From 093507fc381fd5bf6c5b851a75674c4f9fec532c Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 20 Oct 2011 20:16:07 +0100 Subject: [PATCH 17/45] ipc: document the GET_BAR_CONFIG request/reply --- docs/ipc | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/docs/ipc b/docs/ipc index 76643573..db1ef681 100644 --- a/docs/ipc +++ b/docs/ipc @@ -64,6 +64,10 @@ GET_MARKS (5):: Gets a list of marks (identifiers for containers to easily jump to them later). The reply will be a JSON-encoded list of window marks (see reply section). +GET_BAR_CONFIG (6):: + Gets the configuration (as JSON map) of the workspace bar with the + given ID. If no ID is provided, an array with all configured bar IDs is + returned instead. So, a typical message could look like this: -------------------------------------------------- @@ -117,6 +121,8 @@ GET_TREE (4):: Reply to the GET_TREE message. GET_MARKS (5):: Reply to the GET_MARKS message. +GET_BAR_CONFIG (6):: + Reply to the GET_BAR_CONFIG message. === COMMAND reply @@ -434,6 +440,89 @@ contents are not unique). If no window has a mark the response will be the empty array []. +=== GET_BAR_CONFIG reply + +This can be used by third-party workspace bars (especially i3bar, but others +are free to implement compatible alternatives) to get the +bar+ block +configuration from i3. + +Depending on the input, the reply is either: + +empty input:: + An array of configured bar IDs +Bar ID:: + A JSON map containing the configuration for the specified bar. + +Each bar configuration has the following properties: + +id (string):: + The ID for this bar. Included in case you request multiple + configurations and want to differentiate the different replies. +mode (string):: + Either +dock+ (the bar sets the dock window type) or +hide+ (the bar + does not show unless a specific key is pressed). +position (string):: + Either +bottom+ or +top+ at the moment. +status_command (string):: + Command which will be run to generate a statusline. Each line on stdout + of this command will be displayed in the bar. At the moment, no + formatting is supported. +font (string):: + The font to use for text on the bar. +workspace_buttons (boolean):: + Display workspace buttons or not? Defaults to true. +verbose (boolean):: + Should the bar enable verbose output for debugging? Defaults to false. +colors (map):: + Contains key/value pairs of colors. Each value is a color code in hex, + formatted rrggbb (like used in HTML). + +The following colors can be configured at the moment: + +background:: + Background color of the bar. +statusline:: + Text color to be used for the statusline. +focused_workspace_text/focused_workspace_bg:: + Text color/background color for a workspace button when the workspace + has focus. +active_workspace_text/active_workspace_bg:: + Text color/background color for a workspace button when the workspace + is active (visible) on some output, but the focus is on another one. + You can only tell this apart from the focused workspace when you are + using multiple monitors. +inactive_workspace_text/inactive_workspace_bg:: + Text color/background color for a workspace button when the workspace + does not have focus and is not active (visible) on any output. This + will be the case for most workspaces. +urgent_workspace_text/urgent_workspace_bar:: + Text color/background color for workspaces which contain at least one + window with the urgency hint set. + + +*Example of configured bars:* +-------------- +["bar-bxuqzf"] +-------------- + +*Example of bar configuration:* +-------------- +{ + "id": "bar-bxuqzf", + "mode": "dock", + "position": "bottom", + "status_command": "i3status", + "font": "-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1", + "workspace_buttons": true, + "verbose": false, + "colors": { + "background": "c0c0c0", + "statusline": "00ff00", + "focused_workspace_text": "ffffff", + "focused_workspace_bg": "000000" + } +} +-------------- == Events From bf408c9a08ceff81444bbeb252014c2e774fd46a Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 20 Oct 2011 20:31:44 +0100 Subject: [PATCH 18/45] tests: depend on AnyEvent::I3 0.09 (for get_bar_config) --- testcases/Makefile.PL | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testcases/Makefile.PL b/testcases/Makefile.PL index 60083667..11385f76 100755 --- a/testcases/Makefile.PL +++ b/testcases/Makefile.PL @@ -8,7 +8,7 @@ WriteMakefile( MIN_PERL_VERSION => '5.010000', # 5.10.0 PREREQ_PM => { 'AnyEvent' => 0, - 'AnyEvent::I3' => '0.08', + 'AnyEvent::I3' => '0.09', 'X11::XCB' => '0.03', 'Test::Most' => 0, 'Test::Deep' => 0, From 12d866e4f66149d426658b5e11876e739105e256 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 20 Oct 2011 22:25:59 +0100 Subject: [PATCH 19/45] =?UTF-8?q?Don=E2=80=99t=20start=20i3-nagbar=20when?= =?UTF-8?q?=20using=20-C=20to=20validate=20the=20config?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/i3.h | 1 + src/cfgparse.y | 5 ++++- src/main.c | 6 +++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/i3.h b/include/i3.h index 089dfcba..fca983ec 100644 --- a/include/i3.h +++ b/include/i3.h @@ -44,5 +44,6 @@ extern uint8_t root_depth; extern bool xcursor_supported, xkb_supported; extern xcb_window_t root; extern struct ev_loop *main_loop; +extern bool only_check_config; #endif diff --git a/src/cfgparse.y b/src/cfgparse.y index 2c796af1..c9e1eb98 100644 --- a/src/cfgparse.y +++ b/src/cfgparse.y @@ -266,7 +266,10 @@ static void nagbar_cleanup(EV_P_ ev_cleanup *watcher, int revent) { * */ static void start_configerror_nagbar(const char *config_path) { - fprintf(stderr, "Would start i3-nagscreen now\n"); + if (only_check_config) + return; + + fprintf(stderr, "Starting i3-nagbar due to configuration errors\n"); configerror_pid = fork(); if (configerror_pid == -1) { warn("Could not fork()"); diff --git a/src/main.c b/src/main.c index 50ebaa34..1bf6862d 100644 --- a/src/main.c +++ b/src/main.c @@ -61,6 +61,11 @@ struct ws_assignments_head ws_assignments = TAILQ_HEAD_INITIALIZER(ws_assignment bool xcursor_supported = true; bool xkb_supported = true; +/* This will be set to true when -C is used so that functions can behave + * slightly differently. We don’t want i3-nagbar to be started when validating + * the config, for example. */ +bool only_check_config = false; + /* * This callback is only a dummy, see xcb_prepare_cb and xcb_check_cb. * See also man libev(3): "ev_prepare" and "ev_check" - customise your event loop @@ -194,7 +199,6 @@ int main(int argc, char *argv[]) { bool autostart = true; char *layout_path = NULL; bool delete_layout_path = false; - bool only_check_config = false; bool force_xinerama = false; bool disable_signalhandler = false; static struct option long_options[] = { From caee0a0fdac257ea8e4394e26f453007a3e87db5 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 20 Oct 2011 22:38:46 +0100 Subject: [PATCH 20/45] cfgparse: eliminate absolute states, use yy_push_state/yy_pop_state This fixes a problem with workspace assignments. I tested i3 -C with three user configs (Thanks SardemFF7, julien, xeen) and did not notice any problems. --- src/cfgparse.l | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/cfgparse.l b/src/cfgparse.l index 2278a81e..88e6ad2c 100644 --- a/src/cfgparse.l +++ b/src/cfgparse.l @@ -136,7 +136,7 @@ EOL (\r?\n) return STR; } [^\n]+ { yy_pop_state(); yylval.string = sstrdup(yytext); return STR; } -[a-zA-Z0-9_-]+ { yylval.string = sstrdup(yytext); return OUTPUT; } +[a-zA-Z0-9_-]+ { yy_pop_state(); yylval.string = sstrdup(yytext); return OUTPUT; } ^[ \t]*#[^\n]* { return TOKCOMMENT; } [0-9a-fA-F]+ { yylval.string = sstrdup(yytext); return HEX; } [ \t]*→[ \t]* { BEGIN(WANT_STRING); } @@ -147,8 +147,8 @@ mode { return TOKMODE; } bind { yy_push_state(WANT_STRING); yy_push_state(EAT_WHITESPACE); yy_push_state(EAT_WHITESPACE); return TOKBINDCODE; } bindcode { yy_push_state(WANT_STRING); yy_push_state(EAT_WHITESPACE); yy_push_state(EAT_WHITESPACE); return TOKBINDCODE; } bindsym { yy_push_state(BINDSYM_COND); yy_push_state(EAT_WHITESPACE); return TOKBINDSYM; } -floating_modifier { BEGIN(INITIAL); return TOKFLOATING_MODIFIER; } -workspace { BEGIN(INITIAL); return TOKWORKSPACE; } +floating_modifier { return TOKFLOATING_MODIFIER; } +workspace { return TOKWORKSPACE; } output { yy_push_state(OUTPUT_COND); yy_push_state(EAT_WHITESPACE); return TOKOUTPUT; } terminal { WS_STRING; return TOKTERMINAL; } font { WS_STRING; return TOKFONT; } @@ -234,7 +234,6 @@ title { yy_push_state(WANT_QSTRING); return TOK_TITLE; /* if ASSIGN_COND then */ if (yy_start_stack_ptr > 0) yy_pop_state(); - else BEGIN(INITIAL); /* yylval will be the string, but without quotes */ char *copy = sstrdup(yytext+1); copy[strlen(copy)-1] = '\0'; From d970b19b597066316f8bf93c1e3bf25befc9d2fc Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 20 Oct 2011 22:55:24 +0100 Subject: [PATCH 21/45] i3bar: update manpage --- i3bar/doc/i3bar.man | 80 ++++++++++++++++----------------------------- 1 file changed, 29 insertions(+), 51 deletions(-) diff --git a/i3bar/doc/i3bar.man b/i3bar/doc/i3bar.man index d28f6249..dcf3022b 100644 --- a/i3bar/doc/i3bar.man +++ b/i3bar/doc/i3bar.man @@ -1,7 +1,7 @@ i3bar(1) ======== Axel Wagner -v0.7, July 2011 +v4.1, October 2011 == NAME @@ -9,81 +9,59 @@ i3bar - xcb-based status- and workspace-bar == SYNOPSIS -*i3bar* [*-s* 'sock_path'] [*-c* 'command'] [*-m*|*-d*['pos']] [*-f* 'font'] [*-V*] [*-h*] +*i3bar* [*-s* 'sock_path'] [*-b* 'bar_id'] [*-v*] [*-h*] + +== WARNING + +i3bar will automatically be invoked by i3 for every 'bar' configuration block. + +Starting it manually is usually not what you want to do. + +You have been warned! == 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 '/tmp/i3-ipc.sock' +Overwrites the path to the i3 IPC socket. -*-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* +*-b, --bar_id* 'bar_id':: +Specifies the bar ID for which to get the configuration from i3. -*-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. -This is the default behavior of i3bar. - -*-d*['pos']*, --dock*[*=*'pos']:: -Put i3bar in dockmode. This will reserve some space for it, so it does not overlap other clients. -You can specify either *bottom* (default) or *top* as 'pos'. - -*-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' +*-v, --version*:: +Display version number and exit. *-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. +*i3bar* displays a bar at the bottom (or top) of your monitor(s) containing +workspace switching buttons and a statusline generated by i3status(1) or +similar. It is automatically invoked (and configured through) i3. -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 its config file. - -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, --color-focus-ws-fg, --color-focus-ws-bg* - -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. +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 its config file. == ENVIRONMENT === I3SOCK -If no ipc-socket is specified on the commandline, this variable is used -to determine the path, at wich the unix domain socket is expected, on which -to connect to i3. +Used as a fallback for the i3 IPC socket path if neither the commandline +contains an argument nor the I3_SOCKET_PATH property is set on the X11 root +window. == EXAMPLES -To get a docked bar with some statusinformation, you use +Nothing to see here, move along. As stated above, you should not run i3bar manually. -*i3status | i3bar --dock* - -If you rather have it displayed at the top of the screen, you use - -*i3status | i3bar --dock=top* - -If you want it to hide when not needed, you should instead simply use - -*i3bar -c i3status* +Instead, see the i3 documentation, especially the User’s Guide. == SEE ALSO -+i3(1)+, +i3-wsbar(1)+, +dzen2(1)+, +i3status(1)+ ++i3status(1)+ or +conky(1)+ for programs generating a statusline. + ++dzen2(1)+ or +xmobar(1)+ for similar programs to i3bar. == AUTHORS From 0f3d31124dc0982ce647278b83c8f705ddb829c7 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 20 Oct 2011 23:38:34 +0100 Subject: [PATCH 22/45] docs/userguide: document the bar configuration --- docs/userguide | 168 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) diff --git a/docs/userguide b/docs/userguide index e12d8b6e..aa258f6e 100644 --- a/docs/userguide +++ b/docs/userguide @@ -756,6 +756,174 @@ workspace_auto_back_and_forth workspace_auto_back_and_forth yes --------------------------------- +== Configuring i3bar + +The bar at the bottom of your monitor is drawn by a separate process called +i3bar. Having this part of "the i3 user interface" in a separate process has +several advantages: + +1. It is a modular approach. If you don’t need a workspace bar at all, or if + you prefer a different one (dzen2, xmobar, maybe even gnome-panel?), you can + just remove the i3bar configuration and start your favorite bar instead. +2. It follows the UNIX philosophy of "Make each program do one thing well". + While i3 manages your windows well, i3bar is good at displaying a bar on + each monitor (unless you configure it otherwise). +3. It leads to two separate, clean codebases. If you want to understand i3, you + don’t need to bother with the details of i3bar and vice versa. + +That said, i3bar is configured in the same configuration file as i3. This is +because it is tightly coupled with i3 (in contrary to i3lock or i3status which +are useful for people using other window managers). Therefore, it makes no +sense to use a different configuration place when we already have a good +configuration infrastructure in place. + +Configuring your workspace bar starts with opening a +bar+ block. You can have +multiple bar blocks to use different settings for different outputs (monitors): + +*Example*: +--------------------------- +bar { + status_command i3status +} +--------------------------- + +=== Statusline command + +i3bar can run a program and display every line of its +stdout+ output on the +right hand side of the bar. This is useful to display system information like +your current IP address, battery status or date/time. + +The specified command will be passed to +sh -c+, so you can use globbing and +have to have correct quoting etc. + +*Syntax*: +---------------------- +status_command command +---------------------- + +*Example*: +------------------------------------------------- +status_command i3status --config ~/.i3status.conf +------------------------------------------------- + +=== Display mode + +You can have i3bar either be visible permanently at one edge of the screen +(+dock+ mode) or make it show up when you press your modifier key (+hide+ +mode). + +The hide mode maximizes screen space that can be used for actual windows. Also, +i3bar sends the +SIGSTOP+ and +SIGCONT+ signals to the statusline process to +save battery power. + +The default is dock mode. + +*Syntax*: +---------------- +mode +---------------- + +*Example*: +---------------- +mode hide +---------------- + +=== Position + +This option determines in which edge of the screen i3bar should show up. + +The default is bottom. + +*Syntax*: +--------------------- +position +--------------------- + +*Example*: +--------------------- +position top +--------------------- + +=== Font + +Specifies the font (again, X core font, not Xft, just like in i3) to be used in +the bar. + +*Syntax*: +--------------------- +font +--------------------- + +*Example*: +-------------------------------------------------------------- +font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 +-------------------------------------------------------------- + +=== Workspace buttons + +Specifies whether workspace buttons should be shown or not. This is useful if +you want to display a statusline-only bar containing additional information. + +The default is to show workspace buttons. + +*Syntax*: +-------------------------- +workspace_buttons +-------------------------- + +*Example*: +-------------------- +workspace_buttons no +-------------------- + +=== Colors + +As with i3, colors are in HTML hex format (#rrggbb). The following colors can +be configured at the moment: + +background:: + Background color of the bar. +statusline:: + Text color to be used for the statusline. +focused_workspace_text/focused_workspace_bg:: + Text color/background color for a workspace button when the workspace + has focus. +active_workspace_text/active_workspace_bg:: + Text color/background color for a workspace button when the workspace + is active (visible) on some output, but the focus is on another one. + You can only tell this apart from the focused workspace when you are + using multiple monitors. +inactive_workspace_text/inactive_workspace_bg:: + Text color/background color for a workspace button when the workspace + does not have focus and is not active (visible) on any output. This + will be the case for most workspaces. +urgent_workspace_text/urgent_workspace_bar:: + Text color/background color for workspaces which contain at least one + window with the urgency hint set. + +*Syntax*: +---------------------------------------- +colors { + background + statusline + + colorclass +} +---------------------------------------- + +*Example*: +-------------------------------------- +colors { + background #000000 + statusline #ffffff + + focused_workspace #ffffff #285577 + active_workspace #888888 #222222 + inactive_workspace #888888 #222222 + urgent_workspace #ffffff #900000 +} +-------------------------------------- + == List of commands Commands are what you bind to specific keypresses. You can also issue commands From 2647f47ec5533e738b57d1c4f4aff27c34fc6e25 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 20 Oct 2011 23:38:55 +0100 Subject: [PATCH 23/45] bar config: make dock mode the default --- include/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/config.h b/include/config.h index a4a274cf..bb092091 100644 --- a/include/config.h +++ b/include/config.h @@ -198,7 +198,7 @@ struct Barconfig { char *socket_path; /** Bar display mode (hide unless modifier is pressed or show in dock mode) */ - enum { M_HIDE = 0, M_DOCK = 1 } mode; + enum { M_DOCK = 0, M_HIDE = 1 } mode; /** Bar position (bottom by default). */ enum { P_BOTTOM = 0, P_TOP = 1 } position; From cf67966fa0924ff874f90c29e688811fb2ec725a Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 21 Oct 2011 18:59:59 +0100 Subject: [PATCH 24/45] i3bar: document -b in --help (Thanks mxf) --- i3bar/src/main.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index ea489941..ea84ca44 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -41,10 +41,17 @@ char *expand_path(char *path) { } void print_usage(char *elf_name) { - printf("Usage: %s [-s sock_path] [-h] [-v]\n", elf_name); + printf("Usage: %s [-b bar_id] [-s sock_path] [-h] [-v]\n", elf_name); + printf("\n"); + printf("-b \tBar ID for which to get the configuration\n"); printf("-s \tConnect to i3 via \n"); printf("-h\t\tDisplay this help-message and exit\n"); printf("-v\t\tDisplay version number and exit\n"); + printf("\n"); + printf(" PLEASE NOTE that i3bar will be automatically started by i3\n" + " as soon as there is a 'bar' configuration block in your\n" + " config file. You should never need to start it manually.\n"); + printf("\n"); } /* From bc679b0168c89fbfe71dcb6932288389649f4c5d Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 21 Oct 2011 19:01:02 +0100 Subject: [PATCH 25/45] change default config to use 'bar' blocks (Thanks mxf) --- i3.config | 4 +++- i3.config.keycodes | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/i3.config b/i3.config index 7d7fce33..9a040585 100644 --- a/i3.config +++ b/i3.config @@ -147,7 +147,9 @@ bindsym Mod1+r mode "resize" # Start i3bar to display a workspace bar (plus the system information i3status # finds out, if available) -exec i3status | i3bar -d +bar { + status_line i3status +} ####################################################################### # automatically start i3-config-wizard to offer the user to create a diff --git a/i3.config.keycodes b/i3.config.keycodes index 0f1112db..89811dbb 100644 --- a/i3.config.keycodes +++ b/i3.config.keycodes @@ -148,4 +148,6 @@ bindcode $mod+27 mode "resize" # Start i3bar to display a workspace bar (plus the system information i3status # finds out, if available) -exec i3status | i3bar -d +bar { + status_line i3status +} From 0298a32e37cc1b1ef0d92fd5c6153dddb60ddec6 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 21 Oct 2011 19:03:54 +0100 Subject: [PATCH 26/45] i3bar: makefile: prefix messages with [i3bar] --- i3bar/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/i3bar/Makefile b/i3bar/Makefile index 2a05b146..deb3ffbf 100644 --- a/i3bar/Makefile +++ b/i3bar/Makefile @@ -11,7 +11,7 @@ CPPFLAGS += -I$(TOPDIR)/include all: i3bar doc i3bar: libi3/libi3.a ${FILES} - echo "LINK" + echo "[i3bar] LINK" $(CC) $(LDFLAGS) -o $@ $(filter-out libi3/libi3.a,$^) $(LIBS) libi3/%.a: @@ -19,15 +19,15 @@ libi3/%.a: doc: echo "" - echo "SUBDIR doc" + echo "[i3bar] SUBDIR doc" $(MAKE) -C doc src/%.o: src/%.c ${HEADERS} - echo "CC $<" + echo "[i3bar] CC $<" $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< install: all - echo "INSTALL" + echo "[i3bar] INSTALL" $(INSTALL) -d -m 0755 $(DESTDIR)$(PREFIX)/bin $(INSTALL) -m 0755 i3bar $(DESTDIR)$(PREFIX)/bin From c65d13ff9f58f557569e3e2bdadcf392be8a1a90 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 21 Oct 2011 19:06:53 +0100 Subject: [PATCH 27/45] i3bar: makefile: fix dependency on libi3 --- i3bar/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3bar/Makefile b/i3bar/Makefile index deb3ffbf..753ee4d6 100644 --- a/i3bar/Makefile +++ b/i3bar/Makefile @@ -10,7 +10,7 @@ CPPFLAGS += -I$(TOPDIR)/include all: i3bar doc -i3bar: libi3/libi3.a ${FILES} +i3bar: $(TOPDIR)/libi3/libi3.a ${FILES} echo "[i3bar] LINK" $(CC) $(LDFLAGS) -o $@ $(filter-out libi3/libi3.a,$^) $(LIBS) From d71db710ddc59e9153ba655fb3af42e4b4fb8e29 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 21 Oct 2011 19:30:46 +0100 Subject: [PATCH 28/45] i3bar: use safewrappers from libi3 --- i3bar/include/common.h | 1 + i3bar/src/child.c | 8 ++++---- i3bar/src/config.c | 2 +- i3bar/src/ipc.c | 27 ++++----------------------- i3bar/src/main.c | 18 ++++-------------- i3bar/src/outputs.c | 14 +++++++------- i3bar/src/ucs2_to_utf8.c | 10 ++++------ i3bar/src/workspaces.c | 12 ++++-------- i3bar/src/xcb.c | 17 ++++++++--------- 9 files changed, 37 insertions(+), 72 deletions(-) diff --git a/i3bar/include/common.h b/i3bar/include/common.h index 74bd2152..4b0d4485 100644 --- a/i3bar/include/common.h +++ b/i3bar/include/common.h @@ -34,5 +34,6 @@ struct rect_t { #include "xcb.h" #include "ucs2_to_utf8.h" #include "config.h" +#include "libi3.h" #endif diff --git a/i3bar/src/child.c b/i3bar/src/child.c index ff1bc8bb..9ab6d23f 100644 --- a/i3bar/src/child.c +++ b/i3bar/src/child.c @@ -62,7 +62,7 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { int n = 0; int rec = 0; int buffer_len = STDIN_CHUNK_SIZE; - char *buffer = malloc(buffer_len); + char *buffer = smalloc(buffer_len); buffer[0] = '\0'; while(1) { n = read(fd, buffer + rec, buffer_len - rec); @@ -91,7 +91,7 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { if (rec == buffer_len) { buffer_len += STDIN_CHUNK_SIZE; - buffer = realloc(buffer, buffer_len); + buffer = srealloc(buffer, buffer_len); } } if (*buffer == '\0') { @@ -169,12 +169,12 @@ 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)); + stdin_io = smalloc(sizeof(ev_io)); ev_io_init(stdin_io, &stdin_io_cb, STDIN_FILENO, EV_READ); ev_io_start(main_loop, stdin_io); /* We must cleanup, if the child unexpectedly terminates */ - child_sig = malloc(sizeof(ev_child)); + child_sig = smalloc(sizeof(ev_child)); ev_child_init(child_sig, &child_sig_cb, child_pid, 0); ev_child_start(main_loop, child_sig); diff --git a/i3bar/src/config.c b/i3bar/src/config.c index 23c5e122..ad99fb9a 100644 --- a/i3bar/src/config.c +++ b/i3bar/src/config.c @@ -35,7 +35,7 @@ static int config_map_key_cb(void *params_, const unsigned char *keyVal, unsigne #endif FREE(cur_key); - cur_key = malloc(sizeof(unsigned char) * (keyLen + 1)); + cur_key = smalloc(sizeof(unsigned char) * (keyLen + 1)); strncpy(cur_key, (const char*) keyVal, keyLen); cur_key[keyLen] = '\0'; diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index db60a362..cfbc404e 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -150,11 +150,7 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { /* First we only read the header, because we know its length */ uint32_t header_len = strlen(I3_IPC_MAGIC) + sizeof(uint32_t)*2; - char *header = malloc(header_len); - if (header == NULL) { - ELOG("Could not allocate memory: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } + char *header = smalloc(header_len); /* We first parse the fixed-length IPC-header, to know, how much data * we have to expect */ @@ -191,13 +187,7 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) { /* 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) { - /* EOF received. Since i3 will restart i3bar instances as appropriate, - * we exit here. */ - DLOG("EOF received, exiting...\n"); - exit(EXIT_SUCCESS); - } + char *buffer = smalloc(size + 1); rec = 0; while (rec < size) { @@ -243,12 +233,7 @@ int i3_send_msg(uint32_t type, const char *payload) { /* 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) { - ELOG("Could not allocate memory: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - + char *buffer = smalloc(to_write); char *walk = buffer; strncpy(buffer, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)); @@ -301,11 +286,7 @@ int init_connection(const char *socket_path) { exit(EXIT_FAILURE); } - i3_connection = malloc(sizeof(ev_io)); - if (i3_connection == NULL) { - ELOG("malloc() failed: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } + i3_connection = smalloc(sizeof(ev_io)); ev_io_init(i3_connection, &got_data, sockfd, EV_READ); ev_io_start(main_loop, i3_connection); return 1; diff --git a/i3bar/src/main.c b/i3bar/src/main.c index ea84ca44..f018f2ab 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -19,7 +19,6 @@ #include #include "common.h" -#include "libi3.h" /* * Glob path, i.e. expand ~ @@ -31,11 +30,7 @@ char *expand_path(char *path) { ELOG("glob() failed\n"); exit(EXIT_FAILURE); } - char *result = strdup(globbuf.gl_pathc > 0 ? globbuf.gl_pathv[0] : path); - if (result == NULL) { - ELOG("malloc() failed: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } + char *result = sstrdup(globbuf.gl_pathc > 0 ? globbuf.gl_pathv[0] : path); globfree(&globbuf); return result; } @@ -142,14 +137,9 @@ 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 = malloc(sizeof(ev_signal)); - ev_signal *sig_int = malloc(sizeof(ev_signal)); - ev_signal *sig_hup = malloc(sizeof(ev_signal)); - - if (sig_term == NULL || sig_int == NULL || sig_hup == NULL) { - ELOG("malloc() failed: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } + ev_signal *sig_term = smalloc(sizeof(ev_signal)); + ev_signal *sig_int = smalloc(sizeof(ev_signal)); + ev_signal *sig_hup = smalloc(sizeof(ev_signal)); ev_signal_init(sig_term, &sig_cb, SIGTERM); ev_signal_init(sig_int, &sig_cb, SIGINT); diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index 11f7dc2b..98939fb4 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -115,7 +115,7 @@ static int outputs_string_cb(void *params_, const unsigned char *val, unsigned i struct outputs_json_params *params = (struct outputs_json_params*) params_; if (!strcmp(params->cur_key, "current_workspace")) { - char *copy = malloc(sizeof(const unsigned char) * (len + 1)); + char *copy = smalloc(sizeof(const unsigned char) * (len + 1)); strncpy(copy, (const char*) val, len); copy[len] = '\0'; @@ -134,7 +134,7 @@ static int outputs_string_cb(void *params_, const unsigned char *val, unsigned i return 0; } - char *name = malloc(sizeof(const unsigned char) * (len + 1)); + char *name = smalloc(sizeof(const unsigned char) * (len + 1)); strncpy(name, (const char*) val, len); name[len] = '\0'; @@ -154,16 +154,16 @@ static int outputs_start_map_cb(void *params_) { i3_output *new_output = NULL; if (params->cur_key == NULL) { - new_output = malloc(sizeof(i3_output)); + new_output = smalloc(sizeof(i3_output)); new_output->name = NULL; new_output->ws = 0, memset(&new_output->rect, 0, sizeof(rect)); new_output->bar = XCB_NONE; - new_output->workspaces = malloc(sizeof(struct ws_head)); + new_output->workspaces = smalloc(sizeof(struct ws_head)); TAILQ_INIT(new_output->workspaces); - new_output->trayclients = malloc(sizeof(struct tc_head)); + new_output->trayclients = smalloc(sizeof(struct tc_head)); TAILQ_INIT(new_output->trayclients); params->outputs_walk = new_output; @@ -208,7 +208,7 @@ static int outputs_map_key_cb(void *params_, const unsigned char *keyVal, unsign struct outputs_json_params *params = (struct outputs_json_params*) params_; FREE(params->cur_key); - params->cur_key = malloc(sizeof(unsigned char) * (keyLen + 1)); + params->cur_key = smalloc(sizeof(unsigned char) * (keyLen + 1)); strncpy(params->cur_key, (const char*) keyVal, keyLen); params->cur_key[keyLen] = '\0'; @@ -235,7 +235,7 @@ yajl_callbacks outputs_callbacks = { * */ void init_outputs() { - outputs = malloc(sizeof(struct outputs_head)); + outputs = smalloc(sizeof(struct outputs_head)); SLIST_INIT(outputs); } diff --git a/i3bar/src/ucs2_to_utf8.c b/i3bar/src/ucs2_to_utf8.c index 68984227..c07f63fd 100644 --- a/i3bar/src/ucs2_to_utf8.c +++ b/i3bar/src/ucs2_to_utf8.c @@ -14,6 +14,8 @@ #include #include +#include "libi3.h" + static iconv_t conversion_descriptor = 0; static iconv_t conversion_descriptor2 = 0; @@ -27,9 +29,7 @@ char *convert_ucs_to_utf8(char *input) { /* UTF-8 may consume up to 4 byte */ int buffer_size = 8; - char *buffer = calloc(buffer_size, 1); - if (buffer == NULL) - err(EXIT_FAILURE, "malloc() failed\n"); + char *buffer = scalloc(buffer_size); size_t output_size = buffer_size; /* We need to use an additional pointer, because iconv() modifies it */ char *output = buffer; @@ -68,9 +68,7 @@ char *convert_utf8_to_ucs2(char *input, int *real_strlen) { /* UCS-2 consumes exactly two bytes for each glyph */ int buffer_size = input_size * 2; - char *buffer = malloc(buffer_size); - if (buffer == NULL) - err(EXIT_FAILURE, "malloc() failed\n"); + char *buffer = smalloc(buffer_size); size_t output_size = buffer_size; /* We need to use an additional pointer, because iconv() modifies it */ char *output = buffer; diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index 8099cd78..c2bb886c 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -117,7 +117,7 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, unsigne if (!strcmp(params->cur_key, "name")) { /* Save the name */ - params->workspaces_walk->name = malloc(sizeof(const unsigned char) * (len + 1)); + params->workspaces_walk->name = smalloc(sizeof(const unsigned char) * (len + 1)); strncpy(params->workspaces_walk->name, (const char*) val, len); params->workspaces_walk->name[len] = '\0'; @@ -141,7 +141,7 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, unsigne if (!strcmp(params->cur_key, "output")) { /* We add the ws to the TAILQ of the output, it belongs to */ - output_name = malloc(sizeof(const unsigned char) * (len + 1)); + output_name = smalloc(sizeof(const unsigned char) * (len + 1)); strncpy(output_name, (const char*) val, len); output_name[len] = '\0'; params->workspaces_walk->output = get_output_by_name(output_name); @@ -167,7 +167,7 @@ static int workspaces_start_map_cb(void *params_) { i3_ws *new_workspace = NULL; if (params->cur_key == NULL) { - new_workspace = malloc(sizeof(i3_ws)); + new_workspace = smalloc(sizeof(i3_ws)); new_workspace->num = -1; new_workspace->name = NULL; new_workspace->visible = 0; @@ -197,11 +197,7 @@ static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, uns struct workspaces_json_params *params = (struct workspaces_json_params*) params_; FREE(params->cur_key); - params->cur_key = malloc(sizeof(unsigned char) * (keyLen + 1)); - if (params->cur_key == NULL) { - ELOG("Could not allocate memory: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } + params->cur_key = smalloc(sizeof(unsigned char) * (keyLen + 1)); strncpy(params->cur_key, (const char*) keyVal, keyLen); params->cur_key[keyLen] = '\0'; diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 471209c7..a3dba91e 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -51,8 +51,7 @@ char *strndup(const char *str, size_t n) { for (len = 0; len < n && str[len]; len++) continue; - if ((copy = malloc(len + 1)) == NULL) - return (NULL); + copy = smalloc(len + 1); memcpy(copy, str, len); copy[len] = '\0'; return (copy); @@ -516,7 +515,7 @@ static void handle_client_message(xcb_client_message_event_t* event) { values); /* send the XEMBED_EMBEDDED_NOTIFY message */ - void *event = calloc(32, 1); + void *event = scalloc(32); xcb_client_message_event_t *ev = event; ev->response_type = XCB_CLIENT_MESSAGE; ev->window = client; @@ -539,7 +538,7 @@ static void handle_client_message(xcb_client_message_event_t* event) { } else { DLOG("Not mapping dock client yet\n"); } - trayclient *tc = malloc(sizeof(trayclient)); + trayclient *tc = smalloc(sizeof(trayclient)); tc->win = client; tc->mapped = map_it; tc->xe_version = xe_version; @@ -841,9 +840,9 @@ char *init_xcb_early() { /* The various Watchers to communicate with xcb */ - xcb_io = malloc(sizeof(ev_io)); - xcb_prep = malloc(sizeof(ev_prepare)); - xcb_chk = malloc(sizeof(ev_check)); + xcb_io = smalloc(sizeof(ev_io)); + xcb_prep = smalloc(sizeof(ev_prepare)); + xcb_chk = smalloc(sizeof(ev_check)); ev_io_init(xcb_io, &xcb_io_cb, xcb_get_file_descriptor(xcb_connection), EV_READ); ev_prepare_init(xcb_prep, &xcb_prep_cb); @@ -956,7 +955,7 @@ void init_xcb_late(char *fontname) { exit(EXIT_FAILURE); } - xkb_io = malloc(sizeof(ev_io)); + xkb_io = smalloc(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); @@ -1053,7 +1052,7 @@ void init_tray() { } /* Inform clients waiting for a new _NET_SYSTEM_TRAY that we are here */ - void *event = calloc(32, 1); + void *event = scalloc(32); xcb_client_message_event_t *ev = event; ev->response_type = XCB_CLIENT_MESSAGE; ev->window = xcb_root; From 8a24be955541ff92fd5be2f90c7790009d362ea9 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 21 Oct 2011 19:47:56 +0100 Subject: [PATCH 29/45] i3bar: implement the tray_output option --- i3bar/include/config.h | 1 + i3bar/src/config.c | 5 +++-- i3bar/src/xcb.c | 14 +++++++++++--- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/i3bar/include/config.h b/i3bar/include/config.h index 19b246dc..5997b7f1 100644 --- a/i3bar/include/config.h +++ b/i3bar/include/config.h @@ -18,6 +18,7 @@ typedef struct config_t { char *bar_id; char *command; char *fontname; + char *tray_output; } config_t; config_t config; diff --git a/i3bar/src/config.c b/i3bar/src/config.c index ad99fb9a..644c623e 100644 --- a/i3bar/src/config.c +++ b/i3bar/src/config.c @@ -90,8 +90,9 @@ static int config_string_cb(void *params_, const unsigned char *val, unsigned in } if (!strcmp(cur_key, "tray_output")) { - printf("tray_output %.*s\n", len, val); - /* XXX: these are not implemented yet */ + DLOG("tray_output %.*s\n", len, val); + FREE(config.tray_output); + asprintf(&config.tray_output, "%.*s", len, val); return 1; } diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index a3dba91e..4e347f57 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -489,6 +489,9 @@ static void handle_client_message(xcb_client_message_event_t* event) { SLIST_FOREACH(walk, outputs, slist) { if (!walk->active) continue; + if (config.tray_output && + strcasecmp(walk->name, config.tray_output) != 0) + continue; DLOG("using output %s\n", walk->name); output = walk; } @@ -988,6 +991,7 @@ void init_xcb_late(char *fontname) { * */ void init_tray() { + DLOG("Initializing system tray functionality\n"); /* request the tray manager atom for the X11 display we are running on */ char atomname[strlen("_NET_SYSTEM_TRAY_S") + 11]; snprintf(atomname, strlen("_NET_SYSTEM_TRAY_S") + 11, "_NET_SYSTEM_TRAY_S%d", screen); @@ -1194,6 +1198,7 @@ void realloc_sl_buffer() { void reconfig_windows() { uint32_t mask; uint32_t values[5]; + static bool tray_configured = false; i3_output *walk; SLIST_FOREACH(walk, outputs, slist) { @@ -1207,9 +1212,6 @@ void reconfig_windows() { if (walk->bar == XCB_NONE) { DLOG("Creating Window for output %s\n", walk->name); - /* TODO: only call init_tray() if the tray is configured for this output */ - init_tray(); - 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; @@ -1353,6 +1355,12 @@ void reconfig_windows() { (!config.hide_on_modifier && xcb_request_failed(map_cookie, "Could not map window"))) { exit(EXIT_FAILURE); } + + if (!tray_configured && + strcasecmp("none", config.tray_output) != 0) { + init_tray(); + tray_configured = true; + } } else { /* We already have a bar, so we just reconfigure it */ mask = XCB_CONFIG_WINDOW_X | From 0f2642a9c9b68b06b7c8a758fee00f09ff2fc82e Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 21 Oct 2011 19:50:40 +0100 Subject: [PATCH 30/45] docs/userguide: document the tray_output bar option --- docs/userguide | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/userguide b/docs/userguide index aa258f6e..3c0c6856 100644 --- a/docs/userguide +++ b/docs/userguide @@ -844,6 +844,28 @@ position position top --------------------- +=== Tray output + +i3bar by default provides a system tray area where programs such as +NetworkManager, VLC, Pidgin, etc. can place little icons. + +You can configure on which output (monitor) the icons should be displayed or +you can turn off the functionality entirely. + +*Syntax*: +------------------------- +tray_output +------------------------- + +*Example*: +------------------------- +# disable system tray +tray_output none + +# show tray icons on the big monitor +tray_output HDMI2 +------------------------- + === Font Specifies the font (again, X core font, not Xft, just like in i3) to be used in From a3b7ba15ed5f43c28f970666261fd02aaeefece0 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 21 Oct 2011 19:59:25 +0100 Subject: [PATCH 31/45] i3bar: also use the position option when in 'hide' mode --- i3bar/include/config.h | 10 +++++----- i3bar/src/config.c | 2 +- i3bar/src/xcb.c | 12 +++++++----- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/i3bar/include/config.h b/i3bar/include/config.h index 5997b7f1..b914954c 100644 --- a/i3bar/include/config.h +++ b/i3bar/include/config.h @@ -4,14 +4,14 @@ #include "common.h" typedef enum { - DOCKPOS_NONE = 0, - DOCKPOS_TOP, - DOCKPOS_BOT -} dockpos_t; + POS_NONE = 0, + POS_TOP, + POS_BOT +} position_t; typedef struct config_t { int hide_on_modifier; - dockpos_t dockpos; + position_t position; int verbose; struct xcb_color_strings_t colors; int disable_ws; diff --git a/i3bar/src/config.c b/i3bar/src/config.c index 644c623e..caf13029 100644 --- a/i3bar/src/config.c +++ b/i3bar/src/config.c @@ -63,7 +63,7 @@ static int config_string_cb(void *params_, const unsigned char *val, unsigned in if (!strcmp(cur_key, "position")) { DLOG("position = %.*s\n", len, val); - config.dockpos = (len == 3 && !strncmp((const char*)val, "top", strlen("top")) ? DOCKPOS_TOP : DOCKPOS_BOT); + config.position = (len == 3 && !strncmp((const char*)val, "top", strlen("top")) ? POS_TOP : POS_BOT); return 1; } diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 4e347f57..a9ecc004 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -281,7 +281,9 @@ void unhide_bars() { 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; + if (config.position == POS_TOP) + values[1] = walk->rect.y; + else 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; @@ -1305,15 +1307,15 @@ void reconfig_windows() { uint32_t bottom_start_x; uint32_t bottom_end_x; } __attribute__((__packed__)) strut_partial = {0,}; - switch (config.dockpos) { - case DOCKPOS_NONE: + switch (config.position) { + case POS_NONE: break; - case DOCKPOS_TOP: + case POS_TOP: strut_partial.top = font_height + 6; strut_partial.top_start_x = walk->rect.x; strut_partial.top_end_x = walk->rect.x + walk->rect.w; break; - case DOCKPOS_BOT: + case POS_BOT: strut_partial.bottom = font_height + 6; strut_partial.bottom_start_x = walk->rect.x; strut_partial.bottom_end_x = walk->rect.x + walk->rect.w; From 6de1590e5902bb44d9f8a84eba52139ac8a308a1 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 21 Oct 2011 20:04:55 +0100 Subject: [PATCH 32/45] i3bar: spit out an error on wrong bar id --- i3bar/src/config.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/i3bar/src/config.c b/i3bar/src/config.c index caf13029..179bc464 100644 --- a/i3bar/src/config.c +++ b/i3bar/src/config.c @@ -42,6 +42,22 @@ static int config_map_key_cb(void *params_, const unsigned char *keyVal, unsigne return 1; } +/* + * Parse a null-value (current_workspace) + * + */ +static int config_null_cb(void *params_) { + if (!strcmp(cur_key, "id")) { + /* If 'id' is NULL, the bar config was not found. Error out. */ + ELOG("No such bar config. Use 'i3-msg -t get_bar_config' to get the available configs.\n"); + ELOG("Are you starting i3bar by hand? You should not:\n"); + ELOG("Configure a 'bar' block in your i3 config and i3 will launch i3bar automatically.\n"); + exit(EXIT_FAILURE); + } + + return 1; +} + /* * Parse a string * @@ -143,7 +159,7 @@ static int config_boolean_cb(void *params_, int val) { /* A datastructure to pass all these callbacks to yajl */ static yajl_callbacks outputs_callbacks = { - NULL, + &config_null_cb, &config_boolean_cb, NULL, NULL, From 15f021b4fc8097a2870e56008db423dac9f430a1 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 21 Oct 2011 22:17:41 +0100 Subject: [PATCH 33/45] i3bar: Implement the output option --- i3bar/include/config.h | 2 ++ i3bar/src/config.c | 7 +++++-- i3bar/src/outputs.c | 35 +++++++++++++++++++++++++++++++++-- i3bar/src/workspaces.c | 11 +++++++---- 4 files changed, 47 insertions(+), 8 deletions(-) diff --git a/i3bar/include/config.h b/i3bar/include/config.h index b914954c..c5fc218c 100644 --- a/i3bar/include/config.h +++ b/i3bar/include/config.h @@ -19,6 +19,8 @@ typedef struct config_t { char *command; char *fontname; char *tray_output; + int num_outputs; + char **outputs; } config_t; config_t config; diff --git a/i3bar/src/config.c b/i3bar/src/config.c index 179bc464..9e4552ed 100644 --- a/i3bar/src/config.c +++ b/i3bar/src/config.c @@ -100,8 +100,11 @@ static int config_string_cb(void *params_, const unsigned char *val, unsigned in } if (!strcmp(cur_key, "outputs")) { - printf("+output %.*s\n", len, val); - /* XXX: these are not implemented yet */ + DLOG("+output %.*s\n", len, val); + int new_num_outputs = config.num_outputs + 1; + config.outputs = srealloc(config.outputs, sizeof(char*) * new_num_outputs); + asprintf(&config.outputs[config.num_outputs], "%.*s", len, val); + config.num_outputs = new_num_outputs; return 1; } diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index 98939fb4..6278974f 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -26,7 +26,7 @@ struct outputs_json_params { i3_output *outputs_walk; char *cur_key; char *json; - bool init; + bool in_rect; }; /* @@ -171,6 +171,10 @@ static int outputs_start_map_cb(void *params_) { return 1; } + if (!strcmp(params->cur_key, "rect")) { + params->in_rect = true; + } + return 1; } @@ -180,7 +184,33 @@ static int outputs_start_map_cb(void *params_) { */ static int outputs_end_map_cb(void *params_) { struct outputs_json_params *params = (struct outputs_json_params*) params_; - /* FIXME: What is at the end of a rect? */ + if (params->in_rect) { + params->in_rect = false; + /* Ignore the end of a rect */ + return 1; + } + + /* See if we actually handle that output */ + if (config.num_outputs > 0) { + bool handle_output = false; + for (int c = 0; c < config.num_outputs; c++) { + if (strcasecmp(params->outputs_walk->name, config.outputs[c]) != 0) + continue; + + handle_output = true; + break; + } + if (!handle_output) { + DLOG("Ignoring output \"%s\", not configured to handle it.\n", + params->outputs_walk->name); + FREE(params->outputs_walk->name); + FREE(params->outputs_walk->workspaces); + FREE(params->outputs_walk->trayclients); + FREE(params->outputs_walk); + FREE(params->cur_key); + return 1; + } + } i3_output *target = get_output_by_name(params->outputs_walk->name); @@ -249,6 +279,7 @@ void parse_outputs_json(char *json) { params.outputs_walk = NULL; params.cur_key = NULL; params.json = json; + params.in_rect = false; yajl_handle handle; yajl_status state; diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index c2bb886c..bb00f0ba 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -144,11 +144,14 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, unsigne output_name = smalloc(sizeof(const unsigned char) * (len + 1)); strncpy(output_name, (const char*) val, len); output_name[len] = '\0'; - params->workspaces_walk->output = get_output_by_name(output_name); + i3_output *target = get_output_by_name(output_name); + if (target) { + params->workspaces_walk->output = target; - TAILQ_INSERT_TAIL(params->workspaces_walk->output->workspaces, - params->workspaces_walk, - tailq); + TAILQ_INSERT_TAIL(params->workspaces_walk->output->workspaces, + params->workspaces_walk, + tailq); + } FREE(output_name); return 1; From 202b216c1408db58a7e6916112c6bba30f8dcc6c Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 21 Oct 2011 22:22:02 +0100 Subject: [PATCH 34/45] docs/userguide: document the output bar option --- docs/userguide | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/docs/userguide b/docs/userguide index 3c0c6856..135c6bae 100644 --- a/docs/userguide +++ b/docs/userguide @@ -547,7 +547,7 @@ exec_always command *Examples*: -------------------------------- -exec i3status | i3bar -d +exec chromium exec_always ~/my_script.sh -------------------------------- @@ -844,6 +844,36 @@ position position top --------------------- +=== Output(s) + +You can restrict i3bar to one or more outputs (monitors). The default is to +handle all outputs. Restricting the outputs is useful for using different +options for different outputs by using multiple 'bar' blocks. + +*Syntax*: +--------------- +output +--------------- + +*Example*: +------------------------------- +# big monitor: everything +bar { + output HDMI2 + status_command i3status +} + +# laptop monitor: bright colors and i3status with less modules. +bar { + output LVDS1 + status_command i3status --config ~/.i3status-small.conf + colors { + background #000000 + statusline #ffffff + } +} +------------------------------- + === Tray output i3bar by default provides a system tray area where programs such as From 3baeeb1834e95de9dcf77c82fd3eedd58a569c0f Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 21 Oct 2011 22:58:53 +0100 Subject: [PATCH 35/45] Bugfix: properly transition in and out of the COLOR_COND state (Thanks fernandotcl) --- src/cfgparse.l | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/cfgparse.l b/src/cfgparse.l index 88e6ad2c..50fbc6ca 100644 --- a/src/cfgparse.l +++ b/src/cfgparse.l @@ -138,7 +138,7 @@ EOL (\r?\n) [^\n]+ { yy_pop_state(); yylval.string = sstrdup(yytext); return STR; } [a-zA-Z0-9_-]+ { yy_pop_state(); yylval.string = sstrdup(yytext); return OUTPUT; } ^[ \t]*#[^\n]* { return TOKCOMMENT; } -[0-9a-fA-F]+ { yylval.string = sstrdup(yytext); return HEX; } +[0-9a-fA-F]+ { yy_pop_state(); yylval.string = sstrdup(yytext); return HEX; } [ \t]*→[ \t]* { BEGIN(WANT_STRING); } [ \t]+ { BEGIN(WANT_STRING); } [0-9]+ { yylval.number = atoi(yytext); return NUMBER; } @@ -196,14 +196,14 @@ cols { /* yylval.number = STACK_LIMIT_COLS; */return rows { /* yylval.number = STACK_LIMIT_ROWS; */return TOKSTACKLIMIT; } exec { WS_STRING; return TOKEXEC; } exec_always { WS_STRING; return TOKEXEC_ALWAYS; } -client.background { BEGIN(COLOR_COND); yylval.single_color = &config.client.background; return TOKSINGLECOLOR; } -client.focused { BEGIN(COLOR_COND); yylval.color = &config.client.focused; return TOKCOLOR; } -client.focused_inactive { BEGIN(COLOR_COND); yylval.color = &config.client.focused_inactive; return TOKCOLOR; } -client.unfocused { BEGIN(COLOR_COND); yylval.color = &config.client.unfocused; return TOKCOLOR; } -client.urgent { BEGIN(COLOR_COND); yylval.color = &config.client.urgent; return TOKCOLOR; } -bar.focused { BEGIN(COLOR_COND); yylval.color = &config.bar.focused; return TOKCOLOR; } -bar.unfocused { BEGIN(COLOR_COND); yylval.color = &config.bar.unfocused; return TOKCOLOR; } -bar.urgent { BEGIN(COLOR_COND); yylval.color = &config.bar.urgent; return TOKCOLOR; } +client.background { yy_push_state(COLOR_COND); yylval.single_color = &config.client.background; return TOKSINGLECOLOR; } +client.focused { yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yylval.color = &config.client.focused; return TOKCOLOR; } +client.focused_inactive { yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yylval.color = &config.client.focused_inactive; return TOKCOLOR; } +client.unfocused { yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yylval.color = &config.client.unfocused; return TOKCOLOR; } +client.urgent { yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yylval.color = &config.client.urgent; return TOKCOLOR; } +bar.focused { yy_push_state(COLOR_COND); yylval.color = &config.bar.focused; return TOKCOLOR; } +bar.unfocused { yy_push_state(COLOR_COND); yylval.color = &config.bar.unfocused; return TOKCOLOR; } +bar.urgent { yy_push_state(COLOR_COND); yylval.color = &config.bar.urgent; return TOKCOLOR; } Mod1 { yylval.number = BIND_MOD1; return MODIFIER; } Mod2 { yylval.number = BIND_MOD2; return MODIFIER; } Mod3 { yylval.number = BIND_MOD3; return MODIFIER; } @@ -227,8 +227,8 @@ title { yy_push_state(WANT_QSTRING); return TOK_TITLE; context->line_number++; yy_push_state(BUFFER_LINE); } -[ \t]+ { BEGIN(WANT_STRING); } -[ \t]+ { BEGIN(WANT_STRING); } +[ \t]+ { yy_pop_state(); yy_push_state(WANT_STRING); } +[ \t]+ { yy_pop_state(); yy_push_state(WANT_STRING); } [ \t]+ { /* ignore whitespace */ ; } \"[^\"]+\" { /* if ASSIGN_COND then */ From 3a99c914e01720c43ffaecea13b0f8ed7c8c2928 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 21 Oct 2011 23:00:38 +0100 Subject: [PATCH 36/45] tests: default bar mode changed --- testcases/t/177-bar-config.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testcases/t/177-bar-config.t b/testcases/t/177-bar-config.t index 761dbf21..371f26f5 100644 --- a/testcases/t/177-bar-config.t +++ b/testcases/t/177-bar-config.t @@ -51,7 +51,7 @@ my $bar_config = $i3->get_bar_config($bar_id)->recv; is($bar_config->{status_command}, 'i3status --foo', 'status_command correct'); ok(!$bar_config->{verbose}, 'verbose off by default'); ok($bar_config->{workspace_buttons}, 'workspace buttons enabled per default'); -is($bar_config->{mode}, 'hide', 'hide mode by default'); +is($bar_config->{mode}, 'dock', 'dock mode by default'); is($bar_config->{position}, 'bottom', 'position bottom by default'); ##################################################################### From 77961ad9c84ade490da8d79578be764a4e77053c Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 21 Oct 2011 23:09:57 +0100 Subject: [PATCH 37/45] =?UTF-8?q?cfgparse:=20Don=E2=80=99t=20use=20asprint?= =?UTF-8?q?f=20when=20parsing=20hex=20colors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cfgparse.l | 2 +- src/cfgparse.y | 11 +++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/cfgparse.l b/src/cfgparse.l index 50fbc6ca..39e1d398 100644 --- a/src/cfgparse.l +++ b/src/cfgparse.l @@ -138,7 +138,7 @@ EOL (\r?\n) [^\n]+ { yy_pop_state(); yylval.string = sstrdup(yytext); return STR; } [a-zA-Z0-9_-]+ { yy_pop_state(); yylval.string = sstrdup(yytext); return OUTPUT; } ^[ \t]*#[^\n]* { return TOKCOMMENT; } -[0-9a-fA-F]+ { yy_pop_state(); yylval.string = sstrdup(yytext); return HEX; } +#[0-9a-fA-F]+ { yy_pop_state(); yylval.string = sstrdup(yytext+1); return HEXCOLOR; } [ \t]*→[ \t]* { BEGIN(WANT_STRING); } [ \t]+ { BEGIN(WANT_STRING); } [0-9]+ { yylval.number = atoi(yytext); return NUMBER; } diff --git a/src/cfgparse.y b/src/cfgparse.y index c9e1eb98..bc4928f6 100644 --- a/src/cfgparse.y +++ b/src/cfgparse.y @@ -590,7 +590,6 @@ void parse_file(const char *f) { %token WORD "" %token STR "" %token STR_NG "" -%token HEX "" %token HEXCOLOR "#" %token OUTPUT "" %token TOKBINDCODE @@ -1506,14 +1505,10 @@ color: ; colorpixel: - '#' HEX + HEXCOLOR { - char *hex; - if (asprintf(&hex, "#%s", $2) == -1) - die("asprintf()"); - free($2); - $$ = get_colorpixel(hex); - free(hex); + $$ = get_colorpixel($1); + free($1); } ; From 014c3e4b95b574e3b290889c29bd537432553056 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 21 Oct 2011 23:15:15 +0100 Subject: [PATCH 38/45] =?UTF-8?q?i3bar:=20Bugfix:=20Don=E2=80=99t=20crash?= =?UTF-8?q?=20when=20tray=5Foutput=20is=20not=20set=20(Thanks=20fernandotc?= =?UTF-8?q?l)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 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 a9ecc004..fa3860e8 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -1359,7 +1359,8 @@ void reconfig_windows() { } if (!tray_configured && - strcasecmp("none", config.tray_output) != 0) { + (!config.tray_output || + strcasecmp("none", config.tray_output) != 0)) { init_tray(); tray_configured = true; } From 9b84348201d2720e24712683d7030e781020be09 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 21 Oct 2011 23:22:48 +0100 Subject: [PATCH 39/45] Bugfix: fix off by one when copying the hex colorcode (Thanks fernandotcl) --- src/cfgparse.l | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cfgparse.l b/src/cfgparse.l index 39e1d398..cd936ac5 100644 --- a/src/cfgparse.l +++ b/src/cfgparse.l @@ -138,7 +138,7 @@ EOL (\r?\n) [^\n]+ { yy_pop_state(); yylval.string = sstrdup(yytext); return STR; } [a-zA-Z0-9_-]+ { yy_pop_state(); yylval.string = sstrdup(yytext); return OUTPUT; } ^[ \t]*#[^\n]* { return TOKCOMMENT; } -#[0-9a-fA-F]+ { yy_pop_state(); yylval.string = sstrdup(yytext+1); return HEXCOLOR; } +#[0-9a-fA-F]+ { yy_pop_state(); yylval.string = sstrdup(yytext); return HEXCOLOR; } [ \t]*→[ \t]* { BEGIN(WANT_STRING); } [ \t]+ { BEGIN(WANT_STRING); } [0-9]+ { yylval.number = atoi(yytext); return NUMBER; } From 3ee8bd502d246699e764f0c6d50abbadcd4a7e93 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sat, 22 Oct 2011 12:34:06 +0100 Subject: [PATCH 40/45] i3bar: change default colors to fit the i3 look & feel The new default looks like this (like in docs/userguide): colors { background #000000 statusline #ffffff focused_workspace #ffffff #285577 active_workspace #888888 #222222 inactive_workspace #888888 #222222 urgent_workspace #ffffff #900000 } If you want to go back to the previous colors, use: colors { background #000000 statusline #ffffff focused_workspace #ffffff #480000 active_workspace #ffffff #480000 inactive_workspace #ffffff #240000 urgent_workspace #ffffff #002400 } --- i3bar/src/xcb.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index fa3860e8..e9cc6ea1 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -311,14 +311,14 @@ void init_colors(const struct xcb_color_strings_t *new_colors) { } 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(active_ws_fg, "888888"); + PARSE_COLOR(active_ws_bg, "222222"); + PARSE_COLOR(inactive_ws_fg, "888888"); + PARSE_COLOR(inactive_ws_bg, "222222"); PARSE_COLOR(urgent_ws_fg, "FFFFFF"); - PARSE_COLOR(urgent_ws_bg, "002400"); + PARSE_COLOR(urgent_ws_bg, "900000"); PARSE_COLOR(focus_ws_fg, "FFFFFF"); - PARSE_COLOR(focus_ws_bg, "480000"); + PARSE_COLOR(focus_ws_bg, "285577"); #undef PARSE_COLOR } From bc2c63d4ede01b2fab626f160dd66e3beac3265f Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sat, 22 Oct 2011 15:00:31 +0100 Subject: [PATCH 41/45] i3bar: change default font to the i3 default one --- i3bar/src/xcb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index e9cc6ea1..b5b79ae2 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -897,10 +897,8 @@ char *init_xcb_early() { */ void init_xcb_late(char *fontname) { 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"; + /* XXX: font fallback to 'misc' like i3 does it would be good. */ + fontname = "-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1"; } /* We load and allocate the font */ From 95c2e86db962205b3960e3ca3988e1ba1090a952 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sat, 22 Oct 2011 15:08:24 +0100 Subject: [PATCH 42/45] =?UTF-8?q?i3bar:=20delete=20include/queue.h,=20use?= =?UTF-8?q?=20i3=E2=80=99s=20copy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- i3bar/include/queue.h | 527 ------------------------------------------ 1 file changed, 527 deletions(-) delete mode 100644 i3bar/include/queue.h diff --git a/i3bar/include/queue.h b/i3bar/include/queue.h deleted file mode 100644 index 75bb957a..00000000 --- a/i3bar/include/queue.h +++ /dev/null @@ -1,527 +0,0 @@ -/* $OpenBSD: queue.h,v 1.1 2007/10/26 03:14:08 niallo Exp $ */ -/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ - -/* - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)queue.h 8.5 (Berkeley) 8/20/94 - */ - -#ifndef _SYS_QUEUE_H_ -#define _SYS_QUEUE_H_ - -/* - * This file defines five types of data structures: singly-linked lists, - * lists, simple queues, tail queues, and circular queues. - * - * - * A singly-linked list is headed by a single forward pointer. The elements - * are singly linked for minimum space and pointer manipulation overhead at - * the expense of O(n) removal for arbitrary elements. New elements can be - * added to the list after an existing element or at the head of the list. - * Elements being removed from the head of the list should use the explicit - * macro for this purpose for optimum efficiency. A singly-linked list may - * only be traversed in the forward direction. Singly-linked lists are ideal - * for applications with large datasets and few or no removals or for - * implementing a LIFO queue. - * - * A list is headed by a single forward pointer (or an array of forward - * pointers for a hash table header). The elements are doubly linked - * so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before - * or after an existing element or at the head of the list. A list - * may only be traversed in the forward direction. - * - * A simple queue is headed by a pair of pointers, one the head of the - * list and the other to the tail of the list. The elements are singly - * linked to save space, so elements can only be removed from the - * head of the list. New elements can be added to the list before or after - * an existing element, at the head of the list, or at the end of the - * list. A simple queue may only be traversed in the forward direction. - * - * A tail queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or - * after an existing element, at the head of the list, or at the end of - * the list. A tail queue may be traversed in either direction. - * - * A circle queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or after - * an existing element, at the head of the list, or at the end of the list. - * A circle queue may be traversed in either direction, but has a more - * complex end of list detection. - * - * For details on the use of these macros, see the queue(3) manual page. - */ - -#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) -#define _Q_INVALIDATE(a) (a) = ((void *)-1) -#else -#define _Q_INVALIDATE(a) -#endif - -/* - * Singly-linked List definitions. - */ -#define SLIST_HEAD(name, type) \ -struct name { \ - struct type *slh_first; /* first element */ \ -} - -#define SLIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define SLIST_ENTRY(type) \ -struct { \ - struct type *sle_next; /* next element */ \ -} - -/* - * Singly-linked List access methods. - */ -#define SLIST_FIRST(head) ((head)->slh_first) -#define SLIST_END(head) NULL -#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) -#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) - -#define SLIST_FOREACH(var, head, field) \ - for((var) = SLIST_FIRST(head); \ - (var) != SLIST_END(head); \ - (var) = SLIST_NEXT(var, field)) - -#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ - for ((varp) = &SLIST_FIRST((head)); \ - ((var) = *(varp)) != SLIST_END(head); \ - (varp) = &SLIST_NEXT((var), field)) - -/* - * Singly-linked List functions. - */ -#define SLIST_INIT(head) { \ - SLIST_FIRST(head) = SLIST_END(head); \ -} - -#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ - (elm)->field.sle_next = (slistelm)->field.sle_next; \ - (slistelm)->field.sle_next = (elm); \ -} while (0) - -#define SLIST_INSERT_HEAD(head, elm, field) do { \ - (elm)->field.sle_next = (head)->slh_first; \ - (head)->slh_first = (elm); \ -} while (0) - -#define SLIST_REMOVE_NEXT(head, elm, field) do { \ - (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ -} while (0) - -#define SLIST_REMOVE_HEAD(head, field) do { \ - (head)->slh_first = (head)->slh_first->field.sle_next; \ -} while (0) - -#define SLIST_REMOVE(head, elm, type, field) do { \ - if ((head)->slh_first == (elm)) { \ - SLIST_REMOVE_HEAD((head), field); \ - } else { \ - struct type *curelm = (head)->slh_first; \ - \ - while (curelm->field.sle_next != (elm)) \ - curelm = curelm->field.sle_next; \ - curelm->field.sle_next = \ - curelm->field.sle_next->field.sle_next; \ - _Q_INVALIDATE((elm)->field.sle_next); \ - } \ -} while (0) - -/* - * List definitions. - */ -#define LIST_HEAD(name, type) \ -struct name { \ - struct type *lh_first; /* first element */ \ -} - -#define LIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define LIST_ENTRY(type) \ -struct { \ - struct type *le_next; /* next element */ \ - struct type **le_prev; /* address of previous next element */ \ -} - -/* - * List access methods - */ -#define LIST_FIRST(head) ((head)->lh_first) -#define LIST_END(head) NULL -#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) -#define LIST_NEXT(elm, field) ((elm)->field.le_next) - -#define LIST_FOREACH(var, head, field) \ - for((var) = LIST_FIRST(head); \ - (var)!= LIST_END(head); \ - (var) = LIST_NEXT(var, field)) - -/* - * List functions. - */ -#define LIST_INIT(head) do { \ - LIST_FIRST(head) = LIST_END(head); \ -} while (0) - -#define LIST_INSERT_AFTER(listelm, elm, field) do { \ - if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ - (listelm)->field.le_next->field.le_prev = \ - &(elm)->field.le_next; \ - (listelm)->field.le_next = (elm); \ - (elm)->field.le_prev = &(listelm)->field.le_next; \ -} while (0) - -#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ - (elm)->field.le_prev = (listelm)->field.le_prev; \ - (elm)->field.le_next = (listelm); \ - *(listelm)->field.le_prev = (elm); \ - (listelm)->field.le_prev = &(elm)->field.le_next; \ -} while (0) - -#define LIST_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.le_next = (head)->lh_first) != NULL) \ - (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ - (head)->lh_first = (elm); \ - (elm)->field.le_prev = &(head)->lh_first; \ -} while (0) - -#define LIST_REMOVE(elm, field) do { \ - if ((elm)->field.le_next != NULL) \ - (elm)->field.le_next->field.le_prev = \ - (elm)->field.le_prev; \ - *(elm)->field.le_prev = (elm)->field.le_next; \ - _Q_INVALIDATE((elm)->field.le_prev); \ - _Q_INVALIDATE((elm)->field.le_next); \ -} while (0) - -#define LIST_REPLACE(elm, elm2, field) do { \ - if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ - (elm2)->field.le_next->field.le_prev = \ - &(elm2)->field.le_next; \ - (elm2)->field.le_prev = (elm)->field.le_prev; \ - *(elm2)->field.le_prev = (elm2); \ - _Q_INVALIDATE((elm)->field.le_prev); \ - _Q_INVALIDATE((elm)->field.le_next); \ -} while (0) - -/* - * Simple queue definitions. - */ -#define SIMPLEQ_HEAD(name, type) \ -struct name { \ - struct type *sqh_first; /* first element */ \ - struct type **sqh_last; /* addr of last next element */ \ -} - -#define SIMPLEQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).sqh_first } - -#define SIMPLEQ_ENTRY(type) \ -struct { \ - struct type *sqe_next; /* next element */ \ -} - -/* - * Simple queue access methods. - */ -#define SIMPLEQ_FIRST(head) ((head)->sqh_first) -#define SIMPLEQ_END(head) NULL -#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) -#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) - -#define SIMPLEQ_FOREACH(var, head, field) \ - for((var) = SIMPLEQ_FIRST(head); \ - (var) != SIMPLEQ_END(head); \ - (var) = SIMPLEQ_NEXT(var, field)) - -/* - * Simple queue functions. - */ -#define SIMPLEQ_INIT(head) do { \ - (head)->sqh_first = NULL; \ - (head)->sqh_last = &(head)->sqh_first; \ -} while (0) - -#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ - (head)->sqh_last = &(elm)->field.sqe_next; \ - (head)->sqh_first = (elm); \ -} while (0) - -#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.sqe_next = NULL; \ - *(head)->sqh_last = (elm); \ - (head)->sqh_last = &(elm)->field.sqe_next; \ -} while (0) - -#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ - if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ - (head)->sqh_last = &(elm)->field.sqe_next; \ - (listelm)->field.sqe_next = (elm); \ -} while (0) - -#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ - if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ - (head)->sqh_last = &(head)->sqh_first; \ -} while (0) - -/* - * Tail queue definitions. - */ -#define TAILQ_HEAD(name, type) \ -struct name { \ - struct type *tqh_first; /* first element */ \ - struct type **tqh_last; /* addr of last next element */ \ -} - -#define TAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).tqh_first } - -#define TAILQ_ENTRY(type) \ -struct { \ - struct type *tqe_next; /* next element */ \ - struct type **tqe_prev; /* address of previous next element */ \ -} - -/* - * tail queue access methods - */ -#define TAILQ_FIRST(head) ((head)->tqh_first) -#define TAILQ_END(head) NULL -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) -#define TAILQ_LAST(head, headname) \ - (*(((struct headname *)((head)->tqh_last))->tqh_last)) -/* XXX */ -#define TAILQ_PREV(elm, headname, field) \ - (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) -#define TAILQ_EMPTY(head) \ - (TAILQ_FIRST(head) == TAILQ_END(head)) - -#define TAILQ_FOREACH(var, head, field) \ - for((var) = TAILQ_FIRST(head); \ - (var) != TAILQ_END(head); \ - (var) = TAILQ_NEXT(var, field)) - -#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ - for((var) = TAILQ_LAST(head, headname); \ - (var) != TAILQ_END(head); \ - (var) = TAILQ_PREV(var, headname, field)) - -/* - * Tail queue functions. - */ -#define TAILQ_INIT(head) do { \ - (head)->tqh_first = NULL; \ - (head)->tqh_last = &(head)->tqh_first; \ -} while (0) - -#define TAILQ_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ - (head)->tqh_first->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (head)->tqh_first = (elm); \ - (elm)->field.tqe_prev = &(head)->tqh_first; \ -} while (0) - -#define TAILQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.tqe_next = NULL; \ - (elm)->field.tqe_prev = (head)->tqh_last; \ - *(head)->tqh_last = (elm); \ - (head)->tqh_last = &(elm)->field.tqe_next; \ -} while (0) - -#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ - if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ - (elm)->field.tqe_next->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (listelm)->field.tqe_next = (elm); \ - (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ -} while (0) - -#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ - (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ - (elm)->field.tqe_next = (listelm); \ - *(listelm)->field.tqe_prev = (elm); \ - (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ -} while (0) - -#define TAILQ_REMOVE(head, elm, field) do { \ - if (((elm)->field.tqe_next) != NULL) \ - (elm)->field.tqe_next->field.tqe_prev = \ - (elm)->field.tqe_prev; \ - else \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ - _Q_INVALIDATE((elm)->field.tqe_prev); \ - _Q_INVALIDATE((elm)->field.tqe_next); \ -} while (0) - -#define TAILQ_REPLACE(head, elm, elm2, field) do { \ - if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ - (elm2)->field.tqe_next->field.tqe_prev = \ - &(elm2)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm2)->field.tqe_next; \ - (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ - *(elm2)->field.tqe_prev = (elm2); \ - _Q_INVALIDATE((elm)->field.tqe_prev); \ - _Q_INVALIDATE((elm)->field.tqe_next); \ -} while (0) - -/* - * Circular queue definitions. - */ -#define CIRCLEQ_HEAD(name, type) \ -struct name { \ - struct type *cqh_first; /* first element */ \ - struct type *cqh_last; /* last element */ \ -} - -#define CIRCLEQ_HEAD_INITIALIZER(head) \ - { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } - -#define CIRCLEQ_ENTRY(type) \ -struct { \ - struct type *cqe_next; /* next element */ \ - struct type *cqe_prev; /* previous element */ \ -} - -/* - * Circular queue access methods - */ -#define CIRCLEQ_FIRST(head) ((head)->cqh_first) -#define CIRCLEQ_LAST(head) ((head)->cqh_last) -#define CIRCLEQ_END(head) ((void *)(head)) -#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) -#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) -#define CIRCLEQ_EMPTY(head) \ - (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) - -#define CIRCLEQ_FOREACH(var, head, field) \ - for((var) = CIRCLEQ_FIRST(head); \ - (var) != CIRCLEQ_END(head); \ - (var) = CIRCLEQ_NEXT(var, field)) - -#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ - for((var) = CIRCLEQ_LAST(head); \ - (var) != CIRCLEQ_END(head); \ - (var) = CIRCLEQ_PREV(var, field)) - -/* - * Circular queue functions. - */ -#define CIRCLEQ_INIT(head) do { \ - (head)->cqh_first = CIRCLEQ_END(head); \ - (head)->cqh_last = CIRCLEQ_END(head); \ -} while (0) - -#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ - (elm)->field.cqe_next = (listelm)->field.cqe_next; \ - (elm)->field.cqe_prev = (listelm); \ - if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ - (head)->cqh_last = (elm); \ - else \ - (listelm)->field.cqe_next->field.cqe_prev = (elm); \ - (listelm)->field.cqe_next = (elm); \ -} while (0) - -#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ - (elm)->field.cqe_next = (listelm); \ - (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ - if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ - (head)->cqh_first = (elm); \ - else \ - (listelm)->field.cqe_prev->field.cqe_next = (elm); \ - (listelm)->field.cqe_prev = (elm); \ -} while (0) - -#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ - (elm)->field.cqe_next = (head)->cqh_first; \ - (elm)->field.cqe_prev = CIRCLEQ_END(head); \ - if ((head)->cqh_last == CIRCLEQ_END(head)) \ - (head)->cqh_last = (elm); \ - else \ - (head)->cqh_first->field.cqe_prev = (elm); \ - (head)->cqh_first = (elm); \ -} while (0) - -#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.cqe_next = CIRCLEQ_END(head); \ - (elm)->field.cqe_prev = (head)->cqh_last; \ - if ((head)->cqh_first == CIRCLEQ_END(head)) \ - (head)->cqh_first = (elm); \ - else \ - (head)->cqh_last->field.cqe_next = (elm); \ - (head)->cqh_last = (elm); \ -} while (0) - -#define CIRCLEQ_REMOVE(head, elm, field) do { \ - if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ - (head)->cqh_last = (elm)->field.cqe_prev; \ - else \ - (elm)->field.cqe_next->field.cqe_prev = \ - (elm)->field.cqe_prev; \ - if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ - (head)->cqh_first = (elm)->field.cqe_next; \ - else \ - (elm)->field.cqe_prev->field.cqe_next = \ - (elm)->field.cqe_next; \ - _Q_INVALIDATE((elm)->field.cqe_prev); \ - _Q_INVALIDATE((elm)->field.cqe_next); \ -} while (0) - -#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ - if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ - CIRCLEQ_END(head)) \ - (head)->cqh_last = (elm2); \ - else \ - (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ - if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ - CIRCLEQ_END(head)) \ - (head)->cqh_first = (elm2); \ - else \ - (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ - _Q_INVALIDATE((elm)->field.cqe_prev); \ - _Q_INVALIDATE((elm)->field.cqe_next); \ -} while (0) - -#endif /* !_SYS_QUEUE_H_ */ From 409dcf44dbe86cce190eea1918d2036bd017d0bb Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sat, 22 Oct 2011 15:24:18 +0100 Subject: [PATCH 43/45] i3-migrate-config-to-v4: generate a bar {} block instead of exec i3bar --- i3-migrate-config-to-v4 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/i3-migrate-config-to-v4 b/i3-migrate-config-to-v4 index 4dd4418f..4f4d0134 100755 --- a/i3-migrate-config-to-v4 +++ b/i3-migrate-config-to-v4 @@ -358,6 +358,8 @@ sub convert_command { # add an i3bar invocation automatically if no 'workspace_bar no' was found if ($workspace_bar) { print "\n"; - print "# XXX: Automatically added a call to i3bar to provide a workspace bar\n"; - print "exec i3status | i3bar -d\n"; + print "# XXX: Automatically added a bar configuration\n"; + print "bar {\n"; + print " status_command i3status\n"; + print "}\n"; } From d7eba46de5c75734b07f417e9dc997d36b927fa5 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sat, 22 Oct 2011 16:16:06 +0100 Subject: [PATCH 44/45] i3-nagbar: Implement -t warning, makes colors yellow(ish) --- i3-nagbar/main.c | 57 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/i3-nagbar/main.c b/i3-nagbar/main.c index d0d7e77a..a1b473ae 100644 --- a/i3-nagbar/main.c +++ b/i3-nagbar/main.c @@ -45,6 +45,14 @@ static int font_height; static char *prompt = "Please do not run this program."; static button_t *buttons; static int buttoncnt; + +/* Result of get_colorpixel() for the various colors. */ +static uint32_t color_background; /* background of the bar */ +static uint32_t color_button_background; /* background for buttons */ +static uint32_t color_border; /* color of the button border */ +static uint32_t color_border_bottom; /* color of the bottom border */ +static uint32_t color_text; /* color of the text */ + xcb_window_t root; /* @@ -118,16 +126,14 @@ static void handle_button_release(xcb_connection_t *conn, xcb_button_release_eve * */ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) { - printf("expose!\n"); - /* re-draw the background */ - xcb_change_gc_single(conn, pixmap_gc, XCB_GC_FOREGROUND, get_colorpixel(conn, "#900000")); + xcb_change_gc_single(conn, pixmap_gc, XCB_GC_FOREGROUND, color_background); xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &rect); /* restore font color */ uint32_t values[3]; - values[0] = get_colorpixel(conn, "#FFFFFF"); - values[1] = get_colorpixel(conn, "#900000"); + values[0] = color_text; + values[1] = color_background; xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND | XCB_GC_BACKGROUND, values); xcb_image_text_8(conn, strlen(prompt), pixmap, pixmap_gc, 4 + 4/* X */, font_height + 2 + 4 /* Y = baseline of font */, prompt); @@ -136,14 +142,14 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) { int line_width = 4; int w = 20; int y = rect.width; - values[0] = get_colorpixel(conn, "#680a0a"); + values[0] = color_button_background; values[1] = line_width; xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND | XCB_GC_LINE_WIDTH, values); xcb_rectangle_t close = { y - w - (2 * line_width), 0, w + (2 * line_width), rect.height }; xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &close); - xcb_change_gc_single(conn, pixmap_gc, XCB_GC_FOREGROUND, get_colorpixel(conn, "#d92424")); + xcb_change_gc_single(conn, pixmap_gc, XCB_GC_FOREGROUND, color_border); xcb_point_t points[] = { { y - w - (2 * line_width), line_width / 2 }, { y - (line_width / 2), line_width / 2 }, @@ -153,8 +159,8 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) { }; xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, pixmap, pixmap_gc, 5, points); - values[0] = get_colorpixel(conn, "#ffffff"); - values[1] = get_colorpixel(conn, "#680a0a"); + values[0] = color_text; + values[1] = color_button_background; values[2] = 1; xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_LINE_WIDTH, values); xcb_image_text_8(conn, strlen("x"), pixmap, pixmap_gc, y - w - line_width + (w / 2) - 4/* X */, @@ -169,11 +175,11 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) { /* TODO: make w = text extents of the label */ w = 90; y -= 30; - xcb_change_gc_single(conn, pixmap_gc, XCB_GC_FOREGROUND, get_colorpixel(conn, "#680a0a")); + xcb_change_gc_single(conn, pixmap_gc, XCB_GC_FOREGROUND, color_button_background); close = (xcb_rectangle_t){ y - w - (2 * line_width), 2, w + (2 * line_width), rect.height - 6 }; xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &close); - xcb_change_gc_single(conn, pixmap_gc, XCB_GC_FOREGROUND, get_colorpixel(conn, "#d92424")); + xcb_change_gc_single(conn, pixmap_gc, XCB_GC_FOREGROUND, color_border); buttons[c].x = y - w - (2 * line_width); buttons[c].width = w; xcb_point_t points2[] = { @@ -185,8 +191,8 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) { }; xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, pixmap, pixmap_gc, 5, points2); - values[0] = get_colorpixel(conn, "#ffffff"); - values[1] = get_colorpixel(conn, "#680a0a"); + values[0] = color_text; + values[1] = color_button_background; xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND | XCB_GC_BACKGROUND, values); xcb_image_text_8(conn, strlen(buttons[c].label), pixmap, pixmap_gc, y - w - line_width + 6/* X */, font_height + 2 + 3/* Y = baseline of font */, buttons[c].label); @@ -196,7 +202,7 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) { /* border line at the bottom */ line_width = 2; - values[0] = get_colorpixel(conn, "#470909"); + values[0] = color_border_bottom; values[1] = line_width; xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND | XCB_GC_LINE_WIDTH, values); xcb_point_t bottom[] = { @@ -216,6 +222,7 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) { int main(int argc, char *argv[]) { char *pattern = "-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1"; int o, option_index = 0; + enum { TYPE_ERROR = 0, TYPE_WARNING = 1 } bar_type = TYPE_ERROR; static struct option long_options[] = { {"version", no_argument, 0, 'v'}, @@ -223,10 +230,11 @@ int main(int argc, char *argv[]) { {"button", required_argument, 0, 'b'}, {"help", no_argument, 0, 'h'}, {"message", no_argument, 0, 'm'}, + {"type", required_argument, 0, 't'}, {0, 0, 0, 0} }; - char *options_string = "b:f:m:vh"; + char *options_string = "b:f:m:t:vh"; while ((o = getopt_long(argc, argv, options_string, long_options, &option_index)) != -1) { switch (o) { @@ -240,6 +248,9 @@ int main(int argc, char *argv[]) { case 'm': prompt = strdup(optarg); break; + case 't': + bar_type = (strcasecmp(optarg, "warning") == 0 ? TYPE_WARNING : TYPE_ERROR); + break; case 'h': printf("i3-nagbar " I3_VERSION "\n"); printf("i3-nagbar [-m ] [-b