Specially for https://github.com/wangwenx190/framelesshelper - Cross-platform window customization framework for Qt Widgets and Qt Quick. Supports Windows, Linux and macOS.
Last active
November 13, 2022 16:20
-
-
Save ivanstepanovftw/8a257f40acd4cb4a532569c88be545b2 to your computer and use it in GitHub Desktop.
Gtk3 on theme change event example for GNOME DE C++
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ... | |
| if (LINUX) | |
| find_package(PkgConfig REQUIRED) | |
| pkg_check_modules(GTK3 REQUIRED IMPORTED_TARGET gtk+-3.0) | |
| endif() | |
| ... | |
| add_executable(scratch_theme | |
| test/scratch_theme.cpp | |
| ) | |
| target_link_libraries(scratch_theme PRIVATE | |
| PkgConfig::GTK3 | |
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /// | |
| /// Listen for Gtk theme changer events | |
| /// | |
| #include <gio/gio.h> | |
| #include <thread> | |
| #include <atomic> | |
| #include <iostream> | |
| namespace { | |
| using namespace std::chrono_literals; | |
| GApplication *app = nullptr; | |
| gulong activate_sh; // signal handler | |
| gulong shutdown_sh; // signal handler | |
| gulong interface_changed_sh; // signal handler | |
| GSettings *settings = nullptr; | |
| // GMutex running_mutex; | |
| std::atomic<int> tries_till_exit = 1; | |
| std::atomic<bool> is_activated = false; | |
| std::atomic<bool> is_shutdown = false; | |
| } | |
| void interface_changed_cb(GSettings *settings, gchar *name, gpointer user_data) { | |
| gchar *theme = g_settings_get_string(settings, name); | |
| if (strcmp(name, "color-scheme") == 0) { | |
| tries_till_exit.fetch_sub(1, std::memory_order_relaxed); | |
| } | |
| g_print("theme_changed: %s:%s\n", name, theme); | |
| g_free(theme); | |
| } | |
| /// Main loop | |
| gpointer app_runner(gpointer data) { | |
| g_print("app_runner!!!\n"); | |
| int status = g_application_run(app, 0, nullptr); | |
| return reinterpret_cast<void *>(status); | |
| } | |
| void activate_cb(GApplication *app, gpointer user_data) { | |
| g_print("activate_cb\n"); | |
| settings = g_settings_new("org.gnome.desktop.interface"); | |
| interface_changed_sh = g_signal_connect(settings, "changed", G_CALLBACK(interface_changed_cb), NULL); | |
| is_activated.store(true, std::memory_order_relaxed); | |
| } | |
| void shutdown_cb(GApplication *app, gpointer user_data) { | |
| g_print("shutdown_cb\n"); | |
| g_signal_handler_disconnect(settings, interface_changed_sh); | |
| g_object_unref(settings); | |
| settings = nullptr; | |
| is_shutdown.store(true, std::memory_order_relaxed); | |
| } | |
| int main(int argc, char *argv[]) { | |
| // Create app | |
| app = g_application_new("com.wowcube.editor.test", G_APPLICATION_FLAGS_NONE); | |
| g_application_set_inactivity_timeout(app, 1000); | |
| g_application_hold(app); // Hold! Do not exit immediately. | |
| activate_sh = g_signal_connect(app, "activate", G_CALLBACK(activate_cb), NULL); | |
| shutdown_sh = g_signal_connect(app, "shutdown", G_CALLBACK(shutdown_cb), NULL); | |
| GThread *thread = g_thread_new("gio_theme_listener", app_runner, nullptr); | |
| // Wait max 5000 ms until started | |
| auto activate_next_check = std::chrono::steady_clock::now(); | |
| auto activate_time_out = activate_next_check + 5000ms; | |
| bool activate_timed_out = false; | |
| while (true) { | |
| if (is_activated.load(std::memory_order_relaxed)) { | |
| break; | |
| } | |
| if (activate_next_check >= activate_time_out) { | |
| activate_timed_out = true; | |
| break; | |
| } | |
| activate_next_check += 100ms; | |
| std::this_thread::sleep_until(activate_next_check); | |
| } | |
| if (activate_timed_out) { | |
| g_print("activate_timed_out\n"); | |
| // g_application_quit(app); | |
| return 1; | |
| } | |
| // Do some work on this thread... | |
| while (tries_till_exit != 0) { | |
| #define WAIT_AND_DEBUG | |
| #ifdef WAIT_AND_DEBUG | |
| static int i = 0; | |
| if (i % 10 == 0) { | |
| std::cout << "waiting: tries_till_exit: " << tries_till_exit << std::endl; | |
| } | |
| std::this_thread::sleep_for(std::chrono::milliseconds(100)); | |
| i++; | |
| #endif | |
| } | |
| // Free connection and exit application | |
| g_application_release(app); // Unhold! | |
| // g_application_quit(app); // FIXME: should I call it? | |
| // // Wait max 5000 ms till shutdown | |
| // auto shutdown_next_check = std::chrono::steady_clock::now(); | |
| // auto shutdown_time_out = shutdown_next_check + 5000ms; | |
| // bool shutdown_timed_out = false; | |
| // while (true) { | |
| // if (is_shutdown.load(std::memory_order_relaxed)) { | |
| // break; | |
| // } | |
| // if (shutdown_next_check < shutdown_time_out) { | |
| // shutdown_next_check += 100ms; | |
| // std::this_thread::sleep_until(shutdown_next_check); | |
| // } else { | |
| // shutdown_timed_out = true; | |
| // break; | |
| // } | |
| // } | |
| // if (shutdown_timed_out) { | |
| // g_print("shutdown_timed_out\n"); | |
| // return 2; | |
| // } | |
| std::cout << "Joining..." << std::endl; | |
| int result = (int)(uintptr_t)(g_thread_join(thread)); | |
| // Cleanup | |
| // g_object_unref(app); | |
| std::cout << "return " << result << std::endl; | |
| return result; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment