From 6c7b648570eb306c2163dfbc364d5ca260a1afa3 Mon Sep 17 00:00:00 2001 From: Aleksey Samoilov Date: Thu, 8 May 2025 17:58:20 +0400 Subject: [PATCH] [Wayland]: Add support for xdg-toplevel-icon-v1 --- .gitignore | 2 + Makefile.common | 1 + .../staging/xdg-toplevel-icon/README | 4 + .../xdg-toplevel-icon-v1.xml | 205 ++++++++++++++++++ gfx/common/wayland/generate_wayland_protos.sh | 1 + gfx/common/wayland_common.c | 85 ++++++-- input/common/wayland_common.c | 4 + input/common/wayland_common.h | 3 + 8 files changed, 281 insertions(+), 24 deletions(-) create mode 100644 deps/wayland-protocols/staging/xdg-toplevel-icon/README create mode 100644 deps/wayland-protocols/staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml diff --git a/.gitignore b/.gitignore index a29b8ebd83..cce661252b 100644 --- a/.gitignore +++ b/.gitignore @@ -241,6 +241,8 @@ gfx/common/wayland/content-type-v1.h gfx/common/wayland/content-type-v1.c gfx/common/wayland/single-pixel-buffer-v1.h gfx/common/wayland/single-pixel-buffer-v1.c +gfx/common/wayland/xdg-toplevel-icon-v1.h +gfx/common/wayland/xdg-toplevel-icon-v1.c # libretro-common samples libretro-common/samples/streams/rzip/rzip diff --git a/Makefile.common b/Makefile.common index c9ed198348..2175fbd298 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1284,6 +1284,7 @@ ifeq ($(HAVE_WAYLAND), 1) gfx/common/wayland_common.o \ gfx/common/wayland/fractional-scale-v1.o \ gfx/common/wayland/viewporter.o \ + gfx/common/wayland/xdg-toplevel-icon-v1.o \ gfx/common/wayland/xdg-shell.o \ gfx/common/wayland/idle-inhibit-unstable-v1.o \ gfx/common/wayland/xdg-decoration-unstable-v1.o \ diff --git a/deps/wayland-protocols/staging/xdg-toplevel-icon/README b/deps/wayland-protocols/staging/xdg-toplevel-icon/README new file mode 100644 index 0000000000..76a394f5da --- /dev/null +++ b/deps/wayland-protocols/staging/xdg-toplevel-icon/README @@ -0,0 +1,4 @@ +xdg_toplevel_icon protocol + +Maintainers: +Matthias Klumpp (@mak) diff --git a/deps/wayland-protocols/staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml b/deps/wayland-protocols/staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml new file mode 100644 index 0000000000..fc409fef7c --- /dev/null +++ b/deps/wayland-protocols/staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml @@ -0,0 +1,205 @@ + + + + + Copyright © 2023-2024 Matthias Klumpp + Copyright © 2024 David Edmundson + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + This protocol allows clients to set icons for their toplevel surfaces + either via the XDG icon stock (using an icon name), or from pixel data. + + A toplevel icon represents the individual toplevel (unlike the application + or launcher icon, which represents the application as a whole), and may be + shown in window switchers, window overviews and taskbars that list + individual windows. + + This document adheres to RFC 2119 when using words like "must", + "should", "may", etc. + + Warning! The protocol described in this file is currently in the testing + phase. Backward compatible changes may be added together with the + corresponding interface version bump. Backward incompatible changes can + only be done by creating a new major version of the extension. + + + + + This interface allows clients to create toplevel window icons and set + them on toplevel windows to be displayed to the user. + + + + + Destroy the toplevel icon manager. + This does not destroy objects created with the manager. + + + + + + Creates a new icon object. This icon can then be attached to a + xdg_toplevel via the 'set_icon' request. + + + + + + + This request assigns the icon 'icon' to 'toplevel', or clears the + toplevel icon if 'icon' was null. + This state is double-buffered and is applied on the next + wl_surface.commit of the toplevel. + + After making this call, the xdg_toplevel_icon_v1 provided as 'icon' + can be destroyed by the client without 'toplevel' losing its icon. + The xdg_toplevel_icon_v1 is immutable from this point, and any + future attempts to change it must raise the + 'xdg_toplevel_icon_v1.immutable' protocol error. + + The compositor must set the toplevel icon from either the pixel data + the icon provides, or by loading a stock icon using the icon name. + See the description of 'xdg_toplevel_icon_v1' for details. + + If 'icon' is set to null, the icon of the respective toplevel is reset + to its default icon (usually the icon of the application, derived from + its desktop-entry file, or a placeholder icon). + If this request is passed an icon with no pixel buffers or icon name + assigned, the icon must be reset just like if 'icon' was null. + + + + + + + + This event indicates an icon size the compositor prefers to be + available if the client has scalable icons and can render to any size. + + When the 'xdg_toplevel_icon_manager_v1' object is created, the + compositor may send one or more 'icon_size' events to describe the list + of preferred icon sizes. If the compositor has no size preference, it + may not send any 'icon_size' event, and it is up to the client to + decide a suitable icon size. + + A sequence of 'icon_size' events must be finished with a 'done' event. + If the compositor has no size preferences, it must still send the + 'done' event, without any preceding 'icon_size' events. + + + + + + + This event is sent after all 'icon_size' events have been sent. + + + + + + + This interface defines a toplevel icon. + An icon can have a name, and multiple buffers. + In order to be applied, the icon must have either a name, or at least + one buffer assigned. Applying an empty icon (with no buffer or name) to + a toplevel should reset its icon to the default icon. + + It is up to compositor policy whether to prefer using a buffer or loading + an icon via its name. See 'set_name' and 'add_buffer' for details. + + + + + + + + + + + Destroys the 'xdg_toplevel_icon_v1' object. + The icon must still remain set on every toplevel it was assigned to, + until the toplevel icon is reset explicitly. + + + + + + This request assigns an icon name to this icon. + Any previously set name is overridden. + + The compositor must resolve 'icon_name' according to the lookup rules + described in the XDG icon theme specification[1] using the + environment's current icon theme. + + If the compositor does not support icon names or cannot resolve + 'icon_name' according to the XDG icon theme specification it must + fall back to using pixel buffer data instead. + + If this request is made after the icon has been assigned to a toplevel + via 'set_icon', a 'immutable' error must be raised. + + [1]: https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html + + + + + + + This request adds pixel data supplied as wl_buffer to the icon. + + The client should add pixel data for all icon sizes and scales that + it can provide, or which are explicitly requested by the compositor + via 'icon_size' events on xdg_toplevel_icon_manager_v1. + + The wl_buffer supplying pixel data as 'buffer' must be backed by wl_shm + and must be a square (width and height being equal). + If any of these buffer requirements are not fulfilled, a 'invalid_buffer' + error must be raised. + + If this icon instance already has a buffer of the same size and scale + from a previous 'add_buffer' request, data from the last request + overrides the preexisting pixel data. + + The wl_buffer must be kept alive for as long as the xdg_toplevel_icon + it is associated with is not destroyed, otherwise a 'no_buffer' error + is raised. The buffer contents must not be modified after it was + assigned to the icon. As a result, the region of the wl_shm_pool's + backing storage used for the wl_buffer must not be modified after this + request is sent. The wl_buffer.release event is unused. + + If this request is made after the icon has been assigned to a toplevel + via 'set_icon', a 'immutable' error must be raised. + + + + + + diff --git a/gfx/common/wayland/generate_wayland_protos.sh b/gfx/common/wayland/generate_wayland_protos.sh index c26b3cbbc6..d45de79218 100755 --- a/gfx/common/wayland/generate_wayland_protos.sh +++ b/gfx/common/wayland/generate_wayland_protos.sh @@ -73,3 +73,4 @@ generate_source 'staging/cursor-shape' 'cursor-shape-v1' generate_source 'unstable/tablet' 'tablet-unstable-v2' generate_source 'staging/content-type' 'content-type-v1' generate_source 'staging/single-pixel-buffer' 'single-pixel-buffer-v1' +generate_source 'staging/xdg-toplevel-icon' 'xdg-toplevel-icon-v1' diff --git a/gfx/common/wayland_common.c b/gfx/common/wayland_common.c index 8b0f557bcb..b2f9359845 100644 --- a/gfx/common/wayland_common.c +++ b/gfx/common/wayland_common.c @@ -295,6 +295,10 @@ void gfx_ctx_wl_destroy_resources_common(gfx_ctx_wayland_data_t *wl) zxdg_toplevel_decoration_v1_destroy(wl->deco); if (wl->xdg_toplevel) xdg_toplevel_destroy(wl->xdg_toplevel); + if (wl->xdg_toplevel_icon_manager) + xdg_toplevel_icon_manager_v1_destroy(wl->xdg_toplevel_icon_manager); + if (wl->xdg_toplevel_icon) + xdg_toplevel_icon_v1_destroy(wl->xdg_toplevel_icon); if (wl->xdg_surface) xdg_surface_destroy(wl->xdg_surface); if (wl->surface) @@ -363,30 +367,32 @@ void gfx_ctx_wl_destroy_resources_common(gfx_ctx_wayland_data_t *wl) wl_display_disconnect(wl->input.dpy); } - wl->input.dpy = NULL; - wl->registry = NULL; - wl->compositor = NULL; - wl->shm = NULL; - wl->data_device_manager = NULL; - wl->xdg_shell = NULL; - wl->seat = NULL; - wl->relative_pointer_manager = NULL; - wl->pointer_constraints = NULL; - wl->content_type = NULL; - wl->content_type_manager = NULL; - wl->cursor_shape_manager = NULL; - wl->cursor_shape_device = NULL; - wl->idle_inhibit_manager = NULL; - wl->deco_manager = NULL; - wl->single_pixel_manager = NULL; - wl->surface = NULL; - wl->xdg_surface = NULL; - wl->xdg_toplevel = NULL; - wl->deco = NULL; - wl->idle_inhibitor = NULL; - wl->wl_touch = NULL; - wl->wl_pointer = NULL; - wl->wl_keyboard = NULL; + wl->input.dpy = NULL; + wl->registry = NULL; + wl->compositor = NULL; + wl->shm = NULL; + wl->data_device_manager = NULL; + wl->xdg_shell = NULL; + wl->seat = NULL; + wl->relative_pointer_manager = NULL; + wl->pointer_constraints = NULL; + wl->content_type = NULL; + wl->content_type_manager = NULL; + wl->cursor_shape_manager = NULL; + wl->cursor_shape_device = NULL; + wl->idle_inhibit_manager = NULL; + wl->deco_manager = NULL; + wl->single_pixel_manager = NULL; + wl->surface = NULL; + wl->xdg_surface = NULL; + wl->xdg_toplevel = NULL; + wl->xdg_toplevel_icon = NULL; + wl->xdg_toplevel_icon_manager = NULL; + wl->deco = NULL; + wl->idle_inhibitor = NULL; + wl->wl_touch = NULL; + wl->wl_pointer = NULL; + wl->wl_keyboard = NULL; wl->width = 0; wl->height = 0; @@ -586,6 +592,29 @@ static void shm_buffer_paint_icon( } } +static bool wl_create_toplevel_icon(gfx_ctx_wayland_data_t *wl) +{ + wl->xdg_toplevel_icon = xdg_toplevel_icon_manager_v1_create_icon( + wl->xdg_toplevel_icon_manager); + xdg_toplevel_icon_v1_set_name(wl->xdg_toplevel_icon, WAYLAND_APP_ID); + + const int icon_size = wl->buffer_scale > 1 ? 128 : 64; + shm_buffer_t *icon_buffer = create_shm_buffer(wl, + icon_size, icon_size, WL_SHM_FORMAT_ARGB8888); + + if (icon_buffer) + { + shm_buffer_paint_icon(icon_buffer, icon_size, icon_size, 1, icon_size / 16); + xdg_toplevel_icon_v1_add_buffer( + wl->xdg_toplevel_icon, icon_buffer->wl_buffer, 1); + } + + xdg_toplevel_icon_manager_v1_set_icon( + wl->xdg_toplevel_icon_manager, wl->xdg_toplevel, wl->xdg_toplevel_icon); + + return true; +} + static void shm_buffer_paint_checkerboard( shm_buffer_t *buffer, int width, int height, int scale, @@ -778,6 +807,11 @@ bool gfx_ctx_wl_init_common( RARCH_LOG("[Wayland]: Compositor doesn't support the %s protocol!\n", wp_single_pixel_buffer_manager_v1_interface.name); } + if (!wl->xdg_toplevel_icon_manager) + { + RARCH_LOG("[Wayland]: Compositor doesn't support the %s protocol!\n", xdg_toplevel_icon_manager_v1_interface.name); + } + wl->surface = wl_compositor_create_surface(wl->compositor); if (wl->viewporter) wl->viewport = wp_viewporter_get_viewport(wl->viewporter, wl->surface); @@ -842,6 +876,9 @@ bool gfx_ctx_wl_init_common( wl->deco = zxdg_decoration_manager_v1_get_toplevel_decoration( wl->deco_manager, wl->xdg_toplevel); + if (wl->xdg_toplevel_icon_manager) + wl_create_toplevel_icon(wl); + /* Waiting for xdg_toplevel to be configured before starting to draw */ wl_surface_commit(wl->surface); wl->configured = true; diff --git a/input/common/wayland_common.c b/input/common/wayland_common.c index f17d2fe2ca..8eb59f829b 100644 --- a/input/common/wayland_common.c +++ b/input/common/wayland_common.c @@ -806,6 +806,10 @@ static void wl_registry_handle_global(void *data, struct wl_registry *reg, wl->single_pixel_manager = (struct wp_single_pixel_buffer_manager_v1*) wl_registry_bind( reg, id, &wp_single_pixel_buffer_manager_v1_interface, MIN(version, 1)); + else if (string_is_equal(interface, xdg_toplevel_icon_manager_v1_interface.name) && found++) + wl->xdg_toplevel_icon_manager = (struct xdg_toplevel_icon_manager_v1*) + wl_registry_bind( + reg, id, &xdg_toplevel_icon_manager_v1_interface, MIN(version, 1)); if (found > 1) RARCH_LOG("[Wayland]: Registered interface %s at version %u\n", diff --git a/input/common/wayland_common.h b/input/common/wayland_common.h index 125af85307..9d00619327 100644 --- a/input/common/wayland_common.h +++ b/input/common/wayland_common.h @@ -44,6 +44,7 @@ #include "../../gfx/common/wayland/viewporter.h" #include "../../gfx/common/wayland/xdg-decoration-unstable-v1.h" #include "../../gfx/common/wayland/xdg-shell.h" +#include "../../gfx/common/wayland/xdg-toplevel-icon-v1.h" #define FRACTIONAL_SCALE_V1_DEN 120 #define FRACTIONAL_SCALE_MULT(v, scale_num) \ @@ -159,6 +160,8 @@ typedef struct gfx_ctx_wayland_data struct wp_fractional_scale_v1 *fractional_scale; struct xdg_wm_base *xdg_shell; struct xdg_toplevel *xdg_toplevel; + struct xdg_toplevel_icon_v1 *xdg_toplevel_icon; + struct xdg_toplevel_icon_manager_v1 *xdg_toplevel_icon_manager; struct wl_keyboard *wl_keyboard; struct wl_pointer *wl_pointer; struct zwp_relative_pointer_v1 *wl_relative_pointer;