[Bugfix] 修复 #6526: macOS 下 主题模式-跟随系统设置 失效 (#6555)

Fixes #6526
This commit is contained in:
ToobLac
2026-09-09 20:58:39 +08:00
committed by GitHub
parent 8767cc0e98
commit 450504ceda
3 changed files with 69 additions and 16 deletions
@@ -24,8 +24,7 @@ import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.binding.ObjectBinding;
import javafx.beans.binding.ObjectExpression;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.*;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.SetChangeListener;
@@ -80,6 +79,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -283,6 +283,9 @@ public final class Themes {
colorScheme
);
/// Whether the current color scheme brightness is inherited from system.
private static final ReadOnlyBooleanWrapper autoBrightness = new ReadOnlyBooleanWrapper();
/// The current JavaFX launcher background and its node opacity.
private static final ReadOnlyObjectWrapper<LauncherBackground> background = new ReadOnlyObjectWrapper<>(
new LauncherBackground(
@@ -380,6 +383,35 @@ public final class Themes {
}
static {
Supplier<@Nullable Brightness> effectiveBrightnessSupplier = () -> {
try {
return ThemePackManager.resolveCurrentThemeBrightness(ThemePackManager.currentResolveContext());
} catch (IOException | RuntimeException e) {
return null;
}
};
InvalidationListener autoBrightnessListener = o -> {
boolean auto;
if (settings().getThemeAppearanceOverrides().contains(LauncherSettings.THEME_APPEARANCE_BRIGHTNESS_MODE)) {
String val = settings().themeBrightnessModeProperty().get();
auto = val == null || switch (val.trim().toLowerCase(Locale.ROOT)) {
case "light", "dark" -> false;
default -> true;
};
} else {
auto = effectiveBrightnessSupplier.get() == null;
}
autoBrightness.set(auto);
};
settings().selectedThemeProperty().addListener(autoBrightnessListener);
settings().getThemeAppearanceOverrides().addListener(autoBrightnessListener);
settings().themeBrightnessModeProperty().addListener(autoBrightnessListener);
settings().backgroundTypeProperty().addListener(autoBrightnessListener);
if (FXUtils.DARK_MODE != null) {
FXUtils.DARK_MODE.addListener(autoBrightnessListener);
}
autoBrightnessListener.invalidated(null);
ChangeListener<ResolvedTheme> listener = (observable, oldValue, newValue) -> {
if (!Objects.equals(oldValue, newValue)) {
colorScheme.set(newValue.toColorScheme());
@@ -433,7 +465,7 @@ public final class Themes {
}
String themeBrightnessMode = settings().themeBrightnessModeProperty().get();
return switch (Objects.toString(themeBrightnessMode, "").toLowerCase(Locale.ROOT).trim()) {
return switch (Objects.toString(themeBrightnessMode, "").trim().toLowerCase(Locale.ROOT)) {
case "light" -> Brightness.LIGHT;
case "dark" -> Brightness.DARK;
default -> getAutomaticBrightness();
@@ -444,24 +476,16 @@ public final class Themes {
///
/// @return the effective launcher brightness
public static Brightness getCurrentBrightness() {
Brightness contextBrightness = getThemeConditionBrightness();
if (!settings().getThemeAppearanceOverrides().contains(LauncherSettings.THEME_APPEARANCE_BRIGHTNESS_MODE)) {
Brightness contextBrightness = getThemeConditionBrightness();
try {
return Objects.requireNonNullElse(
ThemePackManager.resolveCurrentThemeBrightness(ThemeResolveContext.current(contextBrightness)),
contextBrightness);
} catch (IOException | RuntimeException e) {
return contextBrightness;
} catch (IOException | RuntimeException ignored) {
}
}
String themeBrightnessMode = settings().themeBrightnessModeProperty().get();
return switch (Objects.toString(themeBrightnessMode, "").toLowerCase(Locale.ROOT).trim()) {
case "auto" -> getAutomaticBrightness();
case "dark" -> Brightness.DARK;
case "light" -> Brightness.LIGHT;
default -> getAutomaticBrightness();
};
return contextBrightness;
}
/// Returns the brightness requested by the current system or platform settings.
@@ -1119,6 +1143,11 @@ public final class Themes {
return darkMode;
}
/// Returns whether the current color scheme brightness is inherited from system.
public static ReadOnlyBooleanProperty autoBrightnessProperty() {
return autoBrightness.getReadOnlyProperty();
}
/// Applies native dark-mode integration to a JavaFX stage where the platform supports it.
public static void applyNativeDarkMode(Stage stage) {
if (OperatingSystem.SYSTEM_VERSION.isAtLeast(OSVersion.WINDOWS_11) && NativeUtils.USE_JNA && Dwmapi.INSTANCE != null) {
@@ -18,6 +18,8 @@
package org.jackhuang.hmcl.ui;
import com.sun.jna.Pointer;
import javafx.beans.property.ReadOnlyBooleanProperty;
import org.jackhuang.hmcl.theme.Themes;
import org.jackhuang.hmcl.util.platform.macos.ObjectiveCRuntime;
import org.jetbrains.annotations.Nullable;
@@ -56,8 +58,30 @@ public final class MacOSNativeUtils {
return pointer == null || Pointer.nativeValue(pointer) == 0;
}
private static final ReadOnlyBooleanProperty autoBrightness = Themes.autoBrightnessProperty();
static {
FXUtils.onChange(autoBrightness, b -> setAppearance(Themes.darkModeProperty().get()));
}
public static void setAppearance(boolean dark) {
setAppearance(dark, false);
if (autoBrightness.get()) {
clearAppearance();
} else {
setAppearance(dark, false);
}
}
public static void clearAppearance() {
if (nsApp == null) return;
try {
var objc = ObjectiveCRuntime.INSTANCE;
Pointer setSel = objc.sel_registerName("setAppearance:");
objc.objc_msgSend(nsApp, setSel, Pointer.NULL);
} catch (Throwable t) {
LOG.warning("Failed to set macOS appearance", t);
}
}
public static void setAppearance(boolean dark, boolean highContrast) {
@@ -435,7 +435,7 @@ public class PersonalizationPage extends StackPane {
LineSelectButton<String> brightnessPane = new LineSelectButton<>();
brightnessPane.setTitle(i18n("settings.launcher.brightness"));
brightnessPane.setConverter(name -> i18n("settings.launcher.brightness."
+ Objects.requireNonNullElse(name, "auto")));
+ Objects.requireNonNullElse(name, "auto").trim().toLowerCase(Locale.ROOT)));
brightnessPane.setItems(Arrays.asList("auto", "light", "dark"));
bindThemeAppearanceLineSelectButton(
brightnessPane,