A4: workspace switching badge for Wayland backend
Workspace switching (map/unmap) already worked via the vtable. This commit adds the workspace name badge overlay: - Create badge frame_buf in WL_LAYER_OVERLAY during screen init - Implement wl_workspace_badge_render (pixman text rendering) - Implement wl_workspace_badge_update (scene buffer refresh) - Add workspace_badge_get_background vtable slot - X11 backend: captures root window background (RGetXImage) - Wayland backend: returns solid dark background - workspace.c: replace direct RGetXImage/RCreateImageFromXImage with vtable call (zero backend guards in policy code)
This commit is contained in:
parent
cc9fc26817
commit
de0300d0fe
|
|
@ -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) */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue