aboutsummaryrefslogtreecommitdiffstats
path: root/games/README.md
blob: b0b6f5b7f8e1ee8dbc209df07b26c0ec120ef58c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# games

A game launcher on DP-1: an endless horizontal strip of small slanted
tiles along the bottom, and the selected game, the one at the centre,
shown large above it in Steam's wide hero art with its title. Installed
games come first, most recently played first; owned games that are not
installed follow, greyed and framed in peach. Non-Steam shortcuts added to
Steam count as installed. A short library repeats to fill the loop.

Left and Right or the wheel move, Enter or a click on the centre tile
launches, a click on another tile selects it. Typing filters by name.
Escape or a click on the background closes. Everything goes through
`steam -silent steam://...`, so the Steam window stays down: `rungameid`
for an installed game or shortcut (keeping its Proton and launch options),
`install` for one that is not.

`games.py` reads, on every opening:

- installed games from the `appmanifest_*.acf` files of every library in
  `steamapps/libraryfolders.vdf`, leaving out Proton and the runtimes;
- shortcuts from the binary `userdata/<account>/config/shortcuts.vdf`,
  whose game id is `appid << 32 | 0x02000000`;
- covers and hero art from Steam's own `appcache/librarycache`, so
  nothing is fetched for them. A tile with no cover shows the initial.

Owned games need the Steam Web API (`IPlayerService/GetOwnedGames`), so
they come from `~/.cache/keystone/games/owned.json`, which
`games.py --refresh` rewrites in the background on every opening. The API
key is read with `pass show "$GAMES_PASS_ENTRY"`; the SteamID is derived
from the userdata account directory.

Every game window lands on workspace 8, however it was started. Steam
sets `SteamGameId` in the environment of every game it runs, native,
Proton or a non-Steam shortcut, so the shell moves any newly opened
window whose process carries it. Class rules in the Hyprland config miss
games that name themselves: a GOG Ren'Py build added as a shortcut had no
`steam_app_` class and opened wherever focus was.

## Running

    qs -p ./games
    qs -p ./games ipc call games toggle    # bound to XF86Search

## Check

    /usr/bin/python3 games/games.py --check