* vim:ts=4:sw=4:expandtab
*
* i3bar - an xcb-based status- and ws-bar for i3
- * © 2010-2012 Axel Wagner and contributors (see also: LICENSE)
+ * © 2010 Axel Wagner and contributors (see also: LICENSE)
*
* xcb.c: Communicating with X
*
/* The font we'll use */
static i3Font font;
+/* Icon size (based on font size) */
+int icon_size;
+
/* Overall height of the bar (based on font size) */
int bar_height;
-/* Cached width of the custom separator if one was set */
-int separator_symbol_width;
-
/* These are only relevant for XKB, which we only need for grabbing modifiers */
int xkb_base;
int mod_pressed = 0;
uint32_t focus_ws_bg;
uint32_t focus_ws_fg;
uint32_t focus_ws_border;
+ uint32_t binding_mode_bg;
+ uint32_t binding_mode_fg;
+ uint32_t binding_mode_border;
};
struct xcb_colors_t colors;
/* Horizontal offset between a workspace label and button borders */
-const static int ws_hoff_px = 4;
+static const int ws_hoff_px = 4;
/* Vertical offset between a workspace label and button borders */
-const static int ws_voff_px = 3;
+static const int ws_voff_px = 3;
/* Offset between two workspace buttons */
-const static int ws_spacing_px = 1;
+static const int ws_spacing_px = 1;
/* Offset between the statusline and 1) workspace buttons on the left
* 2) the tray or screen edge on the right */
-const static int sb_hoff_px = 4;
+static const int sb_hoff_px = 4;
/* Additional offset between the tray and the statusline, if the tray is not empty */
-const static int tray_loff_px = 2;
+static const int tray_loff_px = 2;
/* Vertical offset between the bar and a separator */
-const static int sep_voff_px = 4;
+static const int sep_voff_px = 4;
/* We define xcb_request_failed as a macro to include the relevant line number */
#define xcb_request_failed(cookie, err_msg) _xcb_request_failed(cookie, err_msg, __LINE__)
TAILQ_FOREACH_REVERSE(trayclient, trayclients, tc_head, tailq) {
if (!trayclient->mapped)
continue;
- tray_width += font.height + logical_px(2);
+ tray_width += icon_size + logical_px(config.tray_padding);
}
if (tray_width > 0)
tray_width += logical_px(tray_loff_px);
PARSE_COLOR(focus_ws_border, "#4c7899");
#undef PARSE_COLOR
+#define PARSE_COLOR_FALLBACK(name, fallback) \
+ do { \
+ colors.name = new_colors->name ? get_colorpixel(new_colors->name) : colors.fallback; \
+ } while (0)
+
+ /* For the binding mode indicator colors, we don't hardcode a default.
+ * Instead, we fall back to urgent_ws_* colors. */
+ PARSE_COLOR_FALLBACK(binding_mode_fg, urgent_ws_fg);
+ PARSE_COLOR_FALLBACK(binding_mode_bg, urgent_ws_bg);
+ PARSE_COLOR_FALLBACK(binding_mode_border, urgent_ws_border);
+#undef PARSE_COLOR_FALLBACK
+
init_tray_colors();
xcb_flush(xcb_connection);
}
int offset = walk->rect.w - statusline_width - tray_width - logical_px(sb_hoff_px);
x = original_x - offset;
- if (x >= 0) {
+ if (x >= 0 && (size_t)x < statusline_width) {
struct status_block *block;
int sep_offset_remainder = 0;
return;
}
+ /* If a custom command was specified for this mouse button, it overrides
+ * the default behavior. */
+ binding_t *binding;
+ TAILQ_FOREACH(binding, &(config.bindings), bindings) {
+ if (binding->input_code != event->detail)
+ continue;
+
+ i3_send_msg(I3_IPC_MESSAGE_TYPE_COMMAND, binding->command);
+ return;
+ }
+
switch (event->detail) {
case 4:
/* Mouse wheel up. We select the previous ws, if any.
* If there is no more workspace, don’t even send the workspace
* command, otherwise (with workspace auto_back_and_forth) we’d end
* up on the wrong workspace. */
-
- /* If `wheel_up_cmd [COMMAND]` was specified, it should override
- * the default behavior */
- if (config.wheel_up_cmd) {
- i3_send_msg(I3_IPC_MESSAGE_TYPE_COMMAND, config.wheel_up_cmd);
- return;
- }
-
if (cur_ws == TAILQ_FIRST(walk->workspaces))
return;
* If there is no more workspace, don’t even send the workspace
* command, otherwise (with workspace auto_back_and_forth) we’d end
* up on the wrong workspace. */
-
- /* if `wheel_down_cmd [COMMAND]` was specified, it should override
- * the default behavior */
- if (config.wheel_down_cmd) {
- i3_send_msg(I3_IPC_MESSAGE_TYPE_COMMAND, config.wheel_down_cmd);
- return;
- }
-
if (cur_ws == TAILQ_LAST(walk->workspaces, ws_head))
return;
size_t namelen = 0;
const char *utf8_name = cur_ws->canonical_name;
for (const char *walk = utf8_name; *walk != '\0'; walk++) {
- if (*walk == '"')
+ if (*walk == '"' || *walk == '\\')
num_quotes++;
/* While we’re looping through the name anyway, we can save one
* strlen(). */
for (inpos = 0, outpos = strlen("workspace \"");
inpos < namelen;
inpos++, outpos++) {
- if (utf8_name[inpos] == '"') {
+ if (utf8_name[inpos] == '"' || utf8_name[inpos] == '\\') {
buffer[outpos] = '\\';
outpos++;
}
clients++;
DLOG("Configuring tray window %08x to x=%d\n",
- trayclient->win, output->rect.w - (clients * (font.height + logical_px(2))));
- uint32_t x = output->rect.w - (clients * (font.height + logical_px(2)));
+ trayclient->win, output->rect.w - (clients * (icon_size + logical_px(config.tray_padding))));
+ uint32_t x = output->rect.w - (clients * (icon_size + logical_px(config.tray_padding)));
xcb_configure_window(xcb_connection,
trayclient->win,
XCB_CONFIG_WINDOW_X,
xcb_reparent_window(xcb_connection,
client,
output->bar,
- output->rect.w - font.height - 2,
- 2);
+ output->rect.w - icon_size - logical_px(config.tray_padding),
+ logical_px(config.tray_padding));
/* We reconfigure the window to use a reasonable size. The systray
* specification explicitly says:
* Tray icons may be assigned any size by the system tray, and
* should do their best to cope with any size effectively
*/
mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
- values[0] = font.height;
- values[1] = font.height;
+ values[0] = icon_size;
+ values[1] = icon_size;
xcb_configure_window(xcb_connection,
client,
mask,
continue;
xcb_rectangle_t rect;
- rect.x = output->rect.w - (clients * (font.height + 2));
- rect.y = 2;
- rect.width = font.height;
- rect.height = font.height;
+ rect.x = output->rect.w - (clients * (icon_size + logical_px(config.tray_padding)));
+ rect.y = logical_px(config.tray_padding);
+ rect.width = icon_size;
+ rect.height = icon_size;
DLOG("This is a tray window. x = %d\n", rect.x);
fake_configure_notify(xcb_connection, rect, event->window, 0);
set_font(&font);
DLOG("Calculated font height: %d\n", font.height);
bar_height = font.height + 2 * logical_px(ws_voff_px);
+ icon_size = bar_height - 2 * logical_px(config.tray_padding);
if (config.separator_symbol)
separator_symbol_width = predict_text_width(config.separator_symbol);
void draw_bars(bool unhide) {
DLOG("Drawing bars...\n");
int workspace_width = 0;
+ /* Is the currently-rendered statusline using short_text items? */
+ bool rendered_statusline_is_short = false;
refresh_statusline(false);
if (binding.name && !config.disable_binding_mode_indicator) {
workspace_width += logical_px(ws_spacing_px);
- uint32_t fg_color = colors.urgent_ws_fg;
- uint32_t bg_color = colors.urgent_ws_bg;
+ uint32_t fg_color = colors.binding_mode_fg;
+ uint32_t bg_color = colors.binding_mode_bg;
uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
- uint32_t vals_border[] = {colors.urgent_ws_border, colors.urgent_ws_border};
+ uint32_t vals_border[] = {colors.binding_mode_border, colors.binding_mode_border};
xcb_change_gc(xcb_connection,
outputs_walk->bargc,
mask,
DLOG("Printing statusline!\n");
int tray_width = get_tray_width(outputs_walk->trayclients);
- int max_statusline_width = outputs_walk->rect.w - workspace_width - tray_width - 2 * logical_px(sb_hoff_px);
+ uint32_t max_statusline_width = outputs_walk->rect.w - workspace_width - tray_width - 2 * logical_px(sb_hoff_px);
/* If the statusline is too long, try to use short texts. */
- if (statusline_width > max_statusline_width)
+ if (statusline_width > max_statusline_width) {
+ /* If the currently rendered statusline is long, render a short status line */
refresh_statusline(true);
+ rendered_statusline_is_short = true;
+ } else if (rendered_statusline_is_short) {
+ /* If the currently rendered statusline is short, render a long status line */
+ refresh_statusline(false);
+ rendered_statusline_is_short = false;
+ }
/* Luckily we already prepared a seperate pixmap containing the rendered
* statusline, we just have to copy the relevant parts to the relevant