From 619578f62f964dae50bcbc6af8f977dfc69e0a3a Mon Sep 17 00:00:00 2001 From: Marius Vlad Date: Thu, 3 Aug 2023 15:52:02 +0300 Subject: [PATCH] kiosk-shell, xwayland: Add a new weston_xwayland_surface_api function Such that shells can retrieve Xwayland's surface WM_CLASS/WM_NAME and use it to place the corresponding Xwayland surface on the appropriate output, similar to what xdg_shell::set_app_id does. Signed-off-by: Marius Vlad --- include/libweston/xwayland-api.h | 17 ++++++++- kiosk-shell/kiosk-shell.c | 61 +++++++++++++++++++++++++++----- kiosk-shell/kiosk-shell.h | 2 ++ xwayland/window-manager.c | 20 +++++++++++ 4 files changed, 91 insertions(+), 9 deletions(-) diff --git a/include/libweston/xwayland-api.h b/include/libweston/xwayland-api.h index 649721ebc..947c0983a 100644 --- a/include/libweston/xwayland-api.h +++ b/include/libweston/xwayland-api.h @@ -38,7 +38,12 @@ struct weston_compositor; struct weston_xwayland; #define WESTON_XWAYLAND_API_NAME "weston_xwayland_v3" -#define WESTON_XWAYLAND_SURFACE_API_NAME "weston_xwayland_surface_v1" +#define WESTON_XWAYLAND_SURFACE_API_NAME "weston_xwayland_surface_v2" + +enum window_atom_type { + WM_NAME, + WM_CLASS, +}; typedef struct wl_client * (*weston_xwayland_spawn_xserver_func_t)( @@ -146,6 +151,16 @@ struct weston_xwayland_surface_api { */ void (*send_position)(struct weston_surface *surface, int32_t x, int32_t y); + + /** Grab the window's name using enume window_atom_type + * + * + * \param surface The Xwayland surface. + * \param atype the type of the atom, either WM_NAME or WM_CLASS + * \returns the net_wm_name, as a string. + */ + const char * + (*get_xwayland_window_name)(struct weston_surface *surface, enum window_atom_type atype); }; /** Retrieve the API object for the libweston Xwayland surface. diff --git a/kiosk-shell/kiosk-shell.c b/kiosk-shell/kiosk-shell.c index 03071ae51..cf8e4ba41 100644 --- a/kiosk-shell/kiosk-shell.c +++ b/kiosk-shell/kiosk-shell.c @@ -112,6 +112,25 @@ transform_handler(struct wl_listener *listener, void *data) shsurf->view->geometry.pos_offset.y); } +static const char * +xwayland_get_xwayland_name(struct kiosk_shell_surface *shsurf, enum window_atom_type type) +{ + const struct weston_xwayland_surface_api *api; + struct weston_surface *surface; + + api = shsurf->shell->xwayland_surface_api; + if (!api) { + api = weston_xwayland_surface_get_api(shsurf->shell->compositor); + shsurf->shell->xwayland_surface_api = api; + } + + surface = weston_desktop_surface_get_surface(shsurf->desktop_surface); + if (!api || !api->is_xwayland_surface(surface)) + return NULL; + + return api->get_xwayland_window_name(surface, type); +} + /* * kiosk_shell_surface */ @@ -162,8 +181,7 @@ kiosk_shell_surface_get_parent_root(struct kiosk_shell_surface *shsurf) } static bool -kiosk_shell_output_has_app_id(struct kiosk_shell_output *shoutput, - const char *app_id); +kiosk_shell_output_has_app_id(char *config_app_ids, const char *app_id); static struct weston_output * kiosk_shell_surface_find_best_output(struct kiosk_shell_surface *shsurf) @@ -181,7 +199,27 @@ kiosk_shell_surface_find_best_output(struct kiosk_shell_surface *shsurf) app_id = weston_desktop_surface_get_app_id(shsurf->desktop_surface); if (app_id) { wl_list_for_each(shoutput, &shsurf->shell->output_list, link) { - if (kiosk_shell_output_has_app_id(shoutput, app_id)) { + if (kiosk_shell_output_has_app_id(shoutput->app_ids, app_id)) { + shsurf->appid_output_assigned = true; + return shoutput->output; + } + } + } + + app_id = xwayland_get_xwayland_name(shsurf, WM_NAME); + if (app_id) { + wl_list_for_each(shoutput, &shsurf->shell->output_list, link) { + if (kiosk_shell_output_has_app_id(shoutput->x11_wm_name_app_ids, app_id)) { + shsurf->appid_output_assigned = true; + return shoutput->output; + } + } + } + + app_id = xwayland_get_xwayland_name(shsurf, WM_CLASS); + if (app_id) { + wl_list_for_each(shoutput, &shsurf->shell->output_list, link) { + if (kiosk_shell_output_has_app_id(shoutput->x11_wm_class_app_ids, app_id)) { shsurf->appid_output_assigned = true; return shoutput->output; } @@ -669,27 +707,28 @@ kiosk_shell_output_destroy(struct kiosk_shell_output *shoutput) wl_list_remove(&shoutput->link); free(shoutput->app_ids); + free(shoutput->x11_wm_name_app_ids); + free(shoutput->x11_wm_class_app_ids); free(shoutput); } static bool -kiosk_shell_output_has_app_id(struct kiosk_shell_output *shoutput, - const char *app_id) +kiosk_shell_output_has_app_id(char *config_app_ids, const char *app_id) { char *cur; size_t app_id_len; - if (!shoutput->app_ids) + if (!config_app_ids) return false; - cur = shoutput->app_ids; + cur = config_app_ids; app_id_len = strlen(app_id); while ((cur = strstr(cur, app_id))) { /* Check whether we have found a complete match of app_id. */ if ((cur[app_id_len] == ',' || cur[app_id_len] == '\0') && - (cur == shoutput->app_ids || cur[-1] == ',')) + (cur == config_app_ids || cur[-1] == ',')) return true; cur++; } @@ -705,10 +744,16 @@ kiosk_shell_output_configure(struct kiosk_shell_output *shoutput) weston_config_get_section(wc, "output", "name", shoutput->output->name); assert(shoutput->app_ids == NULL); + assert(shoutput->x11_wm_name_app_ids == NULL); + assert(shoutput->x11_wm_class_app_ids == NULL); if (section) { weston_config_section_get_string(section, "app-ids", &shoutput->app_ids, NULL); + weston_config_section_get_string(section, "x11-wm-name", + &shoutput->x11_wm_name_app_ids, NULL); + weston_config_section_get_string(section, "x11-wm-class", + &shoutput->x11_wm_class_app_ids, NULL); } } diff --git a/kiosk-shell/kiosk-shell.h b/kiosk-shell/kiosk-shell.h index 5f7b6851f..b914147f6 100644 --- a/kiosk-shell/kiosk-shell.h +++ b/kiosk-shell/kiosk-shell.h @@ -98,6 +98,8 @@ struct kiosk_shell_output { struct wl_list link; char *app_ids; + char *x11_wm_name_app_ids; + char *x11_wm_class_app_ids; struct wl_list *active_surface_tree; }; diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c index 422ac4606..5a53abfb4 100644 --- a/xwayland/window-manager.c +++ b/xwayland/window-manager.c @@ -2986,6 +2986,25 @@ is_wm_window(struct weston_surface *surface) return get_wm_window(surface) != NULL; } +static const char * +get_xwayland_window_name(struct weston_surface *surface, enum window_atom_type atype) +{ + struct weston_wm_window *window = get_wm_window(surface); + + switch (atype) { + case WM_NAME: + return window->name; + break; + case WM_CLASS: + return window->class; + break; + default: + break; + } + + return NULL; +} + static void weston_wm_window_configure(void *data) { @@ -3354,4 +3373,5 @@ xserver_map_shell_surface(struct weston_wm_window *window, const struct weston_xwayland_surface_api surface_api = { is_wm_window, send_position, + get_xwayland_window_name, };