diff options
-rw-r--r-- | include/sway/input/seat.h | 20 | ||||
-rw-r--r-- | include/sway/output.h | 14 | ||||
-rw-r--r-- | include/sway/tree/container.h | 19 | ||||
-rw-r--r-- | include/sway/tree/layout.h | 2 | ||||
-rw-r--r-- | include/sway/tree/root.h | 15 | ||||
-rw-r--r-- | include/sway/tree/workspace.h | 13 | ||||
-rw-r--r-- | sway/commands/floating.c | 3 | ||||
-rw-r--r-- | sway/commands/fullscreen.c | 3 | ||||
-rw-r--r-- | sway/commands/hide_edge_borders.c | 2 | ||||
-rw-r--r-- | sway/commands/move.c | 6 | ||||
-rw-r--r-- | sway/commands/rename.c | 3 | ||||
-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/cursor.c | 34 | ||||
-rw-r--r-- | sway/input/seat.c | 33 | ||||
-rw-r--r-- | sway/ipc-server.c | 8 | ||||
-rw-r--r-- | sway/tree/container.c | 76 | ||||
-rw-r--r-- | sway/tree/layout.c | 23 | ||||
-rw-r--r-- | sway/tree/output.c | 73 | ||||
-rw-r--r-- | sway/tree/root.c | 78 | ||||
-rw-r--r-- | sway/tree/view.c | 6 | ||||
-rw-r--r-- | sway/tree/workspace.c | 85 |
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 { struct wl_listener destroy; }; +enum sway_seat_operation { + OP_NONE, + OP_DOWN, + OP_MOVE, + OP_RESIZE_FLOATING, + OP_RESIZE_TILING, +}; + struct sway_seat { struct wlr_seat *wlr_seat; struct sway_cursor *cursor; @@ -54,13 +62,7 @@ struct sway_seat { double touch_x, touch_y; // Operations (drag and resize) - enum { - OP_NONE, - OP_MOVE, - OP_RESIZE_FLOATING, - OP_RESIZE_TILING, - } operation; - + enum sway_seat_operation operation; struct sway_container *op_container; enum wlr_edges op_resize_edge; uint32_t op_button; @@ -68,6 +70,7 @@ struct sway_seat { double op_ref_lx, op_ref_ly; // cursor's x/y at start of op double op_ref_width, op_ref_height; // container's size at start of op double op_ref_con_lx, op_ref_con_ly; // container's x/y at start of op + bool op_moved; // if the mouse moved during a down op uint32_t last_button; uint32_t last_button_serial; @@ -157,6 +160,9 @@ bool seat_is_input_allowed(struct sway_seat *seat, struct wlr_surface *surface); void drag_icon_update_position(struct sway_drag_icon *icon); +void seat_begin_down(struct sway_seat *seat, struct sway_container *con, + uint32_t button, double sx, double sy); + void seat_begin_move(struct sway_seat *seat, struct sway_container *con, uint32_t button); 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, struct sway_container *output_by_name(const char *name); +void output_sort_workspaces(struct sway_container *output); + void output_enable(struct sway_output *output); bool 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, struct wl_list *drag_icons, sway_surface_iterator_func_t iterator, void *user_data); +void output_for_each_workspace(struct sway_container *output, + void (*f)(struct sway_container *con, void *data), void *data); + +void output_for_each_container(struct sway_container *output, + void (*f)(struct sway_container *con, void *data), void *data); + +struct sway_container *output_find_workspace(struct sway_container *output, + bool (*test)(struct sway_container *con, void *data), void *data); + +struct sway_container *output_find_container(struct sway_container *output, + bool (*test)(struct sway_container *con, void *data), void *data); + #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); struct sway_container *container_close(struct sway_container *container); -void container_descendants(struct sway_container *root, - enum sway_container_type type, - void (*func)(struct sway_container *item, void *data), void *data); - /** * Search a container's descendants a container based on test criteria. Returns * the first container that passes the test. */ -struct sway_container *container_find(struct sway_container *container, +struct sway_container *container_find_child(struct sway_container *container, bool (*test)(struct sway_container *view, void *data), void *data); /** @@ -244,10 +240,7 @@ struct sway_container *tiling_container_at( struct sway_container *con, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy); -/** - * Apply the function for each child of the container depth first. - */ -void container_for_each_descendant(struct sway_container *container, +void container_for_each_child(struct sway_container *container, void (*f)(struct sway_container *container, void *data), void *data); /** @@ -361,12 +354,4 @@ bool container_is_floating_or_child(struct sway_container *container); */ bool container_is_fullscreen_or_child(struct sway_container *container); -/** - * Wrap the children of parent in a new container. The new container will be the - * only child of parent. - * - * The new container is returned. - */ -struct sway_container *container_wrap_children(struct sway_container *parent); - #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, enum sway_container_layout container_get_default_layout( struct sway_container *con); -void container_sort_workspaces(struct sway_container *output); - struct sway_container *container_get_in_direction(struct sway_container *container, struct sway_seat *seat, enum movement_direction dir); 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); void root_record_workspace_pid(pid_t pid); +void root_for_each_workspace(void (*f)(struct sway_container *con, void *data), + void *data); + +void root_for_each_container(void (*f)(struct sway_container *con, void *data), + void *data); + +struct sway_container *root_find_output( + bool (*test)(struct sway_container *con, void *data), void *data); + +struct sway_container *root_find_workspace( + bool (*test)(struct sway_container *con, void *data), void *data); + +struct sway_container *root_find_container( + bool (*test)(struct sway_container *con, void *data), void *data); + #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( void workspace_detect_urgent(struct sway_container *workspace); +void workspace_for_each_container(struct sway_container *ws, + void (*f)(struct sway_container *con, void *data), void *data); + +struct sway_container *workspace_find_container(struct sway_container *ws, + bool (*test)(struct sway_container *con, void *data), void *data); + +/** + * Wrap the workspace's tiling children in a new container. + * The new container will be the only direct tiling child of the workspace. + * The new container is returned. + */ +struct sway_container *workspace_wrap_children(struct sway_container *ws); + #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 @@ #include "sway/tree/container.h" #include "sway/tree/layout.h" #include "sway/tree/view.h" +#include "sway/tree/workspace.h" #include "list.h" struct cmd_results *cmd_floating(int argc, char **argv) { @@ -24,7 +25,7 @@ struct cmd_results *cmd_floating(int argc, char **argv) { if (container->type == C_WORKSPACE) { // Wrap the workspace's children in a container so we can float it struct sway_container *workspace = container; - container = container_wrap_children(container); + container = workspace_wrap_children(container); workspace->layout = L_HORIZ; seat_set_focus(config->handler_context.seat, container); } 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 @@ #include "sway/tree/arrange.h" #include "sway/tree/container.h" #include "sway/tree/view.h" +#include "sway/tree/workspace.h" #include "sway/tree/layout.h" #include "util.h" @@ -21,7 +22,7 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) { if (container->type == C_WORKSPACE) { // Wrap the workspace's children in a container so we can fullscreen it struct sway_container *workspace = container; - container = container_wrap_children(container); + container = workspace_wrap_children(container); workspace->layout = L_HORIZ; seat_set_focus(config->handler_context.seat, container); } 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) { "<none|vertical|horizontal|both|smart>'"); } - container_for_each_descendant(&root_container, _configure_view, NULL); + root_for_each_container(_configure_view, NULL); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } 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, return cmd_results_new(CMD_FAILURE, "move", "Can't move an empty workspace"); } - current = container_wrap_children(current); + current = workspace_wrap_children(current); } else if (current->type != C_CONTAINER && current->type != C_VIEW) { return cmd_results_new(CMD_FAILURE, "move", "Can only move containers and views."); @@ -245,7 +245,7 @@ static void workspace_move_to_output(struct sway_container *workspace, // Try to remove an empty workspace from the destination output. container_reap_empty_recursive(new_output_focus); - container_sort_workspaces(output); + output_sort_workspaces(output); seat_set_focus(seat, output); workspace_output_raise_priority(workspace, old_output, output); ipc_event_workspace(NULL, workspace, "move"); @@ -437,7 +437,7 @@ static struct cmd_results *move_to_scratchpad(struct sway_container *con) { if (con->type == C_WORKSPACE) { // Wrap the workspace's children in a container struct sway_container *workspace = con; - con = container_wrap_children(con); + con = workspace_wrap_children(con); workspace->layout = L_HORIZ; } 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 @@ #include "sway/commands.h" #include "sway/config.h" #include "sway/ipc-server.h" +#include "sway/output.h" #include "sway/tree/container.h" #include "sway/tree/workspace.h" @@ -82,7 +83,7 @@ struct cmd_results *cmd_rename(int argc, char **argv) { free(workspace->name); workspace->name = new_name; - container_sort_workspaces(workspace->parent); + output_sort_workspaces(workspace->parent); ipc_event_workspace(NULL, workspace, "rename"); 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) { config->show_marks = parse_boolean(argv[0], config->show_marks); if (config->show_marks) { - container_for_each_descendant(&root_container, - rebuild_marks_iterator, NULL); + root_for_each_container(rebuild_marks_iterator, NULL); } 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) { if (strcasecmp(argv[2], "id") == 0) { #ifdef HAVE_XWAYLAND xcb_window_t id = strtol(value, NULL, 0); - other = container_find(&root_container, test_id, (void *)&id); + other = root_find_container(test_id, (void *)&id); #endif } else if (strcasecmp(argv[2], "con_id") == 0) { size_t con_id = atoi(value); - other = container_find(&root_container, test_con_id, (void *)con_id); + other = root_find_container(test_con_id, (void *)con_id); } else if (strcasecmp(argv[2], "mark") == 0) { - other = container_find(&root_container, test_mark, (void *)value); + other = root_find_container(test_mark, (void *)value); } else { free(value); 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) { view_find_and_unmark(mark); } else { // Remove all marks from all views - container_for_each_descendant(&root_container, - remove_all_marks_iterator, NULL); + root_for_each_container(remove_all_marks_iterator, NULL); } free(mark); 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) { size_t prev_max_height = config->font_height; config->font_height = 0; - container_for_each_descendant(&root_container, - find_font_height_iterator, &recalculate); - - // Also consider floating views - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *output = root_container.children->items[i]; - for (int j = 0; j < output->children->length; ++j) { - struct sway_container *ws = output->children->items[j]; - container_for_each_descendant(ws->sway_workspace->floating, - find_font_height_iterator, &recalculate); - } - } + root_for_each_container(find_font_height_iterator, &recalculate); if (config->font_height != prev_max_height) { 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, return false; } list_t *urgent_views = create_list(); - container_for_each_descendant(&root_container, - find_urgent_iterator, urgent_views); + root_for_each_container(find_urgent_iterator, urgent_views); list_stable_sort(urgent_views, cmp_urgent); struct sway_view *target; if (criteria->urgent == 'o') { // oldest @@ -228,17 +227,7 @@ list_t *criteria_get_views(struct criteria *criteria) { .criteria = criteria, .matches = matches, }; - container_for_each_descendant(&root_container, - criteria_get_views_iterator, &data); - - // Scratchpad items which are hidden are not in the tree. - for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) { - struct sway_container *con = - root_container.sway_root->scratchpad->items[i]; - if (!con->parent) { - criteria_get_views_iterator(con, &data); - } - } + root_for_each_container(criteria_get_views_iterator, &data); return matches; } 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 { static void send_frame_done_container_iterator(struct sway_container *con, void *_data) { - struct send_frame_done_data *data = _data; - if (!sway_assert(con->type == C_VIEW, "expected a view")) { + if (con->type != C_VIEW) { return; } - if (!view_is_visible(con->sway_view)) { return; } + struct send_frame_done_data *data = _data; output_view_for_each_surface(data->output, con->sway_view, send_frame_done_iterator, data->when); } @@ -323,8 +322,8 @@ static void send_frame_done_container(struct sway_output *output, .output = output, .when = when, }; - container_descendants(con, C_VIEW, - send_frame_done_container_iterator, &data); + output_for_each_container(output->swayc, + send_frame_done_container_iterator, &data); } static 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, return edge; } +static void handle_down_motion(struct sway_seat *seat, + struct sway_cursor *cursor, uint32_t time_msec) { + struct sway_container *con = seat->op_container; + if (seat_is_input_allowed(seat, con->sway_view->surface)) { + double moved_x = cursor->cursor->x - seat->op_ref_lx; + double moved_y = cursor->cursor->y - seat->op_ref_ly; + double sx = seat->op_ref_con_lx + moved_x; + double sy = seat->op_ref_con_ly + moved_y; + wlr_seat_pointer_notify_motion(seat->wlr_seat, time_msec, sx, sy); + } + seat->op_moved = true; +} + static void handle_move_motion(struct sway_seat *seat, struct sway_cursor *cursor) { struct sway_container *con = seat->op_container; @@ -397,6 +410,9 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, if (seat->operation != OP_NONE) { switch (seat->operation) { + case OP_DOWN: + handle_down_motion(seat, cursor, time_msec); + break; case OP_MOVE: handle_move_motion(seat, cursor); break; @@ -726,13 +742,13 @@ void dispatch_cursor_button(struct sway_cursor *cursor, } // Via mod+click - struct sway_container *floater = cont; - while (floater->parent->layout != L_FLOATING) { - floater = floater->parent; - } uint32_t btn_resize = config->floating_mod_inverse ? BTN_LEFT : BTN_RIGHT; - if (button == btn_resize) { + if (mod_pressed && button == btn_resize) { + struct sway_container *floater = cont; + while (floater->parent->layout != L_FLOATING) { + floater = floater->parent; + } edge = 0; edge |= cursor->cursor->x > floater->x + floater->width / 2 ? WLR_EDGE_RIGHT : WLR_EDGE_LEFT; @@ -743,6 +759,14 @@ void dispatch_cursor_button(struct sway_cursor *cursor, } } + // Handle mousedown on a container surface + if (surface && cont && state == WLR_BUTTON_PRESSED) { + seat_set_focus(seat, cont); + seat_pointer_notify_button(seat, time_msec, button, state); + seat_begin_down(seat, cont, button, sx, sy); + return; + } + // Handle clicking a container surface if (cont) { 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) { static void collect_focus_iter(struct sway_container *con, void *data) { struct sway_seat *seat = data; - if (con->type > C_WORKSPACE) { - return; - } struct sway_seat_container *seat_con = seat_container_from_container(seat, con); if (!seat_con) { @@ -349,7 +346,8 @@ struct sway_seat *seat_create(struct sway_input_manager *input, // init the focus stack wl_list_init(&seat->focus_stack); - container_for_each_descendant(&root_container, collect_focus_iter, seat); + root_for_each_workspace(collect_focus_iter, seat); + root_for_each_container(collect_focus_iter, seat); wl_signal_add(&root_container.sway_root->events.new_container, &seat->new_container); @@ -954,6 +952,18 @@ struct seat_config *seat_get_config(struct sway_seat *seat) { return NULL; } +void seat_begin_down(struct sway_seat *seat, struct sway_container *con, + uint32_t button, double sx, double sy) { + seat->operation = OP_DOWN; + seat->op_container = con; + seat->op_button = button; + seat->op_ref_lx = seat->cursor->cursor->x; + seat->op_ref_ly = seat->cursor->cursor->y; + seat->op_ref_con_lx = sx; + seat->op_ref_con_ly = sy; + seat->op_moved = false; +} + void seat_begin_move(struct sway_seat *seat, struct sway_container *con, uint32_t button) { if (!seat->cursor) { @@ -1007,6 +1017,7 @@ void seat_begin_resize_tiling(struct sway_seat *seat, } void seat_end_mouse_operation(struct sway_seat *seat) { + enum sway_seat_operation operation = seat->operation; if (seat->operation == OP_MOVE) { // We "move" the container to its own location so it discovers its // output again. @@ -1015,7 +1026,19 @@ void seat_end_mouse_operation(struct sway_seat *seat) { } seat->operation = OP_NONE; seat->op_container = NULL; - cursor_set_image(seat->cursor, "left_ptr", NULL); + if (operation == OP_DOWN) { + // Set the cursor's previous coords to the x/y at the start of the + // operation, so the container change will be detected if using + // focus_follows_mouse and the cursor moved off the original container + // during the operation. + seat->cursor->previous.x = seat->op_ref_lx; + seat->cursor->previous.y = seat->op_ref_ly; + if (seat->op_moved) { + cursor_send_pointer_motion(seat->cursor, 0, true); + } + } else { + cursor_set_image(seat->cursor, "left_ptr", NULL); + } } void 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) { static void ipc_get_workspaces_callback(struct sway_container *workspace, void *data) { - if (workspace->type != C_WORKSPACE) { + if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { return; } json_object *workspace_json = ipc_json_describe_container(workspace); @@ -631,8 +631,7 @@ void ipc_client_handle_command(struct ipc_client *client) { case IPC_GET_WORKSPACES: { json_object *workspaces = json_object_new_array(); - container_for_each_descendant(&root_container, - ipc_get_workspaces_callback, workspaces); + root_for_each_workspace(ipc_get_workspaces_callback, workspaces); const char *json_string = json_object_to_json_string(workspaces); client_valid = ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); @@ -729,8 +728,7 @@ void ipc_client_handle_command(struct ipc_client *client) { case IPC_GET_MARKS: { json_object *marks = json_object_new_array(); - container_descendants(&root_container, C_VIEW, ipc_get_marks_callback, - marks); + root_for_each_container(ipc_get_marks_callback, marks); const char *json_string = json_object_to_json_string(marks); client_valid = 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( container_destroy(workspace); } - container_sort_workspaces(new_output); + output_sort_workspaces(new_output); } } } @@ -432,8 +432,10 @@ struct sway_container *container_close(struct sway_container *con) { if (con->type == C_VIEW) { view_close(con->sway_view); - } else { - container_for_each_descendant(con, container_close_func, NULL); + } else if (con->type == C_CONTAINER) { + container_for_each_child(con, container_close_func, NULL); + } else if (con->type == C_WORKSPACE) { + workspace_for_each_container(con, container_close_func, NULL); } return parent; @@ -465,23 +467,12 @@ struct sway_container *container_view_create(struct sway_container *sibling, return swayc; } -void container_descendants(struct sway_container *root, - enum sway_container_type type, - void (*func)(struct sway_container *item, void *data), void *data) { - if (!root->children || !root->children->length) { - return; - } - for (int i = 0; i < root->children->length; ++i) { - struct sway_container *item = root->children->items[i]; - if (item->type == type) { - func(item, data); - } - container_descendants(item, type, func, data); - } -} - -struct sway_container *container_find(struct sway_container *container, +struct sway_container *container_find_child(struct sway_container *container, bool (*test)(struct sway_container *view, void *data), void *data) { + if (!sway_assert(container->type == C_CONTAINER || + container->type == C_VIEW, "Expected a container or view")) { + return NULL; + } if (!container->children) { return NULL; } @@ -489,15 +480,11 @@ struct sway_container *container_find(struct sway_container *container, struct sway_container *child = container->children->items[i]; if (test(child, data)) { return child; - } else { - struct sway_container *res = container_find(child, test, data); - if (res) { - return res; - } } - } - if (container->type == C_WORKSPACE) { - return container_find(container->sway_workspace->floating, test, data); + struct sway_container *res = container_find_child(child, test, data); + if (res) { + return res; + } } return NULL; } @@ -743,26 +730,20 @@ struct sway_container *container_at(struct sway_container *workspace, return NULL; } -void container_for_each_descendant(struct sway_container *container, +void container_for_each_child(struct sway_container *container, void (*f)(struct sway_container *container, void *data), void *data) { - if (!container) { + if (!sway_assert(container->type == C_CONTAINER || + container->type == C_VIEW, "Expected a container or view")) { return; } if (container->children) { for (int i = 0; i < container->children->length; ++i) { struct sway_container *child = container->children->items[i]; - container_for_each_descendant(child, f, data); - } - } - if (container->type == C_WORKSPACE) { - struct sway_container *floating = container->sway_workspace->floating; - for (int i = 0; i < floating->children->length; ++i) { - struct sway_container *child = floating->children->items[i]; - container_for_each_descendant(child, f, data); + f(child, data); + container_for_each_child(child, f, data); } } - f(container, data); } bool container_has_ancestor(struct sway_container *descendant, @@ -1199,13 +1180,12 @@ void container_set_dirty(struct sway_container *container) { list_add(server.dirty_containers, container); } -static bool find_urgent_iterator(struct sway_container *con, - void *data) { +static bool find_urgent_iterator(struct sway_container *con, void *data) { return con->type == C_VIEW && view_is_urgent(con->sway_view); } bool container_has_urgent_child(struct sway_container *container) { - return container_find(container, find_urgent_iterator, NULL); + return container_find_child(container, find_urgent_iterator, NULL); } void container_end_mouse_operation(struct sway_container *container) { @@ -1237,7 +1217,7 @@ void container_set_fullscreen(struct sway_container *container, bool enable) { container_set_fullscreen(workspace->sway_workspace->fullscreen, false); } - container_for_each_descendant(container, set_fullscreen_iterator, &enable); + container_for_each_child(container, set_fullscreen_iterator, &enable); container->is_fullscreen = enable; @@ -1306,15 +1286,3 @@ bool container_is_fullscreen_or_child(struct sway_container *container) { return false; } - -struct sway_container *container_wrap_children(struct sway_container *parent) { - struct sway_container *middle = container_create(C_CONTAINER); - middle->layout = parent->layout; - while (parent->children->length) { - struct sway_container *child = parent->children->items[0]; - container_remove_child(child); - container_add_child(middle, child); - } - container_add_child(parent, middle); - return middle; -} 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 @@ #define _POSIX_C_SOURCE 200809L -#include <ctype.h> #include <math.h> #include <stdbool.h> #include <stdlib.h> @@ -591,28 +590,6 @@ enum sway_container_layout container_get_default_layout( } } -static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { - struct sway_container *a = *(void **)_a; - struct sway_container *b = *(void **)_b; - int retval = 0; - - if (isdigit(a->name[0]) && isdigit(b->name[0])) { - int a_num = strtol(a->name, NULL, 10); - int b_num = strtol(b->name, NULL, 10); - retval = (a_num < b_num) ? -1 : (a_num > b_num); - } else if (isdigit(a->name[0])) { - retval = -1; - } else if (isdigit(b->name[0])) { - retval = 1; - } - - return retval; -} - -void container_sort_workspaces(struct sway_container *output) { - list_stable_sort(output->children, sort_workspace_cmp_qsort); -} - /** * Get swayc in the direction of newly entered output. */ 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 @@ #define _POSIX_C_SOURCE 200809L +#include <ctype.h> #include <string.h> #include <strings.h> #include "sway/ipc-server.h" @@ -28,7 +29,7 @@ static void restore_workspaces(struct sway_container *output) { } } - container_sort_workspaces(output); + output_sort_workspaces(output); } struct sway_container *output_create( @@ -102,3 +103,73 @@ struct sway_container *output_create( return output; } +void output_for_each_workspace(struct sway_container *output, + void (*f)(struct sway_container *con, void *data), void *data) { + if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { + return; + } + for (int i = 0; i < output->children->length; ++i) { + struct sway_container *workspace = output->children->items[i]; + f(workspace, data); + } +} + +void output_for_each_container(struct sway_container *output, + void (*f)(struct sway_container *con, void *data), void *data) { + if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { + return; + } + for (int i = 0; i < output->children->length; ++i) { + struct sway_container *workspace = output->children->items[i]; + workspace_for_each_container(workspace, f, data); + } +} + +struct sway_container *output_find_workspace(struct sway_container *output, + bool (*test)(struct sway_container *con, void *data), void *data) { + if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { + return NULL; + } + for (int i = 0; i < output->children->length; ++i) { + struct sway_container *workspace = output->children->items[i]; + if (test(workspace, data)) { + return workspace; + } + } + return NULL; +} + +struct sway_container *output_find_container(struct sway_container *output, + bool (*test)(struct sway_container *con, void *data), void *data) { + if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { + return NULL; + } + struct sway_container *result = NULL; + for (int i = 0; i < output->children->length; ++i) { + struct sway_container *workspace = output->children->items[i]; + if ((result = workspace_find_container(workspace, test, data))) { + return result; + } + } + return NULL; +} + +static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { + struct sway_container *a = *(void **)_a; + struct sway_container *b = *(void **)_b; + + if (isdigit(a->name[0]) && isdigit(b->name[0])) { + int a_num = strtol(a->name, NULL, 10); + int b_num = strtol(b->name, NULL, 10); + return (a_num < b_num) ? -1 : (a_num > b_num); + } else if (isdigit(a->name[0])) { + return -1; + } else if (isdigit(b->name[0])) { + return 1; + } + return 0; +} + +void output_sort_workspaces(struct sway_container *output) { + list_stable_sort(output->children, sort_workspace_cmp_qsort); +} 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) { &pw->output_destroy); wl_list_insert(&pid_workspaces, &pw->link); } + +void root_for_each_workspace(void (*f)(struct sway_container *con, void *data), + void *data) { + for (int i = 0; i < root_container.children->length; ++i) { + struct sway_container *output = root_container.children->items[i]; + output_for_each_workspace(output, f, data); + } +} + +void root_for_each_container(void (*f)(struct sway_container *con, void *data), + void *data) { + for (int i = 0; i < root_container.children->length; ++i) { + struct sway_container *output = root_container.children->items[i]; + output_for_each_container(output, f, data); + } + + // Scratchpad + for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) { + struct sway_container *container = + root_container.sway_root->scratchpad->items[i]; + // If the container has a parent then it's visible on a workspace + // and will have been iterated in the previous for loop. So we only + // iterate the hidden scratchpad containers here. + if (!container->parent) { + f(container, data); + container_for_each_child(container, f, data); + } + } +} + +struct sway_container *root_find_output( + bool (*test)(struct sway_container *con, void *data), void *data) { + for (int i = 0; i < root_container.children->length; ++i) { + struct sway_container *output = root_container.children->items[i]; + if (test(output, data)) { + return output; + } + } + return NULL; +} + +struct sway_container *root_find_workspace( + bool (*test)(struct sway_container *con, void *data), void *data) { + struct sway_container *result = NULL; + for (int i = 0; i < root_container.children->length; ++i) { + struct sway_container *output = root_container.children->items[i]; + if ((result = output_find_workspace(output, test, data))) { + return result; + } + } + return NULL; +} + +struct sway_container *root_find_container( + bool (*test)(struct sway_container *con, void *data), void *data) { + struct sway_container *result = NULL; + for (int i = 0; i < root_container.children->length; ++i) { + struct sway_container *output = root_container.children->items[i]; + if ((result = output_find_container(output, test, data))) { + return result; + } + } + + // Scratchpad + for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) { + struct sway_container *container = + root_container.sway_root->scratchpad->items[i]; + if (!container->parent) { + if (test(container, data)) { + return container; + } + if ((result = container_find_child(container, test, data))) { + return result; + } + } + } + return NULL; +} 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, } struct sway_view *view_find_mark(char *mark) { - struct sway_container *container = container_find(&root_container, - find_by_mark_iterator, mark); + struct sway_container *container = root_find_container( + find_by_mark_iterator, mark); if (!container) { return NULL; } @@ -890,7 +890,7 @@ struct sway_view *view_find_mark(char *mark) { } bool view_find_and_unmark(char *mark) { - struct sway_container *container = container_find(&root_container, + struct sway_container *container = root_find_container( find_by_mark_iterator, mark); if (!container) { 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, workspace_output_add_priority(workspace, output); container_add_child(output, workspace); - container_sort_workspaces(output); + output_sort_workspaces(output); container_create_notify(workspace); return workspace; @@ -244,8 +244,7 @@ struct sway_container *workspace_by_number(const char* name) { if (wbnd.len <= 0) { return NULL; } - return container_find(&root_container, - _workspace_by_number, (void *) &wbnd); + return root_find_workspace(_workspace_by_number, (void *) &wbnd); } static bool _workspace_by_name(struct sway_container *view, void *data) { @@ -274,11 +273,11 @@ struct sway_container *workspace_by_name(const char *name) { } else if (strcmp(name, "current") == 0) { return current_workspace; } else if (strcasecmp(name, "back_and_forth") == 0) { - return prev_workspace_name ? container_find(&root_container, - _workspace_by_name, (void *)prev_workspace_name) : NULL; + return prev_workspace_name ? + root_find_workspace(_workspace_by_name, (void*)prev_workspace_name) + : NULL; } else { - return container_find(&root_container, _workspace_by_name, - (void *)name); + return root_find_workspace(_workspace_by_name, (void*)name); } } @@ -518,8 +517,7 @@ struct sway_container *workspace_output_get_highest_available( continue; } - struct sway_container *output = container_find(&root_container, - _output_by_name, name); + struct sway_container *output = root_find_output(_output_by_name, name); if (output) { return output; } @@ -528,8 +526,13 @@ struct sway_container *workspace_output_get_highest_available( return NULL; } +static bool find_urgent_iterator(struct sway_container *con, void *data) { + return con->type == C_VIEW && view_is_urgent(con->sway_view); +} + void workspace_detect_urgent(struct sway_container *workspace) { - bool new_urgent = container_has_urgent_child(workspace); + bool new_urgent = (bool)workspace_find_container(workspace, + find_urgent_iterator, NULL); if (workspace->sway_workspace->urgent != new_urgent) { workspace->sway_workspace->urgent = new_urgent; @@ -537,3 +540,65 @@ void workspace_detect_urgent(struct sway_container *workspace) { container_damage_whole(workspace); } } + +void workspace_for_each_container(struct sway_container *ws, + void (*f)(struct sway_container *con, void *data), void *data) { + if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { + return; + } + // Tiling + for (int i = 0; i < ws->children->length; ++i) { + struct sway_container *container = ws->children->items[i]; + f(container, data); + container_for_each_child(container, f, data); + } + // Floating + for (int i = 0; i < ws->sway_workspace->floating->children->length; ++i) { + struct sway_container *container = + ws->sway_workspace->floating->children->items[i]; + f(container, data); + container_for_each_child(container, f, data); + } +} + +struct sway_container *workspace_find_container(struct sway_container *ws, + bool (*test)(struct sway_container *con, void *data), void *data) { + if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { + return NULL; + } + struct sway_container *result = NULL; + // Tiling + for (int i = 0; i < ws->children->length; ++i) { + struct sway_container *child = ws->children->items[i]; + if (test(child, data)) { + return child; + } + if ((result = container_find_child(child, test, data))) { + return result; + } + } + // Floating + for (int i = 0; i < ws->sway_workspace->floating->children->length; ++i) { + struct sway_container *child = + ws->sway_workspace->floating->children->items[i]; + if (test(child, data)) { + return child; + } + if ((result = container_find_child(child, test, data))) { + return result; + } + } + return NULL; +} + +struct sway_container *workspace_wrap_children(struct sway_container *ws) { + struct sway_container *middle = container_create(C_CONTAINER); + middle->layout = ws->layout; + while (ws->children->length) { + struct sway_container *child = ws->children->items[0]; + container_remove_child(child); + container_add_child(middle, child); + } + container_add_child(ws, middle); + return middle; +} |