Commit Graph
40 Commits
Author SHA1 Message Date
ksmithandClaude Sonnet 5 0cdf930303 Fix connect-time username prompt being unreachable for SSH/RDP
validateProfileForConnect() still hard-failed with a blocking
QMessageBox for a blank SSH/RDP username, running before
requestConnectOptions() ever got a chance to prompt for it inline --
so the connect-time username prompt added for issue #21 was dead code
in practice; users just got told to go edit the profile instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 08:28:41 -06:00
ksmithandClaude Sonnet 5 7559488ceb Bump version to v2026.9.16.3
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 08:18:22 -06:00
ksmithandClaude Sonnet 5 7aa8849f8e Bump version to v2026.9.16.2
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 08:07:29 -06:00
ksmithandClaude Sonnet 5 d7f9d4966b Bump version to v2026.9.16
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 03:55:45 -06:00
ksmithandClaude Sonnet 5 e80fe7d634 Fix Apple DH auth wire-order bug, add type 33 fallback, fix missing VNC password prompt
Live testing against a real macOS Screen Sharing server surfaced two
real bugs, independent of each other:

1. SessionTab::requestConnectOptions() never prompted for a password
   on VNC profiles (only SSH/RDP) -- every VNC connection went out
   with an empty password regardless of what the server needed. VNC
   now gets its own prompt; an empty password is allowed through
   (unlike RDP's hard requirement) since no-auth VNC servers exist and
   there's no way to know client-side before the security-type
   negotiation happens.

2. VncSessionBackend's Apple DH (type 30) response sent the client's
   public key before the encrypted credentials. Cross-checking against
   neatvnc's rfb-proto.h (an independent, authoritative reference: both
   the wire struct definitions and the full server-side verification
   code, matched field-by-field against this implementation) showed
   the correct order is credentials first, then public key -- exactly
   backwards from what was implemented. Fixed, with a new regression
   test that decrypts the credentials back out using the trailing
   public-key bytes to derive the shared secret, which would fail if
   the fields were swapped again.

Also adds security type 33 (RSA + AES, src/vnc_apple_rsa_auth.h) as a
fallback Apple auth scheme, sourced from the `asyncvnc` PyPI package.
Preference when multiple are offered: None > AppleDH(30) >
AppleRSA(33) > VNCAuth(2).

Neither scheme has been gotten working live yet against the specific
macOS Tahoe (26.6.2) server available for testing -- type 30's wire
format is now verified correct byte-for-byte against the independent
reference above, but the server still rejects it with a generic
"Authentication or authorization failure"; type 33 is rejected even
earlier, right after the initial host-key request. macOS Tahoe was
released after this assistant's knowledge cutoff, so there may be a
protocol or permission-model change specific to it that isn't
reflected in either reference. Documented as an open issue in
docs/PROGRESS.md rather than claimed as working.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 03:49:06 -06:00
ksmithandClaude Sonnet 5 1f026dde70 Add Apple Screen Sharing authentication for VNC (security type 30)
Apple's macOS Screen Sharing server doesn't speak standard VNC
Authentication -- it uses a Diffie-Hellman key exchange followed by
AES-128-ECB-encrypted credentials, security type 30. Apple never
published this scheme (it's not part of RFC 6143); this implements
the well-established reverse-engineered wire format: the server sends
a generator, prime, and its own DH public key; the client generates
an ephemeral keypair, derives the shared secret, MD5-hashes it into
an AES key, and sends back its public key plus a 128-byte encrypted
username+password buffer.

The DH/AES math lives in new src/vnc_apple_dh_auth.h/.cpp as a pure,
socket-free helper (mirroring vncAuthResponse()'s shape for standard
VNC Auth), built entirely on modern EVP_PKEY-based OpenSSL 3.0 APIs --
no deprecated low-level DH_* calls, unlike VNC Authentication's
necessary use of classic DES. Reuses Profile::username (already a
shared field) since Apple's scheme needs an actual macOS account name,
unlike password-only VNC Authentication.

Security-type preference when multiple are offered is now None >
AppleDH > VNCAuth, since DH+AES is strictly stronger than static-
challenge DES. Adds a DH round-trip test (generates a real 512-bit
group at test time, computes the response, then independently
re-derives the shared secret as the server would and decrypts the
credentials back out -- proving self-consistency without needing a
hand-computed expected value), a fake-server integration test for the
full RFB 3.8 handshake sequencing, and a preference-order test.

Not yet live-verified against a real macOS Screen Sharing server --
that's next.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 21:27:17 -06:00
ksmithandClaude Sonnet 5 4fca8fce41 Add VNC Tight decoding
Implements RFC 6143's Tight encoding: a compression-control byte (low
4 bits reset one of 4 persistent zlib streams; high nibble selects
Fill/JPEG/Basic mode) followed by Fill's 3-byte solid color, JPEG's
compact-length-prefixed baseline JPEG covering the whole rectangle
(decoded via libjpeg-turbo directly, not QImage's plugin, to avoid a
packaging-dependent runtime failure mode), or Basic mode's
compact-length-prefixed zlib payload plus a filter (Copy, Palette, or
Gradient) applied after decompression. Unlike Hextile/ZRLE, Tight has
no internal tiling -- one rectangle is one filtered/compressed unit.

