aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-22 18:30:18 +0200
committeruser <user@clank>2026-08-22 18:30:18 +0200
commitf5ce221ee853d430113063cb85c43bbea078818e (patch)
tree691a77196558e0d5f15aaed6dab889abc725a12e
parentslosh: put-away panes are miniature pane frames (diff)
downloadslosh-f5ce221ee853d430113063cb85c43bbea078818e.tar.gz
slosh-f5ce221ee853d430113063cb85c43bbea078818e.tar.xz
slosh-f5ce221ee853d430113063cb85c43bbea078818e.zip
slosh: paint the padding ring, so a float cannot be seen through
A tiled pane sits on a cleared screen, so unpainted padding looked fine by accident; a float sits on whatever was composited under it, and every unpainted cell let that show through. draw_frame now fills the ring between border and contents with exactly what screen_clear leaves, and a suspended pane's never-composed content rect gets the same treatment.
-rw-r--r--src/app_draw.c25
-rw-r--r--tests/test_float.py27
2 files changed, 52 insertions, 0 deletions
diff --git a/src/app_draw.c b/src/app_draw.c
index 24cc50d..04e8264 100644
--- a/src/app_draw.c
+++ b/src/app_draw.c
@@ -573,6 +573,25 @@ static void draw_frame(app_t *a, screen_t *s, node_t *leaf) {
screen_text(s, x1, y, vbar, fg, NO_COLOR, attrs);
}
+ /* The padding ring between the border and the contents, painted blank
+ * rather than left alone. A tiled pane sits on a cleared screen, so leaving
+ * it unpainted used to look the same by accident — but a float sits on
+ * whatever was composited under it, and every unpainted cell lets that show
+ * through. Blank-with-no-colour is exactly what screen_clear leaves, so a
+ * tiled pane looks as it always did, and with no padding configured the
+ * ring is empty and this writes nothing. */
+ {
+ rect_t c = leaf->content;
+ for (uint16_t y = (uint16_t)(r.y + 1); y < y1; y++)
+ for (uint16_t x = (uint16_t)(r.x + 1); x < x1; x++) {
+ if (x >= c.x && x < c.x + c.w && y >= c.y && y < c.y + c.h) {
+ x = (uint16_t)(c.x + c.w - 1); /* jump past the contents */
+ continue;
+ }
+ screen_text(s, x, y, " ", NO_COLOR, NO_COLOR, 0);
+ }
+ }
+
/* A pane that rang, marked just inside its corner: the same place on every
* pane, whatever its title is doing. */
if (CFG.bell_indicator && pane_bell(leaf->pane) && r.w > 4)
@@ -1360,6 +1379,12 @@ static void draw_cb(node_t *n, void *ud) {
/* Falls through to the shader pass rather than returning: a pane that has
* not started is a state you can want to colour, and its label is the only
* content it has. */
+ /* Nothing has ever composed into this content rect, so paint it blank
+ * first — for the same reason draw_frame paints the padding ring: a
+ * floating suspended pane must not show what is under it. */
+ for (uint16_t y = n->content.y; y < n->content.y + n->content.h; y++)
+ for (uint16_t x = n->content.x; x < n->content.x + n->content.w; x++)
+ screen_text(d->s, x, y, " ", NO_COLOR, NO_COLOR, 0);
/* The pane exists, is laid out, and has run nothing. Say what it would. */
const char *label = pane_label(n->pane);
char line[256];
diff --git a/tests/test_float.py b/tests/test_float.py
index 1745ef7..b9e3233 100644
--- a/tests/test_float.py
+++ b/tests/test_float.py
@@ -912,6 +912,32 @@ def test_the_key_and_the_palette_both_run_it():
check("running it floats the pane", len(floats(s)) == 1, str(here(s)))
+def test_the_padding_ring_hides_what_is_under_it():
+ """A float's padding is painted blank, not left unpainted. A tiled pane
+ sits on a cleared screen, so an unpainted ring looked fine by accident —
+ a float sits on whatever was composited below it, and every unpainted
+ cell let that show through."""
+ conf = cfg("padding 2\n")
+ filler = ["/bin/sh", "-c", 'printf "X%.0s" $(seq 1 4000); stty raw -echo; cat']
+ with Session(filler, cols=90, rows=24, config=conf) as s:
+ s.settle(50)
+ s.api("split", dir="cols")
+ s.settle(50)
+ s.api("float")
+ s.settle(100)
+ fl = floats(s)[0]
+ snap = s.snapshot()
+ # the ring between the border and the content, on a content row and
+ # on a padding row: all of it over the X-filled backdrop, all blank
+ row = snap.line(fl["content_y"])
+ left = row[fl["x"] + 1 : fl["content_x"]]
+ right = row[fl["content_x"] + fl["content_w"] : fl["x"] + fl["w"] - 1]
+ top = snap.line(fl["y"] + 1)[fl["x"] + 1 : fl["x"] + fl["w"] - 1]
+ check("the left padding is blank", set(left) <= {" "}, repr(left))
+ check("the right padding is blank", set(right) <= {" "}, repr(right))
+ check("a full padding row is blank", set(top) <= {" "}, repr(top))
+
+
if __name__ == "__main__":
test_floating_lifts_a_pane_out_of_the_layout()
test_the_overlap_belongs_to_the_float()
@@ -946,4 +972,5 @@ if __name__ == "__main__":
test_a_layout_of_only_floats_self_heals()
test_a_float_is_not_a_drop_target()
test_the_key_and_the_palette_both_run_it()
+ test_the_padding_ring_hides_what_is_under_it()
sys.exit(report())