feat: turn Deck mode on for new installs and add a performance overlay toggle (#101)

* feat: turn Deck mode on for new installs and add a performance overlay toggle

* feat: hide the session fps HUD where Deck mode's performance overlay runs
This commit is contained in:
Kurt Himebauch authored and GitHub committed 2026-09-30 13:06:12 -04:00
1 parent 11a8221623
commit a81363d743
5 files changed
+50 -4

No files matched your search

@@ -12,6 +12,8 @@ class App : Application() {
override fun onCreate() {
super.onCreate()
CrashHandler.install(this)
// Before anything else touches the session prefs: a new install's first read decides it.
com.droiddeck.launcher.session.SessionPrefs.settleDeckModeDefault(this)
BwrapSpawner.start(this)
}
}
@@ -105,6 +105,7 @@ class MainActivity : ComponentActivity() {
private var glThread by mutableStateOf(true)
private var noGlError by mutableStateOf(true)
private var steamDeckMode by mutableStateOf(false)
private var mangoapp by mutableStateOf(true)
private var steamController by mutableStateOf(SessionPrefs.CONTROLLER_DECK)
private var showProtons by mutableStateOf(false)
// Components page: FEX / DXVK / VKD3D-Proton per Proton (ComponentsManager).
@@ -899,6 +900,7 @@ class MainActivity : ComponentActivity() {
fexPreset = if (mode == SessionService.MODE_STEAM) fexPreset else null,
steamChannel = if (mode == SessionService.MODE_STEAM) steamChannel else null,
steamDeckMode = mode == SessionService.MODE_STEAM && steamDeckMode,
mangoapp = mangoapp,
steamController = if (mode == SessionService.MODE_STEAM) steamController else null,
runSteamAtStartup = mode == SessionService.MODE_STEAM && runSteamAtStartup,
addedGamesDirs = if (mode == SessionService.MODE_STEAM) addedGamesDirs else null,
@@ -956,6 +958,7 @@ class MainActivity : ComponentActivity() {
steamDeckMode = on
steamChannel = SessionPrefs.steamChannel(this)
},
onMangoapp = { on -> SessionPrefs.setMangoapp(this, on); mangoapp = on },
onSteamController = { id -> SessionPrefs.setSteamController(this, id); steamController = id },
onRunSteamAtStartup = { on ->
SessionPrefs.setRunSteamAtStartup(this, on)
@@ -1042,6 +1045,7 @@ class MainActivity : ComponentActivity() {
fexPreset = SessionPrefs.fexPreset(this)
steamChannel = SessionPrefs.steamChannel(this)
steamDeckMode = SessionPrefs.steamDeckMode(this)
mangoapp = SessionPrefs.mangoapp(this)
steamController = SessionPrefs.steamController(this)
runSteamAtStartup = SessionPrefs.runSteamAtStartup(this)
addedGamesDirs = SessionPrefs.addedGamesDirs(this)
@@ -44,12 +44,23 @@ object SessionPrefs {
prefs(context).edit().putBoolean("appImagesEnabled", on).apply()
}
fun hudEnabled(context: Context): Boolean = prefs(context).getBoolean("hud", true)
/**
* The session's performance HUD (the fps box). A Deck-mode Steam session with the performance
* overlay has Steam's own (mangoapp, from the QAM), so there the HUD is off unless turned on
* in one - a choice kept apart from every other session's, where it stays on by default.
*/
fun hudEnabled(context: Context): Boolean = prefs(context).getBoolean(hudKey(context), !mangoappSession(context))
fun setHudEnabled(context: Context, on: Boolean) {
prefs(context).edit().putBoolean("hud", on).apply()
prefs(context).edit().putBoolean(hudKey(context), on).apply()
}
private fun hudKey(context: Context) = if (mangoappSession(context)) "hudDeck" else "hud"
/** A Steam session that runs Deck mode with its performance overlay (mangoapp). */
private fun mangoappSession(context: Context) =
SessionState.mode == SessionService.MODE_STEAM && steamDeckMode(context) && mangoapp(context)
/** When enabled, a single Back opens Steam QAM and a double Back opens the session menu. */
fun backActionsInverted(context: Context): Boolean = prefs(context).getBoolean("backActionsInverted", false)
@@ -292,10 +303,30 @@ object SessionPrefs {
prefs(context).getString("steamController", CONTROLLER_DECK) ?: CONTROLLER_DECK
fun setSteamController(context: Context, id: String) { prefs(context).edit().putString("steamController", id).apply() }
/** Runs the SteamOS gamepad client with its Quick Access performance controls. */
fun steamDeckMode(context: Context): Boolean = prefs(context).getBoolean("steamDeckMode", false)
/** Runs the SteamOS gamepad client with its Quick Access performance controls. On for new installs (settleDeckModeDefault). */
fun steamDeckMode(context: Context): Boolean = prefs(context).getBoolean("steamDeckMode", true)
fun setSteamDeckMode(context: Context, on: Boolean) { prefs(context).edit().putBoolean("steamDeckMode", on).apply() }
/**
* Deck mode became the default for new installs; an install from before keeps what it ran with
* (off), so an update never changes its interface or restarts the client on its own. Run once at
* process start, before anything reads or writes these prefs: a new install has neither prefs
* nor a runtime yet. The answer is written down, so it is decided once.
*/
fun settleDeckModeDefault(context: Context) {
val p = prefs(context)
if (p.contains("steamDeckMode")) return
val existing = p.all.isNotEmpty() || java.io.File(context.filesDir, "linuxfs").exists()
p.edit().putBoolean("steamDeckMode", !existing).apply()
}
/**
* Deck mode's performance overlay (mangoapp, beside gamescope): the QAM's Overlay Level draws
* through it. Off is the way out where Valve's mangoapp crashes (one Turnip build did).
*/
fun mangoapp(context: Context): Boolean = prefs(context).getBoolean("mangoapp", true)
fun setMangoapp(context: Context, on: Boolean) { prefs(context).edit().putBoolean("mangoapp", on).apply() }
/**
* Zink's lazy descriptor mode (ZINK_DESCRIPTORS=lazy) with its compact set layout
* (ZINK_DEBUG=compact) for the client's GL-on-Vulkan UI, as WinNative runs it. On by default.
@@ -528,6 +528,7 @@ class SessionService : Service() {
if (SessionPrefs.glThread(this)) guest.add("mesa_glthread=true")
if (SessionPrefs.noGlError(this)) guest.add("MESA_NO_ERROR=1")
if (SessionState.mode == MODE_STEAM) guest.add("BL_STEAMDECK=" + (if (SessionPrefs.steamDeckMode(this)) "1" else "0"))
if (SessionState.mode == MODE_STEAM) guest.add("BL_MANGOAPP=" + (if (SessionPrefs.mangoapp(this)) "1" else "0"))
if (steamHere) guest.add("BL_STEAM_CHANNEL=" + SessionPrefs.steamChannel(this))
if (SessionState.mode == MODE_STEAM) {
guest.add("BL_GAMESCOPE_FORCE_FULLSCREEN=" + (if (SessionPrefs.forceFullscreen(this)) "1" else "0"))
@@ -70,6 +70,8 @@ class ModeSettings(
val steamChannel: String? = null,
/** Steam only: enable the SteamOS client interface and its performance controls. */
val steamDeckMode: Boolean = false,
/** Steam, Deck mode: the QAM's performance overlay (mangoapp) is started. */
val mangoapp: Boolean = true,
/** Steam only: what the pad is to the client (SessionPrefs.CONTROLLER_*); null outside Steam. */
val steamController: String? = null,
/** Steam only: start a Steam session when DroidDeck opens. */
@@ -128,6 +130,7 @@ class ModeSettingsActions(
val onForceFullscreen: (Boolean) -> Unit = {},
val onSteamChannel: (String) -> Unit = {},
val onSteamDeckMode: (Boolean) -> Unit = {},
val onMangoapp: (Boolean) -> Unit = {},
val onSteamController: (String) -> Unit = {},
val onRunSteamAtStartup: (Boolean) -> Unit = {},
val onPickAddedGamesDir: () -> Unit = {},
@@ -359,6 +362,11 @@ fun ModeSettingsPage(s: ModeSettings, a: ModeSettingsActions) {
"Enables Steam's Deck interface and Quick Access performance overlay controls. Applies next session.",
s.steamDeckMode, onChange = a.onSteamDeckMode,
)
if (s.steamDeckMode) ToggleRow(
host, "mangoapp", "Performance overlay",
"The Quick Access Menu's frame-rate and usage overlay. Turn off if games crash or go black with Deck mode on. Applies next session.",
s.mangoapp, onChange = a.onMangoapp,
)
// Deck mode fixes the branch (SessionPrefs.steamChannel); the choice is for Deck mode off.
if (s.steamDeckMode) SettingsRow("Client branch", "Steam Deck public beta: Deck mode needs it, so Steam doesn't keep offering an update") {}
else ChoiceRow(