Internal
Public Access
Tight's JPEG sub-mode (previous commit) links libjpeg-turbo directly. Adds it to docs/BUILDING.md for all three platforms (apt libjpeg-turbo8-dev, brew jpeg-turbo, vcpkg libjpeg-turbo:x64-windows) and to the .deb package's Depends: line (libjpeg-turbo8). No changes needed for Windows (the Inno Setup script already wildcards *.dll) or macOS (macdeployqt bundles non-system dylibs automatically). Left the Flatpak manifests unchanged on the assumption that the KDE runtime already bundles libjpeg-turbo as a standard Qt JPEG-plugin dependency -- flagged in PROGRESS.md as worth confirming next time a Flatpak build actually runs, since that wasn't independently verified here. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
316 lines
18 KiB
Markdown
316 lines
18 KiB
Markdown
# OrbitHub Progress
|
|
|
|
## Milestone 0 - Restart in C++/Qt Widgets
|
|
|
|
Status: Completed
|
|
|
|
Delivered:
|
|
- Fresh C++17/Qt6 Widgets scaffold with CMake
|
|
- `ProfilesWindow` (`QMainWindow`) with search, profile list, and New/Edit/Delete controls
|
|
- Double-click in Profiles opens a `SessionWindow`
|
|
- `SessionWindow` (`QMainWindow`) with `QTabWidget`
|
|
- Placeholder tab content showing `OrbitHub Native Surface`
|
|
- `main.cpp` wiring for application startup
|
|
- Cross-platform build command guide in `docs/BUILDING.md`
|
|
|
|
Git:
|
|
- Tag: `v0-m0-done`
|
|
|
|
## Milestone 1 - Storage and CRUD
|
|
|
|
Status: Completed
|
|
|
|
Delivered:
|
|
- SQLite integration via Qt SQL (`QSQLITE`)
|
|
- Persistent profile database bootstrap (`profiles` table)
|
|
- Profiles CRUD (New / Edit / Delete) in `ProfilesWindow`
|
|
- Search-backed profile listing from storage
|
|
- Double-click connect opens `SessionWindow` tab with selected profile name
|
|
|
|
Git:
|
|
- Tag: `v0-m1-done`
|
|
|
|
## Milestone 2 - Profile Details and Connect Lifecycle
|
|
|
|
Status: Completed
|
|
|
|
Delivered:
|
|
- SQLite schema migration for profile details (`host`, `port`, `username`, `protocol`, `auth_mode`)
|
|
- New `ProfileDialog` form for New/Edit profile workflows
|
|
- Profiles list now shows endpoint metadata and supports search by name or host
|
|
- Connect now loads complete profile details into `SessionWindow`
|
|
- Session tab lifecycle status updates (`Connecting`, `Connected`, `Failed`) via non-blocking timer flow
|
|
|
|
Git:
|
|
- Tag: `v0-m2-done`
|
|
|
|
## Milestone 3 - Real SSH Backend and Session Controls
|
|
|
|
Status: Completed
|
|
|
|
Delivered:
|
|
- Backend architecture introduced (`SessionBackend` + protocol-specific implementations)
|
|
- Worker-thread backend execution for connection lifecycle operations
|
|
- Real SSH process backend (`ssh`) with connect/disconnect/reconnect
|
|
- Unsupported protocol backend with explicit not-implemented messaging (RDP/VNC)
|
|
- Session tab controls: `Connect`, `Disconnect`, `Reconnect`, `Copy Error`
|
|
- Connect-time credential flow (password prompt / private-key path selection)
|
|
- Session event log pane with timestamps and user-friendly error mapping
|
|
- SQLite profile schema migration for `private_key_path` and `known_hosts_policy`
|
|
|
|
Git:
|
|
- Tag: `v0-m3-done`
|
|
|
|
## Milestone 4 - Interactive SSH Session UX
|
|
|
|
Status: Completed
|
|
|
|
Delivered:
|
|
- Embedded interactive SSH terminal using `KodoTerm` + vendored `libvterm`
|
|
- Native in-terminal typing for SSH sessions (no separate input box)
|
|
- ANSI/color rendering with selectable terminal themes (`Dark`, `Light`, `Solarized Dark`)
|
|
- Cross-platform SSH auth path improvements (`ssh-askpass` handling and host-key policy wiring)
|
|
- Session UX simplification: auto-connect on tab open, disconnect on tab close
|
|
- Tab-state indicators via tab color and state suffix (`Connecting`, `Connected`, `Disconnected`, `Failed`)
|
|
- Right-click tab menu for `Disconnect`, `Reconnect`, `Theme`, and `Clear`
|
|
- Collapsible events panel retained as primary diagnostics surface; inline detail/status banners removed
|
|
- Terminal behavior polish: better fixed-width font selection, cursor visibility, backspace handling, and terminal-size negotiation stability
|
|
|
|
Git:
|
|
- Tag: `v0-m4-done`
|
|
|
|
## Milestone 5 - RDP Fully Working
|
|
|
|
Status: Completed
|
|
|
|
Delivered:
|
|
- Added `RdpSessionBackend` and wired protocol selection so `RDP` no longer routes to unsupported backend
|
|
- Pivoted RDP design to embedded-only integration (no external RDP process launches)
|
|
- Implemented embedded FreeRDP client thread with connect/disconnect lifecycle and event-loop handling
|
|
- Added in-window `RdpDisplayWidget` rendering surface with frame updates from FreeRDP GDI
|
|
- Wired direct keyboard/mouse input from the embedded RDP surface to the backend
|
|
- Added RDP connect-time password prompt flow and settings wiring (host/port/user/password, desktop size)
|
|
- Added explicit profile `Domain` support for RDP auth (with `DOMAIN\username` fallback parsing)
|
|
- Updated session tab/context-menu behavior so terminal-only actions are hidden on RDP tabs
|
|
- Implemented dynamic in-session RDP resolution renegotiation from viewport resize events
|
|
- Enabled minimal FreeRDP client-channel build (`drdynvc` + `disp`) and channel loading for runtime resize support
|
|
- Added RDP profile-level security mode and performance profile options, wired into FreeRDP connection settings
|
|
- Hardened RDP lifecycle handling for disconnect/reconnect/abort flows to avoid false failure states on user-initiated stops
|
|
- Expanded RDP error/disconnect diagnostics with richer FreeRDP code mapping and raw disconnect detail events
|
|
- Pulled FreeRDP source for integration planning and API review
|
|
|
|
Git:
|
|
- Tag: `v0-m5-done`
|
|
|
|
## Milestone 6 - VNC Working (initial scope)
|
|
|
|
Status: Completed (initial scope; see gaps below)
|
|
|
|
Delivered:
|
|
- `VncSessionBackend`: an original RFB (RFC 6143) client implementation
|
|
against `QTcpSocket` -- no permissively licensed VNC client library
|
|
exists to vendor the way FreeRDP was for RDP (LibVNCClient is GPLv2,
|
|
gtk-vnc is LGPL but GTK-tied), so this is from-scratch protocol code,
|
|
threaded like `SshSessionBackend` (a `QObject` on its own `QThread`
|
|
driven by Qt's own async socket signals) rather than `RdpSessionBackend`'s
|
|
manual worker-thread/blocking-loop pattern
|
|
- Full connect/disconnect/reconnect lifecycle, RFB protocol-version
|
|
negotiation (3.3/3.7/3.8 handshake differences handled explicitly),
|
|
VNC Authentication (DES challenge-response, using OpenSSL's classic DES
|
|
API) and no-auth security types, Raw + CopyRect framebuffer decoding,
|
|
keyboard (Qt key -> X11 keysym mapping) and mouse/wheel input forwarding
|
|
- `VncDisplayWidget` mirroring `RdpDisplayWidget`'s scale-to-fit rendering
|
|
and input-forwarding shape
|
|
- 41 unit tests (`tests/test_vnc_session_backend.cpp`): pure-function
|
|
coverage (DES key prep verified against an independently documented test
|
|
vector, keysym mapping, socket-error mapping) plus state-machine
|
|
coverage against a scripted in-process fake RFB server (all three
|
|
protocol-version handshake shapes, auth success/failure, unsupported
|
|
security types, pixel-accurate Raw/Hextile/ZRLE/Tight decoding including
|
|
a ZRLE zlib-stream-persistence test across two separate
|
|
`FramebufferUpdate` messages, a Tight stream-reset-flag test, cursor/
|
|
clipboard round trips) -- caught and fixed a real re-entrancy bug
|
|
(`abort()` synchronously re-firing `disconnected()` mid-
|
|
`failConnection()`, silently overwriting a specific error with a
|
|
generic one)
|
|
- Verified live against a real, independently implemented VNC server
|
|
(TightVNC on Windows): connect with VNC Authentication, correct
|
|
framebuffer dimensions and pixel data, clean disconnect, reconnect,
|
|
live cursor-shape and clipboard-send checks. That particular server
|
|
consistently chose Raw for actual framebuffer content regardless of
|
|
which compression encodings were announced, so Hextile/ZRLE/Tight's
|
|
real-world decode path isn't independently confirmed live -- the unit
|
|
tests are the primary correctness evidence for those
|
|
- Per-tab VNC-only display mode toggle (tab-bar right-click ->
|
|
`Display Mode`): `Scale to Fit` (default, matches RDP's behavior) or
|
|
`Actual Size (Scrollbars)` -- renders the remote framebuffer at its
|
|
native pixel size inside a `QScrollArea` so text isn't shrunk, at the
|
|
cost of needing to scroll to see the whole screen. Reuses
|
|
`VncDisplayWidget::renderRect()`'s existing scale-to-fit math unchanged:
|
|
it degenerates to an exact 1:1 mapping once the widget's own bounds are
|
|
fixed to the remote's size, so no separate rendering path was needed.
|
|
Persisted across sessions like the terminal theme preference.
|
|
- Robustness fix: an unrecognized `FramebufferUpdate` rectangle encoding
|
|
used to abort the connection generically; `kAnnouncedEncodings` is now
|
|
the single source of truth for what `SetEncodings` announces and what
|
|
the rectangle-dispatch `switch` can decode, with a regression test
|
|
pinning that every announced encoding has a working case
|
|
- Clipboard sync (`ServerCutText`/`ClientCutText`, Latin-1 only -- no
|
|
Unicode extension) in both directions
|
|
- Remote cursor shape sync via RFB's Cursor pseudo-encoding, mirroring
|
|
`RdpDisplayWidget`'s cursor handling in `VncDisplayWidget`
|
|
- Hextile, ZRLE, and Tight compression encodings, in addition to Raw +
|
|
CopyRect -- meaningfully reduces bandwidth over slower links versus Raw
|
|
alone; Tight in particular is the encoding most real VNC servers prefer
|
|
when the client offers it. Pure tile/pixel decode logic (including
|
|
Tight's three filters -- Copy, Palette, Gradient) lives in
|
|
`src/vnc_pixel_codecs.h/.cpp`, kept separate from the wire-sequencing
|
|
state machine so it's unit-testable without a socket. ZRLE and Tight's
|
|
Basic mode share the same "persistent zlib stream(s), decompress
|
|
in-memory, decode synchronously" approach (Tight has 4 independent
|
|
streams selected per-rectangle, individually reset via the
|
|
compression-control byte's low 4 bits). Tight's JPEG sub-mode decodes
|
|
via libjpeg-turbo directly (`find_package(JPEG REQUIRED)` ->
|
|
`JPEG::JPEG`), not `QImage`'s own JPEG plugin, to avoid a
|
|
packaging-dependent runtime failure mode. ZRLE/Tight link `ZLIB::ZLIB`
|
|
(found via a fresh top-level `find_package(ZLIB REQUIRED)`, independent
|
|
of whether vendored FreeRDP's own internal zlib usage stays enabled)
|
|
- 41 unit tests total, 15 of them for Hextile/ZRLE/Tight specifically,
|
|
including a ZRLE zlib-stream-persistence test across two separate
|
|
`FramebufferUpdate` messages and a Tight stream-reset-flag test proving
|
|
the low 4 control-byte bits actually tear down and reinitialize the
|
|
targeted stream rather than erroring out on stale state
|
|
|
|
Known gaps (explicit scope decisions, not oversights -- see issue #3 for
|
|
follow-up tracking):
|
|
- Apple's Screen Sharing authentication (Diffie-Hellman + AES, security
|
|
type 30) isn't implemented, so this can't yet reach macOS's built-in VNC
|
|
server -- only standard VNC Authentication (type 2) and no-auth (type 1)
|
|
- Tight's Basic compression mode always assumes zlib-compressed payloads;
|
|
the real protocol permits the server to skip compression for very small
|
|
(filtered byte count under ~12) payloads, which this decoder doesn't
|
|
special-case (the exact trigger/wire-signaling for that couldn't be
|
|
verified with confidence against the RFC text alone). In practice this
|
|
only affects rare, tiny rectangles -- solid or near-solid tiny areas are
|
|
virtually always sent as Fill instead -- and fails that one rectangle's
|
|
decode cleanly (disconnects with a clear error) rather than silently
|
|
misinterpreting it
|
|
- Tight's Gradient filter is implemented from RFC 6143's description but
|
|
is the least exercised/confirmed of the three filters against a real
|
|
server in this pass (most real-world Tight traffic uses Copy or
|
|
Palette)
|
|
- Packaging for the new `libjpeg-turbo` dependency: added to
|
|
`docs/BUILDING.md` (apt/brew/vcpkg) and the `.deb` control file's
|
|
`Depends:` (`libjpeg-turbo8`). The Windows Inno Setup script already
|
|
wildcards `*.dll` so no change was needed there, and macOS's
|
|
`macdeployqt`-based bundling picks up non-system dylibs automatically.
|
|
The Flatpak manifests (`packaging/flatpak/*.yml`) were left unchanged on
|
|
the assumption that `org.kde.Platform`/`Sdk` 6.11 already bundles
|
|
libjpeg-turbo (a standard Qt JPEG-plugin dependency) -- worth confirming
|
|
the next time a Flatpak build is actually run, since it wasn't
|
|
independently verified here
|
|
- No dynamic resize (connects at the server's native resolution; the
|
|
`Scale to Fit`/`Actual Size` toggle changes how that fixed resolution is
|
|
displayed locally, not what resolution is requested from the guest --
|
|
VNC has no equivalent of RDP's MS-RDPEDISP for that)
|
|
|
|
## Milestone 7 - Cross-Platform Protocol Hardening
|
|
|
|
Status: Completed
|
|
|
|
Delivered:
|
|
- Validated SSH and RDP workflows on Linux, macOS, and Windows 11 (VNC is out
|
|
of scope while Milestone 6 remains deferred)
|
|
- Windows: validated the full `docs/BUILDING.md` toolchain end-to-end
|
|
(Git/CMake/Ninja/VS Build Tools with the C++ workload/vcpkg for
|
|
Qt6-OpenSSL-zlib); documented a VS Build Tools installer gotcha where the
|
|
actual compiler is a "recommended", not "required", component of the
|
|
VCTools workload
|
|
- Fixed RDP keyboard input misreading punctuation keys on Linux (X11 keycode
|
|
numbering was being treated as a PC/AT scancode; now uses FreeRDP's
|
|
authoritative X11-keycode-to-scancode table)
|
|
- Added RDP clipboard sync (bidirectional, plain text) and RDP cursor/pointer
|
|
shape sync (resize handles, text I-beam, etc. instead of a static arrow)
|
|
- Fixed Tab/Shift+Tab being intercepted by local UI focus navigation instead
|
|
of reaching SSH/RDP sessions
|
|
- Fixed RDP key auto-repeat being dropped, so holding a key only ever sent a
|
|
single keystroke to the remote machine
|
|
- Windows-specific RDP fixes: a crash on every connect attempt (FreeRDP's
|
|
signal-handling critical section was never initialized) and a host
|
|
resolution failure on every connect, including literal IP addresses
|
|
(Winsock was never initialized via `WSAStartup`)
|
|
- Windows: automatic build-time deployment of Qt's platform/SQL-driver
|
|
plugins and their runtime DLL dependencies, and marked the executable as a
|
|
GUI (`WIN32`) app to remove a stray console window behind the UI
|
|
- Windows and macOS: proper native app icon embedding (Windows `.rc`/`.ico`
|
|
resource; macOS `.app` bundle with `.icns`), replacing the generic default
|
|
icon previously shown for the built executable/bundle
|
|
- macOS: fixed Edit/New Profile dialog form fields collapsing to `sizeHint`
|
|
width due to the platform-default `QFormLayout` field growth policy
|
|
|
|
Git:
|
|
- Tag: Pending user approval (`v0-m7-done`)
|
|
|
|
## Milestone 8 - Profile and Session UX Completion
|
|
|
|
Status: Completed
|
|
|
|
Delivered:
|
|
- Added profile `tags` field to storage + schema migration and profile editor UX
|
|
- Added profile `folder_path` field + nested folder/subfolder profile view mode
|
|
- Added profile tree context actions (`New Folder`, `New Connection`) and drag-to-folder profile moves with persistence
|
|
- Added `Help -> About OrbitHub` dialog with third-party library inventory and MIT/Apache-2.0 license links
|
|
- Extended profile search to include tags/folder path and added profile sort controls (`Name`, `Protocol`, `Host`)
|
|
- Persisted profile list UX preferences (`search text`, `view mode`, protocol/tag filters, `sort order`) across app restarts
|
|
- Added protocol-aware profile validation/normalization for SSH/RDP/VNC (repository + dialog)
|
|
- Improved profile form protocol UX hints and SSH private-key path validation
|
|
- Added session events filtering and tab-context actions (`Show/Hide Events`, `Copy Events`, `Clear Events`)
|
|
- Added session diagnostics QoL: severity quick-filter (`All/Warnings/Errors`) and `Export Events` action
|
|
- Persisted session UI defaults (`terminal theme`, `events panel visibility`) for new tabs/windows
|
|
- Added profile quick filters (`Protocol`, `Tag`) with persistence to speed profile browsing
|
|
|
|
Validation:
|
|
- Local build verification passed (`cmake --build build`)
|
|
- No automated tests are currently configured in CTest
|
|
|
|
Git:
|
|
- Tag: Pending user approval (`v0-m8-done`)
|
|
|
|
## Milestone 9 - Packaging and Distribution
|
|
|
|
Status: Completed
|
|
|
|
Delivered:
|
|
- Linux `.deb` (`packaging/linux/build-deb.sh`) and Flatpak (`packaging/flatpak/build-flatpak.sh`) packages, both verified installed and launched with working SSH/RDP
|
|
- Renamed the app's reverse-DNS identity from `io.orbithub.OrbitHub` to `org.darksingularity.OrbitHub` (desktop file, AppStream metainfo, Flatpak manifest, macOS bundle identifier) to reflect a domain actually owned by the project
|
|
- Fixed Linux taskbar/panel pin matching (`StartupWMClass`) so a pinned launcher merges with its running window instead of creating a duplicate entry
|
|
- Replaced the stale, mismatched hand-authored launcher SVG with PNG icons rendered directly from the app's own `createOrbitHubAppIcon()` at each hicolor theme size
|
|
- Windows installer via Inno Setup (`packaging/windows/orbithub.iss`, `packaging/windows/build-installer.ps1`), verified installed silently and launched cleanly with no crash events
|
|
- macOS `.dmg` via `cmake --install` + `macdeployqt` + `hdiutil` (`packaging/macos/build-dmg.sh`), verified installed and launched after fixing:
|
|
- a launch crash caused by `macdeployqt` invalidating the code signature (fixed with ad hoc re-signing)
|
|
- a missing-library crash caused by the Linux-only `$ORIGIN` rpath token and vendored dylibs installing outside the `.app` bundle (fixed with `APPLE`-specific `@executable_path`/`Contents/Frameworks` layout)
|
|
- the dmg showing the generic disk icon instead of the app icon
|
|
- README and `docs/BUILDING.md` Packaging sections documented for all three platforms
|
|
|
|
Validation:
|
|
- All three installers built, installed, and launched successfully with working SSH/RDP sessions
|
|
- Code signing is ad hoc only (no purchased Apple Developer ID or Windows code-signing certificate), so macOS Gatekeeper and Windows SmartScreen still show first-run warnings by design
|
|
|
|
Git:
|
|
- Tag: `v0-m9-done`
|
|
- Release: [v2026.9.8](https://git.darksingularity.org/DarkSingularity/orbithub/releases/tag/v2026.9.8) (`v2026.9.8` tag, installers for Windows/Linux/macOS)
|
|
- Release: [v2026.9.8.2](https://git.darksingularity.org/DarkSingularity/orbithub/releases/tag/v2026.9.8.2) — same-day patch fixing RDP TLS certificate verification (was fully disabled) and preparing Flatpak packaging for Flathub submission
|
|
- Release: [v2026.9.8.3](https://git.darksingularity.org/DarkSingularity/orbithub/releases/tag/v2026.9.8.3) — same-day patch adding an in-app User Guide and standalone User Guide PDF
|
|
- Release: [v2026.9.14](https://git.darksingularity.org/DarkSingularity/orbithub/releases/tag/v2026.9.14) — fixes distorted RDP text on HiDPI monitors and reduces RDP resize-related display glitches
|
|
- Release: [v2026.9.14.2](https://git.darksingularity.org/DarkSingularity/orbithub/releases/tag/v2026.9.14.2) — same-day patch fixing RDP display corruption (missing/misplaced taskbar) after resizing the session window (the client never resized its own display buffer for channel-driven RDP resizes)
|
|
- Release: [v2026.9.15](https://git.darksingularity.org/DarkSingularity/orbithub/releases/tag/v2026.9.15) — adds Import/Export for profile lists (File menu)
|
|
|
|
## Milestone 10 - v1.0 Stabilization
|
|
|
|
Status: Planned
|
|
|
|
Planned Scope:
|
|
- Run final regression and acceptance testing across all protocols
|
|
- Resolve release-blocking defects
|
|
- Finalize docs and publish v1.0 release notes/checklist
|