Skip to content

fix: refuse Shift alone with editing keys, and keep a saved Taildrop file when its delete fails - #21

Merged
napalm255 merged 5 commits into
mainfrom
fix/review-follow-ups
Sep 27, 2026
Merged

napalm255 merged 5 commits into
mainfrom
fix/review-follow-ups

Conversation

@napalm255

Copy link
Copy Markdown
Collaborator

Follow-up to the review sweep. GNOME Settings (gnome-control-center is_valid_binding) refuses a Shift-only binding on Home, the arrows, Page_Up/Page_Down, End, Tab, KP_Enter, Return and Mode_switch. The Shift rule now does too, and also refuses ISO_Left_Tab (what GTK reports for Shift+Tab) and dead keys (so a global Shift+dead key cannot stop international typing). Shift+Tab and Shift+Return, previously accepted, are now refused. Other modifiers are unaffected. The rule is byte-identical in QuickTiler and QuickTS, and QuickClip's name-based check agreed with it on every one of 1376 keyvals under gjs.

Also: the shared, template-locked GLib stub gains a VariantType (byte-identical in all four repos that carry it; template.sha256 regenerated).

Taildrop: if the daemon's DELETE fails after a file was written, saveFile now returns the saved path instead of an error, so a retry no longer saves a duplicate "name (1)". While QuickTS runs, the file is hidden from the waiting list, matched on name and size, and only when a numeric size is known. QuickTS never deletes a received file on its own: a name and size do not prove it is the same file, so the file stays in Tailscale's inbox, where tailscale file get can clear it. After a reload it can be offered again. The docs say so.

just ci passes (883 Vitest tests, 50 docs tests), as do just test-live and localapi-check.

A binding whose only modifier is Shift was accepted whenever its key typed
no visible character. That let Shift+Left, Shift+Home, Shift+Tab,
Shift+Return and Shift+dead keys through, and grabbing any of them globally
breaks text selection, focus movement or typing in every application.

Shift alone is now also refused for GNOME Settings' own forbidden_keyvals
(gnome-control-center, panels/keyboard/keyboard-shortcuts.c: Home, the
arrows, Page_Up, Page_Down, End, Tab, KP_Enter, Return, Mode_switch), for
ISO_Left_Tab, which is how GTK reports Shift+Tab, and for every dead key.
Keyvals were checked under gjs with Gdk 4; the dead-key ranges come from
enumerating Gdk.keyval_name over 0xfe50..0xfeff, plus the four
Gdk.KEY_dead_* constants at 0xfe90..0xfe93 that keyval_name cannot name.

Behavior change: the existing test that accepted Shift+Tab now expects it
refused, and Shift+Return, which the old rule also accepted, is refused too.
The docs' Keyboard section says which keys Shift alone cannot take.
Copy the canonical tests/stubs/gi-glib.js, which now carries a VariantType, byte for byte as in the other quick* extensions, and regenerate template.sha256.
saveFile wrote the file and then asked tailscaled to delete it from its
inbox. When that DELETE threw, the catch discarded the path already
written and the row showed an error, so a retry saved a duplicate
"name (1)".

A failed DELETE after a successful save now returns { path, error: '' },
so the row says "Saved to …" as for any save. The model remembers the
file, with the size it was listed at: waitingFiles leaves it out of the
list, so the next menu open does not offer to save it again, and asks
the daemon to delete it again. A file no longer listed at that size is
forgotten, so a different file that later arrives under the same name is
listed and never deleted unsaved.

The fake daemon can now fail one method on a path ('DELETE /…'), which
the new tests use.
…e keys

The case that accepted Super+Tab passed only because acceleratorValid is
stubbed: Gtk.accelerator_valid refuses Tab with any modifier. Use
Super+Left and Ctrl+Return instead, which GTK accepts.

Nothing covered the \p{Cc} half of the visible-character check once
Shift+Tab and Shift+Return became refusals: reducing it to codePoint > 0
passed every suite. Shift+Delete (keyval 0xffff, code point 0x7f, both
checked under gjs) is accepted, and fails under that reduction.
The previous commit retried a failed DELETE on each listing, for a file
listed under the name and size of one already saved. A name and a size
are not identity: if the saved file left the inbox another way and a new
file of the same name and size arrived, that new file was deleted
unsaved. A successful retry also still returned the deleted file, and a
save made with no listing before it recorded an undefined size that an
unlisted name matched.

Nothing now deletes a file on its own. saveFile(name, size) takes the
size from the row that was clicked, and on a failed DELETE after a
successful save it returns the saved path, recording name and size only
when the size is a number. waitingFiles sends no request of its own: it
forgets any record no longer listed at exactly that size, and hides only
a listed file whose name and size both match. The file stays in
Tailscale's inbox, where `tailscale file get` can clear it, and after a
reload it can be offered again; the docs say so.
@sonarqubecloud

Copy link
Copy Markdown

@napalm255
napalm255 merged commit 8cf4372 into main Sep 27, 2026
6 checks passed
@napalm255
napalm255 deleted the fix/review-follow-ups branch September 27, 2026 13:53
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