aboutsummaryrefslogtreecommitdiffstats
path: root/sway/input
diff options
context:
space:
mode:
authorLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-08-30 21:00:10 +1000
committerLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-09-05 18:01:43 +1000
commit7586f150c058997d9dde387ea7c091ffa7a3c3c7 (patch)
tree63d19027974c1db62ce3a74ca1d2314eb6d5049b /sway/input
parentMerge pull request #2569 from RyanDwyer/deny-reload-repeat (diff)
downloadsway-7586f150c058997d9dde387ea7c091ffa7a3c3c7.tar.gz
sway-7586f150c058997d9dde387ea7c091ffa7a3c3c7.tar.zst
sway-7586f150c058997d9dde387ea7c091ffa7a3c3c7.zip
Implement type safe arguments and demote sway_container
This commit changes the meaning of sway_container so that it only refers to layout containers and view containers. Workspaces, outputs and the root are no longer known as containers. Instead, root, outputs, workspaces and containers are all a type of node, and containers come in two types: layout containers and view containers. In addition to the above, this implements type safe variables. This means we use specific types such as sway_output and sway_workspace instead of generic containers or nodes. However, it's worth noting that in a few places places (eg. seat focus and transactions) referring to them in a generic way is unavoidable which is why we still use nodes in some places. If you want a TL;DR, look at node.h, as well as the struct definitions for root, output, workspace and container. Note that sway_output now contains a workspaces list, and workspaces now contain a tiling and floating list, and containers now contain a pointer back to the workspace. There are now functions for seat_get_focused_workspace and seat_get_focused_container. The latter will return NULL if a workspace itself is focused. Most other seat functions like seat_get_focus and seat_set_focus now accept and return nodes. In the config->handler_context struct, current_container has been replaced with three pointers: node, container and workspace. node is the same as what current_container was, while workspace is the workspace that the node resides on and container is the actual container, which may be NULL if a workspace itself is focused. The global root_container variable has been replaced with one simply called root, which is a pointer to the sway_root instance. The way outputs are created, enabled, disabled and destroyed has changed. Previously we'd wrap the sway_output in a container when it is enabled, but as we don't have containers any more it needs a different approach. The output_create and output_destroy functions previously created/destroyed the container, but now they create/destroy the sway_output. There is a new function output_disable to disable an output without destroying it. Containers have a new view property. If this is populated then the container is a view container, otherwise it's a layout container. Like before, this property is immutable for the life of the container. Containers have both a `sway_container *parent` and `sway_workspace *workspace`. As we use specific types now, parent cannot point to a workspace so it'll be NULL for containers which are direct children of the workspace. The workspace property is set for all containers, except those which are hidden in the scratchpad as they have no workspace. In some cases we need to refer to workspaces in a container-like way. For example, workspaces have layout and children, but when using specific types this makes it difficult. Likewise, it's difficult for a container to get its parent's layout when the parent could be another container or a workspace. To make it easier, some helper functions have been created: container_parent_layout and container_get_siblings. container_remove_child has been renamed to container_detach and container_replace_child has been renamed to container_replace. `container_handle_fullscreen_reparent(con, old_parent)` has had the old_parent removed. We now unfullscreen the workspace when detaching the container, so this function is simplified and only needs one argument now. container_notify_subtree_changed has been renamed to container_update_representation. This is more descriptive of its purpose. I also wanted to be able to call it with whatever container was changed rather than the container's parent, which makes bubbling up to the workspace easier. There are now state structs per node thing. ie. sway_output_state, sway_workspace_state and sway_container_state. The focus, move and layout commands have been completely refactored to work with the specific types. I considered making these a separate PR, but I'd be backporting my changes only to replace them again, and it's easier just to test everything at once.
Diffstat (limited to 'sway/input')
-rw-r--r--sway/input/cursor.c158
-rw-r--r--sway/input/input-manager.c14
-rw-r--r--sway/input/seat.c514
3 files changed, 335 insertions, 351 deletions
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index 00240e84..15993265 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -20,6 +20,7 @@
20#include "sway/layers.h" 20#include "sway/layers.h"
21#include "sway/output.h" 21#include "sway/output.h"
22#include "sway/tree/arrange.h" 22#include "sway/tree/arrange.h"
23#include "sway/tree/container.h"
23#include "sway/tree/root.h" 24#include "sway/tree/root.h"
24#include "sway/tree/view.h" 25#include "sway/tree/view.h"
25#include "sway/tree/workspace.h" 26#include "sway/tree/workspace.h"
@@ -50,15 +51,15 @@ static struct wlr_surface *layer_surface_at(struct sway_output *output,
50} 51}
51 52
52/** 53/**
53 * Returns the container at the cursor's position. If there is a surface at that 54 * Returns the node at the cursor's position. If there is a surface at that
54 * location, it is stored in **surface (it may not be a view). 55 * location, it is stored in **surface (it may not be a view).
55 */ 56 */
56static struct sway_container *container_at_coords( 57static struct sway_node *node_at_coords(
57 struct sway_seat *seat, double lx, double ly, 58 struct sway_seat *seat, double lx, double ly,
58 struct wlr_surface **surface, double *sx, double *sy) { 59 struct wlr_surface **surface, double *sx, double *sy) {
59 // check for unmanaged views first 60 // check for unmanaged views first
60#ifdef HAVE_XWAYLAND 61#ifdef HAVE_XWAYLAND
61 struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged; 62 struct wl_list *unmanaged = &root->xwayland_unmanaged;
62 struct sway_xwayland_unmanaged *unmanaged_surface; 63 struct sway_xwayland_unmanaged *unmanaged_surface;
63 wl_list_for_each_reverse(unmanaged_surface, unmanaged, link) { 64 wl_list_for_each_reverse(unmanaged_surface, unmanaged, link) {
64 struct wlr_xwayland_surface *xsurface = 65 struct wlr_xwayland_surface *xsurface =
@@ -75,67 +76,64 @@ static struct sway_container *container_at_coords(
75 } 76 }
76#endif 77#endif
77 // find the output the cursor is on 78 // find the output the cursor is on
78 struct wlr_output_layout *output_layout =
79 root_container.sway_root->output_layout;
80 struct wlr_output *wlr_output = wlr_output_layout_output_at( 79 struct wlr_output *wlr_output = wlr_output_layout_output_at(
81 output_layout, lx, ly); 80 root->output_layout, lx, ly);
82 if (wlr_output == NULL) { 81 if (wlr_output == NULL) {
83 return NULL; 82 return NULL;
84 } 83 }
85 struct sway_output *output = wlr_output->data; 84 struct sway_output *output = wlr_output->data;
86 double ox = lx, oy = ly; 85 double ox = lx, oy = ly;
87 wlr_output_layout_output_coords(output_layout, wlr_output, &ox, &oy); 86 wlr_output_layout_output_coords(root->output_layout, wlr_output, &ox, &oy);
88 87
89 // find the focused workspace on the output for this seat 88 // find the focused workspace on the output for this seat
90 struct sway_container *ws = seat_get_focus_inactive(seat, output->swayc); 89 struct sway_workspace *ws = output_get_active_workspace(output);
91 if (ws && ws->type != C_WORKSPACE) {
92 ws = container_parent(ws, C_WORKSPACE);
93 }
94 if (!ws) {
95 return output->swayc;
96 }
97 90
98 if ((*surface = layer_surface_at(output, 91 if ((*surface = layer_surface_at(output,
99 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], 92 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
100 ox, oy, sx, sy))) { 93 ox, oy, sx, sy))) {
101 return ws; 94 return &ws->node;
102 } 95 }
103 if (ws->sway_workspace->fullscreen) { 96 if (ws->fullscreen) {
104 return tiling_container_at(ws->sway_workspace->fullscreen, lx, ly, 97 struct sway_container *con =
105 surface, sx, sy); 98 tiling_container_at(&ws->fullscreen->node, lx, ly, surface, sx, sy);
99 if (con) {
100 return &con->node;
101 }
102 return NULL;
106 } 103 }
107 if ((*surface = layer_surface_at(output, 104 if ((*surface = layer_surface_at(output,
108 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], 105 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
109 ox, oy, sx, sy))) { 106 ox, oy, sx, sy))) {
110 return ws; 107 return &ws->node;
111 } 108 }
112 109
113 struct sway_container *c; 110 struct sway_container *c;
114 if ((c = container_at(ws, lx, ly, surface, sx, sy))) { 111 if ((c = container_at(ws, lx, ly, surface, sx, sy))) {
115 return c; 112 return &c->node;
116 } 113 }
117 114
118 if ((*surface = layer_surface_at(output, 115 if ((*surface = layer_surface_at(output,
119 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], 116 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
120 ox, oy, sx, sy))) { 117 ox, oy, sx, sy))) {
121 return ws; 118 return &ws->node;
122 } 119 }
123 if ((*surface = layer_surface_at(output, 120 if ((*surface = layer_surface_at(output,
124 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], 121 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
125 ox, oy, sx, sy))) { 122 ox, oy, sx, sy))) {
126 return ws; 123 return &ws->node;
127 } 124 }
128 125
129 c = seat_get_active_child(seat, output->swayc); 126 return &ws->node;
130 if (c) { 127}
131 return c;
132 }
133 if (!c && output->swayc->children->length) {
134 c = output->swayc->children->items[0];
135 return c;
136 }
137 128
138 return output->swayc; 129static struct sway_container *container_at_coords(struct sway_seat *seat,
130 double lx, double ly,
131 struct wlr_surface **surface, double *sx, double *sy) {
132 struct sway_node *node = node_at_coords(seat, lx, ly, surface, sx, sy);
133 if (node && node->type == N_CONTAINER) {
134 return node->sway_container;
135 }
136 return NULL;
139} 137}
140 138
141/** 139/**
@@ -160,13 +158,14 @@ static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) {
160 158
161 // Iterate the parents until we find one with the layout we want, 159 // Iterate the parents until we find one with the layout we want,
162 // then check if the child has siblings between it and the edge. 160 // then check if the child has siblings between it and the edge.
163 while (cont->type != C_OUTPUT) { 161 while (cont) {
164 if (cont->parent->layout == layout) { 162 if (container_parent_layout(cont) == layout) {
165 int index = list_find(cont->parent->children, cont); 163 list_t *siblings = container_get_siblings(cont);
164 int index = list_find(siblings, cont);
166 if (index > 0 && (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_TOP)) { 165 if (index > 0 && (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_TOP)) {
167 return false; 166 return false;
168 } 167 }
169 if (index < cont->parent->children->length - 1 && 168 if (index < siblings->length - 1 &&
170 (edge == WLR_EDGE_RIGHT || edge == WLR_EDGE_BOTTOM)) { 169 (edge == WLR_EDGE_RIGHT || edge == WLR_EDGE_BOTTOM)) {
171 return false; 170 return false;
172 } 171 }
@@ -178,10 +177,10 @@ static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) {
178 177
179static enum wlr_edges find_edge(struct sway_container *cont, 178static enum wlr_edges find_edge(struct sway_container *cont,
180 struct sway_cursor *cursor) { 179 struct sway_cursor *cursor) {
181 if (cont->type != C_VIEW) { 180 if (!cont->view) {
182 return WLR_EDGE_NONE; 181 return WLR_EDGE_NONE;
183 } 182 }
184 struct sway_view *view = cont->sway_view; 183 struct sway_view *view = cont->view;
185 if (view->border == B_NONE || !view->border_thickness || view->using_csd) { 184 if (view->border == B_NONE || !view->border_thickness || view->using_csd) {
186 return WLR_EDGE_NONE; 185 return WLR_EDGE_NONE;
187 } 186 }
@@ -219,7 +218,7 @@ static enum wlr_edges find_resize_edge(struct sway_container *cont,
219static void handle_down_motion(struct sway_seat *seat, 218static void handle_down_motion(struct sway_seat *seat,
220 struct sway_cursor *cursor, uint32_t time_msec) { 219 struct sway_cursor *cursor, uint32_t time_msec) {
221 struct sway_container *con = seat->op_container; 220 struct sway_container *con = seat->op_container;
222 if (seat_is_input_allowed(seat, con->sway_view->surface)) { 221 if (seat_is_input_allowed(seat, con->view->surface)) {
223 double moved_x = cursor->cursor->x - seat->op_ref_lx; 222 double moved_x = cursor->cursor->x - seat->op_ref_lx;
224 double moved_y = cursor->cursor->y - seat->op_ref_ly; 223 double moved_y = cursor->cursor->y - seat->op_ref_ly;
225 double sx = seat->op_ref_con_lx + moved_x; 224 double sx = seat->op_ref_con_lx + moved_x;
@@ -260,8 +259,7 @@ static void calculate_floating_constraints(struct sway_container *con,
260 if (config->floating_maximum_width == -1) { // no maximum 259 if (config->floating_maximum_width == -1) { // no maximum
261 *max_width = INT_MAX; 260 *max_width = INT_MAX;
262 } else if (config->floating_maximum_width == 0) { // automatic 261 } else if (config->floating_maximum_width == 0) { // automatic
263 struct sway_container *ws = container_parent(con, C_WORKSPACE); 262 *max_width = con->workspace->width;
264 *max_width = ws->width;
265 } else { 263 } else {
266 *max_width = config->floating_maximum_width; 264 *max_width = config->floating_maximum_width;
267 } 265 }
@@ -269,8 +267,7 @@ static void calculate_floating_constraints(struct sway_container *con,
269 if (config->floating_maximum_height == -1) { // no maximum 267 if (config->floating_maximum_height == -1) { // no maximum
270 *max_height = INT_MAX; 268 *max_height = INT_MAX;
271 } else if (config->floating_maximum_height == 0) { // automatic 269 } else if (config->floating_maximum_height == 0) { // automatic
272 struct sway_container *ws = container_parent(con, C_WORKSPACE); 270 *max_height = con->workspace->height;
273 *max_height = ws->height;
274 } else { 271 } else {
275 *max_height = config->floating_maximum_height; 272 *max_height = config->floating_maximum_height;
276 } 273 }
@@ -314,9 +311,9 @@ static void handle_resize_floating_motion(struct sway_seat *seat,
314 height = fmax(min_height, fmin(height, max_height)); 311 height = fmax(min_height, fmin(height, max_height));
315 312
316 // Apply the view's min/max size 313 // Apply the view's min/max size
317 if (con->type == C_VIEW) { 314 if (con->view) {
318 double view_min_width, view_max_width, view_min_height, view_max_height; 315 double view_min_width, view_max_width, view_min_height, view_max_height;
319 view_get_constraints(con->sway_view, &view_min_width, &view_max_width, 316 view_get_constraints(con->view, &view_min_width, &view_max_width,
320 &view_min_height, &view_max_height); 317 &view_min_height, &view_max_height);
321 width = fmax(view_min_width, fmin(width, view_max_width)); 318 width = fmax(view_min_width, fmin(width, view_max_width));
322 height = fmax(view_min_height, fmin(height, view_max_height)); 319 height = fmax(view_min_height, fmin(height, view_max_height));
@@ -357,15 +354,15 @@ static void handle_resize_floating_motion(struct sway_seat *seat,
357 con->width += relative_grow_width; 354 con->width += relative_grow_width;
358 con->height += relative_grow_height; 355 con->height += relative_grow_height;
359 356
360 if (con->type == C_VIEW) { 357 if (con->view) {
361 struct sway_view *view = con->sway_view; 358 struct sway_view *view = con->view;
362 view->x += relative_grow_x; 359 view->x += relative_grow_x;
363 view->y += relative_grow_y; 360 view->y += relative_grow_y;
364 view->width += relative_grow_width; 361 view->width += relative_grow_width;
365 view->height += relative_grow_height; 362 view->height += relative_grow_height;
366 } 363 }
367 364
368 arrange_windows(con); 365 arrange_container(con);
369} 366}
370 367
371static void handle_resize_tiling_motion(struct sway_seat *seat, 368static void handle_resize_tiling_motion(struct sway_seat *seat,
@@ -435,44 +432,40 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
435 struct wlr_surface *surface = NULL; 432 struct wlr_surface *surface = NULL;
436 double sx, sy; 433 double sx, sy;
437 434
438 // Find the container beneath the pointer's previous position 435 // Find the node beneath the pointer's previous position
439 struct sway_container *prev_c = container_at_coords(seat, 436 struct sway_node *prev_node = node_at_coords(seat,
440 cursor->previous.x, cursor->previous.y, &surface, &sx, &sy); 437 cursor->previous.x, cursor->previous.y, &surface, &sx, &sy);
441 // Update the stored previous position 438 // Update the stored previous position
442 cursor->previous.x = cursor->cursor->x; 439 cursor->previous.x = cursor->cursor->x;
443 cursor->previous.y = cursor->cursor->y; 440 cursor->previous.y = cursor->cursor->y;
444 441
445 struct sway_container *c = container_at_coords(seat, 442 struct sway_node *node = node_at_coords(seat,
446 cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); 443 cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
447 if (c && config->focus_follows_mouse && allow_refocusing) { 444 if (node && config->focus_follows_mouse && allow_refocusing) {
448 struct sway_container *focus = seat_get_focus(seat); 445 struct sway_node *focus = seat_get_focus(seat);
449 if (focus && c->type == C_WORKSPACE) { 446 if (focus && node->type == N_WORKSPACE) {
450 // Only follow the mouse if it would move to a new output 447 // Only follow the mouse if it would move to a new output
451 // Otherwise we'll focus the workspace, which is probably wrong 448 // Otherwise we'll focus the workspace, which is probably wrong
452 if (focus->type != C_OUTPUT) { 449 struct sway_output *focused_output = node_get_output(focus);
453 focus = container_parent(focus, C_OUTPUT); 450 struct sway_output *output = node_get_output(node);
454 } 451 if (output != focused_output) {
455 struct sway_container *output = c; 452 seat_set_focus_warp(seat, node, false, true);
456 if (output->type != C_OUTPUT) {
457 output = container_parent(c, C_OUTPUT);
458 }
459 if (output != focus) {
460 seat_set_focus_warp(seat, c, false, true);
461 } 453 }
462 } else if (c->type == C_VIEW) { 454 } else if (node->type == N_CONTAINER && node->sway_container->view) {
463 // Focus c if the following are true: 455 // Focus node if the following are true:
464 // - cursor is over a new view, i.e. entered a new window; and 456 // - cursor is over a new view, i.e. entered a new window; and
465 // - the new view is visible, i.e. not hidden in a stack or tab; and 457 // - the new view is visible, i.e. not hidden in a stack or tab; and
466 // - the seat does not have a keyboard grab 458 // - the seat does not have a keyboard grab
467 if (!wlr_seat_keyboard_has_grab(cursor->seat->wlr_seat) && 459 if (!wlr_seat_keyboard_has_grab(cursor->seat->wlr_seat) &&
468 c != prev_c && 460 node != prev_node &&
469 view_is_visible(c->sway_view)) { 461 view_is_visible(node->sway_container->view)) {
470 seat_set_focus_warp(seat, c, false, true); 462 seat_set_focus_warp(seat, node, false, true);
471 } else { 463 } else {
472 struct sway_container *next_focus = 464 struct sway_node *next_focus =
473 seat_get_focus_inactive(seat, &root_container); 465 seat_get_focus_inactive(seat, &root->node);
474 if (next_focus && next_focus->type == C_VIEW && 466 if (next_focus && next_focus->type == N_CONTAINER &&
475 view_is_visible(next_focus->sway_view)) { 467 node->sway_container->view &&
468 view_is_visible(next_focus->sway_container->view)) {
476 seat_set_focus_warp(seat, next_focus, false, true); 469 seat_set_focus_warp(seat, next_focus, false, true);
477 } 470 }
478 } 471 }
@@ -486,12 +479,12 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
486 if (client != cursor->image_client) { 479 if (client != cursor->image_client) {
487 cursor_set_image(cursor, "left_ptr", client); 480 cursor_set_image(cursor, "left_ptr", client);
488 } 481 }
489 } else if (c) { 482 } else if (node && node->type == N_CONTAINER) {
490 // Try a container's resize edge 483 // Try a node's resize edge
491 enum wlr_edges edge = find_resize_edge(c, cursor); 484 enum wlr_edges edge = find_resize_edge(node->sway_container, cursor);
492 if (edge == WLR_EDGE_NONE) { 485 if (edge == WLR_EDGE_NONE) {
493 cursor_set_image(cursor, "left_ptr", NULL); 486 cursor_set_image(cursor, "left_ptr", NULL);
494 } else if (container_is_floating(c)) { 487 } else if (container_is_floating(node->sway_container)) {
495 cursor_set_image(cursor, wlr_xcursor_get_resize_name(edge), NULL); 488 cursor_set_image(cursor, wlr_xcursor_get_resize_name(edge), NULL);
496 } else { 489 } else {
497 if (edge & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) { 490 if (edge & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) {
@@ -684,7 +677,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
684 // Handle tiling resize via border 677 // Handle tiling resize via border
685 if (resize_edge && button == BTN_LEFT && state == WLR_BUTTON_PRESSED && 678 if (resize_edge && button == BTN_LEFT && state == WLR_BUTTON_PRESSED &&
686 !is_floating) { 679 !is_floating) {
687 seat_set_focus(seat, cont); 680 seat_set_focus(seat, &cont->node);
688 seat_begin_resize_tiling(seat, cont, button, edge); 681 seat_begin_resize_tiling(seat, cont, button, edge);
689 return; 682 return;
690 } 683 }
@@ -713,7 +706,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
713 image = "sw-resize"; 706 image = "sw-resize";
714 } 707 }
715 cursor_set_image(seat->cursor, image, NULL); 708 cursor_set_image(seat->cursor, image, NULL);
716 seat_set_focus(seat, cont); 709 seat_set_focus(seat, &cont->node);
717 seat_begin_resize_tiling(seat, cont, button, edge); 710 seat_begin_resize_tiling(seat, cont, button, edge);
718 return; 711 return;
719 } 712 }
@@ -725,7 +718,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
725 uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT; 718 uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT;
726 if (button == btn_move && state == WLR_BUTTON_PRESSED && 719 if (button == btn_move && state == WLR_BUTTON_PRESSED &&
727 (mod_pressed || on_titlebar)) { 720 (mod_pressed || on_titlebar)) {
728 while (cont->parent->type != C_WORKSPACE) { 721 while (cont->parent) {
729 cont = cont->parent; 722 cont = cont->parent;
730 } 723 }
731 seat_begin_move(seat, cont, button); 724 seat_begin_move(seat, cont, button);
@@ -747,7 +740,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
747 BTN_LEFT : BTN_RIGHT; 740 BTN_LEFT : BTN_RIGHT;
748 if (mod_pressed && button == btn_resize) { 741 if (mod_pressed && button == btn_resize) {
749 struct sway_container *floater = cont; 742 struct sway_container *floater = cont;
750 while (floater->parent->type != C_WORKSPACE) { 743 while (floater->parent) {
751 floater = floater->parent; 744 floater = floater->parent;
752 } 745 }
753 edge = 0; 746 edge = 0;
@@ -762,7 +755,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
762 755
763 // Handle mousedown on a container surface 756 // Handle mousedown on a container surface
764 if (surface && cont && state == WLR_BUTTON_PRESSED) { 757 if (surface && cont && state == WLR_BUTTON_PRESSED) {
765 seat_set_focus(seat, cont); 758 seat_set_focus(seat, &cont->node);
766 seat_pointer_notify_button(seat, time_msec, button, state); 759 seat_pointer_notify_button(seat, time_msec, button, state);
767 seat_begin_down(seat, cont, button, sx, sy); 760 seat_begin_down(seat, cont, button, sx, sy);
768 return; 761 return;
@@ -770,7 +763,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
770 763
771 // Handle clicking a container surface 764 // Handle clicking a container surface
772 if (cont) { 765 if (cont) {
773 seat_set_focus(seat, cont); 766 seat_set_focus(seat, &cont->node);
774 seat_pointer_notify_button(seat, time_msec, button, state); 767 seat_pointer_notify_button(seat, time_msec, button, state);
775 return; 768 return;
776 } 769 }
@@ -1025,8 +1018,7 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
1025 cursor->previous.y = wlr_cursor->y; 1018 cursor->previous.y = wlr_cursor->y;
1026 1019
1027 cursor->seat = seat; 1020 cursor->seat = seat;
1028 wlr_cursor_attach_output_layout(wlr_cursor, 1021 wlr_cursor_attach_output_layout(wlr_cursor, root->output_layout);
1029 root_container.sway_root->output_layout);
1030 1022
1031 // input events 1023 // input events
1032 wl_signal_add(&wlr_cursor->events.motion, &cursor->motion); 1024 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)
293 struct sway_seat *seat; 293 struct sway_seat *seat;
294 wl_list_for_each(seat, &input_manager->seats, link) { 294 wl_list_for_each(seat, &input_manager->seats, link) {
295 seat_set_exclusive_client(seat, NULL); 295 seat_set_exclusive_client(seat, NULL);
296 struct sway_container *previous = seat_get_focus(seat); 296 struct sway_node *previous = seat_get_focus(seat);
297 if (previous) { 297 if (previous) {
298 wlr_log(WLR_DEBUG, "Returning focus to %p %s '%s'", previous,
299 container_type_to_str(previous->type), previous->name);
300 // Hack to get seat to re-focus the return value of get_focus 298 // Hack to get seat to re-focus the return value of get_focus
301 seat_set_focus(seat, previous->parent); 299 seat_set_focus(seat, NULL);
302 seat_set_focus(seat, previous); 300 seat_set_focus(seat, previous);
303 } 301 }
304 } 302 }
@@ -369,10 +367,10 @@ struct sway_input_manager *input_manager_create(
369} 367}
370 368
371bool input_manager_has_focus(struct sway_input_manager *input, 369bool input_manager_has_focus(struct sway_input_manager *input,
372 struct sway_container *container) { 370 struct sway_node *node) {
373 struct sway_seat *seat = NULL; 371 struct sway_seat *seat = NULL;
374 wl_list_for_each(seat, &input->seats, link) { 372 wl_list_for_each(seat, &input->seats, link) {
375 if (seat_get_focus(seat) == container) { 373 if (seat_get_focus(seat) == node) {
376 return true; 374 return true;
377 } 375 }
378 } 376 }
@@ -381,10 +379,10 @@ bool input_manager_has_focus(struct sway_input_manager *input,
381} 379}
382 380
383void input_manager_set_focus(struct sway_input_manager *input, 381void input_manager_set_focus(struct sway_input_manager *input,
384 struct sway_container *container) { 382 struct sway_node *node) {
385 struct sway_seat *seat; 383 struct sway_seat *seat;
386 wl_list_for_each(seat, &input->seats, link) { 384 wl_list_for_each(seat, &input->seats, link) {
387 seat_set_focus(seat, container); 385 seat_set_focus(seat, node);
388 } 386 }
389} 387}
390 388
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 4b7c7893..2f7a3318 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -47,48 +47,36 @@ void seat_destroy(struct sway_seat *seat) {
47 seat_device_destroy(seat_device); 47 seat_device_destroy(seat_device);
48 } 48 }
49 sway_cursor_destroy(seat->cursor); 49 sway_cursor_destroy(seat->cursor);
50 wl_list_remove(&seat->new_container.link); 50 wl_list_remove(&seat->new_node.link);
51 wl_list_remove(&seat->new_drag_icon.link); 51 wl_list_remove(&seat->new_drag_icon.link);
52 wl_list_remove(&seat->link); 52 wl_list_remove(&seat->link);
53 wlr_seat_destroy(seat->wlr_seat); 53 wlr_seat_destroy(seat->wlr_seat);
54} 54}
55 55
56static struct sway_seat_container *seat_container_from_container( 56static struct sway_seat_node *seat_node_from_node(
57 struct sway_seat *seat, struct sway_container *con); 57 struct sway_seat *seat, struct sway_node *node);
58 58
59static void seat_container_destroy(struct sway_seat_container *seat_con) { 59static void seat_node_destroy(struct sway_seat_node *seat_node) {
60 struct sway_container *con = seat_con->container; 60 wl_list_remove(&seat_node->destroy.link);
61 struct sway_container *child = NULL; 61 wl_list_remove(&seat_node->link);
62 62 free(seat_node);
63 if (con->children != NULL) {
64 for (int i = 0; i < con->children->length; ++i) {
65 child = con->children->items[i];
66 struct sway_seat_container *seat_child =
67 seat_container_from_container(seat_con->seat, child);
68 seat_container_destroy(seat_child);
69 }
70 }
71
72 wl_list_remove(&seat_con->destroy.link);
73 wl_list_remove(&seat_con->link);
74 free(seat_con);
75} 63}
76 64
77/** 65/**
78 * Activate all views within this container recursively. 66 * Activate all views within this container recursively.
79 */ 67 */
80static void seat_send_activate(struct sway_container *con, 68static void seat_send_activate(struct sway_node *node, struct sway_seat *seat) {
81 struct sway_seat *seat) { 69 if (node_is_view(node)) {
82 if (con->type == C_VIEW) { 70 if (!seat_is_input_allowed(seat, node->sway_container->view->surface)) {
83 if (!seat_is_input_allowed(seat, con->sway_view->surface)) {
84 wlr_log(WLR_DEBUG, "Refusing to set focus, input is inhibited"); 71 wlr_log(WLR_DEBUG, "Refusing to set focus, input is inhibited");
85 return; 72 return;
86 } 73 }
87 view_set_activated(con->sway_view, true); 74 view_set_activated(node->sway_container->view, true);
88 } else { 75 } else {
89 for (int i = 0; i < con->children->length; ++i) { 76 list_t *children = node_get_children(node);
90 struct sway_container *child = con->children->items[i]; 77 for (int i = 0; i < children->length; ++i) {
91 seat_send_activate(child, seat); 78 struct sway_container *child = children->items[i];
79 seat_send_activate(&child->node, seat);
92 } 80 }
93 } 81 }
94} 82}
@@ -98,14 +86,15 @@ static void seat_send_activate(struct sway_container *con,
98 * If con is a container, set all child views as active and don't enable 86 * If con is a container, set all child views as active and don't enable
99 * keyboard input on any. 87 * keyboard input on any.
100 */ 88 */
101static void seat_send_focus(struct sway_container *con, 89static void seat_send_focus(struct sway_node *node, struct sway_seat *seat) {
102 struct sway_seat *seat) { 90 seat_send_activate(node, seat);
103 seat_send_activate(con, seat);
104 91
105 if (con->type == C_VIEW 92 struct sway_view *view = node->type == N_CONTAINER ?
106 && seat_is_input_allowed(seat, con->sway_view->surface)) { 93 node->sway_container->view : NULL;
94
95 if (view && seat_is_input_allowed(seat, view->surface)) {
107#ifdef HAVE_XWAYLAND 96#ifdef HAVE_XWAYLAND
108 if (con->sway_view->type == SWAY_VIEW_XWAYLAND) { 97 if (view->type == SWAY_VIEW_XWAYLAND) {
109 struct wlr_xwayland *xwayland = 98 struct wlr_xwayland *xwayland =
110 seat->input->server->xwayland.wlr_xwayland; 99 seat->input->server->xwayland.wlr_xwayland;
111 wlr_xwayland_set_seat(xwayland, seat->wlr_seat); 100 wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
@@ -114,71 +103,67 @@ static void seat_send_focus(struct sway_container *con,
114 struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); 103 struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
115 if (keyboard) { 104 if (keyboard) {
116 wlr_seat_keyboard_notify_enter(seat->wlr_seat, 105 wlr_seat_keyboard_notify_enter(seat->wlr_seat,
117 con->sway_view->surface, keyboard->keycodes, 106 view->surface, keyboard->keycodes,
118 keyboard->num_keycodes, &keyboard->modifiers); 107 keyboard->num_keycodes, &keyboard->modifiers);
119 } else { 108 } else {
120 wlr_seat_keyboard_notify_enter( 109 wlr_seat_keyboard_notify_enter(
121 seat->wlr_seat, con->sway_view->surface, NULL, 0, NULL); 110 seat->wlr_seat, view->surface, NULL, 0, NULL);
122 } 111 }
123 } 112 }
124} 113}
125 114
126void seat_focus_inactive_children_for_each(struct sway_seat *seat, 115void seat_for_each_node(struct sway_seat *seat,
127 struct sway_container *container, 116 void (*f)(struct sway_node *node, void *data), void *data) {
128 void (*f)(struct sway_container *container, void *data), void *data) { 117 struct sway_seat_node *current = NULL;
129 struct sway_seat_container *current = NULL;
130 wl_list_for_each(current, &seat->focus_stack, link) { 118 wl_list_for_each(current, &seat->focus_stack, link) {
131 if (current->container->parent == NULL) { 119 f(current->node, data);
132 continue;
133 }
134 if (current->container->parent == container) {
135 f(current->container, data);
136 }
137 } 120 }
138} 121}
139 122
140struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat, 123struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat,
141 struct sway_container *ancestor) { 124 struct sway_node *ancestor) {
142 if (ancestor->type == C_VIEW) { 125 if (ancestor->type == N_CONTAINER && ancestor->sway_container->view) {
143 return ancestor; 126 return ancestor->sway_container;
144 } 127 }
145 struct sway_seat_container *current; 128 struct sway_seat_node *current;
146 wl_list_for_each(current, &seat->focus_stack, link) { 129 wl_list_for_each(current, &seat->focus_stack, link) {
147 struct sway_container *con = current->container; 130 struct sway_node *node = current->node;
148 if (con->type == C_VIEW && container_has_ancestor(con, ancestor)) { 131 if (node->type == N_CONTAINER && node->sway_container->view &&
149 return con; 132 node_has_ancestor(node, ancestor)) {
133 return node->sway_container;
150 } 134 }
151 } 135 }
152 return NULL; 136 return NULL;
153} 137}
154 138
155static void handle_seat_container_destroy(struct wl_listener *listener, 139static void handle_seat_node_destroy(struct wl_listener *listener, void *data) {
156 void *data) { 140 struct sway_seat_node *seat_node =
157 struct sway_seat_container *seat_con = 141 wl_container_of(listener, seat_node, destroy);
158 wl_container_of(listener, seat_con, destroy); 142 struct sway_seat *seat = seat_node->seat;
159 struct sway_seat *seat = seat_con->seat; 143 struct sway_node *node = seat_node->node;
160 struct sway_container *con = seat_con->container; 144 struct sway_node *parent = node_get_parent(node);
161 struct sway_container *parent = con->parent; 145 struct sway_node *focus = seat_get_focus(seat);
162 struct sway_container *focus = seat_get_focus(seat);
163 146
164 bool set_focus = 147 bool set_focus =
165 focus != NULL && 148 focus != NULL &&
166 (focus == con || container_has_ancestor(focus, con)) && 149 (focus == node || node_has_ancestor(focus, node)) &&
167 con->type != C_WORKSPACE; 150 node->type == N_CONTAINER;
168 151
169 seat_container_destroy(seat_con); 152 seat_node_destroy(seat_node);
170 153
171 if (set_focus) { 154 if (set_focus) {
172 struct sway_container *next_focus = NULL; 155 struct sway_node *next_focus = NULL;
173 while (next_focus == NULL) { 156 while (next_focus == NULL) {
174 next_focus = seat_get_focus_inactive_view(seat, parent); 157 struct sway_container *con =
158 seat_get_focus_inactive_view(seat, parent);
159 next_focus = con ? &con->node : NULL;
175 160
176 if (next_focus == NULL && parent->type == C_WORKSPACE) { 161 if (next_focus == NULL && parent->type == N_WORKSPACE) {
177 next_focus = parent; 162 next_focus = parent;
178 break; 163 break;
179 } 164 }
180 165
181 parent = parent->parent; 166 parent = node_get_parent(parent);
182 } 167 }
183 168
184 // the structure change might have caused it to move up to the top of 169 // 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,
191 } 176 }
192} 177}
193 178
194static struct sway_seat_container *seat_container_from_container( 179static struct sway_seat_node *seat_node_from_node(
195 struct sway_seat *seat, struct sway_container *con) { 180 struct sway_seat *seat, struct sway_node *node) {
196 if (con->type == C_ROOT || con->type == C_OUTPUT) { 181 if (node->type == N_ROOT || node->type == N_OUTPUT) {
197 // these don't get seat containers ever 182 // these don't get seat nodes ever
198 return NULL; 183 return NULL;
199 } 184 }
200 185
201 struct sway_seat_container *seat_con = NULL; 186 struct sway_seat_node *seat_node = NULL;
202 wl_list_for_each(seat_con, &seat->focus_stack, link) { 187 wl_list_for_each(seat_node, &seat->focus_stack, link) {
203 if (seat_con->container == con) { 188 if (seat_node->node == node) {
204 return seat_con; 189 return seat_node;
205 } 190 }
206 } 191 }
207 192
208 seat_con = calloc(1, sizeof(struct sway_seat_container)); 193 seat_node = calloc(1, sizeof(struct sway_seat_node));
209 if (seat_con == NULL) { 194 if (seat_node == NULL) {
210 wlr_log(WLR_ERROR, "could not allocate seat container"); 195 wlr_log(WLR_ERROR, "could not allocate seat node");
211 return NULL; 196 return NULL;
212 } 197 }
213 198
214 seat_con->container = con; 199 seat_node->node = node;
215 seat_con->seat = seat; 200 seat_node->seat = seat;
216 wl_list_insert(seat->focus_stack.prev, &seat_con->link); 201 wl_list_insert(seat->focus_stack.prev, &seat_node->link);
217 wl_signal_add(&con->events.destroy, &seat_con->destroy); 202 wl_signal_add(&node->events.destroy, &seat_node->destroy);
218 seat_con->destroy.notify = handle_seat_container_destroy; 203 seat_node->destroy.notify = handle_seat_node_destroy;
219 204
220 return seat_con; 205 return seat_node;
221} 206}
222 207
223static void handle_new_container(struct wl_listener *listener, void *data) { 208static void handle_new_node(struct wl_listener *listener, void *data) {
224 struct sway_seat *seat = wl_container_of(listener, seat, new_container); 209 struct sway_seat *seat = wl_container_of(listener, seat, new_node);
225 struct sway_container *con = data; 210 struct sway_node *node = data;
226 seat_container_from_container(seat, con); 211 seat_node_from_node(seat, node);
227} 212}
228 213
229static void drag_icon_damage_whole(struct sway_drag_icon *icon) { 214static 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) {
272 drag_icon_damage_whole(icon); 257 drag_icon_damage_whole(icon);
273} 258}
274 259
275static void drag_icon_handle_destroy(struct wl_listener *listener, 260static void drag_icon_handle_destroy(struct wl_listener *listener, void *data) {
276 void *data) {
277 struct sway_drag_icon *icon = wl_container_of(listener, icon, destroy); 261 struct sway_drag_icon *icon = wl_container_of(listener, icon, destroy);
278 icon->wlr_drag_icon->data = NULL; 262 icon->wlr_drag_icon->data = NULL;
279 wl_list_remove(&icon->link); 263 wl_list_remove(&icon->link);
@@ -305,20 +289,29 @@ static void handle_new_drag_icon(struct wl_listener *listener, void *data) {
305 icon->destroy.notify = drag_icon_handle_destroy; 289 icon->destroy.notify = drag_icon_handle_destroy;
306 wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy); 290 wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy);
307 291
308 wl_list_insert(&root_container.sway_root->drag_icons, &icon->link); 292 wl_list_insert(&root->drag_icons, &icon->link);
309 293
310 drag_icon_update_position(icon); 294 drag_icon_update_position(icon);
311} 295}
312 296
313static void collect_focus_iter(struct sway_container *con, void *data) { 297static void collect_focus_iter(struct sway_node *node, void *data) {
314 struct sway_seat *seat = data; 298 struct sway_seat *seat = data;
315 struct sway_seat_container *seat_con = 299 struct sway_seat_node *seat_node = seat_node_from_node(seat, node);
316 seat_container_from_container(seat, con); 300 if (!seat_node) {
317 if (!seat_con) {
318 return; 301 return;
319 } 302 }
320 wl_list_remove(&seat_con->link); 303 wl_list_remove(&seat_node->link);
321 wl_list_insert(&seat->focus_stack, &seat_con->link); 304 wl_list_insert(&seat->focus_stack, &seat_node->link);
305}
306
307static void collect_focus_workspace_iter(struct sway_workspace *workspace,
308 void *data) {
309 collect_focus_iter(&workspace->node, data);
310}
311
312static void collect_focus_container_iter(struct sway_container *container,
313 void *data) {
314 collect_focus_iter(&container->node, data);
322} 315}
323 316
324struct sway_seat *seat_create(struct sway_input_manager *input, 317struct sway_seat *seat_create(struct sway_input_manager *input,
@@ -345,12 +338,11 @@ struct sway_seat *seat_create(struct sway_input_manager *input,
345 // init the focus stack 338 // init the focus stack
346 wl_list_init(&seat->focus_stack); 339 wl_list_init(&seat->focus_stack);
347 340
348 root_for_each_workspace(collect_focus_iter, seat); 341 root_for_each_workspace(collect_focus_workspace_iter, seat);
349 root_for_each_container(collect_focus_iter, seat); 342 root_for_each_container(collect_focus_container_iter, seat);
350 343
351 wl_signal_add(&root_container.sway_root->events.new_container, 344 wl_signal_add(&root->events.new_node, &seat->new_node);
352 &seat->new_container); 345 seat->new_node.notify = handle_new_node;
353 seat->new_container.notify = handle_new_container;
354 346
355 wl_signal_add(&seat->wlr_seat->events.new_drag_icon, &seat->new_drag_icon); 347 wl_signal_add(&seat->wlr_seat->events.new_drag_icon, &seat->new_drag_icon);
356 seat->new_drag_icon.notify = handle_new_drag_icon; 348 seat->new_drag_icon.notify = handle_new_drag_icon;
@@ -388,19 +380,11 @@ static void seat_apply_input_config(struct sway_seat *seat,
388 if (mapped_to_output != NULL) { 380 if (mapped_to_output != NULL) {
389 wlr_log(WLR_DEBUG, "Mapping input device %s to output %s", 381 wlr_log(WLR_DEBUG, "Mapping input device %s to output %s",
390 sway_device->input_device->identifier, mapped_to_output); 382 sway_device->input_device->identifier, mapped_to_output);
391 struct sway_container *output = NULL; 383 struct sway_output *output = output_by_name(mapped_to_output);
392 for (int i = 0; i < root_container.children->length; ++i) {
393 struct sway_container *_output = root_container.children->items[i];
394 if (strcasecmp(_output->name, mapped_to_output) == 0) {
395 output = _output;
396 break;
397 }
398 }
399 if (output) { 384 if (output) {
400 wlr_cursor_map_input_to_output(seat->cursor->cursor, 385 wlr_cursor_map_input_to_output(seat->cursor->cursor,
401 sway_device->input_device->wlr_device, 386 sway_device->input_device->wlr_device, output->wlr_output);
402 output->sway_output->wlr_output); 387 wlr_log(WLR_DEBUG, "Mapped to output %s", output->wlr_output->name);
403 wlr_log(WLR_DEBUG, "Mapped to output %s", output->name);
404 } 388 }
405 } 389 }
406} 390}
@@ -423,12 +407,12 @@ static void seat_configure_keyboard(struct sway_seat *seat,
423 sway_keyboard_configure(seat_device->keyboard); 407 sway_keyboard_configure(seat_device->keyboard);
424 wlr_seat_set_keyboard(seat->wlr_seat, 408 wlr_seat_set_keyboard(seat->wlr_seat,
425 seat_device->input_device->wlr_device); 409 seat_device->input_device->wlr_device);
426 struct sway_container *focus = seat_get_focus(seat); 410 struct sway_node *focus = seat_get_focus(seat);
427 if (focus && focus->type == C_VIEW) { 411 if (focus && node_is_view(focus)) {
428 // force notify reenter to pick up the new configuration 412 // force notify reenter to pick up the new configuration
429 wlr_seat_keyboard_clear_focus(seat->wlr_seat); 413 wlr_seat_keyboard_clear_focus(seat->wlr_seat);
430 wlr_seat_keyboard_notify_enter(seat->wlr_seat, 414 wlr_seat_keyboard_notify_enter(seat->wlr_seat,
431 focus->sway_view->surface, wlr_keyboard->keycodes, 415 focus->sway_container->view->surface, wlr_keyboard->keycodes,
432 wlr_keyboard->num_keycodes, &wlr_keyboard->modifiers); 416 wlr_keyboard->num_keycodes, &wlr_keyboard->modifiers);
433 } 417 }
434} 418}
@@ -461,8 +445,7 @@ static struct sway_seat_device *seat_get_device(struct sway_seat *seat,
461 445
462void seat_configure_device(struct sway_seat *seat, 446void seat_configure_device(struct sway_seat *seat,
463 struct sway_input_device *input_device) { 447 struct sway_input_device *input_device) {
464 struct sway_seat_device *seat_device = 448 struct sway_seat_device *seat_device = seat_get_device(seat, input_device);
465 seat_get_device(seat, input_device);
466 if (!seat_device) { 449 if (!seat_device) {
467 return; 450 return;
468 } 451 }
@@ -512,8 +495,7 @@ void seat_add_device(struct sway_seat *seat,
512 495
513void seat_remove_device(struct sway_seat *seat, 496void seat_remove_device(struct sway_seat *seat,
514 struct sway_input_device *input_device) { 497 struct sway_input_device *input_device) {
515 struct sway_seat_device *seat_device = 498 struct sway_seat_device *seat_device = seat_get_device(seat, input_device);
516 seat_get_device(seat, input_device);
517 499
518 if (!seat_device) { 500 if (!seat_device) {
519 return; 501 return;
@@ -539,11 +521,9 @@ void seat_configure_xcursor(struct sway_seat *seat) {
539 } 521 }
540 } 522 }
541 523
542 for (int i = 0; i < root_container.children->length; ++i) { 524 for (int i = 0; i < root->outputs->length; ++i) {
543 struct sway_container *output_container = 525 struct sway_output *sway_output = root->outputs->items[i];
544 root_container.children->items[i]; 526 struct wlr_output *output = sway_output->wlr_output;
545 struct wlr_output *output =
546 output_container->sway_output->wlr_output;
547 bool result = 527 bool result =
548 wlr_xcursor_manager_load(seat->cursor->xcursor_manager, 528 wlr_xcursor_manager_load(seat->cursor->xcursor_manager,
549 output->scale); 529 output->scale);
@@ -566,17 +546,20 @@ bool seat_is_input_allowed(struct sway_seat *seat,
566 return !seat->exclusive_client || seat->exclusive_client == client; 546 return !seat->exclusive_client || seat->exclusive_client == client;
567} 547}
568 548
549static void send_unfocus(struct sway_container *con, void *data) {
550 if (con->view) {
551 view_set_activated(con->view, false);
552 }
553}
554
569// Unfocus the container and any children (eg. when leaving `focus parent`) 555// Unfocus the container and any children (eg. when leaving `focus parent`)
570static void seat_send_unfocus(struct sway_container *container, 556static void seat_send_unfocus(struct sway_node *node, struct sway_seat *seat) {
571 struct sway_seat *seat) { 557 wlr_seat_keyboard_clear_focus(seat->wlr_seat);
572 if (container->type == C_VIEW) { 558 if (node->type == N_WORKSPACE) {
573 wlr_seat_keyboard_clear_focus(seat->wlr_seat); 559 workspace_for_each_container(node->sway_workspace, send_unfocus, seat);
574 view_set_activated(container->sway_view, false);
575 } else { 560 } else {
576 for (int i = 0; i < container->children->length; ++i) { 561 send_unfocus(node->sway_container, seat);
577 struct sway_container *child = container->children->items[i]; 562 container_for_each_child(node->sway_container, send_unfocus, seat);
578 seat_send_unfocus(child, seat);
579 }
580 } 563 }
581} 564}
582 565
@@ -586,26 +569,23 @@ static int handle_urgent_timeout(void *data) {
586 return 0; 569 return 0;
587} 570}
588 571
589void seat_set_focus_warp(struct sway_seat *seat, 572void seat_set_focus_warp(struct sway_seat *seat, struct sway_node *node,
590 struct sway_container *container, bool warp, bool notify) { 573 bool warp, bool notify) {
591 if (seat->focused_layer) { 574 if (seat->focused_layer) {
592 return; 575 return;
593 } 576 }
594 577
595 struct sway_container *last_focus = seat_get_focus(seat); 578 struct sway_node *last_focus = seat_get_focus(seat);
596 if (last_focus == container) { 579 if (last_focus == node) {
597 return; 580 return;
598 } 581 }
599 582
600 struct sway_container *last_workspace = last_focus; 583 struct sway_workspace *last_workspace = seat_get_focused_workspace(seat);
601 if (last_workspace && last_workspace->type != C_WORKSPACE) {
602 last_workspace = container_parent(last_workspace, C_WORKSPACE);
603 }
604 584
605 if (container == NULL) { 585 if (node == NULL) {
606 // Close any popups on the old focus 586 // Close any popups on the old focus
607 if (last_focus->type == C_VIEW) { 587 if (node_is_view(last_focus)) {
608 view_close_popups(last_focus->sway_view); 588 view_close_popups(last_focus->sway_container->view);
609 } 589 }
610 seat_send_unfocus(last_focus, seat); 590 seat_send_unfocus(last_focus, seat);
611 seat->has_focus = false; 591 seat->has_focus = false;
@@ -613,69 +593,70 @@ void seat_set_focus_warp(struct sway_seat *seat,
613 return; 593 return;
614 } 594 }
615 595
616 struct sway_container *new_workspace = container; 596 struct sway_workspace *new_workspace = node->type == N_WORKSPACE ?
617 if (new_workspace->type != C_WORKSPACE) { 597 node->sway_workspace : node->sway_container->workspace;
618 new_workspace = container_parent(new_workspace, C_WORKSPACE); 598 struct sway_container *container = node->type == N_CONTAINER ?
619 } 599 node->sway_container : NULL;
620 600
621 if (last_workspace == new_workspace 601 // Deny setting focus to a view which is hidden by a fullscreen container
622 && last_workspace->sway_workspace->fullscreen 602 if (new_workspace && new_workspace->fullscreen && container &&
623 && !container_is_fullscreen_or_child(container)) { 603 !container_is_fullscreen_or_child(container)) {
624 return; 604 return;
625 } 605 }
626 606
627 struct sway_container *last_output = last_focus; 607 struct sway_output *last_output = last_workspace ?
628 if (last_output && last_output->type != C_OUTPUT) { 608 last_workspace->output : NULL;
629 last_output = container_parent(last_output, C_OUTPUT); 609 struct sway_output *new_output = new_workspace->output;
630 }
631 struct sway_container *new_output = container;
632 if (new_output->type != C_OUTPUT) {
633 new_output = container_parent(new_output, C_OUTPUT);
634 }
635 610
636 // find new output's old workspace, which might have to be removed if empty 611 // find new output's old workspace, which might have to be removed if empty
637 struct sway_container *new_output_last_ws = NULL; 612 struct sway_workspace *new_output_last_ws = NULL;
638 if (new_output && last_output != new_output) { 613 if (new_output && last_output != new_output) {
639 new_output_last_ws = seat_get_active_child(seat, new_output); 614 new_output_last_ws = output_get_active_workspace(new_output);
640 } 615 }
641 616
642 if (container->parent) { 617 // Put the container parents on the focus stack, then the workspace, then
643 struct sway_seat_container *seat_con = 618 // the focused container.
644 seat_container_from_container(seat, container); 619 if (container) {
645 if (seat_con == NULL) { 620 struct sway_container *parent = container->parent;
646 return;
647 }
648
649 // put all the ancestors of this container on top of the focus stack
650 struct sway_seat_container *parent =
651 seat_container_from_container(seat, container->parent);
652 while (parent) { 621 while (parent) {
653 wl_list_remove(&parent->link); 622 struct sway_seat_node *seat_node =
654 wl_list_insert(&seat->focus_stack, &parent->link); 623 seat_node_from_node(seat, &parent->node);
655 container_set_dirty(parent->container); 624 wl_list_remove(&seat_node->link);
656 625 wl_list_insert(&seat->focus_stack, &seat_node->link);
657 parent = seat_container_from_container(seat, 626 node_set_dirty(&parent->node);
658 parent->container->parent); 627 parent = parent->parent;
659 } 628 }
660 629 }
661 wl_list_remove(&seat_con->link); 630 if (new_workspace) {
662 wl_list_insert(&seat->focus_stack, &seat_con->link); 631 struct sway_seat_node *seat_node =
632 seat_node_from_node(seat, &new_workspace->node);
633 wl_list_remove(&seat_node->link);
634 wl_list_insert(&seat->focus_stack, &seat_node->link);
635 node_set_dirty(&new_workspace->node);
636 }
637 if (container) {
638 struct sway_seat_node *seat_node =
639 seat_node_from_node(seat, &container->node);
640 wl_list_remove(&seat_node->link);
641 wl_list_insert(&seat->focus_stack, &seat_node->link);
642 node_set_dirty(&container->node);
663 643
664 if (last_focus) { 644 if (last_focus) {
665 seat_send_unfocus(last_focus, seat); 645 seat_send_unfocus(last_focus, seat);
666 container_set_dirty(last_focus); 646 node_set_dirty(last_focus);
647 struct sway_node *last_parent = node_get_parent(last_focus);
648 if (last_parent) {
649 node_set_dirty(last_parent);
650 }
667 } 651 }
668 seat_send_focus(container, seat); 652 seat_send_focus(&container->node, seat);
669
670 container_set_dirty(container);
671 container_set_dirty(container->parent); // for focused_inactive_child
672 } 653 }
673 654
674 // emit ipc events 655 // emit ipc events
675 if (notify && new_workspace && last_workspace != new_workspace) { 656 if (notify && new_workspace && last_workspace != new_workspace) {
676 ipc_event_workspace(last_workspace, new_workspace, "focus"); 657 ipc_event_workspace(last_workspace, new_workspace, "focus");
677 } 658 }
678 if (container->type == C_VIEW) { 659 if (container && container->view) {
679 ipc_event_window(container, "focus"); 660 ipc_event_window(container, "focus");
680 } 661 }
681 662
@@ -684,14 +665,14 @@ void seat_set_focus_warp(struct sway_seat *seat,
684 } 665 }
685 666
686 // Close any popups on the old focus 667 // Close any popups on the old focus
687 if (last_focus && last_focus->type == C_VIEW) { 668 if (last_focus && node_is_view(last_focus)) {
688 view_close_popups(last_focus->sway_view); 669 view_close_popups(last_focus->sway_container->view);
689 } 670 }
690 671
691 // If urgent, either unset the urgency or start a timer to unset it 672 // If urgent, either unset the urgency or start a timer to unset it
692 if (container->type == C_VIEW && view_is_urgent(container->sway_view) && 673 if (container && container->view && view_is_urgent(container->view) &&
693 !container->sway_view->urgent_timer) { 674 !container->view->urgent_timer) {
694 struct sway_view *view = container->sway_view; 675 struct sway_view *view = container->view;
695 if (last_workspace && last_workspace != new_workspace && 676 if (last_workspace && last_workspace != new_workspace &&
696 config->urgent_timeout > 0) { 677 config->urgent_timeout > 0) {
697 view->urgent_timer = wl_event_loop_add_timer(server.wl_event_loop, 678 view->urgent_timer = wl_event_loop_add_timer(server.wl_event_loop,
@@ -711,12 +692,15 @@ void seat_set_focus_warp(struct sway_seat *seat,
711 692
712 // If we've focused a floating container, bring it to the front. 693 // If we've focused a floating container, bring it to the front.
713 // We do this by putting it at the end of the floating list. 694 // We do this by putting it at the end of the floating list.
714 struct sway_container *floater = container; 695 if (container) {
715 while (floater->parent && floater->parent->type != C_WORKSPACE) { 696 struct sway_container *floater = container;
716 floater = floater->parent; 697 while (floater->parent) {
717 } 698 floater = floater->parent;
718 if (container_is_floating(floater)) { 699 }
719 list_move_to_end(floater->parent->sway_workspace->floating, floater); 700 if (container_is_floating(floater)) {
701 list_move_to_end(floater->workspace->floating, floater);
702 node_set_dirty(&floater->workspace->node);
703 }
720 } 704 }
721 705
722 if (last_focus) { 706 if (last_focus) {
@@ -727,11 +711,8 @@ void seat_set_focus_warp(struct sway_seat *seat,
727 if (config->mouse_warping && warp && new_output != last_output) { 711 if (config->mouse_warping && warp && new_output != last_output) {
728 double x = container->x + container->width / 2.0; 712 double x = container->x + container->width / 2.0;
729 double y = container->y + container->height / 2.0; 713 double y = container->y + container->height / 2.0;
730 struct wlr_output *wlr_output = 714 if (!wlr_output_layout_contains_point(root->output_layout,
731 new_output->sway_output->wlr_output; 715 new_output->wlr_output, seat->cursor->cursor->x,
732 if (!wlr_output_layout_contains_point(
733 root_container.sway_root->output_layout,
734 wlr_output, seat->cursor->cursor->x,
735 seat->cursor->cursor->y)) { 716 seat->cursor->cursor->y)) {
736 wlr_cursor_warp(seat->cursor->cursor, NULL, x, y); 717 wlr_cursor_warp(seat->cursor->cursor, NULL, x, y);
737 cursor_send_pointer_motion(seat->cursor, 0, true); 718 cursor_send_pointer_motion(seat->cursor, 0, true);
@@ -744,9 +725,8 @@ void seat_set_focus_warp(struct sway_seat *seat,
744 update_debug_tree(); 725 update_debug_tree();
745} 726}
746 727
747void seat_set_focus(struct sway_seat *seat, 728void seat_set_focus(struct sway_seat *seat, struct sway_node *node) {
748 struct sway_container *container) { 729 seat_set_focus_warp(seat, node, true, true);
749 seat_set_focus_warp(seat, container, true, true);
750} 730}
751 731
752void seat_set_focus_surface(struct sway_seat *seat, 732void seat_set_focus_surface(struct sway_seat *seat,
@@ -755,12 +735,11 @@ void seat_set_focus_surface(struct sway_seat *seat,
755 return; 735 return;
756 } 736 }
757 if (seat->has_focus && unfocus) { 737 if (seat->has_focus && unfocus) {
758 struct sway_container *focus = seat_get_focus(seat); 738 struct sway_node *focus = seat_get_focus(seat);
759 seat_send_unfocus(focus, seat); 739 seat_send_unfocus(focus, seat);
760 seat->has_focus = false; 740 seat->has_focus = false;
761 } 741 }
762 struct wlr_keyboard *keyboard = 742 struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
763 wlr_seat_get_keyboard(seat->wlr_seat);
764 if (keyboard) { 743 if (keyboard) {
765 wlr_seat_keyboard_notify_enter(seat->wlr_seat, surface, 744 wlr_seat_keyboard_notify_enter(seat->wlr_seat, surface,
766 keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers); 745 keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers);
@@ -773,11 +752,8 @@ void seat_set_focus_layer(struct sway_seat *seat,
773 struct wlr_layer_surface *layer) { 752 struct wlr_layer_surface *layer) {
774 if (!layer && seat->focused_layer) { 753 if (!layer && seat->focused_layer) {
775 seat->focused_layer = NULL; 754 seat->focused_layer = NULL;
776 struct sway_container *previous = 755 struct sway_node *previous = seat_get_focus_inactive(seat, &root->node);
777 seat_get_focus_inactive(seat, &root_container);
778 if (previous) { 756 if (previous) {
779 wlr_log(WLR_DEBUG, "Returning focus to %p %s '%s'", previous,
780 container_type_to_str(previous->type), previous->name);
781 // Hack to get seat to re-focus the return value of get_focus 757 // Hack to get seat to re-focus the return value of get_focus
782 seat_set_focus(seat, NULL); 758 seat_set_focus(seat, NULL);
783 seat_set_focus(seat, previous); 759 seat_set_focus(seat, previous);
@@ -798,13 +774,9 @@ void seat_set_exclusive_client(struct sway_seat *seat,
798 seat->exclusive_client = client; 774 seat->exclusive_client = client;
799 // Triggers a refocus of the topmost surface layer if necessary 775 // Triggers a refocus of the topmost surface layer if necessary
800 // TODO: Make layer surface focus per-output based on cursor position 776 // TODO: Make layer surface focus per-output based on cursor position
801 for (int i = 0; i < root_container.children->length; ++i) { 777 for (int i = 0; i < root->outputs->length; ++i) {
802 struct sway_container *output = root_container.children->items[i]; 778 struct sway_output *output = root->outputs->items[i];
803 if (!sway_assert(output->type == C_OUTPUT, 779 arrange_layers(output);
804 "root container has non-output child")) {
805 continue;
806 }
807 arrange_layers(output->sway_output);
808 } 780 }
809 return; 781 return;
810 } 782 }
@@ -814,9 +786,9 @@ void seat_set_exclusive_client(struct sway_seat *seat,
814 } 786 }
815 } 787 }
816 if (seat->has_focus) { 788 if (seat->has_focus) {
817 struct sway_container *focus = seat_get_focus(seat); 789 struct sway_node *focus = seat_get_focus(seat);
818 if (focus->type == C_VIEW && wl_resource_get_client( 790 if (node_is_view(focus) && wl_resource_get_client(
819 focus->sway_view->surface->resource) != client) { 791 focus->sway_container->view->surface->resource) != client) {
820 seat_set_focus(seat, NULL); 792 seat_set_focus(seat, NULL);
821 } 793 }
822 } 794 }
@@ -837,79 +809,101 @@ void seat_set_exclusive_client(struct sway_seat *seat,
837 seat->exclusive_client = client; 809 seat->exclusive_client = client;
838} 810}
839 811
840struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, 812struct sway_node *seat_get_focus_inactive(struct sway_seat *seat,
841 struct sway_container *con) { 813 struct sway_node *node) {
842 if (con->type == C_WORKSPACE && !con->children->length && 814 if (node_is_view(node)) {
843 !con->sway_workspace->floating->length) { 815 return node;
844 return con;
845 }
846 if (con->type == C_VIEW) {
847 return con;
848 } 816 }
849 struct sway_seat_container *current; 817 struct sway_seat_node *current;
850 wl_list_for_each(current, &seat->focus_stack, link) { 818 wl_list_for_each(current, &seat->focus_stack, link) {
851 if (container_has_ancestor(current->container, con)) { 819 if (node_has_ancestor(current->node, node)) {
852 return current->container; 820 return current->node;
853 } 821 }
854 } 822 }
823 if (node->type == N_WORKSPACE) {
824 return node;
825 }
855 return NULL; 826 return NULL;
856} 827}
857 828
858struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat, 829struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat,
859 struct sway_container *ancestor) { 830 struct sway_workspace *workspace) {
860 if (ancestor->type == C_WORKSPACE && !ancestor->children->length) { 831 if (!workspace->tiling->length) {
861 return ancestor; 832 return NULL;
862 } 833 }
863 struct sway_seat_container *current; 834 struct sway_seat_node *current;
864 wl_list_for_each(current, &seat->focus_stack, link) { 835 wl_list_for_each(current, &seat->focus_stack, link) {
865 struct sway_container *con = current->container; 836 struct sway_node *node = current->node;
866 if (!container_is_floating_or_child(con) && 837 if (node->type == N_CONTAINER &&
867 container_has_ancestor(current->container, ancestor)) { 838 !container_is_floating_or_child(node->sway_container) &&
868 return con; 839 node->sway_container->workspace == workspace) {
840 return node->sway_container;
869 } 841 }
870 } 842 }
871 return NULL; 843 return NULL;
872} 844}
873 845
874struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat, 846struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat,
875 struct sway_container *ancestor) { 847 struct sway_workspace *workspace) {
876 if (ancestor->type == C_WORKSPACE && 848 if (!workspace->floating->length) {
877 !ancestor->sway_workspace->floating->length) {
878 return NULL; 849 return NULL;
879 } 850 }
880 struct sway_seat_container *current; 851 struct sway_seat_node *current;
881 wl_list_for_each(current, &seat->focus_stack, link) { 852 wl_list_for_each(current, &seat->focus_stack, link) {
882 struct sway_container *con = current->container; 853 struct sway_node *node = current->node;
883 if (container_is_floating_or_child(con) && 854 if (node->type == N_CONTAINER &&
884 container_has_ancestor(current->container, ancestor)) { 855 container_is_floating_or_child(node->sway_container) &&
885 return con; 856 node->sway_container->workspace == workspace) {
857 return node->sway_container;
886 } 858 }
887 } 859 }
888 return NULL; 860 return NULL;
889} 861}
890 862
891struct sway_container *seat_get_active_child(struct sway_seat *seat, 863struct sway_node *seat_get_active_child(struct sway_seat *seat,
892 struct sway_container *parent) { 864 struct sway_node *parent) {
893 if (parent->type == C_VIEW) { 865 if (node_is_view(parent)) {
894 return parent; 866 return parent;
895 } 867 }
896 struct sway_seat_container *current; 868 struct sway_seat_node *current;
897 wl_list_for_each(current, &seat->focus_stack, link) { 869 wl_list_for_each(current, &seat->focus_stack, link) {
898 struct sway_container *con = current->container; 870 struct sway_node *node = current->node;
899 if (con->parent == parent) { 871 if (node_get_parent(node) == parent) {
900 return con; 872 return node;
901 } 873 }
902 } 874 }
903 return NULL; 875 return NULL;
904} 876}
905 877
906struct sway_container *seat_get_focus(struct sway_seat *seat) { 878struct sway_node *seat_get_focus(struct sway_seat *seat) {
907 if (!seat->has_focus) { 879 if (!seat->has_focus) {
908 return NULL; 880 return NULL;
909 } 881 }
910 struct sway_seat_container *current = 882 struct sway_seat_node *current =
911 wl_container_of(seat->focus_stack.next, current, link); 883 wl_container_of(seat->focus_stack.next, current, link);
912 return current->container; 884 return current->node;
885}
886
887struct sway_workspace *seat_get_focused_workspace(struct sway_seat *seat) {
888 struct sway_node *focus = seat_get_focus(seat);
889 if (!focus) {
890 return NULL;
891 }
892 if (focus->type == N_CONTAINER) {
893 return focus->sway_container->workspace;
894 }
895 if (focus->type == N_WORKSPACE) {
896 return focus->sway_workspace;
897 }
898 return NULL; // unreachable
899}
900
901struct sway_container *seat_get_focused_container(struct sway_seat *seat) {
902 struct sway_node *focus = seat_get_focus(seat);
903 if (focus && focus->type == N_CONTAINER) {
904 return focus->sway_container;
905 }
906 return NULL;
913} 907}
914 908
915void seat_apply_config(struct sway_seat *seat, 909void seat_apply_config(struct sway_seat *seat,