From b28e91128ffdb2a7fc0e4369eef76051a07e843b Mon Sep 17 00:00:00 2001 From: The412Banner Date: Tue, 22 Sep 2026 10:48:26 -0400 Subject: [PATCH] The desktop uses the client's own game entries; a steam shim hands them to the app The client already writes one menu entry per installed game (steam steam://rungameid/, with the game's icon); they were dead for want of a steam command, and r45 added a second entry per game beside them. Now: steam on the desktop is a shim that hands off to bannerlator-steam-launch (and is the client itself anywhere else), and bannerlator-desktop-games writes an entry only for a game the client wrote none for. --- README.md | 12 +++---- .../launcher/session/SessionFiles.kt | 1 + tools/linuxfs/desktop/steamdeck-desktop | 2 ++ .../usr/local/bin/bannerlator-desktop-games | 32 ++++++++++++++++--- .../usr/local/bin/bannerlator-steam-shim | 12 +++++++ 5 files changed, 48 insertions(+), 11 deletions(-) create mode 100755 tools/linuxfs/overlay/usr/local/bin/bannerlator-steam-shim diff --git a/README.md b/README.md index ec3b4eb86..bdbf4c410 100644 --- a/README.md +++ b/README.md @@ -188,12 +188,12 @@ assets internal. ⚠️ Built; not yet seen installing to a card. ### The client's games on the desktop -The desktop's menu lists every game the Steam client has installed (Games category, the game's -own artwork), and the home folder has **Steam Games** and **SD Games** links to their files. A -game entry - and the menu's **Steam** / **Steam Big Picture** entries - cannot run the client on -the desktop, where nothing can draw with Vulkan; they hand off to the app -(`bannerlator-steam-launch`), which ends the desktop session and starts a Steam session in its -place: the client's **desktop UI** under gamescope, and the game straight away when one was +The Steam client writes a menu entry for every game it installs (Games category, the game's +icon), and the home folder has **Steam Games** and **SD Games** links to their files. Those +entries run `steam steam://rungameid/…`; on this desktop `steam` is a shim, because the client +cannot run where nothing can draw with Vulkan. It - and the menu's **Steam** / **Steam Big +Picture** entries - hand off to the app (`bannerlator-steam-launch`), which ends the desktop +session and starts a Steam session in its place: the client's **desktop UI** under gamescope, and the game straight away when one was chosen. Back opens the drawer as in any session; Stop session returns to the app. The list is rebuilt at every desktop start. ⚠️ Built; not yet tried on a device. diff --git a/app/src/main/java/com/steamdeck/launcher/session/SessionFiles.kt b/app/src/main/java/com/steamdeck/launcher/session/SessionFiles.kt index b246eb175..8403a4c38 100644 --- a/app/src/main/java/com/steamdeck/launcher/session/SessionFiles.kt +++ b/app/src/main/java/com/steamdeck/launcher/session/SessionFiles.kt @@ -36,6 +36,7 @@ object SessionFiles { "usr/local/bin/bannerlator-netmanager" to "usr/local/bin/bannerlator-netmanager", "usr/local/bin/bannerlator-steam-launch" to "usr/local/bin/bannerlator-steam-launch", "usr/local/bin/bannerlator-desktop-games" to "usr/local/bin/bannerlator-desktop-games", + "usr/local/bin/bannerlator-steam-shim" to "usr/local/bin/bannerlator-steam-shim", ) // The desktop's launcher and labwc defaults, only where the desktop package is installed: // staging them into a runtime without it would make the desktop look present when it is not. diff --git a/tools/linuxfs/desktop/steamdeck-desktop b/tools/linuxfs/desktop/steamdeck-desktop index be8bc5e67..664299253 100644 --- a/tools/linuxfs/desktop/steamdeck-desktop +++ b/tools/linuxfs/desktop/steamdeck-desktop @@ -81,7 +81,9 @@ if [ ! -f /var/cache/fontconfig/.steamdeck-built ] && command -v fc-cache >/dev/ fi # The menu's "Steam" / "Steam Big Picture" entries and one entry per installed game: all of them # hand off to the app (bannerlator-steam-launch), since the client cannot draw on this desktop. +export BL_DESKTOP=1 ln -sf /usr/local/bin/bannerlator-steam-launch /usr/local/bin/steamdeck-steam 2>/dev/null +ln -sf /usr/local/bin/bannerlator-steam-shim /usr/local/bin/steam 2>/dev/null python3 /usr/local/bin/bannerlator-desktop-games 2>&1 | sed 's/^/[games] /' echo "== steamdeck-desktop: labwc ($WLR_RENDERER) on $WAYLAND_DISPLAY" diff --git a/tools/linuxfs/overlay/usr/local/bin/bannerlator-desktop-games b/tools/linuxfs/overlay/usr/local/bin/bannerlator-desktop-games index aa6514460..a13afaeb5 100755 --- a/tools/linuxfs/overlay/usr/local/bin/bannerlator-desktop-games +++ b/tools/linuxfs/overlay/usr/local/bin/bannerlator-desktop-games @@ -1,7 +1,8 @@ #!/usr/bin/python3 -# The client's installed games, on the desktop: one menu entry per game (Games category), which -# starts it through bannerlator-steam-launch in Steam's desktop UI under gamescope, and two links -# in the home folder to the game files themselves. Run at every desktop start; stale entries go. +# The client's installed games, on the desktop. The client writes a menu entry per game itself +# (`steam steam://rungameid/`, with the game's icon), which the desktop's `steam` shim hands to +# the app - so an entry of ours exists only for a game the client wrote none for. Plus two links in +# the home folder to the game files. Run at every desktop start; stale entries go. # # bannerlator-desktop-games [steam root] import os @@ -54,12 +55,32 @@ def icon_for(appid): return "steam" +def client_entries(): + """App ids the client already wrote a menu entry for.""" + found = set() + if not os.path.isdir(APPS_DIR): + return found + for entry in os.listdir(APPS_DIR): + if entry.startswith(PREFIX) or not entry.endswith(".desktop"): + continue + try: + with open(os.path.join(APPS_DIR, entry), encoding="utf-8", errors="replace") as f: + m = re.search(r"steam://rungameid/(\d+)", f.read()) + except OSError: + continue + if m: + found.add(int(m.group(1))) + return found + + def write_entries(): os.makedirs(APPS_DIR, exist_ok=True) wanted = {} + theirs = client_entries() for library, _ in LIBRARIES: for appid, name in games(library): - wanted.setdefault(appid, name) + if appid not in theirs: + wanted.setdefault(appid, name) for entry in os.listdir(APPS_DIR): if entry.startswith(PREFIX) and entry.endswith(".desktop"): appid = entry[len(PREFIX):-len(".desktop")] @@ -102,7 +123,8 @@ def link_libraries(): def main(): wanted = write_entries() link_libraries() - print("bannerlator-desktop-games: %d game(s) on the desktop menu" % len(wanted)) + print("bannerlator-desktop-games: %d entr%s of ours, %d the client's" % ( + len(wanted), "y" if len(wanted) == 1 else "ies", len(client_entries()))) if __name__ == "__main__": diff --git a/tools/linuxfs/overlay/usr/local/bin/bannerlator-steam-shim b/tools/linuxfs/overlay/usr/local/bin/bannerlator-steam-shim new file mode 100755 index 000000000..66d1ee085 --- /dev/null +++ b/tools/linuxfs/overlay/usr/local/bin/bannerlator-steam-shim @@ -0,0 +1,12 @@ +#!/bin/bash +# `steam` on the desktop. The client writes a menu entry per installed game that runs +# `steam steam://rungameid/`, and its own launchers say `steam`; neither can run the client +# here (no dma-buf on the desktop), so on the desktop this hands off to the app for a Steam session +# in the client's desktop UI under gamescope. Anywhere else it is the client itself. +set -u +if [ "${BL_DESKTOP:-}" = 1 ]; then + url= + for arg in "$@"; do case $arg in steam://*) url=$arg ;; esac; done + exec /usr/local/bin/bannerlator-steam-launch desktop ${url:+"$url"} +fi +exec "${HOME:-/root}/.local/share/Steam/steamrtarm64/steam" "$@"