From 9178f8a90323eb8abfce9f30a65baa0cfde035e4 Mon Sep 17 00:00:00 2001 From: lkn Date: Sat, 6 Jun 2026 09:40:20 +0200 Subject: [PATCH] step 2: extract wl_background.c from wl_backend.c (desktop background rendering, 304 lines) --- src/Makefile.am | 1 + src/backend/wayland/wl_backend.c | 304 -------------------------- src/backend/wayland/wl_background.c | 326 ++++++++++++++++++++++++++++ 3 files changed, 327 insertions(+), 304 deletions(-) create mode 100644 src/backend/wayland/wl_background.c diff --git a/src/Makefile.am b/src/Makefile.am index 9bf746f..1044424 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -165,6 +165,7 @@ if USE_WAYLAND_BACKEND wmaker_SOURCES += \ backend/wayland/wl_backend.h \ backend/wayland/wl_backend.c \ + backend/wayland/wl_background.c \ backend/wayland/wl_context.c \ backend/wayland/wl_event.c \ backend/wayland/wl_stacking.c \ diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index eb699ab..909a8d7 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -1799,310 +1799,6 @@ wl_screen_load_tech_font(WScreen *scr) RImage *wl_screen_capture_window(WScreen *scr, WWindow *wwin) { (void)scr; (void)wwin; return NULL; } void wl_refresh_desktop(WScreen *scr) { (void)scr; } -/* --- Desktop background rendering --- */ - -/* Simple wlr_buffer implementation backed by a pixman_image_t */ -struct wl_bg_buffer { - struct wlr_buffer base; - pixman_image_t *image; -}; - -static void bg_buffer_destroy(struct wlr_buffer *wlr_buf) -{ - struct wl_bg_buffer *buf = wl_container_of(wlr_buf, buf, base); - if (buf->image) - pixman_image_unref(buf->image); - free(buf); -} - -static bool bg_buffer_begin_data_ptr_access(struct wlr_buffer *wlr_buf, - uint32_t flags, void **data, uint32_t *format, size_t *stride) -{ - (void)flags; - struct wl_bg_buffer *buf = wl_container_of(wlr_buf, buf, base); - *data = pixman_image_get_data(buf->image); - *format = DRM_FORMAT_ARGB8888; - *stride = pixman_image_get_stride(buf->image); - return true; -} - -static void bg_buffer_end_data_ptr_access(struct wlr_buffer *wlr_buf) -{ - (void)wlr_buf; -} - -static const struct wlr_buffer_impl bg_buffer_impl = { - .destroy = bg_buffer_destroy, - .begin_data_ptr_access = bg_buffer_begin_data_ptr_access, - .end_data_ptr_access = bg_buffer_end_data_ptr_access, -}; - -static int parse_color_to_rcolor(WScreen *scr, const char *name, RColor *out) -{ - WMColorRGB wmc; - if (!name || !wGetColor(scr, name, &wmc)) - return 0; - out->red = wmc.red >> 8; - out->green = wmc.green >> 8; - out->blue = wmc.blue >> 8; - out->alpha = 255; - return 1; -} - - void wl_set_desktop_background(WScreen *scr, const char *texture_desc) -{ - if (!scr || !texture_desc) - return; - if (!wl_state.output) { - /* Output not ready yet — cache the background for later */ - wfree(wl_state.pending_background); - wl_state.pending_background = wstrdup(texture_desc); - return; - } - - - int width = wl_state.output->width; - int height = wl_state.output->height; - - /* Parse the texture proplist */ - WMPropList *texpl = WMCreatePropListFromDescription(texture_desc); - if (!texpl) { - return; - } - - /* Render the texture to an RImage using wrlib */ - RContext *rc = scr->rcontext; - RImage *bg = NULL; - - if (WMIsPLArray(texpl) && WMGetPropListItemCount(texpl) > 0) { - WMPropList *type_pl = WMGetFromPLArray(texpl, 0); - const char *type = type_pl ? WMGetFromPLString(type_pl) : ""; - - if (strcasecmp(type, "solid") == 0 && WMGetPropListItemCount(texpl) >= 2) { - const char *colorstr = WMGetFromPLString(WMGetFromPLArray(texpl, 1)); - RColor color = {0x50, 0x50, 0x75, 0xFF}; - if (colorstr) - parse_color_to_rcolor(scr, colorstr, &color); - /* For solid colors, just update the scene rect directly */ - if (wl_state.bg_rect) { - float c[4] = { color.red/255.0f, color.green/255.0f, color.blue/255.0f, 1.0f }; - wlr_scene_rect_set_color(wl_state.bg_rect, c); - wlr_scene_node_set_enabled(&wl_state.bg_rect->node, true); - if (wl_state.bg_image) - wlr_scene_node_set_enabled(&wl_state.bg_image->node, false); - } - if (wl_state.output) - wlr_output_schedule_frame(wl_state.output); - WMReleasePropList(texpl); - return; - } else if ((strcasecmp(type, "vgradient") == 0 || - strcasecmp(type, "hgradient") == 0 || - strcasecmp(type, "dgradient") == 0) && - WMGetPropListItemCount(texpl) >= 3) { - const char *c1str = WMGetFromPLString(WMGetFromPLArray(texpl, 1)); - const char *c2str = WMGetFromPLString(WMGetFromPLArray(texpl, 2)); - RColor color1 = {0, 0, 0, 255}, color2 = {0, 0, 0, 255}; - if (c1str) parse_color_to_rcolor(scr, c1str, &color1); - if (c2str) parse_color_to_rcolor(scr, c2str, &color2); - int style = (type[0] == 'v' || type[0] == 'V') ? RVerticalGradient : - (type[0] == 'h' || type[0] == 'H') ? RHorizontalGradient : - RDiagonalGradient; - bg = RRenderGradient(width, height, &color1, &color2, style); - } else if ((strcasecmp(type, "mvgradient") == 0 || - strcasecmp(type, "mhgradient") == 0 || - strcasecmp(type, "mdgradient") == 0) && - WMGetPropListItemCount(texpl) >= 3) { - int ncolors = WMGetPropListItemCount(texpl) - 1; - RColor **colors = wmalloc((ncolors + 1) * sizeof(RColor *)); - RColor *cbuf = wmalloc(ncolors * sizeof(RColor)); - int ci; - for (ci = 0; ci < ncolors; ci++) { - const char *cs = WMGetFromPLString(WMGetFromPLArray(texpl, ci + 1)); - cbuf[ci] = (RColor){0, 0, 0, 255}; - if (cs) parse_color_to_rcolor(scr, cs, &cbuf[ci]); - colors[ci] = &cbuf[ci]; - } - colors[ncolors] = NULL; - int style = (type[1] == 'v' || type[1] == 'V') ? RVerticalGradient : - (type[1] == 'h' || type[1] == 'H') ? RHorizontalGradient : - RDiagonalGradient; - bg = RRenderMultiGradient(width, height, colors, style); - wfree(cbuf); - wfree(colors); - } else if ((strcasecmp(type, "pixmap") == 0 || - 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) { - /* Try the path as-is first, then search pixmap_path */ - RImage *img = RLoadImage(rc, path, 0); - if (!img && path[0] != '/') { - /* Relative path — search pixmap_path */ - char *search_paths[] = { wPreferences.pixmap_path, PKGDATADIR "/Backgrounds", NULL }; - for (int _pi = 0; search_paths[_pi]; _pi++) { - char _full[PATH_MAX]; - snprintf(_full, sizeof(_full), "%s/%s", search_paths[_pi], path); - img = RLoadImage(rc, _full, 0); - if (img) break; - } - } - if (!img) { - } else { - - /* 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) { - 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 (plain "pixmap"): scale to fill */ - bg = RSmoothScaleImage(img, width, height); - } - RReleaseImage(img); - } - } - } - } - - WMReleasePropList(texpl); - - if (!bg) { - return; - } - - - /* Convert RImage to pixman_image and set as scene buffer */ - struct wl_bg_buffer *buf = calloc(1, sizeof(*buf)); - if (!buf) { RReleaseImage(bg); return; } - - buf->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, width, height, NULL, width * 4); - if (!buf->image) { free(buf); RReleaseImage(bg); return; } - - /* Copy RImage (RGBA or RGB) into ARGB32 pixman buffer */ - uint32_t *dst = (uint32_t *)pixman_image_get_data(buf->image); - unsigned char *src = bg->data; - int npixels = width * height; - if (bg->format == RRGBAFormat) { - for (int i = 0; i < npixels; i++) { - dst[i] = ((uint32_t)src[3] << 24) | ((uint32_t)src[0] << 16) | - ((uint32_t)src[1] << 8) | (uint32_t)src[2]; - src += 4; - } - } else { - for (int i = 0; i < npixels; i++) { - dst[i] = 0xFF000000 | ((uint32_t)src[0] << 16) | - ((uint32_t)src[1] << 8) | (uint32_t)src[2]; - src += 3; - } - } - RReleaseImage(bg); - - wlr_buffer_init(&buf->base, &bg_buffer_impl, width, height); - - /* Hide the solid-color rect */ - if (wl_state.bg_rect) - wlr_scene_node_set_enabled(&wl_state.bg_rect->node, false); - - /* Replace or create the background scene buffer */ - if (wl_state.bg_image) { - wlr_scene_buffer_set_buffer(wl_state.bg_image, &buf->base); - wlr_scene_node_set_enabled(&wl_state.bg_image->node, true); - } else { - wl_state.bg_image = wlr_scene_buffer_create( - wl_state.level_trees[WL_LAYER_BACKGROUND], &buf->base); - } - - /* Release old buffer, keep new one */ - if (wl_state.bg_wlr_buf) - wlr_buffer_drop(wl_state.bg_wlr_buf); - wl_state.bg_wlr_buf = &buf->base; - - /* Schedule a frame to display the new background immediately */ - if (wl_state.output) - wlr_output_schedule_frame(wl_state.output); -} void wl_monitors_query(WScreen *scr, WHeadGeometry **heads_out, int *count_out) diff --git a/src/backend/wayland/wl_background.c b/src/backend/wayland/wl_background.c new file mode 100644 index 0000000..26bc1dd --- /dev/null +++ b/src/backend/wayland/wl_background.c @@ -0,0 +1,326 @@ +/* + * wl_background.c -- Desktop background rendering (wlr_buffer + RImage backend) + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../screen.h" +#include "../../resources.h" +#include "wl_types.h" + +/* --- Desktop background rendering --- */ + +/* Simple wlr_buffer implementation backed by a pixman_image_t */ +struct wl_bg_buffer { + struct wlr_buffer base; + pixman_image_t *image; +}; + +static void bg_buffer_destroy(struct wlr_buffer *wlr_buf) +{ + struct wl_bg_buffer *buf = wl_container_of(wlr_buf, buf, base); + if (buf->image) + pixman_image_unref(buf->image); + free(buf); +} + +static bool bg_buffer_begin_data_ptr_access(struct wlr_buffer *wlr_buf, + uint32_t flags, void **data, uint32_t *format, size_t *stride) +{ + (void)flags; + struct wl_bg_buffer *buf = wl_container_of(wlr_buf, buf, base); + *data = pixman_image_get_data(buf->image); + *format = DRM_FORMAT_ARGB8888; + *stride = pixman_image_get_stride(buf->image); + return true; +} + +static void bg_buffer_end_data_ptr_access(struct wlr_buffer *wlr_buf) +{ + (void)wlr_buf; +} + +static const struct wlr_buffer_impl bg_buffer_impl = { + .destroy = bg_buffer_destroy, + .begin_data_ptr_access = bg_buffer_begin_data_ptr_access, + .end_data_ptr_access = bg_buffer_end_data_ptr_access, +}; + +static int parse_color_to_rcolor(WScreen *scr, const char *name, RColor *out) +{ + WMColorRGB wmc; + if (!name || !wGetColor(scr, name, &wmc)) + return 0; + out->red = wmc.red >> 8; + out->green = wmc.green >> 8; + out->blue = wmc.blue >> 8; + out->alpha = 255; + return 1; +} + + void wl_set_desktop_background(WScreen *scr, const char *texture_desc) +{ + if (!scr || !texture_desc) + return; + if (!wl_state.output) { + /* Output not ready yet — cache the background for later */ + wfree(wl_state.pending_background); + wl_state.pending_background = wstrdup(texture_desc); + return; + } + + + int width = wl_state.output->width; + int height = wl_state.output->height; + + /* Parse the texture proplist */ + WMPropList *texpl = WMCreatePropListFromDescription(texture_desc); + if (!texpl) { + return; + } + + /* Render the texture to an RImage using wrlib */ + RContext *rc = scr->rcontext; + RImage *bg = NULL; + + if (WMIsPLArray(texpl) && WMGetPropListItemCount(texpl) > 0) { + WMPropList *type_pl = WMGetFromPLArray(texpl, 0); + const char *type = type_pl ? WMGetFromPLString(type_pl) : ""; + + if (strcasecmp(type, "solid") == 0 && WMGetPropListItemCount(texpl) >= 2) { + const char *colorstr = WMGetFromPLString(WMGetFromPLArray(texpl, 1)); + RColor color = {0x50, 0x50, 0x75, 0xFF}; + if (colorstr) + parse_color_to_rcolor(scr, colorstr, &color); + /* For solid colors, just update the scene rect directly */ + if (wl_state.bg_rect) { + float c[4] = { color.red/255.0f, color.green/255.0f, color.blue/255.0f, 1.0f }; + wlr_scene_rect_set_color(wl_state.bg_rect, c); + wlr_scene_node_set_enabled(&wl_state.bg_rect->node, true); + if (wl_state.bg_image) + wlr_scene_node_set_enabled(&wl_state.bg_image->node, false); + } + if (wl_state.output) + wlr_output_schedule_frame(wl_state.output); + WMReleasePropList(texpl); + return; + } else if ((strcasecmp(type, "vgradient") == 0 || + strcasecmp(type, "hgradient") == 0 || + strcasecmp(type, "dgradient") == 0) && + WMGetPropListItemCount(texpl) >= 3) { + const char *c1str = WMGetFromPLString(WMGetFromPLArray(texpl, 1)); + const char *c2str = WMGetFromPLString(WMGetFromPLArray(texpl, 2)); + RColor color1 = {0, 0, 0, 255}, color2 = {0, 0, 0, 255}; + if (c1str) parse_color_to_rcolor(scr, c1str, &color1); + if (c2str) parse_color_to_rcolor(scr, c2str, &color2); + int style = (type[0] == 'v' || type[0] == 'V') ? RVerticalGradient : + (type[0] == 'h' || type[0] == 'H') ? RHorizontalGradient : + RDiagonalGradient; + bg = RRenderGradient(width, height, &color1, &color2, style); + } else if ((strcasecmp(type, "mvgradient") == 0 || + strcasecmp(type, "mhgradient") == 0 || + strcasecmp(type, "mdgradient") == 0) && + WMGetPropListItemCount(texpl) >= 3) { + int ncolors = WMGetPropListItemCount(texpl) - 1; + RColor **colors = wmalloc((ncolors + 1) * sizeof(RColor *)); + RColor *cbuf = wmalloc(ncolors * sizeof(RColor)); + int ci; + for (ci = 0; ci < ncolors; ci++) { + const char *cs = WMGetFromPLString(WMGetFromPLArray(texpl, ci + 1)); + cbuf[ci] = (RColor){0, 0, 0, 255}; + if (cs) parse_color_to_rcolor(scr, cs, &cbuf[ci]); + colors[ci] = &cbuf[ci]; + } + colors[ncolors] = NULL; + int style = (type[1] == 'v' || type[1] == 'V') ? RVerticalGradient : + (type[1] == 'h' || type[1] == 'H') ? RHorizontalGradient : + RDiagonalGradient; + bg = RRenderMultiGradient(width, height, colors, style); + wfree(cbuf); + wfree(colors); + } else if ((strcasecmp(type, "pixmap") == 0 || + 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) { + /* Try the path as-is first, then search pixmap_path */ + RImage *img = RLoadImage(rc, path, 0); + if (!img && path[0] != '/') { + /* Relative path — search pixmap_path */ + char *search_paths[] = { wPreferences.pixmap_path, PKGDATADIR "/Backgrounds", NULL }; + for (int _pi = 0; search_paths[_pi]; _pi++) { + char _full[PATH_MAX]; + snprintf(_full, sizeof(_full), "%s/%s", search_paths[_pi], path); + img = RLoadImage(rc, _full, 0); + if (img) break; + } + } + if (!img) { + } else { + + /* 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) { + 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 (plain "pixmap"): scale to fill */ + bg = RSmoothScaleImage(img, width, height); + } + RReleaseImage(img); + } + } + } + } + + WMReleasePropList(texpl); + + if (!bg) { + return; + } + + + /* Convert RImage to pixman_image and set as scene buffer */ + struct wl_bg_buffer *buf = calloc(1, sizeof(*buf)); + if (!buf) { RReleaseImage(bg); return; } + + buf->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, width, height, NULL, width * 4); + if (!buf->image) { free(buf); RReleaseImage(bg); return; } + + /* Copy RImage (RGBA or RGB) into ARGB32 pixman buffer */ + uint32_t *dst = (uint32_t *)pixman_image_get_data(buf->image); + unsigned char *src = bg->data; + int npixels = width * height; + if (bg->format == RRGBAFormat) { + for (int i = 0; i < npixels; i++) { + dst[i] = ((uint32_t)src[3] << 24) | ((uint32_t)src[0] << 16) | + ((uint32_t)src[1] << 8) | (uint32_t)src[2]; + src += 4; + } + } else { + for (int i = 0; i < npixels; i++) { + dst[i] = 0xFF000000 | ((uint32_t)src[0] << 16) | + ((uint32_t)src[1] << 8) | (uint32_t)src[2]; + src += 3; + } + } + RReleaseImage(bg); + + wlr_buffer_init(&buf->base, &bg_buffer_impl, width, height); + + /* Hide the solid-color rect */ + if (wl_state.bg_rect) + wlr_scene_node_set_enabled(&wl_state.bg_rect->node, false); + + /* Replace or create the background scene buffer */ + if (wl_state.bg_image) { + wlr_scene_buffer_set_buffer(wl_state.bg_image, &buf->base); + wlr_scene_node_set_enabled(&wl_state.bg_image->node, true); + } else { + wl_state.bg_image = wlr_scene_buffer_create( + wl_state.level_trees[WL_LAYER_BACKGROUND], &buf->base); + } + + /* Release old buffer, keep new one */ + if (wl_state.bg_wlr_buf) + wlr_buffer_drop(wl_state.bg_wlr_buf); + wl_state.bg_wlr_buf = &buf->base; + + /* Schedule a frame to display the new background immediately */ + if (wl_state.output) + wlr_output_schedule_frame(wl_state.output); +}