Continues the build order past Options/Scheduler/Speed Limiter/Batch/
Grabber/tray.
- DropTargetWidget: frameless always-on-top drop target (docs/03-gui-spec.md
§5), position persisted, accepts a dropped http(s) URL or link text and
opens FileInfoDialog directly (skipping Add URL, since the URL is already
known). Shown/hidden from general.showDropTarget, live via
event.settings.changed, same pattern MainWindow already used for
general.minimizeToTray.
- Clipboard, explicit path #2 (docs/06-risks-and-spikes.md R2):
GlobalShortcut wraps org.freedesktop.portal.GlobalShortcuts
(CreateSession -> BindShortcuts -> Activated), triggering the same Add URL
flow. Guarded end-to-end on `if(TARGET Qt6::DBus)` / VELOX_GUI_HAVE_DBUS
so a build without the component degrades to "feature skipped," not
broken (gui/docs/pkg-qa-requests-m1.md R4). Best-effort by design per the
risk doc: fails silent, never advertised.
Verified live against the real portal (a real Wayland session, not just
offscreen): `CreateSession` refuses every caller with "An app id is
required" — reproduced identically via a bare `busctl` call with no Qt
involved at all, so this is the portal requiring a sandboxed caller
identity, not something fixable from an unconfined process. Recorded as
a partial Spike S2 answer in docs/06-risks-and-spikes.md: this explicit
path likely doesn't work for Velox as a traditionally-packaged app on
stock GNOME, only if/when it ships confined. Also fixed a real leak this
verification caught: QDBusInterface's introspection cache reads as a
LeakSanitizer leak the first time anything touches D-Bus (tst_rtl went
red under ASan) — switched to QDBusMessage::createMethodCall, which
needs no introspection.
- Theming (docs/03-gui-spec.md §7): gui/resources/qss/{idm-like,dark}.qss,
each with a documented palette block up top (QSS itself has no variable
syntax), applied by ThemeManager and kept live via
QStyleHints::colorSchemeChanged. util/Theme.hpp gives the handful of
inline C++ styles (status dot, offline banner, the eleven identical
error-label styles across dialogs) named constants instead of a twelfth
copy of the same hex.
- UiThreadWatchdog: the M1 DoD's 200 ms debug-build watchdog. A background
std::thread pings the UI thread every 50 ms via a queued invokeMethod and
warns once (not per-poll) if a ping goes unanswered past 200 ms; no
QThread, no Qt event loop of its own, so the watchdog itself can never be
what blocks the thread it watches. No-op in a release build. Proven both
ways in tst_uithreadwatchdog: fires on a genuinely blocked UI thread
(synchronous sleep, no processEvents) and stays silent on a responsive
one.
Full non-conformance suite (55 tests across every lane, `ctest -LE
conformance`) passes clean at this point, including the whole gui label
under ASan+UBSan.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NSCdCWFXBTSBBK3MzWtJiC