Index: gnome-keybinding-properties.c
===================================================================
--- gnome-keybinding-properties.c	(revision 7323)
+++ gnome-keybinding-properties.c	(working copy)
@@ -19,6 +19,13 @@
 #define LABEL_DATA "gnome-keybinding-properties-label"
 #define MAX_ELEMENTS_BEFORE_SCROLLING 10
 
+typedef struct {
+  char *name;
+  //FIXME conditions
+  /* an array of KeyListEntry */
+  GArray *entries;
+} KeyList;
+
 typedef enum {
   ALWAYS_VISIBLE,
   N_WORKSPACES_GT
@@ -26,7 +33,7 @@
 
 typedef struct
 {
-  const char *name;
+  char *name;
   KeyListEntryVisibility visibility;
   gint data;
 } KeyListEntry;
@@ -171,6 +178,8 @@
   GladeXML *dialog;
 
   dialog = glade_xml_new (GNOMECC_GLADE_DIR "/gnome-keybinding-properties.glade", "gnome-keybinding-dialog", NULL);
+  if (!dialog)
+    dialog = glade_xml_new ("gnome-keybinding-properties.glade", "gnome-keybinding-dialog", NULL);
 
   return dialog;
 }
@@ -487,7 +496,7 @@
 
       if (!should_show_key (&keys_list[j]))
 	continue;
-      
+
       key_string = keys_list[j].name;
 
       entry = gconf_client_get_entry (client,
@@ -565,17 +574,216 @@
 }
 
 static void
