[gtk/wip/otte/builder: 4/10] builder: Add gtk_builder_create_closure()



commit 094c537001c4618aad71e890af937013d06a579a
Author: Benjamin Otte <otte redhat com>
Date:   Thu Nov 21 21:20:16 2019 +0100

    builder: Add gtk_builder_create_closure()
    
    This will be the future way to connect signals automatically (and be
    used for other things, too).
    
    For now, gtk_builder_connect_signals_default() is ported to use it.

 docs/reference/gtk/gtk4-sections.txt |   2 +
 gtk/gtkbuilder.c                     | 150 ++++++++++++++++++++++++++++++-----
 gtk/gtkbuilder.h                     |  21 ++++-
 3 files changed, 150 insertions(+), 23 deletions(-)
---
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index 04bf68f83b..c9fefcebf1 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -529,6 +529,8 @@ gtk_builder_new_from_string
 gtk_builder_add_callback_symbol
 gtk_builder_add_callback_symbols
 gtk_builder_lookup_callback_symbol
+gtk_builder_create_closure
+gtk_builder_create_cclosure
 gtk_builder_add_from_file
 gtk_builder_add_from_resource
 gtk_builder_add_from_string
diff --git a/gtk/gtkbuilder.c b/gtk/gtkbuilder.c
index 5538ecfe8c..5c00a50570 100644
--- a/gtk/gtkbuilder.c
+++ b/gtk/gtkbuilder.c
@@ -1658,31 +1658,23 @@ gtk_builder_connect_signals_default (GtkBuilder    *builder,
                                      GConnectFlags  flags,
                                      gpointer       user_data)
 {
-  GCallback func;
+  GClosure *closure;
+  GError *error = NULL;
 
-  func = gtk_builder_lookup_callback_symbol (builder, handler_name);
+  closure = gtk_builder_create_closure (builder,
+                                        handler_name,
+                                        flags & G_CONNECT_SWAPPED ? TRUE : FALSE,
+                                        connect_object,
+                                        &error);
 
-  if (!func)
+  if (closure == NULL)
     {
-      GModule *module = gtk_builder_get_module (builder);
-
-      /* Only error out for missing GModule support if we've not
-       * found the symbols explicitly added with gtk_builder_add_callback_symbol()
-       */
-      if (module == NULL)
-        g_error ("gtk_builder_connect_signals() requires working GModule");
-
-      if (!g_module_symbol (module, handler_name, (gpointer)&func))
-        {
-          g_warning ("Could not find signal handler '%s'.  Did you compile with -rdynamic?", handler_name);
-          return;
-        }
+      g_warning ("%s", error->message);
+      g_error_free (error);
+      return;
     }
 
-  if (connect_object)
-    g_signal_connect_object (object, signal_name, func, connect_object, flags);
-  else
-    g_signal_connect_data (object, signal_name, func, user_data, NULL, flags);
+  g_signal_connect_closure (object, signal_name, closure, flags & G_CONNECT_AFTER ? TRUE : FALSE);
 }
 
 
@@ -2571,7 +2563,7 @@ _gtk_builder_get_template_type (GtkBuilder *builder)
  *
  * Adds the @callback_symbol to the scope of @builder under the given @callback_name.
  *
- * Using this function overrides the behavior of gtk_builder_connect_signals()
+ * Using this function overrides the behavior of gtk_builder_create_closure()
  * for any callback symbols that are added. Using this method allows for better
  * encapsulation as it does not require that callback symbols be declared in
  * the global namespace.
@@ -2666,6 +2658,122 @@ gtk_builder_lookup_callback_symbol (GtkBuilder  *builder,
   return g_hash_table_lookup (priv->callbacks, callback_name);
 }
 
