xdg-activation-v1: enable compositors to request their own tokens

These new functions allow a compositor to request new managed tokens
without participating in the xdg-activation procedure as a wayland
client.

This enables the compositor itself to behave as a launcher
application.
This commit is contained in:
Ronan Pigott 2021-10-23 18:55:54 -07:00 committed by Simon Ser
parent 83090de034
commit 6ad0f819e2
2 changed files with 102 additions and 33 deletions

View file

@ -44,6 +44,8 @@ struct wlr_xdg_activation_v1 {
// private state // private state
struct wl_display *display;
struct wl_global *global; struct wl_global *global;
struct wl_listener display_destroy; struct wl_listener display_destroy;
@ -60,4 +62,17 @@ struct wlr_xdg_activation_v1_request_activate_event {
struct wlr_xdg_activation_v1 *wlr_xdg_activation_v1_create( struct wlr_xdg_activation_v1 *wlr_xdg_activation_v1_create(
struct wl_display *display); struct wl_display *display);
struct wlr_xdg_activation_token_v1 *wlr_xdg_activation_token_v1_create(
struct wlr_xdg_activation_v1 *activation);
void wlr_xdg_activation_token_v1_destroy(
struct wlr_xdg_activation_token_v1 *token);
struct wlr_xdg_activation_token_v1 *wlr_xdg_activation_v1_find_token(
struct wlr_xdg_activation_v1 *activation, const char *token_str);
// Get a string suitable for exporting to launched clients
const char *wlr_xdg_activation_token_v1_get_name(
struct wlr_xdg_activation_token_v1 *token);
#endif #endif

View file

@ -21,7 +21,8 @@ static struct wlr_xdg_activation_token_v1 *token_from_resource(
return wl_resource_get_user_data(resource); return wl_resource_get_user_data(resource);
} }
static void token_destroy(struct wlr_xdg_activation_token_v1 *token) { void wlr_xdg_activation_token_v1_destroy(
struct wlr_xdg_activation_token_v1 *token) {
if (token == NULL) { if (token == NULL) {
return; return;
} }
@ -42,13 +43,13 @@ static void token_destroy(struct wlr_xdg_activation_token_v1 *token) {
static int token_handle_timeout(void *data) { static int token_handle_timeout(void *data) {
struct wlr_xdg_activation_token_v1 *token = data; struct wlr_xdg_activation_token_v1 *token = data;
wlr_log(WLR_DEBUG, "Activation token '%s' has expired", token->token); wlr_log(WLR_DEBUG, "Activation token '%s' has expired", token->token);
token_destroy(token); wlr_xdg_activation_token_v1_destroy(token);
return 0; 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); wlr_xdg_activation_token_v1_destroy(token);
} }
static void token_handle_destroy(struct wl_client *client, static void token_handle_destroy(struct wl_client *client,
@ -56,6 +57,36 @@ static void token_handle_destroy(struct wl_client *client,
wl_resource_destroy(token_resource); wl_resource_destroy(token_resource);
} }
static bool token_init( struct wlr_xdg_activation_token_v1 *token) {
char token_str[TOKEN_STRLEN + 1] = {0};
if (!generate_token(token_str)) {
return false;
}
token->token = strdup(token_str);
if (token->token == NULL) {
return false;
}
if (token->activation->token_timeout_msec > 0) {
// Needs wayland > 1.19
// struct wl_display *display = wl_global_get_display(activation->global);
struct wl_display *display = token->activation->display;
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) {
return false;
}
wl_event_source_timer_update(token->timeout,
token->activation->token_timeout_msec);
}
assert(wl_list_empty(&token->link));
wl_list_insert(&token->activation->tokens, &token->link);
return true;
}
static void token_handle_commit(struct wl_client *client, static void token_handle_commit(struct wl_client *client,
struct wl_resource *token_resource) { struct wl_resource *token_resource) {
struct wlr_xdg_activation_token_v1 *token = struct wlr_xdg_activation_token_v1 *token =
@ -71,12 +102,6 @@ static void token_handle_commit(struct wl_client *client,
wl_resource_set_user_data(token->resource, NULL); wl_resource_set_user_data(token->resource, NULL);
token->resource = NULL; token->resource = NULL;
char token_str[TOKEN_STRLEN + 1] = {0};
if (!generate_token(token_str)) {
wl_client_post_no_memory(client);
return;
}
if (token->seat != NULL) { if (token->seat != NULL) {
struct wlr_seat_client *seat_client = struct wlr_seat_client *seat_client =
wlr_seat_client_for_wl_client(token->seat, client); wlr_seat_client_for_wl_client(token->seat, client);
@ -95,39 +120,28 @@ static void token_handle_commit(struct wl_client *client,
} }
} }
token->token = strdup(token_str); if (!token_init(token)) {
if (token->token == NULL) {
wl_client_post_no_memory(client); wl_client_post_no_memory(client);
return; return;
} }
if (token->activation->token_timeout_msec > 0) { xdg_activation_token_v1_send_done(token_resource, token->token);
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));
wl_list_insert(&token->activation->tokens, &token->link);
xdg_activation_token_v1_send_done(token_resource, token_str);
// TODO: consider emitting a new_token event // TODO: consider emitting a new_token event
return; return;
error: error:;
// Here we send the generated token, but it's invalid and can't be used to // Here we send a generated token, but it's invalid and can't be used to
// request activation. // request activation.
char token_str[TOKEN_STRLEN + 1] = {0};
if (!generate_token(token_str)) {
wl_client_post_no_memory(client);
return;
}
xdg_activation_token_v1_send_done(token_resource, token_str); xdg_activation_token_v1_send_done(token_resource, token_str);
token_destroy(token); wlr_xdg_activation_token_v1_destroy(token);
} }
static void token_handle_set_app_id(struct wl_client *client, static void token_handle_set_app_id(struct wl_client *client,
@ -286,7 +300,7 @@ static void activation_handle_activate(struct wl_client *client,
}; };
wlr_signal_emit_safe(&activation->events.request_activate, &event); wlr_signal_emit_safe(&activation->events.request_activate, &event);
token_destroy(token); wlr_xdg_activation_token_v1_destroy(token);
} }
static const struct xdg_activation_v1_interface activation_impl = { static const struct xdg_activation_v1_interface activation_impl = {
@ -315,7 +329,7 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) {
struct wlr_xdg_activation_token_v1 *token, *token_tmp; struct wlr_xdg_activation_token_v1 *token, *token_tmp;
wl_list_for_each_safe(token, token_tmp, &activation->tokens, link) { wl_list_for_each_safe(token, token_tmp, &activation->tokens, link) {
token_destroy(token); wlr_xdg_activation_token_v1_destroy(token);
} }
wl_list_remove(&activation->display_destroy.link); wl_list_remove(&activation->display_destroy.link);
@ -343,8 +357,48 @@ struct wlr_xdg_activation_v1 *wlr_xdg_activation_v1_create(
return NULL; return NULL;
} }
activation->display = display;
activation->display_destroy.notify = handle_display_destroy; activation->display_destroy.notify = handle_display_destroy;
wl_display_add_destroy_listener(display, &activation->display_destroy); wl_display_add_destroy_listener(display, &activation->display_destroy);
return activation; return activation;
} }
struct wlr_xdg_activation_token_v1 *wlr_xdg_activation_token_v1_create(
struct wlr_xdg_activation_v1 *activation) {
struct wlr_xdg_activation_token_v1 *token = calloc(1, sizeof(*token));
if (token == NULL) {
return NULL;
}
wl_list_init(&token->link);
// Currently no way to set seat/surface
wl_list_init(&token->seat_destroy.link);
wl_list_init(&token->surface_destroy.link);
token->activation = activation;
if (!token_init(token)) {
wlr_xdg_activation_token_v1_destroy(token);
return NULL;
}
return token;
}
struct wlr_xdg_activation_token_v1 *wlr_xdg_activation_v1_find_token(
struct wlr_xdg_activation_v1 *activation, const char *token_str) {
struct wlr_xdg_activation_token_v1 *token;
wl_list_for_each(token, &activation->tokens, link) {
if (strcmp(token_str, token->token) == 0) {
return token;
}
}
return NULL;
}
const char *wlr_xdg_activation_token_v1_get_name(
struct wlr_xdg_activation_token_v1 *token) {
return token->token;
}