aboutsummaryrefslogtreecommitdiffstats
path: root/sway/input/seat.c
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/seat.c
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/seat.c')
-rw-r--r--sway/input/seat.c514
1 files changed, 254 insertions, 260 deletions
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,