mirror of
https://github.com/lhns/steam-frame-nix.git
synced 2026-10-06 04:04:16 +02:00
Launchers: apps' own desktop entries, rewritten; keyring moves into them
steamFrame.launchers.<desktop ID> takes the app's own entry (a Flatpak's
export, a Nix package's or a host file) and rewrites only its command lines
(hostEnv, env, flatpakArgs, args, wrappers) and the keys asked for
(mimeTypes, defaultFor, settings), so name, icon, translations and actions
stay the app's and follow its updates.
- Package entries are rewritten at build time; Flatpak/host file entries at
runtime by steam-frame-nix-launchers into
<session.runtimeDir>/steam-frame-nix/applications (tmpfs), on switch, at
login and when Flatpak installs/updates apps (path unit); the Home Manager
links point there.
- keyring.{enable,electron} replaces steamFrame.keyring.{flatpaks,programs}
(clean break: the old options fail with the new form).
- Firefox's launcher is the Flatpak's entry with the profile wrapper in
front (no --profile for the profile manager); Jellyfin's hardware
decoding sets flatpakArgs and env.
- cleanup --all removes the tmpfs entries.
- Check on copies of the real Element, KRDC, Firefox, gedit, Jellyfin and
Claude entries, quoting and generator behaviour.
This commit is contained in:
1 parent
5d15902ba1
commit
0d9a238e5a
37 files changed
+4140
-577
No files matched your search
@@ -25,6 +25,7 @@ is reported as "left alone" and never touched:
|
||||
| `firefox`: `user.js` in Firefox profiles | links to `/app/etc/firefox/steam-frame-nix-desktop-user.js` (left alone while the profile is in use), older links to `*-firefox-*user.js` and copies starting with the steam-frame-nix marker comment, and the values they left in `prefs.js` (only with Firefox closed) |
|
||||
| `jellyfin` | the hwdec shim entries in the Jellyfin Flatpak's user override `~/.local/share/flatpak/overrides/org.jellyfin.JellyfinDesktop` (nix-flatpak), an empty override file, and the shim copy of earlier versions in `~/.var/app/org.jellyfin.JellyfinDesktop` (marker `~/.local/state/steam-frame-nix/jellyfin-hwdec-shim`) |
|
||||
| `ui-state`: `~/.local/state/steam-frame-nix/ui-patches/<name>.json` | the dashboard patches' saved choices; `--all` only, never `--orphans`; stray `*.json.tmp` files |
|
||||
| `launchers`: `/run/user/1000/steam-frame-nix/applications` | the entries of [launchers](launchers.md) (tmpfs); `--all` only (switches remove those of removed launchers themselves) |
|
||||
| `dirs` | `~/.local/state/steam-frame-nix` and `/run/user/1000/steam-frame-nix` when empty |
|
||||
|
||||
### Left by older versions
|
||||
|
||||
+12
-5
@@ -53,12 +53,18 @@ modules/
|
||||
keyboard-layout.nix gamescope-session drop-in with XKB_DEFAULT_* (keyboard.layout)
|
||||
clipboard-sync.nix app: KDE autostart of clipboard-sync (clipboardSync)
|
||||
hidden-apps.nix Hidden=true desktop entries (launcherMenu.hiddenApps)
|
||||
keyring.nix app: launchers sharing the KDE wallet (keyring)
|
||||
launchers.nix links, MIME defaults, units of the launchers (launchers.<id>)
|
||||
launchers/
|
||||
lib.nix the launcher option type, Exec quoting, package entries (build)
|
||||
rewrite.awk build+service: rewrites a desktop entry's Exec lines and keys
|
||||
generate.sh service steam-frame-nix-launchers (+ .path), switch: entries
|
||||
of Flatpaks/host files in <runtimeDir>/steam-frame-nix/applications
|
||||
check.nix, fixtures/ test: real entries rewritten (fixtures/expected), generator runs
|
||||
docker.nix service: rootless dockerd (docker)
|
||||
firefox.nix Flatpak prefs extension and launcher entry (firefox)
|
||||
firefox/launcher.nix app: launcher script (desktop profile, fullscreen fix)
|
||||
firefox/check.nix test: launcher against a fake flatpak
|
||||
jellyfin.nix desktop entry with flatpak run options (jellyfin.hardwareDecoding)
|
||||
firefox.nix Flatpak prefs extension and launcher (firefox)
|
||||
firefox/wrapper.nix app: launcher wrapper (desktop profile, fullscreen fix)
|
||||
firefox/check.nix test: wrapper against a fake flatpak
|
||||
jellyfin.nix launcher with flatpak run options (jellyfin.hardwareDecoding)
|
||||
jellyfin/mpv-hwdec-shim.c app: LD_PRELOAD shim, hwdec auto* -> v4l2m2m-copy
|
||||
jellyfin/shim.nix build: the shim as lib/mpv-hwdec-shim.so
|
||||
jellyfin/check.nix test: shim ELF and rewriting
|
||||
@@ -116,6 +122,7 @@ they are kept even where a file name says more:
|
||||
| `window-curvature` | `dashboard.windowCurvature` | `window-curvature` (SteamVR) | `steam-ui-patches` |
|
||||
| `frame-controls` | `dashboard.frameControls` | `frame-controls` (SteamVR, state) | `steam-ui-patches` |
|
||||
| `steamvr-debugger` | `steamvrDebugger` | | `steamvr-webhelper-debugger` |
|
||||
| `launchers` | `launchers` | | `steam-frame-nix-launchers` (`.service`, `.path`) |
|
||||
|
||||
Log of all patches:
|
||||
`journalctl --user -u steam-ui-patches -u steam-keyboard-patch -u vr-keyboard-relay`.
|
||||
|
||||
+12
-9
@@ -14,9 +14,10 @@ browser the portal opens links with the first installed `https` handler
|
||||
|
||||
## What you get
|
||||
|
||||
A launcher for the Flathub Firefox Flatpak (`org.mozilla.firefox`, stable;
|
||||
install it yourself). The launcher shadows the Flatpak's own entry (same
|
||||
ID), so default-browser associations keep working.
|
||||
A [launcher](launchers.md) for the Flathub Firefox Flatpak
|
||||
(`org.mozilla.firefox`, stable; install it yourself): the Flatpak's own
|
||||
entry with a wrapper in front, same ID, so default-browser associations
|
||||
keep working.
|
||||
|
||||
- **`vrFullscreenFix`** (on): `full-screen-api.ignore-widgets` makes
|
||||
fullscreen fill just the window. Not applied in the desktop profile.
|
||||
@@ -26,11 +27,11 @@ ID), so default-browser associations keep working.
|
||||
- **`prefs`:** further `about:config` values for every profile; they can
|
||||
also override the fixes above.
|
||||
- **`desktopProfile`** (`"desktop"`): in the nested desktop the launcher
|
||||
uses this separate profile (a normal Firefox profile with its own browser
|
||||
uses this separate profile (not for "Open Profile Manager") (a normal Firefox profile with its own browser
|
||||
data, created on first use). `null`: the default profile in both sessions.
|
||||
- **`defaultBrowser`** (off): the launcher becomes the default for `http`,
|
||||
`https` and `text/html` (Home Manager's `xdg.mimeApps`, which then owns
|
||||
`~/.config/mimeapps.list`).
|
||||
`https` and `text/html` (the launcher's `defaultFor`: Home Manager's
|
||||
`xdg.mimeApps`, which then owns `~/.config/mimeapps.list`).
|
||||
|
||||
`prefs` and the fixes are *default* values, not user values: `about:config`
|
||||
can still change them per profile, and removing one leaves nothing behind.
|
||||
@@ -71,9 +72,11 @@ to a store directory; Flatpak mounts it itself, so the sandbox doesn't get
|
||||
|
||||
### Desktop profile
|
||||
|
||||
The launcher (a desktop entry with the Flatpak's ID) picks `desktopProfile`
|
||||
when started in the nested desktop. The desktop profile undoes the
|
||||
fullscreen fix only while its Firefox runs: the launcher links the
|
||||
The launcher's wrapper (`modules/firefox/wrapper.nix`) gets the entry's
|
||||
`flatpak run …` command line and, in the nested desktop, adds `--profile
|
||||
<desktopProfile>` (not to the profile manager action, `--ProfileManager`).
|
||||
The desktop profile undoes the fullscreen fix only while its Firefox runs:
|
||||
the wrapper links the
|
||||
profile's `user.js` to `/app/etc/firefox/steam-frame-nix-desktop-user.js`
|
||||
(a sandbox path) right before starting Firefox, waits for it, and once it
|
||||
has exited and the profile is no longer in use removes the link and the
|
||||
|
||||
+12
-9
@@ -19,8 +19,9 @@ which
|
||||
|
||||
## What you get
|
||||
|
||||
The Jellyfin desktop entry (same ID as the Flatpak's, so the KDE menu and
|
||||
the "+" menu start it) runs the Flatpak with device access (`devices=all`)
|
||||
A [launcher](launchers.md) (the Flatpak's own entry, rewritten under its
|
||||
ID, so the KDE menu and the "+" menu start it) runs the Flatpak with device
|
||||
access (`devices=all`)
|
||||
and makes mpv use `hwdec` (default `v4l2m2m-copy,auto-copy`); explicit
|
||||
values such as `no` stay. mpv tries the listed decoders in order and falls
|
||||
back to software decoding per stream. With the default, 1080p H.264 plays
|
||||
@@ -38,7 +39,7 @@ steamFrame.jellyfin.hardwareDecoding.enable = true;
|
||||
```
|
||||
|
||||
From a terminal, start it with the command line of
|
||||
`steamFrame.jellyfin.hardwareDecoding.command` (or `grep ^Exec=
|
||||
`steamFrame.jellyfin.hardwareDecoding.command` (or the one of `grep ^Exec=
|
||||
~/.local/share/applications/org.jellyfin.JellyfinDesktop.desktop`); its
|
||||
output shows `mpv-hwdec-shim: hwdec "auto-copy" -> "v4l2m2m-copy,auto-copy"`,
|
||||
then mpv's `Using hardware decoding (v4l2m2m-copy)`.
|
||||
@@ -63,12 +64,13 @@ option). It is preloaded from the Nix store; only its store path is exposed
|
||||
(read-only) to the sandbox. It would work for any libmpv app that sets
|
||||
`hwdec=auto*`, but only Jellyfin Desktop is set up here.
|
||||
|
||||
### The desktop entry
|
||||
### The launcher
|
||||
|
||||
Nothing is written to Flatpak's overrides: the entry
|
||||
(`~/.local/share/applications/org.jellyfin.JellyfinDesktop.desktop`) passes
|
||||
device access and the shim as `flatpak run` options, so they apply to
|
||||
launches from that entry and are gone with it:
|
||||
Nothing is written to Flatpak's overrides: the launcher
|
||||
`steamFrame.launchers."org.jellyfin.JellyfinDesktop"` passes device access
|
||||
and the shim as `flatpak run` options (`flatpakArgs`, `env`), so they apply
|
||||
to launches from the entry and are gone with it. Its command lines (the
|
||||
entry's and the four actions') become
|
||||
|
||||
```sh
|
||||
flatpak run --branch=stable --arch=aarch64 --command=jellyfin-desktop \
|
||||
@@ -77,7 +79,8 @@ flatpak run --branch=stable --arch=aarch64 --command=jellyfin-desktop \
|
||||
--env=SFN_MPV_HWDEC=v4l2m2m-copy,auto-copy org.jellyfin.JellyfinDesktop
|
||||
```
|
||||
|
||||
(`command` is this line with the store path.)
|
||||
(`command` is about this line, with the store path and without the
|
||||
entry's `--branch`/`--arch`/`--command`.)
|
||||
|
||||
Older versions used a Flatpak override (via nix-flatpak or a Home Manager
|
||||
link) and a shim copy in `~/.var/app/org.jellyfin.JellyfinDesktop`;
|
||||
|
||||
+4
-126
@@ -1,128 +1,6 @@
|
||||
# Keyring launchers
|
||||
|
||||
`keyring.flatpaks.<app ID>`, `keyring.programs.<desktop ID>`, module
|
||||
`keyring`. Options: [README, Options](../README.md#options).
|
||||
|
||||
## Problem
|
||||
|
||||
Apps that keep logins or passwords in the KDE wallet lose them between the
|
||||
Frame's [two sessions](../README.md#two-sessions):
|
||||
|
||||
- **A second wallet:** the nested desktop has its own D-Bus. An app started
|
||||
there starts a second `kwalletd6` on that bus; what it stores there is
|
||||
invisible to the same app in the Steam session, which talks to the running
|
||||
`kwalletd6` on the outer bus.
|
||||
- **Electron in the Steam session:** Electron picks its keyring from
|
||||
`XDG_CURRENT_DESKTOP`. In the Steam session that is `gamescope`, which it
|
||||
doesn't know, so it falls back to `basic` (a local, unencrypted store) and
|
||||
the login made in the desktop (stored in the wallet) is gone.
|
||||
- **Flatpak permissions:** many Flatpaks may not talk to the wallet at all
|
||||
(Element), or only to `org.kde.kwalletd6` while their KF6 wallet client
|
||||
reads through the Secret Service `org.freedesktop.secrets` (KRDC: "Password
|
||||
not found").
|
||||
- **Login callbacks:** SSO logins come back through a URL scheme
|
||||
(`io.element.desktop://`, `claude://`) opened by the portal. Unless the app
|
||||
is the default and a recommended handler, the portal opens an app chooser,
|
||||
which isn't shown in VR.
|
||||
|
||||
## What you get
|
||||
|
||||
For each listed app, a desktop entry in `~/.local/share/applications` with
|
||||
the app's own desktop ID, so it replaces the Flatpak's or package's entry in
|
||||
the KDE menu and the "+" menu. It starts the app
|
||||
|
||||
- on the outer bus (`session.busEnv`): one `kwalletd6` for both sessions;
|
||||
- for Flatpaks, with `--talk-name=org.kde.kwalletd6` and
|
||||
`--talk-name=org.freedesktop.secrets` as `flatpak run` options (not a
|
||||
Flatpak override: they apply only to launches from this entry and are
|
||||
gone with it);
|
||||
- with `electron = true`, with `--password-store=kwallet6`;
|
||||
- as the default and recommended handler of its `schemeHandlers`
|
||||
(`xdg.mimeApps`).
|
||||
|
||||
Logins then survive switching between the desktop and VR windows. Changes
|
||||
take effect at the next start of the app.
|
||||
|
||||
## Configuration
|
||||
|
||||
The Flatpak isn't in the Nix store, so its entry can't be read at build
|
||||
time: give the fields you want in menus (`name` is required; `icon`
|
||||
defaults to the app ID, as Flatpaks export it). A Flatpak (installing it is
|
||||
up to you):
|
||||
|
||||
```nix
|
||||
steamFrame.keyring.flatpaks = {
|
||||
"im.riot.Riot" = {
|
||||
name = "Element";
|
||||
electron = true;
|
||||
categories = [ "Network" "InstantMessaging" ];
|
||||
schemeHandlers = [ "element" "io.element.desktop" ]; # SSO callback
|
||||
};
|
||||
"org.kde.krdc" = {
|
||||
name = "KRDC";
|
||||
fieldCode = "%u";
|
||||
categories = [ "Qt" "KDE" "Network" "RemoteAccess" ];
|
||||
mimeTypes = [ "x-scheme-handler/vnc" "x-scheme-handler/rdp" ]; # listed, not made default
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
A program from a Nix package: use the package's own desktop ID (without
|
||||
`.desktop`), so the entry replaces the package's:
|
||||
|
||||
```nix
|
||||
{ pkgs, ... }: {
|
||||
home.packages = [ pkgs.claude-desktop ];
|
||||
steamFrame.keyring.programs."com.anthropic.Claude" = {
|
||||
name = "Claude";
|
||||
executable = "${pkgs.claude-desktop}/bin/claude-desktop";
|
||||
icon = "claude-desktop";
|
||||
electron = true;
|
||||
startupWMClass = "com.anthropic.Claude";
|
||||
schemeHandlers = [ "claude" ]; # login callback
|
||||
settings.StartupNotify = "true";
|
||||
actions.NewChat = {
|
||||
name = "New Chat";
|
||||
args = [ ''"claude://claude.ai/new?surface=chat&source=desktop_action"'' ];
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
`args`, `actions.<name>.args` and `settings` are written into the entry as
|
||||
given (desktop entry syntax: quote yourself). Each app's `command` (read
|
||||
only) is its command line without arguments, to start it from a terminal
|
||||
the same way. The fields each entry takes are in the
|
||||
[options](../README.md#options).
|
||||
|
||||
## Caveats
|
||||
|
||||
- The wallet must be KDE's (`kwalletd6`, and `ksecretd` for the Secret
|
||||
Service), as SteamOS ships it.
|
||||
- Only launches from the entry get the fixes: a Flatpak started with plain
|
||||
`flatpak run`, or a program from `~/.nix-profile/bin`, doesn't.
|
||||
- `schemeHandlers` turns on Home Manager's `xdg.mimeApps`, which then owns
|
||||
`~/.config/mimeapps.list`: set other defaults there too.
|
||||
- A Flatpak's own entry may have fields not given here (translations,
|
||||
`Keywords`, actions); add what you need through `settings` and `actions`.
|
||||
|
||||
## How it works
|
||||
|
||||
For `"im.riot.Riot" = { name = "Element"; electron = true; ... }` the entry's
|
||||
command line is
|
||||
|
||||
```sh
|
||||
env DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus \
|
||||
flatpak run --talk-name=org.kde.kwalletd6 --talk-name=org.freedesktop.secrets \
|
||||
im.riot.Riot --password-store=kwallet6 %U
|
||||
```
|
||||
|
||||
`flatpak run` connects the sandbox's D-Bus proxy to the bus in its own
|
||||
environment, so the prefix (not `--env=`) moves the app to the outer bus.
|
||||
`--talk-name` adds to the Flatpak's permissions for this launch only. The
|
||||
entry also sets `X-Flatpak=<app ID>`. For `programs` the prefix runs
|
||||
`executable` directly.
|
||||
|
||||
`schemeHandlers` go into `xdg.mimeApps.defaultApplications` and
|
||||
`associations.added` (Added Associations, what the portal treats as
|
||||
recommended), and into the entry's `MimeType=` with `mimeTypes`.
|
||||
Moved: apps that keep their logins in the KDE wallet are now
|
||||
[launchers](launchers.md) with `keyring.enable` (the former
|
||||
`keyring.flatpaks` / `keyring.programs` options and how to convert them are
|
||||
described there).
|
||||
@@ -0,0 +1,204 @@
|
||||
# Launchers
|
||||
|
||||
`launchers.<desktop ID>`, module `launchers`. Options:
|
||||
[README, Options](../README.md#options).
|
||||
|
||||
## Problem
|
||||
|
||||
Starting an app the way the Frame needs often means changing its desktop
|
||||
entry: extra `flatpak run` options, environment, a wrapper script, making it
|
||||
a default handler. A hand-written entry with the same ID replaces the
|
||||
original, but loses what the original has (translations, icon, actions,
|
||||
MIME types) and goes stale when the app changes its entry in an update.
|
||||
|
||||
The most common case is the KDE wallet, where apps lose their logins between
|
||||
the Frame's [two sessions](../README.md#two-sessions):
|
||||
|
||||
- **A second wallet:** the nested desktop has its own D-Bus. An app started
|
||||
there starts a second `kwalletd6` on that bus; what it stores there is
|
||||
invisible to the same app in the Steam session, which talks to the running
|
||||
`kwalletd6` on the outer bus.
|
||||
- **Electron in the Steam session:** Electron picks its keyring from
|
||||
`XDG_CURRENT_DESKTOP`. In the Steam session that is `gamescope`, which it
|
||||
doesn't know, so it falls back to `basic` (a local, unencrypted store) and
|
||||
the login made in the desktop (stored in the wallet) is gone.
|
||||
- **Flatpak permissions:** many Flatpaks may not talk to the wallet at all
|
||||
(Element), or only to `org.kde.kwalletd6` while their KF6 wallet client
|
||||
reads through the Secret Service `org.freedesktop.secrets` (KRDC: "Password
|
||||
not found").
|
||||
- **Login callbacks:** SSO logins come back through a URL scheme
|
||||
(`io.element.desktop://`, `claude://`) opened by the portal. Unless the app
|
||||
is the default and a recommended handler, the portal opens an app chooser,
|
||||
which isn't shown in VR.
|
||||
|
||||
## What you get
|
||||
|
||||
For each `launchers.<desktop ID>`, the app's own desktop entry, rewritten,
|
||||
under the same ID in `~/.local/share/applications`: it replaces the original
|
||||
in the KDE menu and the "+" menu (which reads only that directory). Name,
|
||||
icon, translations, categories, actions and MIME types stay the app's; only
|
||||
the command lines (the entry's and every action's) and the keys you set
|
||||
change. When a Flatpak update changes its entry, the launcher follows within
|
||||
seconds.
|
||||
|
||||
- **`keyring.enable`:** the app runs on the outer bus (one `kwalletd6` for
|
||||
both sessions); a Flatpak may also talk to the wallet
|
||||
(`--talk-name=org.kde.kwalletd6 --talk-name=org.freedesktop.secrets`).
|
||||
**`keyring.electron`** adds `--password-store=kwallet6`. Logins then
|
||||
survive switching between the desktop and VR windows.
|
||||
- **`defaultFor`:** the app becomes the default and a recommended handler of
|
||||
these MIME types / URL schemes (login callbacks open without a chooser).
|
||||
- **`flatpakArgs`, `env`, `hostEnv`, `args`, `wrappers`:** options,
|
||||
environment and wrapper commands for the launch; Flatpak permissions this
|
||||
way apply only to launches from the entry (no Flatpak override files).
|
||||
- **`mimeTypes`, `settings`:** further `MimeType=` entries; set, override or
|
||||
remove `[Desktop Entry]` keys.
|
||||
|
||||
Changes take effect at the next start of the app. [Firefox](firefox.md)
|
||||
(`firefox.*`) and [Jellyfin](jellyfin.md) (`jellyfin.hardwareDecoding`) are
|
||||
launchers too.
|
||||
|
||||
## Configuration
|
||||
|
||||
The desktop ID is the attribute name; the source is the Flatpak with that
|
||||
app ID unless `source.package` or `source.file` is set. Installing the app
|
||||
is up to you.
|
||||
|
||||
A Flatpak whose logins live in the wallet (Element, an Electron app), with
|
||||
its SSO callback schemes:
|
||||
|
||||
```nix
|
||||
steamFrame.launchers."im.riot.Riot" = {
|
||||
keyring = { enable = true; electron = true; };
|
||||
defaultFor = [ "x-scheme-handler/element" "x-scheme-handler/io.element.desktop" ];
|
||||
};
|
||||
steamFrame.launchers."org.kde.krdc".keyring.enable = true;
|
||||
```
|
||||
|
||||
A program from a Nix package, from the package's own entry
|
||||
(`share/applications/<desktop ID>.desktop`, rewritten at build time):
|
||||
|
||||
```nix
|
||||
{ pkgs, ... }: {
|
||||
home.packages = [ pkgs.claude-desktop ];
|
||||
steamFrame.launchers."com.anthropic.Claude" = {
|
||||
source.package = pkgs.claude-desktop;
|
||||
keyring = { enable = true; electron = true; };
|
||||
defaultFor = [ "x-scheme-handler/claude" ]; # login callback
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Flatpak permissions and environment for one app (what
|
||||
[Jellyfin](jellyfin.md) sets):
|
||||
|
||||
```nix
|
||||
steamFrame.launchers."org.jellyfin.JellyfinDesktop" = {
|
||||
flatpakArgs = [ "--device=all" ];
|
||||
env.SFN_MPV_HWDEC = "v4l2m2m-copy"; # --env= inside the sandbox
|
||||
};
|
||||
```
|
||||
|
||||
A wrapper, which gets the whole original command line as its arguments (how
|
||||
[Firefox](firefox.md) picks its desktop profile), and keys of the entry:
|
||||
|
||||
```nix
|
||||
{ pkgs, ... }: {
|
||||
steamFrame.launchers."org.chromium.Chromium" = {
|
||||
wrappers = [ "${pkgs.writeShellScript "no-gpu" ''exec "$@" --disable-gpu''}" ];
|
||||
settings = { Name = "Chromium (no GPU)"; Keywords = null; }; # null: removed
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
`args`, `flatpakArgs`, `wrappers` and the environment values are plain
|
||||
strings, quoted for the entry for you; `settings` values are written as
|
||||
given (key-file syntax). Each launcher's `command` (read only) is roughly its
|
||||
command line, to start it the same way from a terminal. A host file as
|
||||
source: `source.file = "/usr/share/applications/<ID>.desktop"`.
|
||||
|
||||
**From `keyring.*` (until 2026-09):** `keyring.flatpaks.<ID>` and
|
||||
`keyring.programs.<ID>` are gone; using them fails with the new form.
|
||||
`electron = true` is `keyring = { enable = true; electron = true; }`,
|
||||
`schemeHandlers = [ "x" ]` is `defaultFor = [ "x-scheme-handler/x" ]`,
|
||||
`programs.<ID>.executable` becomes `source.package`; name, icon, categories,
|
||||
actions and field codes come from the app's entry.
|
||||
|
||||
## Caveats
|
||||
|
||||
- Only launches from the entry get the changes: a Flatpak started with plain
|
||||
`flatpak run`, or a program from `~/.nix-profile/bin`, doesn't.
|
||||
- A Flatpak's or host file's launcher exists only while its source does: an
|
||||
app not installed (or uninstalled) has none. The entry is written at
|
||||
runtime into `/run/user/1000` (tmpfs); until then, e.g. right after boot
|
||||
before the Steam session's user services started, the link in
|
||||
`~/.local/share/applications` points nowhere, and menus show neither the
|
||||
launcher nor the original entry.
|
||||
- An entry whose command line isn't recognised (a Flatpak's without
|
||||
`flatpak run ... <app ID>`, a program's starting with `env -…`) is used
|
||||
unchanged, with a warning in the journal.
|
||||
- Edits with KDE's "Edit Application" don't last: use `settings`. An
|
||||
edited entry is overwritten at the next rewrite; a file that replaced the
|
||||
link is reported, and Home Manager refuses the next switch until it is
|
||||
removed. Warnings go to the journal
|
||||
(`journalctl --user -u steam-frame-nix-launchers`).
|
||||
- `defaultFor` turns on Home Manager's `xdg.mimeApps`, which then owns
|
||||
`~/.config/mimeapps.list`: set other defaults there too. Two launchers
|
||||
claiming the same type fail the build.
|
||||
- The wallet must be KDE's (`kwalletd6`, and `ksecretd` for the Secret
|
||||
Service), as SteamOS ships it.
|
||||
|
||||
## How it works
|
||||
|
||||
The Exec lines are rewritten, everything else is copied line by line
|
||||
(comments, unknown and localized keys as they are):
|
||||
|
||||
| Source | Exec= becomes |
|
||||
|---|---|
|
||||
| Flatpak | `<hostEnv> <wrappers> <original up to the app ID> <flatpakArgs> <--env=…> <app ID> <args> <rest>` |
|
||||
| package, file | `<hostEnv + env> <wrappers> <original up to the program> <args> <rest>` |
|
||||
|
||||
For a Flatpak the app ID is the first token equal to `X-Flatpak=` (or the
|
||||
source ID) after `flatpak run`; for others the program is the first token
|
||||
after an optional leading `env A=B …`. The rest (`--file-forwarding`,
|
||||
`@@u %U @@`, `%c`, action arguments) stays. `DBusActivatable=true` becomes
|
||||
`false` (otherwise the desktop would start the app over D-Bus, skipping
|
||||
Exec), `defaultFor` and `mimeTypes` are added to `MimeType=`, and
|
||||
`X-SteamFrameNix-Source=` names the source. Element's entry with
|
||||
`keyring = { enable = true; electron = true; }`:
|
||||
|
||||
```sh
|
||||
env DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus \
|
||||
/usr/bin/flatpak run --branch=stable --arch=aarch64 --command=/app/bin/element \
|
||||
--file-forwarding --talk-name=org.kde.kwalletd6 --talk-name=org.freedesktop.secrets \
|
||||
im.riot.Riot --password-store=kwallet6 @@u %U @@
|
||||
```
|
||||
|
||||
`flatpak run` connects the sandbox's D-Bus proxy (and portals) to the bus in
|
||||
its own environment, so `hostEnv` (not `--env=`) moves the app to the outer
|
||||
bus. `defaultFor` goes into `xdg.mimeApps.defaultApplications` and
|
||||
`associations.added` (Added Associations, what the portal treats as
|
||||
recommended).
|
||||
|
||||
**When it is written:** a package's entry at build time (a Home Manager link
|
||||
into the store). Flatpak and host file entries can't be read at build time,
|
||||
so `steam-frame-nix-launchers` (`modules/launchers/generate.sh`,
|
||||
`rewrite.awk`) writes them to `/run/user/1000/steam-frame-nix/applications`
|
||||
(tmpfs, `session.runtimeDir`), where the Home Manager links in
|
||||
`~/.local/share/applications` point. It runs
|
||||
|
||||
- on every switch (Home Manager activation; skipped with a message when the
|
||||
Steam session isn't running),
|
||||
- at login (`steam-frame-nix-launchers.service` of the Steam session's user
|
||||
manager),
|
||||
- when Flatpak installs, updates or removes apps
|
||||
(`steam-frame-nix-launchers.path` watches `.changed` of both Flatpak
|
||||
installations and their exported `applications` directories).
|
||||
|
||||
Sources: `~/.local/share/flatpak/exports/share/applications/<ID>.desktop`,
|
||||
then `/var/lib/flatpak/exports/share/applications/<ID>.desktop`. An entry is
|
||||
replaced (temp file and rename) only when its content changes; entries of
|
||||
launchers no longer configured or without a source are removed. If anything
|
||||
changed, the mtime of `~/.local/share/applications` is updated, so a running
|
||||
Steam rescans the "+" menu. A hash of the last written entry
|
||||
(`.<ID>.desktop.sum`) shows edits by others.
|
||||
+8
-9
@@ -23,18 +23,17 @@ running") and skips `reloadSystemd`.
|
||||
and applies `session.services.start` / `stop` / `restart`, which other
|
||||
modules fill (you can add your own units).
|
||||
|
||||
**Configuration:** apps that keep secrets in the wallet get launchers from
|
||||
[keyring](keyring.md). Another launcher that must reach the outer session
|
||||
(its bus, services or wallet) uses the prefix:
|
||||
**Configuration:** apps that keep secrets in the wallet get a
|
||||
[launcher](launchers.md) with `keyring.enable`. Another app that must reach
|
||||
the outer session (its bus, services or wallet) gets the bus through its
|
||||
launcher's `hostEnv`; a hand-written entry uses the prefix `session.busEnv`:
|
||||
|
||||
```nix
|
||||
{ config, ... }: {
|
||||
xdg.dataFile."applications/org.example.App.desktop".text = ''
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Example
|
||||
Exec=${config.steamFrame.session.busEnv} flatpak run org.example.App %U
|
||||
'';
|
||||
steamFrame.launchers."org.example.App".hostEnv.DBUS_SESSION_BUS_ADDRESS =
|
||||
config.steamFrame.session.bus;
|
||||
# or, in an entry of your own:
|
||||
# Exec=${config.steamFrame.session.busEnv} flatpak run org.example.App %U
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Reference in new issue
Block a user