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.
This commit is contained in:
Window Maker 2026-05-24 14:41:57 +02:00
parent 07022840ac
commit 94054aeec8
1 changed files with 83 additions and 12 deletions

View File

@ -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);
}