[gtk+/composite-templates-new: 4/32] GtkBuilder: Added api to allow private signal callbacks



commit d3d0d1a9781046a111a98db56fba381c9ac9d513
Author: Tristan Van Berkom <tristanvb openismus com>
Date:   Wed Mar 20 12:48:38 2013 +0900

    GtkBuilder: Added api to allow private signal callbacks
    
    In preperation for composite objects, for better encapsulation
    the following APIs are added to allow handling of signals declared
    in the XML with callbacks declared statically.
    
      o gtk_builder_add_callback_symbol[s]()
    
        Adds a symbol to the internal symbol hash
    
      o gtk_builder_lookup_symbol()
    
        Looks up a symbol, exposed in case added symbols are used
        in conjunction with gtk_builder_connect_signals_full()
    
    The default implementation of gtk_builder_connect_signals() now
    does not have a strong requirement on GModule (or a strong requirement
    on symbols being declared in the global namespace). Instead GModule
    is used as a fallback in the case that symbols are not declared
    explicitly.

 docs/reference/gtk/gtk3-sections.txt |    3 +
 gtk/gtk.symbols                      |    3 +
 gtk/gtkbuilder.c                     |  147 +++++++++++++++++++++++++++++++---
 gtk/gtkbuilder.h                     |   13 +++
 4 files changed, 154 insertions(+), 12 deletions(-)
---
diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt
index 6f3c4fd..2098369 100644
--- a/docs/reference/gtk/gtk3-sections.txt
+++ b/docs/reference/gtk/gtk3-sections.txt
@@ -539,6 +539,9 @@ gtk_builder_get_objects
 gtk_builder_expose_object
 gtk_builder_connect_signals
 gtk_builder_connect_signals_full
+gtk_builder_add_callback_symbol
+gtk_builder_add_callback_symbols
+gtk_builder_lookup_callback_symbol
 gtk_builder_set_translation_domain
 gtk_builder_get_translation_domain
 gtk_builder_get_type_from_name
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index 96811a5..31a2a8b 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -330,6 +330,8 @@ gtk_buildable_get_type
 gtk_buildable_parser_finished
 gtk_buildable_set_buildable_property
 gtk_buildable_set_name
+gtk_builder_add_callback_symbol
+gtk_builder_add_callback_symbols
 gtk_builder_add_from_file
 gtk_builder_add_from_resource
 gtk_builder_add_from_string
@@ -346,6 +348,7 @@ gtk_builder_get_objects
 gtk_builder_get_translation_domain
 gtk_builder_get_type_from_name
 gtk_builder_get_type
+gtk_builder_lookup_callback_symbol
 gtk_builder_new
 gtk_builder_set_translation_domain
 gtk_builder_value_from_string
