From a9511d0f89b524e93fdb6787ff5c5862ba688d98 Mon Sep 17 00:00:00 2001 From: "Anna (navi) Figueiredo Gomes" Date: Mon, 19 May 2025 00:36:31 +0200 Subject: [PATCH 1/4] ext-foreign-toplevel-handle-v1: use per-handle version. the version of the list might not always be the same as the version of the handle, plus ext-foreign-toplevel-request-manager-v1 will need to create handle resources, using it's own resources, whose version might not match the handle as well Signed-off-by: Anna (navi) Figueiredo Gomes --- include/wlr/types/wlr_ext_foreign_toplevel_list_v1.h | 6 +++--- types/wlr_ext_foreign_toplevel_list_v1.c | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/include/wlr/types/wlr_ext_foreign_toplevel_list_v1.h b/include/wlr/types/wlr_ext_foreign_toplevel_list_v1.h index 902418eaf..e28000d4a 100644 --- a/include/wlr/types/wlr_ext_foreign_toplevel_list_v1.h +++ b/include/wlr/types/wlr_ext_foreign_toplevel_list_v1.h @@ -32,6 +32,7 @@ struct wlr_ext_foreign_toplevel_handle_v1 { struct wl_list resources; // wl_resource_get_link() struct wl_list link; // wlr_ext_foreign_toplevel_list_v1.toplevels + uint32_t version; char *title; char *app_id; char *identifier; @@ -62,9 +63,8 @@ struct wlr_ext_foreign_toplevel_handle_v1 *wlr_ext_foreign_toplevel_handle_v1_cr void wlr_ext_foreign_toplevel_handle_v1_destroy( struct wlr_ext_foreign_toplevel_handle_v1 *toplevel); -void wlr_ext_foreign_toplevel_handle_v1_update_state( - struct wlr_ext_foreign_toplevel_handle_v1 *toplevel, - const struct wlr_ext_foreign_toplevel_handle_v1_state *state); +void wlr_ext_foreign_toplevel_handle_v1_update_state(struct wlr_ext_foreign_toplevel_handle_v1 *toplevel, + const struct wlr_ext_foreign_toplevel_handle_v1_state *state, uint32_t version); struct wlr_ext_foreign_toplevel_handle_v1 *wlr_ext_foreign_toplevel_handle_v1_from_resource( struct wl_resource *resource); diff --git a/types/wlr_ext_foreign_toplevel_list_v1.c b/types/wlr_ext_foreign_toplevel_list_v1.c index f20ddc877..f40d4b2c0 100644 --- a/types/wlr_ext_foreign_toplevel_list_v1.c +++ b/types/wlr_ext_foreign_toplevel_list_v1.c @@ -10,6 +10,7 @@ #include "util/token.h" #define FOREIGN_TOPLEVEL_LIST_V1_VERSION 1 +#define FOREIGN_TOPLEVEL_HANDLE_V1_VERSION 1 static const struct ext_foreign_toplevel_handle_v1_interface toplevel_handle_impl; @@ -117,8 +118,7 @@ static struct wl_resource *create_toplevel_resource_for_resource( struct wl_resource *list_resource) { struct wl_client *client = wl_resource_get_client(list_resource); struct wl_resource *resource = wl_resource_create(client, - &ext_foreign_toplevel_handle_v1_interface, - wl_resource_get_version(list_resource), 0); + &ext_foreign_toplevel_handle_v1_interface, toplevel->version, 0); if (!resource) { wl_client_post_no_memory(client); return NULL; @@ -148,13 +148,15 @@ static void toplevel_send_details_to_toplevel_resource( struct wlr_ext_foreign_toplevel_handle_v1 * wlr_ext_foreign_toplevel_handle_v1_create(struct wlr_ext_foreign_toplevel_list_v1 *list, - const struct wlr_ext_foreign_toplevel_handle_v1_state *state) { + const struct wlr_ext_foreign_toplevel_handle_v1_state *state, uint32_t version) { + assert(version <= FOREIGN_TOPLEVEL_HANDLE_V1_VERSION); struct wlr_ext_foreign_toplevel_handle_v1 *toplevel = calloc(1, sizeof(*toplevel)); if (!toplevel) { wlr_log(WLR_ERROR, "failed to allocate memory for toplevel handle"); return NULL; } + toplevel->version = version; toplevel->identifier = calloc(TOKEN_SIZE, sizeof(char)); if (toplevel->identifier == NULL) { wlr_log(WLR_ERROR, "failed to allocate memory for toplevel identifier"); From 22e1d9e91f527709e12c3c0346f26540b7bacfe8 Mon Sep 17 00:00:00 2001 From: "Anna (navi) Figueiredo Gomes" Date: Mon, 19 May 2025 00:44:27 +0200 Subject: [PATCH 2/4] ext-foreign-toplevel-handle: make foreign_toplevel_send_details_to_resource non-static Signed-off-by: Anna (navi) Figueiredo Gomes --- include/types/wlr_foreign_toplevel.h | 10 ++++++++++ types/wlr_ext_foreign_toplevel_list_v1.c | 8 ++++---- 2 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 include/types/wlr_foreign_toplevel.h diff --git a/include/types/wlr_foreign_toplevel.h b/include/types/wlr_foreign_toplevel.h new file mode 100644 index 000000000..67b8eab10 --- /dev/null +++ b/include/types/wlr_foreign_toplevel.h @@ -0,0 +1,10 @@ +#ifndef TYPES_WLR_FOREIGN_TOPLEVEL_H +#define TYPES_WLR_FOREIGN_TOPLEVEL_H + +#include +#include + +void foreign_toplevel_send_details_to_resource( + struct wlr_ext_foreign_toplevel_handle_v1 *toplevel, struct wl_resource *resource); + +#endif diff --git a/types/wlr_ext_foreign_toplevel_list_v1.c b/types/wlr_ext_foreign_toplevel_list_v1.c index f40d4b2c0..c0954cac0 100644 --- a/types/wlr_ext_foreign_toplevel_list_v1.c +++ b/types/wlr_ext_foreign_toplevel_list_v1.c @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include "ext-foreign-toplevel-list-v1-protocol.h" @@ -132,7 +132,7 @@ static struct wl_resource *create_toplevel_resource_for_resource( return resource; } -static void toplevel_send_details_to_toplevel_resource( +void foreign_toplevel_send_details_to_resource( struct wlr_ext_foreign_toplevel_handle_v1 *toplevel, struct wl_resource *resource) { if (toplevel->title) { @@ -189,7 +189,7 @@ wlr_ext_foreign_toplevel_handle_v1_create(struct wlr_ext_foreign_toplevel_list_v if (!toplevel_resource) { continue; } - toplevel_send_details_to_toplevel_resource(toplevel, toplevel_resource); + foreign_toplevel_send_details_to_resource(toplevel, toplevel_resource); } return toplevel; @@ -247,7 +247,7 @@ static void foreign_toplevel_list_bind(struct wl_client *client, void *data, wl_list_for_each(toplevel, &list->toplevels, link) { struct wl_resource *toplevel_resource = create_toplevel_resource_for_resource(toplevel, resource); - toplevel_send_details_to_toplevel_resource(toplevel, + foreign_toplevel_send_details_to_resource(toplevel, toplevel_resource); } } From 9522b77e84a98b2b6e22008fe9858e3e5e844e04 Mon Sep 17 00:00:00 2001 From: "Anna (navi) Figueiredo Gomes" Date: Mon, 19 May 2025 00:45:18 +0200 Subject: [PATCH 3/4] ext-foreign-toplevel-handle: split out foreign_toplevel_create_resource_for_client Signed-off-by: Anna (navi) Figueiredo Gomes --- include/types/wlr_foreign_toplevel.h | 2 ++ types/wlr_ext_foreign_toplevel_list_v1.c | 14 ++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/include/types/wlr_foreign_toplevel.h b/include/types/wlr_foreign_toplevel.h index 67b8eab10..6b808e789 100644 --- a/include/types/wlr_foreign_toplevel.h +++ b/include/types/wlr_foreign_toplevel.h @@ -4,6 +4,8 @@ #include #include +struct wl_resource *foreign_toplevel_create_resource_for_client( + struct wlr_ext_foreign_toplevel_handle_v1 *toplevel, struct wl_client *client); void foreign_toplevel_send_details_to_resource( struct wlr_ext_foreign_toplevel_handle_v1 *toplevel, struct wl_resource *resource); diff --git a/types/wlr_ext_foreign_toplevel_list_v1.c b/types/wlr_ext_foreign_toplevel_list_v1.c index c0954cac0..5a6ea71ed 100644 --- a/types/wlr_ext_foreign_toplevel_list_v1.c +++ b/types/wlr_ext_foreign_toplevel_list_v1.c @@ -113,10 +113,8 @@ static void foreign_toplevel_resource_destroy(struct wl_resource *resource) { wl_list_remove(wl_resource_get_link(resource)); } -static struct wl_resource *create_toplevel_resource_for_resource( - struct wlr_ext_foreign_toplevel_handle_v1 *toplevel, - struct wl_resource *list_resource) { - struct wl_client *client = wl_resource_get_client(list_resource); +struct wl_resource *foreign_toplevel_create_resource_for_client( + struct wlr_ext_foreign_toplevel_handle_v1 *toplevel, struct wl_client *client) { struct wl_resource *resource = wl_resource_create(client, &ext_foreign_toplevel_handle_v1_interface, toplevel->version, 0); if (!resource) { @@ -128,6 +126,14 @@ static struct wl_resource *create_toplevel_resource_for_resource( foreign_toplevel_resource_destroy); wl_list_insert(&toplevel->resources, wl_resource_get_link(resource)); + return resource; +} + +static struct wl_resource *create_toplevel_resource_for_resource( + struct wlr_ext_foreign_toplevel_handle_v1 *toplevel, + struct wl_resource *list_resource) { + struct wl_resource *resource = foreign_toplevel_create_resource_for_client( + toplevel, wl_resource_get_client(list_resource)); ext_foreign_toplevel_list_v1_send_toplevel(list_resource, resource); return resource; } From 00166aa0d6ba402be8ba4088ae6eed638317630c Mon Sep 17 00:00:00 2001 From: "Anna (navi) Figueiredo Gomes" Date: Mon, 19 May 2025 00:45:57 +0200 Subject: [PATCH 4/4] ext-foreign-toplevel-request-v1: new protocol Signed-off-by: Anna (navi) Figueiredo Gomes --- .../wlr_ext_foreign_toplevel_request_v1.h | 73 +++++ protocol/meson.build | 1 + types/meson.build | 1 + types/wlr_ext_foreign_toplevel_request_v1.c | 298 ++++++++++++++++++ 4 files changed, 373 insertions(+) create mode 100644 include/wlr/types/wlr_ext_foreign_toplevel_request_v1.h create mode 100644 types/wlr_ext_foreign_toplevel_request_v1.c diff --git a/include/wlr/types/wlr_ext_foreign_toplevel_request_v1.h b/include/wlr/types/wlr_ext_foreign_toplevel_request_v1.h new file mode 100644 index 000000000..35d118e49 --- /dev/null +++ b/include/wlr/types/wlr_ext_foreign_toplevel_request_v1.h @@ -0,0 +1,73 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + +#ifndef WLR_TYPES_WLR_FOREIGN_TOPLEVEL_REQUEST_V1_H +#define WLR_TYPES_WLR_FOREIGN_TOPLEVEL_REQUEST_V1_H + +#include + +struct wlr_ext_foreign_toplevel_request_manager_v1 { + struct wl_global *global; + struct wl_list resources; // wl_resource_get_link() + + struct { + struct wl_signal request; + struct wl_signal destroy; + } events; + + void *data; + + struct { + struct wl_listener display_destroy; + } WLR_PRIVATE; +}; + +struct wlr_ext_foreign_toplevel_request_v1 { + struct wl_resource *manager; + struct wl_resource *resource; + + struct { + struct wl_signal destroy; + } events; +}; + +struct wlr_ext_foreign_toplevel_request_source_v1 { + struct wl_global *global; + struct wl_list resources; // wl_resource_get_link() + + struct { + struct wl_signal toplevel; + struct wl_signal cancel; + struct wl_signal destroy; + } events; + + struct { + struct wl_listener display_destroy; + } WLR_PRIVATE; +}; + +struct wlr_ext_foreign_toplevel_request_pending_v1 { + struct wlr_ext_foreign_toplevel_request_source_v1 *source; + struct wlr_ext_foreign_toplevel_request_v1 *request; + struct wlr_ext_foreign_toplevel_handle_v1 *handle; + struct wl_resource *resource; +}; + +struct wlr_ext_foreign_toplevel_request_manager_v1 * + wlr_ext_foreign_toplevel_request_manager_v1_create(struct wl_display *display, uint32_t version); + +void wlr_ext_foreign_toplevel_request_v1_send_toplevel( + struct wlr_ext_foreign_toplevel_request_v1 *request, struct wlr_ext_foreign_toplevel_handle_v1 *toplevel); +void wlr_ext_foreign_toplevel_request_v1_cancel(struct wlr_ext_foreign_toplevel_request_v1 *request); + +struct wlr_ext_foreign_toplevel_request_source_v1 * + wlr_ext_foreign_toplevel_request_source_v1_create(struct wl_display *display, uint32_t version); + +void wlr_ext_foreign_toplevel_request_source_v1_request( + struct wlr_ext_foreign_toplevel_request_source_v1 *source, struct wlr_ext_foreign_toplevel_request_v1 *request); +#endif diff --git a/protocol/meson.build b/protocol/meson.build index 2a04a0377..61ece03a1 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -29,6 +29,7 @@ protocols = { 'cursor-shape-v1': wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml', 'drm-lease-v1': wl_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml', 'ext-foreign-toplevel-list-v1': wl_protocol_dir / 'staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml', + 'ext-foreign-toplevel-request-v1': wl_protocol_dir / 'staging/ext-foreign-toplevel-request/ext-foreign-toplevel-request-v1.xml', 'ext-idle-notify-v1': wl_protocol_dir / 'staging/ext-idle-notify/ext-idle-notify-v1.xml', 'ext-image-capture-source-v1': wl_protocol_dir / 'staging/ext-image-capture-source/ext-image-capture-source-v1.xml', 'ext-image-copy-capture-v1': wl_protocol_dir / 'staging/ext-image-copy-capture/ext-image-copy-capture-v1.xml', diff --git a/types/meson.build b/types/meson.build index 831698eb9..9f0d7b34e 100644 --- a/types/meson.build +++ b/types/meson.build @@ -48,6 +48,7 @@ wlr_files += files( 'wlr_foreign_toplevel_management_v1.c', 'wlr_ext_image_copy_capture_v1.c', 'wlr_ext_foreign_toplevel_list_v1.c', + 'wlr_ext_foreign_toplevel_request_v1.c', 'wlr_ext_data_control_v1.c', 'wlr_fractional_scale_v1.c', 'wlr_gamma_control_v1.c', diff --git a/types/wlr_ext_foreign_toplevel_request_v1.c b/types/wlr_ext_foreign_toplevel_request_v1.c new file mode 100644 index 000000000..7ba60d7a2 --- /dev/null +++ b/types/wlr_ext_foreign_toplevel_request_v1.c @@ -0,0 +1,298 @@ +#include +#include +#include +#include +#include +#include "ext-foreign-toplevel-request-v1-protocol.h" + +#define FOREIGN_TOPLEVEL_REQUEST_V1_VERSION 1 + +struct ext_foreign_toplevel_request_v1_interface foreign_toplevel_request_v1_impl; +static struct wlr_ext_foreign_toplevel_request_v1 * + foreign_toplevel_request_v1_from_resource(struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &ext_foreign_toplevel_request_v1_interface, &foreign_toplevel_request_v1_impl)); + return wl_resource_get_user_data(resource); +} + +static void foreign_toplevel_request_v1_destroy(struct wl_client *client, struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &ext_foreign_toplevel_request_v1_interface, &foreign_toplevel_request_v1_impl)); + wl_resource_destroy(resource); +} + +static void foreign_toplevel_request_v1_resource_destroy(struct wl_resource *resource) { + struct wlr_ext_foreign_toplevel_request_v1 *request = + foreign_toplevel_request_v1_from_resource(resource); + wl_signal_emit_mutable(&request->events.destroy, NULL); + free(request); +} + +struct ext_foreign_toplevel_request_v1_interface foreign_toplevel_request_v1_impl = { + .destroy = foreign_toplevel_request_v1_destroy, +}; + +static const struct ext_foreign_toplevel_request_manager_v1_interface foreign_toplevel_request_manager_v1_impl; +static struct wlr_ext_foreign_toplevel_request_manager_v1 * + foreign_toplevel_request_manager_v1_from_resource(struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &ext_foreign_toplevel_request_manager_v1_interface, + &foreign_toplevel_request_manager_v1_impl)); + return wl_resource_get_user_data(resource); +} + +static void foreign_toplevel_request_manager_request( + struct wl_client *client, struct wl_resource *resource, uint32_t request) { + struct wlr_ext_foreign_toplevel_request_manager_v1 *manager + = foreign_toplevel_request_manager_v1_from_resource(resource); + struct wlr_ext_foreign_toplevel_request_v1 *wlr_request = calloc(1, sizeof(*wlr_request)); + if (!wlr_request) { + wl_resource_post_no_memory(resource); + return; + } + + wlr_request->manager = resource; + wlr_request->resource = wl_resource_create(client, + &ext_foreign_toplevel_request_v1_interface, + ext_foreign_toplevel_request_v1_interface.version, request); + if (!wlr_request->resource) { + wl_resource_post_no_memory(resource); + free(wlr_request); + return; + } + + wl_signal_init(&wlr_request->events.destroy); + + wl_resource_set_implementation(wlr_request->resource, &foreign_toplevel_request_v1_impl, + wlr_request, foreign_toplevel_request_v1_resource_destroy); + + wl_signal_emit_mutable(&manager->events.request, wlr_request); +} + +static void foreign_toplevel_request_manager_destroy( + struct wl_client *client, struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &ext_foreign_toplevel_request_manager_v1_interface, + &foreign_toplevel_request_manager_v1_impl)); + + wl_resource_destroy(resource); +} + +static const struct ext_foreign_toplevel_request_manager_v1_interface foreign_toplevel_request_manager_v1_impl = { + .request = foreign_toplevel_request_manager_request, + .destroy = foreign_toplevel_request_manager_destroy +}; + +static void foreign_toplevel_request_manager_resource_destroy(struct wl_resource *resource) { + wl_list_remove(wl_resource_get_link(resource)); +} + +static void foreign_toplevel_request_manager_bind( + struct wl_client *client, void *data, uint32_t version, uint32_t id) { + struct wlr_ext_foreign_toplevel_request_manager_v1 *manager = data; + struct wl_resource *resource = wl_resource_create(client, + &ext_foreign_toplevel_request_manager_v1_interface, version, id); + if (!resource) { + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(resource, &foreign_toplevel_request_manager_v1_impl, + manager, foreign_toplevel_request_manager_resource_destroy); + wl_list_insert(&manager->resources, wl_resource_get_link(resource)); +} + +static void manager_handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_ext_foreign_toplevel_request_manager_v1 *manager = + wl_container_of(listener, manager, display_destroy); + wl_signal_emit_mutable(&manager->events.destroy, NULL); + + assert(wl_list_empty(&manager->events.destroy.listener_list)); + + wl_list_remove(&manager->display_destroy.link); + wl_global_destroy(manager->global); + free(manager); +} + +struct wlr_ext_foreign_toplevel_request_manager_v1 * + wlr_ext_foreign_toplevel_request_manager_v1_create(struct wl_display *display, uint32_t version) { + assert(version <= FOREIGN_TOPLEVEL_REQUEST_V1_VERSION); + + struct wlr_ext_foreign_toplevel_request_manager_v1 *manager = calloc(1, sizeof(*manager)); + if (!manager) { + return NULL; + } + + manager->global = wl_global_create(display, + &ext_foreign_toplevel_request_manager_v1_interface, + version, manager, foreign_toplevel_request_manager_bind); + if (!manager->global) { + free(manager); + return NULL; + } + + wl_list_init(&manager->resources); + + wl_signal_init(&manager->events.request); + wl_signal_init(&manager->events.destroy); + + manager->display_destroy.notify = manager_handle_display_destroy; + wl_display_add_destroy_listener(display, &manager->display_destroy); + + return manager; +} + +struct wl_resource *create_toplevel_resource_for_resource( + struct wlr_ext_foreign_toplevel_handle_v1 *toplevel, struct wl_resource *list_resource); + +void wlr_ext_foreign_toplevel_request_v1_send_toplevel( + struct wlr_ext_foreign_toplevel_request_v1 *request, struct wlr_ext_foreign_toplevel_handle_v1 *toplevel) { + struct wl_resource *resource = foreign_toplevel_create_resource_for_client( + toplevel, wl_resource_get_client(request->manager)); + ext_foreign_toplevel_request_v1_send_toplevel(request->resource, resource); + foreign_toplevel_send_details_to_resource(toplevel, resource); +} + +void wlr_ext_foreign_toplevel_request_v1_cancel(struct wlr_ext_foreign_toplevel_request_v1 *request) { + ext_foreign_toplevel_request_v1_send_cancelled(request->resource); +} + +struct ext_foreign_toplevel_request_source_v1_interface foreign_toplevel_request_source_v1_impl; +static void foreign_toplevel_request_source_destroy( + struct wl_client *client, struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &ext_foreign_toplevel_request_source_v1_interface, + &foreign_toplevel_request_source_v1_impl)); + + wl_resource_destroy(resource); +} + +struct ext_foreign_toplevel_request_source_v1_interface foreign_toplevel_request_source_v1_impl = { + .destroy = foreign_toplevel_request_source_destroy +}; + +static void source_handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_ext_foreign_toplevel_request_source_v1 *source = + wl_container_of(listener, source, display_destroy); + wl_signal_emit_mutable(&source->events.destroy, NULL); + + assert(wl_list_empty(&source->events.destroy.listener_list)); + + wl_list_remove(&source->display_destroy.link); + wl_global_destroy(source->global); + free(source); +} + +static void foreign_toplevel_request_source_resource_destroy(struct wl_resource *resource) { + wl_list_remove(wl_resource_get_link(resource)); +} + +static void foreign_toplevel_request_source_bind( + struct wl_client *client, void *data, uint32_t version, uint32_t id) { + struct wlr_ext_foreign_toplevel_request_source_v1 *source = data; + struct wl_resource *resource = wl_resource_create(client, + &ext_foreign_toplevel_request_source_v1_interface, version, id); + if (!resource) { + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(resource, &foreign_toplevel_request_source_v1_impl, + source, foreign_toplevel_request_source_resource_destroy); + wl_list_insert(&source->resources, wl_resource_get_link(resource)); +} + +struct wlr_ext_foreign_toplevel_request_source_v1 * + wlr_ext_foreign_toplevel_request_source_v1_create(struct wl_display *display, uint32_t version) { + assert(version <= FOREIGN_TOPLEVEL_REQUEST_V1_VERSION); + + struct wlr_ext_foreign_toplevel_request_source_v1 *source = calloc(1, sizeof(*source)); + if (!source) { + return NULL; + } + + source->global = wl_global_create(display, + &ext_foreign_toplevel_request_source_v1_interface, + version, source, foreign_toplevel_request_source_bind); + if (!source->global) { + free(source); + return NULL; + } + + wl_list_init(&source->resources); + + wl_signal_init(&source->events.toplevel); + wl_signal_init(&source->events.cancel); + wl_signal_init(&source->events.destroy); + + source->display_destroy.notify = source_handle_display_destroy; + wl_display_add_destroy_listener(display, &source->display_destroy); + + return source; +} + +struct ext_foreign_toplevel_request_pending_v1_interface foreign_toplevel_request_pending_v1_impl; +static struct wlr_ext_foreign_toplevel_request_pending_v1 * + foreign_toplevel_request_pending_v1_from_resource(struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &ext_foreign_toplevel_request_pending_v1_interface, &foreign_toplevel_request_pending_v1_impl)); + return wl_resource_get_user_data(resource); +} + +static void foreign_toplevel_request_pending_v1_resource_destroy(struct wl_resource *resource) { + free(foreign_toplevel_request_pending_v1_from_resource(resource)); +} + +static void foreign_toplevel_request_pending_toplevel( + struct wl_client *client, struct wl_resource *resource, struct wl_resource *toplevel) { + struct wlr_ext_foreign_toplevel_request_pending_v1 *response = + foreign_toplevel_request_pending_v1_from_resource(resource); + response->handle = wlr_ext_foreign_toplevel_handle_v1_from_resource(toplevel); + + wl_signal_emit_mutable(&response->source->events.toplevel, response); + wl_resource_destroy(resource); +} + +static void foreign_toplevel_request_pending_cancel( + struct wl_client *client, struct wl_resource *resource) { + struct wlr_ext_foreign_toplevel_request_pending_v1 *response = + foreign_toplevel_request_pending_v1_from_resource(resource); + + wl_signal_emit_mutable(&response->source->events.cancel, response); + wl_resource_destroy(resource); +} + +struct ext_foreign_toplevel_request_pending_v1_interface foreign_toplevel_request_pending_v1_impl = { + .toplevel = foreign_toplevel_request_pending_toplevel, + .cancel = foreign_toplevel_request_pending_cancel +}; + +#include + +void wlr_ext_foreign_toplevel_request_source_v1_request( + struct wlr_ext_foreign_toplevel_request_source_v1 *source, struct wlr_ext_foreign_toplevel_request_v1 *request) { + struct wlr_ext_foreign_toplevel_request_pending_v1 *response = calloc(1, sizeof(*response)); + struct wl_resource *source_resource = wl_container_of(source->resources.next, source_resource, link); + if (!response) { + wl_client_post_no_memory(wl_resource_get_client(request->resource)); + return; + } + + response->source = source; + response->request = request; + response->resource = wl_resource_create(wl_resource_get_client(source_resource), + &ext_foreign_toplevel_request_pending_v1_interface, + ext_foreign_toplevel_request_pending_v1_interface.version, 0); + if (!response->resource) { + wl_client_post_no_memory(wl_resource_get_client(request->resource)); + free(response); + return; + } + + wl_resource_set_implementation(response->resource, &foreign_toplevel_request_pending_v1_impl, + response, foreign_toplevel_request_pending_v1_resource_destroy); + + ext_foreign_toplevel_request_source_v1_send_request(source_resource, response->resource); + + return; +}