aboutsummaryrefslogtreecommitdiff
path: root/sway/tree
diff options
context:
space:
mode:
Diffstat (limited to 'sway/tree')
-rw-r--r--sway/tree/arrange.c78
-rw-r--r--sway/tree/container.c58
-rw-r--r--sway/tree/layout.c14
-rw-r--r--sway/tree/view.c78
-rw-r--r--sway/tree/workspace.c13
5 files changed, 156 insertions, 85 deletions
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c
index bcc3ee9a..533cf71c 100644
--- a/sway/tree/arrange.c
+++ b/sway/tree/arrange.c
@@ -144,38 +144,22 @@ 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;
}
@@ -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,14 +197,13 @@ 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;
}
@@ -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);
+ 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);
+ 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,43 +256,35 @@ 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) {
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 58852717..6d52c38c 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -159,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);
@@ -325,7 +317,7 @@ static struct sway_container *container_destroy_noreaping(
}
con->destroying = true;
- list_add(server.destroying_containers, con);
+ container_set_dirty(con);
if (!con->parent) {
return NULL;
@@ -682,16 +674,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,
@@ -1069,9 +1068,26 @@ void container_floating_move_to(struct sway_container *con,
if (old_workspace != new_workspace) {
container_remove_child(con);
container_add_child(new_workspace->sway_workspace->floating, con);
- struct sway_transaction *transaction = transaction_create();
- arrange_windows(old_workspace, transaction);
- arrange_windows(new_workspace, transaction);
- transaction_commit(transaction);
+ 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);
+}
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index ba234e89..197a2fc8 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) {
@@ -224,6 +225,15 @@ 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);
+ workspace_detect_urgent(old_workspace);
+ }
}
static bool sway_dir_to_wlr(enum movement_direction dir,
@@ -547,6 +557,8 @@ 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);
}
}
diff --git a/sway/tree/view.c b/sway/tree/view.c
index b356183c..76e0f42c 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -25,6 +25,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);
}
@@ -504,20 +505,38 @@ void view_execute_criteria(struct sway_view *view) {
}
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(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;
@@ -571,9 +590,11 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
view_set_tiled(view, true);
}
- input_manager_set_focus(input_manager, cont);
- if (workspace) {
- workspace_switch(workspace);
+ if (should_focus(view)) {
+ input_manager_set_focus(input_manager, cont);
+ if (workspace) {
+ workspace_switch(workspace);
+ }
}
view_update_title(view, false);
@@ -589,16 +610,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 *parent;
+ struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
+
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);
+ arrange_windows(parent);
}
+ if (parent->type >= C_WORKSPACE) { // if the workspace still exists
+ workspace_detect_urgent(ws);
+ }
+ transaction_commit_dirty();
view->surface = NULL;
}
@@ -1046,3 +1078,29 @@ bool view_is_visible(struct sway_view *view) {
}
return true;
}
+
+void view_set_urgent(struct sway_view *view, bool enable) {
+ 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 50f9400a..622f01ec 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -11,6 +11,7 @@
#include "sway/ipc-server.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"
@@ -427,7 +428,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,3 +519,13 @@ 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);
+ }
+}