diff options
author | Drew DeVault <sir@cmpwn.com> | 2018-07-23 20:27:56 -0400 |
---|---|---|
committer | Drew DeVault <sir@cmpwn.com> | 2018-07-23 20:31:11 -0400 |
commit | f4b882475eee7a81c206c7825616cc4656b2f60b (patch) | |
tree | 38e6ebf81b235424f105dcbcbb194e5e9eac70c0 /sway/tree | |
parent | acd79e1505c06089e4fb9fb6c0c6e1d351ba9176 (diff) | |
parent | 224ade138208e9aa525423cbfbd643aa9d9b63c3 (diff) |
Merge branch 'master' into pid-workspaces
Diffstat (limited to 'sway/tree')
-rw-r--r-- | sway/tree/arrange.c | 102 | ||||
-rw-r--r-- | sway/tree/container.c | 209 | ||||
-rw-r--r-- | sway/tree/layout.c | 97 | ||||
-rw-r--r-- | sway/tree/output.c | 6 | ||||
-rw-r--r-- | sway/tree/view.c | 191 | ||||
-rw-r--r-- | sway/tree/workspace.c | 57 |
6 files changed, 472 insertions, 190 deletions
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index 582b2891..533cf71c 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c @@ -47,11 +47,11 @@ static void apply_horiz_layout(struct sway_container *parent) { double scale = parent->width / total_width; // Resize windows - wlr_log(L_DEBUG, "Arranging %p horizontally", parent); + wlr_log(WLR_DEBUG, "Arranging %p horizontally", parent); double child_x = parent->x; for (size_t i = 0; i < num_children; ++i) { struct sway_container *child = parent->children->items[i]; - wlr_log(L_DEBUG, + wlr_log(WLR_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", child, child->type, child->width, scale); child->x = child_x; @@ -99,11 +99,11 @@ static void apply_vert_layout(struct sway_container *parent) { double scale = parent_height / total_height; // Resize - wlr_log(L_DEBUG, "Arranging %p vertically", parent); + wlr_log(WLR_DEBUG, "Arranging %p vertically", parent); double child_y = parent->y + parent_offset; for (size_t i = 0; i < num_children; ++i) { struct sway_container *child = parent->children->items[i]; - wlr_log(L_DEBUG, + wlr_log(WLR_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", child, child->type, child->height, scale); child->x = parent->x; @@ -144,42 +144,26 @@ static void apply_tabbed_or_stacked_layout(struct sway_container *parent) { } } -/** - * If a container has been deleted from the pending tree state, we must add it - * to the transaction so it can be freed afterwards. To do this, we iterate the - * server's destroying_containers list and add all of them. We may add more than - * what we need to, but this is easy and has no negative consequences. - */ -static void add_deleted_containers(struct sway_transaction *transaction) { - for (int i = 0; i < server.destroying_containers->length; ++i) { - struct sway_container *child = server.destroying_containers->items[i]; - transaction_add_container(transaction, child); - } -} - -static void arrange_children_of(struct sway_container *parent, - struct sway_transaction *transaction); +static void arrange_children_of(struct sway_container *parent); -static void arrange_floating(struct sway_container *floating, - struct sway_transaction *transaction) { +static void arrange_floating(struct sway_container *floating) { for (int i = 0; i < floating->children->length; ++i) { struct sway_container *floater = floating->children->items[i]; if (floater->type == C_VIEW) { view_autoconfigure(floater->sway_view); } else { - arrange_children_of(floater, transaction); + arrange_children_of(floater); } - transaction_add_container(transaction, floater); + container_set_dirty(floater); } - transaction_add_container(transaction, floating); + container_set_dirty(floating); } -static void arrange_children_of(struct sway_container *parent, - struct sway_transaction *transaction) { +static void arrange_children_of(struct sway_container *parent) { if (config->reloading) { return; } - wlr_log(L_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", parent, + wlr_log(WLR_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", parent, parent->name, parent->width, parent->height, parent->x, parent->y); // Calculate x, y, width and height of children @@ -198,7 +182,7 @@ static void arrange_children_of(struct sway_container *parent, apply_horiz_layout(parent); break; case L_FLOATING: - arrange_floating(parent, transaction); + arrange_floating(parent); break; } @@ -213,20 +197,19 @@ static void arrange_children_of(struct sway_container *parent, if (child->type == C_VIEW) { view_autoconfigure(child->sway_view); } else { - arrange_children_of(child, transaction); + arrange_children_of(child); } - transaction_add_container(transaction, child); + container_set_dirty(child); } } -static void arrange_workspace(struct sway_container *workspace, - struct sway_transaction *transaction) { +static void arrange_workspace(struct sway_container *workspace) { if (config->reloading) { return; } struct sway_container *output = workspace->parent; struct wlr_box *area = &output->sway_output->usable_area; - wlr_log(L_DEBUG, "Usable area for ws: %dx%d@%d,%d", + wlr_log(WLR_DEBUG, "Usable area for ws: %dx%d@%d,%d", area->width, area->height, area->x, area->y); remove_gaps(workspace); workspace->width = area->width; @@ -234,15 +217,14 @@ static void arrange_workspace(struct sway_container *workspace, workspace->x = output->x + area->x; workspace->y = output->y + area->y; add_gaps(workspace); - transaction_add_container(transaction, workspace); - wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name, + container_set_dirty(workspace); + wlr_log(WLR_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name, workspace->x, workspace->y); - arrange_floating(workspace->sway_workspace->floating, transaction); - arrange_children_of(workspace, transaction); + arrange_floating(workspace->sway_workspace->floating); + arrange_children_of(workspace); } -static void arrange_output(struct sway_container *output, - struct sway_transaction *transaction) { +static void arrange_output(struct sway_container *output) { if (config->reloading) { return; } @@ -253,16 +235,16 @@ static void arrange_output(struct sway_container *output, output->y = output_box->y; output->width = output_box->width; output->height = output_box->height; - transaction_add_container(transaction, output); - wlr_log(L_DEBUG, "Arranging output '%s' at %f,%f", + container_set_dirty(output); + wlr_log(WLR_DEBUG, "Arranging output '%s' at %f,%f", output->name, output->x, output->y); for (int i = 0; i < output->children->length; ++i) { struct sway_container *workspace = output->children->items[i]; - arrange_workspace(workspace, transaction); + arrange_workspace(workspace); } } -static void arrange_root(struct sway_transaction *transaction) { +static void arrange_root() { if (config->reloading) { return; } @@ -274,48 +256,40 @@ static void arrange_root(struct sway_transaction *transaction) { root_container.y = layout_box->y; root_container.width = layout_box->width; root_container.height = layout_box->height; - transaction_add_container(transaction, &root_container); + container_set_dirty(&root_container); for (int i = 0; i < root_container.children->length; ++i) { struct sway_container *output = root_container.children->items[i]; - arrange_output(output, transaction); + arrange_output(output); } } -void arrange_windows(struct sway_container *container, - struct sway_transaction *transaction) { +void arrange_windows(struct sway_container *container) { switch (container->type) { case C_ROOT: - arrange_root(transaction); + arrange_root(); break; case C_OUTPUT: - arrange_output(container, transaction); + arrange_output(container); break; case C_WORKSPACE: - arrange_workspace(container, transaction); + arrange_workspace(container); break; case C_CONTAINER: - arrange_children_of(container, transaction); - transaction_add_container(transaction, container); + arrange_children_of(container); + container_set_dirty(container); break; case C_VIEW: view_autoconfigure(container->sway_view); - transaction_add_container(transaction, container); + container_set_dirty(container); break; case C_TYPES: break; } - add_deleted_containers(transaction); -} - -void arrange_and_commit(struct sway_container *container) { - struct sway_transaction *transaction = transaction_create(); - arrange_windows(container, transaction); - transaction_commit(transaction); } void remove_gaps(struct sway_container *c) { if (c->current_gaps == 0) { - wlr_log(L_DEBUG, "Removing gaps: not gapped: %p", c); + wlr_log(WLR_DEBUG, "Removing gaps: not gapped: %p", c); return; } @@ -326,12 +300,12 @@ void remove_gaps(struct sway_container *c) { c->current_gaps = 0; - wlr_log(L_DEBUG, "Removing gaps %p", c); + wlr_log(WLR_DEBUG, "Removing gaps %p", c); } void add_gaps(struct sway_container *c) { if (c->current_gaps > 0 || c->type == C_CONTAINER) { - wlr_log(L_DEBUG, "Not adding gaps: %p", c); + wlr_log(WLR_DEBUG, "Not adding gaps: %p", c); return; } @@ -348,5 +322,5 @@ void add_gaps(struct sway_container *c) { c->height -= 2 * gaps; c->current_gaps = gaps; - wlr_log(L_DEBUG, "Adding gaps: %p", c); + wlr_log(WLR_DEBUG, "Adding gaps: %p", c); } diff --git a/sway/tree/container.c b/sway/tree/container.c index 6f6137c4..4f743c40 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -11,11 +11,15 @@ #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/scratchpad.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 +32,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; } } @@ -151,18 +155,11 @@ void container_free(struct sway_container *cont) { return; } free(cont->name); + free(cont->formatted_title); wlr_texture_destroy(cont->title_focused); 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); @@ -203,16 +200,23 @@ static struct sway_container *container_workspace_destroy( return NULL; } - // Do not destroy this if it's the last workspace on this output struct sway_container *output = container_parent(workspace, C_OUTPUT); - if (output && output->children->length == 1) { + + // If we're destroying the output, it will be NULL here. Return the root so + // that it doesn't appear that the workspace has refused to be destoyed, + // which would leave it in a broken state with no parent. + if (output == NULL) { + return &root_container; + } + + // Do not destroy this if it's the last workspace on this output + if (output->children->length == 1) { return NULL; } - wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name); + wlr_log(WLR_DEBUG, "destroying workspace '%s'", workspace->name); - struct sway_container *parent = workspace->parent; - if (!workspace_is_empty(workspace) && output) { + if (!workspace_is_empty(workspace)) { // Move children to a different workspace on this output struct sway_container *new_workspace = NULL; for (int i = 0; i < output->children->length; i++) { @@ -222,7 +226,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); @@ -234,7 +238,7 @@ static struct sway_container *container_workspace_destroy( } } - return parent; + return output; } static struct sway_container *container_output_destroy( @@ -288,7 +292,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; } @@ -315,13 +319,19 @@ 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; } } + container_end_mouse_operation(con); + con->destroying = true; - list_add(server.destroying_containers, con); + container_set_dirty(con); + + if (con->scratchpad) { + scratchpad_remove_container(con); + } if (!con->parent) { return NULL; @@ -342,7 +352,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; } @@ -435,7 +445,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; @@ -657,7 +667,9 @@ struct sway_container *floating_container_at(double lx, double ly, if (!workspace_is_visible(workspace)) { continue; } - for (int k = 0; k < ws->floating->children->length; ++k) { + // Items at the end of the list are on top, so iterate the list in + // reverse. + for (int k = ws->floating->children->length - 1; k >= 0; --k) { struct sway_container *floater = ws->floating->children->items[k]; struct wlr_box box = { @@ -678,16 +690,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); } - f(container, 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); } void container_for_each_descendant_bfs(struct sway_container *con, @@ -698,7 +717,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; } @@ -782,7 +801,7 @@ static void update_title_texture(struct sway_container *con, double scale = output->sway_output->wlr_output->scale; int width = 0; - int height = config->font_height * scale; + int height = con->title_height * scale; cairo_t *c = cairo_create(NULL); get_text_size(c, config->font, &width, NULL, scale, config->pango_markup, @@ -935,11 +954,15 @@ void container_set_floating(struct sway_container *container, bool enable) { container_add_child(workspace->sway_workspace->floating, container); if (container->type == C_VIEW) { view_init_floating(container->sway_view); + view_set_tiled(container->sway_view, false); } seat_set_focus(seat, seat_get_focus_inactive(seat, container)); container_reap_empty_recursive(workspace); } else { // Returning to tiled + if (container->scratchpad) { + scratchpad_remove_container(container); + } container_remove_child(container); container_add_child(workspace, container); container->width = container->parent->width; @@ -951,6 +974,8 @@ void container_set_floating(struct sway_container *container, bool enable) { container_reap_empty_recursive(workspace->sway_workspace->floating); } + container_end_mouse_operation(container); + ipc_event_window(container, "floating"); } @@ -963,9 +988,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; @@ -987,3 +1017,112 @@ 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. + */ +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); +} + +void container_end_mouse_operation(struct sway_container *container) { + struct sway_seat *seat; + wl_list_for_each(seat, &input_manager->seats, link) { + if (seat->op_container == container) { + seat_end_mouse_operation(seat); + } + } +} diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 14631ad4..a2be0ef3 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -22,7 +22,8 @@ struct sway_container root_container; static void output_layout_handle_change(struct wl_listener *listener, void *data) { - arrange_and_commit(&root_container); + arrange_windows(&root_container); + transaction_commit_dirty(); } void layout_init(void) { @@ -41,6 +42,7 @@ void layout_init(void) { wl_list_init(&root_container.sway_root->xwayland_unmanaged); wl_list_init(&root_container.sway_root->drag_icons); wl_signal_init(&root_container.sway_root->events.new_container); + root_container.sway_root->scratchpad = create_list(); root_container.sway_root->output_layout_change.notify = output_layout_handle_change; @@ -101,7 +103,7 @@ void container_insert_child(struct sway_container *parent, if (old_parent) { container_remove_child(child); } - wlr_log(L_DEBUG, "Inserting id:%zd at index %d", child->id, i); + wlr_log(WLR_DEBUG, "Inserting id:%zd at index %d", child->id, i); list_insert(parent->children, i, child); child->parent = parent; container_handle_fullscreen_reparent(child, old_parent); @@ -127,13 +129,17 @@ struct sway_container *container_add_sibling(struct sway_container *fixed, void container_add_child(struct sway_container *parent, struct sway_container *child) { - wlr_log(L_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)", + wlr_log(WLR_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)", child, child->type, child->width, child->height, parent, parent->type, parent->width, parent->height); struct sway_container *old_parent = child->parent; list_add(parent->children, child); child->parent = parent; container_handle_fullscreen_reparent(child, old_parent); + if (old_parent) { + container_set_dirty(old_parent); + } + container_set_dirty(child); } struct sway_container *container_remove_child(struct sway_container *child) { @@ -152,6 +158,9 @@ struct sway_container *container_remove_child(struct sway_container *child) { child->parent = NULL; container_notify_subtree_changed(parent); + container_set_dirty(parent); + container_set_dirty(child); + return parent; } @@ -168,7 +177,12 @@ void container_move_to(struct sway_container *container, struct sway_container *old_parent = container_remove_child(container); container->width = container->height = 0; container->saved_width = container->saved_height = 0; - struct sway_container *new_parent; + + struct sway_container *new_parent, *new_parent_focus; + struct sway_seat *seat = input_manager_get_default_seat(input_manager); + + // Get the focus of the destination before we change it. + new_parent_focus = seat_get_focus_inactive(seat, destination); if (destination->type == C_VIEW) { new_parent = container_add_sibling(destination, container); } else { @@ -176,17 +190,20 @@ void container_move_to(struct sway_container *container, container_add_child(destination, container); } wl_signal_emit(&container->events.reparent, old_parent); + if (container->type == C_WORKSPACE) { // If moving a workspace to a new output, maybe create a new workspace // on the previous output - struct sway_seat *seat = input_manager_get_default_seat(input_manager); if (old_parent->children->length == 0) { char *ws_name = workspace_next_name(old_parent->name); - struct sway_container *ws = - workspace_create(old_parent, ws_name); + struct sway_container *ws = workspace_create(old_parent, ws_name); free(ws_name); seat_set_focus(seat, ws); } + + // Try to remove an empty workspace from the destination output. + container_reap_empty_recursive(new_parent_focus); + container_sort_workspaces(new_parent); seat_set_focus(seat, new_parent); workspace_output_raise_priority(container, old_parent, new_parent); @@ -216,6 +233,17 @@ void container_move_to(struct sway_container *container, } } } + // Update workspace urgent state + struct sway_container *old_workspace = old_parent; + if (old_workspace->type != C_WORKSPACE) { + old_workspace = container_parent(old_workspace, C_WORKSPACE); + } + if (new_workspace != old_workspace) { + workspace_detect_urgent(new_workspace); + if (old_workspace) { + workspace_detect_urgent(old_workspace); + } + } } static bool sway_dir_to_wlr(enum movement_direction dir, @@ -311,13 +339,13 @@ static void move_out_of_tabs_stacks(struct sway_container *container, int offs) { if (container->parent == current->parent && current->parent->children->length == 1) { - wlr_log(L_DEBUG, "Changing layout of %zd", current->parent->id); + wlr_log(WLR_DEBUG, "Changing layout of %zd", current->parent->id); current->parent->layout = move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; return; } - wlr_log(L_DEBUG, "Moving out of tab/stack into a split"); + wlr_log(WLR_DEBUG, "Moving out of tab/stack into a split"); bool is_workspace = current->parent->type == C_WORKSPACE; struct sway_container *new_parent = container_split(current->parent, move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT); @@ -362,7 +390,7 @@ void container_move(struct sway_container *container, } parent = current->parent; - wlr_log(L_DEBUG, "Visiting %p %s '%s'", current, + wlr_log(WLR_DEBUG, "Visiting %p %s '%s'", current, container_type_to_str(current->type), current->name); int index = index_child(current); @@ -380,12 +408,12 @@ void container_move(struct sway_container *container, root_container.sway_root->output_layout, wlr_dir, current->sway_output->wlr_output, ref_lx, ref_ly); if (!next) { - wlr_log(L_DEBUG, "Hit edge of output, nowhere else to go"); + wlr_log(WLR_DEBUG, "Hit edge of output, nowhere else to go"); return; } struct sway_output *next_output = next->data; current = next_output->swayc; - wlr_log(L_DEBUG, "Selected next output (%s)", current->name); + wlr_log(WLR_DEBUG, "Selected next output (%s)", current->name); // Select workspace and get outta here current = seat_get_focus_inactive( config->handler_context.seat, current); @@ -398,20 +426,20 @@ void container_move(struct sway_container *container, case C_WORKSPACE: if (!is_parallel(current->layout, move_dir)) { if (current->children->length >= 2) { - wlr_log(L_DEBUG, "Rejiggering the workspace (%d kiddos)", + wlr_log(WLR_DEBUG, "Rejiggering the workspace (%d kiddos)", current->children->length); workspace_rejigger(current, container, move_dir); return; } else { - wlr_log(L_DEBUG, "Selecting output"); + wlr_log(WLR_DEBUG, "Selecting output"); current = current->parent; } } else if (current->layout == L_TABBED || current->layout == L_STACKED) { - wlr_log(L_DEBUG, "Rejiggering out of tabs/stacks"); + wlr_log(WLR_DEBUG, "Rejiggering out of tabs/stacks"); workspace_rejigger(current, container, move_dir); } else { - wlr_log(L_DEBUG, "Selecting output"); + wlr_log(WLR_DEBUG, "Selecting output"); current = current->parent; } break; @@ -427,11 +455,11 @@ void container_move(struct sway_container *container, move_dir, offs); return; } else { - wlr_log(L_DEBUG, "Hit limit, selecting parent"); + wlr_log(WLR_DEBUG, "Hit limit, selecting parent"); current = current->parent; } } else { - wlr_log(L_DEBUG, "Hit limit, " + wlr_log(WLR_DEBUG, "Hit limit, " "promoting descendant to sibling"); // Special case container_insert_child(current->parent, container, @@ -441,14 +469,14 @@ void container_move(struct sway_container *container, } } else { sibling = parent->children->items[index + offs]; - wlr_log(L_DEBUG, "Selecting sibling id:%zd", sibling->id); + wlr_log(WLR_DEBUG, "Selecting sibling id:%zd", sibling->id); } } else if (parent->layout == L_TABBED || parent->layout == L_STACKED) { move_out_of_tabs_stacks(container, current, move_dir, offs); return; } else { - wlr_log(L_DEBUG, "Moving up to find a parallel container"); + wlr_log(WLR_DEBUG, "Moving up to find a parallel container"); current = current->parent; } break; @@ -467,11 +495,11 @@ void container_move(struct sway_container *container, switch (sibling->type) { case C_VIEW: if (sibling->parent == container->parent) { - wlr_log(L_DEBUG, "Swapping siblings"); + wlr_log(WLR_DEBUG, "Swapping siblings"); sibling->parent->children->items[index + offs] = container; sibling->parent->children->items[index] = sibling; } else { - wlr_log(L_DEBUG, "Promoting to sibling of cousin"); + wlr_log(WLR_DEBUG, "Promoting to sibling of cousin"); container_insert_child(sibling->parent, container, index_child(sibling) + (offs > 0 ? 0 : 1)); container->width = container->height = 0; @@ -482,31 +510,31 @@ void container_move(struct sway_container *container, case C_CONTAINER: if (is_parallel(sibling->layout, move_dir)) { int limit = container_limit(sibling, invert_movement(move_dir)); - wlr_log(L_DEBUG, "limit: %d", limit); - wlr_log(L_DEBUG, + wlr_log(WLR_DEBUG, "limit: %d", limit); + wlr_log(WLR_DEBUG, "Reparenting container (parallel) to index %d " "(move dir: %d)", limit, move_dir); container_insert_child(sibling, container, limit); container->width = container->height = 0; sibling = NULL; } else { - wlr_log(L_DEBUG, "Reparenting container (perpendicular)"); + wlr_log(WLR_DEBUG, "Reparenting container (perpendicular)"); struct sway_container *focus_inactive = seat_get_focus_inactive( config->handler_context.seat, sibling); if (focus_inactive && focus_inactive != sibling) { while (focus_inactive->parent != sibling) { focus_inactive = focus_inactive->parent; } - wlr_log(L_DEBUG, "Focus inactive: id:%zd", + wlr_log(WLR_DEBUG, "Focus inactive: id:%zd", focus_inactive->id); sibling = focus_inactive; continue; } else if (sibling->children->length) { - wlr_log(L_DEBUG, "No focus-inactive, adding arbitrarily"); + wlr_log(WLR_DEBUG, "No focus-inactive, adding arbitrarily"); container_remove_child(container); container_add_sibling(sibling->children->items[0], container); } else { - wlr_log(L_DEBUG, "No kiddos, adding container alone"); + wlr_log(WLR_DEBUG, "No kiddos, adding container alone"); container_remove_child(container); container_add_child(sibling, container); } @@ -539,7 +567,10 @@ void container_move(struct sway_container *container, } if (last_ws && next_ws && last_ws != next_ws) { ipc_event_workspace(last_ws, container, "focus"); + workspace_detect_urgent(last_ws); + workspace_detect_urgent(next_ws); } + container_end_mouse_operation(container); } enum sway_container_layout container_get_default_layout( @@ -603,7 +634,7 @@ static struct sway_container *get_swayc_in_output_direction( } if (ws == NULL) { - wlr_log(L_ERROR, "got an output without a workspace"); + wlr_log(WLR_ERROR, "got an output without a workspace"); return NULL; } @@ -775,7 +806,7 @@ struct sway_container *container_get_in_direction( } else { struct sway_container *desired_con = parent->children->items[desired]; - wlr_log(L_DEBUG, + wlr_log(WLR_DEBUG, "cont %d-%p dir %i sibling %d: %p", idx, container, dir, desired, desired_con); return seat_get_focus_inactive_view(seat, desired_con); @@ -840,7 +871,7 @@ struct sway_container *container_split(struct sway_container *child, struct sway_container *cont = container_create(C_CONTAINER); - wlr_log(L_DEBUG, "creating container %p around %p", cont, child); + wlr_log(WLR_DEBUG, "creating container %p around %p", cont, child); remove_gaps(child); @@ -888,7 +919,7 @@ struct sway_container *container_split(struct sway_container *child, void container_recursive_resize(struct sway_container *container, double amount, enum resize_edge edge) { bool layout_match = true; - wlr_log(L_DEBUG, "Resizing %p with amount: %f", container, amount); + wlr_log(WLR_DEBUG, "Resizing %p with amount: %f", container, amount); if (edge == RESIZE_EDGE_LEFT || edge == RESIZE_EDGE_RIGHT) { container->width += amount; layout_match = container->layout == L_HORIZ; @@ -978,7 +1009,7 @@ void container_swap(struct sway_container *con1, struct sway_container *con2) { return; } - wlr_log(L_DEBUG, "Swapping containers %zu and %zu", con1->id, con2->id); + wlr_log(WLR_DEBUG, "Swapping containers %zu and %zu", con1->id, con2->id); int fs1 = con1->type == C_VIEW && con1->sway_view->is_fullscreen; int fs2 = con2->type == C_VIEW && con2->sway_view->is_fullscreen; diff --git a/sway/tree/output.c b/sway/tree/output.c index e2927cdb..da535c18 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -43,11 +43,11 @@ struct sway_container *output_create( if (strcasecmp(name, cur->name) == 0 || strcasecmp(identifier, cur->name) == 0) { - wlr_log(L_DEBUG, "Matched output config for %s", name); + wlr_log(WLR_DEBUG, "Matched output config for %s", name); oc = cur; } if (strcasecmp("*", cur->name) == 0) { - wlr_log(L_DEBUG, "Matched wildcard output config for %s", name); + wlr_log(WLR_DEBUG, "Matched wildcard output config for %s", name); all = cur; } @@ -86,7 +86,7 @@ struct sway_container *output_create( if (!output->children->length) { // Create workspace char *ws_name = workspace_next_name(output->name); - wlr_log(L_DEBUG, "Creating default workspace %s", ws_name); + wlr_log(WLR_DEBUG, "Creating default workspace %s", ws_name); struct sway_container *ws = workspace_create(output, ws_name); // Set each seat's focus if not already set struct sway_seat *seat = NULL; diff --git a/sway/tree/view.c b/sway/tree/view.c index 24fb6864..a55c8a29 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -26,6 +26,7 @@ void view_init(struct sway_view *view, enum sway_view_type type, view->impl = impl; view->executed_criteria = create_list(); view->marks = create_list(); + view->allow_request_urgent = true; wl_signal_init(&view->events.unmap); } @@ -141,6 +142,19 @@ const char *view_get_shell(struct sway_view *view) { return "unknown"; } +void view_get_constraints(struct sway_view *view, double *min_width, + double *max_width, double *min_height, double *max_height) { + if (view->impl->get_constraints) { + view->impl->get_constraints(view, + min_width, max_width, min_height, max_height); + } else { + *min_width = DBL_MIN; + *max_width = DBL_MAX; + *min_height = DBL_MIN; + *max_height = DBL_MAX; + } +} + uint32_t view_configure(struct sway_view *view, double lx, double ly, int width, int height) { if (view->impl->configure) { @@ -151,12 +165,43 @@ uint32_t view_configure(struct sway_view *view, double lx, double ly, int width, void view_init_floating(struct sway_view *view) { struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - int max_width = ws->width * 0.6666; - int max_height = ws->height * 0.6666; - view->width = - view->natural_width > max_width ? max_width : view->natural_width; - view->height = - view->natural_height > max_height ? max_height : view->natural_height; + int min_width, min_height; + int max_width, max_height; + + if (config->floating_minimum_width == -1) { // no minimum + min_width = 0; + } else if (config->floating_minimum_width == 0) { // automatic + min_width = 75; + } else { + min_width = config->floating_minimum_width; + } + + if (config->floating_minimum_height == -1) { // no minimum + min_height = 0; + } else if (config->floating_minimum_height == 0) { // automatic + min_height = 50; + } else { + min_height = config->floating_minimum_height; + } + + if (config->floating_maximum_width == -1) { // no maximum + max_width = INT_MAX; + } else if (config->floating_maximum_width == 0) { // automatic + max_width = ws->width * 0.6666; + } else { + max_width = config->floating_maximum_width; + } + + if (config->floating_maximum_height == -1) { // no maximum + max_height = INT_MAX; + } else if (config->floating_maximum_height == 0) { // automatic + max_height = ws->height * 0.6666; + } else { + max_height = config->floating_maximum_height; + } + + view->width = fmax(min_width, fmin(view->natural_width, max_width)); + view->height = fmax(min_height, fmin(view->natural_height, max_height)); view->x = ws->x + (ws->width - view->width) / 2; view->y = ws->y + (ws->height - view->height) / 2; @@ -165,9 +210,6 @@ void view_init_floating(struct sway_view *view) { view->border_left = view->border_right = true; container_set_geometry_from_floating_view(view->swayc); - - // Don't maximize floating windows - view_set_tiled(view, false); } void view_autoconfigure(struct sway_view *view) { @@ -279,7 +321,6 @@ void view_autoconfigure(struct sway_view *view) { view->y = y; view->width = width; view->height = height; - view_set_tiled(view, true); } void view_set_activated(struct sway_view *view, bool activated) { @@ -289,7 +330,15 @@ void view_set_activated(struct sway_view *view, bool activated) { } void view_set_tiled(struct sway_view *view, bool tiled) { - view->border = tiled ? config->border : B_NONE; + if (!tiled) { + view->using_csd = true; + if (view->impl->has_client_side_decorations) { + view->using_csd = view->impl->has_client_side_decorations(view); + } + } else { + view->using_csd = false; + } + if (view->impl->set_tiled) { view->impl->set_tiled(view, tiled); } @@ -352,6 +401,8 @@ void view_set_fullscreen(struct sway_view *view, bool fullscreen) { } } + container_end_mouse_operation(view->swayc); + ipc_event_window(view->swayc, "fullscreen_mode"); } @@ -467,27 +518,45 @@ void view_execute_criteria(struct sway_view *view) { list_t *criterias = criteria_for_view(view, CT_COMMAND); for (int i = 0; i < criterias->length; i++) { struct criteria *criteria = criterias->items[i]; - wlr_log(L_DEBUG, "Checking criteria %s", criteria->raw); + wlr_log(WLR_DEBUG, "Checking criteria %s", criteria->raw); if (view_has_executed_criteria(view, criteria)) { - wlr_log(L_DEBUG, "Criteria already executed"); + wlr_log(WLR_DEBUG, "Criteria already executed"); continue; } - wlr_log(L_DEBUG, "for_window '%s' matches view %p, cmd: '%s'", + wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'", criteria->raw, view, criteria->cmdlist); + seat_set_focus(seat, view->swayc); list_add(view->executed_criteria, criteria); struct cmd_results *res = execute_command(criteria->cmdlist, NULL); if (res->status != CMD_SUCCESS) { - wlr_log(L_ERROR, "Command '%s' failed: %s", res->input, res->error); + wlr_log(WLR_ERROR, "Command '%s' failed: %s", res->input, res->error); } free_cmd_results(res); - // view must be focused for commands to affect it, - // so always refocus in-between command lists - seat_set_focus(seat, view->swayc); } list_free(criterias); seat_set_focus(seat, prior_focus); } +static bool should_focus(struct sway_view *view) { + // If the view is the only one in the focused workspace, it'll get focus + // regardless of any no_focus criteria. + struct sway_container *parent = view->swayc->parent; + struct sway_seat *seat = input_manager_current_seat(input_manager); + if (parent->type == C_WORKSPACE && seat_get_focus(seat) == parent) { + size_t num_children = parent->children->length + + parent->sway_workspace->floating->children->length; + if (num_children == 1) { + return true; + } + } + + // Check no_focus criteria + list_t *criterias = criteria_for_view(view, CT_NO_FOCUS); + size_t len = criterias->length; + list_free(criterias); + return len == 0; +} + void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { if (!sway_assert(view->surface == NULL, "cannot map mapped view")) { return; @@ -524,7 +593,11 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { prev_focus = target_sibling; target_sibling = seat_get_focus_inactive(seat, workspace); } else { - // TODO: CT_ASSIGN_OUTPUT + // CT_ASSIGN_OUTPUT + struct sway_container *output = output_by_name(criteria->target); + if (output) { + prev_focus = seat_get_focus_inactive(seat, output); + } } } list_free(criterias); @@ -549,8 +622,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { view->surface = wlr_surface; view->swayc = cont; - view->border = config->border; - view->border_thickness = config->border_thickness; view_init_subsurfaces(view, wlr_surface); wl_signal_add(&wlr_surface->events.new_subsurface, @@ -561,11 +632,20 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { view->container_reparent.notify = view_handle_container_reparent; if (view->impl->wants_floating && view->impl->wants_floating(view)) { + view->border = config->floating_border; + view->border_thickness = config->floating_border_thickness; container_set_floating(view->swayc, true); + } else { + view->border = config->border; + view->border_thickness = config->border_thickness; + view_set_tiled(view, true); } - if (prev_focus == target_sibling) { + if (should_focus(view) && prev_focus == target_sibling) { input_manager_set_focus(input_manager, cont); + if (workspace) { + workspace_switch(workspace); + } } view_update_title(view, false); @@ -581,16 +661,27 @@ void view_unmap(struct sway_view *view) { wl_list_remove(&view->surface_new_subsurface.link); wl_list_remove(&view->container_reparent.link); + if (view->urgent_timer) { + wl_event_source_remove(view->urgent_timer); + view->urgent_timer = NULL; + } + + struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); + + struct sway_container *parent; if (view->is_fullscreen) { - struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); ws->sway_workspace->fullscreen = NULL; - container_destroy(view->swayc); + parent = container_destroy(view->swayc); - arrange_and_commit(ws->parent); + arrange_windows(ws->parent); } else { - struct sway_container *parent = container_destroy(view->swayc); - arrange_and_commit(parent); + parent = container_destroy(view->swayc); + arrange_windows(parent); + } + if (parent->type >= C_WORKSPACE) { // if the workspace still exists + workspace_detect_urgent(ws); } + transaction_commit_dirty(); view->surface = NULL; } @@ -601,6 +692,8 @@ void view_update_position(struct sway_view *view, double lx, double ly) { container_damage_whole(view->swayc); view->x = lx; view->y = ly; + view->swayc->current.view_x = lx; + view->swayc->current.view_y = ly; if (container_is_floating(view->swayc)) { container_set_geometry_from_floating_view(view->swayc); } @@ -614,6 +707,8 @@ void view_update_size(struct sway_view *view, int width, int height) { container_damage_whole(view->swayc); view->width = width; view->height = height; + view->swayc->current.view_width = width; + view->swayc->current.view_height = height; if (container_is_floating(view->swayc)) { container_set_geometry_from_floating_view(view->swayc); } @@ -624,7 +719,7 @@ static void view_subsurface_create(struct sway_view *view, struct wlr_subsurface *subsurface) { struct sway_view_child *child = calloc(1, sizeof(struct sway_view_child)); if (child == NULL) { - wlr_log(L_ERROR, "Allocation failed"); + wlr_log(WLR_ERROR, "Allocation failed"); return; } view_child_init(child, NULL, view, subsurface->surface); @@ -744,8 +839,9 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) { return NULL; } - wlr_log(L_DEBUG, "Surface of unknown type (role %s): %p", - wlr_surface->role, wlr_surface); + const char *role = wlr_surface->role ? wlr_surface->role->name : NULL; + wlr_log(WLR_DEBUG, "Surface of unknown type (role %s): %p", + role, wlr_surface); return NULL; } @@ -812,7 +908,7 @@ static char *escape_title(char *buffer) { char *escaped_title = calloc(length + 1, sizeof(char)); int result = escape_markup_text(buffer, escaped_title, length); if (result != length) { - wlr_log(L_ERROR, "Could not escape title: %s", buffer); + wlr_log(WLR_ERROR, "Could not escape title: %s", buffer); free(escaped_title); return buffer; } @@ -946,7 +1042,7 @@ static void update_marks_texture(struct sway_view *view, double scale = output->sway_output->wlr_output->scale; int width = 0; - int height = config->font_height * scale; + int height = view->swayc->title_height * scale; cairo_t *c = cairo_create(NULL); get_text_size(c, config->font, &width, NULL, scale, false, "%s", buffer); @@ -995,7 +1091,7 @@ void view_update_marks_textures(struct sway_view *view) { } bool view_is_visible(struct sway_view *view) { - if (!view->swayc || view->swayc->destroying) { + if (!view->swayc || view->swayc->destroying || !view->swayc->parent) { return false; } struct sway_container *workspace = @@ -1033,3 +1129,32 @@ bool view_is_visible(struct sway_view *view) { } return true; } + +void view_set_urgent(struct sway_view *view, bool enable) { + if (view_is_urgent(view) == enable) { + return; + } + if (enable) { + struct sway_seat *seat = input_manager_current_seat(input_manager); + if (seat_get_focus(seat) == view->swayc) { + return; + } + clock_gettime(CLOCK_MONOTONIC, &view->urgent); + } else { + view->urgent = (struct timespec){ 0 }; + if (view->urgent_timer) { + wl_event_source_remove(view->urgent_timer); + view->urgent_timer = NULL; + } + } + container_damage_whole(view->swayc); + + ipc_event_window(view->swayc, "urgent"); + + struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); + workspace_detect_urgent(ws); +} + +bool view_is_urgent(struct sway_view *view) { + return view->urgent.tv_sec || view->urgent.tv_nsec; +} diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 651cc011..a93d9f44 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -12,6 +12,7 @@ #include "sway/output.h" #include "sway/tree/arrange.h" #include "sway/tree/container.h" +#include "sway/tree/view.h" #include "sway/tree/workspace.h" #include "list.h" #include "log.h" @@ -50,7 +51,7 @@ struct sway_container *workspace_create(struct sway_container *output, output = get_workspace_initial_output(name); } - wlr_log(L_DEBUG, "Added workspace %s for output %s", name, output->name); + wlr_log(WLR_DEBUG, "Added workspace %s for output %s", name, output->name); struct sway_container *workspace = container_create(C_WORKSPACE); workspace->x = output->x; @@ -108,9 +109,8 @@ static bool workspace_valid_on_output(const char *output_name, } char *workspace_next_name(const char *output_name) { - wlr_log(L_DEBUG, "Workspace: Generating new workspace name for output %s", + wlr_log(WLR_DEBUG, "Workspace: Generating new workspace name for output %s", output_name); - int l = 1; // Scan all workspace bindings to find the next available workspace name, // if none are found/available then default to a number struct sway_mode *mode = config->current_mode; @@ -137,7 +137,7 @@ char *workspace_next_name(const char *output_name) { while (isspace(*_target)) { memmove(_target, _target+1, strlen(_target+1)); } - wlr_log(L_DEBUG, "Got valid workspace command for target: '%s'", + wlr_log(WLR_DEBUG, "Got valid workspace command for target: '%s'", _target); // Make sure that the command references an actual workspace @@ -163,7 +163,7 @@ char *workspace_next_name(const char *output_name) { temp[length - 1] = '\0'; free(_target); _target = temp; - wlr_log(L_DEBUG, "Isolated name from workspace number: '%s'", _target); + wlr_log(WLR_DEBUG, "Isolated name from workspace number: '%s'", _target); // Make sure the workspace number doesn't already exist if (workspace_by_number(_target)) { @@ -192,7 +192,9 @@ char *workspace_next_name(const char *output_name) { order = binding->order; free(target); target = _target; - wlr_log(L_DEBUG, "Workspace: Found free name %s", _target); + wlr_log(WLR_DEBUG, "Workspace: Found free name %s", _target); + } else { + free(_target); } } free(dup); @@ -203,14 +205,9 @@ char *workspace_next_name(const char *output_name) { // As a fall back, get the current number of active workspaces // and return that + 1 for the next workspace's name int ws_num = root_container.children->length; - if (ws_num >= 10) { - l = 2; - } else if (ws_num >= 100) { - l = 3; - } + int l = snprintf(NULL, 0, "%d", ws_num); char *name = malloc(l + 1); - if (!name) { - wlr_log(L_ERROR, "Could not allocate workspace name"); + if (!sway_assert(name, "Cloud not allocate workspace name")) { return NULL; } sprintf(name, "%d", ws_num++); @@ -272,6 +269,9 @@ struct sway_container *workspace_by_name(const char *name) { */ struct sway_container *workspace_output_prev_next_impl( struct sway_container *output, bool next) { + if (!output) { + return NULL; + } if (!sway_assert(output->type == C_OUTPUT, "Argument must be an output, is %d", output->type)) { return NULL; @@ -304,6 +304,9 @@ struct sway_container *workspace_output_prev_next_impl( */ struct sway_container *workspace_prev_next_impl( struct sway_container *workspace, bool next) { + if (!workspace) { + return NULL; + } if (!sway_assert(workspace->type == C_WORKSPACE, "Argument must be a workspace, is %d", workspace->type)) { return NULL; @@ -386,7 +389,7 @@ bool workspace_switch(struct sway_container *workspace) { free(prev_workspace_name); prev_workspace_name = malloc(strlen(active_ws->name) + 1); if (!prev_workspace_name) { - wlr_log(L_ERROR, "Unable to allocate previous workspace name"); + wlr_log(WLR_ERROR, "Unable to allocate previous workspace name"); return false; } strcpy(prev_workspace_name, active_ws->name); @@ -408,7 +411,7 @@ bool workspace_switch(struct sway_container *workspace) { } } - wlr_log(L_DEBUG, "Switching to workspace %p:%s", + wlr_log(WLR_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name); struct sway_container *next = seat_get_focus_inactive(seat, workspace); if (next == NULL) { @@ -426,7 +429,7 @@ bool workspace_switch(struct sway_container *workspace) { } seat_set_focus(seat, next); struct sway_container *output = container_parent(workspace, C_OUTPUT); - arrange_and_commit(output); + arrange_windows(output); return true; } @@ -518,6 +521,16 @@ struct sway_container *workspace_output_get_highest_available( return NULL; } +void workspace_detect_urgent(struct sway_container *workspace) { + bool new_urgent = container_has_urgent_child(workspace); + + if (workspace->sway_workspace->urgent != new_urgent) { + workspace->sway_workspace->urgent = new_urgent; + ipc_event_workspace(NULL, workspace, "urgent"); + container_damage_whole(workspace); + } +} + struct pid_workspace { pid_t pid; char *workspace; @@ -540,14 +553,14 @@ struct sway_container *workspace_for_pid(pid_t pid) { struct sway_container *ws = NULL; struct pid_workspace *pw = NULL; - wlr_log(L_DEBUG, "Looking up workspace for pid %d", pid); + wlr_log(WLR_DEBUG, "Looking up workspace for pid %d", pid); do { struct pid_workspace *_pw = NULL; wl_list_for_each(_pw, &pid_workspaces, link) { if (pid == _pw->pid) { pw = _pw; - wlr_log(L_DEBUG, + wlr_log(WLR_DEBUG, "found pid_workspace for pid %d, workspace %s", pid, pw->workspace); goto found; @@ -561,7 +574,7 @@ found: ws = workspace_by_name(pw->workspace); if (!ws) { - wlr_log(L_DEBUG, + wlr_log(WLR_DEBUG, "Creating workspace %s for pid %d because it disappeared", pw->workspace, pid); ws = workspace_create(pw->output, pw->workspace); @@ -582,7 +595,7 @@ static void pw_handle_output_destroy(struct wl_listener *listener, void *data) { } void workspace_record_pid(pid_t pid) { - wlr_log(L_DEBUG, "Recording workspace for process %d", pid); + wlr_log(WLR_DEBUG, "Recording workspace for process %d", pid); if (!pid_workspaces.prev && !pid_workspaces.next) { wl_list_init(&pid_workspaces); } @@ -594,12 +607,12 @@ void workspace_record_pid(pid_t pid) { ws = container_parent(ws, C_WORKSPACE); } if (!ws) { - wlr_log(L_DEBUG, "Bailing out, no workspace"); + wlr_log(WLR_DEBUG, "Bailing out, no workspace"); return; } struct sway_container *output = ws->parent; if (!output) { - wlr_log(L_DEBUG, "Bailing out, no output"); + wlr_log(WLR_DEBUG, "Bailing out, no output"); return; } |