aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authoruser <user@clank>2026-09-29 14:25:34 +0200
committeruser <user@clank>2026-09-29 14:25:34 +0200
commit3760c4e99aff06d09edb0575d7596d0607298e71 (patch)
treec6e1a676cdccb449e1f59309dd622bd14a7bb544 /src
parentskill: the verbs that shipped since, and the bare form's other shape (diff)
downloadslosh-3760c4e99aff06d09edb0575d7596d0607298e71.tar.gz
slosh-3760c4e99aff06d09edb0575d7596d0607298e71.tar.xz
slosh-3760c4e99aff06d09edb0575d7596d0607298e71.zip
mouse: encode pixel reports against the cell size we advertise
A pane is told how big a cell is twice -- in mode 2048's resize report and in the XTWINOPS answers -- and the mouse encoder was told something else: a 1x1 cell, so that cell coordinates and "pixels" were the same number. That held until a program turned on SGR-pixel mouse (mode 1016) by itself. Textual does, the moment in-band resize works, and then divides every coordinate it is sent by the pixels-per-cell we advertised: a click 30 cells across and 9 down arrived as (3, 0), so every click in a Textual app landed in the top-left corner. Hand the encoder the cell size the pane already has, and put the pointer in the middle of its cell. A size that contradicts what the same pane was told about itself is the lie, not the precision.
Diffstat (limited to 'src')
-rw-r--r--src/pane.c28
1 files changed, 20 insertions, 8 deletions
diff --git a/src/pane.c b/src/pane.c
index b9b3f44..5252f14 100644
--- a/src/pane.c
+++ b/src/pane.c
@@ -846,17 +846,29 @@ void pane_send_key(pane_t *p, const input_event_t *ev) {
void pane_send_mouse(pane_t *p, const input_event_t *ev) {
ghostty_mouse_encoder_setopt_from_terminal(p->menc, p->term);
- /* The encoder works in surface pixels. We have no pixels, so we declare a
- * 1x1-pixel cell: cell coordinates and "pixels" become the same number, and
- * SGR-pixel mode degrades to cell precision instead of lying. */
+ /* The encoder works in surface pixels, so we hand it the cell size we
+ * already tell the pane about (mode 2048's resize reports and the XTWINOPS
+ * answers in on_size_report) and put the pointer in the middle of its cell.
+ *
+ * It used to declare a 1x1 cell, so that cell coordinates and "pixels" were
+ * the same number -- which was fine until a program turned on SGR-pixel mouse
+ * (mode 1016). Textual does that by itself the moment in-band resize works,
+ * and then divides every reported coordinate by the pixels-per-cell it got
+ * from OUR resize report (8x16): a click 30 cells across and 9 down arrived
+ * as (3, 0), so every click in a Textual app landed in the top-left corner.
+ * A size that contradicts what the same pane was told about itself is the
+ * lie, not the precision. */
+ uint16_t cw = p->cell_w ? p->cell_w : 1;
+ uint16_t ch = p->cell_h ? p->cell_h : 1;
GhosttyMouseEncoderSize size = GHOSTTY_INIT_SIZED(GhosttyMouseEncoderSize);
- size.screen_width = p->cols;
- size.screen_height = p->rows_n;
- size.cell_width = 1;
- size.cell_height = 1;
+ size.screen_width = (uint32_t)p->cols * cw;
+ size.screen_height = (uint32_t)p->rows_n * ch;
+ size.cell_width = cw;
+ size.cell_height = ch;
ghostty_mouse_encoder_setopt(p->menc, GHOSTTY_MOUSE_ENCODER_OPT_SIZE, &size);
- GhosttyMousePosition pos = {.x = (float)ev->mx, .y = (float)ev->my};
+ GhosttyMousePosition pos = {.x = (float)ev->mx * cw + cw / 2.0f,
+ .y = (float)ev->my * ch + ch / 2.0f};
ghostty_mouse_event_set_position(p->mev, pos);
/* "no button held" is its own thing, not button zero: bare motion (hover)
* must be encoded as none, or a pane in any-event tracking sees nothing. */