From 94054aeec89f244d53b844f94edda9a010f00264 Mon Sep 17 00:00:00 2001 From: Window Maker Date: Sun, 24 May 2026 14:41:57 +0200 Subject: [PATCH] wl_backend: implement all background image fill modes - tpixmap (Tiled): repeat image across screen - spixmap (Scaled): stretch to exact screen dimensions - cpixmap (Centered): place at center with background color fill - mpixmap (Maximized): scale preserving aspect ratio, letterbox - fpixmap (Filled): scale preserving aspect ratio, crop to fill All modes now use RSmoothScaleImage for quality, respect the background color (3rd texture argument) for uncovered areas, and handle transparent images via RCombineImageWithColor. --- src/backend/wayland/wl_backend.c | 95 ++++++++++++++++++++++++++++---- 1 file changed, 83 insertions(+), 12 deletions(-) diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index 43d34aa..5982a7b 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -7775,28 +7775,99 @@ static void wl_set_desktop_background(WScreen *scr, const char *texture_desc) strcasecmp(type, "spixmap") == 0 || strcasecmp(type, "mpixmap") == 0 || strcasecmp(type, "cpixmap") == 0 || + strcasecmp(type, "fpixmap") == 0 || strcasecmp(type, "tpixmap") == 0) && WMGetPropListItemCount(texpl) >= 2) { const char *path = WMGetFromPLString(WMGetFromPLArray(texpl, 1)); + /* Background color (3rd argument, optional) */ + RColor bgcolor = {0, 0, 0, 255}; + if (WMGetPropListItemCount(texpl) >= 3) { + const char *cstr = WMGetFromPLString(WMGetFromPLArray(texpl, 2)); + if (cstr) parse_color_to_rcolor(scr, cstr, &bgcolor); + } if (path) { RImage *img = RLoadImage(rc, path, 0); if (img) { - if (type[0] == 's' || type[0] == 'S') { - /* Scale to fill */ - bg = RScaleImage(img, width, height); - } else if (type[0] == 'c' || type[0] == 'C') { - /* Center */ + /* Combine with background color if image has alpha */ + if (img->format == RRGBAFormat) + RCombineImageWithColor(img, &bgcolor); + + char mode = (type[0] >= 'a' && type[0] <= 'z') ? type[0] - 32 : type[0]; + if (mode == 'S') { + /* Scaled: stretch to exact screen size */ + bg = RSmoothScaleImage(img, width, height); + } else if (mode == 'F') { + /* Filled: scale preserving aspect, fill screen (crop) */ + int w, h; + if (img->width * height > img->height * width) { + w = (height * img->width) / img->height; + h = height; + } else { + w = width; + h = (width * img->height) / img->width; + } + RImage *scaled = RSmoothScaleImage(img, w, h); + if (scaled) { + bg = RCreateImage(width, height, 0); + if (bg) { + RClearImage(bg, &bgcolor); + int sx = (scaled->width - width) / 2; + int sy = (scaled->height - height) / 2; + RCopyArea(bg, scaled, sx, sy, width, height, 0, 0); + } + RReleaseImage(scaled); + } + } else if (mode == 'M') { + /* Maximized: scale preserving aspect, fit inside (letterbox) */ + int w, h; + if (img->width * height > img->height * width) { + w = width; + h = (width * img->height) / img->width; + } else { + w = (height * img->width) / img->height; + h = height; + } + RImage *scaled = RSmoothScaleImage(img, w, h); + if (scaled) { + bg = RCreateImage(width, height, 0); + if (bg) { + RClearImage(bg, &bgcolor); + int dx = (width - scaled->width) / 2; + int dy = (height - scaled->height) / 2; + RCombineArea(bg, scaled, 0, 0, scaled->width, scaled->height, dx, dy); + } + RReleaseImage(scaled); + } + } else if (mode == 'C') { + /* Centered: place at center, no scaling */ bg = RCreateImage(width, height, 0); if (bg) { - RColor black = {0, 0, 0, 255}; - RClearImage(bg, &black); - int x = (width - img->width) / 2; - int y = (height - img->height) / 2; - RCombineArea(bg, img, 0, 0, img->width, img->height, x, y); + RClearImage(bg, &bgcolor); + int dx = (width - img->width) / 2; + int dy = (height - img->height) / 2; + /* Handle images larger than screen */ + int sx = 0, sy = 0, cw = img->width, ch = img->height; + if (dx < 0) { sx = -dx; dx = 0; cw = width; } + if (dy < 0) { sy = -dy; dy = 0; ch = height; } + RCombineArea(bg, img, sx, sy, cw, ch, dx, dy); + } + } else if (mode == 'T') { + /* Tiled: repeat the image */ + bg = RCreateImage(width, height, 0); + if (bg) { + for (int ty = 0; ty < height; ty += img->height) { + for (int tx = 0; tx < width; tx += img->width) { + int cw = img->width; + int ch = img->height; + if (tx + cw > width) cw = width - tx; + if (ty + ch > height) ch = height - ty; + RCombineArea(bg, img, 0, 0, cw, ch, tx, ty); + } + } } } else { - /* Default: scale to fill */ - bg = RScaleImage(img, width, height); + /* Default (plain "pixmap"): scale to fill */ + bg = RSmoothScaleImage(img, width, height); } RReleaseImage(img); }