Skip to content

Commit 15716e2

Browse files
committed
fix: per-container .arch and Wine prefix paths to stop cross-game cascade
Launching one container with a different Wine version reverted another container's installed redists (d3dx9_*, d3dcompiler_*, msvc) back to Wine builtins, shrinking the registry hives and black-screening the second game. Two interlocking causes, both inherited from Winlator's single-container origins: 1. The launch-time gate compared container.wineVersion against the global <imagefs>/.winlator/.arch file (imageFs.getArch()). That file stores whichever container's wineVersion launched most recently, so a foreign launch flipped it and the next unrelated container saw a fake mismatch and ran applyGeneralPatches -> extractContainerPatternFile -> extractCommonDlls, deleting and re-extracting every entry in common_dlls.json (which includes all d3dx9_* / d3dcompiler_* / msvc100 / atl100 / dsound) from Wine's bundle, replacing installed-redist DLLs with Wine builtins. 2. Many per-container writes (system.reg, user.reg, DXVK/XAudio extraction, Steam install dir, OpenAL DLLs, theme writes, registry-key gamefixes, Steam install-script shim, autoLogin / firstTimeSetup) resolved through ImageFs.WINEPREFIX = "/home/xuser/.wine" or imageFs.wineprefix, both of which go through the global xuser symlink. The symlink points at whichever container ContainerManager.activateContainer touched last, so writes during a transition or from a SIGKILL'd leftover wineserver landed in the wrong container's prefix. Switch every per-container path to container.getRootDir() + "/.wine" and record the last-applied wineVersion / variant in container.extraData ("lastAppliedWineVersion", "lastAppliedVariant") instead of reading the global .arch / .variant files. The xuser symlink stays in place for display / login-flow fallback, but no per-container write resolves through it. Touched: WineUtils.applySystemTweaks (now takes Container); WineThemeManager.apply (now takes Container); RegistryKeyFix; SteamUtils.autoLoginUserChanges / skipFirstTimeSteamSetup / applySteamInstallScriptShim; XServerScreen WINEPREFIX env var, the applyGeneralPatches gate, extractDXWrapperFiles, cloneOriginalDllFiles / restoreOriginalDllFiles, extractWinComponentFiles, changeWineAudioDriver, extractSteamFiles, OpenAL extraction, zink_dlls extraction, and the real-Steam steam.exe probe / staleSteam dir delete. Verified by snapshot diff: launching Dead Cells (proton-10) then 868-HACK (proton-9) no longer shrinks 868's d3dx9_*/d3dcompiler_* in system32/syswow64 or its registry hives.
1 parent 187b86a commit 15716e2

5 files changed

Lines changed: 115 additions & 58 deletions

File tree

