[gtkmm] Gtk::Widget, Window: Fix the removal of a hidden window from its app



commit a167090b40c4deeb2f13461b653995fed754e986
Author: Kjell Ahlstedt <kjellahlstedt gmail com>
Date:   Wed Nov 27 16:13:12 2019 +0100

    Gtk::Widget, Window: Fix the removal of a hidden window from its app
    
    * tools/m4/class_gtkobject.m4: The _CUSTOM_MOVE_OPERATIONS macro can be
    used in a _CLASS_GTKOBJECT.
    * gtk/src/widget.ccg: Don't remove a window from its application in
    Widget_Class::hide_callback(). It's not called, if the underlying C object
    is a GtkWindow, and not a gtkmm__GtkWindow.
    * gtk/src/window.[ccg|hg]: All constructors connect a signal handler
    that removes a window from its application when the window is hidden.

 gtk/src/widget.ccg          | 18 +--------------
 gtk/src/window.ccg          | 54 +++++++++++++++++++++++++++++++++++++++++++++
 gtk/src/window.hg           | 19 +++++++++++++---
 tools/m4/class_gtkobject.m4 | 19 +++++++++++++---
 4 files changed, 87 insertions(+), 23 deletions(-)
---
diff --git a/gtk/src/widget.ccg b/gtk/src/widget.ccg
index 17eb1758..f20d12eb 100644
--- a/gtk/src/widget.ccg
+++ b/gtk/src/widget.ccg
@@ -113,25 +113,9 @@ 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,
-// and so that we can remove a hidden window from its application.
+// from calling an on_hide() override, if the C++ wrapper is being deleted.
 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.ccg b/gtk/src/window.ccg
