diff options
Diffstat (limited to 'sway')
-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 | 24 | ||||
-rw-r--r-- | sway/input/seat.c | 16 | ||||
-rw-r--r-- | sway/ipc-json.c | 3 | ||||
-rw-r--r-- | sway/meson.build | 1 | ||||
-rw-r--r-- | sway/tree/view.c | 30 | ||||
-rw-r--r-- | sway/tree/workspace.c | 10 |
9 files changed, 158 insertions, 7 deletions
diff --git a/sway/commands.c b/sway/commands.c index addd64a6..3578e748 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -153,6 +153,7 @@ static struct cmd_handler command_handlers[] = { | |||
153 | { "swap", cmd_swap }, | 153 | { "swap", cmd_swap }, |
154 | { "title_format", cmd_title_format }, | 154 | { "title_format", cmd_title_format }, |
155 | { "unmark", cmd_unmark }, | 155 | { "unmark", cmd_unmark }, |
156 | { "urgent", cmd_urgent }, | ||
156 | }; | 157 | }; |
157 | 158 | ||
158 | static int handler_compare(const void *_a, const void *_b) { | 159 | 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..3180f8ba 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; |
@@ -608,7 +612,11 @@ static void render_container_tabbed(struct sway_output *output, | |||
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 | ||
611 | if (cstate->focused || parent_focused) { | 615 | if (view && view_is_urgent(view)) { |
616 | colors = &config->border_colors.urgent; | ||
617 | title_texture = child->title_urgent; | ||
618 | marks_texture = view->marks_urgent; | ||
619 | } else if (cstate->focused || parent_focused) { | ||
612 | colors = &config->border_colors.focused; | 620 | colors = &config->border_colors.focused; |
613 | title_texture = child->title_focused; | 621 | title_texture = child->title_focused; |
614 | marks_texture = view ? view->marks_focused : NULL; | 622 | marks_texture = view ? view->marks_focused : NULL; |
@@ -671,7 +679,11 @@ static void render_container_stacked(struct sway_output *output, | |||
671 | struct wlr_texture *title_texture; | 679 | struct wlr_texture *title_texture; |
672 | struct wlr_texture *marks_texture; | 680 | struct wlr_texture *marks_texture; |
673 | 681 | ||
674 | if (cstate->focused || parent_focused) { | 682 | if (view && view_is_urgent(view)) { |
683 | colors = &config->border_colors.urgent; | ||
684 | title_texture = child->title_urgent; | ||
685 | marks_texture = view->marks_urgent; | ||
686 | } else if (cstate->focused || parent_focused) { | ||
675 | colors = &config->border_colors.focused; | 687 | colors = &config->border_colors.focused; |
676 | title_texture = child->title_focused; | 688 | title_texture = child->title_focused; |
677 | marks_texture = view ? view->marks_focused : NULL; | 689 | marks_texture = view ? view->marks_focused : NULL; |
@@ -731,7 +743,11 @@ static void render_floating_container(struct sway_output *soutput, | |||
731 | struct wlr_texture *title_texture; | 743 | struct wlr_texture *title_texture; |
732 | struct wlr_texture *marks_texture; | 744 | struct wlr_texture *marks_texture; |
733 | 745 | ||
734 | if (con->current.focused) { | 746 | if (view_is_urgent(view)) { |
747 | colors = &config->border_colors.urgent; | ||
748 | title_texture = con->title_urgent; | ||
749 | marks_texture = view->marks_urgent; | ||
750 | } else if (con->current.focused) { | ||
735 | colors = &config->border_colors.focused; | 751 | colors = &config->border_colors.focused; |
736 | title_texture = con->title_focused; | 752 | title_texture = con->title_focused; |
737 | marks_texture = view->marks_focused; | 753 | marks_texture = view->marks_focused; |
diff --git a/sway/input/seat.c b/sway/input/seat.c index 74f1375e..7058cc92 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) { |
@@ -670,6 +676,16 @@ void seat_set_focus_warp(struct sway_seat *seat, | |||
670 | } | 676 | } |
671 | } | 677 | } |
672 | 678 | ||
679 | // If urgent, start a timer to unset it | ||
680 | if (container && container->type == C_VIEW && | ||
681 | view_is_urgent(container->sway_view) && | ||
682 | !container->sway_view->urgent_timer) { | ||
683 | struct sway_view *view = container->sway_view; | ||
684 | view->urgent_timer = wl_event_loop_add_timer(server.wl_event_loop, | ||
685 | handle_urgent_timeout, view); | ||
686 | wl_event_source_timer_update(view->urgent_timer, 1000); | ||
687 | } | ||
688 | |||
673 | // If we've focused a floating container, bring it to the front. | 689 | // If we've focused a floating container, bring it to the front. |
674 | // We do this by putting it at the end of the floating list. | 690 | // We do this by putting it at the end of the floating list. |
675 | // This must happen for both the pending and current children lists. | 691 | // 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..8c48e724 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_is_urgent(workspace))); | ||
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 | ||
diff --git a/sway/meson.build b/sway/meson.build index f878450d..b64bd137 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -76,6 +76,7 @@ sway_sources = files( | |||
76 | 'commands/swap.c', | 76 | 'commands/swap.c', |
77 | 'commands/title_format.c', | 77 | 'commands/title_format.c', |
78 | 'commands/unmark.c', | 78 | 'commands/unmark.c', |
79 | 'commands/urgent.c', | ||
79 | 'commands/workspace.c', | 80 | 'commands/workspace.c', |
80 | 'commands/workspace_layout.c', | 81 | 'commands/workspace_layout.c', |
81 | 'commands/ws_auto_back_and_forth.c', | 82 | 'commands/ws_auto_back_and_forth.c', |
diff --git a/sway/tree/view.c b/sway/tree/view.c index bf380d98..a2dbe92c 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 | ||
@@ -589,6 +590,11 @@ void view_unmap(struct sway_view *view) { | |||
589 | wl_list_remove(&view->surface_new_subsurface.link); | 590 | wl_list_remove(&view->surface_new_subsurface.link); |
590 | wl_list_remove(&view->container_reparent.link); | 591 | wl_list_remove(&view->container_reparent.link); |
591 | 592 | ||
593 | if (view->urgent_timer) { | ||
594 | wl_event_source_remove(view->urgent_timer); | ||
595 | view->urgent_timer = NULL; | ||
596 | } | ||
597 | |||
592 | if (view->is_fullscreen) { | 598 | if (view->is_fullscreen) { |
593 | struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); | 599 | struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); |
594 | ws->sway_workspace->fullscreen = NULL; | 600 | ws->sway_workspace->fullscreen = NULL; |
@@ -1047,3 +1053,27 @@ bool view_is_visible(struct sway_view *view) { | |||
1047 | } | 1053 | } |
1048 | return true; | 1054 | return true; |
1049 | } | 1055 | } |
1056 | |||
1057 | void view_set_urgent(struct sway_view *view, bool enable) { | ||
1058 | if (enable) { | ||
1059 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
1060 | if (seat_get_focus(seat) == view->swayc) { | ||
1061 | return; | ||
1062 | } | ||
1063 | clock_gettime(CLOCK_MONOTONIC, &view->urgent); | ||
1064 | } else { | ||
1065 | view->urgent = (struct timespec){ 0 }; | ||
1066 | if (view->urgent_timer) { | ||
1067 | wl_event_source_remove(view->urgent_timer); | ||
1068 | view->urgent_timer = NULL; | ||
1069 | } | ||
1070 | } | ||
1071 | container_damage_whole(view->swayc); | ||
1072 | |||
1073 | struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); | ||
1074 | ipc_event_workspace(ws, NULL, "urgent"); | ||
1075 | } | ||
1076 | |||
1077 | bool view_is_urgent(struct sway_view *view) { | ||
1078 | return view->urgent.tv_sec || view->urgent.tv_nsec; | ||
1079 | } | ||
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 2a2d834a..d71b0a53 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,12 @@ struct sway_container *workspace_output_get_highest_available( | |||
518 | 519 | ||
519 | return NULL; | 520 | return NULL; |
520 | } | 521 | } |
522 | |||
523 | static bool find_urgent_iterator(struct sway_container *con, | ||
524 | void *data) { | ||
525 | return con->type == C_VIEW && view_is_urgent(con->sway_view); | ||
526 | } | ||
527 | |||
528 | bool workspace_is_urgent(struct sway_container *workspace) { | ||
529 | return container_find(workspace, find_urgent_iterator, NULL); | ||
530 | } | ||