Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"toggleSwitch": false,
"text": "",
"iconId": 0,
"range": "FROM_1_TO_12"
"range": "FROM_0_TO_9"
},
{
"type": "BUTTON",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"toggleSwitch": false,
"text": "",
"iconId": 0,
"range": "FROM_1_TO_12"
"range": "FROM_0_TO_9"
},
{
"type": "RADIAL_MENU",
Expand Down
8 changes: 4 additions & 4 deletions app/src/main/cpp/winlator/vulkan.c
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ static VkResult enumerate_physical_devices() {
}

JNIEXPORT jstring JNICALL
Java_com_winlator_cmod_runtime_system_GPUInformation_getVulkanVersion(
Java_com_winlator_cmod_runtime_system_GPUInformation_getVulkanVersionNative(
JNIEnv *env, jclass obj, jstring driverName, jobject context) {
VkPhysicalDeviceProperties props = {};
char *driverVersion;
Expand Down Expand Up @@ -392,7 +392,7 @@ Java_com_winlator_cmod_runtime_system_GPUInformation_getVulkanVersion(
}

JNIEXPORT jint JNICALL
Java_com_winlator_cmod_runtime_system_GPUInformation_getVendorID(
Java_com_winlator_cmod_runtime_system_GPUInformation_getVendorIDNative(
JNIEnv *env, jclass obj, jstring driverName, jobject context) {
VkPhysicalDeviceProperties props = {};
uint32_t vendorID;
Expand Down Expand Up @@ -421,7 +421,7 @@ Java_com_winlator_cmod_runtime_system_GPUInformation_getVendorID(
}

JNIEXPORT jstring JNICALL
Java_com_winlator_cmod_runtime_system_GPUInformation_getRenderer(
Java_com_winlator_cmod_runtime_system_GPUInformation_getRendererNative(
JNIEnv *env, jclass obj, jstring driverName, jobject context) {
VkPhysicalDeviceProperties props = {};

Expand Down Expand Up @@ -449,7 +449,7 @@ Java_com_winlator_cmod_runtime_system_GPUInformation_getRenderer(
}

JNIEXPORT jobjectArray JNICALL
Java_com_winlator_cmod_runtime_system_GPUInformation_enumerateExtensions(
Java_com_winlator_cmod_runtime_system_GPUInformation_enumerateExtensionsNative(
JNIEnv *env, jclass obj, jstring driverName, jobject context) {
jobjectArray extensions;
VkResult result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -502,29 +502,34 @@ class ContainerSettingsComposeDialog @JvmOverloads constructor(
val themeInfo = WineThemeManager.ThemeInfo(desktopThemeValue)
state.desktopBackgroundColor.value = String.format("#%06X", themeInfo.backgroundColor and 0x00FFFFFF)

// Mouse warp override lives in .wine/user.reg, not on the container.
var mouseWarp = "disable"
val rootDir = c?.getRootDir()
if (rootDir != null) {
val userRegFile = File(rootDir, ".wine/user.reg")
if (userRegFile.exists()) {
try {
WineRegistryEditor(userRegFile).use { reg ->
mouseWarp = reg.getStringValue(
"Software\\Wine\\DirectInput",
"MouseWarpOverride",
"disable"
)
}
} catch (e: Throwable) {
Log.w(TAG, "Error reading MouseWarpOverride", e)
}

private var pendingMouseWarpValue = "disable"

private fun readMouseWarpOverride(): String {
val rootDir = container?.getRootDir() ?: return "disable"
val userRegFile = File(rootDir, ".wine/user.reg")
if (!userRegFile.exists()) return "disable"
val value =
try {
WineRegistryEditor(userRegFile).use { reg ->
reg.getStringValue("Software\\Wine\\DirectInput", "MouseWarpOverride", "disable")
}
} catch (e: Throwable) {
Log.w(TAG, "Error reading MouseWarpOverride", e)
"disable"
}
}
pendingMouseWarpValue = mouseWarp.lowercase()
return value.lowercase()
}

private var pendingMouseWarpValue = "disable"
private fun applyMouseWarpOverride(value: String) {
pendingMouseWarpValue = value
state.selectedMouseWarpOverride.intValue = when (value) {
"enable" -> 1
"force" -> 2
else -> 0
}
}

private fun loadResourceArrays() {
val c = container
Expand Down Expand Up @@ -694,10 +699,12 @@ class ContainerSettingsComposeDialog @JvmOverloads constructor(

private fun loadContentsAsync() {
Executors.newSingleThreadExecutor().execute {
val mouseWarp = readMouseWarpOverride()
try {
contentsManager.syncContents()
activity.runOnUiThread {
try {
applyMouseWarpOverride(mouseWarp)
populateContentsDependentData()
} finally {
state.isLoaded.value = true
Expand Down Expand Up @@ -1304,69 +1311,49 @@ class ContainerSettingsComposeDialog @JvmOverloads constructor(
state.graphicsDriverVersion.value = config.get("version") ?: ""
}

private var extensionsRequest = 0

private fun savedGraphicsDriverConfig() =
GraphicsDriverConfigUtils.parseGraphicsDriverConfig(
container?.getGraphicsDriverConfig() ?: Container.DEFAULT_GRAPHICSDRIVERCONFIG,
)

private fun loadGraphicsDriverVersions() {
val versions = mutableListOf<String>()
try {
val defaults = context.resources.getStringArray(R.array.wrapper_graphics_driver_version_entries)
for (ver in defaults) {
try {
if (com.winlator.cmod.runtime.system.GPUInformation.isDriverSupported(ver, context))
versions.add(ver)
} catch (e: Throwable) {
Log.w(TAG, "Driver support check failed: $ver", e)
}
val savedVersion = savedGraphicsDriverConfig().get("version") ?: ""
state.gfxDriverVersionEntries.value = listOf(if (savedVersion.isNotEmpty()) savedVersion else "System")
state.gfxSelectedDriverVersion.intValue = 0
scope.launch {
val versions = withContext(Dispatchers.IO) {
com.winlator.cmod.runtime.system.GraphicsDriverCatalog.supportedVersions(context)
}
try {
val adreno = com.winlator.cmod.runtime.content.AdrenotoolsManager(context)
val installed = adreno.enumarateInstalledDrivers()
if (installed != null) versions.addAll(installed)
} catch (e: Throwable) {
Log.w(TAG, "Error loading Adrenotools drivers", e)
}
} catch (e: Throwable) {
Log.e(TAG, "Error loading wrapper versions", e)
}
if (versions.isEmpty()) versions.add("System")
state.gfxDriverVersionEntries.value = versions

val configStr2 = container?.getGraphicsDriverConfig() ?: Container.DEFAULT_GRAPHICSDRIVERCONFIG
val config = GraphicsDriverConfigUtils.parseGraphicsDriverConfig(configStr2)
val initialVersion = config.get("version") ?: ""
if (initialVersion.isNotEmpty()) {
val idx = versions.indexOfFirst { it.equals(initialVersion, ignoreCase = true) }
if (idx >= 0) state.gfxSelectedDriverVersion.intValue = idx
state.gfxDriverVersionEntries.value = versions
val idx = versions.indexOfFirst { it.equals(savedVersion, ignoreCase = true) }
state.gfxSelectedDriverVersion.intValue = if (idx >= 0) idx else 0
loadExtensionsForVersion(state.gfxSelectedDriverVersion.intValue)
}
loadExtensionsForVersion(state.gfxSelectedDriverVersion.intValue)
}

private fun loadExtensionsForVersion(versionIndex: Int) {
val versions = state.gfxDriverVersionEntries.value
val version = versions.getOrElse(versionIndex) { return }
try {
val extensions = com.winlator.cmod.runtime.system.GPUInformation.enumerateExtensions(version, context)
if (extensions != null) {
state.gfxAvailableExtensions.value = extensions.toList()
val configStr = container?.getGraphicsDriverConfig() ?: Container.DEFAULT_GRAPHICSDRIVERCONFIG
val config = GraphicsDriverConfigUtils.parseGraphicsDriverConfig(configStr)
val savedVersion = config.get("version") ?: ""
if (version == savedVersion) {
val version = state.gfxDriverVersionEntries.value.getOrElse(versionIndex) { return }
val request = ++extensionsRequest
scope.launch {
val extensions = withContext(Dispatchers.IO) {
com.winlator.cmod.runtime.system.GraphicsDriverCatalog.extensions(context, version)
}
if (request != extensionsRequest) return@launch
state.gfxAvailableExtensions.value = extensions
val config = savedGraphicsDriverConfig()
state.gfxBlacklistedExtensions.value =
if (version == (config.get("version") ?: "")) {
val bl = config.get("blacklistedExtensions") ?: ""
state.gfxBlacklistedExtensions.value =
if (bl.isNotEmpty()) bl.split(",").toSet() else emptySet()
if (bl.isNotEmpty()) bl.split(",").toSet() else emptySet()
} else {
state.gfxBlacklistedExtensions.value = emptySet()
emptySet()
}
} else {
state.gfxAvailableExtensions.value = emptyList()
state.gfxBlacklistedExtensions.value = emptySet()
}
} catch (e: Throwable) {
Log.e(TAG, "Error loading extensions for $version", e)
state.gfxAvailableExtensions.value = emptyList()
state.gfxBlacklistedExtensions.value = emptySet()
}
}


private fun initialDxWrapperConfig(): String =
container?.getDXWrapperConfig()
?: ContainerCreation.defaultDxWrapperConfig(contentsManager, isArm64EC)
Expand Down Expand Up @@ -1618,7 +1605,12 @@ class ContainerSettingsComposeDialog @JvmOverloads constructor(
private fun buildDesktopThemeString(): String {
val themeEntries = state.desktopThemeEntries.value
val themeIdx = state.selectedDesktopTheme.intValue
val theme = if (themeIdx in themeEntries.indices) themeEntries[themeIdx].uppercase() else "LIGHT"
val theme =
if (themeIdx in themeEntries.indices) {
WineThemeManager.Theme.values().getOrNull(themeIdx)?.name ?: "LIGHT"
} else {
"LIGHT"
}

val typeIdx = state.selectedDesktopBackgroundType.intValue
val type = WineThemeManager.BackgroundType.values().getOrNull(typeIdx)?.name ?: "IMAGE"
Expand Down
113 changes: 47 additions & 66 deletions app/src/main/feature/shortcuts/ShortcutSettingsComposeDialog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import kotlinx.coroutines.withContext
import kotlinx.coroutines.CoroutineScope
import com.winlator.cmod.app.config.DeviceProfileSettings
import com.winlator.cmod.runtime.display.environment.components.NetworkingSettings
import com.winlator.cmod.runtime.wine.WineThemeManager
import com.winlator.cmod.BuildConfig
import com.winlator.cmod.R
import com.winlator.cmod.app.PluviaApp
Expand Down Expand Up @@ -727,10 +728,9 @@ class ShortcutSettingsComposeDialog private constructor(
state.desktopThemeEntries.value = desktopThemeArr
// Desktop theme is stored as compound "THEME,TYPE,COLOR" — extract theme name
val savedDesktopTheme = getShortcutSetting("desktopTheme", container.getDesktopTheme())
val themePart = savedDesktopTheme.split(",").firstOrNull()?.trim() ?: ""
// Match case-insensitively: enum is "LIGHT"/"DARK", entries are "Light"/"Dark"
val themeIdx = desktopThemeArr.indexOfFirst { it.equals(themePart, ignoreCase = true) }
state.selectedDesktopTheme.intValue = if (themeIdx >= 0) themeIdx else 0
state.selectedDesktopTheme.intValue =
WineThemeManager.ThemeInfo(savedDesktopTheme).theme.ordinal
.coerceIn(0, (desktopThemeArr.size - 1).coerceAtLeast(0))

// Show Box64/FEXCore frames based on saved emulator selection immediately,
// before the async content sync runs
Expand Down Expand Up @@ -1457,8 +1457,12 @@ class ShortcutSettingsComposeDialog private constructor(
if (state.desktopThemeEntries.value.isNotEmpty()) {
val desktopThemeEntries = state.desktopThemeEntries.value
val dtIdx = state.selectedDesktopTheme.intValue
val selectedLabel = if (dtIdx in desktopThemeEntries.indices) desktopThemeEntries[dtIdx] else ""
val themeName = selectedLabel.uppercase()
val themeName =
if (dtIdx in desktopThemeEntries.indices) {
WineThemeManager.Theme.values().getOrNull(dtIdx)?.name ?: "LIGHT"
} else {
"LIGHT"
}
// Preserve existing compound value, only replace the theme portion
val existing = getShortcutSetting("desktopTheme", container.getDesktopTheme())
val parts = existing.split(",").toMutableList()
Expand Down Expand Up @@ -2168,75 +2172,52 @@ class ShortcutSettingsComposeDialog private constructor(
state.graphicsDriverVersion.value = config["version"] ?: ""
}

private fun loadGraphicsDriverVersions(container: Container = shortcut.container) {
val versions = mutableListOf<String>()
try {
val defaults = context.resources.getStringArray(R.array.wrapper_graphics_driver_version_entries)
for (ver in defaults) {
try {
if (com.winlator.cmod.runtime.system.GPUInformation.isDriverSupported(ver, context))
versions.add(ver)
} catch (e: Throwable) {
Log.w(TAG, "Error checking driver support: $ver", e)
}
}
try {
val adrenoManager = com.winlator.cmod.runtime.content.AdrenotoolsManager(context)
val installed = adrenoManager.enumarateInstalledDrivers()
if (installed != null) versions.addAll(installed)
} catch (e: Throwable) {
Log.w(TAG, "Error loading Adrenotools drivers", e)
}
} catch (e: Throwable) {
Log.e(TAG, "Error loading wrapper versions", e)
}
if (versions.isEmpty()) versions.add("System")

state.gfxDriverVersionEntries.value = versions
private var extensionsRequest = 0

private fun savedGraphicsDriverConfig(container: Container = shortcut.container): Map<String, String> {
val configStr = if (shouldUseShortcutOverrides(container))
getShortcutSetting("graphicsDriverConfig", container.getGraphicsDriverConfig())
else
container.getGraphicsDriverConfig()
val config = GraphicsDriverConfigUtils.parseGraphicsDriverConfig(configStr)
val initialVersion = config["version"] ?: ""
if (initialVersion.isNotEmpty()) {
val idx = versions.indexOfFirst { it.equals(initialVersion, ignoreCase = true) }
if (idx >= 0) state.gfxSelectedDriverVersion.intValue = idx
}
return GraphicsDriverConfigUtils.parseGraphicsDriverConfig(configStr)
}

loadExtensionsForVersion(state.gfxSelectedDriverVersion.intValue)
private fun loadGraphicsDriverVersions(container: Container = shortcut.container) {
val savedVersion = savedGraphicsDriverConfig(container)["version"] ?: ""
state.gfxDriverVersionEntries.value = listOf(if (savedVersion.isNotEmpty()) savedVersion else "System")
state.gfxSelectedDriverVersion.intValue = 0
Thread({
val versions = com.winlator.cmod.runtime.system.GraphicsDriverCatalog.supportedVersions(context)
activity.runOnUiThread {
state.gfxDriverVersionEntries.value = versions
val idx = versions.indexOfFirst { it.equals(savedVersion, ignoreCase = true) }
state.gfxSelectedDriverVersion.intValue = if (idx >= 0) idx else 0
loadExtensionsForVersion(state.gfxSelectedDriverVersion.intValue)
}
}, "GraphicsDriverProbe").start()
}

private fun loadExtensionsForVersion(versionIndex: Int) {
val versions = state.gfxDriverVersionEntries.value
val version = versions.getOrElse(versionIndex) { return }
try {
val extensions = com.winlator.cmod.runtime.system.GPUInformation.enumerateExtensions(version, context)
if (extensions != null) {
state.gfxAvailableExtensions.value = extensions.toList()

// On initial load, set blacklisted from config; on version change, clear blacklist
val configStr = getShortcutSetting("graphicsDriverConfig", shortcut.container.getGraphicsDriverConfig())
val config = GraphicsDriverConfigUtils.parseGraphicsDriverConfig(configStr)
val savedVersion = config["version"] ?: ""
if (version == savedVersion) {
val bl = config["blacklistedExtensions"] ?: ""
state.gfxBlacklistedExtensions.value = if (bl.isNotEmpty()) bl.split(",").toSet() else emptySet()
} else {
state.gfxBlacklistedExtensions.value = emptySet()
}
} else {
state.gfxAvailableExtensions.value = emptyList()
state.gfxBlacklistedExtensions.value = emptySet()
val version = state.gfxDriverVersionEntries.value.getOrElse(versionIndex) { return }
val request = ++extensionsRequest
Thread({
val extensions = com.winlator.cmod.runtime.system.GraphicsDriverCatalog.extensions(context, version)
activity.runOnUiThread {
if (request != extensionsRequest) return@runOnUiThread
state.gfxAvailableExtensions.value = extensions
val config = savedGraphicsDriverConfig()
state.gfxBlacklistedExtensions.value =
if (version == (config["version"] ?: "")) {
val bl = config["blacklistedExtensions"] ?: ""
if (bl.isNotEmpty()) bl.split(",").toSet() else emptySet()
} else {
emptySet()
}
}
} catch (e: Throwable) {
Log.e(TAG, "Error loading extensions for $version", e)
state.gfxAvailableExtensions.value = emptyList()
state.gfxBlacklistedExtensions.value = emptySet()
}
}, "GraphicsDriverExtensions").start()
}


private fun loadDxvkConfigState(container: Container = shortcut.container) {
val configStr = if (shouldUseShortcutOverrides(container))
getShortcutSetting("dxwrapperConfig", container.getDXWrapperConfig())
Expand Down Expand Up @@ -2442,9 +2423,9 @@ class ShortcutSettingsComposeDialog private constructor(
// Desktop theme is stored as compound "THEME,TYPE,COLOR".
val desktopThemeArr = state.desktopThemeEntries.value
if (desktopThemeArr.isNotEmpty()) {
val themePart = container.getDesktopTheme().split(",").firstOrNull()?.trim() ?: ""
val themeIdx = desktopThemeArr.indexOfFirst { it.equals(themePart, ignoreCase = true) }
state.selectedDesktopTheme.intValue = if (themeIdx >= 0) themeIdx else 0
state.selectedDesktopTheme.intValue =
WineThemeManager.ThemeInfo(container.getDesktopTheme()).theme.ordinal
.coerceIn(0, desktopThemeArr.size - 1)
}

val directX = mutableListOf<WinComponentItem>()
Expand Down
Loading
Loading