diff options
Diffstat (limited to 'sway/tree/container.c')
-rw-r--r-- | sway/tree/container.c | 163 |
1 files changed, 135 insertions, 28 deletions
diff --git a/sway/tree/container.c b/sway/tree/container.c index 7cea43fa..02384199 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -11,11 +11,14 @@ #include "cairo.h" #include "pango.h" #include "sway/config.h" +#include "sway/desktop.h" +#include "sway/desktop/transaction.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" #include "sway/ipc-server.h" #include "sway/output.h" #include "sway/server.h" +#include "sway/tree/arrange.h" #include "sway/tree/layout.h" #include "sway/tree/view.h" #include "sway/tree/workspace.h" @@ -28,7 +31,7 @@ static list_t *get_bfs_queue() { if (!bfs_queue) { bfs_queue = create_list(); if (!bfs_queue) { - wlr_log(L_ERROR, "could not allocate list for bfs queue"); + wlr_log(WLR_ERROR, "could not allocate list for bfs queue"); return NULL; } } @@ -156,14 +159,6 @@ void container_free(struct sway_container *cont) { wlr_texture_destroy(cont->title_focused_inactive); wlr_texture_destroy(cont->title_unfocused); wlr_texture_destroy(cont->title_urgent); - - for (int i = 0; i < server.destroying_containers->length; ++i) { - if (server.destroying_containers->items[i] == cont) { - list_del(server.destroying_containers, i); - break; - } - } - list_free(cont->instructions); list_free(cont->children); list_free(cont->current.children); @@ -218,7 +213,7 @@ static struct sway_container *container_workspace_destroy( return NULL; } - wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name); + wlr_log(WLR_DEBUG, "destroying workspace '%s'", workspace->name); if (!workspace_is_empty(workspace)) { // Move children to a different workspace on this output @@ -230,7 +225,7 @@ static struct sway_container *container_workspace_destroy( } } - wlr_log(L_DEBUG, "moving children to different workspace '%s' -> '%s'", + wlr_log(WLR_DEBUG, "moving children to different workspace '%s' -> '%s'", workspace->name, new_workspace->name); for (int i = 0; i < workspace->children->length; i++) { container_move_to(workspace->children->items[i], new_workspace); @@ -296,7 +291,7 @@ static struct sway_container *container_output_destroy( output->sway_output->swayc = NULL; output->sway_output = NULL; - wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); + wlr_log(WLR_DEBUG, "OUTPUT: Destroying output '%s'", output->name); return &root_container; } @@ -323,13 +318,13 @@ static struct sway_container *container_destroy_noreaping( // Workspaces will refuse to be destroyed if they're the last workspace // on their output. if (!container_workspace_destroy(con)) { - wlr_log(L_ERROR, "workspace doesn't want to destroy"); + wlr_log(WLR_ERROR, "workspace doesn't want to destroy"); return NULL; } } con->destroying = true; - list_add(server.destroying_containers, con); + container_set_dirty(con); if (!con->parent) { return NULL; @@ -350,7 +345,7 @@ bool container_reap_empty(struct sway_container *con) { break; case C_WORKSPACE: if (!workspace_is_visible(con) && workspace_is_empty(con)) { - wlr_log(L_DEBUG, "Destroying workspace via reaper"); + wlr_log(WLR_DEBUG, "Destroying workspace via reaper"); container_destroy_noreaping(con); return true; } @@ -443,7 +438,7 @@ struct sway_container *container_view_create(struct sway_container *sibling, } const char *title = view_get_title(sway_view); struct sway_container *swayc = container_create(C_VIEW); - wlr_log(L_DEBUG, "Adding new view %p:%s to container %p %d %s", + wlr_log(WLR_DEBUG, "Adding new view %p:%s to container %p %d %s", swayc, title, sibling, sibling ? sibling->type : 0, sibling->name); // Setup values swayc->sway_view = sway_view; @@ -686,16 +681,23 @@ struct sway_container *floating_container_at(double lx, double ly, void container_for_each_descendant_dfs(struct sway_container *container, void (*f)(struct sway_container *container, void *data), void *data) { - if (container) { - if (container->children) { - for (int i = 0; i < container->children->length; ++i) { - struct sway_container *child = - container->children->items[i]; - container_for_each_descendant_dfs(child, f, data); - } + if (!container) { + 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_dfs(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_dfs(child, f, data); } - f(container, data); } + f(container, data); } void container_for_each_descendant_bfs(struct sway_container *con, @@ -706,7 +708,7 @@ void container_for_each_descendant_bfs(struct sway_container *con, } if (queue == NULL) { - wlr_log(L_ERROR, "could not allocate list"); + wlr_log(WLR_ERROR, "could not allocate list"); return; } @@ -972,9 +974,14 @@ void container_set_geometry_from_floating_view(struct sway_container *con) { return; } struct sway_view *view = con->sway_view; - size_t border_width = view->border_thickness * (view->border != B_NONE); - size_t top = - view->border == B_NORMAL ? container_titlebar_height() : border_width; + size_t border_width = 0; + size_t top = 0; + + if (!view->using_csd) { + border_width = view->border_thickness * (view->border != B_NONE); + top = view->border == B_NORMAL ? + container_titlebar_height() : border_width; + } con->x = view->x - border_width; con->y = view->y - top; @@ -996,3 +1003,103 @@ void container_get_box(struct sway_container *container, struct wlr_box *box) { box->width = container->width; box->height = container->height; } + +/** + * Translate the container's position as well as all children. + */ +static void container_floating_translate(struct sway_container *con, + double x_amount, double y_amount) { + con->x += x_amount; + con->y += y_amount; + con->current.swayc_x += x_amount; + con->current.swayc_y += y_amount; + if (con->type == C_VIEW) { + con->sway_view->x += x_amount; + con->sway_view->y += y_amount; + con->current.view_x += x_amount; + con->current.view_y += y_amount; + } else { + for (int i = 0; i < con->children->length; ++i) { + struct sway_container *child = con->children->items[i]; + container_floating_translate(child, x_amount, y_amount); + } + } +} + +/** + * Choose an output for the floating container's new position. + * + * If the center of the container intersects an output then we'll choose that + * one, otherwise we'll choose whichever output is closest to the container's + * center. + */ +static struct sway_container *container_floating_find_output( + struct sway_container *con) { + double center_x = con->x + con->width / 2; + double center_y = con->y + con->height / 2; + struct sway_container *closest_output = NULL; + double closest_distance = DBL_MAX; + for (int i = 0; i < root_container.children->length; ++i) { + struct sway_container *output = root_container.children->items[i]; + struct wlr_box output_box; + double closest_x, closest_y; + container_get_box(output, &output_box); + wlr_box_closest_point(&output_box, center_x, center_y, + &closest_x, &closest_y); + if (center_x == closest_x && center_y == closest_y) { + // The center of the floating container is on this output + return output; + } + double x_dist = closest_x - center_x; + double y_dist = closest_y - center_y; + double distance = x_dist * x_dist + y_dist * y_dist; + if (distance < closest_distance) { + closest_output = output; + closest_distance = distance; + } + } + return closest_output; +} + +void container_floating_move_to(struct sway_container *con, + double lx, double ly) { + if (!sway_assert(container_is_floating(con), + "Expected a floating container")) { + return; + } + desktop_damage_whole_container(con); + container_floating_translate(con, lx - con->x, ly - con->y); + desktop_damage_whole_container(con); + struct sway_container *old_workspace = container_parent(con, C_WORKSPACE); + struct sway_container *new_output = container_floating_find_output(con); + if (!sway_assert(new_output, "Unable to find any output")) { + return; + } + struct sway_container *new_workspace = + output_get_active_workspace(new_output->sway_output); + if (old_workspace != new_workspace) { + container_remove_child(con); + container_add_child(new_workspace->sway_workspace->floating, con); + arrange_windows(old_workspace); + arrange_windows(new_workspace); + workspace_detect_urgent(old_workspace); + workspace_detect_urgent(new_workspace); + } +} + +void container_set_dirty(struct sway_container *container) { + if (container->dirty) { + return; + } + container->dirty = true; + list_add(server.dirty_containers, container); +} + +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); +} |