wayland: Add support for setting window icons via the xdg-toplevel-icon-v1 protocol

This commit is contained in:
Frank Praznik
2024-03-28 10:26:16 -04:00
parent c57cf716af
commit 5d5a685a80
6 changed files with 288 additions and 6 deletions

View File

@@ -63,6 +63,7 @@
#include "xdg-foreign-unstable-v2-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h"
#include "xdg-shell-client-protocol.h"
#include "xdg-toplevel-icon-v1-client-protocol.h"
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
@@ -549,6 +550,7 @@ static SDL_VideoDevice *Wayland_CreateDevice(bool require_preferred_protocols)
device->SetWindowModalFor = Wayland_SetWindowModalFor;
device->SetWindowOpacity = Wayland_SetWindowOpacity;
device->SetWindowTitle = Wayland_SetWindowTitle;
device->SetWindowIcon = Wayland_SetWindowIcon;
device->GetWindowSizeInPixels = Wayland_GetWindowSizeInPixels;
device->GetDisplayForWindow = Wayland_GetDisplayForWindow;
device->DestroyWindow = Wayland_DestroyWindow;
@@ -1191,6 +1193,8 @@ static void display_handle_global(void *data, struct wl_registry *registry, uint
d->xdg_wm_dialog_v1 = wl_registry_bind(d->registry, id, &xdg_wm_dialog_v1_interface, 1);
} else if (SDL_strcmp(interface, "wp_alpha_modifier_v1") == 0) {
d->wp_alpha_modifier_v1 = wl_registry_bind(d->registry, id, &wp_alpha_modifier_v1_interface, 1);
} else if (SDL_strcmp(interface, "xdg_toplevel_icon_manager_v1") == 0) {
d->xdg_toplevel_icon_manager_v1 = wl_registry_bind(d->registry, id, &xdg_toplevel_icon_manager_v1_interface, 1);
} else if (SDL_strcmp(interface, "kde_output_order_v1") == 0) {
d->kde_output_order = wl_registry_bind(d->registry, id, &kde_output_order_v1_interface, 1);
kde_output_order_v1_add_listener(d->kde_output_order, &kde_output_order_listener, d);
@@ -1460,6 +1464,11 @@ static void Wayland_VideoCleanup(SDL_VideoDevice *_this)
data->wp_alpha_modifier_v1 = NULL;
}
if (data->xdg_toplevel_icon_manager_v1) {
xdg_toplevel_icon_manager_v1_destroy(data->xdg_toplevel_icon_manager_v1);
data->xdg_toplevel_icon_manager_v1 = NULL;
}
if (data->kde_output_order) {
Wayland_FlushOutputOrder(data);
kde_output_order_v1_destroy(data->kde_output_order);

View File

@@ -81,6 +81,7 @@ struct SDL_VideoData
struct zxdg_exporter_v2 *zxdg_exporter_v2;
struct xdg_wm_dialog_v1 *xdg_wm_dialog_v1;
struct wp_alpha_modifier_v1 *wp_alpha_modifier_v1;
struct xdg_toplevel_icon_manager_v1 *xdg_toplevel_icon_manager_v1;
struct kde_output_order_v1 *kde_output_order;
struct frog_color_management_factory_v1 *frog_color_management_factory_v1;
struct zwp_tablet_manager_v2 *tablet_manager;

View File

@@ -42,6 +42,7 @@
#include "xdg-foreign-unstable-v2-client-protocol.h"
#include "xdg-dialog-v1-client-protocol.h"
#include "frog-color-management-v1-client-protocol.h"
#include "xdg-toplevel-icon-v1-client-protocol.h"
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
@@ -1722,6 +1723,12 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
zxdg_exported_v2_add_listener(data->exported, &exported_v2_listener, data);
}
if (c->xdg_toplevel_icon_manager_v1 && data->xdg_toplevel_icon_v1) {
xdg_toplevel_icon_manager_v1_set_icon(_this->internal->xdg_toplevel_icon_manager_v1,
libdecor_frame_get_xdg_toplevel(data->shell_surface.libdecor.frame),
data->xdg_toplevel_icon_v1);
}
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_SURFACE_POINTER, libdecor_frame_get_xdg_surface(data->shell_surface.libdecor.frame));
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, libdecor_frame_get_xdg_toplevel(data->shell_surface.libdecor.frame));
}
@@ -1802,6 +1809,12 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
zxdg_exported_v2_add_listener(data->exported, &exported_v2_listener, data);
}
if (c->xdg_toplevel_icon_manager_v1 && data->xdg_toplevel_icon_v1) {
xdg_toplevel_icon_manager_v1_set_icon(_this->internal->xdg_toplevel_icon_manager_v1,
data->shell_surface.xdg.roleobj.toplevel,
data->xdg_toplevel_icon_v1);
}
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, data->shell_surface.xdg.roleobj.toplevel);
}
}
@@ -2666,6 +2679,51 @@ void Wayland_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window)
}
}
bool Wayland_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *icon)
{
SDL_WindowData *wind = window->internal;
struct xdg_toplevel *toplevel = NULL;
if (!_this->internal->xdg_toplevel_icon_manager_v1) {
return SDL_SetError("wayland: cannot set icon; xdg_toplevel_icon_v1 protocol not supported");
}
if (icon->w != icon->h) {
return SDL_SetError("wayland: icon width and height must be equal, got %ix%i", icon->w, icon->h);
}
if (wind->xdg_toplevel_icon_v1) {
xdg_toplevel_icon_v1_destroy(wind->xdg_toplevel_icon_v1);
wind->xdg_toplevel_icon_v1 = NULL;
}
// TODO: Add high-DPI icon support
Wayland_ReleaseSHMBuffer(&wind->icon);
if (Wayland_AllocSHMBuffer(icon->w, icon->h, &wind->icon) != 0) {
return SDL_SetError("wayland: failed to allocate SHM buffer for the icon");
}
SDL_PremultiplyAlpha(icon->w, icon->h, icon->format, icon->pixels, icon->pitch, SDL_PIXELFORMAT_ARGB8888, wind->icon.shm_data, icon->w * 4, SDL_TRUE);
wind->xdg_toplevel_icon_v1 = xdg_toplevel_icon_manager_v1_create_icon(_this->internal->xdg_toplevel_icon_manager_v1);
xdg_toplevel_icon_v1_add_buffer(wind->xdg_toplevel_icon_v1, wind->icon.wl_buffer, 1);
#ifdef HAVE_LIBDECOR_H
if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR && wind->shell_surface.libdecor.frame) {
toplevel = libdecor_frame_get_xdg_toplevel(wind->shell_surface.libdecor.frame);
} else
#endif
if (wind->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL && wind->shell_surface.xdg.roleobj.toplevel) {
toplevel = wind->shell_surface.xdg.roleobj.toplevel;
}
if (toplevel) {
xdg_toplevel_icon_manager_v1_set_icon(_this->internal->xdg_toplevel_icon_manager_v1, toplevel, wind->xdg_toplevel_icon_v1);
}
return true;
}
bool Wayland_SyncWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_WindowData *wind = window->internal;
@@ -2803,6 +2861,12 @@ void Wayland_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
Wayland_RemoveWindowDataFromExternalList(wind);
}
if (wind->xdg_toplevel_icon_v1) {
xdg_toplevel_icon_v1_destroy(wind->xdg_toplevel_icon_v1);
}
Wayland_ReleaseSHMBuffer(&wind->icon);
SDL_free(wind);
WAYLAND_wl_display_flush(data->display);
}

