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
|
||||
container with opposite orientation compared to the parent container.
|
||||
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*:
|
||||
--------------------------------
|
||||
|
@ -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,
|
||||
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
|
||||
+fullscreen enable global+ for the global mode), to leave either fullscreen
|
||||
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 toggle [split|all]
|
||||
layout toggle [split|tabbed|stacking|splitv|splith] [split|tabbed|stacking|splitv|splith]…
|
||||
--------------------------------------------
|
||||
|
||||
*Examples*:
|
||||
|
@ -1848,6 +1855,15 @@ bindsym $mod+x layout toggle
|
|||
# Toggle between stacking/tabbed/splith/splitv:
|
||||
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
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* interpreted as a "named workspace".
|
||||
|
|
|
@ -110,7 +110,7 @@ state LAYOUT:
|
|||
state LAYOUT_TOGGLE:
|
||||
end
|
||||
-> call cmd_layout_toggle($toggle_mode)
|
||||
toggle_mode = 'split', 'all'
|
||||
toggle_mode = string
|
||||
-> call cmd_layout_toggle($toggle_mode)
|
||||
|
||||
# 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) {
|
||||
HANDLE_EMPTY_MATCH;
|
||||
|
||||
if (strcmp(layout_str, "stacking") == 0)
|
||||
layout_str = "stacked";
|
||||
layout_t layout;
|
||||
/* default is a special case which will be handled in con_set_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 {
|
||||
if (!layout_from_name(layout_str, &layout)) {
|
||||
ELOG("Unknown layout \"%s\", this is a mismatch between code and parser spec.\n", layout_str);
|
||||
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;
|
||||
DLOG("con_toggle_layout(%p, %s), parent = %p\n", con, toggle_mode, parent);
|
||||
|
||||
if (strcmp(toggle_mode, "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)
|
||||
con_set_layout(con, parent->last_split_layout);
|
||||
else {
|
||||
if (parent->layout == L_SPLITH)
|
||||
con_set_layout(con, L_SPLITV);
|
||||
else
|
||||
con_set_layout(con, L_SPLITH);
|
||||
const char delim[] = " ";
|
||||
|
||||
if (strcasecmp(toggle_mode, "split") == 0 || strstr(toggle_mode, delim)) {
|
||||
/* L_DEFAULT is used as a placeholder value to distinguish if
|
||||
* the first layout has already been saved. (it can never be L_DEFAULT) */
|
||||
layout_t new_layout = L_DEFAULT;
|
||||
bool current_layout_found = false;
|
||||
char *tm_dup = sstrdup(toggle_mode);
|
||||
char *cur_tok = strtok(tm_dup, delim);
|
||||
|
||||
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)
|
||||
con_set_layout(con, 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);
|
||||
else
|
||||
con_set_layout(con, parent->last_split_layout);
|
||||
} 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
|
||||
* splith/splitv, whereas normally we just directly jump to
|
||||
* stacked. */
|
||||
|
|
28
src/util.c
28
src/util.c
|
@ -66,6 +66,34 @@ __attribute__((pure)) bool name_is_digits(const char *name) {
|
|||
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
|
||||
* interpreted as a "named workspace".
|
||||
|
|
|
@ -95,4 +95,72 @@ cmd 'layout toggle all';
|
|||
($nodes, $focus) = get_ws_content($tmp);
|
||||
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;
|
||||
|
|
Loading…
Reference in New Issue