What's Changed
Fixed
-
Sidebar context menu did not open when it had no room below the pointer (issue #298) — the third and last cause behind this report, found after 0.20.7 fixed the two selection bugs: moving the main window higher up made the same right-click work, which is the signature of a popup that cannot be placed rather than a handler that never ran. A
GtkPopovercan never be smaller than its child, and the menu's child is a plain box of up to twenty rows and six separators — around 700 logical pixels. That was the popover's minimum height, so where neither anchoring below the pointer nor flipping above it left that much room, GTK had nowhere to put the surface and it never mapped: no menu, no error, nothing in the log. The menu now lives in aScrolledWindowcapped at two thirds of the monitor's height, which keeps room for the flip in either direction and scrolls whatever does not fit; a short menu is still allocated exactly as tall as its items, so nothing changes for a group or the empty-space menu. Keyboard navigation is unaffected — aScrolledWindowscrolls to whichever item takes focus. Separately, a menu that closes within 300 ms of opening with no user interaction now says so at debug level whether or not it was holding the input grab; the existing message only covered the grab-less case, which is why both this and #299 arrived as "the menu just does not open" with nothing to go on. -
Embedded mode on Web connections reverted to System, permanently (reported for 0.20.7) —
WebBrowserMode::Embeddedonly existed as an enum variant when theweb-embeddedfeature was compiled in, so a build without it parsed a storedbrowser_mode = "embedded"asSystem. The connection then sat in memory asSystem, and becauseconnections.tomlis rewritten whole from that in-memory copy, the next save of any connection destroyed the choice for every Web bookmark in the file — and updatinglast_connectedon a single connect is enough to trigger one. Nothing warned: the downgrade was logged at debug level and the rewrite not at all. This needs no exotic setup.rustconn-clitakesrustconn-corewithdefault-features = falseand never enables the feature, so a CLI built on its own did it too, and any distribution package built without WebKitGTK 6.0 does it to a configuration written by a Flatpak build that has it — the three can share one~/.config/rustconn. All three modes now exist in every build, and the feature decides whether Embedded can be run rather than whether it can be stored: a build with no WebView opens the URL in the system browser and leaves the stored mode alone, saying so at info level instead of silently. Round-tripping"embedded"through save and load is now asserted in both feature configurations. -
rustconn-cli --browser-mode embeddedset the opposite of what it asked for — the same root cause seen from the CLI:"embedded"fell through to the compile-time default, which for this crate isSystem. Bothrustconn-cli addandrustconn-cli updatenow store the mode that was requested. -
Editing a Web connection reset its page zoom and its certificate exception — the Web page of the connection editor has a widget for six of
WebConfig's eight fields, andbuild_web_configrebuilt the other two from literals:zoom_level: 1.0andaccept_invalid_certs: false. So changing a bookmark's URL threw away the zoom the embedded browser had persisted from its own zoom controls, and cleared a certificate exception that onlyrustconn-clican set — neither of which the dialog ever showed, so there was nothing on screen to suggest either was at stake. Saving now starts from the config the dialog was populated with and overlays what the widgets know; a new connection has no such value and correctly gets the defaults. In the same function, the custom browser command and user agent were only written into their rows when the stored value wasSome, so editing a connection that had neither left whatever the previously edited connection had in those rows — and saving adopted it. Both are now set unconditionally, empty string included. -
Config writes fought each other inside a single process —
flock(2)is held per open file description, so two writes contend even within one process, and.lockcovers the whole config directory. RustConn has four independent writers: three debounce workers (connections, groups, trash) and the history flusher on its own thread, plus synchronoussave_settingscalls from GTK callbacks. One connect starts two of those two-second debounces at the same instant, so they woke together and one found the lock taken — which is why "Waiting for another rustconn instance to release config lock…" appeared roughly two seconds after every connect with no other instance running. In-process writers now queue on a mutex, leaving the advisory lock to do the job it is actually for, and the message no longer names a cause it cannot observe. Three further problems in the same path: the wait was unbounded, so a lock genuinely held by another process could freeze the window forever from a GTK callback — it is now bounded and reports a timeout instead;save_toml_file_asyncwas a second, hand-maintained copy of the write sequence that opened with a synchronousflock, parking a runtime worker and defeating the caller'stokio::time::timeout(a timer only fires when the future yields, and a future stuck in a syscall never does), so the write now goes to a blocking-pool thread through the same single code path as the synchronous version; andflush_persistencetook each pending snapshot out of its channel before awaiting the write and then used?, so one failure onconnections.tomldiscarded that snapshot and returned before groups and trash were written at all — three files lost to one error, on the shutdown path, with a single log line to show for it. All three are now attempted, and each snapshot is cleared only once its write succeeds. -
A single credential lookup opened 25 encrypted Secret Service sessions —
LibSecretBackendconnected separately for every field of a credential, andoo7::dbus::Service::new()performs a DH key exchange each time (~12 ms, one "Starting an encrypted Secret Service session" line apiece). Oneretrievetherefore cost five connections — an availability probe plus one per field — and because resolving a credential tries five different lookup keys, a single click spent ~330 ms opening 25 of them. Visible in any debug log as a wall of identical oo7 lines whenever a password was not found. Each operation now opens one connection and passes it down, and the availability probe is cached briefly:SecretManagerprobes every backend before every lookup, for an answer that cannot meaningfully change inside one resolution. Storing a credential drops from four connections to one as well. -
Embedded RDP and VNC toolbars were barely readable on a light theme — the floating toolbar carried a fixed dark scrim (
rgba(36, 36, 36, 0.85)) and no foreground colour, on the reasoning that it floats over a remote desktop whose colours are not ours. Its contents are ours and take their colour from the local theme regardless, so under a light theme Copy, Paste, Autotype and the toolbar's icon buttons were near-black text on a near-black bar; only Ctrl+Alt+Del stayed legible, becausesuggested-actionbrings its own colour pair. The embedded browser had already been split out of that shared rule one release earlier for the same reason — a light URL bar inside a dark bar — which was this defect showing a different symptom. All three toolbars now follow the local theme the way a header bar does, and a drop shadow rather than a contrasting fill is what separates the bar from the content underneath. VNC and SPICE share the class and are fixed with it.
Dependencies
-
Updated: h2 0.4.18→0.4.19, open 5.4.1→5.4.2, syn 3.0.3→3.0.4. Seventeen further crates sit behind their latest release but cannot move: they are held at
-rcor exact versions by constraints elsewhere in the graph (the RustCrypto stack pinned through ironrdp, picky and sspi), so they need an upstream release rather than a lockfile change. -
Audited, no change needed: every auto-resolving CLI download endpoint answered — kubectl 1.36.4, Tailscale 1.102.3, Teleport 18.10.0, Boundary 0.21.3, Hoop.dev 1.148.0, Bitwarden CLI 2026.8.0, 1Password CLI 2.39.0 — and TigerVNC, the only pinned CLI download, is current at 1.16.2.
Installation
Flatpak (Recommended)
flatpak install flathub io.github.totoshko88.RustConnSnap
sudo snap install rustconnDebian/Ubuntu (.deb from this release)
sudo dpkg -i rustconn_0.20.8_amd64.deb
sudo apt-get install -f # Install dependencies if neededFedora (.rpm from this release)
sudo dnf install rustconn-0.20.8-1.fc44.x86_64.rpmAppImage
chmod +x RustConn-0.20.8-x86_64.AppImage
./RustConn-0.20.8-x86_64.AppImagemacOS (Homebrew)
brew tap totoshko88/rustconn
brew install rustconn
open $(brew --prefix)/opt/rustconn/RustConn.appAll dependencies (GTK4, libadwaita, VTE, Adwaita icons) are installed automatically.
Requires macOS 13 (Ventura) or later.
OBS Repositories
Packages available at: https://build.opensuse.org/package/show/home:totoshko88:rustconn/rustconn
# Debian 13 (Trixie)
echo 'deb http://download.opensuse.org/repositories/home:/totoshko88:/rustconn/Debian_13/ /' \
| sudo tee /etc/apt/sources.list.d/rustconn.list
curl -fsSL https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/Debian_13/Release.key \
| gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/rustconn.gpg > /dev/null
sudo apt update && sudo apt install rustconn
# Ubuntu 24.04 LTS (Noble)
echo 'deb http://download.opensuse.org/repositories/home:/totoshko88:/rustconn/xUbuntu_24.04/ /' \
| sudo tee /etc/apt/sources.list.d/rustconn.list
curl -fsSL https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/xUbuntu_24.04/Release.key \
| gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/rustconn.gpg > /dev/null
sudo apt update && sudo apt install rustconn
# Ubuntu 26.04 LTS (Resolute)
echo 'deb http://download.opensuse.org/repositories/home:/totoshko88:/rustconn/xUbuntu_26.04/ /' \
| sudo tee /etc/apt/sources.list.d/rustconn.list
curl -fsSL https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/xUbuntu_26.04/Release.key \
| gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/rustconn.gpg > /dev/null
sudo apt update && sudo apt install rustconn
# Fedora 44
sudo dnf config-manager addrepo --from-repofile=https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/Fedora_44/home:totoshko88:rustconn.repo
sudo dnf install rustconn
# Fedora 43
sudo dnf config-manager addrepo --from-repofile=https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/Fedora_43/home:totoshko88:rustconn.repo
sudo dnf install rustconn
# openSUSE Tumbleweed
sudo zypper ar https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/openSUSE_Tumbleweed/ rustconn
sudo zypper ref && sudo zypper in rustconn
# openSUSE Leap 16.0
sudo zypper ar https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/openSUSE_Leap_16.0/ rustconn
sudo zypper ref && sudo zypper in rustconnArch Linux (AUR)
yay -S rustconnFreeBSD (Ports)
pkg install rustconnFull installation guide: https://github.com/totoshko88/RustConn/blob/main/docs/INSTALL.md