Skip to content

v0.21.7

Latest

Choose a tag to compare

@github-actions github-actions released this 06 Sep 17:36

What's Changed

Fixed

  • The Session Logs dialog could not be made narrow — its file list and content pane were held apart by a gtk::Paned, which keeps both children on screen at every width, so the dialog had a wide floor and could not sit beside anything on a small display. It is an adw::OverlaySplitView now, with a breakpoint that collapses the list into an overlay below 500sp and a header toggle that appears only once collapsed. Picking a file while collapsed dismisses the overlay, since otherwise the log just opened would stay hidden behind the list. The project's own HIG notes name this substitution directly — a collapsing sidebar rather than a fixed pane — and the main window had been following it for releases.

  • Two boxed lists were drawn inside a second border, and an information row carried two icons — the workspace list sat in a gtk::Frame while already carrying the boxed-list style class, which draws its own border, so the list appeared with a frame around its frame. The Credentials Storage row in the export dialog had typed into its title and a dialog-information-symbolic prefix, so the same idea was stated twice — once as a themed icon and once as a character, which does not follow the icon theme, cannot be translated, and is read out by a screen reader as part of the heading.

  • Client detection reported its result by colour and a glyph alone — each row on Preferences ▸ Clients carried a bare , or styled with a CSS colour class and nothing else: no tooltip, no accessible label. A screen reader read out the glyph, which says nothing about whether the client was found, and the distinction between the three states rested on colour, which is precisely what the accessibility guidance rules out. Each indicator now carries the state as words — "Installed", "Not found", "Using embedded client" — as both its accessible label and its tooltip. The glyph and colour stay as the visual cue.

  • Preferences showed internal action names to the user — every row on the Keyboard Shortcuts page used the action identifier as its subtitle, so the list read "Close Tab / app.close-tab", "Quit / app.quit" and so on. That string is what the code keys its accelerator lookups by; it is not a description, and it was the one untranslated piece of text on the page. The subtitle is gone — the row's title already names the action in the user's language.

  • Three switches in Preferences ▸ Secrets were not boxed-list rows — "Use API key authentication" (Bitwarden), "Use password" and "Use key file" (KeePassXC) were built as a bare GtkSwitch dropped into an AdwActionRow suffix, while every other switch on the page had already moved to AdwSwitchRow. They behaved correctly but sat slightly apart from their neighbours and needed a manual set_activatable_widget to make the row clickable at all. All three are AdwSwitchRow now, which handles that itself, and the three intermediate rows they needed are gone.

  • A smart folder whose icon was an icon name displayed the name as text — the folder row pushed whatever the icon field held straight into a Label, so entering folder-symbolic showed the literal string "folder-symbolic" instead of an icon. Connection rows in the same file already got this right, telling an emoji from a themed icon name with is_glyph_icon and falling back through theme_icon_or when the active theme lacks it; the folder row is on that path now. Its default stopped being a hardcoded 📁 glyph, and the "Smart Folders" section header stopped being a 🔍 one — both are symbolic icons, so they follow the icon theme and the high-contrast setting instead of the font. An emoji the user typed is still shown exactly as typed: that is a choice, not a default.

  • The Smart Folders context menus were invisible to a screen reader and unusable from the keyboard — right-clicking a smart folder, or a connection inside one, opened a menu built by hand in smart_folder_ui: a GtkBox of plain buttons with no AccessibleRole::Menu on the container and no MenuItem on the items, so assistive technology announced a box of buttons rather than a menu. There was no arrow-key navigation, no Home/End, no Escape handler, no height cap, and no coordination with the rest of the application's popovers. The sidebar's own context menus have had all of that for several releases; these two were a parallel implementation that never received any of it. They now go through the same show_popover builder, so the behaviour cannot drift again. Making that possible meant generalising ContextMenuItem: an item carries a list of actions to activate in order, each with an optional target value, which is what the smart-folder items need — "select this connection by id, then run the action that operates on the selection". Two side effects worth noting: the shared builder brings the fixes those menus had been missing (the grab handling from issues #157/#299, the early-dismissal retry, the focus-loss close from #93, the menu height cap from #298), and Delete in the sidebar's menu is now styled as destructive, which only the hand-rolled copies had been doing.

  • The embedded VNC status screen was English-only — the placeholder drawn before the framebuffer arrives ("Disconnected", "Connecting…", "Connected", "Connection error", "Session running in external window") passed bare literals straight to Cairo, so it stayed in English in every locale. The RDP equivalent had been going through i18n() all along, which is what made the gap easy to miss: the two screens look the same and only one of them was translated. The host placeholder shown when nothing is configured yet was untranslated too, on both sides — VNC's "Not configured" and RDP's "No connection". All of it is wrapped now, and VNC's "Connecting..." picked up the proper ellipsis while it was being touched.

  • Copy in an embedded VNC session did nothing and said nothing — the button was wired to a handler that read the local clipboard, logged its length at debug level, and stopped. Nothing was transferred, no status appeared, and the button was enabled from the moment the toolbar was built, so pressing it on a fresh session was indistinguishable from a button with no handler. The RDP toolbar next to it had the full version — cache the text the server pushed, put it in the local clipboard on demand, report "Copied N chars" or "No remote clipboard data" — and VNC had none of it. It does now. The one structural difference from RDP is worth stating, because it decides what the button can mean: RFB clipboard transfer is push-only, so there is no request a client can send to read the remote clipboard. The text the server volunteered through ServerCutText is the only copy that exists locally, so EmbeddedVncWidget retains it and Copy re-asserts it into the local clipboard — which is what you want when something else has since overwritten it. The automatic mirror on arrival stays, since without it a remote copy would never reach the local clipboard at all. The button now starts insensitive with a tooltip saying it is waiting for remote data, exactly as the RDP one does, and becomes active when the first text arrives. It also gained the accessible label it was missing. show_status_briefly moved from embedded_rdp::clipboard to embedded_trait, where both toolbars can reach it — the absence of a shared helper is part of why the VNC side had no feedback to give.

  • The wizard threw away the icon when you pressed "Advanced…" — typing an emoji or icon name on the wizard's Authentication page and then continuing into the full editor lost it, so the field opened empty and the connection was saved without it. Save and Save & Connect kept the icon, which is what made this hard to spot: the icon was read in build_connection, the method those two buttons use, and collect_partial — the one that feeds WizardResult::OpenAdvanced — never asked for it. PartialConnection had no icon field at all, so there was nowhere for it to go even if it had been read. The field exists now and the fallback to the selected template's icon is resolved once, inside collect_partial, rather than separately in build_connection; both paths read the same value, so they cannot disagree about it again. from_connection carries the icon in the other direction too, which fixes the same omission in "Duplicate via Wizard…" — it dropped the original's icon on the way into the wizard, and AuthPage had a getter for the field but no setter, so nothing could have pre-filled it.

  • The connection editor kept calling a URL a Host, and hid fields by leaving an empty row behind — selecting the Web protocol was supposed to retitle the Host row to URL, and the protocols that have no host or port — Serial, Kubernetes, and every Zero Trust provider but Custom Command — were supposed to drop those rows entirely. Neither worked. The General tab created seven gtk::Label widgets for Host, Port, Username, Domain, Tags, Password Source and Value, stored them on BasicTabWidgets, and never added a single one to any container. The visible text of a boxed-list row is the row's own AdwActionRow::title, set separately when the row was built, so the labels were orphans from the moment they were constructed. apply_general_field_visibility then spent its whole body acting on them: host_label.set_text("URL") retitled a widget nobody could see, and host_label.set_visible(false) hid the same one. What made the second half look like it worked is that the entries were being hidden alongside — so a hidden field left its row on screen, titled "Host" or "Port", with nothing in it to type into. Visibility and titles now act on the rows, which is also why the paired *_entry.set_visible() calls are gone: an entry is a suffix inside the row, so hiding the row already takes the entry with it, and toggling both invited the two to disagree. The orphaned labels are deleted rather than wired up, along with the Value one that had no reader at all. Three of them turned out to be the only thing keeping username_entry, tags_entry and domain_entry alive in the visibility struct, and the whole #[expect(dead_code)] on BasicTabWidgets went with them — an attribute that had been silently absorbing this bug, since "these fields are never read" was the compiler pointing straight at it.

Changed

  • Every ellipsis in the interface is now one character instead of three periods — GNOME's writing-style guidance calls for , and the codebase had been using both spellings side by side: 111 user-facing strings across 31 files still spelled it ..., next to strings that already carried . All of them are now. Only strings the user reads were touched: Display impls, tracing messages, doc comments, icon names and action identifiers keep their periods, because the first two end up in log files a person greps and the last two are identifiers the toolkit matches literally.

    The two spellings were not separated by dialog, which is the part worth recording, because it means two strings had been living in the catalogues twice. dialogs/connection/dialog/build.rs sets a button label to Testing... while testing the connection and to Testing… while testing a post-login script — two buttons in one dialog, two msgids, seventeen translators each asked the same question twice. Verifying... in the KeePassXC unlock dialog and Verifying… in the portable-storage one are the same duplication across two files. The answers diverged: for Verifying seven catalogues chose a different verb for each copy (Dutch "Verifiëren" against "Controleren", Polish "Weryfikowanie" against "Sprawdzanie", and the same split in Danish, Italian, Georgian, Slovak and Swedish), and Ukrainian did it for Testing too — «Випробовування…» on one button and «Тестування…» on the other, so which word appeared depended on which code path built it. Normalising the spelling merges each pair down to one msgid, and the entry kept is the one that already carried the proper ellipsis.

    Regenerating the template also surfaced five strings that had never reached the translators at all. Four are from earlier in this release — the Credentials Storage row that lost its , the "Show log file list" toggle the Session Logs dialog gained, and the "Using embedded client" / "Not found" wording the Clients page now speaks out loud — where the source string changed and the catalogues were not resynced in the same commit. The fifth, No connection, is older: it is the host placeholder an embedded RDP session draws before anything is configured, present in the code since v0.8.4 and missing from the template ever since, so it had never been translatable in any release. All five are translated in all seventeen languages, and the punctuation-only differences were carried across without a fuzzy flag, since an ellipsis is not a linguistic change.

Removed

  • Around 390 lines of unreachable UI code, including one control that lied about what it did — the audit for this release went looking for dead widgets and found that most of what it turned up was not merely unused but a spare copy of something already written elsewhere, kept alive by an #[expect(dead_code)] whose stated reason had stopped being true. embedded_trait held three: EmbeddedWidgetState, a state-and-callbacks helper no widget ever adopted because RDP, VNC and web each keep their own fields; create_embedded_toolbar, which built a toolbar nobody asked for and was actively misleading, since it set accessible labels on its buttons and so made the VNC toolbar look as though it had merely forgotten to, when it had never been built from there at all; and draw_status_overlay, a third copy of the pre-framebuffer placeholder alongside the one RDP calls and the one VNC draws inline. sidebar_types held DragDropData, marked "Fields used by drag-drop callback system" when no callback system referenced it, plus the index-tracking half of DropIndicator — two fields written and never read, a setter only ever called with None, and a show() whose row index its one caller passed as 0 beneath a comment saying it was unused; all of it left over from before the drop visual moved to CSS classes. connection::web held validate_web_options, reserved for "upcoming connection-editor validation wiring" that had in fact already been done, better, in ConnectionDialogData::validate, where a refusal produces a message the user sees rather than a bare bool. The one with a user-visible edge is SessionControls: its fullscreen button flipped a private bool and called no window API whatsoever, so it could not have done what its tooltip promised. It was never on screen — the only EmbeddedSessionTab ever built is the force_external one that owns a spawned viewer process and is never added to the notebook — but a button that cannot work is worse than no button, so it is gone rather than fixed. Fullscreen for a real session is win.toggle-fullscreen.

Dependencies

  • Updated: crossbeam-channel 0.5.16 → 0.5.17, crossbeam-deque 0.8.7 → 0.8.8, crossbeam-epoch 0.9.20 → 0.9.21, crossbeam-utils 0.8.22 → 0.8.23, der 0.8.1 → 0.8.2, ipnet 2.12.1 → 2.12.2. All in-range patch/minor updates within existing requirements; cargo deny check advisories clean. dirs was held at 6.0 rather than taken to 7.0: the API is identical for the functions in use, but tray-icon 0.24 still pins dirs = "^6", so bumping would duplicate the crate in the tree for no functional gain.

Installation

Flatpak (Recommended)

flatpak install flathub io.github.totoshko88.RustConn

Snap

sudo snap install rustconn

Debian/Ubuntu (.deb from this release)

sudo dpkg -i rustconn_0.21.7_amd64.deb
sudo apt-get install -f  # Install dependencies if needed

Fedora (.rpm from this release)

sudo dnf install rustconn-0.21.7-1.fc44.x86_64.rpm

AppImage

chmod +x RustConn-0.21.7-x86_64.AppImage
./RustConn-0.21.7-x86_64.AppImage

macOS (Homebrew)

brew tap totoshko88/rustconn
brew install rustconn
open $(brew --prefix)/opt/rustconn/RustConn.app

All 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 rustconn

Arch Linux (AUR)

yay -S rustconn

FreeBSD (Ports)

pkg install rustconn

Full installation guide: https://github.com/totoshko88/RustConn/blob/main/docs/INSTALL.md