+parse_start_tag (GMarkupParseContext *ctx,
+		 const gchar         *element_name,
+		 const gchar        **attr_names,
+		 const gchar        **attr_values,
+		 gpointer             user_data,
+		 GError             **error)
+{
+  KeyList *keylist = (KeyList *) user_data;
+  KeyListEntry key;
+  const char *name;
+  KeyListEntryVisibility visibility;
+  gint data;
+
+  name = NULL;
+
+  /* The top-level element, names the section in the tree */
+  if (g_str_equal (element_name, "KeyListEntries"))
+    {
+      while (*attr_names && *attr_values)
+        {
+	  if (g_str_equal (*attr_names, "name"))
+	    {
+	      if (**attr_values)
+		name = *attr_values;
+	    }
+	  ++attr_names;
+	  ++attr_values;
+	}
+
+      if (name)
+        {
+	  if (keylist->name)
+	    g_warning ("Duplicate section name");
+	  g_free (keylist->name);
+	  keylist->name = g_strdup (name);
+	}
+      return;
+    }
+
+  /* The conditions, defined one-by-one */
+  if (g_str_equal (element_name, "Condition"))
+    {
+      const char *key, *comparison;
+
+      key = NULL;
+      comparison = NULL;
+
+      while (*attr_names && *attr_values)
+        {
+	  if (g_str_equal (*attr_names, "name"))
+	    {
+	      if (**attr_values)
+		name = *attr_values;
+	    } else if (g_str_equal (*attr_names, "key")) {
+	      if (**attr_values)
+		key = *attr_values;
+	    } else if (g_str_equal (*attr_names, "comparison")) {
+	      if (**attr_values)
+		comparison = *attr_values;
+	    }
+
+	  ++attr_names;
+	  ++attr_values;
+	}
+
+      if (!name || !key || !comparison)
+	return;
+
+      g_message ("condition name: %s, key %s, comparison %s", name, key, comparison);
+      return;
+    }
+
+  if (!g_str_equal (element_name, "KeyListEntry")
+      || attr_names == NULL
+      || attr_values == NULL)
+    return;
+
+  visibility = ALWAYS_VISIBLE;
+  data = 0;
+
+  while (*attr_names && *attr_values)
+    {
+      if (g_str_equal (*attr_names, "name"))
+        {
+	  /* skip if empty */
+	  if (**attr_values)
+	    name = *attr_values;
+	} else if (g_str_equal (*attr_names, "visibility")) {
+	  /* skip if empty */
+	  if (**attr_values)
+	    {
+	      if (g_str_equal (*attr_values, "ALWAYS_VISIBLE"))
+	        {
+		  visibility = ALWAYS_VISIBLE;
+		} else if (g_str_equal (*attr_values, "N_WORKSPACES_GT")) {
+		  visibility = N_WORKSPACES_GT;
+		} else {
+		  g_warning ("Unknown visibility value '%s'", *attr_values);
+		}
+	    }
+	} else if (g_str_equal (*attr_names, "data")) {
+	  if (**attr_values) {
+	    data = (int) g_ascii_strtoull (*attr_values, NULL, 0);
+	  }
+	}
+
+      ++attr_names;
+      ++attr_values;
+    }
+
+  if (name == NULL)
+    return;
+
+  g_message ("adding key '%s', visibility '%d', data '%d'",
+	     name, visibility, data);
+
+  key.name = g_strdup (name);
+  key.visibility = visibility;
+  key.data = data;
+  g_array_append_val (keylist->entries, key);
+}
+
+static void
+append_keys_to_tree_from_file (GladeXML *dialog, const char *filename)
+{
+  GMarkupParseContext *ctx;
+  GMarkupParser parser = { parse_start_tag, NULL, NULL, NULL, NULL };
+  KeyList *keylist;
+  KeyListEntry key, *keys;
+  GError *err = NULL;
+  char *buf;
+  gsize buf_len;
+  guint i;
+
+  if (!g_file_get_contents (filename, &buf, &buf_len, &err))
+    return;
+
+  keylist = g_new0 (KeyList, 1);
+  keylist->entries = g_array_new (FALSE, TRUE, sizeof (KeyListEntry));
+  ctx = g_markup_parse_context_new (&parser, 0, keylist, NULL);
+
+  if (!g_markup_parse_context_parse (ctx, buf, buf_len, &err))
+    {
+      g_warning ("Failed to parse '%s': '%s'", filename, err->message);
+      g_error_free (err);
+      for (i = 0; i < keylist->entries->len; i++)
+	g_free (((KeyListEntry *) &(keylist->entries->data[i]))->name);
+      g_array_free (keylist->entries, TRUE);
+      g_free (keylist);
+      keylist = NULL;
+    }
+  g_markup_parse_context_free (ctx);
+  g_free (buf);
+
+  if (keylist == NULL)
+    return;
+
+  if (keylist->entries->len == 0)
+    {
+      g_array_free (keylist->entries, TRUE);
+      g_free (keylist);
+      return;
+    }
+
+  /* Empty KeyListEntry to end the array */
+  key.name = NULL;
+  key.visibility = 0;
+  key.data = 0;
+  g_array_append_val (keylist->entries, key);
+
+  keys = (KeyListEntry *) g_array_free (keylist->entries, FALSE);
+
+  append_keys_to_tree (dialog, keylist->name, keys);
+
+  g_free (keylist->name);
+  for (i = 0; keys[i].name != NULL; i++)
+    g_free (keys[i].name);
+  g_free (keylist);
+}
+
+static void
 reload_key_entries (gpointer wm_name, GladeXML *dialog)
 {
+  GDir *dir;
+  const char *name;
+
   clear_old_model (dialog);
   
-  append_keys_to_tree (dialog, _("Desktop"), desktop_key_list);
-  append_keys_to_tree (dialog, _("Sound"), sounds_key_list);
-  
+//  append_keys_to_tree (dialog, _("Desktop"), desktop_key_list);
+//  append_keys_to_tree (dialog, _("Sound"), sounds_key_list);
+
+  //FIXME this should be in a separate file as well.
   if (strcmp((char *) wm_name, WM_COMMON_METACITY) == 0)
     {
-      append_keys_to_tree (dialog, _("Window Management"), metacity_key_list);
+//      append_keys_to_tree (dialog, _("Window Management"), metacity_key_list);
     }
+
+  //FIXME path
+  dir = g_dir_open ("./", 0, NULL);
+  if (!dir)
+    {
+      return;
+    }
+
+  for (name = g_dir_read_name (dir) ; name ; name = g_dir_read_name (dir))
+    {
+      if (g_str_has_suffix (name, ".xml"))
+        append_keys_to_tree_from_file (dialog, name);
+    }
+  g_dir_close (dir);
 }
 
 static void
@@ -910,10 +1118,10 @@
 
   g_signal_connect (GTK_TREE_VIEW (WID ("shortcut_treeview")),
 		    "button_press_event",
-		    G_CALLBACK (start_editing_cb), dialog),
-	g_signal_connect (GTK_TREE_VIEW (WID ("shortcut_treeview")),
-	      "row-activated",
-		    G_CALLBACK (start_editing_kb_cb), dialog),
+		    G_CALLBACK (start_editing_cb), dialog);
+  g_signal_connect (GTK_TREE_VIEW (WID ("shortcut_treeview")),
+		    "row-activated",
+		    G_CALLBACK (start_editing_kb_cb), dialog);
 		    
   column = gtk_tree_view_column_new_with_attributes (_("Action"),
 						     gtk_cell_renderer_text_new (),
@@ -945,7 +1153,7 @@
 
   gtk_tree_view_append_column (GTK_TREE_VIEW (WID ("shortcut_treeview")), column);
   gtk_tree_view_column_set_sort_column_id (column, KEYENTRY_COLUMN); 
-  
+
   gconf_client_add_dir (client, "/apps/gnome_keybinding_properties", GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
   gconf_client_add_dir (client, "/apps/metacity/general", GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
   gconf_client_notify_add (client,
@@ -995,3 +1203,7 @@
   g_object_unref (program);
   return 0;
 }
+
+/*
+ * vim: sw=2 ts=8 cindent noai bs=2
+ */
