Merge pull request #2649 from s3rb31/next
layout toggle: take any combination of layouts as arguments (continuation of #2476)
This commit is contained in:
commit
c474ddd782
|
@ -1802,7 +1802,8 @@ The +toggle+ option will toggle the orientation of the split container if it
|
||||||
contains a single window. Otherwise it makes the current window a split
|
contains a single window. Otherwise it makes the current window a split
|
||||||
container with opposite orientation compared to the parent container.
|
container with opposite orientation compared to the parent container.
|
||||||
Use +layout toggle split+ to change the layout of any split container from
|
Use +layout toggle split+ to change the layout of any split container from
|
||||||
splitv to splith or vice-versa.
|
splitv to splith or vice-versa. You can also define a custom sequence of layouts
|
||||||
|
to cycle through with +layout toggle+, see <<manipulating_layout>>.
|
||||||
|
|
||||||
*Syntax*:
|
*Syntax*:
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
@ -1822,6 +1823,11 @@ Use +layout toggle split+, +layout stacking+, +layout tabbed+, +layout splitv+
|
||||||
or +layout splith+ to change the current container layout to splith/splitv,
|
or +layout splith+ to change the current container layout to splith/splitv,
|
||||||
stacking, tabbed layout, splitv or splith, respectively.
|
stacking, tabbed layout, splitv or splith, respectively.
|
||||||
|
|
||||||
|
Specify up to four layouts after +layout toggle+ to cycle through them. Every
|
||||||
|
time the command is executed, the layout specified after the currently active
|
||||||
|
one will be applied. If the currently active layout is not in the list, the
|
||||||
|
first layout in the list will be activated.
|
||||||
|
|
||||||
To make the current window (!) fullscreen, use +fullscreen enable+ (or
|
To make the current window (!) fullscreen, use +fullscreen enable+ (or
|
||||||
+fullscreen enable global+ for the global mode), to leave either fullscreen
|
+fullscreen enable global+ for the global mode), to leave either fullscreen
|
||||||
mode use +fullscreen disable+, and to toggle between these two states use
|
mode use +fullscreen disable+, and to toggle between these two states use
|
||||||
|
@ -1834,6 +1840,7 @@ enable+ respectively +floating disable+ (or +floating toggle+):
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
layout default|tabbed|stacking|splitv|splith
|
layout default|tabbed|stacking|splitv|splith
|
||||||
layout toggle [split|all]
|
layout toggle [split|all]
|
||||||
|
layout toggle [split|tabbed|stacking|splitv|splith] [split|tabbed|stacking|splitv|splith]…
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
|
|
||||||
*Examples*:
|
*Examples*:
|
||||||
|
@ -1848,6 +1855,15 @@ bindsym $mod+x layout toggle
|
||||||
# Toggle between stacking/tabbed/splith/splitv:
|
# Toggle between stacking/tabbed/splith/splitv:
|
||||||
bindsym $mod+x layout toggle all
|
bindsym $mod+x layout toggle all
|
||||||
|
|
||||||
|
# Toggle between stacking/tabbed/splith:
|
||||||
|
bindsym $mod+x layout toggle stacking tabbed splith
|
||||||
|
|
||||||
|
# Toggle between splitv/tabbed
|
||||||
|
bindsym $mod+x layout toggle splitv tabbed
|
||||||
|
|
||||||
|
# Toggle between last split layout/tabbed/stacking
|
||||||
|
bindsym $mod+x layout toggle split tabbed stacking
|
||||||
|
|
||||||
# Toggle fullscreen
|
# Toggle fullscreen
|
||||||
bindsym $mod+f fullscreen toggle
|
bindsym $mod+f fullscreen toggle
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,14 @@ Rect rect_sub(Rect a, Rect b);
|
||||||
*/
|
*/
|
||||||
__attribute__((pure)) bool name_is_digits(const char *name);
|
__attribute__((pure)) bool name_is_digits(const char *name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set 'out' to the layout_t value for the given layout. The function
|
||||||
|
* returns true on success or false if the passed string is not a valid
|
||||||
|
* layout name.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool layout_from_name(const char *layout_str, layout_t *out);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the workspace name as a number. Returns -1 if the workspace should be
|
* Parses the workspace name as a number. Returns -1 if the workspace should be
|
||||||
* interpreted as a "named workspace".
|
* interpreted as a "named workspace".
|
||||||
|
|
|
@ -110,7 +110,7 @@ state LAYOUT:
|
||||||
state LAYOUT_TOGGLE:
|
state LAYOUT_TOGGLE:
|
||||||
end
|
end
|
||||||
-> call cmd_layout_toggle($toggle_mode)
|
-> call cmd_layout_toggle($toggle_mode)
|
||||||
toggle_mode = 'split', 'all'
|
toggle_mode = string
|
||||||
-> call cmd_layout_toggle($toggle_mode)
|
-> call cmd_layout_toggle($toggle_mode)
|
||||||
|
|
||||||
# append_layout <path>
|
# append_layout <path>
|
||||||
|
|
|
@ -1489,21 +1489,8 @@ void cmd_move_direction(I3_CMD, const char *direction, long move_px) {
|
||||||
void cmd_layout(I3_CMD, const char *layout_str) {
|
void cmd_layout(I3_CMD, const char *layout_str) {
|
||||||
HANDLE_EMPTY_MATCH;
|
HANDLE_EMPTY_MATCH;
|
||||||
|
|
||||||
if (strcmp(layout_str, "stacking") == 0)
|
|
||||||
layout_str = "stacked";
|
|
||||||
layout_t layout;
|
layout_t layout;
|
||||||
/* default is a special case which will be handled in con_set_layout(). */
|
if (!layout_from_name(layout_str, &layout)) {
|
||||||
if (strcmp(layout_str, "default") == 0)
|
|
||||||
layout = L_DEFAULT;
|
|
||||||
else if (strcmp(layout_str, "stacked") == 0)
|
|
||||||
layout = L_STACKED;
|
|
||||||
else if (strcmp(layout_str, "tabbed") == 0)
|
|
||||||
layout = L_TABBED;
|
|
||||||
else if (strcmp(layout_str, "splitv") == 0)
|
|
||||||
layout = L_SPLITV;
|
|
||||||
else if (strcmp(layout_str, "splith") == 0)
|
|
||||||
layout = L_SPLITH;
|
|
||||||
else {
|
|
||||||
ELOG("Unknown layout \"%s\", this is a mismatch between code and parser spec.\n", layout_str);
|
ELOG("Unknown layout \"%s\", this is a mismatch between code and parser spec.\n", layout_str);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
64
src/con.c
64
src/con.c
|
@ -1719,28 +1719,64 @@ void con_toggle_layout(Con *con, const char *toggle_mode) {
|
||||||
parent = con->parent;
|
parent = con->parent;
|
||||||
DLOG("con_toggle_layout(%p, %s), parent = %p\n", con, toggle_mode, parent);
|
DLOG("con_toggle_layout(%p, %s), parent = %p\n", con, toggle_mode, parent);
|
||||||
|
|
||||||
if (strcmp(toggle_mode, "split") == 0) {
|
const char delim[] = " ";
|
||||||
/* Toggle between splits. When the current layout is not a split
|
|
||||||
* layout, we just switch back to last_split_layout. Otherwise, we
|
if (strcasecmp(toggle_mode, "split") == 0 || strstr(toggle_mode, delim)) {
|
||||||
* change to the opposite split layout. */
|
/* L_DEFAULT is used as a placeholder value to distinguish if
|
||||||
if (parent->layout != L_SPLITH && parent->layout != L_SPLITV)
|
* the first layout has already been saved. (it can never be L_DEFAULT) */
|
||||||
con_set_layout(con, parent->last_split_layout);
|
layout_t new_layout = L_DEFAULT;
|
||||||
else {
|
bool current_layout_found = false;
|
||||||
if (parent->layout == L_SPLITH)
|
char *tm_dup = sstrdup(toggle_mode);
|
||||||
con_set_layout(con, L_SPLITV);
|
char *cur_tok = strtok(tm_dup, delim);
|
||||||
else
|
|
||||||
con_set_layout(con, L_SPLITH);
|
for (layout_t layout; cur_tok != NULL; cur_tok = strtok(NULL, delim)) {
|
||||||
|
if (strcasecmp(cur_tok, "split") == 0) {
|
||||||
|
/* Toggle between splits. When the current layout is not a split
|
||||||
|
* layout, we just switch back to last_split_layout. Otherwise, we
|
||||||
|
* change to the opposite split layout. */
|
||||||
|
if (parent->layout != L_SPLITH && parent->layout != L_SPLITV) {
|
||||||
|
layout = parent->last_split_layout;
|
||||||
|
} else {
|
||||||
|
layout = (parent->layout == L_SPLITH) ? L_SPLITV : L_SPLITH;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bool success = layout_from_name(cur_tok, &layout);
|
||||||
|
if (!success || layout == L_DEFAULT) {
|
||||||
|
ELOG("The token '%s' was not recognized and has been skipped.\n", cur_tok);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If none of the specified layouts match the current,
|
||||||
|
* fall back to the first layout in the list */
|
||||||
|
if (new_layout == L_DEFAULT) {
|
||||||
|
new_layout = layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We found the active layout in the last iteration, so
|
||||||
|
* now let's activate the current layout (next in list) */
|
||||||
|
if (current_layout_found) {
|
||||||
|
new_layout = layout;
|
||||||
|
free(tm_dup);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent->layout == layout) {
|
||||||
|
current_layout_found = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
|
con_set_layout(con, new_layout);
|
||||||
|
} else if (strcasecmp(toggle_mode, "all") == 0 || strcasecmp(toggle_mode, "default") == 0) {
|
||||||
if (parent->layout == L_STACKED)
|
if (parent->layout == L_STACKED)
|
||||||
con_set_layout(con, L_TABBED);
|
con_set_layout(con, L_TABBED);
|
||||||
else if (parent->layout == L_TABBED) {
|
else if (parent->layout == L_TABBED) {
|
||||||
if (strcmp(toggle_mode, "all") == 0)
|
if (strcasecmp(toggle_mode, "all") == 0)
|
||||||
con_set_layout(con, L_SPLITH);
|
con_set_layout(con, L_SPLITH);
|
||||||
else
|
else
|
||||||
con_set_layout(con, parent->last_split_layout);
|
con_set_layout(con, parent->last_split_layout);
|
||||||
} else if (parent->layout == L_SPLITH || parent->layout == L_SPLITV) {
|
} else if (parent->layout == L_SPLITH || parent->layout == L_SPLITV) {
|
||||||
if (strcmp(toggle_mode, "all") == 0) {
|
if (strcasecmp(toggle_mode, "all") == 0) {
|
||||||
/* When toggling through all modes, we toggle between
|
/* When toggling through all modes, we toggle between
|
||||||
* splith/splitv, whereas normally we just directly jump to
|
* splith/splitv, whereas normally we just directly jump to
|
||||||
* stacked. */
|
* stacked. */
|
||||||
|
|
28
src/util.c
28
src/util.c
|
@ -66,6 +66,34 @@ __attribute__((pure)) bool name_is_digits(const char *name) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set 'out' to the layout_t value for the given layout. The function
|
||||||
|
* returns true on success or false if the passed string is not a valid
|
||||||
|
* layout name.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool layout_from_name(const char *layout_str, layout_t *out) {
|
||||||
|
if (strcmp(layout_str, "default") == 0) {
|
||||||
|
*out = L_DEFAULT;
|
||||||
|
return true;
|
||||||
|
} else if (strcasecmp(layout_str, "stacked") == 0 ||
|
||||||
|
strcasecmp(layout_str, "stacking") == 0) {
|
||||||
|
*out = L_STACKED;
|
||||||
|
return true;
|
||||||
|
} else if (strcasecmp(layout_str, "tabbed") == 0) {
|
||||||
|
*out = L_TABBED;
|
||||||
|
return true;
|
||||||
|
} else if (strcasecmp(layout_str, "splitv") == 0) {
|
||||||
|
*out = L_SPLITV;
|
||||||
|
return true;
|
||||||
|
} else if (strcasecmp(layout_str, "splith") == 0) {
|
||||||
|
*out = L_SPLITH;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parses the workspace name as a number. Returns -1 if the workspace should be
|
* Parses the workspace name as a number. Returns -1 if the workspace should be
|
||||||
* interpreted as a "named workspace".
|
* interpreted as a "named workspace".
|
||||||
|
|
|
@ -95,4 +95,72 @@ cmd 'layout toggle all';
|
||||||
($nodes, $focus) = get_ws_content($tmp);
|
($nodes, $focus) = get_ws_content($tmp);
|
||||||
is($nodes->[1]->{layout}, 'splitv', 'layout now splitv');
|
is($nodes->[1]->{layout}, 'splitv', 'layout now splitv');
|
||||||
|
|
||||||
|
cmd 'layout toggle splith splitv';
|
||||||
|
($nodes, $focus) = get_ws_content($tmp);
|
||||||
|
is($nodes->[1]->{layout}, 'splith', 'layout now splith');
|
||||||
|
|
||||||
|
cmd 'layout toggle splith splitv';
|
||||||
|
($nodes, $focus) = get_ws_content($tmp);
|
||||||
|
is($nodes->[1]->{layout}, 'splitv', 'layout now splitv');
|
||||||
|
|
||||||
|
cmd 'layout toggle stacked splitv tabbed';
|
||||||
|
($nodes, $focus) = get_ws_content($tmp);
|
||||||
|
is($nodes->[1]->{layout}, 'tabbed', 'layout now tabbed');
|
||||||
|
|
||||||
|
cmd 'layout toggle stacking splitv tabbed';
|
||||||
|
($nodes, $focus) = get_ws_content($tmp);
|
||||||
|
is($nodes->[1]->{layout}, 'stacked', 'layout now stacked');
|
||||||
|
|
||||||
|
cmd 'layout toggle stacking splitv tabbed';
|
||||||
|
($nodes, $focus) = get_ws_content($tmp);
|
||||||
|
is($nodes->[1]->{layout}, 'splitv', 'layout now splitv');
|
||||||
|
|
||||||
|
cmd 'layout toggle splitv i stacking tabbed';
|
||||||
|
($nodes, $focus) = get_ws_content($tmp);
|
||||||
|
is($nodes->[1]->{layout}, 'stacked', 'layout now stacked');
|
||||||
|
|
||||||
|
cmd 'layout toggle stacked';
|
||||||
|
($nodes, $focus) = get_ws_content($tmp);
|
||||||
|
# this is correct if it does nothing
|
||||||
|
is($nodes->[1]->{layout}, 'stacked', 'layout now tabbed');
|
||||||
|
|
||||||
|
cmd 'layout toggle tabbed stacked';
|
||||||
|
($nodes, $focus) = get_ws_content($tmp);
|
||||||
|
is($nodes->[1]->{layout}, 'tabbed', 'layout now stacked');
|
||||||
|
|
||||||
|
# obsoletes 'split' ;)
|
||||||
|
cmd 'layout toggle splith splitv';
|
||||||
|
($nodes, $focus) = get_ws_content($tmp);
|
||||||
|
is($nodes->[1]->{layout}, 'splith', 'layout now splith');
|
||||||
|
|
||||||
|
# nonsense but works expectedly
|
||||||
|
cmd 'layout toggle split split';
|
||||||
|
($nodes, $focus) = get_ws_content($tmp);
|
||||||
|
is($nodes->[1]->{layout}, 'splitv', 'layout now splitv');
|
||||||
|
|
||||||
|
cmd 'layout toggle split split';
|
||||||
|
($nodes, $focus) = get_ws_content($tmp);
|
||||||
|
is($nodes->[1]->{layout}, 'splith', 'layout now splith');
|
||||||
|
|
||||||
|
# testing with arbitrary length and garbage
|
||||||
|
cmd 'layout toggle stacking splith tabbed splitv stacking';
|
||||||
|
($nodes, $focus) = get_ws_content($tmp);
|
||||||
|
is($nodes->[1]->{layout}, 'tabbed', 'layout now tabbed');
|
||||||
|
|
||||||
|
cmd 'layout toggle stacking splith garbage tabbed splitv stacking';
|
||||||
|
($nodes, $focus) = get_ws_content($tmp);
|
||||||
|
is($nodes->[1]->{layout}, 'splitv', 'layout now splitv');
|
||||||
|
|
||||||
|
cmd 'layout toggle stacking splith garbage tabbed splitv stacking';
|
||||||
|
($nodes, $focus) = get_ws_content($tmp);
|
||||||
|
is($nodes->[1]->{layout}, 'stacked', 'layout now stacked');
|
||||||
|
|
||||||
|
cmd 'layout toggle splitv splith garbage splitv tabbed stacking splitv';
|
||||||
|
($nodes, $focus) = get_ws_content($tmp);
|
||||||
|
is($nodes->[1]->{layout}, 'splitv', 'layout now splitv');
|
||||||
|
|
||||||
|
cmd 'layout toggle splitv garbage tabbed';
|
||||||
|
($nodes, $focus) = get_ws_content($tmp);
|
||||||
|
is($nodes->[1]->{layout}, 'tabbed', 'layout now tabbed');
|
||||||
|
|
||||||
done_testing;
|
done_testing;
|
||||||
|
|
Loading…
Reference in New Issue