unify overlay rendering: one shared layout behind host-GL and wlr-pass backends
This commit is contained in:
parent
ff8a5bc23b
commit
7bd5cd7dbd
1 changed files with 119 additions and 177 deletions
296
kick.c
296
kick.c
|
|
@ -1935,7 +1935,35 @@ static bool app_overlay_row(struct kick_app *app) {
|
|||
return app_live(app) && !app->closing;
|
||||
}
|
||||
|
||||
static void draw_tab_overlay(void) {
|
||||
/* ---------- Alt overlay rendering (shared layout, two backends) ----------
|
||||
Nested mode composites the overlay onto the imported scene blit with the
|
||||
host-GL program; standalone paints it as a second wlr render pass on the
|
||||
output buffer. The layout is identical, so one body emits through three
|
||||
primitives and only the leaves differ per path. All overlay text is
|
||||
greyscale: the pass backend folds the value into its single tint axis
|
||||
(alpha), the only coloring its premultiplied blend exposes for text. */
|
||||
|
||||
struct overlay_backend;
|
||||
typedef void (*overlay_rect_fn)(const struct overlay_backend *,
|
||||
int x, int y, int w, int h,
|
||||
float r, float g, float b, float a);
|
||||
typedef void (*overlay_text_fn)(const struct overlay_backend *,
|
||||
const char *s, int x, int y,
|
||||
float v, float a);
|
||||
typedef bool (*overlay_icon_fn)(const struct overlay_backend *,
|
||||
struct kick_tab_group_member *m,
|
||||
int x, int y, int size, bool active);
|
||||
|
||||
struct overlay_backend {
|
||||
struct wlr_render_pass *pass; /* wlr-pass backend only, else NULL */
|
||||
overlay_rect_fn rect;
|
||||
overlay_text_fn text;
|
||||
/* Draws m's loaded icon dimmed when inactive; returns false when none
|
||||
is loaded so the shared body can paint the placeholder tile. */
|
||||
overlay_icon_fn icon;
|
||||
};
|
||||
|
||||
static void draw_tab_overlay_with(const struct overlay_backend *bk) {
|
||||
if (!host.overlay_visible || server.num_apps < 1) return;
|
||||
|
||||
int margin = 8, boxpad = 6;
|
||||
|
|
@ -1986,14 +2014,14 @@ static void draw_tab_overlay(void) {
|
|||
see-through panel; render_standalone() forces whole-scene repaints
|
||||
while the overlay shows, so a translucent value stays true instead of
|
||||
stacking toward opaque on partial repaints.) */
|
||||
draw_rect(box_x + bw, box_y + bw, box_w - 2 * bw, box_h - 2 * bw,
|
||||
0.07f, 0.07f, 0.09f, 1.0f);
|
||||
draw_rect(box_x, box_y, box_w, bw, 0.45f, 0.45f, 0.48f, 1.0f);
|
||||
draw_rect(box_x, box_y + box_h - bw, box_w, bw,
|
||||
0.45f, 0.45f, 0.48f, 1.0f);
|
||||
draw_rect(box_x, box_y, bw, box_h, 0.45f, 0.45f, 0.48f, 1.0f);
|
||||
draw_rect(box_x + box_w - bw, box_y, bw, box_h,
|
||||
0.45f, 0.45f, 0.48f, 1.0f);
|
||||
bk->rect(bk, box_x + bw, box_y + bw, box_w - 2 * bw, box_h - 2 * bw,
|
||||
0.07f, 0.07f, 0.09f, 1.0f);
|
||||
bk->rect(bk, box_x, box_y, box_w, bw, 0.45f, 0.45f, 0.48f, 1.0f);
|
||||
bk->rect(bk, box_x, box_y + box_h - bw, box_w, bw,
|
||||
0.45f, 0.45f, 0.48f, 1.0f);
|
||||
bk->rect(bk, box_x, box_y, bw, box_h, 0.45f, 0.45f, 0.48f, 1.0f);
|
||||
bk->rect(bk, box_x + box_w - bw, box_y, bw, box_h,
|
||||
0.45f, 0.45f, 0.48f, 1.0f);
|
||||
|
||||
int row = 0;
|
||||
for (int i = 0; i < server.num_apps; i++) {
|
||||
|
|
@ -2044,43 +2072,31 @@ static void draw_tab_overlay(void) {
|
|||
int ctw = overlay_text_width(ctb);
|
||||
int cmw = icon_sz + icon_gap + ctw;
|
||||
int cpen = box_x + boxpad + (row_inner - cmw) / 2;
|
||||
draw_rect(cpen - 2, ry - 1, cmw + 4, row_h,
|
||||
0.22f, 0.22f, 0.25f, 1.0f);
|
||||
draw_text(ctb, cpen + icon_sz + icon_gap,
|
||||
ry + (row_h - host.overlay_font_h) / 2,
|
||||
1.0f, 1.0f, 1.0f, 0.9f);
|
||||
bk->rect(bk, cpen - 2, ry - 1, cmw + 4, row_h,
|
||||
0.22f, 0.22f, 0.25f, 1.0f);
|
||||
bk->text(bk, ctb, cpen + icon_sz + icon_gap,
|
||||
ry + (row_h - host.overlay_font_h) / 2, 1.0f, 0.9f);
|
||||
}
|
||||
for (int k = 0; k < n; k++) {
|
||||
struct kick_tab_group_member *m = members[k];
|
||||
int tw = widths[k];
|
||||
int mw = icon_sz + icon_gap + tw;
|
||||
bool is_cursor = active && app->focus_member == m;
|
||||
draw_rect(pen - 2, ry - 1, mw + 4, row_h,
|
||||
0.22f, 0.22f, 0.25f, 1.0f);
|
||||
bk->rect(bk, pen - 2, ry - 1, mw + 4, row_h,
|
||||
0.22f, 0.22f, 0.25f, 1.0f);
|
||||
if (is_cursor)
|
||||
draw_rect(pen - 2, ry - 1, mw + 4, row_h,
|
||||
0.24f, 0.36f, 0.60f, 0.9f);
|
||||
bk->rect(bk, pen - 2, ry - 1, mw + 4, row_h,
|
||||
0.24f, 0.36f, 0.60f, 0.9f);
|
||||
int mx = pen, my = iy;
|
||||
if (m->icon_tex) {
|
||||
GLfloat tint[4] = { active ? 1.0f : 0.72f,
|
||||
active ? 1.0f : 0.72f,
|
||||
active ? 1.0f : 0.72f, 1.0f };
|
||||
draw_texture_rect(m->icon_tex, m->icon_w, m->icon_h,
|
||||
0, 0, m->icon_w, m->icon_h,
|
||||
mx, my, icon_sz, icon_sz,
|
||||
host.width, host.height, tint);
|
||||
} else {
|
||||
draw_rect(mx, my, icon_sz, icon_sz,
|
||||
0.45f, 0.45f, 0.48f, 0.85f);
|
||||
draw_rect(mx + 3, my + 3, icon_sz - 6, icon_sz - 6,
|
||||
0.07f, 0.07f, 0.09f, 1.0f);
|
||||
if (!bk->icon(bk, m, mx, my, icon_sz, active)) {
|
||||
bk->rect(bk, mx, my, icon_sz, icon_sz,
|
||||
0.45f, 0.45f, 0.48f, 0.85f);
|
||||
bk->rect(bk, mx + 3, my + 3, icon_sz - 6, icon_sz - 6,
|
||||
0.07f, 0.07f, 0.09f, 1.0f);
|
||||
}
|
||||
draw_text(fitt[k], mx + icon_sz + icon_gap,
|
||||
ry + (row_h - host.overlay_font_h) / 2,
|
||||
active ? 1.0f : 0.72f,
|
||||
active ? 1.0f : 0.72f,
|
||||
active ? 1.0f : 0.72f,
|
||||
active ? 1.0f : 0.9f);
|
||||
bk->text(bk, fitt[k], mx + icon_sz + icon_gap,
|
||||
ry + (row_h - host.overlay_font_h) / 2,
|
||||
active ? 1.0f : 0.72f, active ? 1.0f : 0.9f);
|
||||
pen += mw + member_gap;
|
||||
}
|
||||
row++;
|
||||
|
|
@ -2152,149 +2168,73 @@ static void overlay_pass_icon_tex(struct wlr_render_pass *pass,
|
|||
wlr_render_pass_add_texture(pass, &o);
|
||||
}
|
||||
|
||||
static void draw_tab_overlay_pass(struct wlr_render_pass *pass) {
|
||||
if (!host.overlay_visible || server.num_apps < 1) return;
|
||||
/* --- host-GL backend (nested): leaves onto the imported scene blit --- */
|
||||
|
||||
int margin = 8, boxpad = 6;
|
||||
int icon_sz = OVERLAY_ICON_SZ, icon_gap = 8, member_gap = 12;
|
||||
int row_h = host.overlay_font_h > 0 ? host.overlay_font_h + 8 : 18;
|
||||
int row_gap = 8;
|
||||
if (row_h < icon_sz + 4) row_h = icon_sz + 4;
|
||||
int max_row_w = 0, n_rows = 0;
|
||||
for (int i = 0; i < server.num_apps; i++) {
|
||||
struct kick_app *app = server.apps[i];
|
||||
if (!app_overlay_row(app)) continue;
|
||||
(void)app_row_title(app);
|
||||
int n = 0, row_w = 0;
|
||||
struct kick_tab_group_member *m;
|
||||
wl_list_for_each(m, &app->group_members, link) {
|
||||
if (!member_mapped(m)) continue;
|
||||
char tb[64];
|
||||
const char *t = overlay_member_title(m, tb, sizeof(tb));
|
||||
row_w += icon_sz + icon_gap + overlay_text_width(t);
|
||||
n++;
|
||||
}
|
||||
if (n > 0) {
|
||||
if (n > 1) row_w += (n - 1) * member_gap;
|
||||
} else {
|
||||
const char *ct = (app->cmd && app->cmd[0]) ? app->cmd : "pending";
|
||||
row_w = icon_sz + icon_gap + overlay_text_width(ct);
|
||||
}
|
||||
if (row_w > max_row_w) max_row_w = row_w;
|
||||
n_rows++;
|
||||
}
|
||||
if (n_rows == 0) return;
|
||||
|
||||
int avail_w = host.width - 2 * margin - 2 * boxpad;
|
||||
if (max_row_w > avail_w) max_row_w = avail_w;
|
||||
|
||||
int box_w = max_row_w + 2 * boxpad;
|
||||
int box_h = n_rows * row_h + (n_rows - 1) * row_gap + 2 * boxpad;
|
||||
if (box_w > host.width - 2 * margin) box_w = host.width - 2 * margin;
|
||||
if (box_h > host.height - 2 * margin) box_h = host.height - 2 * margin;
|
||||
int box_x = (host.width - box_w) / 2;
|
||||
int box_y = (host.height - box_h) / 2;
|
||||
|
||||
int bw = 1;
|
||||
/* Opaque backdrop filling the box, framed by four rim strokes -- keeps
|
||||
the titles readable over any content. (Alpha below 1.0 here gives a
|
||||
see-through panel; render_standalone() forces whole-scene repaints
|
||||
while the overlay shows, so a translucent value stays true instead of
|
||||
stacking toward opaque on partial repaints.) */
|
||||
overlay_pass_rect(pass, box_x + bw, box_y + bw, box_w - 2 * bw,
|
||||
box_h - 2 * bw, 0.07f, 0.07f, 0.09f, 1.0f);
|
||||
overlay_pass_rect(pass, box_x, box_y, box_w, bw,
|
||||
0.45f, 0.45f, 0.48f, 1.0f);
|
||||
overlay_pass_rect(pass, box_x, box_y + box_h - bw, box_w, bw,
|
||||
0.45f, 0.45f, 0.48f, 1.0f);
|
||||
overlay_pass_rect(pass, box_x, box_y, bw, box_h,
|
||||
0.45f, 0.45f, 0.48f, 1.0f);
|
||||
overlay_pass_rect(pass, box_x + box_w - bw, box_y, bw, box_h,
|
||||
0.45f, 0.45f, 0.48f, 1.0f);
|
||||
|
||||
int row = 0;
|
||||
for (int i = 0; i < server.num_apps; i++) {
|
||||
struct kick_app *app = server.apps[i];
|
||||
if (!app_overlay_row(app)) continue;
|
||||
(void)app_row_title(app);
|
||||
int ry = box_y + boxpad + row * (row_h + row_gap);
|
||||
bool active = app == server.active_app;
|
||||
int row_inner = box_w - 2 * boxpad;
|
||||
|
||||
struct kick_tab_group_member *members[32];
|
||||
char fitt[32][256];
|
||||
int widths[32];
|
||||
int n = 0;
|
||||
struct kick_tab_group_member *m;
|
||||
wl_list_for_each(m, &app->group_members, link) {
|
||||
if (!member_mapped(m)) continue;
|
||||
if (n >= 32) break;
|
||||
if (overlay_member_icon_needs_load(m))
|
||||
overlay_icon_load_member(m);
|
||||
members[n++] = m;
|
||||
}
|
||||
int share = 0;
|
||||
if (n > 0) {
|
||||
int avail = row_inner - n * (icon_sz + icon_gap);
|
||||
if (n > 1) avail -= (n - 1) * member_gap;
|
||||
share = avail / n;
|
||||
if (share < 0) share = 0;
|
||||
}
|
||||
int total_w = 0;
|
||||
for (int k = 0; k < n; k++) {
|
||||
char tb[64];
|
||||
const char *dt = overlay_member_title(members[k], tb, sizeof(tb));
|
||||
fit_text(dt, share, fitt[k], sizeof(fitt[k]));
|
||||
widths[k] = overlay_text_width(fitt[k]);
|
||||
total_w += icon_sz + icon_gap + widths[k];
|
||||
}
|
||||
if (n > 1) total_w += (n - 1) * member_gap;
|
||||
|
||||
int pen = box_x + boxpad + (row_inner - total_w) / 2;
|
||||
int iy = ry + (row_h - icon_sz) / 2;
|
||||
if (n == 0) {
|
||||
const char *ct = (app->cmd && app->cmd[0]) ? app->cmd : "pending";
|
||||
char ctb[64];
|
||||
int cavail = row_inner - (icon_sz + icon_gap) - 4;
|
||||
if (cavail < 0) cavail = 0;
|
||||
fit_text(ct, cavail, ctb, sizeof(ctb));
|
||||
int ctw = overlay_text_width(ctb);
|
||||
int cmw = icon_sz + icon_gap + ctw;
|
||||
int cpen = box_x + boxpad + (row_inner - cmw) / 2;
|
||||
overlay_pass_rect(pass, cpen - 2, ry - 1, cmw + 4, row_h,
|
||||
0.22f, 0.22f, 0.25f, 1.0f);
|
||||
overlay_pass_text(pass, ctb, cpen + icon_sz + icon_gap,
|
||||
ry + (row_h - host.overlay_font_h) / 2, 1.0f);
|
||||
}
|
||||
for (int k = 0; k < n; k++) {
|
||||
struct kick_tab_group_member *m = members[k];
|
||||
int tw = widths[k];
|
||||
int mw = icon_sz + icon_gap + tw;
|
||||
bool is_cursor = active && app->focus_member == m;
|
||||
overlay_pass_rect(pass, pen - 2, ry - 1, mw + 4, row_h,
|
||||
0.22f, 0.22f, 0.25f, 1.0f);
|
||||
if (is_cursor)
|
||||
overlay_pass_rect(pass, pen - 2, ry - 1, mw + 4, row_h,
|
||||
0.24f, 0.36f, 0.60f, 0.9f);
|
||||
int mx = pen, my = iy;
|
||||
if (m->icon_wlr) {
|
||||
overlay_pass_icon_tex(pass, m->icon_wlr, mx, my, icon_sz,
|
||||
active ? 1.0f : 0.72f);
|
||||
} else {
|
||||
overlay_pass_rect(pass, mx, my, icon_sz, icon_sz,
|
||||
0.45f, 0.45f, 0.48f, 0.85f);
|
||||
overlay_pass_rect(pass, mx + 3, my + 3, icon_sz - 6, icon_sz - 6,
|
||||
0.07f, 0.07f, 0.09f, 1.0f);
|
||||
}
|
||||
overlay_pass_text(pass, fitt[k], mx + icon_sz + icon_gap,
|
||||
ry + (row_h - host.overlay_font_h) / 2,
|
||||
active ? 1.0f : 0.648f);
|
||||
pen += mw + member_gap;
|
||||
}
|
||||
row++;
|
||||
}
|
||||
static void ovl_gl_rect(const struct overlay_backend *bk, int x, int y,
|
||||
int w, int h, float r, float g, float b, float a) {
|
||||
(void)bk;
|
||||
draw_rect(x, y, w, h, r, g, b, a);
|
||||
}
|
||||
|
||||
static void ovl_gl_text(const struct overlay_backend *bk, const char *s,
|
||||
int x, int y, float v, float a) {
|
||||
(void)bk;
|
||||
draw_text(s, x, y, v, v, v, a);
|
||||
}
|
||||
|
||||
static bool ovl_gl_icon(const struct overlay_backend *bk,
|
||||
struct kick_tab_group_member *m,
|
||||
int x, int y, int size, bool active) {
|
||||
(void)bk;
|
||||
if (!m->icon_tex)
|
||||
return false;
|
||||
GLfloat tint[4] = { active ? 1.0f : 0.72f,
|
||||
active ? 1.0f : 0.72f,
|
||||
active ? 1.0f : 0.72f, 1.0f };
|
||||
draw_texture_rect(m->icon_tex, m->icon_w, m->icon_h,
|
||||
0, 0, m->icon_w, m->icon_h,
|
||||
x, y, size, size, host.width, host.height, tint);
|
||||
return true;
|
||||
}
|
||||
|
||||
static const struct overlay_backend overlay_backend_gl = {
|
||||
NULL, ovl_gl_rect, ovl_gl_text, ovl_gl_icon,
|
||||
};
|
||||
|
||||
/* --- wlr-pass backend (standalone): leaves onto the output buffer --- */
|
||||
|
||||
static void ovl_pass_rect(const struct overlay_backend *bk, int x, int y,
|
||||
int w, int h, float r, float g, float b, float a) {
|
||||
overlay_pass_rect(bk->pass, x, y, w, h, r, g, b, a);
|
||||
}
|
||||
|
||||
static void ovl_pass_text(const struct overlay_backend *bk, const char *s,
|
||||
int x, int y, float v, float a) {
|
||||
/* Greyscale text: the dim value folds into the one tint axis. */
|
||||
overlay_pass_text(bk->pass, s, x, y, v * a);
|
||||
}
|
||||
|
||||
static bool ovl_pass_icon(const struct overlay_backend *bk,
|
||||
struct kick_tab_group_member *m,
|
||||
int x, int y, int size, bool active) {
|
||||
if (!m->icon_wlr)
|
||||
return false;
|
||||
overlay_pass_icon_tex(bk->pass, m->icon_wlr, x, y, size,
|
||||
active ? 1.0f : 0.72f);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Nested entry: composite onto the host window's blitted frame. */
|
||||
static void draw_tab_overlay(void) {
|
||||
draw_tab_overlay_with(&overlay_backend_gl);
|
||||
}
|
||||
|
||||
/* Standalone entry: second render pass on the output buffer. */
|
||||
static void draw_tab_overlay_pass(struct wlr_render_pass *pass) {
|
||||
struct overlay_backend bk = { pass, ovl_pass_rect, ovl_pass_text,
|
||||
ovl_pass_icon };
|
||||
draw_tab_overlay_with(&bk);
|
||||
}
|
||||
|
||||
/* ===================== Server-side wlroots setup ===================== */
|
||||
|
||||
|
|
@ -6202,11 +6142,13 @@ static void overlay_refresh_if_visible(void) {
|
|||
}
|
||||
|
||||
static void handle_toplevel_set_title(struct wl_listener *l, void *data) {
|
||||
(void)l;
|
||||
(void)data;
|
||||
overlay_refresh_if_visible();
|
||||
}
|
||||
|
||||
static void handle_toplevel_set_app_id(struct wl_listener *l, void *data) {
|
||||
(void)l;
|
||||
(void)data;
|
||||
overlay_refresh_if_visible();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue