|
|
@@ -3003,10 +3003,6 @@ bool Wayland_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surfa
|
|
|
return SDL_SetError("wayland: cannot set icon; required 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);
|
|
|
- }
|
|
|
-
|
|
|
int image_count = 0;
|
|
|
SDL_Surface **images = SDL_GetSurfaceImages(icon, &image_count);
|
|
|
if (!images || !image_count) {
|
|
|
@@ -3034,11 +3030,12 @@ bool Wayland_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surfa
|
|
|
size_t pool_size = 0;
|
|
|
for (int i = 0; i < image_count; ++i) {
|
|
|
// Ignore non-square images; if we got here, we know that at least the base image is square.
|
|
|
- if (images[i]->w == images[i]->h) {
|
|
|
- pool_size += images[i]->w * images[i]->h * 4;
|
|
|
- } 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);
|
|
|
+ if (images[i]->w != images[i]->h) {
|
|
|
+ SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "wayland: icon width and height must be equal, got %ix%i for image level %i; icon will be scaled", images[i]->w, images[i]->h, i);
|
|
|
}
|
|
|
+
|
|
|
+ const int size = SDL_max(images[i]->w, images[i]->h);
|
|
|
+ pool_size += size * size * 4;
|
|
|
}
|
|
|
|
|
|
// Sort the images in ascending order by size.
|
|
|
@@ -3046,46 +3043,65 @@ bool Wayland_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surfa
|
|
|
|
|
|
shm_pool = Wayland_AllocSHMPool(pool_size);
|
|
|
if (!shm_pool) {
|
|
|
- SDL_SetError("wayland: failed to allocate SHM pool for the icon");
|
|
|
+ SDL_SetError("wayland: failed to allocate an SHM pool for the icon");
|
|
|
goto failure_cleanup;
|
|
|
}
|
|
|
|
|
|
+ const double base_size = (double)SDL_max(icon->w, icon->h);
|
|
|
for (int i = 0; i < image_count; ++i) {
|
|
|
- if (images[i]->w == images[i]->h) {
|
|
|
- SDL_Surface *surface = images[i];
|
|
|
+ SDL_Surface *surface = images[i];
|
|
|
|
|
|
- // Choose the largest image for each integer scale, ignoring any below the base size.
|
|
|
- const int scale = (int)SDL_floor((double)surface->w / (double)icon->w);
|
|
|
- if (!scale) {
|
|
|
- continue;
|
|
|
- }
|
|
|
+ // Choose the largest image for each integer scale, ignoring any below the base size.
|
|
|
+ const int level_size = SDL_max(surface->w, surface->h);
|
|
|
+ const int scale = (int)SDL_floor((double)level_size / base_size);
|
|
|
+ if (!scale) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- void *buffer_mem;
|
|
|
- struct wl_buffer *buffer = Wayland_AllocBufferFromPool(shm_pool, surface->w, surface->h, &buffer_mem);
|
|
|
- if (!buffer) {
|
|
|
- SDL_SetError("wayland: failed to allocate SHM buffer for the icon");
|
|
|
+ if (surface->format != SDL_PIXELFORMAT_ARGB8888) {
|
|
|
+ surface = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_ARGB8888);
|
|
|
+ if (!surface) {
|
|
|
+ SDL_SetError("wayland: failed to convert the icon image to ARGB8888 format");
|
|
|
goto failure_cleanup;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- wind->icon_buffers[wind->icon_buffer_count++] = buffer;
|
|
|
+ if (surface->w != surface->h) {
|
|
|
+ SDL_Surface *scaled_surface = SDL_ScaleSurface(surface, level_size, level_size, SDL_SCALEMODE_LINEAR);
|
|
|
|
|
|
- if (surface->format != SDL_PIXELFORMAT_ARGB8888) {
|
|
|
- surface = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_ARGB8888);
|
|
|
- if (!surface) {
|
|
|
- SDL_SetError("wayland: unable to convert surface to ARGB8888 format");
|
|
|
- goto failure_cleanup;
|
|
|
- }
|
|
|
+ // Clean up the temporary conversion surface.
|
|
|
+ if (surface != images[i]) {
|
|
|
+ SDL_DestroySurface(surface);
|
|
|
}
|
|
|
+ surface = scaled_surface;
|
|
|
|
|
|
- SDL_PremultiplyAlpha(surface->w, surface->h, surface->format, surface->pixels, surface->pitch,
|
|
|
- SDL_PIXELFORMAT_ARGB8888, buffer_mem, surface->w * 4, true);
|
|
|
-
|
|
|
- xdg_toplevel_icon_v1_add_buffer(wind->xdg_toplevel_icon_v1, buffer, scale);
|
|
|
+ if (!surface) {
|
|
|
+ SDL_SetError("wayland: failed to scale the non-square icon image to the required size");
|
|
|
+ goto failure_cleanup;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // Clean up the temporary conversion surface.
|
|
|
+ void *buffer_mem;
|
|
|
+ struct wl_buffer *buffer = Wayland_AllocBufferFromPool(shm_pool, surface->w, surface->h, &buffer_mem);
|
|
|
+ if (!buffer) {
|
|
|
+ // Clean up the temporary scaled or conversion surface.
|
|
|
if (surface != images[i]) {
|
|
|
SDL_DestroySurface(surface);
|
|
|
}
|
|
|
+ SDL_SetError("wayland: failed to allocate a wl_buffer for the icon");
|
|
|
+ goto failure_cleanup;
|
|
|
+ }
|
|
|
+
|
|
|
+ wind->icon_buffers[wind->icon_buffer_count++] = buffer;
|
|
|
+
|
|
|
+ SDL_PremultiplyAlpha(surface->w, surface->h, surface->format, surface->pixels, surface->pitch,
|
|
|
+ SDL_PIXELFORMAT_ARGB8888, buffer_mem, surface->w * 4, true);
|
|
|
+
|
|
|
+ xdg_toplevel_icon_v1_add_buffer(wind->xdg_toplevel_icon_v1, buffer, scale);
|
|
|
+
|
|
|
+ // Clean up the temporary scaled or conversion surface.
|
|
|
+ if (surface != images[i]) {
|
|
|
+ SDL_DestroySurface(surface);
|
|
|
}
|
|
|
}
|
|
|
|