fix background image rendering on Wayland: defer bg until output ready, disable wmsetbg helper, add pixmap path search, fix output destroy crash, update background.menu to use wdwrite
This commit is contained in:
parent
550d7828a8
commit
8c65d3fa88
|
|
@ -23,10 +23,10 @@
|
|||
"Wine Shades" WS_BACK '(vgradient, "#600040", "#180010")'
|
||||
"Gradient" END
|
||||
"Images" MENU
|
||||
"Tiled" OPEN_MENU BACKGROUNDS_DIR USER_BACKGROUNDS_DIR WITH wmsetbg -u -t
|
||||
"Scaled" OPEN_MENU BACKGROUNDS_DIR USER_BACKGROUNDS_DIR WITH wmsetbg -u -s
|
||||
"Centered" OPEN_MENU BACKGROUNDS_DIR USER_BACKGROUNDS_DIR WITH wmsetbg -u -e
|
||||
"Maximized" OPEN_MENU BACKGROUNDS_DIR USER_BACKGROUNDS_DIR WITH wmsetbg -u -a
|
||||
"Filled" OPEN_MENU BACKGROUNDS_DIR USER_BACKGROUNDS_DIR WITH wmsetbg -u -f
|
||||
"Tiled" OPEN_MENU BACKGROUNDS_DIR USER_BACKGROUNDS_DIR WITH sh -c 'wdwrite WindowMaker WorkspaceBack "(tpixmap, $1, black)"' placeholder
|
||||
"Scaled" OPEN_MENU BACKGROUNDS_DIR USER_BACKGROUNDS_DIR WITH sh -c 'wdwrite WindowMaker WorkspaceBack "(spixmap, $1, black)"' placeholder
|
||||
"Centered" OPEN_MENU BACKGROUNDS_DIR USER_BACKGROUNDS_DIR WITH sh -c 'wdwrite WindowMaker WorkspaceBack "(cpixmap, $1, black)"' placeholder
|
||||
"Maximized" OPEN_MENU BACKGROUNDS_DIR USER_BACKGROUNDS_DIR WITH sh -c 'wdwrite WindowMaker WorkspaceBack "(mpixmap, $1, black)"' placeholder
|
||||
"Filled" OPEN_MENU BACKGROUNDS_DIR USER_BACKGROUNDS_DIR WITH sh -c 'wdwrite WindowMaker WorkspaceBack "(fpixmap, $1, black)"' placeholder
|
||||
"Images" END
|
||||
"Background" END
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@
|
|||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/* debug helper for __func__ */
|
||||
#define DBG() wwarning("DEBUG %s:%d: %s", __FILE__, __LINE__, __func__)
|
||||
#define DBG1(fmt, ...) wwarning("DEBUG %s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/backend/headless.h>
|
||||
|
|
@ -1828,6 +1832,11 @@ wl_screen_alloc_gcs(WScreen *scr)
|
|||
void
|
||||
wl_screen_create_internals(WScreen *scr)
|
||||
{
|
||||
wl_state.scr = scr;
|
||||
{
|
||||
FILE *fp = fopen("/tmp/wl_backend_trace.log", "a");
|
||||
if (fp) { fprintf(fp, "wl_screen_create_internals: scr=%p\n", (void*)scr); fclose(fp); }
|
||||
}
|
||||
/* Create a real off-screen InputOnly X window that absorbs keyboard focus
|
||||
* when no application window holds it. This mirrors x11_screen_create_internals
|
||||
* exactly: without a mapped, viewable focus-sink window, any XSetInputFocus
|
||||
|
|
@ -2021,18 +2030,30 @@ static int parse_color_to_rcolor(WScreen *scr, const char *name, RColor *out)
|
|||
|
||||
void wl_set_desktop_background(WScreen *scr, const char *texture_desc)
|
||||
{
|
||||
if (!scr || !texture_desc || !wl_state.output)
|
||||
DBG1("texture_desc=%s output=%p", texture_desc, wl_state.output);
|
||||
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);
|
||||
DBG1("output not ready, cached pending_background=%s", texture_desc);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int width = wl_state.output->width;
|
||||
int height = wl_state.output->height;
|
||||
|
||||
/* Parse the texture proplist */
|
||||
DBG();
|
||||
WMPropList *texpl = WMCreatePropListFromDescription(texture_desc);
|
||||
if (!texpl)
|
||||
if (!texpl) {
|
||||
DBG1("WMCreatePropListFromDescription returned NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
DBG();
|
||||
/* Render the texture to an RImage using wrlib */
|
||||
RContext *rc = scr->rcontext;
|
||||
RImage *bg = NULL;
|
||||
|
|
@ -2041,6 +2062,7 @@ static int parse_color_to_rcolor(WScreen *scr, const char *name, RColor *out)
|
|||
WMPropList *type_pl = WMGetFromPLArray(texpl, 0);
|
||||
const char *type = type_pl ? WMGetFromPLString(type_pl) : "";
|
||||
|
||||
DBG1("type=%s", type);
|
||||
if (strcasecmp(type, "solid") == 0 && WMGetPropListItemCount(texpl) >= 2) {
|
||||
const char *colorstr = WMGetFromPLString(WMGetFromPLArray(texpl, 1));
|
||||
RColor color = {0x50, 0x50, 0x75, 0xFF};
|
||||
|
|
@ -2107,8 +2129,25 @@ static int parse_color_to_rcolor(WScreen *scr, const char *name, RColor *out)
|
|||
if (cstr) parse_color_to_rcolor(scr, cstr, &bgcolor);
|
||||
}
|
||||
if (path) {
|
||||
DBG1("loading image: %s", path);
|
||||
/* Try the path as-is first, then search pixmap_path */
|
||||
RImage *img = RLoadImage(rc, path, 0);
|
||||
if (img) {
|
||||
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);
|
||||
DBG1("trying: %s", _full);
|
||||
img = RLoadImage(rc, _full, 0);
|
||||
if (img) break;
|
||||
}
|
||||
}
|
||||
if (!img) {
|
||||
DBG1("RLoadImage failed: %s", RMessageForError(RErrorCode));
|
||||
} else {
|
||||
DBG1("image loaded: %dx%d fmt=%d", img->width, img->height, img->format);
|
||||
|
||||
/* Combine with background color if image has alpha */
|
||||
if (img->format == RRGBAFormat)
|
||||
RCombineImageWithColor(img, &bgcolor);
|
||||
|
|
@ -2199,10 +2238,13 @@ static int parse_color_to_rcolor(WScreen *scr, const char *name, RColor *out)
|
|||
WMReleasePropList(texpl);
|
||||
|
||||
if (!bg) {
|
||||
DBG1("bg is NULL after processing");
|
||||
return;
|
||||
}
|
||||
DBG1("bg created: %dx%d fmt=%d", bg->width, bg->height, bg->format);
|
||||
|
||||
|
||||
DBG1("converting RImage to pixman buffer (width=%d height=%d)", width, height);
|
||||
/* Convert RImage to pixman_image and set as scene buffer */
|
||||
struct wl_bg_buffer *buf = calloc(1, sizeof(*buf));
|
||||
if (!buf) { RReleaseImage(bg); return; }
|
||||
|
|
@ -2235,13 +2277,16 @@ static int parse_color_to_rcolor(WScreen *scr, const char *name, RColor *out)
|
|||
if (wl_state.bg_rect)
|
||||
wlr_scene_node_set_enabled(&wl_state.bg_rect->node, false);
|
||||
|
||||
DBG1("bg_image=%p bg_rect=%p level_tree=%p", wl_state.bg_image, wl_state.bg_rect, wl_state.level_trees[WL_LAYER_BACKGROUND]);
|
||||
/* 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);
|
||||
DBG1("updated existing bg_image");
|
||||
} else {
|
||||
wl_state.bg_image = wlr_scene_buffer_create(
|
||||
wl_state.level_trees[WL_LAYER_BACKGROUND], &buf->base);
|
||||
DBG1("created new bg_image=%p", wl_state.bg_image);
|
||||
}
|
||||
|
||||
/* Release old buffer, keep new one */
|
||||
|
|
|
|||
|
|
@ -38,6 +38,16 @@ handle_output_frame(struct wl_listener *listener, void *data)
|
|||
}
|
||||
}
|
||||
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
static void handle_output_destroy(struct wl_listener *listener, void *data)
|
||||
{
|
||||
(void)listener; (void)data;
|
||||
wl_list_remove(&wl_state.output_frame_listener.link);
|
||||
wl_state.scene_output = NULL;
|
||||
wl_state.output = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
handle_backend_new_output(struct wl_listener *listener, void *data)
|
||||
{
|
||||
|
|
@ -88,6 +98,8 @@ handle_backend_new_output(struct wl_listener *listener, void *data)
|
|||
wl_state.scene_output = wlr_scene_output_create(wl_state.scene, output);
|
||||
wl_state.output_frame_listener.notify = handle_output_frame;
|
||||
wl_signal_add(&output->events.frame, &wl_state.output_frame_listener);
|
||||
wl_state.output_destroy_listener.notify = handle_output_destroy;
|
||||
wl_signal_add(&output->events.destroy, &wl_state.output_destroy_listener);
|
||||
wwarning("wl_backend: scene output created for %s (%dx%d)",
|
||||
output->name, output->width, output->height);
|
||||
|
||||
|
|
@ -99,6 +111,14 @@ handle_backend_new_output(struct wl_listener *listener, void *data)
|
|||
wwarning("wl_backend: root background created (%dx%d)",
|
||||
(int)output->width, (int)output->height);
|
||||
}
|
||||
|
||||
/* Apply any background that was cached before output was ready */
|
||||
if (wl_state.pending_background && wl_state.scr) {
|
||||
wwarning("wl_backend: applying pending background");
|
||||
wl_set_desktop_background(wl_state.scr, wl_state.pending_background);
|
||||
wfree(wl_state.pending_background);
|
||||
wl_state.pending_background = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
wwarning("wl_backend: new output %s (%dx%d)",
|
||||
|
|
|
|||
|
|
@ -212,7 +212,8 @@ struct wl_compositor_state {
|
|||
struct wlr_scene *scene;
|
||||
struct wlr_scene_output *scene_output;
|
||||
struct wl_listener backend_new_output_listener;
|
||||
struct wl_listener output_frame_listener;
|
||||
struct wl_listener output_frame_listener;
|
||||
struct wl_listener output_destroy_listener;
|
||||
char socket_name[64]; /* Phase 34: e.g. "wayland-0" */
|
||||
int started; /* non-zero after successful display_open */
|
||||
/* Self-pipe for async-signal-safe shutdown: signal handler writes to [1],
|
||||
|
|
@ -350,6 +351,7 @@ struct wl_compositor_state {
|
|||
struct wlr_scene_rect *bg_rect; /* default solid background */
|
||||
struct wlr_scene_buffer *bg_image; /* wallpaper image (if set) */
|
||||
struct wlr_buffer *bg_wlr_buf; /* backing buffer for bg_image */
|
||||
char *pending_background; /* cached texture desc, applied when output is ready */
|
||||
|
||||
/* Phase 81: full-screen overlay surface for XOR animation drawing */
|
||||
struct wm_shm_surface *overlay_surf; /* NULL until first draw */
|
||||
|
|
@ -364,6 +366,7 @@ struct wl_compositor_state {
|
|||
/* Deferred dock creation: set in screen_create_internals, consumed in
|
||||
* wl_event_loop_run() after the startup pump thread stops (to avoid racing
|
||||
* with the pump thread's frame-timer callback on the scene graph). */
|
||||
WScreen *scr; /* first screen, set during screen_create_internals */
|
||||
WScreen *dock_pending_scr;
|
||||
/* Button icon RImages (parsed from XPM on first use) */
|
||||
RImage *btn_close_img;
|
||||
|
|
|
|||
|
|
@ -2926,6 +2926,12 @@ static int setWorkspaceSpecificBack(WScreen * scr, WDefaultEntry * entry, void *
|
|||
(void) entry;
|
||||
(void) bar;
|
||||
|
||||
/* If the backend handles backgrounds directly (Wayland), skip helper */
|
||||
if (wm_backend->set_desktop_background) {
|
||||
WMReleasePropList(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (scr->flags.backimage_helper_launched) {
|
||||
if (WMGetPropListItemCount(value) == 0) {
|
||||
SendHelperMessage(scr, 'C', 0, NULL);
|
||||
|
|
@ -2972,6 +2978,7 @@ static int setWorkspaceBack(WScreen * scr, WDefaultEntry * entry, void *tdata, v
|
|||
(void) entry;
|
||||
(void) bar;
|
||||
|
||||
fprintf(stderr, "TRACE setWorkspaceBack: backend=%p valcount=%d\n", (void*)wm_backend->set_desktop_background, WMGetPropListItemCount(value));
|
||||
/* If the backend can render backgrounds directly (Wayland), use it */
|
||||
if (wm_backend->set_desktop_background && WMGetPropListItemCount(value) > 0) {
|
||||
char *str = WMGetPropListDescription(value, False);
|
||||
|
|
@ -2979,6 +2986,8 @@ static int setWorkspaceBack(WScreen * scr, WDefaultEntry * entry, void *tdata, v
|
|||
wm_backend->set_desktop_background(scr, str);
|
||||
wfree(str);
|
||||
}
|
||||
WMReleasePropList(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (scr->flags.backimage_helper_launched) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue