diff --git a/WindowMaker/background.menu b/WindowMaker/background.menu index c81ae7b..2413109 100644 --- a/WindowMaker/background.menu +++ b/WindowMaker/background.menu @@ -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 diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index b1ad596..aad1d09 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -21,6 +21,10 @@ #include #include +/* 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 #include #include @@ -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 */ diff --git a/src/backend/wayland/wl_output.c b/src/backend/wayland/wl_output.c index d1cebd3..33711f8 100644 --- a/src/backend/wayland/wl_output.c +++ b/src/backend/wayland/wl_output.c @@ -38,6 +38,16 @@ handle_output_frame(struct wl_listener *listener, void *data) } } +#include + +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)", diff --git a/src/backend/wayland/wl_types.h b/src/backend/wayland/wl_types.h index 2f80786..b13d043 100644 --- a/src/backend/wayland/wl_types.h +++ b/src/backend/wayland/wl_types.h @@ -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; diff --git a/src/defaults.c b/src/defaults.c index 5e1488d..c59db92 100644 --- a/src/defaults.c +++ b/src/defaults.c @@ -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) {