diff --git a/gtk/gtkbuilder.c b/gtk/gtkbuilder.c
index 6ae127f..9e2f294 100644
--- a/gtk/gtkbuilder.c
+++ b/gtk/gtkbuilder.c
@@ -270,6 +270,7 @@ struct _GtkBuilderPrivate
 {
   gchar *domain;
   GHashTable *objects;
+  GHashTable *callbacks;
   GSList *delayed_properties;
   GSList *signals;
   gchar *filename;
@@ -1390,11 +1391,22 @@ gtk_builder_connect_signals_default (GtkBuilder    *builder,
 {
   GCallback func;
   connect_args *args = (connect_args*)user_data;
-  
-  if (!g_module_symbol (args->module, handler_name, (gpointer)&func))
+
+  func = gtk_builder_lookup_callback_symbol (builder, handler_name);
+
+  if (!func)
     {
-      g_warning ("Could not find signal handler '%s'", handler_name);
-      return;
+      /* Only error out for missing GModule support if we've not
+       * found the symbols explicitly added with gtk_builder_add_callback_symbol()
+       */
+      if (args->module == NULL)
+       g_error ("gtk_builder_connect_signals() requires working GModule");
+  
+      if (!g_module_symbol (args->module, handler_name, (gpointer)&func))
+       {
+         g_warning ("Could not find signal handler '%s'", handler_name);
+         return;
+       }
     }
 
   if (connect_object)
@@ -1410,14 +1422,20 @@ gtk_builder_connect_signals_default (GtkBuilder    *builder,
  * @user_data: a pointer to a structure sent in as user data to all signals
  *
  * This method is a simpler variation of gtk_builder_connect_signals_full().
- * It uses #GModule's introspective features (by opening the module %NULL) 
+ * It uses symbols explicitly added to @builder with prior calls to
+ * gtk_builder_add_callback_symbol(). In the case that symbols are not
+ * explicitly added; it uses #GModule's introspective features (by opening the module %NULL) 
  * to look at the application's symbol table. From here it tries to match
  * the signal handler names given in the interface description with
  * symbols in the application and connects the signals. Note that this
  * function can only be called once, subsequent calls will do nothing.
  * 
- * Note that this function will not work correctly if #GModule is not
- * supported on the platform.
+ * Note that unless gtk_builder_add_callback_symbol() is called for
+ * all signal callbacks which are referenced by the loaded XML, this 
+ * function will require that #GModule be supported on the platform.
+ * 
+ * If you rely on #GModule support to lookup callbacks in the symbol table,
+ * the following details should be noted:
  *
  * When compiling applications for Windows, you must declare signal callbacks
  * with #G_MODULE_EXPORT, or they will not be put in the symbol table.
@@ -1435,17 +1453,17 @@ gtk_builder_connect_signals (GtkBuilder *builder,
   
   g_return_if_fail (GTK_IS_BUILDER (builder));
   
-  if (!g_module_supported ())
-    g_error ("gtk_builder_connect_signals() requires working GModule");
-
   args = g_slice_new0 (connect_args);
-  args->module = g_module_open (NULL, G_MODULE_BIND_LAZY);
   args->data = user_data;
+
+  if (g_module_supported ())
+    args->module = g_module_open (NULL, G_MODULE_BIND_LAZY);
   
   gtk_builder_connect_signals_full (builder,
                                     gtk_builder_connect_signals_default,
                                     args);
-  g_module_close (args->module);
+  if (args->module)
+    g_module_close (args->module);
 
   g_slice_free (connect_args, args);
 }
@@ -2122,3 +2140,108 @@ _gtk_builder_get_absolute_filename (GtkBuilder *builder, const gchar *string)
   
   return filename;
 }
+
+/**
+ * gtk_builder_add_callback_symbol:
+ * @builder: a #GtkBuilder
+ * @callback_name: The name of the callback, as expected in the XML
+ * @callback_symbol: (scope async): The callback pointer
+ *
+ * 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()
+ * 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.
+ *
+ * Since: 3.10
+ */
+void
+gtk_builder_add_callback_symbol (GtkBuilder    *builder,
+                                const gchar   *callback_name,
+                                GCallback      callback_symbol)
+{
+  g_return_if_fail (GTK_IS_BUILDER (builder));
+  g_return_if_fail (callback_name && callback_name[0]);
+  g_return_if_fail (callback_symbol != NULL);
+
+  if (!builder->priv->callbacks)
+    builder->priv->callbacks = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                     g_free, NULL);
+
+  g_hash_table_insert (builder->priv->callbacks, g_strdup (callback_name), callback_symbol);
+}
+
+/**
+ * gtk_builder_add_callback_symbols:
+ * @builder: a #GtkBuilder
+ * @first_callback_name: The name of the callback, as expected in the XML
+ * @first_callback_symbol: (scope async): The callback pointer
+ * @...: A list of callback name and callback symbol pairs terminated with %NULL
+ *
+ * A convenience function to add many callbacks instead of calling
+ * gtk_builder_add_callback_symbol() for each symbol.
+ *
+ * Since: 3.10
+ */
+void
+gtk_builder_add_callback_symbols (GtkBuilder    *builder,
+                                 const gchar   *first_callback_name,
+                                 GCallback      first_callback_symbol,
+                                 ...)
+{
+  va_list var_args;
+  const gchar *callback_name;
+  GCallback callback_symbol;
+
+  g_return_if_fail (GTK_IS_BUILDER (builder));
+  g_return_if_fail (first_callback_name && first_callback_name[0]);
+  g_return_if_fail (first_callback_symbol != NULL);
+
+  callback_name = first_callback_name;
+  callback_symbol = first_callback_symbol;
+
+  va_start (var_args, first_callback_symbol);
+
+  do {
+
+    gtk_builder_add_callback_symbol (builder, callback_name, callback_symbol);
+
+    callback_name = va_arg (var_args, const gchar*);
+
+    if (callback_name)
+      callback_symbol = va_arg (var_args, GCallback);
+
+  } while (callback_name != NULL);
+
+  va_end (var_args);
+}
+
+/**
+ * gtk_builder_lookup_callback_symbol:
+ * @builder: a #GtkBuilder
+ * @callback_name: The name of the callback
+ *
+ * Fetches a symbol previously added to @builder
+ * with gtk_builder_add_callback_symbols()
+ *
+ * This function is intended for possible use in language bindings
+ * or for any case that one might be cusomizing signal connections
+ * using gtk_builder_connect_signals_full()
+ *
+ * Returns: The callback symbol in @builder for @callback_name, or %NULL
+ *
+ * Since: 3.10
+ */
+GCallback
+gtk_builder_lookup_callback_symbol (GtkBuilder    *builder,
+                                   const gchar   *callback_name)
+{
+  g_return_val_if_fail (GTK_IS_BUILDER (builder), NULL);
+  g_return_val_if_fail (callback_name && callback_name[0], NULL);
+
+  if (!builder->priv->callbacks)
+    return NULL;
+
+  return g_hash_table_lookup (builder->priv->callbacks, callback_name);
+}
diff --git a/gtk/gtkbuilder.h b/gtk/gtkbuilder.h
index 31e5a24..5b22eb1 100644
--- a/gtk/gtkbuilder.h
+++ b/gtk/gtkbuilder.h
@@ -167,6 +167,19 @@ gboolean     gtk_builder_value_from_string_type  (GtkBuilder    *builder,
                                                   GValue               *value,
                                                  GError       **error);
 
+GDK_AVAILABLE_IN_3_10
+void         gtk_builder_add_callback_symbol     (GtkBuilder    *builder,
+                                                 const gchar   *callback_name,
+                                                 GCallback      callback_symbol);
+GDK_AVAILABLE_IN_3_10
+void         gtk_builder_add_callback_symbols    (GtkBuilder    *builder,
+                                                 const gchar   *first_callback_name,
+                                                 GCallback      first_callback_symbol,
+                                                 ...) G_GNUC_NULL_TERMINATED;
+GDK_AVAILABLE_IN_3_10
+GCallback    gtk_builder_lookup_callback_symbol  (GtkBuilder    *builder,
+                                                 const gchar   *callback_name);
+
 /**
  * GTK_BUILDER_WARN_INVALID_CHILD_TYPE:
  * @object: the #GtkBuildable on which the warning ocurred


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