patches/control-center-07-custom-keybinding.diff
author dcarbery
Fri, 24 Nov 2006 16:37:59 +0000
branch217update
changeset 19096 d542fc2c823e
parent 8550 30136d86c39c
permissions -rw-r--r--
Merged trunk changes r9797:9829 into 217update branch.

--- /dev/null	Tue Nov 14 14:11:58 2006
+++ control-center-2.16.1/capplets/keybindings/custom-binding.h	Tue Nov 14 14:02:17 2006
@@ -0,0 +1,107 @@
+/* Erwann Chenede 2002 */
+
+#include <config.h>
+
+#include <string.h>
+#include <gtk/gtk.h>
+#include <gconf/gconf-client.h>
+#include <gdk/gdkx.h>
+#include <glade/glade.h>
+#include <X11/Xatom.h>
+
+#include "wm-common.h"
+#include "capplet-util.h"
+#include "eggcellrendererkeys.h"
+#include "activate-settings-daemon.h"
+
+#ifndef __CUSTOM_BINDING__H__
+#define __CUSTOM_BINDING__H__
+
+#define GCONF_CUSTOM_BINDING_DIR "/desktop/gnome/keybindings"
+
+typedef enum {
+  ALWAYS_VISIBLE,
+  N_WORKSPACES_GT
+} KeyListEntryVisibility;
+
+typedef struct
+{
+  const char *name;
+  KeyListEntryVisibility visibility;
+  gint data;
+} KeyListEntry;
+
+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;
+  gboolean custom_key;
+  guint cmd_line_cnxn;
+  char *action;
+  char *binding;
+  char *description;
+} KeyEntry;
+
+void
+my_verbose (const char *format, ...);
+
+void
+cmd_line_changed (GConfClient *client,
+		  guint        cnxn_id,
+		  GConfEntry  *entry,
+		  gpointer     user_data);
+
+void 
+disable_custom (GtkWidget *widget, GtkTreeView *tree_view);
+
+gboolean
+grab_key_callback (GtkWidget    *widget,
+                   GdkEventKey  *event,
+                   void         *data);
+void grab_key (GtkWidget *widget, GladeXML *dialog);
+
+void custom_cancel (GtkWidget *widget, GladeXML *dialog);
+
+void delete_event_cb (GtkWidget *widget, GdkEventAny *event, gpointer *user_data);
+void cursor_changed_cb (GtkTreeView *treeview, GladeXML *dialog);
+
+GladeXML *
+setup_custom_binding_dialog ();
+
+void 
+add_custom (GtkWidget *widget);
+
+void 
+edit_custom (GtkWidget *widget);
+
+void 
+create_custom_bindings_list ();
+
+KeyEntry *
+custom_key_new (char *dir);
+
+gboolean
+is_gconf_key_custom_binding (char *key);
+
+gboolean
+keybinding_key_changed_foreach (GtkTreeModel *model,
+				GtkTreePath  *path,
+				GtkTreeIter  *iter,
+				gpointer      user_data);
+
+void
+reload_key_entries (gpointer wm_name, GladeXML *dialog);
+#endif /*__CUSTOM_BINDING__H__*/
+
--- /dev/null	Tue Nov 14 14:12:48 2006
+++ control-center-2.16.1/capplets/keybindings/custom-binding.c	Tue Nov 14 14:02:17 2006
@@ -0,0 +1,514 @@
+/* Erwann Chenede 2002 */
+
+#include <config.h>
+
+#include <string.h>
+#include <gtk/gtk.h>
+#include <gconf/gconf-client.h>
+#include <gdk/gdkx.h>
+#include <glade/glade.h>
+#include <X11/Xatom.h>
+
+#include "wm-common.h"
+#include "capplet-util.h"
+#include "eggcellrendererkeys.h"
+#include "activate-settings-daemon.h"
+#include "custom-binding.h"
+
+extern KeyListEntry *custom_binding_list;
+extern GladeXML *main_dialog;
+
+void
+my_verbose (const char *format, ...)
+{
+  va_list args;
+  gchar *str;
+
+  if (format == NULL)
+    return;
+
+  if (1) /*DEBUG*/
+    return;
+  
+  va_start (args, format);
+  str = g_strdup_vprintf (format, args);
+  va_end (args);
+  
+  fputs (str, stderr);
+
+  fflush (stderr);
+  
+  g_free (str);
+}
+
+void
+cmd_line_changed (GConfClient *client,
+		  guint        cnxn_id,
+		  GConfEntry  *entry,
+		  gpointer     user_data)
+{
+  KeyEntry *key_entry;
+
+  my_verbose ("In cmd_line_changed\n");
+  
+  key_entry = (KeyEntry *)user_data;
+  g_free (key_entry->action);
+  key_entry->action = g_strdup (gconf_value_get_string (entry->value));
+  key_entry->editable = gconf_entry_get_is_writable (entry);
+
+  /* update the model */
+  gtk_tree_model_foreach (key_entry->model, keybinding_key_changed_foreach, key_entry);
+}
+
+KeyEntry *
+find_keyentry_selected (GtkTreeView *tree_view)
+{
+  GtkTreeSelection* sel = NULL;
+  sel = gtk_tree_view_get_selection (tree_view);
+  
+  if (sel)
+    {
+      GtkTreeIter iter;
+      GtkTreeModel *model;
+      if (gtk_tree_selection_get_selected (sel, &model, &iter))
+	{
+	  KeyEntry *key_entry;
+
+	  gtk_tree_model_get (model, &iter, KEYENTRY_COLUMN, &key_entry, -1);
+	  return key_entry;
+	}
+    }
+  return NULL;
+}
+	
+static gboolean key_delete_cleanup (KeyEntry *key_entry)
+{
+  GConfClient *client = gconf_client_get_default();
+
+  gconf_client_recursive_unset (client, key_entry->gconf_key, 0, NULL);
+
+  create_custom_bindings_list ();
+  reload_key_entries (wm_common_get_current_window_manager(), main_dialog);
+
+  return FALSE;
+}
+
+void 
+disable_custom (GtkWidget *widget, GtkTreeView *tree_view)
+{
+  KeyEntry *key_entry = find_keyentry_selected (tree_view);
+  
+  if (key_entry)
+    {
+      if (key_entry->custom_key)
+	{
+	  GConfClient *client = gconf_client_get_default();
+	  gchar *binding = g_strdup_printf ("%s/binding", key_entry->gconf_key);
+	  gchar *binding_str;
+
+	  gconf_client_notify_remove (client, key_entry->gconf_cnxn);
+	  gconf_client_notify_remove (client, key_entry->cmd_line_cnxn);
+
+	  key_entry->gconf_cnxn = 0;
+	  key_entry->cmd_line_cnxn = 0;
+
+	  binding_str = gconf_client_get_string (client,binding, NULL);
+	
+	  if (binding_str && strcmp (binding_str, "disabled")) {
+		/* This is a neccessery evil. We need to follow a similar
+		   pattern of sequence in setting the binding to disabled state
+		   before deleting it. The timeout is to ensure that when
+		   g-s-d is getting the changes it does not find a key which
+		   is non-existent and crash.
+		*/
+		gconf_client_set_string (client,
+					binding,
+					"disabled",
+					NULL);
+	  	g_timeout_add (1000,  (GSourceFunc) key_delete_cleanup, key_entry);
+
+		g_free (binding_str);
+	  } else 
+		key_delete_cleanup (key_entry);
+
+	  g_free (binding);
+	}
+      else
+	gconf_client_set_string (gconf_client_get_default(),key_entry->gconf_key, "", NULL);
+    }
+}
+
+static int
+get_trailing_num (char *str)
+{
+  char **result = g_strsplit (str, "_", 2);
+  int i = atoi (result[1]);
+  g_strfreev (result);
+  return i;
+}
+
+static char *
+find_free_custom_gconf_key ()
+{
+  GConfClient *client;
+  GSList *list, *li;
+  int num_bindings = 0;
+  int max_num = 0;
+  
+  client  = gconf_client_get_default ();
+
+  list = gconf_client_all_dirs (client, GCONF_CUSTOM_BINDING_DIR, NULL);
+
+  num_bindings = g_slist_length (list);
+
+  custom_binding_list = g_new0 (KeyListEntry, num_bindings+1);
+
+  /*find the highest num */
+
+  for (li = list; li != NULL; li = li->next)
+    {
+      char *subdir = li->data;
+      char *key = g_path_get_basename(subdir);
+      li->data = NULL;
+
+      if (g_ascii_strncasecmp(key, "custom_", 7) == 0)
+	{
+	  int i = get_trailing_num (key);
+	  if (i > max_num)
+	    max_num = i;
+	}
+    }
+  g_slist_free (list);
+  
+  return g_strdup_printf ("%s/custom_%d",GCONF_CUSTOM_BINDING_DIR, max_num + 1);
+}
+
+
+static void 
+add_real_key (GtkWidget *widget, GladeXML *dialog)
+{
+  KeyEntry *entry = NULL;
+  GError *err = NULL;
+  GtkWidget *area_tf = WID ("action_tf");
+  char *binding_key, *action_key;
+  char *action = g_strdup (gtk_entry_get_text (GTK_ENTRY (area_tf)));
+
+  entry = g_object_steal_data (G_OBJECT (area_tf), "key_entry");
+  
+  if (!entry)
+    {
+      char *new_gconf_key = find_free_custom_gconf_key ();
+      GConfClient *client = gconf_client_get_default ();
+      
+      binding_key = g_strdup_printf ("%s/binding", new_gconf_key);
+      action_key = g_strdup_printf ("%s/action", new_gconf_key);
+      
+      gconf_client_set_string (client, new_gconf_key, "", &err);
+      
+      gconf_client_set_string  (client, binding_key, "", &err);
+      
+      gconf_client_set_string  (client,	action_key, action, &err);
+      
+      create_custom_bindings_list ();
+      reload_key_entries (wm_common_get_current_window_manager(), main_dialog);
+      g_free (binding_key);
+      g_free (new_gconf_key);
+    }
+  else
+    {
+      action_key = g_strdup_printf ("%s/action", entry->gconf_key);
+      gconf_client_set_string  (gconf_client_get_default (),
+				action_key, action, &err);
+    }
+
+  g_free (action);
+  g_free (action_key);
+
+  custom_cancel (widget, dialog);
+}
+
+void 
+custom_cancel (GtkWidget *widget, GladeXML *dialog)
+{
+  gtk_entry_set_text (GTK_ENTRY (WID ("action_tf")), "");
+
+  gtk_widget_hide (WID ("custom-binding-dialog"));
+}
+
+void
+delete_event_cb (GtkWidget *widget, GdkEventAny *event, gpointer *user_data)
+{
+  GtkWidget *entry = GTK_WIDGET (user_data);
+  gtk_entry_set_text (GTK_ENTRY (entry), "");
+
+  gtk_widget_hide (widget);
+}
+
+static void 
+cb_dialog_response (GtkWidget *widget, GladeXML *dialog)
+{
+	capplet_help (GTK_WINDOW (gtk_widget_get_toplevel (widget)),
+		      "user-guide.xml",
+		      "goscustdesk-39");
+}
+
+typedef struct 
+{
+  GtkFileSelection *fs;
+  GladeXML *dialog;
+} FileSelData;
+
+
+static void 
+command_selection_ok (FileSelData *fs_data)
+{
+  GtkWidget *action_tf = glade_xml_get_widget (fs_data->dialog, "action_tf");
+  gchar **selections;
+
+  selections = gtk_file_selection_get_selections (fs_data->fs);
+
+  gtk_entry_set_text (GTK_ENTRY (action_tf), selections[0]);
+  gtk_widget_destroy (GTK_WIDGET (fs_data->fs));
+}
+
+static void 
+set_command (GtkWidget *widget, GladeXML *dialog)
+{
+  GtkWidget *window;
+  FileSelData *fs_data = g_new (FileSelData, 1);
+  
+  window = gtk_file_selection_new ("Select Command");
+
+  gtk_window_set_screen (GTK_WINDOW (window),
+			 gtk_widget_get_screen (widget));
+
+  gtk_file_selection_set_select_multiple (GTK_FILE_SELECTION (window),
+					  FALSE);
+
+  g_signal_connect (window, "destroy",
+		    G_CALLBACK (gtk_widget_destroyed),
+		    &window);
+ 
+  fs_data->fs = GTK_FILE_SELECTION (window);
+  fs_data->dialog = dialog;
+  
+  g_signal_connect_swapped (GTK_FILE_SELECTION (window)->ok_button,
+			    "clicked",			    
+			    G_CALLBACK (command_selection_ok),
+			    fs_data);
+
+  g_signal_connect_swapped (GTK_FILE_SELECTION (window)->cancel_button,
+			    "clicked",
+			    G_CALLBACK (gtk_widget_destroy),
+			    window);
+  gtk_widget_show (window);
+}
+
+GladeXML *
+setup_custom_binding_dialog ()
+{
+  static GladeXML *dialog = NULL;
+  GtkWidget *widget, *entry;
+
+  if (dialog)
+    return dialog;
+
+  /* setup dialog */
+  dialog = glade_xml_new (GNOMECC_DATA_DIR "/interfaces/gnome-keybinding-properties.glade", "custom-binding-dialog", NULL);
+  
+  widget = WID ("custom-binding-dialog");
+  entry = WID ("action_tf");
+  g_signal_connect (G_OBJECT (widget), "delete_event",
+		    G_CALLBACK (delete_event_cb),
+		    entry);
+
+  g_signal_connect (G_OBJECT (WID ("browse_button")), "clicked", 
+		    G_CALLBACK (set_command), dialog);
+
+  g_signal_connect (G_OBJECT (WID ("cancelbutton1")), "clicked", 
+		    G_CALLBACK (custom_cancel), dialog);
+
+  g_signal_connect (G_OBJECT (WID ("okbutton1")), "clicked", 
+		    G_CALLBACK (add_real_key), dialog);
+  
+  g_signal_connect (G_OBJECT (WID ("helpbutton2")), "clicked", 
+		    G_CALLBACK (cb_dialog_response), NULL);
+
+  /* gtk_widget_hide (WID ("custom-binding-dialog")); */
+  return dialog;
+}
+void 
+edit_custom (GtkWidget *widget)
+{
+  KeyEntry *entry = find_keyentry_selected (GTK_TREE_VIEW (glade_xml_get_widget (main_dialog,"shortcut_treeview")));
+  if (entry)
+    {
+      if (entry->custom_key)
+	{
+	  GladeXML *dialog = setup_custom_binding_dialog ();
+	  GtkWidget *widget;
+	  widget =  WID ("action_tf");
+	  g_object_set_data (G_OBJECT (widget), "key_entry", entry);
+	  gtk_entry_set_text (GTK_ENTRY (widget), entry->action);
+	  gtk_widget_show_all (WID ("custom-binding-dialog"));
+	}
+    }
+}
+void 
+add_custom (GtkWidget *widget) 
+{
+  GladeXML *dialog = setup_custom_binding_dialog ();
+  GtkWidget *action_widget;
+  action_widget =  WID ("action_tf");
+  g_object_set_data (G_OBJECT (action_widget), "key_entry", NULL);
+  gtk_widget_show_all (WID ("custom-binding-dialog"));
+}
+
+void 
+create_custom_bindings_list ()
+{
+  GConfClient *client;
+  GSList *list, *li;
+  int num_bindings = 0, i = 0;
+  
+  client  = gconf_client_get_default ();
+
+  list = gconf_client_all_dirs (client, GCONF_CUSTOM_BINDING_DIR, NULL);
+
+  num_bindings = g_slist_length (list);
+
+  if (custom_binding_list)
+    g_free (custom_binding_list);
+    
+
+  custom_binding_list = g_new0 (KeyListEntry, num_bindings+1);
+
+  for (li = list; li != NULL; li = li->next)
+    {
+      char *subdir = li->data;
+      li->data = NULL;
+      custom_binding_list[i].name = subdir;
+      custom_binding_list[i].visibility = ALWAYS_VISIBLE;
+      i++;
+    }
+  g_slist_free (list);
+}
+
+KeyEntry *
+custom_key_new (char *dir)
+{
+  GConfValue *value;
+  KeyEntry *new_binding;
+  GSList *tmp_elem = NULL, *list = NULL, *li;
+  char *gconf_key;
+  char *action = NULL;
+  char *key = NULL;
+  
+  g_return_val_if_fail (dir != NULL, NULL);
+  
+  /* value = gconf_entry_get_value (entry); */
+  gconf_key = dir;
+
+  if (!gconf_key)
+    return NULL;
+
+  /* Get entries for this binding */
+  list = gconf_client_all_entries (gconf_client_get_default (), dir, NULL);
+
+  for (li = list; li != NULL; li = li->next)
+    {
+      GConfEntry *entry = li->data;
+      char *key_name = g_path_get_basename (gconf_entry_get_key (entry));
+      if (strcmp (key_name, "action") == 0)
+	{
+	  if (!action)
+	    {
+	      value = gconf_entry_get_value (entry);
+              if (value) 
+               {
+	          if (value->type != GCONF_VALUE_STRING)
+		     return NULL;
+	          action = g_strdup (gconf_value_get_string (value));
+              }
+	    }
+	  else
+	    g_warning (_("Key Binding (%s) has its action defined multiple times\n"),
+		       gconf_key);
+	}
+      if (strcmp (key_name, "binding") == 0)
+	{
+	  if (!key)
+	    {
+	      value = gconf_entry_get_value (entry);
+              if (value)
+                {
+	          if (value->type != GCONF_VALUE_STRING)
+		     return NULL;
+	          key = g_strdup (gconf_value_get_string (value));
+               }
+	    }
+	  else
+	    g_warning (_("Key Binding (%s) has its binding defined multiple times\n"),
+		       gconf_key);
+	}
+    }
+  if (!action || !key)
+    { 
+      g_warning (_("Key Binding (%s) is incomplete\n"), gconf_key);
+      return NULL;
+    }
+  
+  new_binding = g_new0 (KeyEntry, 1);
+  
+  
+  new_binding->binding = key;
+  new_binding->action = action;
+  new_binding->gconf_key = gconf_key;
+  return new_binding;
+}
+
+gboolean
+is_gconf_key_custom_binding (char *key)
+{
+  char *str = NULL;
+
+  str = g_strrstr (key, "keybindings");
+
+  if (str)
+    return TRUE;
+  return FALSE;
+}
+
+void
+cursor_changed_cb (GtkTreeView    *tree_view,
+                   GladeXML       *dialog)
+{
+  KeyEntry *key_entry = find_keyentry_selected (tree_view);
+  GtkWidget *widget;
+
+  my_verbose ("In cursor_changed_cb\n");
+  if (key_entry)
+    {
+      if (key_entry->custom_key)
+        {
+          widget = WID ("edit_custom_button");
+          gtk_widget_set_sensitive (widget, TRUE);
+          widget = WID ("disable_custom_button");
+          gtk_widget_set_sensitive (widget, TRUE);
+        }
+      else
+        {
+          widget = WID ("edit_custom_button");
+          gtk_widget_set_sensitive (widget, FALSE);
+          widget = WID ("disable_custom_button");
+          gtk_widget_set_sensitive (widget, FALSE);
+        }
+    }
+  else
+    {
+      widget = WID ("edit_custom_button");
+      gtk_widget_set_sensitive (widget, FALSE);
+      widget = WID ("disable_custom_button");
+      gtk_widget_set_sensitive (widget, FALSE);
+    }
+}
--- control-center-2.10.1/capplets/keybindings/gnome-keybinding-properties.glade	Thu May 12 16:46:18 2005
+++ control-center-2.10.1-new/capplets/keybindings/gnome-keybinding-properties.glade	Fri May 13 11:51:17 2005
@@ -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>
@@ -152,6 +159,362 @@
 	      <property name="padding">0</property>
 	      <property name="expand">True</property>
 	      <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>
