Implement moving workspaces as if they're regular containers
This commit is contained in:
parent
72c66a2091
commit
e89a25f81f
|
@ -174,4 +174,11 @@ void ws_force_orientation(Con *ws, orientation_t orientation);
|
|||
*/
|
||||
Con *workspace_attach_to(Con *ws);
|
||||
|
||||
/**
|
||||
* Creates a new container and re-parents all of children from the given
|
||||
* workspace into it.
|
||||
*
|
||||
* The container inherits the layout from the workspace.
|
||||
*/
|
||||
Con *workspace_encapsulate(Con *ws);
|
||||
#endif
|
||||
|
|
|
@ -388,7 +388,8 @@ void cmd_move_con_to_workspace(I3_CMD, char *which) {
|
|||
* when criteria was specified but didn't match any window or
|
||||
* when criteria wasn't specified and we don't have any window focused. */
|
||||
if ((!match_is_empty(current_match) && TAILQ_EMPTY(&owindows)) ||
|
||||
(match_is_empty(current_match) && focused->type == CT_WORKSPACE)) {
|
||||
(match_is_empty(current_match) && focused->type == CT_WORKSPACE &&
|
||||
con_is_leaf(focused))) {
|
||||
ysuccess(false);
|
||||
return;
|
||||
}
|
||||
|
@ -476,9 +477,8 @@ void cmd_move_con_to_workspace_name(I3_CMD, char *name) {
|
|||
ysuccess(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (match_is_empty(current_match) && focused->type == CT_WORKSPACE) {
|
||||
ELOG("No window to move, you have focused a workspace.\n");
|
||||
else if (match_is_empty(current_match) && focused->type == CT_WORKSPACE &&
|
||||
con_is_leaf(focused)) {
|
||||
ysuccess(false);
|
||||
return;
|
||||
}
|
||||
|
@ -512,7 +512,8 @@ void cmd_move_con_to_workspace_number(I3_CMD, char *which) {
|
|||
* when criteria was specified but didn't match any window or
|
||||
* when criteria wasn't specified and we don't have any window focused. */
|
||||
if ((!match_is_empty(current_match) && TAILQ_EMPTY(&owindows)) ||
|
||||
(match_is_empty(current_match) && focused->type == CT_WORKSPACE)) {
|
||||
(match_is_empty(current_match) && focused->type == CT_WORKSPACE &&
|
||||
con_is_leaf(focused))) {
|
||||
ysuccess(false);
|
||||
return;
|
||||
}
|
||||
|
|
20
src/con.c
20
src/con.c
|
@ -607,11 +607,6 @@ void con_toggle_fullscreen(Con *con, int fullscreen_mode) {
|
|||
*
|
||||
*/
|
||||
void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool dont_warp) {
|
||||
if (con->type == CT_WORKSPACE) {
|
||||
DLOG("Moving workspaces is not yet implemented.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Prevent moving if this would violate the fullscreen focus restrictions. */
|
||||
if (!con_fullscreen_permits_focusing(workspace)) {
|
||||
LOG("Cannot move out of a fullscreen container");
|
||||
|
@ -629,6 +624,21 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool
|
|||
return;
|
||||
}
|
||||
|
||||
if (con->type == CT_WORKSPACE) {
|
||||
con = workspace_encapsulate(con);
|
||||
if (con == NULL) {
|
||||
ELOG("Workspace failed to move its contents into a container!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Re-parent all of the old workspace's floating windows. */
|
||||
Con *child;
|
||||
while (!TAILQ_EMPTY(&(source_ws->floating_head))) {
|
||||
child = TAILQ_FIRST(&(source_ws->floating_head));
|
||||
con_move_to_workspace(child, workspace, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
/* Save the current workspace. So we can call workspace_show() by the end
|
||||
* of this function. */
|
||||
Con *current_ws = con_get_workspace(focused);
|
||||
|
|
|
@ -830,3 +830,34 @@ Con *workspace_attach_to(Con *ws) {
|
|||
|
||||
return new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new container and re-parents all of children from the given
|
||||
* workspace into it.
|
||||
*
|
||||
* The container inherits the layout from the workspace.
|
||||
*/
|
||||
Con *workspace_encapsulate(Con *ws) {
|
||||
if (TAILQ_EMPTY(&(ws->nodes_head))) {
|
||||
ELOG("Workspace %p / %s has no children to encapsulate\n", ws, ws->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Con *new = con_new(NULL, NULL);
|
||||
new->parent = ws;
|
||||
new->layout = ws->layout;
|
||||
|
||||
DLOG("Moving children of workspace %p / %s into container %p\n",
|
||||
ws, ws->name, new);
|
||||
|
||||
Con *child;
|
||||
while (!TAILQ_EMPTY(&(ws->nodes_head))) {
|
||||
child = TAILQ_FIRST(&(ws->nodes_head));
|
||||
con_detach(child);
|
||||
con_attach(child, new, true);
|
||||
}
|
||||
|
||||
con_attach(new, ws, true);
|
||||
|
||||
return new;
|
||||
}
|
||||
|
|
|
@ -198,4 +198,124 @@ cmd 'move workspace number 17';
|
|||
ok(workspace_exists('17'), 'workspace 17 created by moving');
|
||||
is(@{get_ws('17')->{nodes}}, 1, 'one node on ws 16');
|
||||
|
||||
################################################################################
|
||||
# The following four tests verify the various 'move workspace' commands when
|
||||
# the selection is itself a workspace.
|
||||
################################################################################
|
||||
|
||||
# borrowed from 122-split.t
|
||||
# recursively sums up all nodes and their children
|
||||
sub sum_nodes {
|
||||
my ($nodes) = @_;
|
||||
|
||||
return 0 if !@{$nodes};
|
||||
|
||||
my @children = (map { @{$_->{nodes}} } @{$nodes},
|
||||
map { @{$_->{'floating_nodes'}} } @{$nodes});
|
||||
|
||||
return @{$nodes} + sum_nodes(\@children);
|
||||
}
|
||||
|
||||
############################################################
|
||||
# move workspace 'next|prev'
|
||||
############################################################
|
||||
$tmp = get_unused_workspace();
|
||||
$tmp2 = get_unused_workspace();
|
||||
|
||||
cmd "workspace $tmp";
|
||||
cmd 'open';
|
||||
is_num_children($tmp, 1, 'one container on first ws');
|
||||
|
||||
cmd "workspace $tmp2";
|
||||
cmd 'open';
|
||||
is_num_children($tmp2, 1, 'one container on second ws');
|
||||
cmd 'open';
|
||||
is_num_children($tmp2, 2, 'two containers on second ws');
|
||||
|
||||
cmd 'focus parent';
|
||||
cmd 'move workspace prev';
|
||||
|
||||
is_num_children($tmp, 2, 'two child containers on first ws');
|
||||
is(sum_nodes(get_ws_content($tmp)), 4, 'four total containers on first ws');
|
||||
is_num_children($tmp2, 0, 'no containers on second ws');
|
||||
|
||||
############################################################
|
||||
# move workspace current
|
||||
# This is a special case that should be a no-op.
|
||||
############################################################
|
||||
$tmp = fresh_workspace();
|
||||
|
||||
cmd 'open';
|
||||
is_num_children($tmp, 1, 'one container on first ws');
|
||||
my $tmpcount = sum_nodes(get_ws_content($tmp));
|
||||
|
||||
cmd 'focus parent';
|
||||
cmd "move workspace $tmp";
|
||||
|
||||
is(sum_nodes(get_ws_content($tmp)), $tmpcount, 'number of containers in first ws unchanged');
|
||||
|
||||
############################################################
|
||||
# move workspace '<name>'
|
||||
############################################################
|
||||
$tmp2 = get_unused_workspace();
|
||||
$tmp = fresh_workspace();
|
||||
|
||||
cmd 'open';
|
||||
is_num_children($tmp, 1, 'one container on first ws');
|
||||
|
||||
cmd "workspace $tmp2";
|
||||
cmd 'open';
|
||||
is_num_children($tmp2, 1, 'one container on second ws');
|
||||
cmd 'open';
|
||||
is_num_children($tmp2, 2, 'two containers on second ws');
|
||||
|
||||
cmd 'focus parent';
|
||||
cmd "move workspace $tmp";
|
||||
|
||||
is_num_children($tmp, 2, 'two child containers on first ws');
|
||||
is(sum_nodes(get_ws_content($tmp)), 4, 'four total containers on first ws');
|
||||
is_num_children($tmp2, 0, 'no containers on second ws');
|
||||
|
||||
############################################################
|
||||
# move workspace number '<number>'
|
||||
############################################################
|
||||
cmd 'workspace 18';
|
||||
cmd 'open';
|
||||
is_num_children('18', 1, 'one container on ws 18');
|
||||
|
||||
cmd 'workspace 19';
|
||||
cmd 'open';
|
||||
is_num_children('19', 1, 'one container on ws 19');
|
||||
cmd 'open';
|
||||
is_num_children('19', 2, 'two containers on ws 19');
|
||||
|
||||
cmd 'focus parent';
|
||||
cmd 'move workspace number 18';
|
||||
|
||||
is_num_children('18', 2, 'two child containers on ws 18');
|
||||
is(sum_nodes(get_ws_content('18')), 4, 'four total containers on ws 18');
|
||||
is_num_children('19', 0, 'no containers on ws 19');
|
||||
|
||||
###################################################################
|
||||
# move workspace '<name>' with a floating child
|
||||
###################################################################
|
||||
$tmp2 = get_unused_workspace();
|
||||
$tmp = fresh_workspace();
|
||||
cmd 'open';
|
||||
cmd 'floating toggle';
|
||||
cmd 'open';
|
||||
cmd 'floating toggle';
|
||||
cmd 'open';
|
||||
|
||||
$ws = get_ws($tmp);
|
||||
is_num_children($tmp, 1, 'one container on first workspace');
|
||||
is(@{$ws->{floating_nodes}}, 2, 'two floating nodes on first workspace');
|
||||
|
||||
cmd 'focus parent';
|
||||
cmd "move workspace $tmp2";
|
||||
|
||||
$ws = get_ws($tmp2);
|
||||
is_num_children($tmp2, 1, 'one container on second workspace');
|
||||
is(@{$ws->{floating_nodes}}, 2, 'two floating nodes on second workspace');
|
||||
|
||||
done_testing;
|
||||
|
|
Loading…
Reference in New Issue