Skip to content

Draw the pointer ourselves, open where you left off, and keep an address you cannot land on - #81

Merged
PatrickSt1991 merged 1 commit into
mainfrom
feat/cursor-startpage-favourites
Sep 6, 2026
Merged

PatrickSt1991 merged 1 commit into
mainfrom
feat/cursor-startpage-favourites

Conversation

@PatrickSt1991

Copy link
Copy Markdown
Contributor

Issues 78, 79 and 80 — all from the same reporter, all filed the day after build-d526114, and all three are what a browser gets asked for once it has stopped breaking.

78 — the pointer slowed down on heavy sites

His words: "if we load a heavy site cursor start to become less responsive, when we load light site it is faster, default browser cursor perform same on all sites." Correct, and it was ours.

The pointer lived in the page. Every D-pad step was one script evaluation, and that script did an elementFromPoint and dispatched a mousemove — a forced layout plus whatever the site's own move handlers do, on the busiest thread on the television. The TV's own browser draws its pointer in the compositor, which is why his comparison holds and always would have.

Two halves, neither sufficient alone:

  • The app draws the pointer — DALi views over the web view, positioned from the same viewport fraction the script was already being sent. NuiCursor's old header said an overlay "would need to track scroll and zoom itself"; it does not, because the position is a fraction of the viewport and the viewport is the view's own rectangle. That is the entire reason it is kept as a fraction.
  • The page hears about it once a tick, not once a key press — on the 150 ms timer both builds already run. A held key that was twenty hover updates is now six, and none of them is in front of the drawing.

The rule the second half must not break: the page and the pointer agree at the moment of a click. PageScript.click() hit-tests wherever move() last left it, so a click that overtook its own pending move would land where the pointer used to be. Both builds put the pending move inside the click's own script — one evaluation, not two, because two are two chances for that ordering to be wrong and the failure would be a click that occasionally hits the wrong thing.

Cost: up to 150 ms of hover lag behind the drawn pointer, and the arrow — neither toolkit draws a triangle, so the app-drawn pointer is the ringed dot the ElmSharp build has always used for its native style. A dot that keeps up beats an arrow that does not.

NUI defaults to drawing it; a menu row switches back. The ElmSharp default is unchanged — #78 is a report from a 2025 set, the ewk packages are the ones that cannot be tested before somebody installs them, and src/nui not being able to break them is why the source is split this way. They get the coalescing, which is the half that is safe everywhere, and key 2 was already there for the rest.

79 — where the browser opens

Three states now, owned by StartPage: the start screen, a fixed address (#15's start key), or wherever the last session got to.

  • The mode is stored beside the address, not encoded into it. A sentinel URL meaning "not a URL" becomes a site nobody can visit the first time it turns up in a history.
  • "Where I left off" is the first history entry, which is only the right answer because RecordVisit already refuses our own generated pages (Black screen issue #53) and sign-in waypoints. Without those, it would be the start screen you closed the app from or the captcha you passed an hour earlier.
  • An install from before this has no mode key, so it is derived from whether an address was ever set — nobody's start page moves under them on upgrade, and the harness holds that.
  • Turning it off goes back to the address if one was set. Making somebody retype a URL on a remote to get it back would be its own small cruelty.

80 — keeping an address you cannot land on

"i like to set https://www.instagram.com/reel as favourite but when i go to the url it opens a reel so it saves url of reel instead."

Key 8 keeps the page you are on — the whole vocabulary favourites had, and no answer at all for an address that redirects. A third KeyboardTarget lets the same keyboard finish into Store.ToggleFavourite instead of Navigate. Prefilled with the current address (what you want to keep is usually what you are looking at with a few segments removed), the entry line reads Keep as a tile rather than Go to, it toggles exactly as 8 does and says which of the two it just did, and the tile is named after the site since there is no page title to take from a page nobody opened.

Checks

  • tools/cdpharness/run.sh — green, before and after. Required: both cursors changed the shape of the click script. Run against the Linux Chrome under ~/.local/chrome, not a /mnt/c one.
  • tools/startpage/run.sh — extended to compile StartPage: the three states, "where I left off" landing on the last real visit and never on our own start screen, the toggle returning to the address, and both upgrade shapes. Green.
  • tools/siterules/run.sh, tools/adblock/run.sh — green.
  • ./build.sh all (5 packages, 0 warnings) and OverscanProbe.

Docs: INTERNALS gains A pointer inside the page moves at the page's speed and Keeping an address you cannot land on, Where the browser opens is rewritten for the three states, and What is left on the 2025 sets records what his next report decides — the one that matters being "drawn by Overscan and still slow", which would say the lag was never our script.

…ess you cannot land on

Issues 78, 79 and 80, all from the same reporter the day after build-d526114.

78 is the one with a fault behind it. "if we load a heavy site cursor start to
become less responsive" — the pointer lived in the page, so every D-pad step was
one script evaluation that did an elementFromPoint and dispatched a mousemove.
That is a forced layout plus whatever the site's own move handlers do, on the
busiest thread on the television, and it meant the pointer could only move as
fast as the page allowed. The TV's own browser draws its pointer in the
compositor, which is why his comparison held.

Two halves. The app now draws the pointer — DALi views over the web view on NUI,
positioned from the same viewport fraction the script was being sent. NuiCursor's
old header said an overlay would have to track scroll and zoom itself; it does
not, because the fraction is of the viewport and the viewport is the view's own
rectangle, which is why it is kept as a fraction. And the page is told where the
pointer is once a tick rather than once a key press, on the 150 ms timer both
builds already run. A held key that was twenty hover updates is now six, none of
them in front of the drawing.

The rule that must not break is that the page and the pointer agree at the moment
of a click: PageScript.click() hit-tests wherever move() last left it. So a
pending move goes into the click's own script, one evaluation, rather than being
sent as a call before it — two evaluations are two chances for that ordering to
be wrong, and the failure would be a click that occasionally hits the wrong
thing.

NUI defaults to drawing it, with a menu row to go back to the page's arrow. The
ElmSharp default is unchanged: 78 is a report from a 2025 set, the ewk packages
cannot be tested before somebody installs them, and src/nui not being able to
break them is the reason the source is split this way. They get the coalescing,
which is the half that is safe everywhere; key 2 was already there for the rest.

79 makes the start page three states rather than two. StartPage owns which, the
mode is stored beside the address rather than encoded into it, and an install
from before this has no mode key so it is derived from whether an address was
ever set — nobody's start page moves under them on upgrade. "Where I left off"
is the first history entry, which is only the right answer because RecordVisit
already refuses our own generated pages and sign-in waypoints. Turning it off
goes back to the address if one was set, rather than making somebody retype it.

80 adds a third KeyboardTarget so the same keyboard can finish into
ToggleFavourite instead of Navigate. instagram.com/reel redirects to one reel, so
key 8 there saves that clip for ever; typing the address keeps the address. It is
prefilled with the current page, the entry line reads "Keep as a tile" rather
than "Go to", it toggles like key 8 and says which of the two it did, and the
tile is named after the site since there is no page title to take.

tools/startpage/run.sh now compiles StartPage too and holds it to the three
states, to "where I left off" never landing on our own start screen, and to the
upgrade. cdpharness re-run for the click path.
@PatrickSt1991
PatrickSt1991 merged commit afa4ce8 into main Sep 6, 2026
7 checks passed
@PatrickSt1991
PatrickSt1991 deleted the feat/cursor-startpage-favourites branch September 6, 2026 12:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant