wayland: Add support for high-DPI icons
This commit is contained in:
@@ -2865,28 +2865,56 @@ bool Wayland_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surfa
|
|||||||
struct xdg_toplevel *toplevel = NULL;
|
struct xdg_toplevel *toplevel = NULL;
|
||||||
|
|
||||||
if (!_this->internal->xdg_toplevel_icon_manager_v1) {
|
if (!_this->internal->xdg_toplevel_icon_manager_v1) {
|
||||||
return SDL_SetError("wayland: cannot set icon; xdg_toplevel_icon_v1 protocol not supported");
|
return SDL_SetError("wayland: cannot set icon; required xdg_toplevel_icon_v1 protocol not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (icon->w != icon->h) {
|
if (icon->w != icon->h) {
|
||||||
return SDL_SetError("wayland: icon width and height must be equal, got %ix%i", icon->w, icon->h);
|
return SDL_SetError("wayland: icon width and height must be equal, got %ix%i", icon->w, icon->h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int image_count = 0;
|
||||||
|
SDL_Surface **images = SDL_GetSurfaceImages(icon, &image_count);
|
||||||
|
if (!images || !image_count) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release the old icon resources.
|
||||||
if (wind->xdg_toplevel_icon_v1) {
|
if (wind->xdg_toplevel_icon_v1) {
|
||||||
xdg_toplevel_icon_v1_destroy(wind->xdg_toplevel_icon_v1);
|
xdg_toplevel_icon_v1_destroy(wind->xdg_toplevel_icon_v1);
|
||||||
wind->xdg_toplevel_icon_v1 = NULL;
|
wind->xdg_toplevel_icon_v1 = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add high-DPI icon support
|
for (int i = 0; i < wind->icon_buffer_count; ++i) {
|
||||||
Wayland_ReleaseSHMBuffer(&wind->icon);
|
Wayland_ReleaseSHMBuffer(&wind->icon_buffers[i]);
|
||||||
if (!Wayland_AllocSHMBuffer(icon->w, icon->h, &wind->icon)) {
|
|
||||||
return SDL_SetError("wayland: failed to allocate SHM buffer for the icon");
|
|
||||||
}
|
}
|
||||||
|
SDL_free(wind->icon_buffers);
|
||||||
SDL_PremultiplyAlpha(icon->w, icon->h, icon->format, icon->pixels, icon->pitch, SDL_PIXELFORMAT_ARGB8888, wind->icon.shm_data, icon->w * 4, true);
|
wind->icon_buffer_count = 0;
|
||||||
|
|
||||||
wind->xdg_toplevel_icon_v1 = xdg_toplevel_icon_manager_v1_create_icon(_this->internal->xdg_toplevel_icon_manager_v1);
|
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);
|
wind->icon_buffers = SDL_calloc(image_count, sizeof(struct Wayland_SHMBuffer));
|
||||||
|
if (!wind->icon_buffers) {
|
||||||
|
goto failure_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < image_count; ++i) {
|
||||||
|
if (images[i]->w == images[i]->h) {
|
||||||
|
struct Wayland_SHMBuffer *buffer = &wind->icon_buffers[wind->icon_buffer_count];
|
||||||
|
|
||||||
|
if (!Wayland_AllocSHMBuffer(images[i]->w, images[i]->h, buffer)) {
|
||||||
|
SDL_SetError("wayland: failed to allocate SHM buffer for the icon");
|
||||||
|
goto failure_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_PremultiplyAlpha(images[i]->w, images[i]->h, images[i]->format, images[i]->pixels, images[i]->pitch, SDL_PIXELFORMAT_ARGB8888, buffer->shm_data, images[i]->w * 4, true);
|
||||||
|
const int scale = (int)SDL_ceil((double)images[i]->w / (double)icon->w);
|
||||||
|
xdg_toplevel_icon_v1_add_buffer(wind->xdg_toplevel_icon_v1, buffer->wl_buffer, scale);
|
||||||
|
wind->icon_buffer_count++;
|
||||||
|
} else {
|
||||||
|
SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "wayland: icon width and height must be equal, got %ix%i for image level %i; skipping", images[i]->w, images[i]->h, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_free(images);
|
||||||
|
|
||||||
#ifdef HAVE_LIBDECOR_H
|
#ifdef HAVE_LIBDECOR_H
|
||||||
if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR && wind->shell_surface.libdecor.frame) {
|
if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR && wind->shell_surface.libdecor.frame) {
|
||||||
@@ -2902,6 +2930,22 @@ bool Wayland_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surfa
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
failure_cleanup:
|
||||||
|
|
||||||
|
if (wind->xdg_toplevel_icon_v1) {
|
||||||
|
xdg_toplevel_icon_v1_destroy(wind->xdg_toplevel_icon_v1);
|
||||||
|
wind->xdg_toplevel_icon_v1 = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < wind->icon_buffer_count; ++i) {
|
||||||
|
Wayland_ReleaseSHMBuffer(&wind->icon_buffers[i]);
|
||||||
|
}
|
||||||
|
SDL_free(wind->icon_buffers);
|
||||||
|
wind->icon_buffers = NULL;
|
||||||
|
wind->icon_buffer_count = 0;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *Wayland_GetWindowICCProfile(SDL_VideoDevice *_this, SDL_Window *window, size_t *size)
|
void *Wayland_GetWindowICCProfile(SDL_VideoDevice *_this, SDL_Window *window, size_t *size)
|
||||||
@@ -3070,7 +3114,11 @@ void Wayland_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
|||||||
xdg_toplevel_icon_v1_destroy(wind->xdg_toplevel_icon_v1);
|
xdg_toplevel_icon_v1_destroy(wind->xdg_toplevel_icon_v1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Wayland_ReleaseSHMBuffer(&wind->icon);
|
for (int i = 0; i < wind->icon_buffer_count; ++i) {
|
||||||
|
Wayland_ReleaseSHMBuffer(&wind->icon_buffers[i]);
|
||||||
|
}
|
||||||
|
SDL_free(wind->icon_buffers);
|
||||||
|
wind->icon_buffer_count = 0;
|
||||||
|
|
||||||
SDL_free(wind);
|
SDL_free(wind);
|
||||||
WAYLAND_wl_display_flush(data->display);
|
WAYLAND_wl_display_flush(data->display);
|
||||||
|
|||||||
@@ -128,7 +128,8 @@ struct SDL_WindowData
|
|||||||
char *app_id;
|
char *app_id;
|
||||||
double scale_factor;
|
double scale_factor;
|
||||||
|
|
||||||
struct Wayland_SHMBuffer icon;
|
struct Wayland_SHMBuffer *icon_buffers;
|
||||||
|
int icon_buffer_count;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user