[gtkmm] Gtk::Application, Window: Always remove a window from its app when hidden



commit 01ff5c7a8ea28082c28794f35927be44c3b79d58
Author: Kjell Ahlstedt <kjellahlstedt gmail com>
Date:   Thu Nov 14 17:02:31 2019 +0100

    Gtk::Application, Window: Always remove a window from its app when hidden
    
    * gtk/src/application.[ccg|hg]: add_window() is not hand-coded.
    * gtk/src/widget.ccg: Widget_Class::hide_callback(): Remove a hidden
    window from its application.
    * gtk/src/window.hg: set_application(): Update the description.
    
    When Widget_Class::hide_callback() removes a hidden window from its
    application, the removal is performed regardless of how the window
    has been added to the application: by Application::add_window(),
    by Window::set_application() or by some other means.
    Fixes #56

 gtk/src/application.ccg | 40 +++-------------------------------------
 gtk/src/application.hg  | 10 ++++++----
 gtk/src/widget.ccg      | 18 +++++++++++++++++-
 gtk/src/window.hg       | 17 +++++++++++++++++
 4 files changed, 43 insertions(+), 42 deletions(-)
---
diff --git a/gtk/src/application.ccg b/gtk/src/application.ccg
index 8aa5ad6a..b7602ece 100644
--- a/gtk/src/application.ccg
+++ b/gtk/src/application.ccg
@@ -110,29 +110,6 @@ Glib::RefPtr<Application> Application::create(const Glib::ustring& application_i
   return Glib::RefPtr<Application>( new Application(application_id, flags) );
 }
 
-void Application::on_window_hide(Window* window)
-{
-  //Tell GtkApplication to forget the window.
-  //This can cause run() to return, if it is the last window.
-  //Otherwise, GtkApplication waits for the window to be _destroyed_,
-  //which is just not something that it should care about:
-  //See https://bugzilla.gnome.org/show_bug.cgi?id=639931
-  if(window && window->get_application()) //We check that it's still in an application anyway.
-    remove_window(*window);
-}
-
-void Application::add_window(Window& window)
-{
-  //Respond to window hiding, not destruction:
-  //See https://bugzilla.gnome.org/show_bug.cgi?id=639931
-  window.signal_hide().connect(
-    sigc::bind(
-      sigc::mem_fun(*this, &Application::on_window_hide),
-      &window));
-
-  gtk_application_add_window(gobj(), (window).gobj());
-}
-
 int Application::run(int argc, char** argv)
 {
   return Gio::Application::run(argc, argv);
@@ -148,29 +125,18 @@ int Application::run(Window& window, int argc, char** argv)
       sigc::mem_fun(*this, &Application::on_activate_add_and_show_main_window),
       &window));
 
-  const auto result = Gio::Application::run(argc, argv);
-  return result;
+  return Gio::Application::run(argc, argv);
 }
 
 
 int Application::run(Window& window)
 {
-  //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));
-
-  const auto result = Gio::Application::run(0, nullptr);
-  return result;
+  return run(window, 0, nullptr);
 }
 
 int Application::run()
 {
-  const auto result = Gio::Application::run(0, nullptr);
-  return result;
+  return Gio::Application::run(0, nullptr);
 }
 
 void Application::on_activate_add_and_show_main_window(Window* window)
diff --git a/gtk/src/application.hg b/gtk/src/application.hg
index 0d4fa10c..f46aef89 100644
--- a/gtk/src/application.hg
+++ b/gtk/src/application.hg
@@ -141,11 +141,14 @@ public:
 #m4 _CONVERSION(`GList*',`std::vector<const Window*>',`Glib::ListHandler<const Window*>::list_to_vector($3, 
Glib::OWNERSHIP_NONE)')
   _WRAP_METHOD(std::vector<const Window*> get_windows() const, gtk_application_get_windows)
 
-  //Concerning the note on quit(), see https://bugzilla.gnome.org/show_bug.cgi?id=731126
+  // Concerning the note on quit(), see https://bugzilla.gnome.org/show_bug.cgi?id=731126
+  // Concerning the return from run() on hidden windows, see
+  // https://bugzilla.gnome.org/show_bug.cgi?id=639931 and Gtk::Widget_Class::hide_callback().
   /** Adds a window to the Gtk::Application.
    *
    * If all the windows managed by Gtk::Application are closed (hidden) or
-   * removed from the application then the call to run() will return.
+   * removed from the application then the call to run() will return,
+   * unless Gio::Application::hold() has been called.
    *
    * This call is equivalent to calling Gtk::Window::set_application().
    *
@@ -161,8 +164,7 @@ public:
    *
    * @param window A toplevel window to add to the application.
    */
-  void add_window(Window& window);
-  _IGNORE(gtk_application_add_window)
+  _WRAP_METHOD(void add_window(Window& window), gtk_application_add_window)
 
   _WRAP_METHOD(void remove_window(Window& window), gtk_application_remove_window)
 
diff --git a/gtk/src/widget.ccg b/gtk/src/widget.ccg
index f20d12eb..17eb1758 100644
--- a/gtk/src/widget.ccg
+++ b/gtk/src/widget.ccg
@@ -113,9 +113,25 @@ namespace Gtk
 {
 
 // This default handler callback is custom implemented, so that we can refrain
-// from calling an on_hide() override, if the C++ wrapper is being deleted.
+// from calling an on_hide() override, if the C++ wrapper is being deleted,
+// and so that we can remove a hidden window from its application.
 void Widget_Class::hide_callback(GtkWidget* self)
 {
+  if (GTK_IS_WINDOW(self))
+  {
+    GtkWindow* window = GTK_WINDOW(self);
+    GtkApplication* appl = gtk_window_get_application(window);
+    if (appl)
+    {
+      // Tell GtkApplication to forget the window.
+      // This can cause Application::run() to return, if it is the last window.
+      // Otherwise, GtkApplication waits for the window to be _destroyed_,
+      // which is just not something that it should care about:
+      // See https://bugzilla.gnome.org/show_bug.cgi?id=639931
+      gtk_application_remove_window(appl, window);
+    }
+  }
+
   const auto obj_base = static_cast<Glib::ObjectBase*>(
       Glib::ObjectBase::_get_current_wrapper((GObject*)self));
 
diff --git a/gtk/src/window.hg b/gtk/src/window.hg
index 6c18d887..d946fa78 100644
--- a/gtk/src/window.hg
+++ b/gtk/src/window.hg
@@ -276,6 +276,23 @@ dnl
   _WRAP_METHOD(Glib::RefPtr<Application> get_application(), gtk_window_get_application, refreturn)
   _WRAP_METHOD(Glib::RefPtr<const Application> get_application() const, gtk_window_get_application, 
refreturn)
 
+  // Concerning the removal of a hidden window from the application, see
+  // https://bugzilla.gnome.org/show_bug.cgi?id=639931 and Gtk::Widget_Class::hide_callback().
+  /** Sets the Gtk::Application associated with the window.
+   *
+   * The application will be kept alive for at least as long as it has any windows
+   * associated with it. (See Gio::Application::hold() for a way to keep it alive
+   * without windows.)
+   *
+   * Normally, the connection between the application and the window will remain
+   * until the window is closed (hidden), but you can explicitly remove it by
+   * calling unset_application().
+   *
+   * This is equivalent to calling Gtk::Application::remove_window() and/or
+   * Gtk::Application::add_window() on the old/new applications as relevant.
+   *
+   * @param application A Gtk::Application.
+   */
   _WRAP_METHOD(void set_application(const Glib::RefPtr<Application>& application), 
gtk_window_set_application)
 
   /** Unsets the Application associated with the window.


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]