Skip to content

fix: harden persistence, capture safety, and configurator validation - #338

Merged
devmobasa merged 24 commits into
mainfrom
fix/correctness-and-hardening
Aug 14, 2026
Merged

fix: harden persistence, capture safety, and configurator validation#338
devmobasa merged 24 commits into
mainfrom
fix/correctness-and-hardening

Conversation

@devmobasa

Copy link
Copy Markdown
Owner

Summary

  • Preserve drawing and session correctness when restoring history, persisting in-place text edits, hit- testing pressure strokes, and round-tripping board pan settings.
  • Harden file and config handling by containing capture/export paths, bounding config loads, rejecting
    invalid values, and opening clipboard and portal files without following symlinks.
  • Make portal freeze and zoom captures output-aware by tracking desktop origins and layout generations, refreshing geometry on every output change, and rejecting stale or invalid crops.
  • Accept valid portal file:// responses from any location while deleting files only from known portal temporary roots.
  • Align configurator destinations, labels, validation, and subtab navigation with runtime metadata and feature gates.
  • Detach timed-out GTK toolbar threads cleanly after the bounded shutdown wait.

Create redo added an enumerate offset on top of already-final indices, so pasting or duplicating two shapes and then undoing/redoing panicked. Delete undo used the same offset, which restacked non-adjacent shapes in the wrong order.
In-place text edit clears the stored string and keeps the live buffer in DrawingState. Autosave, shutdown, and output-switch snapshots read the frame directly, so a pause or quit during editing wrote empty text. Snapshot through the existing cancel-and-restore helper, and defer autosave while text input is active.
Portal captures are full-desktop images. Cropping with logical * this output's scale picks the wrong pixels on mixed-DPI layouts, and zoom kept the uncropped desktop when that crop missed.
The renderer fills a circle at each stylus sample, but FreehandPressure hit testing only walked segments, so a single-point tap could not be selected.
Filename templates and format strings were joined onto the save directory, so a value with / or .. could write outside it. Require a single path component, allowlist the extension, and reject the same escapes in the configurator.
Portal capture accepted any file:// URI, followed symlinks, and deleted the target. Read only regular files under $XDG_RUNTIME_DIR or the portal cache, with O_NOFOLLOW and a 256 MiB cap.
URI-list paste used metadata() and a following open, so a symlink to a regular file was treated as the image. lstat and O_NOFOLLOW keep the paste on the named file.
Config loading read the whole file into memory. Cap both the typed load and the lossless document path at 2 MiB, matching the session snapshot size-guard pattern.
BoardsDraft rebuilt BoardsConfig from defaults, so a save dropped pan_enabled and show_pan_badge. Keep those fields on the draft so an existing false value survives a round trip.
Save used to parse any number and let validate_and_clamp rewrite it. Drawing, arrow, and history fields now reject the same ranges the UI already shows, and a remaining clamp still blocks the write so keybinding arbitration can keep saving.
Comma-splitting accepted any token, so an unparseable shortcut reached save and was dropped by validate_and_clamp. Parse each entry with KeyBinding and mark the row so Save cannot write a binding the overlay would ignore.
An empty Apply Shortcut field used to write Super+g or Ctrl+Shift+g. Treat blank input as an error so a cleared field cannot bind a default the user did not type.
Hiding a GtkStackPage before selecting the next one lets GTK fall back to another child. Match the keybindings page: show needed pages, select the model tab, then hide the rest.
KeybindingField kept its own title strings, so overlay and configurator names drifted. Look up each field's Action and use action_label, and search the same metadata aliases so terms like eyedropper still find the row.
Capture, Performance, Daemon, Arrow, Render Profiles, Tablet, Help Overlay, and Presenter Mode had no screen token, so overlay and tray could not land there. Add the missing destinations and keep help, parse, and the configurator match in sync.
Dropping the JoinHandle after the deadline detaches GTK's main loop. Leak the handle instead so a stuck thread is not abandoned while the process is still running.
A capture with no target output used to apply to whichever output was active, and ARGB crop sizes could wrap before the allocation. Require both sides of the output id, and use checked arithmetic for the crop buffer.
Stale Phase 2 dead_code allows hid live capture types, and silent onboarding saves hid migrate/recover failures. Document the Cairo buffer casts and keep mixed-DPI geometry helpers available for tests.
--open tablet and the help list advertised a tab that does not exist without the feature. Keep the destination, help text, and parse table behind the same gate.
Save now rejects unparseable keybindings before writing. Cover that the document stays and the field error is shown, instead of only checking a warning status.
The Screenshot portal does not promise a temp directory, so refusing paths outside $XDG_RUNTIME_DIR broke legitimate captures. Keep O_NOFOLLOW and the size cap, and delete only files under the runtime dir or portal cache.
Forgetting the JoinHandle at the deadline leaked a handle that could never be joined. Drop it so the OS can reap the thread if it later finishes.
A monitor added, moved, or destroyed to the left used to leave a stale screenshot origin. Recompute on add and update, and exclude the dying output in output_destroyed because SCTK 0.20 still lists it.
Portal tasks snapshot crop geometry before the screenshot returns, and output-id matching misses a monitor added or moved to the left. Track a layout generation, fail closed on an unknown origin unless the image is this output's size, and discard stale results.
@devmobasa
devmobasa merged commit f062956 into main Aug 14, 2026
2 checks passed
@devmobasa
devmobasa deleted the fix/correctness-and-hardening branch August 14, 2026 23:49
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