Fix text rendering and titlebar positioning

- wl_draw_string: remove ascent subtraction, y is TOP position (matches
  X11 Pango behavior where pango_xft_render_layout takes top-left)
- Menu entry text: pass top position (y+3) not baseline (y+3+fh-1)
- Icon title: pass y=0 (top) not y=fh (baseline)
- frame_paint_titlebar: pass centered top not baseline
- frame_configure: compute absolute position from parent for children
  (was setting absolute pos to relative coords, warping to 0,0)
- Titlebar buffer: always render full frame width, resize if needed
- Frame scene node: disable when no resizebar (transparent, not needed)
- Always call frame_paint after show/hide button (TS_NEW was skipping it)
This commit is contained in:
Levi Neely 2026-05-13 19:03:49 +02:00
parent 3a48a0eb30
commit 531dcf8235
2 changed files with 68 additions and 25 deletions

View File

@ -164,7 +164,7 @@ wl_draw_string(void *sctx, void *handle, WMDrawable d,
};
pango_ft2_render_layout(&bm, h->layout, 0, 0);
blit_alpha_to_pixman(dst, buf, stride, pw, ph, x, y - h->ascent, r, g, b, a);
blit_alpha_to_pixman(dst, buf, stride, pw, ph, x, y, r, g, b, a);
wfree(buf);
}

View File

