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:
committed by
Michael Stapelberg
parent
f0eba6d15c
commit
e3913093b6
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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\" ]");
|
||||
}
|
||||
}
|
||||
|
107
i3bar/src/xcb.c
107
i3bar/src/xcb.c
@ -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();
|
||||
}
|
||||
|
Reference in New Issue
Block a user