v0.1.12 — Patch gamescope-session-plus so refresh-rate selection actually reaches gamescope
The real bug behind every "60 Hz stuck in Gaming Mode" report:
- DeckShift installs `gamescope` from Arch's `extra` repo (upstream
Valve binary). That binary does NOT have `--custom-refresh-rates`.
The flag is a ChimeraOS-fork (`gamescope-plus`) addition that
never landed upstream, and the fork is not packaged in AUR for
64-bit Arch.
- The AUR `gamescope-session-git` script (OpenGamingCollective,
ex-ChimeraOS) was written assuming gamescope-plus. It feature-
detects via `gamescope_has_option "--custom-refresh-rates"` and
silently drops the value when missing.
- Net effect: CUSTOM_REFRESH_RATES from the env conf reaches the
session script but never reaches the gamescope binary. Every
refresh-rate selection in the DeckShift TUI since the project
began has been a paper fix; gamescope just launched at the
EDID-preferred mode (usually 60 Hz).
- v0.1.8's comma-list "fix" was correct on paper but the value
never reached the binary, so it didn't actually do anything on
Omarchy. The Framework Desktop user wasn't reporting a hardware-
specific bug — they were the first user to notice a bug that
affected everyone, because their 170 Hz monitor made the regression
obvious. On a 165 Hz Acer Nitro you'd just never notice 60 vs 165
in Steam BPM.
Fix: ./deckshift.sh now patches the installed gamescope-session-plus
in place, adding an elif fallback that uses `--nested-refresh` (a flag
present in every gamescope version) with the highest value from the
CUSTOM_REFRESH_RATES list as the launch rate. Marked with a
DECKSHIFT-NESTED-REFRESH-FALLBACK sentinel comment for idempotency,
re-applied on every install so AUR upgrades that clobber the file
don't silently regress refresh-rate handling.
Implementation: new patch_gamescope_session_plus() function in
deckshift.sh, called from setup_session_switching() after the AUR
install completes. Uses Python regex with a function-based replacement
(re.sub with a string-form replacement was the first attempt and got
caught by Python's backslash processing turning `\n` in the `tr`
argument into a real newline — function callbacks bypass that, so the
literal `\n` reaches the shell as intended).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
52c883b780
commit
a3cb6f28e4
2 changed files with 101 additions and 1 deletions
|
|
@ -10,6 +10,12 @@ Lineage: forked from [Super-Shift-S-Omarchy-Deck-Mode](https://git.no-signal.uk/
|
|||
|
||||
## What's New
|
||||
|
||||
### v0.1.12 — Refresh-rate selection actually reaches gamescope now
|
||||
|
||||
- **The real bug:** Omarchy installs `gamescope` from Arch's `extra` repo (upstream Valve binary), but the AUR `gamescope-session-git` script (OpenGamingCollective / ex-ChimeraOS fork) was written assuming the ChimeraOS-fork `gamescope-plus` binary that ships `--custom-refresh-rates`. The fork isn't packaged for 64-bit Arch — we can't install it cleanly. The session script feature-detects via `gamescope_has_option "--custom-refresh-rates"`, finds it absent, and **silently drops the `CUSTOM_REFRESH_RATES` value before it reaches gamescope**. Net effect: every refresh-rate selection in the DeckShift TUI since the project began has been a no-op. Gaming Mode has been launching at the EDID-preferred mode (usually 60 Hz) regardless of what the user picked. v0.1.8's "60 Hz fix" was correct on paper but never actually reached the binary on Omarchy.
|
||||
- **The fix:** `./deckshift.sh` now patches `/usr/share/gamescope-session-plus/gamescope-session-plus` in place, adding an `elif` branch that falls back to `--nested-refresh` (a flag present in every gamescope version) with the highest value from the `CUSTOM_REFRESH_RATES` list as the launch rate. The patch is marked with a `DECKSHIFT-NESTED-REFRESH-FALLBACK` sentinel comment for idempotency, and is re-applied on every install so AUR upgrades that clobber the file don't silently regress refresh-rate handling.
|
||||
- **What you should do after upgrading:** re-run `./deckshift.sh` once. Future-you, if you ever see Gaming Mode stuck at 60 Hz after a `pacman -Syu` that touched `gamescope-session-git`, just re-run the installer — the patch reapplies cleanly.
|
||||
|
||||
### v0.1.11 — Multi-monitor handling: disable an auxiliary monitor before Gaming Mode
|
||||
|
||||
- New env var `OUTPUT_CONNECTOR_TO_DISABLE` (single connector or comma list). When set, `switch-to-gaming` runs `hyprctl keyword monitor <conn>,disable` for each listed connector *before* SDDM restart, while Hyprland is still alive. The disable is runtime-only — when the user returns from Gaming Mode, the new Hyprland reads its static config fresh and the monitor comes back automatically.
|
||||
|
|
|
|||
96
deckshift.sh
96
deckshift.sh
|
|
@ -34,7 +34,7 @@ set -Euo pipefail
|
|||
# -u: Treat unset variables as errors (catches typos in variable names)
|
||||
# -o pipefail: A pipeline fails if ANY command in it fails, not just the last one
|
||||
|
||||
DECKSHIFT_VERSION="0.1.11"
|
||||
DECKSHIFT_VERSION="0.1.12"
|
||||
|
||||
# Resolve the directory this script lives in so we can find sibling files like
|
||||
# bin/deckshift-settings and applications/deckshift-settings.desktop when
|
||||
|
|
@ -1302,6 +1302,95 @@ setup_settings_tui() {
|
|||
# It also installs ChimeraOS's gamescope-session packages from AUR, which
|
||||
# provide the base session framework that the Steam Deck uses.
|
||||
# ==============================================================================
|
||||
|
||||
# Patch the installed gamescope-session-plus script to add a --nested-refresh
|
||||
# fallback for CUSTOM_REFRESH_RATES.
|
||||
#
|
||||
# Why this exists:
|
||||
# - DeckShift installs `gamescope` from Arch's `extra` repo (upstream Valve
|
||||
# binary). That binary does NOT have `--custom-refresh-rates` — the flag is
|
||||
# a ChimeraOS-fork (gamescope-plus) addition that never landed upstream.
|
||||
# - The OpenGamingCollective (ex-ChimeraOS) `gamescope-session-plus` script
|
||||
# we install from AUR was written assuming gamescope-plus. It feature-
|
||||
# detects via `gamescope_has_option "--custom-refresh-rates"` and silently
|
||||
# drops the value when the flag is missing. Result: CUSTOM_REFRESH_RATES
|
||||
# reaches the script but never reaches gamescope, and Gaming Mode launches
|
||||
# at the EDID-preferred rate (usually 60 Hz) regardless of TUI selection.
|
||||
# - This patch adds an `elif` branch that falls back to `--nested-refresh`
|
||||
# (the older flag that exists in every gamescope version) with the highest
|
||||
# rate from the comma list as the launch rate.
|
||||
#
|
||||
# Idempotent: the patched line carries a `DECKSHIFT-NESTED-REFRESH-FALLBACK`
|
||||
# marker so re-runs detect "already patched" and skip. Re-applied on every
|
||||
# ./deckshift.sh run so pacman/AUR upgrades that clobber the script don't
|
||||
# silently regress refresh-rate handling.
|
||||
patch_gamescope_session_plus() {
|
||||
local gsp="/usr/share/gamescope-session-plus/gamescope-session-plus"
|
||||
if [[ ! -f "$gsp" ]]; then
|
||||
warn "$gsp not found — skipping refresh-rate fallback patch"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if grep -q "DECKSHIFT-NESTED-REFRESH-FALLBACK" "$gsp" 2>/dev/null; then
|
||||
info "gamescope-session-plus already has DeckShift refresh-rate fallback"
|
||||
return 0
|
||||
fi
|
||||
|
||||
info "Patching gamescope-session-plus to add --nested-refresh fallback..."
|
||||
|
||||
local tmp
|
||||
tmp=$(mktemp)
|
||||
if ! python3 - "$gsp" "$tmp" <<'PY'
|
||||
import re, sys
|
||||
src, dst = sys.argv[1], sys.argv[2]
|
||||
with open(src) as f:
|
||||
content = f.read()
|
||||
|
||||
# Match the 4-line block exactly as it ships in gamescope-session-git r339.
|
||||
# Group 1 = leading 3 lines (kept), group 2 = closing `fi` (kept). The new
|
||||
# elif+body lines are inserted between them.
|
||||
pattern = re.compile(
|
||||
r'(\tCUSTOM_REFRESH_RATES_OPTION=""\n'
|
||||
r'\tif \[ -n "\$CUSTOM_REFRESH_RATES" \] && gamescope_has_option "--custom-refresh-rates"; then\n'
|
||||
r'\t\tCUSTOM_REFRESH_RATES_OPTION="--custom-refresh-rates \$CUSTOM_REFRESH_RATES"\n'
|
||||
r')(\tfi\n)'
|
||||
)
|
||||
|
||||
# Use a function as the replacement so re.sub doesn't process backslash escapes
|
||||
# in our string — we need literal `\n` in the `tr "," "\n"` argument to reach
|
||||
# the shell, and a string-form replacement would turn it into a real newline.
|
||||
def _patch(m):
|
||||
return m.group(1) + (
|
||||
'\telif [ -n "$CUSTOM_REFRESH_RATES" ] && gamescope_has_option "--nested-refresh"; then # DECKSHIFT-NESTED-REFRESH-FALLBACK\n'
|
||||
'\t\t_deckshift_rate=$(echo "$CUSTOM_REFRESH_RATES" | tr "," "\\n" | sort -nr | head -1)\n'
|
||||
'\t\tCUSTOM_REFRESH_RATES_OPTION="--nested-refresh $_deckshift_rate"\n'
|
||||
) + m.group(2)
|
||||
|
||||
new = pattern.sub(_patch, content, count=1)
|
||||
if new == content:
|
||||
sys.stderr.write("could not locate CUSTOM_REFRESH_RATES_OPTION block in expected shape\n")
|
||||
sys.exit(1)
|
||||
with open(dst, "w") as f:
|
||||
f.write(new)
|
||||
PY
|
||||
then
|
||||
warn "Could not patch $gsp — upstream may have changed shape"
|
||||
warn "Refresh-rate selection in the TUI will continue to be a no-op until this is resolved"
|
||||
rm -f "$tmp"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! grep -q "DECKSHIFT-NESTED-REFRESH-FALLBACK" "$tmp"; then
|
||||
warn "Patch produced output but marker is missing — aborting install"
|
||||
rm -f "$tmp"
|
||||
return 1
|
||||
fi
|
||||
|
||||
sudo install -m 0755 "$tmp" "$gsp"
|
||||
rm -f "$tmp"
|
||||
info "Patched $gsp — CUSTOM_REFRESH_RATES now reaches gamescope via --nested-refresh"
|
||||
}
|
||||
|
||||
setup_session_switching() {
|
||||
echo ""
|
||||
echo "================================================================"
|
||||
|
|
@ -1526,6 +1615,11 @@ setup_session_switching() {
|
|||
info "ChimeraOS gamescope-session packages already installed (correct -git versions)"
|
||||
fi
|
||||
|
||||
# Patch the installed gamescope-session-plus to add --nested-refresh
|
||||
# fallback. Runs on every install so AUR upgrades that overwrite the file
|
||||
# get re-patched the next time the user re-runs ./deckshift.sh.
|
||||
patch_gamescope_session_plus
|
||||
|
||||
# NetworkManager Integration
|
||||
#
|
||||
# Omarchy uses iwd (Intel Wireless Daemon) for WiFi, but Steam requires
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue