From db9982cfad77c6a92f5b7c36b84f83cc395d2e45 Mon Sep 17 00:00:00 2001 From: Keeyou Date: Thu, 27 Jun 2024 14:08:19 +0800 Subject: [PATCH] gtk4: call gtk_widget_dispose_template - gtk4: cleanup opengl context see #1027. --- src/gtk/yass.cpp | 6 ++-- src/gtk4/option_dialog.cpp | 20 +++++++++++++ src/gtk4/option_dialog.hpp | 7 +++-- src/gtk4/yass.cpp | 43 ++++++++++++++++++++-------- src/gtk4/yass_window.cpp | 57 ++++++++++++++++++++++++++++++-------- src/gtk4/yass_window.hpp | 3 ++ 6 files changed, 109 insertions(+), 27 deletions(-) diff --git a/src/gtk/yass.cpp b/src/gtk/yass.cpp index a86bed251..c916d436c 100644 --- a/src/gtk/yass.cpp +++ b/src/gtk/yass.cpp @@ -176,10 +176,12 @@ int YASSApp::ApplicationRun(int argc, char** argv) { LOG(WARNING) << "app exited with code " << ret; } - delete main_window_; - LOG(WARNING) << "Application exiting"; + delete main_window_; + g_object_unref(impl_); + impl_ = nullptr; + // Memory leak clean up path pango_cairo_font_map_set_default(nullptr); cairo_debug_reset_static_data(); diff --git a/src/gtk4/option_dialog.cpp b/src/gtk4/option_dialog.cpp index 61c71cf38..63d32a527 100644 --- a/src/gtk4/option_dialog.cpp +++ b/src/gtk4/option_dialog.cpp @@ -34,6 +34,24 @@ static void option_dialog_init(OptionGtkDialog* win) { gtk_widget_init_template(GTK_WIDGET(win)); } +static void option_dialog_dispose(GObject* object) { + OptionGtkDialog* dialog = OPTION_DIALOG(object); +#if GTK_CHECK_VERSION(4, 8, 0) + gtk_widget_dispose_template(GTK_WIDGET(dialog), option_dialog_get_type()); +#else + gtk_widget_unparent(dialog->tcp_keep_alive_check); + gtk_widget_unparent(dialog->tcp_keep_alive_cnt); + gtk_widget_unparent(dialog->tcp_keep_alive_idle_timeout); + gtk_widget_unparent(dialog->tcp_keep_alive_interval); + gtk_widget_unparent(dialog->enable_post_quantum_kyber); + + gtk_widget_unparent(dialog->okay_button); + gtk_widget_unparent(dialog->cancel_button); +#endif + + G_OBJECT_CLASS(option_dialog_parent_class)->dispose(object); +} + static void option_dialog_class_init(OptionGtkDialogClass* cls) { gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS(cls), "/it/gui/yass/option_dialog.ui"); @@ -45,6 +63,8 @@ static void option_dialog_class_init(OptionGtkDialogClass* cls) { gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(cls), OptionGtkDialog, okay_button); gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(cls), OptionGtkDialog, cancel_button); + + G_OBJECT_CLASS(cls)->dispose = option_dialog_dispose; } OptionGtkDialog* option_dialog_new(const gchar* title, GtkWindow* parent, GtkDialogFlags flags) { diff --git a/src/gtk4/option_dialog.hpp b/src/gtk4/option_dialog.hpp index 19f6a4993..d4a8cd186 100644 --- a/src/gtk4/option_dialog.hpp +++ b/src/gtk4/option_dialog.hpp @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2021-2024 Chilledheart */ -#ifndef OPTION_DIALOG -#define OPTION_DIALOG +#ifndef OPTION_DIALOG_H +#define OPTION_DIALOG_H #include @@ -9,6 +9,7 @@ extern "C" { #define OPTION_DIALOG_TYPE (option_dialog_get_type()) +#define OPTION_DIALOG(dialog) (G_TYPE_CHECK_INSTANCE_CAST((dialog), OPTION_DIALOG_TYPE, OptionGtkDialog)) G_DECLARE_FINAL_TYPE(OptionGtkDialog, option_dialog, OPTIONGtk, DIALOG, GtkDialog) OptionGtkDialog* option_dialog_new(const gchar* title, GtkWindow* parent, GtkDialogFlags flags); @@ -32,4 +33,4 @@ class OptionDialog { OptionGtkDialog* impl_; }; // OptionDialog -#endif // OPTION_DIALOG +#endif // OPTION_DIALOG_H diff --git a/src/gtk4/yass.cpp b/src/gtk4/yass.cpp index 147bdff5a..ed4ed92b7 100644 --- a/src/gtk4/yass.cpp +++ b/src/gtk4/yass.cpp @@ -53,15 +53,16 @@ static void about_activated(GSimpleAction* action, GVariant* parameter, gpointer } static void quit_activated(GSimpleAction* action, GVariant* parameter, gpointer app) { + LOG(WARNING) << "Quit Action is clicked"; YASSGtk_APP(app)->thiz->Exit(); } -static GActionEntry app_entries[] = {{"option", option_activated, NULL, NULL, NULL}, - {"about", about_activated, NULL, NULL, NULL}, - {"quit", quit_activated, NULL, NULL, NULL}}; +static GActionEntry app_entries[] = {{"option", option_activated, nullptr, nullptr, nullptr}, + {"about", about_activated, nullptr, nullptr, nullptr}, + {"quit", quit_activated, nullptr, nullptr, nullptr}}; static void yass_app_startup(GApplication* app) { - const char* quit_accels[2] = {"Q", NULL}; + const char* quit_accels[2] = {"Q", nullptr}; G_APPLICATION_CLASS(yass_app_parent_class)->startup(app); @@ -69,17 +70,30 @@ static void yass_app_startup(GApplication* app) { gtk_application_set_accels_for_action(GTK_APPLICATION(app), "app.quit", quit_accels); } +static void yass_app_shutdown(GApplication* app) { +#if GLIB_VERSION_MIN_REQUIRED >= (G_ENCODE_VERSION(2, 78)) + const char* quit_accels[2] = {"Q", nullptr}; + + g_action_map_remove_action_entries(G_ACTION_MAP(app), app_entries, G_N_ELEMENTS(app_entries)); +#endif + + G_APPLICATION_CLASS(yass_app_parent_class)->shutdown(app); +} + static void yass_app_activate(GApplication* app) { YASSGtk_APP(app)->thiz->OnActivate(); } static void yass_app_class_init(YASSGtkAppClass* cls) { G_APPLICATION_CLASS(cls)->startup = yass_app_startup; + G_APPLICATION_CLASS(cls)->shutdown = yass_app_shutdown; G_APPLICATION_CLASS(cls)->activate = yass_app_activate; } YASSGtkApp* yass_app_new(void) { - return YASSGtk_APP(g_object_new(yass_app_get_type(), "application-id", kAppId, NULL)); + auto app = YASSGtk_APP(g_object_new(yass_app_get_type(), "application-id", kAppId, nullptr)); + g_set_application_name(kAppName); + return app; } } // extern "C" @@ -144,7 +158,6 @@ int main(int argc, const char** argv) { YASSApp::YASSApp() : impl_(G_APPLICATION(yass_app_new())), idle_source_(g_timeout_source_new(200)) { YASSGtk_APP(impl_)->thiz = this; - g_set_application_name(kAppName); auto idle_handler = [](gpointer user_data) -> gboolean { if (!mApp) { @@ -211,16 +224,24 @@ int YASSApp::ApplicationRun(int argc, char** argv) { if (ret) { LOG(WARNING) << "app exited with code " << ret; - } else { - LOG(WARNING) << "Application exiting"; } -#if 0 + LOG(WARNING) << "Application exiting"; + + delete main_window_; + g_object_unref(impl_); + impl_ = nullptr; + + // Cleanup opengl's context prior to pango cleanup + if (auto context = gdk_gl_context_get_current()) { + gdk_display_close(gdk_gl_context_get_display(context)); + gdk_gl_context_clear_current(); + } + // Memory leak clean up path pango_cairo_font_map_set_default(nullptr); cairo_debug_reset_static_data(); FcFini(); -#endif PrintMallocStats(); @@ -235,7 +256,7 @@ void YASSApp::Exit() { g_source_destroy(idle_source_); g_source_destroy(exit_int_source_); g_source_destroy(exit_term_source_); - g_application_quit(G_APPLICATION(impl_)); + main_window_->close(); } void YASSApp::OnIdle() { diff --git a/src/gtk4/yass_window.cpp b/src/gtk4/yass_window.cpp index f92939e22..67024fd99 100644 --- a/src/gtk4/yass_window.cpp +++ b/src/gtk4/yass_window.cpp @@ -60,6 +60,35 @@ static void yass_window_init(YASSGtkWindow* win) { g_object_unref(builder); } +static void yass_window_dispose(GObject* object) { + YASSGtkWindow* window = YASS_WINDOW(object); +#if GTK_CHECK_VERSION(4, 8, 0) + gtk_widget_dispose_template(GTK_WIDGET(window), yass_window_get_type()); +#else + gtk_widget_unparent(window->gears); + + gtk_widget_unparent(window->status_bar); + + gtk_widget_unparent(window->start_button); + gtk_widget_unparent(window->stop_button); + + gtk_widget_unparent(window->server_host); + gtk_widget_unparent(window->server_sni); + gtk_widget_unparent(window->server_port); + gtk_widget_unparent(window->username); + gtk_widget_unparent(window->password); + gtk_widget_unparent(window->method); + gtk_widget_unparent(window->local_host); + gtk_widget_unparent(window->local_port); + gtk_widget_unparent(window->doh_url); + gtk_widget_unparent(window->dot_host); + gtk_widget_unparent(window->timeout); + gtk_widget_unparent(window->autostart); + gtk_widget_unparent(window->systemproxy); +#endif + G_OBJECT_CLASS(yass_window_parent_class)->dispose(object); +} + static void yass_window_class_init(YASSGtkWindowClass* cls) { gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS(cls), "/it/gui/yass/yass_window.ui"); gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(cls), YASSGtkWindow, gears); @@ -82,22 +111,22 @@ static void yass_window_class_init(YASSGtkWindowClass* cls) { gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(cls), YASSGtkWindow, timeout); gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(cls), YASSGtkWindow, autostart); gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(cls), YASSGtkWindow, systemproxy); + + G_OBJECT_CLASS(cls)->dispose = yass_window_dispose; } YASSGtkWindow* yass_window_new(YASSGtkApp* app) { - return YASSGtk_WINDOW(g_object_new(yass_window_get_type(), "application", app, NULL)); + auto window = YASSGtk_WINDOW(g_object_new(yass_window_get_type(), "application", app, nullptr)); + gtk_window_set_resizable(GTK_WINDOW(window), false); + gtk_window_set_icon_name(GTK_WINDOW(window), "yass"); + return window; } } // extern "C" -YASSWindow::YASSWindow(GApplication* app) : impl_(yass_window_new(YASSGtk_APP(app))) { -#if 0 - gtk_window_set_position(GTK_WINDOW(impl_), GTK_WIN_POS_CENTER); -#endif - gtk_window_set_resizable(GTK_WINDOW(impl_), false); - gtk_window_set_icon_name(GTK_WINDOW(impl_), "yass"); - - static YASSWindow* window = this; +YASSWindow::YASSWindow(GApplication* app) : app_(app), impl_(yass_window_new(YASSGtk_APP(app))) { + static YASSWindow* window; + window = this; // forward to hide event gtk_window_set_hide_on_close(GTK_WINDOW(impl_), TRUE); @@ -148,7 +177,9 @@ YASSWindow::YASSWindow(GApplication* app) : impl_(yass_window_new(YASSGtk_APP(ap LoadChanges(); } -YASSWindow::~YASSWindow() = default; +YASSWindow::~YASSWindow() { + gtk_window_destroy(GTK_WINDOW(impl_)); +} void YASSWindow::show() { gtk_widget_set_visible(GTK_WIDGET(impl_), true); @@ -158,6 +189,10 @@ void YASSWindow::present() { gtk_window_present(GTK_WINDOW(impl_)); } +void YASSWindow::close() { + gtk_application_remove_window(GTK_APPLICATION(app_), GTK_WINDOW(impl_)); +} + void YASSWindow::OnStartButtonClicked() { gtk_widget_set_sensitive(impl_->start_button, false); gtk_widget_set_sensitive(impl_->stop_button, false); @@ -378,6 +413,6 @@ void YASSWindow::UpdateStatusBar() { } void YASSWindow::OnClose() { - LOG(WARNING) << "Frame is closing "; + LOG(WARNING) << "Frame is closing"; mApp->Exit(); } diff --git a/src/gtk4/yass_window.hpp b/src/gtk4/yass_window.hpp index 33280bbf5..0fa1e898c 100644 --- a/src/gtk4/yass_window.hpp +++ b/src/gtk4/yass_window.hpp @@ -12,6 +12,7 @@ extern "C" { #define YASS_WINDOW_TYPE (yass_window_get_type()) +#define YASS_WINDOW(window) (G_TYPE_CHECK_INSTANCE_CAST((window), YASS_WINDOW_TYPE, YASSGtkWindow)) G_DECLARE_FINAL_TYPE(YASSGtkWindow, yass_window, YASSGtk, WINDOW, GtkApplicationWindow) YASSGtkWindow* yass_window_new(YASSGtkApp* app); @@ -25,12 +26,14 @@ class YASSWindow { YASSGtkWindow* impl() { return impl_; } private: + GApplication* app_; YASSGtkWindow* impl_; std::string last_status_msg_; public: void show(); void present(); + void close(); void OnStartButtonClicked(); void OnStopButtonClicked();