Skip to content

Commit

Permalink
[linux] #36, #37
Browse files Browse the repository at this point in the history
1. monitor the gsettings change
2. automatically follow the theme of system
  • Loading branch information
ffiirree committed Apr 5, 2023
1 parent ca806df commit 922bdd4
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 20 deletions.
55 changes: 50 additions & 5 deletions src/core/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,10 @@ Config::Config()
settings_["devices"]["speakers"] = Devices::speakers()[0];

connect(this, &Config::changed, this, &Config::save);
connect(this, &Config::SYSTEM_THEME_CHANGED, this, [this](int theme) {
load_theme(platform::system::theme_name(static_cast<platform::system::theme_t>(theme)));
connect(this, &Config::SYSTEM_THEME_CHANGED, this, [this](int theme) {
if (settings_["theme"].get<std::string>() == "auto") {
load_theme(platform::system::theme_name(static_cast<platform::system::theme_t>(theme)));
}
});

monitor_system_theme(settings_["theme"].get<std::string>() == "auto");
Expand Down Expand Up @@ -110,8 +112,8 @@ std::string Config::theme()
void Config::monitor_system_theme(bool m)
{
#ifdef _WIN32
if (m && win_theme_monitor_ == nullptr) {
win_theme_monitor_ = platform::windows::monitor_regkey(
if (m && theme_monitor_ == nullptr) {
theme_monitor_ = platform::windows::monitor_regkey(
HKEY_CURRENT_USER,
R"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)",
[this](auto) {
Expand All @@ -121,8 +123,51 @@ void Config::monitor_system_theme(bool m)
}

if(!m) {
win_theme_monitor_ = nullptr;
theme_monitor_ = nullptr;
}
#elif __linux__
if (m && theme_monitor_ == nullptr) {
if (platform::system::desktop() == platform::system::desktop_t::GNOME ||
platform::system::desktop() == platform::system::desktop_t::Unity) {

auto color_scheme = platform::linux::exec("gsettings get org.gnome.desktop.interface color-scheme").value_or("");
if (!color_scheme.empty() && color_scheme != "\t") { // TODO
theme_monitor_ = platform::linux::monitor_gsettings("org.gnome.desktop.interface", "color-scheme", [this](auto str){
platform::system::theme_t _theme = platform::system::theme_t::dark;
if (str.find("dark") != std::string::npos) {
_theme = platform::system::theme_t::dark;
}
if (str.find("light") != std::string::npos) {
_theme = platform::system::theme_t::light;
}
emit SYSTEM_THEME_CHANGED(static_cast<int>(_theme));
});

return;
}

auto gtk_theme = platform::linux::exec("gsettings get org.gnome.desktop.interface gtk-theme").value_or("");
if (!gtk_theme.empty() && gtk_theme != "\t") {
theme_monitor_ = platform::linux::monitor_gsettings("org.gnome.desktop.interface", "gtk-theme", [this](auto str){
platform::system::theme_t _theme = platform::system::theme_t::dark;
if (str.find("dark") != std::string::npos) {
_theme = platform::system::theme_t::dark;
}
if (str.find("light") != std::string::npos) {
_theme = platform::system::theme_t::light;
}
emit SYSTEM_THEME_CHANGED(static_cast<int>(_theme));
});

return;
}
}
}

// TODO: pclose can not exit
// if (!m) {
// theme_monitor_ = nullptr;
// }
#endif
}

Expand Down
4 changes: 3 additions & 1 deletion src/core/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ public slots:
json settings_ = json::parse("{}");

#ifdef _WIN32
std::shared_ptr<platform::windows::RegistryMonitor> win_theme_monitor_{ nullptr };
std::shared_ptr<platform::windows::RegistryMonitor> theme_monitor_{ nullptr };
#elif __linux__
std::shared_ptr<platform::linux::GSettingsMonitor> theme_monitor_{ nullptr };
#endif // _WIN32
};

Expand Down
47 changes: 42 additions & 5 deletions src/core/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
#include <vector>
#include <optional>
#include <QRect>
#include <functional>
#include <thread>
#include <atomic>

#ifdef _WIN32

#include <thread>
#include <atomic>
#include <functional>
#include <Windows.h>

#endif
Expand Down Expand Up @@ -77,7 +77,7 @@ namespace platform

class RegistryMonitor {
public:
RegistryMonitor(HKEY key, const std::string& subkey, std::function<void(HKEY)> cb) { monitor(key, subkey, cb); }
RegistryMonitor() = default;
~RegistryMonitor() { stop(); }

RegistryMonitor(const RegistryMonitor&) = delete;
Expand All @@ -97,8 +97,27 @@ namespace platform
std::shared_ptr<RegistryMonitor> monitor_regkey(HKEY key, const std::string& subkey, std::function<void(HKEY)> cb);
}
#elif __linux__
namespace linux {
namespace linux
{
std::optional<std::string> exec(const char *);

class GSettingsMonitor {
public:
GSettingsMonitor() = default;
~GSettingsMonitor() { stop(); }

GSettingsMonitor(const GSettingsMonitor&) = delete;
GSettingsMonitor& operator= (const GSettingsMonitor&) = delete;

int monitor(const std::string&, const std::string&, std::function<void(const std::string&)>);
void stop();

private:
std::thread thread_;
std::atomic<bool> running_{ false };
};

std::shared_ptr<GSettingsMonitor> monitor_gsettings(const std::string&, const std::string&, std::function<void(const std::string&)>);
}
#endif // _WIN32

Expand All @@ -121,6 +140,22 @@ namespace platform

namespace system
{
enum class desktop_t
{
unknown,
Windows, // Windows
KDE, // K Desktop Environment, based on Qt
GNOME, // GNU Network Object Model Environment
Unity, // based on GNOME
MATE, // forked from GNOME 2
Cinnamon, // forked from GNOME 3
Xfce,
DeepinDE, // based on Qt
Enlightenment,
LXQT,
Lumina
};

enum class theme_t
{
dark, light
Expand All @@ -143,6 +178,8 @@ namespace platform
theme_t theme();
std::string theme_name(theme_t);

desktop_t desktop();

std::string os_name();
std::string kernel_name();

Expand Down
54 changes: 54 additions & 0 deletions src/core/platform/platform_linux.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
#ifdef __linux__

#include "platform.h"
#include <chrono>
#include "logging.h"


using namespace std::chrono_literals;

namespace platform
{
Expand All @@ -22,6 +27,55 @@ namespace platform
pclose(pipe);
return result;
}

int GSettingsMonitor::monitor(const std::string& key, const std::string& subkey, std::function<void(const std::string&)> callback)
{
const std::string cmd = "gsettings monitor " + key + " " + subkey;

running_ = true;
thread_ = std::thread([=](){
while (running_) {
FILE* pipe = popen(cmd.c_str(), "r");

if (!pipe) {
LOG(ERROR) << "failed to open : " << cmd;
std::this_thread::sleep_for(100ms);
continue;
}

char buffer[256]{};
while (running_ && (fgets(buffer, sizeof(buffer), pipe) != nullptr)) {
callback(buffer);
}

pclose(pipe); // TODO: stuck if the cmd process does not exit

// exit unexpectedly
if (running_) {
LOG(WARNING) << "exit unexpectedly, try monitor the '" << cmd << "' again after 250ms";
std::this_thread::sleep_for(250ms);
}
}
});

return 0;
}

void GSettingsMonitor::stop()
{
running_ = false;

if (thread_.joinable())
thread_.join();
}

std::shared_ptr<GSettingsMonitor> monitor_gsettings(const std::string& key, const std::string& subkey, std::function<void(const std::string&)> cb)
{
auto monitor = std::make_shared<GSettingsMonitor>();
monitor->monitor(key, subkey, cb);
return monitor;
}

} // namespace linux

namespace util
Expand Down
4 changes: 3 additions & 1 deletion src/core/platform/platform_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ namespace platform

std::shared_ptr<RegistryMonitor> monitor_regkey(HKEY key, const std::string& subkey, std::function<void(HKEY)> cb)
{
return std::make_shared<RegistryMonitor>(key, subkey, cb);
auto monitor = std::make_shared<RegistryMonitor>();
monitor->monitor(key, subkey, cb);
return monitor;
}
} // namespace windows

Expand Down
45 changes: 37 additions & 8 deletions src/core/platform/system_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,48 @@ namespace platform::system
return version;
}

theme_t theme()
desktop_t desktop()
{
const char * de = std::getenv("XDG_CURRENT_DESKTOP");
// GNOME
if (std::string_view(de).find("GNOME") != std::string::npos) {
auto result = platform::linux::exec("gsettings get org.gnome.desktop.interface color-scheme").value_or("");
if (result.find("dark") != std::string::npos) {
return theme_t::dark;
}
if (result.find("light") != std::string::npos) {
return theme_t::light;
if (std::string_view(de).find("GNOME") != std::string::npos ||
std::string_view(de).find("gnome") != std::string::npos) {
return desktop_t::GNOME;
}
// Unity
if (std::string_view(de).find("Unity") != std::string::npos ||
std::string_view(de).find("unity") != std::string::npos) {
return desktop_t::GNOME;
}
return desktop_t::unknown;
}


theme_t theme()
{
if (desktop() == desktop_t::GNOME || desktop() == desktop_t::Unity) {

auto color_scheme = platform::linux::exec("gsettings get org.gnome.desktop.interface color-scheme").value_or("");
if (!color_scheme.empty()) {
if (color_scheme.find("dark") != std::string::npos) {
return theme_t::dark;
}
if (color_scheme.find("light") != std::string::npos) {
return theme_t::light;
}
}

auto gtk_theme = platform::linux::exec("gsettings get org.gnome.desktop.interface gtk-theme").value_or("");
if (!gtk_theme.empty()) {
if (gtk_theme.find("dark") != std::string::npos) {
return theme_t::dark;
}
if (gtk_theme.find("light") != std::string::npos) {
return theme_t::light;
}
}
}

// TODO : other desktop env
return theme_t::dark;
}
Expand Down
5 changes: 5 additions & 0 deletions src/core/platform/system_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ namespace platform::system
{
extern "C" NTSYSAPI NTSTATUS NTAPI RtlGetVersion(_Out_ PRTL_OSVERSIONINFOW lpVersionInformation);

desktop_t desktop()
{
return desktop_t::Windows;
}

theme_t theme()
{
if (os_version() >= platform::windows::WIN_10_1ST) {
Expand Down

0 comments on commit 922bdd4

Please sign in to comment.