include/shmlog.h \
include/sighandler.h \
include/startup.h \
+ include/sync.h \
include/tree.h \
include/util.h \
include/window.h \
== Debugging i3bar
-To debug i3bar problems, add +verbose yes+ to all +bar {}+ blocks in your i3
+To debug i3bar problems, use the +--verbose+ commandline parameter,
+or add +verbose yes+ to all +bar {}+ blocks in your i3
config, reload your config and then restart all i3bar instances like this:
---------------------------------------------------------------------
This field is set to null for split containers or otherwise empty
containers. This ID corresponds to what xwininfo(1) and other
X11-related tools display (usually in hex).
+window_properties (map)::
+ X11 window properties title, instance, class, window_role and transient_for.
urgent (bool)::
Whether this container (window, split container, floating container or
workspace) has the urgency hint set, directly or indirectly. All parent
"width": 1280,
"height": 782
},
+ "window_properties": {
+ "class": "Evince",
+ "instance": "evince",
+ "title": "Properties",
+ "transient_for": 52428808
+ },
"floating_nodes": [],
"nodes": [
border (including window title), +border pixel 1+ to use a 1-pixel border (no window title)
and +border none+ to make the client borderless.
-There is also +border toggle+ which will toggle the different border styles.
+There is also +border toggle+ which will toggle the different border styles. The
+optional pixel argument can be used to specify the border width when switching
+to the normal and pixel styles.
Note that "pixel" refers to logical pixel. On HiDPI displays, a logical pixel
may be represented by multiple physical pixels, so +pixel 1+ might not
*Syntax*:
-----------------------------------------------
-border normal|pixel [<n>]
-border none|toggle
+border normal|pixel|toggle [<n>]
+border none
# legacy syntax, equivalent to "border pixel 1"
border 1pixel
} tray_output_t;
typedef struct config_t {
- int modifier;
+ uint32_t modifier;
TAILQ_HEAD(bindings_head, binding_t)
bindings;
position_t position;
- int verbose;
+ bool verbose;
struct xcb_color_strings_t colors;
bool disable_binding_mode_indicator;
bool disable_ws;
return 1;
}
+ /* Kept for backwards compatibility. */
if (!strcmp(cur_key, "modifier")) {
DLOG("modifier = %.*s\n", len, val);
if (len == strlen("none") && !strncmp((const char *)val, "none", strlen("none"))) {
}
if (!strcmp(cur_key, "verbose")) {
- DLOG("verbose = %d\n", val);
- config.verbose = val;
+ if (!config.verbose) {
+ DLOG("verbose = %d\n", val);
+ config.verbose = val;
+ }
return 1;
}
return 1;
}
+ if (!strcmp(cur_key, "modifier")) {
+ DLOG("modifier = %lld\n", val);
+ config.modifier = (uint32_t)val;
+ return 1;
+ }
+
return 0;
}
printf("-s, --socket <sock_path>\tConnect to i3 via <sock_path>\n");
printf("-h, --help Display this help message and exit\n");
printf("-v, --version Display version number and exit\n");
+ printf("-V, --verbose Enable verbose mode\n");
printf("\n");
printf(" PLEASE NOTE that i3bar will be automatically started by i3\n"
" as soon as there is a 'bar' configuration block in your\n"
{"bar_id", required_argument, 0, 'b'},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'v'},
+ {"verbose", no_argument, 0, 'V'},
{NULL, 0, 0, 0}};
- while ((opt = getopt_long(argc, argv, "b:s:hv", long_opt, &option_index)) != -1) {
+ while ((opt = getopt_long(argc, argv, "b:s:hvV", long_opt, &option_index)) != -1) {
switch (opt) {
case 's':
socket_path = expand_path(optarg);
case 'b':
config.bar_id = sstrdup(optarg);
break;
+ case 'V':
+ config.verbose = true;
+ break;
default:
print_usage(argv[0]);
exit(EXIT_SUCCESS);
/* These are only relevant for XKB, which we only need for grabbing modifiers */
int xkb_base;
-int mod_pressed = 0;
+bool mod_pressed = 0;
/* Event watchers, to interact with the user */
ev_prepare *xcb_prep;
DLOG("received an xkb event\n");
xcb_xkb_state_notify_event_t *state = (xcb_xkb_state_notify_event_t *)event;
+ const uint32_t mod = (config.modifier & 0xFFFF);
+ mod_pressed = (mod != 0 && (state->mods & mod) == mod);
if (state->xkbType == XCB_XKB_STATE_NOTIFY && config.modifier != XCB_NONE) {
- int modstate = state->mods & config.modifier;
-
-#define DLOGMOD(modmask, status) \
- do { \
- switch (modmask) { \
- case ShiftMask: \
- DLOG("ShiftMask got " #status "!\n"); \
- break; \
- case ControlMask: \
- DLOG("ControlMask got " #status "!\n"); \
- break; \
- case Mod1Mask: \
- DLOG("Mod1Mask got " #status "!\n"); \
- break; \
- case Mod2Mask: \
- DLOG("Mod2Mask got " #status "!\n"); \
- break; \
- case Mod3Mask: \
- DLOG("Mod3Mask got " #status "!\n"); \
- break; \
- case Mod4Mask: \
- DLOG("Mod4Mask got " #status "!\n"); \
- break; \
- case Mod5Mask: \
- DLOG("Mod5Mask got " #status "!\n"); \
- break; \
- } \
- } while (0)
-
- if (modstate != mod_pressed) {
- if (modstate == 0) {
- DLOGMOD(config.modifier, released);
- if (!activated_mode)
- hide_bars();
- } else {
- DLOGMOD(config.modifier, pressed);
- activated_mode = false;
- unhide_bars();
- }
- mod_pressed = modstate;
+ if (mod_pressed) {
+ activated_mode = false;
+ unhide_bars();
+ } else if (!activated_mode) {
+ hide_bars();
}
-#undef DLOGMOD
}
free(event);
CFGFUN(bar_id, const char *bar_id);
CFGFUN(bar_output, const char *output);
CFGFUN(bar_verbose, const char *verbose);
-CFGFUN(bar_modifier, const char *modifier);
+CFGFUN(bar_modifier, const char *modifiers);
CFGFUN(bar_wheel_up_cmd, const char *command);
CFGFUN(bar_wheel_down_cmd, const char *command);
CFGFUN(bar_bindsym, const char *button, const char *release, const char *command);
S_SHOW = 1 } hidden_state;
/** Bar modifier (to show bar when in hide mode). */
- enum {
- M_NONE = 0,
- M_CONTROL = 1,
- M_SHIFT = 2,
- M_MOD1 = 3,
- M_MOD2 = 4,
- M_MOD3 = 5,
- M_MOD4 = 6,
- M_MOD5 = 7
- } modifier;
+ uint32_t modifier;
TAILQ_HEAD(bar_bindings_head, Barbinding)
bar_bindings;
#define STARTS_WITH(string, needle) (strncasecmp((string), (needle), strlen((needle))) == 0)
#define CIRCLEQ_NEXT_OR_NULL(head, elm, field) (CIRCLEQ_NEXT(elm, field) != CIRCLEQ_END(head) ? CIRCLEQ_NEXT(elm, field) : NULL)
#define CIRCLEQ_PREV_OR_NULL(head, elm, field) (CIRCLEQ_PREV(elm, field) != CIRCLEQ_END(head) ? CIRCLEQ_PREV(elm, field) : NULL)
-#define FOR_TABLE(workspace) \
- for (int cols = 0; cols < (workspace)->cols; cols++) \
- for (int rows = 0; rows < (workspace)->rows; rows++)
#define NODES_FOREACH(head) \
for (Con *child = (Con *)-1; (child == (Con *)-1) && ((child = 0), true);) \
i3-input(1)
-=========
+===========
Michael Stapelberg <michael+i3@stapelberg.de>
v4.1.2, April 2012
i3-sensible-editor(1)
-===================
+=====================
Michael Stapelberg <michael+i3@stapelberg.de>
v4.1, November 2011
i3-sensible-pager(1)
-===================
+====================
Michael Stapelberg <michael+i3@stapelberg.de>
v4.1, November 2011
# border normal|pixel [<n>]
# border none|1pixel|toggle
state BORDER:
- border_style = 'normal', 'pixel'
+ border_style = 'normal', 'pixel', 'toggle'
-> BORDER_WIDTH
- border_style = 'none', 'toggle'
+ border_style = 'none'
-> call cmd_border($border_style, 0)
- border_style = '1pixel'
- -> call cmd_border($border_style, 1)
+ '1pixel'
+ -> call cmd_border("pixel", 1)
state BORDER_WIDTH:
end
- -> call cmd_border($border_style, 2)
+ -> call cmd_border($border_style, -1)
border_width = number
-> call cmd_border($border_style, &border_width)
-> call cfg_bar_id($bar_id); BAR
state BAR_MODIFIER:
- modifier = 'Mod1', 'Mod2', 'Mod3', 'Mod4', 'Mod5', 'Control', 'Ctrl', 'Shift', 'none', 'off'
- -> call cfg_bar_modifier($modifier); BAR
+ 'off', 'none'
+ -> call cfg_bar_modifier(NULL); BAR
+ modifiers = 'Mod1', 'Mod2', 'Mod3', 'Mod4', 'Mod5', 'Shift', 'Control', 'Ctrl'
+ ->
+ '+'
+ ->
+ end
+ -> call cfg_bar_modifier($modifiers); BAR
state BAR_WHEEL_UP_CMD:
command = string
ysuccess(success);
}
+static int border_width_from_style(border_style_t border_style, long border_width, Con *con) {
+ if (border_style == BS_NONE) {
+ return 0;
+ }
+ if (border_width >= 0) {
+ return logical_px(border_width);
+ }
+
+ const bool is_floating = con_inside_floating(con) != NULL;
+ /* Load the configured defaults. */
+ if (is_floating && border_style == config.default_floating_border) {
+ return config.default_floating_border_width;
+ } else if (!is_floating && border_style == config.default_border) {
+ return config.default_border_width;
+ } else {
+ /* Use some hardcoded values. */
+ return logical_px(border_style == BS_NORMAL ? 2 : 1);
+ }
+}
+
/*
* Implementation of 'border normal|pixel [<n>]', 'border none|1pixel|toggle'.
*
TAILQ_FOREACH(current, &owindows, owindows) {
DLOG("matching: %p / %s\n", current->con, current->con->name);
- int border_style = current->con->border_style;
- int con_border_width = border_width;
+ border_style_t border_style;
if (strcmp(border_style_str, "toggle") == 0) {
- border_style++;
- border_style %= 3;
- if (border_style == BS_NORMAL)
- con_border_width = 2;
- else if (border_style == BS_NONE)
- con_border_width = 0;
- else if (border_style == BS_PIXEL)
- con_border_width = 1;
+ border_style = (current->con->border_style + 1) % 3;
+ } else if (strcmp(border_style_str, "normal") == 0) {
+ border_style = BS_NORMAL;
+ } else if (strcmp(border_style_str, "pixel") == 0) {
+ border_style = BS_PIXEL;
+ } else if (strcmp(border_style_str, "none") == 0) {
+ border_style = BS_NONE;
} else {
- if (strcmp(border_style_str, "normal") == 0) {
- border_style = BS_NORMAL;
- } else if (strcmp(border_style_str, "pixel") == 0) {
- border_style = BS_PIXEL;
- } else if (strcmp(border_style_str, "1pixel") == 0) {
- border_style = BS_PIXEL;
- con_border_width = 1;
- } else if (strcmp(border_style_str, "none") == 0) {
- border_style = BS_NONE;
- } else {
- ELOG("BUG: called with border_style=%s\n", border_style_str);
- ysuccess(false);
- return;
- }
+ ELOG("BUG: called with border_style=%s\n", border_style_str);
+ ysuccess(false);
+ return;
}
- con_set_border_style(current->con, border_style, logical_px(con_border_width));
+ const int con_border_width = border_width_from_style(border_style, border_width, current->con);
+ con_set_border_style(current->con, border_style, con_border_width);
}
cmd_output->needs_tree_render = true;
return true;
}
- if (con->type == CT_WORKSPACE) {
+ if (target->type == CT_WORKSPACE) {
DLOG("target container is a workspace, simply moving the container there.\n");
con_move_to_workspace(con, target, true, false, false);
return true;
bindings = default_mode->bindings;
-#define REQUIRED_OPTION(name) \
- if (config.name == NULL) \
- die("You did not specify required configuration option " #name "\n");
-
/* Clear the old config or initialize the data structure */
memset(&config, 0, sizeof(config));
current_bar->verbose = eval_boolstr(verbose);
}
-CFGFUN(bar_modifier, const char *modifier) {
- if (strcmp(modifier, "Mod1") == 0)
- current_bar->modifier = M_MOD1;
- else if (strcmp(modifier, "Mod2") == 0)
- current_bar->modifier = M_MOD2;
- else if (strcmp(modifier, "Mod3") == 0)
- current_bar->modifier = M_MOD3;
- else if (strcmp(modifier, "Mod4") == 0)
- current_bar->modifier = M_MOD4;
- else if (strcmp(modifier, "Mod5") == 0)
- current_bar->modifier = M_MOD5;
- else if (strcmp(modifier, "Control") == 0 ||
- strcmp(modifier, "Ctrl") == 0)
- current_bar->modifier = M_CONTROL;
- else if (strcmp(modifier, "Shift") == 0)
- current_bar->modifier = M_SHIFT;
- else if (strcmp(modifier, "none") == 0 ||
- strcmp(modifier, "off") == 0)
- current_bar->modifier = M_NONE;
+CFGFUN(bar_modifier, const char *modifiers) {
+ current_bar->modifier = modifiers ? event_state_from_str(modifiers) : XCB_NONE;
}
static void bar_configure_binding(const char *button, const char *release, const char *command) {
TAILQ_INIT(&(current_bar->bar_bindings));
TAILQ_INIT(&(current_bar->tray_outputs));
current_bar->tray_padding = 2;
- current_bar->modifier = M_MOD4;
+ current_bar->modifier = XCB_KEY_BUT_MASK_MOD_4;
}
CFGFUN(bar_finish) {
}
ystr("modifier");
- switch (config->modifier) {
- case M_NONE:
- ystr("none");
- break;
- case M_CONTROL:
- ystr("ctrl");
- break;
- case M_SHIFT:
- ystr("shift");
- break;
- case M_MOD1:
- ystr("Mod1");
- break;
- case M_MOD2:
- ystr("Mod2");
- break;
- case M_MOD3:
- ystr("Mod3");
- break;
- case M_MOD5:
- ystr("Mod5");
- break;
- default:
- ystr("Mod4");
- break;
- }
+ y(integer, config->modifier);
dump_bar_bindings(gen, config);
Barconfig *barconfig;
TAILQ_FOREACH(barconfig, &barconfigs, configs) {
char *command = NULL;
- sasprintf(&command, "%s --bar_id=%s --socket=\"%s\"",
+ sasprintf(&command, "%s %s --bar_id=%s --socket=\"%s\"",
barconfig->i3bar_command ? barconfig->i3bar_command : "i3bar",
+ barconfig->verbose ? "-V" : "",
barconfig->id, current_socketpath);
LOG("Starting bar process: %s\n", command);
start_application(command, true);
cmd 'border 1pixel';
@nodes = @{get_ws_content($tmp)};
-is($nodes[0]->{border}, 'pixel', 'border style 1pixel');
+is($nodes[0]->{border}, 'pixel', 'border style pixel');
is($nodes[0]->{current_border_width}, 1, 'border width = 1px');
cmd 'border none';
cmd 'border toggle';
@nodes = @{get_ws_content($tmp)};
-is($nodes[0]->{border}, 'pixel', 'border style 1pixel');
+is($nodes[0]->{border}, 'pixel', 'border style pixel');
is($nodes[0]->{current_border_width}, 1, 'border width = 1px');
cmd 'border toggle';
is($nodes[0]->{border}, 'normal', 'border style back to normal');
is($nodes[0]->{current_border_width}, 2, 'border width = 2px');
+cmd 'border toggle 10';
+@nodes = @{get_ws_content($tmp)};
+is($nodes[0]->{border}, 'none', 'border style back to none even with width argument');
+is($nodes[0]->{current_border_width}, 0, 'border width = 0px');
+
+cmd 'border toggle 10';
+@nodes = @{get_ws_content($tmp)};
+is($nodes[0]->{border}, 'pixel', 'border style pixel');
+is($nodes[0]->{current_border_width}, 10, 'border width = 10px');
+
+cmd 'border toggle 10';
+@nodes = @{get_ws_content($tmp)};
+is($nodes[0]->{border}, 'normal', 'border style back to normal');
+is($nodes[0]->{current_border_width}, 10, 'border width = 10px');
+
done_testing;
does_i3_live;
+###############################################################################
+# Given 'S' and 'M' where 'M' is a workspace and 'S' is on a different
+# workspace, then 'S' ends up as a tiling container on 'M'.
+###############################################################################
+
+fresh_workspace;
+$S = open_window;
+$target_ws = fresh_workspace;
+$M = $target_ws;
+cmd 'mark target';
+
+cmd '[id="' . $S->{id} . '"] move container to mark target';
+sync_with_i3;
+
+does_i3_live;
+
+($nodes, $focus) = get_ws_content($target_ws);
+is(@{$nodes}, 1, 'tiling container moved to the target workspace');
+
+###############################################################################
+# Given 'S' and 'M' where 'S' is a workspace and 'M' is a container on a
+# different workspace, then all the contents of workspace 'S' end up in 'M's
+# workspace.
+###############################################################################
+
+$S = fresh_workspace;
+cmd 'mark S';
+open_window;
+open_window;
+cmd 'splitv';
+open_window;
+open_floating_window;
+$target_ws = fresh_workspace;
+$M = open_window;
+cmd 'mark target';
+
+cmd '[con_mark=S] move container to mark target';
+sync_with_i3;
+
+($nodes, $focus) = get_ws_content($target_ws);
+is(@{$nodes}, 2, 'there is a window and a container with the contents of the original workspace');
+is($nodes->[0]->{window}, $M->{id}, 'M remains the first window');
+is(@{get_ws($target_ws)->{floating_nodes}}, 1, 'target workspace has the floating container');
+
###############################################################################
done_testing;