From 7586f150c058997d9dde387ea7c091ffa7a3c3c7 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Thu, 30 Aug 2018 21:00:10 +1000 Subject: Implement type safe arguments and demote sway_container This commit changes the meaning of sway_container so that it only refers to layout containers and view containers. Workspaces, outputs and the root are no longer known as containers. Instead, root, outputs, workspaces and containers are all a type of node, and containers come in two types: layout containers and view containers. In addition to the above, this implements type safe variables. This means we use specific types such as sway_output and sway_workspace instead of generic containers or nodes. However, it's worth noting that in a few places places (eg. seat focus and transactions) referring to them in a generic way is unavoidable which is why we still use nodes in some places. If you want a TL;DR, look at node.h, as well as the struct definitions for root, output, workspace and container. Note that sway_output now contains a workspaces list, and workspaces now contain a tiling and floating list, and containers now contain a pointer back to the workspace. There are now functions for seat_get_focused_workspace and seat_get_focused_container. The latter will return NULL if a workspace itself is focused. Most other seat functions like seat_get_focus and seat_set_focus now accept and return nodes. In the config->handler_context struct, current_container has been replaced with three pointers: node, container and workspace. node is the same as what current_container was, while workspace is the workspace that the node resides on and container is the actual container, which may be NULL if a workspace itself is focused. The global root_container variable has been replaced with one simply called root, which is a pointer to the sway_root instance. The way outputs are created, enabled, disabled and destroyed has changed. Previously we'd wrap the sway_output in a container when it is enabled, but as we don't have containers any more it needs a different approach. The output_create and output_destroy functions previously created/destroyed the container, but now they create/destroy the sway_output. There is a new function output_disable to disable an output without destroying it. Containers have a new view property. If this is populated then the container is a view container, otherwise it's a layout container. Like before, this property is immutable for the life of the container. Containers have both a `sway_container *parent` and `sway_workspace *workspace`. As we use specific types now, parent cannot point to a workspace so it'll be NULL for containers which are direct children of the workspace. The workspace property is set for all containers, except those which are hidden in the scratchpad as they have no workspace. In some cases we need to refer to workspaces in a container-like way. For example, workspaces have layout and children, but when using specific types this makes it difficult. Likewise, it's difficult for a container to get its parent's layout when the parent could be another container or a workspace. To make it easier, some helper functions have been created: container_parent_layout and container_get_siblings. container_remove_child has been renamed to container_detach and container_replace_child has been renamed to container_replace. `container_handle_fullscreen_reparent(con, old_parent)` has had the old_parent removed. We now unfullscreen the workspace when detaching the container, so this function is simplified and only needs one argument now. container_notify_subtree_changed has been renamed to container_update_representation. This is more descriptive of its purpose. I also wanted to be able to call it with whatever container was changed rather than the container's parent, which makes bubbling up to the workspace easier. There are now state structs per node thing. ie. sway_output_state, sway_workspace_state and sway_container_state. The focus, move and layout commands have been completely refactored to work with the specific types. I considered making these a separate PR, but I'd be backporting my changes only to replace them again, and it's easier just to test everything at once. --- sway/commands/border.c | 13 +- sway/commands/floating.c | 18 +- sway/commands/focus.c | 264 +++++------- sway/commands/fullscreen.c | 18 +- sway/commands/gaps.c | 35 +- sway/commands/hide_edge_borders.c | 4 +- sway/commands/kill.c | 20 +- sway/commands/layout.c | 186 ++++---- sway/commands/mark.c | 7 +- sway/commands/move.c | 873 ++++++++++++++++++-------------------- sway/commands/opacity.c | 3 +- sway/commands/reload.c | 2 +- sway/commands/rename.c | 11 +- sway/commands/resize.c | 86 ++-- sway/commands/scratchpad.c | 42 +- sway/commands/seat/cursor.c | 4 +- sway/commands/show_marks.c | 10 +- sway/commands/smart_gaps.c | 2 +- sway/commands/split.c | 23 +- sway/commands/sticky.c | 27 +- sway/commands/swap.c | 76 ++-- sway/commands/title_format.c | 7 +- sway/commands/unmark.c | 13 +- sway/commands/urgent.c | 7 +- sway/commands/workspace.c | 2 +- 25 files changed, 838 insertions(+), 915 deletions(-) (limited to 'sway/commands') diff --git a/sway/commands/border.c b/sway/commands/border.c index 9502c877..95498b2f 100644 --- a/sway/commands/border.c +++ b/sway/commands/border.c @@ -13,13 +13,12 @@ struct cmd_results *cmd_border(int argc, char **argv) { return error; } - struct sway_container *container = - config->handler_context.current_container; - if (container->type != C_VIEW) { + struct sway_container *container = config->handler_context.container; + if (!container->view) { return cmd_results_new(CMD_INVALID, "border", "Only views can have borders"); } - struct sway_view *view = container->sway_view; + struct sway_view *view = container->view; if (strcmp(argv[0], "none") == 0) { view->border = B_NONE; @@ -38,11 +37,11 @@ struct cmd_results *cmd_border(int argc, char **argv) { view->border_thickness = atoi(argv[1]); } - if (container_is_floating(view->swayc)) { - container_set_geometry_from_floating_view(view->swayc); + if (container_is_floating(view->container)) { + container_set_geometry_from_floating_view(view->container); } - arrange_windows(view->swayc); + arrange_container(view->container); struct sway_seat *seat = input_manager_current_seat(input_manager); if (seat->cursor) { diff --git a/sway/commands/floating.c b/sway/commands/floating.c index 436376e3..d8729094 100644 --- a/sway/commands/floating.c +++ b/sway/commands/floating.c @@ -15,24 +15,23 @@ struct cmd_results *cmd_floating(int argc, char **argv) { if ((error = checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1))) { return error; } - struct sway_container *container = - config->handler_context.current_container; - if (container->type == C_WORKSPACE && container->children->length == 0) { + struct sway_container *container = config->handler_context.container; + struct sway_workspace *workspace = config->handler_context.workspace; + if (!container && workspace->tiling->length == 0) { return cmd_results_new(CMD_INVALID, "floating", "Can't float an empty workspace"); } - if (container->type == C_WORKSPACE) { + if (!container) { // Wrap the workspace's children in a container so we can float it - struct sway_container *workspace = container; - container = workspace_wrap_children(container); + container = workspace_wrap_children(workspace); workspace->layout = L_HORIZ; - seat_set_focus(config->handler_context.seat, container); + seat_set_focus(config->handler_context.seat, &container->node); } // If the container is in a floating split container, // operate on the split container instead of the child. if (container_is_floating_or_child(container)) { - while (container->parent->type != C_WORKSPACE) { + while (container->parent) { container = container->parent; } } @@ -51,8 +50,7 @@ struct cmd_results *cmd_floating(int argc, char **argv) { container_set_floating(container, wants_floating); - struct sway_container *workspace = container_parent(container, C_WORKSPACE); - arrange_windows(workspace); + arrange_workspace(container->workspace); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/focus.c b/sway/commands/focus.c index f342e524..e31898af 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c @@ -34,211 +34,139 @@ static bool parse_movement_direction(const char *name, } /** - * Get swayc in the direction of newly entered output. + * Get node in the direction of newly entered output. */ -static struct sway_container *get_swayc_in_output_direction( - struct sway_container *output, enum movement_direction dir, - struct sway_seat *seat) { - if (!output) { - return NULL; - } - - struct sway_container *ws = seat_get_focus_inactive(seat, output); - if (ws->type != C_WORKSPACE) { - ws = container_parent(ws, C_WORKSPACE); - } - - if (ws == NULL) { - wlr_log(WLR_ERROR, "got an output without a workspace"); - return NULL; +static struct sway_node *get_node_in_output_direction( + struct sway_output *output, enum movement_direction dir) { + struct sway_seat *seat = config->handler_context.seat; + struct sway_workspace *ws = output_get_active_workspace(output); + if (ws->fullscreen) { + return seat_get_focus_inactive(seat, &ws->fullscreen->node); } + struct sway_container *container = NULL; - if (ws->children->length > 0) { + if (ws->tiling->length > 0) { switch (dir) { case MOVE_LEFT: if (ws->layout == L_HORIZ || ws->layout == L_TABBED) { // get most right child of new output - return ws->children->items[ws->children->length-1]; + container = ws->tiling->items[ws->tiling->length-1]; } else { - return seat_get_focus_inactive(seat, ws); + container = seat_get_focus_inactive_tiling(seat, ws); } + return &container->node; case MOVE_RIGHT: if (ws->layout == L_HORIZ || ws->layout == L_TABBED) { // get most left child of new output - return ws->children->items[0]; + container = ws->tiling->items[0]; } else { - return seat_get_focus_inactive(seat, ws); + container = seat_get_focus_inactive_tiling(seat, ws); } + return &container->node; case MOVE_UP: + if (ws->layout == L_VERT || ws->layout == L_STACKED) { + // get most bottom child of new output + container = ws->tiling->items[ws->tiling->length-1]; + } else { + container = seat_get_focus_inactive_tiling(seat, ws); + } + return &container->node; case MOVE_DOWN: { - struct sway_container *focused = - seat_get_focus_inactive(seat, ws); - if (focused && focused->parent) { - struct sway_container *parent = focused->parent; - if (parent->layout == L_VERT) { - if (dir == MOVE_UP) { - // get child furthest down on new output - int idx = parent->children->length - 1; - return parent->children->items[idx]; - } else if (dir == MOVE_DOWN) { - // get child furthest up on new output - return parent->children->items[0]; - } - } - return focused; + if (ws->layout == L_VERT || ws->layout == L_STACKED) { + // get most top child of new output + container = ws->tiling->items[0]; + } else { + container = seat_get_focus_inactive_tiling(seat, ws); } - break; + return &container->node; } default: break; } } - return ws; + return &ws->node; } -static struct sway_container *container_get_in_direction( - struct sway_container *container, struct sway_seat *seat, - enum movement_direction dir) { - struct sway_container *parent = container->parent; - +static struct sway_node *node_get_in_direction(struct sway_container *container, + struct sway_seat *seat, enum movement_direction dir) { if (dir == MOVE_CHILD) { - return seat_get_focus_inactive(seat, container); + return seat_get_active_child(seat, &container->node); } if (container->is_fullscreen) { if (dir == MOVE_PARENT) { return NULL; } - container = container_parent(container, C_OUTPUT); - parent = container->parent; - } else { - if (dir == MOVE_PARENT) { - if (parent->type == C_OUTPUT || container_is_floating(container)) { - return NULL; - } else { - return parent; - } - } + // Fullscreen container with a direction - go straight to outputs + struct sway_output *output = container->workspace->output; + struct sway_output *new_output = output_get_in_direction(output, dir); + return get_node_in_output_direction(new_output, dir); + } + if (dir == MOVE_PARENT) { + return node_get_parent(&container->node); } struct sway_container *wrap_candidate = NULL; - while (true) { + struct sway_container *current = container; + while (current) { bool can_move = false; int desired; - int idx = list_find(container->parent->children, container); - if (idx == -1) { - return NULL; - } - if (parent->type == C_ROOT) { - enum wlr_direction wlr_dir = 0; - if (!sway_assert(sway_dir_to_wlr(dir, &wlr_dir), - "got invalid direction: %d", dir)) { - return NULL; - } - int lx = container->x + container->width / 2; - int ly = container->y + container->height / 2; - struct wlr_output_layout *layout = - root_container.sway_root->output_layout; - struct wlr_output *wlr_adjacent = - wlr_output_layout_adjacent_output(layout, wlr_dir, - container->sway_output->wlr_output, lx, ly); - struct sway_container *adjacent = - output_from_wlr_output(wlr_adjacent); + int idx = container_sibling_index(current); + enum sway_container_layout parent_layout = + container_parent_layout(current); + list_t *siblings = container_get_siblings(current); - if (!adjacent || adjacent == container) { - if (!wrap_candidate) { - return NULL; - } - return seat_get_focus_inactive_view(seat, wrap_candidate); - } - struct sway_container *next = - get_swayc_in_output_direction(adjacent, dir, seat); - if (next == NULL) { - return NULL; - } - struct sway_container *next_workspace = next; - if (next_workspace->type != C_WORKSPACE) { - next_workspace = container_parent(next_workspace, C_WORKSPACE); - } - sway_assert(next_workspace, "Next container has no workspace"); - if (next_workspace->sway_workspace->fullscreen) { - return seat_get_focus_inactive(seat, - next_workspace->sway_workspace->fullscreen); - } - if (next->children && next->children->length) { - // TODO consider floating children as well - return seat_get_focus_inactive_view(seat, next); - } else { - return next; + if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { + if (parent_layout == L_HORIZ || parent_layout == L_TABBED) { + can_move = true; + desired = idx + (dir == MOVE_LEFT ? -1 : 1); } } else { - if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { - if (parent->layout == L_HORIZ || parent->layout == L_TABBED) { - can_move = true; - desired = idx + (dir == MOVE_LEFT ? -1 : 1); - } - } else { - if (parent->layout == L_VERT || parent->layout == L_STACKED) { - can_move = true; - desired = idx + (dir == MOVE_UP ? -1 : 1); - } + if (parent_layout == L_VERT || parent_layout == L_STACKED) { + can_move = true; + desired = idx + (dir == MOVE_UP ? -1 : 1); } } if (can_move) { - // TODO handle floating - if (desired < 0 || desired >= parent->children->length) { + if (desired < 0 || desired >= siblings->length) { can_move = false; - int len = parent->children->length; + int len = siblings->length; if (config->focus_wrapping != WRAP_NO && !wrap_candidate && len > 1) { if (desired < 0) { - wrap_candidate = parent->children->items[len-1]; + wrap_candidate = siblings->items[len-1]; } else { - wrap_candidate = parent->children->items[0]; + wrap_candidate = siblings->items[0]; } if (config->focus_wrapping == WRAP_FORCE) { - return seat_get_focus_inactive_view(seat, - wrap_candidate); + struct sway_container *c = seat_get_focus_inactive_view( + seat, &wrap_candidate->node); + return &c->node; } } } else { - struct sway_container *desired_con = - parent->children->items[desired]; - wlr_log(WLR_DEBUG, - "cont %d-%p dir %i sibling %d: %p", idx, - container, dir, desired, desired_con); - return seat_get_focus_inactive_view(seat, desired_con); + struct sway_container *desired_con = siblings->items[desired]; + struct sway_container *c = seat_get_focus_inactive_view( + seat, &desired_con->node); + return &c->node; } } - if (!can_move) { - container = parent; - parent = parent->parent; - if (!parent) { - // wrapping is the last chance - if (!wrap_candidate) { - return NULL; - } - return seat_get_focus_inactive_view(seat, wrap_candidate); - } - } + current = current->parent; } -} -static struct cmd_results *focus_mode(struct sway_container *con, - struct sway_seat *seat, bool floating) { - struct sway_container *ws = con->type == C_WORKSPACE ? - con : container_parent(con, C_WORKSPACE); - - // If the container is in a floating split container, - // operate on the split container instead of the child. - if (container_is_floating_or_child(con)) { - while (con->parent->type != C_WORKSPACE) { - con = con->parent; - } + // Check a different output + struct sway_output *output = container->workspace->output; + struct sway_output *new_output = output_get_in_direction(output, dir); + if (new_output) { + return get_node_in_output_direction(new_output, dir); } + return NULL; +} +static struct cmd_results *focus_mode(struct sway_workspace *ws, + struct sway_seat *seat, bool floating) { struct sway_container *new_focus = NULL; if (floating) { new_focus = seat_get_focus_inactive_floating(seat, ws); @@ -246,7 +174,7 @@ static struct cmd_results *focus_mode(struct sway_container *con, new_focus = seat_get_focus_inactive_tiling(seat, ws); } if (new_focus) { - seat_set_focus(seat, new_focus); + seat_set_focus(seat, &new_focus->node); } else { return cmd_results_new(CMD_FAILURE, "focus", "Failed to find a %s container in workspace", @@ -255,14 +183,14 @@ static struct cmd_results *focus_mode(struct sway_container *con, return cmd_results_new(CMD_SUCCESS, NULL, NULL); } -static struct cmd_results *focus_output(struct sway_container *con, - struct sway_seat *seat, int argc, char **argv) { +static struct cmd_results *focus_output(struct sway_seat *seat, + int argc, char **argv) { if (!argc) { return cmd_results_new(CMD_INVALID, "focus", "Expected 'focus output '"); } char *identifier = join_args(argv, argc); - struct sway_container *output = output_by_name(identifier); + struct sway_output *output = output_by_name(identifier); if (!output) { enum movement_direction direction; @@ -272,14 +200,13 @@ static struct cmd_results *focus_output(struct sway_container *con, return cmd_results_new(CMD_INVALID, "focus", "There is no output with that name"); } - struct sway_container *focus = seat_get_focus(seat); - focus = container_parent(focus, C_OUTPUT); - output = container_get_in_direction(focus, seat, direction); + struct sway_workspace *ws = seat_get_focused_workspace(seat); + output = output_get_in_direction(ws->output, direction); } free(identifier); if (output) { - seat_set_focus(seat, seat_get_focus_inactive(seat, output)); + seat_set_focus(seat, seat_get_focus_inactive(seat, &output->node)); } return cmd_results_new(CMD_SUCCESS, NULL, NULL); @@ -289,29 +216,32 @@ struct cmd_results *cmd_focus(int argc, char **argv) { if (config->reading || !config->active) { return cmd_results_new(CMD_DEFER, NULL, NULL); } - struct sway_container *con = config->handler_context.current_container; + struct sway_node *node = config->handler_context.node; + struct sway_container *container = config->handler_context.container; + struct sway_workspace *workspace = config->handler_context.workspace; struct sway_seat *seat = config->handler_context.seat; - if (con->type < C_WORKSPACE) { + if (node->type < N_WORKSPACE) { return cmd_results_new(CMD_FAILURE, "focus", "Command 'focus' cannot be used above the workspace level"); } if (argc == 0) { - seat_set_focus(seat, con); + seat_set_focus(seat, node); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } if (strcmp(argv[0], "floating") == 0) { - return focus_mode(con, seat, true); + return focus_mode(workspace, seat, true); } else if (strcmp(argv[0], "tiling") == 0) { - return focus_mode(con, seat, false); + return focus_mode(workspace, seat, false); } else if (strcmp(argv[0], "mode_toggle") == 0) { - return focus_mode(con, seat, !container_is_floating_or_child(con)); + bool floating = container && container_is_floating_or_child(container); + return focus_mode(workspace, seat, !floating); } if (strcmp(argv[0], "output") == 0) { argc--; argv++; - return focus_output(con, seat, argc, argv); + return focus_output(seat, argc, argv); } enum movement_direction direction = 0; @@ -321,8 +251,18 @@ struct cmd_results *cmd_focus(int argc, char **argv) { "or 'focus output '"); } - struct sway_container *next_focus = container_get_in_direction( - con, seat, direction); + if (node->type == N_WORKSPACE) { + // A workspace is focused, so just jump to the next output + struct sway_output *new_output = + output_get_in_direction(workspace->output, direction); + struct sway_node *node = + get_node_in_output_direction(new_output, direction); + seat_set_focus(seat, node); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + + struct sway_node *next_focus = + node_get_in_direction(container, seat, direction); if (next_focus) { seat_set_focus(seat, next_focus); } diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c index ac65dffb..3bbe00c5 100644 --- a/sway/commands/fullscreen.c +++ b/sway/commands/fullscreen.c @@ -12,18 +12,18 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) { if ((error = checkarg(argc, "fullscreen", EXPECTED_LESS_THAN, 2))) { return error; } - struct sway_container *container = - config->handler_context.current_container; - if (container->type == C_WORKSPACE && container->children->length == 0) { + struct sway_node *node = config->handler_context.node; + struct sway_container *container = config->handler_context.container; + struct sway_workspace *workspace = config->handler_context.workspace; + if (node->type == N_WORKSPACE && workspace->tiling->length == 0) { return cmd_results_new(CMD_INVALID, "fullscreen", "Can't fullscreen an empty workspace"); } - if (container->type == C_WORKSPACE) { + if (node->type == N_WORKSPACE) { // Wrap the workspace's children in a container so we can fullscreen it - struct sway_container *workspace = container; - container = workspace_wrap_children(container); + container = workspace_wrap_children(workspace); workspace->layout = L_HORIZ; - seat_set_focus(config->handler_context.seat, container); + seat_set_focus(config->handler_context.seat, &container->node); } bool enable = !container->is_fullscreen; @@ -32,9 +32,7 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) { } container_set_fullscreen(container, enable); - - struct sway_container *workspace = container_parent(container, C_WORKSPACE); - arrange_windows(workspace->parent); + arrange_workspace(workspace); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/gaps.c b/sway/commands/gaps.c index 3906eb70..d676e475 100644 --- a/sway/commands/gaps.c +++ b/sway/commands/gaps.c @@ -2,6 +2,7 @@ #include "sway/commands.h" #include "sway/config.h" #include "sway/tree/arrange.h" +#include "sway/tree/workspace.h" #include "log.h" #include "stringop.h" #include @@ -43,7 +44,7 @@ struct cmd_results *cmd_gaps(int argc, char **argv) { return cmd_results_new(CMD_INVALID, "gaps", "gaps edge_gaps on|off|toggle"); } - arrange_windows(&root_container); + arrange_root(); } else { int amount_idx = 0; // the current index in argv enum gaps_op op = GAPS_OP_SET; @@ -124,7 +125,7 @@ struct cmd_results *cmd_gaps(int argc, char **argv) { if (amount_idx == 0) { // gaps config->gaps_inner = val; config->gaps_outer = val; - arrange_windows(&root_container); + arrange_root(); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } // Other variants. The middle-length variant (gaps inner|outer ) @@ -155,21 +156,27 @@ struct cmd_results *cmd_gaps(int argc, char **argv) { } else { config->gaps_outer = total; } - arrange_windows(&root_container); + arrange_root(); } else { - struct sway_container *c = - config->handler_context.current_container; - if (scope == GAPS_SCOPE_WORKSPACE && c->type != C_WORKSPACE) { - c = container_parent(c, C_WORKSPACE); - } - c->has_gaps = true; - if (inner) { - c->gaps_inner = total; + if (scope == GAPS_SCOPE_WORKSPACE) { + struct sway_workspace *ws = config->handler_context.workspace; + ws->has_gaps = true; + if (inner) { + ws->gaps_inner = total; + } else { + ws->gaps_outer = total; + } + arrange_workspace(ws); } else { - c->gaps_outer = total; + struct sway_container *c = config->handler_context.container; + c->has_gaps = true; + if (inner) { + c->gaps_inner = total; + } else { + c->gaps_outer = total; + } + arrange_workspace(c->workspace); } - - arrange_windows(c->parent ? c->parent : &root_container); } } diff --git a/sway/commands/hide_edge_borders.c b/sway/commands/hide_edge_borders.c index e494f6aa..0a5c7f28 100644 --- a/sway/commands/hide_edge_borders.c +++ b/sway/commands/hide_edge_borders.c @@ -5,8 +5,8 @@ #include "sway/tree/view.h" static void _configure_view(struct sway_container *con, void *data) { - if (con->type == C_VIEW) { - view_autoconfigure(con->sway_view); + if (con->view) { + view_autoconfigure(con->view); } } diff --git a/sway/commands/kill.c b/sway/commands/kill.c index f3fa52f1..85ca0f33 100644 --- a/sway/commands/kill.c +++ b/sway/commands/kill.c @@ -2,15 +2,27 @@ #include "log.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" -#include "sway/tree/view.h" #include "sway/tree/container.h" +#include "sway/tree/view.h" +#include "sway/tree/workspace.h" #include "sway/commands.h" +static void close_container_iterator(struct sway_container *con, void *data) { + if (con->view) { + view_close(con->view); + } +} + struct cmd_results *cmd_kill(int argc, char **argv) { - struct sway_container *con = - config->handler_context.current_container; + struct sway_container *con = config->handler_context.container; + struct sway_workspace *ws = config->handler_context.workspace; - container_close(con); + if (con) { + close_container_iterator(con, NULL); + container_for_each_child(con, close_container_iterator, NULL); + } else { + workspace_for_each_container(ws, close_container_iterator, NULL); + } return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/layout.c b/sway/commands/layout.c index a06832de..8fa1ce98 100644 --- a/sway/commands/layout.c +++ b/sway/commands/layout.c @@ -4,21 +4,20 @@ #include "sway/commands.h" #include "sway/tree/arrange.h" #include "sway/tree/container.h" +#include "sway/tree/workspace.h" #include "log.h" -static bool parse_layout_string(char *s, enum sway_container_layout *ptr) { +static enum sway_container_layout parse_layout_string(char *s) { if (strcasecmp(s, "splith") == 0) { - *ptr = L_HORIZ; + return L_HORIZ; } else if (strcasecmp(s, "splitv") == 0) { - *ptr = L_VERT; + return L_VERT; } else if (strcasecmp(s, "tabbed") == 0) { - *ptr = L_TABBED; + return L_TABBED; } else if (strcasecmp(s, "stacking") == 0) { - *ptr = L_STACKED; - } else { - return false; + return L_STACKED; } - return true; + return L_NONE; } static const char* expected_syntax = @@ -26,84 +25,129 @@ static const char* expected_syntax = "'layout toggle [split|all]' or " "'layout toggle [split|tabbed|stacking|splitv|splith] [split|tabbed|stacking|splitv|splith]...'"; +static enum sway_container_layout get_layout_toggle(int argc, char **argv, + enum sway_container_layout layout, + enum sway_container_layout prev_split_layout) { + // "layout toggle" + if (argc == 0) { + return layout == L_HORIZ ? L_VERT : L_HORIZ; + } + + if (argc == 2) { + // "layout toggle split" (same as "layout toggle") + if (strcasecmp(argv[1], "split") == 0) { + return layout == L_HORIZ ? L_VERT : L_HORIZ; + } + // "layout toggle all" + if (strcasecmp(argv[1], "all") == 0) { + return layout == L_HORIZ ? L_VERT : + layout == L_VERT ? L_STACKED : + layout == L_STACKED ? L_TABBED : L_HORIZ; + } + return L_NONE; + } + + enum sway_container_layout parsed; + int curr = 1; + for (; curr < argc; curr++) { + parsed = parse_layout_string(argv[curr]); + if (parsed == layout || (strcmp(argv[curr], "split") == 0 && + (layout == L_VERT || layout == L_HORIZ))) { + break; + } + } + for (int i = curr + 1; i != curr; ++i) { + // cycle round to find next valid layout + if (i >= argc) { + i = 1; + } + parsed = parse_layout_string(argv[i]); + if (parsed != L_NONE) { + return parsed; + } + if (strcmp(argv[i], "split") == 0) { + return layout == L_HORIZ ? L_VERT : + layout == L_VERT ? L_HORIZ : prev_split_layout; + } + // invalid layout strings are silently ignored + } + return L_NONE; +} + +static enum sway_container_layout get_layout(int argc, char **argv, + enum sway_container_layout layout, + enum sway_container_layout prev_split_layout) { + // Check if assigned directly + enum sway_container_layout parsed = parse_layout_string(argv[0]); + if (parsed != L_NONE) { + return parsed; + } + + if (strcasecmp(argv[0], "default") == 0) { + return prev_split_layout; + } + + if (strcasecmp(argv[0], "toggle") == 0) { + argc--; argv++; + return get_layout_toggle(argc, argv, layout, prev_split_layout); + } + + return L_NONE; +} + struct cmd_results *cmd_layout(int argc, char **argv) { struct cmd_results *error = NULL; if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) { return error; } - struct sway_container *parent = config->handler_context.current_container; + struct sway_container *container = config->handler_context.container; + struct sway_workspace *workspace = config->handler_context.workspace; - if (container_is_floating(parent)) { + if (container && container_is_floating(container)) { return cmd_results_new(CMD_FAILURE, "layout", "Unable to change layout of floating windows"); } - while (parent->type == C_VIEW) { - parent = parent->parent; + // Typically we change the layout of the current container, but if the + // current container is a view (it usually is) then we'll change the layout + // of the parent instead, as it doesn't make sense for views to have layout. + if (container && container->view) { + container = container->parent; } - enum sway_container_layout prev = parent->layout; - bool assigned_directly = parse_layout_string(argv[0], &parent->layout); - if (!assigned_directly) { - if (strcasecmp(argv[0], "default") == 0) { - parent->layout = parent->prev_split_layout; - } else if (strcasecmp(argv[0], "toggle") == 0) { - if (argc == 1) { - parent->layout = - parent->layout == L_STACKED ? L_TABBED : - parent->layout == L_TABBED ? parent->prev_split_layout : L_STACKED; - } else if (argc == 2) { - if (strcasecmp(argv[1], "all") == 0) { - parent->layout = - parent->layout == L_HORIZ ? L_VERT : - parent->layout == L_VERT ? L_STACKED : - parent->layout == L_STACKED ? L_TABBED : L_HORIZ; - } else if (strcasecmp(argv[1], "split") == 0) { - parent->layout = - parent->layout == L_HORIZ ? L_VERT : - parent->layout == L_VERT ? L_HORIZ : parent->prev_split_layout; - } else { - return cmd_results_new(CMD_INVALID, "layout", expected_syntax); - } - } else { - enum sway_container_layout parsed_layout; - int curr = 1; - for (; curr < argc; curr++) { - bool valid = parse_layout_string(argv[curr], &parsed_layout); - if ((valid && parsed_layout == parent->layout) || - (strcmp(argv[curr], "split") == 0 && - (parent->layout == L_VERT || parent->layout == L_HORIZ))) { - break; - } - } - for (int i = curr + 1; i != curr; ++i) { - // cycle round to find next valid layout - if (i >= argc) { - i = 1; - } - if (parse_layout_string(argv[i], &parent->layout)) { - break; - } else if (strcmp(argv[i], "split") == 0) { - parent->layout = - parent->layout == L_HORIZ ? L_VERT : - parent->layout == L_VERT ? L_HORIZ : parent->prev_split_layout; - break; - } // invalid layout strings are silently ignored - } - } - } else { - return cmd_results_new(CMD_INVALID, "layout", expected_syntax); - } + // We could be working with a container OR a workspace. These are different + // structures, so we set up pointers to they layouts so we can refer them in + // an abstract way. + enum sway_container_layout new_layout = L_NONE; + enum sway_container_layout old_layout = L_NONE; + if (container) { + old_layout = container->layout; + new_layout = get_layout(argc, argv, + container->layout, container->prev_split_layout); + } else { + old_layout = workspace->layout; + new_layout = get_layout(argc, argv, + workspace->layout, workspace->prev_split_layout); } - if (parent->layout == L_NONE) { - parent->layout = container_get_default_layout(parent); + if (new_layout == L_NONE) { + return cmd_results_new(CMD_INVALID, "layout", expected_syntax); } - if (prev != parent->layout) { - if (prev != L_TABBED && prev != L_STACKED) { - parent->prev_split_layout = prev; + if (new_layout != old_layout) { + if (container) { + if (old_layout != L_TABBED && old_layout != L_STACKED) { + container->prev_split_layout = old_layout; + } + container->layout = new_layout; + container_update_representation(container); + arrange_container(container); + } else { + if (old_layout != L_TABBED && old_layout != L_STACKED) { + workspace->prev_split_layout = old_layout; + } + workspace->layout = new_layout; + workspace_update_representation(workspace); + arrange_workspace(workspace); } - container_notify_subtree_changed(parent); - arrange_windows(parent->parent); } return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/commands/mark.c b/sway/commands/mark.c index 9ea8c301..fb95a7d0 100644 --- a/sway/commands/mark.c +++ b/sway/commands/mark.c @@ -18,13 +18,12 @@ struct cmd_results *cmd_mark(int argc, char **argv) { if ((error = checkarg(argc, "mark", EXPECTED_AT_LEAST, 1))) { return error; } - struct sway_container *container = - config->handler_context.current_container; - if (container->type != C_VIEW) { + struct sway_container *container = config->handler_context.container; + if (!container->view) { return cmd_results_new(CMD_INVALID, "mark", "Only views can have marks"); } - struct sway_view *view = container->sway_view; + struct sway_view *view = container->view; bool add = false, toggle = false; while (argc > 0 && strncmp(*argv, "--", 2) == 0) { diff --git a/sway/commands/move.c b/sway/commands/move.c index 4426f24e..1b2e830c 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -40,7 +40,7 @@ enum wlr_direction opposite_direction(enum wlr_direction d) { } } -static struct sway_container *output_in_direction(const char *direction_string, +static struct sway_output *output_in_direction(const char *direction_string, struct wlr_output *reference, int ref_lx, int ref_ly) { struct { char *name; @@ -63,447 +63,367 @@ static struct sway_container *output_in_direction(const char *direction_string, if (direction) { struct wlr_output *target = wlr_output_layout_adjacent_output( - root_container.sway_root->output_layout, - direction, reference, ref_lx, ref_ly); + root->output_layout, direction, reference, ref_lx, ref_ly); if (!target) { target = wlr_output_layout_farthest_output( - root_container.sway_root->output_layout, - opposite_direction(direction), reference, ref_lx, ref_ly); + root->output_layout, opposite_direction(direction), + reference, ref_lx, ref_ly); } if (target) { - struct sway_output *sway_output = target->data; - return sway_output->swayc; + return target->data; } } return output_by_name(direction_string); } -static void container_move_to(struct sway_container *container, - struct sway_container *destination) { - if (!sway_assert(container->type == C_CONTAINER || - container->type == C_VIEW, "Expected a container or view")) { - return; +static bool is_parallel(enum sway_container_layout layout, + enum movement_direction dir) { + switch (layout) { + case L_TABBED: + case L_HORIZ: + return dir == MOVE_LEFT || dir == MOVE_RIGHT; + case L_STACKED: + case L_VERT: + return dir == MOVE_UP || dir == MOVE_DOWN; + default: + return false; } - if (container == destination - || container_has_ancestor(container, destination)) { +} + +/** + * Ensures all seats focus the fullscreen container if needed. + */ +static void workspace_focus_fullscreen(struct sway_workspace *workspace) { + if (!workspace->fullscreen) { return; } - struct sway_container *old_parent = NULL; - struct sway_container *new_parent = NULL; - if (container_is_floating(container)) { - // Resolve destination into a workspace - struct sway_container *new_ws = NULL; - if (destination->type == C_OUTPUT) { - new_ws = output_get_active_workspace(destination->sway_output); - } else if (destination->type == C_WORKSPACE) { - new_ws = destination; - } else { - new_ws = container_parent(destination, C_WORKSPACE); + struct sway_seat *seat; + struct sway_workspace *focus_ws; + wl_list_for_each(seat, &input_manager->seats, link) { + focus_ws = seat_get_focused_workspace(seat); + if (focus_ws == workspace) { + struct sway_node *new_focus = + seat_get_focus_inactive(seat, &workspace->fullscreen->node); + seat_set_focus(seat, new_focus); } - if (!new_ws) { - // This can happen if the user has run "move container to mark foo", - // where mark foo is on a hidden scratchpad container. - return; + } +} + +static void container_move_to_container_from_direction( + struct sway_container *container, struct sway_container *destination, + enum movement_direction move_dir) { + if (destination->view) { + if (destination->parent == container->parent) { + wlr_log(WLR_DEBUG, "Swapping siblings"); + list_t *siblings = container_get_siblings(container); + int container_index = list_find(siblings, container); + int destination_index = list_find(siblings, destination); + list_swap(siblings, container_index, destination_index); + } else { + wlr_log(WLR_DEBUG, "Promoting to sibling of cousin"); + int offset = move_dir == MOVE_LEFT || move_dir == MOVE_UP; + int index = container_sibling_index(destination) + offset; + if (destination->parent) { + container_insert_child(destination->parent, container, index); + } else { + workspace_insert_tiling(destination->workspace, + container, index); + } + container->width = container->height = 0; } - struct sway_container *old_output = - container_parent(container, C_OUTPUT); - old_parent = container_remove_child(container); - workspace_add_floating(new_ws, container); - container_handle_fullscreen_reparent(container, old_parent); + return; + } + + if (is_parallel(destination->layout, move_dir)) { + wlr_log(WLR_DEBUG, "Reparenting container (parallel)"); + int index = move_dir == MOVE_RIGHT || move_dir == MOVE_DOWN ? + 0 : destination->children->length; + container_insert_child(destination, container, index); + container->width = container->height = 0; + return; + } + + wlr_log(WLR_DEBUG, "Reparenting container (perpendicular)"); + struct sway_node *focus_inactive = seat_get_active_child( + config->handler_context.seat, &destination->node); + if (!focus_inactive || focus_inactive == &destination->node) { + // The container has no children + container_add_child(destination, container); + return; + } + + // Try again but with the child + container_move_to_container_from_direction(container, + focus_inactive->sway_container, move_dir); +} + +static void container_move_to_workspace_from_direction( + struct sway_container *container, struct sway_workspace *workspace, + enum movement_direction move_dir) { + if (is_parallel(workspace->layout, move_dir)) { + wlr_log(WLR_DEBUG, "Reparenting container (parallel)"); + int index = move_dir == MOVE_RIGHT || move_dir == MOVE_DOWN ? + 0 : workspace->tiling->length; + workspace_insert_tiling(workspace, container, index); + return; + } + + wlr_log(WLR_DEBUG, "Reparenting container (perpendicular)"); + struct sway_container *focus_inactive = seat_get_focus_inactive_tiling( + config->handler_context.seat, workspace); + if (!focus_inactive) { + // The workspace has no tiling children + workspace_add_tiling(workspace, container); + return; + } + while (focus_inactive->parent) { + focus_inactive = focus_inactive->parent; + } + container_move_to_container_from_direction(container, focus_inactive, + move_dir); +} + +static void container_move_to_workspace(struct sway_container *container, + struct sway_workspace *workspace) { + if (container->workspace == workspace) { + return; + } + struct sway_workspace *old_workspace = container->workspace; + if (container_is_floating(container)) { + struct sway_output *old_output = container->workspace->output; + container_detach(container); + workspace_add_floating(workspace, container); + container_handle_fullscreen_reparent(container); // If changing output, center it within the workspace - if (old_output != new_ws->parent && !container->is_fullscreen) { + if (old_output != workspace->output && !container->is_fullscreen) { container_floating_move_to_center(container); } } else { - old_parent = container_remove_child(container); + container_detach(container); container->width = container->height = 0; container->saved_width = container->saved_height = 0; - - if (destination->type == C_VIEW) { - new_parent = container_add_sibling(destination, container); - } else { - new_parent = destination; - container_add_child(destination, container); - } + workspace_add_tiling(workspace, container); + container_update_representation(container); } - - if (container->type == C_VIEW) { + if (container->view) { ipc_event_window(container, "move"); } - container_notify_subtree_changed(old_parent); - container_notify_subtree_changed(new_parent); - - // If view was moved to a fullscreen workspace, refocus the fullscreen view - struct sway_container *new_workspace = container; - if (new_workspace->type != C_WORKSPACE) { - new_workspace = container_parent(new_workspace, C_WORKSPACE); - } - if (new_workspace->sway_workspace->fullscreen) { - struct sway_seat *seat; - struct sway_container *focus, *focus_ws; - wl_list_for_each(seat, &input_manager->seats, link) { - focus = seat_get_focus(seat); - focus_ws = focus; - if (focus_ws->type != C_WORKSPACE) { - focus_ws = container_parent(focus_ws, C_WORKSPACE); - } - if (focus_ws == new_workspace) { - struct sway_container *new_focus = seat_get_focus_inactive(seat, - new_workspace->sway_workspace->fullscreen); - seat_set_focus(seat, new_focus); - } - } + workspace_detect_urgent(old_workspace); + workspace_detect_urgent(workspace); + workspace_focus_fullscreen(workspace); +} + +static void container_move_to_container(struct sway_container *container, + struct sway_container *destination) { + if (container == destination + || container_has_ancestor(container, destination) + || container_has_ancestor(destination, container)) { + return; } - // Update workspace urgent state - struct sway_container *old_workspace = old_parent; - if (old_workspace->type != C_WORKSPACE) { - old_workspace = container_parent(old_workspace, C_WORKSPACE); - } - if (new_workspace != old_workspace) { - workspace_detect_urgent(new_workspace); - if (old_workspace) { - workspace_detect_urgent(old_workspace); - } + if (container_is_floating(container)) { + return; } -} + struct sway_workspace *old_workspace = container->workspace; -static bool is_parallel(enum sway_container_layout layout, - enum movement_direction dir) { - switch (layout) { - case L_TABBED: - case L_HORIZ: - return dir == MOVE_LEFT || dir == MOVE_RIGHT; - case L_STACKED: - case L_VERT: - return dir == MOVE_UP || dir == MOVE_DOWN; - default: - return false; + container_detach(container); + container->width = container->height = 0; + container->saved_width = container->saved_height = 0; + + if (destination->view) { + container_add_sibling(destination, container, 1); + } else { + container_add_child(destination, container); } -} -static enum movement_direction invert_movement(enum movement_direction dir) { - switch (dir) { - case MOVE_LEFT: - return MOVE_RIGHT; - case MOVE_RIGHT: - return MOVE_LEFT; - case MOVE_UP: - return MOVE_DOWN; - case MOVE_DOWN: - return MOVE_UP; - default: - sway_assert(0, "This function expects left|right|up|down"); - return MOVE_LEFT; + if (container->view) { + ipc_event_window(container, "move"); } -} -static int move_offs(enum movement_direction move_dir) { - return move_dir == MOVE_LEFT || move_dir == MOVE_UP ? -1 : 1; -} + workspace_focus_fullscreen(destination->workspace); -/* Gets the index of the most extreme member based on the movement offset */ -static int container_limit(struct sway_container *container, - enum movement_direction move_dir) { - return move_offs(move_dir) < 0 ? 0 : container->children->length; + // Update workspace urgent state + workspace_detect_urgent(destination->workspace); + if (old_workspace != destination->workspace) { + workspace_detect_urgent(old_workspace); + } } /* 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_container *ws, +static void workspace_rejigger(struct sway_workspace *ws, struct sway_container *child, enum movement_direction move_dir) { - struct sway_container *original_parent = child->parent; - struct sway_container *new_parent = - container_split(ws, ws->layout); - - container_remove_child(child); - for (int i = 0; i < ws->children->length; ++i) { - struct sway_container *_child = ws->children->items[i]; - container_move_to(new_parent, _child); + if (!sway_assert(child->parent == NULL, "Expected a root child")) { + return; } + container_detach(child); + workspace_wrap_children(ws); - int index = move_offs(move_dir); - container_insert_child(ws, child, index < 0 ? 0 : 1); + int index = move_dir == MOVE_LEFT || move_dir == MOVE_UP ? 0 : 1; + workspace_insert_tiling(ws, child, index); ws->layout = move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; - - container_flatten(ws); - container_reap_empty(original_parent); - container_create_notify(new_parent); + workspace_update_representation(ws); } static void move_out_of_tabs_stacks(struct sway_container *container, struct sway_container *current, enum movement_direction move_dir, int offs) { - if (container->parent == current->parent - && current->parent->children->length == 1) { - wlr_log(WLR_DEBUG, "Changing layout of %zd", current->parent->id); - current->parent->layout = move_dir == - MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; + enum sway_container_layout layout = move_dir == + MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; + list_t *siblings = container_get_siblings(container); + if (container == current && siblings->length == 1) { + wlr_log(WLR_DEBUG, "Changing layout of parent"); + if (container->parent) { + container->parent->layout = layout; + container_update_representation(container); + } else { + container->workspace->layout = layout; + workspace_update_representation(container->workspace); + } return; } wlr_log(WLR_DEBUG, "Moving out of tab/stack into a split"); - bool is_workspace = current->parent->type == C_WORKSPACE; - struct sway_container *new_parent = container_split(current->parent, - move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT); - if (is_workspace) { - container_insert_child(new_parent->parent, container, offs < 0 ? 0 : 1); - } else { + if (container->parent) { + struct sway_container *new_parent = + container_split(current->parent, layout); container_insert_child(new_parent, container, offs < 0 ? 0 : 1); - container_reap_empty(new_parent->parent); - container_flatten(new_parent->parent); + container_reap_empty(new_parent); + container_flatten(new_parent); + } else { + // Changing a workspace + struct sway_workspace *workspace = container->workspace; + workspace_split(workspace, layout); + workspace_insert_tiling(workspace, container, offs < 0 ? 0 : 1); } - container_create_notify(new_parent); - container_notify_subtree_changed(new_parent); } -static void container_move(struct sway_container *container, - enum movement_direction move_dir, int move_amt) { - if (!sway_assert( - container->type != C_CONTAINER || container->type != C_VIEW, - "Can only move containers and views")) { - return; - } - int offs = move_offs(move_dir); - - struct sway_container *sibling = NULL; - struct sway_container *current = container; - struct sway_container *parent = current->parent; - struct sway_container *top = &root_container; - +// Returns true if moved +static bool container_move_in_direction(struct sway_container *container, + enum movement_direction move_dir) { // If moving a fullscreen view, only consider outputs if (container->is_fullscreen) { - current = container_parent(container, C_OUTPUT); - } else if (container_is_fullscreen_or_child(container) || - container_is_floating_or_child(container)) { - // If we've fullscreened a split container, only allow the child to move - // around within the fullscreen parent. - // Same with floating a split container. - struct sway_container *ws = container_parent(container, C_WORKSPACE); - top = ws->sway_workspace->fullscreen; - } - - struct sway_container *new_parent = container_flatten(parent); - if (new_parent != parent) { - // Special case: we were the last one in this container, so leave - return; + 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); + container_move_to_workspace(container, ws); + return true; } - while (!sibling) { - if (current == top) { - return; + // If container is in a split container by itself, move out of the split + if (container->parent) { + struct sway_container *new_parent = + container_flatten(container->parent); + if (new_parent != container->parent) { + return true; } + } - parent = current->parent; - wlr_log(WLR_DEBUG, "Visiting %p %s '%s'", current, - container_type_to_str(current->type), current->name); - - int index = container_sibling_index(current); - - switch (current->type) { - case C_OUTPUT: { - enum wlr_direction wlr_dir = 0; - if (!sway_assert(sway_dir_to_wlr(move_dir, &wlr_dir), - "got invalid direction: %d", move_dir)) { - return; - } - double ref_lx = current->x + current->width / 2; - double ref_ly = current->y + current->height / 2; - struct wlr_output *next = wlr_output_layout_adjacent_output( - root_container.sway_root->output_layout, wlr_dir, - current->sway_output->wlr_output, ref_lx, ref_ly); - if (!next) { - wlr_log(WLR_DEBUG, "Hit edge of output, nowhere else to go"); - return; - } - struct sway_output *next_output = next->data; - current = next_output->swayc; - wlr_log(WLR_DEBUG, "Selected next output (%s)", current->name); - // Select workspace and get outta here - current = seat_get_focus_inactive( - config->handler_context.seat, current); - if (current->type != C_WORKSPACE) { - current = container_parent(current, C_WORKSPACE); - } - sibling = current; - break; - } - case C_WORKSPACE: - if (!is_parallel(current->layout, move_dir)) { - if (current->children->length >= 2) { - wlr_log(WLR_DEBUG, "Rejiggering the workspace (%d kiddos)", - current->children->length); - workspace_rejigger(current, container, move_dir); - return; - } else { - wlr_log(WLR_DEBUG, "Selecting output"); - current = current->parent; - } - } else if (current->layout == L_TABBED - || current->layout == L_STACKED) { - wlr_log(WLR_DEBUG, "Rejiggering out of tabs/stacks"); - workspace_rejigger(current, container, move_dir); - } else { - wlr_log(WLR_DEBUG, "Selecting output"); - current = current->parent; - } - break; - case C_CONTAINER: - case C_VIEW: - if (is_parallel(parent->layout, move_dir)) { - if ((index == parent->children->length - 1 && offs > 0) - || (index == 0 && offs < 0)) { - if (current->parent == container->parent) { - if (!parent->is_fullscreen && - (parent->layout == L_TABBED || - parent->layout == L_STACKED)) { - move_out_of_tabs_stacks(container, current, - move_dir, offs); - return; - } else { - wlr_log(WLR_DEBUG, "Hit limit, selecting parent"); - current = current->parent; - } + // 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 == MOVE_LEFT || move_dir == MOVE_UP ? -1 : 1; + + while (current) { + struct sway_container *parent = current->parent; + list_t *siblings = container_get_siblings(current); + enum sway_container_layout layout = container_parent_layout(current); + int index = list_find(siblings, current); + int desired = index + offs; + + if (is_parallel(layout, move_dir)) { + if (desired == -1 || desired == siblings->length) { + if (current->parent == container->parent) { + if (!(parent && parent->is_fullscreen) && + (layout == L_TABBED || layout == L_STACKED)) { + move_out_of_tabs_stacks(container, current, + move_dir, offs); + return true; } else { - wlr_log(WLR_DEBUG, "Hit limit, " - "promoting descendant to sibling"); - // Special case + current = current->parent; + continue; + } + } else { + // Special case + if (current->parent) { container_insert_child(current->parent, container, index + (offs < 0 ? 0 : 1)); - container->width = container->height = 0; - return; + } else { + workspace_insert_tiling(current->workspace, container, + index + (offs < 0 ? 0 : 1)); } - } else { - sibling = parent->children->items[index + offs]; - wlr_log(WLR_DEBUG, "Selecting sibling id:%zd", sibling->id); + return true; } - } else if (!parent->is_fullscreen && (parent->layout == L_TABBED || - parent->layout == L_STACKED)) { - move_out_of_tabs_stacks(container, current, move_dir, offs); - return; } else { - wlr_log(WLR_DEBUG, "Moving up to find a parallel container"); - current = current->parent; + // Container can move within its siblings + container_move_to_container_from_direction(container, + siblings->items[desired], move_dir); + return true; } - break; - default: - sway_assert(0, "Not expecting to see container of type %s here", - container_type_to_str(current->type)); - return; + } else if (!(parent && parent->is_fullscreen) && + (layout == L_TABBED || layout == L_STACKED)) { + move_out_of_tabs_stacks(container, current, move_dir, offs); + return true; } - } - // Part two: move stuff around - int index = container_sibling_index(container); - struct sway_container *old_parent = container->parent; + current = current->parent; - while (sibling) { - switch (sibling->type) { - case C_VIEW: - if (sibling->parent == container->parent) { - wlr_log(WLR_DEBUG, "Swapping siblings"); - sibling->parent->children->items[index + offs] = container; - sibling->parent->children->items[index] = sibling; - } else { - wlr_log(WLR_DEBUG, "Promoting to sibling of cousin"); - container_insert_child(sibling->parent, container, - container_sibling_index(sibling) + (offs > 0 ? 0 : 1)); - container->width = container->height = 0; - } - sibling = NULL; - break; - case C_WORKSPACE: // Note: only in the case of moving between outputs - case C_CONTAINER: - if (is_parallel(sibling->layout, move_dir)) { - int limit = container_limit(sibling, invert_movement(move_dir)); - wlr_log(WLR_DEBUG, "limit: %d", limit); - wlr_log(WLR_DEBUG, - "Reparenting container (parallel) to index %d " - "(move dir: %d)", limit, move_dir); - container_insert_child(sibling, container, limit); - container->width = container->height = 0; - sibling = NULL; - } else { - wlr_log(WLR_DEBUG, "Reparenting container (perpendicular)"); - struct sway_container *focus_inactive = seat_get_focus_inactive( - config->handler_context.seat, sibling); - if (focus_inactive && focus_inactive != sibling) { - while (focus_inactive->parent != sibling) { - focus_inactive = focus_inactive->parent; - } - wlr_log(WLR_DEBUG, "Focus inactive: id:%zd", - focus_inactive->id); - sibling = focus_inactive; - continue; - } else if (sibling->children->length) { - wlr_log(WLR_DEBUG, "No focus-inactive, adding arbitrarily"); - container_remove_child(container); - container_add_sibling(sibling->children->items[0], container); - } else { - wlr_log(WLR_DEBUG, "No kiddos, adding container alone"); - container_remove_child(container); - container_add_child(sibling, container); - } - container->width = container->height = 0; - sibling = NULL; - } - break; - default: - sway_assert(0, "Not expecting to see container of type %s here", - container_type_to_str(sibling->type)); - return; + // Don't allow containers to move out of their + // fullscreen or floating parent + if (current && + (current->is_fullscreen || container_is_floating(current))) { + return false; } } - container_notify_subtree_changed(old_parent); - container_notify_subtree_changed(container->parent); - - if (container->type == C_VIEW) { - ipc_event_window(container, "move"); - } - - if (old_parent) { - seat_set_focus(config->handler_context.seat, old_parent); - seat_set_focus(config->handler_context.seat, container); + // Maybe rejigger the workspace + struct sway_workspace *ws = container->workspace; + if (!is_parallel(ws->layout, move_dir)) { + if (ws->tiling->length >= 2) { + workspace_rejigger(ws, container, move_dir); + return true; + } + } else if (ws->layout == L_TABBED || ws->layout == L_STACKED) { + workspace_rejigger(ws, container, move_dir); + return true; } - struct sway_container *last_ws = old_parent; - struct sway_container *next_ws = container->parent; - if (last_ws && last_ws->type != C_WORKSPACE) { - last_ws = container_parent(last_ws, C_WORKSPACE); - } - if (next_ws && next_ws->type != C_WORKSPACE) { - next_ws = container_parent(next_ws, C_WORKSPACE); + // 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); + container_move_to_workspace_from_direction(container, ws, move_dir); + return true; } - if (last_ws && next_ws && last_ws != next_ws) { - ipc_event_workspace(last_ws, next_ws, "focus"); - workspace_detect_urgent(last_ws); - workspace_detect_urgent(next_ws); - } - container_end_mouse_operation(container); + wlr_log(WLR_DEBUG, "Hit edge of output, nowhere else to go"); + return false; } -static struct cmd_results *cmd_move_container(struct sway_container *current, - int argc, char **argv) { +static struct cmd_results *cmd_move_container(int argc, char **argv) { struct cmd_results *error = NULL; if ((error = checkarg(argc, "move container/window", EXPECTED_AT_LEAST, 3))) { return error; } - if (current->type == C_WORKSPACE) { - if (current->children->length == 0) { + struct sway_node *node = config->handler_context.node; + struct sway_workspace *workspace = config->handler_context.workspace; + struct sway_container *container = config->handler_context.container; + if (node->type == N_WORKSPACE) { + if (workspace->tiling->length == 0) { return cmd_results_new(CMD_FAILURE, "move", "Can't move an empty workspace"); } - current = workspace_wrap_children(current); - } else if (current->type != C_CONTAINER && current->type != C_VIEW) { - return cmd_results_new(CMD_FAILURE, "move", - "Can only move containers and views."); + container = workspace_wrap_children(workspace); } bool no_auto_back_and_forth = false; @@ -530,15 +450,15 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, } struct sway_seat *seat = config->handler_context.seat; - struct sway_container *old_parent = current->parent; - struct sway_container *old_ws = container_parent(current, C_WORKSPACE); - struct sway_container *old_output = container_parent(current, C_OUTPUT); - struct sway_container *destination = NULL; + struct sway_container *old_parent = container->parent; + struct sway_workspace *old_ws = container->workspace; + struct sway_output *old_output = old_ws->output; + struct sway_node *destination = NULL; // determine destination if (strcasecmp(argv[1], "workspace") == 0) { // move container to workspace x - struct sway_container *ws = NULL; + struct sway_workspace *ws = NULL; char *ws_name = NULL; if (strcasecmp(argv[2], "next") == 0 || strcasecmp(argv[2], "prev") == 0 || @@ -588,8 +508,8 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, // We have to create the workspace, but if the container is // sticky and the workspace is going to be created on the same // output, we'll bail out first. - if (current->is_sticky) { - struct sway_container *new_output = + if (container->is_sticky) { + struct sway_output *new_output = workspace_get_initial_output(ws_name); if (old_output == new_output) { free(ws_name); @@ -601,105 +521,113 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, ws = workspace_create(NULL, ws_name); } free(ws_name); - destination = seat_get_focus_inactive(seat, ws); + destination = seat_get_focus_inactive(seat, &ws->node); } else if (strcasecmp(argv[1], "output") == 0) { - struct sway_container *dest_output = output_in_direction(argv[2], - old_output->sway_output->wlr_output, current->x, current->y); - if (!dest_output) { + struct sway_output *new_output = output_in_direction(argv[2], + old_output->wlr_output, container->x, container->y); + if (!new_output) { return cmd_results_new(CMD_FAILURE, "move workspace", "Can't find output with name/direction '%s'", argv[2]); } - destination = seat_get_focus_inactive(seat, dest_output); - if (!destination) { - // We've never been to this output before - destination = dest_output->children->items[0]; - } + destination = seat_get_focus_inactive(seat, &new_output->node); } else if (strcasecmp(argv[1], "mark") == 0) { struct sway_view *dest_view = view_find_mark(argv[2]); if (dest_view == NULL) { return cmd_results_new(CMD_FAILURE, "move", "Mark '%s' not found", argv[2]); } - destination = dest_view->swayc; + destination = &dest_view->container->node; } else { return cmd_results_new(CMD_INVALID, "move", expected_syntax); } - struct sway_container *new_output = destination->type == C_OUTPUT ? - destination : container_parent(destination, C_OUTPUT); - if (current->is_sticky && old_output == new_output) { + if (container->is_sticky && + node_has_ancestor(destination, &old_output->node)) { return cmd_results_new(CMD_FAILURE, "move", "Can't move sticky " "container to another workspace on the same output"); } - struct sway_container *new_output_last_ws = old_output == new_output ? - NULL : seat_get_active_child(seat, new_output); - struct sway_container *new_workspace = destination->type == C_WORKSPACE ? - destination : container_parent(destination, C_WORKSPACE); + struct sway_output *new_output = node_get_output(destination); + struct sway_workspace *new_output_last_ws = old_output == new_output ? + NULL : output_get_active_workspace(new_output); // move container, arrange windows and return focus - container_move_to(current, destination); + switch (destination->type) { + case N_WORKSPACE: + container_move_to_workspace(container, destination->sway_workspace); + break; + case N_OUTPUT: { + struct sway_output *output = destination->sway_output; + struct sway_workspace *ws = output_get_active_workspace(output); + container_move_to_workspace(container, ws); + } + break; + case N_CONTAINER: + container_move_to_container(container, destination->sway_container); + break; + case N_ROOT: + break; + } + struct sway_workspace *new_workspace = + output_get_active_workspace(new_output); if (new_output_last_ws && new_output_last_ws != new_workspace) { // change focus on destination output back to its last active workspace - struct sway_container *new_output_last_focus = - seat_get_focus_inactive(seat, new_output_last_ws); + struct sway_node *new_output_last_focus = + seat_get_focus_inactive(seat, &new_output_last_ws->node); seat_set_focus_warp(seat, new_output_last_focus, false, false); } - struct sway_container *focus = seat_get_focus_inactive(seat, old_parent); + + struct sway_node *focus = NULL; + if (old_parent) { + focus = seat_get_focus_inactive(seat, &old_parent->node); + } else { + focus = seat_get_focus_inactive(seat, &old_ws->node); + } seat_set_focus_warp(seat, focus, true, false); - container_reap_empty(old_parent); - container_reap_empty(destination->parent); - // TODO: Ideally we would arrange the surviving parent after reaping, - // but container_reap_empty does not return it, so we arrange the - // workspace instead. - arrange_windows(old_ws); - arrange_windows(destination->parent); + if (old_parent) { + container_reap_empty(old_parent); + } else { + workspace_consider_destroy(old_ws); + } + + arrange_workspace(old_ws); + arrange_node(node_get_parent(destination)); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } -static void workspace_move_to_output(struct sway_container *workspace, - struct sway_container *output) { - if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { +static void workspace_move_to_output(struct sway_workspace *workspace, + struct sway_output *output) { + if (workspace->output == output) { return; } - if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { - return; - } - if (workspace->parent == output) { - return; - } - struct sway_container *old_output = container_remove_child(workspace); - struct sway_seat *seat = input_manager_get_default_seat(input_manager); - struct sway_container *new_output_focus = - seat_get_focus_inactive(seat, output); + struct sway_output *old_output = workspace->output; + workspace_detach(workspace); + struct sway_workspace *new_output_old_ws = + output_get_active_workspace(output); - container_add_child(output, workspace); + output_add_workspace(output, workspace); // If moving the last workspace from the old output, create a new workspace // on the old output - if (old_output->children->length == 0) { - char *ws_name = workspace_next_name(old_output->name); - struct sway_container *ws = workspace_create(old_output, ws_name); + struct sway_seat *seat = config->handler_context.seat; + if (old_output->workspaces->length == 0) { + char *ws_name = workspace_next_name(old_output->wlr_output->name); + struct sway_workspace *ws = workspace_create(old_output, ws_name); free(ws_name); - seat_set_focus(seat, ws); + seat_set_focus(seat, &ws->node); } - // Try to remove an empty workspace from the destination output. - container_reap_empty(new_output_focus); + workspace_consider_destroy(new_output_old_ws); output_sort_workspaces(output); - seat_set_focus(seat, output); + seat_set_focus(seat, &output->node); workspace_output_raise_priority(workspace, old_output, output); ipc_event_workspace(NULL, workspace, "move"); - - container_notify_subtree_changed(old_output); - container_notify_subtree_changed(output); } -static struct cmd_results *cmd_move_workspace(struct sway_container *current, - int argc, char **argv) { +static struct cmd_results *cmd_move_workspace(int argc, char **argv) { struct cmd_results *error = NULL; if ((error = checkarg(argc, "move workspace", EXPECTED_AT_LEAST, 2))) { return error; @@ -716,27 +644,25 @@ static struct cmd_results *cmd_move_workspace(struct sway_container *current, return cmd_results_new(CMD_INVALID, "move", expected_syntax); } - struct sway_container *source = container_parent(current, C_OUTPUT); - int center_x = current->width / 2 + current->x, - center_y = current->height / 2 + current->y; - struct sway_container *destination = output_in_direction(argv[2], - source->sway_output->wlr_output, center_x, center_y); - if (!destination) { + struct sway_workspace *workspace = config->handler_context.workspace; + struct sway_output *old_output = workspace->output; + int center_x = workspace->width / 2 + workspace->x, + center_y = workspace->height / 2 + workspace->y; + struct sway_output *new_output = output_in_direction(argv[2], + old_output->wlr_output, center_x, center_y); + if (!new_output) { return cmd_results_new(CMD_FAILURE, "move workspace", "Can't find output with name/direction '%s'", argv[2]); } - if (current->type != C_WORKSPACE) { - current = container_parent(current, C_WORKSPACE); - } - workspace_move_to_output(current, destination); + workspace_move_to_output(workspace, new_output); - arrange_windows(source); - arrange_windows(destination); + arrange_output(old_output); + arrange_output(new_output); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } -static struct cmd_results *move_in_direction(struct sway_container *container, +static struct cmd_results *cmd_move_in_direction( enum movement_direction direction, int argc, char **argv) { int move_amt = 10; if (argc > 1) { @@ -748,7 +674,8 @@ static struct cmd_results *move_in_direction(struct sway_container *container, } } - if (container->type == C_WORKSPACE) { + struct sway_container *container = config->handler_context.container; + if (!container) { return cmd_results_new(CMD_FAILURE, "move", "Cannot move workspaces in a direction"); } @@ -780,20 +707,34 @@ static struct cmd_results *move_in_direction(struct sway_container *container, container_floating_move_to(container, lx, ly); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } - // For simplicity, we'll arrange the entire workspace. The reason for this - // is moving the container might reap the old parent, and container_move - // does not return a surviving parent. - // TODO: Make container_move return the surviving parent so we can arrange - // just that. - struct sway_container *old_ws = container_parent(container, C_WORKSPACE); - container_move(container, direction, move_amt); - struct sway_container *new_ws = container_parent(container, C_WORKSPACE); + struct sway_workspace *old_ws = container->workspace; - arrange_windows(old_ws); + if (!container_move_in_direction(container, direction)) { + // Container didn't move + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + + struct sway_workspace *new_ws = container->workspace; + + arrange_workspace(old_ws); if (new_ws != old_ws) { - arrange_windows(new_ws); + arrange_workspace(new_ws); + } + + if (container->view) { + ipc_event_window(container, "move"); } + seat_set_focus(config->handler_context.seat, &new_ws->node); + seat_set_focus(config->handler_context.seat, &container->node); + + if (old_ws != new_ws) { + ipc_event_workspace(old_ws, new_ws, "focus"); + workspace_detect_urgent(old_ws); + workspace_detect_urgent(new_ws); + } + container_end_mouse_operation(container); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); } @@ -802,9 +743,9 @@ static const char *expected_position_syntax = "'move [absolute] position center' or " "'move position cursor|mouse|pointer'"; -static struct cmd_results *move_to_position(struct sway_container *container, - int argc, char **argv) { - if (!container_is_floating(container)) { +static struct cmd_results *cmd_move_to_position(int argc, char **argv) { + struct sway_container *container = config->handler_context.container; + if (!container || !container_is_floating(container)) { return cmd_results_new(CMD_FAILURE, "move", "Only floating containers " "can be moved to an absolute position"); @@ -842,10 +783,10 @@ static struct cmd_results *move_to_position(struct sway_container *container, } else if (strcmp(argv[0], "center") == 0) { double lx, ly; if (absolute) { - lx = root_container.x + (root_container.width - container->width) / 2; - ly = root_container.y + (root_container.height - container->height) / 2; + lx = root->x + (root->width - container->width) / 2; + ly = root->y + (root->height - container->height) / 2; } else { - struct sway_container *ws = container_parent(container, C_WORKSPACE); + struct sway_workspace *ws = container->workspace; lx = ws->x + (ws->width - container->width) / 2; ly = ws->y + (ws->height - container->height) / 2; } @@ -881,30 +822,31 @@ static struct cmd_results *move_to_position(struct sway_container *container, } if (!absolute) { - struct sway_container *ws = container_parent(container, C_WORKSPACE); - lx += ws->x; - ly += ws->y; + lx += container->workspace->x; + ly += container->workspace->y; } container_floating_move_to(container, lx, ly); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } -static struct cmd_results *move_to_scratchpad(struct sway_container *con) { - if (con->type == C_WORKSPACE && con->children->length == 0) { +static struct cmd_results *cmd_move_to_scratchpad(void) { + struct sway_node *node = config->handler_context.node; + struct sway_container *con = config->handler_context.container; + struct sway_workspace *ws = config->handler_context.workspace; + if (node->type == N_WORKSPACE && ws->tiling->length == 0) { return cmd_results_new(CMD_INVALID, "move", "Can't move an empty workspace to the scratchpad"); } - if (con->type == C_WORKSPACE) { + if (node->type == N_WORKSPACE) { // Wrap the workspace's children in a container - struct sway_container *workspace = con; - con = workspace_wrap_children(con); - workspace->layout = L_HORIZ; + con = workspace_wrap_children(ws); + ws->layout = L_HORIZ; } // If the container is in a floating split container, // operate on the split container instead of the child. if (container_is_floating_or_child(con)) { - while (con->parent->type != C_WORKSPACE) { + while (con->parent) { con = con->parent; } } @@ -922,32 +864,31 @@ struct cmd_results *cmd_move(int argc, char **argv) { if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) { return error; } - struct sway_container *current = config->handler_context.current_container; if (strcasecmp(argv[0], "left") == 0) { - return move_in_direction(current, MOVE_LEFT, argc, argv); + return cmd_move_in_direction(MOVE_LEFT, argc, argv); } else if (strcasecmp(argv[0], "right") == 0) { - return move_in_direction(current, MOVE_RIGHT, argc, argv); + return cmd_move_in_direction(MOVE_RIGHT, argc, argv); } else if (strcasecmp(argv[0], "up") == 0) { - return move_in_direction(current, MOVE_UP, argc, argv); + return cmd_move_in_direction(MOVE_UP, argc, argv); } else if (strcasecmp(argv[0], "down") == 0) { - return move_in_direction(current, MOVE_DOWN, argc, argv); + return cmd_move_in_direction(MOVE_DOWN, argc, argv); } else if ((strcasecmp(argv[0], "container") == 0 || strcasecmp(argv[0], "window") == 0) || - (strcasecmp(argv[0], "--no-auto-back-and-forth") && - (strcasecmp(argv[0], "container") == 0 - || strcasecmp(argv[0], "window") == 0))) { - return cmd_move_container(current, argc, argv); + (strcasecmp(argv[0], "--no-auto-back-and-forth") && argc >= 2 + && (strcasecmp(argv[1], "container") == 0 + || strcasecmp(argv[1], "window") == 0))) { + return cmd_move_container(argc, argv); } else if (strcasecmp(argv[0], "workspace") == 0) { - return cmd_move_workspace(current, argc, argv); + return cmd_move_workspace(argc, argv); } else if (strcasecmp(argv[0], "scratchpad") == 0 || (strcasecmp(argv[0], "to") == 0 && argc == 2 && strcasecmp(argv[1], "scratchpad") == 0)) { - return move_to_scratchpad(current); + return cmd_move_to_scratchpad(); } else if (strcasecmp(argv[0], "position") == 0) { - return move_to_position(current, argc, argv); + return cmd_move_to_position(argc, argv); } else if (strcasecmp(argv[0], "absolute") == 0) { - return move_to_position(current, argc, argv); + return cmd_move_to_position(argc, argv); } else { return cmd_results_new(CMD_INVALID, "move", expected_syntax); } diff --git a/sway/commands/opacity.c b/sway/commands/opacity.c index 68fd9f42..9cdaad7f 100644 --- a/sway/commands/opacity.c +++ b/sway/commands/opacity.c @@ -19,8 +19,7 @@ struct cmd_results *cmd_opacity(int argc, char **argv) { return error; } - struct sway_container *con = - config->handler_context.current_container; + struct sway_container *con = config->handler_context.container; float opacity = 0.0f; diff --git a/sway/commands/reload.c b/sway/commands/reload.c index f8ca374d..36fb9092 100644 --- a/sway/commands/reload.c +++ b/sway/commands/reload.c @@ -42,7 +42,7 @@ struct cmd_results *cmd_reload(int argc, char **argv) { } list_free(bar_ids); - arrange_windows(&root_container); + arrange_root(); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/rename.c b/sway/commands/rename.c index 21d2aa64..d982f941 100644 --- a/sway/commands/rename.c +++ b/sway/commands/rename.c @@ -25,14 +25,11 @@ struct cmd_results *cmd_rename(int argc, char **argv) { } int argn = 1; - struct sway_container *workspace; + struct sway_workspace *workspace = NULL; if (strcasecmp(argv[1], "to") == 0) { // 'rename workspace to new_name' - workspace = config->handler_context.current_container; - if (workspace->type != C_WORKSPACE) { - workspace = container_parent(workspace, C_WORKSPACE); - } + workspace = config->handler_context.workspace; } else if (strcasecmp(argv[1], "number") == 0) { // 'rename workspace number x to new_name' if (!isdigit(argv[2][0])) { @@ -78,7 +75,7 @@ struct cmd_results *cmd_rename(int argc, char **argv) { return cmd_results_new(CMD_INVALID, "rename", "Cannot use special workspace name '%s'", argv[argn]); } - struct sway_container *tmp_workspace = workspace_by_name(new_name); + struct sway_workspace *tmp_workspace = workspace_by_name(new_name); if (tmp_workspace) { free(new_name); return cmd_results_new(CMD_INVALID, "rename", @@ -89,7 +86,7 @@ struct cmd_results *cmd_rename(int argc, char **argv) { free(workspace->name); workspace->name = new_name; - output_sort_workspaces(workspace->parent); + output_sort_workspaces(workspace->output); ipc_event_workspace(NULL, workspace, "rename"); return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/commands/resize.c b/sway/commands/resize.c index ad659ef5..99e9dbda 100644 --- a/sway/commands/resize.c +++ b/sway/commands/resize.c @@ -10,6 +10,7 @@ #include "sway/commands.h" #include "sway/tree/arrange.h" #include "sway/tree/view.h" +#include "sway/tree/workspace.h" #include "log.h" static const int MIN_SANE_W = 100, MIN_SANE_H = 60; @@ -75,7 +76,7 @@ static int parse_resize_amount(int argc, char **argv, static void calculate_constraints(int *min_width, int *max_width, int *min_height, int *max_height) { - struct sway_container *con = config->handler_context.current_container; + struct sway_container *con = config->handler_context.container; if (config->floating_minimum_width == -1) { // no minimum *min_width = 0; @@ -96,8 +97,7 @@ static void calculate_constraints(int *min_width, int *max_width, if (config->floating_maximum_width == -1) { // no maximum *max_width = INT_MAX; } else if (config->floating_maximum_width == 0) { // automatic - struct sway_container *ws = container_parent(con, C_WORKSPACE); - *max_width = ws->width; + *max_width = con->workspace->width; } else { *max_width = config->floating_maximum_width; } @@ -105,8 +105,7 @@ static void calculate_constraints(int *min_width, int *max_width, if (config->floating_maximum_height == -1) { // no maximum *max_height = INT_MAX; } else if (config->floating_maximum_height == 0) { // automatic - struct sway_container *ws = container_parent(con, C_WORKSPACE); - *max_height = ws->height; + *max_height = con->workspace->height; } else { *max_height = config->floating_maximum_height; } @@ -191,11 +190,11 @@ static void resize_tiled(struct sway_container *parent, int amount, normalize_axis(axis) == RESIZE_AXIS_HORIZONTAL ? L_HORIZ : L_VERT; int minor_weight = 0; int major_weight = 0; - while (parent->parent) { - struct sway_container *next = parent->parent; - if (next->layout == parallel_layout) { - for (int i = 0; i < next->children->length; i++) { - struct sway_container *sibling = next->children->items[i]; + while (parent) { + list_t *siblings = container_get_siblings(parent); + if (container_parent_layout(parent) == parallel_layout) { + for (int i = 0; i < siblings->length; i++) { + struct sway_container *sibling = siblings->items[i]; int sibling_pos = parallel_coord(sibling, axis); int focused_pos = parallel_coord(focused, axis); @@ -213,17 +212,13 @@ static void resize_tiled(struct sway_container *parent, int amount, break; } } - parent = next; + parent = parent->parent; } - - if (parent->type == C_ROOT) { + if (!parent) { + // Can't resize in this direction return; } - wlr_log(WLR_DEBUG, - "Found the proper parent: %p. It has %d l conts, and %d r conts", - parent->parent, minor_weight, major_weight); - // Implement up/down/left/right direction by zeroing one of the weights, // then setting the axis to be horizontal or vertical if (axis == RESIZE_AXIS_UP || axis == RESIZE_AXIS_LEFT) { @@ -237,9 +232,10 @@ static void resize_tiled(struct sway_container *parent, int amount, //TODO: Ensure rounding is done in such a way that there are NO pixel leaks // ^ ????? + list_t *siblings = container_get_siblings(parent); - for (int i = 0; i < parent->parent->children->length; i++) { - struct sway_container *sibling = parent->parent->children->items[i]; + for (int i = 0; i < siblings->length; i++) { + struct sway_container *sibling = siblings->items[i]; int sibling_pos = parallel_coord(sibling, axis); int focused_pos = parallel_coord(focused, axis); @@ -277,8 +273,8 @@ static void resize_tiled(struct sway_container *parent, int amount, enum wlr_edges major_edge = axis == RESIZE_AXIS_HORIZONTAL ? WLR_EDGE_RIGHT : WLR_EDGE_BOTTOM; - for (int i = 0; i < parent->parent->children->length; i++) { - struct sway_container *sibling = parent->parent->children->items[i]; + for (int i = 0; i < siblings->length; i++) { + struct sway_container *sibling = siblings->items[i]; int sibling_pos = parallel_coord(sibling, axis); int focused_pos = parallel_coord(focused, axis); @@ -316,7 +312,11 @@ static void resize_tiled(struct sway_container *parent, int amount, } } - arrange_windows(parent->parent); + if (parent->parent) { + arrange_container(parent->parent); + } else { + arrange_workspace(parent->workspace); + } } void container_resize_tiled(struct sway_container *parent, @@ -346,7 +346,7 @@ void container_resize_tiled(struct sway_container *parent, */ static struct cmd_results *resize_adjust_floating(enum resize_axis axis, struct resize_amount *amount) { - struct sway_container *con = config->handler_context.current_container; + struct sway_container *con = config->handler_context.container; int grow_width = 0, grow_height = 0; switch (axis) { case RESIZE_AXIS_HORIZONTAL: @@ -400,15 +400,15 @@ static struct cmd_results *resize_adjust_floating(enum resize_axis axis, con->width += grow_width; con->height += grow_height; - if (con->type == C_VIEW) { - struct sway_view *view = con->sway_view; + if (con->view) { + struct sway_view *view = con->view; view->x += grow_x; view->y += grow_y; view->width += grow_width; view->height += grow_height; } - arrange_windows(con); + arrange_container(con); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } @@ -418,7 +418,7 @@ static struct cmd_results *resize_adjust_floating(enum resize_axis axis, */ static struct cmd_results *resize_adjust_tiled(enum resize_axis axis, struct resize_amount *amount) { - struct sway_container *current = config->handler_context.current_container; + struct sway_container *current = config->handler_context.container; if (amount->unit == RESIZE_UNIT_DEFAULT) { amount->unit = RESIZE_UNIT_PPT; @@ -456,13 +456,15 @@ static struct cmd_results *resize_set_tiled(struct sway_container *con, width->unit == RESIZE_UNIT_DEFAULT) { // Convert to px struct sway_container *parent = con->parent; - while (parent->type >= C_WORKSPACE && parent->layout != L_HORIZ) { + while (parent && parent->layout != L_HORIZ) { parent = parent->parent; } - if (parent->type >= C_WORKSPACE) { + if (parent) { width->amount = parent->width * width->amount / 100; - width->unit = RESIZE_UNIT_PX; + } else { + width->amount = con->workspace->width * width->amount / 100; } + width->unit = RESIZE_UNIT_PX; } if (width->unit == RESIZE_UNIT_PX) { resize_tiled(con, width->amount - con->width, @@ -475,13 +477,15 @@ static struct cmd_results *resize_set_tiled(struct sway_container *con, height->unit == RESIZE_UNIT_DEFAULT) { // Convert to px struct sway_container *parent = con->parent; - while (parent->type >= C_WORKSPACE && parent->layout != L_VERT) { + while (parent && parent->layout != L_VERT) { parent = parent->parent; } - if (parent->type >= C_WORKSPACE) { + if (parent) { height->amount = parent->height * height->amount / 100; - height->unit = RESIZE_UNIT_PX; + } else { + height->amount = con->workspace->height * height->amount / 100; } + height->unit = RESIZE_UNIT_PX; } if (height->unit == RESIZE_UNIT_PX) { resize_tiled(con, height->amount - con->height, @@ -508,15 +512,15 @@ static struct cmd_results *resize_set_floating(struct sway_container *con, con->width = width->amount; con->height = height->amount; - if (con->type == C_VIEW) { - struct sway_view *view = con->sway_view; + if (con->view) { + struct sway_view *view = con->view; view->x -= grow_width / 2; view->y -= grow_height / 2; view->width += grow_width; view->height += grow_height; } - arrange_windows(con); + arrange_container(con); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } @@ -555,7 +559,7 @@ static struct cmd_results *cmd_resize_set(int argc, char **argv) { } // If 0, don't resize that dimension - struct sway_container *con = config->handler_context.current_container; + struct sway_container *con = config->handler_context.container; if (width.amount <= 0) { width.amount = con->width; } @@ -624,7 +628,7 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv, first_amount.amount *= multiplier; second_amount.amount *= multiplier; - struct sway_container *con = config->handler_context.current_container; + struct sway_container *con = config->handler_context.container; if (container_is_floating(con)) { // Floating containers can only resize in px. Choose an amount which // uses px, with fallback to an amount that specified no unit. @@ -657,14 +661,10 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv, } struct cmd_results *cmd_resize(int argc, char **argv) { - struct sway_container *current = config->handler_context.current_container; + struct sway_container *current = config->handler_context.container; if (!current) { return cmd_results_new(CMD_INVALID, "resize", "Cannot resize nothing"); } - if (current->type != C_VIEW && current->type != C_CONTAINER) { - return cmd_results_new(CMD_INVALID, "resize", - "Can only resize views/containers"); - } struct cmd_results *error; if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) { diff --git a/sway/commands/scratchpad.c b/sway/commands/scratchpad.c index 7da20015..d8bae615 100644 --- a/sway/commands/scratchpad.c +++ b/sway/commands/scratchpad.c @@ -9,36 +9,34 @@ static void scratchpad_toggle_auto(void) { struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - struct sway_container *ws = focus->type == C_WORKSPACE ? - focus : container_parent(focus, C_WORKSPACE); + struct sway_container *focus = seat_get_focused_container(seat); + struct sway_workspace *ws = seat_get_focused_workspace(seat); // If the focus is in a floating split container, // operate on the split container instead of the child. - if (container_is_floating_or_child(focus)) { - while (focus->parent->type != C_WORKSPACE) { + if (focus && container_is_floating_or_child(focus)) { + while (focus->parent) { focus = focus->parent; } } - // Check if the currently focused window is a scratchpad window and should // be hidden again. - if (focus->scratchpad) { + if (focus && focus->scratchpad) { wlr_log(WLR_DEBUG, "Focus is a scratchpad window - hiding %s", - focus->name); + focus->title); root_scratchpad_hide(focus); return; } // Check if there is an unfocused scratchpad window on the current workspace // and focus it. - for (int i = 0; i < ws->sway_workspace->floating->length; ++i) { - struct sway_container *floater = ws->sway_workspace->floating->items[i]; + for (int i = 0; i < ws->floating->length; ++i) { + struct sway_container *floater = ws->floating->items[i]; if (floater->scratchpad && focus != floater) { wlr_log(WLR_DEBUG, "Focusing other scratchpad window (%s) in this workspace", - floater->name); + floater->title); root_scratchpad_show(floater); return; } @@ -46,25 +44,23 @@ static void scratchpad_toggle_auto(void) { // Check if there is a visible scratchpad window on another workspace. // In this case we move it to the current workspace. - for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) { - struct sway_container *con = - root_container.sway_root->scratchpad->items[i]; + for (int i = 0; i < root->scratchpad->length; ++i) { + struct sway_container *con = root->scratchpad->items[i]; if (con->parent) { wlr_log(WLR_DEBUG, "Moving a visible scratchpad window (%s) to this workspace", - con->name); + con->title); root_scratchpad_show(con); return; } } // Take the container at the bottom of the scratchpad list - if (!sway_assert(root_container.sway_root->scratchpad->length, - "Scratchpad is empty")) { + if (!sway_assert(root->scratchpad->length, "Scratchpad is empty")) { return; } - struct sway_container *con = root_container.sway_root->scratchpad->items[0]; - wlr_log(WLR_DEBUG, "Showing %s from list", con->name); + struct sway_container *con = root->scratchpad->items[0]; + wlr_log(WLR_DEBUG, "Showing %s from list", con->title); root_scratchpad_show(con); } @@ -74,7 +70,7 @@ static void scratchpad_toggle_container(struct sway_container *con) { } // Check if it matches a currently visible scratchpad window and hide it. - if (con->parent) { + if (con->workspace) { root_scratchpad_hide(con); return; } @@ -91,18 +87,18 @@ struct cmd_results *cmd_scratchpad(int argc, char **argv) { return cmd_results_new(CMD_INVALID, "scratchpad", "Expected 'scratchpad show'"); } - if (!root_container.sway_root->scratchpad->length) { + if (!root->scratchpad->length) { return cmd_results_new(CMD_INVALID, "scratchpad", "Scratchpad is empty"); } if (config->handler_context.using_criteria) { - struct sway_container *con = config->handler_context.current_container; + struct sway_container *con = config->handler_context.container; // If the container is in a floating split container, // operate on the split container instead of the child. if (container_is_floating_or_child(con)) { - while (con->parent->type != C_WORKSPACE) { + while (con->parent) { con = con->parent; } } diff --git a/sway/commands/seat/cursor.c b/sway/commands/seat/cursor.c index 4d0a22c7..cd6630e0 100644 --- a/sway/commands/seat/cursor.c +++ b/sway/commands/seat/cursor.c @@ -42,8 +42,8 @@ struct cmd_results *seat_cmd_cursor(int argc, char **argv) { return cmd_results_new(CMD_INVALID, "cursor", expected_syntax); } // map absolute coords (0..1,0..1) to root container coords - float x = strtof(argv[1], NULL) / root_container.width; - float y = strtof(argv[2], NULL) / root_container.height; + float x = strtof(argv[1], NULL) / root->width; + float y = strtof(argv[2], NULL) / root->height; wlr_cursor_warp_absolute(cursor->cursor, NULL, x, y); cursor_send_pointer_motion(cursor, 0, true); } else { diff --git a/sway/commands/show_marks.c b/sway/commands/show_marks.c index 1844e917..d501584a 100644 --- a/sway/commands/show_marks.c +++ b/sway/commands/show_marks.c @@ -11,8 +11,8 @@ #include "util.h" static void rebuild_marks_iterator(struct sway_container *con, void *data) { - if (con->type == C_VIEW) { - view_update_marks_textures(con->sway_view); + if (con->view) { + view_update_marks_textures(con->view); } } @@ -28,9 +28,9 @@ struct cmd_results *cmd_show_marks(int argc, char **argv) { root_for_each_container(rebuild_marks_iterator, NULL); } - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *con = root_container.children->items[i]; - output_damage_whole(con->sway_output); + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; + output_damage_whole(output); } return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/commands/smart_gaps.c b/sway/commands/smart_gaps.c index 7d27e571..273905df 100644 --- a/sway/commands/smart_gaps.c +++ b/sway/commands/smart_gaps.c @@ -23,7 +23,7 @@ struct cmd_results *cmd_smart_gaps(int argc, char **argv) { "Expected 'smart_gaps ' "); } - arrange_windows(&root_container); + arrange_root(); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/split.c b/sway/commands/split.c index a8eddf54..9a53f3d3 100644 --- a/sway/commands/split.c +++ b/sway/commands/split.c @@ -4,15 +4,21 @@ #include "sway/tree/arrange.h" #include "sway/tree/container.h" #include "sway/tree/view.h" +#include "sway/tree/workspace.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" #include "log.h" static struct cmd_results *do_split(int layout) { - struct sway_container *con = config->handler_context.current_container; - struct sway_container *parent = container_split(con, layout); - container_create_notify(parent); - arrange_windows(parent->parent); + struct sway_container *con = config->handler_context.container; + struct sway_workspace *ws = config->handler_context.workspace; + if (con) { + container_split(con, layout); + } else { + workspace_split(ws, layout); + } + + arrange_workspace(ws); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } @@ -29,10 +35,9 @@ struct cmd_results *cmd_split(int argc, char **argv) { return do_split(L_HORIZ); } else if (strcasecmp(argv[0], "t") == 0 || strcasecmp(argv[0], "toggle") == 0) { - struct sway_container *focused = - config->handler_context.current_container; + struct sway_container *focused = config->handler_context.container; - if (focused->parent->layout == L_VERT) { + if (focused && container_parent_layout(focused) == L_VERT) { return do_split(L_HORIZ); } else { return do_split(L_VERT); @@ -66,9 +71,9 @@ struct cmd_results *cmd_splitt(int argc, char **argv) { return error; } - struct sway_container *con = config->handler_context.current_container; + struct sway_container *con = config->handler_context.container; - if (con->parent->layout == L_VERT) { + if (con && container_parent_layout(con) == L_VERT) { return do_split(L_HORIZ); } else { return do_split(L_VERT); diff --git a/sway/commands/sticky.c b/sway/commands/sticky.c index 8692e08d..7995cdd6 100644 --- a/sway/commands/sticky.c +++ b/sway/commands/sticky.c @@ -15,8 +15,7 @@ struct cmd_results *cmd_sticky(int argc, char **argv) { if ((error = checkarg(argc, "sticky", EXPECTED_EQUAL_TO, 1))) { return error; } - struct sway_container *container = - config->handler_context.current_container; + struct sway_container *container = config->handler_context.container; if (!container_is_floating(container)) { return cmd_results_new(CMD_FAILURE, "sticky", "Can't set sticky on a tiled container"); @@ -37,20 +36,16 @@ struct cmd_results *cmd_sticky(int argc, char **argv) { container->is_sticky = wants_sticky; if (wants_sticky) { - // move container to focused workspace - struct sway_container *output = container_parent(container, C_OUTPUT); - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus_inactive(seat, output); - struct sway_container *focused_workspace = container_parent(focus, C_WORKSPACE); - struct sway_container *current_workspace = container_parent(container, C_WORKSPACE); - if (current_workspace != focused_workspace) { - container_remove_child(container); - workspace_add_floating(focused_workspace, container); - container_handle_fullscreen_reparent(container, current_workspace); - arrange_windows(focused_workspace); - if (!container_reap_empty(current_workspace)) { - arrange_windows(current_workspace); - } + // move container to active workspace + struct sway_workspace *active_workspace = + output_get_active_workspace(container->workspace->output); + if (container->workspace != active_workspace) { + struct sway_workspace *old_workspace = container->workspace; + container_detach(container); + workspace_add_floating(active_workspace, container); + container_handle_fullscreen_reparent(container); + arrange_workspace(active_workspace); + workspace_consider_destroy(old_workspace); } } diff --git a/sway/commands/swap.c b/sway/commands/swap.c index f25c43a1..a0ffbda8 100644 --- a/sway/commands/swap.c +++ b/sway/commands/swap.c @@ -4,6 +4,7 @@ #include "config.h" #include "log.h" #include "sway/commands.h" +#include "sway/output.h" #include "sway/tree/arrange.h" #include "sway/tree/root.h" #include "sway/tree/view.h" @@ -43,27 +44,28 @@ static void swap_focus(struct sway_container *con1, struct sway_container *con2, struct sway_seat *seat, struct sway_container *focus) { if (focus == con1 || focus == con2) { - struct sway_container *ws1 = container_parent(con1, C_WORKSPACE); - struct sway_container *ws2 = container_parent(con2, C_WORKSPACE); - if (focus == con1 && (con2->parent->layout == L_TABBED - || con2->parent->layout == L_STACKED)) { + struct sway_workspace *ws1 = con1->workspace; + struct sway_workspace *ws2 = con2->workspace; + enum sway_container_layout layout1 = container_parent_layout(con1); + enum sway_container_layout layout2 = container_parent_layout(con2); + if (focus == con1 && (layout2 == L_TABBED || layout2 == L_STACKED)) { if (workspace_is_visible(ws2)) { - seat_set_focus_warp(seat, con2, false, true); + seat_set_focus_warp(seat, &con2->node, false, true); } - seat_set_focus(seat, ws1 != ws2 ? con2 : con1); - } else if (focus == con2 && (con1->parent->layout == L_TABBED - || con1->parent->layout == L_STACKED)) { + seat_set_focus(seat, ws1 != ws2 ? &con2->node : &con1->node); + } else if (focus == con2 && (layout1 == L_TABBED + || layout1 == L_STACKED)) { if (workspace_is_visible(ws1)) { - seat_set_focus_warp(seat, con1, false, true); + seat_set_focus_warp(seat, &con1->node, false, true); } - seat_set_focus(seat, ws1 != ws2 ? con1 : con2); + seat_set_focus(seat, ws1 != ws2 ? &con1->node : &con2->node); } else if (ws1 != ws2) { - seat_set_focus(seat, focus == con1 ? con2 : con1); + seat_set_focus(seat, focus == con1 ? &con2->node : &con1->node); } else { - seat_set_focus(seat, focus); + seat_set_focus(seat, &focus->node); } } else { - seat_set_focus(seat, focus); + seat_set_focus(seat, &focus->node); } } @@ -72,10 +74,6 @@ static void container_swap(struct sway_container *con1, if (!sway_assert(con1 && con2, "Cannot swap with nothing")) { return; } - if (!sway_assert(con1->type >= C_CONTAINER && con2->type >= C_CONTAINER, - "Can only swap containers and views")) { - return; - } if (!sway_assert(!container_has_ancestor(con1, con2) && !container_has_ancestor(con2, con1), "Cannot swap ancestor and descendant")) { @@ -87,10 +85,11 @@ static void container_swap(struct sway_container *con1, return; } - wlr_log(WLR_DEBUG, "Swapping containers %zu and %zu", con1->id, con2->id); + wlr_log(WLR_DEBUG, "Swapping containers %zu and %zu", + con1->node.id, con2->node.id); - int fs1 = con1->is_fullscreen; - int fs2 = con2->is_fullscreen; + bool fs1 = con1->is_fullscreen; + bool fs2 = con2->is_fullscreen; if (fs1) { container_set_fullscreen(con1, false); } @@ -99,13 +98,11 @@ static void container_swap(struct sway_container *con1, } struct sway_seat *seat = input_manager_get_default_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - struct sway_container *vis1 = container_parent( - seat_get_focus_inactive(seat, container_parent(con1, C_OUTPUT)), - C_WORKSPACE); - struct sway_container *vis2 = container_parent( - seat_get_focus_inactive(seat, container_parent(con2, C_OUTPUT)), - C_WORKSPACE); + struct sway_container *focus = seat_get_focused_container(seat); + struct sway_workspace *vis1 = + output_get_active_workspace(con1->workspace->output); + struct sway_workspace *vis2 = + output_get_active_workspace(con2->workspace->output); char *stored_prev_name = NULL; if (prev_workspace_name) { @@ -115,10 +112,10 @@ static void container_swap(struct sway_container *con1, swap_places(con1, con2); if (!workspace_is_visible(vis1)) { - seat_set_focus(seat, seat_get_focus_inactive(seat, vis1)); + seat_set_focus(seat, seat_get_focus_inactive(seat, &vis1->node)); } if (!workspace_is_visible(vis2)) { - seat_set_focus(seat, seat_get_focus_inactive(seat, vis2)); + seat_set_focus(seat, seat_get_focus_inactive(seat, &vis2->node)); } swap_focus(con1, con2, seat, focus); @@ -137,23 +134,22 @@ static void container_swap(struct sway_container *con1, } static bool test_con_id(struct sway_container *container, void *con_id) { - return container->id == (size_t)con_id; + return container->node.id == (size_t)con_id; } static bool test_id(struct sway_container *container, void *id) { #ifdef HAVE_XWAYLAND xcb_window_t *wid = id; - return (container->type == C_VIEW - && container->sway_view->type == SWAY_VIEW_XWAYLAND - && container->sway_view->wlr_xwayland_surface->window_id == *wid); + return (container->view && container->view->type == SWAY_VIEW_XWAYLAND + && container->view->wlr_xwayland_surface->window_id == *wid); #else return false; #endif } static bool test_mark(struct sway_container *container, void *mark) { - if (container->type == C_VIEW && container->sway_view->marks->length) { - return !list_seq_find(container->sway_view->marks, + if (container->view && container->view->marks->length) { + return !list_seq_find(container->view->marks, (int (*)(const void *, const void *))strcmp, mark); } return false; @@ -169,7 +165,7 @@ struct cmd_results *cmd_swap(int argc, char **argv) { return cmd_results_new(CMD_INVALID, "swap", EXPECTED_SYNTAX); } - struct sway_container *current = config->handler_context.current_container; + struct sway_container *current = config->handler_context.container; struct sway_container *other; char *value = join_args(argv + 3, argc - 3); @@ -191,7 +187,7 @@ struct cmd_results *cmd_swap(int argc, char **argv) { if (!other) { error = cmd_results_new(CMD_FAILURE, "swap", "Failed to find %s '%s'", argv[2], value); - } else if (current->type < C_CONTAINER || other->type < C_CONTAINER) { + } else if (!current) { error = cmd_results_new(CMD_FAILURE, "swap", "Can only swap with containers and views"); } else if (container_has_ancestor(current, other) @@ -211,9 +207,9 @@ struct cmd_results *cmd_swap(int argc, char **argv) { container_swap(current, other); - arrange_windows(current->parent); - if (other->parent != current->parent) { - arrange_windows(other->parent); + arrange_node(node_get_parent(¤t->node)); + if (node_get_parent(&other->node) != node_get_parent(¤t->node)) { + arrange_node(node_get_parent(&other->node)); } return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/commands/title_format.c b/sway/commands/title_format.c index 3d1c578c..c9ffe8fa 100644 --- a/sway/commands/title_format.c +++ b/sway/commands/title_format.c @@ -11,13 +11,12 @@ struct cmd_results *cmd_title_format(int argc, char **argv) { if ((error = checkarg(argc, "title_format", EXPECTED_AT_LEAST, 1))) { return error; } - struct sway_container *container = - config->handler_context.current_container; - if (container->type != C_VIEW) { + struct sway_container *container = config->handler_context.container; + if (!container->view) { return cmd_results_new(CMD_INVALID, "title_format", "Only views can have a title_format"); } - struct sway_view *view = container->sway_view; + struct sway_view *view = container->view; char *format = join_args(argv, argc); if (view->title_format) { free(view->title_format); diff --git a/sway/commands/unmark.c b/sway/commands/unmark.c index 62127c97..c6251dc8 100644 --- a/sway/commands/unmark.c +++ b/sway/commands/unmark.c @@ -9,9 +9,9 @@ #include "stringop.h" static void remove_all_marks_iterator(struct sway_container *con, void *data) { - if (con->type == C_VIEW) { - view_clear_marks(con->sway_view); - view_update_marks_textures(con->sway_view); + if (con->view) { + view_clear_marks(con->view); + view_update_marks_textures(con->view); } } @@ -24,13 +24,12 @@ struct cmd_results *cmd_unmark(int argc, char **argv) { // Determine the view struct sway_view *view = NULL; if (config->handler_context.using_criteria) { - struct sway_container *container = - config->handler_context.current_container; - if (container->type != C_VIEW) { + struct sway_container *container = config->handler_context.container; + if (!container->view) { return cmd_results_new(CMD_INVALID, "unmark", "Only views can have marks"); } - view = container->sway_view; + view = container->view; } // Determine the mark diff --git a/sway/commands/urgent.c b/sway/commands/urgent.c index bccb33fe..53c37d4d 100644 --- a/sway/commands/urgent.c +++ b/sway/commands/urgent.c @@ -11,13 +11,12 @@ struct cmd_results *cmd_urgent(int argc, char **argv) { if ((error = checkarg(argc, "urgent", EXPECTED_EQUAL_TO, 1))) { return error; } - struct sway_container *container = - config->handler_context.current_container; - if (container->type != C_VIEW) { + struct sway_container *container = config->handler_context.container; + if (!container->view) { return cmd_results_new(CMD_INVALID, "urgent", "Only views can be urgent"); } - struct sway_view *view = container->sway_view; + struct sway_view *view = container->view; if (strcmp(argv[0], "allow") == 0) { view->allow_request_urgent = true; diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index ceb4cd6e..f026a39d 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c @@ -58,7 +58,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { } - struct sway_container *ws = NULL; + struct sway_workspace *ws = NULL; if (strcasecmp(argv[0], "number") == 0) { if (argc < 2) { return cmd_results_new(CMD_INVALID, "workspace", -- cgit v1.2.3-54-g00ecf