diff -urN gtk-3.24.52-orig/gdk/wayland/gdkdisplay-wayland.c gtk-3.24.52/gdk/wayland/gdkdisplay-wayland.c --- gtk-3.24.52-orig/gdk/wayland/gdkdisplay-wayland.c 2026-03-23 11:24:49 +0900 +++ gtk-3.24.52/gdk/wayland/gdkdisplay-wayland.c 2026-09-03 00:32:26 +0900 @@ -559,6 +559,12 @@ wl_registry_bind (display_wayland->wl_registry, id, &wp_cursor_shape_manager_v1_interface, 1); } + else if (strcmp (interface, xdg_toplevel_icon_manager_v1_interface.name) == 0) + { + display_wayland->xdg_toplevel_icon_manager = + wl_registry_bind (display_wayland->wl_registry, id, + &xdg_toplevel_icon_manager_v1_interface, 1); + } g_hash_table_insert (display_wayland->known_globals, GUINT_TO_POINTER (id), g_strdup (interface)); diff -urN gtk-3.24.52-orig/gdk/wayland/gdkdisplay-wayland.h gtk-3.24.52/gdk/wayland/gdkdisplay-wayland.h --- gtk-3.24.52-orig/gdk/wayland/gdkdisplay-wayland.h 2026-03-23 11:24:49 +0900 +++ gtk-3.24.52/gdk/wayland/gdkdisplay-wayland.h 2026-09-02 21:49:03 +0900 @@ -41,6 +41,7 @@ #include #endif #include +#include #include #include @@ -110,6 +111,7 @@ struct xdg_activation_v1 *xdg_activation; #endif struct wp_cursor_shape_manager_v1 *cursor_shape; + struct xdg_toplevel_icon_manager_v1 *xdg_toplevel_icon_manager; GList *async_roundtrips; diff -urN gtk-3.24.52-orig/gdk/wayland/gdkwindow-wayland.c gtk-3.24.52/gdk/wayland/gdkwindow-wayland.c --- gtk-3.24.52-orig/gdk/wayland/gdkwindow-wayland.c 2026-03-23 11:24:49 +0900 +++ gtk-3.24.52/gdk/wayland/gdkwindow-wayland.c 2026-09-03 03:05:16 +0900 @@ -124,6 +124,8 @@ struct xdg_toplevel *xdg_toplevel; struct xdg_popup *xdg_popup; + struct xdg_toplevel_icon_v1 *xdg_toplevel_icon; + /* Legacy xdg-shell unstable v6 fallback support */ struct zxdg_surface_v6 *zxdg_surface_v6; struct zxdg_toplevel_v6 *zxdg_toplevel_v6; @@ -2038,6 +2040,11 @@ xdg_toplevel_add_listener (impl->display_server.xdg_toplevel, &xdg_toplevel_listener, window); + + if (impl->display_server.xdg_toplevel_icon) + xdg_toplevel_icon_manager_v1_set_icon (display_wayland->xdg_toplevel_icon_manager, + impl->display_server.xdg_toplevel, + impl->display_server.xdg_toplevel_icon); } static void @@ -4419,6 +4426,81 @@ gdk_wayland_window_set_icon_list (GdkWindow *window, GList *pixbufs) { + GdkWindowImplWayland *impl; + GdkWaylandDisplay *display_wayland; + struct xdg_toplevel_icon_manager_v1 *manager; + struct xdg_toplevel_icon_v1 *icon; + GList *l; + + if (GDK_WINDOW_DESTROYED (window) || + !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window)) + return; + + impl = GDK_WINDOW_IMPL_WAYLAND (window->impl); + display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window)); + + manager = display_wayland->xdg_toplevel_icon_manager; + if (!manager) + return; + + // FIXME(achurch): this is a trivial implementation that leaks all objects + + icon = xdg_toplevel_icon_manager_v1_create_icon (manager); + + l = pixbufs; + while (l) + { + GdkPixbuf *pixbuf; + cairo_surface_t *surface; + struct wl_buffer *buffer; + gint width, height, stride_in, stride_out, n_channels; + guchar *pixels_in; + guint32 *pixels_out; + gint x, y; + + pixbuf = l->data; + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + stride_in = gdk_pixbuf_get_rowstride (pixbuf); + n_channels = gdk_pixbuf_get_n_channels (pixbuf); + pixels_in = gdk_pixbuf_get_pixels (pixbuf); + + surface = _gdk_wayland_display_create_shm_surface (display_wayland, + width, + height, + 1); + stride_out = cairo_image_surface_get_stride (surface) / 4; + pixels_out = (guint32 *) cairo_image_surface_get_data (surface); + + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + guchar r, g, b, a; + + r = pixels_in[y*stride_in + x*n_channels + 0]; + g = pixels_in[y*stride_in + x*n_channels + 1]; + b = pixels_in[y*stride_in + x*n_channels + 2]; + if (n_channels >= 4) + a = pixels_in[y*stride_in + x*n_channels + 3]; + else + a = 255; + + pixels_out[y*stride_out + x] = a << 24 | r << 16 | g << 8 | b; + } + } + + buffer = _gdk_wayland_shm_surface_get_wl_buffer (surface); + xdg_toplevel_icon_v1_add_buffer (icon, buffer, 1); + + l = l->next; + } + + impl->display_server.xdg_toplevel_icon = icon; + if (impl->display_server.xdg_toplevel) + xdg_toplevel_icon_manager_v1_set_icon (manager, + impl->display_server.xdg_toplevel, + icon); } static void diff -urN gtk-3.24.52-orig/gdk/wayland/meson.build gtk-3.24.52/gdk/wayland/meson.build --- gtk-3.24.52-orig/gdk/wayland/meson.build 2026-03-23 11:24:49 +0900 +++ gtk-3.24.52/gdk/wayland/meson.build 2026-09-02 21:46:23 +0900 @@ -60,6 +60,7 @@ ['xdg-output', 'unstable', 'v1', ], ['primary-selection', 'unstable', 'v1', ], ['cursor-shape-v1', 'private', ], + ['xdg-toplevel-icon', 'staging', 'v1', ], ] if wlprotocolsdep.version().version_compare('>=1.21') proto_sources += [['xdg-activation', 'staging', 'v1', ]]