app/src/main/java/app/gamenative/gamefixes/RegistryKeyFix.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@ class RegistryKeyFix(
2121
installPathWindows: String,
2222
container: Container,
2323
): Boolean {
24-
val imageFs = ImageFs.find(context)
25-
val systemRegFile = File(imageFs.wineprefix, "system.reg")
24+
// Per-container path; imageFs.wineprefix resolves through the global
25+
// xuser symlink which is unsafe for writes (see WineUtils.applySystemTweaks
26+
// for the cascade-corruption rationale).
27+
val systemRegFile = File(container.rootDir, ".wine/system.reg")
2628
if (!systemRegFile.exists()) {
2729
Timber.tag("GameFixes").w("system.reg not found at ${systemRegFile.absolutePath}")
2830
return false

app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt

Lines changed: 62 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2837,7 +2837,13 @@ private fun setupXEnvironment(
28372837
envVars.put("LC_ALL", lc_all)
28382838
envVars.put("MESA_DEBUG", "silent")
28392839
envVars.put("MESA_NO_ERROR", "1")
2840-
envVars.put("WINEPREFIX", imageFs.wineprefix)
2840+
// Use the per-container wine prefix path directly. imageFs.wineprefix
2841+
// resolves through the global `xuser` symlink which points at whichever
2842+
// container was last activated, so writes from this Wine process can race
2843+
// a concurrent activate-container on another launch and corrupt the wrong
2844+
// container's prefix (registry hives shrink, native d3dx9/d3dcompiler
2845+
// revert to Wine builtins, etc.).
2846+
envVars.put("WINEPREFIX", File(container.rootDir, ".wine").absolutePath)
28412847
if (container.isSdlControllerAPI){
28422848
if (container.inputType == PreferredInputApi.XINPUT.ordinal || container.inputType == PreferredInputApi.AUTO.ordinal){
28432849
envVars.put("SDL_XINPUT_ENABLED", "1")
@@ -4027,15 +4033,28 @@ private fun setupWineSystemFiles(
40274033
val imageFs = ImageFs.find(context)
40284034
val appVersion = AppUtils.getVersionCode(context).toString()
40294035
val imgVersion = imageFs.getVersion().toString()
4030-
val wineVersion = imageFs.getArch()
4031-
val variant = imageFs.getVariant()
4036+
// imageFs.getArch() and imageFs.getVariant() read .winlator/.arch and
4037+
// .winlator/.variant which are GLOBAL files shared across containers
4038+
// (whichever container launched last writes them). When a container with a
4039+
// different Wine version launches, that flips the global file and the next
4040+
// launch of any other container sees a fake "wineVersion changed" mismatch
4041+
// and runs applyGeneralPatches, which deletes and re-extracts every common
4042+
// DLL (including d3dx9_*/d3dcompiler_*) from Wine's bundle — reverting
4043+
// installed-redist DLLs back to Wine builtins and breaking the prefix.
4044+
// Compare against per-container state instead so a foreign launch can't
4045+
// contaminate this container.
4046+
val lastAppliedWine = container.getExtra("lastAppliedWineVersion", "")
4047+
val lastAppliedVariant = container.getExtra("lastAppliedVariant", "")
40324048
var containerDataChanged = false
40334049

40344050
if (!container.getExtra("appVersion").equals(appVersion) || !container.getExtra("imgVersion").equals(imgVersion) ||
4035-
container.containerVariant != variant || (container.containerVariant == variant && container.wineVersion != wineVersion)) {
4051+
container.containerVariant != lastAppliedVariant ||
4052+
(container.containerVariant == lastAppliedVariant && container.wineVersion != lastAppliedWine)) {
40364053
applyGeneralPatches(context, container, imageFs, xServerState.value.wineInfo, containerManager, onExtractFileListener)
40374054
container.putExtra("appVersion", appVersion)
40384055
container.putExtra("imgVersion", imgVersion)
4056+
container.putExtra("lastAppliedWineVersion", container.wineVersion)
4057+
container.putExtra("lastAppliedVariant", container.containerVariant)
40394058
containerDataChanged = true
40404059
}
40414060

@@ -4056,7 +4075,7 @@ private fun setupWineSystemFiles(
40564075
)
40574076
}
40584077

4059-
val needReextract = ALWAYS_REEXTRACT || xServerState.value.dxwrapper != container.getExtra("dxwrapper") || container.wineVersion != wineVersion
4078+
val needReextract = ALWAYS_REEXTRACT || xServerState.value.dxwrapper != container.getExtra("dxwrapper") || container.wineVersion != lastAppliedWine
40604079

40614080
Timber.i("needReextract is " + needReextract)
40624081
Timber.i("xServerState.value.dxwrapper is " + xServerState.value.dxwrapper)
@@ -4093,7 +4112,9 @@ private fun setupWineSystemFiles(
40934112
val openalState = if (needsOpenalDlls) "yes" else "no"
40944113
if (openalState != container.getExtra("openal_dlls") || firstTimeBoot) {
40954114
if (needsOpenalDlls) {
4096-
val windowsDir = File(imageFs.rootDir, ImageFs.WINEPREFIX + "/drive_c/windows")
4115+
// Per-container path; xuser symlink is unsafe for writes (see
4116+
// applySystemTweaks rationale).
4117+
val windowsDir = File(container.rootDir, ".wine/drive_c/windows")
40974118
TarCompressorUtils.extract(
40984119
TarCompressorUtils.Type.ZSTD, context.assets,
40994120
"wincomponents/openal.tzst", windowsDir, onExtractFileListener,
@@ -4108,12 +4129,12 @@ private fun setupWineSystemFiles(
41084129
// on launch, so invalidate the extraction when Wine version or variant changes.
41094130
val steamExtractedKey = "${container.wineVersion}|${container.containerVariant}"
41104131
val steamExtractedPrev = container.getExtra("steamExtractedForWine")
4111-
val steamExeFile = File(ImageFs.find(context).rootDir.absolutePath, ImageFs.WINEPREFIX + "/drive_c/Program Files (x86)/Steam/steam.exe")
4132+
val steamExeFile = File(container.rootDir, ".wine/drive_c/Program Files (x86)/Steam/steam.exe")
41124133
if (steamExtractedPrev != steamExtractedKey && steamExeFile.exists()) {
41134134
// Symlink-safe delete: steamapps/common/<installdir> symlinks point at
41144135
// GameNative's own Steam dir, and a following recursive delete would wipe
41154136
// every installed game's files.
4116-
val steamDir = File(ImageFs.find(context).rootDir.absolutePath, ImageFs.WINEPREFIX + "/drive_c/Program Files (x86)/Steam")
4137+
val steamDir = File(container.rootDir, ".wine/drive_c/Program Files (x86)/Steam")
41174138
SteamUtils.deleteTreeNoFollowSymlinks(steamDir)
41184139
}
41194140
extractSteamFiles(context, container, onExtractFileListener)
@@ -4126,7 +4147,7 @@ private fun setupWineSystemFiles(
41264147

41274148
val desktopTheme = container.desktopTheme
41284149
if ((desktopTheme + "," + screenInfo) != container.getExtra("desktopTheme")) {
4129-
WineThemeManager.apply(context, WineThemeManager.ThemeInfo(desktopTheme), screenInfo)
4150+
WineThemeManager.apply(context, WineThemeManager.ThemeInfo(desktopTheme), screenInfo, container)
41304151
container.putExtra("desktopTheme", desktopTheme + "," + screenInfo)
41314152
containerDataChanged = true
41324153
}
@@ -4181,7 +4202,7 @@ private fun applyGeneralPatches(
41814202
Timber.i("Attempting to extract _container_pattern.tzst with wine version " + container.wineVersion)
41824203
}
41834204
containerManager.extractContainerPatternFile(container.getWineVersion(), contentsManager, container.rootDir, null)
4184-
WineUtils.applySystemTweaks(context, wineInfo)
4205+
WineUtils.applySystemTweaks(context, wineInfo, container)
41854206
container.putExtra("graphicsDriver", null)
41864207
container.putExtra("desktopTheme", null)
41874208
WinlatorPrefManager.init(context)
@@ -4215,9 +4236,11 @@ private fun extractDXWrapperFiles(
42154236
"ddraw.dll",
42164237
)
42174238
val splitDxWrapper = dxwrapper.split("-")[0]
4218-
if (firstTimeBoot && splitDxWrapper != "vkd3d") cloneOriginalDllFiles(imageFs, *dlls)
4219-
val rootDir = imageFs.getRootDir()
4220-
val windowsDir = File(rootDir, ImageFs.WINEPREFIX + "/drive_c/windows")
4239+
if (firstTimeBoot && splitDxWrapper != "vkd3d") cloneOriginalDllFiles(imageFs, container, *dlls)
4240+
// Per-container .wine paths; the xuser symlink is unsafe for writes
4241+
// (see applySystemTweaks for the cascade-corruption rationale).
4242+
val containerRoot = container.rootDir
4243+
val windowsDir = File(containerRoot, ".wine/drive_c/windows")
42214244

42224245
when (splitDxWrapper) {
42234246
"wined3d" -> {
@@ -4226,9 +4249,9 @@ private fun extractDXWrapperFiles(
42264249
"cnc-ddraw" -> {
42274250
restoreOriginalDllFiles(context, container, containerManager, imageFs, *dlls)
42284251
val assetDir = "dxwrapper/cnc-ddraw-" + DefaultVersion.CNC_DDRAW
4229-
val configFile = File(rootDir, ImageFs.WINEPREFIX + "/drive_c/ProgramData/cnc-ddraw/ddraw.ini")
4252+
val configFile = File(containerRoot, ".wine/drive_c/ProgramData/cnc-ddraw/ddraw.ini")
42304253
if (!configFile.isFile) FileUtils.copy(context, "$assetDir/ddraw.ini", configFile)
4231-
val shadersDir = File(rootDir, ImageFs.WINEPREFIX + "/drive_c/ProgramData/cnc-ddraw/Shaders")
4254+
val shadersDir = File(containerRoot, ".wine/drive_c/ProgramData/cnc-ddraw/Shaders")
42324255
FileUtils.delete(shadersDir)
42334256
FileUtils.copy(context, "$assetDir/Shaders", shadersDir)
42344257
TarCompressorUtils.extract(
@@ -4287,11 +4310,11 @@ private fun extractDXWrapperFiles(
42874310
}
42884311
}
42894312
}
4290-
private fun cloneOriginalDllFiles(imageFs: ImageFs, vararg dlls: String) {
4291-
val rootDir = imageFs.rootDir
4292-
val cacheDir = File(rootDir, ImageFs.CACHE_PATH + "/original_dlls")
4313+
private fun cloneOriginalDllFiles(imageFs: ImageFs, container: Container, vararg dlls: String) {
4314+
val containerRoot = container.rootDir
4315+
val cacheDir = File(containerRoot, ".cache/original_dlls")
42934316
if (!cacheDir.isDirectory) cacheDir.mkdirs()
4294-
val windowsDir = File(rootDir, ImageFs.WINEPREFIX + "/drive_c/windows")
4317+
val windowsDir = File(containerRoot, ".wine/drive_c/windows")
42954318
val dirnames = arrayOf("system32", "syswow64")
42964319

42974320
for (dll in dlls) {
@@ -4308,12 +4331,12 @@ private fun restoreOriginalDllFiles(
43084331
imageFs: ImageFs,
43094332
vararg dlls: String,
43104333
) {
4311-
val rootDir = imageFs.rootDir
4334+
val containerRoot = container.rootDir
43124335
if (container.containerVariant.equals(Container.GLIBC)) {
4313-
val cacheDir = File(rootDir, ImageFs.CACHE_PATH + "/original_dlls")
4336+
val cacheDir = File(containerRoot, ".cache/original_dlls")
43144337
val contentsManager = ContentsManager(context)
43154338
if (cacheDir.isDirectory) {
4316-
val windowsDir = File(rootDir, ImageFs.WINEPREFIX + "/drive_c/windows")
4339+
val windowsDir = File(containerRoot, ".wine/drive_c/windows")
43174340
val dirnames = cacheDir.list()
43184341
var filesCopied = 0
43194342

@@ -4345,9 +4368,9 @@ private fun restoreOriginalDllFiles(
43454368
},
43464369
)
43474370

4348-
cloneOriginalDllFiles(imageFs, *dlls)
4371+
cloneOriginalDllFiles(imageFs, container, *dlls)
43494372
} else {
4350-
val windowsDir = File(rootDir, ImageFs.WINEPREFIX + "/drive_c/windows")
4373+
val windowsDir = File(containerRoot, ".wine/drive_c/windows")
43514374
var system32dlls: File? = null
43524375
var syswow64dlls: File? = null
43534376

@@ -4376,9 +4399,11 @@ private fun extractWinComponentFiles(
43764399
// shortcut: Shortcut?,
43774400
onExtractFileListener: OnExtractFileListener?,
43784401
) {
4379-
val rootDir = imageFs.rootDir
4380-
val windowsDir = File(rootDir, ImageFs.WINEPREFIX + "/drive_c/windows")
4381-
val systemRegFile = File(rootDir, ImageFs.WINEPREFIX + "/system.reg")
4402+
// Resolve through container.rootDir, not the global xuser symlink — see
4403+
// applySystemTweaks for the cascade-corruption rationale.
4404+
val containerRoot = container.rootDir
4405+
val windowsDir = File(containerRoot, ".wine/drive_c/windows")
4406+
val systemRegFile = File(containerRoot, ".wine/system.reg")
43824407

43834408
try {
43844409
val wincomponentsJSONObject = JSONObject(FileUtils.readString(context, "wincomponents/wincomponents.json"))
@@ -4395,7 +4420,7 @@ private fun extractWinComponentFiles(
43954420
}
43964421
}
43974422

4398-
cloneOriginalDllFiles(imageFs, *dlls.toTypedArray())
4423+
cloneOriginalDllFiles(imageFs, container, *dlls.toTypedArray())
43994424
dlls.clear()
44004425
}
44014426

@@ -4669,11 +4694,13 @@ private fun extractGraphicsDriverFiles(
46694694
)
46704695
val renderer = GPUInformation.getRenderer(null, null)
46714696
if (container.wineVersion.contains("arm64ec") && renderer?.contains("Mali") != true) {
4697+
// Per-container path; xuser symlink is unsafe for writes
4698+
// (see applySystemTweaks rationale).
46724699
TarCompressorUtils.extract(
46734700
TarCompressorUtils.Type.ZSTD,
46744701
context.assets,
46754702
"graphics_driver/zink_dlls" + ".tzst",
4676-
File(rootDir, ImageFs.WINEPREFIX + "/drive_c/windows"),
4703+
File(container.rootDir, ".wine/drive_c/windows"),
46774704
)
46784705
}
46794706
}
@@ -4771,7 +4798,9 @@ private fun extractSteamFiles(
47714798
onExtractFileListener: OnExtractFileListener?,
47724799
) {
47734800
val imageFs = ImageFs.find(context)
4774-
if (File(ImageFs.find(context).rootDir.absolutePath, ImageFs.WINEPREFIX + "/drive_c/Program Files (x86)/Steam/steam.exe").exists()) return
4801+
// Per-container path; xuser symlink is unsafe for writes (see
4802+
// applySystemTweaks rationale).
4803+
if (File(container.rootDir, ".wine/drive_c/Program Files (x86)/Steam/steam.exe").exists()) return
47754804
val downloaded = File(imageFs.getFilesDir(), "steam.tzst")
47764805
Timber.i("Extracting steam.tzst")
47774806
TarCompressorUtils.extract(
@@ -4802,8 +4831,9 @@ private fun readLibraryNameFromExtractedDir(destinationDir: File): String? {
48024831
}
48034832
private fun changeWineAudioDriver(audioDriver: String, container: Container, imageFs: ImageFs) {
48044833
if (audioDriver != container.getExtra("audioDriver")) {
4805-
val rootDir = imageFs.rootDir
4806-
val userRegFile = File(rootDir, ImageFs.WINEPREFIX + "/user.reg")
4834+
// Per-container path; xuser symlink is unsafe for writes (see
4835+
// applySystemTweaks rationale).
4836+
val userRegFile = File(container.rootDir, ".wine/user.reg")
48074837
WineRegistryEditor(userRegFile).use { registryEditor ->
48084838
if (audioDriver == "alsa") {
48094839
registryEditor.setStringValue("Software\\Wine\\Drivers", "Audio", "alsa")

app/src/main/java/app/gamenative/utils/SteamUtils.kt

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,11 @@ object SteamUtils {
159159
*/
160160
fun applySteamInstallScriptShim(context: Context, steamAppId: Int) {
161161
try {
162-
val imageFs = ImageFs.find(context)
163-
val systemRegFile = File(imageFs.wineprefix, "system.reg")
162+
// Per-container path; imageFs.wineprefix resolves through the
163+
// global xuser symlink which is unsafe for writes (see
164+
// WineUtils.applySystemTweaks rationale).
165+
val container = ContainerUtils.getContainer(context, "STEAM_$steamAppId")
166+
val systemRegFile = File(container.rootDir, ".wine/system.reg")
164167
if (!systemRegFile.isFile) return
165168

166169
val appKeys = listOf(
@@ -298,7 +301,11 @@ object SteamUtils {
298301
var replaced64Count = 0
299302
val backupPaths = mutableSetOf<String>()
300303
val imageFs = ImageFs.find(context)
301-
autoLoginUserChanges(imageFs)
304+
// Pass the container so writes go to the per-container .wine prefix
305+
// rather than through the global xuser symlink (which can race with
306+
// another concurrent launch and corrupt that game's prefix).
307+
val container = ContainerUtils.getContainer(context, appId)
308+
autoLoginUserChanges(imageFs, container)
302309
setupLightweightSteamConfig(imageFs, SteamService.userSteamId?.toString())
303310

304311
val rootPath = Paths.get(appDirPath)
@@ -555,19 +562,25 @@ object SteamUtils {
555562
)
556563
}
557564

558-
fun autoLoginUserChanges(imageFs: ImageFs) {
565+
fun autoLoginUserChanges(imageFs: ImageFs, container: Container? = null) {
559566
val vdfFileText = SteamService.getLoginUsersVdfOauth(
560567
steamId64 = SteamService.userSteamId?.convertToUInt64().toString(),
561568
account = PrefManager.username,
562569
refreshToken = PrefManager.refreshToken,
563570
accessToken = PrefManager.accessToken, // may be blank
564571
personaName = SteamService.instance?.localPersona?.value?.name ?: PrefManager.username
565572
)
566-
val steamConfigDir = File(imageFs.wineprefix, "drive_c/Program Files (x86)/Steam/config")
573+
// When called from a launch flow, prefer the per-container path.
574+
// imageFs.wineprefix resolves through the global xuser symlink which is
575+
// unsafe for concurrent launches (writes leak into the wrong
576+
// container's prefix). The symlink-based fallback is kept for the
577+
// login flow, which has no specific container context.
578+
val winePrefixBase: File = container?.let { File(it.rootDir, ".wine") }
579+
?: File(imageFs.wineprefix)
580+
val steamConfigDir = File(winePrefixBase, "drive_c/Program Files (x86)/Steam/config")
567581
try {
568582
File(steamConfigDir, "loginusers.vdf").writeText(vdfFileText)
569-
val rootDir = imageFs.rootDir
570-
val userRegFile = File(rootDir, ImageFs.WINEPREFIX + "/user.reg")
583+
val userRegFile = File(winePrefixBase, "user.reg")
571584
val steamRoot = "C:\\Program Files (x86)\\Steam"
572585
val steamExe = "$steamRoot\\steam.exe"
573586
val hkcu = "Software\\Valve\\Steam"
@@ -1372,7 +1385,7 @@ object SteamUtils {
13721385
// Update or modify localconfig.vdf
13731386
updateOrModifyLocalConfig(imageFs, container, steamAppId.toString(), SteamService.userSteamId!!.accountID.toString())
13741387

1375-
skipFirstTimeSteamSetup(imageFs.rootDir)
1388+
skipFirstTimeSteamSetup(imageFs.rootDir, container)
13761389
val appDirPath = SteamService.getAppDirPath(steamAppId)
13771390

13781391
val restoredMarkerPresent = MarkerUtils.hasMarker(appDirPath, Marker.STEAM_DLL_RESTORED)
@@ -1382,7 +1395,7 @@ object SteamUtils {
13821395
MarkerUtils.removeMarker(appDirPath, Marker.STEAM_DLL_REPLACED)
13831396
MarkerUtils.removeMarker(appDirPath, Marker.STEAM_COLDCLIENT_USED)
13841397

1385-
autoLoginUserChanges(imageFs)
1398+
autoLoginUserChanges(imageFs, container)
13861399
setupLightweightSteamConfig(imageFs, SteamService.userSteamId!!.accountID.toString())
13871400

13881401
putBackSteamDlls(appDirPath)
@@ -2015,8 +2028,11 @@ object SteamUtils {
20152028
return androidId.hashCode()
20162029
}
20172030

2018-
private fun skipFirstTimeSteamSetup(rootDir: File?) {
2019-
val systemRegFile = File(rootDir, ImageFs.WINEPREFIX + "/system.reg")
2031+
private fun skipFirstTimeSteamSetup(rootDir: File?, container: Container? = null) {
2032+
// Per-container path when available — see autoLoginUserChanges for the
2033+
// cascade-corruption rationale.
2034+
val systemRegFile = container?.let { File(it.rootDir, ".wine/system.reg") }
2035+
?: File(rootDir, ImageFs.WINEPREFIX + "/system.reg")
20202036
val redistributables = listOf(
20212037
"DirectX\\Jun2010" to "DXSetup", // DirectX Jun 2010
20222038
".NET\\3.5" to "3.5 SP1", // .NET 3.5

app/src/main/java/com/winlator/core/WineThemeManager.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ public ThemeInfo(String value) {
4141
}
4242
}
4343

44-
public static void apply(Context context, ThemeInfo themeInfo, ScreenInfo screenInfo) {
45-
File rootDir = ImageFs.find(context).getRootDir();
46-
File userRegFile = new File(rootDir, ImageFs.WINEPREFIX+"/user.reg");
44+
public static void apply(Context context, ThemeInfo themeInfo, ScreenInfo screenInfo, com.winlator.container.Container container) {
45+
// Per-container path; xuser symlink is unsafe for writes (see
46+
// WineUtils.applySystemTweaks rationale).
47+
File userRegFile = new File(container.getRootDir(), ".wine/user.reg");
4748
String background = Color.red(themeInfo.backgroundColor)+" "+Color.green(themeInfo.backgroundColor)+" "+Color.blue(themeInfo.backgroundColor);
4849

4950
if (themeInfo.backgroundType == BackgroundType.IMAGE) createWallpaperBMPFile(context, screenInfo);

0 commit comments

Comments
 (0)