@ -3683,11 +3683,25 @@ wl_frame_configure(WNativeWindow win, int x, int y, int width, int height)
struct wl_frame_buf *fb = frame_buf_find(win);
if (!fb) return;
fb->x = x;
fb->y = y;
/* x,y are relative to parent for child windows */
fb->rel_x = x;
fb->rel_y = y;
if (fb->parent_id) {
struct wl_frame_buf *parent = frame_buf_find(fb->parent_id);
if (parent) {
fb->x = parent->x + x;
fb->y = parent->y + y;
} else {
fb->x = x;
fb->y = y;
}
} else {
fb->x = x;
fb->y = y;
}
if (fb->scene_buf)
wlr_scene_node_set_position(&fb->scene_buf->node, x, y);
wlr_scene_node_set_position(&fb->scene_buf->node, fb->x, fb->y);
/* Resize: reallocate the pixman image if dimensions changed. */
if (width > 0 && height > 0 && (width != fb->width || height != fb->height)) {
@ -3729,17 +3743,36 @@ wl_frame_paint(struct WFrameWindow *fwin)
/* --- Titlebar --- */
if (fwin->titlebar && fwin->top_width > 0) {
int tb_w = total_w;
struct wl_frame_buf *tb_fb = frame_buf_find(fwin->titlebar->window);
pixman_image_t *tb_img = tb_fb ? tb_fb->image : fb->image;
int tb_w = total_w; /* always full frame width */
int tb_h = fwin->top_width;
/* Ensure titlebar buffer is full width */
if (tb_fb && tb_fb->width < tb_w) {
pixman_image_unref(tb_fb->image);
tb_fb->image = pixman_image_create_bits(PIXMAN_a8r8g8b8,
tb_w, tb_h, NULL, 0);
tb_fb->width = tb_w;
tb_fb->height = tb_h;
tb_fb->base.width = tb_w;
tb_fb->base.height = tb_h;
tb_img = tb_fb->image;
}
WTexture *tex = fwin->title_texture[state];
/* Clear titlebar buffer */
if (tb_fb) {
pixman_color_t clear = {0, 0, 0, 0};
pixman_image_fill_rectangles(PIXMAN_OP_SRC, tb_img, &clear,
1, &(pixman_rectangle16_t){0, 0, tb_w, tb_h});
}
/* Render texture to RImage. */
RImage *img = wTextureRenderImage(tex, tb_w, tb_h, WREL_RAISED);
if (img) {
/* Blit RImage into the pixman buffer at (0, 0).
* RImage is RGBA (4 bytes/pixel) or RGB (3 bytes/pixel). */
uint32_t *dst = pixman_image_get_data(fb->image);
int dst_stride = pixman_image_get_stride(fb->image) / 4;
uint32_t *dst = pixman_image_get_data(tb_img);
int dst_stride = pixman_image_get_stride(tb_img) / 4;
int x, y;
if (img->format == RRGBAFormat) {
for (y = 0; y < tb_h && y < img->height; y++) {
@ -3796,12 +3829,15 @@ wl_frame_paint(struct WFrameWindow *fwin)
}
ty = (tb_h - th) / 2;
/* Draw text into the frame buffer using WMDrawable = pixman_image_t* */
WMDrawString(fwin->screen_ptr->wmscreen, (WMDrawable)fb->image,
WMDrawString(fwin->screen_ptr->wmscreen, (WMDrawable)tb_img,
fwin->title_color[state], *fwin->font,
tx, ty, title, titlelen);
wfree(title);
}
/* Commit titlebar buffer */
if (tb_fb && tb_fb->scene_buf)
wlr_scene_buffer_set_buffer(tb_fb->scene_buf, &tb_fb->base);
}
/* --- Titlebar buttons --- */
@ -3862,9 +3898,13 @@ wl_frame_paint(struct WFrameWindow *fwin)
}
}
/* Commit the buffer to the scene graph. */
if (fb->scene_buf)
wlr_scene_buffer_set_buffer(fb->scene_buf, &fb->base);
/* Commit the buffer to the scene graph only if it has content (resizebar). */
if (fb->scene_buf) {
if (fwin->resizebar && fwin->bottom_width > 0)
wlr_scene_buffer_set_buffer(fb->scene_buf, &fb->base);
else
wlr_scene_node_set_enabled(&fb->scene_buf->node, false);
}
return 1;
}
@ -6257,8 +6297,11 @@ static void wl_frame_paint_button(WCoreWindow *button, WTexture *texture,
return;
struct wl_frame_buf *frame_fb = frame_buf_find(fwin->core->window);
struct wl_frame_buf *tb_fb = fwin->titlebar ? frame_buf_find(fwin->titlebar->window) : NULL;
struct wl_frame_buf *btn_fb = frame_buf_find(button->window);
if (!frame_fb || !frame_fb->image || !btn_fb)
/* Render into titlebar buffer if available, else frame buffer */
struct wl_frame_buf *target = (tb_fb && tb_fb->image) ? tb_fb : frame_fb;
if (!target || !target->image || !btn_fb)
return;
int bx = btn_fb->rel_x;
@ -6283,18 +6326,18 @@ static void wl_frame_paint_button(WCoreWindow *button, WTexture *texture,
return;
/* Blit icon centered in button area */
uint32_t *dst = pixman_image_get_data(frame_fb->image);
int dst_stride = pixman_image_get_stride(frame_fb->image) / 4;
uint32_t *dst = pixman_image_get_data(target->image);
int dst_stride = pixman_image_get_stride(target->image) / 4;
int ix = bx + (bw - icon->width) / 2 + (pushed ? 1 : 0);
int iy = by + (bh - icon->height) / 2 + (pushed ? 1 : 0);
for (int y = 0; y < icon->height; y++) {
int dy = iy + y;
if (dy < 0 || dy >= frame_fb->height) continue;
if (dy < 0 || dy >= target->height) continue;
uint32_t *dst_row = dst + dy * dst_stride;
for (int x = 0; x < icon->width; x++) {
int dx = ix + x;
if (dx < 0 || dx >= frame_fb->width) continue;
if (dx < 0 || dx >= target->width) continue;
unsigned char r, g, b, a;
if (icon->format == RRGBAFormat) {
int off = (y * icon->width + x) * 4;
@ -6311,8 +6354,8 @@ static void wl_frame_paint_button(WCoreWindow *button, WTexture *texture,
}
}
if (frame_fb->scene_buf)
wlr_scene_buffer_set_buffer(frame_fb->scene_buf, &frame_fb->base);
if (target->scene_buf)
wlr_scene_buffer_set_buffer(target->scene_buf, &target->base);
}
static void wl_noop_netwm_init(WScreen *scr) { (void)scr; }
@ -6464,7 +6507,7 @@ static void wl_appicon_paint(WAppIcon *aicon)
strlen(icon->icon_name));
int tx = (size - tw) / 2;
if (tx < 2) tx = 2;
int ty = fh; /* baseline near top */
int ty = 0; /* top of text area */
WMColor *color = scr->icon_title_color;
if (color)
WMDrawString(scr->wmscreen, d, color, scr->icon_title_font,
@ -6662,14 +6705,14 @@ static void wl_menu_paint_entry(WMenu *menu, int index, int selected)
WMDrawable d = (WMDrawable)(uintptr_t)fb->image;
if (entry->text && font && color) {
int text_y = y + 3 + WMFontHeight(font) - 1;
int text_y = y + 3;
WMDrawString(scr->wmscreen, d, color, font,
8, text_y, entry->text, strlen(entry->text));
}
if (entry->rtext && entry->cascade < 0 && font && color) {
int tw = WMWidthOfString(font, entry->rtext, strlen(entry->rtext));
int text_y = y + 3 + WMFontHeight(font) - 1;
int text_y = y + 3;
WMDrawString(scr->wmscreen, d, color, font,
w - 8 - tw, text_y, entry->rtext, strlen(entry->rtext));
}
@ -6832,7 +6875,7 @@ static void wl_frame_paint_titlebar(WFrameWindow *fwin, int state)
default: x = (fb->width - tw) / 2; break;
}
int fh = WMFontHeight(*fwin->font);
int y = (fb->height - fh) / 2 + fh;
int y = (fb->height - fh) / 2;
WMDrawable d = (WMDrawable)(uintptr_t)fb->image;
WMDrawString(scr->wmscreen, d, fwin->title_color[state],