@ -263,126 +263,141 @@ static void container_move_to_container(struct sway_container *container,
}
}
/* Takes one child, sets it aside, wraps the rest of the children in a new
* container , switches the layout of the workspace , and drops the child back in .
* In other words , rejigger it . */
static void workspace_rejigger ( struct sway_workspace * ws ,
struct sway_container * child , enum wlr_direction move_dir ) {
if ( ! child - > parent & & ws - > tiling - > length = = 1 ) {
ws - > layout =
move_dir = = WLR_DIRECTION_LEFT | | move_dir = = WLR_DIRECTION_RIGHT ?
L_HORIZ : L_VERT ;
workspace_update_representation ( ws ) ;
return ;
static bool container_move_to_next_output ( struct sway_container * container ,
struct sway_output * output , enum wlr_direction move_dir ) {
struct sway_output * next_output =
output_get_in_direction ( output , move_dir ) ;
if ( next_output ) {
struct sway_workspace * ws = output_get_active_workspace ( next_output ) ;
if ( ! sway_assert ( ws , " Expected output to have a workspace " ) ) {
return false ;
}
container_detach ( child ) ;
struct sway_container * new_parent = workspace_wrap_children ( ws ) ;
int index =
move_dir = = WLR_DIRECTION_LEFT | | move_dir = = WLR_DIRECTION_UP ? 0 : 1 ;
workspace_insert_tiling ( ws , child , index ) ;
container_flatten ( new_parent ) ;
ws - > layout =
move_dir = = WLR_DIRECTION_LEFT | | move_dir = = WLR_DIRECTION_RIGHT ?
L_HORIZ : L_VERT ;
workspace_update_representation ( ws ) ;
child - > width = child - > height = 0 ;
switch ( container - > fullscreen_mode ) {
case FULLSCREEN_NONE :
container_move_to_workspace_from_direction ( container , ws , move_dir ) ;
return true ;
case FULLSCREEN_WORKSPACE :
container_move_to_workspace ( container , ws ) ;
return true ;
case FULLSCREEN_GLOBAL :
return false ;
}
}
return false ;
}
// Returns true if moved
static bool container_move_in_direction ( struct sway_container * container ,
enum wlr_direction move_dir ) {
// If moving a fullscreen view, only consider outputs
if ( container - > fullscreen_mode = = FULLSCREEN_WORKSPACE ) {
struct sway_output * new_output =
output_get_in_direction ( container - > workspace - > output , move_dir ) ;
if ( ! new_output ) {
return false ;
}
struct sway_workspace * ws = output_get_active_workspace ( new_output ) ;
if ( ! sway_assert ( ws , " Expected output to have a workspace " ) ) {
return false ;
}
container_move_to_workspace ( container , ws ) ;
return true ;
}
if ( container - > fullscreen_mode = = FULLSCREEN_GLOBAL ) {
switch ( container - > fullscreen_mode ) {
case FULLSCREEN_NONE :
break ;
case FULLSCREEN_WORKSPACE :
return container_move_to_next_output ( container ,
container - > workspace - > output , move_dir ) ;
case FULLSCREEN_GLOBAL :
return false ;
}
// Look for a suitable *container* sibling or parent.
// The below loop stops once we hit the workspace because current->parent
// is NULL for the topmost containers in a workspace.
struct sway_container * current = container ;
int offs =
move_dir = = WLR_DIRECTION_LEFT | | move_dir = = WLR_DIRECTION_UP ? - 1 : 1 ;
int index = - 1 ;
int desired = - 1 ;
list_t * siblings = NULL ;
struct sway_container * target = NULL ;
while ( current ) {
list_t * siblings = container_get_siblings ( current ) ;
if ( siblings ) {
enum sway_container_layout layout = container_parent_layout ( current ) ;
int index = list_find ( siblings , current ) ;
int desired = index + offs ;
// Look for a suitable ancestor of the container to move within
struct sway_container * ancestor = NULL ;
struct sway_container * current = container ;
bool wrapped = false ;
while ( ! ancestor ) {
// Don't allow containers to move out of their
// fullscreen or floating parent
if ( current - > fullscreen_mode | | container_is_floating ( current ) ) {
return false ;
}
if ( is_parallel ( layout , move_dir ) ) {
if ( desired = = - 1 | | desired = = siblings - > length ) {
if ( current - > parent = = container - > parent ) {
current = current - > parent ;
continue ;
} else {
// Reparenting
if ( current - > parent ) {
container_insert_child ( current - > parent , container ,
index + ( offs < 0 ? 0 : 1 ) ) ;
enum sway_container_layout parent_layout = container_parent_layout ( current ) ;
if ( ! is_parallel ( parent_layout , move_dir ) ) {
if ( ! current - > parent ) {
// No parallel parent, so we reorient the workspace
current = workspace_wrap_children ( current - > workspace ) ;
current - > workspace - > layout =
move_dir = = WLR_DIRECTION_LEFT | |
move_dir = = WLR_DIRECTION_RIGHT ?
L_HORIZ : L_VERT ;
container - > height = container - > width = 0 ;
container - > height_fraction = container - > width_fraction = 0 ;
workspace_update_representation ( current - > workspace ) ;
wrapped = true ;
} else {
workspace_insert_tiling ( current - > workspace , container ,
index + ( offs < 0 ? 0 : 1 ) ) ;
// Keep looking for a parallel parent
current = current - > parent ;
}
return tr ue;
contin ue;
}
} else {
// Container can move within its siblings
// Only scratchpad hidden containers don't have siblings
// so siblings != NULL here
siblings = container_get_siblings ( current ) ;
index = list_find ( siblings , current ) ;
desired = index + offs ;
target = desired = = - 1 | | desired = = siblings - > length ?
NULL : siblings - > items [ desired ] ;
// If the move is simple we can complete it here early
if ( current = = container ) {
if ( target ) {
// Container will swap with or descend into its neighbor
container_move_to_container_from_direction ( container ,
siblings - > items [ desired ] , move_dir ) ;
target , move_dir ) ;
return true ;
}
} else if ( ! container - > parent ) {
// Container is at workspace level so we move it to the
// next workspace if possible
return container_move_to_next_output ( container ,
current - > workspace - > output , move_dir ) ;
} else {
// Container has escaped its immediate parallel parent
current = current - > parent ;
continue ;
}
}
current = current - > parent ;
// We found a suitable ancestor, the loop will end
ancestor = current ;
}
// Maybe rejigger the workspace
struct sway_workspace * ws = container - > workspace ;
if ( ws ) {
if ( ! is_parallel ( ws - > layout , move_dir ) ) {
workspace_rejigger ( ws , container , move_dir ) ;
return true ;
} else if ( ws - > layout = = L_TABBED | | ws - > layout = = L_STACKED ) {
workspace_rejigger ( ws , container , move_dir ) ;
if ( target ) {
// Container will move in with its cousin
container_move_to_container_from_direction ( container ,
target , move_dir ) ;
return true ;
} else if ( ! wrapped & & ! container - > parent - > parent & &
container - > parent - > children - > length = = 1 ) {
// Treat singleton children as if they are at workspace level like i3
// https://github.com/i3/i3/blob/1d9160f2d247dbaa83fb62f02fd7041dec767fc2/src/move.c#L367
return container_move_to_next_output ( container ,
ancestor - > workspace - > output , move_dir ) ;
} else {
// Container will be promoted
struct sway_container * old_parent = container - > parent ;
if ( ancestor - > parent ) {
// Container will move in with its parent
container_insert_child ( ancestor - > parent , container ,
index + ( offs < 0 ? 0 : 1 ) ) ;
} else {
// Container will move to workspace level,
// may be re-split by workspace_layout
workspace_insert_tiling ( ancestor - > workspace , container ,
index + ( offs < 0 ? 0 : 1 ) ) ;
}
// Try adjacent output
struct sway_output * output =
output_get_in_direction ( container - > workspace - > output , move_dir ) ;
if ( output ) {
struct sway_workspace * ws = output_get_active_workspace ( output ) ;
if ( ! sway_assert ( ws , " Expected output to have a workspace " ) ) {
return false ;
if ( old_parent ) {
container_reap_empty ( old_parent ) ;
}
container_move_to_workspace_from_direction ( container , ws , move_dir ) ;
return true ;
}
sway_log ( SWAY_DEBUG , " Hit edge of output, nowhere else to go " ) ;
}
return false ;
}
static struct cmd_results * cmd_move_to_scratchpad ( void ) ;