summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2018-07-16 15:39:08 -0700
committerLibravatar GitHub <noreply@github.com>2018-07-16 15:39:08 -0700
commitd6bd314dffb7385eec73de40f0fdd5775cd5941b (patch)
tree1cec389e971cda3e42766c07789d0f51c2d39715
parentMerge pull request #2265 from RedSoxFan/implement-1962 (diff)
parentswaybar: Read urgent colors from IPC (diff)
downloadsway-d6bd314dffb7385eec73de40f0fdd5775cd5941b.tar.gz
sway-d6bd314dffb7385eec73de40f0fdd5775cd5941b.tar.zst
sway-d6bd314dffb7385eec73de40f0fdd5775cd5941b.zip
Merge pull request #2276 from RyanDwyer/urgency
Implement urgency base functionality
-rw-r--r--include/sway/commands.h1
-rw-r--r--include/sway/tree/container.h2
-rw-r--r--include/sway/tree/view.h8
-rw-r--r--include/sway/tree/workspace.h4
-rw-r--r--sway/commands.c1
-rw-r--r--sway/commands/urgent.c36
-rw-r--r--sway/criteria.c44
-rw-r--r--sway/desktop/render.c32
-rw-r--r--sway/desktop/xwayland.c4
-rw-r--r--sway/input/seat.c16
-rw-r--r--sway/ipc-json.c7
-rw-r--r--sway/meson.build1
-rw-r--r--sway/sway.5.scd5
-rw-r--r--sway/tree/container.c34
-rw-r--r--sway/tree/layout.c11
-rw-r--r--sway/tree/view.c41
-rw-r--r--sway/tree/workspace.c11
-rw-r--r--swaybar/ipc.c12
18 files changed, 251 insertions, 19 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h
index 3ebd0002..1e93e2a3 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -152,6 +152,7 @@ sway_cmd cmd_swaybg_command;
152sway_cmd cmd_swap; 152sway_cmd cmd_swap;
153sway_cmd cmd_title_format; 153sway_cmd cmd_title_format;
154sway_cmd cmd_unmark; 154sway_cmd cmd_unmark;
155sway_cmd cmd_urgent;
155sway_cmd cmd_workspace; 156sway_cmd cmd_workspace;
156sway_cmd cmd_ws_auto_back_and_forth; 157sway_cmd cmd_ws_auto_back_and_forth;
157sway_cmd cmd_workspace_layout; 158sway_cmd cmd_workspace_layout;
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index 04e50fc6..ca7a3288 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -316,4 +316,6 @@ void container_floating_move_to(struct sway_container *con,
316 */ 316 */
317void container_set_dirty(struct sway_container *container); 317void container_set_dirty(struct sway_container *container);
318 318
319bool container_has_urgent_child(struct sway_container *container);
320
319#endif 321#endif
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h
index 21d6403e..9022f7a6 100644
--- a/include/sway/tree/view.h
+++ b/include/sway/tree/view.h
@@ -70,6 +70,10 @@ struct sway_view {
70 bool border_left; 70 bool border_left;
71 bool border_right; 71 bool border_right;
72 72
73 struct timespec urgent;
74 bool allow_request_urgent;
75 struct wl_event_source *urgent_timer;
76
73 bool destroying; 77 bool destroying;
74 78
75 list_t *executed_criteria; // struct criteria * 79 list_t *executed_criteria; // struct criteria *
@@ -305,4 +309,8 @@ void view_update_marks_textures(struct sway_view *view);
305 */ 309 */
306bool view_is_visible(struct sway_view *view); 310bool view_is_visible(struct sway_view *view);
307 311
312void view_set_urgent(struct sway_view *view, bool enable);
313
314bool view_is_urgent(struct sway_view *view);
315
308#endif 316#endif
diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h
index c72a4ac0..bc95317a 100644
--- a/include/sway/tree/workspace.h
+++ b/include/sway/tree/workspace.h
@@ -10,6 +10,7 @@ struct sway_workspace {
10 struct sway_view *fullscreen; 10 struct sway_view *fullscreen;
11 struct sway_container *floating; 11 struct sway_container *floating;
12 list_t *output_priority; 12 list_t *output_priority;
13 bool urgent;
13}; 14};
14 15
15extern char *prev_workspace_name; 16extern char *prev_workspace_name;
@@ -42,4 +43,7 @@ void workspace_output_add_priority(struct sway_container *workspace,
42 43
43struct sway_container *workspace_output_get_highest_available( 44struct sway_container *workspace_output_get_highest_available(
44 struct sway_container *ws, struct sway_container *exclude); 45 struct sway_container *ws, struct sway_container *exclude);
46
47void workspace_detect_urgent(struct sway_container *workspace);
48
45#endif 49#endif
diff --git a/sway/commands.c b/sway/commands.c
index c2ba02cf..27329602 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -154,6 +154,7 @@ static struct cmd_handler command_handlers[] = {
154 { "swap", cmd_swap }, 154 { "swap", cmd_swap },
155 { "title_format", cmd_title_format }, 155 { "title_format", cmd_title_format },
156 { "unmark", cmd_unmark }, 156 { "unmark", cmd_unmark },
157 { "urgent", cmd_urgent },
157}; 158};
158 159
159static int handler_compare(const void *_a, const void *_b) { 160static int handler_compare(const void *_a, const void *_b) {
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 @@
1#include "log.h"
2#include "sway/commands.h"
3#include "sway/config.h"
4#include "sway/tree/arrange.h"
5#include "sway/tree/container.h"
6#include "sway/tree/view.h"
7#include "sway/tree/layout.h"
8
9struct cmd_results *cmd_urgent(int argc, char **argv) {
10 struct cmd_results *error = NULL;
11 if ((error = checkarg(argc, "urgent", EXPECTED_EQUAL_TO, 1))) {
12 return error;
13 }
14 struct sway_container *container =
15 config->handler_context.current_container;
16 if (container->type != C_VIEW) {
17 return cmd_results_new(CMD_INVALID, "urgent",
18 "Only views can be urgent");
19 }
20 struct sway_view *view = container->sway_view;
21
22 if (strcmp(argv[0], "enable") == 0) {
23 view_set_urgent(view, true);
24 } else if (strcmp(argv[0], "disable") == 0) {
25 view_set_urgent(view, false);
26 } else if (strcmp(argv[0], "allow") == 0) {
27 view->allow_request_urgent = true;
28 } else if (strcmp(argv[0], "deny") == 0) {
29 view->allow_request_urgent = false;
30 } else {
31 return cmd_results_new(CMD_INVALID, "urgent",
32 "Expected 'urgent <enable|disable|allow|deny>'");
33 }
34
35 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
36}
diff --git a/sway/criteria.c b/sway/criteria.c
index 29a3668b..c999d248 100644
--- a/sway/criteria.c
+++ b/sway/criteria.c
@@ -46,6 +46,31 @@ static int regex_cmp(const char *item, const pcre *regex) {
46 return pcre_exec(regex, NULL, item, strlen(item), 0, 0, NULL, 0); 46 return pcre_exec(regex, NULL, item, strlen(item), 0, 0, NULL, 0);
47} 47}
48 48
49static int cmp_urgent(const void *_a, const void *_b) {
50 struct sway_view *a = *(void **)_a;
51 struct sway_view *b = *(void **)_b;
52
53 if (a->urgent.tv_sec < b->urgent.tv_sec) {
54 return -1;
55 } else if (a->urgent.tv_sec > b->urgent.tv_sec) {
56 return 1;
57 }
58 if (a->urgent.tv_nsec < b->urgent.tv_nsec) {
59 return -1;
60 } else if (a->urgent.tv_nsec > b->urgent.tv_nsec) {
61 return 1;
62 }
63 return 0;
64}
65
66static void find_urgent_iterator(struct sway_container *swayc, void *data) {
67 if (swayc->type != C_VIEW || !view_is_urgent(swayc->sway_view)) {
68 return;
69 }
70 list_t *urgent_views = data;
71 list_add(urgent_views, swayc->sway_view);
72}
73
49static bool criteria_matches_view(struct criteria *criteria, 74static bool criteria_matches_view(struct criteria *criteria,
50 struct sway_view *view) { 75 struct sway_view *view) {
51 if (criteria->title) { 76 if (criteria->title) {
@@ -133,8 +158,23 @@ static bool criteria_matches_view(struct criteria *criteria,
133 } 158 }
134 159
135 if (criteria->urgent) { 160 if (criteria->urgent) {
136 // TODO 161 if (!view_is_urgent(view)) {
137 return false; 162 return false;
163 }
164 list_t *urgent_views = create_list();
165 container_for_each_descendant_dfs(&root_container,
166 find_urgent_iterator, urgent_views);
167 list_stable_sort(urgent_views, cmp_urgent);
168 struct sway_view *target;
169 if (criteria->urgent == 'o') { // oldest
170 target = urgent_views->items[0];
171 } else { // latest
172 target = urgent_views->items[urgent_views->length - 1];
173 }
174 list_free(urgent_views);
175 if (view != target) {
176 return false;
177 }
138 } 178 }
139 179
140 if (criteria->workspace) { 180 if (criteria->workspace) {
diff --git a/sway/desktop/render.c b/sway/desktop/render.c
index 17fe823a..cb995215 100644
--- a/sway/desktop/render.c
+++ b/sway/desktop/render.c
@@ -553,7 +553,11 @@ static void render_container_simple(struct sway_output *output,
553 struct wlr_texture *marks_texture; 553 struct wlr_texture *marks_texture;
554 struct sway_container_state *state = &child->current; 554 struct sway_container_state *state = &child->current;
555 555
556 if (state->focused || parent_focused) { 556 if (view_is_urgent(view)) {
557 colors = &config->border_colors.urgent;
558 title_texture = child->title_urgent;
559 marks_texture = view->marks_urgent;
560 } else if (state->focused || parent_focused) {
557 colors = &config->border_colors.focused; 561 colors = &config->border_colors.focused;
558 title_texture = child->title_focused; 562 title_texture = child->title_focused;
559 marks_texture = view->marks_focused; 563 marks_texture = view->marks_focused;
@@ -607,8 +611,14 @@ static void render_container_tabbed(struct sway_output *output,
607 struct border_colors *colors; 611 struct border_colors *colors;
608 struct wlr_texture *title_texture; 612 struct wlr_texture *title_texture;
609 struct wlr_texture *marks_texture; 613 struct wlr_texture *marks_texture;
610 614 bool urgent = view ?
611 if (cstate->focused || parent_focused) { 615 view_is_urgent(view) : container_has_urgent_child(child);
616
617 if (urgent) {
618 colors = &config->border_colors.urgent;
619 title_texture = child->title_urgent;
620 marks_texture = view ? view->marks_urgent : NULL;
621 } else if (cstate->focused || parent_focused) {
612 colors = &config->border_colors.focused; 622 colors = &config->border_colors.focused;
613 title_texture = child->title_focused; 623 title_texture = child->title_focused;
614 marks_texture = view ? view->marks_focused : NULL; 624 marks_texture = view ? view->marks_focused : NULL;
@@ -670,8 +680,14 @@ static void render_container_stacked(struct sway_output *output,
670 struct border_colors *colors; 680 struct border_colors *colors;
671 struct wlr_texture *title_texture; 681 struct wlr_texture *title_texture;
672 struct wlr_texture *marks_texture; 682 struct wlr_texture *marks_texture;
673 683 bool urgent = view ?
674 if (cstate->focused || parent_focused) { 684 view_is_urgent(view) : container_has_urgent_child(child);
685
686 if (urgent) {
687 colors = &config->border_colors.urgent;
688 title_texture = child->title_urgent;
689 marks_texture = view ? view->marks_urgent : NULL;
690 } else if (cstate->focused || parent_focused) {
675 colors = &config->border_colors.focused; 691 colors = &config->border_colors.focused;
676 title_texture = child->title_focused; 692 title_texture = child->title_focused;
677 marks_texture = view ? view->marks_focused : NULL; 693 marks_texture = view ? view->marks_focused : NULL;
@@ -731,7 +747,11 @@ static void render_floating_container(struct sway_output *soutput,
731 struct wlr_texture *title_texture; 747 struct wlr_texture *title_texture;
732 struct wlr_texture *marks_texture; 748 struct wlr_texture *marks_texture;
733 749
734 if (con->current.focused) { 750 if (view_is_urgent(view)) {
751 colors = &config->border_colors.urgent;
752 title_texture = con->title_urgent;
753 marks_texture = view->marks_urgent;
754 } else if (con->current.focused) {
735 colors = &config->border_colors.focused; 755 colors = &config->border_colors.focused;
736 title_texture = con->title_focused; 756 title_texture = con->title_focused;
737 marks_texture = view->marks_focused; 757 marks_texture = view->marks_focused;
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) {
297 } 297 }
298 298
299 view_damage_from(view); 299 view_damage_from(view);
300
301 if (view->allow_request_urgent) {
302 view_set_urgent(view, (bool)xsurface->hints_urgency);
303 }
300} 304}
301 305
302static void handle_unmap(struct wl_listener *listener, void *data) { 306static void handle_unmap(struct wl_listener *listener, void *data) {
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 85321dbe..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,
594 } 594 }
595} 595}
596 596
597static int handle_urgent_timeout(void *data) {
598 struct sway_view *view = data;
599 view_set_urgent(view, false);
600 return 0;
601}
602
597void seat_set_focus_warp(struct sway_seat *seat, 603void seat_set_focus_warp(struct sway_seat *seat,
598 struct sway_container *container, bool warp) { 604 struct sway_container *container, bool warp) {
599 if (seat->focused_layer) { 605 if (seat->focused_layer) {
@@ -671,6 +677,16 @@ void seat_set_focus_warp(struct sway_seat *seat,
671 } 677 }
672 } 678 }
673 679
680 // If urgent, start a timer to unset it
681 if (container && container->type == C_VIEW &&
682 view_is_urgent(container->sway_view) &&
683 !container->sway_view->urgent_timer) {
684 struct sway_view *view = container->sway_view;
685 view->urgent_timer = wl_event_loop_add_timer(server.wl_event_loop,
686 handle_urgent_timeout, view);
687 wl_event_source_timer_update(view->urgent_timer, 1000);
688 }
689
674 // If we've focused a floating container, bring it to the front. 690 // If we've focused a floating container, bring it to the front.
675 // We do this by putting it at the end of the floating list. 691 // We do this by putting it at the end of the floating list.
676 // This must happen for both the pending and current children lists. 692 // 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,
170 json_object_object_add(object, "output", workspace->parent ? 170 json_object_object_add(object, "output", workspace->parent ?
171 json_object_new_string(workspace->parent->name) : NULL); 171 json_object_new_string(workspace->parent->name) : NULL);
172 json_object_object_add(object, "type", json_object_new_string("workspace")); 172 json_object_object_add(object, "type", json_object_new_string("workspace"));
173 json_object_object_add(object, "urgent", json_object_new_boolean(false)); 173 json_object_object_add(object, "urgent",
174 json_object_new_boolean(workspace->sway_workspace->urgent));
174 json_object_object_add(object, "representation", workspace->formatted_title ? 175 json_object_object_add(object, "representation", workspace->formatted_title ?
175 json_object_new_string(workspace->formatted_title) : NULL); 176 json_object_new_string(workspace->formatted_title) : NULL);
176 177
@@ -196,6 +197,10 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object
196 json_object_object_add(object, "layout", 197 json_object_object_add(object, "layout",
197 json_object_new_string(ipc_json_layout_description(c->layout))); 198 json_object_new_string(ipc_json_layout_description(c->layout)));
198 } 199 }
200
201 bool urgent = c->type == C_VIEW ?
202 view_is_urgent(c->sway_view) : container_has_urgent_child(c);
203 json_object_object_add(object, "urgent", json_object_new_boolean(urgent));
199} 204}
200 205
201static void focus_inactive_children_iterator(struct sway_container *c, void *data) { 206static void focus_inactive_children_iterator(struct sway_container *c, void *data) {
diff --git a/sway/meson.build b/sway/meson.build
index 4afef7b4..23e54a62 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -77,6 +77,7 @@ sway_sources = files(
77 'commands/swap.c', 77 'commands/swap.c',
78 'commands/title_format.c', 78 'commands/title_format.c',
79 'commands/unmark.c', 79 'commands/unmark.c',
80 'commands/urgent.c',
80 'commands/workspace.c', 81 'commands/workspace.c',
81 'commands/workspace_layout.c', 82 'commands/workspace_layout.c',
82 'commands/ws_auto_back_and_forth.c', 83 '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.
499 *unmark* will remove _identifier_ from the list of current marks on a 499 *unmark* will remove _identifier_ from the list of current marks on a
500 window. If _identifier_ is omitted, all marks are removed. 500 window. If _identifier_ is omitted, all marks are removed.
501 501
502*urgent* enable|disable|allow|deny
503 Using _enable_ or _disable_ manually sets or unsets the window's urgent
504 state. Using _allow_ or _deny_ controls the window's ability to set itself
505 as urgent. By default, windows are allowed to set their own urgency.
506
502*workspace* [number] <name> 507*workspace* [number] <name>
503 Switches to the specified workspace. The string "number" is optional and is 508 Switches to the specified workspace. The string "number" is optional and is
504 used to sort workspaces. 509 used to sort workspaces.
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 35f67cce..6d52c38c 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,
674void container_for_each_descendant_dfs(struct sway_container *container, 674void container_for_each_descendant_dfs(struct sway_container *container,
675 void (*f)(struct sway_container *container, void *data), 675 void (*f)(struct sway_container *container, void *data),
676 void *data) { 676 void *data) {
677 if (container) { 677 if (!container) {
678 if (container->children) { 678 return;
679 for (int i = 0; i < container->children->length; ++i) { 679 }
680 struct sway_container *child = 680 if (container->children) {
681 container->children->items[i]; 681 for (int i = 0; i < container->children->length; ++i) {
682 container_for_each_descendant_dfs(child, f, data); 682 struct sway_container *child = container->children->items[i];
683 } 683 container_for_each_descendant_dfs(child, f, data);
684 }
685 }
686 if (container->type == C_WORKSPACE) {
687 struct sway_container *floating = container->sway_workspace->floating;
688 for (int i = 0; i < floating->children->length; ++i) {
689 struct sway_container *child = floating->children->items[i];
690 container_for_each_descendant_dfs(child, f, data);
684 } 691 }
685 f(container, data);
686 } 692 }
693 f(container, data);
687} 694}
688 695
689void container_for_each_descendant_bfs(struct sway_container *con, 696void container_for_each_descendant_bfs(struct sway_container *con,
@@ -1063,6 +1070,8 @@ void container_floating_move_to(struct sway_container *con,
1063 container_add_child(new_workspace->sway_workspace->floating, con); 1070 container_add_child(new_workspace->sway_workspace->floating, con);
1064 arrange_windows(old_workspace); 1071 arrange_windows(old_workspace);
1065 arrange_windows(new_workspace); 1072 arrange_windows(new_workspace);
1073 workspace_detect_urgent(old_workspace);
1074 workspace_detect_urgent(new_workspace);
1066 } 1075 }
1067} 1076}
1068 1077
@@ -1073,3 +1082,12 @@ void container_set_dirty(struct sway_container *container) {
1073 container->dirty = true; 1082 container->dirty = true;
1074 list_add(server.dirty_containers, container); 1083 list_add(server.dirty_containers, container);
1075} 1084}
1085
1086static bool find_urgent_iterator(struct sway_container *con,
1087 void *data) {
1088 return con->type == C_VIEW && view_is_urgent(con->sway_view);
1089}
1090
1091bool container_has_urgent_child(struct sway_container *container) {
1092 return container_find(container, find_urgent_iterator, NULL);
1093}
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,
225 } 225 }
226 } 226 }
227 } 227 }
228 // Update workspace urgent state
229 struct sway_container *old_workspace = old_parent;
230 if (old_workspace->type != C_WORKSPACE) {
231 old_workspace = container_parent(old_workspace, C_WORKSPACE);
232 }
233 if (new_workspace != old_workspace) {
234 workspace_detect_urgent(new_workspace);
235 workspace_detect_urgent(old_workspace);
236 }
228} 237}
229 238
230static bool sway_dir_to_wlr(enum movement_direction dir, 239static bool sway_dir_to_wlr(enum movement_direction dir,
@@ -548,6 +557,8 @@ void container_move(struct sway_container *container,
548 } 557 }
549 if (last_ws && next_ws && last_ws != next_ws) { 558 if (last_ws && next_ws && last_ws != next_ws) {
550 ipc_event_workspace(last_ws, container, "focus"); 559 ipc_event_workspace(last_ws, container, "focus");
560 workspace_detect_urgent(last_ws);
561 workspace_detect_urgent(next_ws);
551 } 562 }
552} 563}
553 564
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 10c97518..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,
25 view->impl = impl; 25 view->impl = impl;
26 view->executed_criteria = create_list(); 26 view->executed_criteria = create_list();
27 view->marks = create_list(); 27 view->marks = create_list();
28 view->allow_request_urgent = true;
28 wl_signal_init(&view->events.unmap); 29 wl_signal_init(&view->events.unmap);
29} 30}
30 31
@@ -609,16 +610,26 @@ void view_unmap(struct sway_view *view) {
609 wl_list_remove(&view->surface_new_subsurface.link); 610 wl_list_remove(&view->surface_new_subsurface.link);
610 wl_list_remove(&view->container_reparent.link); 611 wl_list_remove(&view->container_reparent.link);
611 612
613 if (view->urgent_timer) {
614 wl_event_source_remove(view->urgent_timer);
615 view->urgent_timer = NULL;
616 }
617
618 struct sway_container *parent;
619 struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
620
612 if (view->is_fullscreen) { 621 if (view->is_fullscreen) {
613 struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
614 ws->sway_workspace->fullscreen = NULL; 622 ws->sway_workspace->fullscreen = NULL;
615 container_destroy(view->swayc); 623 parent = container_destroy(view->swayc);
616 624
617 arrange_windows(ws->parent); 625 arrange_windows(ws->parent);
618 } else { 626 } else {
619 struct sway_container *parent = container_destroy(view->swayc); 627 struct sway_container *parent = container_destroy(view->swayc);
620 arrange_windows(parent); 628 arrange_windows(parent);
621 } 629 }
630 if (parent->type >= C_WORKSPACE) { // if the workspace still exists
631 workspace_detect_urgent(ws);
632 }
622 transaction_commit_dirty(); 633 transaction_commit_dirty();
623 view->surface = NULL; 634 view->surface = NULL;
624} 635}
@@ -1067,3 +1078,29 @@ bool view_is_visible(struct sway_view *view) {
1067 } 1078 }
1068 return true; 1079 return true;
1069} 1080}
1081
1082void view_set_urgent(struct sway_view *view, bool enable) {
1083 if (enable) {
1084 struct sway_seat *seat = input_manager_current_seat(input_manager);
1085 if (seat_get_focus(seat) == view->swayc) {
1086 return;
1087 }
1088 clock_gettime(CLOCK_MONOTONIC, &view->urgent);
1089 } else {
1090 view->urgent = (struct timespec){ 0 };
1091 if (view->urgent_timer) {
1092 wl_event_source_remove(view->urgent_timer);
1093 view->urgent_timer = NULL;
1094 }
1095 }
1096 container_damage_whole(view->swayc);
1097
1098 ipc_event_window(view->swayc, "urgent");
1099
1100 struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
1101 workspace_detect_urgent(ws);
1102}
1103
1104bool view_is_urgent(struct sway_view *view) {
1105 return view->urgent.tv_sec || view->urgent.tv_nsec;
1106}
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 @@
11#include "sway/ipc-server.h" 11#include "sway/ipc-server.h"
12#include "sway/tree/arrange.h" 12#include "sway/tree/arrange.h"
13#include "sway/tree/container.h" 13#include "sway/tree/container.h"
14#include "sway/tree/view.h"
14#include "sway/tree/workspace.h" 15#include "sway/tree/workspace.h"
15#include "list.h" 16#include "list.h"
16#include "log.h" 17#include "log.h"
@@ -518,3 +519,13 @@ struct sway_container *workspace_output_get_highest_available(
518 519
519 return NULL; 520 return NULL;
520} 521}
522
523void workspace_detect_urgent(struct sway_container *workspace) {
524 bool new_urgent = container_has_urgent_child(workspace);
525
526 if (workspace->sway_workspace->urgent != new_urgent) {
527 workspace->sway_workspace->urgent = new_urgent;
528 ipc_event_workspace(NULL, workspace, "urgent");
529 container_damage_whole(workspace);
530 }
531}
diff --git a/swaybar/ipc.c b/swaybar/ipc.c
index 08531f2a..c2d05920 100644
--- a/swaybar/ipc.c
+++ b/swaybar/ipc.c
@@ -115,6 +115,18 @@ static void ipc_parse_colors(
115 config->colors.inactive_workspace.text = parse_color( 115 config->colors.inactive_workspace.text = parse_color(
116 json_object_get_string(inactive_workspace_text)); 116 json_object_get_string(inactive_workspace_text));
117 } 117 }
118 if (urgent_workspace_border) {
119 config->colors.urgent_workspace.border = parse_color(
120 json_object_get_string(urgent_workspace_border));
121 }
122 if (urgent_workspace_bg) {
123 config->colors.urgent_workspace.background = parse_color(
124 json_object_get_string(urgent_workspace_bg));
125 }
126 if (urgent_workspace_text) {
127 config->colors.urgent_workspace.text = parse_color(
128 json_object_get_string(urgent_workspace_text));
129 }
118 if (binding_mode_border) { 130 if (binding_mode_border) {
119 config->colors.binding_mode.border = parse_color( 131 config->colors.binding_mode.border = parse_color(
120 json_object_get_string(binding_mode_border)); 132 json_object_get_string(binding_mode_border));