qwen: scroll the chat with the keyboard and the mouse wheel #152

Open
nonos-sync wants to merge 7 commits from nonos-sync/gh-605 into main AGit
Member

The Qwen chat window drew only the newest lines that fit (qwenui_draw.cpp, from = lines.size() - fit). Earlier turns, and the start of any answer taller than the window, could not be brought back. This adds scrolling with the keyboard and the mouse wheel.

Base is main. This replaces #602, which targeted release/0.9.2 before that branch was merged here (#601); the commits are the same five, cherry-picked onto main.

What changes

Keys (qwen only). Up/Down move one line, Page Up/Down one page, Home goes to the oldest line and End to the newest. These keys already reached qwen as the NONOS codes 0x1201..0x1208, which the bridge forwards unchanged; window_key just never matched them. They are named in qwenui.h, hand-synced with app_skeleton/src/input/keys.rs.

One geometry for drawing and scrolling. Line building and the row count move out of ui_draw into ui_lines / ui_fit. The painter and ui_scroll_key both call them, so the scroll range is always the drawn range. View::back counts lines up from the newest; at 0 the window behaves exactly as before. ui_from clamps back, so a resize that shortens the history can't index past it.

While loading or answering. busy_stop used to keep nothing but Esc; it now gives every key to ui_scroll_key and redraws when the view moved. The error screen left by a refused model scrolls too. When scrolled up, to_window adds to back the lines the streaming answer gained, so the text being read holds still. Sending a line, /reset and End all return to the newest.

Wheel through the bridge (capsule_linux). The bridge's input_router subscription now takes Wheel (KINDS 0x6B -> 0x7B). A guest holding a wl_pointer gets a vertical wl_pointer.axis followed by frame, at 10 surface units per notch, clamped to app_skeleton::scroll::MAX_NOTCHES. The sign is flipped: Wayland's positive is toward the end, NONOS delta_y's is toward the top.

Wheel in qwen. qwen now also does wl_seat.get_pointer, under a new id PTR appended after the others so no existing id moves. A vertical axis becomes a Key carrying notches; a nonzero value smaller than one notch counts as one. Horizontal axis, zero values and the pointer's enter/motion/button/frame events produce nothing. Scrolling is 3 lines per notch, as in app_skeleton::scroll::WHEEL_LINES.

Hand-synced numbers

  • wl_seat.get_pointer = 0: ops.rs <-> qwenwl_open.cpp
  • wl_pointer.axis = 4, axis 0 = vertical, 10 units per notch: input_send.rs <-> qwenwl_loop.cpp
  • NONOS key codes 0x1201..0x1208: app_skeleton/src/input/keys.rs <-> qwenui.h

Not changed

  • Guest windows stay frameless.
  • The footer hint stays as it is: it is full (83 of 84 cells), so it doesn't advertise the new keys.
  • The bridge's pointer motion and button forwarding is untouched; qwen ignores those events.

Testing

  • make nonos-mk-qwenscroll-check NONOS_LINUX_GUESTS=1 NONOS_QWEN=1 is a new host check. It covers:

    • ui_from clamping, including the resize-shrink case;
    • every scroll key and the wheel, with steps and clamps checked at both ends and other keys left inert;
    • the real wl_poll decoding wl_pointer.axis over a socketpair.

    It has been shown to fail when WHEEL_LINES or the sub-notch rule is broken.

  • The existing qwenresize_check still passes.

  • On macOS both qwen checks build only with a test-only memfd_create shim, which is not in the tree. The make targets themselves have not been run on a Linux host.

  • On main @ 514cfd078: cargo check --release --target ../x86_64-nonos-user.json -Zbuild-std=core,alloc -Zbuild-std-features=compiler-builtins-mem in userland/capsule_linux gives 0 warnings, and rustfmt --check is clean.

  • make dev-image builds. The staged nonos.img contains the new qwenchat binaries byte for byte. make dev-boot boots clean (Handoff OK, boot attest enrolled, capsules spawned) and Qwen loads its model.

  • Scrolling has not yet been confirmed on a running system. Overflow the chat, then try Page Up/Down, Up/Down, Home/End and the wheel, including while it answers.