--- control-center-2.10.1/capplets/keybindings/Makefile.am	Thu May 12 16:46:18 2005
+++ control-center-2.10.1-new/capplets/keybindings/Makefile.am	Fri May 13 11:51:17 2005
@@ -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		\
--- control-center-2.10.1/gnome-settings-daemon/gnome-settings-keybindings.c	Thu May 12 16:46:31 2005
+++ control-center-2.10.1-new/gnome-settings-daemon/gnome-settings-keybindings.c	Fri May 13 11:51:17 2005
@@ -199,7 +199,7 @@ bindings_get_entry (char *subdir)
 	  if (!action)
 	    {
 	      value = gconf_entry_get_value (entry);
-	      if (value->type != GCONF_VALUE_STRING)
+	      if (value && value->type != GCONF_VALUE_STRING)
 		return FALSE;
 	      action = g_strdup (gconf_value_get_string (value));
 	    }
@@ -212,7 +212,7 @@ bindings_get_entry (char *subdir)
 	  if (!key)
 	    {
 	      value = gconf_entry_get_value (entry);
-	      if (value->type != GCONF_VALUE_STRING)
+	      if (value && value->type != GCONF_VALUE_STRING)
 		return FALSE;
 	      key = g_strdup (gconf_value_get_string (value));
 	    }
