Options regrouped: session.*, keyboard.*, launcherMenu.hiddenApps

- runtimeDir, userBus, outerBusEnv, userServices.*, portalFix.enable
  -> session.{runtimeDir, bus, busEnv, services.*, portalFix.enable}
- keyboardLayout/keyboardVariant -> keyboard.layout/variant;
  steamKeyboardPatch.enable -> keyboard.vr.extraKeys.enable
- hiddenApps -> launcherMenu.hiddenApps
- launcherMenu.launchDebounce -> launchDebounceSeconds (also the patch's
  option key; launcher-menu-launch VERSION 3)
- "Steam UI patch" in option descriptions

Old names keep working with a rename warning (outerBusEnv is read-only:
reading it warns).
This commit is contained in:
Pierre Kisters committed 2026-09-28 03:36:38 +02:00
1 parent 36fcb207bd
commit a0c3e0846f
8 files changed
+124 -63

No files matched your search

+11 -3
View File
@@ -1,15 +1,23 @@
# Hide desktop entries from the "+" menu and the KDE menu: a user entry with
# Hidden=true masks the system one.
{ config, lib, ... }: {
options.steamFrame.hiddenApps = lib.mkOption {
imports = [
(lib.mkRenamedOptionModule
[ "steamFrame" "hiddenApps" ] [ "steamFrame" "launcherMenu" "hiddenApps" ])
];
options.steamFrame.launcherMenu.hiddenApps = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
example = [ "lxterminal" "cmake-gui" "firewall-config" "renderdoc" ];
description = "Desktop entry ids (without .desktop) to hide from the \"+\" menu and the KDE menu.";
description = ''
Desktop entry ids (without .desktop) to hide from the "+" menu and the
KDE menu.
'';
};
config.xdg.dataFile = lib.genAttrs
(map (id: "applications/${id}.desktop") config.steamFrame.hiddenApps)
(map (id: "applications/${id}.desktop") config.steamFrame.launcherMenu.hiddenApps)
(_: {
text = ''
[Desktop Entry]
+14 -9
View File
@@ -4,10 +4,15 @@
# (next session start).
{ config, lib, ... }:
let
cfg = config.steamFrame;
cfg = config.steamFrame.keyboard;
in {
options.steamFrame = {
keyboardLayout = lib.mkOption {
imports = [
(lib.mkRenamedOptionModule [ "steamFrame" "keyboardLayout" ] [ "steamFrame" "keyboard" "layout" ])
(lib.mkRenamedOptionModule [ "steamFrame" "keyboardVariant" ] [ "steamFrame" "keyboard" "variant" ])
];
options.steamFrame.keyboard = {
layout = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "de";
@@ -15,7 +20,7 @@ in {
XKB layout for the Steam session (XKB_DEFAULT_LAYOUT); null = US.
'';
};
keyboardVariant = lib.mkOption {
variant = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "nodeadkeys";
@@ -23,12 +28,12 @@ in {
};
};
config = lib.mkIf (cfg.keyboardLayout != null || cfg.keyboardVariant != null) {
config = lib.mkIf (cfg.layout != null || cfg.variant != null) {
xdg.configFile."systemd/user/gamescope-session.service.d/keyboard.conf".text =
"[Service]\n"
+ lib.optionalString (cfg.keyboardLayout != null)
"Environment=XKB_DEFAULT_LAYOUT=${cfg.keyboardLayout}\n"
+ lib.optionalString (cfg.keyboardVariant != null)
"Environment=XKB_DEFAULT_VARIANT=${cfg.keyboardVariant}\n";
+ lib.optionalString (cfg.layout != null)
"Environment=XKB_DEFAULT_LAYOUT=${cfg.layout}\n"
+ lib.optionalString (cfg.variant != null)
"Environment=XKB_DEFAULT_VARIANT=${cfg.variant}\n";
};
}
+18 -15
View File
@@ -1,5 +1,5 @@
# The VR dashboard's "+" menu (non-Steam programs). Steam lists them in GLib
# hash-table order (random-looking). Runtime patches in SharedJSContext, each
# hash-table order (random-looking). Steam UI patches in SharedJSContext, each
# registered only when its option is set, reverted when unset (next switch):
# - order/: sorts ScanForInstalledNonSteamApps() by name;
# - pinned-desktop/: hides Desktop in the list, pins a proxy above/below it;
@@ -26,14 +26,19 @@ let
text = builtins.readFile ./launcher-menu/icon-fallbacks.sh;
};
in {
imports = [ ./steam-ui-patches.nix ];
imports = [
./steam-ui-patches.nix
(lib.mkRenamedOptionModule
[ "steamFrame" "launcherMenu" "launchDebounce" ]
[ "steamFrame" "launcherMenu" "launchDebounceSeconds" ])
];
options.steamFrame.launcherMenu = {
sort = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Sort the "+" menu (non-Steam programs) by name. Runtime patch.
Sort the "+" menu (non-Steam programs) by name. Steam UI patch.
'';
};
pinDesktop = lib.mkOption {
@@ -43,7 +48,7 @@ in {
description = ''
Pin "Desktop" (the nested Plasma session) above ("top") or below
("bottom") the "+" menu's scrolling list, so it is always visible;
null = normal list entry. Runtime patch.
null = normal list entry. Steam UI patch.
'';
};
closeOnLaunch = lib.mkOption {
@@ -51,23 +56,24 @@ in {
default = false;
description = ''
Close the "+" menu as soon as a program is launched (stock: it stays
open until the window appears, inviting double launches). Runtime patch.
open until the window appears, inviting double launches). Steam UI
patch.
'';
};
launchDebounce = lib.mkOption {
launchDebounceSeconds = lib.mkOption {
type = lib.types.ints.unsigned;
default = 0;
example = 10;
description = ''
Ignore another "+" menu launch of the same command line within this
many seconds of the last one that went through (logged); 0 = off.
Runtime patch.
Steam UI patch.
'';
};
grid = {
enable = lib.mkEnableOption ''
the "+" menu's programs as a grid of tiles (icon, name below) instead
of a list. Runtime patch'';
of a list. Steam UI patch'';
columns = lib.mkOption {
type = lib.types.ints.between 1 8;
default = 4;
@@ -93,8 +99,8 @@ in {
List all programs in the "+" menu without Developer Mode (Steam
otherwise hides konsole, systemsettings, dolphin, plasma-discover, vlc,
firewall-config, cmake-gui, qrenderdoc, lxterminal, sh). Developer Mode
itself is untouched; hide single programs with steamFrame.hiddenApps.
Runtime patch.
itself is untouched; hide single programs with
steamFrame.launcherMenu.hiddenApps. Steam UI patch.
'';
};
iconFallbacks = lib.mkOption {
@@ -179,16 +185,13 @@ in {
};
unpatch = ./launcher-menu/pinned-desktop/unpatch.js;
}
++ lib.optional (cfg.closeOnLaunch || cfg.launchDebounce > 0) {
++ lib.optional (cfg.closeOnLaunch || cfg.launchDebounceSeconds > 0) {
name = "launcher-menu-launch";
target = sharedJSContext;
patch = mkPatch {
name = "launcher-menu-launch";
src = ./launcher-menu/launch/patch.js;
opts = {
inherit (cfg) closeOnLaunch;
debounceSeconds = cfg.launchDebounce;
};
opts = { inherit (cfg) closeOnLaunch launchDebounceSeconds; };
};
unpatch = ./launcher-menu/launch/unpatch.js;
}
+4 -4
View File
@@ -1,11 +1,11 @@
// launch: what activating a program in the VR dashboard's "+" menu does.
// mkPatch patch (see lib/default.nix); opts: { closeOnLaunch, debounceSeconds }.
// mkPatch patch (see lib/default.nix); opts: { closeOnLaunch, launchDebounceSeconds }.
//
// Stock, an item only calls SteamClient.Apps.LaunchNonSteamApp(cmdline) and
// the popup stays open until the new window appears, so users click twice.
// That call is its only UI use and is looked up at call time, so it is wrapped
// here in SharedJSContext:
// - debounceSeconds > 0: the same command line within that many seconds of
// - launchDebounceSeconds > 0: the same command line within that many seconds of
// the last accepted launch is ignored (console.info; reported in the
// steam-ui-patches journal on the next re-injection);
// - closeOnLaunch: afterwards the "+" popup is closed via the bar button's
@@ -16,10 +16,10 @@
// Covers every activation path (pointer, controller, pinned Desktop copy).
// Original kept as __sfuiOrig for unpatch.js; bump VERSION on changes.
((find, sigs, opts) => {
const VERSION = 2;
const VERSION = 3;
const NAME = 'launcher-menu-launch';
const CLOSE = opts.closeOnLaunch === true;
const DEBOUNCE_MS = Math.max(0, Number(opts.debounceSeconds) || 0) * 1000;
const DEBOUNCE_MS = Math.max(0, Number(opts.launchDebounceSeconds) || 0) * 1000;
const Apps = window.SteamClient?.Apps;
const cur = Apps?.LaunchNonSteamApp;
if (typeof cur !== 'function') return 'SteamClient.Apps.LaunchNonSteamApp missing';
+8 -2
View File
@@ -8,7 +8,13 @@ let
sys = "/usr/share/xdg-desktop-portal/gamescope-portals";
dir = "xdg-desktop-portal/gamescope-portals";
in {
options.steamFrame.portalFix.enable = lib.mkOption {
imports = [
(lib.mkRenamedOptionModule
[ "steamFrame" "portalFix" "enable" ]
[ "steamFrame" "session" "portalFix" "enable" ])
];
options.steamFrame.session.portalFix.enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
@@ -17,7 +23,7 @@ in {
'';
};
config = lib.mkIf config.steamFrame.portalFix.enable {
config = lib.mkIf config.steamFrame.session.portalFix.enable {
xdg.dataFile."${dir}/holo.portal".source =
config.lib.file.mkOutOfStoreSymlink "${sys}/holo.portal";
xdg.dataFile."${dir}/gamescope.portal".source =
+52 -20
View File
@@ -5,66 +5,98 @@
# and private bus. `switch` usually runs from the nested desktop, where
# home-manager's reloadSystemd is skipped ("User systemd daemon not running"),
# so `steamFrameUserServices` does it against the outer session: always
# daemon-reload, then start/stop/restart the units in `userServices`.
# daemon-reload, then start/stop/restart the units in `session.services`.
{ config, lib, ... }:
let
cfg = config.steamFrame;
cfg = config.steamFrame.session;
units = lib.escapeShellArgs;
rename = from: to: lib.mkRenamedOptionModule ([ "steamFrame" ] ++ from) [ "steamFrame" "session" to ];
in {
options.steamFrame = {
imports = [
(rename [ "runtimeDir" ] "runtimeDir")
(rename [ "userBus" ] "bus")
] ++ map (n: lib.mkRenamedOptionModule
[ "steamFrame" "userServices" n ] [ "steamFrame" "session" "services" n ])
[ "start" "restart" "stop" ];
# Read-only, so no mkRenamedOptionModule (its alias definition would be a
# second one); reading the old name warns.
options.steamFrame.outerBusEnv = lib.mkOption {
type = lib.types.str;
readOnly = true;
visible = false;
default = lib.warn
"The option `steamFrame.outerBusEnv' has been renamed to `steamFrame.session.busEnv'."
cfg.busEnv;
defaultText = lib.literalExpression "config.steamFrame.session.busEnv";
description = "Alias of {option}`steamFrame.session.busEnv`.";
};
options.steamFrame.session = {
runtimeDir = lib.mkOption {
type = lib.types.str;
default = "/run/user/1000";
description = "XDG_RUNTIME_DIR of the outer (Steam/VR) session.";
};
userBus = lib.mkOption {
bus = lib.mkOption {
type = lib.types.str;
default = "unix:path=${cfg.runtimeDir}/bus";
defaultText = lib.literalExpression ''"unix:path=''${config.steamFrame.runtimeDir}/bus"'';
defaultText = lib.literalExpression
''"unix:path=''${config.steamFrame.session.runtimeDir}/bus"'';
description = ''
Outer session D-Bus address; the only bus that reaches the user
systemd manager and the running kwalletd6.
'';
};
outerBusEnv = lib.mkOption {
busEnv = lib.mkOption {
type = lib.types.str;
readOnly = true;
default = "env DBUS_SESSION_BUS_ADDRESS=${cfg.userBus}";
defaultText = lib.literalExpression ''"env DBUS_SESSION_BUS_ADDRESS=''${config.steamFrame.userBus}"'';
default = "env DBUS_SESSION_BUS_ADDRESS=${cfg.bus}";
defaultText = lib.literalExpression
''"env DBUS_SESSION_BUS_ADDRESS=''${config.steamFrame.session.bus}"'';
description = ''
Exec= prefix for launchers that must use the outer bus, e.g. so apps
in the nested desktop use the running kwalletd6 instead of a second one.
in the nested desktop use the running kwalletd6 instead of a second
one.
'';
};
userServices = {
services = {
start = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
example = [ "docker.service" ];
description = "User units started on switch if not already running (outer user manager).";
description = ''
User units started on switch if not already running (outer user
manager).
'';
};
restart = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
example = [ "steam-keyboard-patch.service" ];
description = "User units restarted on every switch (outer user manager).";
description = ''
User units restarted on every switch (outer user manager).
'';
};
stop = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "User units stopped on switch if running (e.g. of a just-disabled feature).";
description = ''
User units stopped on switch if running (e.g. of a just-disabled
feature).
'';
};
};
};
config.home.activation.steamFrameUserServices = lib.hm.dag.entryAfter [ "reloadSystemd" ] (''
export XDG_RUNTIME_DIR=${lib.escapeShellArg cfg.runtimeDir} DBUS_SESSION_BUS_ADDRESS=${lib.escapeShellArg cfg.userBus}
export XDG_RUNTIME_DIR=${lib.escapeShellArg cfg.runtimeDir} DBUS_SESSION_BUS_ADDRESS=${lib.escapeShellArg cfg.bus}
run /usr/bin/systemctl --user daemon-reload
'' + lib.optionalString (cfg.userServices.start != [ ]) ''
run /usr/bin/systemctl --user start ${units cfg.userServices.start}
'' + lib.optionalString (cfg.userServices.stop != [ ]) ''
run /usr/bin/systemctl --user stop ${units cfg.userServices.stop} || true
'' + lib.optionalString (cfg.userServices.restart != [ ]) ''
run /usr/bin/systemctl --user restart ${units cfg.userServices.restart}
'' + lib.optionalString (cfg.services.start != [ ]) ''
run /usr/bin/systemctl --user start ${units cfg.services.start}
'' + lib.optionalString (cfg.services.stop != [ ]) ''
run /usr/bin/systemctl --user stop ${units cfg.services.stop} || true
'' + lib.optionalString (cfg.services.restart != [ ]) ''
run /usr/bin/systemctl --user restart ${units cfg.services.restart}
'');
}
+13 -7
View File
@@ -13,16 +13,22 @@ let
name = "steam-keyboard-patch";
src = ./steam-keyboard-patch/patch.js;
};
cfg = config.steamFrame.keyboard.vr.extraKeys;
in {
imports = [ ./session.nix ];
imports = [
./session.nix
(lib.mkRenamedOptionModule
[ "steamFrame" "steamKeyboardPatch" "enable" ]
[ "steamFrame" "keyboard" "vr" "extraKeys" "enable" ])
];
options.steamFrame.steamKeyboardPatch.enable = lib.mkEnableOption ''
options.steamFrame.keyboard.vr.extraKeys.enable = lib.mkEnableOption ''
Esc/Ctrl/Alt, arrow keys, Ctrl/Alt chords (held while toggled) and
AltGr/non-ASCII characters on Steam's VR keyboard (runtime patch plus an
AltGr/non-ASCII characters on Steam's VR keyboard (Steam UI patch plus an
xdotool helper service); off reverts it on the next switch'';
config = lib.mkMerge [
(lib.mkIf config.steamFrame.steamKeyboardPatch.enable {
(lib.mkIf cfg.enable {
systemd.user.services.steam-keyboard-patch = {
Unit.Description = "Modifier keys for Steam's VR keyboard (CEF patch + xdotool)";
Service = {
@@ -41,11 +47,11 @@ in {
};
# Restart on switch to re-inject a changed patch.
steamFrame.userServices.restart = [ "steam-keyboard-patch.service" ];
steamFrame.session.services.restart = [ "steam-keyboard-patch.service" ];
})
# Disabled: stopping the helper reverts the patch right away.
(lib.mkIf (!config.steamFrame.steamKeyboardPatch.enable) {
steamFrame.userServices.stop = [ "steam-keyboard-patch.service" ];
(lib.mkIf (!cfg.enable) {
steamFrame.session.services.stop = [ "steam-keyboard-patch.service" ];
})
];
}
+4 -3
View File
@@ -23,7 +23,8 @@ let
default = "http://127.0.0.1:8080";
example = "http://127.0.0.1:8087";
description = ''
DevTools base URL (its /json/list is polled): Steam 8080, SteamVR 8087.
DevTools base URL (its /json/list is polled): Steam 8080, SteamVR
8087.
'';
};
target = {
@@ -134,11 +135,11 @@ in {
# Restart on switch: re-inject changed patches; the old instance reverts
# removed ones.
steamFrame.userServices.restart = [ "steam-ui-patches.service" ];
steamFrame.session.services.restart = [ "steam-ui-patches.service" ];
})
# No patches: stopping the injector reverts them right away.
(lib.mkIf (cfg.patches == [ ]) {
steamFrame.userServices.stop = [ "steam-ui-patches.service" ];
steamFrame.session.services.stop = [ "steam-ui-patches.service" ];
})
];
}