introduced i3 command for changing the hidden state and the mode of i3bar

The hidden_state and mode of each i3bar instance can now be controlled from within i3.
Therefore, two new i3 command were introduced:
    _
    bar hidden_state show|hide|toggle [<bar_id>]

    show: always show the bar
    hide: normal hide mode
    toggle: toggle between show and hide (individually for each bar)
    _
    bar mode dock|hide|invisible|toggle [<bar_id>]

    hide,dock: like before
    invisible: always keep the bar hidden
    toggle: toggle between dock and hide (individually for each bar)

This patch introduces a hidden_state ("hidden_state hide|show") in the
barconfig, which indicates the current hidden_state of each i3bar
instance. It only affects the bar when in hide mode. Additionally, a new
invisible mode was introduced. In order to change the hidden_state or
mode of the bar from i3, a barconfig-update event was introduced, for
which a bar can subscribe and the bar then gets notified about the
currently set hidden_state and mode in its barconfig.

For convenience, an id field ("id <bar_id>") was added to the barconfig, where one can
set the desired id for the corresponding bar. If the id is not specified, i3 will
deterministically choose an id; otherwise, with the previous random approach for finding
a new id, which is actually not shared with i3bar, as it would determine its id on
startup, the event-subscription would be destroyed on reload. Still, this issue remains
when manually changing the bar_id in the config and then reloading.

fixes #833, #651
This commit is contained in:
haptix@web.de
2013-05-25 14:30:00 +02:00
committed by Michael Stapelberg
parent f0eba6d15c
commit e3913093b6
18 changed files with 470 additions and 58 deletions

View File

@ -73,7 +73,15 @@ static int config_string_cb(void *params_, const unsigned char *val, unsigned in
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")));
config.hide_on_modifier = (len == 4 && !strncmp((const char*)val, "dock", strlen("dock")) ? M_DOCK
: (len == 4 && !strncmp((const char*)val, "hide", strlen("hide")) ? M_HIDE
: M_INVISIBLE));
return 1;
}
if (!strcmp(cur_key, "hidden_state")) {
DLOG("hidden_state = %.*s, len = %d\n", len, val, len);
config.hidden_state = (len == 4 && !strncmp((const char*)val, "hide", strlen("hide")) ? S_HIDE : S_SHOW);
return 1;
}

View File

@ -149,12 +149,37 @@ void got_mode_event(char *event) {
draw_bars(false);
}
/*
* Called, when a barconfig_update event arrives (i.e. i3 changed the bar hidden_state or mode)
*
*/
void got_bar_config_update(char *event) {
/* check whether this affect this bar instance by checking the bar_id */
char *expected_id;
sasprintf(&expected_id, "\"id\":\"%s\"", config.bar_id);
char *found_id = strstr(event, expected_id);
FREE(expected_id);
if (found_id == NULL)
return;
/* Data-structure to easily call the reply-handlers later */
/* update the configuration with the received settings */
DLOG("Received bar config update \"%s\"\n", event);
int old_mode = config.hide_on_modifier;
parse_config_json(event);
if (old_mode != config.hide_on_modifier) {
reconfig_windows();
}
draw_bars(false);
}
/* Data-structure to easily call the event-handlers later */
handler_t event_handlers[] = {
&got_workspace_event,
&got_output_event,
&got_mode_event
&got_mode_event,
NULL,
&got_bar_config_update,
};
/*
@ -310,8 +335,8 @@ void destroy_connection(void) {
*/
void subscribe_events(void) {
if (config.disable_ws) {
i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"output\", \"mode\" ]");
i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"output\", \"mode\", \"barconfig_update\" ]");
} else {
i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"workspace\", \"output\", \"mode\" ]");
i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"workspace\", \"output\", \"mode\", \"barconfig_update\" ]");
}
}

View File

