diff options
author | Drew DeVault <sir@cmpwn.com> | 2018-07-16 15:39:08 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-07-16 15:39:08 -0700 |
commit | d6bd314dffb7385eec73de40f0fdd5775cd5941b (patch) | |
tree | 1cec389e971cda3e42766c07789d0f51c2d39715 | |
parent | Merge pull request #2265 from RedSoxFan/implement-1962 (diff) | |
parent | swaybar: Read urgent colors from IPC (diff) | |
download | sway-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.h | 1 | ||||
-rw-r--r-- | include/sway/tree/container.h | 2 | ||||
-rw-r--r-- | include/sway/tree/view.h | 8 | ||||
-rw-r--r-- | include/sway/tree/workspace.h | 4 | ||||
-rw-r--r-- | sway/commands.c | 1 | ||||
-rw-r--r-- | sway/commands/urgent.c | 36 | ||||
-rw-r--r-- | sway/criteria.c | 44 | ||||
-rw-r--r-- | sway/desktop/render.c | 32 | ||||
-rw-r--r-- | sway/desktop/xwayland.c | 4 | ||||
-rw-r--r-- | sway/input/seat.c | 16 | ||||
-rw-r--r-- | sway/ipc-json.c | 7 | ||||
-rw-r--r-- | sway/meson.build | 1 | ||||
-rw-r--r-- | sway/sway.5.scd | 5 | ||||
-rw-r--r-- | sway/tree/container.c | 34 | ||||
-rw-r--r-- | sway/tree/layout.c | 11 | ||||
-rw-r--r-- | sway/tree/view.c | 41 | ||||
-rw-r--r-- | sway/tree/workspace.c | 11 | ||||
-rw-r--r-- | swaybar/ipc.c | 12 |
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; | |||
152 | sway_cmd cmd_swap; | 152 | sway_cmd cmd_swap; |
153 | sway_cmd cmd_title_format; | 153 | sway_cmd cmd_title_format; |
154 | sway_cmd cmd_unmark; | 154 | sway_cmd cmd_unmark; |
155 | sway_cmd cmd_urgent; | ||
155 | sway_cmd cmd_workspace; | 156 | sway_cmd cmd_workspace; |
156 | sway_cmd cmd_ws_auto_back_and_forth; | 157 | sway_cmd cmd_ws_auto_back_and_forth; |
157 | sway_cmd cmd_workspace_layout; | 158 | sway_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 | */ |
317 | void container_set_dirty(struct sway_container *container); | 317 | void container_set_dirty(struct sway_container *container); |
318 | 318 | ||
319 | bool 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 | */ |
306 | bool view_is_visible(struct sway_view *view); | 310 | bool view_is_visible(struct sway_view *view); |
307 | 311 | ||
312 | void view_set_urgent(struct sway_view *view, bool enable); | ||
313 | |||
314 | bool 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 | ||
15 | extern char *prev_workspace_name; | 16 | extern char *prev_workspace_name; |
@@ -42,4 +43,7 @@ void workspace_output_add_priority(struct sway_container *workspace, | |||
42 | 43 | ||
43 | struct sway_container *workspace_output_get_highest_available( | 44 | struct 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 | |||
47 | void 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 | ||
159 | static int handler_compare(const void *_a, const void *_b) { | 160 | static 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 | |||
9 | struct 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 | ||
49 | static 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 | |||
66 | static 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 | |||
49 | static bool criteria_matches_view(struct criteria *criteria, | 74 | static 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 | ||
302 | static void handle_unmap(struct wl_listener *listener, void *data) { | 306 | static 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 | ||
597 | static int handle_urgent_timeout(void *data) { | ||
598 | struct sway_view *view = data; | ||
599 | view_set_urgent(view, false); | ||
600 | return 0; | ||
601 | } | ||
602 | |||
597 | void seat_set_focus_warp(struct sway_seat *seat, | 603 | void 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 | ||
201 | static void focus_inactive_children_iterator(struct sway_container *c, void *data) { | 206 | static 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, | |||
674 | void container_for_each_descendant_dfs(struct sway_container *container, | 674 | void 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 | ||
689 | void container_for_each_descendant_bfs(struct sway_container *con, | 696 | void 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 | |||
1086 | static 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 | |||
1091 | bool 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 | ||
230 | static bool sway_dir_to_wlr(enum movement_direction dir, | 239 | static 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 | |||
1082 | void 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 | |||
1104 | bool 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 | |||
523 | void 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)); |