Compare commits
2
Commits
835a939a81
...
738014ae54
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
738014ae54 | ||
|
|
4b7725849f |
@@ -4,12 +4,18 @@
|
|||||||
|
|
||||||
Lineage: forked from [Super-Shift-S-Omarchy-Deck-Mode](https://git.no-signal.uk/nosignal/Super-Shift-S-Omarchy-Deck-Mode), briefly renamed Omarchy Deck, then renamed DeckShift.
|
Lineage: forked from [Super-Shift-S-Omarchy-Deck-Mode](https://git.no-signal.uk/nosignal/Super-Shift-S-Omarchy-Deck-Mode), briefly renamed Omarchy Deck, then renamed DeckShift.
|
||||||
|
|
||||||
> **Target:** [Omarchy](https://omarchy.com) — Arch + Hyprland + SDDM + Walker. DeckShift depends on Omarchy-specific helpers (`omarchy-pkg-add`, `omarchy-restart-walker`, etc.) and is not intended to be cross-distro.
|
> **Target:** [Omarchy](https://omarchy.com) — Arch + Hyprland + SDDM + Walker. Experimental DMS/greetd manual session switching is available through `DECKSHIFT_SESSION_BACKEND=dms-greeter-manual`. DeckShift still depends on Omarchy-specific helpers (`omarchy-pkg-add`, `omarchy-restart-walker`, etc.) and is not intended to be cross-distro.
|
||||||
|
|
||||||
[](https://youtu.be/nj4pLh3spCs)
|
[](https://youtu.be/nj4pLh3spCs)
|
||||||
|
|
||||||
## What's New
|
## What's New
|
||||||
|
|
||||||
|
### Unreleased — Session backend abstraction
|
||||||
|
|
||||||
|
- DeckShift now writes `/etc/deckshift/session-backend.conf` and routes mode selection through `/usr/local/bin/deckshift-session-switch` plus `/usr/local/bin/deckshift-session-transition`.
|
||||||
|
- `sddm` preserves the existing behavior: update `/etc/sddm.conf.d/zz-gaming-session.conf`, then restart SDDM.
|
||||||
|
- `dms-greeter-manual` is experimental: it writes DMS greeter memory to select the target session, then terminates the current login session so the user authenticates through DMS. It does not implement one-shot auto-login yet.
|
||||||
|
|
||||||
### v0.1.13 — Pacman hook keeps gamescope's cap_sys_nice across upgrades
|
### v0.1.13 — Pacman hook keeps gamescope's cap_sys_nice across upgrades
|
||||||
|
|
||||||
- Linux file capabilities live as an xattr (`security.capability`) on the inode, so every time pacman replaces `/usr/bin/gamescope` during an upgrade the previously-granted `cap_sys_nice=eip` is silently lost. Performance mode keeps "working" but the compositor thread loses its priority boost — worse frame pacing and input latency, with no error surfaced anywhere.
|
- Linux file capabilities live as an xattr (`security.capability`) on the inode, so every time pacman replaces `/usr/bin/gamescope` during an upgrade the previously-granted `cap_sys_nice=eip` is silently lost. Performance mode keeps "working" but the compositor thread loses its priority boost — worse frame pacing and input latency, with no error surfaced anywhere.
|
||||||
@@ -117,11 +123,11 @@ This installer transforms your desktop into a dual-mode system:
|
|||||||
- **Desktop Mode** — your normal Hyprland session.
|
- **Desktop Mode** — your normal Hyprland session.
|
||||||
- **Gaming Mode** — full-screen Steam Big Picture running inside Gamescope (the same compositor used by the Steam Deck), with automatic performance tuning, controller support, and external drive mounting.
|
- **Gaming Mode** — full-screen Steam Big Picture running inside Gamescope (the same compositor used by the Steam Deck), with automatic performance tuning, controller support, and external drive mounting.
|
||||||
|
|
||||||
Switching between modes is seamless — SDDM handles session transitions, and your network, audio, and peripherals carry over automatically.
|
Switching between modes is handled by a session backend. SDDM remains the default and preserves the seamless auto-login flow. The experimental DMS greeter backend preselects the next session and returns to the greeter for manual authentication.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- **OS**: [Omarchy](https://omarchy.com) (Arch Linux + Hyprland + SDDM)
|
- **OS**: [Omarchy](https://omarchy.com) (Arch Linux + Hyprland + SDDM), or an experimental DMS/greetd setup for manual session switching
|
||||||
- **GPU**: AMD (discrete or APU), NVIDIA (discrete), or Intel (Arc / Iris Xe), or any hybrid combo of the above
|
- **GPU**: AMD (discrete or APU), NVIDIA (discrete), or Intel (Arc / Iris Xe), or any hybrid combo of the above
|
||||||
- Intel Arc (Alchemist, Battlemage): well-supported
|
- Intel Arc (Alchemist, Battlemage): well-supported
|
||||||
- Tiger Lake / Alder Lake Iris Xe: playable for indies / older AAA
|
- Tiger Lake / Alder Lake Iris Xe: playable for indies / older AAA
|
||||||
@@ -129,7 +135,7 @@ Switching between modes is seamless — SDDM handles session transitions, and yo
|
|||||||
- Hybrid laptops (NVIDIA + iGPU, AMD dGPU + iGPU): use the corresponding `[hybrid-*]` GPU mode in the Settings TUI
|
- Hybrid laptops (NVIDIA + iGPU, AMD dGPU + iGPU): use the corresponding `[hybrid-*]` GPU mode in the Settings TUI
|
||||||
- **AUR Helper**: yay or paru (for ChimeraOS session packages)
|
- **AUR Helper**: yay or paru (for ChimeraOS session packages)
|
||||||
|
|
||||||
> **Note**: This script targets Omarchy and its stack (Hyprland, SDDM, iwd, UWSM, PipeWire). It works on other Arch + Hyprland setups with light tweaks, but isn't tested there.
|
> **Note**: This script targets Omarchy and its stack (Hyprland, SDDM, iwd, UWSM, PipeWire). The DMS/greetd backend is experimental and currently manual-only.
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
@@ -234,9 +240,11 @@ Package installs use Omarchy's `omarchy-pkg-add` (idempotent, double-checks pacm
|
|||||||
| Path | Purpose |
|
| Path | Purpose |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `/usr/local/bin/switch-to-gaming` | Hyprland → Gaming Mode |
|
| `/usr/local/bin/switch-to-gaming` | Hyprland → Gaming Mode |
|
||||||
| `/usr/local/bin/switch-to-desktop` | Gaming Mode → Hyprland (synchronous power-state restore + atomic SDDM restart) |
|
| `/usr/local/bin/switch-to-desktop` | Gaming Mode → Hyprland (synchronous power-state restore + backend transition) |
|
||||||
| `/usr/local/bin/gamescope-session-nm-wrapper` | Main session wrapper (performance mode, NM, drive mounting, saves pre-Gaming-Mode state) |
|
| `/usr/local/bin/gamescope-session-nm-wrapper` | Main session wrapper (performance mode, NM, drive mounting, saves pre-Gaming-Mode state) |
|
||||||
| `/usr/local/bin/gaming-session-switch` | Helper that toggles SDDM autologin between Hyprland and Gamescope |
|
| `/usr/local/bin/deckshift-session-switch` | Backend-neutral helper that selects desktop or gaming session |
|
||||||
|
| `/usr/local/bin/deckshift-session-transition` | Backend-neutral helper that restarts SDDM or exits to DMS greeter |
|
||||||
|
| `/usr/local/bin/gaming-session-switch` | Compatibility wrapper for `deckshift-session-switch` |
|
||||||
| `/usr/local/bin/gaming-keybind-monitor` | Python evdev daemon catching `Super+Shift+R` inside Gamescope |
|
| `/usr/local/bin/gaming-keybind-monitor` | Python evdev daemon catching `Super+Shift+R` inside Gamescope |
|
||||||
| `/usr/lib/os-session-select` | Handler for Steam's "Exit to Desktop" button |
|
| `/usr/lib/os-session-select` | Handler for Steam's "Exit to Desktop" button |
|
||||||
| `/usr/local/lib/gamescope-nvidia/gamescope` | NVIDIA wrapper that adds `--force-composition` |
|
| `/usr/local/lib/gamescope-nvidia/gamescope` | NVIDIA wrapper that adds `--force-composition` |
|
||||||
@@ -257,8 +265,10 @@ Package installs use Omarchy's `omarchy-pkg-add` (idempotent, double-checks pacm
|
|||||||
#### Session & Display Manager
|
#### Session & Display Manager
|
||||||
| Path | Purpose |
|
| Path | Purpose |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `/usr/share/wayland-sessions/gamescope-session-steam-nm.desktop` | SDDM session entry for Gaming Mode |
|
| `/usr/share/wayland-sessions/gamescope-session-steam-nm.desktop` | Wayland session entry for Gaming Mode |
|
||||||
| `/etc/sddm.conf.d/zz-gaming-session.conf` | SDDM autologin session switching config |
|
| `/etc/deckshift/session-backend.conf` | Active session backend and session IDs |
|
||||||
|
| `/etc/sddm.conf.d/zz-gaming-session.conf` | SDDM autologin session switching config when using the SDDM backend |
|
||||||
|
| `/var/cache/dms-greeter/.local/state/memory.json` | DMS greeter memory updated when using the DMS manual backend |
|
||||||
|
|
||||||
#### Permissions & Security
|
#### Permissions & Security
|
||||||
| Path | Purpose |
|
| Path | Purpose |
|
||||||
@@ -300,8 +310,8 @@ Desktop Mode (Hyprland)
|
|||||||
├─ Super+Shift+S pressed
|
├─ Super+Shift+S pressed
|
||||||
│ └─ switch-to-gaming runs:
|
│ └─ switch-to-gaming runs:
|
||||||
│ ├─ Masks suspend targets (prevents sleep during switch)
|
│ ├─ Masks suspend targets (prevents sleep during switch)
|
||||||
│ ├─ Updates SDDM config to gaming session
|
│ ├─ Selects the gaming session through deckshift-session-switch
|
||||||
│ └─ Restarts SDDM → boots into Gaming Mode
|
│ └─ Runs deckshift-session-transition
|
||||||
│
|
│
|
||||||
Gaming Mode (Gamescope + Steam Big Picture)
|
Gaming Mode (Gamescope + Steam Big Picture)
|
||||||
│
|
│
|
||||||
@@ -320,8 +330,8 @@ Gaming Mode (Gamescope + Steam Big Picture)
|
|||||||
│ ├─ Restores Bluetooth
|
│ ├─ Restores Bluetooth
|
||||||
│ ├─ Shuts down Steam gracefully
|
│ ├─ Shuts down Steam gracefully
|
||||||
│ ├─ Kills gamescope
|
│ ├─ Kills gamescope
|
||||||
│ ├─ Updates SDDM config to Hyprland session
|
│ ├─ Selects the desktop session through deckshift-session-switch
|
||||||
│ └─ Atomic systemctl restart sddm → boots into Desktop Mode
|
│ └─ Runs deckshift-session-transition
|
||||||
│
|
│
|
||||||
└─ On session cleanup (trap handler — backup path):
|
└─ On session cleanup (trap handler — backup path):
|
||||||
├─ Kills steam-library-mount and keybind-monitor
|
├─ Kills steam-library-mount and keybind-monitor
|
||||||
@@ -553,7 +563,8 @@ sudo pkill -f steam-library-mount
|
|||||||
|
|
||||||
# Remove scripts
|
# Remove scripts
|
||||||
sudo rm -f /usr/local/bin/{switch-to-gaming,switch-to-desktop,gamescope-session-nm-wrapper,\
|
sudo rm -f /usr/local/bin/{switch-to-gaming,switch-to-desktop,gamescope-session-nm-wrapper,\
|
||||||
gaming-session-switch,gaming-keybind-monitor,gamescope-nm-start,gamescope-nm-stop,\
|
deckshift-session-switch,deckshift-session-transition,gaming-session-switch,\
|
||||||
|
gaming-keybind-monitor,gamescope-nm-start,gamescope-nm-stop,\
|
||||||
steam-library-mount,deckshift-settings}
|
steam-library-mount,deckshift-settings}
|
||||||
sudo rm -f /usr/lib/os-session-select
|
sudo rm -f /usr/lib/os-session-select
|
||||||
sudo rm -rf /usr/local/lib/gamescope-nvidia
|
sudo rm -rf /usr/local/lib/gamescope-nvidia
|
||||||
@@ -572,6 +583,7 @@ sudo rm -f /etc/udev/rules.d/99-gaming-performance.rules
|
|||||||
sudo rm -f /etc/security/limits.d/99-gaming-memlock.conf
|
sudo rm -f /etc/security/limits.d/99-gaming-memlock.conf
|
||||||
|
|
||||||
# Remove configs
|
# Remove configs
|
||||||
|
sudo rm -rf /etc/deckshift
|
||||||
sudo rm -f /etc/sddm.conf.d/zz-gaming-session.conf
|
sudo rm -f /etc/sddm.conf.d/zz-gaming-session.conf
|
||||||
sudo rm -f /etc/environment.d/99-shader-cache.conf
|
sudo rm -f /etc/environment.d/99-shader-cache.conf
|
||||||
sudo rm -f /etc/environment.d/90-nvidia-gamescope.conf
|
sudo rm -f /etc/environment.d/90-nvidia-gamescope.conf
|
||||||
|
|||||||
+311
-56
@@ -48,6 +48,9 @@ CONFIG_FILE="/etc/gaming-mode.conf"
|
|||||||
[[ -f "$HOME/.gaming-mode.conf" ]] && CONFIG_FILE="$HOME/.gaming-mode.conf"
|
[[ -f "$HOME/.gaming-mode.conf" ]] && CONFIG_FILE="$HOME/.gaming-mode.conf"
|
||||||
source "$CONFIG_FILE" 2>/dev/null || true
|
source "$CONFIG_FILE" 2>/dev/null || true
|
||||||
: "${PERFORMANCE_MODE:=enabled}"
|
: "${PERFORMANCE_MODE:=enabled}"
|
||||||
|
: "${DECKSHIFT_SESSION_BACKEND:=auto}"
|
||||||
|
: "${DECKSHIFT_DESKTOP_SESSION_ID:=hyprland-uwsm.desktop}"
|
||||||
|
: "${DECKSHIFT_GAMING_SESSION_ID:=gamescope-session-steam-nm.desktop}"
|
||||||
|
|
||||||
# Flags that track whether the user needs to reboot or re-login after setup.
|
# Flags that track whether the user needs to reboot or re-login after setup.
|
||||||
# Various steps set these to 1 when they make changes that only take effect
|
# Various steps set these to 1 when they make changes that only take effect
|
||||||
@@ -1321,10 +1324,10 @@ setup_settings_tui() {
|
|||||||
# to seamlessly switch between Desktop Mode (Hyprland) and Gaming Mode
|
# to seamlessly switch between Desktop Mode (Hyprland) and Gaming Mode
|
||||||
# (Gamescope + Steam Big Picture).
|
# (Gamescope + Steam Big Picture).
|
||||||
#
|
#
|
||||||
# The switching mechanism works through SDDM (the display/login manager):
|
# The switching mechanism works through a session backend:
|
||||||
# 1. User presses Super+Shift+S in Hyprland
|
# 1. User presses Super+Shift+S in Hyprland
|
||||||
# 2. switch-to-gaming script updates SDDM config to point to Gaming session
|
# 2. switch-to-gaming selects the Gaming Mode session
|
||||||
# 3. SDDM restarts and auto-logs into the Gaming Mode session
|
# 3. The backend transitions through SDDM or the configured greeter
|
||||||
# 4. gamescope-session-nm-wrapper starts performance tuning, NetworkManager,
|
# 4. gamescope-session-nm-wrapper starts performance tuning, NetworkManager,
|
||||||
# drive mounting, keybind monitor, then launches Gamescope + Steam
|
# drive mounting, keybind monitor, then launches Gamescope + Steam
|
||||||
# 5. When done (Super+Shift+R or Steam > Exit to Desktop), the reverse happens
|
# 5. When done (Super+Shift+R or Steam > Exit to Desktop), the reverse happens
|
||||||
@@ -1335,7 +1338,7 @@ setup_settings_tui() {
|
|||||||
# - Keybind monitor (Python daemon using evdev for Super+Shift+R)
|
# - Keybind monitor (Python daemon using evdev for Super+Shift+R)
|
||||||
# - NetworkManager start/stop scripts (iwd <-> NM handoff)
|
# - NetworkManager start/stop scripts (iwd <-> NM handoff)
|
||||||
# - Steam library auto-mount daemon
|
# - Steam library auto-mount daemon
|
||||||
# - SDDM session entry and config
|
# - Session entry, backend config, and display-manager helpers
|
||||||
# - Polkit and sudoers rules for passwordless operation
|
# - Polkit and sudoers rules for passwordless operation
|
||||||
# - Hyprland keybind for Super+Shift+S
|
# - Hyprland keybind for Super+Shift+S
|
||||||
#
|
#
|
||||||
@@ -1431,6 +1434,50 @@ PY
|
|||||||
info "Patched $gsp — CUSTOM_REFRESH_RATES now reaches gamescope via --nested-refresh"
|
info "Patched $gsp — CUSTOM_REFRESH_RATES now reaches gamescope via --nested-refresh"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detect_session_backend() {
|
||||||
|
case "${DECKSHIFT_SESSION_BACKEND}" in
|
||||||
|
sddm|dms-greeter-manual)
|
||||||
|
printf '%s\n' "$DECKSHIFT_SESSION_BACKEND"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
auto)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
die "Unsupported DECKSHIFT_SESSION_BACKEND: $DECKSHIFT_SESSION_BACKEND"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
local display_manager=""
|
||||||
|
if [[ -L /etc/systemd/system/display-manager.service ]]; then
|
||||||
|
display_manager=$(basename "$(readlink -f /etc/systemd/system/display-manager.service)" 2>/dev/null || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$display_manager" == "greetd.service" ]] &&
|
||||||
|
[[ -r /etc/greetd/config.toml ]] &&
|
||||||
|
grep -q 'dms-greeter' /etc/greetd/config.toml; then
|
||||||
|
printf '%s\n' "dms-greeter-manual"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s\n' "sddm"
|
||||||
|
}
|
||||||
|
|
||||||
|
read_installed_session_backend() {
|
||||||
|
local conf="/etc/deckshift/session-backend.conf"
|
||||||
|
if [[ -r "$conf" ]]; then
|
||||||
|
local installed_backend
|
||||||
|
installed_backend=$(sed -n 's/^DECKSHIFT_SESSION_BACKEND=//p' "$conf" 2>/dev/null | head -1)
|
||||||
|
case "$installed_backend" in
|
||||||
|
sddm|dms-greeter-manual)
|
||||||
|
printf '%s\n' "$installed_backend"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
detect_session_backend
|
||||||
|
}
|
||||||
|
|
||||||
setup_session_switching() {
|
setup_session_switching() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "================================================================"
|
echo "================================================================"
|
||||||
@@ -1471,6 +1518,10 @@ setup_session_switching() {
|
|||||||
local current_user="${SUDO_USER:-$USER}"
|
local current_user="${SUDO_USER:-$USER}"
|
||||||
local user_home
|
local user_home
|
||||||
user_home=$(eval echo "~$current_user")
|
user_home=$(eval echo "~$current_user")
|
||||||
|
local session_backend
|
||||||
|
session_backend=$(detect_session_backend)
|
||||||
|
local gaming_session_path="/usr/share/wayland-sessions/${DECKSHIFT_GAMING_SESSION_ID}"
|
||||||
|
info "Using session backend: $session_backend"
|
||||||
|
|
||||||
# GPU detection only — the installer no longer chooses a monitor, resolution
|
# GPU detection only — the installer no longer chooses a monitor, resolution
|
||||||
# or refresh rate. Those are user choices, made later via Walker → "DeckShift
|
# or refresh rate. Those are user choices, made later via Walker → "DeckShift
|
||||||
@@ -2285,14 +2336,13 @@ NM_WRAPPER
|
|||||||
sudo chmod +x "$nm_wrapper"
|
sudo chmod +x "$nm_wrapper"
|
||||||
info "Created $nm_wrapper"
|
info "Created $nm_wrapper"
|
||||||
|
|
||||||
# SDDM Session Entry
|
# Gaming Session Entry
|
||||||
#
|
#
|
||||||
# SDDM (the login/display manager) needs a .desktop file to know about
|
# Display managers and greeters need a .desktop file to know about Gaming
|
||||||
# Gaming Mode as a session option. This is what tells SDDM "when you
|
# Mode as a session option. The active session backend selects this entry
|
||||||
# auto-login to the gaming session, run this script." It's placed in
|
# when switching into Gaming Mode.
|
||||||
# /usr/share/wayland-sessions/ alongside the normal Hyprland session.
|
info "Creating Gaming Mode session entry..."
|
||||||
info "Creating SDDM session entry..."
|
local session_desktop="$gaming_session_path"
|
||||||
local session_desktop="/usr/share/wayland-sessions/gamescope-session-steam-nm.desktop"
|
|
||||||
|
|
||||||
sudo tee "$session_desktop" > /dev/null << 'SESSION_DESKTOP'
|
sudo tee "$session_desktop" > /dev/null << 'SESSION_DESKTOP'
|
||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
@@ -2310,19 +2360,19 @@ SESSION_DESKTOP
|
|||||||
# When you click Steam > Power > "Exit to Desktop" inside Gaming Mode,
|
# When you click Steam > Power > "Exit to Desktop" inside Gaming Mode,
|
||||||
# Steam calls /usr/lib/os-session-select. On a real Steam Deck this
|
# Steam calls /usr/lib/os-session-select. On a real Steam Deck this
|
||||||
# switches to Desktop Mode. Our version does the same thing — it updates
|
# switches to Desktop Mode. Our version does the same thing — it updates
|
||||||
# SDDM to boot back into Hyprland and restarts the display manager.
|
# selects the desktop session and asks the active backend to transition.
|
||||||
info "Creating session-select script..."
|
info "Creating session-select script..."
|
||||||
local os_session_select="/usr/lib/os-session-select"
|
local os_session_select="/usr/lib/os-session-select"
|
||||||
|
|
||||||
sudo tee "$os_session_select" > /dev/null << 'OS_SESSION_SELECT'
|
sudo tee "$os_session_select" > /dev/null << 'OS_SESSION_SELECT'
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
rm -f /tmp/.gaming-session-active
|
rm -f /tmp/.gaming-session-active
|
||||||
sudo -n /usr/local/bin/gaming-session-switch desktop 2>/dev/null || {
|
sudo -n /usr/local/bin/deckshift-session-switch desktop 2>/dev/null || {
|
||||||
echo "Warning: Failed to update session config"
|
echo "Warning: Failed to update session config"
|
||||||
}
|
}
|
||||||
timeout 5 steam -shutdown 2>/dev/null || true
|
timeout 5 steam -shutdown 2>/dev/null || true
|
||||||
sleep 1
|
sleep 1
|
||||||
nohup sudo -n systemctl restart sddm &>/dev/null &
|
nohup /usr/local/bin/deckshift-session-transition desktop &>/dev/null &
|
||||||
disown
|
disown
|
||||||
exit 0
|
exit 0
|
||||||
OS_SESSION_SELECT
|
OS_SESSION_SELECT
|
||||||
@@ -2335,10 +2385,10 @@ OS_SESSION_SELECT
|
|||||||
# This script handles the transition from Desktop to Gaming Mode:
|
# This script handles the transition from Desktop to Gaming Mode:
|
||||||
# 1. Masks suspend targets — prevents the system from sleeping when the
|
# 1. Masks suspend targets — prevents the system from sleeping when the
|
||||||
# monitor briefly disconnects during the display manager restart
|
# monitor briefly disconnects during the display manager restart
|
||||||
# 2. Updates SDDM config to auto-login to the gaming session
|
# 2. Selects the gaming session through DeckShift's active backend
|
||||||
# 3. Kills any leftover gamescope processes from a previous session
|
# 3. Kills any leftover gamescope processes from a previous session
|
||||||
# 4. Switches to VT2 (virtual terminal) to avoid display conflicts
|
# 4. Switches to VT2 (virtual terminal) to avoid display conflicts
|
||||||
# 5. Restarts SDDM, which auto-logs into Gaming Mode
|
# 5. Transitions through SDDM or the configured greeter
|
||||||
info "Creating switch-to-gaming script..."
|
info "Creating switch-to-gaming script..."
|
||||||
local switch_script="/usr/local/bin/switch-to-gaming"
|
local switch_script="/usr/local/bin/switch-to-gaming"
|
||||||
|
|
||||||
@@ -2346,7 +2396,7 @@ OS_SESSION_SELECT
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Inhibit suspend FIRST - prevents suspend when monitor detaches during switch
|
# Inhibit suspend FIRST - prevents suspend when monitor detaches during switch
|
||||||
sudo -n systemctl mask --runtime sleep.target suspend.target hibernate.target hybrid-sleep.target 2>/dev/null
|
sudo -n systemctl mask --runtime sleep.target suspend.target hibernate.target hybrid-sleep.target 2>/dev/null
|
||||||
sudo -n /usr/local/bin/gaming-session-switch gaming 2>/dev/null || {
|
sudo -n /usr/local/bin/deckshift-session-switch gaming 2>/dev/null || {
|
||||||
notify-send -u critical -t 3000 "Gaming Mode" "Failed to update session config" 2>/dev/null || true
|
notify-send -u critical -t 3000 "Gaming Mode" "Failed to update session config" 2>/dev/null || true
|
||||||
}
|
}
|
||||||
notify-send -u normal -t 2000 "Gaming Mode" "Switching to Gaming Mode..." 2>/dev/null || true
|
notify-send -u normal -t 2000 "Gaming Mode" "Switching to Gaming Mode..." 2>/dev/null || true
|
||||||
@@ -2377,7 +2427,7 @@ fi
|
|||||||
|
|
||||||
sudo -n chvt 2 2>/dev/null || true
|
sudo -n chvt 2 2>/dev/null || true
|
||||||
sleep 0.3
|
sleep 0.3
|
||||||
sudo -n systemctl restart sddm
|
/usr/local/bin/deckshift-session-transition gaming
|
||||||
SWITCH_SCRIPT
|
SWITCH_SCRIPT
|
||||||
|
|
||||||
sudo chmod +x "$switch_script"
|
sudo chmod +x "$switch_script"
|
||||||
@@ -2390,8 +2440,8 @@ SWITCH_SCRIPT
|
|||||||
# 2. Restores Bluetooth (disabled during gaming to reduce interference)
|
# 2. Restores Bluetooth (disabled during gaming to reduce interference)
|
||||||
# 3. Gracefully shuts down Steam (timeout 5s, then force kill)
|
# 3. Gracefully shuts down Steam (timeout 5s, then force kill)
|
||||||
# 4. Kills gamescope with SIGTERM first, then SIGKILL if it won't die
|
# 4. Kills gamescope with SIGTERM first, then SIGKILL if it won't die
|
||||||
# 5. Updates SDDM config back to Hyprland session
|
# 5. Selects the desktop session through DeckShift's active backend
|
||||||
# 6. Restarts SDDM, which auto-logs into Desktop Mode
|
# 6. Transitions through SDDM or the configured greeter
|
||||||
info "Creating switch-to-desktop script..."
|
info "Creating switch-to-desktop script..."
|
||||||
local switch_desktop_script="/usr/local/bin/switch-to-desktop"
|
local switch_desktop_script="/usr/local/bin/switch-to-desktop"
|
||||||
|
|
||||||
@@ -2429,7 +2479,7 @@ fi
|
|||||||
sudo -n systemctl unmask sleep.target suspend.target hibernate.target hybrid-sleep.target 2>/dev/null
|
sudo -n systemctl unmask sleep.target suspend.target hibernate.target hybrid-sleep.target 2>/dev/null
|
||||||
sudo -n systemctl unmask --runtime sleep.target suspend.target hibernate.target hybrid-sleep.target 2>/dev/null
|
sudo -n systemctl unmask --runtime sleep.target suspend.target hibernate.target hybrid-sleep.target 2>/dev/null
|
||||||
sudo -n systemctl daemon-reload 2>/dev/null
|
sudo -n systemctl daemon-reload 2>/dev/null
|
||||||
sudo -n /usr/local/bin/gaming-session-switch desktop 2>/dev/null || true
|
sudo -n /usr/local/bin/deckshift-session-switch desktop 2>/dev/null || true
|
||||||
|
|
||||||
# Re-enable Bluetooth
|
# Re-enable Bluetooth
|
||||||
sudo -n /usr/bin/rfkill unblock bluetooth 2>/dev/null || true
|
sudo -n /usr/bin/rfkill unblock bluetooth 2>/dev/null || true
|
||||||
@@ -2465,9 +2515,10 @@ sudo -n chvt 2 2>/dev/null || true
|
|||||||
sleep 0.5
|
sleep 0.5
|
||||||
# Atomic restart — stop+start (with stop and start as separate sudo calls)
|
# Atomic restart — stop+start (with stop and start as separate sudo calls)
|
||||||
# was unreliable: stop/start aren't NOPASSWD-allowed individually (only
|
# was unreliable: stop/start aren't NOPASSWD-allowed individually (only
|
||||||
# `restart` is), and the disowned `start` could be killed by session teardown
|
# `restart` is for SDDM), and the disowned `start` could be killed by session
|
||||||
# before SDDM actually came back up, leaving the user on a black screen.
|
# teardown before the display manager actually came back up, leaving the user
|
||||||
sudo -n systemctl restart sddm
|
# on a black screen.
|
||||||
|
/usr/local/bin/deckshift-session-transition desktop
|
||||||
exit 0
|
exit 0
|
||||||
SWITCH_DESKTOP
|
SWITCH_DESKTOP
|
||||||
|
|
||||||
@@ -2661,21 +2712,14 @@ HYPR_PORTAL
|
|||||||
warn "Add manually: exec-once = /usr/local/bin/deckshift-portal-recovery"
|
warn "Add manually: exec-once = /usr/local/bin/deckshift-portal-recovery"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# SDDM Session Switching Config
|
# Session Backend Config
|
||||||
#
|
#
|
||||||
# SDDM supports auto-login — it can automatically log in a user to a
|
# Keep display-manager-specific behavior behind small helpers so DeckShift's
|
||||||
# specific session without showing the login screen. This config file
|
# Gamescope, Steam, GPU, and performance logic can stay backend-agnostic.
|
||||||
# controls WHICH session SDDM auto-logs into.
|
info "Creating session backend config..."
|
||||||
#
|
local deckshift_config_dir="/etc/deckshift"
|
||||||
# The switching mechanism works by editing this file:
|
local deckshift_backend_conf="${deckshift_config_dir}/session-backend.conf"
|
||||||
# - "Session=hyprland-uwsm" → boots into Desktop Mode
|
sudo install -d -m 0755 "$deckshift_config_dir"
|
||||||
# - "Session=gamescope-session-steam-nm" → boots into Gaming Mode
|
|
||||||
#
|
|
||||||
# The gaming-session-switch helper script toggles this value, then SDDM
|
|
||||||
# is restarted to pick up the change. The "zz-" prefix ensures this
|
|
||||||
# config loads LAST and overrides any other SDDM autologin settings.
|
|
||||||
info "Creating SDDM session switching config..."
|
|
||||||
local sddm_gaming_conf="/etc/sddm.conf.d/zz-gaming-session.conf"
|
|
||||||
|
|
||||||
local autologin_user="$current_user"
|
local autologin_user="$current_user"
|
||||||
if [[ -f /etc/sddm.conf.d/autologin.conf ]]; then
|
if [[ -f /etc/sddm.conf.d/autologin.conf ]]; then
|
||||||
@@ -2683,49 +2727,198 @@ HYPR_PORTAL
|
|||||||
[[ -z "$autologin_user" ]] && autologin_user="$current_user"
|
[[ -z "$autologin_user" ]] && autologin_user="$current_user"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
sudo tee "$deckshift_backend_conf" > /dev/null << BACKEND_CONF
|
||||||
|
DECKSHIFT_SESSION_BACKEND=${session_backend}
|
||||||
|
DECKSHIFT_DESKTOP_SESSION_ID=${DECKSHIFT_DESKTOP_SESSION_ID}
|
||||||
|
DECKSHIFT_GAMING_SESSION_ID=${DECKSHIFT_GAMING_SESSION_ID}
|
||||||
|
DECKSHIFT_GAMING_SESSION_PATH=${gaming_session_path}
|
||||||
|
DECKSHIFT_SDDM_CONF=/etc/sddm.conf.d/zz-gaming-session.conf
|
||||||
|
DECKSHIFT_SDDM_USER=${autologin_user}
|
||||||
|
DECKSHIFT_DMS_MEMORY_FILE=/var/cache/dms-greeter/.local/state/memory.json
|
||||||
|
DECKSHIFT_DMS_GREETER_GROUP=greeter
|
||||||
|
BACKEND_CONF
|
||||||
|
sudo chmod 0644 "$deckshift_backend_conf"
|
||||||
|
|
||||||
|
info "Created $deckshift_backend_conf"
|
||||||
|
|
||||||
|
if [[ "$session_backend" == "sddm" ]]; then
|
||||||
|
info "Creating SDDM session switching config..."
|
||||||
|
local sddm_gaming_conf="/etc/sddm.conf.d/zz-gaming-session.conf"
|
||||||
|
sudo install -d -m 0755 /etc/sddm.conf.d
|
||||||
sudo tee "$sddm_gaming_conf" > /dev/null << SDDM_GAMING
|
sudo tee "$sddm_gaming_conf" > /dev/null << SDDM_GAMING
|
||||||
[Autologin]
|
[Autologin]
|
||||||
User=${autologin_user}
|
User=${autologin_user}
|
||||||
Session=hyprland-uwsm
|
Session=${DECKSHIFT_DESKTOP_SESSION_ID%.desktop}
|
||||||
Relogin=true
|
Relogin=true
|
||||||
SDDM_GAMING
|
SDDM_GAMING
|
||||||
|
|
||||||
info "Created $sddm_gaming_conf"
|
info "Created $sddm_gaming_conf"
|
||||||
|
else
|
||||||
|
info "DMS greeter backend selected; SDDM autologin config will not be created"
|
||||||
|
fi
|
||||||
|
|
||||||
info "Creating session switching helper script..."
|
info "Creating session switching helper scripts..."
|
||||||
local session_helper="/usr/local/bin/gaming-session-switch"
|
local session_helper="/usr/local/bin/deckshift-session-switch"
|
||||||
|
|
||||||
sudo tee "$session_helper" > /dev/null << 'SESSION_HELPER'
|
sudo tee "$session_helper" > /dev/null << 'SESSION_HELPER'
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
CONF="/etc/sddm.conf.d/zz-gaming-session.conf"
|
set -euo pipefail
|
||||||
|
|
||||||
|
CONF="/etc/deckshift/session-backend.conf"
|
||||||
if [[ ! -f "$CONF" ]]; then
|
if [[ ! -f "$CONF" ]]; then
|
||||||
echo "Error: Config file not found: $CONF" >&2
|
echo "Error: Config file not found: $CONF" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
case "$1" in
|
# shellcheck disable=SC1090
|
||||||
gaming)
|
source "$CONF"
|
||||||
sed -i 's/^Session=.*/Session=gamescope-session-steam-nm/' "$CONF"
|
|
||||||
echo "Session set to: gaming mode"
|
target="${1:-}"
|
||||||
;;
|
case "$target" in
|
||||||
desktop)
|
gaming|desktop) ;;
|
||||||
sed -i 's/^Session=.*/Session=hyprland-uwsm/' "$CONF"
|
|
||||||
echo "Session set to: desktop mode"
|
|
||||||
;;
|
|
||||||
*)
|
*)
|
||||||
echo "Usage: $0 {gaming|desktop}" >&2
|
echo "Usage: $0 {gaming|desktop}" >&2
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
session_id_for_target() {
|
||||||
|
case "$1" in
|
||||||
|
gaming) printf '%s\n' "$DECKSHIFT_GAMING_SESSION_ID" ;;
|
||||||
|
desktop) printf '%s\n' "$DECKSHIFT_DESKTOP_SESSION_ID" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_session_path() {
|
||||||
|
local session_id="$1"
|
||||||
|
local explicit=""
|
||||||
|
if [[ "$session_id" == "$DECKSHIFT_GAMING_SESSION_ID" ]]; then
|
||||||
|
explicit="${DECKSHIFT_GAMING_SESSION_PATH:-}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$explicit" && -f "$explicit" ]]; then
|
||||||
|
printf '%s\n' "$explicit"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local dir candidate
|
||||||
|
for dir in /usr/local/share/wayland-sessions /usr/share/wayland-sessions; do
|
||||||
|
candidate="${dir}/${session_id}"
|
||||||
|
if [[ -f "$candidate" ]]; then
|
||||||
|
printf '%s\n' "$candidate"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Error: session file not found for ${session_id}" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
write_dms_memory() {
|
||||||
|
local session_id="$1"
|
||||||
|
local session_path="$2"
|
||||||
|
local memory_file="${DECKSHIFT_DMS_MEMORY_FILE:-/var/cache/dms-greeter/.local/state/memory.json}"
|
||||||
|
local tmp
|
||||||
|
tmp=$(mktemp)
|
||||||
|
|
||||||
|
python3 - "$memory_file" "$session_path" "$session_id" > "$tmp" <<'PY'
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
path, session_path, session_id = sys.argv[1:4]
|
||||||
|
data = {}
|
||||||
|
try:
|
||||||
|
if os.path.exists(path):
|
||||||
|
with open(path) as fh:
|
||||||
|
loaded = json.load(fh)
|
||||||
|
if isinstance(loaded, dict):
|
||||||
|
data = loaded
|
||||||
|
except Exception:
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
data["lastSessionId"] = session_path
|
||||||
|
data["lastSessionDesktopId"] = session_id
|
||||||
|
json.dump(data, sys.stdout, indent=2)
|
||||||
|
sys.stdout.write("\n")
|
||||||
|
PY
|
||||||
|
|
||||||
|
install -d -m 0775 "$(dirname "$memory_file")"
|
||||||
|
install -m 0664 "$tmp" "$memory_file"
|
||||||
|
rm -f "$tmp"
|
||||||
|
|
||||||
|
if getent group "${DECKSHIFT_DMS_GREETER_GROUP:-greeter}" >/dev/null 2>&1; then
|
||||||
|
chgrp "${DECKSHIFT_DMS_GREETER_GROUP:-greeter}" "$(dirname "$memory_file")" "$memory_file" || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
session_id="$(session_id_for_target "$target")"
|
||||||
|
|
||||||
|
case "${DECKSHIFT_SESSION_BACKEND:-sddm}" in
|
||||||
|
sddm)
|
||||||
|
sddm_conf="${DECKSHIFT_SDDM_CONF:-/etc/sddm.conf.d/zz-gaming-session.conf}"
|
||||||
|
if [[ ! -f "$sddm_conf" ]]; then
|
||||||
|
echo "Error: SDDM config file not found: $sddm_conf" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
sed -i "s/^Session=.*/Session=${session_id%.desktop}/" "$sddm_conf"
|
||||||
|
;;
|
||||||
|
dms-greeter-manual)
|
||||||
|
session_path="$(resolve_session_path "$session_id")"
|
||||||
|
write_dms_memory "$session_id" "$session_path"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Error: unsupported DeckShift session backend: ${DECKSHIFT_SESSION_BACKEND:-}" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "Session set to: ${target} mode"
|
||||||
SESSION_HELPER
|
SESSION_HELPER
|
||||||
|
|
||||||
sudo chmod +x "$session_helper"
|
sudo chmod +x "$session_helper"
|
||||||
info "Created $session_helper"
|
info "Created $session_helper"
|
||||||
|
|
||||||
|
local legacy_session_helper="/usr/local/bin/gaming-session-switch"
|
||||||
|
sudo tee "$legacy_session_helper" > /dev/null << 'LEGACY_SESSION_HELPER'
|
||||||
|
#!/bin/bash
|
||||||
|
exec /usr/local/bin/deckshift-session-switch "$@"
|
||||||
|
LEGACY_SESSION_HELPER
|
||||||
|
sudo chmod +x "$legacy_session_helper"
|
||||||
|
info "Created compatibility wrapper $legacy_session_helper"
|
||||||
|
|
||||||
|
local transition_helper="/usr/local/bin/deckshift-session-transition"
|
||||||
|
sudo tee "$transition_helper" > /dev/null << 'TRANSITION_HELPER'
|
||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
CONF="/etc/deckshift/session-backend.conf"
|
||||||
|
[[ -f "$CONF" ]] || { echo "Error: Config file not found: $CONF" >&2; exit 1; }
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
source "$CONF"
|
||||||
|
|
||||||
|
case "${DECKSHIFT_SESSION_BACKEND:-sddm}" in
|
||||||
|
sddm)
|
||||||
|
exec sudo -n systemctl restart sddm
|
||||||
|
;;
|
||||||
|
dms-greeter-manual)
|
||||||
|
if [[ -n "${XDG_SESSION_ID:-}" ]]; then
|
||||||
|
exec loginctl terminate-session "$XDG_SESSION_ID"
|
||||||
|
fi
|
||||||
|
exec sudo -n systemctl restart greetd.service
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Error: unsupported DeckShift session backend: ${DECKSHIFT_SESSION_BACKEND:-}" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
TRANSITION_HELPER
|
||||||
|
sudo chmod +x "$transition_helper"
|
||||||
|
info "Created $transition_helper"
|
||||||
|
|
||||||
# Sudoers Rules for Session Switching
|
# Sudoers Rules for Session Switching
|
||||||
#
|
#
|
||||||
# The session switching scripts need to run several commands as root
|
# The session switching scripts need to run several commands as root
|
||||||
# (restart SDDM, start/stop NetworkManager, control Bluetooth, etc.).
|
# (restart display managers, start/stop NetworkManager, control Bluetooth, etc.).
|
||||||
# These sudoers rules allow members of the "video" and "wheel" groups
|
# These sudoers rules allow members of the "video" and "wheel" groups
|
||||||
# to run ONLY these specific commands without a password.
|
# to run ONLY these specific commands without a password.
|
||||||
#
|
#
|
||||||
@@ -2744,7 +2937,10 @@ SESSION_HELPER
|
|||||||
local switch_output
|
local switch_output
|
||||||
switch_output=$(sudo tee "$sudoers_session" << 'SUDOERS_SWITCH' 2>&1
|
switch_output=$(sudo tee "$sudoers_session" << 'SUDOERS_SWITCH' 2>&1
|
||||||
%video ALL=(ALL) NOPASSWD: /usr/local/bin/gaming-session-switch
|
%video ALL=(ALL) NOPASSWD: /usr/local/bin/gaming-session-switch
|
||||||
|
%video ALL=(ALL) NOPASSWD: /usr/local/bin/deckshift-session-switch
|
||||||
|
%video ALL=(ALL) NOPASSWD: /usr/local/bin/deckshift-session-transition
|
||||||
%video ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart sddm
|
%video ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart sddm
|
||||||
|
%video ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart greetd.service
|
||||||
%video ALL=(ALL) NOPASSWD: /usr/bin/chvt
|
%video ALL=(ALL) NOPASSWD: /usr/bin/chvt
|
||||||
%video ALL=(ALL) NOPASSWD: /usr/bin/systemctl mask --runtime sleep.target suspend.target hibernate.target hybrid-sleep.target
|
%video ALL=(ALL) NOPASSWD: /usr/bin/systemctl mask --runtime sleep.target suspend.target hibernate.target hybrid-sleep.target
|
||||||
%video ALL=(ALL) NOPASSWD: /usr/bin/systemctl unmask sleep.target suspend.target hibernate.target hybrid-sleep.target
|
%video ALL=(ALL) NOPASSWD: /usr/bin/systemctl unmask sleep.target suspend.target hibernate.target hybrid-sleep.target
|
||||||
@@ -2846,10 +3042,13 @@ HYPR_GAMING
|
|||||||
echo " Files created/modified:"
|
echo " Files created/modified:"
|
||||||
echo " - ~/.config/environment.d/gamescope-session-plus.conf"
|
echo " - ~/.config/environment.d/gamescope-session-plus.conf"
|
||||||
echo " - /usr/local/bin/gamescope-session-nm-wrapper"
|
echo " - /usr/local/bin/gamescope-session-nm-wrapper"
|
||||||
echo " - /usr/share/wayland-sessions/gamescope-session-steam-nm.desktop"
|
echo " - ${gaming_session_path}"
|
||||||
echo " - /usr/lib/os-session-select"
|
echo " - /usr/lib/os-session-select"
|
||||||
echo " - /usr/local/bin/switch-to-gaming"
|
echo " - /usr/local/bin/switch-to-gaming"
|
||||||
echo " - /usr/local/bin/switch-to-desktop"
|
echo " - /usr/local/bin/switch-to-desktop"
|
||||||
|
echo " - /usr/local/bin/deckshift-session-switch"
|
||||||
|
echo " - /usr/local/bin/deckshift-session-transition"
|
||||||
|
echo " - /etc/deckshift/session-backend.conf (${session_backend})"
|
||||||
echo " - /usr/local/bin/gaming-keybind-monitor (Super+Shift+R)"
|
echo " - /usr/local/bin/gaming-keybind-monitor (Super+Shift+R)"
|
||||||
echo " - ~/.config/hypr/bindings.conf (keybind added)"
|
echo " - ~/.config/hypr/bindings.conf (keybind added)"
|
||||||
echo ""
|
echo ""
|
||||||
@@ -2910,10 +3109,14 @@ verify_installation() {
|
|||||||
local all_ok=true
|
local all_ok=true
|
||||||
local missing_files=()
|
local missing_files=()
|
||||||
local permission_issues=()
|
local permission_issues=()
|
||||||
|
local verify_session_backend
|
||||||
|
verify_session_backend=$(read_installed_session_backend)
|
||||||
|
|
||||||
declare -A expected_files=(
|
declare -A expected_files=(
|
||||||
["/usr/local/bin/gamescope-session-nm-wrapper"]="755:ChimeraOS session with NM wrapper"
|
["/usr/local/bin/gamescope-session-nm-wrapper"]="755:ChimeraOS session with NM wrapper"
|
||||||
["/usr/local/lib/gamescope-nvidia/gamescope"]="755:NVIDIA gamescope wrapper (--force-composition)"
|
["/usr/local/lib/gamescope-nvidia/gamescope"]="755:NVIDIA gamescope wrapper (--force-composition)"
|
||||||
|
["/usr/local/bin/deckshift-session-switch"]="755:Backend-neutral session selector"
|
||||||
|
["/usr/local/bin/deckshift-session-transition"]="755:Backend-neutral display-manager transition helper"
|
||||||
["/usr/local/bin/gaming-session-switch"]="755:Session switching helper (gaming/desktop)"
|
["/usr/local/bin/gaming-session-switch"]="755:Session switching helper (gaming/desktop)"
|
||||||
["/usr/lib/os-session-select"]="755:Steam Exit to Desktop handler"
|
["/usr/lib/os-session-select"]="755:Steam Exit to Desktop handler"
|
||||||
["/usr/local/bin/switch-to-gaming"]="755:Hyprland to Gaming Mode switcher"
|
["/usr/local/bin/switch-to-gaming"]="755:Hyprland to Gaming Mode switcher"
|
||||||
@@ -2927,8 +3130,9 @@ verify_installation() {
|
|||||||
["/usr/bin/steamos-update"]="755:Steam compatibility (from AUR package)"
|
["/usr/bin/steamos-update"]="755:Steam compatibility (from AUR package)"
|
||||||
["/usr/bin/jupiter-biosupdate"]="755:Steam compatibility (from AUR package)"
|
["/usr/bin/jupiter-biosupdate"]="755:Steam compatibility (from AUR package)"
|
||||||
["/usr/bin/steamos-select-branch"]="755:Steam compatibility (from AUR package)"
|
["/usr/bin/steamos-select-branch"]="755:Steam compatibility (from AUR package)"
|
||||||
["/usr/share/wayland-sessions/gamescope-session-steam-nm.desktop"]="644:SDDM session entry"
|
["/usr/share/wayland-sessions/gamescope-session-steam-nm.desktop"]="644:Gaming Mode Wayland session entry"
|
||||||
["/usr/share/gamescope-session-plus/gamescope-session-plus"]="755:ChimeraOS session launcher (from AUR)"
|
["/usr/share/gamescope-session-plus/gamescope-session-plus"]="755:ChimeraOS session launcher (from AUR)"
|
||||||
|
["/etc/deckshift/session-backend.conf"]="644:Session backend config"
|
||||||
["/etc/sddm.conf.d/zz-gaming-session.conf"]="644:SDDM session switching config"
|
["/etc/sddm.conf.d/zz-gaming-session.conf"]="644:SDDM session switching config"
|
||||||
["/etc/polkit-1/rules.d/50-gamescope-networkmanager.rules"]="644:Polkit NM rules"
|
["/etc/polkit-1/rules.d/50-gamescope-networkmanager.rules"]="644:Polkit NM rules"
|
||||||
["/etc/polkit-1/rules.d/50-udisks-gaming.rules"]="644:Polkit udisks2 rules (external drive mount)"
|
["/etc/polkit-1/rules.d/50-udisks-gaming.rules"]="644:Polkit udisks2 rules (external drive mount)"
|
||||||
@@ -2953,7 +3157,16 @@ verify_installation() {
|
|||||||
local description="${expected_files[$file]#*:}"
|
local description="${expected_files[$file]#*:}"
|
||||||
local is_optional=false
|
local is_optional=false
|
||||||
|
|
||||||
[[ "$description" == *"(optional)"* ]] && is_optional=true
|
case "$file" in
|
||||||
|
/etc/sddm.conf.d/zz-gaming-session.conf)
|
||||||
|
[[ "$verify_session_backend" == "dms-greeter-manual" ]] && is_optional=true
|
||||||
|
;;
|
||||||
|
/etc/NetworkManager/conf.d/10-iwd-backend.conf|\
|
||||||
|
/etc/NetworkManager/conf.d/20-unmanaged-systemd.conf|\
|
||||||
|
/usr/share/libalpm/hooks/deckshift-gamescope-cap.hook)
|
||||||
|
is_optional=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
if sudo test -f "$file" 2>/dev/null; then
|
if sudo test -f "$file" 2>/dev/null; then
|
||||||
local actual_perm
|
local actual_perm
|
||||||
@@ -3112,6 +3325,48 @@ verify_installation() {
|
|||||||
echo " systemd-networkd: $(systemctl is-active systemd-networkd.service 2>/dev/null || echo 'inactive')"
|
echo " systemd-networkd: $(systemctl is-active systemd-networkd.service 2>/dev/null || echo 'inactive')"
|
||||||
echo " polkit: $(systemctl is-active polkit.service 2>/dev/null || echo 'inactive')"
|
echo " polkit: $(systemctl is-active polkit.service 2>/dev/null || echo 'inactive')"
|
||||||
|
|
||||||
|
if [[ "$verify_session_backend" == "dms-greeter-manual" ]]; then
|
||||||
|
echo ""
|
||||||
|
echo " DMS GREETER BACKEND:"
|
||||||
|
echo " --------------------"
|
||||||
|
local dms_memory_file="/var/cache/dms-greeter/.local/state/memory.json"
|
||||||
|
if [[ -r /etc/deckshift/session-backend.conf ]]; then
|
||||||
|
local configured_memory_file
|
||||||
|
configured_memory_file=$(sed -n 's/^DECKSHIFT_DMS_MEMORY_FILE=//p' /etc/deckshift/session-backend.conf 2>/dev/null | head -1)
|
||||||
|
[[ -n "$configured_memory_file" ]] && dms_memory_file="$configured_memory_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo " Backend: $verify_session_backend"
|
||||||
|
echo " Memory file: $dms_memory_file"
|
||||||
|
if [[ -r "$dms_memory_file" ]]; then
|
||||||
|
local memory_stat
|
||||||
|
memory_stat=$(stat -c "%U:%G %a" "$dms_memory_file" 2>/dev/null || echo "unknown")
|
||||||
|
echo " ✓ DMS memory readable ($memory_stat)"
|
||||||
|
if python3 - "$dms_memory_file" <<'PY'
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
with open(sys.argv[1]) as fh:
|
||||||
|
data = json.load(fh)
|
||||||
|
if not isinstance(data, dict):
|
||||||
|
raise SystemExit(1)
|
||||||
|
for key in ("lastSessionId", "lastSessionDesktopId"):
|
||||||
|
value = data.get(key)
|
||||||
|
if not isinstance(value, str) or not value:
|
||||||
|
raise SystemExit(1)
|
||||||
|
PY
|
||||||
|
then
|
||||||
|
echo " ✓ DMS memory has lastSessionId and lastSessionDesktopId"
|
||||||
|
else
|
||||||
|
echo " ✗ DMS memory JSON is missing expected session keys"
|
||||||
|
all_ok=false
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " ✗ DMS memory file is not readable"
|
||||||
|
all_ok=false
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo " SUDO PERMISSIONS TEST:"
|
echo " SUDO PERMISSIONS TEST:"
|
||||||
echo " ----------------------"
|
echo " ----------------------"
|
||||||
|
|||||||
@@ -0,0 +1,423 @@
|
|||||||
|
# DeckShift Session Backend Handoff
|
||||||
|
|
||||||
|
Last updated: 2026-07-11.
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Extend DeckShift so its Steam Deck-style gaming mode is not hard-wired to SDDM.
|
||||||
|
The first target is to preserve the existing SDDM behavior for upstream/Omarchy
|
||||||
|
users while adding a DMS/greetd manual backend for our Hyprland/DMS dotfiles.
|
||||||
|
|
||||||
|
The long-term goal is:
|
||||||
|
|
||||||
|
- `sddm`: existing seamless auto-login flow for Omarchy users.
|
||||||
|
- `dms-greeter-manual`: select the next session through DMS greeter memory and
|
||||||
|
require normal greeter authentication.
|
||||||
|
- Later: a host-gated one-shot auto-login backend for living-room machines, if
|
||||||
|
it can be made safe and recoverable.
|
||||||
|
|
||||||
|
## Repository State
|
||||||
|
|
||||||
|
Local checkout:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/home/anodyine/Projects/deckshift
|
||||||
|
```
|
||||||
|
|
||||||
|
Current work branch:
|
||||||
|
|
||||||
|
```text
|
||||||
|
feature/session-backends
|
||||||
|
```
|
||||||
|
|
||||||
|
Remotes:
|
||||||
|
|
||||||
|
```text
|
||||||
|
origin ssh://git@tea.kyle-merritt.com:2222/anodyine/deckshift.git
|
||||||
|
github https://github.com/Anodyine/deckshift.git
|
||||||
|
upstream https://github.com/28allday/deckshift.git
|
||||||
|
```
|
||||||
|
|
||||||
|
`origin` is the Gitea working remote. `github` is the public fork. `upstream`
|
||||||
|
is fetch-only for the original DeckShift project.
|
||||||
|
|
||||||
|
## What Changed So Far
|
||||||
|
|
||||||
|
All code changes so far are in:
|
||||||
|
|
||||||
|
```text
|
||||||
|
deckshift.sh
|
||||||
|
README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
### Installer Configuration
|
||||||
|
|
||||||
|
`deckshift.sh` now accepts these variables:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
DECKSHIFT_SESSION_BACKEND=auto
|
||||||
|
DECKSHIFT_DESKTOP_SESSION_ID=hyprland-uwsm.desktop
|
||||||
|
DECKSHIFT_GAMING_SESSION_ID=gamescope-session-steam-nm.desktop
|
||||||
|
```
|
||||||
|
|
||||||
|
Supported backend values right now:
|
||||||
|
|
||||||
|
```text
|
||||||
|
auto
|
||||||
|
sddm
|
||||||
|
dms-greeter-manual
|
||||||
|
```
|
||||||
|
|
||||||
|
`auto` detects DMS/greetd when:
|
||||||
|
|
||||||
|
- `/etc/systemd/system/display-manager.service` resolves to `greetd.service`.
|
||||||
|
- `/etc/greetd/config.toml` contains `dms-greeter`.
|
||||||
|
|
||||||
|
Otherwise it falls back to `sddm`.
|
||||||
|
|
||||||
|
### Generated Backend Config
|
||||||
|
|
||||||
|
The installer writes:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/etc/deckshift/session-backend.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
It records the active backend, desktop/gaming session IDs, the Gamescope session
|
||||||
|
file path, SDDM config path, and DMS greeter memory path.
|
||||||
|
|
||||||
|
### Generated Helpers
|
||||||
|
|
||||||
|
The old SDDM-specific calls are now routed through backend-neutral helpers:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/usr/local/bin/deckshift-session-switch
|
||||||
|
/usr/local/bin/deckshift-session-transition
|
||||||
|
```
|
||||||
|
|
||||||
|
`/usr/local/bin/gaming-session-switch` is still generated as a compatibility
|
||||||
|
wrapper that execs `deckshift-session-switch`.
|
||||||
|
|
||||||
|
Existing generated scripts now call the backend-neutral helpers:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/usr/lib/os-session-select
|
||||||
|
/usr/local/bin/switch-to-gaming
|
||||||
|
/usr/local/bin/switch-to-desktop
|
||||||
|
```
|
||||||
|
|
||||||
|
### SDDM Backend Behavior
|
||||||
|
|
||||||
|
The SDDM backend preserves the previous model:
|
||||||
|
|
||||||
|
1. Write or update `/etc/sddm.conf.d/zz-gaming-session.conf`.
|
||||||
|
2. `deckshift-session-switch gaming|desktop` changes `Session=...`.
|
||||||
|
3. `deckshift-session-transition` runs `sudo -n systemctl restart sddm`.
|
||||||
|
|
||||||
|
This should be behaviorally equivalent to the original DeckShift flow.
|
||||||
|
|
||||||
|
### DMS Manual Backend Behavior
|
||||||
|
|
||||||
|
The DMS manual backend does not create SDDM config.
|
||||||
|
|
||||||
|
`deckshift-session-switch gaming|desktop`:
|
||||||
|
|
||||||
|
1. Resolves the target session file from an allowlist:
|
||||||
|
- desktop: `DECKSHIFT_DESKTOP_SESSION_ID`
|
||||||
|
- gaming: `DECKSHIFT_GAMING_SESSION_ID`
|
||||||
|
2. Looks in:
|
||||||
|
- `/usr/local/share/wayland-sessions`
|
||||||
|
- `/usr/share/wayland-sessions`
|
||||||
|
3. Writes DMS greeter memory:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/var/cache/dms-greeter/.local/state/memory.json
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Preserves any existing JSON keys and updates:
|
||||||
|
- `lastSessionId`
|
||||||
|
- `lastSessionDesktopId`
|
||||||
|
|
||||||
|
`deckshift-session-transition`:
|
||||||
|
|
||||||
|
1. If `XDG_SESSION_ID` exists, runs:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
loginctl terminate-session "$XDG_SESSION_ID"
|
||||||
|
```
|
||||||
|
|
||||||
|
2. If there is no current session ID, falls back to:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo -n systemctl restart greetd.service
|
||||||
|
```
|
||||||
|
|
||||||
|
This intentionally returns the user to the DMS greeter for normal
|
||||||
|
authentication. It is not a one-shot auto-login implementation.
|
||||||
|
|
||||||
|
### Sudoers
|
||||||
|
|
||||||
|
The generated sudoers file now includes NOPASSWD entries for:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/usr/local/bin/deckshift-session-switch
|
||||||
|
/usr/local/bin/deckshift-session-transition
|
||||||
|
/usr/bin/systemctl restart sddm
|
||||||
|
/usr/bin/systemctl restart greetd.service
|
||||||
|
```
|
||||||
|
|
||||||
|
The existing compatibility and NetworkManager/Bluetooth rules remain.
|
||||||
|
|
||||||
|
### README
|
||||||
|
|
||||||
|
The README now documents:
|
||||||
|
|
||||||
|
- The experimental DMS/greetd manual backend.
|
||||||
|
- The new backend config and helper files.
|
||||||
|
- The backend-neutral session switching flow.
|
||||||
|
- Updated uninstall cleanup for `/etc/deckshift` and the new helper scripts.
|
||||||
|
|
||||||
|
## Validation Already Run
|
||||||
|
|
||||||
|
These checks passed:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bash -n deckshift.sh
|
||||||
|
git diff --check
|
||||||
|
```
|
||||||
|
|
||||||
|
The generated heredoc scripts were also extracted and syntax-checked with
|
||||||
|
`bash -n`:
|
||||||
|
|
||||||
|
- `deckshift-session-switch`
|
||||||
|
- `deckshift-session-transition`
|
||||||
|
- `switch-to-gaming`
|
||||||
|
- `switch-to-desktop`
|
||||||
|
- `os-session-select`
|
||||||
|
- `gaming-session-switch` compatibility wrapper
|
||||||
|
|
||||||
|
`shellcheck` was not installed on this machine, so it has not been run yet.
|
||||||
|
|
||||||
|
No installer run has been performed. No live `/etc`, `/usr/local/bin`, greeter,
|
||||||
|
or display-manager state was changed by this work.
|
||||||
|
|
||||||
|
### DMS Greeter Selection Probe
|
||||||
|
|
||||||
|
After the first code pass, a manual DMS greeter selection test was run outside
|
||||||
|
this checkout. The greeter selected the expected `Deckshift dms test` session.
|
||||||
|
|
||||||
|
That confirms the core DMS manual backend assumption still holds: writing DMS
|
||||||
|
greeter memory can preselect a non-SDDM session for the next login. This does
|
||||||
|
not yet prove the full DeckShift-generated helper flow or Gamescope session
|
||||||
|
entry, but it is the right green light for implementing and testing the manual
|
||||||
|
DMS backend path before any auto-login work.
|
||||||
|
|
||||||
|
### DMS Generated Helper Probe
|
||||||
|
|
||||||
|
The generated helper path was then tested manually:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo -n /usr/local/bin/deckshift-session-switch gaming
|
||||||
|
/usr/local/bin/deckshift-session-transition gaming
|
||||||
|
```
|
||||||
|
|
||||||
|
It behaved as expected: the current session exited, DMS greeter appeared, and
|
||||||
|
the target gaming session was preselected.
|
||||||
|
|
||||||
|
This proves the first real DMS manual backend flow at the DeckShift helper
|
||||||
|
layer. Remaining DMS validation should focus on the full `switch-to-gaming`
|
||||||
|
script, Gamescope/Steam session startup, and the return path back to the
|
||||||
|
Hyprland UWSM desktop session.
|
||||||
|
|
||||||
|
### DMS Manual Round Trip
|
||||||
|
|
||||||
|
The DMS manual backend was also tested in both directions. It successfully
|
||||||
|
switched the greeter selection away from Hyprland UWSM and then back to the
|
||||||
|
Hyprland UWSM session. The user was able to log back into the UWSM desktop.
|
||||||
|
|
||||||
|
This proves the non-SDDM manual session-selection loop:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Hyprland UWSM -> selected gaming/test session -> DMS greeter
|
||||||
|
DMS greeter/session -> selected Hyprland UWSM -> DMS greeter -> Hyprland UWSM
|
||||||
|
```
|
||||||
|
|
||||||
|
The next layer to test is no longer DMS memory/session preselection. It is the
|
||||||
|
real DeckShift gaming session: `switch-to-gaming`, Gamescope/Steam startup, and
|
||||||
|
`switch-to-desktop` return behavior.
|
||||||
|
|
||||||
|
## Important Constraints
|
||||||
|
|
||||||
|
Do not implement one-shot DMS auto-login yet. Manual DMS switching is the first
|
||||||
|
safe milestone.
|
||||||
|
|
||||||
|
Do not make this dotfiles-specific inside DeckShift. The DeckShift fork should
|
||||||
|
grow generic backend seams; the dotfiles repo can decide whether and how to
|
||||||
|
install/use the DMS backend.
|
||||||
|
|
||||||
|
Keep the SDDM behavior stable for existing users. The backend abstraction should
|
||||||
|
be boring and low-risk for the default Omarchy path.
|
||||||
|
|
||||||
|
## Known Gaps And Risks
|
||||||
|
|
||||||
|
### Not Tested Live
|
||||||
|
|
||||||
|
The backend helpers have only been syntax-checked. They still need live testing
|
||||||
|
on:
|
||||||
|
|
||||||
|
- An SDDM/Omarchy machine or VM.
|
||||||
|
- A DMS/greetd machine or VM.
|
||||||
|
- A real target host with Gamescope/Steam.
|
||||||
|
|
||||||
|
### DMS Memory Contract
|
||||||
|
|
||||||
|
The DMS greeter memory write is based on a local proof from the dotfiles repo:
|
||||||
|
writing `lastSessionId` and `lastSessionDesktopId` successfully preselected a
|
||||||
|
test session in DMS greeter.
|
||||||
|
|
||||||
|
Still verify:
|
||||||
|
|
||||||
|
- Ownership and permissions after DeckShift writes the file.
|
||||||
|
- Whether DMS ever overwrites the file during greeter startup.
|
||||||
|
- Whether preserving extra JSON keys is sufficient across DMS versions.
|
||||||
|
|
||||||
|
### Transition Semantics
|
||||||
|
|
||||||
|
For DMS manual mode, `loginctl terminate-session "$XDG_SESSION_ID"` is preferred.
|
||||||
|
The fallback `systemctl restart greetd.service` is more disruptive and should be
|
||||||
|
treated as a fallback only.
|
||||||
|
|
||||||
|
Verify whether `switch-to-desktop` from inside Gamescope has a valid
|
||||||
|
`XDG_SESSION_ID`. If not, returning from gaming may restart greetd.
|
||||||
|
|
||||||
|
### Session File Location
|
||||||
|
|
||||||
|
The installer currently writes the gaming session to:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/usr/share/wayland-sessions/gamescope-session-steam-nm.desktop
|
||||||
|
```
|
||||||
|
|
||||||
|
For our dotfiles, `/usr/local/share/wayland-sessions` may be a better long-term
|
||||||
|
owner boundary. Decide whether DeckShift should make this configurable or leave
|
||||||
|
the current upstream-compatible path alone.
|
||||||
|
|
||||||
|
### Verification Mode
|
||||||
|
|
||||||
|
`verify_installation` still treats `/etc/sddm.conf.d/zz-gaming-session.conf` as
|
||||||
|
optional by description only. The verification logic marks missing optional
|
||||||
|
files by checking whether the description contains `(optional)`, so this may
|
||||||
|
need adjustment if verifying a DMS backend install.
|
||||||
|
|
||||||
|
### Documentation Still Has Historical SDDM Mentions
|
||||||
|
|
||||||
|
Some README changelog and troubleshooting sections still mention SDDM because
|
||||||
|
they describe older releases or SDDM-specific recovery. That is probably fine,
|
||||||
|
but before publishing this branch upstream, review the README for places where
|
||||||
|
current behavior should say "session backend" instead.
|
||||||
|
|
||||||
|
## Recommended Next Steps
|
||||||
|
|
||||||
|
1. Install `shellcheck` on the dev machine or run it in a container/VM:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
shellcheck deckshift.sh
|
||||||
|
shellcheck bin/deckshift-settings
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Test SDDM backend generation without changing behavior:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
DECKSHIFT_SESSION_BACKEND=sddm ./deckshift.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify:
|
||||||
|
|
||||||
|
- `/etc/deckshift/session-backend.conf`
|
||||||
|
- `/etc/sddm.conf.d/zz-gaming-session.conf`
|
||||||
|
- `/usr/local/bin/deckshift-session-switch`
|
||||||
|
- `/usr/local/bin/deckshift-session-transition`
|
||||||
|
- Existing Super+Shift+S / Super+Shift+R behavior.
|
||||||
|
|
||||||
|
3. Test DMS backend in the CachyOS/DMS VM or sacrificial host:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
DECKSHIFT_SESSION_BACKEND=dms-greeter-manual ./deckshift.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify before switching:
|
||||||
|
|
||||||
|
- Gaming session appears in the DMS greeter session list.
|
||||||
|
- `deckshift-session-switch gaming` writes the expected DMS memory.
|
||||||
|
- `deckshift-session-switch desktop` restores the Hyprland UWSM session.
|
||||||
|
- File ownership/group/mode allow DMS greeter to read the memory file.
|
||||||
|
|
||||||
|
4. Test DMS manual transition without Steam first:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo -n /usr/local/bin/deckshift-session-switch gaming
|
||||||
|
/usr/local/bin/deckshift-session-transition gaming
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected result:
|
||||||
|
|
||||||
|
- Current session exits.
|
||||||
|
- DMS greeter appears.
|
||||||
|
- Gaming session is preselected.
|
||||||
|
- User must authenticate manually.
|
||||||
|
|
||||||
|
5. Test return path:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo -n /usr/local/bin/deckshift-session-switch desktop
|
||||||
|
/usr/local/bin/deckshift-session-transition desktop
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected result:
|
||||||
|
|
||||||
|
- Current session exits.
|
||||||
|
- DMS greeter appears.
|
||||||
|
- Hyprland UWSM is preselected.
|
||||||
|
|
||||||
|
6. Only after manual DMS mode works, test full Gamescope/Steam entry and return.
|
||||||
|
|
||||||
|
7. After both SDDM and DMS manual mode are proven, split large generated helper
|
||||||
|
bodies into clearer functions or files if desired. Avoid refactoring before
|
||||||
|
the behavior is proven.
|
||||||
|
|
||||||
|
8. Add Gitea issues for follow-up work:
|
||||||
|
|
||||||
|
- Prove SDDM backend parity.
|
||||||
|
- Prove DMS manual backend in VM.
|
||||||
|
- Fix verification mode for backend-specific expected files.
|
||||||
|
- Decide session file owner path.
|
||||||
|
- Prototype one-shot DMS/greetd auto-login separately.
|
||||||
|
|
||||||
|
## Recovery Notes For DMS Testing
|
||||||
|
|
||||||
|
If a DMS switch leaves the host at the wrong selected session, switch to a TTY
|
||||||
|
and write DMS memory back to Hyprland UWSM:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo python3 - <<'PY'
|
||||||
|
import json
|
||||||
|
path = "/var/cache/dms-greeter/.local/state/memory.json"
|
||||||
|
data = {}
|
||||||
|
try:
|
||||||
|
with open(path) as fh:
|
||||||
|
data = json.load(fh)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
data["lastSessionId"] = "/usr/local/share/wayland-sessions/hyprland-uwsm.desktop"
|
||||||
|
data["lastSessionDesktopId"] = "hyprland-uwsm.desktop"
|
||||||
|
with open(path, "w") as fh:
|
||||||
|
json.dump(data, fh, indent=2)
|
||||||
|
fh.write("\n")
|
||||||
|
PY
|
||||||
|
sudo chgrp greeter /var/cache/dms-greeter/.local/state /var/cache/dms-greeter/.local/state/memory.json 2>/dev/null || true
|
||||||
|
sudo chmod 0664 /var/cache/dms-greeter/.local/state/memory.json
|
||||||
|
sudo systemctl restart greetd.service
|
||||||
|
```
|
||||||
|
|
||||||
|
Do not rely on `chezmoi apply` as the only recovery path. The failure mode may
|
||||||
|
be that the graphical desktop is unavailable.
|
||||||
Reference in New Issue
Block a user