aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorsl0p <sl0p@sl0p.foo>2026-08-14 00:28:57 +0200
committersl0p <sl0p@sl0p.foo>2026-08-14 00:28:57 +0200
commit61ac1318eaad46363235d41e9cbc31eb7e3e2f84 (patch)
treeef9b88ec45dbb7227ad15736f80aa22c3354c6ab /src
parentsl0ptty: the border is the button — click an edge to split toward it (diff)
downloadslosh-61ac1318eaad46363235d41e9cbc31eb7e3e2f84.tar.gz
slosh-61ac1318eaad46363235d41e9cbc31eb7e3e2f84.tar.xz
slosh-61ac1318eaad46363235d41e9cbc31eb7e3e2f84.zip
sl0ptty: fix the split guide describing the layout from before the split
Which border the pointer is over was remembered from the last motion event, so after a click split the guide stayed attached to the old pane and the old edge until the mouse moved and corrected it. It is derived during the paint now: draw_split_guide asks the hit list where the pointer is, using the entries that same pass just registered for that pane. Drawing and hit-testing already could not disagree; now drawing and the layout cannot either. The pointer position is the only thing kept. Same lesson as the hit list, one level up: do not remember what you can derive from the frame you are drawing. Regression test splits by clicking a border and then deliberately does not move the mouse, asserting exactly one pane shows a guide, that it is the pane the pointer is actually inside, and that it is on the edge the pointer is on. 391 checks green.
Diffstat (limited to 'src')
-rw-r--r--src/app.c52
1 files changed, 30 insertions, 22 deletions
diff --git a/src/app.c b/src/app.c
index e5a9e57..c913029 100644
--- a/src/app.c
+++ b/src/app.c
@@ -130,11 +130,12 @@ struct app {
char side; /* border press: 'l' 'r' 't' 'b' */
} drag;
- /* Which pane border the pointer is over, for the split guide. Recomputed
- * from the hit list on every motion, so it cannot describe a border that is
- * not there any more. */
- uint32_t hover_pane;
- char hover_side;
+ /* Where the pointer is. Which border that *means* is derived during the
+ * paint, from the rects painted in that same pass — remembering the answer
+ * instead left the guide describing the layout from before a split, until
+ * the mouse moved and corrected it. */
+ uint16_t ptr_x, ptr_y;
+ bool ptr_valid;
/* Transient announcements: "copied 13 chars", a notification from a pane,
* a config reload. They stack upward from the bottom right and expire on
@@ -1181,12 +1182,31 @@ static void draw_pane_status(screen_t *s, node_t *leaf, color_t fg,
* dashed line crosses it — the first version was painted under the terminal
* and was invisible. Hover only, so an idle frame stays quiet. */
static void draw_split_guide(app_t *a, screen_t *s, node_t *leaf) {
- if (a->hover_pane != leaf->id || !a->hover_side) return;
+ if (!a->ptr_valid) return;
+ if (a->drag.kind == DRAG_TITLE || a->drag.kind == DRAG_SELECT ||
+ a->drag.kind == DRAG_EDGE)
+ return; /* a drag in progress means the pointer is busy */
+
+ /* Ask the hit list where the pointer is, using the entries this very pass
+ * registered for this pane. Drawing and hit-testing cannot disagree, and
+ * neither can drawing and *the layout*. */
+ const char *action = hit_test(&s->hits, a->ptr_x, a->ptr_y);
+ if (!action) return;
+ char side = 0;
+ char want[48];
+ snprintf(want, sizeof want, "border:%u:", leaf->id);
+ if (strncmp(action, want, strlen(want)) == 0) {
+ side = action[strlen(want)];
+ } else {
+ snprintf(want, sizeof want, "title:%u", leaf->id);
+ if (strcmp(action, want) == 0) side = 't';
+ }
+ if (!side) return;
+
rect_t r = leaf->rect;
if (r.w < 4 || r.h < 4) return;
uint16_t x1 = (uint16_t)(r.x + r.w - 1), y1 = (uint16_t)(r.y + r.h - 1);
color_t hi = FRAME_FOCUS;
- char side = a->hover_side;
if (side == 'l' || side == 'r') {
uint16_t bx = side == 'l' ? r.x : x1;
@@ -1896,21 +1916,9 @@ void app_event(app_t *a, const input_event_t *ev) {
if (!a->painted) break;
const char *action = hit_test(&a->painted->hits, ev->mx, ev->my);
- /* Which border the pointer is over, for the guide. */
- if (ev->maction == MOUSE_MOTION && a->drag.kind == DRAG_NONE) {
- uint32_t hp = 0;
- char hs = 0;
- if (action && strncmp(action, "border:", 7) == 0) {
- hp = (uint32_t)strtoul(action + 7, NULL, 10);
- const char *colon = strchr(action + 7, ':');
- hs = colon && colon[1] ? colon[1] : 0;
- } else if (action && strncmp(action, "title:", 6) == 0) {
- hp = (uint32_t)strtoul(action + 6, NULL, 10);
- hs = 't';
- }
- a->hover_pane = hp;
- a->hover_side = hs;
- }
+ a->ptr_x = ev->mx;
+ a->ptr_y = ev->my;
+ a->ptr_valid = true;
if (a->drag.kind != DRAG_NONE) {
if (ev->maction == MOUSE_MOTION) {