在 Linux 平台使用 dbus-send 检测深色模式设置 (#5317)

This commit is contained in:
Glavo
2026-02-01 16:05:19 +08:00
committed by GitHub
parent 5a518cec03
commit 17be25c036
2 changed files with 49 additions and 3 deletions

View File

@@ -36,6 +36,7 @@ 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.util.io.FileUtils;
import org.jackhuang.hmcl.ui.WindowsNativeUtils;
import org.jackhuang.hmcl.util.platform.NativeUtils;
import org.jackhuang.hmcl.util.platform.OSVersion;
@@ -46,9 +47,12 @@ 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.nio.file.Path;
import java.time.Duration;
import java.util.*;
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
/// @author Glavo
public final class Themes {
@@ -113,6 +117,7 @@ public final class Themes {
if (defaultBrightness != null)
return defaultBrightness;
LOG.info("Detecting system theme brightness");
Brightness brightness = Brightness.DEFAULT;
if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) {
WinReg reg = WinReg.INSTANCE;
@@ -130,7 +135,38 @@ public final class Themes {
// If the key does not exist, it means Light mode is used
brightness = Brightness.LIGHT;
}
} else if (OperatingSystem.CURRENT_OS == OperatingSystem.LINUX) {
Path dbusSend = SystemUtils.which("dbus-send");
if (dbusSend != null) {
try {
String[] result = SystemUtils.run(List.of(
FileUtils.getAbsolutePath(dbusSend),
"--session",
"--print-reply=literal",
"--reply-timeout=1000",
"--dest=org.freedesktop.portal.Desktop",
"/org/freedesktop/portal/desktop",
"org.freedesktop.portal.Settings.Read",
"string:org.freedesktop.appearance",
"string:color-scheme"
), Duration.ofSeconds(2)).trim().split(" ");
if (result.length > 0) {
String value = result[result.length - 1];
// 1: prefer dark
// 2: prefer light
if ("1".equals(value)) {
brightness = Brightness.DARK;
} else if ("2".equals(value)) {
brightness = Brightness.LIGHT;
}
}
} catch (Exception e) {
LOG.warning("Failed to get system theme from D-Bus", e);
}
}
}
LOG.info("Detected system theme brightness: " + brightness);
return defaultBrightness = brightness;
}

View File

@@ -29,6 +29,7 @@ import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
@@ -75,12 +76,21 @@ public final class SystemUtils {
return managedProcess.getProcess().waitFor();
}
private static final Duration DEFAULT_MAX_WAIT_TIME = Duration.ofSeconds(15);
public static String run(String... command) throws Exception {
return run(Arrays.asList(command),
inputStream -> IOUtils.readFullyAsString(inputStream, OperatingSystem.NATIVE_CHARSET));
return run(List.of(command), DEFAULT_MAX_WAIT_TIME);
}
public static String run(List<String> command, Duration maxWaitTime) throws Exception {
return run(command, inputStream -> IOUtils.readFullyAsString(inputStream, OperatingSystem.NATIVE_CHARSET), maxWaitTime);
}
public static <T> T run(List<String> command, ExceptionalFunction<InputStream, T, ?> convert) throws Exception {
return run(command, convert, DEFAULT_MAX_WAIT_TIME);
}
public static <T> T run(List<String> command, ExceptionalFunction<InputStream, T, ?> convert, Duration maxWaitTime) throws Exception {
Process process = new ProcessBuilder(command)
.redirectError(ProcessBuilder.Redirect.DISCARD)
.start();
@@ -90,7 +100,7 @@ public final class SystemUtils {
Lang.wrap(() -> convert.apply(inputStream)),
Schedulers.io());
if (!process.waitFor(15, TimeUnit.SECONDS))
if (!process.waitFor(maxWaitTime.toMillis(), TimeUnit.MILLISECONDS))
throw new TimeoutException();
if (process.exitValue() != 0)