---
Type: desktop-application
ID: com.github.paolostivanin.OTPClient.desktop
Package: otpclient
ProjectLicense: GPL-3.0+
Name:
C: OTPClient
Summary:
C: Application for managing TOTP/HOTP tokens with built-in encryption
Description:
C: |-
<p>OTPClient is a secure and easy-to-use desktop client for TOTP and HOTP one-time passwords, built with
GTK4 and libadwaita. Features:</p>
<ul>
<li>multiple databases with sidebar management and cross-database search</li>
<li>token grouping with quick filtering</li>
<li>desktop search provider for GNOME Shell and KDE KRunner (opt-in trigger keyword)</li>
<li>command-line companion (otpclient-cli) with scriptable table/JSON/CSV output</li>
<li>support for TOTP, HOTP, and Steam codes</li>
<li>configurable digits (4 to 10), period (1 to 120 seconds), and algorithm (SHA1, SHA256, SHA512)</li>
<li>import and export of encrypted/plain Aegis backups</li>
<li>import and export of encrypted/plain Authenticator Pro and 2FAS backups</li>
<li>import and export of plain FreeOTP+ backups (key URI format)</li>
<li>import of Google Authenticator migration QR codes (file, webcam, clipboard)</li>
<li>integration with the OS secret service provider via libsecret (opt-in)</li>
<li>local database encrypted with AES-256-GCM and Argon2id key derivation; plaintext lives only in
libgcrypt secure memory while unlocked</li>
</ul>
Developer:
id: com.paolostivanin
name:
C: Paolo Stivanin
Categories:
- System
- Security
Keywords:
C:
- otp
- totp
- hotp
- "2fa"
- "2factor"
- "2fa-client"
- "2step"
- twostep
Url:
homepage: https://github.com/paolostivanin/OTPClient
bugtracker: https://github.com/paolostivanin/OTPClient/issues
Icon:
cached:
- name: otpclient_com.github.paolostivanin.OTPClient.jxl
width: 48
height: 48
- name: otpclient_com.github.paolostivanin.OTPClient.jxl
width: 64
height: 64
- name: otpclient_com.github.paolostivanin.OTPClient.jxl
width: 128
height: 128
remote:
- url: com/github/paolostivanin.OTPClient.desktop/7b47b8ece5cf35b3fa7f475d52f2eb4f/icons/128x128/otpclient_com.github.paolostivanin.OTPClient.jxl
width: 128
height: 128
stock: com.github.paolostivanin.OTPClient
Launchable:
desktop-id:
- com.github.paolostivanin.OTPClient.desktop
Provides:
binaries:
- otpclient
Screenshots:
- default: true
caption:
C: Empty main window
thumbnails:
- url: com/github/paolostivanin.OTPClient.desktop/7b47b8ece5cf35b3fa7f475d52f2eb4f/screenshots/image-1_224x263@1.jxl
width: 224
height: 263
source-image:
url: com/github/paolostivanin.OTPClient.desktop/7b47b8ece5cf35b3fa7f475d52f2eb4f/screenshots/image-1_orig.jxl
width: 501
height: 590
- caption:
C: Add menu
thumbnails:
- url: com/github/paolostivanin.OTPClient.desktop/7b47b8ece5cf35b3fa7f475d52f2eb4f/screenshots/image-2_224x263@1.jxl
width: 224
height: 263
source-image:
url: com/github/paolostivanin.OTPClient.desktop/7b47b8ece5cf35b3fa7f475d52f2eb4f/screenshots/image-2_orig.jxl
width: 501
height: 590
- caption:
C: General menu
thumbnails:
- url: com/github/paolostivanin.OTPClient.desktop/7b47b8ece5cf35b3fa7f475d52f2eb4f/screenshots/image-3_224x263@1.jxl
width: 224
height: 263
source-image:
url: com/github/paolostivanin.OTPClient.desktop/7b47b8ece5cf35b3fa7f475d52f2eb4f/screenshots/image-3_orig.jxl
width: 501
height: 590
- caption:
C: Settings menu
thumbnails:
- url: com/github/paolostivanin.OTPClient.desktop/7b47b8ece5cf35b3fa7f475d52f2eb4f/screenshots/image-4_224x257@1.jxl
width: 224
height: 257
source-image:
url: com/github/paolostivanin.OTPClient.desktop/7b47b8ece5cf35b3fa7f475d52f2eb4f/screenshots/image-4_orig.jxl
width: 352
height: 405
Releases:
- version: "5.2.0"
type: stable
unix-timestamp: 1789516800
description:
C: |-
<p>Selecting a token no longer copies it. Clicking a row, or just arrowing past one, used to copy the
code and, for HOTP, burn a counter, so scrolling through the list could silently desynchronise an account
from its provider. Selection is now inert and each row carries an explicit Copy or Generate button, with
Enter and Ctrl+C as the keyboard equivalent. Underneath that, HOTP counters are written to the encrypted
database before a code is ever shown, in a single transaction, which also means the GUI and the command
line finally agree on what the stored counter means. The tray menu was separately empty on every desktop
except KDE Plasma, and had been since the tray was rewritten: right-clicking the icon opened a blank
rectangle on GNOME, Cinnamon, MATE, Xfce and Waybar alike. That is fixed too, and OTPClient can now start
minimized to the tray and start at login. Alongside all of those: the clipboard is no longer wiped out
from under another application, locking clears the dialogs it used to leave open, imports say which entries
they skipped and why, backup reminders are tracked per database instead of globally, and a round of fixes
lands for things that never worked inside the Flatpak sandbox. A pre-release audit of the whole release
then turned up a handful more that had never worked anywhere: GNOME Shell search results that did nothing
when activated, desktop integration that could not be started at all on sessions using dbus-daemon, and
exports that reported success after writing nothing.</p>
<ul>
<li>FIX: merely selecting an HOTP token consumed its counter. Single-click and arrow-key navigation
both went through the copy path, so browsing the list advanced counters with nothing to show for it,
and enough of that would desynchronise the account from its provider. Selection now does nothing but
select. A new Action column carries a button per row, copy for TOTP and generate for HOTP, labelled
by its icon and its tooltip; the same action heads the row's right-click menu, a double-click on the
row does the same, Enter and Ctrl+C activate the selected token while the list has focus, and Enter
also activates a search result</li>
<li>FIX: the validity countdown was drawn only for the selected row, a leftover from when selecting
a row was what revealed its code. With selection inert the two came apart, and a code could sit visible
with no countdown beside it, most obviously right after the row's own Action button revealed one: the
button claims the click, so the row never gets selected. The countdown now follows the code it counts
down and appears for every TOTP that is showing one. HOTP rows no longer get one at all, having no
rotation period to count down</li>
<li>FIX: toggling "Hide OTPs by Default" left the already-drawn rows alone until a scroll or a selection
change rebound them. The refresh was wired up in the window's constructed(), which reads the application
property before GObject has set it, so the hook was never connected at all</li>
<li>FIX: an HOTP counter could be shown or copied without ever reaching disk. The GUI generated the
code, advanced the counter in memory, and deferred the encrypted re-save by up to five seconds to coalesce
bursts of clicks; a crash, a kill, or a power loss inside that window handed out a code the database
no longer knew it had issued. Generation and persistence are now one atomic transaction, and the code
is not revealed until the write has committed</li>
<li>NOTE: the stored HOTP counter now means the next unused code in both interfaces. Older GUI versions
stored the last generated one while the CLI stored the next, and there is no way to tell which wrote
a given value, so existing counters are left exactly as they are. If an HOTP account rejects its first
code after upgrading, generate the next one or resynchronise the counter with the provider. This affects
HOTP only, and only accounts previously used from the GUI</li>
<li>FIX: a database still in the version 1 or 2 format could crash the app while being upgraded. If
the decryption that follows the upgrade failed, after a rekey with the wrong password, on a truncated
file, or with the secure-memory pool exhausted, the same buffer was released twice. Upgrading is the
first thing an older database does on this release, so the window was narrow but badly placed</li>
<li>FIX: a database whose directory is full, read-only or over quota could not be saved at all. The
lock file added in 5.1.x reported "Failed to open database lock" and stopped there, where it was meant
to warn once and carry on unlocked, which is what earlier releases did. Sandboxed builds were the most
exposed, the lock sitting beside the database inside the Flatpak's own data directory</li>
<li>FIX: the backup taken beside the database was overwritten with a copy of the database that had
just been saved, so it held the same generation as the file it was there to protect and could not be
used to go back. It is now taken before the write and left alone afterwards, and failing to write it
no longer aborts the save</li>
<li>FIX: exiting or locking wiped the clipboard even when the user had since copied something else,
destroying unrelated data. OTPClient now clears the clipboard only while it still owns the content
it put there, and copying anything elsewhere cancels both the pending wipe and the automatic next-code
copy</li>
<li>FIX: locking left sensitive dialogs open with their contents intact. A displayed QR code, a typed
secret, an export password, or an unlock prompt survived the lock in memory and on screen. Locking
now closes those dialogs, zeroes their entry buffers, drops their QR textures and snapshots, and cancels
any operation still in flight, including when an open file chooser is holding the dialog alive</li>
<li>FIX: a new encrypted migration export could be created with an empty password, producing a file
that looked encrypted and was not. Encrypted exports now require a password. Existing empty-password
exports still import, so nothing already on disk becomes unreadable</li>
<li>FIX: encrypted Aegis, Authenticator Pro and 2FAS exports were written from a buffer sized with
different formatting flags than the dump that filled it, and the size mismatch was checked against
a value the function cannot return</li>
<li>NEW: partial imports now report what was skipped and why, per entry, instead of silently importing
fewer tokens than the file contained. The command line keeps a success status when at least one valid
entry was imported and prints the warnings to stderr; input with nothing valid in it fails and leaves
the database untouched</li>
<li>FIX: malformed third-party backups could slip past the importers. The Aegis, Authenticator Pro
and 2FAS readers now check that the entry list is actually a list, validate and repair each token before
accepting it, report a parse failure through an error instead of a printed line, and no longer leak
the fields of an entry they reject</li>
<li>FIX: an export that could not be written reported success. None of the four exporters closed the
file they had opened, and with the atomic-replace mode in use the rename happens inside that close,
so a full disk or an exceeded quota produced "Data successfully exported to" over a truncated file,
with a stray temporary left beside it. This is the backup feature, so the silence was the worst part
of it</li>
<li>FIX: a token whose account name contains a percent sign, or whose issuer contains a colon, did
not survive a round trip through our own plain-text export. The label was percent-decoded twice, so
"alice 100%" was rejected outright on re-import and "Acme:Corp" was split in the wrong place. Query
values were decoded twice as well, which dropped any token with an issuer such as "50%off". Exports
now escape the two halves of the label separately and imports decode exactly once. Files written by
older releases still import</li>
<li>FIX: importing a large file of junk produced one diagnostic line per skipped entry and handed the
lot to a single label, which for a big enough file meant hundreds of megabytes of text nobody could
read. The list now stops at the first fifty and counts the rest</li>
<li>FIX: reading an otpauth file trusted the size reported before the read rather than the number of
bytes actually read, so a file rewritten shorter in between was read past its end and then zeroed past
its end</li>
<li>FIX: secrets were left in ordinary, pageable memory in three places: the key that unwraps an encrypted
Aegis backup, the per-token seeds handed back by the Google Authenticator migration decoder, and the
URI written by the FreeOTP+ exporter. All three now use the secure pool or are wiped before being released</li>
<li>FIX: Steam tokens were exported with the issuer named twice, which strict third-party parsers reject</li>
<li>FIX: the command line's JSON output was not a single document and its CSV had no header row, so
neither could be piped into an ordinary parser. Diagnostics also went to stdout, mixed in with the
data. JSON is now one document, CSV starts with a header, and diagnostics go to stderr</li>
<li>FIX: the command line never saved the master password to the keyring on first run, so with Secret
Service enabled it asked for the password on every single invocation and never explained why. The store
was started asynchronously in a process that has no main loop to finish it</li>
<li>FIX: every argument-validation error from the command line went to standard output, mixed in with
the data, contrary to what the manual page promises. A mistyped option fed an English sentence to whatever
was parsing the JSON, and redirecting stdout to /dev/null threw away the only diagnostic there was.
They now go to standard error</li>
<li>FIX: the backup reminder tracked one global timestamp, which could not say which database it referred
to and was also bumped by migration exports, so exporting for another app suppressed a genuine reminder.
Backup history and snoozes are now recorded per database, and exports no longer count as backups from
either interface. The old global value cannot be attributed to a database, so it is not carried over:
after upgrading, each database reads "No backup recorded" until you take one, and any active snooze
is reset</li>
<li>FIX: search-provider settings needed a restart, typically a logout, to take effect. Disabling the
provider, clearing its keyword, or turning off Secret Service now applies immediately and revokes cached
keys, cached entry lists, and any activation ID already handed out. A clipboard delivery in flight
when the settings change can no longer land afterwards</li>
<li>FIX: an HOTP search result from a database other than the open one had nowhere to write its counter.
Activating one now opens the owning database so it can be unlocked and generated there, rather than
appearing to work</li>
<li>FIX: drag-reordering the list when the save failed left what is on screen and what is in the database
disagreeing about which row is which. The next Copy or Generate then acted on a different account,
and for HOTP that meant advancing and storing another token's counter. The list is now rebuilt from
the database whenever a reorder fails to commit</li>
<li>FIX: importing or exporting settings from a network or phone mount, sftp, SMB, MTP or a cloud drive,
crashed the app. Those locations have no local path, and the failure was reported by reading an error
that had never been set. The unsupported location is now named instead. Exporting a backup to one of
them also claimed to have succeeded without writing anything</li>
<li>FIX: searching while the database was locked froze the window for minutes and filled the journal
with warnings. The group list is empty while locked, and the loop over it counted down from an empty
list rather than skipping it</li>
<li>FIX: clicking another database in the sidebar while the current one was locked switched to it anyway,
out from under the lock</li>
<li>FIX: a QR code pasted from the clipboard with a transparent background never scanned. Pasted images
arrive with their colour channels premultiplied by alpha, which the brightness calculation ignored,
so a transparent background read as solid black. Images opened from a file were never affected</li>
<li>FIX: the typed Base32 secret and the export password were left sitting in their entry buffers when
the dialog closed along certain paths, instead of being zeroed</li>
<li>FIX: several memory leaks in the GUI, and one path where a dialog could be disposed twice</li>
<li>FIX: pressing Enter on a GNOME Shell search result did nothing at all, and never had. A malformed
format string meant the handler read none of its arguments, so there was no copy, no notification and
no error, only a warning in the journal. Results appeared and were drawn correctly, which is what made
the feature look like it worked</li>
<li>FIX: neither the search provider nor the KRunner plugin could be started at all on sessions that
activate services through dbus-daemon rather than systemd, which covers the Debian and Ubuntu defaults,
distributions without systemd, and anything run under dbus-run-session. The service files named the
executable without a path, and dbus-daemon does not search PATH. The Flatpak was never affected</li>
<li>FIX: with the search provider disabled, the process exited before taking its bus name, so every
search produced a spawn error for GNOME Shell and KRunner instead of an empty result. It now answers,
with nothing to show, and starts serving again the moment the feature is re-enabled</li>
<li>FIX: a locked login keyring froze the search provider inside the first search it was asked for,
and each database it then had to decrypt blocked it again, with every other request queued behind.
The keyring lookup and the key derivation now run off the main loop</li>
<li>FIX: activating a search result whose password is not in the keyring, or whose database will not
decrypt, did nothing whatsoever, not even a log line. The reason is now reported</li>
<li>FIX: handing the code to a clipboard tool could hang the search provider indefinitely if the tool
never returned, which is what an xclip against an unreachable display does. The call is now asynchronous
and bounded by a timeout</li>
<li>FIX: the notification carrying the code is now marked transient, so desktops keep it out of their
notification history</li>
<li>NOTE: the search provider's trigger keyword is a query filter, not an authentication mechanism,
and is no longer described as one. Desktop search additionally requires Secret Service access, a saved
database password, and the provider to be enabled</li>
<li>FIX: the tray menu was an empty rectangle on every host built on libdbusmenu, which is GNOME with
AppIndicator, Cinnamon, MATE, Xfce, Ayatana and Waybar. The tray declared dbusmenu version 3, which
makes clients fetch labels with GetGroupProperties and dispatch clicks through EventGroup, and neither
method existed, so both menu entries were silently dropped. The group methods are now implemented,
and clicking an entry works rather than doing nothing (#470, Flathub #81)</li>
<li>NEW: start minimized to the tray, from Settings under Integration or with <code>otpclient --start-minimized</code>.
It needs minimize-to-tray and a real system tray, and is ignored with the window shown normally when
either is missing. The database is deliberately left locked, so the first time you bring the window
up it asks for the password (#471)</li>
<li>NEW: start at login, from Settings under Integration. Native builds write an autostart entry; the
Flatpak asks the desktop through the background portal, which a few desktops do not implement, and
there the setting is greyed out. The entry follows the start-minimized preference</li>
<li>FIX: an autostart entry created by hand, or by GNOME Tweaks' Startup Applications, was deleted
on the first launch of this release. The start-at-login setting is new and defaults to off, and startup
enforced that against a file it had never written. An entry already present is now adopted, with the
setting turned on to match, instead of being removed</li>
<li>FIX: with start-minimized on, the first click on the tray icon always asked for the master password,
even with the system keyring enabled and the password saved there. The deferred unlock never consulted
the keyring; it does now, which is the combination start-at-login exists for</li>
<li>FIX: the start-at-login and background-permission settings recorded what had been asked for rather
than what the desktop agreed to. A refusal, a timeout, or a quit part way through left a switch claiming
a state that was not real, the worst shape of that being a login entry nobody can see still launching
the app while the switch reads off. Every answer is now reconciled against what the desktop actually
said, an inconclusive one is remembered and retried on the next launch, and only one background request
is ever in flight</li>
<li>FIX: the autostart entry named the executable without a path and carried no TryExec, so an install
outside the session's PATH wrote an entry that silently never launched, and uninstalling left one that
failed at every login. It now carries the absolute path it was installed to</li>
<li>FIX: the background-permission prompt was closed out from under the user after a minute, which
turned minimize-to-tray off and blamed the desktop for refusing it. The wait is now five minutes, and
a local failure to write the autostart file no longer reports itself as a refusal from the desktop
either</li>
<li>FIX: a tray host restarting, a GNOME Shell reload or a plasmashell --replace, force-raised a window
the user had hidden, and on a start-minimized launch it brought the password prompt up with it. A short
grace period now tells a panel that is coming back from one that is gone</li>
<li>FIX: webcam QR scanning has never worked in the GTK4 rewrite, on any platform. The scanner opened
a zbar preview window instead of the camera, then failed on every frame and reported a timeout. It
now opens the camera, and no longer needs an X display to do it</li>
<li>FIX: in the Flatpak, activating a search result copied nothing. The daemon shells out to a clipboard
tool and the runtime shipped none, so every candidate failed silently. The tools are now bundled, the
Wayland session is detected from WAYLAND_DISPLAY rather than a variable the sandbox may not set, every
available tool is tried instead of committing to one, and a failure is reported instead of being swallowed</li>
<li>FIX: <code>otpclient-cli</code> failed with "Application does not handle command line arguments"
whenever the GUI was running, because both registered the same application id and the CLI became a
remote of the GUI. This mattered rarely before and would have become permanent with start-at-login</li>
<li>FIX: databases opened from outside the Flatpak's own data directory were saved without any lock
held. The document portal implements POSIX record locks and refuses flock outright, which is what the
code used, so the "Database lock not supported on this filesystem" warning was reached on every save.
Locking works again for those databases</li>
<li>FIX: a database picked from outside the sandbox could stop opening after a reboot, on btrfs and
other filesystems whose device numbers are not stable, and the dialog then suggested two things that
could not recover it. The dialog now says the sandbox lost access rather than that the file is missing,
and offers to re-pick it</li>
<li>FIX: "Locate..." on the "Database No Longer Accessible" dialog routed into the plain open picker,
which appends a row, so relocating a database left the old entry behind and the new one under a different
name. It now replaces the path on the row that is already there, keeps its name, drops the duplicate
if the target was listed twice, and moves the saved Secret Service password across to the new path</li>
<li>FIX: a settings backup silently dropped the search-provider keyword and the clipboard-clear timeout,
both of which the settings dialog offers, and an imported sidebar-visibility value did not reach a
window that was already open</li>
<li>FIX: turning minimize-to-tray off inside the Flatpak left a dead icon in the panel until the app
exited, because the sandboxed tray had no bus name it could release</li>
<li>FIX: the tray icon now says so when the database is locked, and the "Show OTPClient" entry raises
the window on Wayland instead of being blocked by focus-stealing prevention</li>
<li>FIX: every Flatpak launch logged a warning about not being able to subscribe to suspend events.
The system bus is not there to be reached, so the attempt is no longer made and no longer complained
about. Locking on screen lock is unaffected</li>
<li>NOTE: the search provider is a separate process with its own lock state. A hidden or locked GUI
does not stop search from working, and using search does not unlock or reveal the GUI</li>
<li>NOTE: if you use the system keyring to unlock automatically and turn start-minimized on, OTPClient
will sit in the tray over a locked database rather than an open one. That is intentional, and it is
the reason the first show asks for the password</li>
</ul>
- version: "5.1.8"
type: stable
unix-timestamp: 1787270400
description:
C: |-
<p>Bug-fix release. Minimize-to-tray did not work in the Flatpak: the switch was greyed out as if the
desktop had no system tray, and granting the missing permission by hand still produced no icon. The sandbox
refuses the process-derived bus name the tray asks to own, so the tray now registers with the tray host
under its unique connection name instead, which needs no permission and works in any sandbox. The Flatpak
was also missing the permissions Auto-Lock needs, so locking on screen lock silently did nothing; that
is fixed in the Flathub packaging, though locking on suspend stays unavailable there.</p>
<ul>
<li>FIX: no tray icon appeared in sandboxed builds even with a tray host present, because the session
bus refused the process-derived StatusNotifierItem name and the tray gave up. It now falls back to
registering under its unique bus connection name, which is what Qt applications do, so the icon appears
regardless of what the sandbox grants (Flathub #79)</li>
<li>FIX: two sandboxed applications could not both show a tray icon: every Flatpak process sees itself
as pid 2, so the process-derived StatusNotifierItem names collided and whichever lost the race silently
got none. Both now get an icon (Flathub #79)</li>
<li>PACKAGING: the Flatpak lacked the D-Bus permissions the tray and Auto-Lock need. Access to the
StatusNotifierWatcher name un-greys the minimize-to-tray switch, which had reported "No system tray
was detected on this desktop" on desktops that do run one, and access to the desktop screensaver services
makes Auto-Lock on screen lock work, which had been a no-op. Auto-Lock on suspend stays unavailable
in the Flatpak because it needs logind, which Flathub does not permit, so the "Could not subscribe
to suspend events" warning remains there (Flathub #79)</li>
</ul>
- version: "5.1.7"
type: stable
unix-timestamp: 1785801600
description:
C: |-
<p>Minimize-to-tray is now offered in default builds. It had been an opt-in build flag because turning
it on could strand the application: on a desktop with no system tray, closing the window hid it anyway
and left OTPClient running invisibly, holding a decrypted database, with no icon to bring it back. The
app now confirms a tray host is really there before it will hide to one, and restores the window if the
tray goes away. The feature itself is still off by default in Settings.</p>
<ul>
<li>FIX: with minimize-to-tray enabled on a desktop that has no system tray (stock GNOME without the
AppIndicator extension, i3bar, polybar), closing the window hid it with no icon to restore it, leaving
an invisible process holding a decrypted database that only killall could stop. The window is now hidden
only once a tray host has accepted the icon, and if the tray disappears while the window is hidden
the window comes back (#405)</li>
<li>BUILD: ENABLE_MINIMIZE_TO_TRAY now defaults to ON, so distribution packages offer the feature without
a custom build. The tray has not needed libayatana-appindicator since it moved to a direct StatusNotifierItem
implementation over GDBus, so this adds no dependency. The minimize-to-tray setting itself is unchanged
and still defaults to off, and its switch is greyed out where no tray was detected (#405)</li>
</ul>
- version: "5.1.6"
type: stable
unix-timestamp: 1784678400
description:
C: |-
<p>Bug-fix release. Auto-Lock was effectively unusable: on any profile that enabled it without changing
the timeout, the database re-locked about five seconds after every unlock, and the unlock prompt could
not be dismissed and quit the whole application when closed, leaving Settings unreachable. The timeout
now defaults to five minutes, and the unlock prompt is dismissable and returns to a locked screen instead
of quitting.</p>
<ul>
<li>FIX: with Auto-Lock enabled but the timeout left at its default, the database re-locked roughly
five seconds after each unlock. The idle timer counts seconds, but the default was 5 and documented
as minutes; the default is now 300 seconds (five minutes), so profiles that never set a timeout pick
up a sane value automatically (#467)</li>
<li>FIX: the unlock prompt could not be dismissed and closing it quit the whole application, so Settings
could not be reached while locked. Dismissing it (Escape, the dialog close button, clicking outside,
or the window close button) now drops to the locked screen and keeps the toolbar reachable; the toolbar
lock button doubles as an unlock button while locked, and an explicit Quit button remains on the prompt
(#467)</li>
</ul>
ContentRating:
oars-1.0:
violence-cartoon: none
violence-fantasy: none
violence-realistic: none
violence-bloodshed: none
violence-sexual: none
drugs-alcohol: none
drugs-narcotics: none
drugs-tobacco: none
sex-nudity: none
sex-themes: none
language-profanity: none
language-humor: none
language-discrimination: none
social-chat: none
social-info: none
social-audio: none
social-location: none
social-contacts: none
money-purchasing: none
money-gambling: none