View File

@@ -28,6 +28,7 @@
#include "../../events/SDL_touch_c.h"
#include "SDL_waylandvideo.h"
#include "SDL_waylandshmbuffer.h"
struct SDL_WaylandInput;
@@ -98,6 +99,7 @@ struct SDL_WindowData
struct zxdg_exported_v2 *exported;
struct xdg_dialog_v1 *xdg_dialog_v1;
struct wp_alpha_modifier_surface_v1 *wp_alpha_modifier_surface_v1;
struct xdg_toplevel_icon_v1 *xdg_toplevel_icon_v1;
struct frog_color_managed_surface *frog_color_managed_surface;
SDL_AtomicInt swap_interval_ready;
@@ -110,6 +112,8 @@ struct SDL_WindowData
char *app_id;
float windowed_scale_factor;
struct Wayland_SHMBuffer icon;
struct
{
float x;
@@ -202,6 +206,7 @@ extern void Wayland_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
extern void Wayland_ShowWindowSystemMenu(SDL_Window *window, int x, int y);
extern void Wayland_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern bool Wayland_SuspendScreenSaver(SDL_VideoDevice *_this);
extern bool Wayland_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *icon);
extern bool Wayland_SetWindowHitTest(SDL_Window *window, bool enabled);
extern bool Wayland_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);