Opened on GitHub by senseix21 as pull request 605. Review and merge happen there while this repository is kept in step from GitHub; this copy follows it, and is marked merged or closed when it is.

The Qwen chat window drew only the newest lines that fit (`qwenui_draw.cpp`, `from = lines.size() - fit`). Earlier turns, and the start of any answer taller than the window, could not be brought back. This adds scrolling with the keyboard and the mouse wheel. Base is `main`. This replaces [#602](https://github.com/NON-OS/nonos-micro-kernel/issues/602), which targeted `release/0.9.2` before that branch was merged here ([#601](https://github.com/NON-OS/nonos-micro-kernel/issues/601)); the commits are the same five, cherry-picked onto main. ## What changes **Keys (qwen only).** Up/Down move one line, Page Up/Down one page, Home goes to the oldest line and End to the newest. These keys already reached qwen as the NONOS codes `0x1201`..`0x1208`, which the bridge forwards unchanged; `window_key` just never matched them. They are named in `qwenui.h`, hand-synced with `app_skeleton/src/input/keys.rs`. **One geometry for drawing and scrolling.** Line building and the row count move out of `ui_draw` into `ui_lines` / `ui_fit`. The painter and `ui_scroll_key` both call them, so the scroll range is always the drawn range. `View::back` counts lines up from the newest; at 0 the window behaves exactly as before. `ui_from` clamps `back`, so a resize that shortens the history can't index past it. **While loading or answering.** `busy_stop` used to keep nothing but Esc; it now gives every key to `ui_scroll_key` and redraws when the view moved. The error screen left by a refused model scrolls too. When scrolled up, `to_window` adds to `back` the lines the streaming answer gained, so the text being read holds still. Sending a line, `/reset` and End all return to the newest. **Wheel through the bridge (`capsule_linux`).** The bridge's input_router subscription now takes `Wheel` (`KINDS` 0x6B -> 0x7B). A guest holding a `wl_pointer` gets a vertical `wl_pointer.axis` followed by `frame`, at 10 surface units per notch, clamped to `app_skeleton::scroll::MAX_NOTCHES`. The sign is flipped: Wayland's positive is toward the end, NONOS `delta_y`'s is toward the top. **Wheel in qwen.** qwen now also does `wl_seat.get_pointer`, under a new id `PTR` appended after the others so no existing id moves. A vertical axis becomes a `Key` carrying notches; a nonzero value smaller than one notch counts as one. Horizontal axis, zero values and the pointer's enter/motion/button/frame events produce nothing. Scrolling is 3 lines per notch, as in `app_skeleton::scroll::WHEEL_LINES`. ## Hand-synced numbers - `wl_seat.get_pointer` = 0: `ops.rs` <-> `qwenwl_open.cpp` - `wl_pointer.axis` = 4, axis 0 = vertical, 10 units per notch: `input_send.rs` <-> `qwenwl_loop.cpp` - NONOS key codes `0x1201`..`0x1208`: `app_skeleton/src/input/keys.rs` <-> `qwenui.h` ## Not changed - Guest windows stay frameless. - The footer hint stays as it is: it is full (83 of 84 cells), so it doesn't advertise the new keys. - The bridge's pointer motion and button forwarding is untouched; qwen ignores those events. ## Testing - `make nonos-mk-qwenscroll-check NONOS_LINUX_GUESTS=1 NONOS_QWEN=1` is a new host check. It covers: - `ui_from` clamping, including the resize-shrink case; - every scroll key and the wheel, with steps and clamps checked at both ends and other keys left inert; - the real `wl_poll` decoding `wl_pointer.axis` over a socketpair. It has been shown to fail when `WHEEL_LINES` or the sub-notch rule is broken. - The existing `qwenresize_check` still passes. - On macOS both qwen checks build only with a test-only `memfd_create` shim, which is not in the tree. The make targets themselves have not been run on a Linux host. - On `main` @ 514cfd078: `cargo check --release --target ../x86_64-nonos-user.json -Zbuild-std=core,alloc -Zbuild-std-features=compiler-builtins-mem` in `userland/capsule_linux` gives 0 warnings, and `rustfmt --check` is clean. - `make dev-image` builds. The staged `nonos.img` contains the new qwenchat binaries byte for byte. `make dev-boot` boots clean (Handoff OK, boot attest enrolled, capsules spawned) and Qwen loads its model. - **Scrolling has not yet been confirmed on a running system.** Overflow the chat, then try Page Up/Down, Up/Down, Home/End and the wheel, including while it answers. --- Opened on GitHub by senseix21 as [pull request 605](https://github.com/NON-OS/microkernel/pull/605). Review and merge happen there while this repository is kept in step from GitHub; this copy follows it, and is marked merged or closed when it is.
The chat window drew only the newest lines that fit, so earlier turns and
the head of any answer taller than the window could not be seen again.

The conversation's line building and row count move out of ui_draw into
ui_lines and ui_fit, which the painter and the new scroll handler share,
so the range a key may scroll to is always the range that is drawn.
View::back counts lines up from the newest; 0 keeps today's behaviour.
Sending a line and /reset return to the newest. The keys arrive as the
NONOS codes the bridge forwards unchanged, named here and hand-synced
with app_skeleton's keys.rs.

Refs: release/0.9.2 (PR #601)
Scrolling only worked between turns: while the model loads or answers,
busy_stop was the only reader of keys and kept nothing but Esc, and the
error a refused model leaves on screen could not be scrolled either.
Both now offer each key to ui_scroll_key and redraw when it moved.

Scrolled up, the text being read used to slide away as the answer grew
under it. to_window now grows back by the lines the answer gained, so
the view holds still; at the newest line it follows the answer as before.

Refs: release/0.9.2 (PR #601)
Native apps scroll with the wheel, but a Linux guest never saw it: the
bridge's input_router subscription left the Wheel kind out, so the
router never delivered one, and the bridge had no wl_pointer.axis to
send it as.

The subscription now takes Wheel, and a guest holding a wl_pointer gets
a vertical axis event and a frame, 10 surface units a notch, the notches
held to app_skeleton's MAX_NOTCHES. The sign is flipped: Wayland's
positive is toward the end, NONOS delta_y's toward the top.

Refs: release/0.9.2 (PR #601)
qwen held only a wl_keyboard, so the wheel the bridge now sends as
wl_pointer.axis never reached it. It now takes a wl_pointer too, under
a new id appended after the others so none of theirs moves.

A vertical axis event becomes a Key carrying wheel notches, 10 surface
units each as the bridge encodes them, a smaller nonzero value counting
as one notch; a wheel Key has code 0, which no key branch matches.
ui_scroll_key moves 3 lines a notch, as app_skeleton's WHEEL_LINES. The
pointer's other events, enter, motion, button and frame, fall through.

Refs: release/0.9.2 (PR #601)
Pins the scroll contract on the host, without llama.cpp: ui_from holds
back in range, including a history a resize left shorter than back; the
scroll keys and the wheel move back by their steps, clamped at both
ends, and every other key leaves it alone; and over a socketpair the
real wl_poll makes a vertical wl_pointer.axis into a wheel Key with the
bridge's 10 units a notch, while horizontal, zero and the pointer's
other events make none. Shown to fail when WHEEL_LINES or the sub-notch
rule is broken.

make nonos-mk-qwenscroll-check NONOS_LINUX_GUESTS=1 NONOS_QWEN=1

Refs: release/0.9.2 (PR #601)
This pull request can be merged automatically.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin +refs/pull/152/head:nonos-sync/gh-605
git switch nonos-sync/gh-605
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
NON-OS/nonos-micro-kernel!152
No description provided.