[gtk+] GtkContainer: Support focus chain in GtkBuilder



commit aa3020a39ec2428b6a44e309d64246aa9b8342f9
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Sep 27 00:20:50 2014 -0400

    GtkContainer: Support focus chain in GtkBuilder
    
    This adds support for a <focus-chain> element which can be
    used to specify a custom focus order for the children of
    a container.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=582799

 gtk/gtkcontainer.c |  127 ++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 119 insertions(+), 8 deletions(-)
---
diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c
index 0394a99..11fbdc2 100644
--- a/gtk/gtkcontainer.c
+++ b/gtk/gtkcontainer.c
@@ -221,21 +221,33 @@
  * a <packing> element for children, which can contain multiple <property>
  * elements that specify child properties for the child.
  * 
- * An example of child properties in UI definitions:
+ * Since 2.16, child properties can also be marked as translatable using
+ * the same “translatable”, “comments” and “context” attributes that are used
+ * for regular properties.
+ *
+ * Since 3.16, containers can have a <focus-chain> element containing multiple
+ * <widget> elements, one for each child that should be added to the focus
+ * chain. The ”name” attribute gives the id of the widget.
+ *
+ * An example of these properties in UI definitions:
  * |[
- * <object class="GtkVBox">
+ * <object class="GtkBox">
  *   <child>
- *     <object class="GtkLabel"/>
+ *     <object class="GtkEntry" id="entry1"/>
  *     <packing>
  *       <property name="pack-type">start</property>
  *     </packing>
  *   </child>
+ *   <child>
+ *     <object class="GtkEntry" id="entry2"/>
+ *   </child>
+ *   <focus-chain>
+ *     <widget name="entry1"/>
+ *     <widget name="entry2"/>
+ *   </focus-chain>
  * </object>
  * ]|
  *
- * Since 2.16, child properties can also be marked as translatable using
- * the same “translatable”, “comments” and “context” attributes that are used
- * for regular properties.
  */
 
 
@@ -353,6 +365,11 @@ static void    gtk_container_buildable_custom_tag_end (GtkBuildable *buildable,
                                                        GObject      *child,
                                                        const gchar  *tagname,
                                                        gpointer     *data);
+static void    gtk_container_buildable_custom_finished (GtkBuildable *buildable,
+                                                        GtkBuilder   *builder,
+                                                        GObject      *child,
+                                                        const gchar  *tagname,
+                                                        gpointer      data);
 
 static gboolean gtk_container_should_propagate_draw (GtkContainer   *container,
                                                      GtkWidget      *child,
@@ -557,6 +574,7 @@ gtk_container_buildable_init (GtkBuildableIface *iface)
   iface->add_child = gtk_container_buildable_add_child;
   iface->custom_tag_start = gtk_container_buildable_custom_tag_start;
   iface->custom_tag_end = gtk_container_buildable_custom_tag_end;
+  iface->custom_finished = gtk_container_buildable_custom_finished;
 }
 
 static void
@@ -727,6 +745,46 @@ static const GMarkupParser attributes_parser =
     attributes_text_element,
   };
 
+typedef struct
+  {
+    GSList *items;
+    GObject *object;
+  } FocusChainData;
+
+static void
+focus_chain_start_element (GMarkupParseContext *context,
+                           const gchar         *element_name,
+                           const gchar        **names,
+                           const gchar        **values,
+                           gpointer            user_data,
+                           GError            **error)
+{
+  guint i;
+  FocusChainData *data = (FocusChainData*)user_data;
+
+  if (strcmp (element_name, "widget") == 0)
+    {
+      for (i = 0; names[i]; i++)
+        {
+          if (strcmp (names[i], "name") == 0)
+            data->items = g_slist_prepend (data->items, g_strdup (values[i]));
+        }
+    }
+  else if (strcmp (element_name, "focus-chain") == 0)
+    {
+      return;
+    }
+  else
+    {
+      g_warning ("Unsupported type tag for GtkContainer %s\n", element_name);
+    }
+}
+
+static const GMarkupParser focus_chain_parser =
+  {
+    focus_chain_start_element
+  };
+
 static gboolean
 gtk_container_buildable_custom_tag_start (GtkBuildable  *buildable,
                                           GtkBuilder    *builder,
@@ -735,14 +793,14 @@ gtk_container_buildable_custom_tag_start (GtkBuildable  *buildable,
                                           GMarkupParser *parser,
                                           gpointer      *data)
 {
-  PackingPropertiesData *parser_data;
-
   if (parent_buildable_iface->custom_tag_start (buildable, builder, child,
                                                 tagname, parser, data))
     return TRUE;
 
   if (child && strcmp (tagname, "packing") == 0)
     {
+      PackingPropertiesData *parser_data;
+
       parser_data = g_slice_new0 (PackingPropertiesData);
       parser_data->string = g_string_new ("");
       parser_data->builder = builder;
@@ -754,6 +812,17 @@ gtk_container_buildable_custom_tag_start (GtkBuildable  *buildable,
       *data = parser_data;
       return TRUE;
     }
+  else if (!child && strcmp (tagname, "focus-chain") == 0)
+    {
+      FocusChainData *parser_data;
+      parser_data = g_slice_new0 (FocusChainData);
+      parser_data->items = NULL;
+      parser_data->object = G_OBJECT (buildable);
+
+      *parser = focus_chain_parser;
+      *data = parser_data;
+      return TRUE;
+    }
 
   return FALSE;
 }
@@ -778,6 +847,48 @@ gtk_container_buildable_custom_tag_end (GtkBuildable *buildable,
                                             child, tagname, data);
 }
 
+static void
+gtk_container_buildable_custom_finished (GtkBuildable *buildable,
+                                         GtkBuilder   *builder,
+                                         GObject      *child,
+                                         const gchar  *tagname,
+                                         gpointer      data)
+{
+   if (strcmp (tagname, "focus-chain") == 0)
+    {
+      FocusChainData *parser_data = (FocusChainData*)data;
+      GSList *l;
+      GList *chain;
+      GObject *object;
+
+      chain = NULL;
+      for (l = parser_data->items; l; l = l->next)
+        {
+          object = gtk_builder_get_object (builder, l->data);
+          if (!object)
+            {
+              g_warning ("Unknown object %s specified in focus-chain for %s",
+                         (const gchar*)l->data,
+                         gtk_buildable_get_name (GTK_BUILDABLE (parser_data->object)));
+              continue;
+            }
+          chain = g_list_prepend (chain, object);
+        }
+
+      gtk_container_set_focus_chain (GTK_CONTAINER (parser_data->object), chain);
+      g_list_free (chain);
+
+      g_slist_free_full (parser_data->items, g_free);
+      g_slice_free (FocusChainData, parser_data);
+
+      return;
+    }
+
+  if (parent_buildable_iface->custom_finished)
+    parent_buildable_iface->custom_finished (buildable, builder,
+                                             child, tagname, data);
+}
+
 /**
  * gtk_container_child_type:
  * @container: a #GtkContainer


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