index 04606239..926edc76 100644
--- a/gtk/src/window.ccg
+++ b/gtk/src/window.ccg
@@ -27,6 +27,60 @@
 namespace Gtk
 {
 
+// All constructors are hand-coded, because they connect a signal handler
+// that removes the window from its application when the window is closed (hidden).
+Window::Window(const Glib::ConstructParams& construct_params)
+:
+  Gtk::Bin(construct_params)
+{
+  signal_hide().connect(sigc::mem_fun(*this, &Window::on_window_hide));
+}
+
+Window::Window(GtkWindow* castitem)
+:
+  Gtk::Bin((GtkBin*)castitem)
+{
+  signal_hide().connect(sigc::mem_fun(*this, &Window::on_window_hide));
+}
+
+Window::Window(Window&& src)
+: Gtk::Bin(std::move(src))
+  , Native(std::move(src))
+  , Root(std::move(src))
+{
+  signal_hide().connect(sigc::mem_fun(*this, &Window::on_window_hide));
+}
+
+// The move assignment is identical to the one that gmmproc can generate.
+// _CUSTOM_MOVE_OPERATIONS() suppresses both move contructor and move assignment. 
+Window& Window::operator=(Window&& src) noexcept
+{
+  Gtk::Bin::operator=(std::move(src));
+  Native::operator=(std::move(src));
+  Root::operator=(std::move(src));
+  return *this;
+}
+
+Window::Window(WindowType type)
+: _CONSTRUCT("type", static_cast<GtkWindowType>(type))
+{
+  signal_hide().connect(sigc::mem_fun(*this, &Window::on_window_hide));
+}
+
+void Window::on_window_hide()
+{
+  auto appl = get_application();
+  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
+    appl->remove_window(*this);
+  }
+}
+
 std::vector< Glib::RefPtr<AccelGroup> > Window::get_accel_groups()
 {
   return Glib::SListHandler< Glib::RefPtr<AccelGroup> >::slist_to_vector(
diff --git a/gtk/src/window.hg b/gtk/src/window.hg
index 9752e115..85fb66e0 100644
--- a/gtk/src/window.hg
+++ b/gtk/src/window.hg
@@ -40,13 +40,18 @@ namespace Gtk
 class AccelGroup;
 class WindowGroup;
 
-/** Toplevel Window.
+/** Toplevel %Window.
  * This represents all widgets which are physical windows controlled
  * by the window manager.
  *
- * The window will be hidden when the window manager's close button is clicked. Override on_delete_event() 
to stop this.
+ * The window will be hidden when the window manager's close button is clicked.
+ * Override on_delete_event() to stop this.
  *
  * Gtk::manage() has no effect on Windows because they have no parent Containers.
+ *
+ * When a window is closed (hidden), it's removed from its application.
+ * This can cause Application::run() to return, if it is the last window.
+ *
  * @ingroup Widgets
  */
 class Window : public Bin, public Native, public Root
@@ -65,7 +70,14 @@ public:
   // to call gtk_widget_get_display() from a class that implements GtkRoot.
   using Root::get_display;
 
-  _WRAP_CTOR(Window(WindowType type = WindowType::TOPLEVEL), gtk_window_new)
+  // All constructors are hand-coded, because they connect a signal handler.
+  _CUSTOM_CTOR_CAST()
+  _CUSTOM_MOVE_OPERATIONS()
+  Window(Window&& src);
+  Window& operator=(Window&& src) noexcept;
+
+  explicit Window(WindowType type =  WindowType::TOPLEVEL);
+  _IGNORE(gtk_window_new)
 
   _WRAP_PROPERTY("type", WindowType)
   _WRAP_PROPERTY("title", Glib::ustring)
@@ -333,6 +345,7 @@ dnl
   void set_manage() override;
 
 protected:
+  void on_window_hide();
 
   //See comments in the implementations:
   void destroy_();
diff --git a/tools/m4/class_gtkobject.m4 b/tools/m4/class_gtkobject.m4
index 7c0897ca..1cf15669 100644
--- a/tools/m4/class_gtkobject.m4
+++ b/tools/m4/class_gtkobject.m4
@@ -1,7 +1,5 @@
 dnl $Id$
 
-
-
 define(`_CLASS_GTKOBJECT',`dnl
 _PUSH()
 dnl
@@ -38,7 +36,16 @@ define(`__BOOL_CUSTOM_DTOR__',`$1')
 _POP()
 ')
 
-dnl Gtk::Object has a custom-written cast implementation:
+dnl For classes that need custom code for move operations.
+define(`_CUSTOM_MOVE_OPERATIONS', `dnl
+_PUSH()
+dnl Define this macro to be tested for later.
+define(`__BOOL_CUSTOM_MOVE_OPERATIONS__',`$1')
+_POP()
+')
+
+dnl For classes that need custom code in their cast and construct_params
+dnl constructors.
 define(`_CUSTOM_CTOR_CAST',`dnl
 _PUSH()
 dnl Define this macro to be tested for later.
@@ -192,6 +199,8 @@ __CPPNAME__::__CPPNAME__`'(__CNAME__* castitem)
 
 ')dnl
 
+ifdef(`__BOOL_CUSTOM_MOVE_OPERATIONS__',`dnl
+',`dnl
 __CPPNAME__::__CPPNAME__`'(__CPPNAME__&& src) noexcept
 : __CPPPARENT__`'(std::move(src))
 _IMPORT(SECTION_CC_MOVE_CONSTRUCTOR_INTERFACES)
@@ -203,6 +212,7 @@ __CPPNAME__& __CPPNAME__::operator=(__CPPNAME__&& src) noexcept
 _IMPORT(SECTION_CC_MOVE_ASSIGNMENT_OPERATOR_INTERFACES)
   return *this;
 }
+')dnl
 
 ifdef(`__BOOL_CUSTOM_DTOR__',`dnl
 ',`dnl
@@ -233,8 +243,11 @@ public:
   typedef __REAL_CNAME__`'Class BaseClassType;
 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
 
+ifdef(`__BOOL_CUSTOM_MOVE_OPERATIONS__',`dnl
+',`dnl
   __CPPNAME__`'(__CPPNAME__&& src) noexcept;
   __CPPNAME__& operator=(__CPPNAME__&& src) noexcept;
+')dnl
 
   // noncopyable
   __CPPNAME__`'(const __CPPNAME__&) = delete;


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