The three filters live in vnc_pixel_codecs.h/.cpp alongside the
Hextile/ZRLE decoders. Adds find_package(JPEG REQUIRED) + JPEG::JPEG
as a new build dependency (confirmed available via libjpeg-turbo on
this dev machine). 5 new tests cover Fill, Basic+Copy, Basic+Palette,
JPEG (round-tripped through a real libjpeg-turbo-encoded fixture,
compared with tolerance since JPEG is lossy), and the stream-reset
flag correctly tearing down and reinitializing a targeted stream
rather than erroring on stale state.

Known, documented gap: this decoder always treats Basic-mode payloads
as zlib-compressed; the real protocol allows very small payloads to
skip compression, which couldn't be verified with confidence against
the RFC text alone and is narrow enough in practice (tiny solid areas
are virtually always sent as Fill instead) to leave unhandled for now
-- it fails that one rectangle's decode cleanly rather than
misinterpreting it silently. The Gradient filter is implemented from
the spec description but is the least exercised of the three in this
pass.

Live-verified against the TightVNC test server that nothing
regressed; that server still consistently chose Raw for actual
framebuffer content regardless of announced encodings, so Tight's live
decode path isn't independently confirmed against a real server here
either -- the unit tests are the primary evidence.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 21:13:17 -06:00
ksmithandClaude Sonnet 5 bb022edcf2 Add VNC ZRLE decoding
Implements RFC 6143 SS7.7.6: a ZRLE rectangle is a 4-byte compressed
length followed by that many zlib-compressed bytes, decompressing to
64x64 tiles each using one of five subencodings (Raw, Solid, packed
palette, Plain RLE, Palette RLE). The zlib stream persists for the
whole connection rather than being reset per-rectangle or per-update,
so VncSessionBackend now owns a lazily-initialized, persistent
z_stream torn down only in resetProtocolState() on a fresh
connect/reconnect.

Since the entire rectangle's compressed data decompresses into memory
in one shot, tile parsing is a plain synchronous loop rather than
needing its own RfbState values -- only the compressed-length and
compressed-data reads are actual protocol states. Tile decoding (the
five subencodings, including the continuation-byte run-length
encoding shared by two of them) lives in vnc_pixel_codecs.h/.cpp
alongside the Hextile decoder, unit-tested with 6 new tests covering
each subencoding plus a persistence test that splits one continuous
deflate stream across two separate FramebufferUpdate messages -- it
only decodes correctly if the connection's inflate stream is retained
between them.

