aboutsummaryrefslogtreecommitdiff
path: root/sway
diff options
context:
space:
mode:
Diffstat (limited to 'sway')
-rw-r--r--sway/commands.c3
-rw-r--r--sway/commands/default_floating_border.c29
-rw-r--r--sway/commands/no_focus.c26
-rw-r--r--sway/commands/urgent.c36
-rw-r--r--sway/config.c9
-rw-r--r--sway/criteria.c46
-rw-r--r--sway/desktop/idle_inhibit_v1.c1
-rw-r--r--sway/desktop/layer_shell.c12
-rw-r--r--sway/desktop/render.c64
-rw-r--r--sway/desktop/xwayland.c4
-rw-r--r--sway/input/seat.c17
-rw-r--r--sway/ipc-json.c7
-rw-r--r--sway/meson.build3
-rw-r--r--sway/sway.5.scd5
-rw-r--r--sway/tree/container.c45
-rw-r--r--sway/tree/layout.c11
-rw-r--r--sway/tree/view.c96
-rw-r--r--sway/tree/workspace.c11
18 files changed, 369 insertions, 56 deletions
diff --git a/sway/commands.c b/sway/commands.c
index addd64a6..a3e6a500 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -98,6 +98,7 @@ static struct cmd_handler handlers[] = {
{ "client.unfocused", cmd_client_unfocused },
{ "client.urgent", cmd_client_urgent },
{ "default_border", cmd_default_border },
+ { "default_floating_border", cmd_default_floating_border },
{ "exec", cmd_exec },
{ "exec_always", cmd_exec_always },
{ "floating_maximum_size", cmd_floating_maximum_size },
@@ -114,6 +115,7 @@ static struct cmd_handler handlers[] = {
{ "input", cmd_input },
{ "mode", cmd_mode },
{ "mouse_warping", cmd_mouse_warping },
+ { "no_focus", cmd_no_focus },
{ "output", cmd_output },
{ "seat", cmd_seat },
{ "set", cmd_set },
@@ -153,6 +155,7 @@ static struct cmd_handler command_handlers[] = {
{ "swap", cmd_swap },
{ "title_format", cmd_title_format },
{ "unmark", cmd_unmark },
+ { "urgent", cmd_urgent },
};
static int handler_compare(const void *_a, const void *_b) {
diff --git a/sway/commands/default_floating_border.c b/sway/commands/default_floating_border.c
new file mode 100644
index 00000000..1bfc24af
--- /dev/null
+++ b/sway/commands/default_floating_border.c
@@ -0,0 +1,29 @@
+#include "log.h"
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "sway/tree/container.h"
+
+struct cmd_results *cmd_default_floating_border(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "default_floating_border",
+ EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+
+ if (strcmp(argv[0], "none") == 0) {
+ config->floating_border = B_NONE;
+ } else if (strcmp(argv[0], "normal") == 0) {
+ config->floating_border = B_NORMAL;
+ } else if (strcmp(argv[0], "pixel") == 0) {
+ config->floating_border = B_PIXEL;
+ } else {
+ return cmd_results_new(CMD_INVALID, "default_floating_border",
+ "Expected 'default_floating_border <none|normal|pixel>' "
+ "or 'default_floating_border <normal|pixel> <px>'");
+ }
+ if (argc == 2) {
+ config->floating_border_thickness = atoi(argv[1]);
+ }
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/no_focus.c b/sway/commands/no_focus.c
new file mode 100644
index 00000000..61a8de7e
--- /dev/null
+++ b/sway/commands/no_focus.c
@@ -0,0 +1,26 @@
+#define _XOPEN_SOURCE 500
+#include <string.h>
+#include "sway/commands.h"
+#include "sway/criteria.h"
+#include "list.h"
+#include "log.h"
+
+struct cmd_results *cmd_no_focus(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "no_focus", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+
+ char *err_str = NULL;
+ struct criteria *criteria = criteria_parse(argv[0], &err_str);
+ if (!criteria) {
+ error = cmd_results_new(CMD_INVALID, "no_focus", err_str);
+ free(err_str);
+ return error;
+ }
+
+ criteria->type = CT_NO_FOCUS;
+ list_add(config->criteria, criteria);
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/urgent.c b/sway/commands/urgent.c
new file mode 100644
index 00000000..d199858a
--- /dev/null
+++ b/sway/commands/urgent.c
@@ -0,0 +1,36 @@
+#include "log.h"
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "sway/tree/arrange.h"
+#include "sway/tree/container.h"
+#include "sway/tree/view.h"
+#include "sway/tree/layout.h"
+
+struct cmd_results *cmd_urgent(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "urgent", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+ struct sway_container *container =
+ config->handler_context.current_container;
+ if (container->type != C_VIEW) {
+ return cmd_results_new(CMD_INVALID, "urgent",
+ "Only views can be urgent");
+ }
+ struct sway_view *view = container->sway_view;
+
+ if (strcmp(argv[0], "enable") == 0) {
+ view_set_urgent(view, true);
+ } else if (strcmp(argv[0], "disable") == 0) {
+ view_set_urgent(view, false);
+ } else if (strcmp(argv[0], "allow") == 0) {
+ view->allow_request_urgent = true;
+ } else if (strcmp(argv[0], "deny") == 0) {
+ view->allow_request_urgent = false;
+ } else {
+ return cmd_results_new(CMD_INVALID, "urgent",
+ "Expected 'urgent <enable|disable|allow|deny>'");
+ }
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/config.c b/sway/config.c
index f63835bf..c620e4c7 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -24,6 +24,7 @@
#include "sway/input/seat.h"
#include "sway/commands.h"
#include "sway/config.h"
+#include "sway/criteria.h"
#include "sway/tree/arrange.h"
#include "sway/tree/layout.h"
#include "sway/tree/workspace.h"
@@ -105,7 +106,12 @@ void free_config(struct sway_config *config) {
}
list_free(config->seat_configs);
}
- list_free(config->criteria);
+ if (config->criteria) {
+ for (int i = 0; i < config->criteria->length; ++i) {
+ criteria_destroy(config->criteria->items[i]);
+ }
+ list_free(config->criteria);
+ }
list_free(config->no_focus);
list_free(config->active_bar_modifiers);
list_free(config->config_chain);
@@ -474,7 +480,6 @@ static bool load_include_config(const char *path, const char *parent_dir,
list_del(config->config_chain, index);
return false;
}
- free(real_path);
// restore current_config_path
config->current_config_path = parent_config;
diff --git a/sway/criteria.c b/sway/criteria.c
index 29a3668b..e2b248de 100644
--- a/sway/criteria.c
+++ b/sway/criteria.c
@@ -37,7 +37,7 @@ void criteria_destroy(struct criteria *criteria) {
pcre_free(criteria->con_mark);
pcre_free(criteria->window_role);
free(criteria->workspace);
-
+ free(criteria->cmdlist);
free(criteria->raw);
free(criteria);
}
@@ -46,6 +46,31 @@ static int regex_cmp(const char *item, const pcre *regex) {
return pcre_exec(regex, NULL, item, strlen(item), 0, 0, NULL, 0);
}
+static int cmp_urgent(const void *_a, const void *_b) {
+ struct sway_view *a = *(void **)_a;
+ struct sway_view *b = *(void **)_b;
+
+ if (a->urgent.tv_sec < b->urgent.tv_sec) {
+ return -1;
+ } else if (a->urgent.tv_sec > b->urgent.tv_sec) {
+ return 1;
+ }
+ if (a->urgent.tv_nsec < b->urgent.tv_nsec) {
+ return -1;
+ } else if (a->urgent.tv_nsec > b->urgent.tv_nsec) {
+ return 1;
+ }
+ return 0;
+}
+
+static void find_urgent_iterator(struct sway_container *swayc, void *data) {
+ if (swayc->type != C_VIEW || !view_is_urgent(swayc->sway_view)) {
+ return;
+ }
+ list_t *urgent_views = data;
+ list_add(urgent_views, swayc->sway_view);
+}
+
static bool criteria_matches_view(struct criteria *criteria,
struct sway_view *view) {
if (criteria->title) {
@@ -133,8 +158,23 @@ static bool criteria_matches_view(struct criteria *criteria,
}
if (criteria->urgent) {
- // TODO
- return false;
+ if (!view_is_urgent(view)) {
+ return false;
+ }
+ list_t *urgent_views = create_list();
+ container_for_each_descendant_dfs(&root_container,
+ find_urgent_iterator, urgent_views);
+ list_stable_sort(urgent_views, cmp_urgent);
+ struct sway_view *target;
+ if (criteria->urgent == 'o') { // oldest
+ target = urgent_views->items[0];
+ } else { // latest
+ target = urgent_views->items[urgent_views->length - 1];
+ }
+ list_free(urgent_views);
+ if (view != target) {
+ return false;
+ }
}
if (criteria->workspace) {
diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c
index 108a8417..da17d0f2 100644
--- a/sway/desktop/idle_inhibit_v1.c
+++ b/sway/desktop/idle_inhibit_v1.c
@@ -67,6 +67,7 @@ struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create(
manager->wlr_manager = wlr_idle_inhibit_v1_create(wl_display);
if (!manager->wlr_manager) {
+ free(manager);
return NULL;
}
manager->idle = idle;
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index 91baa6f8..a7d96717 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -325,12 +325,6 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
layer_surface->client_pending.margin.bottom,
layer_surface->client_pending.margin.left);
- struct sway_layer_surface *sway_layer =
- calloc(1, sizeof(struct sway_layer_surface));
- if (!sway_layer) {
- return;
- }
-
if (!layer_surface->output) {
// Assign last active output
struct sway_container *output = NULL;
@@ -352,6 +346,12 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
layer_surface->output = output->sway_output->wlr_output;
}
+ struct sway_layer_surface *sway_layer =
+ calloc(1, sizeof(struct sway_layer_surface));
+ if (!sway_layer) {
+ return;
+ }
+
sway_layer->surface_commit.notify = handle_surface_commit;
wl_signal_add(&layer_surface->surface->events.commit,
&sway_layer->surface_commit);
diff --git a/sway/desktop/render.c b/sway/desktop/render.c
index 17fe823a..4c85e516 100644
--- a/sway/desktop/render.c
+++ b/sway/desktop/render.c
@@ -256,6 +256,10 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage,
render_view_surfaces(view, output, damage, view->swayc->alpha);
}
+ if (view->using_csd) {
+ return;
+ }
+
struct wlr_box box;
float output_scale = output->wlr_output->scale;
float color[4];
@@ -553,7 +557,11 @@ static void render_container_simple(struct sway_output *output,
struct wlr_texture *marks_texture;
struct sway_container_state *state = &child->current;
- if (state->focused || parent_focused) {
+ if (view_is_urgent(view)) {
+ colors = &config->border_colors.urgent;
+ title_texture = child->title_urgent;
+ marks_texture = view->marks_urgent;
+ } else if (state->focused || parent_focused) {
colors = &config->border_colors.focused;
title_texture = child->title_focused;
marks_texture = view->marks_focused;
@@ -567,12 +575,14 @@ static void render_container_simple(struct sway_output *output,
marks_texture = view->marks_unfocused;
}
- if (state->border == B_NORMAL) {
- render_titlebar(output, damage, child, state->swayc_x,
- state->swayc_y, state->swayc_width, colors,
- title_texture, marks_texture);
- } else {
- render_top_border(output, damage, child, colors);
+ if (!view->using_csd) {
+ if (state->border == B_NORMAL) {
+ render_titlebar(output, damage, child, state->swayc_x,
+ state->swayc_y, state->swayc_width, colors,
+ title_texture, marks_texture);
+ } else {
+ render_top_border(output, damage, child, colors);
+ }
}
render_view(output, damage, child, colors);
} else {
@@ -607,8 +617,14 @@ static void render_container_tabbed(struct sway_output *output,
struct border_colors *colors;
struct wlr_texture *title_texture;
struct wlr_texture *marks_texture;
-
- if (cstate->focused || parent_focused) {
+ bool urgent = view ?
+ view_is_urgent(view) : container_has_urgent_child(child);
+
+ if (urgent) {
+ colors = &config->border_colors.urgent;
+ title_texture = child->title_urgent;
+ marks_texture = view ? view->marks_urgent : NULL;
+ } else if (cstate->focused || parent_focused) {
colors = &config->border_colors.focused;
title_texture = child->title_focused;
marks_texture = view ? view->marks_focused : NULL;
@@ -670,8 +686,14 @@ static void render_container_stacked(struct sway_output *output,
struct border_colors *colors;
struct wlr_texture *title_texture;
struct wlr_texture *marks_texture;
-
- if (cstate->focused || parent_focused) {
+ bool urgent = view ?
+ view_is_urgent(view) : container_has_urgent_child(child);
+
+ if (urgent) {
+ colors = &config->border_colors.urgent;
+ title_texture = child->title_urgent;
+ marks_texture = view ? view->marks_urgent : NULL;
+ } else if (cstate->focused || parent_focused) {
colors = &config->border_colors.focused;
title_texture = child->title_focused;
marks_texture = view ? view->marks_focused : NULL;
@@ -731,7 +753,11 @@ static void render_floating_container(struct sway_output *soutput,
struct wlr_texture *title_texture;
struct wlr_texture *marks_texture;
- if (con->current.focused) {
+ if (view_is_urgent(view)) {
+ colors = &config->border_colors.urgent;
+ title_texture = con->title_urgent;
+ marks_texture = view->marks_urgent;
+ } else if (con->current.focused) {
colors = &config->border_colors.focused;
title_texture = con->title_focused;
marks_texture = view->marks_focused;
@@ -741,12 +767,14 @@ static void render_floating_container(struct sway_output *soutput,
marks_texture = view->marks_unfocused;
}
- if (con->current.border == B_NORMAL) {
- render_titlebar(soutput, damage, con, con->current.swayc_x,
- con->current.swayc_y, con->current.swayc_width, colors,
- title_texture, marks_texture);
- } else if (con->current.border != B_NONE) {
- render_top_border(soutput, damage, con, colors);
+ if (!view->using_csd) {
+ if (con->current.border == B_NORMAL) {
+ render_titlebar(soutput, damage, con, con->current.swayc_x,
+ con->current.swayc_y, con->current.swayc_width, colors,
+ title_texture, marks_texture);
+ } else if (con->current.border != B_NONE) {
+ render_top_border(soutput, damage, con, colors);
+ }
}
render_view(soutput, damage, con, colors);
} else {
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 11516673..9df7977d 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -297,6 +297,10 @@ static void handle_commit(struct wl_listener *listener, void *data) {
}
view_damage_from(view);
+
+ if (view->allow_request_urgent) {
+ view_set_urgent(view, (bool)xsurface->hints_urgency);
+ }
}
static void handle_unmap(struct wl_listener *listener, void *data) {
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 74f1375e..12b1fab5 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -594,6 +594,12 @@ static void seat_send_unfocus(struct sway_container *container,
}
}
+static int handle_urgent_timeout(void *data) {
+ struct sway_view *view = data;
+ view_set_urgent(view, false);
+ return 0;
+}
+
void seat_set_focus_warp(struct sway_seat *seat,
struct sway_container *container, bool warp) {
if (seat->focused_layer) {
@@ -649,6 +655,7 @@ void seat_set_focus_warp(struct sway_seat *seat,
while (parent) {
wl_list_remove(&parent->link);
wl_list_insert(&seat->focus_stack, &parent->link);
+ container_set_dirty(parent->container);
parent =
seat_container_from_container(seat,
@@ -670,6 +677,16 @@ void seat_set_focus_warp(struct sway_seat *seat,
}
}
+ // If urgent, start a timer to unset it
+ if (container && container->type == C_VIEW &&
+ view_is_urgent(container->sway_view) &&
+ !container->sway_view->urgent_timer) {
+ struct sway_view *view = container->sway_view;
+ view->urgent_timer = wl_event_loop_add_timer(server.wl_event_loop,
+ handle_urgent_timeout, view);
+ wl_event_source_timer_update(view->urgent_timer, 1000);
+ }
+
// If we've focused a floating container, bring it to the front.
// We do this by putting it at the end of the floating list.
// This must happen for both the pending and current children lists.
diff --git a/sway/ipc-json.c b/sway/ipc-json.c
index 3d0e88f0..c49ea47e 100644
--- a/sway/ipc-json.c
+++ b/sway/ipc-json.c
@@ -170,7 +170,8 @@ static void ipc_json_describe_workspace(struct sway_container *workspace,
json_object_object_add(object, "output", workspace->parent ?
json_object_new_string(workspace->parent->name) : NULL);
json_object_object_add(object, "type", json_object_new_string("workspace"));
- json_object_object_add(object, "urgent", json_object_new_boolean(false));
+ json_object_object_add(object, "urgent",
+ json_object_new_boolean(workspace->sway_workspace->urgent));
json_object_object_add(object, "representation", workspace->formatted_title ?
json_object_new_string(workspace->formatted_title) : NULL);
@@ -196,6 +197,10 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object
json_object_object_add(object, "layout",
json_object_new_string(ipc_json_layout_description(c->layout)));
}
+
+ bool urgent = c->type == C_VIEW ?
+ view_is_urgent(c->sway_view) : container_has_urgent_child(c);
+ json_object_object_add(object, "urgent", json_object_new_boolean(urgent));
}
static void focus_inactive_children_iterator(struct sway_container *c, void *data) {
diff --git a/sway/meson.build b/sway/meson.build
index f878450d..c58d3470 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -35,6 +35,7 @@ sway_sources = files(
'commands/border.c',
'commands/client.c',
'commands/default_border.c',
+ 'commands/default_floating_border.c',
'commands/default_orientation.c',
'commands/exit.c',
'commands/exec.c',
@@ -59,6 +60,7 @@ sway_sources = files(
'commands/mode.c',
'commands/mouse_warping.c',
'commands/move.c',
+ 'commands/no_focus.c',
'commands/output.c',
'commands/reload.c',
'commands/rename.c',
@@ -76,6 +78,7 @@ sway_sources = files(
'commands/swap.c',
'commands/title_format.c',
'commands/unmark.c',
+ 'commands/urgent.c',
'commands/workspace.c',
'commands/workspace_layout.c',
'commands/ws_auto_back_and_forth.c',
diff --git a/sway/sway.5.scd b/sway/sway.5.scd
index c6eb5e6d..d369d7b6 100644
--- a/sway/sway.5.scd
+++ b/sway/sway.5.scd
@@ -499,6 +499,11 @@ config after the others, or it will be matched instead of the others.
*unmark* will remove _identifier_ from the list of current marks on a
window. If _identifier_ is omitted, all marks are removed.
+*urgent* enable|disable|allow|deny
+ Using _enable_ or _disable_ manually sets or unsets the window's urgent
+ state. Using _allow_ or _deny_ controls the window's ability to set itself
+ as urgent. By default, windows are allowed to set their own urgency.
+
*workspace* [number] <name>
Switches to the specified workspace. The string "number" is optional and is
used to sort workspaces.
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 35f67cce..3f9d701a 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -674,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);
}
- 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,
@@ -960,9 +967,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;
@@ -1063,6 +1075,8 @@ void container_floating_move_to(struct sway_container *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);
}
}
@@ -1073,3 +1087,12 @@ void container_set_dirty(struct sway_container *container) {
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 54ddb3f9..197a2fc8 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -225,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,
@@ -548,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 bf380d98..fc31699c 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);
}
@@ -315,11 +316,15 @@ void view_set_activated(struct sway_view *view, bool activated) {
}
void view_set_tiled(struct sway_view *view, bool tiled) {
- bool csd = true;
- if (view->impl->has_client_side_decorations) {
- csd = view->impl->has_client_side_decorations(view);
+ 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;
}
- view->border = tiled || !csd ? config->border : B_NONE;
+
if (view->impl->set_tiled) {
view->impl->set_tiled(view, tiled);
}
@@ -504,20 +509,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;
@@ -554,8 +577,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,
@@ -566,14 +587,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);
}
- 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 +616,26 @@ 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_windows(ws->parent);
} else {
- struct sway_container *parent = container_destroy(view->swayc);
+ 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;
}
@@ -1047,3 +1084,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 2a2d834a..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"
@@ -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);
+ }
+}