aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sway/input/seat.h20
-rw-r--r--include/sway/output.h14
-rw-r--r--include/sway/tree/container.h19
-rw-r--r--include/sway/tree/layout.h2
-rw-r--r--include/sway/tree/root.h15
-rw-r--r--include/sway/tree/workspace.h13
-rw-r--r--sway/commands/floating.c3
-rw-r--r--sway/commands/fullscreen.c3
-rw-r--r--sway/commands/hide_edge_borders.c2
-rw-r--r--sway/commands/move.c6
-rw-r--r--sway/commands/rename.c3
-rw-r--r--sway/commands/show_marks.c3
-rw-r--r--sway/commands/swap.c6
-rw-r--r--sway/commands/unmark.c3
-rw-r--r--sway/config.c13
-rw-r--r--sway/criteria.c15
-rw-r--r--sway/desktop/output.c9
-rw-r--r--sway/input/cursor.c34
-rw-r--r--sway/input/seat.c33
-rw-r--r--sway/ipc-server.c8
-rw-r--r--sway/tree/container.c76
-rw-r--r--sway/tree/layout.c23
-rw-r--r--sway/tree/output.c73
-rw-r--r--sway/tree/root.c78
-rw-r--r--sway/tree/view.c6
-rw-r--r--sway/tree/workspace.c85
26 files changed, 389 insertions, 176 deletions
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h
index 9dfb0714..5c404ecd 100644
--- a/include/sway/input/seat.h
+++ b/include/sway/input/seat.h
@@ -35,6 +35,14 @@ struct sway_drag_icon {
35 struct wl_listener destroy; 35 struct wl_listener destroy;
36}; 36};
37 37
38enum sway_seat_operation {
39 OP_NONE,
40 OP_DOWN,
41 OP_MOVE,
42 OP_RESIZE_FLOATING,
43 OP_RESIZE_TILING,
44};
45
38struct sway_seat { 46struct sway_seat {
39 struct wlr_seat *wlr_seat; 47 struct wlr_seat *wlr_seat;
40 struct sway_cursor *cursor; 48 struct sway_cursor *cursor;
@@ -54,13 +62,7 @@ struct sway_seat {
54 double touch_x, touch_y; 62 double touch_x, touch_y;
55 63
56 // Operations (drag and resize) 64 // Operations (drag and resize)
57 enum { 65 enum sway_seat_operation operation;
58 OP_NONE,
59 OP_MOVE,
60 OP_RESIZE_FLOATING,
61 OP_RESIZE_TILING,
62 } operation;
63
64 struct sway_container *op_container; 66 struct sway_container *op_container;
65 enum wlr_edges op_resize_edge; 67 enum wlr_edges op_resize_edge;
66 uint32_t op_button; 68 uint32_t op_button;
@@ -68,6 +70,7 @@ struct sway_seat {
68 double op_ref_lx, op_ref_ly; // cursor's x/y at start of op 70 double op_ref_lx, op_ref_ly; // cursor's x/y at start of op
69 double op_ref_width, op_ref_height; // container's size at start of op 71 double op_ref_width, op_ref_height; // container's size at start of op
70 double op_ref_con_lx, op_ref_con_ly; // container's x/y at start of op 72 double op_ref_con_lx, op_ref_con_ly; // container's x/y at start of op
73 bool op_moved; // if the mouse moved during a down op
71 74
72 uint32_t last_button; 75 uint32_t last_button;
73 uint32_t last_button_serial; 76 uint32_t last_button_serial;
@@ -157,6 +160,9 @@ bool seat_is_input_allowed(struct sway_seat *seat, struct wlr_surface *surface);
157 160
158void drag_icon_update_position(struct sway_drag_icon *icon); 161void drag_icon_update_position(struct sway_drag_icon *icon);
159 162
163void seat_begin_down(struct sway_seat *seat, struct sway_container *con,
164 uint32_t button, double sx, double sy);
165
160void seat_begin_move(struct sway_seat *seat, struct sway_container *con, 166void seat_begin_move(struct sway_seat *seat, struct sway_container *con,
161 uint32_t button); 167 uint32_t button);
162 168
diff --git a/include/sway/output.h b/include/sway/output.h
index 80dcd37b..d0d034b3 100644
--- a/include/sway/output.h
+++ b/include/sway/output.h
@@ -58,6 +58,8 @@ void output_damage_whole_container(struct sway_output *output,
58 58
59struct sway_container *output_by_name(const char *name); 59struct sway_container *output_by_name(const char *name);
60 60
61void output_sort_workspaces(struct sway_container *output);
62
61void output_enable(struct sway_output *output); 63void output_enable(struct sway_output *output);
62 64
63bool output_has_opaque_overlay_layer_surface(struct sway_output *output); 65bool output_has_opaque_overlay_layer_surface(struct sway_output *output);
@@ -93,4 +95,16 @@ void output_drag_icons_for_each_surface(struct sway_output *output,
93 struct wl_list *drag_icons, sway_surface_iterator_func_t iterator, 95 struct wl_list *drag_icons, sway_surface_iterator_func_t iterator,
94 void *user_data); 96 void *user_data);
95 97
98void output_for_each_workspace(struct sway_container *output,
99 void (*f)(struct sway_container *con, void *data), void *data);
100
101void output_for_each_container(struct sway_container *output,
102 void (*f)(struct sway_container *con, void *data), void *data);
103
104struct sway_container *output_find_workspace(struct sway_container *output,
105 bool (*test)(struct sway_container *con, void *data), void *data);
106
107struct sway_container *output_find_container(struct sway_container *output,
108 bool (*test)(struct sway_container *con, void *data), void *data);
109
96#endif 110#endif
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index fdcc31ec..c8410801 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -214,15 +214,11 @@ struct sway_container *container_destroy(struct sway_container *container);
214 214
215struct sway_container *container_close(struct sway_container *container); 215struct sway_container *container_close(struct sway_container *container);
216 216
217void container_descendants(struct sway_container *root,
218 enum sway_container_type type,
219 void (*func)(struct sway_container *item, void *data), void *data);
220
221/** 217/**
222 * Search a container's descendants a container based on test criteria. Returns 218 * Search a container's descendants a container based on test criteria. Returns
223 * the first container that passes the test. 219 * the first container that passes the test.
224 */ 220 */
225struct sway_container *container_find(struct sway_container *container, 221struct sway_container *container_find_child(struct sway_container *container,
226 bool (*test)(struct sway_container *view, void *data), void *data); 222 bool (*test)(struct sway_container *view, void *data), void *data);
227 223
228/** 224/**
@@ -244,10 +240,7 @@ struct sway_container *tiling_container_at(
244 struct sway_container *con, double lx, double ly, 240 struct sway_container *con, double lx, double ly,
245 struct wlr_surface **surface, double *sx, double *sy); 241 struct wlr_surface **surface, double *sx, double *sy);
246 242
247/** 243void container_for_each_child(struct sway_container *container,
248 * Apply the function for each child of the container depth first.
249 */
250void container_for_each_descendant(struct sway_container *container,
251 void (*f)(struct sway_container *container, void *data), void *data); 244 void (*f)(struct sway_container *container, void *data), void *data);
252 245
253/** 246/**
@@ -361,12 +354,4 @@ bool container_is_floating_or_child(struct sway_container *container);
361 */ 354 */
362bool container_is_fullscreen_or_child(struct sway_container *container); 355bool container_is_fullscreen_or_child(struct sway_container *container);
363 356
364/**
365 * Wrap the children of parent in a new container. The new container will be the
366 * only child of parent.
367 *
368 * The new container is returned.
369 */
370struct sway_container *container_wrap_children(struct sway_container *parent);
371
372#endif 357#endif
diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h
index 77cd954b..5b803dfe 100644
--- a/include/sway/tree/layout.h
+++ b/include/sway/tree/layout.h
@@ -45,8 +45,6 @@ void container_move(struct sway_container *container,
45enum sway_container_layout container_get_default_layout( 45enum sway_container_layout container_get_default_layout(
46 struct sway_container *con); 46 struct sway_container *con);
47 47
48void container_sort_workspaces(struct sway_container *output);
49
50struct sway_container *container_get_in_direction(struct sway_container 48struct sway_container *container_get_in_direction(struct sway_container
51 *container, struct sway_seat *seat, enum movement_direction dir); 49 *container, struct sway_seat *seat, enum movement_direction dir);
52 50
diff --git a/include/sway/tree/root.h b/include/sway/tree/root.h
index edb7c817..d1f04a96 100644
--- a/include/sway/tree/root.h
+++ b/include/sway/tree/root.h
@@ -58,4 +58,19 @@ struct sway_container *root_workspace_for_pid(pid_t pid);
58 58
59void root_record_workspace_pid(pid_t pid); 59void root_record_workspace_pid(pid_t pid);
60 60
61void root_for_each_workspace(void (*f)(struct sway_container *con, void *data),
62 void *data);
63
64void root_for_each_container(void (*f)(struct sway_container *con, void *data),
65 void *data);
66
67struct sway_container *root_find_output(
68 bool (*test)(struct sway_container *con, void *data), void *data);
69
70struct sway_container *root_find_workspace(
71 bool (*test)(struct sway_container *con, void *data), void *data);
72
73struct sway_container *root_find_container(
74 bool (*test)(struct sway_container *con, void *data), void *data);
75
61#endif 76#endif
diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h
index 056f2329..c9dbb538 100644
--- a/include/sway/tree/workspace.h
+++ b/include/sway/tree/workspace.h
@@ -50,4 +50,17 @@ struct sway_container *workspace_output_get_highest_available(
50 50
51void workspace_detect_urgent(struct sway_container *workspace); 51void workspace_detect_urgent(struct sway_container *workspace);
52 52
53void workspace_for_each_container(struct sway_container *ws,
54 void (*f)(struct sway_container *con, void *data), void *data);
55
56struct sway_container *workspace_find_container(struct sway_container *ws,
57 bool (*test)(struct sway_container *con, void *data), void *data);
58
59/**
60 * Wrap the workspace's tiling children in a new container.
61 * The new container will be the only direct tiling child of the workspace.
62 * The new container is returned.
63 */
64struct sway_container *workspace_wrap_children(struct sway_container *ws);
65
53#endif 66#endif
diff --git a/sway/commands/floating.c b/sway/commands/floating.c
index 31de5ec3..c9467ef0 100644
--- a/sway/commands/floating.c
+++ b/sway/commands/floating.c
@@ -8,6 +8,7 @@
8#include "sway/tree/container.h" 8#include "sway/tree/container.h"
9#include "sway/tree/layout.h" 9#include "sway/tree/layout.h"
10#include "sway/tree/view.h" 10#include "sway/tree/view.h"
11#include "sway/tree/workspace.h"
11#include "list.h" 12#include "list.h"
12 13
13struct cmd_results *cmd_floating(int argc, char **argv) { 14struct cmd_results *cmd_floating(int argc, char **argv) {
@@ -24,7 +25,7 @@ struct cmd_results *cmd_floating(int argc, char **argv) {
24 if (container->type == C_WORKSPACE) { 25 if (container->type == C_WORKSPACE) {
25 // Wrap the workspace's children in a container so we can float it 26 // Wrap the workspace's children in a container so we can float it
26 struct sway_container *workspace = container; 27 struct sway_container *workspace = container;
27 container = container_wrap_children(container); 28 container = workspace_wrap_children(container);
28 workspace->layout = L_HORIZ; 29 workspace->layout = L_HORIZ;
29 seat_set_focus(config->handler_context.seat, container); 30 seat_set_focus(config->handler_context.seat, container);
30 } 31 }
diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c
index 5ad06e40..a0661200 100644
--- a/sway/commands/fullscreen.c
+++ b/sway/commands/fullscreen.c
@@ -4,6 +4,7 @@
4#include "sway/tree/arrange.h" 4#include "sway/tree/arrange.h"
5#include "sway/tree/container.h" 5#include "sway/tree/container.h"
6#include "sway/tree/view.h" 6#include "sway/tree/view.h"
7#include "sway/tree/workspace.h"
7#include "sway/tree/layout.h" 8#include "sway/tree/layout.h"
8#include "util.h" 9#include "util.h"
9 10
@@ -21,7 +22,7 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) {
21 if (container->type == C_WORKSPACE) { 22 if (container->type == C_WORKSPACE) {
22 // Wrap the workspace's children in a container so we can fullscreen it 23 // Wrap the workspace's children in a container so we can fullscreen it
23 struct sway_container *workspace = container; 24 struct sway_container *workspace = container;
24 container = container_wrap_children(container); 25 container = workspace_wrap_children(container);
25 workspace->layout = L_HORIZ; 26 workspace->layout = L_HORIZ;
26 seat_set_focus(config->handler_context.seat, container); 27 seat_set_focus(config->handler_context.seat, container);
27 } 28 }
diff --git a/sway/commands/hide_edge_borders.c b/sway/commands/hide_edge_borders.c
index bb390f5f..d59c9fdb 100644
--- a/sway/commands/hide_edge_borders.c
+++ b/sway/commands/hide_edge_borders.c
@@ -31,7 +31,7 @@ struct cmd_results *cmd_hide_edge_borders(int argc, char **argv) {
31 "<none|vertical|horizontal|both|smart>'"); 31 "<none|vertical|horizontal|both|smart>'");
32 } 32 }
33 33
34 container_for_each_descendant(&root_container, _configure_view, NULL); 34 root_for_each_container(_configure_view, NULL);
35 35
36 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 36 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
37} 37}
diff --git a/sway/commands/move.c b/sway/commands/move.c
index de6b1b0a..acdc50b5 100644
--- a/sway/commands/move.c
+++ b/sway/commands/move.c
@@ -64,7 +64,7 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
64 return cmd_results_new(CMD_FAILURE, "move", 64 return cmd_results_new(CMD_FAILURE, "move",
65 "Can't move an empty workspace"); 65 "Can't move an empty workspace");
66 } 66 }
67 current = container_wrap_children(current); 67 current = workspace_wrap_children(current);
68 } else if (current->type != C_CONTAINER && current->type != C_VIEW) { 68 } else if (current->type != C_CONTAINER && current->type != C_VIEW) {
69 return cmd_results_new(CMD_FAILURE, "move", 69 return cmd_results_new(CMD_FAILURE, "move",
70 "Can only move containers and views."); 70 "Can only move containers and views.");
@@ -245,7 +245,7 @@ static void workspace_move_to_output(struct sway_container *workspace,
245 // Try to remove an empty workspace from the destination output. 245 // Try to remove an empty workspace from the destination output.
246 container_reap_empty_recursive(new_output_focus); 246 container_reap_empty_recursive(new_output_focus);
247 247
248 container_sort_workspaces(output); 248 output_sort_workspaces(output);
249 seat_set_focus(seat, output); 249 seat_set_focus(seat, output);
250 workspace_output_raise_priority(workspace, old_output, output); 250 workspace_output_raise_priority(workspace, old_output, output);
251 ipc_event_workspace(NULL, workspace, "move"); 251 ipc_event_workspace(NULL, workspace, "move");
@@ -437,7 +437,7 @@ static struct cmd_results *move_to_scratchpad(struct sway_container *con) {
437 if (con->type == C_WORKSPACE) { 437 if (con->type == C_WORKSPACE) {
438 // Wrap the workspace's children in a container 438 // Wrap the workspace's children in a container
439 struct sway_container *workspace = con; 439 struct sway_container *workspace = con;
440 con = container_wrap_children(con); 440 con = workspace_wrap_children(con);
441 workspace->layout = L_HORIZ; 441 workspace->layout = L_HORIZ;
442 } 442 }
443 443
diff --git a/sway/commands/rename.c b/sway/commands/rename.c
index c6952bbb..c69bbdac 100644
--- a/sway/commands/rename.c
+++ b/sway/commands/rename.c
@@ -6,6 +6,7 @@
6#include "sway/commands.h" 6#include "sway/commands.h"
7#include "sway/config.h" 7#include "sway/config.h"
8#include "sway/ipc-server.h" 8#include "sway/ipc-server.h"
9#include "sway/output.h"
9#include "sway/tree/container.h" 10#include "sway/tree/container.h"
10#include "sway/tree/workspace.h" 11#include "sway/tree/workspace.h"
11 12
@@ -82,7 +83,7 @@ struct cmd_results *cmd_rename(int argc, char **argv) {
82 free(workspace->name); 83 free(workspace->name);
83 workspace->name = new_name; 84 workspace->name = new_name;
84 85
85 container_sort_workspaces(workspace->parent); 86 output_sort_workspaces(workspace->parent);
86 ipc_event_workspace(NULL, workspace, "rename"); 87 ipc_event_workspace(NULL, workspace, "rename");
87 88
88 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 89 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/show_marks.c b/sway/commands/show_marks.c
index cf153a0a..dd7d170c 100644
--- a/sway/commands/show_marks.c
+++ b/sway/commands/show_marks.c
@@ -24,8 +24,7 @@ struct cmd_results *cmd_show_marks(int argc, char **argv) {
24 config->show_marks = parse_boolean(argv[0], config->show_marks); 24 config->show_marks = parse_boolean(argv[0], config->show_marks);
25 25
26 if (config->show_marks) { 26 if (config->show_marks) {
27 container_for_each_descendant(&root_container, 27 root_for_each_container(rebuild_marks_iterator, NULL);
28 rebuild_marks_iterator, NULL);
29 } 28 }
30 29
31 for (int i = 0; i < root_container.children->length; ++i) { 30 for (int i = 0; i < root_container.children->length; ++i) {
diff --git a/sway/commands/swap.c b/sway/commands/swap.c
index 4e3a9cce..615e6b1d 100644
--- a/sway/commands/swap.c
+++ b/sway/commands/swap.c
@@ -50,13 +50,13 @@ struct cmd_results *cmd_swap(int argc, char **argv) {
50 if (strcasecmp(argv[2], "id") == 0) { 50 if (strcasecmp(argv[2], "id") == 0) {
51#ifdef HAVE_XWAYLAND 51#ifdef HAVE_XWAYLAND
52 xcb_window_t id = strtol(value, NULL, 0); 52 xcb_window_t id = strtol(value, NULL, 0);
53 other = container_find(&root_container, test_id, (void *)&id); 53 other = root_find_container(test_id, (void *)&id);
54#endif 54#endif
55 } else if (strcasecmp(argv[2], "con_id") == 0) { 55 } else if (strcasecmp(argv[2], "con_id") == 0) {
56 size_t con_id = atoi(value); 56 size_t con_id = atoi(value);
57 other = container_find(&root_container, test_con_id, (void *)con_id); 57 other = root_find_container(test_con_id, (void *)con_id);
58 } else if (strcasecmp(argv[2], "mark") == 0) { 58 } else if (strcasecmp(argv[2], "mark") == 0) {
59 other = container_find(&root_container, test_mark, (void *)value); 59 other = root_find_container(test_mark, (void *)value);
60 } else { 60 } else {
61 free(value); 61 free(value);
62 return cmd_results_new(CMD_INVALID, "swap", EXPECTED_SYNTAX); 62 return cmd_results_new(CMD_INVALID, "swap", EXPECTED_SYNTAX);
diff --git a/sway/commands/unmark.c b/sway/commands/unmark.c
index 44ceccee..c183785b 100644
--- a/sway/commands/unmark.c
+++ b/sway/commands/unmark.c
@@ -52,8 +52,7 @@ struct cmd_results *cmd_unmark(int argc, char **argv) {
52 view_find_and_unmark(mark); 52 view_find_and_unmark(mark);
53 } else { 53 } else {
54 // Remove all marks from all views 54 // Remove all marks from all views
55 container_for_each_descendant(&root_container, 55 root_for_each_container(remove_all_marks_iterator, NULL);
56 remove_all_marks_iterator, NULL);
57 } 56 }
58 free(mark); 57 free(mark);
59 58
diff --git a/sway/config.c b/sway/config.c
index bd14222a..642abbac 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -822,18 +822,7 @@ void config_update_font_height(bool recalculate) {
822 size_t prev_max_height = config->font_height; 822 size_t prev_max_height = config->font_height;
823 config->font_height = 0; 823 config->font_height = 0;
824 824
825 container_for_each_descendant(&root_container, 825 root_for_each_container(find_font_height_iterator, &recalculate);
826 find_font_height_iterator, &recalculate);
827
828 // Also consider floating views
829 for (int i = 0; i < root_container.children->length; ++i) {
830 struct sway_container *output = root_container.children->items[i];
831 for (int j = 0; j < output->children->length; ++j) {
832 struct sway_container *ws = output->children->items[j];
833 container_for_each_descendant(ws->sway_workspace->floating,
834 find_font_height_iterator, &recalculate);
835 }
836 }
837 826
838 if (config->font_height != prev_max_height) { 827 if (config->font_height != prev_max_height) {
839 arrange_windows(&root_container); 828 arrange_windows(&root_container);
diff --git a/sway/criteria.c b/sway/criteria.c
index a5df1eef..81c2325a 100644
--- a/sway/criteria.c
+++ b/sway/criteria.c
@@ -167,8 +167,7 @@ static bool criteria_matches_view(struct criteria *criteria,
167 return false; 167 return false;
168 } 168 }
169 list_t *urgent_views = create_list(); 169 list_t *urgent_views = create_list();
170 container_for_each_descendant(&root_container, 170 root_for_each_container(find_urgent_iterator, urgent_views);
171 find_urgent_iterator, urgent_views);
172 list_stable_sort(urgent_views, cmp_urgent); 171 list_stable_sort(urgent_views, cmp_urgent);
173 struct sway_view *target; 172 struct sway_view *target;
174 if (criteria->urgent == 'o') { // oldest 173 if (criteria->urgent == 'o') { // oldest
@@ -228,17 +227,7 @@ list_t *criteria_get_views(struct criteria *criteria) {
228 .criteria = criteria, 227 .criteria = criteria,
229 .matches = matches, 228 .matches = matches,
230 }; 229 };
231 container_for_each_descendant(&root_container, 230 root_for_each_container(criteria_get_views_iterator, &data);
232 criteria_get_views_iterator, &data);
233
234 // Scratchpad items which are hidden are not in the tree.
235 for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) {
236 struct sway_container *con =
237 root_container.sway_root->scratchpad->items[i];
238 if (!con->parent) {
239 criteria_get_views_iterator(con, &data);
240 }
241 }
242 return matches; 231 return matches;
243} 232}
244 233
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index b4564fac..1e4f196b 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -304,15 +304,14 @@ struct send_frame_done_data {
304 304
305static void send_frame_done_container_iterator(struct sway_container *con, 305static void send_frame_done_container_iterator(struct sway_container *con,
306 void *_data) { 306 void *_data) {
307 struct send_frame_done_data *data = _data; 307 if (con->type != C_VIEW) {
308 if (!sway_assert(con->type == C_VIEW, "expected a view")) {
309 return; 308 return;
310 } 309 }
311
312 if (!view_is_visible(con->sway_view)) { 310 if (!view_is_visible(con->sway_view)) {
313 return; 311 return;
314 } 312 }
315 313
314 struct send_frame_done_data *data = _data;
316 output_view_for_each_surface(data->output, con->sway_view, 315 output_view_for_each_surface(data->output, con->sway_view,
317 send_frame_done_iterator, data->when); 316 send_frame_done_iterator, data->when);
318} 317}
@@ -323,8 +322,8 @@ static void send_frame_done_container(struct sway_output *output,
323 .output = output, 322 .output = output,
324 .when = when, 323 .when = when,
325 }; 324 };
326 container_descendants(con, C_VIEW, 325 output_for_each_container(output->swayc,
327 send_frame_done_container_iterator, &data); 326 send_frame_done_container_iterator, &data);
328} 327}
329 328
330static void send_frame_done(struct sway_output *output, struct timespec *when) { 329static void send_frame_done(struct sway_output *output, struct timespec *when) {
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index 3b70b471..762b8081 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -215,6 +215,19 @@ static enum wlr_edges find_resize_edge(struct sway_container *cont,
215 return edge; 215 return edge;
216} 216}
217 217
218static void handle_down_motion(struct sway_seat *seat,
219 struct sway_cursor *cursor, uint32_t time_msec) {
220 struct sway_container *con = seat->op_container;
221 if (seat_is_input_allowed(seat, con->sway_view->surface)) {
222 double moved_x = cursor->cursor->x - seat->op_ref_lx;
223 double moved_y = cursor->cursor->y - seat->op_ref_ly;
224 double sx = seat->op_ref_con_lx + moved_x;
225 double sy = seat->op_ref_con_ly + moved_y;
226 wlr_seat_pointer_notify_motion(seat->wlr_seat, time_msec, sx, sy);
227 }
228 seat->op_moved = true;
229}
230
218static void handle_move_motion(struct sway_seat *seat, 231static void handle_move_motion(struct sway_seat *seat,
219 struct sway_cursor *cursor) { 232 struct sway_cursor *cursor) {
220 struct sway_container *con = seat->op_container; 233 struct sway_container *con = seat->op_container;
@@ -397,6 +410,9 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
397 410
398 if (seat->operation != OP_NONE) { 411 if (seat->operation != OP_NONE) {
399 switch (seat->operation) { 412 switch (seat->operation) {
413 case OP_DOWN:
414 handle_down_motion(seat, cursor, time_msec);
415 break;
400 case OP_MOVE: 416 case OP_MOVE:
401 handle_move_motion(seat, cursor); 417 handle_move_motion(seat, cursor);
402 break; 418 break;
@@ -726,13 +742,13 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
726 } 742 }
727 743
728 // Via mod+click 744 // Via mod+click
729 struct sway_container *floater = cont;
730 while (floater->parent->layout != L_FLOATING) {
731 floater = floater->parent;
732 }
733 uint32_t btn_resize = config->floating_mod_inverse ? 745 uint32_t btn_resize = config->floating_mod_inverse ?
734 BTN_LEFT : BTN_RIGHT; 746 BTN_LEFT : BTN_RIGHT;
735 if (button == btn_resize) { 747 if (mod_pressed && button == btn_resize) {
748 struct sway_container *floater = cont;
749 while (floater->parent->layout != L_FLOATING) {
750 floater = floater->parent;
751 }
736 edge = 0; 752 edge = 0;
737 edge |= cursor->cursor->x > floater->x + floater->width / 2 ? 753 edge |= cursor->cursor->x > floater->x + floater->width / 2 ?
738 WLR_EDGE_RIGHT : WLR_EDGE_LEFT; 754 WLR_EDGE_RIGHT : WLR_EDGE_LEFT;
@@ -743,6 +759,14 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
743 } 759 }
744 } 760 }
745 761
762 // Handle mousedown on a container surface
763 if (surface && cont && state == WLR_BUTTON_PRESSED) {
764 seat_set_focus(seat, cont);
765 seat_pointer_notify_button(seat, time_msec, button, state);
766 seat_begin_down(seat, cont, button, sx, sy);
767 return;
768 }
769
746 // Handle clicking a container surface 770 // Handle clicking a container surface
747 if (cont) { 771 if (cont) {
748 seat_set_focus(seat, cont); 772 seat_set_focus(seat, cont);
diff --git a/sway/input/seat.c b/sway/input/seat.c
index fa41904a..d35c62a0 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -313,9 +313,6 @@ static void handle_new_drag_icon(struct wl_listener *listener, void *data) {
313 313
314static void collect_focus_iter(struct sway_container *con, void *data) { 314static void collect_focus_iter(struct sway_container *con, void *data) {
315 struct sway_seat *seat = data; 315 struct sway_seat *seat = data;
316 if (con->type > C_WORKSPACE) {
317 return;
318 }
319 struct sway_seat_container *seat_con = 316 struct sway_seat_container *seat_con =
320 seat_container_from_container(seat, con); 317 seat_container_from_container(seat, con);
321 if (!seat_con) { 318 if (!seat_con) {
@@ -349,7 +346,8 @@ struct sway_seat *seat_create(struct sway_input_manager *input,
349 // init the focus stack 346 // init the focus stack
350 wl_list_init(&seat->focus_stack); 347 wl_list_init(&seat->focus_stack);
351 348
352 container_for_each_descendant(&root_container, collect_focus_iter, seat); 349 root_for_each_workspace(collect_focus_iter, seat);
350 root_for_each_container(collect_focus_iter, seat);
353 351
354 wl_signal_add(&root_container.sway_root->events.new_container, 352 wl_signal_add(&root_container.sway_root->events.new_container,
355 &seat->new_container); 353 &seat->new_container);
@@ -954,6 +952,18 @@ struct seat_config *seat_get_config(struct sway_seat *seat) {
954 return NULL; 952 return NULL;
955} 953}
956 954
955void seat_begin_down(struct sway_seat *seat, struct sway_container *con,
956 uint32_t button, double sx, double sy) {
957 seat->operation = OP_DOWN;
958 seat->op_container = con;
959 seat->op_button = button;
960 seat->op_ref_lx = seat->cursor->cursor->x;
961 seat->op_ref_ly = seat->cursor->cursor->y;
962 seat->op_ref_con_lx = sx;
963 seat->op_ref_con_ly = sy;
964 seat->op_moved = false;
965}
966
957void seat_begin_move(struct sway_seat *seat, struct sway_container *con, 967void seat_begin_move(struct sway_seat *seat, struct sway_container *con,
958 uint32_t button) { 968 uint32_t button) {
959 if (!seat->cursor) { 969 if (!seat->cursor) {
@@ -1007,6 +1017,7 @@ void seat_begin_resize_tiling(struct sway_seat *seat,
1007} 1017}
1008 1018
1009void seat_end_mouse_operation(struct sway_seat *seat) { 1019void seat_end_mouse_operation(struct sway_seat *seat) {
1020 enum sway_seat_operation operation = seat->operation;
1010 if (seat->operation == OP_MOVE) { 1021 if (seat->operation == OP_MOVE) {
1011 // We "move" the container to its own location so it discovers its 1022 // We "move" the container to its own location so it discovers its
1012 // output again. 1023 // output again.
@@ -1015,7 +1026,19 @@ void seat_end_mouse_operation(struct sway_seat *seat) {
1015 } 1026 }
1016 seat->operation = OP_NONE; 1027 seat->operation = OP_NONE;
1017 seat->op_container = NULL; 1028 seat->op_container = NULL;
1018 cursor_set_image(seat->cursor, "left_ptr", NULL); 1029 if (operation == OP_DOWN) {
1030 // Set the cursor's previous coords to the x/y at the start of the
1031 // operation, so the container change will be detected if using
1032 // focus_follows_mouse and the cursor moved off the original container
1033 // during the operation.
1034 seat->cursor->previous.x = seat->op_ref_lx;
1035 seat->cursor->previous.y = seat->op_ref_ly;
1036 if (seat->op_moved) {
1037 cursor_send_pointer_motion(seat->cursor, 0, true);
1038 }
1039 } else {
1040 cursor_set_image(seat->cursor, "left_ptr", NULL);
1041 }
1019} 1042}
1020 1043
1021void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec, 1044void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec,
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index dad1f310..34e940ad 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -522,7 +522,7 @@ void ipc_client_disconnect(struct ipc_client *client) {
522 522
523static void ipc_get_workspaces_callback(struct sway_container *workspace, 523static void ipc_get_workspaces_callback(struct sway_container *workspace,
524 void *data) { 524 void *data) {
525 if (workspace->type != C_WORKSPACE) { 525 if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) {
526 return; 526 return;
527 } 527 }
528 json_object *workspace_json = ipc_json_describe_container(workspace); 528 json_object *workspace_json = ipc_json_describe_container(workspace);
@@ -631,8 +631,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
631 case IPC_GET_WORKSPACES: 631 case IPC_GET_WORKSPACES:
632 { 632 {
633 json_object *workspaces = json_object_new_array(); 633 json_object *workspaces = json_object_new_array();
634 container_for_each_descendant(&root_container, 634 root_for_each_workspace(ipc_get_workspaces_callback, workspaces);
635 ipc_get_workspaces_callback, workspaces);
636 const char *json_string = json_object_to_json_string(workspaces); 635 const char *json_string = json_object_to_json_string(workspaces);
637 client_valid = 636 client_valid =
638 ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); 637 ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
@@ -729,8 +728,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
729 case IPC_GET_MARKS: 728 case IPC_GET_MARKS:
730 { 729 {
731 json_object *marks = json_object_new_array(); 730 json_object *marks = json_object_new_array();
732 container_descendants(&root_container, C_VIEW, ipc_get_marks_callback, 731 root_for_each_container(ipc_get_marks_callback, marks);
733 marks);
734 const char *json_string = json_object_to_json_string(marks); 732 const char *json_string = json_object_to_json_string(marks);
735 client_valid = 733 client_valid =
736 ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); 734 ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
diff --git a/sway/tree/container.c b/sway/tree/container.c
index b3f3a344..2a428ca5 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -270,7 +270,7 @@ static struct sway_container *container_output_destroy(
270 container_destroy(workspace); 270 container_destroy(workspace);
271 } 271 }
272 272
273 container_sort_workspaces(new_output); 273 output_sort_workspaces(new_output);
274 } 274 }
275 } 275 }
276 } 276 }
@@ -432,8 +432,10 @@ struct sway_container *container_close(struct sway_container *con) {
432 432
433 if (con->type == C_VIEW) { 433 if (con->type == C_VIEW) {
434 view_close(con->sway_view); 434 view_close(con->sway_view);
435 } else { 435 } else if (con->type == C_CONTAINER) {
436 container_for_each_descendant(con, container_close_func, NULL); 436 container_for_each_child(con, container_close_func, NULL);
437 } else if (con->type == C_WORKSPACE) {
438 workspace_for_each_container(con, container_close_func, NULL);
437 } 439 }
438 440
439 return parent; 441 return parent;
@@ -465,23 +467,12 @@ struct sway_container *container_view_create(struct sway_container *sibling,
465 return swayc; 467 return swayc;
466} 468}
467 469
468void container_descendants(struct sway_container *root, 470struct sway_container *container_find_child(struct sway_container *container,
469 enum sway_container_type type,
470 void (*func)(struct sway_container *item, void *data), void *data) {
471 if (!root->children || !root->children->length) {
472 return;
473 }
474 for (int i = 0; i < root->children->length; ++i) {
475 struct sway_container *item = root->children->items[i];
476 if (item->type == type) {
477 func(item, data);
478 }
479 container_descendants(item, type, func, data);
480 }
481}
482
483struct sway_container *container_find(struct sway_container *container,
484 bool (*test)(struct sway_container *view, void *data), void *data) { 471 bool (*test)(struct sway_container *view, void *data), void *data) {
472 if (!sway_assert(container->type == C_CONTAINER ||
473 container->type == C_VIEW, "Expected a container or view")) {
474 return NULL;
475 }
485 if (!container->children) { 476 if (!container->children) {
486 return NULL; 477 return NULL;
487 } 478 }
@@ -489,15 +480,11 @@ struct sway_container *container_find(struct sway_container *container,
489 struct sway_container *child = container->children->items[i]; 480 struct sway_container *child = container->children->items[i];
490 if (test(child, data)) { 481 if (test(child, data)) {
491 return child; 482 return child;
492 } else {
493 struct sway_container *res = container_find(child, test, data);
494 if (res) {
495 return res;
496 }
497 } 483 }
498 } 484 struct sway_container *res = container_find_child(child, test, data);
499 if (container->type == C_WORKSPACE) { 485 if (res) {
500 return container_find(container->sway_workspace->floating, test, data); 486 return res;
487 }
501 } 488 }
502 return NULL; 489 return NULL;
503} 490}
@@ -743,26 +730,20 @@ struct sway_container *container_at(struct sway_container *workspace,
743 return NULL; 730 return NULL;
744} 731}
745 732
746void container_for_each_descendant(struct sway_container *container, 733void container_for_each_child(struct sway_container *container,
747 void (*f)(struct sway_container *container, void *data), 734 void (*f)(struct sway_container *container, void *data),
748 void *data) { 735 void *data) {
749 if (!container) { 736 if (!sway_assert(container->type == C_CONTAINER ||
737 container->type == C_VIEW, "Expected a container or view")) {
750 return; 738 return;
751 } 739 }
752 if (container->children) { 740 if (container->children) {
753 for (int i = 0; i < container->children->length; ++i) { 741 for (int i = 0; i < container->children->length; ++i) {
754 struct sway_container *child = container->children->items[i]; 742 struct sway_container *child = container->children->items[i];
755 container_for_each_descendant(child, f, data); 743 f(child, data);
756 } 744 container_for_each_child(child, f, data);
757 }
758 if (container->type == C_WORKSPACE) {
759 struct sway_container *floating = container->sway_workspace->floating;
760 for (int i = 0; i < floating->children->length; ++i) {
761 struct sway_container *child = floating->children->items[i];
762 container_for_each_descendant(child, f, data);
763 } 745 }
764 } 746 }
765 f(container, data);
766} 747}
767 748
768bool container_has_ancestor(struct sway_container *descendant, 749bool container_has_ancestor(struct sway_container *descendant,
@@ -1199,13 +1180,12 @@ void container_set_dirty(struct sway_container *container) {
1199 list_add(server.dirty_containers, container); 1180 list_add(server.dirty_containers, container);
1200} 1181}
1201 1182
1202static bool find_urgent_iterator(struct sway_container *con, 1183static bool find_urgent_iterator(struct sway_container *con, void *data) {
1203 void *data) {
1204 return con->type == C_VIEW && view_is_urgent(con->sway_view); 1184 return con->type == C_VIEW && view_is_urgent(con->sway_view);
1205} 1185}
1206 1186
1207bool container_has_urgent_child(struct sway_container *container) { 1187bool container_has_urgent_child(struct sway_container *container) {
1208 return container_find(container, find_urgent_iterator, NULL); 1188 return container_find_child(container, find_urgent_iterator, NULL);
1209} 1189}
1210 1190
1211void container_end_mouse_operation(struct sway_container *container) { 1191void container_end_mouse_operation(struct sway_container *container) {
@@ -1237,7 +1217,7 @@ void container_set_fullscreen(struct sway_container *container, bool enable) {
1237 container_set_fullscreen(workspace->sway_workspace->fullscreen, false); 1217 container_set_fullscreen(workspace->sway_workspace->fullscreen, false);
1238 } 1218 }
1239 1219
1240 container_for_each_descendant(container, set_fullscreen_iterator, &enable); 1220 container_for_each_child(container, set_fullscreen_iterator, &enable);
1241 1221
1242 container->is_fullscreen = enable; 1222 container->is_fullscreen = enable;
1243 1223
@@ -1306,15 +1286,3 @@ bool container_is_fullscreen_or_child(struct sway_container *container) {
1306 1286
1307 return false; 1287 return false;
1308} 1288}
1309
1310struct sway_container *container_wrap_children(struct sway_container *parent) {
1311 struct sway_container *middle = container_create(C_CONTAINER);
1312 middle->layout = parent->layout;
1313 while (parent->children->length) {
1314 struct sway_container *child = parent->children->items[0];
1315 container_remove_child(child);
1316 container_add_child(middle, child);
1317 }
1318 container_add_child(parent, middle);
1319 return middle;
1320}
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index 2b710403..49ec806e 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -1,5 +1,4 @@
1#define _POSIX_C_SOURCE 200809L 1#define _POSIX_C_SOURCE 200809L
2#include <ctype.h>
3#include <math.h> 2#include <math.h>
4#include <stdbool.h> 3#include <stdbool.h>
5#include <stdlib.h> 4#include <stdlib.h>
@@ -591,28 +590,6 @@ enum sway_container_layout container_get_default_layout(
591 } 590 }
592} 591}
593 592
594static int sort_workspace_cmp_qsort(const void *_a, const void *_b) {
595 struct sway_container *a = *(void **)_a;
596 struct sway_container *b = *(void **)_b;
597 int retval = 0;
598
599 if (isdigit(a->name[0]) && isdigit(b->name[0])) {
600 int a_num = strtol(a->name, NULL, 10);
601 int b_num = strtol(b->name, NULL, 10);
602 retval = (a_num < b_num) ? -1 : (a_num > b_num);
603 } else if (isdigit(a->name[0])) {
604 retval = -1;
605 } else if (isdigit(b->name[0])) {
606 retval = 1;
607 }
608
609 return retval;
610}
611
612void container_sort_workspaces(struct sway_container *output) {
613 list_stable_sort(output->children, sort_workspace_cmp_qsort);
614}
615
616/** 593/**
617 * Get swayc in the direction of newly entered output. 594 * Get swayc in the direction of newly entered output.
618 */ 595 */
diff --git a/sway/tree/output.c b/sway/tree/output.c
index 31e3bf9b..6da63064 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -1,4 +1,5 @@
1#define _POSIX_C_SOURCE 200809L 1#define _POSIX_C_SOURCE 200809L
2#include <ctype.h>
2#include <string.h> 3#include <string.h>
3#include <strings.h> 4#include <strings.h>
4#include "sway/ipc-server.h" 5#include "sway/ipc-server.h"
@@ -28,7 +29,7 @@ static void restore_workspaces(struct sway_container *output) {
28 } 29 }
29 } 30 }
30 31
31 container_sort_workspaces(output); 32 output_sort_workspaces(output);
32} 33}
33 34
34struct sway_container *output_create( 35struct sway_container *output_create(
@@ -102,3 +103,73 @@ struct sway_container *output_create(
102 return output; 103 return output;
103} 104}
104 105
106void output_for_each_workspace(struct sway_container *output,
107 void (*f)(struct sway_container *con, void *data), void *data) {
108 if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) {
109 return;
110 }
111 for (int i = 0; i < output->children->length; ++i) {
112 struct sway_container *workspace = output->children->items[i];
113 f(workspace, data);
114 }
115}
116
117void output_for_each_container(struct sway_container *output,
118 void (*f)(struct sway_container *con, void *data), void *data) {
119 if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) {
120 return;
121 }
122 for (int i = 0; i < output->children->length; ++i) {
123 struct sway_container *workspace = output->children->items[i];
124 workspace_for_each_container(workspace, f, data);
125 }
126}
127
128struct sway_container *output_find_workspace(struct sway_container *output,
129 bool (*test)(struct sway_container *con, void *data), void *data) {
130 if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) {
131 return NULL;
132 }
133 for (int i = 0; i < output->children->length; ++i) {
134 struct sway_container *workspace = output->children->items[i];
135 if (test(workspace, data)) {
136 return workspace;
137 }
138 }
139 return NULL;
140}
141
142struct sway_container *output_find_container(struct sway_container *output,
143 bool (*test)(struct sway_container *con, void *data), void *data) {
144 if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) {
145 return NULL;
146 }
147 struct sway_container *result = NULL;
148 for (int i = 0; i < output->children->length; ++i) {
149 struct sway_container *workspace = output->children->items[i];
150 if ((result = workspace_find_container(workspace, test, data))) {
151 return result;
152 }
153 }
154 return NULL;
155}
156
157static int sort_workspace_cmp_qsort(const void *_a, const void *_b) {
158 struct sway_container *a = *(void **)_a;
159 struct sway_container *b = *(void **)_b;
160
161 if (isdigit(a->name[0]) && isdigit(b->name[0])) {
162 int a_num = strtol(a->name, NULL, 10);
163 int b_num = strtol(b->name, NULL, 10);
164 return (a_num < b_num) ? -1 : (a_num > b_num);
165 } else if (isdigit(a->name[0])) {
166 return -1;
167 } else if (isdigit(b->name[0])) {
168 return 1;
169 }
170 return 0;
171}
172
173void output_sort_workspaces(struct sway_container *output) {
174 list_stable_sort(output->children, sort_workspace_cmp_qsort);
175}
diff --git a/sway/tree/root.c b/sway/tree/root.c
index fc908cc1..8d8f42dc 100644
--- a/sway/tree/root.c
+++ b/sway/tree/root.c
@@ -256,3 +256,81 @@ void root_record_workspace_pid(pid_t pid) {
256 &pw->output_destroy); 256 &pw->output_destroy);
257 wl_list_insert(&pid_workspaces, &pw->link); 257 wl_list_insert(&pid_workspaces, &pw->link);
258} 258}
259
260void root_for_each_workspace(void (*f)(struct sway_container *con, void *data),
261 void *data) {
262 for (int i = 0; i < root_container.children->length; ++i) {
263 struct sway_container *output = root_container.children->items[i];
264 output_for_each_workspace(output, f, data);
265 }
266}
267
268void root_for_each_container(void (*f)(struct sway_container *con, void *data),
269 void *data) {
270 for (int i = 0; i < root_container.children->length; ++i) {
271 struct sway_container *output = root_container.children->items[i];
272 output_for_each_container(output, f, data);
273 }
274
275 // Scratchpad
276 for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) {
277 struct sway_container *container =
278 root_container.sway_root->scratchpad->items[i];
279 // If the container has a parent then it's visible on a workspace
280 // and will have been iterated in the previous for loop. So we only
281 // iterate the hidden scratchpad containers here.
282 if (!container->parent) {
283 f(container, data);
284 container_for_each_child(container, f, data);
285 }
286 }
287}
288
289struct sway_container *root_find_output(
290 bool (*test)(struct sway_container *con, void *data), void *data) {
291 for (int i = 0; i < root_container.children->length; ++i) {
292 struct sway_container *output = root_container.children->items[i];
293 if (test(output, data)) {
294 return output;
295 }
296 }
297 return NULL;
298}
299
300struct sway_container *root_find_workspace(
301 bool (*test)(struct sway_container *con, void *data), void *data) {
302 struct sway_container *result = NULL;
303 for (int i = 0; i < root_container.children->length; ++i) {
304 struct sway_container *output = root_container.children->items[i];
305 if ((result = output_find_workspace(output, test, data))) {
306 return result;
307 }
308 }
309 return NULL;
310}
311
312struct sway_container *root_find_container(
313 bool (*test)(struct sway_container *con, void *data), void *data) {
314 struct sway_container *result = NULL;
315 for (int i = 0; i < root_container.children->length; ++i) {
316 struct sway_container *output = root_container.children->items[i];
317 if ((result = output_find_container(output, test, data))) {
318 return result;
319 }
320 }
321
322 // Scratchpad
323 for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) {
324 struct sway_container *container =
325 root_container.sway_root->scratchpad->items[i];
326 if (!container->parent) {
327 if (test(container, data)) {
328 return container;
329 }
330 if ((result = container_find_child(container, test, data))) {
331 return result;
332 }
333 }
334 }
335 return NULL;
336}
diff --git a/sway/tree/view.c b/sway/tree/view.c
index fbe4bc58..1c1fdb47 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -881,8 +881,8 @@ static bool find_by_mark_iterator(struct sway_container *con,
881} 881}
882 882
883struct sway_view *view_find_mark(char *mark) { 883struct sway_view *view_find_mark(char *mark) {
884 struct sway_container *container = container_find(&root_container, 884 struct sway_container *container = root_find_container(
885 find_by_mark_iterator, mark); 885 find_by_mark_iterator, mark);
886 if (!container) { 886 if (!container) {
887 return NULL; 887 return NULL;
888 } 888 }
@@ -890,7 +890,7 @@ struct sway_view *view_find_mark(char *mark) {
890} 890}
891 891
892bool view_find_and_unmark(char *mark) { 892bool view_find_and_unmark(char *mark) {
893 struct sway_container *container = container_find(&root_container, 893 struct sway_container *container = root_find_container(
894 find_by_mark_iterator, mark); 894 find_by_mark_iterator, mark);
895 if (!container) { 895 if (!container) {
896 return false; 896 return false;
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index e7383de0..b7090de6 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -75,7 +75,7 @@ struct sway_container *workspace_create(struct sway_container *output,
75 workspace_output_add_priority(workspace, output); 75 workspace_output_add_priority(workspace, output);
76 76
77 container_add_child(output, workspace); 77 container_add_child(output, workspace);
78 container_sort_workspaces(output); 78 output_sort_workspaces(output);
79 container_create_notify(workspace); 79 container_create_notify(workspace);
80 80
81 return workspace; 81 return workspace;
@@ -244,8 +244,7 @@ struct sway_container *workspace_by_number(const char* name) {
244 if (wbnd.len <= 0) { 244 if (wbnd.len <= 0) {
245 return NULL; 245 return NULL;
246 } 246 }
247 return container_find(&root_container, 247 return root_find_workspace(_workspace_by_number, (void *) &wbnd);
248 _workspace_by_number, (void *) &wbnd);
249} 248}
250 249
251static bool _workspace_by_name(struct sway_container *view, void *data) { 250static bool _workspace_by_name(struct sway_container *view, void *data) {
@@ -274,11 +273,11 @@ struct sway_container *workspace_by_name(const char *name) {
274 } else if (strcmp(name, "current") == 0) { 273 } else if (strcmp(name, "current") == 0) {
275 return current_workspace; 274 return current_workspace;
276 } else if (strcasecmp(name, "back_and_forth") == 0) { 275 } else if (strcasecmp(name, "back_and_forth") == 0) {
277 return prev_workspace_name ? container_find(&root_container, 276 return prev_workspace_name ?
278 _workspace_by_name, (void *)prev_workspace_name) : NULL; 277 root_find_workspace(_workspace_by_name, (void*)prev_workspace_name)
278 : NULL;
279 } else { 279 } else {
280 return container_find(&root_container, _workspace_by_name, 280 return root_find_workspace(_workspace_by_name, (void*)name);
281 (void *)name);
282 } 281 }
283} 282}
284 283
@@ -518,8 +517,7 @@ struct sway_container *workspace_output_get_highest_available(
518 continue; 517 continue;
519 } 518 }
520 519
521 struct sway_container *output = container_find(&root_container, 520 struct sway_container *output = root_find_output(_output_by_name, name);
522 _output_by_name, name);
523 if (output) { 521 if (output) {
524 return output; 522 return output;
525 } 523 }
@@ -528,8 +526,13 @@ struct sway_container *workspace_output_get_highest_available(
528 return NULL; 526 return NULL;
529} 527}
530 528
529static bool find_urgent_iterator(struct sway_container *con, void *data) {
530 return con->type == C_VIEW && view_is_urgent(con->sway_view);
531}
532
531void workspace_detect_urgent(struct sway_container *workspace) { 533void workspace_detect_urgent(struct sway_container *workspace) {
532 bool new_urgent = container_has_urgent_child(workspace); 534 bool new_urgent = (bool)workspace_find_container(workspace,
535 find_urgent_iterator, NULL);
533 536
534 if (workspace->sway_workspace->urgent != new_urgent) { 537 if (workspace->sway_workspace->urgent != new_urgent) {
535 workspace->sway_workspace->urgent = new_urgent; 538 workspace->sway_workspace->urgent = new_urgent;
@@ -537,3 +540,65 @@ void workspace_detect_urgent(struct sway_container *workspace) {
537 container_damage_whole(workspace); 540 container_damage_whole(workspace);
538 } 541 }
539} 542}
543
544void workspace_for_each_container(struct sway_container *ws,
545 void (*f)(struct sway_container *con, void *data), void *data) {
546 if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) {
547 return;
548 }
549 // Tiling
550 for (int i = 0; i < ws->children->length; ++i) {
551 struct sway_container *container = ws->children->items[i];
552 f(container, data);
553 container_for_each_child(container, f, data);
554 }
555 // Floating
556 for (int i = 0; i < ws->sway_workspace->floating->children->length; ++i) {
557 struct sway_container *container =
558 ws->sway_workspace->floating->children->items[i];
559 f(container, data);
560 container_for_each_child(container, f, data);
561 }
562}
563
564struct sway_container *workspace_find_container(struct sway_container *ws,
565 bool (*test)(struct sway_container *con, void *data), void *data) {
566 if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) {
567 return NULL;
568 }
569 struct sway_container *result = NULL;
570 // Tiling
571 for (int i = 0; i < ws->children->length; ++i) {
572 struct sway_container *child = ws->children->items[i];
573 if (test(child, data)) {
574 return child;
575 }
576 if ((result = container_find_child(child, test, data))) {
577 return result;
578 }
579 }
580 // Floating
581 for (int i = 0; i < ws->sway_workspace->floating->children->length; ++i) {
582 struct sway_container *child =
583 ws->sway_workspace->floating->children->items[i];
584 if (test(child, data)) {
585 return child;
586 }
587 if ((result = container_find_child(child, test, data))) {
588 return result;
589 }
590 }
591 return NULL;
592}
593
594struct sway_container *workspace_wrap_children(struct sway_container *ws) {
595 struct sway_container *middle = container_create(C_CONTAINER);
596 middle->layout = ws->layout;
597 while (ws->children->length) {
598 struct sway_container *child = ws->children->items[0];
599 container_remove_child(child);
600 container_add_child(middle, child);
601 }
602 container_add_child(ws, middle);
603 return middle;
604}