aboutsummaryrefslogtreecommitdiff
path: root/sway
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2018-09-05 09:33:27 -0400
committerGitHub <noreply@github.com>2018-09-05 09:33:27 -0400
commit610eb946171f782165a20614b2d3318b89273990 (patch)
tree05eec1df1ef48e05b23d273d31143ad32e7632d2 /sway
parentaa2bf98e0442f9bf41a852c2fafee5b0897010a2 (diff)
parentdbf4aa3e33bdee53876c6893b15ac3f224818e7c (diff)
Merge pull request #2540 from RyanDwyer/typesafety
Implement type safe arguments and demote sway_container
Diffstat (limited to 'sway')
-rw-r--r--sway/commands.c27
-rw-r--r--sway/commands/border.c13
-rw-r--r--sway/commands/floating.c18
-rw-r--r--sway/commands/focus.c284
-rw-r--r--sway/commands/fullscreen.c18
-rw-r--r--sway/commands/gaps.c35
-rw-r--r--sway/commands/hide_edge_borders.c4
-rw-r--r--sway/commands/kill.c20
-rw-r--r--sway/commands/layout.c185
-rw-r--r--sway/commands/mark.c7
-rw-r--r--sway/commands/move.c887
-rw-r--r--sway/commands/opacity.c3
-rw-r--r--sway/commands/reload.c2
-rw-r--r--sway/commands/rename.c11
-rw-r--r--sway/commands/resize.c86
-rw-r--r--sway/commands/scratchpad.c42
-rw-r--r--sway/commands/seat/cursor.c4
-rw-r--r--sway/commands/show_marks.c10
-rw-r--r--sway/commands/smart_gaps.c2
-rw-r--r--sway/commands/split.c23
-rw-r--r--sway/commands/sticky.c27
-rw-r--r--sway/commands/swap.c76
-rw-r--r--sway/commands/title_format.c7
-rw-r--r--sway/commands/unmark.c13
-rw-r--r--sway/commands/urgent.c7
-rw-r--r--sway/commands/workspace.c2
-rw-r--r--sway/config.c2
-rw-r--r--sway/config/bar.c14
-rw-r--r--sway/config/output.c47
-rw-r--r--sway/criteria.c43
-rw-r--r--sway/debug-tree.c111
-rw-r--r--sway/desktop/desktop.c31
-rw-r--r--sway/desktop/layer_shell.c23
-rw-r--r--sway/desktop/output.c182
-rw-r--r--sway/desktop/render.c259
-rw-r--r--sway/desktop/transaction.c374
-rw-r--r--sway/desktop/xdg_shell.c43
-rw-r--r--sway/desktop/xdg_shell_v6.c40
-rw-r--r--sway/desktop/xwayland.c50
-rw-r--r--sway/input/cursor.c164
-rw-r--r--sway/input/input-manager.c14
-rw-r--r--sway/input/seat.c536
-rw-r--r--sway/ipc-json.c185
-rw-r--r--sway/ipc-server.c55
-rw-r--r--sway/main.c6
-rw-r--r--sway/meson.build1
-rw-r--r--sway/server.c7
-rw-r--r--sway/tree/arrange.c109
-rw-r--r--sway/tree/container.c873
-rw-r--r--sway/tree/node.c151
-rw-r--r--sway/tree/output.c348
-rw-r--r--sway/tree/root.c186
-rw-r--r--sway/tree/view.c275
-rw-r--r--sway/tree/workspace.c493
54 files changed, 3202 insertions, 3233 deletions
diff --git a/sway/commands.c b/sway/commands.c
index e72b8916..b32628cd 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -212,6 +212,24 @@ struct cmd_handler *find_handler(char *line, struct cmd_handler *cmd_handlers,
return res;
}
+static void set_config_node(struct sway_node *node) {
+ config->handler_context.node = node;
+ switch (node->type) {
+ case N_CONTAINER:
+ config->handler_context.container = node->sway_container;
+ config->handler_context.workspace = node->sway_container->workspace;
+ break;
+ case N_WORKSPACE:
+ config->handler_context.container = NULL;
+ config->handler_context.workspace = node->sway_workspace;
+ break;
+ default:
+ config->handler_context.container = NULL;
+ config->handler_context.workspace = NULL;
+ break;
+ }
+}
+
struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
// Even though this function will process multiple commands we will only
// return the last error, if any (for now). (Since we have access to an
@@ -295,12 +313,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
if (!config->handler_context.using_criteria) {
// without criteria, the command acts upon the focused
// container
- config->handler_context.current_container =
- seat_get_focus_inactive(seat, &root_container);
- if (!sway_assert(config->handler_context.current_container,
- "could not get focus-inactive for root container")) {
- return NULL;
- }
+ set_config_node(seat_get_focus_inactive(seat, &root->node));
struct cmd_results *res = handler->handle(argc-1, argv+1);
if (res->status != CMD_SUCCESS) {
free_argv(argc, argv);
@@ -314,7 +327,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
} else {
for (int i = 0; i < views->length; ++i) {
struct sway_view *view = views->items[i];
- config->handler_context.current_container = view->swayc;
+ set_config_node(&view->container->node);
struct cmd_results *res = handler->handle(argc-1, argv+1);
if (res->status != CMD_SUCCESS) {
free_argv(argc, argv);
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..83b8c64a 100644
--- a/sway/commands/focus.c
+++ b/sway/commands/focus.c
@@ -34,58 +34,49 @@ 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);
}
+ break;
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);
}
+ break;
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);
+ }
+ break;
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;
}
@@ -94,151 +85,90 @@ static struct sway_container *get_swayc_in_output_direction(
}
}
- return ws;
-}
+ if (container) {
+ container = seat_get_focus_inactive_view(seat, &container->node);
+ return &container->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;
+ return &ws->node;
+}
- if (dir == MOVE_CHILD) {
- return seat_get_focus_inactive(seat, container);
- }
+static struct sway_node *node_get_in_direction(struct sway_container *container,
+ struct sway_seat *seat, enum movement_direction dir) {
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 +176,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 +185,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 <direction|name>'");
}
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 +202,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 +218,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 +253,34 @@ struct cmd_results *cmd_focus(int argc, char **argv) {
"or 'focus output <direction|name>'");
}
- struct sway_container *next_focus = container_get_in_direction(
- con, seat, direction);
+ if (direction == MOVE_CHILD) {
+ struct sway_node *focus = seat_get_active_child(seat, node);
+ if (focus) {
+ seat_set_focus(seat, focus);
+ }
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+ }
+
+ if (node->type == N_WORKSPACE) {
+ if (direction == MOVE_PARENT) {
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+ }
+
+ // Jump to the next output
+ struct sway_output *new_output =
+ output_get_in_direction(workspace->output, direction);
+ if (!new_output) {
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+ }
+
+ 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 <math.h>
@@ -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 <amount>
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 <amount>)
@@ -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..44ce2970 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,128 @@ 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) {
+ 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..7b503624 100644
--- a/sway/commands/move.c
+++ b/sway/commands/move.c
@@ -40,8 +40,8 @@ enum wlr_direction opposite_direction(enum wlr_direction d) {
}
}
-static struct sway_container *output_in_direction(const char *direction_string,
- struct wlr_output *reference, int ref_lx, int ref_ly) {
+static struct sway_output *output_in_direction(const char *direction_string,
+ struct sway_output *reference, int ref_lx, int ref_ly) {
struct {
char *name;
enum wlr_direction direction;
@@ -61,449 +61,370 @@ static struct sway_container *output_in_direction(const char *direction_string,
}
}
- if (direction) {
+ if (reference && 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->wlr_output,
+ 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->wlr_output, 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);
+ } 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 && 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);
+ // 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 (next_ws && next_ws->type != C_WORKSPACE) {
- next_ws = container_parent(next_ws, C_WORKSPACE);
- }
- 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 +451,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 ? old_ws->output : NULL;
+ 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 ||
@@ -576,7 +497,8 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
if (!no_auto_back_and_forth && config->auto_back_and_forth &&
prev_workspace_name) {
// auto back and forth move
- if (old_ws->name && strcmp(old_ws->name, ws_name) == 0) {
+ if (old_ws && old_ws->name &&
+ strcmp(old_ws->name, ws_name) == 0) {
// if target workspace is the current one
free(ws_name);
ws_name = strdup(prev_workspace_name);
@@ -588,8 +510,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 +523,119 @@ 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, 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 && old_output &&
+ 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);
+ if (container->scratchpad) {
+ root_scratchpad_remove_container(container);
+ }
+ 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 if (old_ws) {
+ 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 if (old_ws) {
+ workspace_consider_destroy(old_ws);
+ }
+
+ if (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);
+ struct sway_node *focus = seat_get_focus_inactive(seat, &workspace->node);
+ seat_set_focus(seat, focus);
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 +652,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, 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 +682,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 +715,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 +751,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 +791,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 +830,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 +872,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 <on|off>' ");
}
- 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(&current->node));
+ if (node_get_parent(&other->node) != node_get_parent(&current->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",
diff --git a/sway/config.c b/sway/config.c
index 8105722a..89701640 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -825,6 +825,6 @@ void config_update_font_height(bool recalculate) {
root_for_each_container(find_font_height_iterator, &recalculate);
if (config->font_height != prev_max_height) {
- arrange_windows(&root_container);
+ arrange_root();
}
}
diff --git a/sway/config/bar.c b/sway/config/bar.c
index ae9383d6..f83b37d1 100644
--- a/sway/config/bar.c
+++ b/sway/config/bar.c
@@ -12,6 +12,7 @@
#include <strings.h>
#include <signal.h>
#include "sway/config.h"
+#include "sway/output.h"
#include "stringop.h"
#include "list.h"
#include "log.h"
@@ -218,17 +219,6 @@ void invoke_swaybar(struct bar_config *bar) {
close(filedes[1]);
}
-static bool active_output(const char *name) {
- struct sway_container *cont = NULL;
- for (int i = 0; i < root_container.children->length; ++i) {
- cont = root_container.children->items[i];
- if (cont->type == C_OUTPUT && strcasecmp(name, cont->name) == 0) {
- return true;
- }
- }
- return false;
-}
-
void load_swaybars() {
for (int i = 0; i < config->bars->length; ++i) {
struct bar_config *bar = config->bars->items[i];
@@ -236,7 +226,7 @@ void load_swaybars() {
if (bar->outputs) {
for (int j = 0; j < bar->outputs->length; ++j) {
char *o = bar->outputs->items[j];
- if (!strcmp(o, "*") || active_output(o)) {
+ if (!strcmp(o, "*") || output_by_name(o)) {
apply = true;
break;
}
diff --git a/sway/config/output.c b/sway/config/output.c
index 65f09258..aa53fc46 100644
--- a/sway/config/output.c
+++ b/sway/config/output.c
@@ -174,21 +174,16 @@ void terminate_swaybg(pid_t pid) {
}
}
-void apply_output_config(struct output_config *oc, struct sway_container *output) {
- assert(output->type == C_OUTPUT);
-
- struct wlr_output_layout *output_layout =
- root_container.sway_root->output_layout;
- struct wlr_output *wlr_output = output->sway_output->wlr_output;
+void apply_output_config(struct output_config *oc, struct sway_output *output) {
+ struct wlr_output *wlr_output = output->wlr_output;
if (oc && oc->enabled == 0) {
- if (output->sway_output->bg_pid != 0) {
- terminate_swaybg(output->sway_output->bg_pid);
- output->sway_output->bg_pid = 0;
+ if (output->bg_pid != 0) {
+ terminate_swaybg(output->bg_pid);
+ output->bg_pid = 0;
}
- output_begin_destroy(output);
- wlr_output_layout_remove(root_container.sway_root->output_layout,
- wlr_output);
+ output_disable(output);
+ wlr_output_layout_remove(root->output_layout, wlr_output);
return;
}
@@ -213,21 +208,21 @@ void apply_output_config(struct output_config *oc, struct sway_container *output
// Find position for it
if (oc && (oc->x != -1 || oc->y != -1)) {
wlr_log(WLR_DEBUG, "Set %s position to %d, %d", oc->name, oc->x, oc->y);
- wlr_output_layout_add(output_layout, wlr_output, oc->x, oc->y);
+ wlr_output_layout_add(root->output_layout, wlr_output, oc->x, oc->y);
} else {
- wlr_output_layout_add_auto(output_layout, wlr_output);
+ wlr_output_layout_add_auto(root->output_layout, wlr_output);
}
int output_i;
- for (output_i = 0; output_i < root_container.children->length; ++output_i) {
- if (root_container.children->items[output_i] == output) {
+ for (output_i = 0; output_i < root->outputs->length; ++output_i) {
+ if (root->outputs->items[output_i] == output) {
break;
}
}
if (oc && oc->background) {
- if (output->sway_output->bg_pid != 0) {
- terminate_swaybg(output->sway_output->bg_pid);
+ if (output->bg_pid != 0) {
+ terminate_swaybg(output->bg_pid);
}
wlr_log(WLR_DEBUG, "Setting background for output %d to %s",
@@ -249,8 +244,8 @@ void apply_output_config(struct output_config *oc, struct sway_container *output
wlr_log(WLR_DEBUG, "-> %s", command);
char *const cmd[] = { "sh", "-c", command, NULL };
- output->sway_output->bg_pid = fork();
- if (output->sway_output->bg_pid == 0) {
+ output->bg_pid = fork();
+ if (output->bg_pid == 0) {
execvp(cmd[0], cmd);
} else {
free(command);
@@ -293,12 +288,11 @@ void apply_output_config_to_outputs(struct output_config *oc) {
bool wildcard = strcmp(oc->name, "*") == 0;
char id[128];
struct sway_output *sway_output;
- wl_list_for_each(sway_output,
- &root_container.sway_root->all_outputs, link) {
+ wl_list_for_each(sway_output, &root->all_outputs, link) {
char *name = sway_output->wlr_output->name;
output_get_identifier(id, sizeof(id), sway_output);
if (wildcard || !strcmp(name, oc->name) || !strcmp(id, oc->name)) {
- if (!sway_output->swayc) {
+ if (!sway_output->enabled) {
if (!oc->enabled) {
if (!wildcard) {
break;
@@ -306,7 +300,7 @@ void apply_output_config_to_outputs(struct output_config *oc) {
continue;
}
- output_enable(sway_output);
+ output_enable(sway_output, oc);
}
struct output_config *current = oc;
@@ -316,7 +310,7 @@ void apply_output_config_to_outputs(struct output_config *oc) {
current = tmp;
}
}
- apply_output_config(current, sway_output->swayc);
+ apply_output_config(current, sway_output);
if (!wildcard) {
// Stop looking if the output config isn't applicable to all
@@ -354,8 +348,7 @@ static void default_output_config(struct output_config *oc,
void create_default_output_configs(void) {
struct sway_output *sway_output;
- wl_list_for_each(sway_output,
- &root_container.sway_root->all_outputs, link) {
+ wl_list_for_each(sway_output, &root->all_outputs, link) {
char *name = sway_output->wlr_output->name;
struct output_config *oc = new_output_config(name);
default_output_config(oc, sway_output->wlr_output);
diff --git a/sway/criteria.c b/sway/criteria.c
index feca904a..0193233e 100644
--- a/sway/criteria.c
+++ b/sway/criteria.c
@@ -9,6 +9,7 @@
#include "sway/config.h"
#include "sway/tree/root.h"
#include "sway/tree/view.h"
+#include "sway/tree/workspace.h"
#include "stringop.h"
#include "list.h"
#include "log.h"
@@ -87,12 +88,12 @@ static int cmp_urgent(const void *_a, const void *_b) {
return 0;
}
-static void find_urgent_iterator(struct sway_container *swayc, void *data) {
- if (swayc->type != C_VIEW || !view_is_urgent(swayc->sway_view)) {
+static void find_urgent_iterator(struct sway_container *con, void *data) {
+ if (!con->view || !view_is_urgent(con->view)) {
return;
}
list_t *urgent_views = data;
- list_add(urgent_views, swayc->sway_view);
+ list_add(urgent_views, con->view);
}
static bool criteria_matches_view(struct criteria *criteria,
@@ -117,7 +118,7 @@ static bool criteria_matches_view(struct criteria *criteria,
return false;
}
}
-
+
if (criteria->con_mark) {
bool exists = false;
for (int i = 0; i < view->marks->length; ++i) {
@@ -132,7 +133,7 @@ static bool criteria_matches_view(struct criteria *criteria,
}
if (criteria->con_id) { // Internal ID
- if (!view->swayc || view->swayc->id != criteria->con_id) {
+ if (!view->container || view->container->node.id != criteria->con_id) {
return false;
}
}
@@ -174,13 +175,13 @@ static bool criteria_matches_view(struct criteria *criteria,
#endif
if (criteria->floating) {
- if (!container_is_floating(view->swayc)) {
+ if (!container_is_floating(view->container)) {
return false;
}
}
if (criteria->tiling) {
- if (container_is_floating(view->swayc)) {
+ if (container_is_floating(view->container)) {
return false;
}
}
@@ -205,10 +206,7 @@ static bool criteria_matches_view(struct criteria *criteria,
}
if (criteria->workspace) {
- if (!view->swayc) {
- return false;
- }
- struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
+ struct sway_workspace *ws = view->container->workspace;
if (!ws || strcmp(ws->name, criteria->workspace) != 0) {
return false;
}
@@ -237,9 +235,9 @@ struct match_data {
static void criteria_get_views_iterator(struct sway_container *container,
void *data) {
struct match_data *match_data = data;
- if (container->type == C_VIEW) {
- if (criteria_matches_view(match_data->criteria, container->sway_view)) {
- list_add(match_data->matches, container->sway_view);
+ if (container->view) {
+ if (criteria_matches_view(match_data->criteria, container->view)) {
+ list_add(match_data->matches, container->view);
}
}
}
@@ -355,12 +353,12 @@ static enum criteria_token token_from_name(char *name) {
*/
static char *get_focused_prop(enum criteria_token token) {
struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus = seat_get_focus(seat);
+ struct sway_container *focus = seat_get_focused_container(seat);
- if (!focus || focus->type != C_VIEW) {
+ if (!focus || !focus->view) {
return NULL;
}
- struct sway_view *view = focus->sway_view;
+ struct sway_view *view = focus->view;
const char *value = NULL;
switch (token) {
@@ -374,18 +372,15 @@ static char *get_focused_prop(enum criteria_token token) {
value = view_get_title(view);
break;
case T_WORKSPACE:
- {
- struct sway_container *ws = container_parent(focus, C_WORKSPACE);
- if (ws) {
- value = ws->name;
- }
+ if (focus->workspace) {
+ value = focus->workspace->name;
}
break;
case T_CON_ID:
- if (view->swayc == NULL) {
+ if (view->container == NULL) {
return NULL;
}
- size_t id = view->swayc->id;
+ size_t id = view->container->node.id;
size_t id_size = snprintf(NULL, 0, "%zu", id) + 1;
char *id_str = malloc(id_size);
snprintf(id_str, id_size, "%zu", id);
diff --git a/sway/debug-tree.c b/sway/debug-tree.c
index 2768cf58..973c6d88 100644
--- a/sway/debug-tree.c
+++ b/sway/debug-tree.c
@@ -10,6 +10,7 @@
#include "sway/server.h"
#include "sway/tree/container.h"
#include "sway/tree/root.h"
+#include "sway/tree/workspace.h"
#include "cairo.h"
#include "config.h"
#include "pango.h"
@@ -32,28 +33,78 @@ static const char *layout_to_str(enum sway_container_layout layout) {
return "L_NONE";
}
-static int draw_container(cairo_t *cairo, struct sway_container *container,
- struct sway_container *focus, int x, int y) {
+static char *get_string(struct sway_node *node) {
+ char *buffer = malloc(512);
+ switch (node->type) {
+ case N_ROOT:
+ snprintf(buffer, 512, "N_ROOT id:%zd %.fx%.f@%.f,%.f", node->id,
+ root->width, root->height, root->x, root->y);
+ break;
+ case N_OUTPUT:
+ snprintf(buffer, 512, "N_OUTPUT id:%zd '%s' %dx%d@%d,%d", node->id,
+ node->sway_output->wlr_output->name,
+ node->sway_output->width,
+ node->sway_output->height,
+ node->sway_output->lx,
+ node->sway_output->ly);
+ break;
+ case N_WORKSPACE:
+ snprintf(buffer, 512, "N_WORKSPACE id:%zd '%s' %s %dx%d@%.f,%.f",
+ node->id, node->sway_workspace->name,
+ layout_to_str(node->sway_workspace->layout),
+ node->sway_workspace->width, node->sway_workspace->height,
+ node->sway_workspace->x, node->sway_workspace->y);
+ break;
+ case N_CONTAINER:
+ snprintf(buffer, 512, "N_CONTAINER id:%zd '%s' %s %.fx%.f@%.f,%.f",
+ node->id, node->sway_container->title,
+ layout_to_str(node->sway_container->layout),
+ node->sway_container->width, node->sway_container->height,
+ node->sway_container->x, node->sway_container->y);
+ break;
+ }
+ return buffer;
+}
+
+static list_t *get_children(struct sway_node *node) {
+ switch (node->type) {
+ case N_ROOT:
+ return root->outputs;
+ case N_OUTPUT:
+ return node->sway_output->workspaces;
+ case N_WORKSPACE:
+ return node->sway_workspace->tiling;
+ case N_CONTAINER:
+ return node->sway_container->children;
+ }
+ return NULL;
+}
+
+static int draw_node(cairo_t *cairo, struct sway_node *node,
+ struct sway_node *focus, int x, int y) {
int text_width, text_height;
+ char *buffer = get_string(node);
get_text_size(cairo, "monospace", &text_width, &text_height,
- 1, false, "%s id:%zd '%s' %s %.fx%.f@%.f,%.f",
- container_type_to_str(container->type), container->id, container->name,
- layout_to_str(container->layout),
- container->width, container->height, container->x, container->y);
+ 1, false, buffer);
cairo_save(cairo);
cairo_rectangle(cairo, x + 2, y, text_width - 2, text_height);
cairo_set_source_u32(cairo, 0xFFFFFFE0);
cairo_fill(cairo);
int height = text_height;
- if (container->children) {
- for (int i = 0; i < container->children->length; ++i) {
- struct sway_container *child = container->children->items[i];
- if (child->parent == container) {
+ list_t *children = get_children(node);
+ if (children) {
+ for (int i = 0; i < children->length; ++i) {
+ // This is really dirty - the list contains specific structs but
+ // we're casting them as nodes. This works because node is the first
+ // item in each specific struct. This is acceptable because this is
+ // debug code.
+ struct sway_node *child = children->items[i];
+ if (node_get_parent(child) == node) {
cairo_set_source_u32(cairo, 0x000000FF);
} else {
cairo_set_source_u32(cairo, 0xFF0000FF);
}
- height += draw_container(cairo, child, focus, x + 10, y + height);
+ height += draw_node(cairo, child, focus, x + 10, y + height);
}
}
cairo_set_source_u32(cairo, 0xFFFFFFE0);
@@ -61,13 +112,11 @@ static int draw_container(cairo_t *cairo, struct sway_container *container,
cairo_fill(cairo);
cairo_restore(cairo);
cairo_move_to(cairo, x, y);
- if (focus == container) {
+ if (focus == node) {
cairo_set_source_u32(cairo, 0x0000FFFF);
}
- pango_printf(cairo, "monospace", 1, false, "%s id:%zd '%s' %s %.fx%.f@%.f,%.f",
- container_type_to_str(container->type), container->id, container->name,
- layout_to_str(container->layout),
- container->width, container->height, container->x, container->y);
+ pango_printf(cairo, "monospace", 1, false, buffer);
+ free(buffer);
return height;
}
@@ -77,13 +126,13 @@ void update_debug_tree() {
}
int width = 640, height = 480;
- for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *container = root_container.children->items[i];
- if (container->width > width) {
- width = container->width;
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
+ if (output->width > width) {
+ width = output->width;
}
- if (container->height > height) {
- height = container->height;
+ if (output->height > height) {
+ height = output->height;
}
}
cairo_surface_t *surface =
@@ -91,28 +140,22 @@ void update_debug_tree() {
cairo_t *cairo = cairo_create(surface);
PangoContext *pango = pango_cairo_create_context(cairo);
- struct sway_seat *seat = NULL;
- wl_list_for_each(seat, &input_manager->seats, link) {
- break;
- }
+ struct sway_seat *seat = input_manager_current_seat(input_manager);
+ struct sway_node *focus = seat_get_focus(seat);
- struct sway_container *focus = NULL;
- if (seat != NULL) {
- focus = seat_get_focus(seat);
- }
cairo_set_source_u32(cairo, 0x000000FF);
- draw_container(cairo, &root_container, focus, 0, 0);
+ draw_node(cairo, &root->node, focus, 0, 0);
cairo_surface_flush(surface);
struct wlr_renderer *renderer = wlr_backend_get_renderer(server.backend);
- if (root_container.sway_root->debug_tree) {
- wlr_texture_destroy(root_container.sway_root->debug_tree);
+ if (root->debug_tree) {
+ wlr_texture_destroy(root->debug_tree);
}
unsigned char *data = cairo_image_surface_get_data(surface);
int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
struct wlr_texture *texture = wlr_texture_from_pixels(renderer,
WL_SHM_FORMAT_ARGB8888, stride, width, height, data);
- root_container.sway_root->debug_tree = texture;
+ root->debug_tree = texture;
cairo_surface_destroy(surface);
g_object_unref(pango);
cairo_destroy(cairo);
diff --git a/sway/desktop/desktop.c b/sway/desktop/desktop.c
index 72650397..771b58fe 100644
--- a/sway/desktop/desktop.c
+++ b/sway/desktop/desktop.c
@@ -4,37 +4,32 @@
void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly,
bool whole) {
- for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *cont = root_container.children->items[i];
- if (cont->type == C_OUTPUT) {
- output_damage_surface(cont->sway_output,
- lx - cont->current.swayc_x, ly - cont->current.swayc_y,
- surface, whole);
- }
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
+ output_damage_surface(output, lx - output->wlr_output->lx,
+ ly - output->wlr_output->ly, surface, whole);
}
}
void desktop_damage_whole_container(struct sway_container *con) {
- for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *cont = root_container.children->items[i];
- if (cont->type == C_OUTPUT) {
- output_damage_whole_container(cont->sway_output, con);
- }
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
+ output_damage_whole_container(output, con);
}
}
void desktop_damage_box(struct wlr_box *box) {
- for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *cont = root_container.children->items[i];
- output_damage_box(cont->sway_output, box);
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
+ output_damage_box(output, box);
}
}
void desktop_damage_view(struct sway_view *view) {
- desktop_damage_whole_container(view->swayc);
+ desktop_damage_whole_container(view->container);
struct wlr_box box = {
- .x = view->swayc->current.view_x - view->geometry.x,
- .y = view->swayc->current.view_y - view->geometry.y,
+ .x = view->container->current.view_x - view->geometry.x,
+ .y = view->container->current.view_y - view->geometry.y,
.width = view->surface->current.width,
.height = view->surface->current.height,
};
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index a4f7f928..7d254173 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -14,6 +14,7 @@
#include "sway/output.h"
#include "sway/server.h"
#include "sway/tree/arrange.h"
+#include "sway/tree/workspace.h"
#include "log.h"
static void apply_exclusive(struct wlr_box *usable_area,
@@ -176,7 +177,7 @@ void arrange_layers(struct sway_output *output) {
sizeof(struct wlr_box)) != 0) {
wlr_log(WLR_DEBUG, "Usable area changed, rearranging output");
memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box));
- arrange_output(output->swayc);
+ arrange_output(output);
}
// Arrange non-exlusive surfaces from top->bottom
@@ -256,7 +257,7 @@ static void unmap(struct sway_layer_surface *sway_layer) {
return;
}
struct sway_output *output = wlr_output->data;
- if (output == NULL || output->swayc == NULL) {
+ if (output == NULL) {
return;
}
output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
@@ -283,9 +284,9 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&sway_layer->surface_commit.link);
if (sway_layer->layer_surface->output != NULL) {
struct sway_output *output = sway_layer->layer_surface->output->data;
- if (output != NULL && output->swayc != NULL) {
+ if (output != NULL) {
arrange_layers(output);
- arrange_windows(output->swayc);
+ arrange_output(output);
transaction_commit_dirty();
}
wl_list_remove(&sway_layer->output_destroy.link);
@@ -332,23 +333,21 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
if (!layer_surface->output) {
// Assign last active output
- struct sway_container *output = NULL;
+ struct sway_output *output = NULL;
struct sway_seat *seat = input_manager_get_default_seat(input_manager);
if (seat) {
- output = seat_get_focus_inactive(seat, &root_container);
+ struct sway_workspace *ws = seat_get_focused_workspace(seat);
+ output = ws->output;
}
if (!output) {
- if (!sway_assert(root_container.children->length,
+ if (!sway_assert(root->outputs->length,
"cannot auto-assign output for layer")) {
wlr_layer_surface_close(layer_surface);
return;
}
- output = root_container.children->items[0];
+ output = root->outputs->items[0];
}
- if (output->type != C_OUTPUT) {
- output = container_parent(output, C_OUTPUT);
- }
- layer_surface->output = output->sway_output->wlr_output;
+ layer_surface->output = output->wlr_output;
}
struct sway_layer_surface *sway_layer =
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index c30e52a1..7e9f7b7e 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -28,10 +28,10 @@
#include "sway/tree/view.h"
#include "sway/tree/workspace.h"
-struct sway_container *output_by_name(const char *name) {
- for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *output = root_container.children->items[i];
- if (strcasecmp(output->name, name) == 0) {
+struct sway_output *output_by_name(const char *name) {
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
+ if (strcasecmp(output->wlr_output->name, name) == 0) {
return output;
}
}
@@ -98,8 +98,8 @@ static bool get_surface_box(struct surface_iterator_data *data,
wlr_box_rotated_bounds(&box, data->rotation, &rotated_box);
struct wlr_box output_box = {
- .width = output->swayc->current.swayc_width,
- .height = output->swayc->current.swayc_height,
+ .width = output->width,
+ .height = output->height,
};
struct wlr_box intersection;
@@ -145,12 +145,12 @@ void output_view_for_each_surface(struct sway_output *output,
.user_iterator = iterator,
.user_data = user_data,
.output = output,
- .ox = view->swayc->current.view_x - output->swayc->current.swayc_x
+ .ox = view->container->current.view_x - output->wlr_output->lx
- view->geometry.x,
- .oy = view->swayc->current.view_y - output->swayc->current.swayc_y
+ .oy = view->container->current.view_y - output->wlr_output->ly
- view->geometry.y,
- .width = view->swayc->current.view_width,
- .height = view->swayc->current.view_height,
+ .width = view->container->current.view_width,
+ .height = view->container->current.view_height,
.rotation = 0, // TODO
};
@@ -164,12 +164,12 @@ void output_view_for_each_popup(struct sway_output *output,
.user_iterator = iterator,
.user_data = user_data,
.output = output,
- .ox = view->swayc->current.view_x - output->swayc->current.swayc_x
+ .ox = view->container->current.view_x - output->wlr_output->lx
- view->geometry.x,
- .oy = view->swayc->current.view_y - output->swayc->current.swayc_y
+ .oy = view->container->current.view_y - output->wlr_output->ly
- view->geometry.y,
- .width = view->swayc->current.view_width,
- .height = view->swayc->current.view_height,
+ .width = view->container->current.view_width,
+ .height = view->container->current.view_height,
.rotation = 0, // TODO
};
@@ -197,8 +197,8 @@ void output_unmanaged_for_each_surface(struct sway_output *output,
wl_list_for_each(unmanaged_surface, unmanaged, link) {
struct wlr_xwayland_surface *xsurface =
unmanaged_surface->wlr_xwayland_surface;
- double ox = unmanaged_surface->lx - output->swayc->current.swayc_x;
- double oy = unmanaged_surface->ly - output->swayc->current.swayc_y;
+ double ox = unmanaged_surface->lx - output->wlr_output->lx;
+ double oy = unmanaged_surface->ly - output->wlr_output->ly;
output_surface_for_each_surface(output, xsurface->surface, ox, oy,
iterator, user_data);
@@ -211,8 +211,8 @@ void output_drag_icons_for_each_surface(struct sway_output *output,
void *user_data) {
struct sway_drag_icon *drag_icon;
wl_list_for_each(drag_icon, drag_icons, link) {
- double ox = drag_icon->x - output->swayc->x;
- double oy = drag_icon->y - output->swayc->y;
+ double ox = drag_icon->x - output->wlr_output->lx;
+ double oy = drag_icon->y - output->wlr_output->ly;
if (drag_icon->wlr_drag_icon->mapped) {
output_surface_for_each_surface(output,
@@ -229,19 +229,13 @@ static void scale_box(struct wlr_box *box, float scale) {
box->height *= scale;
}
-struct sway_container *output_get_active_workspace(struct sway_output *output) {
+struct sway_workspace *output_get_active_workspace(struct sway_output *output) {
struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus =
- seat_get_focus_inactive(seat, output->swayc);
+ struct sway_node *focus = seat_get_active_child(seat, &output->node);
if (!focus) {
- // We've never been to this output before
- focus = output->swayc->current.children->items[0];
+ return output->workspaces->items[0];
}
- struct sway_container *workspace = focus;
- if (workspace->type != C_WORKSPACE) {
- workspace = container_parent(workspace, C_WORKSPACE);
- }
- return workspace;
+ return focus->sway_workspace;
}
bool output_has_opaque_overlay_layer_surface(struct sway_output *output) {
@@ -255,8 +249,8 @@ bool output_has_opaque_overlay_layer_surface(struct sway_output *output) {
struct sway_layer_surface *sway_layer_surface =
layer_from_wlr_layer_surface(wlr_layer_surface);
pixman_box32_t output_box = {
- .x2 = output->swayc->current.swayc_width,
- .y2 = output->swayc->current.swayc_height,
+ .x2 = output->width,
+ .y2 = output->height,
};
pixman_region32_t surface_opaque_box;
pixman_region32_init(&surface_opaque_box);
@@ -307,15 +301,15 @@ struct send_frame_done_data {
static void send_frame_done_container_iterator(struct sway_container *con,
void *_data) {
- if (con->type != C_VIEW) {
+ if (!con->view) {
return;
}
- if (!view_is_visible(con->sway_view)) {
+ if (!view_is_visible(con->view)) {
return;
}
struct send_frame_done_data *data = _data;
- output_view_for_each_surface(data->output, con->sway_view,
+ output_view_for_each_surface(data->output, con->view,
send_frame_done_iterator, data->when);
}
@@ -328,15 +322,14 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) {
.output = output,
.when = when,
};
- struct sway_container *workspace = output_get_active_workspace(output);
- if (workspace->current.ws_fullscreen) {
+ struct sway_workspace *workspace = output_get_active_workspace(output);
+ if (workspace->current.fullscreen) {
send_frame_done_container_iterator(
- workspace->current.ws_fullscreen, &data);
- container_for_each_child(workspace->current.ws_fullscreen,
+ workspace->current.fullscreen, &data);
+ container_for_each_child(workspace->current.fullscreen,
send_frame_done_container_iterator, &data);
#ifdef HAVE_XWAYLAND
- send_frame_done_unmanaged(output,
- &root_container.sway_root->xwayland_unmanaged, when);
+ send_frame_done_unmanaged(output, &root->xwayland_unmanaged, when);
#endif
} else {
send_frame_done_layer(output,
@@ -348,8 +341,7 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) {
send_frame_done_container_iterator, &data);
#ifdef HAVE_XWAYLAND
- send_frame_done_unmanaged(output,
- &root_container.sway_root->xwayland_unmanaged, when);
+ send_frame_done_unmanaged(output, &root->xwayland_unmanaged, when);
#endif
send_frame_done_layer(output,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], when);
@@ -358,8 +350,7 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) {
send_frame_overlay:
send_frame_done_layer(output,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], when);
- send_frame_done_drag_icons(output, &root_container.sway_root->drag_icons,
- when);
+ send_frame_done_drag_icons(output, &root->drag_icons, when);
}
static void damage_handle_frame(struct wl_listener *listener, void *data) {
@@ -391,7 +382,11 @@ static void damage_handle_frame(struct wl_listener *listener, void *data) {
}
void output_damage_whole(struct sway_output *output) {
- wlr_output_damage_add_whole(output->damage);
+ // The output can exist with no wlr_output if it's just been disconnected
+ // and the transaction to evacuate it has't completed yet.
+ if (output && output->wlr_output) {
+ wlr_output_damage_add_whole(output->damage);
+ }
}
static void damage_surface_iterator(struct sway_output *output,
@@ -446,14 +441,9 @@ void output_damage_surface(struct sway_output *output, double ox, double oy,
static void output_damage_view(struct sway_output *output,
struct sway_view *view, bool whole) {
- if (!sway_assert(view->swayc != NULL, "expected a view in the tree")) {
- return;
- }
-
if (!view_is_visible(view)) {
return;
}
-
output_view_for_each_surface(output, view, damage_surface_iterator, &whole);
}
@@ -466,31 +456,29 @@ void output_damage_from_view(struct sway_output *output,
void output_damage_box(struct sway_output *output, struct wlr_box *_box) {
struct wlr_box box;
memcpy(&box, _box, sizeof(struct wlr_box));
- box.x -= output->swayc->current.swayc_x;
- box.y -= output->swayc->current.swayc_y;
+ box.x -= output->wlr_output->lx;
+ box.y -= output->wlr_output->ly;
scale_box(&box, output->wlr_output->scale);
wlr_output_damage_add_box(output->damage, &box);
}
static void output_damage_whole_container_iterator(struct sway_container *con,
void *data) {
- struct sway_output *output = data;
-
- if (!sway_assert(con->type == C_VIEW, "expected a view")) {
+ if (!sway_assert(con->view, "expected a view")) {
return;
}
-
- output_damage_view(output, con->sway_view, true);
+ struct sway_output *output = data;
+ output_damage_view(output, con->view, true);
}
void output_damage_whole_container(struct sway_output *output,
struct sway_container *con) {
// Pad the box by 1px, because the width is a double and might be a fraction
struct wlr_box box = {
- .x = con->current.swayc_x - output->wlr_output->lx - 1,
- .y = con->current.swayc_y - output->wlr_output->ly - 1,
- .width = con->current.swayc_width + 2,
- .height = con->current.swayc_height + 2,
+ .x = con->current.con_x - output->wlr_output->lx - 1,
+ .y = con->current.con_y - output->wlr_output->ly - 1,
+ .width = con->current.con_width + 2,
+ .height = con->current.con_height + 2,
};
scale_box(&box, output->wlr_output->scale);
wlr_output_damage_add_box(output->damage, &box);
@@ -499,44 +487,48 @@ void output_damage_whole_container(struct sway_output *output,
static void damage_handle_destroy(struct wl_listener *listener, void *data) {
struct sway_output *output =
wl_container_of(listener, output, damage_destroy);
- output_begin_destroy(output->swayc);
+ output_disable(output);
+ transaction_commit_dirty();
}
static void handle_destroy(struct wl_listener *listener, void *data) {
struct sway_output *output = wl_container_of(listener, output, destroy);
wl_signal_emit(&output->events.destroy, output);
- if (output->swayc) {
- output_begin_destroy(output->swayc);
+ if (output->enabled) {
+ output_disable(output);
}
+ output_begin_destroy(output);
- wl_list_remove(&output->link);
- wl_list_remove(&output->destroy.link);
- output->wlr_output->data = NULL;
- free(output);
-
- arrange_windows(&root_container);
+ transaction_commit_dirty();
}
static void handle_mode(struct wl_listener *listener, void *data) {
struct sway_output *output = wl_container_of(listener, output, mode);
arrange_layers(output);
- arrange_windows(output->swayc);
+ arrange_output(output);
transaction_commit_dirty();
}
static void handle_transform(struct wl_listener *listener, void *data) {
struct sway_output *output = wl_container_of(listener, output, transform);
arrange_layers(output);
- arrange_windows(output->swayc);
+ arrange_output(output);
transaction_commit_dirty();
}
+static void update_textures(struct sway_container *con, void *data) {
+ container_update_title_textures(con);
+ if (con->view) {
+ view_update_marks_textures(con->view);
+ }
+}
+
static void handle_scale(struct wl_listener *listener, void *data) {
struct sway_output *output = wl_container_of(listener, output, scale);
arrange_layers(output);
- container_update_textures_recursive(output->swayc);
- arrange_windows(output->swayc);
+ output_for_each_container(output, update_textures, NULL);
+ arrange_output(output);
transaction_commit_dirty();
}
@@ -545,57 +537,27 @@ void handle_new_output(struct wl_listener *listener, void *data) {
struct wlr_output *wlr_output = data;
wlr_log(WLR_DEBUG, "New output %p: %s", wlr_output, wlr_output->name);
- struct sway_output *output = calloc(1, sizeof(struct sway_output));
+ struct sway_output *output = output_create(wlr_output);
if (!output) {
return;
}
- output->wlr_output = wlr_output;
- wlr_output->data = output;
output->server = server;
output->damage = wlr_output_damage_create(wlr_output);
-
- wl_signal_add(&wlr_output->events.destroy, &output->destroy);
output->destroy.notify = handle_destroy;
- wl_list_insert(&root_container.sway_root->all_outputs, &output->link);
-
- output_enable(output);
-}
-
-void output_enable(struct sway_output *output) {
- struct wlr_output *wlr_output = output->wlr_output;
-
- if (!sway_assert(output->swayc == NULL, "output is already enabled")) {
- return;
- }
-
- output->swayc = output_create(output);
- if (!output->swayc) {
- // Output is disabled
- return;
- }
+ struct output_config *oc = output_find_config(output);
- size_t len = sizeof(output->layers) / sizeof(output->layers[0]);
- for (size_t i = 0; i < len; ++i) {
- wl_list_init(&output->layers[i]);
+ if (!oc || oc->enabled) {
+ output_enable(output, oc);
}
- wl_signal_init(&output->events.destroy);
- input_manager_configure_xcursor(input_manager);
+ transaction_commit_dirty();
+}
- wl_signal_add(&wlr_output->events.mode, &output->mode);
+void output_add_listeners(struct sway_output *output) {
output->mode.notify = handle_mode;
- wl_signal_add(&wlr_output->events.transform, &output->transform);
output->transform.notify = handle_transform;
- wl_signal_add(&wlr_output->events.scale, &output->scale);
output->scale.notify = handle_scale;
-
- wl_signal_add(&output->damage->events.frame, &output->damage_frame);
output->damage_frame.notify = damage_handle_frame;
- wl_signal_add(&output->damage->events.destroy, &output->damage_destroy);
output->damage_destroy.notify = damage_handle_destroy;
-
- arrange_layers(output);
- arrange_windows(&root_container);
- transaction_commit_dirty();
}
diff --git a/sway/desktop/render.c b/sway/desktop/render.c
index 695213eb..9d80f3c7 100644
--- a/sway/desktop/render.c
+++ b/sway/desktop/render.c
@@ -193,10 +193,10 @@ static void render_view_toplevels(struct sway_view *view,
.alpha = alpha,
};
// Render all toplevels without descending into popups
- double ox =
- view->swayc->current.view_x - output->wlr_output->lx - view->geometry.x;
- double oy =
- view->swayc->current.view_y - output->wlr_output->ly - view->geometry.y;
+ double ox = view->container->current.view_x -
+ output->wlr_output->lx - view->geometry.x;
+ double oy = view->container->current.view_y -
+ output->wlr_output->ly - view->geometry.y;
output_surface_for_each_surface(output, view->surface, ox, oy,
render_surface_iterator, &data);
}
@@ -229,17 +229,17 @@ static void render_saved_view(struct sway_view *view,
return;
}
struct wlr_box box = {
- .x = view->swayc->current.view_x - output->swayc->current.swayc_x -
+ .x = view->container->current.view_x - output->wlr_output->lx -
view->saved_geometry.x,
- .y = view->swayc->current.view_y - output->swayc->current.swayc_y -
+ .y = view->container->current.view_y - output->wlr_output->ly -
view->saved_geometry.y,
.width = view->saved_buffer_width,
.height = view->saved_buffer_height,
};
struct wlr_box output_box = {
- .width = output->swayc->current.swayc_width,
- .height = output->swayc->current.swayc_height,
+ .width = output->width,
+ .height = output->height,
};
struct wlr_box intersection;
@@ -263,14 +263,14 @@ static void render_saved_view(struct sway_view *view,
*/
static void render_view(struct sway_output *output, pixman_region32_t *damage,
struct sway_container *con, struct border_colors *colors) {
- struct sway_view *view = con->sway_view;
+ struct sway_view *view = con->view;
if (view->saved_buffer) {
- render_saved_view(view, output, damage, view->swayc->alpha);
+ render_saved_view(view, output, damage, view->container->alpha);
} else {
- render_view_toplevels(view, output, damage, view->swayc->alpha);
+ render_view_toplevels(view, output, damage, view->container->alpha);
}
- if (view->swayc->current.using_csd) {
+ if (view->container->current.using_csd) {
return;
}
@@ -283,7 +283,7 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage,
if (state->border_left) {
memcpy(&color, colors->child_border, sizeof(float) * 4);
premultiply_alpha(color, con->alpha);
- box.x = state->swayc_x;
+ box.x = state->con_x;
box.y = state->view_y;
box.width = state->border_thickness;
box.height = state->view_height;
@@ -291,9 +291,12 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage,
render_rect(output->wlr_output, damage, &box, color);
}
+ list_t *siblings = container_get_current_siblings(con);
+ enum sway_container_layout layout =
+ container_current_parent_layout(con);
+
if (state->border_right) {
- if (state->parent->current.children->length == 1
- && state->parent->current.layout == L_HORIZ) {
+ if (siblings->length == 1 && layout == L_HORIZ) {
memcpy(&color, colors->indicator, sizeof(float) * 4);
} else {
memcpy(&color, colors->child_border, sizeof(float) * 4);
@@ -308,16 +311,15 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage,
}
if (state->border_bottom) {
- if (state->parent->current.children->length == 1
- && con->current.parent->current.layout == L_VERT) {
+ if (siblings->length == 1 && layout == L_VERT) {
memcpy(&color, colors->indicator, sizeof(float) * 4);
} else {
memcpy(&color, colors->child_border, sizeof(float) * 4);
}
premultiply_alpha(color, con->alpha);
- box.x = state->swayc_x;
+ box.x = state->con_x;
box.y = state->view_y + state->view_height;
- box.width = state->swayc_width;
+ box.width = state->con_width;
box.height = state->border_thickness;
scale_box(&box, output_scale);
render_rect(output->wlr_output, damage, &box, color);
@@ -344,12 +346,12 @@ static void render_titlebar(struct sway_output *output,
float color[4];
struct sway_container_state *state = &con->current;
float output_scale = output->wlr_output->scale;
- enum sway_container_layout layout = state->parent->current.layout;
- list_t *children = state->parent->current.children;
+ enum sway_container_layout layout = container_current_parent_layout(con);
+ list_t *children = container_get_current_siblings(con);
bool is_last_child = children->length == 0 ||
children->items[children->length - 1] == con;
- double output_x = output->swayc->current.swayc_x;
- double output_y = output->swayc->current.swayc_y;
+ double output_x = output->wlr_output->lx;
+ double output_y = output->wlr_output->ly;
// Single pixel bar above title
memcpy(&color, colors->border, sizeof(float) * 4);
@@ -366,7 +368,7 @@ static void render_titlebar(struct sway_output *output,
bool connects_sides = false;
if (layout == L_HORIZ || layout == L_VERT ||
(layout == L_STACKED && is_last_child)) {
- if (con->type == C_VIEW) {
+ if (con->view) {
left_offset = state->border_left * state->border_thickness;
right_offset = state->border_right * state->border_thickness;
connects_sides = true;
@@ -542,14 +544,22 @@ static void render_top_border(struct sway_output *output,
// Child border - top edge
memcpy(&color, colors->child_border, sizeof(float) * 4);
premultiply_alpha(color, con->alpha);
- box.x = state->swayc_x;
- box.y = state->swayc_y;
- box.width = state->swayc_width;
+ box.x = state->con_x;
+ box.y = state->con_y;
+ box.width = state->con_width;
box.height = state->border_thickness;
scale_box(&box, output_scale);
render_rect(output->wlr_output, output_damage, &box, color);
}
+struct parent_data {
+ enum sway_container_layout layout;
+ struct wlr_box box;
+ list_t *children;
+ bool focused;
+ struct sway_container *active_child;
+};
+
static void render_container(struct sway_output *output,
pixman_region32_t *damage, struct sway_container *con, bool parent_focused);
@@ -559,14 +569,13 @@ static void render_container(struct sway_output *output,
* Wrap child views in borders and leave child containers borderless because
* they'll apply their own borders to their children.
*/
-static void render_container_simple(struct sway_output *output,
- pixman_region32_t *damage, struct sway_container *con,
- bool parent_focused) {
- for (int i = 0; i < con->current.children->length; ++i) {
- struct sway_container *child = con->current.children->items[i];
-
- if (child->type == C_VIEW) {
- struct sway_view *view = child->sway_view;
+static void render_containers_linear(struct sway_output *output,
+ pixman_region32_t *damage, struct parent_data *parent) {
+ for (int i = 0; i < parent->children->length; ++i) {
+ struct sway_container *child = parent->children->items[i];
+
+ if (child->view) {
+ struct sway_view *view = child->view;
struct border_colors *colors;
struct wlr_texture *title_texture;
struct wlr_texture *marks_texture;
@@ -576,11 +585,11 @@ static void render_container_simple(struct sway_output *output,
colors = &config->border_colors.urgent;
title_texture = child->title_urgent;
marks_texture = view->marks_urgent;
- } else if (state->focused || parent_focused) {
+ } else if (state->focused || parent->focused) {
colors = &config->border_colors.focused;
title_texture = child->title_focused;
marks_texture = view->marks_focused;
- } else if (con->current.focused_inactive_child == child) {
+ } else if (child == parent->active_child) {
colors = &config->border_colors.focused_inactive;
title_texture = child->title_focused_inactive;
marks_texture = view->marks_focused_inactive;
@@ -590,10 +599,10 @@ static void render_container_simple(struct sway_output *output,
marks_texture = view->marks_unfocused;
}
- if (!view->swayc->current.using_csd) {
+ if (!view->container->current.using_csd) {
if (state->border == B_NORMAL) {
- render_titlebar(output, damage, child, state->swayc_x,
- state->swayc_y, state->swayc_width, colors,
+ render_titlebar(output, damage, child, state->con_x,
+ state->con_y, state->con_width, colors,
title_texture, marks_texture);
} else {
render_top_border(output, damage, child, colors);
@@ -602,7 +611,7 @@ static void render_container_simple(struct sway_output *output,
render_view(output, damage, child, colors);
} else {
render_container(output, damage, child,
- parent_focused || child->current.focused);
+ parent->focused || child->current.focused);
}
}
}
@@ -610,22 +619,19 @@ static void render_container_simple(struct sway_output *output,
/**
* Render a container's children using the L_TABBED layout.
*/
-static void render_container_tabbed(struct sway_output *output,
- pixman_region32_t *damage, struct sway_container *con,
- bool parent_focused) {
- if (!con->current.children->length) {
+static void render_containers_tabbed(struct sway_output *output,
+ pixman_region32_t *damage, struct parent_data *parent) {
+ if (!parent->children->length) {
return;
}
- struct sway_container_state *pstate = &con->current;
- struct sway_container *current = pstate->focused_inactive_child;
+ struct sway_container *current = parent->active_child;
struct border_colors *current_colors = &config->border_colors.unfocused;
-
- int tab_width = (pstate->swayc_width) / pstate->children->length;
+ int tab_width = parent->box.width / parent->children->length;
// Render tabs
- for (int i = 0; i < pstate->children->length; ++i) {
- struct sway_container *child = pstate->children->items[i];
- struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL;
+ for (int i = 0; i < parent->children->length; ++i) {
+ struct sway_container *child = parent->children->items[i];
+ struct sway_view *view = child->view;
struct sway_container_state *cstate = &child->current;
struct border_colors *colors;
struct wlr_texture *title_texture;
@@ -637,11 +643,11 @@ static void render_container_tabbed(struct sway_output *output,
colors = &config->border_colors.urgent;
title_texture = child->title_urgent;
marks_texture = view ? view->marks_urgent : NULL;
- } else if (cstate->focused || parent_focused) {
+ } else if (cstate->focused || parent->focused) {
colors = &config->border_colors.focused;
title_texture = child->title_focused;
marks_texture = view ? view->marks_focused : NULL;
- } else if (child == pstate->focused_inactive_child) {
+ } else if (child == parent->active_child) {
colors = &config->border_colors.focused_inactive;
title_texture = child->title_focused_inactive;
marks_texture = view ? view->marks_focused_inactive : NULL;
@@ -651,14 +657,14 @@ static void render_container_tabbed(struct sway_output *output,
marks_texture = view ? view->marks_unfocused : NULL;
}
- int x = cstate->swayc_x + tab_width * i;
+ int x = cstate->con_x + tab_width * i;
// Make last tab use the remaining width of the parent
- if (i == pstate->children->length - 1) {
- tab_width = pstate->swayc_width - tab_width * i;
+ if (i == parent->children->length - 1) {
+ tab_width = parent->box.width - tab_width * i;
}
- render_titlebar(output, damage, child, x, pstate->swayc_y, tab_width,
+ render_titlebar(output, damage, child, x, parent->box.y, tab_width,
colors, title_texture, marks_texture);
if (child == current) {
@@ -667,33 +673,30 @@ static void render_container_tabbed(struct sway_output *output,
}
// Render surface and left/right/bottom borders
- if (current->type == C_VIEW) {
+ if (current->view) {
render_view(output, damage, current, current_colors);
} else {
render_container(output, damage, current,
- parent_focused || current->current.focused);
+ parent->focused || current->current.focused);
}
}
/**
* Render a container's children using the L_STACKED layout.
*/
-static void render_container_stacked(struct sway_output *output,
- pixman_region32_t *damage, struct sway_container *con,
- bool parent_focused) {
- if (!con->current.children->length) {
+static void render_containers_stacked(struct sway_output *output,
+ pixman_region32_t *damage, struct parent_data *parent) {
+ if (!parent->children->length) {
return;
}
- struct sway_container_state *pstate = &con->current;
- struct sway_container *current = pstate->focused_inactive_child;
+ struct sway_container *current = parent->active_child;
struct border_colors *current_colors = &config->border_colors.unfocused;
-
size_t titlebar_height = container_titlebar_height();
// Render titles
- for (int i = 0; i < pstate->children->length; ++i) {
- struct sway_container *child = pstate->children->items[i];
- struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL;
+ for (int i = 0; i < parent->children->length; ++i) {
+ struct sway_container *child = parent->children->items[i];
+ struct sway_view *view = child->view;
struct sway_container_state *cstate = &child->current;
struct border_colors *colors;
struct wlr_texture *title_texture;
@@ -705,11 +708,11 @@ static void render_container_stacked(struct sway_output *output,
colors = &config->border_colors.urgent;
title_texture = child->title_urgent;
marks_texture = view ? view->marks_urgent : NULL;
- } else if (cstate->focused || parent_focused) {
+ } else if (cstate->focused || parent->focused) {
colors = &config->border_colors.focused;
title_texture = child->title_focused;
marks_texture = view ? view->marks_focused : NULL;
- } else if (child == pstate->focused_inactive_child) {
+ } else if (child == parent->active_child) {
colors = &config->border_colors.focused_inactive;
title_texture = child->title_focused_inactive;
marks_texture = view ? view->marks_focused_inactive : NULL;
@@ -719,9 +722,9 @@ static void render_container_stacked(struct sway_output *output,
marks_texture = view ? view->marks_unfocused : NULL;
}
- int y = pstate->swayc_y + titlebar_height * i;
- render_titlebar(output, damage, child, pstate->swayc_x, y,
- pstate->swayc_width, colors, title_texture, marks_texture);
+ int y = parent->box.y + titlebar_height * i;
+ render_titlebar(output, damage, child, parent->box.x, y,
+ parent->box.width, colors, title_texture, marks_texture);
if (child == current) {
current_colors = colors;
@@ -729,36 +732,69 @@ static void render_container_stacked(struct sway_output *output,
}
// Render surface and left/right/bottom borders
- if (current->type == C_VIEW) {
+ if (current->view) {
render_view(output, damage, current, current_colors);
} else {
render_container(output, damage, current,
- parent_focused || current->current.focused);
+ parent->focused || current->current.focused);
}
}
-static void render_container(struct sway_output *output,
- pixman_region32_t *damage, struct sway_container *con,
- bool parent_focused) {
- switch (con->current.layout) {
+static void render_containers(struct sway_output *output,
+ pixman_region32_t *damage, struct parent_data *parent) {
+ switch (parent->layout) {
case L_NONE:
case L_HORIZ:
case L_VERT:
- render_container_simple(output, damage, con, parent_focused);
+ render_containers_linear(output, damage, parent);
break;
case L_STACKED:
- render_container_stacked(output, damage, con, parent_focused);
+ render_containers_stacked(output, damage, parent);
break;
case L_TABBED:
- render_container_tabbed(output, damage, con, parent_focused);
+ render_containers_tabbed(output, damage, parent);
break;
}
}
+static void render_container(struct sway_output *output,
+ pixman_region32_t *damage, struct sway_container *con, bool focused) {
+ struct parent_data data = {
+ .layout = con->current.layout,
+ .box = {
+ .x = con->current.con_x,
+ .y = con->current.con_y,
+ .width = con->current.con_width,
+ .height = con->current.con_height,
+ },
+ .children = con->current.children,
+ .focused = focused,
+ .active_child = con->current.focused_inactive_child,
+ };
+ render_containers(output, damage, &data);
+}
+
+static void render_workspace(struct sway_output *output,
+ pixman_region32_t *damage, struct sway_workspace *ws, bool focused) {
+ struct parent_data data = {
+ .layout = ws->current.layout,
+ .box = {
+ .x = ws->current.x,
+ .y = ws->current.y,
+ .width = ws->current.width,
+ .height = ws->current.height,
+ },
+ .children = ws->current.tiling,
+ .focused = focused,
+ .active_child = ws->current.focused_inactive_child,
+ };
+ render_containers(output, damage, &data);
+}
+
static void render_floating_container(struct sway_output *soutput,
pixman_region32_t *damage, struct sway_container *con) {
- if (con->type == C_VIEW) {
- struct sway_view *view = con->sway_view;
+ if (con->view) {
+ struct sway_view *view = con->view;
struct border_colors *colors;
struct wlr_texture *title_texture;
struct wlr_texture *marks_texture;
@@ -777,10 +813,10 @@ static void render_floating_container(struct sway_output *soutput,
marks_texture = view->marks_unfocused;
}
- if (!view->swayc->current.using_csd) {
+ if (!view->container->current.using_csd) {
if (con->current.border == B_NORMAL) {
- render_titlebar(soutput, damage, con, con->current.swayc_x,
- con->current.swayc_y, con->current.swayc_width, colors,
+ render_titlebar(soutput, damage, con, con->current.con_x,
+ con->current.con_y, con->current.con_width, colors,
title_texture, marks_texture);
} else if (con->current.border != B_NONE) {
render_top_border(soutput, damage, con, colors);
@@ -794,17 +830,15 @@ static void render_floating_container(struct sway_output *soutput,
static void render_floating(struct sway_output *soutput,
pixman_region32_t *damage) {
- for (int i = 0; i < root_container.current.children->length; ++i) {
- struct sway_container *output =
- root_container.current.children->items[i];
- for (int j = 0; j < output->current.children->length; ++j) {
- struct sway_container *ws = output->current.children->items[j];
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
+ for (int j = 0; j < output->current.workspaces->length; ++j) {
+ struct sway_workspace *ws = output->current.workspaces->items[j];
if (!workspace_is_visible(ws)) {
continue;
}
- list_t *floating = ws->current.ws_floating;
- for (int k = 0; k < floating->length; ++k) {
- struct sway_container *floater = floating->items[k];
+ for (int k = 0; k < ws->current.floating->length; ++k) {
+ struct sway_container *floater = ws->current.floating->items[k];
render_floating_container(soutput, damage, floater);
}
}
@@ -837,8 +871,8 @@ void output_render(struct sway_output *output, struct timespec *when,
pixman_region32_union_rect(damage, damage, 0, 0, width, height);
}
- struct sway_container *workspace = output_get_active_workspace(output);
- struct sway_container *fullscreen_con = workspace->current.ws_fullscreen;
+ struct sway_workspace *workspace = output_get_active_workspace(output);
+ struct sway_container *fullscreen_con = workspace->current.fullscreen;
if (output_has_opaque_overlay_layer_surface(output)) {
goto render_overlay;
@@ -855,12 +889,11 @@ void output_render(struct sway_output *output, struct timespec *when,
}
// TODO: handle views smaller than the output
- if (fullscreen_con->type == C_VIEW) {
- if (fullscreen_con->sway_view->saved_buffer) {
- render_saved_view(fullscreen_con->sway_view,
- output, damage, 1.0f);
+ if (fullscreen_con->view) {
+ if (fullscreen_con->view->saved_buffer) {
+ render_saved_view(fullscreen_con->view, output, damage, 1.0f);
} else {
- render_view_toplevels(fullscreen_con->sway_view,
+ render_view_toplevels(fullscreen_con->view,
output, damage, 1.0f);
}
} else {
@@ -868,8 +901,7 @@ void output_render(struct sway_output *output, struct timespec *when,
fullscreen_con->current.focused);
}
#ifdef HAVE_XWAYLAND
- render_unmanaged(output, damage,
- &root_container.sway_root->xwayland_unmanaged);
+ render_unmanaged(output, damage, &root->xwayland_unmanaged);
#endif
} else {
float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};
@@ -886,31 +918,30 @@ void output_render(struct sway_output *output, struct timespec *when,
render_layer(output, damage,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
- render_container(output, damage, workspace, workspace->current.focused);
+ render_workspace(output, damage, workspace, workspace->current.focused);
render_floating(output, damage);
#ifdef HAVE_XWAYLAND
- render_unmanaged(output, damage,
- &root_container.sway_root->xwayland_unmanaged);
+ render_unmanaged(output, damage, &root->xwayland_unmanaged);
#endif
render_layer(output, damage,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]);
}
struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus = seat_get_focus(seat);
- if (focus && focus->type == C_VIEW) {
- render_view_popups(focus->sway_view, output, damage, focus->alpha);
+ struct sway_container *focus = seat_get_focused_container(seat);
+ if (focus && focus->view) {
+ render_view_popups(focus->view, output, damage, focus->alpha);
}
render_overlay:
render_layer(output, damage,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]);
- render_drag_icons(output, damage, &root_container.sway_root->drag_icons);
+ render_drag_icons(output, damage, &root->drag_icons);
renderer_end:
if (debug.render_tree) {
wlr_renderer_scissor(renderer, NULL);
- wlr_render_texture(renderer, root_container.sway_root->debug_tree,
+ wlr_render_texture(renderer, root->debug_tree,
wlr_output->transform_matrix, 0, 40, 1);
}
if (debug.damage == DAMAGE_HIGHLIGHT) {
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c
index 145c5f92..b4eec933 100644
--- a/sway/desktop/transaction.c
+++ b/sway/desktop/transaction.c
@@ -12,6 +12,7 @@
#include "sway/desktop/transaction.h"
#include "sway/output.h"
#include "sway/tree/container.h"
+#include "sway/tree/node.h"
#include "sway/tree/view.h"
#include "sway/tree/workspace.h"
#include "list.h"
@@ -27,8 +28,12 @@ struct sway_transaction {
struct sway_transaction_instruction {
struct sway_transaction *transaction;
- struct sway_container *container;
- struct sway_container_state state;
+ struct sway_node *node;
+ union {
+ struct sway_output_state *output_state;
+ struct sway_workspace_state *workspace_state;
+ struct sway_container_state *container_state;
+ };
uint32_t serial;
};
@@ -47,26 +52,24 @@ static void transaction_destroy(struct sway_transaction *transaction) {
for (int i = 0; i < transaction->instructions->length; ++i) {
struct sway_transaction_instruction *instruction =
transaction->instructions->items[i];
- struct sway_container *con = instruction->container;
- con->ntxnrefs--;
- if (con->instruction == instruction) {
- con->instruction = NULL;
+ struct sway_node *node = instruction->node;
+ node->ntxnrefs--;
+ if (node->instruction == instruction) {
+ node->instruction = NULL;
}
- if (con->destroying && con->ntxnrefs == 0) {
- switch (con->type) {
- case C_ROOT:
+ if (node->destroying && node->ntxnrefs == 0) {
+ switch (node->type) {
+ case N_ROOT:
+ sway_assert(false, "Never reached");
break;
- case C_OUTPUT:
- output_destroy(con);
+ case N_OUTPUT:
+ output_destroy(node->sway_output);
break;
- case C_WORKSPACE:
- workspace_destroy(con);
+ case N_WORKSPACE:
+ workspace_destroy(node->sway_workspace);
break;
- case C_CONTAINER:
- case C_VIEW:
- container_destroy(con);
- break;
- case C_TYPES:
+ case N_CONTAINER:
+ container_destroy(node->sway_container);
break;
}
}
@@ -80,22 +83,79 @@ static void transaction_destroy(struct sway_transaction *transaction) {
free(transaction);
}
-static void copy_pending_state(struct sway_container *container,
- struct sway_container_state *state) {
+static void copy_output_state(struct sway_output *output,
+ struct sway_transaction_instruction *instruction) {
+ struct sway_output_state *state =
+ calloc(1, sizeof(struct sway_output_state));
+ if (!state) {
+ wlr_log(WLR_ERROR, "Could not allocate output state");
+ return;
+ }
+ instruction->output_state = state;
+
+ state->workspaces = create_list();
+ list_cat(state->workspaces, output->workspaces);
+
+ state->active_workspace = output_get_active_workspace(output);
+}
+
+static void copy_workspace_state(struct sway_workspace *ws,
+ struct sway_transaction_instruction *instruction) {
+ struct sway_workspace_state *state =
+ calloc(1, sizeof(struct sway_workspace_state));
+ if (!state) {
+ wlr_log(WLR_ERROR, "Could not allocate workspace state");
+ return;
+ }
+ instruction->workspace_state = state;
+
+ state->fullscreen = ws->fullscreen;
+ state->x = ws->x;
+ state->y = ws->y;
+ state->width = ws->width;
+ state->height = ws->height;
+ state->layout = ws->layout;
+
+ state->output = ws->output;
+ state->floating = create_list();
+ state->tiling = create_list();
+ list_cat(state->floating, ws->floating);
+ list_cat(state->tiling, ws->tiling);
+
+ struct sway_seat *seat = input_manager_current_seat(input_manager);
+ state->focused = seat_get_focus(seat) == &ws->node;
+
+ // Set focused_inactive_child to the direct tiling child
+ struct sway_container *focus = seat_get_focus_inactive_tiling(seat, ws);
+ if (focus) {
+ while (focus->parent) {
+ focus = focus->parent;
+ }
+ }
+ state->focused_inactive_child = focus;
+}
+
+static void copy_container_state(struct sway_container *container,
+ struct sway_transaction_instruction *instruction) {
+ struct sway_container_state *state =
+ calloc(1, sizeof(struct sway_container_state));
+ if (!state) {
+ wlr_log(WLR_ERROR, "Could not allocate container state");
+ return;
+ }
+ instruction->container_state = state;
+
state->layout = container->layout;
- state->swayc_x = container->x;
- state->swayc_y = container->y;
- state->swayc_width = container->width;
- state->swayc_height = container->height;
+ state->con_x = container->x;
+ state->con_y = container->y;
+ state->con_width = container->width;
+ state->con_height = container->height;
state->is_fullscreen = container->is_fullscreen;
- state->has_gaps = container->has_gaps;
- state->current_gaps = container->current_gaps;
- state->gaps_inner = container->gaps_inner;
- state->gaps_outer = container->gaps_outer;
state->parent = container->parent;
+ state->workspace = container->workspace;
- if (container->type == C_VIEW) {
- struct sway_view *view = container->sway_view;
+ if (container->view) {
+ struct sway_view *view = container->view;
state->view_x = view->x;
state->view_y = view->y;
state->view_width = view->width;
@@ -107,50 +167,111 @@ static void copy_pending_state(struct sway_container *container,
state->border_right = view->border_right;
state->border_bottom = view->border_bottom;
state->using_csd = view->using_csd;
- } else if (container->type == C_WORKSPACE) {
- state->ws_fullscreen = container->sway_workspace->fullscreen;
- state->ws_floating = create_list();
- state->children = create_list();
- list_cat(state->ws_floating, container->sway_workspace->floating);
- list_cat(state->children, container->children);
} else {
state->children = create_list();
list_cat(state->children, container->children);
}
struct sway_seat *seat = input_manager_current_seat(input_manager);
- state->focused = seat_get_focus(seat) == container;
-
- if (container->type == C_WORKSPACE) {
- // Set focused_inactive_child to the direct tiling child
- struct sway_container *focus =
- seat_get_focus_inactive_tiling(seat, container);
- if (focus && focus->type > C_WORKSPACE) {
- while (focus->parent->type != C_WORKSPACE) {
- focus = focus->parent;
- }
- }
- state->focused_inactive_child = focus;
- } else if (container->type != C_VIEW) {
- state->focused_inactive_child =
- seat_get_active_child(seat, container);
+ state->focused = seat_get_focus(seat) == &container->node;
+
+ if (!container->view) {
+ struct sway_node *focus = seat_get_active_child(seat, &container->node);
+ state->focused_inactive_child = focus ? focus->sway_container : NULL;
}
}
-static void transaction_add_container(struct sway_transaction *transaction,
- struct sway_container *container) {
+static void transaction_add_node(struct sway_transaction *transaction,
+ struct sway_node *node) {
struct sway_transaction_instruction *instruction =
calloc(1, sizeof(struct sway_transaction_instruction));
if (!sway_assert(instruction, "Unable to allocate instruction")) {
return;
}
instruction->transaction = transaction;
- instruction->container = container;
-
- copy_pending_state(container, &instruction->state);
+ instruction->node = node;
+
+ switch (node->type) {
+ case N_ROOT:
+ break;
+ case N_OUTPUT:
+ copy_output_state(node->sway_output, instruction);
+ break;
+ case N_WORKSPACE:
+ copy_workspace_state(node->sway_workspace, instruction);
+ break;
+ case N_CONTAINER:
+ copy_container_state(node->sway_container, instruction);
+ break;
+ }
list_add(transaction->instructions, instruction);
- container->ntxnrefs++;
+ node->ntxnrefs++;
+}
+
+static void apply_output_state(struct sway_output *output,
+ struct sway_output_state *state) {
+ output_damage_whole(output);
+ list_free(output->current.workspaces);
+ memcpy(&output->current, state, sizeof(struct sway_output_state));
+ output_damage_whole(output);
+}
+
+static void apply_workspace_state(struct sway_workspace *ws,
+ struct sway_workspace_state *state) {
+ output_damage_whole(ws->current.output);
+ list_free(ws->current.floating);
+ list_free(ws->current.tiling);
+ memcpy(&ws->current, state, sizeof(struct sway_workspace_state));
+ output_damage_whole(ws->current.output);
+}
+
+static void apply_container_state(struct sway_container *container,
+ struct sway_container_state *state) {
+ struct sway_view *view = container->view;
+ // Damage the old location
+ desktop_damage_whole_container(container);
+ if (view && view->saved_buffer) {
+ struct wlr_box box = {
+ .x = container->current.view_x - view->saved_geometry.x,
+ .y = container->current.view_y - view->saved_geometry.y,
+ .width = view->saved_buffer_width,
+ .height = view->saved_buffer_height,
+ };
+ desktop_damage_box(&box);
+ }
+
+ // There are separate children lists for each instruction state, the
+ // container's current state and the container's pending state
+ // (ie. con->children). The list itself needs to be freed here.
+ // Any child containers which are being deleted will be cleaned up in
+ // transaction_destroy().
+ list_free(container->current.children);
+
+ memcpy(&container->current, state, sizeof(struct sway_container_state));
+
+ if (view && view->saved_buffer) {
+ if (!container->node.destroying || container->node.ntxnrefs == 1) {
+ view_remove_saved_buffer(view);
+ }
+ }
+
+ // Damage the new location
+ desktop_damage_whole_container(container);
+ if (view && view->surface) {
+ struct wlr_surface *surface = view->surface;
+ struct wlr_box box = {
+ .x = container->current.view_x - view->geometry.x,
+ .y = container->current.view_y - view->geometry.y,
+ .width = surface->current.width,
+ .height = surface->current.height,
+ };
+ desktop_damage_box(&box);
+ }
+
+ if (!container->node.destroying) {
+ container_discover_outputs(container);
+ }
}
/**
@@ -168,67 +289,36 @@ static void transaction_apply(struct sway_transaction *transaction) {
"(%.1f frames if 60Hz)", transaction, ms, ms / (1000.0f / 60));
}
- // Apply the instruction state to the container's current state
+ // Apply the instruction state to the node's current state
for (int i = 0; i < transaction->instructions->length; ++i) {
struct sway_transaction_instruction *instruction =
transaction->instructions->items[i];
- struct sway_container *container = instruction->container;
-
- // Damage the old location
- desktop_damage_whole_container(container);
- if (container->type == C_VIEW && container->sway_view->saved_buffer) {
- struct sway_view *view = container->sway_view;
- struct wlr_box box = {
- .x = container->current.view_x - view->saved_geometry.x,
- .y = container->current.view_y - view->saved_geometry.y,
- .width = view->saved_buffer_width,
- .height = view->saved_buffer_height,
- };
- desktop_damage_box(&box);
- }
-
- // There are separate children lists for each instruction state, the
- // container's current state and the container's pending state
- // (ie. con->children). The list itself needs to be freed here.
- // Any child containers which are being deleted will be cleaned up in
- // transaction_destroy().
- list_free(container->current.children);
- list_free(container->current.ws_floating);
-
- memcpy(&container->current, &instruction->state,
- sizeof(struct sway_container_state));
-
- if (container->type == C_VIEW && container->sway_view->saved_buffer) {
- if (!container->destroying || container->ntxnrefs == 1) {
- view_remove_saved_buffer(container->sway_view);
- }
- }
+ struct sway_node *node = instruction->node;
- // Damage the new location
- desktop_damage_whole_container(container);
- if (container->type == C_VIEW && container->sway_view->surface) {
- struct sway_view *view = container->sway_view;
- struct wlr_surface *surface = view->surface;
- struct wlr_box box = {
- .x = container->current.view_x - view->geometry.x,
- .y = container->current.view_y - view->geometry.y,
- .width = surface->current.width,
- .height = surface->current.height,
- };
- desktop_damage_box(&box);
+ switch (node->type) {
+ case N_ROOT:
+ break;
+ case N_OUTPUT:
+ apply_output_state(node->sway_output, instruction->output_state);
+ break;
+ case N_WORKSPACE:
+ apply_workspace_state(node->sway_workspace,
+ instruction->workspace_state);
+ break;
+ case N_CONTAINER:
+ apply_container_state(node->sway_container,
+ instruction->container_state);
+ break;
}
- container->instruction = NULL;
- if (container->type == C_CONTAINER || container->type == C_VIEW) {
- container_discover_outputs(container);
- }
+ node->instruction = NULL;
}
}
static void transaction_commit(struct sway_transaction *transaction);
-// Return true if both transactions operate on the same containers
-static bool transaction_same_containers(struct sway_transaction *a,
+// Return true if both transactions operate on the same nodes
+static bool transaction_same_nodes(struct sway_transaction *a,
struct sway_transaction *b) {
if (a->instructions->length != b->instructions->length) {
return false;
@@ -236,7 +326,7 @@ static bool transaction_same_containers(struct sway_transaction *a,
for (int i = 0; i < a->instructions->length; ++i) {
struct sway_transaction_instruction *a_inst = a->instructions->items[i];
struct sway_transaction_instruction *b_inst = b->instructions->items[i];
- if (a_inst->container != b_inst->container) {
+ if (a_inst->node != b_inst->node) {
return false;
}
}
@@ -267,7 +357,7 @@ static void transaction_progress_queue() {
while (server.transactions->length >= 2) {
struct sway_transaction *a = server.transactions->items[0];
struct sway_transaction *b = server.transactions->items[1];
- if (transaction_same_containers(a, b)) {
+ if (transaction_same_nodes(a, b)) {
list_del(server.transactions, 0);
transaction_destroy(a);
} else {
@@ -289,16 +379,18 @@ static int handle_timeout(void *data) {
return 0;
}
-static bool should_configure(struct sway_container *con,
+static bool should_configure(struct sway_node *node,
struct sway_transaction_instruction *instruction) {
- if (con->type != C_VIEW) {
+ if (!node_is_view(node)) {
return false;
}
- if (con->destroying) {
+ if (node->destroying) {
return false;
}
- if (con->current.view_width == instruction->state.view_width &&
- con->current.view_height == instruction->state.view_height) {
+ struct sway_container_state *cstate = &node->sway_container->current;
+ struct sway_container_state *istate = instruction->container_state;
+ if (cstate->view_width == istate->view_width &&
+ cstate->view_height == istate->view_height) {
return false;
}
return true;
@@ -311,13 +403,13 @@ static void transaction_commit(struct sway_transaction *transaction) {
for (int i = 0; i < transaction->instructions->length; ++i) {
struct sway_transaction_instruction *instruction =
transaction->instructions->items[i];
- struct sway_container *con = instruction->container;
- if (should_configure(con, instruction)) {
- instruction->serial = view_configure(con->sway_view,
- instruction->state.view_x,
- instruction->state.view_y,
- instruction->state.view_width,
- instruction->state.view_height);
+ struct sway_node *node = instruction->node;
+ if (should_configure(node, instruction)) {
+ instruction->serial = view_configure(node->sway_container->view,
+ instruction->container_state->view_x,
+ instruction->container_state->view_y,
+ instruction->container_state->view_width,
+ instruction->container_state->view_height);
++transaction->num_waiting;
// From here on we are rendering a saved buffer of the view, which
@@ -325,14 +417,16 @@ static void transaction_commit(struct sway_transaction *transaction) {
// as soon as possible. Additionally, this is required if a view is
// mapping and its default geometry doesn't intersect an output.
struct timespec when;
- wlr_surface_send_frame_done(con->sway_view->surface, &when);
+ wlr_surface_send_frame_done(
+ node->sway_container->view->surface, &when);
}
- if (con->type == C_VIEW && !con->sway_view->saved_buffer) {
- view_save_buffer(con->sway_view);
- memcpy(&con->sway_view->saved_geometry, &con->sway_view->geometry,
+ if (node_is_view(node) && !node->sway_container->view->saved_buffer) {
+ view_save_buffer(node->sway_container->view);
+ memcpy(&node->sway_container->view->saved_geometry,
+ &node->sway_container->view->geometry,
sizeof(struct wlr_box));
}
- con->instruction = instruction;
+ node->instruction = instruction;
}
transaction->num_configures = transaction->num_waiting;
if (debug.txn_timings) {
@@ -381,7 +475,7 @@ static void set_instruction_ready(
transaction,
transaction->num_configures - transaction->num_waiting + 1,
transaction->num_configures, ms,
- instruction->container->name);
+ instruction->node->sway_container->title);
}
// If the transaction has timed out then its num_waiting will be 0 already.
@@ -390,41 +484,43 @@ static void set_instruction_ready(
wl_event_source_timer_update(transaction->timer, 0);
}
- instruction->container->instruction = NULL;
+ instruction->node->instruction = NULL;
transaction_progress_queue();
}
void transaction_notify_view_ready_by_serial(struct sway_view *view,
uint32_t serial) {
- struct sway_transaction_instruction *instruction = view->swayc->instruction;
- if (view->swayc->instruction->serial == serial) {
+ struct sway_transaction_instruction *instruction =
+ view->container->node.instruction;
+ if (instruction->serial == serial) {
set_instruction_ready(instruction);
}
}
void transaction_notify_view_ready_by_size(struct sway_view *view,
int width, int height) {
- struct sway_transaction_instruction *instruction = view->swayc->instruction;
- if (instruction->state.view_width == width &&
- instruction->state.view_height == height) {
+ struct sway_transaction_instruction *instruction =
+ view->container->node.instruction;
+ if (instruction->container_state->view_width == width &&
+ instruction->container_state->view_height == height) {
set_instruction_ready(instruction);
}
}
void transaction_commit_dirty(void) {
- if (!server.dirty_containers->length) {
+ if (!server.dirty_nodes->length) {
return;
}
struct sway_transaction *transaction = transaction_create();
if (!transaction) {
return;
}
- for (int i = 0; i < server.dirty_containers->length; ++i) {
- struct sway_container *container = server.dirty_containers->items[i];
- transaction_add_container(transaction, container);
- container->dirty = false;
+ for (int i = 0; i < server.dirty_nodes->length; ++i) {
+ struct sway_node *node = server.dirty_nodes->items[i];
+ transaction_add_node(transaction, node);
+ node->dirty = false;
}
- server.dirty_containers->length = 0;
+ server.dirty_nodes->length = 0;
list_add(server.transactions, transaction);
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c
index 587deb0f..575f229d 100644
--- a/sway/desktop/xdg_shell.c
+++ b/sway/desktop/xdg_shell.c
@@ -11,10 +11,12 @@
#include "sway/desktop/transaction.h"
#include "sway/input/input-manager.h"
#include "sway/input/seat.h"
+#include "sway/output.h"
#include "sway/server.h"
#include "sway/tree/arrange.h"
#include "sway/tree/container.h"
#include "sway/tree/view.h"
+#include "sway/tree/workspace.h"
static const struct sway_view_child_impl popup_impl;
@@ -52,13 +54,13 @@ static void popup_unconstrain(struct sway_xdg_popup *popup) {
struct sway_view *view = popup->child.view;
struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_surface->popup;
- struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
+ struct sway_output *output = view->container->workspace->output;
// the output box expressed in the coordinate system of the toplevel parent
// of the popup
struct wlr_box output_toplevel_sx_box = {
- .x = output->x - view->x,
- .y = output->y - view->y,
+ .x = output->lx - view->x,
+ .y = output->ly - view->y,
.width = output->width,
.height = output->height,
};
@@ -252,11 +254,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
struct sway_view *view = &xdg_shell_view->view;
struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface;
- if (!view->swayc) {
- return;
- }
-
- if (view->swayc->instruction) {
+ if (view->container->node.instruction) {
wlr_xdg_surface_get_geometry(xdg_surface, &view->geometry);
transaction_notify_view_ready_by_serial(view,
xdg_surface->configure_serial);
@@ -265,7 +263,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
wlr_xdg_surface_get_geometry(xdg_surface, &new_geo);
if ((new_geo.width != view->width || new_geo.height != view->height) &&
- container_is_floating(view->swayc)) {
+ container_is_floating(view->container)) {
// A floating view has unexpectedly sent a new size
desktop_damage_view(view);
view_update_size(view, new_geo.width, new_geo.height);
@@ -319,10 +317,9 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
return;
}
- container_set_fullscreen(view->swayc, e->fullscreen);
+ container_set_fullscreen(view->container, e->fullscreen);
- struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
- arrange_windows(output);
+ arrange_workspace(view->container->workspace);
transaction_commit_dirty();
}
@@ -330,13 +327,13 @@ static void handle_request_move(struct wl_listener *listener, void *data) {
struct sway_xdg_shell_view *xdg_shell_view =
wl_container_of(listener, xdg_shell_view, request_move);
struct sway_view *view = &xdg_shell_view->view;
- if (!container_is_floating(view->swayc)) {
+ if (!container_is_floating(view->container)) {
return;
}
struct wlr_xdg_toplevel_move_event *e = data;
struct sway_seat *seat = e->seat->seat->data;
if (e->serial == seat->last_button_serial) {
- seat_begin_move(seat, view->swayc, seat->last_button);
+ seat_begin_move(seat, view->container, seat->last_button);
}
}
@@ -344,13 +341,13 @@ static void handle_request_resize(struct wl_listener *listener, void *data) {
struct sway_xdg_shell_view *xdg_shell_view =
wl_container_of(listener, xdg_shell_view, request_resize);
struct sway_view *view = &xdg_shell_view->view;
- if (!container_is_floating(view->swayc)) {
+ if (!container_is_floating(view->container)) {
return;
}
struct wlr_xdg_toplevel_resize_event *e = data;
struct sway_seat *seat = e->seat->seat->data;
if (e->serial == seat->last_button_serial) {
- seat_begin_resize_floating(seat, view->swayc,
+ seat_begin_resize_floating(seat, view->container,
seat->last_button, e->edges);
}
}
@@ -399,11 +396,14 @@ static void handle_map(struct wl_listener *listener, void *data) {
view_map(view, view->wlr_xdg_surface->surface);
if (xdg_surface->toplevel->client_pending.fullscreen) {
- container_set_fullscreen(view->swayc, true);
- struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
- arrange_windows(ws);
+ container_set_fullscreen(view->container, true);
+ arrange_workspace(view->container->workspace);
} else {
- arrange_windows(view->swayc->parent);
+ if (view->container->parent) {
+ arrange_container(view->container->parent);
+ } else {
+ arrange_workspace(view->container->workspace);
+ }
}
transaction_commit_dirty();
@@ -440,8 +440,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
struct sway_xdg_shell_view *xdg_shell_view =
wl_container_of(listener, xdg_shell_view, destroy);
struct sway_view *view = &xdg_shell_view->view;
- if (!sway_assert(view->swayc == NULL || view->swayc->destroying,
- "Tried to destroy a mapped view")) {
+ if (!sway_assert(view->surface == NULL, "Tried to destroy a mapped view")) {
return;
}
wl_list_remove(&xdg_shell_view->destroy.link);
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index 175416f3..58fbd631 100644
--- a/sway/desktop/xdg_shell_v6.c
+++ b/sway/desktop/xdg_shell_v6.c
@@ -10,10 +10,12 @@
#include "sway/desktop/transaction.h"
#include "sway/input/input-manager.h"
#include "sway/input/seat.h"
+#include "sway/output.h"
#include "sway/server.h"
#include "sway/tree/arrange.h"
#include "sway/tree/container.h"
#include "sway/tree/view.h"
+#include "sway/tree/workspace.h"
static const struct sway_view_child_impl popup_impl;
@@ -51,13 +53,13 @@ static void popup_unconstrain(struct sway_xdg_popup_v6 *popup) {
struct sway_view *view = popup->child.view;
struct wlr_xdg_popup_v6 *wlr_popup = popup->wlr_xdg_surface_v6->popup;
- struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
+ struct sway_output *output = view->container->workspace->output;
// the output box expressed in the coordinate system of the toplevel parent
// of the popup
struct wlr_box output_toplevel_sx_box = {
- .x = output->x - view->x,
- .y = output->y - view->y,
+ .x = output->lx - view->x,
+ .y = output->ly - view->y,
.width = output->width,
.height = output->height,
};
@@ -249,11 +251,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
struct sway_view *view = &xdg_shell_v6_view->view;
struct wlr_xdg_surface_v6 *xdg_surface_v6 = view->wlr_xdg_surface_v6;
- if (!view->swayc) {
- return;
- }
-
- if (view->swayc->instruction) {
+ if (view->container->node.instruction) {
wlr_xdg_surface_v6_get_geometry(xdg_surface_v6, &view->geometry);
transaction_notify_view_ready_by_serial(view,
xdg_surface_v6->configure_serial);
@@ -262,7 +260,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
wlr_xdg_surface_v6_get_geometry(xdg_surface_v6, &new_geo);
if ((new_geo.width != view->width || new_geo.height != view->height) &&
- container_is_floating(view->swayc)) {
+ container_is_floating(view->container)) {
// A floating view has unexpectedly sent a new size
desktop_damage_view(view);
view_update_size(view, new_geo.width, new_geo.height);
@@ -316,10 +314,9 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
return;
}
- container_set_fullscreen(view->swayc, e->fullscreen);
+ container_set_fullscreen(view->container, e->fullscreen);
- struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
- arrange_windows(output);
+ arrange_workspace(view->container->workspace);
transaction_commit_dirty();
}
@@ -327,13 +324,13 @@ static void handle_request_move(struct wl_listener *listener, void *data) {
struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
wl_container_of(listener, xdg_shell_v6_view, request_move);
struct sway_view *view = &xdg_shell_v6_view->view;
- if (!container_is_floating(view->swayc)) {
+ if (!container_is_floating(view->container)) {
return;
}
struct wlr_xdg_toplevel_v6_move_event *e = data;
struct sway_seat *seat = e->seat->seat->data;
if (e->serial == seat->last_button_serial) {
- seat_begin_move(seat, view->swayc, seat->last_button);
+ seat_begin_move(seat, view->container, seat->last_button);
}
}
@@ -341,13 +338,13 @@ static void handle_request_resize(struct wl_listener *listener, void *data) {
struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
wl_container_of(listener, xdg_shell_v6_view, request_resize);
struct sway_view *view = &xdg_shell_v6_view->view;
- if (!container_is_floating(view->swayc)) {
+ if (!container_is_floating(view->container)) {
return;
}
struct wlr_xdg_toplevel_v6_resize_event *e = data;
struct sway_seat *seat = e->seat->seat->data;
if (e->serial == seat->last_button_serial) {
- seat_begin_resize_floating(seat, view->swayc,
+ seat_begin_resize_floating(seat, view->container,
seat->last_button, e->edges);
}
}
@@ -396,11 +393,14 @@ static void handle_map(struct wl_listener *listener, void *data) {
view_map(view, view->wlr_xdg_surface_v6->surface);
if (xdg_surface->toplevel->client_pending.fullscreen) {
- container_set_fullscreen(view->swayc, true);
- struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
- arrange_windows(ws);
+ container_set_fullscreen(view->container, true);
+ arrange_workspace(view->container->workspace);
} else {
- arrange_windows(view->swayc->parent);
+ if (view->container->parent) {
+ arrange_container(view->container->parent);
+ } else {
+ arrange_workspace(view->container->workspace);
+ }
}
transaction_commit_dirty();
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 94a30239..0d192b76 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -59,8 +59,7 @@ static void unmanaged_handle_map(struct wl_listener *listener, void *data) {
wl_container_of(listener, surface, map);
struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
- wl_list_insert(root_container.sway_root->xwayland_unmanaged.prev,
- &surface->link);
+ wl_list_insert(root->xwayland_unmanaged.prev, &surface->link);
wl_signal_add(&xsurface->surface->events.commit, &surface->commit);
surface->commit.notify = unmanaged_handle_commit;
@@ -90,11 +89,10 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) {
if (seat->wlr_seat->keyboard_state.focused_surface ==
xsurface->surface) {
// Restore focus
- struct sway_container *previous =
- seat_get_focus_inactive(seat, &root_container);
+ struct sway_node *previous = seat_get_focus_inactive(seat, &root->node);
if (previous) {
// Hack to get seat to re-focus the return value of get_focus
- seat_set_focus(seat, previous->parent);
+ seat_set_focus(seat, NULL);
seat_set_focus(seat, previous);
}
}
@@ -299,7 +297,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
struct wlr_surface_state *state = &xsurface->surface->current;
- if (view->swayc->instruction) {
+ if (view->container->node.instruction) {
get_geometry(view, &view->geometry);
transaction_notify_view_ready_by_size(view,
state->width, state->height);
@@ -308,7 +306,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
get_geometry(view, &new_geo);
if ((new_geo.width != view->width || new_geo.height != view->height) &&
- container_is_floating(view->swayc)) {
+ container_is_floating(view->container)) {
// A floating view has unexpectedly sent a new size
// eg. The Firefox "Save As" dialog when downloading a file
desktop_damage_view(view);
@@ -391,11 +389,14 @@ static void handle_map(struct wl_listener *listener, void *data) {
view_map(view, xsurface->surface);
if (xsurface->fullscreen) {
- container_set_fullscreen(view->swayc, true);
- struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
- arrange_windows(ws);
+ container_set_fullscreen(view->container, true);
+ arrange_workspace(view->container->workspace);
} else {
- arrange_windows(view->swayc->parent);
+ if (view->container->parent) {
+ arrange_container(view->container->parent);
+ } else {
+ arrange_workspace(view->container->workspace);
+ }
}
transaction_commit_dirty();
}
@@ -411,13 +412,14 @@ static void handle_request_configure(struct wl_listener *listener, void *data) {
ev->width, ev->height);
return;
}
- if (container_is_floating(view->swayc)) {
- configure(view, view->swayc->current.view_x,
- view->swayc->current.view_y, ev->width, ev->height);
+ if (container_is_floating(view->container)) {
+ configure(view, view->container->current.view_x,
+ view->container->current.view_y, ev->width, ev->height);
} else {
- configure(view, view->swayc->current.view_x,
- view->swayc->current.view_y, view->swayc->current.view_width,
- view->swayc->current.view_height);
+ configure(view, view->container->current.view_x,
+ view->container->current.view_y,
+ view->container->current.view_width,
+ view->container->current.view_height);
}
}
@@ -429,10 +431,9 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
if (!xsurface->mapped) {
return;
}
- container_set_fullscreen(view->swayc, xsurface->fullscreen);
+ container_set_fullscreen(view->container, xsurface->fullscreen);
- struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
- arrange_windows(output);
+ arrange_workspace(view->container->workspace);
transaction_commit_dirty();
}
@@ -444,11 +445,11 @@ static void handle_request_move(struct wl_listener *listener, void *data) {
if (!xsurface->mapped) {
return;
}
- if (!container_is_floating(view->swayc)) {
+ if (!container_is_floating(view->container)) {
return;
}
struct sway_seat *seat = input_manager_current_seat(input_manager);
- seat_begin_move(seat, view->swayc, seat->last_button);
+ seat_begin_move(seat, view->container, seat->last_button);
}
static void handle_request_resize(struct wl_listener *listener, void *data) {
@@ -459,12 +460,13 @@ static void handle_request_resize(struct wl_listener *listener, void *data) {
if (!xsurface->mapped) {
return;
}
- if (!container_is_floating(view->swayc)) {
+ if (!container_is_floating(view->container)) {
return;
}
struct wlr_xwayland_resize_event *e = data;
struct sway_seat *seat = input_manager_current_seat(input_manager);
- seat_begin_resize_floating(seat, view->swayc, seat->last_button, e->edges);
+ seat_begin_resize_floating(seat, view->container,
+ seat->last_button, e->edges);
}
static void handle_request_activate(struct wl_listener *listener, void *data) {
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index 00240e84..19dc3165 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -20,6 +20,7 @@
#include "sway/layers.h"
#include "sway/output.h"
#include "sway/tree/arrange.h"
+#include "sway/tree/container.h"
#include "sway/tree/root.h"
#include "sway/tree/view.h"
#include "sway/tree/workspace.h"
@@ -50,15 +51,15 @@ static struct wlr_surface *layer_surface_at(struct sway_output *output,
}
/**
- * Returns the container at the cursor's position. If there is a surface at that
+ * Returns the node at the cursor's position. If there is a surface at that
* location, it is stored in **surface (it may not be a view).
*/
-static struct sway_container *container_at_coords(
+static struct sway_node *node_at_coords(
struct sway_seat *seat, double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy) {
// check for unmanaged views first
#ifdef HAVE_XWAYLAND
- struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged;
+ struct wl_list *unmanaged = &root->xwayland_unmanaged;
struct sway_xwayland_unmanaged *unmanaged_surface;
wl_list_for_each_reverse(unmanaged_surface, unmanaged, link) {
struct wlr_xwayland_surface *xsurface =
@@ -75,67 +76,54 @@ static struct sway_container *container_at_coords(
}
#endif
// find the output the cursor is on
- struct wlr_output_layout *output_layout =
- root_container.sway_root->output_layout;
struct wlr_output *wlr_output = wlr_output_layout_output_at(
- output_layout, lx, ly);
+ root->output_layout, lx, ly);
if (wlr_output == NULL) {
return NULL;
}
struct sway_output *output = wlr_output->data;
double ox = lx, oy = ly;
- wlr_output_layout_output_coords(output_layout, wlr_output, &ox, &oy);
+ wlr_output_layout_output_coords(root->output_layout, wlr_output, &ox, &oy);
// find the focused workspace on the output for this seat
- struct sway_container *ws = seat_get_focus_inactive(seat, output->swayc);
- if (ws && ws->type != C_WORKSPACE) {
- ws = container_parent(ws, C_WORKSPACE);
- }
- if (!ws) {
- return output->swayc;
- }
+ struct sway_workspace *ws = output_get_active_workspace(output);
if ((*surface = layer_surface_at(output,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
ox, oy, sx, sy))) {
- return ws;
+ return NULL;
}
- if (ws->sway_workspace->fullscreen) {
- return tiling_container_at(ws->sway_workspace->fullscreen, lx, ly,
- surface, sx, sy);
+ if (ws->fullscreen) {
+ struct sway_container *con =
+ tiling_container_at(&ws->fullscreen->node, lx, ly, surface, sx, sy);
+ if (con) {
+ return &con->node;
+ }
+ return NULL;
}
if ((*surface = layer_surface_at(output,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
ox, oy, sx, sy))) {
- return ws;
+ return NULL;
}
struct sway_container *c;
if ((c = container_at(ws, lx, ly, surface, sx, sy))) {
- return c;
+ return &c->node;
}
if ((*surface = layer_surface_at(output,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
ox, oy, sx, sy))) {
- return ws;
+ return NULL;
}
if ((*surface = layer_surface_at(output,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
ox, oy, sx, sy))) {
- return ws;
- }
-
- c = seat_get_active_child(seat, output->swayc);
- if (c) {
- return c;
- }
- if (!c && output->swayc->children->length) {
- c = output->swayc->children->items[0];
- return c;
+ return NULL;
}
- return output->swayc;
+ return &ws->node;
}
/**
@@ -160,13 +148,14 @@ static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) {
// Iterate the parents until we find one with the layout we want,
// then check if the child has siblings between it and the edge.
- while (cont->type != C_OUTPUT) {
- if (cont->parent->layout == layout) {
- int index = list_find(cont->parent->children, cont);
+ while (cont) {
+ if (container_parent_layout(cont) == layout) {
+ list_t *siblings = container_get_siblings(cont);
+ int index = list_find(siblings, cont);
if (index > 0 && (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_TOP)) {
return false;
}
- if (index < cont->parent->children->length - 1 &&
+ if (index < siblings->length - 1 &&
(edge == WLR_EDGE_RIGHT || edge == WLR_EDGE_BOTTOM)) {
return false;
}
@@ -178,10 +167,10 @@ static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) {
static enum wlr_edges find_edge(struct sway_container *cont,
struct sway_cursor *cursor) {
- if (cont->type != C_VIEW) {
+ if (!cont->view) {
return WLR_EDGE_NONE;
}
- struct sway_view *view = cont->sway_view;
+ struct sway_view *view = cont->view;
if (view->border == B_NONE || !view->border_thickness || view->using_csd) {
return WLR_EDGE_NONE;
}
@@ -219,7 +208,7 @@ static enum wlr_edges find_resize_edge(struct sway_container *cont,
static void handle_down_motion(struct sway_seat *seat,
struct sway_cursor *cursor, uint32_t time_msec) {
struct sway_container *con = seat->op_container;
- if (seat_is_input_allowed(seat, con->sway_view->surface)) {
+ if (seat_is_input_allowed(seat, con->view->surface)) {
double moved_x = cursor->cursor->x - seat->op_ref_lx;
double moved_y = cursor->cursor->y - seat->op_ref_ly;
double sx = seat->op_ref_con_lx + moved_x;
@@ -260,8 +249,7 @@ static void calculate_floating_constraints(struct sway_container *con,
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;
}
@@ -269,8 +257,7 @@ static void calculate_floating_constraints(struct sway_container *con,
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;
}
@@ -314,9 +301,9 @@ static void handle_resize_floating_motion(struct sway_seat *seat,
height = fmax(min_height, fmin(height, max_height));
// Apply the view's min/max size
- if (con->type == C_VIEW) {
+ if (con->view) {
double view_min_width, view_max_width, view_min_height, view_max_height;
- view_get_constraints(con->sway_view, &view_min_width, &view_max_width,
+ view_get_constraints(con->view, &view_min_width, &view_max_width,
&view_min_height, &view_max_height);
width = fmax(view_min_width, fmin(width, view_max_width));
height = fmax(view_min_height, fmin(height, view_max_height));
@@ -357,15 +344,15 @@ static void handle_resize_floating_motion(struct sway_seat *seat,
con->width += relative_grow_width;
con->height += relative_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 += relative_grow_x;
view->y += relative_grow_y;
view->width += relative_grow_width;
view->height += relative_grow_height;
}
- arrange_windows(con);
+ arrange_container(con);
}
static void handle_resize_tiling_motion(struct sway_seat *seat,
@@ -435,44 +422,40 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
struct wlr_surface *surface = NULL;
double sx, sy;
- // Find the container beneath the pointer's previous position
- struct sway_container *prev_c = container_at_coords(seat,
+ // Find the node beneath the pointer's previous position
+ struct sway_node *prev_node = node_at_coords(seat,
cursor->previous.x, cursor->previous.y, &surface, &sx, &sy);
// Update the stored previous position
cursor->previous.x = cursor->cursor->x;
cursor->previous.y = cursor->cursor->y;
- struct sway_container *c = container_at_coords(seat,
+ struct sway_node *node = node_at_coords(seat,
cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
- if (c && config->focus_follows_mouse && allow_refocusing) {
- struct sway_container *focus = seat_get_focus(seat);
- if (focus && c->type == C_WORKSPACE) {
+ if (node && config->focus_follows_mouse && allow_refocusing) {
+ struct sway_node *focus = seat_get_focus(seat);
+ if (focus && node->type == N_WORKSPACE) {
// Only follow the mouse if it would move to a new output
// Otherwise we'll focus the workspace, which is probably wrong
- if (focus->type != C_OUTPUT) {
- focus = container_parent(focus, C_OUTPUT);
- }
- struct sway_container *output = c;
- if (output->type != C_OUTPUT) {
- output = container_parent(c, C_OUTPUT);
+ struct sway_output *focused_output = node_get_output(focus);
+ struct sway_output *output = node_get_output(node);
+ if (output != focused_output) {
+ seat_set_focus_warp(seat, node, false, true);
}
- if (output != focus) {
- seat_set_focus_warp(seat, c, false, true);
- }
- } else if (c->type == C_VIEW) {
- // Focus c if the following are true:
+ } else if (node->type == N_CONTAINER && node->sway_container->view) {
+ // Focus node if the following are true:
// - cursor is over a new view, i.e. entered a new window; and
// - the new view is visible, i.e. not hidden in a stack or tab; and
// - the seat does not have a keyboard grab
if (!wlr_seat_keyboard_has_grab(cursor->seat->wlr_seat) &&
- c != prev_c &&
- view_is_visible(c->sway_view)) {
- seat_set_focus_warp(seat, c, false, true);
+ node != prev_node &&
+ view_is_visible(node->sway_container->view)) {
+ seat_set_focus_warp(seat, node, false, true);
} else {
- struct sway_container *next_focus =
- seat_get_focus_inactive(seat, &root_container);
- if (next_focus && next_focus->type == C_VIEW &&
- view_is_visible(next_focus->sway_view)) {
+ struct sway_node *next_focus =
+ seat_get_focus_inactive(seat, &root->node);
+ if (next_focus && next_focus->type == N_CONTAINER &&
+ next_focus->sway_container->view &&
+ view_is_visible(next_focus->sway_container->view)) {
seat_set_focus_warp(seat, next_focus, false, true);
}
}
@@ -486,12 +469,12 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
if (client != cursor->image_client) {
cursor_set_image(cursor, "left_ptr", client);
}
- } else if (c) {
- // Try a container's resize edge
- enum wlr_edges edge = find_resize_edge(c, cursor);
+ } else if (node && node->type == N_CONTAINER) {
+ // Try a node's resize edge
+ enum wlr_edges edge = find_resize_edge(node->sway_container, cursor);
if (edge == WLR_EDGE_NONE) {
cursor_set_image(cursor, "left_ptr", NULL);
- } else if (container_is_floating(c)) {
+ } else if (container_is_floating(node->sway_container)) {
cursor_set_image(cursor, wlr_xcursor_get_resize_name(edge), NULL);
} else {
if (edge & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) {
@@ -637,8 +620,10 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
// Determine what's under the cursor
struct wlr_surface *surface = NULL;
double sx, sy;
- struct sway_container *cont = container_at_coords(seat,
+ struct sway_node *node = node_at_coords(seat,
cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
+ struct sway_container *cont = node && node->type == N_CONTAINER ?
+ node->sway_container : NULL;
bool is_floating = cont && container_is_floating(cont);
bool is_floating_or_child = cont && container_is_floating_or_child(cont);
bool is_fullscreen_or_child = cont && container_is_fullscreen_or_child(cont);
@@ -670,6 +655,12 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
return;
}
+ // Handle clicking an empty workspace
+ if (node && node->type == N_WORKSPACE) {
+ seat_set_focus(seat, node);
+ return;
+ }
+
// Handle clicking a layer surface
if (surface && wlr_surface_is_layer_surface(surface)) {
struct wlr_layer_surface *layer =
@@ -684,7 +675,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
// Handle tiling resize via border
if (resize_edge && button == BTN_LEFT && state == WLR_BUTTON_PRESSED &&
!is_floating) {
- seat_set_focus(seat, cont);
+ seat_set_focus(seat, &cont->node);
seat_begin_resize_tiling(seat, cont, button, edge);
return;
}
@@ -713,7 +704,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
image = "sw-resize";
}
cursor_set_image(seat->cursor, image, NULL);
- seat_set_focus(seat, cont);
+ seat_set_focus(seat, &cont->node);
seat_begin_resize_tiling(seat, cont, button, edge);
return;
}
@@ -725,7 +716,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT;
if (button == btn_move && state == WLR_BUTTON_PRESSED &&
(mod_pressed || on_titlebar)) {
- while (cont->parent->type != C_WORKSPACE) {
+ while (cont->parent) {
cont = cont->parent;
}
seat_begin_move(seat, cont, button);
@@ -747,7 +738,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
BTN_LEFT : BTN_RIGHT;
if (mod_pressed && button == btn_resize) {
struct sway_container *floater = cont;
- while (floater->parent->type != C_WORKSPACE) {
+ while (floater->parent) {
floater = floater->parent;
}
edge = 0;
@@ -762,7 +753,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
// Handle mousedown on a container surface
if (surface && cont && state == WLR_BUTTON_PRESSED) {
- seat_set_focus(seat, cont);
+ seat_set_focus(seat, &cont->node);
seat_pointer_notify_button(seat, time_msec, button, state);
seat_begin_down(seat, cont, button, sx, sy);
return;
@@ -770,7 +761,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
// Handle clicking a container surface
if (cont) {
- seat_set_focus(seat, cont);
+ seat_set_focus(seat, &cont->node);
seat_pointer_notify_button(seat, time_msec, button, state);
return;
}
@@ -808,7 +799,7 @@ static void handle_touch_down(struct wl_listener *listener, void *data) {
wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device,
event->x, event->y, &lx, &ly);
double sx, sy;
- container_at_coords(seat, lx, ly, &surface, &sx, &sy);
+ node_at_coords(seat, lx, ly, &surface, &sx, &sy);
seat->touch_id = event->touch_id;
seat->touch_x = lx;
@@ -850,7 +841,7 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) {
wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device,
event->x, event->y, &lx, &ly);
double sx, sy;
- container_at_coords(cursor->seat, lx, ly, &surface, &sx, &sy);
+ node_at_coords(cursor->seat, lx, ly, &surface, &sx, &sy);
if (seat->touch_id == event->touch_id) {
seat->touch_x = lx;
@@ -1025,8 +1016,7 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
cursor->previous.y = wlr_cursor->y;
cursor->seat = seat;
- wlr_cursor_attach_output_layout(wlr_cursor,
- root_container.sway_root->output_layout);
+ wlr_cursor_attach_output_layout(wlr_cursor, root->output_layout);
// input events
wl_signal_add(&wlr_cursor->events.motion, &cursor->motion);
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c
index c820e032..b4352c6a 100644
--- a/sway/input/input-manager.c
+++ b/sway/input/input-manager.c
@@ -293,12 +293,10 @@ static void handle_inhibit_deactivate(struct wl_listener *listener, void *data)
struct sway_seat *seat;
wl_list_for_each(seat, &input_manager->seats, link) {
seat_set_exclusive_client(seat, NULL);
- struct sway_container *previous = seat_get_focus(seat);
+ struct sway_node *previous = seat_get_focus(seat);
if (previous) {
- wlr_log(WLR_DEBUG, "Returning focus to %p %s '%s'", previous,
- container_type_to_str(previous->type), previous->name);
// Hack to get seat to re-focus the return value of get_focus
- seat_set_focus(seat, previous->parent);
+ seat_set_focus(seat, NULL);
seat_set_focus(seat, previous);
}
}
@@ -369,10 +367,10 @@ struct sway_input_manager *input_manager_create(
}
bool input_manager_has_focus(struct sway_input_manager *input,
- struct sway_container *container) {
+ struct sway_node *node) {
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input->seats, link) {
- if (seat_get_focus(seat) == container) {
+ if (seat_get_focus(seat) == node) {
return true;
}
}
@@ -381,10 +379,10 @@ bool input_manager_has_focus(struct sway_input_manager *input,
}
void input_manager_set_focus(struct sway_input_manager *input,
- struct sway_container *container) {
+ struct sway_node *node) {
struct sway_seat *seat;
wl_list_for_each(seat, &input->seats, link) {
- seat_set_focus(seat, container);
+ seat_set_focus(seat, node);
}
}
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 4b7c7893..92d9d7ec 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -47,48 +47,36 @@ void seat_destroy(struct sway_seat *seat) {
seat_device_destroy(seat_device);
}
sway_cursor_destroy(seat->cursor);
- wl_list_remove(&seat->new_container.link);
+ wl_list_remove(&seat->new_node.link);
wl_list_remove(&seat->new_drag_icon.link);
wl_list_remove(&seat->link);
wlr_seat_destroy(seat->wlr_seat);
}
-static struct sway_seat_container *seat_container_from_container(
- struct sway_seat *seat, struct sway_container *con);
+static struct sway_seat_node *seat_node_from_node(
+ struct sway_seat *seat, struct sway_node *node);
-static void seat_container_destroy(struct sway_seat_container *seat_con) {
- struct sway_container *con = seat_con->container;
- struct sway_container *child = NULL;
-
- if (con->children != NULL) {
- for (int i = 0; i < con->children->length; ++i) {
- child = con->children->items[i];
- struct sway_seat_container *seat_child =
- seat_container_from_container(seat_con->seat, child);
- seat_container_destroy(seat_child);
- }
- }
-
- wl_list_remove(&seat_con->destroy.link);
- wl_list_remove(&seat_con->link);
- free(seat_con);
+static void seat_node_destroy(struct sway_seat_node *seat_node) {
+ wl_list_remove(&seat_node->destroy.link);
+ wl_list_remove(&seat_node->link);
+ free(seat_node);
}
/**
* Activate all views within this container recursively.
*/
-static void seat_send_activate(struct sway_container *con,
- struct sway_seat *seat) {
- if (con->type == C_VIEW) {
- if (!seat_is_input_allowed(seat, con->sway_view->surface)) {
+static void seat_send_activate(struct sway_node *node, struct sway_seat *seat) {
+ if (node_is_view(node)) {
+ if (!seat_is_input_allowed(seat, node->sway_container->view->surface)) {
wlr_log(WLR_DEBUG, "Refusing to set focus, input is inhibited");
return;
}
- view_set_activated(con->sway_view, true);
+ view_set_activated(node->sway_container->view, true);
} else {
- for (int i = 0; i < con->children->length; ++i) {
- struct sway_container *child = con->children->items[i];
- seat_send_activate(child, seat);
+ list_t *children = node_get_children(node);
+ for (int i = 0; i < children->length; ++i) {
+ struct sway_container *child = children->items[i];
+ seat_send_activate(&child->node, seat);
}
}
}
@@ -98,14 +86,15 @@ static void seat_send_activate(struct sway_container *con,
* If con is a container, set all child views as active and don't enable
* keyboard input on any.
*/
-static void seat_send_focus(struct sway_container *con,
- struct sway_seat *seat) {
- seat_send_activate(con, seat);
+static void seat_send_focus(struct sway_node *node, struct sway_seat *seat) {
+ seat_send_activate(node, seat);
- if (con->type == C_VIEW
- && seat_is_input_allowed(seat, con->sway_view->surface)) {
+ struct sway_view *view = node->type == N_CONTAINER ?
+ node->sway_container->view : NULL;
+
+ if (view && seat_is_input_allowed(seat, view->surface)) {
#ifdef HAVE_XWAYLAND
- if (con->sway_view->type == SWAY_VIEW_XWAYLAND) {
+ if (view->type == SWAY_VIEW_XWAYLAND) {
struct wlr_xwayland *xwayland =
seat->input->server->xwayland.wlr_xwayland;
wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
@@ -114,71 +103,67 @@ static void seat_send_focus(struct sway_container *con,
struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
if (keyboard) {
wlr_seat_keyboard_notify_enter(seat->wlr_seat,
- con->sway_view->surface, keyboard->keycodes,
+ view->surface, keyboard->keycodes,
keyboard->num_keycodes, &keyboard->modifiers);
} else {
wlr_seat_keyboard_notify_enter(
- seat->wlr_seat, con->sway_view->surface, NULL, 0, NULL);
+ seat->wlr_seat, view->surface, NULL, 0, NULL);
}
}
}
-void seat_focus_inactive_children_for_each(struct sway_seat *seat,
- struct sway_container *container,
- void (*f)(struct sway_container *container, void *data), void *data) {
- struct sway_seat_container *current = NULL;
+void seat_for_each_node(struct sway_seat *seat,
+ void (*f)(struct sway_node *node, void *data), void *data) {
+ struct sway_seat_node *current = NULL;
wl_list_for_each(current, &seat->focus_stack, link) {
- if (current->container->parent == NULL) {
- continue;
- }
- if (current->container->parent == container) {
- f(current->container, data);
- }
+ f(current->node, data);
}
}
struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat,
- struct sway_container *ancestor) {
- if (ancestor->type == C_VIEW) {
- return ancestor;
+ struct sway_node *ancestor) {
+ if (ancestor->type == N_CONTAINER && ancestor->sway_container->view) {
+ return ancestor->sway_container;
}
- struct sway_seat_container *current;
+ struct sway_seat_node *current;
wl_list_for_each(current, &seat->focus_stack, link) {
- struct sway_container *con = current->container;
- if (con->type == C_VIEW && container_has_ancestor(con, ancestor)) {
- return con;
+ struct sway_node *node = current->node;
+ if (node->type == N_CONTAINER && node->sway_container->view &&
+ node_has_ancestor(node, ancestor)) {
+ return node->sway_container;
}
}
return NULL;
}
-static void handle_seat_container_destroy(struct wl_listener *listener,
- void *data) {
- struct sway_seat_container *seat_con =
- wl_container_of(listener, seat_con, destroy);
- struct sway_seat *seat = seat_con->seat;
- struct sway_container *con = seat_con->container;
- struct sway_container *parent = con->parent;
- struct sway_container *focus = seat_get_focus(seat);
+static void handle_seat_node_destroy(struct wl_listener *listener, void *data) {
+ struct sway_seat_node *seat_node =
+ wl_container_of(listener, seat_node, destroy);
+ struct sway_seat *seat = seat_node->seat;
+ struct sway_node *node = seat_node->node;
+ struct sway_node *parent = node_get_parent(node);
+ struct sway_node *focus = seat_get_focus(seat);
bool set_focus =
focus != NULL &&
- (focus == con || container_has_ancestor(focus, con)) &&
- con->type != C_WORKSPACE;
+ (focus == node || node_has_ancestor(focus, node)) &&
+ node->type == N_CONTAINER;
- seat_container_destroy(seat_con);
+ seat_node_destroy(seat_node);
if (set_focus) {
- struct sway_container *next_focus = NULL;
+ struct sway_node *next_focus = NULL;
while (next_focus == NULL) {
- next_focus = seat_get_focus_inactive_view(seat, parent);
+ struct sway_container *con =
+ seat_get_focus_inactive_view(seat, parent);
+ next_focus = con ? &con->node : NULL;
- if (next_focus == NULL && parent->type == C_WORKSPACE) {
+ if (next_focus == NULL && parent->type == N_WORKSPACE) {
next_focus = parent;
break;
}
- parent = parent->parent;
+ parent = node_get_parent(parent);
}
// the structure change might have caused it to move up to the top of
@@ -191,39 +176,39 @@ static void handle_seat_container_destroy(struct wl_listener *listener,
}
}
-static struct sway_seat_container *seat_container_from_container(
- struct sway_seat *seat, struct sway_container *con) {
- if (con->type == C_ROOT || con->type == C_OUTPUT) {
- // these don't get seat containers ever
+static struct sway_seat_node *seat_node_from_node(
+ struct sway_seat *seat, struct sway_node *node) {
+ if (node->type == N_ROOT || node->type == N_OUTPUT) {
+ // these don't get seat nodes ever
return NULL;
}
- struct sway_seat_container *seat_con = NULL;
- wl_list_for_each(seat_con, &seat->focus_stack, link) {
- if (seat_con->container == con) {
- return seat_con;
+ struct sway_seat_node *seat_node = NULL;
+ wl_list_for_each(seat_node, &seat->focus_stack, link) {
+ if (seat_node->node == node) {
+ return seat_node;
}
}
- seat_con = calloc(1, sizeof(struct sway_seat_container));
- if (seat_con == NULL) {
- wlr_log(WLR_ERROR, "could not allocate seat container");
+ seat_node = calloc(1, sizeof(struct sway_seat_node));
+ if (seat_node == NULL) {
+ wlr_log(WLR_ERROR, "could not allocate seat node");
return NULL;
}
- seat_con->container = con;
- seat_con->seat = seat;
- wl_list_insert(seat->focus_stack.prev, &seat_con->link);
- wl_signal_add(&con->events.destroy, &seat_con->destroy);
- seat_con->destroy.notify = handle_seat_container_destroy;
+ seat_node->node = node;
+ seat_node->seat = seat;
+ wl_list_insert(seat->focus_stack.prev, &seat_node->link);
+ wl_signal_add(&node->events.destroy, &seat_node->destroy);
+ seat_node->destroy.notify = handle_seat_node_destroy;
- return seat_con;
+ return seat_node;
}
-static void handle_new_container(struct wl_listener *listener, void *data) {
- struct sway_seat *seat = wl_container_of(listener, seat, new_container);
- struct sway_container *con = data;
- seat_container_from_container(seat, con);
+static void handle_new_node(struct wl_listener *listener, void *data) {
+ struct sway_seat *seat = wl_container_of(listener, seat, new_node);
+ struct sway_node *node = data;
+ seat_node_from_node(seat, node);
}
static void drag_icon_damage_whole(struct sway_drag_icon *icon) {
@@ -272,8 +257,7 @@ static void drag_icon_handle_unmap(struct wl_listener *listener, void *data) {
drag_icon_damage_whole(icon);
}
-static void drag_icon_handle_destroy(struct wl_listener *listener,
- void *data) {
+static void drag_icon_handle_destroy(struct wl_listener *listener, void *data) {
struct sway_drag_icon *icon = wl_container_of(listener, icon, destroy);
icon->wlr_drag_icon->data = NULL;
wl_list_remove(&icon->link);
@@ -305,20 +289,29 @@ static void handle_new_drag_icon(struct wl_listener *listener, void *data) {
icon->destroy.notify = drag_icon_handle_destroy;
wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy);
- wl_list_insert(&root_container.sway_root->drag_icons, &icon->link);
+ wl_list_insert(&root->drag_icons, &icon->link);
drag_icon_update_position(icon);
}
-static void collect_focus_iter(struct sway_container *con, void *data) {
+static void collect_focus_iter(struct sway_node *node, void *data) {
struct sway_seat *seat = data;
- struct sway_seat_container *seat_con =
- seat_container_from_container(seat, con);
- if (!seat_con) {
+ struct sway_seat_node *seat_node = seat_node_from_node(seat, node);
+ if (!seat_node) {
return;
}
- wl_list_remove(&seat_con->link);
- wl_list_insert(&seat->focus_stack, &seat_con->link);
+ wl_list_remove(&seat_node->link);
+ wl_list_insert(&seat->focus_stack, &seat_node->link);
+}
+
+static void collect_focus_workspace_iter(struct sway_workspace *workspace,
+ void *data) {
+ collect_focus_iter(&workspace->node, data);
+}
+
+static void collect_focus_container_iter(struct sway_container *container,
+ void *data) {
+ collect_focus_iter(&container->node, data);
}
struct sway_seat *seat_create(struct sway_input_manager *input,
@@ -345,12 +338,11 @@ struct sway_seat *seat_create(struct sway_input_manager *input,
// init the focus stack
wl_list_init(&seat->focus_stack);
- root_for_each_workspace(collect_focus_iter, seat);
- root_for_each_container(collect_focus_iter, seat);
+ root_for_each_workspace(collect_focus_workspace_iter, seat);
+ root_for_each_container(collect_focus_container_iter, seat);
- wl_signal_add(&root_container.sway_root->events.new_container,
- &seat->new_container);
- seat->new_container.notify = handle_new_container;
+ wl_signal_add(&root->events.new_node, &seat->new_node);
+ seat->new_node.notify = handle_new_node;
wl_signal_add(&seat->wlr_seat->events.new_drag_icon, &seat->new_drag_icon);
seat->new_drag_icon.notify = handle_new_drag_icon;
@@ -388,19 +380,11 @@ static void seat_apply_input_config(struct sway_seat *seat,
if (mapped_to_output != NULL) {
wlr_log(WLR_DEBUG, "Mapping input device %s to output %s",
sway_device->input_device->identifier, mapped_to_output);
- struct sway_container *output = NULL;
- for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *_output = root_container.children->items[i];
- if (strcasecmp(_output->name, mapped_to_output) == 0) {
- output = _output;
- break;
- }
- }
+ struct sway_output *output = output_by_name(mapped_to_output);
if (output) {
wlr_cursor_map_input_to_output(seat->cursor->cursor,
- sway_device->input_device->wlr_device,
- output->sway_output->wlr_output);
- wlr_log(WLR_DEBUG, "Mapped to output %s", output->name);
+ sway_device->input_device->wlr_device, output->wlr_output);
+ wlr_log(WLR_DEBUG, "Mapped to output %s", output->wlr_output->name);
}
}
}
@@ -423,12 +407,12 @@ static void seat_configure_keyboard(struct sway_seat *seat,
sway_keyboard_configure(seat_device->keyboard);
wlr_seat_set_keyboard(seat->wlr_seat,
seat_device->input_device->wlr_device);
- struct sway_container *focus = seat_get_focus(seat);
- if (focus && focus->type == C_VIEW) {
+ struct sway_node *focus = seat_get_focus(seat);
+ if (focus && node_is_view(focus)) {
// force notify reenter to pick up the new configuration
wlr_seat_keyboard_clear_focus(seat->wlr_seat);
wlr_seat_keyboard_notify_enter(seat->wlr_seat,
- focus->sway_view->surface, wlr_keyboard->keycodes,
+ focus->sway_container->view->surface, wlr_keyboard->keycodes,
wlr_keyboard->num_keycodes, &wlr_keyboard->modifiers);
}
}
@@ -461,8 +445,7 @@ static struct sway_seat_device *seat_get_device(struct sway_seat *seat,
void seat_configure_device(struct sway_seat *seat,
struct sway_input_device *input_device) {
- struct sway_seat_device *seat_device =
- seat_get_device(seat, input_device);
+ struct sway_seat_device *seat_device = seat_get_device(seat, input_device);
if (!seat_device) {
return;
}
@@ -512,8 +495,7 @@ void seat_add_device(struct sway_seat *seat,
void seat_remove_device(struct sway_seat *seat,
struct sway_input_device *input_device) {
- struct sway_seat_device *seat_device =
- seat_get_device(seat, input_device);
+ struct sway_seat_device *seat_device = seat_get_device(seat, input_device);
if (!seat_device) {
return;
@@ -539,11 +521,9 @@ void seat_configure_xcursor(struct sway_seat *seat) {
}
}
- for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *output_container =
- root_container.children->items[i];
- struct wlr_output *output =
- output_container->sway_output->wlr_output;
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *sway_output = root->outputs->items[i];
+ struct wlr_output *output = sway_output->wlr_output;
bool result =
wlr_xcursor_manager_load(seat->cursor->xcursor_manager,
output->scale);
@@ -566,17 +546,20 @@ bool seat_is_input_allowed(struct sway_seat *seat,
return !seat->exclusive_client || seat->exclusive_client == client;
}
+static void send_unfocus(struct sway_container *con, void *data) {
+ if (con->view) {
+ view_set_activated(con->view, false);
+ }
+}
+
// Unfocus the container and any children (eg. when leaving `focus parent`)
-static void seat_send_unfocus(struct sway_container *container,
- struct sway_seat *seat) {
- if (container->type == C_VIEW) {
- wlr_seat_keyboard_clear_focus(seat->wlr_seat);
- view_set_activated(container->sway_view, false);
+static void seat_send_unfocus(struct sway_node *node, struct sway_seat *seat) {
+ wlr_seat_keyboard_clear_focus(seat->wlr_seat);
+ if (node->type == N_WORKSPACE) {
+ workspace_for_each_container(node->sway_workspace, send_unfocus, seat);
} else {
- for (int i = 0; i < container->children->length; ++i) {
- struct sway_container *child = container->children->items[i];
- seat_send_unfocus(child, seat);
- }
+ send_unfocus(node->sway_container, seat);
+ container_for_each_child(node->sway_container, send_unfocus, seat);
}
}
@@ -586,26 +569,23 @@ static int handle_urgent_timeout(void *data) {
return 0;
}
-void seat_set_focus_warp(struct sway_seat *seat,
- struct sway_container *container, bool warp, bool notify) {
+void seat_set_focus_warp(struct sway_seat *seat, struct sway_node *node,
+ bool warp, bool notify) {
if (seat->focused_layer) {
return;
}
- struct sway_container *last_focus = seat_get_focus(seat);
- if (last_focus == container) {
+ struct sway_node *last_focus = seat_get_focus(seat);
+ if (last_focus == node) {
return;
}
- struct sway_container *last_workspace = last_focus;
- if (last_workspace && last_workspace->type != C_WORKSPACE) {
- last_workspace = container_parent(last_workspace, C_WORKSPACE);
- }
+ struct sway_workspace *last_workspace = seat_get_focused_workspace(seat);
- if (container == NULL) {
+ if (node == NULL) {
// Close any popups on the old focus
- if (last_focus->type == C_VIEW) {
- view_close_popups(last_focus->sway_view);
+ if (node_is_view(last_focus)) {
+ view_close_popups(last_focus->sway_container->view);
}
seat_send_unfocus(last_focus, seat);
seat->has_focus = false;
@@ -613,69 +593,71 @@ void seat_set_focus_warp(struct sway_seat *seat,
return;
}
- struct sway_container *new_workspace = container;
- if (new_workspace->type != C_WORKSPACE) {
- new_workspace = container_parent(new_workspace, C_WORKSPACE);
- }
+ struct sway_workspace *new_workspace = node->type == N_WORKSPACE ?
+ node->sway_workspace : node->sway_container->workspace;
+ struct sway_container *container = node->type == N_CONTAINER ?
+ node->sway_container : NULL;
- if (last_workspace == new_workspace
- && last_workspace->sway_workspace->fullscreen
- && !container_is_fullscreen_or_child(container)) {
+ // Deny setting focus to a view which is hidden by a fullscreen container
+ if (new_workspace && new_workspace->fullscreen && container &&
+ !container_is_fullscreen_or_child(container)) {
return;
}
- struct sway_container *last_output = last_focus;
- if (last_output && last_output->type != C_OUTPUT) {
- last_output = container_parent(last_output, C_OUTPUT);
- }
- struct sway_container *new_output = container;
- if (new_output->type != C_OUTPUT) {
- new_output = container_parent(new_output, C_OUTPUT);
- }
+ struct sway_output *last_output = last_workspace ?
+ last_workspace->output : NULL;
+ struct sway_output *new_output = new_workspace->output;
// find new output's old workspace, which might have to be removed if empty
- struct sway_container *new_output_last_ws = NULL;
+ struct sway_workspace *new_output_last_ws = NULL;
if (new_output && last_output != new_output) {
- new_output_last_ws = seat_get_active_child(seat, new_output);
+ new_output_last_ws = output_get_active_workspace(new_output);
}
- if (container->parent) {
- struct sway_seat_container *seat_con =
- seat_container_from_container(seat, container);
- if (seat_con == NULL) {
- return;
+ // Unfocus the previous focus
+ if (last_focus) {
+ seat_send_unfocus(last_focus, seat);
+ node_set_dirty(last_focus);
+ struct sway_node *parent = node_get_parent(last_focus);
+ if (parent) {
+ node_set_dirty(parent);
}
+ }
- // put all the ancestors of this container on top of the focus stack
- struct sway_seat_container *parent =
- seat_container_from_container(seat, container->parent);
+ // Put the container parents on the focus stack, then the workspace, then
+ // the focused container.
+ if (container) {
+ struct sway_container *parent = container->parent;
while (parent) {
- wl_list_remove(&parent->link);
- wl_list_insert(&seat->focus_stack, &parent->link);
- container_set_dirty(parent->container);
-
- parent = seat_container_from_container(seat,
- parent->container->parent);
- }
-
- wl_list_remove(&seat_con->link);
- wl_list_insert(&seat->focus_stack, &seat_con->link);
-
- if (last_focus) {
- seat_send_unfocus(last_focus, seat);
- container_set_dirty(last_focus);
+ struct sway_seat_node *seat_node =
+ seat_node_from_node(seat, &parent->node);
+ wl_list_remove(&seat_node->link);
+ wl_list_insert(&seat->focus_stack, &seat_node->link);
+ node_set_dirty(&parent->node);
+ parent = parent->parent;
}
- seat_send_focus(container, seat);
-
- container_set_dirty(container);
- container_set_dirty(container->parent); // for focused_inactive_child
+ }
+ if (new_workspace) {
+ struct sway_seat_node *seat_node =
+ seat_node_from_node(seat, &new_workspace->node);
+ wl_list_remove(&seat_node->link);
+ wl_list_insert(&seat->focus_stack, &seat_node->link);
+ node_set_dirty(&new_workspace->node);
+ }
+ if (container) {
+ struct sway_seat_node *seat_node =
+ seat_node_from_node(seat, &container->node);
+ wl_list_remove(&seat_node->link);
+ wl_list_insert(&seat->focus_stack, &seat_node->link);
+ node_set_dirty(&container->node);
+ seat_send_focus(&container->node, seat);
}
// emit ipc events
if (notify && new_workspace && last_workspace != new_workspace) {
ipc_event_workspace(last_workspace, new_workspace, "focus");
}
- if (container->type == C_VIEW) {
+ if (container && container->view) {
ipc_event_window(container, "focus");
}
@@ -684,14 +666,14 @@ void seat_set_focus_warp(struct sway_seat *seat,
}
// Close any popups on the old focus
- if (last_focus && last_focus->type == C_VIEW) {
- view_close_popups(last_focus->sway_view);
+ if (last_focus && node_is_view(last_focus)) {
+ view_close_popups(last_focus->sway_container->view);
}
// If urgent, either unset the urgency or start a timer to unset it
- if (container->type == C_VIEW && view_is_urgent(container->sway_view) &&
- !container->sway_view->urgent_timer) {
- struct sway_view *view = container->sway_view;
+ if (container && container->view && view_is_urgent(container->view) &&
+ !container->view->urgent_timer) {
+ struct sway_view *view = container->view;
if (last_workspace && last_workspace != new_workspace &&
config->urgent_timeout > 0) {
view->urgent_timer = wl_event_loop_add_timer(server.wl_event_loop,
@@ -711,12 +693,15 @@ void seat_set_focus_warp(struct sway_seat *seat,
// If we've focused a floating container, bring it to the front.
// We do this by putting it at the end of the floating list.
- struct sway_container *floater = container;
- while (floater->parent && floater->parent->type != C_WORKSPACE) {
- floater = floater->parent;
- }
- if (container_is_floating(floater)) {
- list_move_to_end(floater->parent->sway_workspace->floating, floater);
+ if (container) {
+ struct sway_container *floater = container;
+ while (floater->parent) {
+ floater = floater->parent;
+ }
+ if (container_is_floating(floater)) {
+ list_move_to_end(floater->workspace->floating, floater);
+ node_set_dirty(&floater->workspace->node);
+ }
}
if (last_focus) {
@@ -725,16 +710,20 @@ void seat_set_focus_warp(struct sway_seat *seat,
}
if (config->mouse_warping && warp && new_output != last_output) {
- double x = container->x + container->width / 2.0;
- double y = container->y + container->height / 2.0;
- struct wlr_output *wlr_output =
- new_output->sway_output->wlr_output;
- if (!wlr_output_layout_contains_point(
- root_container.sway_root->output_layout,
- wlr_output, seat->cursor->cursor->x,
- seat->cursor->cursor->y)) {
- wlr_cursor_warp(seat->cursor->cursor, NULL, x, y);
- cursor_send_pointer_motion(seat->cursor, 0, true);
+ double x = 0;
+ double y = 0;
+ if (container) {
+ x = container->x + container->width / 2.0;
+ y = container->y + container->height / 2.0;
+ } else {
+ x = new_workspace->x + new_workspace->width / 2.0;
+ y = new_workspace->y + new_workspace->height / 2.0;
+ }
+ if (!wlr_output_layout_contains_point(root->output_layout,
+ new_output->wlr_output, seat->cursor->cursor->x,
+ seat->cursor->cursor->y)) {
+ wlr_cursor_warp(seat->cursor->cursor, NULL, x, y);
+ cursor_send_pointer_motion(seat->cursor, 0, true);
}
}
}
@@ -744,9 +733,8 @@ void seat_set_focus_warp(struct sway_seat *seat,
update_debug_tree();
}
-void seat_set_focus(struct sway_seat *seat,
- struct sway_container *container) {
- seat_set_focus_warp(seat, container, true, true);
+void seat_set_focus(struct sway_seat *seat, struct sway_node *node) {
+ seat_set_focus_warp(seat, node, true, true);
}
void seat_set_focus_surface(struct sway_seat *seat,
@@ -755,12 +743,11 @@ void seat_set_focus_surface(struct sway_seat *seat,
return;
}
if (seat->has_focus && unfocus) {
- struct sway_container *focus = seat_get_focus(seat);
+ struct sway_node *focus = seat_get_focus(seat);
seat_send_unfocus(focus, seat);
seat->has_focus = false;
}
- struct wlr_keyboard *keyboard =
- wlr_seat_get_keyboard(seat->wlr_seat);
+ struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
if (keyboard) {
wlr_seat_keyboard_notify_enter(seat->wlr_seat, surface,
keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers);
@@ -773,11 +760,8 @@ void seat_set_focus_layer(struct sway_seat *seat,
struct wlr_layer_surface *layer) {
if (!layer && seat->focused_layer) {
seat->focused_layer = NULL;
- struct sway_container *previous =
- seat_get_focus_inactive(seat, &root_container);
+ struct sway_node *previous = seat_get_focus_inactive(seat, &root->node);
if (previous) {
- wlr_log(WLR_DEBUG, "Returning focus to %p %s '%s'", previous,
- container_type_to_str(previous->type), previous->name);
// Hack to get seat to re-focus the return value of get_focus
seat_set_focus(seat, NULL);
seat_set_focus(seat, previous);
@@ -798,13 +782,9 @@ void seat_set_exclusive_client(struct sway_seat *seat,
seat->exclusive_client = client;
// Triggers a refocus of the topmost surface layer if necessary
// TODO: Make layer surface focus per-output based on cursor position
- for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *output = root_container.children->items[i];
- if (!sway_assert(output->type == C_OUTPUT,
- "root container has non-output child")) {
- continue;
- }
- arrange_layers(output->sway_output);
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
+ arrange_layers(output);
}
return;
}
@@ -814,9 +794,9 @@ void seat_set_exclusive_client(struct sway_seat *seat,
}
}
if (seat->has_focus) {
- struct sway_container *focus = seat_get_focus(seat);
- if (focus->type == C_VIEW && wl_resource_get_client(
- focus->sway_view->surface->resource) != client) {
+ struct sway_node *focus = seat_get_focus(seat);
+ if (node_is_view(focus) && wl_resource_get_client(
+ focus->sway_container->view->surface->resource) != client) {
seat_set_focus(seat, NULL);
}
}
@@ -837,79 +817,101 @@ void seat_set_exclusive_client(struct sway_seat *seat,
seat->exclusive_client = client;
}
-struct sway_container *seat_get_focus_inactive(struct sway_seat *seat,
- struct sway_container *con) {
- if (con->type == C_WORKSPACE && !con->children->length &&
- !con->sway_workspace->floating->length) {
- return con;
+struct sway_node *seat_get_focus_inactive(struct sway_seat *seat,
+ struct sway_node *node) {
+ if (node_is_view(node)) {
+ return node;
}
- if (con->type == C_VIEW) {
- return con;
- }
- struct sway_seat_container *current;
+ struct sway_seat_node *current;
wl_list_for_each(current, &seat->focus_stack, link) {
- if (container_has_ancestor(current->container, con)) {
- return current->container;
+ if (node_has_ancestor(current->node, node)) {
+ return current->node;
}
}
+ if (node->type == N_WORKSPACE) {
+ return node;
+ }
return NULL;
}
struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat,
- struct sway_container *ancestor) {
- if (ancestor->type == C_WORKSPACE && !ancestor->children->length) {
- return ancestor;
+ struct sway_workspace *workspace) {
+ if (!workspace->tiling->length) {
+ return NULL;
}
- struct sway_seat_container *current;
+ struct sway_seat_node *current;
wl_list_for_each(current, &seat->focus_stack, link) {
- struct sway_container *con = current->container;
- if (!container_is_floating_or_child(con) &&
- container_has_ancestor(current->container, ancestor)) {
- return con;
+ struct sway_node *node = current->node;
+ if (node->type == N_CONTAINER &&
+ !container_is_floating_or_child(node->sway_container) &&
+ node->sway_container->workspace == workspace) {
+ return node->sway_container;
}
}
return NULL;
}
struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat,
- struct sway_container *ancestor) {
- if (ancestor->type == C_WORKSPACE &&
- !ancestor->sway_workspace->floating->length) {
+ struct sway_workspace *workspace) {
+ if (!workspace->floating->length) {
return NULL;
}
- struct sway_seat_container *current;
+ struct sway_seat_node *current;
wl_list_for_each(current, &seat->focus_stack, link) {
- struct sway_container *con = current->container;
- if (container_is_floating_or_child(con) &&
- container_has_ancestor(current->container, ancestor)) {
- return con;
+ struct sway_node *node = current->node;
+ if (node->type == N_CONTAINER &&
+ container_is_floating_or_child(node->sway_container) &&
+ node->sway_container->workspace == workspace) {
+ return node->sway_container;
}
}
return NULL;
}
-struct sway_container *seat_get_active_child(struct sway_seat *seat,
- struct sway_container *parent) {
- if (parent->type == C_VIEW) {
+struct sway_node *seat_get_active_child(struct sway_seat *seat,
+ struct sway_node *parent) {
+ if (node_is_view(parent)) {
return parent;
}
- struct sway_seat_container *current;
+ struct sway_seat_node *current;
wl_list_for_each(current, &seat->focus_stack, link) {
- struct sway_container *con = current->container;
- if (con->parent == parent) {
- return con;
+ struct sway_node *node = current->node;
+ if (node_get_parent(node) == parent) {
+ return node;
}
}
return NULL;
}
-struct sway_container *seat_get_focus(struct sway_seat *seat) {
+struct sway_node *seat_get_focus(struct sway_seat *seat) {
if (!seat->has_focus) {
return NULL;
}
- struct sway_seat_container *current =
+ struct sway_seat_node *current =
wl_container_of(seat->focus_stack.next, current, link);
- return current->container;
+ return current->node;
+}
+
+struct sway_workspace *seat_get_focused_workspace(struct sway_seat *seat) {
+ struct sway_node *focus = seat_get_focus(seat);
+ if (!focus) {
+ return NULL;
+ }
+ if (focus->type == N_CONTAINER) {
+ return focus->sway_container->workspace;
+ }
+ if (focus->type == N_WORKSPACE) {
+ return focus->sway_workspace;
+ }
+ return NULL; // unreachable
+}
+
+struct sway_container *seat_get_focused_container(struct sway_seat *seat) {
+ struct sway_node *focus = seat_get_focus(seat);
+ if (focus && focus->type == N_CONTAINER) {
+ return focus->sway_container;
+ }
+ return NULL;
}
void seat_apply_config(struct sway_seat *seat,
diff --git a/sway/ipc-json.c b/sway/ipc-json.c
index 06cb7e11..abc4a086 100644
--- a/sway/ipc-json.c
+++ b/sway/ipc-json.c
@@ -46,18 +46,18 @@ json_object *ipc_json_get_version() {
return version;
}
-static json_object *ipc_json_create_rect(struct sway_container *c) {
+static json_object *ipc_json_create_rect(struct wlr_box *box) {
json_object *rect = json_object_new_object();
- json_object_object_add(rect, "x", json_object_new_int((int32_t)c->x));
- json_object_object_add(rect, "y", json_object_new_int((int32_t)c->y));
- json_object_object_add(rect, "width", json_object_new_int((int32_t)c->width));
- json_object_object_add(rect, "height", json_object_new_int((int32_t)c->height));
+ json_object_object_add(rect, "x", json_object_new_int(box->x));
+ json_object_object_add(rect, "y", json_object_new_int(box->y));
+ json_object_object_add(rect, "width", json_object_new_int(box->width));
+ json_object_object_add(rect, "height", json_object_new_int(box->height));
return rect;
}
-static void ipc_json_describe_root(struct sway_container *root, json_object *object) {
+static void ipc_json_describe_root(struct sway_root *root, json_object *object) {
json_object_object_add(object, "type", json_object_new_string("root"));
json_object_object_add(object, "layout", json_object_new_string("splith"));
}
@@ -84,17 +84,13 @@ static const char *ipc_json_get_output_transform(enum wl_output_transform transf
return NULL;
}
-static void ipc_json_describe_output(struct sway_container *container,
+static void ipc_json_describe_output(struct sway_output *output,
json_object *object) {
- struct wlr_output *wlr_output = container->sway_output->wlr_output;
- json_object_object_add(object, "type",
- json_object_new_string("output"));
- json_object_object_add(object, "active",
- json_object_new_boolean(true));
- json_object_object_add(object, "primary",
- json_object_new_boolean(false));
- json_object_object_add(object, "layout",
- json_object_new_string("output"));
+ struct wlr_output *wlr_output = output->wlr_output;
+ json_object_object_add(object, "type", json_object_new_string("output"));
+ json_object_object_add(object, "active", json_object_new_boolean(true));
+ json_object_object_add(object, "primary", json_object_new_boolean(false));
+ json_object_object_add(object, "layout", json_object_new_string("output"));
json_object_object_add(object, "make",
json_object_new_string(wlr_output->make));
json_object_object_add(object, "model",
@@ -109,20 +105,9 @@ static void ipc_json_describe_output(struct sway_container *container,
json_object_new_string(
ipc_json_get_output_transform(wlr_output->transform)));
- struct sway_seat *seat = input_manager_get_default_seat(input_manager);
- const char *ws = NULL;
- if (seat) {
- struct sway_container *focus =
- seat_get_focus_inactive(seat, container);
- if (focus && focus->type != C_WORKSPACE) {
- focus = container_parent(focus, C_WORKSPACE);
- }
- if (focus) {
- ws = focus->name;
- }
- }
+ struct sway_workspace *ws = output_get_active_workspace(output);
json_object_object_add(object, "current_workspace",
- json_object_new_string(ws));
+ json_object_new_string(ws->name));
json_object *modes_array = json_object_new_array();
struct wlr_output_mode *mode;
@@ -161,60 +146,57 @@ json_object *ipc_json_describe_disabled_output(struct sway_output *output) {
return object;
}
-static void ipc_json_describe_workspace(struct sway_container *workspace,
+static void ipc_json_describe_workspace(struct sway_workspace *workspace,
json_object *object) {
int num = isdigit(workspace->name[0]) ? atoi(workspace->name) : -1;
json_object_object_add(object, "num", json_object_new_int(num));
- json_object_object_add(object, "output", workspace->parent ?
- json_object_new_string(workspace->parent->name) : NULL);
+ json_object_object_add(object, "output", workspace->output ?
+ json_object_new_string(workspace->output->wlr_output->name) : NULL);
json_object_object_add(object, "type", json_object_new_string("workspace"));
json_object_object_add(object, "urgent",
- json_object_new_boolean(workspace->sway_workspace->urgent));
- json_object_object_add(object, "representation", workspace->formatted_title ?
- json_object_new_string(workspace->formatted_title) : NULL);
+ json_object_new_boolean(workspace->urgent));
+ json_object_object_add(object, "representation", workspace->representation ?
+ json_object_new_string(workspace->representation) : NULL);
const char *layout = ipc_json_layout_description(workspace->layout);
json_object_object_add(object, "layout", json_object_new_string(layout));
// Floating
json_object *floating_array = json_object_new_array();
- list_t *floating = workspace->sway_workspace->floating;
- for (int i = 0; i < floating->length; ++i) {
- struct sway_container *floater = floating->items[i];
+ for (int i = 0; i < workspace->floating->length; ++i) {
+ struct sway_container *floater = workspace->floating->items[i];
json_object_array_add(floating_array,
- ipc_json_describe_container_recursive(floater));
+ ipc_json_describe_node_recursive(&floater->node));
}
json_object_object_add(object, "floating_nodes", floating_array);
}
static void ipc_json_describe_view(struct sway_container *c, json_object *object) {
json_object_object_add(object, "name",
- c->name ? json_object_new_string(c->name) : NULL);
+ c->title ? json_object_new_string(c->title) : NULL);
json_object_object_add(object, "type", json_object_new_string("con"));
- if (c->type == C_VIEW) {
- const char *app_id = view_get_app_id(c->sway_view);
+ if (c->view) {
+ const char *app_id = view_get_app_id(c->view);
json_object_object_add(object, "app_id",
app_id ? json_object_new_string(app_id) : NULL);
- const char *class = view_get_class(c->sway_view);
+ const char *class = view_get_class(c->view);
json_object_object_add(object, "class",
class ? json_object_new_string(class) : NULL);
}
- if (c->parent) {
- json_object_object_add(object, "layout",
- json_object_new_string(ipc_json_layout_description(c->layout)));
- }
+ json_object_object_add(object, "layout",
+ json_object_new_string(ipc_json_layout_description(c->layout)));
- bool urgent = c->type == C_VIEW ?
- view_is_urgent(c->sway_view) : container_has_urgent_child(c);
+ bool urgent = c->view ?
+ view_is_urgent(c->view) : container_has_urgent_child(c);
json_object_object_add(object, "urgent", json_object_new_boolean(urgent));
- if (c->type == C_VIEW) {
+ if (c->view) {
json_object *marks = json_object_new_array();
- list_t *view_marks = c->sway_view->marks;
+ list_t *view_marks = c->view->marks;
for (int i = 0; i < view_marks->length; ++i) {
json_object_array_add(marks, json_object_new_string(view_marks->items[i]));
}
@@ -222,64 +204,97 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object
}
}
-static void focus_inactive_children_iterator(struct sway_container *c, void *data) {
- json_object *focus = data;
- json_object_array_add(focus, json_object_new_int(c->id));
-}
+struct focus_inactive_data {
+ struct sway_node *node;
+ json_object *object;
+};
-json_object *ipc_json_describe_container(struct sway_container *c) {
- if (!(sway_assert(c, "Container must not be null."))) {
- return NULL;
+static void focus_inactive_children_iterator(struct sway_node *node,
+ void *_data) {
+ struct focus_inactive_data *data = _data;
+ if (node_get_parent(node) == data->node) {
+ json_object_array_add(data->object, json_object_new_int(node->id));
}
+}
+json_object *ipc_json_describe_node(struct sway_node *node) {
struct sway_seat *seat = input_manager_get_default_seat(input_manager);
- bool focused = seat_get_focus(seat) == c;
+ bool focused = seat_get_focus(seat) == node;
json_object *object = json_object_new_object();
+ char *name = node_get_name(node);
- json_object_object_add(object, "id", json_object_new_int((int)c->id));
+ struct wlr_box box;
+ node_get_box(node, &box);
+ json_object_object_add(object, "id", json_object_new_int((int)node->id));
json_object_object_add(object, "name",
- c->name ? json_object_new_string(c->name) : NULL);
- json_object_object_add(object, "rect", ipc_json_create_rect(c));
- json_object_object_add(object, "focused",
- json_object_new_boolean(focused));
+ name ? json_object_new_string(name) : NULL);
+ json_object_object_add(object, "rect", ipc_json_create_rect(&box));
+ json_object_object_add(object, "focused", json_object_new_boolean(focused));
json_object *focus = json_object_new_array();
- seat_focus_inactive_children_for_each(seat, c,
- focus_inactive_children_iterator, focus);
+ struct focus_inactive_data data = {
+ .node = node,
+ .object = focus,
+ };
+ seat_for_each_node(seat, focus_inactive_children_iterator, &data);
json_object_object_add(object, "focus", focus);
- switch (c->type) {
- case C_ROOT:
- ipc_json_describe_root(c, object);
+ switch (node->type) {
+ case N_ROOT:
+ ipc_json_describe_root(root, object);
break;
- case C_OUTPUT:
- ipc_json_describe_output(c, object);
+ case N_OUTPUT:
+ ipc_json_describe_output(node->sway_output, object);
break;
- case C_CONTAINER:
- case C_VIEW:
- ipc_json_describe_view(c, object);
+ case N_CONTAINER:
+ ipc_json_describe_view(node->sway_container, object);
break;
- case C_WORKSPACE:
- ipc_json_describe_workspace(c, object);
- break;
- case C_TYPES:
- default:
+ case N_WORKSPACE:
+ ipc_json_describe_workspace(node->sway_workspace, object);
break;
}
return object;
}
-json_object *ipc_json_describe_container_recursive(struct sway_container *c) {
- json_object *object = ipc_json_describe_container(c);
+json_object *ipc_json_describe_node_recursive(struct sway_node *node) {
+ json_object *object = ipc_json_describe_node(node);
int i;
json_object *children = json_object_new_array();
- if (c->type != C_VIEW && c->children) {
- for (i = 0; i < c->children->length; ++i) {
- json_object_array_add(children, ipc_json_describe_container_recursive(c->children->items[i]));
+ switch (node->type) {
+ case N_ROOT:
+ for (i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
+ json_object_array_add(children,
+ ipc_json_describe_node_recursive(&output->node));
+ }
+ break;
+ case N_OUTPUT:
+ for (i = 0; i < node->sway_output->workspaces->length; ++i) {
+ struct sway_workspace *ws = node->sway_output->workspaces->items[i];
+ json_object_array_add(children,
+ ipc_json_describe_node_recursive(&ws->node));
}
+ break;
+ case N_WORKSPACE:
+ for (i = 0; i < node->sway_workspace->tiling->length; ++i) {
+ struct sway_container *con = node->sway_workspace->tiling->items[i];
+ json_object_array_add(children,
+ ipc_json_describe_node_recursive(&con->node));
+ }
+ break;
+ case N_CONTAINER:
+ if (node->sway_container->children) {
+ for (i = 0; i < node->sway_container->children->length; ++i) {
+ struct sway_container *child =
+ node->sway_container->children->items[i];
+ json_object_array_add(children,
+ ipc_json_describe_node_recursive(&child->node));
+ }
+ }
+ break;
}
json_object_object_add(object, "nodes", children);
@@ -329,7 +344,7 @@ json_object *ipc_json_describe_seat(struct sway_seat *seat) {
}
json_object *object = json_object_new_object();
- struct sway_container *focus = seat_get_focus(seat);
+ struct sway_node *focus = seat_get_focus(seat);
json_object_object_add(object, "name",
json_object_new_string(seat->wlr_seat->name));
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index fb5be27b..8ae265f6 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -33,6 +33,7 @@
#include "sway/input/seat.h"
#include "sway/tree/root.h"
#include "sway/tree/view.h"
+#include "sway/tree/workspace.h"
#include "list.h"
#include "log.h"
#include "util.h"
@@ -291,8 +292,8 @@ static void ipc_send_event(const char *json_string, enum ipc_command_type event)
}
}
-void ipc_event_workspace(struct sway_container *old,
- struct sway_container *new, const char *change) {
+void ipc_event_workspace(struct sway_workspace *old,
+ struct sway_workspace *new, const char *change) {
if (!ipc_has_event_listeners(IPC_EVENT_WORKSPACE)) {
return;
}
@@ -301,14 +302,14 @@ void ipc_event_workspace(struct sway_container *old,
json_object_object_add(obj, "change", json_object_new_string(change));
if (old) {
json_object_object_add(obj, "old",
- ipc_json_describe_container_recursive(old));
+ ipc_json_describe_node_recursive(&old->node));
} else {
json_object_object_add(obj, "old", NULL);
}
if (new) {
json_object_object_add(obj, "current",
- ipc_json_describe_container_recursive(new));
+ ipc_json_describe_node_recursive(&new->node));
} else {
json_object_object_add(obj, "current", NULL);
}
@@ -325,7 +326,8 @@ void ipc_event_window(struct sway_container *window, const char *change) {
wlr_log(WLR_DEBUG, "Sending window::%s event", change);
json_object *obj = json_object_new_object();
json_object_object_add(obj, "change", json_object_new_string(change));
- json_object_object_add(obj, "container", ipc_json_describe_container_recursive(window));
+ json_object_object_add(obj, "container",
+ ipc_json_describe_node_recursive(&window->node));
const char *json_string = json_object_to_json_string(obj);
ipc_send_event(json_string, IPC_EVENT_WINDOW);
@@ -521,30 +523,20 @@ void ipc_client_disconnect(struct ipc_client *client) {
free(client);
}
-static void ipc_get_workspaces_callback(struct sway_container *workspace,
+static void ipc_get_workspaces_callback(struct sway_workspace *workspace,
void *data) {
- if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) {
- return;
- }
- json_object *workspace_json = ipc_json_describe_container(workspace);
+ json_object *workspace_json = ipc_json_describe_node(&workspace->node);
// override the default focused indicator because
// it's set differently for the get_workspaces reply
- struct sway_seat *seat =
- input_manager_get_default_seat(input_manager);
- struct sway_container *focused_ws = seat_get_focus(seat);
- if (focused_ws != NULL && focused_ws->type != C_WORKSPACE) {
- focused_ws = container_parent(focused_ws, C_WORKSPACE);
- }
+ struct sway_seat *seat = input_manager_get_default_seat(input_manager);
+ struct sway_workspace *focused_ws = seat_get_focused_workspace(seat);
bool focused = workspace == focused_ws;
json_object_object_del(workspace_json, "focused");
json_object_object_add(workspace_json, "focused",
json_object_new_boolean(focused));
json_object_array_add((json_object *)data, workspace_json);
- focused_ws = seat_get_focus_inactive(seat, workspace->parent);
- if (focused_ws->type != C_WORKSPACE) {
- focused_ws = container_parent(focused_ws, C_WORKSPACE);
- }
+ focused_ws = output_get_active_workspace(workspace->output);
bool visible = workspace == focused_ws;
json_object_object_add(workspace_json, "visible",
json_object_new_boolean(visible));
@@ -552,9 +544,9 @@ static void ipc_get_workspaces_callback(struct sway_container *workspace,
static void ipc_get_marks_callback(struct sway_container *con, void *data) {
json_object *marks = (json_object *)data;
- if (con->type == C_VIEW && con->sway_view->marks) {
- for (int i = 0; i < con->sway_view->marks->length; ++i) {
- char *mark = (char *)con->sway_view->marks->items[i];
+ if (con->view && con->view->marks) {
+ for (int i = 0; i < con->view->marks->length; ++i) {
+ char *mark = (char *)con->view->marks->items[i];
json_object_array_add(marks, json_object_new_string(mark));
}
}
@@ -608,16 +600,14 @@ void ipc_client_handle_command(struct ipc_client *client) {
case IPC_GET_OUTPUTS:
{
json_object *outputs = json_object_new_array();
- for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *container = root_container.children->items[i];
- if (container->type == C_OUTPUT) {
- json_object_array_add(outputs,
- ipc_json_describe_container(container));
- }
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
+ json_object_array_add(outputs,
+ ipc_json_describe_node(&output->node));
}
struct sway_output *output;
- wl_list_for_each(output, &root_container.sway_root->all_outputs, link) {
- if (!output->swayc) {
+ wl_list_for_each(output, &root->all_outputs, link) {
+ if (!output->enabled) {
json_object_array_add(outputs,
ipc_json_describe_disabled_output(output));
}
@@ -717,8 +707,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
case IPC_GET_TREE:
{
- json_object *tree =
- ipc_json_describe_container_recursive(&root_container);
+ json_object *tree = ipc_json_describe_node_recursive(&root->node);
const char *json_string = json_object_to_json_string(tree);
client_valid =
ipc_send_reply(client, json_string, (uint32_t) strlen(json_string));
diff --git a/sway/main.c b/sway/main.c
index 2f05dc38..fb4f0d8c 100644
--- a/sway/main.c
+++ b/sway/main.c
@@ -42,7 +42,6 @@ void sway_terminate(int exit_code) {
}
void sig_handler(int signal) {
- //close_views(&root_container);
sway_terminate(EXIT_SUCCESS);
}
@@ -395,7 +394,7 @@ int main(int argc, char **argv) {
wlr_log(WLR_INFO, "Starting sway version " SWAY_VERSION);
- root_create();
+ root = root_create();
if (!server_init(&server)) {
return 1;
@@ -450,7 +449,8 @@ int main(int argc, char **argv) {
wlr_log(WLR_INFO, "Shutting down sway");
server_fini(&server);
- root_destroy();
+ root_destroy(root);
+ root = NULL;
if (config) {
free_config(config);
diff --git a/sway/meson.build b/sway/meson.build
index c14e58dd..8891ebc0 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -151,6 +151,7 @@ sway_sources = files(
'tree/arrange.c',
'tree/container.c',
+ 'tree/node.c',
'tree/root.c',
'tree/view.c',
'tree/workspace.c',
diff --git a/sway/server.c b/sway/server.c
index 749365cb..09ebe83f 100644
--- a/sway/server.c
+++ b/sway/server.c
@@ -61,8 +61,7 @@ bool server_init(struct sway_server *server) {
server->new_output.notify = handle_new_output;
wl_signal_add(&server->backend->events.new_output, &server->new_output);
- wlr_xdg_output_manager_create(server->wl_display,
- root_container.sway_root->output_layout);
+ wlr_xdg_output_manager_create(server->wl_display, root->output_layout);
server->idle = wlr_idle_create(server->wl_display);
server->idle_inhibit_manager_v1 =
@@ -131,7 +130,7 @@ bool server_init(struct sway_server *server) {
server->txn_timeout_ms = 200;
}
- server->dirty_containers = create_list();
+ server->dirty_nodes = create_list();
server->transactions = create_list();
input_manager = input_manager_create(server);
@@ -145,7 +144,7 @@ void server_fini(struct sway_server *server) {
#endif
wl_display_destroy_clients(server->wl_display);
wl_display_destroy(server->wl_display);
- list_free(server->dirty_containers);
+ list_free(server->dirty_nodes);
list_free(server->transactions);
}
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c
index 92f20fcc..edb05f86 100644
--- a/sway/tree/arrange.c
+++ b/sway/tree/arrange.c
@@ -166,29 +166,23 @@ void arrange_container(struct sway_container *container) {
if (config->reloading) {
return;
}
- if (container->type == C_VIEW) {
- view_autoconfigure(container->sway_view);
- container_set_dirty(container);
- return;
- }
- if (!sway_assert(container->type == C_CONTAINER, "Expected a container")) {
+ if (container->view) {
+ view_autoconfigure(container->view);
+ node_set_dirty(&container->node);
return;
}
struct wlr_box box;
container_get_box(container, &box);
arrange_children(container->children, container->layout, &box);
- container_set_dirty(container);
+ node_set_dirty(&container->node);
}
-void arrange_workspace(struct sway_container *workspace) {
+void arrange_workspace(struct sway_workspace *workspace) {
if (config->reloading) {
return;
}
- if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) {
- return;
- }
- struct sway_container *output = workspace->parent;
- struct wlr_box *area = &output->sway_output->usable_area;
+ struct sway_output *output = workspace->output;
+ struct wlr_box *area = &output->usable_area;
wlr_log(WLR_DEBUG, "Usable area for ws: %dx%d@%d,%d",
area->width, area->height, area->x, area->y);
workspace_remove_gaps(workspace);
@@ -197,21 +191,20 @@ void arrange_workspace(struct sway_container *workspace) {
double prev_y = workspace->y;
workspace->width = area->width;
workspace->height = area->height;
- workspace->x = output->x + area->x;
- workspace->y = output->y + area->y;
+ workspace->x = output->wlr_output->lx + area->x;
+ workspace->y = output->wlr_output->ly + area->y;
// Adjust any floating containers
double diff_x = workspace->x - prev_x;
double diff_y = workspace->y - prev_y;
if (diff_x != 0 || diff_y != 0) {
- for (int i = 0; i < workspace->sway_workspace->floating->length; ++i) {
- struct sway_container *floater =
- workspace->sway_workspace->floating->items[i];
+ for (int i = 0; i < workspace->floating->length; ++i) {
+ struct sway_container *floater = workspace->floating->items[i];
container_floating_translate(floater, diff_x, diff_y);
double center_x = floater->x + floater->width / 2;
double center_y = floater->y + floater->height / 2;
struct wlr_box workspace_box;
- container_get_box(workspace, &workspace_box);
+ workspace_get_box(workspace, &workspace_box);
if (!wlr_box_contains_point(&workspace_box, center_x, center_y)) {
container_floating_move_to_center(floater);
}
@@ -219,43 +212,37 @@ void arrange_workspace(struct sway_container *workspace) {
}
workspace_add_gaps(workspace);
- container_set_dirty(workspace);
+ node_set_dirty(&workspace->node);
wlr_log(WLR_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name,
workspace->x, workspace->y);
- if (workspace->sway_workspace->fullscreen) {
- struct sway_container *fs = workspace->sway_workspace->fullscreen;
- fs->x = workspace->parent->x;
- fs->y = workspace->parent->y;
- fs->width = workspace->parent->width;
- fs->height = workspace->parent->height;
+ if (workspace->fullscreen) {
+ struct sway_container *fs = workspace->fullscreen;
+ fs->x = output->lx;
+ fs->y = output->ly;
+ fs->width = output->width;
+ fs->height = output->height;
arrange_container(fs);
} else {
struct wlr_box box;
- container_get_box(workspace, &box);
- arrange_children(workspace->children, workspace->layout, &box);
- arrange_floating(workspace->sway_workspace->floating);
+ workspace_get_box(workspace, &box);
+ arrange_children(workspace->tiling, workspace->layout, &box);
+ arrange_floating(workspace->floating);
}
}
-void arrange_output(struct sway_container *output) {
+void arrange_output(struct sway_output *output) {
if (config->reloading) {
return;
}
- if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) {
- return;
- }
const struct wlr_box *output_box = wlr_output_layout_get_box(
- root_container.sway_root->output_layout,
- output->sway_output->wlr_output);
- output->x = output_box->x;
- output->y = output_box->y;
+ root->output_layout, output->wlr_output);
+ output->lx = output_box->x;
+ output->ly = output_box->y;
output->width = output_box->width;
output->height = output_box->height;
- container_set_dirty(output);
- wlr_log(WLR_DEBUG, "Arranging output '%s' at %f,%f",
- output->name, output->x, output->y);
- for (int i = 0; i < output->children->length; ++i) {
- struct sway_container *workspace = output->children->items[i];
+
+ for (int i = 0; i < output->workspaces->length; ++i) {
+ struct sway_workspace *workspace = output->workspaces->items[i];
arrange_workspace(workspace);
}
}
@@ -264,37 +251,31 @@ void arrange_root(void) {
if (config->reloading) {
return;
}
- struct wlr_output_layout *output_layout =
- root_container.sway_root->output_layout;
const struct wlr_box *layout_box =
- wlr_output_layout_get_box(output_layout, NULL);
- root_container.x = layout_box->x;
- root_container.y = layout_box->y;
- root_container.width = layout_box->width;
- root_container.height = layout_box->height;
- container_set_dirty(&root_container);
- for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *output = root_container.children->items[i];
+ wlr_output_layout_get_box(root->output_layout, NULL);
+ root->x = layout_box->x;
+ root->y = layout_box->y;
+ root->width = layout_box->width;
+ root->height = layout_box->height;
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
arrange_output(output);
}
}
-void arrange_windows(struct sway_container *container) {
- switch (container->type) {
- case C_ROOT:
+void arrange_node(struct sway_node *node) {
+ switch (node->type) {
+ case N_ROOT:
arrange_root();
break;
- case C_OUTPUT:
- arrange_output(container);
- break;
- case C_WORKSPACE:
- arrange_workspace(container);
+ case N_OUTPUT:
+ arrange_output(node->sway_output);
break;
- case C_CONTAINER:
- case C_VIEW:
- arrange_container(container);
+ case N_WORKSPACE:
+ arrange_workspace(node->sway_workspace);
break;
- case C_TYPES:
+ case N_CONTAINER:
+ arrange_container(node->sway_container);
break;
}
}
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 520b4566..c91b0361 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -24,97 +24,39 @@
#include "log.h"
#include "stringop.h"
-const char *container_type_to_str(enum sway_container_type type) {
- switch (type) {
- case C_ROOT:
- return "C_ROOT";
- case C_OUTPUT:
- return "C_OUTPUT";
- case C_WORKSPACE:
- return "C_WORKSPACE";
- case C_CONTAINER:
- return "C_CONTAINER";
- case C_VIEW:
- return "C_VIEW";
- default:
- return "C_UNKNOWN";
- }
-}
-
-void container_create_notify(struct sway_container *container) {
- if (container->type == C_VIEW) {
- ipc_event_window(container, "new");
- } else if (container->type == C_WORKSPACE) {
- ipc_event_workspace(NULL, container, "init");
- }
- wl_signal_emit(&root_container.sway_root->events.new_container, container);
-}
-
-void container_update_textures_recursive(struct sway_container *con) {
- if (con->type == C_CONTAINER || con->type == C_VIEW) {
- container_update_title_textures(con);
- }
-
- if (con->type == C_VIEW) {
- view_update_marks_textures(con->sway_view);
- } else {
- for (int i = 0; i < con->children->length; ++i) {
- struct sway_container *child = con->children->items[i];
- container_update_textures_recursive(child);
- }
-
- if (con->type == C_WORKSPACE) {
- for (int i = 0; i < con->sway_workspace->floating->length; ++i) {
- struct sway_container *floater =
- con->sway_workspace->floating->items[i];
- container_update_textures_recursive(floater);
- }
- }
- }
-}
-
-struct sway_container *container_create(enum sway_container_type type) {
- // next id starts at 1 because 0 is assigned to root_container in layout.c
- static size_t next_id = 1;
+struct sway_container *container_create(struct sway_view *view) {
struct sway_container *c = calloc(1, sizeof(struct sway_container));
if (!c) {
+ wlr_log(WLR_ERROR, "Unable to allocate sway_container");
return NULL;
}
- c->id = next_id++;
+ node_init(&c->node, N_CONTAINER, c);
c->layout = L_NONE;
- c->type = type;
+ c->view = view;
c->alpha = 1.0f;
- if (type != C_VIEW) {
+ if (!view) {
c->children = create_list();
c->current.children = create_list();
}
c->outputs = create_list();
wl_signal_init(&c->events.destroy);
-
- c->has_gaps = false;
- c->gaps_inner = 0;
- c->gaps_outer = 0;
- c->current_gaps = 0;
+ wl_signal_emit(&root->events.new_node, &c->node);
return c;
}
void container_destroy(struct sway_container *con) {
- if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW,
- "Expected a container or view")) {
- return;
- }
- if (!sway_assert(con->destroying,
+ if (!sway_assert(con->node.destroying,
"Tried to free container which wasn't marked as destroying")) {
return;
}
- if (!sway_assert(con->ntxnrefs == 0, "Tried to free container "
+ if (!sway_assert(con->node.ntxnrefs == 0, "Tried to free container "
"which is still referenced by transactions")) {
return;
}
- free(con->name);
+ free(con->title);
free(con->formatted_title);
wlr_texture_destroy(con->title_focused);
wlr_texture_destroy(con->title_focused_inactive);
@@ -124,14 +66,14 @@ void container_destroy(struct sway_container *con) {
list_free(con->current.children);
list_free(con->outputs);
- if (con->type == C_VIEW) {
- struct sway_view *view = con->sway_view;
- view->swayc = NULL;
+ if (con->view) {
+ struct sway_view *view = con->view;
+ view->container = NULL;
free(view->title_format);
view->title_format = NULL;
if (view->destroying) {
- view_destroy(view);
+ view_destroy(con->view);
}
}
@@ -139,115 +81,57 @@ void container_destroy(struct sway_container *con) {
}
void container_begin_destroy(struct sway_container *con) {
- if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW,
- "Expected a container or view")) {
- return;
- }
-
- if (con->type == C_VIEW) {
+ if (con->view) {
ipc_event_window(con, "close");
}
- wl_signal_emit(&con->events.destroy, con);
+ wl_signal_emit(&con->node.events.destroy, &con->node);
container_end_mouse_operation(con);
- con->destroying = true;
- container_set_dirty(con);
+ con->node.destroying = true;
+ node_set_dirty(&con->node);
if (con->scratchpad) {
root_scratchpad_remove_container(con);
}
- if (con->parent) {
- container_remove_child(con);
+ if (con->parent || con->workspace) {
+ container_detach(con);
}
}
-struct sway_container *container_reap_empty(struct sway_container *con) {
- while (con && con->type == C_CONTAINER) {
- struct sway_container *next = con->parent;
- if (con->children->length == 0) {
- container_begin_destroy(con);
- }
- con = next;
+void container_reap_empty(struct sway_container *con) {
+ if (con->view) {
+ return;
}
- if (con && con->type == C_WORKSPACE) {
- workspace_consider_destroy(con);
- if (con->destroying) {
- con = con->parent;
+ struct sway_workspace *ws = con->workspace;
+ while (con) {
+ if (con->children->length) {
+ return;
}
+ struct sway_container *parent = con->parent;
+ container_begin_destroy(con);
+ con = parent;
}
- return con;
+ workspace_consider_destroy(ws);
}
struct sway_container *container_flatten(struct sway_container *container) {
- while (container->type == C_CONTAINER && container->children->length == 1) {
+ if (container->view) {
+ return NULL;
+ }
+ while (container && container->children->length == 1) {
struct sway_container *child = container->children->items[0];
struct sway_container *parent = container->parent;
- container_replace_child(container, child);
+ container_replace(container, child);
container_begin_destroy(container);
container = parent;
}
return container;
}
-static void container_close_func(struct sway_container *container, void *data) {
- if (container->type == C_VIEW) {
- view_close(container->sway_view);
- }
-}
-
-struct sway_container *container_close(struct sway_container *con) {
- if (!sway_assert(con != NULL,
- "container_close called with a NULL container")) {
- return NULL;
- }
-
- struct sway_container *parent = con->parent;
-
- if (con->type == C_VIEW) {
- view_close(con->sway_view);
- } else if (con->type == C_CONTAINER) {
- container_for_each_child(con, container_close_func, NULL);
- } else if (con->type == C_WORKSPACE) {
- workspace_for_each_container(con, container_close_func, NULL);
- }
-
- return parent;
-}
-
-struct sway_container *container_view_create(struct sway_container *sibling,
- struct sway_view *sway_view) {
- if (!sway_assert(sibling,
- "container_view_create called with NULL sibling/parent")) {
- return NULL;
- }
- const char *title = view_get_title(sway_view);
- struct sway_container *swayc = container_create(C_VIEW);
- wlr_log(WLR_DEBUG, "Adding new view %p:%s to container %p %d %s",
- swayc, title, sibling, sibling ? sibling->type : 0, sibling->name);
- // Setup values
- swayc->sway_view = sway_view;
- swayc->width = 0;
- swayc->height = 0;
-
- if (sibling->type == C_WORKSPACE) {
- // Case of focused workspace, just create as child of it
- container_add_child(sibling, swayc);
- } else {
- // Regular case, create as sibling of current container
- container_add_sibling(sibling, swayc);
- }
- container_create_notify(swayc);
- return swayc;
-}
-
struct sway_container *container_find_child(struct sway_container *container,
- bool (*test)(struct sway_container *view, void *data), void *data) {
- if (!sway_assert(container->type == C_CONTAINER ||
- container->type == C_VIEW, "Expected a container or view")) {
- return NULL;
- }
+ bool (*test)(struct sway_container *con, void *data), void *data) {
if (!container->children) {
return NULL;
}
@@ -264,46 +148,32 @@ struct sway_container *container_find_child(struct sway_container *container,
return NULL;
}
-struct sway_container *container_parent(struct sway_container *container,
- enum sway_container_type type) {
- if (!sway_assert(container, "container is NULL")) {
- return NULL;
- }
- if (!sway_assert(type < C_TYPES && type >= C_ROOT, "invalid type")) {
- return NULL;
- }
- do {
- container = container->parent;
- } while (container && container->type != type);
- return container;
-}
-
-static void surface_at_view(struct sway_container *swayc, double lx, double ly,
+static void surface_at_view(struct sway_container *con, double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy) {
- if (!sway_assert(swayc->type == C_VIEW, "Expected a view")) {
+ if (!sway_assert(con->view, "Expected a view")) {
return;
}
- struct sway_view *sview = swayc->sway_view;
- double view_sx = lx - sview->x + sview->geometry.x;
- double view_sy = ly - sview->y + sview->geometry.y;
+ struct sway_view *view = con->view;
+ double view_sx = lx - view->x + view->geometry.x;
+ double view_sy = ly - view->y + view->geometry.y;
double _sx, _sy;
struct wlr_surface *_surface = NULL;
- switch (sview->type) {
+ switch (view->type) {
#ifdef HAVE_XWAYLAND
case SWAY_VIEW_XWAYLAND:
- _surface = wlr_surface_surface_at(sview->surface,
+ _surface = wlr_surface_surface_at(view->surface,
view_sx, view_sy, &_sx, &_sy);
break;
#endif
case SWAY_VIEW_XDG_SHELL_V6:
_surface = wlr_xdg_surface_v6_surface_at(
- sview->wlr_xdg_surface_v6,
+ view->wlr_xdg_surface_v6,
view_sx, view_sy, &_sx, &_sy);
break;
case SWAY_VIEW_XDG_SHELL:
_surface = wlr_xdg_surface_surface_at(
- sview->wlr_xdg_surface,
+ view->wlr_xdg_surface,
view_sx, view_sy, &_sx, &_sy);
break;
}
@@ -317,65 +187,72 @@ static void surface_at_view(struct sway_container *swayc, double lx, double ly,
/**
* container_at for a container with layout L_TABBED.
*/
-static struct sway_container *container_at_tabbed(struct sway_container *parent,
+static struct sway_container *container_at_tabbed(struct sway_node *parent,
double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy) {
- if (ly < parent->y || ly > parent->y + parent->height) {
+ struct wlr_box box;
+ node_get_box(parent, &box);
+ if (ly < box.y || ly > box.y + box.height) {
return NULL;
}
struct sway_seat *seat = input_manager_current_seat(input_manager);
+ list_t *children = node_get_children(parent);
// Tab titles
int title_height = container_titlebar_height();
- if (ly < parent->y + title_height) {
- int tab_width = parent->width / parent->children->length;
- int child_index = (lx - parent->x) / tab_width;
- if (child_index >= parent->children->length) {
- child_index = parent->children->length - 1;
+ if (ly < box.y + title_height) {
+ int tab_width = box.width / children->length;
+ int child_index = (lx - box.x) / tab_width;
+ if (child_index >= children->length) {
+ child_index = children->length - 1;
}
- struct sway_container *child = parent->children->items[child_index];
- return seat_get_focus_inactive(seat, child);
+ struct sway_container *child = children->items[child_index];
+ struct sway_node *node = seat_get_focus_inactive(seat, &child->node);
+ return node->sway_container;
}
// Surfaces
- struct sway_container *current = seat_get_active_child(seat, parent);
-
+ struct sway_node *current = seat_get_active_child(seat, parent);
return tiling_container_at(current, lx, ly, surface, sx, sy);
}
/**
* container_at for a container with layout L_STACKED.
*/
-static struct sway_container *container_at_stacked(
- struct sway_container *parent, double lx, double ly,
+static struct sway_container *container_at_stacked(struct sway_node *parent,
+ double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy) {
- if (ly < parent->y || ly > parent->y + parent->height) {
+ struct wlr_box box;
+ node_get_box(parent, &box);
+ if (ly < box.y || ly > box.y + box.height) {
return NULL;
}
struct sway_seat *seat = input_manager_current_seat(input_manager);
+ list_t *children = node_get_children(parent);
// Title bars
int title_height = container_titlebar_height();
- int child_index = (ly - parent->y) / title_height;
- if (child_index < parent->children->length) {
- struct sway_container *child = parent->children->items[child_index];
- return seat_get_focus_inactive(seat, child);
+ int child_index = (ly - box.y) / title_height;
+ if (child_index < children->length) {
+ struct sway_container *child = children->items[child_index];
+ struct sway_node *node = seat_get_focus_inactive(seat, &child->node);
+ return node->sway_container;
}
// Surfaces
- struct sway_container *current = seat_get_active_child(seat, parent);
-
+ struct sway_node *current = seat_get_active_child(seat, parent);
return tiling_container_at(current, lx, ly, surface, sx, sy);
}
/**
* container_at for a container with layout L_HORIZ or L_VERT.
*/
-static struct sway_container *container_at_linear(struct sway_container *parent,
+static struct sway_container *container_at_linear(struct sway_node *parent,
double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy) {
- for (int i = 0; i < parent->children->length; ++i) {
- struct sway_container *child = parent->children->items[i];
+ list_t *children = node_get_children(parent);
+ for (int i = 0; i < children->length; ++i) {
+ struct sway_container *child = children->items[i];
struct wlr_box box = {
.x = child->x,
.y = child->y,
@@ -383,7 +260,7 @@ static struct sway_container *container_at_linear(struct sway_container *parent,
.height = child->height,
};
if (wlr_box_contains_point(&box, lx, ly)) {
- return tiling_container_at(child, lx, ly, surface, sx, sy);
+ return tiling_container_at(&child->node, lx, ly, surface, sx, sy);
}
}
return NULL;
@@ -391,12 +268,11 @@ static struct sway_container *container_at_linear(struct sway_container *parent,
static struct sway_container *floating_container_at(double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy) {
- for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *output = root_container.children->items[i];
- for (int j = 0; j < output->children->length; ++j) {
- struct sway_container *workspace = output->children->items[j];
- struct sway_workspace *ws = workspace->sway_workspace;
- if (!workspace_is_visible(workspace)) {
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
+ for (int j = 0; j < output->workspaces->length; ++j) {
+ struct sway_workspace *ws = output->workspaces->items[j];
+ if (!workspace_is_visible(ws)) {
continue;
}
// Items at the end of the list are on top, so iterate the list in
@@ -410,7 +286,7 @@ static struct sway_container *floating_container_at(double lx, double ly,
.height = floater->height,
};
if (wlr_box_contains_point(&box, lx, ly)) {
- return tiling_container_at(floater, lx, ly,
+ return tiling_container_at(&floater->node, lx, ly,
surface, sx, sy);
}
}
@@ -419,25 +295,24 @@ static struct sway_container *floating_container_at(double lx, double ly,
return NULL;
}
-struct sway_container *tiling_container_at(
- struct sway_container *con, double lx, double ly,
+struct sway_container *tiling_container_at(struct sway_node *parent,
+ double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy) {
- if (con->type == C_VIEW) {
- surface_at_view(con, lx, ly, surface, sx, sy);
- return con;
+ if (node_is_view(parent)) {
+ surface_at_view(parent->sway_container, lx, ly, surface, sx, sy);
+ return parent->sway_container;
}
- if (!con->children->length) {
+ if (!node_get_children(parent)) {
return NULL;
}
-
- switch (con->layout) {
+ switch (node_get_layout(parent)) {
case L_HORIZ:
case L_VERT:
- return container_at_linear(con, lx, ly, surface, sx, sy);
+ return container_at_linear(parent, lx, ly, surface, sx, sy);
case L_TABBED:
- return container_at_tabbed(con, lx, ly, surface, sx, sy);
+ return container_at_tabbed(parent, lx, ly, surface, sx, sy);
case L_STACKED:
- return container_at_stacked(con, lx, ly, surface, sx, sy);
+ return container_at_stacked(parent, lx, ly, surface, sx, sy);
case L_NONE:
return NULL;
}
@@ -472,19 +347,16 @@ static bool surface_is_popup(struct wlr_surface *surface) {
return false;
}
-struct sway_container *container_at(struct sway_container *workspace,
+struct sway_container *container_at(struct sway_workspace *workspace,
double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy) {
- if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) {
- return NULL;
- }
struct sway_container *c;
+ // Focused view's popups
struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus =
- seat_get_focus_inactive(seat, &root_container);
+ struct sway_container *focus = seat_get_focused_container(seat);
bool is_floating = focus && container_is_floating_or_child(focus);
// Focused view's popups
- if (focus && focus->type == C_VIEW) {
+ if (focus && focus->view) {
surface_at_view(focus, lx, ly, surface, sx, sy);
if (*surface && surface_is_popup(*surface)) {
return focus;
@@ -492,7 +364,7 @@ struct sway_container *container_at(struct sway_container *workspace,
*surface = NULL;
}
// If focused is floating, focused view's non-popups
- if (focus && focus->type == C_VIEW && is_floating) {
+ if (focus && focus->view && is_floating) {
surface_at_view(focus, lx, ly, surface, sx, sy);
if (*surface) {
return focus;
@@ -504,7 +376,7 @@ struct sway_container *container_at(struct sway_container *workspace,
return c;
}
// If focused is tiling, focused view's non-popups
- if (focus && focus->type == C_VIEW && !is_floating) {
+ if (focus && focus->view && !is_floating) {
surface_at_view(focus, lx, ly, surface, sx, sy);
if (*surface) {
return focus;
@@ -512,7 +384,7 @@ struct sway_container *container_at(struct sway_container *workspace,
*surface = NULL;
}
// Tiling (non-focused)
- if ((c = tiling_container_at(workspace, lx, ly, surface, sx, sy))) {
+ if ((c = tiling_container_at(&workspace->node, lx, ly, surface, sx, sy))) {
return c;
}
return NULL;
@@ -521,10 +393,6 @@ struct sway_container *container_at(struct sway_container *workspace,
void container_for_each_child(struct sway_container *container,
void (*f)(struct sway_container *container, void *data),
void *data) {
- if (!sway_assert(container->type == C_CONTAINER ||
- container->type == C_VIEW, "Expected a container or view")) {
- return;
- }
if (container->children) {
for (int i = 0; i < container->children->length; ++i) {
struct sway_container *child = container->children->items[i];
@@ -536,7 +404,7 @@ void container_for_each_child(struct sway_container *container,
bool container_has_ancestor(struct sway_container *descendant,
struct sway_container *ancestor) {
- while (descendant && descendant->type != C_ROOT) {
+ while (descendant) {
descendant = descendant->parent;
if (descendant == ancestor) {
return true;
@@ -545,27 +413,10 @@ bool container_has_ancestor(struct sway_container *descendant,
return false;
}
-int container_count_descendants_of_type(struct sway_container *con,
- enum sway_container_type type) {
- int children = 0;
- if (con->type == type) {
- children++;
- }
- if (con->children) {
- for (int i = 0; i < con->children->length; i++) {
- struct sway_container *child = con->children->items[i];
- children += container_count_descendants_of_type(child, type);
- }
- }
- return children;
-}
-
void container_damage_whole(struct sway_container *container) {
- for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *cont = root_container.children->items[i];
- if (cont->type == C_OUTPUT) {
- output_damage_whole_container(cont->sway_output, container);
- }
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
+ output_damage_whole_container(output, container);
}
}
@@ -582,10 +433,6 @@ struct sway_output *container_get_effective_output(struct sway_container *con) {
static void update_title_texture(struct sway_container *con,
struct wlr_texture **texture, struct border_colors *class) {
- if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW,
- "Unexpected type %s", container_type_to_str(con->type))) {
- return;
- }
struct sway_output *output = container_get_effective_output(con);
if (!output) {
return;
@@ -664,9 +511,10 @@ void container_calculate_title_height(struct sway_container *container) {
* An example tree representation is: V[Terminal, Firefox]
* If buffer is not NULL, also populate the buffer with the representation.
*/
-static size_t get_tree_representation(struct sway_container *parent, char *buffer) {
+size_t container_build_representation(enum sway_container_layout layout,
+ list_t *children, char *buffer) {
size_t len = 2;
- switch (parent->layout) {
+ switch (layout) {
case L_VERT:
lenient_strcat(buffer, "V[");
break;
@@ -683,17 +531,17 @@ static size_t get_tree_representation(struct sway_container *parent, char *buffe
lenient_strcat(buffer, "D[");
break;
}
- for (int i = 0; i < parent->children->length; ++i) {
+ for (int i = 0; i < children->length; ++i) {
if (i != 0) {
++len;
lenient_strcat(buffer, " ");
}
- struct sway_container *child = parent->children->items[i];
+ struct sway_container *child = children->items[i];
const char *identifier = NULL;
- if (child->type == C_VIEW) {
- identifier = view_get_class(child->sway_view);
+ if (child->view) {
+ identifier = view_get_class(child->view);
if (!identifier) {
- identifier = view_get_app_id(child->sway_view);
+ identifier = view_get_app_id(child->view);
}
} else {
identifier = child->formatted_title;
@@ -711,25 +559,25 @@ static size_t get_tree_representation(struct sway_container *parent, char *buffe
return len;
}
-void container_notify_subtree_changed(struct sway_container *container) {
- if (!container || container->type < C_WORKSPACE) {
- return;
- }
- free(container->formatted_title);
- container->formatted_title = NULL;
-
- size_t len = get_tree_representation(container, NULL);
- char *buffer = calloc(len + 1, sizeof(char));
- if (!sway_assert(buffer, "Unable to allocate title string")) {
- return;
+void container_update_representation(struct sway_container *con) {
+ if (!con->view) {
+ size_t len = container_build_representation(con->layout,
+ con->children, NULL);
+ free(con->formatted_title);
+ con->formatted_title = calloc(len + 1, sizeof(char));
+ if (!sway_assert(con->formatted_title,
+ "Unable to allocate title string")) {
+ return;
+ }
+ container_build_representation(con->layout, con->children,
+ con->formatted_title);
+ container_calculate_title_height(con);
+ container_update_title_textures(con);
}
- get_tree_representation(container, buffer);
-
- container->formatted_title = buffer;
- if (container->type != C_WORKSPACE) {
- container_calculate_title_height(container);
- container_update_title_textures(container);
- container_notify_subtree_changed(container->parent);
+ if (con->parent) {
+ container_update_representation(con->parent);
+ } else if (con->workspace) {
+ workspace_update_representation(con->workspace);
}
}
@@ -738,11 +586,7 @@ size_t container_titlebar_height() {
}
void container_init_floating(struct sway_container *con) {
- if (!sway_assert(con->type == C_VIEW || con->type == C_CONTAINER,
- "Expected a view or container")) {
- return;
- }
- struct sway_container *ws = container_parent(con, C_WORKSPACE);
+ struct sway_workspace *ws = con->workspace;
int min_width, min_height;
int max_width, max_height;
@@ -778,13 +622,13 @@ void container_init_floating(struct sway_container *con) {
max_height = config->floating_maximum_height;
}
- if (con->type == C_CONTAINER) {
+ if (!con->view) {
con->width = max_width;
con->height = max_height;
con->x = ws->x + (ws->width - con->width) / 2;
con->y = ws->y + (ws->height - con->height) / 2;
} else {
- struct sway_view *view = con->sway_view;
+ struct sway_view *view = con->view;
view->width = fmax(min_width, fmin(view->natural_width, max_width));
view->height = fmax(min_height, fmin(view->natural_height, max_height));
view->x = ws->x + (ws->width - view->width) / 2;
@@ -794,7 +638,7 @@ void container_init_floating(struct sway_container *con) {
view->border_top = view->border_bottom = true;
view->border_left = view->border_right = true;
- container_set_geometry_from_floating_view(view->swayc);
+ container_set_geometry_from_floating_view(con);
}
}
@@ -804,32 +648,41 @@ void container_set_floating(struct sway_container *container, bool enable) {
}
struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *workspace = container_parent(container, C_WORKSPACE);
+ struct sway_workspace *workspace = container->workspace;
if (enable) {
- struct sway_container *old_parent = container_remove_child(container);
+ struct sway_container *old_parent = container->parent;
+ container_detach(container);
workspace_add_floating(workspace, container);
container_init_floating(container);
- if (container->type == C_VIEW) {
- view_set_tiled(container->sway_view, false);
+ if (container->view) {
+ view_set_tiled(container->view, false);
+ }
+ if (old_parent) {
+ container_reap_empty(old_parent);
}
- container_reap_empty(old_parent);
} else {
// Returning to tiled
if (container->scratchpad) {
root_scratchpad_remove_container(container);
}
- container_remove_child(container);
+ container_detach(container);
struct sway_container *reference =
seat_get_focus_inactive_tiling(seat, workspace);
- if (reference->type == C_VIEW) {
+ if (reference && reference->view) {
reference = reference->parent;
}
- container_add_child(reference, container);
- container->width = container->parent->width;
- container->height = container->parent->height;
- if (container->type == C_VIEW) {
- view_set_tiled(container->sway_view, true);
+ if (reference) {
+ container_add_child(reference, container);
+ container->width = reference->width;
+ container->height = reference->height;
+ } else {
+ workspace_add_tiling(workspace, container);
+ container->width = workspace->width;
+ container->height = workspace->height;
+ }
+ if (container->view) {
+ view_set_tiled(container->view, true);
}
container->is_sticky = false;
}
@@ -840,14 +693,13 @@ void container_set_floating(struct sway_container *container, bool enable) {
}
void container_set_geometry_from_floating_view(struct sway_container *con) {
- if (!sway_assert(con->type == C_VIEW, "Expected a view")) {
+ if (!sway_assert(con->view, "Expected a view")) {
return;
}
- if (!sway_assert(container_is_floating(con),
- "Expected a floating view")) {
+ if (!sway_assert(container_is_floating(con), "Expected a floating view")) {
return;
}
- struct sway_view *view = con->sway_view;
+ struct sway_view *view = con->view;
size_t border_width = 0;
size_t top = 0;
@@ -861,12 +713,12 @@ void container_set_geometry_from_floating_view(struct sway_container *con) {
con->y = view->y - top;
con->width = view->width + border_width * 2;
con->height = top + view->height + border_width;
- container_set_dirty(con);
+ node_set_dirty(&con->node);
}
bool container_is_floating(struct sway_container *container) {
- return container->parent && container->parent->type == C_WORKSPACE &&
- list_find(container->parent->sway_workspace->floating, container) != -1;
+ return !container->parent && container->workspace &&
+ list_find(container->workspace->floating, container) != -1;
}
void container_get_box(struct sway_container *container, struct wlr_box *box) {
@@ -883,16 +735,16 @@ void container_floating_translate(struct sway_container *con,
double x_amount, double y_amount) {
con->x += x_amount;
con->y += y_amount;
- if (con->type == C_VIEW) {
- con->sway_view->x += x_amount;
- con->sway_view->y += y_amount;
+ if (con->view) {
+ con->view->x += x_amount;
+ con->view->y += y_amount;
} else {
for (int i = 0; i < con->children->length; ++i) {
struct sway_container *child = con->children->items[i];
container_floating_translate(child, x_amount, y_amount);
}
}
- container_set_dirty(con);
+ node_set_dirty(&con->node);
}
/**
@@ -902,17 +754,16 @@ void container_floating_translate(struct sway_container *con,
* one, otherwise we'll choose whichever output is closest to the container's
* center.
*/
-struct sway_container *container_floating_find_output(
- struct sway_container *con) {
+struct sway_output *container_floating_find_output(struct sway_container *con) {
double center_x = con->x + con->width / 2;
double center_y = con->y + con->height / 2;
- struct sway_container *closest_output = NULL;
+ struct sway_output *closest_output = NULL;
double closest_distance = DBL_MAX;
- for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *output = root_container.children->items[i];
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
struct wlr_box output_box;
double closest_x, closest_y;
- container_get_box(output, &output_box);
+ output_get_box(output, &output_box);
wlr_box_closest_point(&output_box, center_x, center_y,
&closest_x, &closest_y);
if (center_x == closest_x && center_y == closest_y) {
@@ -937,18 +788,18 @@ void container_floating_move_to(struct sway_container *con,
return;
}
container_floating_translate(con, lx - con->x, ly - con->y);
- struct sway_container *old_workspace = container_parent(con, C_WORKSPACE);
- struct sway_container *new_output = container_floating_find_output(con);
+ struct sway_workspace *old_workspace = con->workspace;
+ struct sway_output *new_output = container_floating_find_output(con);
if (!sway_assert(new_output, "Unable to find any output")) {
return;
}
- struct sway_container *new_workspace =
- output_get_active_workspace(new_output->sway_output);
+ struct sway_workspace *new_workspace =
+ output_get_active_workspace(new_output);
if (old_workspace != new_workspace) {
- container_remove_child(con);
+ container_detach(con);
workspace_add_floating(new_workspace, con);
- arrange_windows(old_workspace);
- arrange_windows(new_workspace);
+ arrange_workspace(old_workspace);
+ arrange_workspace(new_workspace);
workspace_detect_urgent(old_workspace);
workspace_detect_urgent(new_workspace);
}
@@ -959,22 +810,14 @@ void container_floating_move_to_center(struct sway_container *con) {
"Expected a floating container")) {
return;
}
- struct sway_container *ws = container_parent(con, C_WORKSPACE);
+ struct sway_workspace *ws = con->workspace;
double new_lx = ws->x + (ws->width - con->width) / 2;
double new_ly = ws->y + (ws->height - con->height) / 2;
container_floating_translate(con, new_lx - con->x, new_ly - con->y);
}
-void container_set_dirty(struct sway_container *container) {
- if (container->dirty) {
- return;
- }
- container->dirty = true;
- list_add(server.dirty_containers, container);
-}
-
static bool find_urgent_iterator(struct sway_container *con, void *data) {
- return con->type == C_VIEW && view_is_urgent(con->sway_view);
+ return con->view && view_is_urgent(con->view);
}
bool container_has_urgent_child(struct sway_container *container) {
@@ -991,12 +834,12 @@ void container_end_mouse_operation(struct sway_container *container) {
}
static void set_fullscreen_iterator(struct sway_container *con, void *data) {
- if (con->type != C_VIEW) {
+ if (!con->view) {
return;
}
- if (con->sway_view->impl->set_fullscreen) {
+ if (con->view->impl->set_fullscreen) {
bool *enable = data;
- con->sway_view->impl->set_fullscreen(con->sway_view, *enable);
+ con->view->impl->set_fullscreen(con->view, *enable);
}
}
@@ -1005,9 +848,9 @@ void container_set_fullscreen(struct sway_container *container, bool enable) {
return;
}
- struct sway_container *workspace = container_parent(container, C_WORKSPACE);
- if (enable && workspace->sway_workspace->fullscreen) {
- container_set_fullscreen(workspace->sway_workspace->fullscreen, false);
+ struct sway_workspace *workspace = container->workspace;
+ if (enable && workspace->fullscreen) {
+ container_set_fullscreen(workspace->fullscreen, false);
}
set_fullscreen_iterator(container, &enable);
@@ -1016,36 +859,32 @@ void container_set_fullscreen(struct sway_container *container, bool enable) {
container->is_fullscreen = enable;
if (enable) {
- workspace->sway_workspace->fullscreen = container;
+ workspace->fullscreen = container;
container->saved_x = container->x;
container->saved_y = container->y;
container->saved_width = container->width;
container->saved_height = container->height;
struct sway_seat *seat;
- struct sway_container *focus, *focus_ws;
+ struct sway_workspace *focus_ws;
wl_list_for_each(seat, &input_manager->seats, link) {
- focus = seat_get_focus(seat);
- if (focus) {
- focus_ws = focus;
- if (focus_ws->type != C_WORKSPACE) {
- focus_ws = container_parent(focus_ws, C_WORKSPACE);
- }
+ focus_ws = seat_get_focused_workspace(seat);
+ if (focus_ws) {
if (focus_ws == workspace) {
- seat_set_focus(seat, container);
+ seat_set_focus(seat, &container->node);
}
}
}
} else {
- workspace->sway_workspace->fullscreen = NULL;
+ workspace->fullscreen = NULL;
if (container_is_floating(container)) {
container->x = container->saved_x;
container->y = container->saved_y;
container->width = container->saved_width;
container->height = container->saved_height;
- struct sway_container *output =
+ struct sway_output *output =
container_floating_find_output(container);
- if (!container_has_ancestor(container, output)) {
+ if (workspace->output != output) {
container_floating_move_to_center(container);
}
} else {
@@ -1060,7 +899,7 @@ void container_set_fullscreen(struct sway_container *container, bool enable) {
}
bool container_is_floating_or_child(struct sway_container *container) {
- while (container->parent && container->parent->type != C_WORKSPACE) {
+ while (container->parent) {
container = container->parent;
}
return container_is_floating(container);
@@ -1072,7 +911,7 @@ bool container_is_fullscreen_or_child(struct sway_container *container) {
return true;
}
container = container->parent;
- } while (container && container->type != C_WORKSPACE);
+ } while (container);
return false;
}
@@ -1090,42 +929,37 @@ static void surface_send_leave_iterator(struct wlr_surface *surface,
}
void container_discover_outputs(struct sway_container *con) {
- if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW,
- "Expected a container or view")) {
- return;
- }
struct wlr_box con_box = {
- .x = con->current.swayc_x,
- .y = con->current.swayc_y,
- .width = con->current.swayc_width,
- .height = con->current.swayc_height,
+ .x = con->current.con_x,
+ .y = con->current.con_y,
+ .width = con->current.con_width,
+ .height = con->current.con_height,
};
struct sway_output *old_output = container_get_effective_output(con);
- for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *output = root_container.children->items[i];
- struct sway_output *sway_output = output->sway_output;
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
struct wlr_box output_box;
- container_get_box(output, &output_box);
+ output_get_box(output, &output_box);
struct wlr_box intersection;
bool intersects =
wlr_box_intersection(&con_box, &output_box, &intersection);
- int index = list_find(con->outputs, sway_output);
+ int index = list_find(con->outputs, output);
if (intersects && index == -1) {
// Send enter
- wlr_log(WLR_DEBUG, "Con %p entered output %p", con, sway_output);
- if (con->type == C_VIEW) {
- view_for_each_surface(con->sway_view,
- surface_send_enter_iterator, sway_output->wlr_output);
+ wlr_log(WLR_DEBUG, "Container %p entered output %p", con, output);
+ if (con->view) {
+ view_for_each_surface(con->view,
+ surface_send_enter_iterator, output->wlr_output);
}
- list_add(con->outputs, sway_output);
+ list_add(con->outputs, output);
} else if (!intersects && index != -1) {
// Send leave
- wlr_log(WLR_DEBUG, "Con %p left output %p", con, sway_output);
- if (con->type == C_VIEW) {
- view_for_each_surface(con->sway_view,
- surface_send_leave_iterator, sway_output->wlr_output);
+ wlr_log(WLR_DEBUG, "Container %p left output %p", con, output);
+ if (con->view) {
+ view_for_each_surface(con->view,
+ surface_send_leave_iterator, output->wlr_output);
}
list_del(con->outputs, index);
}
@@ -1135,17 +969,13 @@ void container_discover_outputs(struct sway_container *con) {
double new_scale = new_output ? new_output->wlr_output->scale : -1;
if (old_scale != new_scale) {
container_update_title_textures(con);
- if (con->type == C_VIEW) {
- view_update_marks_textures(con->sway_view);
+ if (con->view) {
+ view_update_marks_textures(con->view);
}
}
}
void container_remove_gaps(struct sway_container *c) {
- if (!sway_assert(c->type == C_CONTAINER || c->type == C_VIEW,
- "Expected a container or view")) {
- return;
- }
if (c->current_gaps == 0) {
return;
}
@@ -1158,25 +988,20 @@ void container_remove_gaps(struct sway_container *c) {
}
void container_add_gaps(struct sway_container *c) {
- if (!sway_assert(c->type == C_CONTAINER || c->type == C_VIEW,
- "Expected a container or view")) {
- return;
- }
if (c->current_gaps > 0) {
return;
}
// Linear containers don't have gaps because it'd create double gaps
- if (c->type == C_CONTAINER &&
- c->layout != L_TABBED && c->layout != L_STACKED) {
+ if (!c->view && c->layout != L_TABBED && c->layout != L_STACKED) {
return;
}
// Children of tabbed/stacked containers re-use the gaps of the container
- enum sway_container_layout layout = c->parent->layout;
+ enum sway_container_layout layout = container_parent_layout(c);
if (layout == L_TABBED || layout == L_STACKED) {
return;
}
- struct sway_container *ws = container_parent(c, C_WORKSPACE);
+ struct sway_workspace *ws = c->workspace;
c->current_gaps = ws->has_gaps ? ws->gaps_inner : config->gaps_inner;
c->x += c->current_gaps;
@@ -1185,222 +1010,158 @@ void container_add_gaps(struct sway_container *c) {
c->height -= 2 * c->current_gaps;
}
-int container_sibling_index(const struct sway_container *child) {
- return list_find(child->parent->children, child);
+enum sway_container_layout container_parent_layout(struct sway_container *con) {
+ if (con->parent) {
+ return con->parent->layout;
+ }
+ return con->workspace->layout;
}
-void container_handle_fullscreen_reparent(struct sway_container *con,
- struct sway_container *old_parent) {
- if (!con->is_fullscreen) {
- return;
+enum sway_container_layout container_current_parent_layout(
+ struct sway_container *con) {
+ if (con->current.parent) {
+ return con->current.parent->current.layout;
}
- struct sway_container *old_workspace = old_parent;
- if (old_workspace && old_workspace->type != C_WORKSPACE) {
- old_workspace = container_parent(old_workspace, C_WORKSPACE);
+ return con->current.workspace->current.layout;
+}
+
+list_t *container_get_siblings(const struct sway_container *container) {
+ if (container->parent) {
+ return container->parent->children;
}
- struct sway_container *new_workspace = container_parent(con, C_WORKSPACE);
- if (old_workspace == new_workspace) {
- return;
+ if (!container->workspace) {
+ return NULL;
}
- // Unmark the old workspace as fullscreen
- if (old_workspace) {
- old_workspace->sway_workspace->fullscreen = NULL;
+ if (list_find(container->workspace->tiling, container) != -1) {
+ return container->workspace->tiling;
}
+ return container->workspace->floating;
+}
- // Mark the new workspace as fullscreen
- if (new_workspace->sway_workspace->fullscreen) {
- container_set_fullscreen(
- new_workspace->sway_workspace->fullscreen, false);
- }
- new_workspace->sway_workspace->fullscreen = con;
+int container_sibling_index(const struct sway_container *child) {
+ return list_find(container_get_siblings(child), child);
+}
- // Resize container to new output dimensions
- struct sway_container *output = new_workspace->parent;
- con->x = output->x;
- con->y = output->y;
- con->width = output->width;
- con->height = output->height;
+list_t *container_get_current_siblings(struct sway_container *container) {
+ if (container->current.parent) {
+ return container->current.parent->current.children;
+ }
+ return container->current.workspace->current.tiling;
+}
- if (con->type == C_VIEW) {
- struct sway_view *view = con->sway_view;
- view->x = output->x;
- view->y = output->y;
- view->width = output->width;
- view->height = output->height;
- } else {
- arrange_windows(new_workspace);
+void container_handle_fullscreen_reparent(struct sway_container *con) {
+ if (!con->is_fullscreen || con->workspace->fullscreen == con) {
+ return;
}
+ if (con->workspace->fullscreen) {
+ container_set_fullscreen(con->workspace->fullscreen, false);
+ }
+ con->workspace->fullscreen = con;
+
+ arrange_workspace(con->workspace);
+}
+
+static void set_workspace(struct sway_container *container, void *data) {
+ container->workspace = container->parent->workspace;
}
void container_insert_child(struct sway_container *parent,
struct sway_container *child, int i) {
- struct sway_container *old_parent = child->parent;
- if (old_parent) {
- container_remove_child(child);
+ if (child->workspace) {
+ container_detach(child);
}
- wlr_log(WLR_DEBUG, "Inserting id:%zd at index %d", child->id, i);
list_insert(parent->children, i, child);
child->parent = parent;
- container_handle_fullscreen_reparent(child, old_parent);
+ child->workspace = parent->workspace;
+ container_for_each_child(child, set_workspace, NULL);
+ container_handle_fullscreen_reparent(child);
+ container_update_representation(parent);
}
-struct sway_container *container_add_sibling(struct sway_container *fixed,
+void container_add_sibling(struct sway_container *fixed,
struct sway_container *active) {
- // TODO handle floating
- struct sway_container *old_parent = NULL;
- if (active->parent) {
- old_parent = active->parent;
- container_remove_child(active);
- }
- struct sway_container *parent = fixed->parent;
- int i = container_sibling_index(fixed);
- list_insert(parent->children, i + 1, active);
- active->parent = parent;
- container_handle_fullscreen_reparent(active, old_parent);
- return active->parent;
+ if (active->workspace) {
+ container_detach(active);
+ }
+ list_t *siblings = container_get_siblings(fixed);
+ int index = list_find(siblings, fixed);
+ list_insert(siblings, index + 1, active);
+ active->parent = fixed->parent;
+ active->workspace = fixed->workspace;
+ container_for_each_child(active, set_workspace, NULL);
+ container_handle_fullscreen_reparent(active);
+ container_update_representation(active);
}
void container_add_child(struct sway_container *parent,
struct sway_container *child) {
- wlr_log(WLR_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)",
- child, child->type, child->width, child->height,
- parent, parent->type, parent->width, parent->height);
- struct sway_container *old_parent = child->parent;
+ if (child->workspace) {
+ container_detach(child);
+ }
list_add(parent->children, child);
child->parent = parent;
- container_handle_fullscreen_reparent(child, old_parent);
- if (old_parent) {
- container_set_dirty(old_parent);
- }
- container_set_dirty(child);
+ child->workspace = parent->workspace;
+ container_for_each_child(child, set_workspace, NULL);
+ container_handle_fullscreen_reparent(child);
+ container_update_representation(parent);
+ node_set_dirty(&child->node);
+ node_set_dirty(&parent->node);
}
-struct sway_container *container_remove_child(struct sway_container *child) {
+void container_detach(struct sway_container *child) {
if (child->is_fullscreen) {
- struct sway_container *workspace = container_parent(child, C_WORKSPACE);
- workspace->sway_workspace->fullscreen = NULL;
+ child->workspace->fullscreen = NULL;
}
- struct sway_container *parent = child->parent;
- list_t *list = container_is_floating(child) ?
- parent->sway_workspace->floating : parent->children;
- int index = list_find(list, child);
- if (index != -1) {
- list_del(list, index);
+ struct sway_container *old_parent = child->parent;
+ struct sway_workspace *old_workspace = child->workspace;
+ list_t *siblings = container_get_siblings(child);
+ if (siblings) {
+ int index = list_find(siblings, child);
+ if (index != -1) {
+ list_del(siblings, index);
+ }
}
child->parent = NULL;
- container_notify_subtree_changed(parent);
+ child->workspace = NULL;
+ container_for_each_child(child, set_workspace, NULL);
- container_set_dirty(parent);
- container_set_dirty(child);
-
- return parent;
-}
-
-enum sway_container_layout container_get_default_layout(
- struct sway_container *con) {
- if (con->type != C_OUTPUT) {
- con = container_parent(con, C_OUTPUT);
- }
-
- if (!sway_assert(con != NULL,
- "container_get_default_layout must be called on an attached"
- " container below the root container")) {
- return 0;
- }
-
- if (config->default_layout != L_NONE) {
- return config->default_layout;
- } else if (config->default_orientation != L_NONE) {
- return config->default_orientation;
- } else if (con->width >= con->height) {
- return L_HORIZ;
- } else {
- return L_VERT;
+ if (old_parent) {
+ container_update_representation(old_parent);
+ node_set_dirty(&old_parent->node);
+ } else if (old_workspace) {
+ workspace_update_representation(old_workspace);
+ node_set_dirty(&old_workspace->node);
}
+ node_set_dirty(&child->node);
}
-struct sway_container *container_replace_child(struct sway_container *child,
- struct sway_container *new_child) {
- struct sway_container *parent = child->parent;
- if (parent == NULL) {
- return NULL;
- }
-
- list_t *list = container_is_floating(child) ?
- parent->sway_workspace->floating : parent->children;
- int i = list_find(list, child);
-
- if (new_child->parent) {
- container_remove_child(new_child);
- }
- list->items[i] = new_child;
- new_child->parent = parent;
- child->parent = NULL;
-
- // Set geometry for new child
- new_child->x = child->x;
- new_child->y = child->y;
- new_child->width = child->width;
- new_child->height = child->height;
-
- // reset geometry for child
- child->width = 0;
- child->height = 0;
-
- return parent;
+void container_replace(struct sway_container *container,
+ struct sway_container *replacement) {
+ container_add_sibling(container, replacement);
+ container_detach(container);
}
struct sway_container *container_split(struct sway_container *child,
enum sway_container_layout layout) {
- // TODO floating: cannot split a floating container
- if (!sway_assert(child, "child cannot be null")) {
- return NULL;
- }
- if (child->type == C_WORKSPACE && child->children->length == 0) {
- // Special case: this just behaves like splitt
- child->prev_split_layout = child->layout;
- child->layout = layout;
- return child;
- }
-
- struct sway_container *cont = container_create(C_CONTAINER);
-
- wlr_log(WLR_DEBUG, "creating container %p around %p", cont, child);
+ struct sway_seat *seat = input_manager_get_default_seat(input_manager);
+ bool set_focus = (seat_get_focus(seat) == &child->node);
- cont->prev_split_layout = L_NONE;
+ struct sway_container *cont = container_create(NULL);
cont->width = child->width;
cont->height = child->height;
cont->x = child->x;
cont->y = child->y;
cont->current_gaps = child->current_gaps;
+ cont->layout = layout;
- struct sway_seat *seat = input_manager_get_default_seat(input_manager);
- bool set_focus = (seat_get_focus(seat) == child);
-
- if (child->type == C_WORKSPACE) {
- struct sway_container *workspace = child;
- while (workspace->children->length) {
- struct sway_container *ws_child = workspace->children->items[0];
- container_remove_child(ws_child);
- container_add_child(cont, ws_child);
- }
-
- container_add_child(workspace, cont);
- enum sway_container_layout old_layout = workspace->layout;
- workspace->layout = layout;
- cont->layout = old_layout;
- } else {
- cont->layout = layout;
- container_replace_child(child, cont);
- container_add_child(cont, child);
- }
+ container_replace(child, cont);
+ container_add_child(cont, child);
if (set_focus) {
- seat_set_focus(seat, cont);
- seat_set_focus(seat, child);
+ seat_set_focus(seat, &cont->node);
+ seat_set_focus(seat, &child->node);
}
- container_notify_subtree_changed(cont);
return cont;
}
diff --git a/sway/tree/node.c b/sway/tree/node.c
new file mode 100644
index 00000000..74661c1a
--- /dev/null
+++ b/sway/tree/node.c
@@ -0,0 +1,151 @@
+#define _POSIX_C_SOURCE 200809L
+#include "sway/output.h"
+#include "sway/server.h"
+#include "sway/tree/container.h"
+#include "sway/tree/node.h"
+#include "sway/tree/root.h"
+#include "sway/tree/workspace.h"
+#include "log.h"
+
+void node_init(struct sway_node *node, enum sway_node_type type, void *thing) {
+ static size_t next_id = 1;
+ node->id = next_id++;
+ node->type = type;
+ node->sway_root = thing;
+ wl_signal_init(&node->events.destroy);
+}
+
+const char *node_type_to_str(enum sway_node_type type) {
+ switch (type) {
+ case N_ROOT:
+ return "N_ROOT";
+ case N_OUTPUT:
+ return "N_OUTPUT";
+ case N_WORKSPACE:
+ return "N_WORKSPACE";
+ case N_CONTAINER:
+ return "N_CONTAINER";
+ }
+ return "";
+}
+
+void node_set_dirty(struct sway_node *node) {
+ if (node->dirty) {
+ return;
+ }
+ node->dirty = true;
+ list_add(server.dirty_nodes, node);
+}
+
+bool node_is_view(struct sway_node *node) {
+ return node->type == N_CONTAINER && node->sway_container->view;
+}
+
+char *node_get_name(struct sway_node *node) {
+ switch (node->type) {
+ case N_ROOT:
+ return "root";
+ case N_OUTPUT:
+ return node->sway_output->wlr_output->name;
+ case N_WORKSPACE:
+ return node->sway_workspace->name;
+ case N_CONTAINER:
+ return node->sway_container->title;
+ }
+ return NULL;
+}
+
+void node_get_box(struct sway_node *node, struct wlr_box *box) {
+ switch (node->type) {
+ case N_ROOT:
+ root_get_box(root, box);
+ break;
+ case N_OUTPUT:
+ output_get_box(node->sway_output, box);
+ break;
+ case N_WORKSPACE:
+ workspace_get_box(node->sway_workspace, box);
+ break;
+ case N_CONTAINER:
+ container_get_box(node->sway_container, box);
+ break;
+ }
+}
+
+struct sway_output *node_get_output(struct sway_node *node) {
+ switch (node->type) {
+ case N_CONTAINER:
+ return node->sway_container->workspace->output;
+ case N_WORKSPACE:
+ return node->sway_workspace->output;
+ case N_OUTPUT:
+ return node->sway_output;
+ case N_ROOT:
+ return NULL;
+ }
+ return NULL;
+}
+
+enum sway_container_layout node_get_layout(struct sway_node *node) {
+ switch (node->type) {
+ case N_CONTAINER:
+ return node->sway_container->layout;
+ case N_WORKSPACE:
+ return node->sway_workspace->layout;
+ case N_OUTPUT:
+ case N_ROOT:
+ return L_NONE;
+ }
+ return L_NONE;
+}
+
+struct sway_node *node_get_parent(struct sway_node *node) {
+ switch (node->type) {
+ case N_CONTAINER: {
+ struct sway_container *con = node->sway_container;
+ if (con->parent) {
+ return &con->parent->node;
+ }
+ if (con->workspace) {
+ return &con->workspace->node;
+ }
+ }
+ return NULL;
+ case N_WORKSPACE: {
+ struct sway_workspace *ws = node->sway_workspace;
+ if (ws->output) {
+ return &ws->output->node;
+ }
+ }
+ return NULL;
+ case N_OUTPUT:
+ return &root->node;
+ case N_ROOT:
+ return NULL;
+ }
+ return NULL;
+}
+
+list_t *node_get_children(struct sway_node *node) {
+ switch (node->type) {
+ case N_CONTAINER:
+ return node->sway_container->children;
+ case N_WORKSPACE:
+ return node->sway_workspace->tiling;
+ case N_OUTPUT:
+ case N_ROOT:
+ return NULL;
+ }
+ return NULL;
+}
+
+bool node_has_ancestor(struct sway_node *node, struct sway_node *ancestor) {
+ struct sway_node *parent = node_get_parent(node);
+ while (parent) {
+ if (parent == ancestor) {
+ return true;
+ }
+ parent = node_get_parent(parent);
+ }
+ return false;
+}
diff --git a/sway/tree/output.c b/sway/tree/output.c
index 6601220b..35589032 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -2,28 +2,31 @@
#include <ctype.h>
#include <string.h>
#include <strings.h>
+#include <wlr/types/wlr_output_damage.h>
#include "sway/ipc-server.h"
+#include "sway/layers.h"
#include "sway/output.h"
#include "sway/tree/arrange.h"
#include "sway/tree/output.h"
#include "sway/tree/workspace.h"
#include "log.h"
+#include "util.h"
-static void restore_workspaces(struct sway_container *output) {
+static void restore_workspaces(struct sway_output *output) {
// Workspace output priority
- for (int i = 0; i < root_container.children->length; i++) {
- struct sway_container *other = root_container.children->items[i];
+ for (int i = 0; i < root->outputs->length; i++) {
+ struct sway_output *other = root->outputs->items[i];
if (other == output) {
continue;
}
- for (int j = 0; j < other->children->length; j++) {
- struct sway_container *ws = other->children->items[j];
- struct sway_container *highest =
+ for (int j = 0; j < other->workspaces->length; j++) {
+ struct sway_workspace *ws = other->workspaces->items[j];
+ struct sway_output *highest =
workspace_output_get_highest_available(ws, NULL);
if (highest == output) {
- container_remove_child(ws);
- container_add_child(output, ws);
+ workspace_detach(ws);
+ output_add_workspace(output, ws);
ipc_event_workspace(NULL, ws, "move");
j--;
}
@@ -31,111 +34,116 @@ static void restore_workspaces(struct sway_container *output) {
}
// Saved workspaces
- list_t *saved = root_container.sway_root->saved_workspaces;
- for (int i = 0; i < saved->length; ++i) {
- struct sway_container *ws = saved->items[i];
- container_add_child(output, ws);
+ for (int i = 0; i < root->saved_workspaces->length; ++i) {
+ struct sway_workspace *ws = root->saved_workspaces->items[i];
+ output_add_workspace(output, ws);
ipc_event_workspace(NULL, ws, "move");
}
- saved->length = 0;
+ root->saved_workspaces->length = 0;
output_sort_workspaces(output);
}
-struct sway_container *output_create(
- struct sway_output *sway_output) {
- const char *name = sway_output->wlr_output->name;
- char identifier[128];
- output_get_identifier(identifier, sizeof(identifier), sway_output);
+struct sway_output *output_create(struct wlr_output *wlr_output) {
+ struct sway_output *output = calloc(1, sizeof(struct sway_output));
+ node_init(&output->node, N_OUTPUT, output);
+ output->wlr_output = wlr_output;
+ wlr_output->data = output;
- struct output_config *oc = NULL, *all = NULL;
- for (int i = 0; i < config->output_configs->length; ++i) {
- struct output_config *cur = config->output_configs->items[i];
+ wl_signal_add(&wlr_output->events.destroy, &output->destroy);
- if (strcasecmp(name, cur->name) == 0 ||
- strcasecmp(identifier, cur->name) == 0) {
- wlr_log(WLR_DEBUG, "Matched output config for %s", name);
- oc = cur;
- }
- if (strcasecmp("*", cur->name) == 0) {
- wlr_log(WLR_DEBUG, "Matched wildcard output config for %s", name);
- all = cur;
- }
+ wl_list_insert(&root->all_outputs, &output->link);
- if (oc && all) {
- break;
- }
- }
- if (!oc) {
- oc = all;
+ if (!wl_list_empty(&wlr_output->modes)) {
+ struct wlr_output_mode *mode =
+ wl_container_of(wlr_output->modes.prev, mode, link);
+ wlr_output_set_mode(wlr_output, mode);
}
- if (oc && !oc->enabled) {
- return NULL;
- }
+ output->workspaces = create_list();
+ output->current.workspaces = create_list();
- struct sway_container *output = container_create(C_OUTPUT);
- output->sway_output = sway_output;
- output->name = strdup(name);
- if (output->name == NULL) {
- output_begin_destroy(output);
- return NULL;
- }
+ return output;
+}
+void output_enable(struct sway_output *output, struct output_config *oc) {
+ if (!sway_assert(!output->enabled, "output is already enabled")) {
+ return;
+ }
+ struct wlr_output *wlr_output = output->wlr_output;
+ output->enabled = true;
apply_output_config(oc, output);
- container_add_child(&root_container, output);
- load_swaybars();
+ list_add(root->outputs, output);
- struct wlr_box size;
- wlr_output_effective_resolution(sway_output->wlr_output, &size.width,
- &size.height);
- output->width = size.width;
- output->height = size.height;
+ output->lx = wlr_output->lx;
+ output->ly = wlr_output->ly;
+ wlr_output_transformed_resolution(wlr_output,
+ &output->width, &output->height);
restore_workspaces(output);
- if (!output->children->length) {
+ if (!output->workspaces->length) {
// Create workspace
- char *ws_name = workspace_next_name(output->name);
+ char *ws_name = workspace_next_name(wlr_output->name);
wlr_log(WLR_DEBUG, "Creating default workspace %s", ws_name);
- struct sway_container *ws = workspace_create(output, ws_name);
+ struct sway_workspace *ws = workspace_create(output, ws_name);
// Set each seat's focus if not already set
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input_manager->seats, link) {
if (!seat->has_focus) {
- seat_set_focus(seat, ws);
+ seat_set_focus(seat, &ws->node);
}
}
free(ws_name);
}
- container_create_notify(output);
- return output;
+ size_t len = sizeof(output->layers) / sizeof(output->layers[0]);
+ for (size_t i = 0; i < len; ++i) {
+ wl_list_init(&output->layers[i]);
+ }
+ wl_signal_init(&output->events.destroy);
+
+ input_manager_configure_xcursor(input_manager);
+
+ wl_signal_add(&wlr_output->events.mode, &output->mode);
+ wl_signal_add(&wlr_output->events.transform, &output->transform);
+ wl_signal_add(&wlr_output->events.scale, &output->scale);
+ wl_signal_add(&output->damage->events.frame, &output->damage_frame);
+ wl_signal_add(&output->damage->events.destroy, &output->damage_destroy);
+
+ output_add_listeners(output);
+
+ wl_signal_emit(&root->events.new_node, &output->node);
+
+ load_swaybars();
+
+ arrange_layers(output);
+ arrange_root();
}
-static void output_evacuate(struct sway_container *output) {
- if (!output->children->length) {
+static void output_evacuate(struct sway_output *output) {
+ if (!output->workspaces->length) {
return;
}
- struct sway_container *fallback_output = NULL;
- if (root_container.children->length > 1) {
- fallback_output = root_container.children->items[0];
+ struct sway_output *fallback_output = NULL;
+ if (root->outputs->length > 1) {
+ fallback_output = root->outputs->items[0];
if (fallback_output == output) {
- fallback_output = root_container.children->items[1];
+ fallback_output = root->outputs->items[1];
}
}
- while (output->children->length) {
- struct sway_container *workspace = output->children->items[0];
+ while (output->workspaces->length) {
+ struct sway_workspace *workspace = output->workspaces->items[0];
- container_remove_child(workspace);
+ workspace_detach(workspace);
if (workspace_is_empty(workspace)) {
workspace_begin_destroy(workspace);
continue;
}
- struct sway_container *new_output =
+ struct sway_output *new_output =
workspace_output_get_highest_available(workspace, output);
if (!new_output) {
new_output = fallback_output;
@@ -143,39 +151,31 @@ static void output_evacuate(struct sway_container *output) {
if (new_output) {
workspace_output_add_priority(workspace, new_output);
- container_add_child(new_output, workspace);
+ output_add_workspace(new_output, workspace);
output_sort_workspaces(new_output);
ipc_event_workspace(NULL, workspace, "move");
} else {
- list_add(root_container.sway_root->saved_workspaces, workspace);
+ list_add(root->saved_workspaces, workspace);
}
}
}
-void output_destroy(struct sway_container *output) {
- if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) {
+void output_destroy(struct sway_output *output) {
+ if (!sway_assert(output->node.destroying,
+ "Tried to free output which wasn't marked as destroying")) {
return;
}
- if (!sway_assert(output->destroying,
- "Tried to free output which wasn't marked as destroying")) {
+ if (!sway_assert(output->wlr_output == NULL,
+ "Tried to free output which still had a wlr_output")) {
return;
}
- if (!sway_assert(output->ntxnrefs == 0, "Tried to free output "
+ if (!sway_assert(output->node.ntxnrefs == 0, "Tried to free output "
"which is still referenced by transactions")) {
return;
}
- free(output->name);
- free(output->formatted_title);
- wlr_texture_destroy(output->title_focused);
- wlr_texture_destroy(output->title_focused_inactive);
- wlr_texture_destroy(output->title_unfocused);
- wlr_texture_destroy(output->title_urgent);
- list_free(output->children);
- list_free(output->current.children);
- list_free(output->outputs);
+ list_free(output->workspaces);
+ list_free(output->current.workspaces);
free(output);
-
- // NOTE: We don't actually destroy the sway_output here
}
static void untrack_output(struct sway_container *con, void *data) {
@@ -186,76 +186,128 @@ static void untrack_output(struct sway_container *con, void *data) {
}
}
-void output_begin_destroy(struct sway_container *output) {
- if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) {
+void output_disable(struct sway_output *output) {
+ if (!sway_assert(output->enabled, "Expected an enabled output")) {
return;
}
- wlr_log(WLR_DEBUG, "OUTPUT: Destroying output '%s'", output->name);
+ wlr_log(WLR_DEBUG, "Disabling output '%s'", output->wlr_output->name);
wl_signal_emit(&output->events.destroy, output);
output_evacuate(output);
- output->destroying = true;
- container_set_dirty(output);
+ root_for_each_container(untrack_output, output);
+
+ int index = list_find(root->outputs, output);
+ list_del(root->outputs, index);
+
+ wl_list_remove(&output->mode.link);
+ wl_list_remove(&output->transform.link);
+ wl_list_remove(&output->scale.link);
+ wl_list_remove(&output->damage_destroy.link);
+ wl_list_remove(&output->damage_frame.link);
+
+ output->enabled = false;
+
+ arrange_root();
+}
+
+void output_begin_destroy(struct sway_output *output) {
+ if (!sway_assert(!output->enabled, "Expected a disabled output")) {
+ return;
+ }
+ wlr_log(WLR_DEBUG, "Destroying output '%s'", output->wlr_output->name);
+
+ output->node.destroying = true;
+ node_set_dirty(&output->node);
+
+ wl_list_remove(&output->link);
+ wl_list_remove(&output->destroy.link);
+ output->wlr_output->data = NULL;
+ output->wlr_output = NULL;
+}
- root_for_each_container(untrack_output, output->sway_output);
+struct output_config *output_find_config(struct sway_output *output) {
+ const char *name = output->wlr_output->name;
+ char identifier[128];
+ output_get_identifier(identifier, sizeof(identifier), output);
- wl_list_remove(&output->sway_output->mode.link);
- wl_list_remove(&output->sway_output->transform.link);
- wl_list_remove(&output->sway_output->scale.link);
- wl_list_remove(&output->sway_output->damage_destroy.link);
- wl_list_remove(&output->sway_output->damage_frame.link);
+ struct output_config *oc = NULL, *all = NULL;
+ for (int i = 0; i < config->output_configs->length; ++i) {
+ struct output_config *cur = config->output_configs->items[i];
- output->sway_output->swayc = NULL;
- output->sway_output = NULL;
+ if (strcasecmp(name, cur->name) == 0 ||
+ strcasecmp(identifier, cur->name) == 0) {
+ wlr_log(WLR_DEBUG, "Matched output config for %s", name);
+ oc = cur;
+ }
+ if (strcasecmp("*", cur->name) == 0) {
+ wlr_log(WLR_DEBUG, "Matched wildcard output config for %s", name);
+ all = cur;
+ }
- if (output->parent) {
- container_remove_child(output);
+ if (oc && all) {
+ break;
+ }
+ }
+ if (!oc) {
+ oc = all;
}
+
+ return oc;
}
-struct sway_container *output_from_wlr_output(struct wlr_output *output) {
- if (output == NULL) {
+struct sway_output *output_from_wlr_output(struct wlr_output *output) {
+ return output->data;
+}
+
+struct sway_output *output_get_in_direction(struct sway_output *reference,
+ enum movement_direction direction) {
+ enum wlr_direction wlr_dir = 0;
+ if (!sway_assert(sway_dir_to_wlr(direction, &wlr_dir),
+ "got invalid direction: %d", direction)) {
return NULL;
}
- for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *o = root_container.children->items[i];
- if (o->type == C_OUTPUT && o->sway_output->wlr_output == output) {
- return o;
- }
+ int lx = reference->wlr_output->lx + reference->width / 2;
+ int ly = reference->wlr_output->ly + reference->height / 2;
+ struct wlr_output *wlr_adjacent = wlr_output_layout_adjacent_output(
+ root->output_layout, wlr_dir, reference->wlr_output, lx, ly);
+ if (!wlr_adjacent) {
+ return NULL;
}
- return NULL;
+ return output_from_wlr_output(wlr_adjacent);
}
-void output_for_each_workspace(struct sway_container *output,
- void (*f)(struct sway_container *con, void *data), void *data) {
- if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) {
- return;
+void output_add_workspace(struct sway_output *output,
+ struct sway_workspace *workspace) {
+ if (workspace->output) {
+ workspace_detach(workspace);
}
- for (int i = 0; i < output->children->length; ++i) {
- struct sway_container *workspace = output->children->items[i];
+ list_add(output->workspaces, workspace);
+ workspace->output = output;
+ node_set_dirty(&output->node);
+ node_set_dirty(&workspace->node);
+}
+
+void output_for_each_workspace(struct sway_output *output,
+ void (*f)(struct sway_workspace *ws, void *data), void *data) {
+ for (int i = 0; i < output->workspaces->length; ++i) {
+ struct sway_workspace *workspace = output->workspaces->items[i];
f(workspace, data);
}
}
-void output_for_each_container(struct sway_container *output,
+void output_for_each_container(struct sway_output *output,
void (*f)(struct sway_container *con, void *data), void *data) {
- if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) {
- return;
- }
- for (int i = 0; i < output->children->length; ++i) {
- struct sway_container *workspace = output->children->items[i];
+ for (int i = 0; i < output->workspaces->length; ++i) {
+ struct sway_workspace *workspace = output->workspaces->items[i];
workspace_for_each_container(workspace, f, data);
}
}
-struct sway_container *output_find_workspace(struct sway_container *output,
- bool (*test)(struct sway_container *con, void *data), void *data) {
- if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) {
- return NULL;
- }
- for (int i = 0; i < output->children->length; ++i) {
- struct sway_container *workspace = output->children->items[i];
+struct sway_workspace *output_find_workspace(struct sway_output *output,
+ bool (*test)(struct sway_workspace *ws, void *data), void *data) {
+ for (int i = 0; i < output->workspaces->length; ++i) {
+ struct sway_workspace *workspace = output->workspaces->items[i];
if (test(workspace, data)) {
return workspace;
}
@@ -263,14 +315,11 @@ struct sway_container *output_find_workspace(struct sway_container *output,
return NULL;
}
-struct sway_container *output_find_container(struct sway_container *output,
+struct sway_container *output_find_container(struct sway_output *output,
bool (*test)(struct sway_container *con, void *data), void *data) {
- if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) {
- return NULL;
- }
struct sway_container *result = NULL;
- for (int i = 0; i < output->children->length; ++i) {
- struct sway_container *workspace = output->children->items[i];
+ for (int i = 0; i < output->workspaces->length; ++i) {
+ struct sway_workspace *workspace = output->workspaces->items[i];
if ((result = workspace_find_container(workspace, test, data))) {
return result;
}
@@ -279,8 +328,8 @@ struct sway_container *output_find_container(struct sway_container *output,
}
static int sort_workspace_cmp_qsort(const void *_a, const void *_b) {
- struct sway_container *a = *(void **)_a;
- struct sway_container *b = *(void **)_b;
+ struct sway_workspace *a = *(void **)_a;
+ struct sway_workspace *b = *(void **)_b;
if (isdigit(a->name[0]) && isdigit(b->name[0])) {
int a_num = strtol(a->name, NULL, 10);
@@ -294,6 +343,27 @@ static int sort_workspace_cmp_qsort(const void *_a, const void *_b) {
return 0;
}
-void output_sort_workspaces(struct sway_container *output) {
- list_stable_sort(output->children, sort_workspace_cmp_qsort);
+void output_sort_workspaces(struct sway_output *output) {
+ list_stable_sort(output->workspaces, sort_workspace_cmp_qsort);
+}
+
+void output_get_box(struct sway_output *output, struct wlr_box *box) {
+ box->x = output->lx;
+ box->y = output->ly;
+ box->width = output->width;
+ box->height = output->height;
+}
+
+enum sway_container_layout output_get_default_layout(
+ struct sway_output *output) {
+ if (config->default_layout != L_NONE) {
+ return config->default_layout;
+ }
+ if (config->default_orientation != L_NONE) {
+ return config->default_orientation;
+ }
+ if (output->height > output->width) {
+ return L_VERT;
+ }
+ return L_HORIZ;
}
diff --git a/sway/tree/root.c b/sway/tree/root.c
index b42371de..ecc04ddb 100644
--- a/sway/tree/root.c
+++ b/sway/tree/root.c
@@ -14,54 +14,45 @@
#include "log.h"
#include "util.h"
-struct sway_container root_container;
+struct sway_root *root;
static void output_layout_handle_change(struct wl_listener *listener,
void *data) {
- arrange_windows(&root_container);
+ arrange_root();
transaction_commit_dirty();
}
-void root_create(void) {
- root_container.id = 0; // normally assigned in new_swayc()
- root_container.type = C_ROOT;
- root_container.layout = L_NONE;
- root_container.name = strdup("root");
- root_container.children = create_list();
- root_container.current.children = create_list();
- wl_signal_init(&root_container.events.destroy);
-
- root_container.sway_root = calloc(1, sizeof(*root_container.sway_root));
- root_container.sway_root->output_layout = wlr_output_layout_create();
- wl_list_init(&root_container.sway_root->all_outputs);
+struct sway_root *root_create(void) {
+ struct sway_root *root = calloc(1, sizeof(struct sway_root));
+ if (!root) {
+ wlr_log(WLR_ERROR, "Unable to allocate sway_root");
+ return NULL;
+ }
+ node_init(&root->node, N_ROOT, root);
+ root->output_layout = wlr_output_layout_create();
+ wl_list_init(&root->all_outputs);
#ifdef HAVE_XWAYLAND
- wl_list_init(&root_container.sway_root->xwayland_unmanaged);
+ wl_list_init(&root->xwayland_unmanaged);
#endif
- wl_list_init(&root_container.sway_root->drag_icons);
- wl_signal_init(&root_container.sway_root->events.new_container);
- root_container.sway_root->scratchpad = create_list();
- root_container.sway_root->saved_workspaces = create_list();
-
- root_container.sway_root->output_layout_change.notify =
- output_layout_handle_change;
- wl_signal_add(&root_container.sway_root->output_layout->events.change,
- &root_container.sway_root->output_layout_change);
+ wl_list_init(&root->drag_icons);
+ wl_signal_init(&root->events.new_node);
+ root->outputs = create_list();
+ root->scratchpad = create_list();
+ root->saved_workspaces = create_list();
+
+ root->output_layout_change.notify = output_layout_handle_change;
+ wl_signal_add(&root->output_layout->events.change,
+ &root->output_layout_change);
+ return root;
}
-void root_destroy(void) {
- // sway_root
- wl_list_remove(&root_container.sway_root->output_layout_change.link);
- list_free(root_container.sway_root->scratchpad);
- list_free(root_container.sway_root->saved_workspaces);
- wlr_output_layout_destroy(root_container.sway_root->output_layout);
- free(root_container.sway_root);
-
- // root_container
- list_free(root_container.children);
- list_free(root_container.current.children);
- free(root_container.name);
-
- memset(&root_container, 0, sizeof(root_container));
+void root_destroy(struct sway_root *root) {
+ wl_list_remove(&root->output_layout_change.link);
+ list_free(root->scratchpad);
+ list_free(root->saved_workspaces);
+ list_free(root->outputs);
+ wlr_output_layout_destroy(root->output_layout);
+ free(root);
}
void root_scratchpad_add_container(struct sway_container *con) {
@@ -69,15 +60,21 @@ void root_scratchpad_add_container(struct sway_container *con) {
return;
}
con->scratchpad = true;
- list_add(root_container.sway_root->scratchpad, con);
+ list_add(root->scratchpad, con);
struct sway_container *parent = con->parent;
+ struct sway_workspace *workspace = con->workspace;
container_set_floating(con, true);
- container_remove_child(con);
- arrange_windows(parent);
+ container_detach(con);
struct sway_seat *seat = input_manager_current_seat(input_manager);
- seat_set_focus(seat, seat_get_focus_inactive(seat, parent));
+ if (parent) {
+ arrange_container(parent);
+ seat_set_focus(seat, seat_get_focus_inactive(seat, &parent->node));
+ } else {
+ arrange_workspace(workspace);
+ seat_set_focus(seat, seat_get_focus_inactive(seat, &workspace->node));
+ }
}
void root_scratchpad_remove_container(struct sway_container *con) {
@@ -85,28 +82,25 @@ void root_scratchpad_remove_container(struct sway_container *con) {
return;
}
con->scratchpad = false;
- int index = list_find(root_container.sway_root->scratchpad, con);
+ int index = list_find(root->scratchpad, con);
if (index != -1) {
- list_del(root_container.sway_root->scratchpad, index);
+ list_del(root->scratchpad, index);
}
}
void root_scratchpad_show(struct sway_container *con) {
struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *ws = seat_get_focus(seat);
- if (ws->type != C_WORKSPACE) {
- ws = container_parent(ws, C_WORKSPACE);
- }
+ struct sway_workspace *ws = seat_get_focused_workspace(seat);
// If the current con or any of its parents are in fullscreen mode, we
// first need to disable it before showing the scratchpad con.
- if (ws->sway_workspace->fullscreen) {
- container_set_fullscreen(ws->sway_workspace->fullscreen, false);
+ if (ws->fullscreen) {
+ container_set_fullscreen(ws->fullscreen, false);
}
// Show the container
- if (con->parent) {
- container_remove_child(con);
+ if (con->workspace) {
+ container_detach(con);
}
workspace_add_floating(ws, con);
@@ -115,7 +109,7 @@ void root_scratchpad_show(struct sway_container *con) {
double center_ly = con->y + con->height / 2;
struct wlr_box workspace_box;
- container_get_box(ws, &workspace_box);
+ workspace_get_box(ws, &workspace_box);
if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) {
// Maybe resize it
if (con->width > ws->width || con->height > ws->height) {
@@ -128,23 +122,21 @@ void root_scratchpad_show(struct sway_container *con) {
container_floating_move_to(con, new_lx, new_ly);
}
- arrange_windows(ws);
- seat_set_focus(seat, seat_get_focus_inactive(seat, con));
-
- container_set_dirty(con->parent);
+ arrange_workspace(ws);
+ seat_set_focus(seat, seat_get_focus_inactive(seat, &con->node));
}
void root_scratchpad_hide(struct sway_container *con) {
struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus = seat_get_focus(seat);
- struct sway_container *ws = container_parent(con, C_WORKSPACE);
+ struct sway_node *focus = seat_get_focus(seat);
+ struct sway_workspace *ws = con->workspace;
- container_remove_child(con);
- arrange_windows(ws);
- if (con == focus) {
- seat_set_focus(seat, seat_get_focus_inactive(seat, ws));
+ container_detach(con);
+ arrange_workspace(ws);
+ if (&con->node == focus) {
+ seat_set_focus(seat, seat_get_focus_inactive(seat, &ws->node));
}
- list_move_to_end(root_container.sway_root->scratchpad, con);
+ list_move_to_end(root->scratchpad, con);
}
struct pid_workspace {
@@ -152,7 +144,7 @@ struct pid_workspace {
char *workspace;
struct timespec time_added;
- struct sway_container *output;
+ struct sway_output *output;
struct wl_listener output_destroy;
struct wl_list link;
@@ -160,13 +152,13 @@ struct pid_workspace {
static struct wl_list pid_workspaces;
-struct sway_container *root_workspace_for_pid(pid_t pid) {
+struct sway_workspace *root_workspace_for_pid(pid_t pid) {
if (!pid_workspaces.prev && !pid_workspaces.next) {
wl_list_init(&pid_workspaces);
return NULL;
}
- struct sway_container *ws = NULL;
+ struct sway_workspace *ws = NULL;
struct pid_workspace *pw = NULL;
wlr_log(WLR_DEBUG, "Looking up workspace for pid %d", pid);
@@ -219,16 +211,12 @@ void root_record_workspace_pid(pid_t pid) {
}
struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *ws =
- seat_get_focus_inactive(seat, &root_container);
- if (ws && ws->type != C_WORKSPACE) {
- ws = container_parent(ws, C_WORKSPACE);
- }
+ struct sway_workspace *ws = seat_get_focused_workspace(seat);
if (!ws) {
wlr_log(WLR_DEBUG, "Bailing out, no workspace");
return;
}
- struct sway_container *output = ws->parent;
+ struct sway_output *output = ws->output;
if (!output) {
wlr_log(WLR_DEBUG, "Bailing out, no output");
return;
@@ -255,30 +243,28 @@ void root_record_workspace_pid(pid_t pid) {
pw->pid = pid;
memcpy(&pw->time_added, &now, sizeof(struct timespec));
pw->output_destroy.notify = pw_handle_output_destroy;
- wl_signal_add(&output->sway_output->wlr_output->events.destroy,
- &pw->output_destroy);
+ wl_signal_add(&output->wlr_output->events.destroy, &pw->output_destroy);
wl_list_insert(&pid_workspaces, &pw->link);
}
-void root_for_each_workspace(void (*f)(struct sway_container *con, void *data),
+void root_for_each_workspace(void (*f)(struct sway_workspace *ws, void *data),
void *data) {
- for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *output = root_container.children->items[i];
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
output_for_each_workspace(output, f, data);
}
}
void root_for_each_container(void (*f)(struct sway_container *con, void *data),
void *data) {
- for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *output = root_container.children->items[i];
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
output_for_each_container(output, f, data);
}
// Scratchpad
- for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) {
- struct sway_container *container =
- root_container.sway_root->scratchpad->items[i];
+ for (int i = 0; i < root->scratchpad->length; ++i) {
+ struct sway_container *container = root->scratchpad->items[i];
// If the container has a parent then it's visible on a workspace
// and will have been iterated in the previous for loop. So we only
// iterate the hidden scratchpad containers here.
@@ -289,10 +275,10 @@ void root_for_each_container(void (*f)(struct sway_container *con, void *data),
}
}
-struct sway_container *root_find_output(
- bool (*test)(struct sway_container *con, void *data), void *data) {
- for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *output = root_container.children->items[i];
+struct sway_output *root_find_output(
+ bool (*test)(struct sway_output *output, void *data), void *data) {
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
if (test(output, data)) {
return output;
}
@@ -300,11 +286,11 @@ struct sway_container *root_find_output(
return NULL;
}
-struct sway_container *root_find_workspace(
- bool (*test)(struct sway_container *con, void *data), void *data) {
- struct sway_container *result = NULL;
- for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *output = root_container.children->items[i];
+struct sway_workspace *root_find_workspace(
+ bool (*test)(struct sway_workspace *ws, void *data), void *data) {
+ struct sway_workspace *result = NULL;
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
if ((result = output_find_workspace(output, test, data))) {
return result;
}
@@ -315,17 +301,16 @@ struct sway_container *root_find_workspace(
struct sway_container *root_find_container(
bool (*test)(struct sway_container *con, void *data), void *data) {
struct sway_container *result = NULL;
- for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *output = root_container.children->items[i];
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
if ((result = output_find_container(output, test, data))) {
return result;
}
}
// Scratchpad
- for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) {
- struct sway_container *container =
- root_container.sway_root->scratchpad->items[i];
+ for (int i = 0; i < root->scratchpad->length; ++i) {
+ struct sway_container *container = root->scratchpad->items[i];
if (!container->parent) {
if (test(container, data)) {
return container;
@@ -337,3 +322,10 @@ struct sway_container *root_find_container(
}
return NULL;
}
+
+void root_get_box(struct sway_root *root, struct wlr_box *box) {
+ box->x = root->x;
+ box->y = root->y;
+ box->width = root->width;
+ box->height = root->height;
+}
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 6bd0ef67..f63a35b5 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -33,6 +33,8 @@ void view_init(struct sway_view *view, enum sway_view_type type,
view->marks = create_list();
view->allow_request_urgent = true;
wl_signal_init(&view->events.unmap);
+
+ view->container = container_create(view);
}
void view_destroy(struct sway_view *view) {
@@ -43,8 +45,8 @@ void view_destroy(struct sway_view *view) {
"Tried to free view which wasn't marked as destroying")) {
return;
}
- if (!sway_assert(view->swayc == NULL,
- "Tried to free view which still has a swayc "
+ if (!sway_assert(view->container == NULL,
+ "Tried to free view which still has a container "
"(might have a pending transaction?)")) {
return;
}
@@ -57,6 +59,7 @@ void view_destroy(struct sway_view *view) {
wlr_texture_destroy(view->marks_focused_inactive);
wlr_texture_destroy(view->marks_unfocused);
wlr_texture_destroy(view->marks_urgent);
+ free(view->title_format);
if (view->impl->destroy) {
view->impl->destroy(view);
@@ -65,23 +68,13 @@ void view_destroy(struct sway_view *view) {
}
}
-/**
- * The view may or may not be involved in a transaction. For example, a view may
- * unmap then attempt to destroy itself before we've applied the new layout. If
- * an unmapping view is still involved in a transaction then it'll still have a
- * swayc.
- *
- * If there's no transaction we can simply free the view. Otherwise the
- * destroying flag will make the view get freed when the transaction is
- * finished.
- */
void view_begin_destroy(struct sway_view *view) {
if (!sway_assert(view->surface == NULL, "Tried to destroy a mapped view")) {
return;
}
view->destroying = true;
- if (!view->swayc) {
+ if (!view->container) {
view_destroy(view);
}
}
@@ -171,30 +164,31 @@ uint32_t view_configure(struct sway_view *view, double lx, double ly, int width,
}
void view_autoconfigure(struct sway_view *view) {
- if (!sway_assert(view->swayc,
- "Called view_autoconfigure() on a view without a swayc")) {
+ if (!view->container->workspace) {
+ // Hidden in the scratchpad
return;
}
+ struct sway_output *output = view->container->workspace->output;
- struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
-
- if (view->swayc->is_fullscreen) {
- view->x = output->x;
- view->y = output->y;
+ if (view->container->is_fullscreen) {
+ view->x = output->lx;
+ view->y = output->ly;
view->width = output->width;
view->height = output->height;
return;
}
- struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
+ struct sway_workspace *ws = view->container->workspace;
- int other_views = 0;
+ bool other_views = false;
if (config->hide_edge_borders == E_SMART) {
- struct sway_container *con = view->swayc;
- while (con != output) {
- if (con->layout != L_TABBED && con->layout != L_STACKED) {
- other_views += con->children ? con->children->length - 1 : 0;
- if (other_views > 0) {
+ struct sway_container *con = view->container;
+ while (con) {
+ enum sway_container_layout layout = container_parent_layout(con);
+ if (layout != L_TABBED && layout != L_STACKED) {
+ list_t *siblings = container_get_siblings(con);
+ if (siblings && siblings->length > 1) {
+ other_views = true;
break;
}
}
@@ -202,7 +196,7 @@ void view_autoconfigure(struct sway_view *view) {
}
}
- struct sway_container *con = view->swayc;
+ struct sway_container *con = view->container;
view->border_top = view->border_bottom = true;
view->border_left = view->border_right = true;
@@ -228,7 +222,8 @@ void view_autoconfigure(struct sway_view *view) {
// In a tabbed or stacked container, the swayc's y is the bottom of the
// title area. We have to disable any top border because the title bar is
// rendered by the parent.
- if (con->parent->layout == L_TABBED || con->parent->layout == L_STACKED) {
+ enum sway_container_layout layout = container_parent_layout(con);
+ if (layout == L_TABBED || layout == L_STACKED) {
view->border_top = false;
} else {
y_offset = container_titlebar_height();
@@ -281,13 +276,16 @@ void view_set_activated(struct sway_view *view, bool activated) {
}
void view_request_activate(struct sway_view *view) {
- struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
+ struct sway_workspace *ws = view->container->workspace;
+ if (!ws) { // hidden scratchpad container
+ return;
+ }
struct sway_seat *seat = input_manager_current_seat(input_manager);
switch (config->focus_on_window_activation) {
case FOWA_SMART:
if (workspace_is_visible(ws)) {
- seat_set_focus(seat, view->swayc);
+ seat_set_focus(seat, &view->container->node);
} else {
view_set_urgent(view, true);
}
@@ -296,7 +294,7 @@ void view_request_activate(struct sway_view *view) {
view_set_urgent(view, true);
break;
case FOWA_FOCUS:
- seat_set_focus(seat, view->swayc);
+ seat_set_focus(seat, &view->container->node);
break;
case FOWA_NONE:
break;
@@ -331,23 +329,12 @@ void view_close_popups(struct sway_view *view) {
}
void view_damage_from(struct sway_view *view) {
- for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *cont = root_container.children->items[i];
- if (cont->type == C_OUTPUT) {
- output_damage_from_view(cont->sway_output, view);
- }
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
+ output_damage_from_view(output, view);
}
}
-static void view_get_layout_box(struct sway_view *view, struct wlr_box *box) {
- struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
-
- box->x = output->x + view->swayc->x;
- box->y = output->y + view->swayc->y;
- box->width = view->width;
- box->height = view->height;
-}
-
void view_for_each_surface(struct sway_view *view,
wlr_surface_iterator_func_t iterator, void *user_data) {
if (!view->surface) {
@@ -396,11 +383,8 @@ static bool view_has_executed_criteria(struct sway_view *view,
}
void view_execute_criteria(struct sway_view *view) {
- if (!view->swayc) {
- return;
- }
struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *prior_focus = seat_get_focus(seat);
+ struct sway_node *prior_focus = seat_get_focus(seat);
list_t *criterias = criteria_for_view(view, CT_COMMAND);
for (int i = 0; i < criterias->length; i++) {
struct criteria *criteria = criterias->items[i];
@@ -411,7 +395,7 @@ void view_execute_criteria(struct sway_view *view) {
}
wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'",
criteria->raw, view, criteria->cmdlist);
- seat_set_focus(seat, view->swayc);
+ seat_set_focus(seat, &view->container->node);
list_add(view->executed_criteria, criteria);
struct cmd_results *res = execute_command(criteria->cmdlist, NULL);
if (res->status != CMD_SUCCESS) {
@@ -423,19 +407,19 @@ void view_execute_criteria(struct sway_view *view) {
seat_set_focus(seat, prior_focus);
}
-static struct sway_container *select_workspace(struct sway_view *view) {
+static struct sway_workspace *select_workspace(struct sway_view *view) {
struct sway_seat *seat = input_manager_current_seat(input_manager);
// Check if there's any `assign` criteria for the view
list_t *criterias = criteria_for_view(view,
CT_ASSIGN_WORKSPACE | CT_ASSIGN_WORKSPACE_NUMBER | CT_ASSIGN_OUTPUT);
- struct sway_container *ws = NULL;
+ struct sway_workspace *ws = NULL;
for (int i = 0; i < criterias->length; ++i) {
struct criteria *criteria = criterias->items[i];
if (criteria->type == CT_ASSIGN_OUTPUT) {
- struct sway_container *output = output_by_name(criteria->target);
+ struct sway_output *output = output_by_name(criteria->target);
if (output) {
- ws = seat_get_active_child(seat, output);
+ ws = output_get_active_workspace(output);
break;
}
} else {
@@ -484,20 +468,14 @@ static struct sway_container *select_workspace(struct sway_view *view) {
}
// Use the focused workspace
- ws = seat_get_focus_inactive(seat, &root_container);
- if (ws->type != C_WORKSPACE) {
- ws = container_parent(ws, C_WORKSPACE);
- }
- return ws;
+ return seat_get_focused_workspace(seat);
}
static bool should_focus(struct sway_view *view) {
struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *prev_focus =
- seat_get_focus_inactive(seat, &root_container);
- struct sway_container *prev_ws = prev_focus->type == C_WORKSPACE ?
- prev_focus : container_parent(prev_focus, C_WORKSPACE);
- struct sway_container *map_ws = container_parent(view->swayc, C_WORKSPACE);
+ struct sway_container *prev_con = seat_get_focused_container(seat);
+ struct sway_workspace *prev_ws = seat_get_focused_workspace(seat);
+ struct sway_workspace *map_ws = view->container->workspace;
// Views can only take focus if they are mapped into the active workspace
if (prev_ws != map_ws) {
@@ -506,10 +484,9 @@ static bool should_focus(struct sway_view *view) {
// If the view is the only one in the focused workspace, it'll get focus
// regardless of any no_focus criteria.
- struct sway_container *parent = view->swayc->parent;
- if (parent->type == C_WORKSPACE && prev_focus == parent) {
- size_t num_children = parent->children->length +
- parent->sway_workspace->floating->length;
+ if (!view->container->parent && !prev_con) {
+ size_t num_children = view->container->workspace->tiling->length +
+ view->container->workspace->floating->length;
if (num_children == 1) {
return true;
}
@@ -529,16 +506,24 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
view->surface = wlr_surface;
struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *ws = select_workspace(view);
- struct sway_container *target_sibling = seat_get_focus_inactive(seat, ws);
+ struct sway_workspace *ws = select_workspace(view);
+ struct sway_node *node = seat_get_focus_inactive(seat, &ws->node);
+ struct sway_container *target_sibling = node->type == N_CONTAINER ?
+ node->sway_container : NULL;
// If we're about to launch the view into the floating container, then
// launch it as a tiled view in the root of the workspace instead.
- if (container_is_floating(target_sibling)) {
- target_sibling = target_sibling->parent;
+ if (target_sibling && container_is_floating(target_sibling)) {
+ target_sibling = NULL;
}
- view->swayc = container_view_create(target_sibling, view);
+ view->container = container_create(view);
+ if (target_sibling) {
+ container_add_sibling(target_sibling, view->container);
+ } else {
+ workspace_add_tiling(ws, view->container);
+ }
+ ipc_event_window(view->container, "new");
view_init_subsurfaces(view, wlr_surface);
wl_signal_add(&wlr_surface->events.new_subsurface,
@@ -548,7 +533,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
if (view->impl->wants_floating && view->impl->wants_floating(view)) {
view->border = config->floating_border;
view->border_thickness = config->floating_border_thickness;
- container_set_floating(view->swayc, true);
+ container_set_floating(view->container, true);
} else {
view->border = config->border;
view->border_thickness = config->border_thickness;
@@ -556,11 +541,11 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
}
if (should_focus(view)) {
- input_manager_set_focus(input_manager, view->swayc);
+ input_manager_set_focus(input_manager, &view->container->node);
}
view_update_title(view, false);
- container_notify_subtree_changed(view->swayc->parent);
+ container_update_representation(view->container);
view_execute_criteria(view);
}
@@ -574,17 +559,17 @@ void view_unmap(struct sway_view *view) {
view->urgent_timer = NULL;
}
- bool was_fullscreen = view->swayc->is_fullscreen;
- struct sway_container *parent = view->swayc->parent;
- container_begin_destroy(view->swayc);
- struct sway_container *surviving_ancestor = container_reap_empty(parent);
+ struct sway_container *parent = view->container->parent;
+ struct sway_workspace *ws = view->container->workspace;
+ container_begin_destroy(view->container);
+ if (parent) {
+ container_reap_empty(parent);
+ } else if (ws) {
+ workspace_consider_destroy(ws);
+ }
- // If the workspace wasn't reaped
- if (surviving_ancestor && surviving_ancestor->type >= C_WORKSPACE) {
- struct sway_container *ws = surviving_ancestor->type == C_WORKSPACE ?
- surviving_ancestor :
- container_parent(surviving_ancestor, C_WORKSPACE);
- arrange_windows(was_fullscreen ? ws : surviving_ancestor);
+ if (ws && !ws->node.destroying) {
+ arrange_workspace(ws);
workspace_detect_urgent(ws);
}
@@ -593,15 +578,15 @@ void view_unmap(struct sway_view *view) {
}
void view_update_size(struct sway_view *view, int width, int height) {
- if (!sway_assert(container_is_floating(view->swayc),
+ if (!sway_assert(container_is_floating(view->container),
"Expected a floating container")) {
return;
}
view->width = width;
view->height = height;
- view->swayc->current.view_width = width;
- view->swayc->current.view_height = height;
- container_set_geometry_from_floating_view(view->swayc);
+ view->container->current.view_width = width;
+ view->container->current.view_height = height;
+ container_set_geometry_from_floating_view(view->container);
}
static void view_subsurface_create(struct sway_view *view,
@@ -670,27 +655,18 @@ void view_child_init(struct sway_view_child *child,
wl_signal_add(&view->events.unmap, &child->view_unmap);
child->view_unmap.notify = view_child_handle_view_unmap;
- struct sway_container *output = child->view->swayc->parent;
- if (output != NULL) {
- if (output->type != C_OUTPUT) {
- output = container_parent(output, C_OUTPUT);
- }
- wlr_surface_send_enter(child->surface, output->sway_output->wlr_output);
- }
+ struct sway_output *output = child->view->container->workspace->output;
+ wlr_surface_send_enter(child->surface, output->wlr_output);
view_init_subsurfaces(child->view, surface);
// TODO: only damage the whole child
- if (child->view->swayc) {
- container_damage_whole(child->view->swayc);
- }
+ container_damage_whole(child->view->container);
}
void view_child_destroy(struct sway_view_child *child) {
// TODO: only damage the whole child
- if (child->view->swayc) {
- container_damage_whole(child->view->swayc);
- }
+ container_damage_whole(child->view->container);
wl_list_remove(&child->surface_commit.link);
wl_list_remove(&child->surface_destroy.link);
@@ -808,22 +784,20 @@ static char *escape_title(char *buffer) {
}
void view_update_title(struct sway_view *view, bool force) {
- if (!view->swayc) {
- return;
- }
const char *title = view_get_title(view);
if (!force) {
- if (title && view->swayc->name && strcmp(title, view->swayc->name) == 0) {
+ if (title && view->container->title &&
+ strcmp(title, view->container->title) == 0) {
return;
}
- if (!title && !view->swayc->name) {
+ if (!title && !view->container->title) {
return;
}
}
- free(view->swayc->name);
- free(view->swayc->formatted_title);
+ free(view->container->title);
+ free(view->container->formatted_title);
if (title) {
size_t len = parse_title_format(view, NULL);
char *buffer = calloc(len + 1, sizeof(char));
@@ -836,25 +810,25 @@ void view_update_title(struct sway_view *view, bool force) {
buffer = escape_title(buffer);
}
- view->swayc->name = strdup(title);
- view->swayc->formatted_title = buffer;
+ view->container->title = strdup(title);
+ view->container->formatted_title = buffer;
} else {
- view->swayc->name = NULL;
- view->swayc->formatted_title = NULL;
+ view->container->title = NULL;
+ view->container->formatted_title = NULL;
}
- container_calculate_title_height(view->swayc);
+ container_calculate_title_height(view->container);
config_update_font_height(false);
// Update title after the global font height is updated
- container_update_title_textures(view->swayc);
+ container_update_title_textures(view->container);
- ipc_event_window(view->swayc, "title");
+ ipc_event_window(view->container, "title");
}
static bool find_by_mark_iterator(struct sway_container *con,
void *data) {
char *mark = data;
- return con->type == C_VIEW && view_has_mark(con->sway_view, mark);
+ return con->view && view_has_mark(con->view, mark);
}
struct sway_view *view_find_mark(char *mark) {
@@ -863,7 +837,7 @@ struct sway_view *view_find_mark(char *mark) {
if (!container) {
return NULL;
}
- return container->sway_view;
+ return container->view;
}
bool view_find_and_unmark(char *mark) {
@@ -872,7 +846,7 @@ bool view_find_and_unmark(char *mark) {
if (!container) {
return false;
}
- struct sway_view *view = container->sway_view;
+ struct sway_view *view = container->view;
for (int i = 0; i < view->marks->length; ++i) {
char *view_mark = view->marks->items[i];
@@ -888,10 +862,9 @@ bool view_find_and_unmark(char *mark) {
}
void view_clear_marks(struct sway_view *view) {
- while (view->marks->length) {
- list_del(view->marks, 0);
- ipc_event_window(view->swayc, "mark");
- }
+ list_foreach(view->marks, free);
+ view->marks->length = 0;
+ ipc_event_window(view->container, "mark");
}
bool view_has_mark(struct sway_view *view, char *mark) {
@@ -906,12 +879,13 @@ bool view_has_mark(struct sway_view *view, char *mark) {
void view_add_mark(struct sway_view *view, char *mark) {
list_add(view->marks, strdup(mark));
- ipc_event_window(view->swayc, "mark");
+ ipc_event_window(view->container, "mark");
}
static void update_marks_texture(struct sway_view *view,
struct wlr_texture **texture, struct border_colors *class) {
- struct sway_output *output = container_get_effective_output(view->swayc);
+ struct sway_output *output =
+ container_get_effective_output(view->container);
if (!output) {
return;
}
@@ -949,7 +923,7 @@ static void update_marks_texture(struct sway_view *view,
double scale = output->wlr_output->scale;
int width = 0;
- int height = view->swayc->title_height * scale;
+ int height = view->container->title_height * scale;
cairo_t *c = cairo_create(NULL);
get_text_size(c, config->font, &width, NULL, scale, false, "%s", buffer);
@@ -994,44 +968,40 @@ void view_update_marks_textures(struct sway_view *view) {
&config->border_colors.unfocused);
update_marks_texture(view, &view->marks_urgent,
&config->border_colors.urgent);
- container_damage_whole(view->swayc);
+ container_damage_whole(view->container);
}
bool view_is_visible(struct sway_view *view) {
- if (!view->swayc || view->swayc->destroying) {
+ if (view->container->node.destroying) {
return false;
}
- struct sway_container *workspace =
- container_parent(view->swayc, C_WORKSPACE);
+ struct sway_workspace *workspace = view->container->workspace;
if (!workspace) {
return false;
}
- // Determine if view is nested inside a floating container which is sticky.
- // A simple floating view will have this ancestry:
- // C_VIEW -> floating -> workspace
- // A more complex ancestry could be:
- // C_VIEW -> C_CONTAINER (tabbed) -> floating -> workspace
- struct sway_container *floater = view->swayc;
- while (floater->parent->type != C_WORKSPACE
- && floater->parent->parent->type != C_WORKSPACE) {
+ // Determine if view is nested inside a floating container which is sticky
+ struct sway_container *floater = view->container;
+ while (floater->parent) {
floater = floater->parent;
}
bool is_sticky = container_is_floating(floater) && floater->is_sticky;
// Check view isn't in a tabbed or stacked container on an inactive tab
struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *container = view->swayc;
- while (container->type != C_WORKSPACE) {
- if (container->parent->layout == L_TABBED ||
- container->parent->layout == L_STACKED) {
- if (seat_get_active_child(seat, container->parent) != container) {
+ struct sway_container *container = view->container;
+ while (container) {
+ enum sway_container_layout layout = container_parent_layout(container);
+ if (layout == L_TABBED || layout == L_STACKED) {
+ struct sway_node *parent = container->parent ?
+ &container->parent->node : &container->workspace->node;
+ if (seat_get_active_child(seat, parent) != &container->node) {
return false;
}
}
container = container->parent;
}
// Check view isn't hidden by another fullscreen view
- if (workspace->sway_workspace->fullscreen &&
- !container_is_fullscreen_or_child(view->swayc)) {
+ if (workspace->fullscreen &&
+ !container_is_fullscreen_or_child(view->container)) {
return false;
}
// Check the workspace is visible
@@ -1047,7 +1017,7 @@ void view_set_urgent(struct sway_view *view, bool enable) {
}
if (enable) {
struct sway_seat *seat = input_manager_current_seat(input_manager);
- if (seat_get_focus(seat) == view->swayc) {
+ if (seat_get_focused_container(seat) == view->container) {
return;
}
clock_gettime(CLOCK_MONOTONIC, &view->urgent);
@@ -1058,12 +1028,13 @@ void view_set_urgent(struct sway_view *view, bool enable) {
view->urgent_timer = NULL;
}
}
- container_damage_whole(view->swayc);
+ container_damage_whole(view->container);
- ipc_event_window(view->swayc, "urgent");
+ ipc_event_window(view->container, "urgent");
- struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
- workspace_detect_urgent(ws);
+ if (view->container->workspace) {
+ workspace_detect_urgent(view->container->workspace);
+ }
}
bool view_is_urgent(struct sway_view *view) {
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index 1957d94f..bb1ded22 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -12,128 +12,105 @@
#include "sway/output.h"
#include "sway/tree/arrange.h"
#include "sway/tree/container.h"
+#include "sway/tree/node.h"
#include "sway/tree/view.h"
#include "sway/tree/workspace.h"
#include "list.h"
#include "log.h"
#include "util.h"
-struct sway_container *workspace_get_initial_output(const char *name) {
- struct sway_container *parent;
+struct sway_output *workspace_get_initial_output(const char *name) {
// Search for workspace<->output pair
- int e = config->workspace_outputs->length;
for (int i = 0; i < config->workspace_outputs->length; ++i) {
struct workspace_output *wso = config->workspace_outputs->items[i];
if (strcasecmp(wso->workspace, name) == 0) {
// Find output to use if it exists
- e = root_container.children->length;
- for (i = 0; i < e; ++i) {
- parent = root_container.children->items[i];
- if (strcmp(parent->name, wso->output) == 0) {
- return parent;
- }
+ struct sway_output *output = output_by_name(wso->output);
+ if (output) {
+ return output;
}
break;
}
}
// Otherwise put it on the focused output
struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus =
- seat_get_focus_inactive(seat, &root_container);
- parent = focus;
- parent = container_parent(parent, C_OUTPUT);
- return parent;
+ struct sway_workspace *focus = seat_get_focused_workspace(seat);
+ return focus->output;
}
-struct sway_container *workspace_create(struct sway_container *output,
+struct sway_workspace *workspace_create(struct sway_output *output,
const char *name) {
if (output == NULL) {
output = workspace_get_initial_output(name);
}
- wlr_log(WLR_DEBUG, "Added workspace %s for output %s", name, output->name);
- struct sway_container *workspace = container_create(C_WORKSPACE);
-
- workspace->x = output->x;
- workspace->y = output->y;
- workspace->width = output->width;
- workspace->height = output->height;
- workspace->name = !name ? NULL : strdup(name);
- workspace->prev_split_layout = L_NONE;
- workspace->layout = container_get_default_layout(output);
+ wlr_log(WLR_DEBUG, "Adding workspace %s for output %s", name,
+ output->wlr_output->name);
- struct sway_workspace *swayws = calloc(1, sizeof(struct sway_workspace));
- if (!swayws) {
+ struct sway_workspace *ws = calloc(1, sizeof(struct sway_workspace));
+ if (!ws) {
+ wlr_log(WLR_ERROR, "Unable to allocate sway_workspace");
return NULL;
}
- swayws->swayc = workspace;
- swayws->floating = create_list();
- swayws->output_priority = create_list();
- workspace->sway_workspace = swayws;
- workspace_output_add_priority(workspace, output);
-
- container_add_child(output, workspace);
+ node_init(&ws->node, N_WORKSPACE, ws);
+ ws->x = output->lx;
+ ws->y = output->ly;
+ ws->width = output->width;
+ ws->height = output->height;
+ ws->name = name ? strdup(name) : NULL;
+ ws->prev_split_layout = L_NONE;
+ ws->layout = output_get_default_layout(output);
+ ws->floating = create_list();
+ ws->tiling = create_list();
+ ws->output_priority = create_list();
+ workspace_output_add_priority(ws, output);
+
+ output_add_workspace(output, ws);
output_sort_workspaces(output);
- container_create_notify(workspace);
- return workspace;
+ ipc_event_workspace(NULL, ws, "init");
+ wl_signal_emit(&root->events.new_node, &ws->node);
+
+ return ws;
}
-void workspace_destroy(struct sway_container *workspace) {
- if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) {
- return;
- }
- if (!sway_assert(workspace->destroying,
+void workspace_destroy(struct sway_workspace *workspace) {
+ if (!sway_assert(workspace->node.destroying,
"Tried to free workspace which wasn't marked as destroying")) {
return;
}
- if (!sway_assert(workspace->ntxnrefs == 0, "Tried to free workspace "
+ if (!sway_assert(workspace->node.ntxnrefs == 0, "Tried to free workspace "
"which is still referenced by transactions")) {
return;
}
- // sway_workspace
- struct sway_workspace *ws = workspace->sway_workspace;
- list_foreach(ws->output_priority, free);
- list_free(ws->output_priority);
- list_free(ws->floating);
- free(ws);
- // swayc
free(workspace->name);
- free(workspace->formatted_title);
- wlr_texture_destroy(workspace->title_focused);
- wlr_texture_destroy(workspace->title_focused_inactive);
- wlr_texture_destroy(workspace->title_unfocused);
- wlr_texture_destroy(workspace->title_urgent);
- list_free(workspace->children);
- list_free(workspace->current.children);
- list_free(workspace->outputs);
+ free(workspace->representation);
+ list_foreach(workspace->output_priority, free);
+ list_free(workspace->output_priority);
+ list_free(workspace->floating);
+ list_free(workspace->tiling);
+ list_free(workspace->current.floating);
+ list_free(workspace->current.tiling);
free(workspace);
}
-void workspace_begin_destroy(struct sway_container *workspace) {
- if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) {
- return;
- }
+void workspace_begin_destroy(struct sway_workspace *workspace) {
wlr_log(WLR_DEBUG, "Destroying workspace '%s'", workspace->name);
- wl_signal_emit(&workspace->events.destroy, workspace);
ipc_event_workspace(NULL, workspace, "empty"); // intentional
+ wl_signal_emit(&workspace->node.events.destroy, &workspace->node);
- workspace->destroying = true;
- container_set_dirty(workspace);
-
- if (workspace->parent) {
- container_remove_child(workspace);
+ if (workspace->output) {
+ workspace_detach(workspace);
}
+
+ workspace->node.destroying = true;
+ node_set_dirty(&workspace->node);
}
-void workspace_consider_destroy(struct sway_container *ws) {
- if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) {
- return;
- }
- struct sway_seat *seat = input_manager_current_seat(input_manager);
- if (ws->children->length == 0 && ws->sway_workspace->floating->length == 0
- && seat_get_active_child(seat, ws->parent) != ws) {
+void workspace_consider_destroy(struct sway_workspace *ws) {
+ if (ws->tiling->length == 0 && ws->floating->length == 0
+ && output_get_active_workspace(ws->output) != ws) {
workspace_begin_destroy(ws);
}
}
@@ -272,59 +249,49 @@ char *workspace_next_name(const char *output_name) {
}
// As a fall back, get the current number of active workspaces
// and return that + 1 for the next workspace's name
- int ws_num = root_container.children->length;
+ int ws_num = root->outputs->length;
int l = snprintf(NULL, 0, "%d", ws_num);
char *name = malloc(l + 1);
- if (!sway_assert(name, "Cloud not allocate workspace name")) {
+ if (!sway_assert(name, "Could not allocate workspace name")) {
return NULL;
}
sprintf(name, "%d", ws_num++);
return name;
}
-static bool _workspace_by_number(struct sway_container *view, void *data) {
- if (view->type != C_WORKSPACE) {
- return false;
- }
+static bool _workspace_by_number(struct sway_workspace *ws, void *data) {
char *name = data;
- char *view_name = view->name;
+ char *ws_name = ws->name;
while (isdigit(*name)) {
- if (*name++ != *view_name++) {
+ if (*name++ != *ws_name++) {
return false;
}
}
- return !isdigit(*view_name);
+ return !isdigit(*ws_name);
}
-struct sway_container *workspace_by_number(const char* name) {
+struct sway_workspace *workspace_by_number(const char* name) {
return root_find_workspace(_workspace_by_number, (void *) name);
}
-static bool _workspace_by_name(struct sway_container *view, void *data) {
- return (view->type == C_WORKSPACE) &&
- (strcasecmp(view->name, (char *) data) == 0);
+static bool _workspace_by_name(struct sway_workspace *ws, void *data) {
+ return strcasecmp(ws->name, data) == 0;
}
-struct sway_container *workspace_by_name(const char *name) {
+struct sway_workspace *workspace_by_name(const char *name) {
struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *current_workspace = NULL, *current_output = NULL;
- struct sway_container *focus = seat_get_focus(seat);
- if (focus) {
- current_workspace = focus->type == C_WORKSPACE ?
- focus : container_parent(focus, C_WORKSPACE);
- current_output = container_parent(focus, C_OUTPUT);
- }
+ struct sway_workspace *current = seat_get_focused_workspace(seat);
if (strcmp(name, "prev") == 0) {
- return workspace_prev(current_workspace);
+ return workspace_prev(current);
} else if (strcmp(name, "prev_on_output") == 0) {
- return workspace_output_prev(current_output);
+ return workspace_output_prev(current);
} else if (strcmp(name, "next") == 0) {
- return workspace_next(current_workspace);
+ return workspace_next(current);
} else if (strcmp(name, "next_on_output") == 0) {
- return workspace_output_next(current_output);
+ return workspace_output_next(current);
} else if (strcmp(name, "current") == 0) {
- return current_workspace;
+ return current;
} else if (strcasecmp(name, "back_and_forth") == 0) {
return prev_workspace_name ?
root_find_workspace(_workspace_by_name, (void*)prev_workspace_name)
@@ -339,97 +306,68 @@ struct sway_container *workspace_by_name(const char *name) {
* the end and beginning. If next is false, the previous workspace is returned,
* otherwise the next one is returned.
*/
-static struct sway_container *workspace_output_prev_next_impl(
- struct sway_container *output, int dir) {
- if (!output) {
- return NULL;
- }
- if (!sway_assert(output->type == C_OUTPUT,
- "Argument must be an output, is %d", output->type)) {
- return NULL;
- }
-
+static struct sway_workspace *workspace_output_prev_next_impl(
+ struct sway_output *output, int dir) {
struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus = seat_get_focus_inactive(seat, output);
- struct sway_container *workspace = (focus->type == C_WORKSPACE ?
- focus :
- container_parent(focus, C_WORKSPACE));
+ struct sway_workspace *workspace = seat_get_focused_workspace(seat);
- int index = list_find(output->children, workspace);
- size_t new_index = wrap(index + dir, output->children->length);
- return output->children->items[new_index];
+ int index = list_find(output->workspaces, workspace);
+ size_t new_index = wrap(index + dir, output->workspaces->length);
+ return output->workspaces->items[new_index];
}
/**
* Get the previous or next workspace. If the first/last workspace on an output
* is active, proceed to the previous/next output's previous/next workspace.
*/
-static struct sway_container *workspace_prev_next_impl(
- struct sway_container *workspace, int dir) {
- if (!workspace) {
- return NULL;
- }
- if (!sway_assert(workspace->type == C_WORKSPACE,
- "Argument must be a workspace, is %d", workspace->type)) {
- return NULL;
- }
-
- struct sway_container *output = workspace->parent;
- int index = list_find(output->children, workspace);
+static struct sway_workspace *workspace_prev_next_impl(
+ struct sway_workspace *workspace, int dir) {
+ struct sway_output *output = workspace->output;
+ int index = list_find(output->workspaces, workspace);
int new_index = index + dir;
- if (new_index >= 0 && new_index < output->children->length) {
- return output->children->items[index + dir];
+ if (new_index >= 0 && new_index < output->workspaces->length) {
+ return output->workspaces->items[new_index];
}
// Look on a different output
- int output_index = list_find(root_container.children, output);
- new_index = wrap(output_index + dir, root_container.children->length);
- output = root_container.children->items[new_index];
+ int output_index = list_find(root->outputs, output);
+ new_index = wrap(output_index + dir, root->outputs->length);
+ output = root->outputs->items[new_index];
if (dir == 1) {
- return output->children->items[0];
+ return output->workspaces->items[0];
} else {
- return output->children->items[output->children->length - 1];
+ return output->workspaces->items[output->workspaces->length - 1];
}
}
-struct sway_container *workspace_output_next(struct sway_container *current) {
- return workspace_output_prev_next_impl(current, 1);
+struct sway_workspace *workspace_output_next(struct sway_workspace *current) {
+ return workspace_output_prev_next_impl(current->output, 1);
}
-struct sway_container *workspace_next(struct sway_container *current) {
+struct sway_workspace *workspace_next(struct sway_workspace *current) {
return workspace_prev_next_impl(current, 1);
}
-struct sway_container *workspace_output_prev(struct sway_container *current) {
- return workspace_output_prev_next_impl(current, -1);
+struct sway_workspace *workspace_output_prev(struct sway_workspace *current) {
+ return workspace_output_prev_next_impl(current->output, -1);
}
-struct sway_container *workspace_prev(struct sway_container *current) {
+struct sway_workspace *workspace_prev(struct sway_workspace *current) {
return workspace_prev_next_impl(current, -1);
}
-bool workspace_switch(struct sway_container *workspace,
+bool workspace_switch(struct sway_workspace *workspace,
bool no_auto_back_and_forth) {
- if (!workspace) {
- return false;
- }
struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus =
- seat_get_focus_inactive(seat, &root_container);
- if (!seat || !focus) {
- return false;
- }
- struct sway_container *active_ws = focus;
- if (active_ws->type != C_WORKSPACE) {
- active_ws = container_parent(focus, C_WORKSPACE);
- }
+ struct sway_node *focus = seat_get_focus_inactive(seat, &root->node);
+ struct sway_workspace *active_ws = seat_get_focused_workspace(seat);
if (!no_auto_back_and_forth && config->auto_back_and_forth
&& active_ws == workspace
&& prev_workspace_name) {
- struct sway_container *new_ws = workspace_by_name(prev_workspace_name);
+ struct sway_workspace *new_ws = workspace_by_name(prev_workspace_name);
workspace = new_ws ?
new_ws :
workspace_create(NULL, prev_workspace_name);
@@ -447,21 +385,21 @@ bool workspace_switch(struct sway_container *workspace,
}
// Move sticky containers to new workspace
- struct sway_container *next_output = workspace->parent;
- struct sway_container *next_output_prev_ws =
- seat_get_active_child(seat, next_output);
- list_t *floating = next_output_prev_ws->sway_workspace->floating;
+ struct sway_output *next_output = workspace->output;
+ struct sway_workspace *next_output_prev_ws =
+ output_get_active_workspace(next_output);
bool has_sticky = false;
if (workspace != next_output_prev_ws) {
- for (int i = 0; i < floating->length; ++i) {
- struct sway_container *floater = floating->items[i];
+ for (int i = 0; i < next_output_prev_ws->floating->length; ++i) {
+ struct sway_container *floater =
+ next_output_prev_ws->floating->items[i];
if (floater->is_sticky) {
has_sticky = true;
- container_remove_child(floater);
+ container_detach(floater);
workspace_add_floating(workspace, floater);
- if (floater == focus) {
+ if (&floater->node == focus) {
seat_set_focus(seat, NULL);
- seat_set_focus(seat, floater);
+ seat_set_focus(seat, &floater->node);
}
--i;
}
@@ -470,9 +408,9 @@ bool workspace_switch(struct sway_container *workspace,
wlr_log(WLR_DEBUG, "Switching to workspace %p:%s",
workspace, workspace->name);
- struct sway_container *next = seat_get_focus_inactive(seat, workspace);
+ struct sway_node *next = seat_get_focus_inactive(seat, &workspace->node);
if (next == NULL) {
- next = workspace;
+ next = &workspace->node;
}
if (has_sticky) {
// If there's a sticky container, we might be setting focus to the same
@@ -483,35 +421,24 @@ bool workspace_switch(struct sway_container *workspace,
workspace_consider_destroy(active_ws);
}
seat_set_focus(seat, next);
- struct sway_container *output = container_parent(workspace, C_OUTPUT);
- arrange_windows(output);
+ arrange_workspace(workspace);
return true;
}
-bool workspace_is_visible(struct sway_container *ws) {
- if (ws->destroying) {
+bool workspace_is_visible(struct sway_workspace *ws) {
+ if (ws->node.destroying) {
return false;
}
- struct sway_container *output = container_parent(ws, C_OUTPUT);
- struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus = seat_get_focus_inactive(seat, output);
- if (focus->type != C_WORKSPACE) {
- focus = container_parent(focus, C_WORKSPACE);
- }
- return focus == ws;
+ return output_get_active_workspace(ws->output) == ws;
}
-bool workspace_is_empty(struct sway_container *ws) {
- if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) {
- return false;
- }
- if (ws->children->length) {
+bool workspace_is_empty(struct sway_workspace *ws) {
+ if (ws->tiling->length) {
return false;
}
// Sticky views are not considered to be part of this workspace
- list_t *floating = ws->sway_workspace->floating;
- for (int i = 0; i < floating->length; ++i) {
- struct sway_container *floater = floating->items[i];
+ for (int i = 0; i < ws->floating->length; ++i) {
+ struct sway_container *floater = ws->floating->items[i];
if (!floater->is_sticky) {
return false;
}
@@ -523,20 +450,19 @@ static int find_output(const void *id1, const void *id2) {
return strcmp(id1, id2) ? 0 : 1;
}
-void workspace_output_raise_priority(struct sway_container *workspace,
- struct sway_container *old_output, struct sway_container *output) {
- struct sway_workspace *ws = workspace->sway_workspace;
-
+void workspace_output_raise_priority(struct sway_workspace *ws,
+ struct sway_output *old_output, struct sway_output *output) {
int old_index = list_seq_find(ws->output_priority, find_output,
- old_output->name);
+ old_output->wlr_output->name);
if (old_index < 0) {
return;
}
int new_index = list_seq_find(ws->output_priority, find_output,
- output->name);
+ output->wlr_output->name);
if (new_index < 0) {
- list_insert(ws->output_priority, old_index, strdup(output->name));
+ list_insert(ws->output_priority, old_index,
+ strdup(output->wlr_output->name));
} else if (new_index > old_index) {
char *name = ws->output_priority->items[new_index];
list_del(ws->output_priority, new_index);
@@ -544,29 +470,24 @@ void workspace_output_raise_priority(struct sway_container *workspace,
}
}
-void workspace_output_add_priority(struct sway_container *workspace,
- struct sway_container *output) {
- int index = list_seq_find(workspace->sway_workspace->output_priority,
- find_output, output->name);
+void workspace_output_add_priority(struct sway_workspace *workspace,
+ struct sway_output *output) {
+ int index = list_seq_find(workspace->output_priority,
+ find_output, output->wlr_output->name);
if (index < 0) {
- list_add(workspace->sway_workspace->output_priority,
- strdup(output->name));
+ list_add(workspace->output_priority, strdup(output->wlr_output->name));
}
}
-static bool _output_by_name(struct sway_container *output, void *data) {
- return output->type == C_OUTPUT && strcasecmp(output->name, data) == 0;
-}
-
-struct sway_container *workspace_output_get_highest_available(
- struct sway_container *ws, struct sway_container *exclude) {
- for (int i = 0; i < ws->sway_workspace->output_priority->length; i++) {
- char *name = ws->sway_workspace->output_priority->items[i];
- if (exclude && strcasecmp(name, exclude->name) == 0) {
+struct sway_output *workspace_output_get_highest_available(
+ struct sway_workspace *ws, struct sway_output *exclude) {
+ for (int i = 0; i < ws->output_priority->length; i++) {
+ char *name = ws->output_priority->items[i];
+ if (exclude && strcasecmp(name, exclude->wlr_output->name) == 0) {
continue;
}
- struct sway_container *output = root_find_output(_output_by_name, name);
+ struct sway_output *output = output_by_name(name);
if (output) {
return output;
}
@@ -576,49 +497,42 @@ struct sway_container *workspace_output_get_highest_available(
}
static bool find_urgent_iterator(struct sway_container *con, void *data) {
- return con->type == C_VIEW && view_is_urgent(con->sway_view);
+ return con->view && view_is_urgent(con->view);
}
-void workspace_detect_urgent(struct sway_container *workspace) {
+void workspace_detect_urgent(struct sway_workspace *workspace) {
bool new_urgent = (bool)workspace_find_container(workspace,
find_urgent_iterator, NULL);
- if (workspace->sway_workspace->urgent != new_urgent) {
- workspace->sway_workspace->urgent = new_urgent;
+ if (workspace->urgent != new_urgent) {
+ workspace->urgent = new_urgent;
ipc_event_workspace(NULL, workspace, "urgent");
- container_damage_whole(workspace);
+ output_damage_whole(workspace->output);
}
}
-void workspace_for_each_container(struct sway_container *ws,
+void workspace_for_each_container(struct sway_workspace *ws,
void (*f)(struct sway_container *con, void *data), void *data) {
- if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) {
- return;
- }
// Tiling
- for (int i = 0; i < ws->children->length; ++i) {
- struct sway_container *container = ws->children->items[i];
+ for (int i = 0; i < ws->tiling->length; ++i) {
+ struct sway_container *container = ws->tiling->items[i];
f(container, data);
container_for_each_child(container, f, data);
}
// Floating
- for (int i = 0; i < ws->sway_workspace->floating->length; ++i) {
- struct sway_container *container =
- ws->sway_workspace->floating->items[i];
+ for (int i = 0; i < ws->floating->length; ++i) {
+ struct sway_container *container = ws->floating->items[i];
f(container, data);
container_for_each_child(container, f, data);
}
}
-struct sway_container *workspace_find_container(struct sway_container *ws,
+struct sway_container *workspace_find_container(struct sway_workspace *ws,
bool (*test)(struct sway_container *con, void *data), void *data) {
- if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) {
- return NULL;
- }
struct sway_container *result = NULL;
// Tiling
- for (int i = 0; i < ws->children->length; ++i) {
- struct sway_container *child = ws->children->items[i];
+ for (int i = 0; i < ws->tiling->length; ++i) {
+ struct sway_container *child = ws->tiling->items[i];
if (test(child, data)) {
return child;
}
@@ -627,8 +541,8 @@ struct sway_container *workspace_find_container(struct sway_container *ws,
}
}
// Floating
- for (int i = 0; i < ws->sway_workspace->floating->length; ++i) {
- struct sway_container *child = ws->sway_workspace->floating->items[i];
+ for (int i = 0; i < ws->floating->length; ++i) {
+ struct sway_container *child = ws->floating->items[i];
if (test(child, data)) {
return child;
}
@@ -639,37 +553,76 @@ struct sway_container *workspace_find_container(struct sway_container *ws,
return NULL;
}
-struct sway_container *workspace_wrap_children(struct sway_container *ws) {
- struct sway_container *middle = container_create(C_CONTAINER);
+struct sway_container *workspace_wrap_children(struct sway_workspace *ws) {
+ struct sway_container *middle = container_create(NULL);
middle->layout = ws->layout;
- while (ws->children->length) {
- struct sway_container *child = ws->children->items[0];
- container_remove_child(child);
+ while (ws->tiling->length) {
+ struct sway_container *child = ws->tiling->items[0];
+ container_detach(child);
container_add_child(middle, child);
}
- container_add_child(ws, middle);
+ workspace_add_tiling(ws, middle);
return middle;
}
-void workspace_add_floating(struct sway_container *workspace,
- struct sway_container *con) {
- if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) {
- return;
+void workspace_detach(struct sway_workspace *workspace) {
+ struct sway_output *output = workspace->output;
+ int index = list_find(output->workspaces, workspace);
+ if (index != -1) {
+ list_del(output->workspaces, index);
}
- if (!sway_assert(con->parent == NULL, "Expected an orphan container")) {
- return;
+ workspace->output = NULL;
+
+ node_set_dirty(&workspace->node);
+ node_set_dirty(&output->node);
+}
+
+static void set_workspace(struct sway_container *container, void *data) {
+ container->workspace = container->parent->workspace;
+}
+
+void workspace_add_tiling(struct sway_workspace *workspace,
+ struct sway_container *con) {
+ if (con->workspace) {
+ container_detach(con);
}
+ list_add(workspace->tiling, con);
+ con->workspace = workspace;
+ container_for_each_child(con, set_workspace, NULL);
+ container_handle_fullscreen_reparent(con);
+ workspace_update_representation(workspace);
+ node_set_dirty(&workspace->node);
+ node_set_dirty(&con->node);
+}
- list_add(workspace->sway_workspace->floating, con);
- con->parent = workspace;
- container_set_dirty(workspace);
- container_set_dirty(con);
+void workspace_add_floating(struct sway_workspace *workspace,
+ struct sway_container *con) {
+ if (con->workspace) {
+ container_detach(con);
+ }
+ list_add(workspace->floating, con);
+ con->workspace = workspace;
+ container_for_each_child(con, set_workspace, NULL);
+ container_handle_fullscreen_reparent(con);
+ node_set_dirty(&workspace->node);
+ node_set_dirty(&con->node);
}
-void workspace_remove_gaps(struct sway_container *ws) {
- if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) {
- return;
+void workspace_insert_tiling(struct sway_workspace *workspace,
+ struct sway_container *con, int index) {
+ if (con->workspace) {
+ container_detach(con);
}
+ list_insert(workspace->tiling, index, con);
+ con->workspace = workspace;
+ container_for_each_child(con, set_workspace, NULL);
+ container_handle_fullscreen_reparent(con);
+ workspace_update_representation(workspace);
+ node_set_dirty(&workspace->node);
+ node_set_dirty(&con->node);
+}
+
+void workspace_remove_gaps(struct sway_workspace *ws) {
if (ws->current_gaps == 0) {
return;
}
@@ -681,15 +634,12 @@ void workspace_remove_gaps(struct sway_container *ws) {
ws->current_gaps = 0;
}
-void workspace_add_gaps(struct sway_container *ws) {
- if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) {
- return;
- }
+void workspace_add_gaps(struct sway_workspace *ws) {
if (ws->current_gaps > 0) {
return;
}
bool should_apply =
- config->edge_gaps || (config->smart_gaps && ws->children->length > 1);
+ config->edge_gaps || (config->smart_gaps && ws->tiling->length > 1);
if (!should_apply) {
return;
}
@@ -708,3 +658,36 @@ void workspace_add_gaps(struct sway_container *ws) {
ws->width -= 2 * ws->current_gaps;
ws->height -= 2 * ws->current_gaps;
}
+
+struct sway_container *workspace_split(struct sway_workspace *workspace,
+ enum sway_container_layout layout) {
+ if (workspace->tiling->length == 0) {
+ workspace->prev_split_layout = workspace->layout;
+ workspace->layout = layout;
+ return NULL;
+ }
+
+ enum sway_container_layout old_layout = workspace->layout;
+ struct sway_container *middle = workspace_wrap_children(workspace);
+ workspace->layout = layout;
+ middle->layout = old_layout;
+
+ return middle;
+}
+
+void workspace_update_representation(struct sway_workspace *ws) {
+ size_t len = container_build_representation(ws->layout, ws->tiling, NULL);
+ free(ws->representation);
+ ws->representation = calloc(len + 1, sizeof(char));
+ if (!sway_assert(ws->representation, "Unable to allocate title string")) {
+ return;
+ }
+ container_build_representation(ws->layout, ws->tiling, ws->representation);
+}
+
+void workspace_get_box(struct sway_workspace *workspace, struct wlr_box *box) {
+ box->x = workspace->x;
+ box->y = workspace->y;
+ box->width = workspace->width;
+ box->height = workspace->height;
+}