diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h index cf2ef2636..e8fc59bb5 100644 --- a/include/wlr/xwayland.h +++ b/include/wlr/xwayland.h @@ -1,2 +1,3 @@ #include #include +#include diff --git a/include/wlr/xwayland/shell.h b/include/wlr/xwayland/shell.h index 6cd3d93e6..eb4828f5d 100644 --- a/include/wlr/xwayland/shell.h +++ b/include/wlr/xwayland/shell.h @@ -26,11 +26,10 @@ struct wlr_xwayland_shell_v1 { // private state - struct wl_client *client; + struct wl_list clients; // wlr_xwayland_shell_client.link struct wl_list surfaces; // wlr_xwayland_surface_v1.link struct wl_listener display_destroy; - struct wl_listener client_destroy; }; /** @@ -65,9 +64,22 @@ void wlr_xwayland_shell_v1_destroy(struct wlr_xwayland_shell_v1 *shell); /** * Allow a client to bind to the xwayland_shell_v1 global. */ -void wlr_xwayland_shell_v1_set_client(struct wlr_xwayland_shell_v1 *shell, +void wlr_xwayland_shell_v1_add_client(struct wlr_xwayland_shell_v1 *shell, struct wl_client *client); +/** + * Cancel allow a client to bind to the xwayland_shell_v1 global. + */ +void wlr_xwayland_shell_v1_remove_client(struct wlr_xwayland_shell_v1 *shell, + struct wl_client *client); + +/** + * Return true if allow this client bind to the xwayland_shell_v1 global, + * Return false otherwise. + */ +bool wlr_xwayland_shell_has_client(struct wlr_xwayland_shell_v1 *shell, + const struct wl_client *client); + /** * Get a Wayland surface from an xwayland_shell_v1 serial. * diff --git a/include/wlr/xwayland/xwayland.h b/include/wlr/xwayland/xwayland.h index 6761eff08..f9eeb9d7d 100644 --- a/include/wlr/xwayland/xwayland.h +++ b/include/wlr/xwayland/xwayland.h @@ -19,6 +19,7 @@ struct wlr_xwm; struct wlr_data_source; struct wlr_drag; +struct wlr_xwayland_shell_v1; struct wlr_xwayland { struct wlr_xwayland_server *server; @@ -197,7 +198,8 @@ struct wlr_xwayland_minimize_event { * client tries to connect. */ struct wlr_xwayland *wlr_xwayland_create(struct wl_display *wl_display, - struct wlr_compositor *compositor, bool lazy); + struct wlr_compositor *compositor, struct wlr_xwayland_shell_v1 *shell, + bool lazy); void wlr_xwayland_destroy(struct wlr_xwayland *wlr_xwayland); diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index 67d2be773..78ba6d33e 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include diff --git a/xwayland/shell.c b/xwayland/shell.c index 9c5a9d20c..0a88b3023 100644 --- a/xwayland/shell.c +++ b/xwayland/shell.c @@ -7,6 +7,55 @@ #define SHELL_VERSION 1 +struct wlr_xwayland_shell_client { + struct wl_client *client; + struct wl_listener client_destroy; + struct wl_list link; +}; + +static void xwl_shell_client_destroy(struct wlr_xwayland_shell_client *xwl_client) { + wl_list_remove(&xwl_client->link); + wl_list_remove(&xwl_client->client_destroy.link); + free(xwl_client); +} + +static void shell_client_handle_client_destroy(struct wl_listener *listener, void *data) { + struct wlr_xwayland_shell_client *shell_client = + wl_container_of(listener, shell_client, client_destroy); + xwl_shell_client_destroy(shell_client); +} + +static struct wlr_xwayland_shell_client *xwl_shell_client_create(struct wl_client *client) { + struct wlr_xwayland_shell_client *xwl_client = calloc(1, sizeof(*xwl_client)); + if (xwl_client == NULL) { + wl_client_post_no_memory(client); + return NULL; + } + + xwl_client->client = client; + + wl_list_init(&xwl_client->link); + wl_list_init(&xwl_client->client_destroy.link); + + xwl_client->client_destroy.notify = shell_client_handle_client_destroy; + wl_client_add_destroy_listener(client, &xwl_client->client_destroy); + + return xwl_client; +} + +static struct wlr_xwayland_shell_client *get_shell_client( + struct wlr_xwayland_shell_v1 *shell, + const struct wl_client *client) { + struct wlr_xwayland_shell_client *xwl_client, *tmp; + wl_list_for_each_safe(xwl_client, tmp, &shell->clients, link) { + if (xwl_client->client == client) { + return xwl_client; + } + } + + return NULL; +} + static void destroy_resource(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); @@ -140,7 +189,7 @@ static void shell_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) { struct wlr_xwayland_shell_v1 *shell = data; - if (client != shell->client) { + if (!get_shell_client(shell, client)) { wl_client_post_implementation_error(client, "Permission denied to bind to %s", xwayland_shell_v1_interface.name); return; @@ -183,7 +232,7 @@ struct wlr_xwayland_shell_v1 *wlr_xwayland_shell_v1_create( shell->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &shell->display_destroy); - wl_list_init(&shell->client_destroy.link); + wl_list_init(&shell->clients); return shell; } @@ -198,30 +247,44 @@ void wlr_xwayland_shell_v1_destroy(struct wlr_xwayland_shell_v1 *shell) { xwl_surface_destroy(xwl_surface); } + { + struct wlr_xwayland_shell_client *xwl_client, *tmp; + wl_list_for_each_safe(xwl_client, tmp, &shell->clients, link) { + xwl_shell_client_destroy(xwl_client); + } + } + wl_list_remove(&shell->display_destroy.link); - wl_list_remove(&shell->client_destroy.link); wl_global_destroy(shell->global); free(shell); } -static void shell_handle_client_destroy(struct wl_listener *listener, void *data) { - struct wlr_xwayland_shell_v1 *shell = - wl_container_of(listener, shell, client_destroy); - wlr_xwayland_shell_v1_set_client(shell, NULL); +void wlr_xwayland_shell_v1_add_client(struct wlr_xwayland_shell_v1 *shell, + struct wl_client *client) { + if (get_shell_client(shell, client)) + return; // already added + + struct wlr_xwayland_shell_client *xwl_client = xwl_shell_client_create(client); + if (!xwl_client) { + return; + } + + wl_list_insert(&shell->clients, &xwl_client->link); } -void wlr_xwayland_shell_v1_set_client(struct wlr_xwayland_shell_v1 *shell, +void wlr_xwayland_shell_v1_remove_client(struct wlr_xwayland_shell_v1 *shell, struct wl_client *client) { - wl_list_remove(&shell->client_destroy.link); - shell->client = client; - if (client != NULL) { - shell->client_destroy.notify = shell_handle_client_destroy; - wl_client_add_destroy_listener(client, &shell->client_destroy); - } else { - wl_list_init(&shell->client_destroy.link); + struct wlr_xwayland_shell_client *xwl_client = get_shell_client(shell, client); + if (xwl_client) { + xwl_shell_client_destroy(xwl_client); } } +bool wlr_xwayland_shell_has_client(struct wlr_xwayland_shell_v1 *shell, + const struct wl_client *client) { + return get_shell_client(shell, client); +} + struct wlr_surface *wlr_xwayland_shell_v1_surface_from_serial( struct wlr_xwayland_shell_v1 *shell, uint64_t serial) { struct wlr_xwayland_surface_v1 *xwl_surface; diff --git a/xwayland/xwayland.c b/xwayland/xwayland.c index 7f3a6eae1..1ad4151bc 100644 --- a/xwayland/xwayland.c +++ b/xwayland/xwayland.c @@ -37,7 +37,7 @@ static void handle_server_destroy(struct wl_listener *listener, void *data) { static void handle_server_start(struct wl_listener *listener, void *data) { struct wlr_xwayland *xwayland = wl_container_of(listener, xwayland, server_start); - wlr_xwayland_shell_v1_set_client(xwayland->shell_v1, xwayland->server->client); + wlr_xwayland_shell_v1_add_client(xwayland->shell_v1, xwayland->server->client); } static void handle_server_ready(struct wl_listener *listener, void *data) { @@ -76,12 +76,12 @@ void wlr_xwayland_destroy(struct wlr_xwayland *xwayland) { wlr_xwayland_set_seat(xwayland, NULL); wlr_xwayland_server_destroy(xwayland->server); xwayland->server = NULL; - wlr_xwayland_shell_v1_destroy(xwayland->shell_v1); free(xwayland); } struct wlr_xwayland *wlr_xwayland_create(struct wl_display *wl_display, - struct wlr_compositor *compositor, bool lazy) { + struct wlr_compositor *compositor, struct wlr_xwayland_shell_v1 *shell, + bool lazy) { struct wlr_xwayland *xwayland = calloc(1, sizeof(struct wlr_xwayland)); if (!xwayland) { return NULL; @@ -94,11 +94,7 @@ struct wlr_xwayland *wlr_xwayland_create(struct wl_display *wl_display, wl_signal_init(&xwayland->events.ready); wl_signal_init(&xwayland->events.remove_startup_info); - xwayland->shell_v1 = wlr_xwayland_shell_v1_create(wl_display, 1); - if (xwayland->shell_v1 == NULL) { - free(xwayland); - return NULL; - } + xwayland->shell_v1 = shell; struct wlr_xwayland_server_options options = { .lazy = lazy, @@ -109,7 +105,6 @@ struct wlr_xwayland *wlr_xwayland_create(struct wl_display *wl_display, }; xwayland->server = wlr_xwayland_server_create(wl_display, &options); if (xwayland->server == NULL) { - wlr_xwayland_shell_v1_destroy(xwayland->shell_v1); free(xwayland); return NULL; }