From e94ded628adcfcbd12f207eb6443b00482e02e6e Mon Sep 17 00:00:00 2001
From: Loskh <1020612624@qq.com>
Date: Mon, 5 Jan 2026 22:42:04 +0800
Subject: [PATCH] fix: respect system dark mode setting
---
.../Interface/Internal/InterfaceManager.cs | 43 ++++++++++++++++++-
.../Windows/Settings/Tabs/SettingsTabLook.cs | 9 +++-
Dalamud/Memory/MemoryHelper.cs | 25 +++++++++++
3 files changed, 75 insertions(+), 2 deletions(-)
diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs
index 96fcb7dfd..72a9eb0f2 100644
--- a/Dalamud/Interface/Internal/InterfaceManager.cs
+++ b/Dalamud/Interface/Internal/InterfaceManager.cs
@@ -32,6 +32,7 @@ using Dalamud.Interface.Windowing;
using Dalamud.Interface.Windowing.Persistence;
using Dalamud.IoC.Internal;
using Dalamud.Logging.Internal;
+using Dalamud.Memory;
using Dalamud.Plugin.Services;
using Dalamud.Utility;
using Dalamud.Utility.Timing;
@@ -500,6 +501,34 @@ internal partial class InterfaceManager : IInternalDisposableService
ImGuiHelpers.ClearStacksOnContext();
}
+ ///
+ /// Applies immersive dark mode to the game window based on the current system theme setting.
+ ///
+ internal void SetImmersiveModeFromSystemTheme()
+ {
+ bool useDark = this.IsSystemInDarkMode();
+ this.SetImmersiveMode(useDark);
+ }
+
+ ///
+ /// Checks whether the system use dark mode.
+ ///
+ /// Returns true if dark mode is preferred.
+ internal bool IsSystemInDarkMode()
+ {
+ try
+ {
+ using var key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(
+ @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize");
+ var value = key?.GetValue("AppsUseLightTheme") as int?;
+ return value != 1;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
///
/// Toggle Windows 11 immersive mode on the game window.
///
@@ -744,6 +773,18 @@ internal partial class InterfaceManager : IInternalDisposableService
private void WndProcHookManagerOnPreWndProc(WndProcEventArgs args)
{
+ if (args.Message == WM.WM_SETTINGCHANGE)
+ {
+ if (this.dalamudConfiguration.WindowIsImmersive)
+ {
+ if (MemoryHelper.EqualsZeroTerminatedWideString("ImmersiveColorSet", args.LParam) ||
+ MemoryHelper.EqualsZeroTerminatedWideString("VisualStyleChanged", args.LParam))
+ {
+ this.SetImmersiveModeFromSystemTheme();
+ }
+ }
+ }
+
var r = this.backend?.ProcessWndProcW(args.Hwnd, args.Message, args.WParam, args.LParam);
if (r is not null)
args.SuppressWithValue(r.Value);
@@ -858,7 +899,7 @@ internal partial class InterfaceManager : IInternalDisposableService
{
// Requires that game window to be there, which will be the case once game swap chain is initialized.
if (Service.Get().WindowIsImmersive)
- this.SetImmersiveMode(true);
+ this.SetImmersiveModeFromSystemTheme();
}
catch (Exception ex)
{
diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs
index 9b2c418b6..3bb16ca74 100644
--- a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs
+++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs
@@ -65,7 +65,14 @@ internal sealed class SettingsTabLook : SettingsTab
{
try
{
- Service.GetNullable()?.SetImmersiveMode(b);
+ if (b)
+ {
+ Service.GetNullable()?.SetImmersiveModeFromSystemTheme();
+ }
+ else
+ {
+ Service.GetNullable()?.SetImmersiveMode(false);
+ }
}
catch (Exception ex)
{
diff --git a/Dalamud/Memory/MemoryHelper.cs b/Dalamud/Memory/MemoryHelper.cs
index 2eae1be6d..f0f4c991f 100644
--- a/Dalamud/Memory/MemoryHelper.cs
+++ b/Dalamud/Memory/MemoryHelper.cs
@@ -264,6 +264,31 @@ public static unsafe class MemoryHelper
}
}
+ ///
+ /// Compares a UTF-16 character span with a null-terminated UTF-16 string at .
+ ///
+ /// UTF-16 character span (e.g., from a string literal).
+ /// Address of null-terminated UTF-16 (wide) string, as used by Windows APIs.
+ /// if equal; otherwise, .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe bool EqualsZeroTerminatedWideString(
+ scoped ReadOnlySpan charSpan,
+ nint memoryAddress)
+ {
+ if (memoryAddress == 0)
+ return charSpan.Length == 0;
+
+ char* p = (char*)memoryAddress;
+
+ foreach (char c in charSpan)
+ {
+ if (*p++ != c)
+ return false;
+ }
+
+ return *p == '\0';
+ }
+
///
/// Read a UTF-8 encoded string from a specified memory address.
///