diff --git a/.gitignore b/.gitignore index 52052d7600..5923b5be9d 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,10 @@ app/release/output-metadata.json local.properties app/src/main/assets/recommendations.json +# Locally built gamescope payloads: fetched at runtime unless one is present, +# and never committed — a payload is an artefact of the branch that built it. +app/src/main/assets/gamescope-gamenative-*.tzst + # Proguard folder generated by Eclipse proguard/ diff --git a/app/src/main/java/app/gamenative/display/GamescopePayload.kt b/app/src/main/java/app/gamenative/display/GamescopePayload.kt index 86db420b57..1bfc696088 100644 --- a/app/src/main/java/app/gamenative/display/GamescopePayload.kt +++ b/app/src/main/java/app/gamenative/display/GamescopePayload.kt @@ -11,7 +11,7 @@ import java.io.File /** Versioned gamescope payload (gamescope, XWayland, scaling clients), fetched on the first gamescope launch. */ object GamescopePayload { - const val VERSION = "20261023.4" + const val VERSION = "20261024.1" const val ARCHIVE = "gamescope-gamenative-$VERSION.tzst" private const val STAMP = ".payload.version" @@ -29,16 +29,39 @@ object GamescopePayload { val archive = File(filesDir, ARCHIVE) if (!archive.isFile || archive.length() == 0L) { archive.delete() - try { - SteamService.fetchFileWithFallback(ARCHIVE, archive, context, onProgress) - } catch (e: Exception) { - archive.delete() - throw e + // A payload shipped inside the APK wins over the download: it is the + // build that was exercised with this app, and it needs no network. + // Only when the asset is absent does the published archive get + // fetched. + if (copyFromAssets(context, archive)) { + onProgress(1.0f) + } else { + try { + SteamService.fetchFileWithFallback(ARCHIVE, archive, context, onProgress) + } catch (e: Exception) { + archive.delete() + throw e + } } } install(archive, filesDir) } + /** Whether this APK carries the payload, and if so, copy it out to [dest]. */ + private fun copyFromAssets(context: Context, dest: File): Boolean { + val assets = context.assets + val present = runCatching { assets.open(ARCHIVE).close() }.isSuccess + if (!present) return false + return runCatching { + assets.open(ARCHIVE).use { input -> dest.outputStream().use { output -> input.copyTo(output) } } + } + .onFailure { + Timber.w(it, "Failed to copy $ARCHIVE from assets") + dest.delete() + } + .isSuccess + } + @Synchronized internal fun install(archive: File, filesDir: File): File { val target = directory(filesDir) diff --git a/app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt b/app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt index 27e9e12fd9..93f9519cd1 100644 --- a/app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt +++ b/app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt @@ -5868,13 +5868,9 @@ private suspend fun setupWineSystemFiles( cleanupBionicSteamAssets(imageFs) } - val desktopTheme = if (gameSession) WineThemeManager.gameSessionTheme(container.desktopTheme) else container.desktopTheme - val desktopThemeKey = desktopTheme + "," + screenInfo + if (gameSession) ",game" else "" - if (desktopThemeKey != container.getExtra("desktopTheme")) { - WineThemeManager.apply(context, WineThemeManager.ThemeInfo(desktopTheme), screenInfo, !gameSession) - container.putExtra("desktopTheme", desktopThemeKey) - containerDataChanged = true - } + // Better to directly update registry on every launch, no need to rely on container `desktopTheme` value + val desktopTheme = if (gameSession) WineThemeManager.GAME_SESSION_THEME else WineThemeManager.DEFAULT_DESKTOP_THEME + WineThemeManager.apply(context, WineThemeManager.ThemeInfo(desktopTheme), screenInfo, !gameSession) WineStartMenuCreator.create(context, container) WineUtils.createDosdevicesSymlinks(context, container) diff --git a/app/src/main/java/com/winlator/core/WineThemeManager.java b/app/src/main/java/com/winlator/core/WineThemeManager.java index de28f1fda9..33d63fb05c 100644 --- a/app/src/main/java/com/winlator/core/WineThemeManager.java +++ b/app/src/main/java/com/winlator/core/WineThemeManager.java @@ -21,6 +21,7 @@ public abstract class WineThemeManager { public enum Theme {LIGHT, DARK} public enum BackgroundType {IMAGE, COLOR} public static final String DEFAULT_DESKTOP_THEME = Theme.LIGHT+","+BackgroundType.IMAGE+",#0277bd"; + public static final String GAME_SESSION_THEME = Theme.DARK+","+BackgroundType.COLOR+",#000000"; public static class ThemeInfo { public final Theme theme; @@ -30,33 +31,14 @@ public static class ThemeInfo { public ThemeInfo(String value) { String[] values = value.split(","); theme = Theme.valueOf(values[0]); - if (values.length < 3) { - backgroundColor = Color.parseColor(values[1]); - backgroundType = BackgroundType.IMAGE; - } - else { - backgroundType = BackgroundType.valueOf(values[1]); - backgroundColor = Color.parseColor(values[2]); - } + backgroundType = BackgroundType.valueOf(values[1]); + backgroundColor = Color.parseColor(values[2]); } } - // Game sessions get a black desktop: gamescope composites Wine's desktop - // surface, so the wallpaper would show through before the game's first frame - // and around its dialogs. The X11 renderers never draw explorer, so it is - // invisible there either way. - public static String gameSessionTheme(String value) { - ThemeInfo info = new ThemeInfo(value); - return info.theme + "," + BackgroundType.COLOR + ",#000000"; - } - - public static void apply(Context context, ThemeInfo themeInfo, ScreenInfo screenInfo) { - apply(context, themeInfo, screenInfo, true); - } - // The desktop is named "shell", which makes explorer draw its taskbar and // start menu; game sessions turn that off along with the standalone systray. - public static void apply(Context context, ThemeInfo themeInfo, ScreenInfo screenInfo, boolean enableShell) { + public static void apply(Context context, ThemeInfo themeInfo, ScreenInfo screenInfo, boolean showDesktop) { File rootDir = ImageFs.find(context).getRootDir(); File userRegFile = new File(rootDir, ImageFs.WINEPREFIX+"/user.reg"); String background = Color.red(themeInfo.backgroundColor)+" "+Color.green(themeInfo.backgroundColor)+" "+Color.blue(themeInfo.backgroundColor); @@ -69,14 +51,8 @@ public static void apply(Context context, ThemeInfo themeInfo, ScreenInfo screen } else registryEditor.removeValue("Control Panel\\Desktop", "Wallpaper"); - if (enableShell) { - registryEditor.removeValue("Software\\Wine\\Explorer\\Desktops\\shell", "EnableShell"); - registryEditor.removeValue("Software\\Wine\\Explorer\\Desktops\\shell", "ShowSystray"); - } - else { - registryEditor.setDwordValue("Software\\Wine\\Explorer\\Desktops\\shell", "EnableShell", 0); - registryEditor.setDwordValue("Software\\Wine\\Explorer\\Desktops\\shell", "ShowSystray", 0); - } + registryEditor.setDwordValue("Software\\Wine\\Explorer\\Desktops\\shell", "EnableShell", showDesktop ? 1 : 0); + registryEditor.setDwordValue("Software\\Wine\\Explorer\\Desktops\\shell", "ShowSystray", showDesktop ? 1 : 0); if (themeInfo.theme == Theme.LIGHT) { registryEditor.setStringValue("Control Panel\\Colors", "ActiveBorder", "245 245 245"); diff --git a/app/src/main/jniLibs/arm64-v8a/libgamenative_drm.so b/app/src/main/jniLibs/arm64-v8a/libgamenative_drm.so index f7f2bcba10..a8bda9fed8 100755 Binary files a/app/src/main/jniLibs/arm64-v8a/libgamenative_drm.so and b/app/src/main/jniLibs/arm64-v8a/libgamenative_drm.so differ