@@ -259,22 +259,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)
 {
@@ -344,9 +328,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);
@@ -354,9 +335,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 ();

--- /usr/tmp/clean/control-center-2.16.1/capplets/keybindings/gnome-keybinding-properties.c	2006-11-14 15:16:57.919910000 +0000
+++ control-center-2.16.1/capplets/keybindings/gnome-keybinding-properties.c	2006-11-14 15:18:14.085992000 +0000
@@ -16,22 +16,10 @@
 #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
-
-typedef enum {
-  ALWAYS_VISIBLE,
-  N_WORKSPACES_GT
-} KeyListEntryVisibility;
-
-typedef struct
-{
-  const char *name;
-  KeyListEntryVisibility visibility;
-  gint data;
-} KeyListEntry;
-
 static const KeyListEntry desktop_key_list[] =
 {
   { "/apps/gnome_settings_daemon/keybindings/help", ALWAYS_VISIBLE, 0 },
@@ -124,13 +112,7 @@
   { NULL }
 };
 
-enum
-{
-  DESCRIPTION_COLUMN,
-  KEYENTRY_COLUMN,
-  N_COLUMNS
-};
-
+/*
 typedef struct
 {
   char *gconf_key;
@@ -142,9 +124,11 @@
   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,
@@ -169,11 +153,8 @@
 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*
@@ -184,7 +165,7 @@
 {
   if (keyval != 0 || keycode != 0)
     return egg_virtual_accelerator_name (keyval, keycode, mask);
-  else
+  else 
     return translate ? g_strdup (_("Disabled")) : g_strdup ("disabled");
 }
 
@@ -249,7 +230,7 @@
 		  NULL);
 }
 
-static gboolean
+gboolean
 keybinding_key_changed_foreach (GtkTreeModel *model,
 				GtkTreePath  *path,
 				GtkTreeIter  *iter,
@@ -265,6 +246,11 @@
 
   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;
     }
@@ -279,7 +265,6 @@
 {
   KeyEntry *key_entry;
   const gchar *key_value;
-
   key_entry = (KeyEntry *)user_data;
   key_value = gconf_value_get_string (entry->value);
 
@@ -352,10 +337,11 @@
 {
   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));
@@ -364,21 +350,33 @@
     {
       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);
     }
 
@@ -441,7 +439,8 @@
 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;
@@ -461,57 +460,97 @@
 
   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)
 	{
@@ -524,20 +563,35 @@
 	}
       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);
@@ -548,18 +602,20 @@
       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
@@ -627,7 +683,6 @@
   /* sanity check */
   if (key_entry == NULL)
     return;
