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.
This commit is contained in:
parent
15bface10d
commit
a5be27cb79
|
@ -13,10 +13,25 @@ typedef struct config_t {
|
||||||
int hide_on_modifier;
|
int hide_on_modifier;
|
||||||
dockpos_t dockpos;
|
dockpos_t dockpos;
|
||||||
int verbose;
|
int verbose;
|
||||||
xcb_colors_t *colors;
|
struct xcb_color_strings_t colors;
|
||||||
int disable_ws;
|
int disable_ws;
|
||||||
|
char *bar_id;
|
||||||
|
char *command;
|
||||||
|
char *fontname;
|
||||||
} config_t;
|
} config_t;
|
||||||
|
|
||||||
config_t config;
|
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
|
#endif
|
||||||
|
|
|
@ -40,10 +40,18 @@ struct xcb_color_strings_t {
|
||||||
typedef struct xcb_colors_t xcb_colors_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
|
* Initialize the colors
|
||||||
|
|
|
@ -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 <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <i3/ipc.h>
|
||||||
|
#include <yajl/yajl_parse.h>
|
||||||
|
#include <yajl/yajl_version.h>
|
||||||
|
|
||||||
|
#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
|
||||||
|
}
|
||||||
|
|
|
@ -114,12 +114,47 @@ void got_output_reply(char *reply) {
|
||||||
reconfig_windows();
|
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 */
|
/* Data-structure to easily call the reply-handlers later */
|
||||||
handler_t reply_handlers[] = {
|
handler_t reply_handlers[] = {
|
||||||
&got_command_reply,
|
&got_command_reply,
|
||||||
&got_workspace_reply,
|
&got_workspace_reply,
|
||||||
&got_subscribe_reply,
|
&got_subscribe_reply,
|
||||||
&got_output_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;
|
type ^= 1 << 31;
|
||||||
event_handlers[type](buffer);
|
event_handlers[type](buffer);
|
||||||
} else {
|
} else {
|
||||||
reply_handlers[type](buffer);
|
if (reply_handlers[type])
|
||||||
|
reply_handlers[type](buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
FREE(header);
|
FREE(header);
|
||||||
|
|
188
i3bar/src/main.c
188
i3bar/src/main.c
|
@ -19,6 +19,7 @@
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "libi3.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Glob path, i.e. expand ~
|
* Glob path, i.e. expand ~
|
||||||
|
@ -39,61 +40,11 @@ char *expand_path(char *path) {
|
||||||
return result;
|
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) {
|
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 <sock_path>\tConnect to i3 via <sock_path>\n");
|
printf("-s <sock_path>\tConnect to i3 via <sock_path>\n");
|
||||||
printf("-c <command>\tExecute <command> to get stdin\n");
|
|
||||||
printf("-m\t\tHide the bars, when mod4 is not pressed.\n");
|
|
||||||
printf("-d[<pos>]\tEnable dockmode. <pos> 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 <font>\tUse X-Core-Font <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("-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 opt;
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
char *socket_path = getenv("I3SOCK");
|
char *socket_path = getenv("I3SOCK");
|
||||||
char *command = NULL;
|
|
||||||
char *fontname = NULL;
|
|
||||||
char *i3_default_sock_path = "/tmp/i3-ipc.sock";
|
char *i3_default_sock_path = "/tmp/i3-ipc.sock";
|
||||||
struct xcb_color_strings_t colors = { NULL, };
|
|
||||||
|
|
||||||
/* Definition of the standard-config */
|
/* Initialize the standard config to use 0 as default */
|
||||||
config.hide_on_modifier = 0;
|
memset(&config, '\0', sizeof(config_t));
|
||||||
config.dockpos = DOCKPOS_NONE;
|
|
||||||
config.disable_ws = 0;
|
|
||||||
|
|
||||||
static struct option long_opt[] = {
|
static struct option long_opt[] = {
|
||||||
{ "socket", required_argument, 0, 's' },
|
{ "socket", required_argument, 0, 's' },
|
||||||
{ "command", required_argument, 0, 'c' },
|
{ "bar_id", required_argument, 0, 0 },
|
||||||
{ "hide", no_argument, 0, 'm' },
|
|
||||||
{ "dock", optional_argument, 0, 'd' },
|
|
||||||
{ "font", required_argument, 0, 'f' },
|
|
||||||
{ "nows", no_argument, 0, 'w' },
|
|
||||||
{ "help", no_argument, 0, 'h' },
|
{ "help", no_argument, 0, 'h' },
|
||||||
{ "version", no_argument, 0, 'v' },
|
{ "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}
|
{ 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) {
|
switch (opt) {
|
||||||
case 's':
|
case 's':
|
||||||
socket_path = expand_path(optarg);
|
socket_path = expand_path(optarg);
|
||||||
break;
|
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':
|
case 'v':
|
||||||
printf("i3bar version " I3_VERSION " © 2010-2011 Axel Wagner and contributors\n");
|
printf("i3bar version " I3_VERSION " © 2010-2011 Axel Wagner and contributors\n");
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
break;
|
break;
|
||||||
case 'V':
|
case 0:
|
||||||
config.verbose = 1;
|
if (!strcmp(long_opt[option_index].name, "bar_id")) {
|
||||||
break;
|
FREE(config.bar_id);
|
||||||
case 'A':
|
config.bar_id = sstrdup(optarg);
|
||||||
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);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
print_usage(argv[0]);
|
print_usage(argv[0]);
|
||||||
|
@ -229,26 +106,16 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fontname == NULL) {
|
if (!config.bar_id) {
|
||||||
/* This is a very restrictive default. More sensefull would be something like
|
/* TODO: maybe we want -f which will automatically ask i3 for the first
|
||||||
* "-misc-*-*-*-*--*-*-*-*-*-*-*-*". But since that produces very ugly results
|
* configured bar (and error out if there are too many)? */
|
||||||
* on my machine, let's stick with this until we have a configfile */
|
ELOG("No bar_id passed. Please let i3 start i3bar or specify --bar_id\n");
|
||||||
fontname = "-misc-fixed-medium-r-semicondensed--12-110-75-75-c-60-iso10646-1";
|
exit(EXIT_FAILURE);
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main_loop = ev_default_loop(0);
|
main_loop = ev_default_loop(0);
|
||||||
|
|
||||||
init_colors(&colors);
|
char *atom_sock_path = init_xcb_early();
|
||||||
char *atom_sock_path = init_xcb(fontname);
|
|
||||||
|
|
||||||
if (socket_path == NULL) {
|
if (socket_path == NULL) {
|
||||||
socket_path = atom_sock_path;
|
socket_path = atom_sock_path;
|
||||||
|
@ -259,27 +126,12 @@ int main(int argc, char **argv) {
|
||||||
socket_path = expand_path(i3_default_sock_path);
|
socket_path = expand_path(i3_default_sock_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
free_colors(&colors);
|
|
||||||
|
|
||||||
init_outputs();
|
init_outputs();
|
||||||
if (init_connection(socket_path)) {
|
if (init_connection(socket_path)) {
|
||||||
/* We subscribe to the i3-events we need */
|
/* Request the bar configuration. When it arrives, we fill the config array. */
|
||||||
subscribe_events();
|
i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_BAR_CONFIG, config.bar_id);
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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 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
|
* We only need those watchers on the stack, so putting them on the stack saves us
|
||||||
* some calls to free() */
|
* some calls to free() */
|
||||||
|
|
159
i3bar/src/xcb.c
159
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 */
|
/* FIXME: xcb_connect leaks Memory */
|
||||||
xcb_connection = xcb_connect(NULL, &screen);
|
xcb_connection = xcb_connect(NULL, &screen);
|
||||||
if (xcb_connection_has_error(xcb_connection)) {
|
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_screen = xcb_setup_roots_iterator(xcb_get_setup(xcb_connection)).data;
|
||||||
xcb_root = xcb_screen->root;
|
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
|
/* 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 */
|
* this way, we can choose to crop it */
|
||||||
uint32_t mask = XCB_GC_FOREGROUND;
|
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);
|
statusline_clear = xcb_generate_id(xcb_connection);
|
||||||
xcb_void_cookie_t clear_ctx_cookie = xcb_create_gc_checked(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,
|
mask,
|
||||||
vals);
|
vals);
|
||||||
|
|
||||||
mask |= XCB_GC_BACKGROUND | XCB_GC_FONT;
|
mask |= XCB_GC_BACKGROUND;
|
||||||
vals[0] = colors.bar_fg;
|
vals[0] = colors.bar_fg;
|
||||||
statusline_ctx = xcb_generate_id(xcb_connection);
|
statusline_ctx = xcb_generate_id(xcb_connection);
|
||||||
xcb_void_cookie_t sl_ctx_cookie = xcb_create_gc_checked(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 */
|
/* Now we save the font-infos */
|
||||||
font_info = xcb_query_font_reply(xcb_connection,
|
font_info = xcb_query_font_reply(xcb_connection,
|
||||||
query_font_cookie,
|
query_font_cookie,
|
||||||
|
@ -949,14 +980,6 @@ char *init_xcb(char *fontname) {
|
||||||
}
|
}
|
||||||
|
|
||||||
DLOG("Calculated Font-height: %d\n", font_height);
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue