? patch.patch
? test.patch
? capplets/about-me/gnome-about-me
? capplets/keybindings/custom-binding.c
? capplets/keybindings/custom-binding.h
? m4/intltool.m4
Index: capplets/keybindings/Makefile.am
===================================================================
RCS file: /cvs/gnome/gnome-control-center/capplets/keybindings/Makefile.am,v
retrieving revision 1.8
diff -u -p -r1.8 Makefile.am
--- capplets/keybindings/Makefile.am	28 Nov 2004 08:14:04 -0000	1.8
+++ capplets/keybindings/Makefile.am	11 Aug 2005 20:30:22 -0000
@@ -3,6 +3,8 @@ bin_PROGRAMS = gnome-keybinding-properti
 gnome_keybinding_properties_LDADD = $(GNOMECC_CAPPLETS_LIBS)
 gnome_keybinding_properties_SOURCES = 	\
 	gnome-keybinding-properties.c	\
+	custom-binding.c		\
+	custom-binding.h		\
 	eggcellrendererkeys.c		\
 	eggcellrendererkeys.h		\
 	eggaccelerators.c		\
Index: capplets/keybindings/gnome-keybinding-properties.c
===================================================================
RCS file: /cvs/gnome/gnome-control-center/capplets/keybindings/gnome-keybinding-properties.c,v
retrieving revision 1.50
diff -u -p -r1.50 gnome-keybinding-properties.c
--- capplets/keybindings/gnome-keybinding-properties.c	22 May 2005 15:46:41 -0000	1.50
+++ capplets/keybindings/gnome-keybinding-properties.c	11 Aug 2005 20:30:22 -0000
@@ -16,6 +16,7 @@
 #include "capplet-util.h"
 #include "eggcellrendererkeys.h"
 #include "activate-settings-daemon.h"
+#include "custom-binding.h"
 
 #define LABEL_DATA "gnome-keybinding-properties-label"
 #define MAX_ELEMENTS_BEFORE_SCROLLING 10
@@ -25,19 +26,6 @@
 #else
 #undef USE_FBLEVEL
 #endif
-
-typedef enum {
-  ALWAYS_VISIBLE,
-  N_WORKSPACES_GT
-} KeyListEntryVisibility;
-
-typedef struct
-{
-  const char *name;
-  KeyListEntryVisibility visibility;
-  gint data;
-} KeyListEntry;
-
 const KeyListEntry desktop_key_list[] =
 {
   { "/apps/gnome_settings_daemon/keybindings/help", ALWAYS_VISIBLE, 0 },
@@ -133,27 +121,9 @@ const KeyListEntry metacity_key_list[] =
   { NULL }
 };
 
-enum
-{
-  DESCRIPTION_COLUMN,
-  KEYENTRY_COLUMN,
-  N_COLUMNS
-};
-
-typedef struct
-{
-  char *gconf_key;
-  guint keyval;
-  guint keycode;
-  EggVirtualModifierType mask;
-  gboolean editable;
-  GtkTreeModel *model;
-  guint gconf_cnxn;
-  char *description;
-} KeyEntry;
+KeyListEntry *custom_binding_list = NULL;
+GladeXML *main_dialog;
 
-static void  reload_key_entries (gpointer                wm_name,
-                                 GladeXML               *dialog);
 static char* binding_name       (guint                   keyval,
 				 guint			 keycode,
                                  EggVirtualModifierType  mask,
@@ -178,11 +148,8 @@ get_real_model (GtkTreeView *tree_view)
 static GladeXML *
 create_dialog (void)
 {
-  GladeXML *dialog;
-
-  dialog = glade_xml_new (GNOMECC_DATA_DIR "/interfaces/gnome-keybinding-properties.glade", "gnome-keybinding-dialog", NULL);
-
-  return dialog;
+   main_dialog = glade_xml_new (GNOMECC_DATA_DIR "/interfaces/gnome-keybinding-properties.glade", "gnome-keybinding-dialog", NULL);
+   return main_dialog;
 }
 
 static char*
@@ -258,7 +225,7 @@ accel_set_func (GtkTreeViewColumn *tree_
 		  NULL);
 }
 
-static gboolean
+gboolean
 keybinding_key_changed_foreach (GtkTreeModel *model,
 				GtkTreePath  *path,
 				GtkTreeIter  *iter,
@@ -274,6 +241,11 @@ keybinding_key_changed_foreach (GtkTreeM
 
   if (key_entry == tmp_key_entry)
     {
+      if (key_entry->custom_key)
+        gtk_tree_store_set (GTK_TREE_STORE (key_entry->model), iter,
+                            DESCRIPTION_COLUMN, key_entry->action,
+                            -1);
+
       gtk_tree_model_row_changed (key_entry->model, path, iter);
       return TRUE;
     }
@@ -361,10 +332,11 @@ clear_old_model (GladeXML  *dialog,
 {
   GtkTreeModel *model;
   GtkTreeModel *sort_model;
-  GtkTreeIter iter;
+  GtkTreeIter iter, parent_iter;
   KeyEntry *key_entry;
   gboolean valid;
   GConfClient *client;
+  int children, i;
 
   client = gconf_client_get_default ();
   model = get_real_model (GTK_TREE_VIEW (tree_view));
@@ -373,21 +345,33 @@ clear_old_model (GladeXML  *dialog,
     {
       g_object_ref (model);
 
-      for (valid = gtk_tree_model_get_iter_first (model, &iter);
-	   valid;
-	   valid = gtk_tree_model_iter_next (model, &iter))
+	valid = gtk_tree_model_get_iter_first (model, &parent_iter);
+	while  (valid)
 	{
-	  gtk_tree_model_get (model, &iter,
-			      KEYENTRY_COLUMN, &key_entry,
-			      -1);
-	  if (key_entry != NULL)
-	    {
-	      gconf_client_notify_remove (client, key_entry->gconf_cnxn);
-	      g_free (key_entry->gconf_key);
-              g_free (key_entry->description);
-	      g_free (key_entry);
-            }
-	}
+          children = gtk_tree_model_iter_n_children (model,&parent_iter);
+
+          for (i = 0; i < children ; i++)
+             {
+                if (gtk_tree_model_iter_nth_child (model, &iter, &parent_iter, i))
+                  {
+                        gtk_tree_model_get (model, &iter,
+                                            KEYENTRY_COLUMN, &key_entry,
+                                            -1);
+	                if (key_entry != NULL)
+	                  {
+			      if (key_entry->custom_key == TRUE)
+	                           gconf_client_notify_remove (client, key_entry->cmd_line_cnxn);
+	                      gconf_client_notify_remove (client, key_entry->gconf_cnxn);
+	                      g_free (key_entry->gconf_key);
+                              g_free (key_entry->description);
+	                      g_free (key_entry);
+                          }
+            
+                  }
+
+	      }
+            valid = gtk_tree_model_iter_next (model, &parent_iter);
+         }
       g_object_unref (model);
     }
 
@@ -451,7 +435,8 @@ should_show_key (const KeyListEntry *ent
 static void
 append_keys_to_tree (GladeXML           *dialog,
 		     const gchar        *title,
-		     const KeyListEntry *keys_list)
+		     const KeyListEntry *keys_list,
+		     gboolean            custom_binding)
 {
   GConfClient *client;
   GtkTreeIter parent_iter;
@@ -471,57 +456,97 @@ append_keys_to_tree (GladeXML           
 
   for (j = 0; keys_list[j].name != NULL; j++)
     {
-      GConfEntry *entry;
+      GConfEntry *entry = NULL;
       GConfSchema *schema = NULL;
-      KeyEntry *key_entry;
+      KeyEntry *key_entry = NULL;
       GError *error = NULL;
       GtkTreeIter iter;
       const gchar *key_string;
       gchar *key_value;
 
       if (!should_show_key (&keys_list[j]))
-	continue;
-      
-      key_string = keys_list[j].name;
+        continue;
 
-      entry = gconf_client_get_entry (client,
-                                      key_string,
-				      NULL,
-				      TRUE,
-				      &error);
-      if (error || entry == NULL)
-	{
-	  /* We don't actually want to popup a dialog - just skip this one */
-	  if (error)
-	    g_error_free (error);
-	  continue;
-	}
+      if (!custom_binding)
+       {
+          key_string = keys_list[j].name;
+
+	  entry = gconf_client_get_entry (client,
+					  key_string,
+					  NULL,
+					  TRUE,
+					  &error);
+       }
+      else if (error || entry == NULL)
+       {
+          key_entry = custom_key_new ((char *)keys_list[j].name);
+          if (!key_entry)
+            continue;
+          key_string = key_entry->gconf_key;
+       }
+
+
+      if (!custom_binding)
+       {
+         if (error || entry == NULL)
+           {
+             /* We don't actually want to popup a dialog - just skip this one */
+             if (error)
+               g_error_free (error);
+             continue;
+           }
 
-      if (gconf_entry_get_schema_name (entry))
-	schema = gconf_client_get_schema (client, gconf_entry_get_schema_name (entry), &error);
+         if (gconf_entry_get_schema_name (entry))
+           schema = gconf_client_get_schema (client, gconf_entry_get_schema_name (entry), &error);
       
-      if (error || schema == NULL)
-	{
-	  /* We don't actually want to popup a dialog - just skip this one */
-	  if (error)
-	    g_error_free (error);
-	  continue;
+         if (error || schema == NULL)
+	   {
+	     /* We don't actually want to popup a dialog - just skip this one */
+	     if (error)
+	       g_error_free (error);
+		continue;
+           }
 	}
 
-      key_value = gconf_client_get_string (client, key_string, &error);
+      if (!custom_binding)
+        {
 
-      key_entry = g_new0 (KeyEntry, 1);
-      key_entry->gconf_key = g_strdup (key_string);
-      key_entry->editable = gconf_entry_get_is_writable (entry);
-      key_entry->model = model;
-      gconf_client_add_dir (client, key_string, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
-      key_entry->gconf_cnxn = gconf_client_notify_add (client,
-						       key_string,
-						       (GConfClientNotifyFunc) &keybinding_key_changed,
-						       key_entry, NULL, NULL);
-      binding_from_string (key_value, &key_entry->keyval, &key_entry->keycode, &key_entry->mask);
-      g_free (key_value);
-      key_entry->description = g_strdup (gconf_schema_get_short_desc (schema));
+           key_entry = g_new0 (KeyEntry, 1);
+           key_value = gconf_client_get_string (client, key_string, &error);
+           key_entry->gconf_key = g_strdup (key_string);
+           key_entry->editable = gconf_entry_get_is_writable (entry);
+           key_entry->model = model;
+           gconf_client_add_dir (client, key_string, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+           key_entry->gconf_cnxn = gconf_client_notify_add (client,
+						            key_string,
+						            (GConfClientNotifyFunc) &keybinding_key_changed,
+						            key_entry, NULL, NULL);
+           binding_from_string (key_value, &key_entry->keyval, &key_entry->keycode, &key_entry->mask);
+           g_free (key_value);
+           key_entry->description = g_strdup (gconf_schema_get_short_desc (schema));
+        }
+      else 
+        {
+           char *key_binding = g_strdup_printf ("%s/binding", key_entry->gconf_key);
+           char *cmd_binding = g_strdup_printf ("%s/action", key_entry->gconf_key);
+           key_entry->editable = TRUE;
+           key_entry->model = model;
+           gconf_client_add_dir (client, key_entry->gconf_key, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+
+           key_entry->gconf_cnxn = gconf_client_notify_add (client,
+                                                            key_binding,
+                                                            (GConfClientNotifyFunc) &keybinding_key_changed,
+                                                            key_entry, NULL, NULL);
+           binding_from_string (key_entry->binding, &key_entry->keyval, &key_entry->keycode, &key_entry->mask);
+
+           key_entry->custom_key = TRUE;
+           key_entry->cmd_line_cnxn = gconf_client_notify_add (client, cmd_binding,
+                                                              (GConfClientNotifyFunc) &cmd_line_changed,
+                                                              key_entry, NULL, NULL);
+           key_entry->action = g_strdup (gconf_client_get_string (client, cmd_binding, &error));
+           g_free (key_binding);
+           g_free (cmd_binding);
+        }
 
       if (i == MAX_ELEMENTS_BEFORE_SCROLLING)
 	{
@@ -534,20 +559,33 @@ append_keys_to_tree (GladeXML           
 	}
       i++;
       gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent_iter);
-      if (gconf_schema_get_short_desc (schema))
-	gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
-			    DESCRIPTION_COLUMN,
-                            key_entry->description,
-			    KEYENTRY_COLUMN, key_entry,
-			    -1);
-      else
-	gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
-			    DESCRIPTION_COLUMN, _("<Unknown Action>"),
-			    KEYENTRY_COLUMN, key_entry,
-			    -1);
+      if (!custom_binding)
+        {
+          if (gconf_schema_get_short_desc (schema))
+	    gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
+			        DESCRIPTION_COLUMN,
+                                key_entry->description,
+			        KEYENTRY_COLUMN, key_entry,
+			        -1);
+          else
+	    gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
+			        DESCRIPTION_COLUMN, _("<Unknown Action>"),
+			        KEYENTRY_COLUMN, key_entry,
+			        -1);
+        }
+      else {
+            gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
+                                DESCRIPTION_COLUMN, key_entry->action,
+                                KEYENTRY_COLUMN, key_entry,
+                                -1);
+      }
+
       gtk_tree_view_expand_all (GTK_TREE_VIEW (WID ("shortcut_treeview")));
-      gconf_entry_free (entry);
-      gconf_schema_free (schema);
+
+      if (entry)
+        gconf_entry_free (entry);
+      if (schema)
+        gconf_schema_free (schema);
     }
 
   g_object_unref (client);
@@ -558,18 +596,20 @@ append_keys_to_tree (GladeXML           
       gtk_widget_show (WID ("shortcuts_vbox"));
 }
 
-static void
+void
 reload_key_entries (gpointer wm_name, GladeXML *dialog)
 {
   clear_old_model (dialog, WID ("shortcut_treeview"));
   
-  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, FALSE);
+  append_keys_to_tree (dialog, _("Sound"), sounds_key_list, FALSE);
   
   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, FALSE);
     }
+ 
+  append_keys_to_tree (dialog, _("Custom Shortcuts"), custom_binding_list, TRUE);
 }
 
 static void
@@ -682,10 +721,21 @@ accel_edited_callback (GtkCellRendererTe
   str = binding_name (keyval, keycode, mask, FALSE);
 
   client = gconf_client_get_default();
-  gconf_client_set_string (client,
-                           key_entry->gconf_key,
-                           str,
-                           &err);
+  if (!key_entry->custom_key)
+    gconf_client_set_string (client,
+                            key_entry->gconf_key,
+                            str,
+                            &err);
+  else
+    {
+      char *key = g_strdup_printf ("%s/binding", key_entry->gconf_key);
+      gconf_client_set_string (client,
+                              key,
+                              str,
+                              &err);
+      g_free (key);
+    }
+
   g_free (str);
   g_object_unref (G_OBJECT (client));
 
@@ -733,10 +783,21 @@ accel_cleared_callback (GtkCellRendererT
 
   /* Unset the key */
   client = gconf_client_get_default();
-  gconf_client_set_string (client,
-			   key_entry->gconf_key,
-			   "disabled",
-			   &err);
+  if (!key_entry->custom_key) {
+     gconf_client_set_string (client,
+			      key_entry->gconf_key,
+			      "disabled",
+			      &err);
+   } else {
+     char *key = g_strdup_printf ("%s/binding", key_entry->gconf_key);
+     gconf_client_set_string (client,
+			      key,
+			      "disabled",
+			      &err);
+     g_free (key);
+
+   }
+
   g_object_unref (G_OBJECT (client));
 
   if (err != NULL)
@@ -846,13 +907,6 @@ setup_dialog (GladeXML *dialog)
   GtkWidget *widget;
 
   client = gconf_client_get_default ();
-
-  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),
 		    
   column = gtk_tree_view_column_new_with_attributes (_("Action"),
 						     gtk_cell_renderer_text_new (),
@@ -888,21 +943,33 @@ setup_dialog (GladeXML *dialog)
   
   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_add_dir (client, GCONF_CUSTOM_BINDING_DIR, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
   gconf_client_notify_add (client,
 			   "/apps/metacity/general/num_workspaces",
 			   (GConfClientNotifyFunc) &key_entry_controlling_key_changed,
 			   dialog, NULL, NULL);
   g_object_unref (client);
 
+  create_custom_bindings_list ();
+
   /* set up the dialog */
   reload_key_entries (wm_common_get_current_window_manager(), dialog);
 
   widget = WID ("gnome-keybinding-dialog");
   capplet_set_icon (widget, "gnome-settings-keybindings");
   gtk_widget_show (widget);
-
   g_signal_connect (G_OBJECT (widget), "response", G_CALLBACK(cb_dialog_response), NULL);
   g_signal_connect (G_OBJECT (widget), "close", gtk_main_quit, NULL);
+
+  /* set up custom bindings buttons and dialog*/
+  widget = WID ("disable_custom_button");
+  g_signal_connect (G_OBJECT (widget), "clicked", G_CALLBACK (disable_custom),
+                    GTK_TREE_VIEW (WID ("shortcut_treeview")));
+  widget = WID ("add_custom_button");
+  g_signal_connect (G_OBJECT (widget), "clicked", G_CALLBACK (add_custom), NULL);
+  widget = WID ("edit_custom_button");
+  g_signal_connect (G_OBJECT (widget), "clicked", G_CALLBACK (edit_custom), NULL);
+
 }
 
 int
Index: capplets/keybindings/gnome-keybinding-properties.glade
===================================================================
RCS file: /cvs/gnome/gnome-control-center/capplets/keybindings/gnome-keybinding-properties.glade,v
retrieving revision 1.19
diff -u -p -r1.19 gnome-keybinding-properties.glade
--- capplets/keybindings/gnome-keybinding-properties.glade	1 Jan 2005 23:18:32 -0000	1.19
+++ capplets/keybindings/gnome-keybinding-properties.glade	11 Aug 2005 20:30:22 -0000
@@ -11,6 +11,11 @@
   <property name="modal">False</property>
   <property name="resizable">True</property>
   <property name="destroy_with_parent">False</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
   <property name="has_separator">False</property>
 
   <child internal-child="vbox">
@@ -32,6 +37,7 @@
 	      <property name="label">gtk-help</property>
 	      <property name="use_stock">True</property>
 	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
 	      <property name="response_id">-11</property>
 	    </widget>
 	  </child>
@@ -44,6 +50,7 @@
 	      <property name="label">gtk-close</property>
 	      <property name="use_stock">True</property>
 	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
 	      <property name="response_id">-7</property>
 	    </widget>
 	  </child>
@@ -154,6 +161,362 @@
 	      <property name="fill">True</property>
 	    </packing>
 	  </child>
+
+	  <child>
+	    <widget class="GtkHBox" id="hbox2">
+	      <property name="border_width">5</property>
+	      <property name="visible">True</property>
+	      <property name="homogeneous">False</property>
+	      <property name="spacing">6</property>
+
+	      <child>
+		<widget class="GtkLabel" id="label13">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">Custom Shortcuts:</property>
+		  <property name="use_underline">False</property>
+		  <property name="use_markup">False</property>
+		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+		  <property name="wrap">False</property>
+		  <property name="selectable">False</property>
+		  <property name="xalign">0.5</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xpad">0</property>
+		  <property name="ypad">0</property>
+		</widget>
+		<packing>
+		  <property name="padding">0</property>
+		  <property name="expand">False</property>
+		  <property name="fill">False</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkButton" id="add_custom_button">
+		  <property name="width_request">60</property>
+		  <property name="height_request">30</property>
+		  <property name="visible">True</property>
+		  <property name="can_focus">True</property>
+		  <property name="label">gtk-new</property>
+		  <property name="use_stock">True</property>
+		  <property name="relief">GTK_RELIEF_NORMAL</property>
+		  <property name="focus_on_click">True</property>
+		</widget>
+		<packing>
+		  <property name="padding">0</property>
+		  <property name="expand">True</property>
+		  <property name="fill">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkButton" id="edit_custom_button">
+		  <property name="visible">True</property>
+		  <property name="can_focus">True</property>
+		  <property name="relief">GTK_RELIEF_NORMAL</property>
+		  <property name="focus_on_click">True</property>
+
+		  <child>
+		    <widget class="GtkAlignment" id="alignment1">
+		      <property name="visible">True</property>
+		      <property name="xalign">0.5</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xscale">0</property>
+		      <property name="yscale">0</property>
+		      <property name="top_padding">0</property>
+		      <property name="bottom_padding">0</property>
+		      <property name="left_padding">0</property>
+		      <property name="right_padding">0</property>
+
+		      <child>
+			<widget class="GtkHBox" id="hbox3">
+			  <property name="visible">True</property>
+			  <property name="homogeneous">False</property>
+			  <property name="spacing">2</property>
+
+			  <child>
+			    <widget class="GtkImage" id="image2">
+			      <property name="visible">True</property>
+			      <property name="stock">gtk-preferences</property>
+			      <property name="icon_size">4</property>
+			      <property name="xalign">0.5</property>
+			      <property name="yalign">0.5</property>
+			      <property name="xpad">0</property>
+			      <property name="ypad">0</property>
+			    </widget>
+			    <packing>
+			      <property name="padding">0</property>
+			      <property name="expand">False</property>
+			      <property name="fill">False</property>
+			    </packing>
+			  </child>
+
+			  <child>
+			    <widget class="GtkLabel" id="label14">
+			      <property name="visible">True</property>
+			      <property name="label" translatable="yes">_Edit...</property>
+			      <property name="use_underline">True</property>
+			      <property name="use_markup">False</property>
+			      <property name="justify">GTK_JUSTIFY_LEFT</property>
+			      <property name="wrap">False</property>
+			      <property name="selectable">False</property>
+			      <property name="xalign">0.5</property>
+			      <property name="yalign">0.5</property>
+			      <property name="xpad">0</property>
+			      <property name="ypad">0</property>
+			    </widget>
+			    <packing>
+			      <property name="padding">0</property>
+			      <property name="expand">False</property>
+			      <property name="fill">False</property>
+			    </packing>
+			  </child>
+			</widget>
+		      </child>
+		    </widget>
+		  </child>
+		</widget>
+		<packing>
+		  <property name="padding">0</property>
+		  <property name="expand">True</property>
+		  <property name="fill">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkButton" id="disable_custom_button">
+		  <property name="visible">True</property>
+		  <property name="can_focus">True</property>
+		  <property name="label">gtk-delete</property>
+		  <property name="use_stock">True</property>
+		  <property name="relief">GTK_RELIEF_NORMAL</property>
+		  <property name="focus_on_click">True</property>
+		</widget>
+		<packing>
+		  <property name="padding">0</property>
+		  <property name="expand">True</property>
+		  <property name="fill">True</property>
+		</packing>
+	      </child>
+	    </widget>
+	    <packing>
+	      <property name="padding">0</property>
+	      <property name="expand">False</property>
+	      <property name="fill">False</property>
+	      <property name="pack_type">GTK_PACK_END</property>
+	    </packing>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">True</property>
+	  <property name="fill">True</property>
+	</packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+<widget class="GtkDialog" id="custom-binding-dialog">
+  <property name="visible">True</property>
+  <property name="title" translatable="yes">Custom Binding</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">False</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <property name="has_separator">True</property>
+  <accessibility>
+    <atkproperty name="AtkObject::accessible_name" translatable="yes">Custom Binding</atkproperty>
+  </accessibility>
+
+  <child internal-child="vbox">
+    <widget class="GtkVBox" id="dialog-vbox1">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">0</property>
+
+      <child internal-child="action_area">
+	<widget class="GtkHButtonBox" id="dialog-action_area2">
+	  <property name="visible">True</property>
+	  <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+	  <child>
+	    <widget class="GtkButton" id="helpbutton2">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="label">gtk-help</property>
+	      <property name="use_stock">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="response_id">-11</property>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkButton" id="cancelbutton1">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="label">gtk-cancel</property>
+	      <property name="use_stock">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="response_id">-6</property>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkButton" id="okbutton1">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="label">gtk-ok</property>
+	      <property name="use_stock">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="response_id">-5</property>
+	    </widget>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">True</property>
+	  <property name="pack_type">GTK_PACK_END</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkHBox" id="hbox5">
+	  <property name="visible">True</property>
+	  <property name="homogeneous">False</property>
+	  <property name="spacing">0</property>
+
+	  <child>
+	    <widget class="GtkLabel" id="label15">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">_New Command: </property>
+	      <property name="use_underline">True</property>
+	      <property name="use_markup">False</property>
+	      <property name="justify">GTK_JUSTIFY_LEFT</property>
+	      <property name="wrap">False</property>
+	      <property name="selectable">False</property>
+	      <property name="xalign">0.5</property>
+	      <property name="yalign">0.5</property>
+	      <property name="xpad">0</property>
+	      <property name="ypad">0</property>
+	    </widget>
+	    <packing>
+	      <property name="padding">0</property>
+	      <property name="expand">False</property>
+	      <property name="fill">False</property>
+	    </packing>
+	  </child>
+
+	  <child>
+	    <widget class="GtkEntry" id="action_tf">
+	      <property name="visible">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="editable">True</property>
+	      <property name="visibility">True</property>
+	      <property name="max_length">0</property>
+	      <property name="text" translatable="yes"></property>
+	      <property name="has_frame">True</property>
+	      <property name="invisible_char" translatable="yes">*</property>
+	      <property name="activates_default">False</property>
+	      <accessibility>
+		<atkproperty name="AtkObject::accessible_name" translatable="yes">action_tf</atkproperty>
+	      </accessibility>
+	    </widget>
+	    <packing>
+	      <property name="padding">0</property>
+	      <property name="expand">True</property>
+	      <property name="fill">True</property>
+	    </packing>
+	  </child>
+
+	  <child>
+	    <widget class="GtkButton" id="browse_button">
+	      <property name="visible">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <accessibility>
+		<atkproperty name="AtkObject::accessible_name" translatable="yes">Browse</atkproperty>
+	      </accessibility>
+
+	      <child>
+		<widget class="GtkAlignment" id="alignment2">
+		  <property name="visible">True</property>
+		  <property name="xalign">0.5</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xscale">0</property>
+		  <property name="yscale">0</property>
+		  <property name="top_padding">0</property>
+		  <property name="bottom_padding">0</property>
+		  <property name="left_padding">0</property>
+		  <property name="right_padding">0</property>
+
+		  <child>
+		    <widget class="GtkHBox" id="hbox6">
+		      <property name="visible">True</property>
+		      <property name="homogeneous">False</property>
+		      <property name="spacing">2</property>
+
+		      <child>
+			<widget class="GtkImage" id="image3">
+			  <property name="visible">True</property>
+			  <property name="stock">gtk-open</property>
+			  <property name="icon_size">4</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkLabel" id="label16">
+			  <property name="visible">True</property>
+			  <property name="label" translatable="yes">_Browse</property>
+			  <property name="use_underline">True</property>
+			  <property name="use_markup">False</property>
+			  <property name="justify">GTK_JUSTIFY_LEFT</property>
+			  <property name="wrap">False</property>
+			  <property name="selectable">False</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</property>
+			</packing>
+		      </child>
+		    </widget>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	    <packing>
+	      <property name="padding">0</property>
+	      <property name="expand">False</property>
+	      <property name="fill">False</property>
+	    </packing>
+	  </child>
 	</widget>
 	<packing>
 	  <property name="padding">0</property>
Index: gnome-settings-daemon/gnome-settings-keybindings.c
===================================================================
RCS file: /cvs/gnome/gnome-control-center/gnome-settings-daemon/gnome-settings-keybindings.c,v
retrieving revision 1.10
diff -u -p -r1.10 gnome-settings-keybindings.c
--- gnome-settings-daemon/gnome-settings-keybindings.c	22 May 2005 15:46:43 -0000	1.10
+++ gnome-settings-daemon/gnome-settings-keybindings.c	11 Aug 2005 20:30:25 -0000
@@ -261,22 +261,6 @@ bindings_get_entry (char *subdir)
   return TRUE;
 }
 
-static gboolean 
-key_already_used (Binding *binding)
-{
-  GSList *li;
-  
-  for (li = binding_list; li != NULL; li = li->next)
-    {
-      Binding *tmp_binding =  (Binding*) li->data;
-
-      if (tmp_binding != binding &&  tmp_binding->key.keycode == binding->key.keycode &&
-	  tmp_binding->key.state == binding->key.state)
-	return TRUE;
-    }
-  return FALSE;
-}
-
 static void
 grab_key (GdkWindow *root, Key *key, int result, gboolean grab)
 {
@@ -346,9 +330,6 @@ binding_register_keys (void)
       if (binding->previous_key.keycode != binding->key.keycode || 
 	  binding->previous_key.state != binding->key.state)
         {
-          /* Ungrab key if it changed and not clashing with previously set binding */
-          if (!key_already_used (binding))
-            {
               if (binding->previous_key.keycode)
 		do_grab (FALSE, &binding->previous_key);
 	      do_grab (TRUE, &binding->key);
@@ -356,9 +337,6 @@ binding_register_keys (void)
 	      binding->previous_key.keysym = binding->key.keysym;
 	      binding->previous_key.state = binding->key.state;
 	      binding->previous_key.keycode = binding->key.keycode;
-            }
-          else
-            g_warning (_("Key Binding (%s) is already in use\n"), binding->binding_str);
         }
     }
   gdk_flush ();
Index: gnome-settings-daemon/gnome-settings-multimedia-keys.c
===================================================================
RCS file: /cvs/gnome/gnome-control-center/gnome-settings-daemon/gnome-settings-multimedia-keys.c,v
retrieving revision 1.14
diff -u -p -r1.14 gnome-settings-multimedia-keys.c
--- gnome-settings-daemon/gnome-settings-multimedia-keys.c	25 Jul 2005 11:55:59 -0000	1.14
+++ gnome-settings-daemon/gnome-settings-multimedia-keys.c	11 Aug 2005 20:30:25 -0000
@@ -57,6 +57,8 @@
  * for these set */
 #define USED_MODS (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK)
 
+#define GCONF_CUSTOM_BINDING_DIR "/apps/gnome_settings_daemon/custom_keybindings"
+
 typedef struct {
 	AcmeVolume *volobj;
 #ifdef USE_FBLEVEL
@@ -79,6 +81,16 @@ enum {
 	ICON_EJECT,
 };
 
+typedef struct {
+	gchar *action;
+	Key *key;
+} CustomBinding;
+CustomBinding *custom_binding_list = NULL;
+static void
+update_custom_bindings_list (GConfClient *client,
+							 guint id,
+							 GConfEntry *entry,
+							 Acme *acme);
 static void
 acme_error (char * msg)
 {
@@ -306,20 +318,17 @@ update_kbd_cb (GConfClient *client, guin
 {
 	Acme *acme = (Acme *) data;
 	int i;
-	gboolean found = FALSE;
 
 	g_return_if_fail (entry->key != NULL);
 
 	/* Find the key that was modified */
-	for (i = 0; i < PLAY_KEY; i++)
+	for (i = 0; i < HANDLED_KEYS; i++)
 	{
 		if (strcmp (entry->key, keys[i].gconf_key) == 0)
 		{
 			const char *tmp;
 			Key *key;
 
-			found = TRUE;
-
 			if (keys[i].key != NULL)
 				grab_key (acme, keys[i].key, FALSE);
 
@@ -338,64 +347,32 @@ update_kbd_cb (GConfClient *client, guin
 				g_free (key);
 				break;
 			}
-
-			grab_key (acme, key, TRUE);
+			
+			if (i < PLAY_KEY)
+				grab_key (acme, key, TRUE);
+			else
+				switch (keys[i].key_type) {
+				case PLAY_KEY:
+					hookup_keysym (key->keycode, "XF86AudioPlay");
+					break;
+				case PAUSE_KEY:
+					hookup_keysym (key->keycode, "XF86AudioPause");
+					break;
+				case STOP_KEY:
+					hookup_keysym (key->keycode, "XF86AudioStop");
+					break;
+				case PREVIOUS_KEY:
+					hookup_keysym (key->keycode, "XF86AudioPrev");
+					break;
+				case NEXT_KEY:
+					hookup_keysym (key->keycode, "XF86AudioNext");
+					break;
+				}
 			keys[i].key = key;
 
 			break;
 		}
 	}
-
-	if (found != FALSE)
-		return;
-
-	for (i = PLAY_KEY; i < HANDLED_KEYS; i++)
-	{
-		if (strcmp (entry->key, keys[i].gconf_key) == 0)
-		{
-			const char *tmp;
-			Key *key;
-
-			if (keys[i].key != NULL)
-				unhookup_keysym (keys[i].key->keycode);
-
-			g_free (keys[i].key);
-			keys[i].key = NULL;
-
-			tmp = gconf_client_get_string (acme->conf_client,
-					keys[i].gconf_key, NULL);
-
-			if (is_valid_shortcut (tmp) == FALSE)
-				break;
-
-			key = g_new0 (Key, 1);
-			if (egg_accelerator_parse_virtual (tmp, &key->keysym, &key->keycode, &key->state) == FALSE)
-			{
-				g_free (key);
-				break;
-			}
-
-			switch (keys[i].key_type) {
-			case PLAY_KEY:
-				hookup_keysym (key->keycode, "XF86AudioPlay");
-				break;
-			case PAUSE_KEY:
-				hookup_keysym (key->keycode, "XF86AudioPause");
-				break;
-			case STOP_KEY:
-				hookup_keysym (key->keycode, "XF86AudioStop");
-				break;
-			case PREVIOUS_KEY:
-				hookup_keysym (key->keycode, "XF86AudioPrev");
-				break;
-			case NEXT_KEY:
-				hookup_keysym (key->keycode, "XF86AudioNext");
-				break;
-			}
-
-			keys[i].key = key;
-		}
-	}
 }
 
 static void
@@ -425,11 +402,90 @@ init_screens (Acme *acme)
 }
 
 static void
+create_custom_bindings_list (Acme *acme)
+{
+  GSList *list, *li;
+  int num_bindings = 0, i = 0;
+  
+  list = gconf_client_all_dirs (acme->conf_client, GCONF_CUSTOM_BINDING_DIR, NULL);
+
+  num_bindings = g_slist_length (list);
+
+  if (custom_binding_list)
+    {
+      for (i = 0; custom_binding_list[i].key; i++)
+        {
+          grab_key (acme, custom_binding_list[i].key, FALSE);
+          g_free (custom_binding_list[i].key);
+          g_free (custom_binding_list[i].action);
+        }
+      g_free (custom_binding_list);
+    }
+
+  custom_binding_list = g_new0 (CustomBinding, num_bindings+1);
+
+  for (li = list; li != NULL; li = li->next)
+    {
+      gchar *subdir = li->data;
+      gchar *gconf_key, *value;
+      Key *key;
+      li->data = NULL;
+      
+      gconf_key = g_strdup_printf ("%s/binding", subdir);
+      value = gconf_client_get_string (acme->conf_client, gconf_key, NULL);
+      gconf_client_notify_add (acme->conf_client,
+                               gconf_key,
+                               update_custom_bindings_list,
+                               acme, NULL, NULL);
+      g_free (gconf_key);
+      if (!is_valid_shortcut (value)) 
+      {
+        g_free (value);
+        continue;
+      }
+      
+      key = g_new0 (Key, 1);
+      if (!egg_accelerator_parse_virtual (value, &key->keysym, &key->keycode, &key->state))
+        {
+          g_free (value);
+          g_free (key); 
+          continue;
+        }
+      g_free (value);
+      grab_key (acme, key, TRUE);
+
+      gconf_key = g_strdup_printf ("%s/action", subdir);
+      value = gconf_client_get_string (acme->conf_client, gconf_key, NULL);
+      gconf_client_notify_add (acme->conf_client,
+                               gconf_key,
+                               update_custom_bindings_list,
+                               acme, NULL, NULL);
+      g_free (gconf_key);
+
+      custom_binding_list[i].action = value;
+      custom_binding_list[i].key = key;
+
+      g_free (subdir);
+      i++;
+    }
+  g_slist_free (list);
+}
+
+static void
+update_custom_bindings_list (GConfClient *client,
+							 guint id,
+							 GConfEntry *entry,
+							 Acme *acme)
+{
+  create_custom_bindings_list (acme);
+}
+
+static void
 init_kbd (Acme *acme)
 {
 	int i;
 
-	for (i = 0; i < PLAY_KEY; i++)
+	for (i = 0; i < HANDLED_KEYS; i++)
 	{
 		char *tmp;
 		Key *key;
@@ -448,69 +504,40 @@ init_kbd (Acme *acme)
 		key = g_new0 (Key, 1);
 		if (!egg_accelerator_parse_virtual (tmp, &key->keysym, &key->keycode, &key->state))
 		{
-		        g_free (tmp);
+		    g_free (tmp);
 			g_free (key);
 			continue;
 		}
 		g_free (tmp);
 
 		keys[i].key = key;
-
-		grab_key (acme, key, TRUE);
-	}
-
-	for (i = PLAY_KEY; i < HANDLED_KEYS; i++)
-	{
-		char *tmp;
-		Key *key;
-
-		gconf_client_notify_add (acme->conf_client,
-				keys[i].gconf_key, update_kbd_cb,
-				acme, NULL, NULL);
-
-		tmp = gconf_client_get_string (acme->conf_client,
-				keys[i].gconf_key, NULL);
-		if (!is_valid_shortcut (tmp)) {
-		        g_free (tmp);
-			continue;
-		}
-
-		key = g_new0 (Key, 1);
-		if (egg_accelerator_parse_virtual (tmp, &key->keysym, &key->keycode, &key->state) == FALSE)
-		{
-		        g_free (tmp);
-			g_free (key);
-			continue;
-		}
-		g_free (tmp);
-
-		keys[i].key = key;
-
-		switch (keys[i].key_type) {
-		case PLAY_KEY:
-			hookup_keysym (keys[i].key->keycode,
-					"XF86AudioPlay");
-			break;
-		case PAUSE_KEY:
-			hookup_keysym (keys[i].key->keycode,
-					"XF86AudioPause");
-			break;
-		case STOP_KEY:
-			hookup_keysym (keys[i].key->keycode,
-					"XF86AudioStop");
-			break;
-		case PREVIOUS_KEY:
-			hookup_keysym (keys[i].key->keycode,
-					"XF86AudioPrev");
-			break;
-		case NEXT_KEY:
-			hookup_keysym (keys[i].key->keycode,
-					"XF86AudioNext");
-			break;
-		}
+		if (i < PLAY_KEY)
+  		  grab_key (acme, key, TRUE);
+  		else
+			switch (keys[i].key_type) {
+			case PLAY_KEY:
+				hookup_keysym (keys[i].key->keycode,
+						"XF86AudioPlay");
+				break;
+			case PAUSE_KEY:
+				hookup_keysym (keys[i].key->keycode,
+						"XF86AudioPause");
+				break;
+			case STOP_KEY:
+				hookup_keysym (keys[i].key->keycode,
+						"XF86AudioStop");
+				break;
+			case PREVIOUS_KEY:
+				hookup_keysym (keys[i].key->keycode,
+						"XF86AudioPrev");
+				break;
+			case NEXT_KEY:
+				hookup_keysym (keys[i].key->keycode,
+						"XF86AudioNext");
+				break;
+			}
 	}
-
-	return;
+	create_custom_bindings_list (acme);
 }
 
 static gboolean
@@ -920,6 +947,17 @@ acme_filter_events (GdkXEvent *xevent, G
 			return GDK_FILTER_REMOVE;
 		}
 	}
+	if (xev->type != KeyRelease)
+		return GDK_FILTER_CONTINUE;
+	
+	if (custom_binding_list)
+		for (i = 0; custom_binding_list[i].key; i++)
+			if (custom_binding_list[i].key->keycode == keycode &&
+			   (state & USED_MODS) == custom_binding_list[i].key->state)
+			{
+				execute (custom_binding_list[i].action, FALSE);
+				return GDK_FILTER_REMOVE;
+			}
 
 	return GDK_FILTER_CONTINUE;
 }
@@ -943,6 +981,11 @@ gnome_settings_multimedia_keys_load (GCo
 		GCONF_CLIENT_PRELOAD_ONELEVEL,
 		NULL);
 
+	gconf_client_add_dir (acme->conf_client,
+		GCONF_CUSTOM_BINDING_DIR,
+		GCONF_CLIENT_PRELOAD_RECURSIVE,
+		NULL);
+
 	init_screens (acme);
 	init_kbd (acme);
 	acme->dialog_timeout = 0;
