[gtkmm] Allow managed Gtk::Window's



commit 39e1941c6b06fab5a1e7ccc317ddfeea1aae78e5
Author: Kjell Ahlstedt <kjellahlstedt gmail com>
Date:   Tue Mar 22 14:40:45 2022 +0100

    Allow managed Gtk::Window's
    
    A managed Window is deleted when its underlying C instance is destroyed.
    
    * gtk/gtkmm/object.h: Add more documentation of Gtk::manage().
    * gtk/src/window.[ccg|hg]: Add set_destroy_with_parent() and destroy().
    set_manage() makes the window managed.
    
    Fixes #24, see also #114

 gtk/gtkmm/object.h | 10 ++++++++--
 gtk/src/window.ccg | 12 +++++++++++-
 gtk/src/window.hg  | 40 +++++++++++++++++++++++++++++-----------
 3 files changed, 48 insertions(+), 14 deletions(-)
---
diff --git a/gtk/gtkmm/object.h b/gtk/gtkmm/object.h
index e36007f3..66d772b0 100644
--- a/gtk/gtkmm/object.h
+++ b/gtk/gtkmm/object.h
@@ -35,6 +35,11 @@ class GTKMM_API Object;
  * vbox.append(*button); //vbox will delete button when vbox is deleted.
  * @endcode
  *
+ * Beginning with gtkmm 4.8, a Gtk::Window can be managed, although it has no parent.
+ * A managed Gtk::Window is deleted when its underlying C instance is destroyed.
+ * The C instance will be destroyed when the window manager's close button
+ * is clicked, unless Gtk::Window::set_hide_on_close() has been called.
+ *
  * @param obj A Gtk::Object, such as a gtkmm widget.
  * @result The Gtk::Object passed as the @a obj parameter.
  */
@@ -47,7 +52,7 @@ T* manage(T* obj)
 
 /** Create a Gtk::Object such as a widget and Gtk::manage() it in a single step.
  * This matches standard functions like std::make_unique<T>(args) and avoids you
- * manually invoking the new operator, which is discouraged in modern C++ style.
+ * manually invoking the @c new operator, which is discouraged in modern C++ style.
  *
  * For instance,
  * @code
@@ -55,6 +60,7 @@ T* manage(T* obj)
  * vbox.append(*button); //vbox will delete button when vbox is deleted.
  * @endcode
  *
+ * @tparam T The type of object to create.
  * @param args Arguments to pass to the constructor of the given template type.
  * @result A new, managed object of that type, constructed with those arguments.
  */
@@ -115,7 +121,7 @@ public:
 
 public:
   #ifndef DOXYGEN_SHOULD_SKIP_THIS
-  /** Used by Gtk::manage(). You should not need to use this directly.
+  /** Used by Gtk::manage() and Gtk::make_managed(). You should not need to use this directly.
    */
   void set_manage() override;
   #endif //DOXYGEN_SHOULD_SKIP_THIS
diff --git a/gtk/src/window.ccg b/gtk/src/window.ccg
index 21300d9f..6037a52e 100644
--- a/gtk/src/window.ccg
+++ b/gtk/src/window.ccg
@@ -98,7 +98,9 @@ void Window::on_window_hide()
 
 void Window::set_manage()
 {
-  g_warning("gtkmm: Attempt to call Gtk::manage() on a Gtk::Window, but a Gtk::Window has no parent 
container to manage its lifetime.\n");
+  // This C++ wrapper is deleted by Gtk::Object::destroy_notify_() when the
+  // underlying C instance is destroyed.
+  referenced_ = false; // Managed
 }
 
 void Window::destroy_()
@@ -209,6 +211,14 @@ void Window_Class::dispose_vfunc_callback(GObject* self)
   #endif
 }
 
+void Window::destroy()
+{
+  // Don't crash if destroy() is called twice.
+  // gobj() can be nullptr after the first call to destroy().
+  if (gobj())
+    gtk_window_destroy(gobj());
+}
+
 void Window::unset_focus()
 {
   gtk_window_set_focus(gobj(), nullptr /* See GTK+ docs */);
diff --git a/gtk/src/window.hg b/gtk/src/window.hg
index 194431e6..1dad7ff1 100644
--- a/gtk/src/window.hg
+++ b/gtk/src/window.hg
@@ -45,8 +45,6 @@ class GTKMM_API WindowGroup;
  * This represents all widgets which are physical windows controlled
  * by the window manager.
  *
- * Gtk::manage() has no effect on Windows because they have no parent containers.
- *
  * The window will be destroyed when the window manager's close button is clicked.
  * Call set_hide_on_close() if you want it to be hidden instead.
  *
@@ -62,9 +60,6 @@ class GTKMM_API Window : public Widget, public Native, public ShortcutManager, p
   _IMPLEMENTS_INTERFACE(ShortcutManager)
   _IMPLEMENTS_INTERFACE(Root)
   _UNMANAGEABLE
-  _IGNORE(gtk_window_destroy, gtk_window_set_destroy_with_parent)
-
-  //TODO: Use gtk_window_set_destroy_with_parent() to allow use of Gtk::manage() with top-level windows, 
using the transient-parent?
 
 public:
   // Disambiguate calls to get_display(). Use Root::get_display(), not Widget::get_display().
@@ -156,12 +151,31 @@ dnl
   _WRAP_METHOD(Window* get_transient_for(), gtk_window_get_transient_for)
   _WRAP_METHOD(const Window* get_transient_for() const, gtk_window_get_transient_for, constversion)
 
-  //_WRAP_METHOD(void set_destroy_with_parent(bool setting = true), gtk_window_set_destroy_with_parent)
-  // I don't that that this is ever a good thing for C++.murrayc.
-
-  //TODO: Remove?
+  _WRAP_METHOD(void set_destroy_with_parent(bool setting = true),
+    gtk_window_set_destroy_with_parent, newin "4,8")
   _WRAP_METHOD(bool get_destroy_with_parent() const, gtk_window_get_destroy_with_parent)
-  // I don't that that this is ever a good thing for C++.murrayc.
+
+  /** Drop the internal reference GTK holds on toplevel windows.
+   *
+   * If this window is managed, this C++ wrapper will be deleted when the
+   * underlying C instance is destroyed.
+   *
+   * After a call to %destroy(), don't call any method that accesses the
+   * underlying C instance.
+   *
+   * If the C++ wrapper is deleted, the underlying C instance will be destroyed.
+   * If the C instance is destroyed and the C++ wrapper is managed, the wrapper
+   * will be deleted. The difference is in the order in which actions are taken.
+   * That may or may not be important. If the C instance is destroyed before
+   * the wrapper is deleted, C++ signal handlers can be called during the destruction.
+   * For instance, if you connect to Gtk::Widget::signal_unrealize() or override
+   * Gtk::Widget::on_unrealize(), those signal handlers can be called only if
+   * the wrapper still exists when the signal is emitted.
+   *
+   * @newin{4,8}
+   */
+  void destroy();
+  _IGNORE(gtk_window_destroy)
 
   _WRAP_METHOD(void set_hide_on_close(bool setting = true), gtk_window_set_hide_on_close)
   _WRAP_METHOD(bool get_hide_on_close() const, gtk_window_get_hide_on_close)
@@ -277,7 +291,11 @@ dnl
   //TODO: _WRAP_METHOD(void show_uri(const Glib::ustring& uri, guint32 timestamp), gtk_show_uri)
   // gtk_show_uri_full[_finish]()
 
-  ///Overriden to warn that it doesn't make sense to use Gtk::manage() on this class because it has no 
parent container.
+  /** Used by Gtk::manage() and Gtk::make_managed(). You should not need to use this directly.
+   * Overridden because a %Gtk::Window is not managed by a container.
+   * Beginning with gtkmm 4.8, a %Gtk::Window can be managed. If managed, it's
+   * deleted when its underlying C instance is destroyed.
+   */
   void set_manage() override;
 
 protected:


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