Skip to content

Commit

Permalink
[windows] #36, #37
Browse files Browse the repository at this point in the history
1. monitor the registry event
2. automatically follow the theme of system
  • Loading branch information
ffiirree committed Apr 5, 2023
1 parent 6e97960 commit ca806df
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 25 deletions.
62 changes: 59 additions & 3 deletions src/core/config.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "config.h"
#include <QApplication>
#include <QStandardPaths>
#include <QDir>
#include <QTextStream>
Expand Down Expand Up @@ -76,6 +77,11 @@ 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)));
});

monitor_system_theme(settings_["theme"].get<std::string>() == "auto");
}

void Config::save()
Expand All @@ -91,12 +97,62 @@ void Config::save()
file.close();
}

QString Config::theme()
std::string Config::theme()
{
auto theme = Config::instance()["theme"].get<QString>();
auto theme = Config::instance()["theme"].get<std::string>();
if (theme == "auto") {
return QString::fromStdString(platform::system::theme_name(platform::system::theme()));
return platform::system::theme_name(platform::system::theme());
}

return (theme == "dark") ? "dark" : "light";
}

void Config::monitor_system_theme(bool m)
{
#ifdef _WIN32
if (m && win_theme_monitor_ == nullptr) {
win_theme_monitor_ = platform::windows::monitor_regkey(
HKEY_CURRENT_USER,
R"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)",
[this](auto) {
emit SYSTEM_THEME_CHANGED(static_cast<int>(platform::system::theme()));
}
);
}

if(!m) {
win_theme_monitor_ = nullptr;
}
#endif
}

void Config::set_theme(const std::string& theme)
{
if (settings_["theme"].get<std::string>() == theme)
return;

set(settings_["theme"], theme);

monitor_system_theme(theme == "auto");

load_theme(Config::theme());
}

void Config::load_theme(const std::string& theme)
{
static std::string _theme = "unknown";
if (_theme != theme) {
_theme = theme;

LOAD_QSS(qApp,
{
":/qss/capturer.qss",
":/qss/capturer-" + QString::fromStdString(theme) + ".qss",
":/qss/menu/menu.qss",
":/qss/menu/menu-" + QString::fromStdString(theme) + ".qss",
":/qss/setting/settingswindow.qss",
":/qss/setting/settingswindow-" + QString::fromStdString(theme) + ".qss"
}
);
}
}
14 changes: 13 additions & 1 deletion src/core/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <QObject>
#include "json.h"
#include "utils.h"
#include "platform.h"

#define IF_NULL_SET(X, default_value) st(if(X.is_null()) X = default_value;)

Expand All @@ -23,7 +24,11 @@ class Config : public QObject

QString getFilePath() const { return filepath_; }

static QString theme();
static std::string theme();

// use this funtion to set theme
void set_theme(const std::string&);
static void load_theme(const std::string&);

template <typename T> void set(json& key, T value)
{
Expand All @@ -39,12 +44,19 @@ public slots:

signals:
void changed();
void SYSTEM_THEME_CHANGED(int);

private:
Config();

void monitor_system_theme(bool);

QString filepath_;
json settings_ = json::parse("{}");

#ifdef _WIN32
std::shared_ptr<platform::windows::RegistryMonitor> win_theme_monitor_{ nullptr };
#endif // _WIN32
};


Expand Down
28 changes: 26 additions & 2 deletions src/core/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

#ifdef _WIN32

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

#endif
Expand Down Expand Up @@ -69,8 +72,29 @@ namespace platform
inline const version_t WIN_11_21H2{ 10, 0, 22000, 194, "21H2" };
inline const version_t WIN_11_22H2{ 10, 0, 22621, 521, "22H2" };

std::optional<DWORD> reg_read_dword(HKEY key, const char*, const char*);
std::optional<std::string> reg_read_string(HKEY key, const char*, const char*);
std::optional<DWORD> reg_read_dword(HKEY key, const std::string&, const std::string&);
std::optional<std::string> reg_read_string(HKEY key, const std::string&, const std::string&);

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

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

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

private:
HKEY key_;
HANDLE STOP_EVENT{ nullptr };
HANDLE NOTIFY_EVENT{ nullptr };
std::thread thread_;
std::atomic<bool> running_{ false };
};

