mirror of
https://github.com/swaywm/sway.git
synced 2025-11-21 06:59:48 -05:00
Implement urgency base functionality
Introduces a command to manually set urgency, as well as rendering of urgent views, sending the IPC event, removing urgency after focused for one second, and matching urgent views via criteria.
This commit is contained in:
parent
b314a8f2cc
commit
315d5311b2
12 changed files with 170 additions and 7 deletions
|
|
@ -153,6 +153,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) {
|
||||
|
|
|
|||
36
sway/commands/urgent.c
Normal file
36
sway/commands/urgent.c
Normal file
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -553,7 +553,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;
|
||||
|
|
@ -608,7 +612,11 @@ static void render_container_tabbed(struct sway_output *output,
|
|||
struct wlr_texture *title_texture;
|
||||
struct wlr_texture *marks_texture;
|
||||
|
||||
if (cstate->focused || parent_focused) {
|
||||
if (view && view_is_urgent(view)) {
|
||||
colors = &config->border_colors.urgent;
|
||||
title_texture = child->title_urgent;
|
||||
marks_texture = view->marks_urgent;
|
||||
} else if (cstate->focused || parent_focused) {
|
||||
colors = &config->border_colors.focused;
|
||||
title_texture = child->title_focused;
|
||||
marks_texture = view ? view->marks_focused : NULL;
|
||||
|
|
@ -671,7 +679,11 @@ static void render_container_stacked(struct sway_output *output,
|
|||
struct wlr_texture *title_texture;
|
||||
struct wlr_texture *marks_texture;
|
||||
|
||||
if (cstate->focused || parent_focused) {
|
||||
if (view && view_is_urgent(view)) {
|
||||
colors = &config->border_colors.urgent;
|
||||
title_texture = child->title_urgent;
|
||||
marks_texture = view->marks_urgent;
|
||||
} 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 +743,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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
@ -670,6 +676,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.
|
||||
|
|
|
|||
|
|
@ -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_is_urgent(workspace)));
|
||||
json_object_object_add(object, "representation", workspace->formatted_title ?
|
||||
json_object_new_string(workspace->formatted_title) : NULL);
|
||||
|
||||
|
|
|
|||
|
|
@ -76,6 +76,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',
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -589,6 +590,11 @@ 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;
|
||||
}
|
||||
|
||||
if (view->is_fullscreen) {
|
||||
struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
|
||||
ws->sway_workspace->fullscreen = NULL;
|
||||
|
|
@ -1047,3 +1053,27 @@ bool view_is_visible(struct sway_view *view) {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void view_set_urgent(struct sway_view *view, bool enable) {
|
||||
if (enable) {
|
||||
struct sway_seat *seat = input_manager_current_seat(input_manager);
|
||||
if (seat_get_focus(seat) == view->swayc) {
|
||||
return;
|
||||
}
|
||||
clock_gettime(CLOCK_MONOTONIC, &view->urgent);
|
||||
} else {
|
||||
view->urgent = (struct timespec){ 0 };
|
||||
if (view->urgent_timer) {
|
||||
wl_event_source_remove(view->urgent_timer);
|
||||
view->urgent_timer = NULL;
|
||||
}
|
||||
}
|
||||
container_damage_whole(view->swayc);
|
||||
|
||||
struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
|
||||
ipc_event_workspace(ws, NULL, "urgent");
|
||||
}
|
||||
|
||||
bool view_is_urgent(struct sway_view *view) {
|
||||
return view->urgent.tv_sec || view->urgent.tv_nsec;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,12 @@ struct sway_container *workspace_output_get_highest_available(
|
|||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool find_urgent_iterator(struct sway_container *con,
|
||||
void *data) {
|
||||
return con->type == C_VIEW && view_is_urgent(con->sway_view);
|
||||
}
|
||||
|
||||
bool workspace_is_urgent(struct sway_container *workspace) {
|
||||
return container_find(workspace, find_urgent_iterator, NULL);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue