builder: Add gtk_builder_set_current_object()
authorBenjamin Otte <otte@redhat.com>
Thu, 28 Nov 2019 03:01:19 +0000 (04:01 +0100)
committerBenjamin Otte <otte@redhat.com>
Thu, 12 Dec 2019 18:12:11 +0000 (19:12 +0100)
Use it as the default object for expression binds and when connecting
signals. It is intended to work kind of as the "this" object while
parsing. In fact, the term "current object" was stolen from the Java
docs and various C++ tutorials for the this pointer.

Set the current object in gtk_widget_init_template() and
GtkListItemBuilder.

This more-or-less replaces the object passed to
gtk_builder_connect_signals() in GTK3.

docs/reference/gtk/gtk4-sections.txt
gtk/gtkbuilder.c
gtk/gtkbuilder.h
gtk/gtkwidget.c

index cb7ed29ddd3c0acf33ca2f03448b1df5408b9d5d..efa6c32df7eae2fed48d59bb9576e1cf78aa041b 100644 (file)
@@ -541,6 +541,8 @@ gtk_builder_extend_with_template
 gtk_builder_get_object
 gtk_builder_get_objects
 gtk_builder_expose_object
+gtk_builder_set_current_object
+gtk_builder_get_current_object
 gtk_builder_set_translation_domain
 gtk_builder_get_translation_domain
 gtk_builder_get_type_from_name
index cafbe4e5f641580218dd57d2d5271c1394d539ed..0be335e63bfaca53605cfc75875da98fa8e3319a 100644 (file)
@@ -253,6 +253,7 @@ static void gtk_builder_get_property   (GObject         *object,
 
 enum {
   PROP_0,
+  PROP_CURRENT_OBJECT,
   PROP_TRANSLATION_DOMAIN,
   LAST_PROP
 };
@@ -281,6 +282,7 @@ typedef struct
   gchar *filename;
   gchar *resource_prefix;
   GType template_type;
+  GObject *current_object;
 
   GtkBuilderClosureFunc closure_func;
   gpointer closure_data;
@@ -289,11 +291,22 @@ typedef struct
 
 G_DEFINE_TYPE_WITH_PRIVATE (GtkBuilder, gtk_builder, G_TYPE_OBJECT)
 
+static void
+gtk_builder_dispose (GObject *object)
+{
+  GtkBuilderPrivate *priv = gtk_builder_get_instance_private (GTK_BUILDER (object));
+
+  g_clear_object (&priv->current_object);
+
+  G_OBJECT_CLASS (gtk_builder_parent_class)->dispose (object);
+}
+
 static void
 gtk_builder_class_init (GtkBuilderClass *klass)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
+  gobject_class->dispose = gtk_builder_dispose;
   gobject_class->finalize = gtk_builder_finalize;
   gobject_class->set_property = gtk_builder_set_property;
   gobject_class->get_property = gtk_builder_get_property;
@@ -313,6 +326,18 @@ gtk_builder_class_init (GtkBuilderClass *klass)
                            NULL,
                            GTK_PARAM_READWRITE);
 
+ /**
+  * GtkBuilder:current-object:
+  *
+  * The object the builder is evaluating for.
+  */
+  builder_props[PROP_CURRENT_OBJECT] =
+      g_param_spec_object ("current-object",
+                           P_("Current object"),
+                           P_("The object the builder is evaluating for"),
+                           G_TYPE_OBJECT,
+                           GTK_PARAM_READWRITE);
+
   g_object_class_install_properties (gobject_class, LAST_PROP, builder_props);
 }
 
@@ -364,9 +389,14 @@ gtk_builder_set_property (GObject      *object,
 
   switch (prop_id)
     {
+    case PROP_CURRENT_OBJECT:
+      gtk_builder_set_current_object (builder, g_value_get_object (value));
+      break;
+
     case PROP_TRANSLATION_DOMAIN:
       gtk_builder_set_translation_domain (builder, g_value_get_string (value));
       break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -384,9 +414,14 @@ gtk_builder_get_property (GObject    *object,
 
   switch (prop_id)
     {
+    case PROP_CURRENT_OBJECT:
+      g_value_set_object (value, priv->current_object);
+      break;
+
     case PROP_TRANSLATION_DOMAIN:
       g_value_set_string (value, priv->domain);
       break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1677,6 +1712,54 @@ gtk_builder_expose_object (GtkBuilder    *builder,
                        g_object_ref (object));
 }
 
+/**
+ * gtk_builder_get_current_object:
+ * @self: a #GtkBuilder
+ *
+ * Gets the current object set via gtk_builder_set_current_object().
+ *
+ * Returns: (nullable) (transfer none): the current object
+ **/
+GObject *
+gtk_builder_get_current_object (GtkBuilder *self)
+{
+  GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self);
+
+  g_return_val_if_fail (GTK_IS_BUILDER (self), NULL);
+
+  return priv->current_object;
+}
+
+/**
+ * gtk_builder_set_current_object:
+ * @self: a #GtkBuilder
+ * @current_object: (nullable) (transfer none): the new current object or
+ *     %NULL for none
+ *
+ * Sets the current object for the @self. The current object can be
+ * tought of as the `this` object that the builder is working for and
+ * will often be used as the default object when an object is optional.
+ *
+ * gtk_widget_init_template() for example will set the current object to
+ * the widget the template is inited for.  
+ * For functions like gtk_builder_new_from_resource(), the current object
+ * will be %NULL.
+ **/
+void
+gtk_builder_set_current_object (GtkBuilder *self,
+                                GObject    *current_object)
+{
+  GtkBuilderPrivate *priv = gtk_builder_get_instance_private (self);
+
+  g_return_if_fail (GTK_IS_BUILDER (self));
+  g_return_if_fail (current_object || G_IS_OBJECT (current_object));
+
+  if (!g_set_object (&priv->current_object, current_object))
+    return;
+
+  g_object_notify_by_pspec (G_OBJECT (self), builder_props[PROP_CURRENT_OBJECT]);
+}
+
 /**
  * GtkBuilderClosureFunc:
  * @builder: a #GtkBuilder
@@ -2701,8 +2784,12 @@ gtk_builder_create_closure_for_funcptr (GtkBuilder *builder,
                                         gboolean    swapped,
                                         GObject    *object)
 {
+  GtkBuilderPrivate *priv = gtk_builder_get_instance_private (builder);
   GClosure *closure;
 
+  if (object == NULL)
+    object = priv->current_object;
+
   if (object)
     {
       if (swapped)
index 3bc752852b54a5c39bbf162de55f21a262ba257d..4c7e6e934cfbce9705193c510083f30f77bae207 100644 (file)
@@ -142,6 +142,11 @@ void         gtk_builder_expose_object           (GtkBuilder    *builder,
                                                   const gchar   *name,
                                                   GObject       *object);
 GDK_AVAILABLE_IN_ALL
+GObject *    gtk_builder_get_current_object      (GtkBuilder    *self);
+GDK_AVAILABLE_IN_ALL
+void         gtk_builder_set_current_object      (GtkBuilder    *self,
+                                                  GObject       *current_object);
+GDK_AVAILABLE_IN_ALL
 void         gtk_builder_set_translation_domain  (GtkBuilder           *builder,
                                                   const gchar          *domain);
 GDK_AVAILABLE_IN_ALL
index 1f86d04bb3c2d54dd69addb59aeecfa1cb2485fa..c2a4ef1cbf57d6ae8910dec5ca31dc4d7c8bd4d5 100644 (file)
@@ -12113,24 +12113,6 @@ setup_template_child (GtkWidgetTemplate   *template_data,
   return TRUE;
 }
 
-static GClosure *
-gtk_widget_template_closure_func (GtkBuilder  *builder,
-                                  const char  *function_name,
-                                  gboolean     swapped,
-                                  GObject     *object,
-                                  gpointer     user_data,
-                                  GError     **error)
-{
-  if (object == NULL)
-    object = user_data;
-
-  return gtk_builder_create_cclosure (builder,
-                                      function_name,
-                                      swapped,
-                                      object,
-                                      error);
-}
-
 /**
  * gtk_widget_init_template:
  * @widget: a #GtkWidget
@@ -12172,6 +12154,8 @@ gtk_widget_init_template (GtkWidget *widget)
 
   builder = gtk_builder_new ();
 
+  gtk_builder_set_current_object (builder, G_OBJECT (widget));
+
   /* Setup closure handling. All signal data from a template receive the 
    * template instance as user data automatically.
    *
@@ -12180,8 +12164,6 @@ gtk_widget_init_template (GtkWidget *widget)
    */
   if (template->closure_func)
     gtk_builder_set_closure_func (builder, template->closure_func, template->closure_data, NULL);
-  else
-    gtk_builder_set_closure_func (builder, gtk_widget_template_closure_func, widget, NULL);
 
   /* Add any callback symbols declared for this GType to the GtkBuilder namespace */
   for (l = template->callbacks; l; l = l->next)