+static GClosure *
+gtk_builder_create_closure_for_funcptr (GtkBuilder *builder,
+                                        GCallback   callback,
+                                        gboolean    swapped,
+                                        GObject    *object)
+{
+  GClosure *closure;
+
+  if (object)
+    {
+      if (swapped)
+        closure = g_cclosure_new_object_swap (callback, object);
+      else
+        closure = g_cclosure_new_object (callback, object);
+    }
+  else
+    {
+      if (swapped)
+        closure = g_cclosure_new_swap (callback, NULL, NULL);
+      else
+        closure = g_cclosure_new (callback, NULL, NULL);
+    }
+
+  return closure;
+}
+
+/**
+ * gtk_builder_create_closure:
+ * @builder: a #GtkBuilder
+ * @function_name: name of the function to look up
+ * @swapped: %TRUE to create a swapped closure
+ * @object: (nullable): Object to create the closure with
+ * @error: (allow-none): return location for an error, or %NULL
+ *
+ * Creates a closure to invoke the function called @function_name.
+ *
+ * If a closure function was set via gtk_builder_set_closure_func(),
+ * will be invoked.
+ * Otherwise, gtk_builder_create_cclosure() will be called.
+ *
+ * If no closure could be created, %NULL will be returned and @error will
+ * be set.
+ *
+ * Returns: (nullable): A new closure for invoking @function_name
+ **/
+GClosure *
+gtk_builder_create_closure (GtkBuilder *builder,
+                            const char *function_name,
+                            gboolean    swapped,
+                            GObject    *object,
+                            GError    **error)
+{
+  g_return_val_if_fail (GTK_IS_BUILDER (builder), NULL);
+  g_return_val_if_fail (function_name, NULL);
+  g_return_val_if_fail (object == NULL || G_IS_OBJECT (object), NULL);
+  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+  return gtk_builder_create_cclosure (builder, function_name, swapped, object, error);
+}
+
+/**
+ * gtk_builder_create_cclosure: (skip)
+ * @builder: a #GtkBuilder
+ * @function_name: name of the function to look up
+ * @swapped: %TRUE to create a swapped closure
+ * @object: (nullable): Object to create the closure with
+ * @error: (allow-none): return location for an error, or %NULL
+ *
+ * This is the default function used by gtk_builder_set_closure_func(). Some bindings
+ * with C support may want to call this function as a fallback from their closure
+ * function.
+ *
+ * This function has no purpose otherwise.
+ *
+ * This function will prefer callbacks added via gtk_builder_add_callback_symbol()
+ * to looking up public symbols.
+ *
+ * Returns: (nullable): A new closure for invoking @function_name
+ **/
+GClosure *
+gtk_builder_create_cclosure (GtkBuilder *builder,
+                             const char *function_name,
+                             gboolean    swapped,
+                             GObject    *object,
+                             GError    **error)
+{
+  GModule *module = gtk_builder_get_module (builder);
+  GCallback func;
+
+  func = gtk_builder_lookup_callback_symbol (builder, function_name);
+  if (func)
+    return gtk_builder_create_closure_for_funcptr (builder, func, swapped, object);
+
+  if (module == NULL)
+    {
+      g_set_error (error,
+                   GTK_BUILDER_ERROR,
+                   GTK_BUILDER_ERROR_INVALID_FUNCTION,
+                   "Could not look up function `%s`: GModule is not supported.",
+                   function_name);
+      return NULL;
+    }
+
+  if (!g_module_symbol (module, function_name, (gpointer)&func))
+    {
+      g_set_error (error,
+                   GTK_BUILDER_ERROR,
+                   GTK_BUILDER_ERROR_INVALID_FUNCTION,
+                   "No function named `%s`.",
+                   function_name);
+      return NULL;
+    }
+
+  return gtk_builder_create_closure_for_funcptr (builder, func, swapped, object);
+}
+
 /**
  * gtk_builder_new_from_file:
  * @filename: filename of user interface description file
diff --git a/gtk/gtkbuilder.h b/gtk/gtkbuilder.h
index f3353cedcf..fb192dc4a9 100644
--- a/gtk/gtkbuilder.h
+++ b/gtk/gtkbuilder.h
@@ -63,7 +63,10 @@ typedef struct _GtkBuilderClass   GtkBuilderClass;
  * @GTK_BUILDER_ERROR_TEMPLATE_MISMATCH: The wrong type was specified in a composite class’s template XML
  * @GTK_BUILDER_ERROR_INVALID_PROPERTY: The specified property is unknown for the object class.
  * @GTK_BUILDER_ERROR_INVALID_SIGNAL: The specified signal is unknown for the object class.
- * @GTK_BUILDER_ERROR_INVALID_ID: An object id is unknown
+ * @GTK_BUILDER_ERROR_INVALID_ID: An object id is unknown.
+ * @GTK_BUILDER_ERROR_INVALID_FUNCTION: A function could not be found. This often happens
+ *     when symbols are set to be kept private. Compiling code with -rdynamic or using the
+ *     `gmodule-export-2.0` pkgconfig module can fix this problem.
  *
  * Error codes that identify various errors that can occur while using
  * #GtkBuilder.
@@ -83,7 +86,8 @@ typedef enum
   GTK_BUILDER_ERROR_TEMPLATE_MISMATCH,
   GTK_BUILDER_ERROR_INVALID_PROPERTY,
   GTK_BUILDER_ERROR_INVALID_SIGNAL,
-  GTK_BUILDER_ERROR_INVALID_ID
+  GTK_BUILDER_ERROR_INVALID_ID,
+  GTK_BUILDER_ERROR_INVALID_FUNCTION
 } GtkBuilderError;
 
 GDK_AVAILABLE_IN_ALL
@@ -196,6 +200,19 @@ void         gtk_builder_add_callback_symbols    (GtkBuilder    *builder,
 GDK_AVAILABLE_IN_ALL
 GCallback    gtk_builder_lookup_callback_symbol  (GtkBuilder    *builder,
                                                  const gchar   *callback_name);
+GDK_AVAILABLE_IN_ALL
+GClosure *   gtk_builder_create_closure          (GtkBuilder    *builder,
+                                                  const char    *function_name,
+                                                  gboolean       swapped,
+                                                  GObject       *object,
+                                                  GError       **error);
+GDK_AVAILABLE_IN_ALL
+GClosure *   gtk_builder_create_cclosure         (GtkBuilder    *builder,
+                                                  const char    *function_name,
+                                                  gboolean       swapped,
+                                                  GObject       *object,
+                                                  GError       **error);
+
 
 
 /**


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