diff --git a/src/backend/backend.h b/src/backend/backend.h index 2acdb01..8b56188 100644 --- a/src/backend/backend.h +++ b/src/backend/backend.h @@ -543,6 +543,18 @@ typedef struct WMBackend { void (*workspace_badge_update)(WScreen *scr, WNativeWindow badge_win, RImage *img); + /* + * Capture the background behind the workspace badge for the fade effect. + * + * X11: RGetXImage + RCreateImageFromXImage on the root window. + * Wayland: returns a solid dark RImage (no screen capture needed). + * + * Returns an RImage* owned by the caller (must be freed with RReleaseImage). + * Returns NULL on failure. + */ + RImage *(*workspace_badge_get_background)(WScreen *scr, int x, int y, + int width, int height); + /* ------------------------------------------------------------------ */ /* Server grab (Phase 11) */ /* ------------------------------------------------------------------ */ diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index 6c04d94..2d3ec5a 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -7076,6 +7076,33 @@ wl_screen_create_internals(WScreen *scr) /* Wayland has no X11-style window border; force to 0 so policy code * does not offset client positions by a non-existent border. */ scr->frame_border_width = 0; + + /* Create workspace name badge overlay (initially 10x10, resized on use) */ + if (wl_state.scene) { + struct wl_frame_buf *fb = wmalloc(sizeof(*fb)); + memset(fb, 0, sizeof(*fb)); + fb->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, 10, 10, NULL, 0); + if (fb->image) { + wlr_buffer_init(&fb->base, &frame_buf_impl, 10, 10); + fb->id = wl_state.next_synthetic_id++; + fb->width = 10; + fb->height = 10; + struct wlr_scene_tree *parent = wl_state.level_trees[WL_LAYER_OVERLAY] + ? wl_state.level_trees[WL_LAYER_OVERLAY] : &wl_state.scene->tree; + fb->tree = wlr_scene_tree_create(parent); + if (fb->tree) { + fb->scene_buf = wlr_scene_buffer_create(fb->tree, &fb->base); + if (fb->scene_buf) + wlr_scene_node_set_enabled(&fb->scene_buf->node, false); + wlr_scene_node_set_enabled(&fb->tree->node, false); + } + wl_list_insert(&wl_state.frame_list, &fb->link); + W_RegisterBacking(fb->id, fb->image); + scr->workspace_name = fb->id; + } else { + wfree(fb); + } + } } static void wl_screen_create_pixmaps(WScreen *scr) { (void)scr; } static void @@ -7147,11 +7174,106 @@ static RImage * wl_workspace_badge_render(WScreen *scr, WNativeWindow badge_win, const char *name, int name_len, int width, int height) -{ (void)scr; (void)badge_win; (void)name; (void)name_len; (void)width; (void)height; return NULL; } +{ + struct wl_frame_buf *fb = frame_buf_find(badge_win); + if (!fb) return NULL; + + /* Resize pixman buffer if needed */ + if (width > 0 && height > 0 && (width != fb->width || height != fb->height)) { + W_UnregisterBacking(fb->id); + pixman_image_unref(fb->image); + fb->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, width, height, NULL, 0); + if (!fb->image) return NULL; + fb->width = width; + fb->height = height; + fb->base.width = width; + fb->base.height = height; + W_RegisterBacking(fb->id, fb->image); + } + + /* Fill black */ + pixman_image_t *black_fill = pixman_image_create_bits(PIXMAN_a8r8g8b8, width, height, NULL, 0); + if (black_fill) { + uint32_t *data = pixman_image_get_data(black_fill); + for (int i = 0; i < width * height; i++) + data[i] = 0xFF000000; + pixman_image_composite32(PIXMAN_OP_SRC, black_fill, NULL, fb->image, + 0, 0, 0, 0, 0, 0, width, height); + pixman_image_unref(black_fill); + } + + /* Draw text (shadow passes + final) */ + for (int x = 0; x <= 4; x++) + for (int y = 0; y <= 4; y++) + WMDrawString(scr->wmscreen, (WMDrawable)badge_win, scr->white, + scr->workspace_name_font, x, y, name, name_len); + + /* Clear and redraw final text centered */ + uint32_t *px = pixman_image_get_data(fb->image); + for (int i = 0; i < width * height; i++) + px[i] = 0xFF000000; + WMDrawString(scr->wmscreen, (WMDrawable)badge_win, scr->white, + scr->workspace_name_font, 2, 2, name, name_len); + + /* Update scene buffer */ + if (fb->scene_buf) + wlr_scene_buffer_set_buffer(fb->scene_buf, &fb->base); + + /* Return RImage copy for fade animation */ + RImage *result = RCreateImage(width, height, False); + if (result) { + uint32_t *src = pixman_image_get_data(fb->image); + for (int i = 0; i < width * height; i++) { + uint32_t p = src[i]; + result->data[i * 3 + 0] = (p >> 16) & 0xFF; /* R */ + result->data[i * 3 + 1] = (p >> 8) & 0xFF; /* G */ + result->data[i * 3 + 2] = p & 0xFF; /* B */ + } + } + return result; +} + +static RImage * +wl_workspace_badge_get_background(WScreen *scr, int x, int y, int width, int height) +{ + (void)scr; (void)x; (void)y; + RImage *img = RCreateImage(width, height, False); + if (img) + memset(img->data, 8, width * height * 3); + return img; +} static void wl_workspace_badge_update(WScreen *scr, WNativeWindow badge_win, RImage *img) -{ (void)scr; (void)badge_win; (void)img; } +{ + (void)scr; + if (!img) return; + struct wl_frame_buf *fb = frame_buf_find(badge_win); + if (!fb || !fb->image) return; + + int w = img->width; + int h = img->height; + if (w > fb->width) w = fb->width; + if (h > fb->height) h = fb->height; + + /* Blit RImage (RGB or RGBA) into pixman ARGB32 buffer */ + uint32_t *dst = pixman_image_get_data(fb->image); + int bpp = img->format == RRGBAFormat ? 4 : 3; + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + int si = (y * img->width + x) * bpp; + uint8_t r = img->data[si]; + uint8_t g = img->data[si + 1]; + uint8_t b = img->data[si + 2]; + dst[y * fb->width + x] = 0xFF000000 | (r << 16) | (g << 8) | b; + } + } + + if (fb->scene_buf) + wlr_scene_buffer_set_buffer(fb->scene_buf, &fb->base); + if (wl_state.output) + wlr_output_schedule_frame(wl_state.output); +} /* ------------------------------------------------------------------ */ /* XKB */ @@ -8329,6 +8451,7 @@ const WMBackend wl_backend = { .workspace_badge_render = wl_workspace_badge_render, .workspace_badge_update = wl_workspace_badge_update, + .workspace_badge_get_background = wl_workspace_badge_get_background, .keysym_to_keycode = wl_keysym_to_keycode, .keysym_from_keycode = wl_keysym_from_keycode, diff --git a/src/backend/x11/x11_backend.c b/src/backend/x11/x11_backend.c index 665d3ba..8095d31 100644 --- a/src/backend/x11/x11_backend.c +++ b/src/backend/x11/x11_backend.c @@ -718,6 +718,17 @@ x11_workspace_badge_update(WScreen *scr, WNativeWindow badge_win, RImage *img) XFlush(dpy); } +static RImage * +x11_workspace_badge_get_background(WScreen *scr, int x, int y, int width, int height) +{ + RXImage *ximg = RGetXImage(scr->rcontext, scr->root_win, x, y, width, height); + if (!ximg) + return NULL; + RImage *result = RCreateImageFromXImage(scr->rcontext, ximg->image, NULL); + RDestroyXImage(scr->rcontext, ximg); + return result; +} + /* -------------------------------------------------------------------- */ /* Keyboard grab */ /* -------------------------------------------------------------------- */ @@ -4258,6 +4269,7 @@ const WMBackend x11_backend = { .pointer_query_full = x11_pointer_query_full, .workspace_badge_render = x11_workspace_badge_render, .workspace_badge_update = x11_workspace_badge_update, + .workspace_badge_get_background = x11_workspace_badge_get_background, .keyboard_grab = x11_keyboard_grab, .keyboard_ungrab = x11_keyboard_ungrab, .keysym_to_keycode = x11_keysym_to_keycode, diff --git a/src/workspace.c b/src/workspace.c index 7901e5d..c8e0898 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -244,7 +244,6 @@ static void hideWorkspaceName(void *data) static void showWorkspaceName(WScreen * scr, int workspace) { WorkspaceNameData *data; - RXImage *ximg; int w, h; int px, py; char *name = scr->workspaces[workspace]->name; @@ -330,15 +329,12 @@ static void showWorkspaceName(WScreen * scr, int workspace) goto erro; } - ximg = RGetXImage(scr->rcontext, scr->root_win, px, py, data->text->width, data->text->height); - if (!ximg) - goto erro; - wm_backend->window_map_raised(scr->workspace_name); wm_backend->event_flush(); - data->back = RCreateImageFromXImage(scr->rcontext, ximg->image, NULL); - RDestroyXImage(scr->rcontext, ximg); + data->back = wm_backend->workspace_badge_get_background(scr, px, py, + data->text->width, + data->text->height); if (!data->back) { goto erro;