@ -198,7 +198,7 @@ void refresh_statusline(void) {
*
*/
void hide_bars(void) {
if (!config.hide_on_modifier) {
if ((config.hide_on_modifier == M_DOCK) || (config.hidden_state == S_SHOW)) {
return;
}
@ -217,7 +217,7 @@ void hide_bars(void) {
*
*/
void unhide_bars(void) {
if (!config.hide_on_modifier) {
if (config.hide_on_modifier != M_HIDE) {
return;
}
@ -988,25 +988,13 @@ char *init_xcb_early() {
}
/*
* Initialization which depends on 'config' being usable. Called after the
* configuration has arrived.
* Register for xkb keyevents. 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.
*
*/
void init_xcb_late(char *fontname) {
if (fontname == NULL)
fontname = "-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1";
/* Load the font */
font = load_font(fontname, true);
set_font(&font);
DLOG("Calculated Font-height: %d\n", font.height);
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) {
void register_xkb_keyevents() {
if (xkb_dpy == NULL) {
int xkb_major, xkb_minor, xkb_errbase, xkb_err;
xkb_major = XkbMajorVersion;
xkb_minor = XkbMinorVersion;
@ -1046,6 +1034,39 @@ void init_xcb_late(char *fontname) {
}
}
/*
* Deregister from xkb keyevents.
*
*/
void deregister_xkb_keyevents() {
if (xkb_dpy != NULL) {
ev_io_stop (main_loop, xkb_io);
close(xkb_io->fd);
FREE(xkb_io);
FREE(xkb_dpy);
}
}
/*
* Initialization which depends on 'config' being usable. Called after the
* configuration has arrived.
*
*/
void init_xcb_late(char *fontname) {
if (fontname == NULL)
fontname = "-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1";
/* Load the font */
font = load_font(fontname, true);
set_font(&font);
DLOG("Calculated Font-height: %d\n", font.height);
xcb_flush(xcb_connection);
if (config.hide_on_modifier == M_HIDE)
register_xkb_keyevents();
}
/*
* Inform clients waiting for a new _NET_SYSTEM_TRAY that we took the
* selection.
@ -1368,8 +1389,8 @@ void reconfig_windows(void) {
mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK;
/* Black background */
values[0] = colors.bar_bg;
/* If hide_on_modifier is set, i3 is not supposed to manage our bar-windows */
values[1] = config.hide_on_modifier;
/* If hide_on_modifier is set to hide or invisible mode, i3 is not supposed to manage our bar-windows */
values[1] = (config.hide_on_modifier == M_DOCK ? 0 : 1);
/* We enable the following EventMask fields:
* EXPOSURE, to get expose events (we have to re-draw then)
* SUBSTRUCTURE_REDIRECT, to get ConfigureRequests when the tray
@ -1490,7 +1511,7 @@ void reconfig_windows(void) {
/* We finally map the bar (display it on screen), unless the modifier-switch is on */
xcb_void_cookie_t map_cookie;
if (!config.hide_on_modifier) {
if (config.hide_on_modifier == M_DOCK) {
map_cookie = xcb_map_window_checked(xcb_connection, walk->bar);
}
@ -1501,7 +1522,7 @@ void reconfig_windows(void) {
xcb_request_failed(name_cookie, "Could not set WM_NAME") ||
xcb_request_failed(strut_cookie, "Could not set strut") ||
xcb_request_failed(gc_cookie, "Could not create graphical context") ||
(!config.hide_on_modifier && xcb_request_failed(map_cookie, "Could not map window"))) {
((config.hide_on_modifier == M_DOCK) && xcb_request_failed(map_cookie, "Could not map window"))) {
exit(EXIT_FAILURE);
}
@ -1533,6 +1554,14 @@ void reconfig_windows(void) {
mask,
values);
mask = XCB_CW_OVERRIDE_REDIRECT;
values[0] = (config.hide_on_modifier == M_DOCK ? 0 : 1);
DLOG("Changing Window attribute override_redirect for output %s to %d\n", walk->name, values[0]);
xcb_void_cookie_t chg_cookie = xcb_change_window_attributes(xcb_connection,
walk->bar,
mask,
values);
DLOG("Recreating buffer for output %s\n", walk->name);
xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection,
root_screen->root_depth,
@ -1541,10 +1570,27 @@ void reconfig_windows(void) {
walk->rect.w,
walk->rect.h);
if (xcb_request_failed(cfg_cookie, "Could not reconfigure window")) {
exit(EXIT_FAILURE);
/* Unmap the window, and draw it again when in dock mode */
xcb_void_cookie_t umap_cookie = xcb_unmap_window_checked(xcb_connection, walk->bar);
xcb_void_cookie_t map_cookie;
if (config.hide_on_modifier == M_DOCK) {
cont_child();
map_cookie = xcb_map_window_checked(xcb_connection, walk->bar);
}
if (xcb_request_failed(pm_cookie, "Could not create pixmap")) {
if (config.hide_on_modifier == M_HIDE) {
/* Switching to hide mode, register for keyevents */
register_xkb_keyevents();
} else {
/* Switching to dock/invisible mode, deregister from keyevents */
deregister_xkb_keyevents();
}
if (xcb_request_failed(cfg_cookie, "Could not reconfigure window") ||
xcb_request_failed(chg_cookie, "Could not change window") ||
xcb_request_failed(pm_cookie, "Could not create pixmap") ||
xcb_request_failed(umap_cookie, "Could not unmap window") ||
((config.hide_on_modifier == M_DOCK) && xcb_request_failed(map_cookie, "Could not map window"))) {
exit(EXIT_FAILURE);
}
}
@ -1718,11 +1764,14 @@ void draw_bars(bool unhide) {
i = 1;
}
/* Assure the bar is hidden/unhidden according to the specified hidden_state and mode */
bool should_unhide = (config.hidden_state == S_SHOW || (unhide && config.hidden_state == S_HIDE));
bool should_hide = (config.hide_on_modifier == M_INVISIBLE);
if (!mod_pressed) {
if (unhide) {
/* The urgent-hint should get noticed, so we unhide the bars shortly */
if ((unhide || should_unhide) && !should_hide) {
unhide_bars();
} else if (walks_away) {
} else if (walks_away || should_hide) {
FREE(last_urgent_ws);
hide_bars();
}