aboutsummaryrefslogtreecommitdiffstats
path: root/sway
diff options
context:
space:
mode:
authorLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-08-17 19:48:34 +1000
committerLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-08-18 23:38:54 +1000
commitd6cd79c342495738fc23fbfbf19a01e73cdc42dc (patch)
tree7a5ebeae1d5e15f047f09698978fa84f61756faa /sway
parentMerge pull request #2460 from RyanDwyer/implement-mousedown (diff)
downloadsway-d6cd79c342495738fc23fbfbf19a01e73cdc42dc.tar.gz
sway-d6cd79c342495738fc23fbfbf19a01e73cdc42dc.tar.zst
sway-d6cd79c342495738fc23fbfbf19a01e73cdc42dc.zip
Implement iterators per container type
This introduces the following `for_each` functions: * root_for_each_workspace * root_for_each_container * output_for_each_workspace * output_for_each_container * workspace_for_each_container And introduces the following `find` functions: * root_find_output * root_find_workspace * root_find_container * output_find_workspace * output_find_container * workspace_find_container * container_find_child And removes the following functions: * container_descendants * container_for_each_descendant * container_find This change is preparing the way for demoting sway_container. Eventually these functions will accept and return sway_outputs, sway_workspaces and sway_containers (meaning a C_CONTAINER or C_VIEW). This change also makes it easy to handle abnormalities like the workspace floating list, root's scratchpad list and (once implemented) root's saved workspaces list for when there's no connected outputs.
Diffstat (limited to 'sway')
-rw-r--r--sway/commands/hide_edge_borders.c2
-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/seat.c6
-rw-r--r--sway/ipc-server.c8
-rw-r--r--sway/tree/container.c62
-rw-r--r--sway/tree/output.c52
-rw-r--r--sway/tree/root.c78
-rw-r--r--sway/tree/view.c6
-rw-r--r--sway/tree/workspace.c71
14 files changed, 233 insertions, 101 deletions
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/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 66747a3f..43ed9793 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -303,15 +303,14 @@ struct send_frame_done_data {
303 303
304static void send_frame_done_container_iterator(struct sway_container *con, 304static void send_frame_done_container_iterator(struct sway_container *con,
305 void *_data) { 305 void *_data) {
306 struct send_frame_done_data *data = _data; 306 if (con->type != C_VIEW) {
307 if (!sway_assert(con->type == C_VIEW, "expected a view")) {
308 return; 307 return;
309 } 308 }
310
311 if (!view_is_visible(con->sway_view)) { 309 if (!view_is_visible(con->sway_view)) {
312 return; 310 return;
313 } 311 }
314 312
313 struct send_frame_done_data *data = _data;
315 output_view_for_each_surface(data->output, con->sway_view, 314 output_view_for_each_surface(data->output, con->sway_view,
316 send_frame_done_iterator, data->when); 315 send_frame_done_iterator, data->when);
317} 316}
@@ -322,8 +321,8 @@ static void send_frame_done_container(struct sway_output *output,
322 .output = output, 321 .output = output,
323 .when = when, 322 .when = when,
324 }; 323 };
325 container_descendants(con, C_VIEW, 324 output_for_each_container(output->swayc,
326 send_frame_done_container_iterator, &data); 325 send_frame_done_container_iterator, &data);
327} 326}
328 327
329static void send_frame_done(struct sway_output *output, struct timespec *when) { 328static void send_frame_done(struct sway_output *output, struct timespec *when) {
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 9d46e760..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);
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 337245fd..1ceae175 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -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 }
740 f(container, data);
752 if (container->children) { 741 if (container->children) {
753 for (int i = 0; i < container->children->length; ++i) { 742 for (int i = 0; i < container->children->length; ++i) {
754 struct sway_container *child = container->children->items[i]; 743 struct sway_container *child = container->children->items[i];
755 container_for_each_descendant(child, f, data); 744 container_for_each_child(child, f, data);
756 } 745 }
757 } 746 }
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 }
764 }
765 f(container, data);
766} 747}
767 748
768bool container_has_ancestor(struct sway_container *descendant, 749bool container_has_ancestor(struct sway_container *descendant,
@@ -1198,13 +1179,12 @@ void container_set_dirty(struct sway_container *container) {
1198 list_add(server.dirty_containers, container); 1179 list_add(server.dirty_containers, container);
1199} 1180}
1200 1181
1201static bool find_urgent_iterator(struct sway_container *con, 1182static bool find_urgent_iterator(struct sway_container *con, void *data) {
1202 void *data) {
1203 return con->type == C_VIEW && view_is_urgent(con->sway_view); 1183 return con->type == C_VIEW && view_is_urgent(con->sway_view);
1204} 1184}
1205 1185
1206bool container_has_urgent_child(struct sway_container *container) { 1186bool container_has_urgent_child(struct sway_container *container) {
1207 return container_find(container, find_urgent_iterator, NULL); 1187 return container_find_child(container, find_urgent_iterator, NULL);
1208} 1188}
1209 1189
1210void container_end_mouse_operation(struct sway_container *container) { 1190void container_end_mouse_operation(struct sway_container *container) {
@@ -1236,7 +1216,7 @@ void container_set_fullscreen(struct sway_container *container, bool enable) {
1236 container_set_fullscreen(workspace->sway_workspace->fullscreen, false); 1216 container_set_fullscreen(workspace->sway_workspace->fullscreen, false);
1237 } 1217 }
1238 1218
1239 container_for_each_descendant(container, set_fullscreen_iterator, &enable); 1219 container_for_each_child(container, set_fullscreen_iterator, &enable);
1240 1220
1241 container->is_fullscreen = enable; 1221 container->is_fullscreen = enable;
1242 1222
diff --git a/sway/tree/output.c b/sway/tree/output.c
index ab955359..6da63064 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -103,6 +103,57 @@ struct sway_container *output_create(
103 return output; 103 return output;
104} 104}
105 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
106static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { 157static int sort_workspace_cmp_qsort(const void *_a, const void *_b) {
107 struct sway_container *a = *(void **)_a; 158 struct sway_container *a = *(void **)_a;
108 struct sway_container *b = *(void **)_b; 159 struct sway_container *b = *(void **)_b;
@@ -122,4 +173,3 @@ static int sort_workspace_cmp_qsort(const void *_a, const void *_b) {
122void output_sort_workspaces(struct sway_container *output) { 173void output_sort_workspaces(struct sway_container *output) {
123 list_stable_sort(output->children, sort_workspace_cmp_qsort); 174 list_stable_sort(output->children, sort_workspace_cmp_qsort);
124} 175}
125
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 950494d8..4495c150 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -899,8 +899,8 @@ static bool find_by_mark_iterator(struct sway_container *con,
899} 899}
900 900
901struct sway_view *view_find_mark(char *mark) { 901struct sway_view *view_find_mark(char *mark) {
902 struct sway_container *container = container_find(&root_container, 902 struct sway_container *container = root_find_container(
903 find_by_mark_iterator, mark); 903 find_by_mark_iterator, mark);
904 if (!container) { 904 if (!container) {
905 return NULL; 905 return NULL;
906 } 906 }
@@ -908,7 +908,7 @@ struct sway_view *view_find_mark(char *mark) {
908} 908}
909 909
910bool view_find_and_unmark(char *mark) { 910bool view_find_and_unmark(char *mark) {
911 struct sway_container *container = container_find(&root_container, 911 struct sway_container *container = root_find_container(
912 find_by_mark_iterator, mark); 912 find_by_mark_iterator, mark);
913 if (!container) { 913 if (!container) {
914 return false; 914 return false;
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index 1c0e6515..b7090de6 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -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;
@@ -538,6 +541,56 @@ void workspace_detect_urgent(struct sway_container *workspace) {
538 } 541 }
539} 542}
540 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
541struct sway_container *workspace_wrap_children(struct sway_container *ws) { 594struct sway_container *workspace_wrap_children(struct sway_container *ws) {
542 struct sway_container *middle = container_create(C_CONTAINER); 595 struct sway_container *middle = container_create(C_CONTAINER);
543 middle->layout = ws->layout; 596 middle->layout = ws->layout;