xdg-activation-v1: add token timeout

There isn't always a good time to prune old tokens. Compositors
which only implement a "give focus on activation" logic can prune
tokens on focus change. However other compositors might want to
implement other semantics, e.g. "mark urgent on activation". In this
case a focus change shouldn't invalidate other tokens.

Additionally, some tokens aren't necessarily tied to a seat.

To avoid ending up with an ever-growing list of tokens, add a timeout.
This commit is contained in:
Simon Ser 2021-06-01 11:29:10 +02:00
parent 8ff435831f
commit 76f51a949f
2 changed files with 26 additions and 1 deletions

View file

@ -26,12 +26,14 @@ struct wlr_xdg_activation_token_v1 {
char *token; char *token;
struct wl_resource *resource; // can be NULL struct wl_resource *resource; // can be NULL
struct wl_event_source *timeout; // can be NULL
struct wl_listener seat_destroy; struct wl_listener seat_destroy;
struct wl_listener surface_destroy; struct wl_listener surface_destroy;
}; };
struct wlr_xdg_activation_v1 { struct wlr_xdg_activation_v1 {
uint32_t token_timeout_msec; // token timeout in milliseconds (0 to disable)
struct wl_list tokens; // wlr_xdg_activation_token_v1.link struct wl_list tokens; // wlr_xdg_activation_token_v1.link

View file

@ -28,6 +28,9 @@ static void token_destroy(struct wlr_xdg_activation_token_v1 *token) {
if (token->resource != NULL) { if (token->resource != NULL) {
wl_resource_set_user_data(token->resource, NULL); // make inert wl_resource_set_user_data(token->resource, NULL); // make inert
} }
if (token->timeout != NULL) {
wl_event_source_remove(token->timeout);
}
wl_list_remove(&token->link); wl_list_remove(&token->link);
wl_list_remove(&token->seat_destroy.link); wl_list_remove(&token->seat_destroy.link);
wl_list_remove(&token->surface_destroy.link); wl_list_remove(&token->surface_destroy.link);
@ -36,6 +39,13 @@ static void token_destroy(struct wlr_xdg_activation_token_v1 *token) {
free(token); free(token);
} }
static int token_handle_timeout(void *data) {
struct wlr_xdg_activation_token_v1 *token = data;
wlr_log(WLR_DEBUG, "Activation token '%s' has expired", token->token);
token_destroy(token);
return 0;
}
static void token_handle_resource_destroy(struct wl_resource *resource) { static void token_handle_resource_destroy(struct wl_resource *resource) {
struct wlr_xdg_activation_token_v1 *token = token_from_resource(resource); struct wlr_xdg_activation_token_v1 *token = token_from_resource(resource);
token_destroy(token); token_destroy(token);
@ -91,12 +101,24 @@ static void token_handle_commit(struct wl_client *client,
return; return;
} }
if (token->activation->token_timeout_msec > 0) {
struct wl_display *display = wl_client_get_display(client);
struct wl_event_loop *loop = wl_display_get_event_loop(display);
token->timeout =
wl_event_loop_add_timer(loop, token_handle_timeout, token);
if (token->timeout == NULL) {
wl_client_post_no_memory(client);
return;
}
wl_event_source_timer_update(token->timeout,
token->activation->token_timeout_msec);
}
assert(wl_list_empty(&token->link)); assert(wl_list_empty(&token->link));
wl_list_insert(&token->activation->tokens, &token->link); wl_list_insert(&token->activation->tokens, &token->link);
xdg_activation_token_v1_send_done(token_resource, token_str); xdg_activation_token_v1_send_done(token_resource, token_str);
// TODO: figure out when to discard the token
// TODO: consider emitting a new_token event // TODO: consider emitting a new_token event
return; return;
@ -308,6 +330,7 @@ struct wlr_xdg_activation_v1 *wlr_xdg_activation_v1_create(
return NULL; return NULL;
} }
activation->token_timeout_msec = 30000; // 30s
wl_list_init(&activation->tokens); wl_list_init(&activation->tokens);
wl_signal_init(&activation->events.destroy); wl_signal_init(&activation->events.destroy);
wl_signal_init(&activation->events.request_activate); wl_signal_init(&activation->events.request_activate);