-
   model = get_real_model (view);
   tmp_key.model  = model;
   tmp_key.keyval = keyval;
@@ -712,10 +767,22 @@
   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 (gconf_client_get_default(),
+                             key_entry->gconf_key,
+                             str,
+                             &err);
+   else
+     {
+       char *key = g_strdup_printf ("%s/binding", key_entry->gconf_key);
+       gconf_client_set_string (gconf_client_get_default(),
+                               key,
+                               str,
+                               &err);
+       g_free (key);
+     }
+
   g_free (str);
   g_object_unref (G_OBJECT (client));
 
@@ -763,6 +830,22 @@
 
   /* Unset the key */
   client = gconf_client_get_default();
+
+  if (!key_entry->custom_key) {
+      gconf_client_set_string (gconf_client_get_default(),
+                             key_entry->gconf_key,
+                             "disabled",
+                             &err);
+    } else {
+      char *key = g_strdup_printf ("%s/binding", key_entry->gconf_key);
+      gconf_client_set_string (gconf_client_get_default(),
+                             key,
+                             "disabled",
+                             &err);
+      g_free (key);
+
+    }
+
   gconf_client_set_string (client,
 			   key_entry->gconf_key,
 			   "disabled",
@@ -830,6 +913,8 @@
 {
   GtkTreePath *path;
 
+  my_verbose ("In start_editing_cb\n");
+
   if (event->window != gtk_tree_view_get_bin_window (tree_view))
     return FALSE;
 
@@ -878,11 +963,11 @@
   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",
+	            "row-activated",
 		    G_CALLBACK (start_editing_kb_cb), dialog),
+  g_signal_connect (GTK_TREE_VIEW (WID ("shortcut_treeview")),
+	            "cursor-changed",
+		    G_CALLBACK (cursor_changed_cb), dialog),
 		    
   column = gtk_tree_view_column_new_with_attributes (_("Action"),
 						     gtk_cell_renderer_text_new (),
@@ -893,6 +978,7 @@
   gtk_tree_view_append_column (GTK_TREE_VIEW (WID ("shortcut_treeview")), column);
   gtk_tree_view_column_set_sort_column_id (column, DESCRIPTION_COLUMN);  
   
+
   renderer = (GtkCellRenderer *) g_object_new (EGG_TYPE_CELL_RENDERER_KEYS,
 					       "editable", TRUE,
 					       "accel_mode", EGG_CELL_RENDERER_KEYS_MODE_X,
@@ -918,12 +1004,14 @@
   
   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);
 
@@ -932,6 +1020,19 @@
   gtk_widget_show (widget);
 
   g_signal_connect (G_OBJECT (widget), "response", G_CALLBACK(cb_dialog_response), 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")));
+   gtk_widget_set_sensitive (widget, FALSE);
+ 
+   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);
+   gtk_widget_set_sensitive (widget, FALSE);
 }
 
 int