Unverified Commit 87e97798 authored by Gabriel Souza's avatar Gabriel Souza Committed by GitHub

Support linux system theme (#491)

parent 76bc8837
......@@ -90,7 +90,7 @@ jobs:
sudo apt-get install gcc-9 g++-9 -y
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 60 --slave /usr/bin/g++ g++ /usr/bin/g++-9
sudo update-alternatives --config gcc
sudo apt-get install ninja-build fontconfig libfontconfig1-dev libglu1-mesa-dev libxrandr-dev zip xvfb -y
sudo apt-get install ninja-build fontconfig libfontconfig1-dev libglu1-mesa-dev libxrandr-dev libdbus-1-dev zip xvfb -y
sudo Xvfb :0 -screen 0 1280x720x24 &
export DISPLAY=:0
./gradlew --stacktrace --info -Pskiko.native.enabled=true :skiko:linuxX64Test :skiko:awtTest
......
......@@ -806,6 +806,7 @@ fun createCompileJvmBindingsTask(
}
OS.Linux -> {
includeHeadersNonRecursive(jdkHome.resolve("include/linux"))
includeHeadersNonRecursive(runPkgConfig("dbus-1"))
osFlags = arrayOf(
*buildType.clangFlags,
"-fPIC",
......
import java.io.File
import java.util.concurrent.TimeUnit
import org.gradle.api.GradleException
fun runPkgConfig(
vararg packageNames: String,
): List<File> {
val process = ProcessBuilder(
"pkg-config", "--cflags", *packageNames
).run {
environment()["PKG_CONFIG_ALLOW_SYSTEM_LIBS"] = "1"
start()
}.also { it.waitFor(10, TimeUnit.SECONDS) }
if (process.exitValue() != 0) {
throw GradleException("Error executing pkg-config: ${process.errorStream.bufferedReader().readText()}")
}
return process.inputStream.bufferedReader().readText().split(" ").map { it.trim() }
.map { it.removePrefix("-I") }
.map(::File)
}
\ No newline at end of file
......@@ -17,7 +17,7 @@ ENV PATH=/usr/lib/binutils-2.26/bin:$PATH
ENV DEPOT_TOOLS=/usr/depot_tools
ENV PATH=$DEPOT_TOOLS:$PATH
RUN apt-get install git python wget -y && \
apt-get install fontconfig libfontconfig1-dev libglu1-mesa-dev libxrandr-dev curl zip -y && \
apt-get install fontconfig libfontconfig1-dev libglu1-mesa-dev libxrandr-dev libdbus-1-dev curl zip -y && \
git clone 'https://chromium.googlesource.com/chromium/tools/depot_tools.git' $DEPOT_TOOLS
# Install Java
......
......@@ -3,7 +3,7 @@ ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update -y
RUN apt-get install binutils build-essential -y
RUN apt-get install software-properties-common -y
RUN apt-get install python git fontconfig libfontconfig1-dev libglu1-mesa-dev libxrandr-dev curl wget -y
RUN apt-get install python git fontconfig libfontconfig1-dev libglu1-mesa-dev libxrandr-dev libdbus-1-dev curl wget -y
RUN apt-get install openjdk-11-jdk -y
RUN apt-get install clang-11 -y && \
apt-get remove g++ -y && \
......
......@@ -88,13 +88,6 @@ extern "C"
return (float) getDpiScaleByDisplay(dsi_x11->display);
}
JNIEXPORT jint JNICALL Java_org_jetbrains_skiko_SystemTheme_1awtKt_getCurrentSystemTheme(JNIEnv *env, jobject topLevel)
{
// Unknown.
return 2;
}
JNIEXPORT jfloat JNICALL Java_org_jetbrains_skiko_SetupKt_linuxGetSystemDpiScale(JNIEnv *env, jobject layer)
{
return (float) getDpiScale();
......
#include <jawt_md.h>
#include <dbus/dbus.h>
#include <iostream>
#include <dlfcn.h>
#include "jni_helpers.h"
static void* loadLibDbus() {
static void* result = nullptr;
if (result != nullptr) return result;
result = dlopen("libdbus-1.so", RTLD_LAZY | RTLD_LOCAL);
return result;
}
static DBusMessage* dbus_message_new_method_call_dynamic(const char *bus_name, const char *path, const char *iface, const char *method) {
typedef DBusMessage* (*dbus_message_new_method_call_t)(const char*, const char*, const char*, const char*);
static dbus_message_new_method_call_t func = nullptr;
if(!func) {
void* lib = loadLibDbus();
if(!lib) return nullptr;
func = (dbus_message_new_method_call_t) dlsym(lib, "dbus_message_new_method_call");
}
if(!func) return nullptr;
return func(bus_name, path, iface, method);
}
static dbus_bool_t dbus_message_append_args_dynamic(DBusMessage *message, int first_arg_type, ...) {
typedef dbus_bool_t (*dbus_message_append_args_valist_t)(DBusMessage *, int, va_list);
static dbus_message_append_args_valist_t func = nullptr;
if (!func) {
void *lib = loadLibDbus();
if (!lib) return false;
func = (dbus_message_append_args_valist_t) dlsym(lib, "dbus_message_append_args_valist");
}
if (!func) return false;
va_list var_args;
va_start(var_args, first_arg_type);
dbus_bool_t result = func(message, first_arg_type, var_args);
va_end(var_args);
return result;
}
static DBusMessage* dbus_connection_send_with_reply_and_block_dynamic(DBusConnection *connection, DBusMessage *message, int timeout_milliseconds, DBusError *error) {
typedef DBusMessage* (*dbus_connection_send_with_reply_and_block_t)(DBusConnection*, DBusMessage*, int, DBusError*);
static dbus_connection_send_with_reply_and_block_t func = nullptr;
if(!func) {
void* lib = loadLibDbus();
if(!lib) return nullptr;
func = (dbus_connection_send_with_reply_and_block_t) dlsym(lib, "dbus_connection_send_with_reply_and_block");
}
if(!func) return nullptr;
return func(connection, message, timeout_milliseconds, error);
}
static bool dbus_message_unref_dynamic(DBusMessage *message) {
typedef void* (*dbus_message_unref_t)(DBusMessage*);
static dbus_message_unref_t func = nullptr;
if(!func) {
void* lib = loadLibDbus();
if(!lib) return false;
func = (dbus_message_unref_t) dlsym(lib, "dbus_message_unref");
}
if(!func) return false;
func(message);
return true;
}
static dbus_bool_t dbus_error_is_set_dynamic(const DBusError *error) {
typedef dbus_bool_t (*dbus_error_is_set_t)(const DBusError*);
static dbus_error_is_set_t func = nullptr;
if(!func) {
void* lib = loadLibDbus();
if(!lib) return true;
func = (dbus_error_is_set_t) dlsym(lib, "dbus_error_is_set");
}
if(!func) return true;
return func(error);
}
static dbus_bool_t dbus_message_iter_init_dynamic(DBusMessage *message, DBusMessageIter *iter) {
typedef dbus_bool_t (*dbus_message_iter_init_t)(DBusMessage*, DBusMessageIter*);
static dbus_message_iter_init_t func = nullptr;
if(!func) {
void* lib = loadLibDbus();
if(!lib) return false;
func = (dbus_message_iter_init_t) dlsym(lib, "dbus_message_iter_init");
}
if(!func) return false;
return func(message, iter);
}
static int dbus_message_iter_get_arg_type_dynamic(DBusMessageIter *iter) {
typedef int (*dbus_message_iter_get_arg_type_t)(DBusMessageIter*);
static dbus_message_iter_get_arg_type_t func = nullptr;
if(!func) {
void* lib = loadLibDbus();
if(!lib) return -1;
func = (dbus_message_iter_get_arg_type_t) dlsym(lib, "dbus_message_iter_get_arg_type");
}
if(!func) return -1;
return func(iter);
}
static bool dbus_message_iter_recurse_dynamic(DBusMessageIter *iter, DBusMessageIter *sub) {
typedef void (*dbus_message_iter_recurse_t)(DBusMessageIter*, DBusMessageIter*);
static dbus_message_iter_recurse_t func = nullptr;
if(!func) {
void* lib = loadLibDbus();
if(!lib) return false;
func = (dbus_message_iter_recurse_t) dlsym(lib, "dbus_message_iter_recurse");
}
if(!func) return false;
func(iter, sub);
return true;
}
static bool dbus_message_iter_get_basic_dynamic(DBusMessageIter *iter, void *value) {
typedef void (*dbus_message_iter_get_basic_t)(DBusMessageIter*, void*);
static dbus_message_iter_get_basic_t func = nullptr;
if(!func) {
void* lib = loadLibDbus();
if(!lib) return false;
func = (dbus_message_iter_get_basic_t) dlsym(lib, "dbus_message_iter_get_basic");
}
if(!func) return false;
func(iter, value);
return true;
}
static DBusConnection* dbus_bus_get_dynamic(DBusBusType type, DBusError *error) {
typedef DBusConnection* (*dbus_bus_get_t)(DBusBusType, DBusError*);
static dbus_bus_get_t func = nullptr;
if(!func) {
void* lib = loadLibDbus();
if(!lib) return nullptr;
func = (dbus_bus_get_t) dlsym(lib, "dbus_bus_get");
}
if(!func) return nullptr;
return func(type, error);
}
static bool dbus_error_init_dynamic(DBusError *error) {
typedef void (*dbus_error_init_t)(DBusError*);
static dbus_error_init_t func = nullptr;
if(!func) {
void* lib = loadLibDbus();
if(!lib) return false;
func = (dbus_error_init_t) dlsym(lib, "dbus_error_init");
}
if(!func) return false;
func(error);
return true;
}
extern "C"
{
static DBusMessage *getSetting(DBusConnection *connection, std::string key, std::string value)
{
DBusError error;
if(!dbus_error_init_dynamic(&error)) return nullptr;
DBusMessage *message = dbus_message_new_method_call_dynamic(
"org.freedesktop.portal.Desktop",
"/org/freedesktop/portal/desktop",
"org.freedesktop.portal.Settings",
"Read"
);
if(!message) return nullptr;
dbus_bool_t wasSuccessfully = dbus_message_append_args_dynamic(
message,
DBUS_TYPE_STRING, &key,
DBUS_TYPE_STRING, &value,
DBUS_TYPE_INVALID
);
if (!wasSuccessfully) return nullptr;
DBusMessage *result = dbus_connection_send_with_reply_and_block_dynamic(
connection,
message,
DBUS_TIMEOUT_USE_DEFAULT,
&error
);
if(!result) return nullptr;
if(!dbus_message_unref_dynamic(message)) return nullptr;
if (dbus_error_is_set_dynamic(&error)) return nullptr;
return result;
}
static bool parseSettingValue(DBusMessage *message, int type, void *value)
{
DBusMessageIter messageIter[3];
if(!dbus_message_iter_init_dynamic(message, &messageIter[0])) return false;
if (dbus_message_iter_get_arg_type_dynamic(&messageIter[0]) != DBUS_TYPE_VARIANT) return false;
if(!dbus_message_iter_recurse_dynamic(&messageIter[0], &messageIter[1])) return false;
if (dbus_message_iter_get_arg_type_dynamic(&messageIter[1]) != DBUS_TYPE_VARIANT) return false;
if(!dbus_message_iter_recurse_dynamic(&messageIter[1], &messageIter[2])) return false;
if (dbus_message_iter_get_arg_type_dynamic(&messageIter[2]) != type) return false;
if(!dbus_message_iter_get_basic_dynamic(&messageIter[2], value)) return false;
return true;
}
JNIEXPORT jint JNICALL Java_org_jetbrains_skiko_SystemTheme_1awtKt_getCurrentSystemTheme(JNIEnv *env, jobject topLevel)
{
int systemTheme = 0;
DBusError error;
if(!dbus_error_init_dynamic(&error)) return 2; // Unknown.
DBusConnection *connection = dbus_bus_get_dynamic(DBUS_BUS_SESSION, &error);
if(!connection) return 2; // Unknown.
if (dbus_error_is_set_dynamic(&error)) return 2; // Unknown.
DBusMessage *valueMessage = getSetting(connection, "org.freedesktop.appearance", "color-scheme");
if (!valueMessage) return 2; // Unknown.
parseSettingValue(valueMessage, DBUS_TYPE_UINT32, &systemTheme);
if(!dbus_message_unref_dynamic(valueMessage)) return 2; // Unknown.
switch (systemTheme) {
case 1:
return 1; // Dark.
case 2:
return 0; // Light.
default:
return 2; // Unknown.
}
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment