Fix installer GUI ghosting: add double-buffer, fix text baseline
Ghosting root cause: all X11 drawing (XFillRectangle, XDrawLine, XDrawArc, XDrawRectangle) and XRender Xft text rendering were going directly to the window. XRender composites text on top of pixels without clearing underneath, so previous log lines bled through on every update. Fix: - Added Pixmap buf to Ins struct (created at WIN_W × WIN_H after window init) - Redirected all drawing calls (fill_rect, draw_line, XDrawRectangle, XDrawArc, XFillArc) from s->win to s->buf - XftDrawCreate in redraw() now targets s->buf - At end of redraw(): XCopyArea(buf → win) blits the complete frame at once - Also fixed xft_text baseline: was y + ext.height - ext.y (glyph-specific, varied per string); now y + f->ascent (consistent font metric) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
33ae437b5b
commit
d19aca2333
1 file changed
+21
-15
@@ -126,6 +126,7 @@ typedef struct {
|
|||||||
Display *dpy;
|
Display *dpy;
|
||||||
int scr;
|
int scr;
|
||||||
Window win;
|
Window win;
|
||||||
|
Pixmap buf; /* double-buffer — all drawing goes here, then blit */
|
||||||
GC gc;
|
GC gc;
|
||||||
Colormap cmap;
|
Colormap cmap;
|
||||||
Visual *vis;
|
Visual *vis;
|
||||||
@@ -195,12 +196,12 @@ static void xftcol(Ins *s, unsigned long rgb, XftColor *out) {
|
|||||||
|
|
||||||
static void fill_rect(Ins *s, int x, int y, int w, int h, unsigned long rgb) {
|
static void fill_rect(Ins *s, int x, int y, int w, int h, unsigned long rgb) {
|
||||||
XSetForeground(s->dpy, s->gc, mkcolor(s, rgb));
|
XSetForeground(s->dpy, s->gc, mkcolor(s, rgb));
|
||||||
XFillRectangle(s->dpy, s->win, s->gc, x, y, w, h);
|
XFillRectangle(s->dpy, s->buf, s->gc, x, y, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_line(Ins *s, int x1, int y1, int x2, int y2, unsigned long rgb) {
|
static void draw_line(Ins *s, int x1, int y1, int x2, int y2, unsigned long rgb) {
|
||||||
XSetForeground(s->dpy, s->gc, mkcolor(s, rgb));
|
XSetForeground(s->dpy, s->gc, mkcolor(s, rgb));
|
||||||
XDrawLine(s->dpy, s->win, s->gc, x1, y1, x2, y2);
|
XDrawLine(s->dpy, s->buf, s->gc, x1, y1, x2, y2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Draw text and return pixel width */
|
/* Draw text and return pixel width */
|
||||||
@@ -210,7 +211,8 @@ static int xft_text(Ins *s, XftDraw *xd, XftFont *f, unsigned long rgb,
|
|||||||
XftColor col; xftcol(s, rgb, &col);
|
XftColor col; xftcol(s, rgb, &col);
|
||||||
XGlyphInfo ext;
|
XGlyphInfo ext;
|
||||||
XftTextExtentsUtf8(s->dpy, f, (const FcChar8 *)str, strlen(str), &ext);
|
XftTextExtentsUtf8(s->dpy, f, (const FcChar8 *)str, strlen(str), &ext);
|
||||||
XftDrawStringUtf8(xd, &col, f, x, y + ext.height - ext.y,
|
/* y is the TOP of the text row; compute baseline from font metrics */
|
||||||
|
XftDrawStringUtf8(xd, &col, f, x, y + f->ascent,
|
||||||
(const FcChar8 *)str, strlen(str));
|
(const FcChar8 *)str, strlen(str));
|
||||||
XftColorFree(s->dpy, s->vis, s->cmap, &col);
|
XftColorFree(s->dpy, s->vis, s->cmap, &col);
|
||||||
return ext.width;
|
return ext.width;
|
||||||
@@ -264,7 +266,7 @@ static void draw_textfield(Ins *s, XftDraw *xd, int x, int y, int w,
|
|||||||
fill_rect(s, x, y, w, 32, C_INPUT_BG);
|
fill_rect(s, x, y, w, 32, C_INPUT_BG);
|
||||||
/* border */
|
/* border */
|
||||||
XSetForeground(s->dpy, s->gc, mkcolor(s, bord));
|
XSetForeground(s->dpy, s->gc, mkcolor(s, bord));
|
||||||
XDrawRectangle(s->dpy, s->win, s->gc, x, y, w - 1, 31);
|
XDrawRectangle(s->dpy, s->buf, s->gc, x, y, w - 1, 31);
|
||||||
|
|
||||||
/* content */
|
/* content */
|
||||||
if (tf->len == 0 && !focused && placeholder) {
|
if (tf->len == 0 && !focused && placeholder) {
|
||||||
@@ -321,10 +323,10 @@ static void draw_radio(Ins *s, XftDraw *xd, int x, int y, int w,
|
|||||||
/* radio circle */
|
/* radio circle */
|
||||||
int cx = x + 20, cy = y + 22;
|
int cx = x + 20, cy = y + 22;
|
||||||
XSetForeground(s->dpy, s->gc, mkcolor(s, C_SEP));
|
XSetForeground(s->dpy, s->gc, mkcolor(s, C_SEP));
|
||||||
XDrawArc(s->dpy, s->win, s->gc, cx-8, cy-8, 16, 16, 0, 360*64);
|
XDrawArc(s->dpy, s->buf, s->gc, cx-8, cy-8, 16, 16, 0, 360*64);
|
||||||
if (selected) {
|
if (selected) {
|
||||||
XSetForeground(s->dpy, s->gc, mkcolor(s, C_BTN_PRI));
|
XSetForeground(s->dpy, s->gc, mkcolor(s, C_BTN_PRI));
|
||||||
XFillArc(s->dpy, s->win, s->gc, cx-5, cy-5, 10, 10, 0, 360*64);
|
XFillArc(s->dpy, s->buf, s->gc, cx-5, cy-5, 10, 10, 0, 360*64);
|
||||||
}
|
}
|
||||||
|
|
||||||
xft_text(s, xd, s->f_body, C_TXT, x+38, y+8, label);
|
xft_text(s, xd, s->f_body, C_TXT, x+38, y+8, label);
|
||||||
@@ -335,7 +337,7 @@ static void draw_radio(Ins *s, XftDraw *xd, int x, int y, int w,
|
|||||||
static void draw_progress(Ins *s, int x, int y, int w, int h, int pct) {
|
static void draw_progress(Ins *s, int x, int y, int w, int h, int pct) {
|
||||||
fill_rect(s, x, y, w, h, C_BAR_BG);
|
fill_rect(s, x, y, w, h, C_BAR_BG);
|
||||||
XSetForeground(s->dpy, s->gc, mkcolor(s, C_BORDER));
|
XSetForeground(s->dpy, s->gc, mkcolor(s, C_BORDER));
|
||||||
XDrawRectangle(s->dpy, s->win, s->gc, x, y, w-1, h-1);
|
XDrawRectangle(s->dpy, s->buf, s->gc, x, y, w-1, h-1);
|
||||||
|
|
||||||
if (pct > 0) {
|
if (pct > 0) {
|
||||||
int fw = (w - 2) * pct / 100;
|
int fw = (w - 2) * pct / 100;
|
||||||
@@ -439,7 +441,7 @@ static void draw_footer(Ins *s, XftDraw *xd,
|
|||||||
int dy = fy + FOOT_H/2;
|
int dy = fy + FOOT_H/2;
|
||||||
unsigned long dc = (i == dot_step) ? C_BTN_PRI : C_SEP;
|
unsigned long dc = (i == dot_step) ? C_BTN_PRI : C_SEP;
|
||||||
XSetForeground(s->dpy, s->gc, mkcolor(s, dc));
|
XSetForeground(s->dpy, s->gc, mkcolor(s, dc));
|
||||||
XFillArc(s->dpy, s->win, s->gc, dx-4, dy-4, 8, 8, 0, 360*64);
|
XFillArc(s->dpy, s->buf, s->gc, dx-4, dy-4, 8, 8, 0, 360*64);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bw = 120, bh = 36, by = fy + (FOOT_H - bh) / 2;
|
int bw = 120, bh = 36, by = fy + (FOOT_H - bh) / 2;
|
||||||
@@ -592,21 +594,21 @@ static void draw_locale(Ins *s, XftDraw *xd) {
|
|||||||
unsigned long fbd = factive ? C_INPUT_ACT : C_INPUT_BD;
|
unsigned long fbd = factive ? C_INPUT_ACT : C_INPUT_BD;
|
||||||
fill_rect(s, lx, fy, LC_PANE_W, 26, C_INPUT_BG);
|
fill_rect(s, lx, fy, LC_PANE_W, 26, C_INPUT_BG);
|
||||||
XSetForeground(s->dpy, s->gc, mkcolor(s, fbd));
|
XSetForeground(s->dpy, s->gc, mkcolor(s, fbd));
|
||||||
XDrawRectangle(s->dpy, s->win, s->gc, lx, fy, LC_PANE_W-1, 25);
|
XDrawRectangle(s->dpy, s->buf, s->gc, lx, fy, LC_PANE_W-1, 25);
|
||||||
const char *fdisp = s->tz_filter_len ? s->tz_filter : "";
|
const char *fdisp = s->tz_filter_len ? s->tz_filter : "";
|
||||||
xft_text(s, xd, s->f_body, s->tz_filter_len ? C_TXT_INP : C_TXT_DIM,
|
xft_text(s, xd, s->f_body, s->tz_filter_len ? C_TXT_INP : C_TXT_DIM,
|
||||||
lx + 6, fy + 17, s->tz_filter_len ? fdisp : "Filter…");
|
lx + 6, fy + 17, s->tz_filter_len ? fdisp : "Filter…");
|
||||||
if (factive) {
|
if (factive) {
|
||||||
int cx = lx + 6 + text_w(s, s->f_body, fdisp);
|
int cx = lx + 6 + text_w(s, s->f_body, fdisp);
|
||||||
XSetForeground(s->dpy, s->gc, mkcolor(s, C_TXT_INP));
|
XSetForeground(s->dpy, s->gc, mkcolor(s, C_TXT_INP));
|
||||||
XDrawLine(s->dpy, s->win, s->gc, cx, fy + 4, cx, fy + 21);
|
XDrawLine(s->dpy, s->buf, s->gc, cx, fy + 4, cx, fy + 21);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* timezone list */
|
/* timezone list */
|
||||||
int ly = fy + 32;
|
int ly = fy + 32;
|
||||||
fill_rect(s, lx, ly, LC_PANE_W, LC_LIST_H, C_PANEL);
|
fill_rect(s, lx, ly, LC_PANE_W, LC_LIST_H, C_PANEL);
|
||||||
XSetForeground(s->dpy, s->gc, mkcolor(s, C_SEP));
|
XSetForeground(s->dpy, s->gc, mkcolor(s, C_SEP));
|
||||||
XDrawRectangle(s->dpy, s->win, s->gc, lx, ly, LC_PANE_W-1, LC_LIST_H-1);
|
XDrawRectangle(s->dpy, s->buf, s->gc, lx, ly, LC_PANE_W-1, LC_LIST_H-1);
|
||||||
|
|
||||||
int vis = 0, row = 0;
|
int vis = 0, row = 0;
|
||||||
for (int i = 0; i < NTZ && vis < LC_ROWS_VIS + s->tz_scroll; i++) {
|
for (int i = 0; i < NTZ && vis < LC_ROWS_VIS + s->tz_scroll; i++) {
|
||||||
@@ -631,7 +633,7 @@ static void draw_locale(Ins *s, XftDraw *xd) {
|
|||||||
int kly = ty + 22 + 32; /* align with timezone list (below filter) */
|
int kly = ty + 22 + 32; /* align with timezone list (below filter) */
|
||||||
fill_rect(s, rx, kly, LC_PANE_W, LC_LIST_H + 26, C_PANEL);
|
fill_rect(s, rx, kly, LC_PANE_W, LC_LIST_H + 26, C_PANEL);
|
||||||
XSetForeground(s->dpy, s->gc, mkcolor(s, C_SEP));
|
XSetForeground(s->dpy, s->gc, mkcolor(s, C_SEP));
|
||||||
XDrawRectangle(s->dpy, s->win, s->gc, rx, kly, LC_PANE_W-1, LC_LIST_H+25);
|
XDrawRectangle(s->dpy, s->buf, s->gc, rx, kly, LC_PANE_W-1, LC_LIST_H+25);
|
||||||
|
|
||||||
int kvis = NKB < LC_ROWS_VIS + 1 ? NKB : LC_ROWS_VIS + 1;
|
int kvis = NKB < LC_ROWS_VIS + 1 ? NKB : LC_ROWS_VIS + 1;
|
||||||
for (int i = s->kb_scroll; i < NKB && (i - s->kb_scroll) < kvis; i++) {
|
for (int i = s->kb_scroll; i < NKB && (i - s->kb_scroll) < kvis; i++) {
|
||||||
@@ -908,7 +910,7 @@ static void draw_done(Ins *s, XftDraw *xd) {
|
|||||||
/* ══════════════════════════════════════════════════════════════════ */
|
/* ══════════════════════════════════════════════════════════════════ */
|
||||||
|
|
||||||
static void redraw(Ins *s) {
|
static void redraw(Ins *s) {
|
||||||
XftDraw *xd = XftDrawCreate(s->dpy, s->win, s->vis, s->cmap);
|
XftDraw *xd = XftDrawCreate(s->dpy, s->buf, s->vis, s->cmap);
|
||||||
fill_rect(s, 0, 0, WIN_W, WIN_H, C_BG);
|
fill_rect(s, 0, 0, WIN_W, WIN_H, C_BG);
|
||||||
|
|
||||||
switch (s->step) {
|
switch (s->step) {
|
||||||
@@ -923,9 +925,12 @@ static void redraw(Ins *s) {
|
|||||||
|
|
||||||
/* outer border */
|
/* outer border */
|
||||||
XSetForeground(s->dpy, s->gc, mkcolor(s, C_BORDER));
|
XSetForeground(s->dpy, s->gc, mkcolor(s, C_BORDER));
|
||||||
XDrawRectangle(s->dpy, s->win, s->gc, 0, 0, WIN_W-1, WIN_H-1);
|
XDrawRectangle(s->dpy, s->buf, s->gc, 0, 0, WIN_W-1, WIN_H-1);
|
||||||
|
|
||||||
XftDrawDestroy(xd);
|
XftDrawDestroy(xd);
|
||||||
|
|
||||||
|
/* blit double-buffer → window in one shot (eliminates ghosting) */
|
||||||
|
XCopyArea(s->dpy, s->buf, s->win, s->gc, 0, 0, WIN_W, WIN_H, 0, 0);
|
||||||
XFlush(s->dpy);
|
XFlush(s->dpy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1258,7 +1263,8 @@ static void init(Ins *s) {
|
|||||||
(sw - WIN_W)/2, (sh - WIN_H)/2, WIN_W, WIN_H,
|
(sw - WIN_W)/2, (sh - WIN_H)/2, WIN_W, WIN_H,
|
||||||
0, s->depth, InputOutput, s->vis,
|
0, s->depth, InputOutput, s->vis,
|
||||||
CWBackPixel | CWEventMask, &swa);
|
CWBackPixel | CWEventMask, &swa);
|
||||||
s->gc = XCreateGC(s->dpy, s->win, 0, NULL);
|
s->gc = XCreateGC(s->dpy, s->win, 0, NULL);
|
||||||
|
s->buf = XCreatePixmap(s->dpy, s->win, WIN_W, WIN_H, s->depth);
|
||||||
|
|
||||||
/* window title + WM hints */
|
/* window title + WM hints */
|
||||||
XStoreName(s->dpy, s->win, "OrionOS Installer");
|
XStoreName(s->dpy, s->win, "OrionOS Installer");
|
||||||
|
|||||||
Reference in new issue
Block a user