From 7f04cdd6b117431ab07668616bca7734688ae6e3 Mon Sep 17 00:00:00 2001 From: Glavo Date: Mon, 28 Jul 2025 15:58:13 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9C=A8=E6=97=A5=E5=BF=97=E4=B8=AD=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E6=9B=B4=E5=A4=9A=E7=B3=BB=E7=BB=9F=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=20(#4126)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/jackhuang/hmcl/Launcher.java | 7 +++ .../java/org/jackhuang/hmcl/ui/FXUtils.java | 45 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/Launcher.java b/HMCL/src/main/java/org/jackhuang/hmcl/Launcher.java index 8d0d8c183..efa971ced 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/Launcher.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/Launcher.java @@ -19,6 +19,7 @@ package org.jackhuang.hmcl; import javafx.application.Application; import javafx.application.Platform; +import javafx.beans.value.ObservableBooleanValue; import javafx.scene.control.Alert; import javafx.scene.control.Alert.AlertType; import javafx.scene.control.ButtonType; @@ -27,6 +28,7 @@ import javafx.scene.input.DataFormat; import javafx.stage.Stage; import org.jackhuang.hmcl.setting.ConfigHolder; import org.jackhuang.hmcl.setting.SambaException; +import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.util.FileSaver; import org.jackhuang.hmcl.task.AsyncTaskExecutor; import org.jackhuang.hmcl.task.Schedulers; @@ -54,6 +56,8 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; +import java.util.Objects; +import java.util.Optional; import java.util.concurrent.TimeUnit; import static org.jackhuang.hmcl.ui.FXUtils.runInFX; @@ -78,6 +82,9 @@ public final class Launcher extends Application { LOG.warning("Failed to get prism pipeline", e); } + LOG.info("Dark Mode: " + Optional.ofNullable(FXUtils.DARK_MODE).map(ObservableBooleanValue::get).orElse(false)); + LOG.info("Reduced Motion: " + Objects.requireNonNullElse(FXUtils.REDUCED_MOTION, false)); + try { try { ConfigHolder.init(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java index ba4eb2554..c350cd1bf 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java @@ -25,9 +25,12 @@ import javafx.beans.InvalidationListener; import javafx.beans.Observable; import javafx.beans.WeakInvalidationListener; import javafx.beans.WeakListener; +import javafx.beans.binding.Bindings; import javafx.beans.property.BooleanProperty; import javafx.beans.property.Property; +import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.value.*; +import javafx.collections.ObservableMap; import javafx.event.Event; import javafx.event.EventDispatcher; import javafx.event.EventType; @@ -66,6 +69,7 @@ import org.jackhuang.hmcl.util.javafx.ExtendedProperties; import org.jackhuang.hmcl.util.javafx.SafeStringConverter; import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.SystemUtils; +import org.jetbrains.annotations.Nullable; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -79,6 +83,8 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.*; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.lang.ref.WeakReference; import java.net.*; import java.nio.file.Files; @@ -105,6 +111,11 @@ public final class FXUtils { public static final int JAVAFX_MAJOR_VERSION; + /// @see Platform.Preferences + public static final @Nullable ObservableMap PREFERENCES; + public static final @Nullable ObservableBooleanValue DARK_MODE; + public static final @Nullable Boolean REDUCED_MOTION; + static { String jfxVersion = System.getProperty("javafx.version"); int majorVersion = -1; @@ -115,6 +126,40 @@ public final class FXUtils { } } JAVAFX_MAJOR_VERSION = majorVersion; + + ObservableMap preferences = null; + ObservableBooleanValue darkMode = null; + Boolean reducedMotion = null; + if (JAVAFX_MAJOR_VERSION >= 22) { + try { + MethodHandles.Lookup lookup = MethodHandles.publicLookup(); + Class preferencesClass = Class.forName("javafx.application.Platform$Preferences"); + @SuppressWarnings("unchecked") + var preferences0 = (ObservableMap) lookup.findStatic(Platform.class, "getPreferences", MethodType.methodType(preferencesClass)) + .invoke(); + preferences = preferences0; + + @SuppressWarnings("unchecked") + var colorSchemeProperty = + (ReadOnlyObjectProperty>) + lookup.findVirtual(preferencesClass, "colorSchemeProperty", MethodType.methodType(ReadOnlyObjectProperty.class)) + .invoke(preferences); + + darkMode = Bindings.createBooleanBinding(() -> + "DARK".equals(colorSchemeProperty.get().name()), colorSchemeProperty); + + if (JAVAFX_MAJOR_VERSION >= 24) { + reducedMotion = (boolean) + lookup.findVirtual(preferencesClass, "isReducedMotion", MethodType.methodType(boolean.class)) + .invoke(preferences); + } + } catch (Throwable e) { + LOG.warning("Failed to get preferences", e); + } + } + PREFERENCES = preferences; + DARK_MODE = darkMode; + REDUCED_MOTION = reducedMotion; } public static final String DEFAULT_MONOSPACE_FONT = OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS ? "Consolas" : "Monospace";