Adds a top-level find_package(ZLIB REQUIRED) + ZLIB::ZLIB link
(previously only pulled in transitively via vendored FreeRDP's own
smartcard-emulation feature, which happened to have it enabled but
shouldn't be relied on for that).

Live-verified against the TightVNC test server that nothing regressed
(connect, cursor, clipboard); that server consistently sends Raw for
actual framebuffer content regardless of announced encodings, so
Hextile/ZRLE's live decode path isn't independently confirmed against
a real server -- the unit tests are the primary evidence here.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 21:02:26 -06:00
ksmithandClaude Sonnet 5 e49fa0cf26 Add VNC Hextile decoding
Implements RFC 6143 SS7.7.4: rectangles announced as Hextile (type 5)
tile the update into 16x16 blocks, each either raw pixels or a
background fill plus an optional list of foreground/individually-
colored subrects, with background/foreground persisting across tiles
within one rectangle when not re-specified.

The pure byte-decode logic (tile metadata, subrect list) lives in new
src/vnc_pixel_codecs.h/.cpp, kept separate from
VncSessionBackend's wire-sequencing state machine so it's unit-testable
without a socket -- the pattern the plan calls for continuing into the
ZRLE/Tight work still ahead. Adds 5 fake-server tests covering a raw
tile, a background-only solid fill, uncoloured and individually-colored
subrects, and a 4-tile rectangle proving background persistence and
correct tile-cursor wraparound.

Verified against the live TightVNC test server (connect, frame,
cursor, clipboard all still work); that particular server always
chose Raw for the actual framebuffer content during this session, so
Hextile's real-world path isn't independently confirmed live -- the
unit tests are the primary correctness evidence for this phase.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 20:49:08 -06:00
ksmithandClaude Sonnet 5 6da9dc6ca5 Add VNC support (Milestone 6, issue #3)
Implements RFB (RFC 6143) directly 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, and vendoring either
would force a licensing decision on the whole (MIT) project. This is
from-scratch protocol code instead, 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, since QTcpSocket is already async.

Scope, matching SessionTab's existing SSH/RDP dispatch pattern
(session_backend_factory.cpp, session_tab.cpp's widget construction and
signal wiring) and VncDisplayWidget mirroring RdpDisplayWidget's
scale-to-fit rendering:
- Protocol handshake: RFB 3.3/3.7/3.8 negotiated explicitly (the
  SecurityResult message only exists in 3.8; pre-3.8 servers signal auth
  failure by closing the socket, which the disconnect handler accounts
  for)
- VNC Authentication (DES challenge-response, via OpenSSL's classic DES
  API) and no-auth security types
- Raw + CopyRect framebuffer decoding into a persistent QImage, requesting
  a fixed 32bpp format whose byte layout matches QImage::Format_RGB32
  directly (same zero-conversion trick RdpSessionBackend uses for
  FreeRDP's GDI buffer)
- Keyboard (Qt key -> X11 keysym, including the Unicode-beyond-Latin-1
  keysym convention) and mouse/wheel input forwarding

Explicit non-goals for this pass (see docs/PROGRESS.md for the full
list): Apple's Screen Sharing auth (so this can't yet reach macOS's
built-in VNC server), compression encodings beyond Raw/CopyRect, dynamic
resize, remote cursor shape sync, clipboard sync.

19 unit tests (tests/test_vnc_session_backend.cpp): pure-function
coverage (DES key prep verified against an independently documented test
vector for password "COW", X11 keysym mapping, socket-error mapping) plus
state-machine coverage against a scripted in-process fake RFB server
covering all three protocol-version handshake shapes, auth success/
failure, unsupported security types, and pixel-accurate Raw decoding.
That harness caught a real re-entrancy bug: QAbstractSocket::abort()
synchronously re-emits disconnected() before returning, so
failConnection() calling it was silently letting a second, generic
disconnected-socket handler overwrite an already-correct, specific error
message.

Also 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.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 18:02:49 -06:00
ksmithandClaude Sonnet 5 dbcc20d155 Add File -> Import from mRemoteNG...
Parses mRemoteNG's confCons.xml export format directly -- schema verified
against mRemoteNG's own XmlConnectionsDeserializer.cs source and a real
exported sample, not guessed at. Maps nested <Node Type="Container">
folders and <Node Type="Connection"> entries onto OrbitHub profiles:
RDP stays RDP, SSH1/SSH2 collapse to OrbitHub's single SSH protocol,
anything else (VNC, Telnet, HTTP, PowerShell, ...) is skipped and listed
in the import summary rather than silently dropped.

Passwords are never read, not even for the common case where they're
technically readable without a master password (mRemoteNG only encrypts
the Password attribute itself, everything else -- Hostname, Username,
Domain, Protocol -- is plaintext). A FullFileEncryption="true" export
encrypts the whole node tree instead and genuinely can't be read without
the user's master password; that case is detected and refused with a
clear message rather than failing confusingly.

The parser (src/mremoteng_importer.h/.cpp) is a pure function decoupled
from any file/UI I/O, matching this session's established pattern of
keeping business logic separately testable from the Qt Widgets shell that
calls it (ProfilesWindow::importFromMRemoteNG() is the thin wrapper:
QFileDialog, call the parser, write results via ProfileRepository, show a
summary). 11 test cases against realistic sample XML.

Hit a real moc gotcha along the way: a literal "//" inside a raw string
literal (the xmlns URL) makes moc's lexer think a line comment started
there, silently desyncing its parse so it never finds the QObject-derived
test class at all (no error, just a missing vtable at link time). Fixed
by moving the XML fixtures into a plain non-QObject header moc never
scans, split across two adjacent literals as a second safeguard.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 16:08:02 -06:00
ksmithandClaude Sonnet 5 3fab2f9de3 Wire up CTest and add unit test coverage for ProfileRepository
Adds a Qt6::Test-based unit test target (tests/test_profile_repository.cpp,
21 cases), gated behind an ORBITHUB_BUILD_TESTS option that no-ops
gracefully if Qt6::Test isn't available, so it can't break app-only
builds. Covers profile CRUD, validation rules, search/sort, tag
normalization, and folder handling, each against an isolated temporary
SQLite file (new ProfileRepository(databasePathOverride) constructor
overload added for exactly this).

Caught and fixed a real bug along the way: normalizedTags()'s result was
bound directly without the nonNullTrimmed() null-guard every other field
already uses, so creating a profile with no tags at all hit the `tags
NOT NULL` constraint and silently failed -- including via the Import
Profiles feature for any export where a profile has no tags key.

Partial progress on #1 (RdpSessionBackend/SshSessionBackend state-machine
coverage still open -- much larger lift, needs a testability pass on
those backends first).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 06:39:20 -06:00
ksmithandClaude Sonnet 5 df99c78998 Bump version to v2026.9.15
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 06:22:53 -06:00
ksmithandClaude Sonnet 5 96c8403f3b Bump version to v2026.9.14.2
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 21:57:43 -06:00
ksmithandClaude Sonnet 5 c4a62e8fb6 About dialog: fix unreadable dark-mode text and missing version
The subtitle and version line used palette(mid), a role meant for 3D
bevel/shadow decoration, not text -- it has poor contrast against the
window background in dark themes. Replaced with a color blended from
the widget's actual text/window palette colors, so it stays readable
(de-emphasized but never low-contrast) in either theme.

Also: QCoreApplication::applicationVersion() was never being set
anywhere, so the dialog always showed "Development build" regardless
of the actual built version. CMake's PROJECT_VERSION is now exposed
to the app via a compile definition and wired into
setApplicationVersion() at startup.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 21:29:36 -06:00
ksmithandClaude Sonnet 5 e90e9b5abf Bump version to v2026.9.14
RDP HiDPI text fix and resize-glitch mitigations.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 21:17:18 -06:00
ksmithandClaude Sonnet 5 8e98c208c9 Bump version to v2026.9.8.3
Same-day patch release: adds the in-app User Guide and standalone
User Guide PDF.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 18:31:50 -06:00
ksmithandClaude Sonnet 5 ce1e40a12d Add an in-app User Guide and standalone PDF
Adds docs/USER_GUIDE.md, a 10-section end-user guide (getting
started, managing/organizing profiles, SSH and RDP connections,
session management, settings, troubleshooting). It's embedded into
the app binary via a Qt resource file and rendered by a new
Help -> User Guide window: a topic sidebar plus content pane, not a
single scrolling document, with cross-reference links between
sections routed to sidebar selection rather than relying on Qt's
Markdown importer's lack of heading anchors.

A separate, non-shipped tool (tools/user-guide-pdf/) renders the
same source to a standalone PDF via QTextDocument + QPrinter,
wrapped by packaging/docs/build-user-guide-pdf.sh. Kept fully
outside the main CMake target so Qt6::PrintSupport never becomes a
runtime dependency of the shipped app (confirmed via ldd). The PDF
itself isn't committed -- generated per release like the platform
installers.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 18:17:21 -06:00
ksmithandClaude Sonnet 5 80bc50e54c packaging: fix license install path, document Flathub AI-policy risk
License files were installing to share/licenses/orbithub instead of
the path Flathub's own docs specify for this app
(share/licenses/org.darksingularity.OrbitHub, i.e. $FLATPAK_ID).
Also installs FreeRDP's and KodoTerm's bundled LICENSE files there
alongside OrbitHub's own, since previously only the latter was
installed at all.

docs/FLATHUB.md now documents two things found by checking Flathub's
current requirements directly rather than assuming prior packaging
work was sufficient: the vendored libvterm copy has no LICENSE file
at all (needs to come from upstream, not fabricated here), and
Flathub's Generative AI disclosure policy is a real, reviewer-
discretion acceptance risk for this project given its development
history — not something further packaging work resolves.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 16:56:22 -06:00
ksmithandClaude Sonnet 5 4c649f727f Bump version to v2026.9.8.2
Same-day patch release: RDP TLS certificate verification fix and
Flathub submission prep.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 16:27:22 -06:00
ksmithandClaude Sonnet 5 aa812b0da7 macOS: fix launch crash, missing dylibs, and dmg volume icon
The app crashed at launch with "cannot be opened because of a
problem" because macdeployqt invalidates the code signature when it
rewrites library load paths; re-sign (ad hoc) after macdeployqt runs.

Also fixes the underlying cause of a Library-missing crash: orbithub's
INSTALL_RPATH used the Linux linker token $ORIGIN, which dyld does not
understand, and the bundled FreeRDP/WinPR/KodoTerm dylibs installed to
a sibling lib/orbithub/ directory outside OrbitHub.app rather than
Contents/Frameworks, so they were never copied into the dmg at all.
Both are now APPLE-specific, matching macdeployqt's own layout
(Contents/Frameworks, @executable_path/../Frameworks).

build-dmg.sh now also sets a custom volume icon (via SetFile or the
fileicon brew formula, whichever is available) instead of the
generic disk image icon, degrading gracefully if neither is present.

Also includes the StartupWMClass desktop-file fix from the prior
commit's message, which was never actually staged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 14:00:46 -06:00
ksmithandClaude Sonnet 5 3840ea9f62 Linux: fix taskbar pin matching and launcher icon mismatch
Add StartupWMClass=OrbitHub to the desktop file so panels (GNOME
Shell, Cinnamon, KDE) can match the running window to the pinned
launcher instead of creating a duplicate taskbar entry.

Replace the hand-authored, stale launcher SVG with PNG icons
rendered directly from createOrbitHubAppIcon() at each hicolor
theme size, so the pinned/menu icon matches the actual app icon
shown in the running window, Windows .ico, and macOS .icns.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 13:50:25 -06:00
ksmithandClaude Sonnet 5 7ce7260305 packaging: rename app ID to org.darksingularity.OrbitHub
The reverse-DNS app ID should reflect a domain we actually control.
Renames the desktop file, AppStream metainfo, icon, Flatpak manifest,
and macOS bundle identifier from io.orbithub.OrbitHub to
org.darksingularity.OrbitHub. Also fixes a stale homepage URL in the
metainfo file pointing at an old git host.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 13:39:06 -06:00
ksmithandClaude Sonnet 5 0990049241 Fix Flatpak build issues: EOL runtime and icon naming mismatch
- Bump the KDE runtime/SDK from 6.8 (now end-of-life per Flathub) to the
  current stable 6.10.
- The .desktop file's Icon=orbithub didn't match the app ID
  (io.orbithub.OrbitHub), so Flatpak's export step skipped it entirely
  ("Icon referenced in desktop file but not exported"). Use the app-ID-
  matching icon name everywhere instead, and drop the now-redundant
  renamed orbithub.svg install() rule that existed only for the old name.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 13:14:45 -06:00
ksmithandClaude Sonnet 5 6d5133e1bd Switch to date-based version scheme
Release versions now follow v<year>.<month>.<day>, with a .N suffix
appended only if a second release happens the same day (e.g. v2026.9.8,
then v2026.9.8.2 for a same-day follow-up). Replaces the placeholder
0.1.0 the project started with.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 13:14:33 -06:00
ksmithandClaude Sonnet 5 49ee12f5a1 Fix macOS configure error: add BUNDLE DESTINATION for install(TARGETS)
CMake requires an explicit BUNDLE DESTINATION for install(TARGETS) when
the target has MACOSX_BUNDLE set, or configure fails with "install
TARGETS give no BUNDLE DESTINATION for MACOSX_BUNDLE executable target".
The RUNTIME clause still covers Linux/Windows; BUNDLE only applies when
the target actually is a bundle (macOS), so no platform guard is needed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 12:37:47 -06:00
ksmithandClaude Sonnet 5 ac3cebc9ae macOS: build a proper .app bundle with an embedded icon
Same root cause as the earlier Windows exe icon fix: add_executable()
never set MACOSX_BUNDLE, so on macOS this produced a bare Mach-O binary
rather than a proper .app bundle -- and without a bundle there's no
Info.plist/.icns mechanism for Finder to show a custom icon at all.

Added packaging/macos/orbithub.icns, rendered at up to 1024px directly
from the same createOrbitHubAppIcon() logic used at runtime (via a
one-off export tool, not committed) so it matches what the app actually
looks like. CMake's MACOSX_BUNDLE keyword and MACOSX_BUNDLE_ICON_FILE
wire it into an auto-generated Info.plist; both keywords are no-ops on
other platforms. The profile database uses QStandardPaths::AppDataLocation,
not the executable's own path, so this doesn't affect where existing
profiles are found.

Build output on macOS changes from build/orbithub to build/orbithub.app
(launch with `open build/orbithub.app`); docs/BUILDING.md updated to match.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 12:35:52 -06:00
ksmithandClaude Sonnet 5 ac1deac148 Windows: embed app icon into the executable file
The app's icon only appeared at runtime (window/taskbar), set programmatically
via QApplication::setWindowIcon(). Explorer showed the generic default icon
for orbithub.exe itself, since that requires an icon baked into the PE file
as a Windows resource at build time -- a completely separate mechanism.

Added packaging/windows/orbithub.ico, rendered directly from the same
createOrbitHubAppIcon() logic used at runtime (via a one-off export tool,
not committed) so the file icon matches what the app actually looks like.
A minimal .rc resource file embeds it, compiled in only for WIN32 builds.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 09:49:38 -06:00
ksmithandClaude Sonnet 5 f3ea7f12a3 Windows: deploy sqlite3.dll and mark orbithub as a GUI (WIN32) executable
Two more Windows launch issues found alongside the Qt plugin deployment:
vcpkg's qtbase[sql-sqlite] links the QSQLITE driver plugin against vcpkg's
own shared sqlite3 port rather than bundling it, so the plugin was found
but failed to load without sqlite3.dll alongside the executable. Separately,
plain add_executable() defaults to the console subsystem on Windows, so a
command-prompt window appeared behind the GUI on every launch; add_executable
needs the WIN32 keyword to mark it as a GUI app (a no-op on other platforms).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 08:27:50 -06:00
ksmithandClaude Sonnet 5 30f0134748 Deploy Qt platform and SQLite plugins automatically on Windows
Qt loads its platform integration and SQL driver plugins dynamically
(QFactoryLoader) rather than importing them at link time, so they never
show up in orbithub.exe's import table and vcpkg's automatic DLL
deployment never copies them. Without this, the app fails to launch on
Windows with "Could not find the Qt platform plugin" or "can not load
requested driver 'QSQLITE'". Copy them out explicitly via Qt's own
exported plugin targets after each build, plus matching install() rules
for future packaging.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 08:20:17 -06:00
ksmithandClaude Sonnet 5 793fdd9366 RDP session fixes: correct keyboard scancodes, clipboard sync, cursor shapes
Fix RDP keyboard input using FreeRDP's authoritative X11-keycode-to-scancode
table instead of ad hoc bit math, which misread punctuation keys as unrelated
letter keys (e.g. apostrophe as B) because X11 keycode numbering only
coincidentally overlaps PC/AT scancodes.

Add bidirectional clipboard sync (CF_UNICODETEXT) over the cliprdr channel,
and RDP pointer/cursor shape sync so the local cursor reflects what the
remote OS wants displayed (resize handles, text I-beam, etc.) instead of
staying a static arrow.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 14:53:03 -06:00
ksmith c1c23d115a packaging: add deb/flatpak build flow and desktop metadata 2026-03-03 20:46:03 -07:00
ksmith eadcdd7f10 Milestone 8 UX: folder tree workflows, about dialog, and app icon polish 2026-03-03 20:07:41 -07:00
ksmith 36006bd4aa Milestone 5: deliver embedded RDP sessions and lifecycle hardening 2026-03-03 18:59:26 -07:00
ksmith 776ddc1a53 Integrate KodoTerm for SSH terminal sessions 2026-03-01 10:36:06 -07:00
ksmith 2b4f498259 Allow direct terminal typing and collapsible session panels 2026-03-01 09:58:21 -07:00
ksmith 6a4bcb75eb Add threaded session backend architecture with real SSH backend 2026-03-01 09:37:34 -07:00
ksmith f8a81ebe36 Implement Milestone 2 profile schema, dialog, and connect lifecycle 2026-03-01 09:21:53 -07:00
ksmith fba7336f69 Add SQLite profile repository and Qt SQL dependency 2026-03-01 09:06:31 -07:00
ksmith 285a81d9b5 Scaffold Qt6 Widgets app for Milestone 0 2026-03-01 08:56:10 -07:00