std::shared_ptr<RegistryMonitor> monitor_regkey(HKEY key, const std::string& subkey, std::function<void(HKEY)> cb);
}
#elif __linux__
namespace linux {
Expand Down
84 changes: 78 additions & 6 deletions src/core/platform/platform_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

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

namespace platform
{
Expand All @@ -10,11 +11,12 @@ namespace platform
// https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-value-types
// REG_DWORD : A 32-bit number.
// REG_QWORD : A 64-bit number.
std::optional<DWORD> reg_read_dword(HKEY key, const char* subkey, const char* valuename)
std::optional<DWORD> reg_read_dword(HKEY key, const std::string& subkey, const std::string& valuename)
{
DWORD value = 0;
DWORD size = sizeof(uint32_t);
if (RegGetValueA(key, subkey, valuename, RRF_RT_REG_DWORD, nullptr, &value, &size) == ERROR_SUCCESS) {
if (RegGetValue(key, util::to_utf16(subkey).c_str(), util::to_utf16(valuename).c_str(),
RRF_RT_REG_DWORD, nullptr, &value, &size) == ERROR_SUCCESS) {
return value;
}

Expand All @@ -24,22 +26,92 @@ namespace platform
// REG_SZ : A null - terminated string.
// It's either a Unicode or an ANSI string,
// depending on whether you use the Unicode or ANSI functions.
std::optional<std::string> reg_read_string(HKEY key, const char* subkey, const char* valuename)
std::optional<std::string> reg_read_string(HKEY key, const std::string& subkey, const std::string& valuename)
{

DWORD size = 0;
if (RegGetValueA(key, subkey, valuename, RRF_RT_REG_SZ, nullptr, nullptr, &size) != ERROR_SUCCESS) {
if (RegGetValue(key, util::to_utf16(subkey).c_str(), util::to_utf16(valuename).c_str(),
RRF_RT_REG_SZ, nullptr, nullptr, &size) != ERROR_SUCCESS) {
return std::nullopt;
}

std::string value(size, {});

if (RegGetValueA(key, subkey, valuename, RRF_RT_REG_SZ, nullptr, reinterpret_cast<LPBYTE>(&value[0]), &size) != ERROR_SUCCESS) {
if (RegGetValue(key, util::to_utf16(subkey).c_str(), util::to_utf16(valuename).c_str(),
RRF_RT_REG_SZ, nullptr, reinterpret_cast<LPBYTE>(&value[0]), &size) != ERROR_SUCCESS) {
return std::nullopt;
}

return value;
}

int RegistryMonitor::monitor(HKEY key, const std::string& subkey, std::function<void(HKEY)> callback)
{
if (::RegOpenKeyEx(key, platform::util::to_utf16(subkey).c_str(), 0, KEY_NOTIFY, &key_) != ERROR_SUCCESS) {
LOG(ERROR) << "failed to open the registry key : " << subkey;
return -1;
}

if ((STOP_EVENT = ::CreateEvent(nullptr, TRUE, FALSE, L"Registry Stop Event")) == nullptr) {
LOG(ERROR) << "failed to create event for the registry key : " << subkey;
return -1;
}

if ((NOTIFY_EVENT = ::CreateEvent(nullptr, FALSE, FALSE, L"Registry Notify Evnent")) == nullptr) {
LOG(ERROR) << "failed to create event for the registry key : " << subkey;
return -1;
}

running_ = true;
thread_ = std::thread([=]()
{
const HANDLE events[] = { STOP_EVENT, NOTIFY_EVENT };

while (running_) {
if (::RegNotifyChangeKeyValue(
key_, TRUE, REG_LEGAL_CHANGE_FILTER, NOTIFY_EVENT, TRUE) != ERROR_SUCCESS) {
LOG(ERROR) << "failed to monitor the registry key : " << subkey;
::SetEvent(STOP_EVENT);
}

switch (::WaitForMultipleObjects(2, events, false, INFINITE))
{
case WAIT_OBJECT_0 + 0: // STOP_EVENT
running_ = false;
break;

case WAIT_OBJECT_0 + 1: // NOTIFIY_EVENT
callback(key_);
break;

default: break;
}
}
}
);

return 0;
}

void RegistryMonitor::stop()
{
running_ = false;
::SetEvent(STOP_EVENT);

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

::CloseHandle(NOTIFY_EVENT);
::CloseHandle(STOP_EVENT);
::RegCloseKey(key_);

LOG(INFO) << "REG MONITOR DESTORY";
}

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);
}
} // namespace windows

namespace util
Expand Down Expand Up @@ -74,7 +146,7 @@ namespace platform
std::wstring wstr(wlen, {});
MultiByteToWideChar(CP_UTF8, 0, mstr, static_cast<int>(mlen), wstr.data(), static_cast<int>(wstr.size()));

return wstr;
return std::move(wstr);
}
} // namespace util
}
Expand Down
2 changes: 1 addition & 1 deletion src/core/platform/system_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace platform::system
if (os_version() >= platform::windows::WIN_10_1ST) {
if (platform::windows::reg_read_dword(
HKEY_CURRENT_USER,
"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
R"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)",
"AppsUseLightTheme"
).value_or(1) == 0) {
return theme_t::dark;
Expand Down
12 changes: 1 addition & 11 deletions src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include <QApplication>
#include <QOperatingSystemVersion>
#include <QFile>
#include <QTranslator>
#include "version.h"
#include "utils.h"
Expand Down Expand Up @@ -34,16 +33,7 @@ int main(int argc, char *argv[])
// displays
LOG(INFO) << "VIRTUAL SCREEN: " << platform::display::virtual_screen_geometry();

LOAD_QSS(qApp,
{
":/qss/capturer.qss",
":/qss/capturer-" + Config::theme() + ".qss",
":/qss/menu/menu.qss",
":/qss/menu/menu-" + Config::theme() + ".qss",
":/qss/setting/settingswindow.qss",
":/qss/setting/settingswindow-" + Config::theme() + ".qss"
}
);
Config::load_theme(Config::theme());

auto language = Config::instance()["language"].get<QString>();
LOG(INFO) << "LANGUAGE: " << language;
Expand Down
2 changes: 1 addition & 1 deletion src/setting/settingdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ void SettingWindow::setupGeneralWidget()
_3_2->addItem(tr("Light"), "light");
_3_2->setCurrentIndex(std::max(0, _3_2->findData(config["theme"].get<QString>())));
connect(_3_2, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [this, _3_2](int i) {
config.set(config["theme"], _3_2->currentData().toString());
config.set_theme(_3_2->currentData().toString().toStdString());
});
layout->addWidget(new QLabel(tr("Theme")), 3, 0, 1, 1);
layout->addWidget(_3_2, 3, 1, 1, 2);
Expand Down

0 comments on commit ca806df

Please sign in to comment.