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;
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
|
188
i3bar/src/main.c
188
i3bar/src/main.c
|
@ -19,6 +19,7 @@
|
|||
#include <glob.h>
|
||||
|
||||
#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 <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("-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() */
|
||||
|
|
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 */
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue