*
*/
void cmd_split(I3_CMD, char *direction) {
+ owindow *current;
/* TODO: use matches */
LOG("splitting in direction %c\n", direction[0]);
- tree_split(focused, (direction[0] == 'v' ? VERT : HORIZ));
+ if (match_is_empty(current_match))
+ tree_split(focused, (direction[0] == 'v' ? VERT : HORIZ));
+ else {
+ TAILQ_FOREACH(current, &owindows, owindows) {
+ DLOG("matching: %p / %s\n", current->con, current->con->name);
+ tree_split(current->con, (direction[0] == 'v' ? VERT : HORIZ));
+ }
+ }
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
/* check if the match is empty, not if the result is empty */
if (match_is_empty(current_match))
- con_set_layout(focused->parent, layout);
+ con_set_layout(focused, layout);
else {
TAILQ_FOREACH(current, &owindows, owindows) {
DLOG("matching: %p / %s\n", current->con, current->con->name);
/* check if the match is empty, not if the result is empty */
if (match_is_empty(current_match))
- con_toggle_layout(focused->parent, toggle_mode);
+ con_toggle_layout(focused, toggle_mode);
else {
TAILQ_FOREACH(current, &owindows, owindows) {
DLOG("matching: %p / %s\n", current->con, current->con->name);
*
*/
void con_set_layout(Con *con, int layout) {
+ DLOG("con_set_layout(%p, %d), con->type = %d\n",
+ con, layout, con->type);
+
+ /* Users can focus workspaces, but not any higher in the hierarchy.
+ * Focus on the workspace is a special case, since in every other case, the
+ * user means "change the layout of the parent split container". */
+ if (con->type != CT_WORKSPACE)
+ con = con->parent;
+
/* We fill in last_split_layout when switching to a different layout
* since there are many places in the code that don’t use
* con_set_layout(). */
* whole workspace into stacked/tabbed mode. To do this and still allow
* intuitive operations (like level-up and then opening a new window), we
* need to create a new split container. */
- if (con->type == CT_WORKSPACE) {
+ if (con->type == CT_WORKSPACE &&
+ (layout == L_STACKED || layout == L_TABBED)) {
DLOG("Creating new split container\n");
/* 1: create a new split container */
Con *new = con_new(NULL, NULL);
/* 2: Set the requested layout on the split container and mark it as
* split. */
- con_set_layout(new, layout);
+ new->layout = layout;
new->last_split_layout = con->last_split_layout;
new->split = true;
*
*/
void con_toggle_layout(Con *con, const char *toggle_mode) {
+ Con *parent = con;
+ /* Users can focus workspaces, but not any higher in the hierarchy.
+ * Focus on the workspace is a special case, since in every other case, the
+ * user means "change the layout of the parent split container". */
+ if (con->type != CT_WORKSPACE)
+ 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 (con->layout != L_SPLITH && con->layout != L_SPLITV)
- con_set_layout(con, con->last_split_layout);
+ if (parent->layout != L_SPLITH && parent->layout != L_SPLITV)
+ con_set_layout(con, parent->last_split_layout);
else {
- if (con->layout == L_SPLITH)
+ if (parent->layout == L_SPLITH)
con_set_layout(con, L_SPLITV);
else con_set_layout(con, L_SPLITH);
}
} else {
- if (con->layout == L_STACKED)
+ if (parent->layout == L_STACKED)
con_set_layout(con, L_TABBED);
- else if (con->layout == L_TABBED) {
+ else if (parent->layout == L_TABBED) {
if (strcmp(toggle_mode, "all") == 0)
con_set_layout(con, L_SPLITH);
- else con_set_layout(con, con->last_split_layout);
- } else if (con->layout == L_SPLITH || con->layout == L_SPLITV) {
+ 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) {
/* When toggling through all modes, we toggle between
* splith/splitv, whereas normally we just directly jump to
* stacked. */
- if (con->layout == L_SPLITH)
+ if (parent->layout == L_SPLITH)
con_set_layout(con, L_SPLITV);
else con_set_layout(con, L_STACKED);
} else {
# Tests splitting
#
use i3test;
+use List::Util qw(first);
my $tmp;
my $ws;
is(scalar @content, 1, 'Still one container on this ws');
is(scalar @{$content[0]->{nodes}}, 1, 'Stacked con still has one child node');
+################################################################################
+# When focusing the workspace, changing the layout should have an effect on the
+# workspace, not on the parent (CT_CONTENT) container.
+################################################################################
+
+sub get_output_content {
+ my $tree = i3(get_socket_path())->get_tree->recv;
+
+ my @outputs = grep { $_->{name} !~ /^__/ } @{$tree->{nodes}};
+ is(scalar @outputs, 1, 'exactly one output (testcase not multi-monitor capable)');
+ my $output = $outputs[0];
+ # get the first (and only) CT_CON
+ return first { $_->{type} == 2 } @{$output->{nodes}};
+}
+
+$tmp = fresh_workspace;
+
+cmd 'open';
+cmd 'split v';
+cmd 'open';
+cmd 'focus parent';
+is(get_output_content()->{layout}, 'splith', 'content container layout ok');
+cmd 'layout stacked';
+is(get_output_content()->{layout}, 'splith', 'content container layout still ok');
+
done_testing;