diff options
| author | user <user@clank> | 2026-08-14 13:52:42 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-08-14 13:52:42 +0200 |
| commit | c7c8111bb3d20acc926fa28db6bccc6752a5e87e (patch) | |
| tree | 450cdfc188c1128dd53eb5203a7efe15b89345ba /src/app.c | |
| parent | sl0ppty: terminal shaders — a colour pass over pane contents (diff) | |
| download | slosh-c7c8111bb3d20acc926fa28db6bccc6752a5e87e.tar.gz slosh-c7c8111bb3d20acc926fa28db6bccc6752a5e87e.tar.xz slosh-c7c8111bb3d20acc926fa28db6bccc6752a5e87e.zip | |
sl0ppty: drag greys the other panes, and dim_unfocused
The first two consumers of the shader pass, and between them they settle how a
pane gets one.
Dragging a pane by its title now greys every *other* pane, so the one that is
moving lifts off the page — which is the thing that made a colour pass worth
building. It engages only once the pointer has actually moved, because a press
on a title that turns out to be a click would otherwise flash the whole
session grey on its way to doing nothing. dim_unfocused fades everything but
the focused pane and is off by default: an always-on effect is the kind you
stop seeing and start fighting, so it should be asked for.
Both are derived every frame rather than attached and cleared. Focus and drags
move through far too many paths — hover, click, the finder, a close, a layout
apply, any keystroke ending a drag — to keep an attachment in sync with, and a
pane left grey by the one path that forgot is a bug that only turns up in
front of someone. The rect and the collapsed flag are recomputed every pass
for exactly this reason; this is the same rule applied to colour. It also
makes the awkward cases free: dropping into the margin, a keystroke ending the
drag, or the dragged pane being closed under it all un-grey without anywhere
having to say so, and there are tests for each because "it turns off again" is
the whole risk.
The two policies replace rather than stack. Dragging an unfocused pane while
dim_unfocused is on would otherwise give it two reasons to be grey, and they
compound into one muddy grey that reads as neither; the drag wins, so the
dragged pane is at full colour whatever the focus says.
shade_apply no longer caps at SHADE_MAX. That cap was right when the only
shaders were the ones a pane had attached, and wrong the moment the session
derives one on top of them: a full stack would have silently dropped it. The
count is the caller's to bound.
The chrome check that mattered was already there: test_drop_target_is_visible
samples a frame corner mid-drag, and it still passes, because the pass runs
between the contents and the chrome drawn over them.
Diffstat (limited to 'src/app.c')
| -rw-r--r-- | src/app.c | 44 |
1 files changed, 39 insertions, 5 deletions
@@ -1448,18 +1448,52 @@ size_t app_shade_count(app_t *a, uint32_t pane_id) { return n ? n->nshaders : 0; } -/* A pane with no shaders costs nothing: no context is built and no cell is - * visited, so an unshaded session emits the same bytes it did before. */ +/* The session's opinion about this pane at this moment, as a shader. + * + * Derived every frame rather than attached and remembered. Focus and drags + * move through too many paths — hover, click, the finder, a close, a layout — + * to keep an attachment in sync with, and a pane left grey by the one path + * that forgot to clear it is a bug that only shows up in front of someone. + * The rect and the collapsed flag are recomputed every pass for exactly this + * reason; this is the same rule applied to colour. */ +static size_t policy_shader(app_t *a, node_t *n, shader_t *out) { + /* Only once the pointer has actually moved: a press that turns out to be a + * click would otherwise flash the whole session grey on its way to nothing. */ + if (a->drag.kind == DRAG_TITLE && a->drag.moved) { + /* The pane being dragged keeps its colour and everything else goes grey, + * so the one that is moving lifts off the page. This replaces the focus + * dimming rather than stacking with it: two reasons to be grey compound + * into one muddy grey that reads as neither. */ + if (n->id == a->drag.src || !CFG.drag_grayscale) return 0; + return shader_make(out, "grayscale", (color_t){0}, CFG.drag_grayscale) ? 1 + : 0; + } + if (CFG.dim_unfocused && n != cur(a)->focus) + return shader_make(out, "dim", (color_t){0}, CFG.dim_unfocused) ? 1 : 0; + return 0; +} + +/* A pane with nothing to apply costs nothing: no context is built and no cell + * is visited, so an unshaded session emits the same bytes it did before. */ static void shade_leaf(app_t *a, screen_t *s, node_t *n) { - if (!n->nshaders) return; + shader_t chain[SHADE_MAX + 1]; + size_t nc = 0; + + /* Attached first, policy last: a pane's own colour is the thing the + * session's opinion of the moment is then applied to. */ + for (size_t i = 0; i < n->nshaders && nc < SHADE_MAX; i++) + chain[nc++] = n->shaders[i]; + nc += policy_shader(a, n, &chain[nc]); + + if (!nc) return; shade_ctx_t base = { .now_ms = now_ms_(), .focused = n == cur(a)->focus, .default_fg = CFG.default_fg, .default_bg = CFG.default_bg, }; - shade_apply(s, n->shaders, n->nshaders, n->content.x, n->content.y, - n->content.w, n->content.h, &base); + shade_apply(s, chain, nc, n->content.x, n->content.y, n->content.w, + n->content.h, &base); } static void draw_node(app_t *a, screen_t *s, node_t *n); |
