Index: gnome-keybinding-properties.c
===================================================================
--- gnome-keybinding-properties.c	(revision 7317)
+++ gnome-keybinding-properties.c	(working copy)
@@ -26,7 +26,7 @@
 
 typedef struct
 {
-  const char *name;
+  char *name;
   KeyListEntryVisibility visibility;
   gint data;
 } KeyListEntry;
@@ -171,6 +171,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 +489,7 @@
 
       if (!should_show_key (&keys_list[j]))
 	continue;
-      
+
       key_string = keys_list[j].name;
 
       entry = gconf_client_get_entry (client,
@@ -565,17 +567,169 @@
 }
 
 static void
+parse_start_tag (GMarkupParseContext *ctx,
+		 const gchar         *element_name,
+		 const gchar        **attr_names,
+		 const gchar        **attr_values,
+		 gpointer             user_data,
+		 GError             **error)
+{
+	GArray *array = (GArray *) user_data;
+	KeyListEntry key;
+	const char *name, *section_name;
+	KeyListEntryVisibility visibility;
+	gint data;
+
+	if (!g_str_equal (element_name, "KeyListEntry")
+			|| attr_names == NULL
+			|| attr_values == NULL)
+		return;
+
+	section_name = NULL;
+	name = NULL;
+	visibility = ALWAYS_VISIBLE;
+	data = 0;
+
+	while (*attr_names && *attr_values)
+	{
+		if (g_str_equal (*attr_names, "section")) {
+			if (**attr_values)
+				section_name = *attr_values;
+		} else 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") == 0) {
+					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 (section_name != NULL) {
+		g_message ("BLEH: %s", section_name);
+	}
+
+	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 (array, key);
+}
+
+static void
+key_list_entry_free (KeyListEntry *entry)
+{
+	if (!entry)
+		return;
+	g_free (entry->name);
+	g_free (entry);
+}
+
+static void
+append_keys_to_tree_from_file (GladeXML *dialog, const char *filename)
+{
+	GArray *arr; // = g_array_new (FALSE, TRUE, sizeof (KeyListEntry));
+	const char *name = "My supa-test";
+	KeyListEntry key, *keys_list;
+	GError *err = NULL;
+	char *buf;
+	gsize buf_len;
+	guint i;
+
+	arr = NULL;
+
+	if (g_file_get_contents (filename, &buf, &buf_len, &err)) {
+		GMarkupParseContext *ctx;
+		GMarkupParser parser = { parse_start_tag, NULL, NULL, NULL, NULL };
+
+		arr = g_array_new (FALSE, TRUE, sizeof (KeyListEntry));
+		ctx = g_markup_parse_context_new (&parser, 0, arr, 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 < arr->len; i++)
+				key_list_entry_free ((KeyListEntry *) &(arr->data[i]));
+			g_array_free (arr, TRUE);
+			arr = NULL;
+		}
+
+		g_markup_parse_context_free (ctx);
+		g_free (buf);
+	}
+
+	if (arr == NULL)
+		return;
+	if (arr->len == 0) {
+		g_array_free (arr, TRUE);
+		return;
+	}
+
+	key.name = NULL;
+	key.visibility = 0;
+	key.data = 0;
+	g_array_append_val (arr, key);
+
+	keys_list = (KeyListEntry *) g_array_free (arr, FALSE);
+
+	append_keys_to_tree (dialog, name, keys_list);
+
+	for (i = 0; keys_list[i].name != NULL; i++) {
+		key_list_entry_free (&keys_list[i]);
+	}
+}
+
+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);
-  
+
+  //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);
     }
+
+  //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 +1064,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 +1099,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,
