[gtkmm/kjellahl/application-run] Gtk::Application: Add make_window_and_run()
- From: Kjell Ahlstedt <kjellahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtkmm/kjellahl/application-run] Gtk::Application: Add make_window_and_run()
- Date: Tue, 20 Oct 2020 14:08:24 +0000 (UTC)
commit 531777206609d15778795389c30fc5ecfbaa160f
Author: Kjell Ahlstedt <kjellahlstedt gmail com>
Date: Tue Oct 20 15:22:08 2020 +0200
Gtk::Application: Add make_window_and_run()
and remove the run() overloads that take a Window&.
There are new restrictions on Widgets. From the class description:
Most widgets can't safely be created before the application has been
registered or activated. They can't safely be deleted after run() or
make_window_and_run() returns.
The main() functions in the demo program and in most test programs
have been updated.
Fixes #78
demos/gtk-demo/main.cc | 6 +-
gtk/src/application.ccg | 30 +---------
gtk/src/application.hg | 109 +++++++++++++++++++-----------------
tests/builder/main.cc | 52 +++++++++++------
tests/child_widget/main.cc | 5 +-
tests/child_widget2/main.cc | 6 +-
tests/child_widget_managed/main.cc | 4 +-
tests/delete_cpp_child/main.cc | 3 +-
tests/dialog_deletethis/main.cc | 1 +
tests/main_with_options/main.cc | 3 +-
tests/property_notification/main.cc | 28 ++++-----
tests/refcount_dialog/main.cc | 4 +-
tests/scrolledwindow/main.cc | 3 +-
tests/wrap_existing/main.cc | 3 +-
14 files changed, 124 insertions(+), 133 deletions(-)
---
diff --git a/demos/gtk-demo/main.cc b/demos/gtk-demo/main.cc
index c302ae73..c158786f 100644
--- a/demos/gtk-demo/main.cc
+++ b/demos/gtk-demo/main.cc
@@ -20,11 +20,9 @@
#include <gtkmm/application.h>
#include "demowindow.h"
-int main (int argc, char *argv[])
+int main(int argc, char* argv[])
{
auto app = Gtk::Application::create();
- DemoWindow window;
-
- return app->run(window, argc, argv);
+ return app->make_window_and_run<DemoWindow>(argc, argv);
}
diff --git a/gtk/src/application.ccg b/gtk/src/application.ccg
index 01891927..023dee7d 100644
--- a/gtk/src/application.ccg
+++ b/gtk/src/application.ccg
@@ -93,7 +93,7 @@ Application::Application(const Glib::ustring& application_id, Gio::Application::
{
// gtk_init() is called by the 'startup' default signal handler when g_application_run() is called.
// It's also called here, to make it possible for users of gtkmm to create
- // a window and other widgets before calling run().
+ // a window and other widgets before calling run(). (This is not recommended.)
// See https://bugzilla.gnome.org/show_bug.cgi?id=639925
gtk_init();
set_cxx_locale_to_c_locale();
@@ -109,39 +109,11 @@ int Application::run(int argc, char** argv)
return Gio::Application::run(argc, argv);
}
-int Application::run(Window& window, int argc, char** argv)
-{
- //We cannot add and show the window until the GApplication::activate signal
- //has been emitted, or we will crash because the application has not been
- //registered. (At least if window is an ApplicationWindow.)
- signal_activate().connect(
- sigc::bind(
- sigc::mem_fun(*this, &Application::on_activate_add_and_show_main_window),
- &window));
-
- return Gio::Application::run(argc, argv);
-}
-
-
-int Application::run(Window& window)
-{
- return run(window, 0, nullptr);
-}
-
int Application::run()
{
return Gio::Application::run(0, nullptr);
}
-void Application::on_activate_add_and_show_main_window(Window* window)
-{
- if(window)
- {
- add_window(*window);
- window->show();
- }
-}
-
void Application::set_accel_for_action(const Glib::ustring& detailed_action_name, const Glib::ustring& accel)
{
std::vector<Glib::ustring> vec;
diff --git a/gtk/src/application.hg b/gtk/src/application.hg
index 9a50a245..4039d2c4 100644
--- a/gtk/src/application.hg
+++ b/gtk/src/application.hg
@@ -18,6 +18,8 @@
_CONFIGINCLUDE(gtkmmconfig.h)
#include <vector>
+#include <type_traits>
+#include <utility>
#include <giomm/application.h>
#include <giomm/menumodel.h>
#include <giomm/menu.h>
@@ -80,6 +82,12 @@ class GTKMM_API Window;
* inform the user about the negative consequences of ending the
* session while inhibitors are present.
*
+ * @note
+ * Most widgets can't safely be created before the application has been registered
+ * (Gio::Application::register_application() called) or activated
+ * (Gio::Application::signal_activate() emitted).
+ * They can't safely be deleted after run() or make_window_and_run() returns.
+ *
* @newin{3,4}
*/
class GTKMM_API Application
@@ -109,7 +117,6 @@ protected:
_IGNORE(gtk_application_new)
_IGNORE(gtk_application_window_new)
-
public:
_WRAP_ENUM(InhibitFlags, GtkApplicationInhibitFlags, decl_prefix GTKMM_API)
@@ -166,73 +173,53 @@ public:
/** Starts the application.
*
- * The default implementation of this virtual function will simply run
- * a main loop.
- *
- * It is an error to call this function if @a application is a proxy for
- * a remote application.
- *
- * @param argc The argc from main() (or 0 if @a argv is <tt>0</tt>).
- * @param argv The argv from main(), or <tt>0</tt>.
+ * @param argc The argc from main() (or 0 if @a argv is <tt>nullptr</tt>).
+ * @param argv The argv from main(), or <tt>nullptr</tt>.
* @return The exit status.
*
+ * @see Gio::Application::run()
+ *
* @newin{3,4}
*/
int run(int argc, char** argv);
/** Starts the application.
*
- * The default implementation of this virtual function will simply run
- * a main loop.
- *
- * It is an error to call this function if @a application is a proxy for
- * a remote application.
- *
- * @note If you call Gio::Application::quit() while a window is connected to
- * the application, and then return from main() without removing the window
- * from the application, the application's destructor will not be called.
- *
- * @param window The window to show. This method will return when the window is hidden.
- * @param argc The argc from main() (or 0 if @a argv is <tt>0</tt>).
- * @param argv The argv from main(), or <tt>0</tt>.
* @return The exit status.
*
+ * @see Gio::Application::run()
+ *
* @newin{3,4}
*/
- int run(Window& window, int argc, char** argv);
+ int run();
- /** Starts the application.
- *
- * The default implementation of this virtual function will simply run
- * a main loop.
- *
- * It is an error to call this function if @a application is a proxy for
- * a remote application.
+ /** Starts the application, creates and shows a window.
*
- * @note If you call Gio::Application::quit() while a window is connected to
- * the application, and then return from main() without removing the window
- * from the application, the application's destructor will not be called.
+ * A window of type T_Window is constructed and added to the application
+ * in a signal_activate() handler. The window is deleted when it is hidden
+ * or removed from the application. The method returns when the window is hidden,
+ * unless other windows have been added but not removed.
*
- * @param window The window to show. This method will return when the window is hidden.
+ * @tparam T_Window The type of window to show. Must be Gtk::Window or a class type
+ * that inherits from Gtk::Window.
+ * @param argc The argc from main() (or 0 if @a argv is <tt>nullptr</tt>).
+ * @param argv The argv from main(), or <tt>nullptr</tt>.
+ * @param args Arguments to T_Window's constructor, if any.
* @return The exit status.
*
- * @newin{3,4}
+ * @see Gio::Application::run()
+ *
+ * @newin{3,98}
*/
- int run(Window& window);
+ template <typename T_Window, typename... T_Args>
+ int make_window_and_run(int argc, char** argv, T_Args&&... args);
- /** Starts the application.
- *
- * The default implementation of this virtual function will simply run
- * a main loop.
- *
- * It is an error to call this function if @a application is a proxy for
- * a remote application.
- *
- * @return The exit status.
- *
- * @newin{3,4}
+ /** Get the window, constructed by make_window_and_run().
*/
- int run();
+ Window* get_run_window() { return m_run_window; }
+ /** Get the window, constructed by make_window_and_run().
+ */
+ const Window* get_run_window() const { return m_run_window; }
_WRAP_METHOD(Glib::RefPtr<Gio::MenuModel> get_menubar(), gtk_application_get_menubar, refreturn)
_WRAP_METHOD(Glib::RefPtr<const Gio::MenuModel> get_menubar() const, gtk_application_get_menubar,
refreturn, constversion)
@@ -302,8 +289,30 @@ private:
*/
const Glib::Class& custom_class_init();
- void on_activate_add_and_show_main_window(Window* window);
- void on_window_hide(Window* window);
+ Window* m_run_window = nullptr;
};
+template <typename T_Window, typename... T_Args>
+int Application::make_window_and_run(int argc, char** argv, T_Args&&... args)
+{
+ static_assert(std::is_base_of<Window, T_Window>::value);
+
+ signal_activate().connect([this, &args...] () {
+ auto window = new T_Window(std::forward<T_Args>(args)...);
+ m_run_window = window;
+ add_window(*window);
+ window->show();
+ });
+
+ signal_window_removed().connect([this] (Window* window) {
+ if (window == m_run_window)
+ {
+ delete window;
+ m_run_window = nullptr;
+ }
+ });
+
+ return Gio::Application::run(argc, argv);
+}
+
} // namespace Gtk
diff --git a/tests/builder/main.cc b/tests/builder/main.cc
index 68a13db8..b1beb3cd 100644
--- a/tests/builder/main.cc
+++ b/tests/builder/main.cc
@@ -208,6 +208,7 @@ int main(int argc, char* argv[])
auto app = Gtk::Application::create();
g_assert_nonnull(app);
+ app->register_application();
DerivedButton::ensure_type();
auto builder = Gtk::Builder::create_from_string(gladefile);
@@ -233,37 +234,52 @@ int main(int argc, char* argv[])
const GObject* const standard_button = (GObject*)main_win->get_standard_button()->gobj();
const GObject* const adjustment_gobj = (GObject*)adjustment->gobj();
- std::cout << "Before app->run(*main_win, argc1, argv)" << std::endl
+ std::cout << "Before app->run(argc1, argv)" << std::endl
<< " ref_count(MainWindow)=" << window->ref_count << std::endl
<< " ref_count(DerivedButton)=" << derived_button->ref_count << std::endl
<< " ref_count(Gtk::Button)=" << standard_button->ref_count << std::endl
<< " ref_count(orphaned_button)=" << orphaned_button->ref_count << std::endl
<< " ref_count(adjustment)=" << adjustment_gobj->ref_count << std::endl;
- const int result = app->run(*main_win, argc1, argv);
-
- std::cout << "After app->run(*main_win, argc1, argv)" << std::endl
- << " ref_count(MainWindow)=" << window->ref_count << std::endl
- << " ref_count(DerivedButton)=" << derived_button->ref_count << std::endl
- << " ref_count(Gtk::Button)=" << standard_button->ref_count << std::endl
- << " ref_count(orphaned_button)=" << orphaned_button->ref_count << std::endl
- << " ref_count(adjustment)=" << adjustment_gobj->ref_count << std::endl;
+ // This is approximately what Gtk::Application::make_window_and_run() would do.
+ app->signal_activate().connect([&app, main_win] ()
+ {
+ app->add_window(*main_win);
+ main_win->show();
+ });
+ main_win->signal_hide().connect([&] ()
+ {
+ delete main_win;
- delete main_win;
+ std::cout << "After delete main_win" << std::endl
+ << " ref_count(MainWindow)=" << window->ref_count << std::endl
+ << " ref_count(DerivedButton)=" << derived_button->ref_count << std::endl
+ << " ref_count(Gtk::Button)=" << standard_button->ref_count << std::endl
+ << " ref_count(orphaned_button)=" << orphaned_button->ref_count << std::endl
+ << " ref_count(adjustment)=" << adjustment_gobj->ref_count << std::endl;
- std::cout << "After delete main_win" << std::endl
- << " ref_count(MainWindow)=" << window->ref_count << std::endl
- << " ref_count(DerivedButton)=" << derived_button->ref_count << std::endl
- << " ref_count(Gtk::Button)=" << standard_button->ref_count << std::endl
- << " ref_count(orphaned_button)=" << orphaned_button->ref_count << std::endl
- << " ref_count(adjustment)=" << adjustment_gobj->ref_count << std::endl;
+ builder.reset();
+
+ std::cout << "After builder.reset()" << std::endl;
+ if (print_after_deletion)
+ {
+ // If Builder is correct, this code will access deallocated memory.
+ std::cout
+ << " ref_count(MainWindow)=" << window->ref_count << std::endl
+ << " ref_count(DerivedButton)=" << derived_button->ref_count << std::endl
+ << " ref_count(Gtk::Button)=" << standard_button->ref_count << std::endl
+ << " ref_count(orphaned_button)=" << orphaned_button->ref_count << std::endl
+ << " ref_count(adjustment)=" << adjustment_gobj->ref_count << std::endl;
+ }
+ });
- builder.reset();
+ const int result = app->run(argc1, argv);
+ std::cout << "After app->run(argc1, argv)" << std::endl;
if (print_after_deletion)
{
// If Builder is correct, this code will access deallocated memory.
- std::cout << "After builder.reset()" << std::endl
+ std::cout
<< " ref_count(MainWindow)=" << window->ref_count << std::endl
<< " ref_count(DerivedButton)=" << derived_button->ref_count << std::endl
<< " ref_count(Gtk::Button)=" << standard_button->ref_count << std::endl
diff --git a/tests/child_widget/main.cc b/tests/child_widget/main.cc
index ebb538d3..9b68a745 100644
--- a/tests/child_widget/main.cc
+++ b/tests/child_widget/main.cc
@@ -17,10 +17,9 @@
#include <gtkmm/application.h>
#include "testwindow.h"
-int main(int argc, char *argv[])
+int main(int argc, char* argv[])
{
auto app = Gtk::Application::create();
- TestWindow testWindow;
- return app->run(testWindow, argc, argv); //Shows the window and returns when it is closed.
+ return app->make_window_and_run<TestWindow>(argc, argv); //Shows the window and returns when it is closed.
}
diff --git a/tests/child_widget2/main.cc b/tests/child_widget2/main.cc
index a6f2f6c2..8ec1fd04 100644
--- a/tests/child_widget2/main.cc
+++ b/tests/child_widget2/main.cc
@@ -18,10 +18,8 @@ MyWindow::MyWindow() :
vbox.append(b);
}
-int main (int argc, char *argv[])
+int main(int argc, char* argv[])
{
auto app = Gtk::Application::create();
-
- MyWindow window;
- return app->run(window, argc, argv);
+ return app->make_window_and_run<MyWindow>(argc, argv);
}
diff --git a/tests/child_widget_managed/main.cc b/tests/child_widget_managed/main.cc
index 692b2729..00ca6b7f 100644
--- a/tests/child_widget_managed/main.cc
+++ b/tests/child_widget_managed/main.cc
@@ -44,7 +44,5 @@ ExampleWindow::~ExampleWindow()
int main(int argc, char* argv[])
{
auto app = Gtk::Application::create();
-
- ExampleWindow window;
- return app->run(window, argc, argv);
+ return app->make_window_and_run<ExampleWindow>(argc, argv);
}
diff --git a/tests/delete_cpp_child/main.cc b/tests/delete_cpp_child/main.cc
index 6b709a72..9a911c81 100644
--- a/tests/delete_cpp_child/main.cc
+++ b/tests/delete_cpp_child/main.cc
@@ -47,6 +47,5 @@ void AppWindow::on_button_clicked()
int main(int argc, char *argv[])
{
auto app = Gtk::Application::create();
- AppWindow window;
- return app->run(window, argc, argv);
+ return app->make_window_and_run<AppWindow>(argc, argv);
}
diff --git a/tests/dialog_deletethis/main.cc b/tests/dialog_deletethis/main.cc
index fc02ae5c..f3749d7f 100644
--- a/tests/dialog_deletethis/main.cc
+++ b/tests/dialog_deletethis/main.cc
@@ -48,6 +48,7 @@ class Dlg : public sigc::trackable
int main (int argc, char **argv)
{
app = Gtk::Application::create();
+ app->register_application();
new Dlg(); //Not a Gtk::Dialog - it creates one in its constructor.
diff --git a/tests/main_with_options/main.cc b/tests/main_with_options/main.cc
index 5e84c31c..aa4b3830 100644
--- a/tests/main_with_options/main.cc
+++ b/tests/main_with_options/main.cc
@@ -122,8 +122,7 @@ int main(int argc, char *argv[])
}
std::cout << std::endl;
- Gtk::Window testWindow;
- return app->run(testWindow); //Shows the window and returns when it is closed.
+ return app->make_window_and_run<Gtk::Window>(0, nullptr); //Shows the window and returns when it is
closed.
}
catch(const Glib::Error& ex)
{
diff --git a/tests/property_notification/main.cc b/tests/property_notification/main.cc
index 69f8ef13..d4970553 100644
--- a/tests/property_notification/main.cc
+++ b/tests/property_notification/main.cc
@@ -17,22 +17,24 @@ void on_property_name_changed()
std::cout << "name property changed" << std::endl;
}
-int main (int argc, char **argv)
+class TestWindow : public Gtk::Window
{
- auto app = Gtk::Application::create();
+public:
+ TestWindow()
+ {
+ button.connect_property_changed("rgba", sigc::ptr_fun(&on_property_rgba_changed));
+ button.property_rgba().signal_changed().connect(sigc::ptr_fun(&on_property_rgba_changed_nicer_api));
+ button.connect_property_changed("name", sigc::ptr_fun(&on_property_name_changed));
- Gtk::Window window;
+ set_child(button);
+ }
+protected:
Gtk::ColorButton button;
- button.show();
-
- button.connect_property_changed("rgba", sigc::ptr_fun(&on_property_rgba_changed));
-
- button.property_rgba().signal_changed().connect(sigc::ptr_fun(&on_property_rgba_changed_nicer_api));
-
- button.connect_property_changed("name", sigc::ptr_fun(&on_property_name_changed));
+};
- window.set_child(button);
-
- return app->run(window, argc, argv);
+int main (int argc, char **argv)
+{
+ auto app = Gtk::Application::create();
+ return app->make_window_and_run<TestWindow>(argc, argv);
}
diff --git a/tests/refcount_dialog/main.cc b/tests/refcount_dialog/main.cc
index 30c543d0..07f74d79 100644
--- a/tests/refcount_dialog/main.cc
+++ b/tests/refcount_dialog/main.cc
@@ -67,7 +67,5 @@ void MyWindow::on_dialog_response(int /* response_id */)
int main(int argc, char* argv[])
{
auto app = Gtk::Application::create();
-
- MyWindow win;
- return app->run(win, argc, argv);
+ return app->make_window_and_run<MyWindow>(argc, argv);
}
diff --git a/tests/scrolledwindow/main.cc b/tests/scrolledwindow/main.cc
index 151b4533..75d8195e 100644
--- a/tests/scrolledwindow/main.cc
+++ b/tests/scrolledwindow/main.cc
@@ -55,9 +55,10 @@ protected:
DerivedScrolledWindow m_ScrolledWindow;
};
-int main (int /* argc */, char** /* argv */)
+int main(int /* argc */, char** /* argv */)
{
auto app = Gtk::Application::create();
+ app->register_application();
Instance instance;
diff --git a/tests/wrap_existing/main.cc b/tests/wrap_existing/main.cc
index 1a1482ab..7b04ac00 100644
--- a/tests/wrap_existing/main.cc
+++ b/tests/wrap_existing/main.cc
@@ -18,9 +18,10 @@ void on_object_qdata_destroyed(gpointer data)
g_warning("on_object_qdata_destroyed(): c instance=%p", (void*)data);
}
-int main (int /* argc */, char** /* argv */)
+int main(int /* argc */, char** /* argv */)
{
auto app = Gtk::Application::create();
+ app->register_application();
auto pDialog = new Gtk::Dialog();
Gtk::Box* pBox = pDialog->get_content_area();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]