diff options
author | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-08-17 19:48:34 +1000 |
---|---|---|
committer | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-08-18 23:38:54 +1000 |
commit | d6cd79c342495738fc23fbfbf19a01e73cdc42dc (patch) | |
tree | 7a5ebeae1d5e15f047f09698978fa84f61756faa | |
parent | Merge pull request #2460 from RyanDwyer/implement-mousedown (diff) | |
download | sway-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.
-rw-r--r-- | include/sway/output.h | 12 | ||||
-rw-r--r-- | include/sway/tree/container.h | 11 | ||||
-rw-r--r-- | include/sway/tree/root.h | 15 | ||||
-rw-r--r-- | include/sway/tree/workspace.h | 6 | ||||
-rw-r--r-- | sway/commands/hide_edge_borders.c | 2 | ||||
-rw-r--r-- | sway/commands/show_marks.c | 3 | ||||
-rw-r--r-- | sway/commands/swap.c | 6 | ||||
-rw-r--r-- | sway/commands/unmark.c | 3 | ||||
-rw-r--r-- | sway/config.c | 13 | ||||
-rw-r--r-- | sway/criteria.c | 15 | ||||
-rw-r--r-- | sway/desktop/output.c | 9 | ||||
-rw-r--r-- | sway/input/seat.c | 6 | ||||
-rw-r--r-- | sway/ipc-server.c | 8 | ||||
-rw-r--r-- | sway/tree/container.c | 62 | ||||
-rw-r--r-- | sway/tree/output.c | 52 | ||||
-rw-r--r-- | sway/tree/root.c | 78 | ||||
-rw-r--r-- | sway/tree/view.c | 6 | ||||
-rw-r--r-- | sway/tree/workspace.c | 71 |
18 files changed, 268 insertions, 110 deletions
diff --git a/include/sway/output.h b/include/sway/output.h index 8bdd1919..d0d034b3 100644 --- a/include/sway/output.h +++ b/include/sway/output.h | |||
@@ -95,4 +95,16 @@ void output_drag_icons_for_each_surface(struct sway_output *output, | |||
95 | struct wl_list *drag_icons, sway_surface_iterator_func_t iterator, | 95 | struct wl_list *drag_icons, sway_surface_iterator_func_t iterator, |
96 | void *user_data); | 96 | void *user_data); |
97 | 97 | ||
98 | void output_for_each_workspace(struct sway_container *output, | ||
99 | void (*f)(struct sway_container *con, void *data), void *data); | ||
100 | |||
101 | void output_for_each_container(struct sway_container *output, | ||
102 | void (*f)(struct sway_container *con, void *data), void *data); | ||
103 | |||
104 | struct sway_container *output_find_workspace(struct sway_container *output, | ||
105 | bool (*test)(struct sway_container *con, void *data), void *data); | ||
106 | |||
107 | struct sway_container *output_find_container(struct sway_container *output, | ||
108 | bool (*test)(struct sway_container *con, void *data), void *data); | ||
109 | |||
98 | #endif | 110 | #endif |
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index d866ec03..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 | ||
215 | struct sway_container *container_close(struct sway_container *container); | 215 | struct sway_container *container_close(struct sway_container *container); |
216 | 216 | ||
217 | void 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 | */ |
225 | struct sway_container *container_find(struct sway_container *container, | 221 | struct 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 | /** | 243 | void container_for_each_child(struct sway_container *container, |
248 | * Apply the function for each child of the container depth first. | ||
249 | */ | ||
250 | void 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 | /** |
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 | ||
59 | void root_record_workspace_pid(pid_t pid); | 59 | void root_record_workspace_pid(pid_t pid); |
60 | 60 | ||
61 | void root_for_each_workspace(void (*f)(struct sway_container *con, void *data), | ||
62 | void *data); | ||
63 | |||
64 | void root_for_each_container(void (*f)(struct sway_container *con, void *data), | ||
65 | void *data); | ||
66 | |||
67 | struct sway_container *root_find_output( | ||
68 | bool (*test)(struct sway_container *con, void *data), void *data); | ||
69 | |||
70 | struct sway_container *root_find_workspace( | ||
71 | bool (*test)(struct sway_container *con, void *data), void *data); | ||
72 | |||
73 | struct 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 5b43ae87..c9dbb538 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h | |||
@@ -50,6 +50,12 @@ struct sway_container *workspace_output_get_highest_available( | |||
50 | 50 | ||
51 | void workspace_detect_urgent(struct sway_container *workspace); | 51 | void workspace_detect_urgent(struct sway_container *workspace); |
52 | 52 | ||
53 | void workspace_for_each_container(struct sway_container *ws, | ||
54 | void (*f)(struct sway_container *con, void *data), void *data); | ||
55 | |||
56 | struct sway_container *workspace_find_container(struct sway_container *ws, | ||
57 | bool (*test)(struct sway_container *con, void *data), void *data); | ||
58 | |||
53 | /** | 59 | /** |
54 | * Wrap the workspace's tiling children in a new container. | 60 | * Wrap the workspace's tiling children in a new container. |
55 | * The new container will be the only direct tiling child of the workspace. | 61 | * The new container will be the only direct tiling child of the workspace. |
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 | ||
304 | static void send_frame_done_container_iterator(struct sway_container *con, | 304 | static 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 | ||
329 | static void send_frame_done(struct sway_output *output, struct timespec *when) { | 328 | static 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 | ||
314 | static void collect_focus_iter(struct sway_container *con, void *data) { | 314 | static 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 | ||
523 | static void ipc_get_workspaces_callback(struct sway_container *workspace, | 523 | static 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 | ||
468 | void container_descendants(struct sway_container *root, | 470 | struct 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 | |||
483 | struct 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 | ||
746 | void container_for_each_descendant(struct sway_container *container, | 733 | void 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 | ||
768 | bool container_has_ancestor(struct sway_container *descendant, | 749 | bool 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 | ||
1201 | static bool find_urgent_iterator(struct sway_container *con, | 1182 | static 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 | ||
1206 | bool container_has_urgent_child(struct sway_container *container) { | 1186 | bool 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 | ||
1210 | void container_end_mouse_operation(struct sway_container *container) { | 1190 | void 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 | ||
106 | void 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 | |||
117 | void 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 | |||
128 | struct 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 | |||
142 | struct 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 | |||
106 | static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { | 157 | static 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) { | |||
122 | void output_sort_workspaces(struct sway_container *output) { | 173 | void 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 | |||
260 | void 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 | |||
268 | void 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 | |||
289 | struct 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 | |||
300 | struct 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 | |||
312 | struct 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 | ||
901 | struct sway_view *view_find_mark(char *mark) { | 901 | struct 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 | ||
910 | bool view_find_and_unmark(char *mark) { | 910 | bool 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 | ||
251 | static bool _workspace_by_name(struct sway_container *view, void *data) { | 250 | static 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 | ||
529 | static bool find_urgent_iterator(struct sway_container *con, void *data) { | ||
530 | return con->type == C_VIEW && view_is_urgent(con->sway_view); | ||
531 | } | ||
532 | |||
531 | void workspace_detect_urgent(struct sway_container *workspace) { | 533 | void 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 | ||
544 | void 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 | |||
564 | struct 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 | |||
541 | struct sway_container *workspace_wrap_children(struct sway_container *ws) { | 594 | struct 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; |