From 179ccb78055a521eef5118e551de225f7959d314 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 25 Jan 2026 03:27:39 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9C=A8=20Windows=20=E5=B9=B3=E5=8F=B0?= =?UTF-8?q?=E4=B8=8A=20GameCrashWindow=20=E6=A0=87=E9=A2=98=E6=A0=8F?= =?UTF-8?q?=E5=BA=94=E5=BD=93=E8=B7=9F=E9=9A=8F=E6=B7=B1=E8=89=B2=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E8=AE=BE=E7=BD=AE=20(#5319)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/jackhuang/hmcl/theme/Themes.java | 48 +++++++++++++++++-- .../jackhuang/hmcl/ui/GameCrashWindow.java | 3 ++ .../java/org/jackhuang/hmcl/ui/LogWindow.java | 38 +-------------- 3 files changed, 49 insertions(+), 40 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/theme/Themes.java b/HMCL/src/main/java/org/jackhuang/hmcl/theme/Themes.java index 3e01293ef..4a855977f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/theme/Themes.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/theme/Themes.java @@ -17,6 +17,7 @@ */ package org.jackhuang.hmcl.theme; +import com.sun.jna.Pointer; import javafx.beans.Observable; import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanBinding; @@ -24,7 +25,10 @@ import javafx.beans.binding.ObjectBinding; import javafx.beans.binding.ObjectExpression; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; +import javafx.event.EventHandler; import javafx.scene.paint.Color; +import javafx.stage.Stage; +import javafx.stage.WindowEvent; import org.glavo.monetfx.Brightness; import org.glavo.monetfx.ColorScheme; import org.glavo.monetfx.Contrast; @@ -32,14 +36,17 @@ import org.glavo.monetfx.beans.property.ColorSchemeProperty; import org.glavo.monetfx.beans.property.ReadOnlyColorSchemeProperty; import org.glavo.monetfx.beans.property.SimpleColorSchemeProperty; import org.jackhuang.hmcl.ui.FXUtils; +import org.jackhuang.hmcl.ui.WindowsNativeUtils; +import org.jackhuang.hmcl.util.platform.NativeUtils; +import org.jackhuang.hmcl.util.platform.OSVersion; import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.SystemUtils; +import org.jackhuang.hmcl.util.platform.windows.Dwmapi; +import org.jackhuang.hmcl.util.platform.windows.WinConstants; import org.jackhuang.hmcl.util.platform.windows.WinReg; +import org.jackhuang.hmcl.util.platform.windows.WinTypes; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.Objects; +import java.util.*; import static org.jackhuang.hmcl.setting.ConfigHolder.config; @@ -160,6 +167,39 @@ public final class Themes { return darkMode; } + public static void applyNativeDarkMode(Stage stage) { + if (OperatingSystem.SYSTEM_VERSION.isAtLeast(OSVersion.WINDOWS_11) && NativeUtils.USE_JNA && Dwmapi.INSTANCE != null) { + ChangeListener listener = FXUtils.onWeakChange(Themes.darkModeProperty(), darkMode -> { + if (stage.isShowing()) { + WindowsNativeUtils.getWindowHandle(stage).ifPresent(handle -> { + if (handle == WinTypes.HANDLE.INVALID_VALUE) + return; + + Dwmapi.INSTANCE.DwmSetWindowAttribute( + new WinTypes.HANDLE(Pointer.createConstant(handle)), + WinConstants.DWMWA_USE_IMMERSIVE_DARK_MODE, + new WinTypes.BOOLByReference(new WinTypes.BOOL(darkMode)), + WinTypes.BOOL.SIZE + ); + }); + } + }); + stage.getProperties().put("Themes.applyNativeDarkMode.listener", listener); + + if (stage.isShowing()) { + listener.changed(null, false, Themes.darkModeProperty().get()); + } else { + stage.addEventFilter(WindowEvent.WINDOW_SHOWN, new EventHandler<>() { + @Override + public void handle(WindowEvent event) { + stage.removeEventFilter(WindowEvent.WINDOW_SHOWN, this); + listener.changed(null, false, Themes.darkModeProperty().get()); + } + }); + } + } + } + private Themes() { } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java index 03c32f3e8..6cc322ec9 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java @@ -40,6 +40,7 @@ import org.jackhuang.hmcl.launch.ProcessListener; import org.jackhuang.hmcl.setting.StyleSheets; import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Task; +import org.jackhuang.hmcl.theme.Themes; import org.jackhuang.hmcl.ui.construct.MessageDialogPane; import org.jackhuang.hmcl.ui.construct.TwoLineListItem; import org.jackhuang.hmcl.util.Lang; @@ -90,6 +91,8 @@ public class GameCrashWindow extends Stage { private final List logs; public GameCrashWindow(ManagedProcess managedProcess, ProcessListener.ExitType exitType, DefaultGameRepository repository, Version version, LaunchOptions launchOptions, List logs) { + Themes.applyNativeDarkMode(this); + this.managedProcess = managedProcess; this.exitType = exitType; this.repository = repository; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.java index 47394f98e..c049c76b5 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.java @@ -21,7 +21,6 @@ import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXCheckBox; import com.jfoenix.controls.JFXComboBox; import com.jfoenix.controls.JFXListView; -import com.sun.jna.Pointer; import javafx.application.Platform; import javafx.beans.InvalidationListener; import javafx.beans.binding.Bindings; @@ -29,7 +28,6 @@ import javafx.beans.property.*; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.css.PseudoClass; -import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Scene; @@ -38,7 +36,6 @@ import javafx.scene.input.KeyCode; import javafx.scene.input.MouseButton; import javafx.scene.layout.*; import javafx.stage.Stage; -import javafx.stage.WindowEvent; import org.jackhuang.hmcl.game.GameDumpGenerator; import org.jackhuang.hmcl.game.Log; import org.jackhuang.hmcl.setting.StyleSheets; @@ -48,9 +45,6 @@ import org.jackhuang.hmcl.ui.construct.NoneMultipleSelectionModel; import org.jackhuang.hmcl.ui.construct.SpinnerPane; import org.jackhuang.hmcl.util.*; import org.jackhuang.hmcl.util.platform.*; -import org.jackhuang.hmcl.util.platform.windows.Dwmapi; -import org.jackhuang.hmcl.util.platform.windows.WinConstants; -import org.jackhuang.hmcl.util.platform.windows.WinTypes; import java.io.IOException; import java.nio.file.Files; @@ -87,41 +81,13 @@ public final class LogWindow extends Stage { private final LogWindowImpl impl; private final ManagedProcess gameProcess; - @SuppressWarnings("unused") - private Object windowsDarkModeListenerHolder; - - { - if (OperatingSystem.SYSTEM_VERSION.isAtLeast(OSVersion.WINDOWS_11) && NativeUtils.USE_JNA && Dwmapi.INSTANCE != null) { - this.addEventFilter(WindowEvent.WINDOW_SHOWN, new EventHandler<>() { - @Override - public void handle(WindowEvent event) { - LogWindow.this.removeEventFilter(WindowEvent.WINDOW_SHOWN, this); - - windowsDarkModeListenerHolder = FXUtils.onWeakChangeAndOperate(Themes.darkModeProperty(), darkMode -> { - if (LogWindow.this.isShowing()) { - WindowsNativeUtils.getWindowHandle(LogWindow.this).ifPresent(handle -> { - if (handle == WinTypes.HANDLE.INVALID_VALUE) - return; - - Dwmapi.INSTANCE.DwmSetWindowAttribute( - new WinTypes.HANDLE(Pointer.createConstant(handle)), - WinConstants.DWMWA_USE_IMMERSIVE_DARK_MODE, - new WinTypes.BOOLByReference(new WinTypes.BOOL(darkMode)), - WinTypes.BOOL.SIZE - ); - }); - } - }); - } - }); - } - } - public LogWindow(ManagedProcess gameProcess) { this(gameProcess, new CircularArrayList<>()); } public LogWindow(ManagedProcess gameProcess, CircularArrayList logs) { + Themes.applyNativeDarkMode(this); + this.logs = logs; this.impl = new LogWindowImpl(); setScene(new Scene(impl, 800, 480));