/* The font we'll use */
static i3Font font;
+/* Overall height of the bar (based on font size) */
+int bar_height;
+
/* These are only relevant for XKB, which we only need for grabbing modifiers */
Display *xkb_dpy;
int xkb_event_base;
*
*/
void hide_bars(void) {
- if (!config.hide_on_modifier) {
+ if ((config.hide_on_modifier == M_DOCK) || (config.hidden_state == S_SHOW && config.hide_on_modifier == M_HIDE)) {
return;
}
*
*/
void unhide_bars(void) {
- if (!config.hide_on_modifier) {
+ if (config.hide_on_modifier != M_HIDE) {
return;
}
values[0] = walk->rect.x;
if (config.position == POS_TOP)
values[1] = walk->rect.y;
- else values[1] = walk->rect.y + walk->rect.h - font.height - 6;
+ else values[1] = walk->rect.y + walk->rect.h - bar_height;
values[2] = walk->rect.w;
- values[3] = font.height + 6;
+ values[3] = bar_height;
values[4] = XCB_STACK_MODE_ABOVE;
DLOG("Reconfiguring Window for output %s to %d,%d\n", walk->name, values[0], values[1]);
cookie = xcb_configure_window_checked(xcb_connection,
/* Now we get the atoms and save them in a nice data structure */
get_atoms();
- xcb_get_property_cookie_t path_cookie;
- path_cookie = xcb_get_property_unchecked(xcb_connection,
- 0,
- xcb_root,
- atoms[I3_SOCKET_PATH],
- XCB_GET_PROPERTY_TYPE_ANY,
- 0, PATH_MAX);
-
- /* We check, if i3 set its socket-path */
- xcb_get_property_reply_t *path_reply = xcb_get_property_reply(xcb_connection,
- path_cookie,
- NULL);
- char *path = NULL;
- if (path_reply) {
- int len = xcb_get_property_value_length(path_reply);
- if (len != 0) {
- path = strndup(xcb_get_property_value(path_reply), len);
- }
- }
-
+ char *path = root_atom_contents("I3_SOCKET_PATH", xcb_connection, screen);
if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer") ||
xcb_request_failed(clear_ctx_cookie, "Could not allocate statusline-buffer-clearcontext") ||
}
/*
- * 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;
}
}
+/*
+ * Deregister from xkb keyevents.
+ *
+ */
+void deregister_xkb_keyevents() {
+ if (xkb_dpy != NULL) {
+ ev_io_stop (main_loop, xkb_io);
+ XCloseDisplay(xkb_dpy);
+ close(xkb_io->fd);
+ FREE(xkb_io);
+ xkb_dpy = NULL;
+ }
+}
+
+/*
+ * 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);
+ bar_height = font.height + 6;
+
+ 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.
statusline_pm,
xcb_root,
MAX(root_screen->width_in_pixels, statusline_width),
- root_screen->height_in_pixels);
+ bar_height);
uint32_t mask = XCB_GC_FOREGROUND;
uint32_t vals[2] = { colors.bar_bg, colors.bar_bg };
* Reconfigure all bars and create new bars for recently activated outputs
*
*/
-void reconfig_windows(void) {
+void reconfig_windows(bool redraw_bars) {
uint32_t mask;
uint32_t values[5];
static bool tray_configured = false;
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
root_screen->root_depth,
walk->bar,
xcb_root,
- walk->rect.x, walk->rect.y + walk->rect.h - font.height - 6,
- walk->rect.w, font.height + 6,
+ walk->rect.x, walk->rect.y + walk->rect.h - bar_height,
+ walk->rect.w, bar_height,
0,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
root_screen->root_visual,
walk->buffer,
walk->bar,
walk->rect.w,
- walk->rect.h);
+ bar_height);
/* Set the WM_CLASS and WM_NAME (we don't need UTF-8) atoms */
xcb_void_cookie_t class_cookie;
case POS_NONE:
break;
case POS_TOP:
- strut_partial.top = font.height + 6;
+ strut_partial.top = bar_height;
strut_partial.top_start_x = walk->rect.x;
strut_partial.top_end_x = walk->rect.x + walk->rect.w;
break;
case POS_BOT:
- strut_partial.bottom = font.height + 6;
+ strut_partial.bottom = bar_height;
strut_partial.bottom_start_x = walk->rect.x;
strut_partial.bottom_end_x = walk->rect.x + walk->rect.w;
break;
/* 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);
}
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);
}
- if (!tray_configured &&
- (!config.tray_output ||
- strcasecmp("none", config.tray_output) != 0)) {
- init_tray();
+ const char *tray_output = (config.tray_output ? config.tray_output : SLIST_FIRST(outputs)->name);
+ if (!tray_configured && strcasecmp(tray_output, "none") != 0) {
+ /* Configuration sanity check: ensure this i3bar instance handles the output on
+ * which the tray should appear (e.g. don’t initialize a tray if tray_output ==
+ * VGA-1 but output == [HDMI-1]).
+ */
+ i3_output *output;
+ SLIST_FOREACH(output, outputs, slist) {
+ if (strcasecmp(output->name, tray_output) == 0 ||
+ (strcasecmp(tray_output, "primary") == 0 && output->primary)) {
+ init_tray();
+ break;
+ }
+ }
tray_configured = true;
}
} else {
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;
+ values[1] = walk->rect.y + walk->rect.h - bar_height;
values[2] = walk->rect.w;
- values[3] = font.height + 6;
+ values[3] = bar_height;
values[4] = XCB_STACK_MODE_ABOVE;
DLOG("Destroying buffer for output %s\n", walk->name);
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,
walk->buffer,
walk->bar,
walk->rect.w,
- walk->rect.h);
+ bar_height);
+
+ xcb_void_cookie_t map_cookie, umap_cookie;
+ if (redraw_bars) {
+ /* Unmap the window, and draw it again when in dock mode */
+ umap_cookie = xcb_unmap_window_checked(xcb_connection, walk->bar);
+ if (config.hide_on_modifier == M_DOCK) {
+ cont_child();
+ map_cookie = xcb_map_window_checked(xcb_connection, walk->bar);
+ } else {
+ stop_child();
+ }
- if (xcb_request_failed(cfg_cookie, "Could not reconfigure window")) {
- exit(EXIT_FAILURE);
+ 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(pm_cookie, "Could not create pixmap")) {
+
+ 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") ||
+ (redraw_bars && (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);
}
}
*/
void draw_bars(bool unhide) {
DLOG("Drawing Bars...\n");
- int i = 1;
+ int i = 0;
refresh_statusline();
- static char *last_urgent_ws = NULL;
- bool walks_away = true;
-
i3_output *outputs_walk;
SLIST_FOREACH(outputs_walk, outputs, slist) {
if (!outputs_walk->active) {
}
if (outputs_walk->bar == XCB_NONE) {
/* Oh shit, an active output without an own bar. Create it now! */
- reconfig_windows();
+ reconfig_windows(false);
}
/* First things first: clear the backbuffer */
uint32_t color = colors.bar_bg;
outputs_walk->bargc,
XCB_GC_FOREGROUND,
&color);
- xcb_rectangle_t rect = { 0, 0, outputs_walk->rect.w, font.height + 6 };
+ xcb_rectangle_t rect = { 0, 0, outputs_walk->rect.w, bar_height };
xcb_poly_fill_rectangle(xcb_connection,
outputs_walk->buffer,
outputs_walk->bargc,
MIN(outputs_walk->rect.w - traypx - 4, statusline_width), font.height + 2);
}
- if (config.disable_ws) {
- continue;
- }
-
- i3_ws *ws_walk;
-
- TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) {
- DLOG("Drawing Button for WS %s at x = %d, len = %d\n", i3string_as_utf8(ws_walk->name), i, ws_walk->name_width);
- uint32_t fg_color = colors.inactive_ws_fg;
- uint32_t bg_color = colors.inactive_ws_bg;
- uint32_t border_color = colors.inactive_ws_border;
- if (ws_walk->visible) {
- if (!ws_walk->focused) {
- fg_color = colors.active_ws_fg;
- bg_color = colors.active_ws_bg;
- border_color = colors.active_ws_border;
- } else {
- fg_color = colors.focus_ws_fg;
- bg_color = colors.focus_ws_bg;
- border_color = colors.focus_ws_border;
- if (last_urgent_ws && strcmp(i3string_as_utf8(ws_walk->name), last_urgent_ws) == 0)
- walks_away = false;
+ if (!config.disable_ws) {
+ i3_ws *ws_walk;
+ TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) {
+ DLOG("Drawing Button for WS %s at x = %d, len = %d\n",
+ i3string_as_utf8(ws_walk->name), i, ws_walk->name_width);
+ uint32_t fg_color = colors.inactive_ws_fg;
+ uint32_t bg_color = colors.inactive_ws_bg;
+ uint32_t border_color = colors.inactive_ws_border;
+ if (ws_walk->visible) {
+ if (!ws_walk->focused) {
+ fg_color = colors.active_ws_fg;
+ bg_color = colors.active_ws_bg;
+ border_color = colors.active_ws_border;
+ } else {
+ fg_color = colors.focus_ws_fg;
+ bg_color = colors.focus_ws_bg;
+ border_color = colors.focus_ws_border;
+ }
}
- }
- if (ws_walk->urgent) {
- DLOG("WS %s is urgent!\n", i3string_as_utf8(ws_walk->name));
- fg_color = colors.urgent_ws_fg;
- bg_color = colors.urgent_ws_bg;
- border_color = colors.urgent_ws_border;
- unhide = true;
- if (!ws_walk->focused) {
- FREE(last_urgent_ws);
- last_urgent_ws = sstrdup(i3string_as_utf8(ws_walk->name));
+ if (ws_walk->urgent) {
+ DLOG("WS %s is urgent!\n", i3string_as_utf8(ws_walk->name));
+ fg_color = colors.urgent_ws_fg;
+ bg_color = colors.urgent_ws_bg;
+ border_color = colors.urgent_ws_border;
+ unhide = true;
}
- }
- uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
- uint32_t vals_border[] = { border_color, border_color };
- xcb_change_gc(xcb_connection,
- outputs_walk->bargc,
- mask,
- vals_border);
- xcb_rectangle_t rect_border = { i, 1, ws_walk->name_width + 10, font.height + 4 };
- xcb_poly_fill_rectangle(xcb_connection,
- outputs_walk->buffer,
- outputs_walk->bargc,
- 1,
- &rect_border);
- uint32_t vals[] = { bg_color, bg_color };
- xcb_change_gc(xcb_connection,
- outputs_walk->bargc,
- mask,
- vals);
- xcb_rectangle_t rect = { i + 1, 2, ws_walk->name_width + 8, font.height + 2 };
- xcb_poly_fill_rectangle(xcb_connection,
- outputs_walk->buffer,
- outputs_walk->bargc,
- 1,
- &rect);
- set_font_colors(outputs_walk->bargc, fg_color, bg_color);
- draw_text(ws_walk->name, outputs_walk->buffer, outputs_walk->bargc, i + 5, 3, ws_walk->name_width);
- i += 10 + ws_walk->name_width + 1;
+ uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
+ uint32_t vals_border[] = { border_color, border_color };
+ xcb_change_gc(xcb_connection,
+ outputs_walk->bargc,
+ mask,
+ vals_border);
+ xcb_rectangle_t rect_border = { i, 1, ws_walk->name_width + 10, font.height + 4 };
+ xcb_poly_fill_rectangle(xcb_connection,
+ outputs_walk->buffer,
+ outputs_walk->bargc,
+ 1,
+ &rect_border);
+ uint32_t vals[] = { bg_color, bg_color };
+ xcb_change_gc(xcb_connection,
+ outputs_walk->bargc,
+ mask,
+ vals);
+ xcb_rectangle_t rect = { i + 1, 2, ws_walk->name_width + 8, font.height + 2 };
+ xcb_poly_fill_rectangle(xcb_connection,
+ outputs_walk->buffer,
+ outputs_walk->bargc,
+ 1,
+ &rect);
+ set_font_colors(outputs_walk->bargc, fg_color, bg_color);
+ draw_text(ws_walk->name, outputs_walk->buffer, outputs_walk->bargc,
+ i + 5, 3, ws_walk->name_width);
+ i += 10 + ws_walk->name_width + 1;
+ }
}
- if (binding.name) {
-
+ if (binding.name && !config.disable_binding_mode_indicator) {
uint32_t fg_color = colors.urgent_ws_fg;
uint32_t bg_color = colors.urgent_ws_bg;
uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
i = 0;
}
- if (!mod_pressed) {
- if (unhide) {
- /* The urgent-hint should get noticed, so we unhide the bars shortly */
- unhide_bars();
- } else if (walks_away) {
- FREE(last_urgent_ws);
- hide_bars();
- }
+ /* Assure the bar is hidden/unhidden according to the specified hidden_state and mode */
+ if (mod_pressed ||
+ config.hidden_state == S_SHOW ||
+ unhide) {
+ unhide_bars();
+ } else if (config.hide_on_modifier == M_HIDE) {
+ hide_bars();
}
redraw_bars();