Home | History | Annotate | Download | only in patches
      1 --- /dev/null	Tue Nov 14 14:11:58 2006
      2 +++ control-center-2.16.1/capplets/keybindings/custom-binding.h	Tue Nov 14 14:02:17 2006
      3 @@ -0,0 +1,107 @@
      4 +/* Erwann Chenede 2002 */
      5 +
      6 +#include <config.h>
      7 +
      8 +#include <string.h>
      9 +#include <gtk/gtk.h>
     10 +#include <gconf/gconf-client.h>
     11 +#include <gdk/gdkx.h>
     12 +#include <glade/glade.h>
     13 +#include <X11/Xatom.h>
     14 +
     15 +#include "wm-common.h"
     16 +#include "capplet-util.h"
     17 +#include "eggcellrendererkeys.h"
     18 +#include "activate-settings-daemon.h"
     19 +
     20 +#ifndef __CUSTOM_BINDING__H__
     21 +#define __CUSTOM_BINDING__H__
     22 +
     23 +#define GCONF_CUSTOM_BINDING_DIR "/desktop/gnome/keybindings"
     24 +
     25 +typedef enum {
     26 +  ALWAYS_VISIBLE,
     27 +  N_WORKSPACES_GT
     28 +} KeyListEntryVisibility;
     29 +
     30 +typedef struct
     31 +{
     32 +  const char *name;
     33 +  KeyListEntryVisibility visibility;
     34 +  gint data;
     35 +} KeyListEntry;
     36 +
     37 +enum
     38 +{
     39 +  DESCRIPTION_COLUMN,
     40 +  KEYENTRY_COLUMN,
     41 +  N_COLUMNS
     42 +};
     43 +
     44 +typedef struct
     45 +{
     46 +  char *gconf_key;
     47 +  guint keyval;
     48 +  guint keycode;
     49 +  EggVirtualModifierType mask;
     50 +  gboolean editable;
     51 +  GtkTreeModel *model;
     52 +  guint gconf_cnxn;
     53 +  gboolean custom_key;
     54 +  guint cmd_line_cnxn;
     55 +  char *action;
     56 +  char *binding;
     57 +  char *description;
     58 +} KeyEntry;
     59 +
     60 +void
     61 +my_verbose (const char *format, ...);
     62 +
     63 +void
     64 +cmd_line_changed (GConfClient *client,
     65 +		  guint        cnxn_id,
     66 +		  GConfEntry  *entry,
     67 +		  gpointer     user_data);
     68 +
     69 +void 
     70 +disable_custom (GtkWidget *widget, GtkTreeView *tree_view);
     71 +
     72 +gboolean
     73 +grab_key_callback (GtkWidget    *widget,
     74 +                   GdkEventKey  *event,
     75 +                   void         *data);
     76 +void grab_key (GtkWidget *widget, GladeXML *dialog);
     77 +
     78 +void custom_cancel (GtkWidget *widget, GladeXML *dialog);
     79 +
     80 +void delete_event_cb (GtkWidget *widget, GdkEventAny *event, gpointer *user_data);
     81 +void cursor_changed_cb (GtkTreeView *treeview, GladeXML *dialog);
     82 +
     83 +GladeXML *
     84 +setup_custom_binding_dialog ();
     85 +
     86 +void 
     87 +add_custom (GtkWidget *widget);
     88 +
     89 +void 
     90 +edit_custom (GtkWidget *widget);
     91 +
     92 +void 
     93 +create_custom_bindings_list ();
     94 +
     95 +KeyEntry *
     96 +custom_key_new (char *dir);
     97 +
     98 +gboolean
     99 +is_gconf_key_custom_binding (char *key);
    100 +
    101 +gboolean
    102 +keybinding_key_changed_foreach (GtkTreeModel *model,
    103 +				GtkTreePath  *path,
    104 +				GtkTreeIter  *iter,
    105 +				gpointer      user_data);
    106 +
    107 +void
    108 +reload_key_entries (gpointer wm_name, GladeXML *dialog);
    109 +#endif /*__CUSTOM_BINDING__H__*/
    110 +
    111 --- /dev/null	Tue Nov 14 14:12:48 2006
    112 +++ control-center-2.16.1/capplets/keybindings/custom-binding.c	Tue Nov 14 14:02:17 2006
    113 @@ -0,0 +1,514 @@
    114 +/* Erwann Chenede 2002 */
    115 +
    116 +#include <config.h>
    117 +
    118 +#include <string.h>
    119 +#include <gtk/gtk.h>
    120 +#include <gconf/gconf-client.h>
    121 +#include <gdk/gdkx.h>
    122 +#include <glade/glade.h>
    123 +#include <X11/Xatom.h>
    124 +
    125 +#include "wm-common.h"
    126 +#include "capplet-util.h"
    127 +#include "eggcellrendererkeys.h"
    128 +#include "activate-settings-daemon.h"
    129 +#include "custom-binding.h"
    130 +
    131 +extern KeyListEntry *custom_binding_list;
    132 +extern GladeXML *main_dialog;
    133 +
    134 +void
    135 +my_verbose (const char *format, ...)
    136 +{
    137 +  va_list args;
    138 +  gchar *str;
    139 +
    140 +  if (format == NULL)
    141 +    return;
    142 +
    143 +  if (1) /*DEBUG*/
    144 +    return;
    145 +  
    146 +  va_start (args, format);
    147 +  str = g_strdup_vprintf (format, args);
    148 +  va_end (args);
    149 +  
    150 +  fputs (str, stderr);
    151 +
    152 +  fflush (stderr);
    153 +  
    154 +  g_free (str);
    155 +}
    156 +
    157 +void
    158 +cmd_line_changed (GConfClient *client,
    159 +		  guint        cnxn_id,
    160 +		  GConfEntry  *entry,
    161 +		  gpointer     user_data)
    162 +{
    163 +  KeyEntry *key_entry;
    164 +
    165 +  my_verbose ("In cmd_line_changed\n");
    166 +  
    167 +  key_entry = (KeyEntry *)user_data;
    168 +  g_free (key_entry->action);
    169 +  key_entry->action = g_strdup (gconf_value_get_string (entry->value));
    170 +  key_entry->editable = gconf_entry_get_is_writable (entry);
    171 +
    172 +  /* update the model */
    173 +  gtk_tree_model_foreach (key_entry->model, keybinding_key_changed_foreach, key_entry);
    174 +}
    175 +
    176 +KeyEntry *
    177 +find_keyentry_selected (GtkTreeView *tree_view)
    178 +{
    179 +  GtkTreeSelection* sel = NULL;
    180 +  sel = gtk_tree_view_get_selection (tree_view);
    181 +  
    182 +  if (sel)
    183 +    {
    184 +      GtkTreeIter iter;
    185 +      GtkTreeModel *model;
    186 +      if (gtk_tree_selection_get_selected (sel, &model, &iter))
    187 +	{
    188 +	  KeyEntry *key_entry;
    189 +
    190 +	  gtk_tree_model_get (model, &iter, KEYENTRY_COLUMN, &key_entry, -1);
    191 +	  return key_entry;
    192 +	}
    193 +    }
    194 +  return NULL;
    195 +}
    196 +	
    197 +static gboolean key_delete_cleanup (KeyEntry *key_entry)
    198 +{
    199 +  GConfClient *client = gconf_client_get_default();
    200 +
    201 +  gconf_client_recursive_unset (client, key_entry->gconf_key, 0, NULL);
    202 +
    203 +  create_custom_bindings_list ();
    204 +  reload_key_entries (wm_common_get_current_window_manager(), main_dialog);
    205 +
    206 +  return FALSE;
    207 +}
    208 +
    209 +void 
    210 +disable_custom (GtkWidget *widget, GtkTreeView *tree_view)
    211 +{
    212 +  KeyEntry *key_entry = find_keyentry_selected (tree_view);
    213 +  
    214 +  if (key_entry)
    215 +    {
    216 +      if (key_entry->custom_key)
    217 +	{
    218 +	  GConfClient *client = gconf_client_get_default();
    219 +	  gchar *binding = g_strdup_printf ("%s/binding", key_entry->gconf_key);
    220 +	  gchar *binding_str;
    221 +
    222 +	  gconf_client_notify_remove (client, key_entry->gconf_cnxn);
    223 +	  gconf_client_notify_remove (client, key_entry->cmd_line_cnxn);
    224 +
    225 +	  key_entry->gconf_cnxn = 0;
    226 +	  key_entry->cmd_line_cnxn = 0;
    227 +
    228 +	  binding_str = gconf_client_get_string (client,binding, NULL);
    229 +	
    230 +	  if (binding_str && strcmp (binding_str, "disabled")) {
    231 +		/* This is a neccessery evil. We need to follow a similar
    232 +		   pattern of sequence in setting the binding to disabled state
    233 +		   before deleting it. The timeout is to ensure that when
    234 +		   g-s-d is getting the changes it does not find a key which
    235 +		   is non-existent and crash.
    236 +		*/
    237 +		gconf_client_set_string (client,
    238 +					binding,
    239 +					"disabled",
    240 +					NULL);
    241 +	  	g_timeout_add (1000,  (GSourceFunc) key_delete_cleanup, key_entry);
    242 +
    243 +		g_free (binding_str);
    244 +	  } else 
    245 +		key_delete_cleanup (key_entry);
    246 +
    247 +	  g_free (binding);
    248 +	}
    249 +      else
    250 +	gconf_client_set_string (gconf_client_get_default(),key_entry->gconf_key, "", NULL);
    251 +    }
    252 +}
    253 +
    254 +static int
    255 +get_trailing_num (char *str)
    256 +{
    257 +  char **result = g_strsplit (str, "_", 2);
    258 +  int i = atoi (result[1]);
    259 +  g_strfreev (result);
    260 +  return i;
    261 +}
    262 +
    263 +static char *
    264 +find_free_custom_gconf_key ()
    265 +{
    266 +  GConfClient *client;
    267 +  GSList *list, *li;
    268 +  int num_bindings = 0;
    269 +  int max_num = 0;
    270 +  
    271 +  client  = gconf_client_get_default ();
    272 +
    273 +  list = gconf_client_all_dirs (client, GCONF_CUSTOM_BINDING_DIR, NULL);
    274 +
    275 +  num_bindings = g_slist_length (list);
    276 +
    277 +  custom_binding_list = g_new0 (KeyListEntry, num_bindings+1);
    278 +
    279 +  /*find the highest num */
    280 +
    281 +  for (li = list; li != NULL; li = li->next)
    282 +    {
    283 +      char *subdir = li->data;
    284 +      char *key = g_path_get_basename(subdir);
    285 +      li->data = NULL;
    286 +
    287 +      if (g_ascii_strncasecmp(key, "custom_", 7) == 0)
    288 +	{
    289 +	  int i = get_trailing_num (key);
    290 +	  if (i > max_num)
    291 +	    max_num = i;
    292 +	}
    293 +    }
    294 +  g_slist_free (list);
    295 +  
    296 +  return g_strdup_printf ("%s/custom_%d",GCONF_CUSTOM_BINDING_DIR, max_num + 1);
    297 +}
    298 +
    299 +
    300 +static void 
    301 +add_real_key (GtkWidget *widget, GladeXML *dialog)
    302 +{
    303 +  KeyEntry *entry = NULL;
    304 +  GError *err = NULL;
    305 +  GtkWidget *area_tf = WID ("action_tf");
    306 +  char *binding_key, *action_key;
    307 +  char *action = g_strdup (gtk_entry_get_text (GTK_ENTRY (area_tf)));
    308 +
    309 +  entry = g_object_steal_data (G_OBJECT (area_tf), "key_entry");
    310 +  
    311 +  if (!entry)
    312 +    {
    313 +      char *new_gconf_key = find_free_custom_gconf_key ();
    314 +      GConfClient *client = gconf_client_get_default ();
    315 +      
    316 +      binding_key = g_strdup_printf ("%s/binding", new_gconf_key);
    317 +      action_key = g_strdup_printf ("%s/action", new_gconf_key);
    318 +      
    319 +      gconf_client_set_string (client, new_gconf_key, "", &err);
    320 +      
    321 +      gconf_client_set_string  (client, binding_key, "", &err);
    322 +      
    323 +      gconf_client_set_string  (client,	action_key, action, &err);
    324 +      
    325 +      create_custom_bindings_list ();
    326 +      reload_key_entries (wm_common_get_current_window_manager(), main_dialog);
    327 +      g_free (binding_key);
    328 +      g_free (new_gconf_key);
    329 +    }
    330 +  else
    331 +    {
    332 +      action_key = g_strdup_printf ("%s/action", entry->gconf_key);
    333 +      gconf_client_set_string  (gconf_client_get_default (),
    334 +				action_key, action, &err);
    335 +    }
    336 +
    337 +  g_free (action);
    338 +  g_free (action_key);
    339 +
    340 +  custom_cancel (widget, dialog);
    341 +}
    342 +
    343 +void 
    344 +custom_cancel (GtkWidget *widget, GladeXML *dialog)
    345 +{
    346 +  gtk_entry_set_text (GTK_ENTRY (WID ("action_tf")), "");
    347 +
    348 +  gtk_widget_hide (WID ("custom-binding-dialog"));
    349 +}
    350 +
    351 +void
    352 +delete_event_cb (GtkWidget *widget, GdkEventAny *event, gpointer *user_data)
    353 +{
    354 +  GtkWidget *entry = GTK_WIDGET (user_data);
    355 +  gtk_entry_set_text (GTK_ENTRY (entry), "");
    356 +
    357 +  gtk_widget_hide (widget);
    358 +}
    359 +
    360 +static void 
    361 +cb_dialog_response (GtkWidget *widget, GladeXML *dialog)
    362 +{
    363 +	capplet_help (GTK_WINDOW (gtk_widget_get_toplevel (widget)),
    364 +		      "user-guide.xml",
    365 +		      "goscustdesk-39");
    366 +}
    367 +
    368 +typedef struct 
    369 +{
    370 +  GtkFileSelection *fs;
    371 +  GladeXML *dialog;
    372 +} FileSelData;
    373 +
    374 +
    375 +static void 
    376 +command_selection_ok (FileSelData *fs_data)
    377 +{
    378 +  GtkWidget *action_tf = glade_xml_get_widget (fs_data->dialog, "action_tf");
    379 +  gchar **selections;
    380 +
    381 +  selections = gtk_file_selection_get_selections (fs_data->fs);
    382 +
    383 +  gtk_entry_set_text (GTK_ENTRY (action_tf), selections[0]);
    384 +  gtk_widget_destroy (GTK_WIDGET (fs_data->fs));
    385 +}
    386 +
    387 +static void 
    388 +set_command (GtkWidget *widget, GladeXML *dialog)
    389 +{
    390 +  GtkWidget *window;
    391 +  FileSelData *fs_data = g_new (FileSelData, 1);
    392 +  
    393 +  window = gtk_file_selection_new ("Select Command");
    394 +
    395 +  gtk_window_set_screen (GTK_WINDOW (window),
    396 +			 gtk_widget_get_screen (widget));
    397 +
    398 +  gtk_file_selection_set_select_multiple (GTK_FILE_SELECTION (window),
    399 +					  FALSE);
    400 +
    401 +  g_signal_connect (window, "destroy",
    402 +		    G_CALLBACK (gtk_widget_destroyed),
    403 +		    &window);
    404 + 
    405 +  fs_data->fs = GTK_FILE_SELECTION (window);
    406 +  fs_data->dialog = dialog;
    407 +  
    408 +  g_signal_connect_swapped (GTK_FILE_SELECTION (window)->ok_button,
    409 +			    "clicked",			    
    410 +			    G_CALLBACK (command_selection_ok),
    411 +			    fs_data);
    412 +
    413 +  g_signal_connect_swapped (GTK_FILE_SELECTION (window)->cancel_button,
    414 +			    "clicked",
    415 +			    G_CALLBACK (gtk_widget_destroy),
    416 +			    window);
    417 +  gtk_widget_show (window);
    418 +}
    419 +
    420 +GladeXML *
    421 +setup_custom_binding_dialog ()
    422 +{
    423 +  static GladeXML *dialog = NULL;
    424 +  GtkWidget *widget, *entry;
    425 +
    426 +  if (dialog)
    427 +    return dialog;
    428 +
    429 +  /* setup dialog */
    430 +  dialog = glade_xml_new (GNOMECC_DATA_DIR "/interfaces/gnome-keybinding-properties.glade", "custom-binding-dialog", NULL);
    431 +  
    432 +  widget = WID ("custom-binding-dialog");
    433 +  entry = WID ("action_tf");
    434 +  g_signal_connect (G_OBJECT (widget), "delete_event",
    435 +		    G_CALLBACK (delete_event_cb),
    436 +		    entry);
    437 +
    438 +  g_signal_connect (G_OBJECT (WID ("browse_button")), "clicked", 
    439 +		    G_CALLBACK (set_command), dialog);
    440 +
    441 +  g_signal_connect (G_OBJECT (WID ("cancelbutton1")), "clicked", 
    442 +		    G_CALLBACK (custom_cancel), dialog);
    443 +
    444 +  g_signal_connect (G_OBJECT (WID ("okbutton1")), "clicked", 
    445 +		    G_CALLBACK (add_real_key), dialog);
    446 +  
    447 +  g_signal_connect (G_OBJECT (WID ("helpbutton2")), "clicked", 
    448 +		    G_CALLBACK (cb_dialog_response), NULL);
    449 +
    450 +  /* gtk_widget_hide (WID ("custom-binding-dialog")); */
    451 +  return dialog;
    452 +}
    453 +void 
    454 +edit_custom (GtkWidget *widget)
    455 +{
    456 +  KeyEntry *entry = find_keyentry_selected (GTK_TREE_VIEW (glade_xml_get_widget (main_dialog,"shortcut_treeview")));
    457 +  if (entry)
    458 +    {
    459 +      if (entry->custom_key)
    460 +	{
    461 +	  GladeXML *dialog = setup_custom_binding_dialog ();
    462 +	  GtkWidget *widget;
    463 +	  widget =  WID ("action_tf");
    464 +	  g_object_set_data (G_OBJECT (widget), "key_entry", entry);
    465 +	  gtk_entry_set_text (GTK_ENTRY (widget), entry->action);
    466 +	  gtk_widget_show_all (WID ("custom-binding-dialog"));
    467 +	}
    468 +    }
    469 +}
    470 +void 
    471 +add_custom (GtkWidget *widget) 
    472 +{
    473 +  GladeXML *dialog = setup_custom_binding_dialog ();
    474 +  GtkWidget *action_widget;
    475 +  action_widget =  WID ("action_tf");
    476 +  g_object_set_data (G_OBJECT (action_widget), "key_entry", NULL);
    477 +  gtk_widget_show_all (WID ("custom-binding-dialog"));
    478 +}
    479 +
    480 +void 
    481 +create_custom_bindings_list ()
    482 +{
    483 +  GConfClient *client;
    484 +  GSList *list, *li;
    485 +  int num_bindings = 0, i = 0;
    486 +  
    487 +  client  = gconf_client_get_default ();
    488 +
    489 +  list = gconf_client_all_dirs (client, GCONF_CUSTOM_BINDING_DIR, NULL);
    490 +
    491 +  num_bindings = g_slist_length (list);
    492 +
    493 +  if (custom_binding_list)
    494 +    g_free (custom_binding_list);
    495 +    
    496 +
    497 +  custom_binding_list = g_new0 (KeyListEntry, num_bindings+1);
    498 +
    499 +  for (li = list; li != NULL; li = li->next)
    500 +    {
    501 +      char *subdir = li->data;
    502 +      li->data = NULL;
    503 +      custom_binding_list[i].name = subdir;
    504 +      custom_binding_list[i].visibility = ALWAYS_VISIBLE;
    505 +      i++;
    506 +    }
    507 +  g_slist_free (list);
    508 +}
    509 +
    510 +KeyEntry *
    511 +custom_key_new (char *dir)
    512 +{
    513 +  GConfValue *value;
    514 +  KeyEntry *new_binding;
    515 +  GSList *tmp_elem = NULL, *list = NULL, *li;
    516 +  char *gconf_key;
    517 +  char *action = NULL;
    518 +  char *key = NULL;
    519 +  
    520 +  g_return_val_if_fail (dir != NULL, NULL);
    521 +  
    522 +  /* value = gconf_entry_get_value (entry); */
    523 +  gconf_key = dir;
    524 +
    525 +  if (!gconf_key)
    526 +    return NULL;
    527 +
    528 +  /* Get entries for this binding */
    529 +  list = gconf_client_all_entries (gconf_client_get_default (), dir, NULL);
    530 +
    531 +  for (li = list; li != NULL; li = li->next)
    532 +    {
    533 +      GConfEntry *entry = li->data;
    534 +      char *key_name = g_path_get_basename (gconf_entry_get_key (entry));
    535 +      if (strcmp (key_name, "action") == 0)
    536 +	{
    537 +	  if (!action)
    538 +	    {
    539 +	      value = gconf_entry_get_value (entry);
    540 +              if (value) 
    541 +               {
    542 +	          if (value->type != GCONF_VALUE_STRING)
    543 +		     return NULL;
    544 +	          action = g_strdup (gconf_value_get_string (value));
    545 +              }
    546 +	    }
    547 +	  else
    548 +	    g_warning (_("Key Binding (%s) has its action defined multiple times\n"),
    549 +		       gconf_key);
    550 +	}
    551 +      if (strcmp (key_name, "binding") == 0)
    552 +	{
    553 +	  if (!key)
    554 +	    {
    555 +	      value = gconf_entry_get_value (entry);
    556 +              if (value)
    557 +                {
    558 +	          if (value->type != GCONF_VALUE_STRING)
    559 +		     return NULL;
    560 +	          key = g_strdup (gconf_value_get_string (value));
    561 +               }
    562 +	    }
    563 +	  else
    564 +	    g_warning (_("Key Binding (%s) has its binding defined multiple times\n"),
    565 +		       gconf_key);
    566 +	}
    567 +    }
    568 +  if (!action || !key)
    569 +    { 
    570 +      g_warning (_("Key Binding (%s) is incomplete\n"), gconf_key);
    571 +      return NULL;
    572 +    }
    573 +  
    574 +  new_binding = g_new0 (KeyEntry, 1);
    575 +  
    576 +  
    577 +  new_binding->binding = key;
    578 +  new_binding->action = action;
    579 +  new_binding->gconf_key = gconf_key;
    580 +  return new_binding;
    581 +}
    582 +
    583 +gboolean
    584 +is_gconf_key_custom_binding (char *key)
    585 +{
    586 +  char *str = NULL;
    587 +
    588 +  str = g_strrstr (key, "keybindings");
    589 +
    590 +  if (str)
    591 +    return TRUE;
    592 +  return FALSE;
    593 +}
    594 +
    595 +void
    596 +cursor_changed_cb (GtkTreeView    *tree_view,
    597 +                   GladeXML       *dialog)
    598 +{
    599 +  KeyEntry *key_entry = find_keyentry_selected (tree_view);
    600 +  GtkWidget *widget;
    601 +
    602 +  my_verbose ("In cursor_changed_cb\n");
    603 +  if (key_entry)
    604 +    {
    605 +      if (key_entry->custom_key)
    606 +        {
    607 +          widget = WID ("edit_custom_button");
    608 +          gtk_widget_set_sensitive (widget, TRUE);
    609 +          widget = WID ("disable_custom_button");
    610 +          gtk_widget_set_sensitive (widget, TRUE);
    611 +        }
    612 +      else
    613 +        {
    614 +          widget = WID ("edit_custom_button");
    615 +          gtk_widget_set_sensitive (widget, FALSE);
    616 +          widget = WID ("disable_custom_button");
    617 +          gtk_widget_set_sensitive (widget, FALSE);
    618 +        }
    619 +    }
    620 +  else
    621 +    {
    622 +      widget = WID ("edit_custom_button");
    623 +      gtk_widget_set_sensitive (widget, FALSE);
    624 +      widget = WID ("disable_custom_button");
    625 +      gtk_widget_set_sensitive (widget, FALSE);
    626 +    }
    627 +}
    628 --- control-center-2.10.1/capplets/keybindings/gnome-keybinding-properties.glade	Thu May 12 16:46:18 2005
    629 +++ control-center-2.10.1-new/capplets/keybindings/gnome-keybinding-properties.glade	Fri May 13 11:51:17 2005
    630 @@ -11,6 +11,11 @@
    631    <property name="modal">False</property>
    632    <property name="resizable">True</property>
    633    <property name="destroy_with_parent">False</property>
    634 +  <property name="decorated">True</property>
    635 +  <property name="skip_taskbar_hint">False</property>
    636 +  <property name="skip_pager_hint">False</property>
    637 +  <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
    638 +  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
    639    <property name="has_separator">False</property>
    640  
    641    <child internal-child="vbox">
    642 @@ -32,6 +37,7 @@
    643  	      <property name="label">gtk-help</property>
    644  	      <property name="use_stock">True</property>
    645  	      <property name="relief">GTK_RELIEF_NORMAL</property>
    646 +	      <property name="focus_on_click">True</property>
    647  	      <property name="response_id">-11</property>
    648  	    </widget>
    649  	  </child>
    650 @@ -44,6 +50,7 @@
    651  	      <property name="label">gtk-close</property>
    652  	      <property name="use_stock">True</property>
    653  	      <property name="relief">GTK_RELIEF_NORMAL</property>
    654 +	      <property name="focus_on_click">True</property>
    655  	      <property name="response_id">-7</property>
    656  	    </widget>
    657  	  </child>
    658 @@ -152,6 +159,362 @@
    659  	      <property name="padding">0</property>
    660  	      <property name="expand">True</property>
    661  	      <property name="fill">True</property>
    662 +	    </packing>
    663 +	  </child>
    664 +
    665 +	  <child>
    666 +	    <widget class="GtkHBox" id="hbox2">
    667 +	      <property name="border_width">5</property>
    668 +	      <property name="visible">True</property>
    669 +	      <property name="homogeneous">False</property>
    670 +	      <property name="spacing">6</property>
    671 +
    672 +	      <child>
    673 +		<widget class="GtkLabel" id="label13">
    674 +		  <property name="visible">True</property>
    675 +		  <property name="label" translatable="yes">Custom Shortcuts:</property>
    676 +		  <property name="use_underline">False</property>
    677 +		  <property name="use_markup">False</property>
    678 +		  <property name="justify">GTK_JUSTIFY_LEFT</property>
    679 +		  <property name="wrap">False</property>
    680 +		  <property name="selectable">False</property>
    681 +		  <property name="xalign">0.5</property>
    682 +		  <property name="yalign">0.5</property>
    683 +		  <property name="xpad">0</property>
    684 +		  <property name="ypad">0</property>
    685 +		</widget>
    686 +		<packing>
    687 +		  <property name="padding">0</property>
    688 +		  <property name="expand">False</property>
    689 +		  <property name="fill">False</property>
    690 +		</packing>
    691 +	      </child>
    692 +
    693 +	      <child>
    694 +		<widget class="GtkButton" id="add_custom_button">
    695 +		  <property name="width_request">60</property>
    696 +		  <property name="height_request">30</property>
    697 +		  <property name="visible">True</property>
    698 +		  <property name="can_focus">True</property>
    699 +		  <property name="label">gtk-new</property>
    700 +		  <property name="use_stock">True</property>
    701 +		  <property name="relief">GTK_RELIEF_NORMAL</property>
    702 +		  <property name="focus_on_click">True</property>
    703 +		</widget>
    704 +		<packing>
    705 +		  <property name="padding">0</property>
    706 +		  <property name="expand">True</property>
    707 +		  <property name="fill">True</property>
    708 +		</packing>
    709 +	      </child>
    710 +
    711 +	      <child>
    712 +		<widget class="GtkButton" id="edit_custom_button">
    713 +		  <property name="visible">True</property>
    714 +		  <property name="can_focus">True</property>
    715 +		  <property name="relief">GTK_RELIEF_NORMAL</property>
    716 +		  <property name="focus_on_click">True</property>
    717 +
    718 +		  <child>
    719 +		    <widget class="GtkAlignment" id="alignment1">
    720 +		      <property name="visible">True</property>
    721 +		      <property name="xalign">0.5</property>
    722 +		      <property name="yalign">0.5</property>
    723 +		      <property name="xscale">0</property>
    724 +		      <property name="yscale">0</property>
    725 +		      <property name="top_padding">0</property>
    726 +		      <property name="bottom_padding">0</property>
    727 +		      <property name="left_padding">0</property>
    728 +		      <property name="right_padding">0</property>
    729 +
    730 +		      <child>
    731 +			<widget class="GtkHBox" id="hbox3">
    732 +			  <property name="visible">True</property>
    733 +			  <property name="homogeneous">False</property>
    734 +			  <property name="spacing">2</property>
    735 +
    736 +			  <child>
    737 +			    <widget class="GtkImage" id="image2">
    738 +			      <property name="visible">True</property>
    739 +			      <property name="stock">gtk-preferences</property>
    740 +			      <property name="icon_size">4</property>
    741 +			      <property name="xalign">0.5</property>
    742 +			      <property name="yalign">0.5</property>
    743 +			      <property name="xpad">0</property>
    744 +			      <property name="ypad">0</property>
    745 +			    </widget>
    746 +			    <packing>
    747 +			      <property name="padding">0</property>
    748 +			      <property name="expand">False</property>
    749 +			      <property name="fill">False</property>
    750 +			    </packing>
    751 +			  </child>
    752 +
    753 +			  <child>
    754 +			    <widget class="GtkLabel" id="label14">
    755 +			      <property name="visible">True</property>
    756 +			      <property name="label" translatable="yes">_Edit...</property>
    757 +			      <property name="use_underline">True</property>
    758 +			      <property name="use_markup">False</property>
    759 +			      <property name="justify">GTK_JUSTIFY_LEFT</property>
    760 +			      <property name="wrap">False</property>
    761 +			      <property name="selectable">False</property>
    762 +			      <property name="xalign">0.5</property>
    763 +			      <property name="yalign">0.5</property>
    764 +			      <property name="xpad">0</property>
    765 +			      <property name="ypad">0</property>
    766 +			    </widget>
    767 +			    <packing>
    768 +			      <property name="padding">0</property>
    769 +			      <property name="expand">False</property>
    770 +			      <property name="fill">False</property>
    771 +			    </packing>
    772 +			  </child>
    773 +			</widget>
    774 +		      </child>
    775 +		    </widget>
    776 +		  </child>
    777 +		</widget>
    778 +		<packing>
    779 +		  <property name="padding">0</property>
    780 +		  <property name="expand">True</property>
    781 +		  <property name="fill">True</property>
    782 +		</packing>
    783 +	      </child>
    784 +
    785 +	      <child>
    786 +		<widget class="GtkButton" id="disable_custom_button">
    787 +		  <property name="visible">True</property>
    788 +		  <property name="can_focus">True</property>
    789 +		  <property name="label">gtk-delete</property>
    790 +		  <property name="use_stock">True</property>
    791 +		  <property name="relief">GTK_RELIEF_NORMAL</property>
    792 +		  <property name="focus_on_click">True</property>
    793 +		</widget>
    794 +		<packing>
    795 +		  <property name="padding">0</property>
    796 +		  <property name="expand">True</property>
    797 +		  <property name="fill">True</property>
    798 +		</packing>
    799 +	      </child>
    800 +	    </widget>
    801 +	    <packing>
    802 +	      <property name="padding">0</property>
    803 +	      <property name="expand">False</property>
    804 +	      <property name="fill">False</property>
    805 +	      <property name="pack_type">GTK_PACK_END</property>
    806 +	    </packing>
    807 +	  </child>
    808 +	</widget>
    809 +	<packing>
    810 +	  <property name="padding">0</property>
    811 +	  <property name="expand">True</property>
    812 +	  <property name="fill">True</property>
    813 +	</packing>
    814 +      </child>
    815 +    </widget>
    816 +  </child>
    817 +</widget>
    818 +
    819 +<widget class="GtkDialog" id="custom-binding-dialog">
    820 +  <property name="visible">True</property>
    821 +  <property name="title" translatable="yes">Custom Binding</property>
    822 +  <property name="type">GTK_WINDOW_TOPLEVEL</property>
    823 +  <property name="window_position">GTK_WIN_POS_NONE</property>
    824 +  <property name="modal">False</property>
    825 +  <property name="resizable">True</property>
    826 +  <property name="destroy_with_parent">False</property>
    827 +  <property name="decorated">True</property>
    828 +  <property name="skip_taskbar_hint">False</property>
    829 +  <property name="skip_pager_hint">False</property>
    830 +  <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
    831 +  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
    832 +  <property name="has_separator">True</property>
    833 +  <accessibility>
    834 +    <atkproperty name="AtkObject::accessible_name" translatable="yes">Custom Binding</atkproperty>
    835 +  </accessibility>
    836 +
    837 +  <child internal-child="vbox">
    838 +    <widget class="GtkVBox" id="dialog-vbox1">
    839 +      <property name="visible">True</property>
    840 +      <property name="homogeneous">False</property>
    841 +      <property name="spacing">0</property>
    842 +
    843 +      <child internal-child="action_area">
    844 +	<widget class="GtkHButtonBox" id="dialog-action_area2">
    845 +	  <property name="visible">True</property>
    846 +	  <property name="layout_style">GTK_BUTTONBOX_END</property>
    847 +
    848 +	  <child>
    849 +	    <widget class="GtkButton" id="helpbutton2">
    850 +	      <property name="visible">True</property>
    851 +	      <property name="can_default">True</property>
    852 +	      <property name="can_focus">True</property>
    853 +	      <property name="label">gtk-help</property>
    854 +	      <property name="use_stock">True</property>
    855 +	      <property name="relief">GTK_RELIEF_NORMAL</property>
    856 +	      <property name="focus_on_click">True</property>
    857 +	      <property name="response_id">-11</property>
    858 +	    </widget>
    859 +	  </child>
    860 +
    861 +	  <child>
    862 +	    <widget class="GtkButton" id="cancelbutton1">
    863 +	      <property name="visible">True</property>
    864 +	      <property name="can_default">True</property>
    865 +	      <property name="can_focus">True</property>
    866 +	      <property name="label">gtk-cancel</property>
    867 +	      <property name="use_stock">True</property>
    868 +	      <property name="relief">GTK_RELIEF_NORMAL</property>
    869 +	      <property name="focus_on_click">True</property>
    870 +	      <property name="response_id">-6</property>
    871 +	    </widget>
    872 +	  </child>
    873 +
    874 +	  <child>
    875 +	    <widget class="GtkButton" id="okbutton1">
    876 +	      <property name="visible">True</property>
    877 +	      <property name="can_default">True</property>
    878 +	      <property name="can_focus">True</property>
    879 +	      <property name="label">gtk-ok</property>
    880 +	      <property name="use_stock">True</property>
    881 +	      <property name="relief">GTK_RELIEF_NORMAL</property>
    882 +	      <property name="focus_on_click">True</property>
    883 +	      <property name="response_id">-5</property>
    884 +	    </widget>
    885 +	  </child>
    886 +	</widget>
    887 +	<packing>
    888 +	  <property name="padding">0</property>
    889 +	  <property name="expand">False</property>
    890 +	  <property name="fill">True</property>
    891 +	  <property name="pack_type">GTK_PACK_END</property>
    892 +	</packing>
    893 +      </child>
    894 +
    895 +      <child>
    896 +	<widget class="GtkHBox" id="hbox5">
    897 +	  <property name="visible">True</property>
    898 +	  <property name="homogeneous">False</property>
    899 +	  <property name="spacing">0</property>
    900 +
    901 +	  <child>
    902 +	    <widget class="GtkLabel" id="label15">
    903 +	      <property name="visible">True</property>
    904 +	      <property name="label" translatable="yes">_New Command: </property>
    905 +	      <property name="use_underline">True</property>
    906 +	      <property name="use_markup">False</property>
    907 +	      <property name="justify">GTK_JUSTIFY_LEFT</property>
    908 +	      <property name="wrap">False</property>
    909 +	      <property name="selectable">False</property>
    910 +	      <property name="xalign">0.5</property>
    911 +	      <property name="yalign">0.5</property>
    912 +	      <property name="xpad">0</property>
    913 +	      <property name="ypad">0</property>
    914 +	    </widget>
    915 +	    <packing>
    916 +	      <property name="padding">0</property>
    917 +	      <property name="expand">False</property>
    918 +	      <property name="fill">False</property>
    919 +	    </packing>
    920 +	  </child>
    921 +
    922 +	  <child>
    923 +	    <widget class="GtkEntry" id="action_tf">
    924 +	      <property name="visible">True</property>
    925 +	      <property name="can_focus">True</property>
    926 +	      <property name="editable">True</property>
    927 +	      <property name="visibility">True</property>
    928 +	      <property name="max_length">0</property>
    929 +	      <property name="text" translatable="yes"></property>
    930 +	      <property name="has_frame">True</property>
    931 +	      <property name="invisible_char" translatable="yes">*</property>
    932 +	      <property name="activates_default">False</property>
    933 +	      <accessibility>
    934 +		<atkproperty name="AtkObject::accessible_name" translatable="yes">action_tf</atkproperty>
    935 +	      </accessibility>
    936 +	    </widget>
    937 +	    <packing>
    938 +	      <property name="padding">0</property>
    939 +	      <property name="expand">True</property>
    940 +	      <property name="fill">True</property>
    941 +	    </packing>
    942 +	  </child>
    943 +
    944 +	  <child>
    945 +	    <widget class="GtkButton" id="browse_button">
    946 +	      <property name="visible">True</property>
    947 +	      <property name="can_focus">True</property>
    948 +	      <property name="relief">GTK_RELIEF_NORMAL</property>
    949 +	      <property name="focus_on_click">True</property>
    950 +	      <accessibility>
    951 +		<atkproperty name="AtkObject::accessible_name" translatable="yes">Browse</atkproperty>
    952 +	      </accessibility>
    953 +
    954 +	      <child>
    955 +		<widget class="GtkAlignment" id="alignment2">
    956 +		  <property name="visible">True</property>
    957 +		  <property name="xalign">0.5</property>
    958 +		  <property name="yalign">0.5</property>
    959 +		  <property name="xscale">0</property>
    960 +		  <property name="yscale">0</property>
    961 +		  <property name="top_padding">0</property>
    962 +		  <property name="bottom_padding">0</property>
    963 +		  <property name="left_padding">0</property>
    964 +		  <property name="right_padding">0</property>
    965 +
    966 +		  <child>
    967 +		    <widget class="GtkHBox" id="hbox6">
    968 +		      <property name="visible">True</property>
    969 +		      <property name="homogeneous">False</property>
    970 +		      <property name="spacing">2</property>
    971 +
    972 +		      <child>
    973 +			<widget class="GtkImage" id="image3">
    974 +			  <property name="visible">True</property>
    975 +			  <property name="stock">gtk-open</property>
    976 +			  <property name="icon_size">4</property>
    977 +			  <property name="xalign">0.5</property>
    978 +			  <property name="yalign">0.5</property>
    979 +			  <property name="xpad">0</property>
    980 +			  <property name="ypad">0</property>
    981 +			</widget>
    982 +			<packing>
    983 +			  <property name="padding">0</property>
    984 +			  <property name="expand">False</property>
    985 +			  <property name="fill">False</property>
    986 +			</packing>
    987 +		      </child>
    988 +
    989 +		      <child>
    990 +			<widget class="GtkLabel" id="label16">
    991 +			  <property name="visible">True</property>
    992 +			  <property name="label" translatable="yes">_Browse</property>
    993 +			  <property name="use_underline">True</property>
    994 +			  <property name="use_markup">False</property>
    995 +			  <property name="justify">GTK_JUSTIFY_LEFT</property>
    996 +			  <property name="wrap">False</property>
    997 +			  <property name="selectable">False</property>
    998 +			  <property name="xalign">0.5</property>
    999 +			  <property name="yalign">0.5</property>
   1000 +			  <property name="xpad">0</property>
   1001 +			  <property name="ypad">0</property>
   1002 +			</widget>
   1003 +			<packing>
   1004 +			  <property name="padding">0</property>
   1005 +			  <property name="expand">False</property>
   1006 +			  <property name="fill">False</property>
   1007 +			</packing>
   1008 +		      </child>
   1009 +		    </widget>
   1010 +		  </child>
   1011 +		</widget>
   1012 +	      </child>
   1013 +	    </widget>
   1014 +	    <packing>
   1015 +	      <property name="padding">0</property>
   1016 +	      <property name="expand">False</property>
   1017 +	      <property name="fill">False</property>
   1018  	    </packing>
   1019  	  </child>
   1020  	</widget>
   1021 --- control-center-2.10.1/capplets/keybindings/Makefile.am	Thu May 12 16:46:18 2005
   1022 +++ control-center-2.10.1-new/capplets/keybindings/Makefile.am	Fri May 13 11:51:17 2005
   1023 @@ -3,6 +3,8 @@ bin_PROGRAMS = gnome-keybinding-properti
   1024  gnome_keybinding_properties_LDADD = $(GNOMECC_CAPPLETS_LIBS)
   1025  gnome_keybinding_properties_SOURCES = 	\
   1026  	gnome-keybinding-properties.c	\
   1027 +	custom-binding.c		\
   1028 +	custom-binding.h		\
   1029  	eggcellrendererkeys.c		\
   1030  	eggcellrendererkeys.h		\
   1031  	eggaccelerators.c		\
   1032 --- control-center-2.10.1/gnome-settings-daemon/gnome-settings-keybindings.c	Thu May 12 16:46:31 2005
   1033 +++ control-center-2.10.1-new/gnome-settings-daemon/gnome-settings-keybindings.c	Fri May 13 11:51:17 2005
   1034 @@ -199,7 +199,7 @@ bindings_get_entry (char *subdir)
   1035  	  if (!action)
   1036  	    {
   1037  	      value = gconf_entry_get_value (entry);
   1038 -	      if (value->type != GCONF_VALUE_STRING)
   1039 +	      if (value && value->type != GCONF_VALUE_STRING)
   1040  		return FALSE;
   1041  	      action = g_strdup (gconf_value_get_string (value));
   1042  	    }
   1043 @@ -212,7 +212,7 @@ bindings_get_entry (char *subdir)
   1044  	  if (!key)
   1045  	    {
   1046  	      value = gconf_entry_get_value (entry);
   1047 -	      if (value->type != GCONF_VALUE_STRING)
   1048 +	      if (value && value->type != GCONF_VALUE_STRING)
   1049  		return FALSE;
   1050  	      key = g_strdup (gconf_value_get_string (value));
   1051  	    }
   1052 @@ -259,22 +259,6 @@ bindings_get_entry (char *subdir)
   1053    return TRUE;
   1054  }
   1055  
   1056 -static gboolean 
   1057 -key_already_used (Binding *binding)
   1058 -{
   1059 -  GSList *li;
   1060 -  
   1061 -  for (li = binding_list; li != NULL; li = li->next)
   1062 -    {
   1063 -      Binding *tmp_binding =  (Binding*) li->data;
   1064 -
   1065 -      if (tmp_binding != binding &&  tmp_binding->key.keycode == binding->key.keycode &&
   1066 -	  tmp_binding->key.state == binding->key.state)
   1067 -	return TRUE;
   1068 -    }
   1069 -  return FALSE;
   1070 -}
   1071 -
   1072  static void
   1073  grab_key (GdkWindow *root, Key *key, int result, gboolean grab)
   1074  {
   1075 @@ -344,9 +328,6 @@ binding_register_keys (void)
   1076        if (binding->previous_key.keycode != binding->key.keycode || 
   1077  	  binding->previous_key.state != binding->key.state)
   1078          {
   1079 -          /* Ungrab key if it changed and not clashing with previously set binding */
   1080 -          if (!key_already_used (binding))
   1081 -            {
   1082                if (binding->previous_key.keycode)
   1083  		do_grab (FALSE, &binding->previous_key);
   1084  	      do_grab (TRUE, &binding->key);
   1085 @@ -354,9 +335,6 @@ binding_register_keys (void)
   1086  	      binding->previous_key.keysym = binding->key.keysym;
   1087  	      binding->previous_key.state = binding->key.state;
   1088  	      binding->previous_key.keycode = binding->key.keycode;
   1089 -            }
   1090 -          else
   1091 -            g_warning (_("Key Binding (%s) is already in use\n"), binding->binding_str);
   1092          }
   1093      }
   1094    gdk_flush ();
   1095 
   1096 --- /usr/tmp/clean/control-center-2.16.1/capplets/keybindings/gnome-keybinding-properties.c	2006-11-14 15:16:57.919910000 +0000
   1097 +++ control-center-2.16.1/capplets/keybindings/gnome-keybinding-properties.c	2006-11-14 15:18:14.085992000 +0000
   1098 @@ -16,22 +16,10 @@
   1099  #include "capplet-util.h"
   1100  #include "eggcellrendererkeys.h"
   1101  #include "activate-settings-daemon.h"
   1102 +#include "custom-binding.h"
   1103  
   1104  #define LABEL_DATA "gnome-keybinding-properties-label"
   1105  #define MAX_ELEMENTS_BEFORE_SCROLLING 10
   1106 -
   1107 -typedef enum {
   1108 -  ALWAYS_VISIBLE,
   1109 -  N_WORKSPACES_GT
   1110 -} KeyListEntryVisibility;
   1111 -
   1112 -typedef struct
   1113 -{
   1114 -  const char *name;
   1115 -  KeyListEntryVisibility visibility;
   1116 -  gint data;
   1117 -} KeyListEntry;
   1118 -
   1119  static const KeyListEntry desktop_key_list[] =
   1120  {
   1121    { "/apps/gnome_settings_daemon/keybindings/help", ALWAYS_VISIBLE, 0 },
   1122 @@ -124,13 +112,7 @@
   1123    { NULL }
   1124  };
   1125  
   1126 -enum
   1127 -{
   1128 -  DESCRIPTION_COLUMN,
   1129 -  KEYENTRY_COLUMN,
   1130 -  N_COLUMNS
   1131 -};
   1132 -
   1133 +/*
   1134  typedef struct
   1135  {
   1136    char *gconf_key;
   1137 @@ -142,9 +124,11 @@
   1138    guint gconf_cnxn;
   1139    char *description;
   1140  } KeyEntry;
   1141 +*/
   1142 +
   1143 +KeyListEntry *custom_binding_list = NULL;
   1144 +GladeXML *main_dialog;
   1145  
   1146 -static void  reload_key_entries (gpointer                wm_name,
   1147 -                                 GladeXML               *dialog);
   1148  static char* binding_name       (guint                   keyval,
   1149  				 guint			 keycode,
   1150                                   EggVirtualModifierType  mask,
   1151 @@ -169,11 +153,8 @@
   1152  static GladeXML *
   1153  create_dialog (void)
   1154  {
   1155 -  GladeXML *dialog;
   1156 -
   1157 -  dialog = glade_xml_new (GNOMECC_DATA_DIR "/interfaces/gnome-keybinding-properties.glade", "gnome-keybinding-dialog", NULL);
   1158 -
   1159 -  return dialog;
   1160 +   main_dialog = glade_xml_new (GNOMECC_DATA_DIR "/interfaces/gnome-keybinding-properties.glade", "gnome-keybinding-dialog", NULL);
   1161 +   return main_dialog;
   1162  }
   1163  
   1164  static char*
   1165 @@ -184,7 +165,7 @@
   1166  {
   1167    if (keyval != 0 || keycode != 0)
   1168      return egg_virtual_accelerator_name (keyval, keycode, mask);
   1169 -  else
   1170 +  else 
   1171      return translate ? g_strdup (_("Disabled")) : g_strdup ("disabled");
   1172  }
   1173  
   1174 @@ -249,7 +230,7 @@
   1175  		  NULL);
   1176  }
   1177  
   1178 -static gboolean
   1179 +gboolean
   1180  keybinding_key_changed_foreach (GtkTreeModel *model,
   1181  				GtkTreePath  *path,
   1182  				GtkTreeIter  *iter,
   1183 @@ -265,6 +246,11 @@
   1184  
   1185    if (key_entry == tmp_key_entry)
   1186      {
   1187 +      if (key_entry->custom_key)
   1188 +        gtk_tree_store_set (GTK_TREE_STORE (key_entry->model), iter,
   1189 +                            DESCRIPTION_COLUMN, key_entry->action,
   1190 +                            -1);
   1191 +
   1192        gtk_tree_model_row_changed (key_entry->model, path, iter);
   1193        return TRUE;
   1194      }
   1195 @@ -279,7 +265,6 @@
   1196  {
   1197    KeyEntry *key_entry;
   1198    const gchar *key_value;
   1199 -
   1200    key_entry = (KeyEntry *)user_data;
   1201    key_value = gconf_value_get_string (entry->value);
   1202  
   1203 @@ -352,10 +337,11 @@
   1204  {
   1205    GtkTreeModel *model;
   1206    GtkTreeModel *sort_model;
   1207 -  GtkTreeIter iter;
   1208 +  GtkTreeIter iter, parent_iter;
   1209    KeyEntry *key_entry;
   1210    gboolean valid;
   1211    GConfClient *client;
   1212 +  int children, i;
   1213  
   1214    client = gconf_client_get_default ();
   1215    model = get_real_model (GTK_TREE_VIEW (tree_view));
   1216 @@ -364,21 +350,33 @@
   1217      {
   1218        g_object_ref (model);
   1219  
   1220 -      for (valid = gtk_tree_model_get_iter_first (model, &iter);
   1221 -	   valid;
   1222 -	   valid = gtk_tree_model_iter_next (model, &iter))
   1223 +	valid = gtk_tree_model_get_iter_first (model, &parent_iter);
   1224 +	while  (valid)
   1225  	{
   1226 -	  gtk_tree_model_get (model, &iter,
   1227 -			      KEYENTRY_COLUMN, &key_entry,
   1228 -			      -1);
   1229 -	  if (key_entry != NULL)
   1230 -	    {
   1231 -	      gconf_client_notify_remove (client, key_entry->gconf_cnxn);
   1232 -	      g_free (key_entry->gconf_key);
   1233 -              g_free (key_entry->description);
   1234 -	      g_free (key_entry);
   1235 -            }
   1236 -	}
   1237 +          children = gtk_tree_model_iter_n_children (model,&parent_iter);
   1238 +
   1239 +          for (i = 0; i < children ; i++)
   1240 +             {
   1241 +                if (gtk_tree_model_iter_nth_child (model, &iter, &parent_iter, i))
   1242 +                  {
   1243 +                        gtk_tree_model_get (model, &iter,
   1244 +                                            KEYENTRY_COLUMN, &key_entry,
   1245 +                                            -1);
   1246 +	                if (key_entry != NULL)
   1247 +	                  {
   1248 +			      if (key_entry->custom_key == TRUE)
   1249 +	                           gconf_client_notify_remove (client, key_entry->cmd_line_cnxn);
   1250 +	                      gconf_client_notify_remove (client, key_entry->gconf_cnxn);
   1251 +	                      g_free (key_entry->gconf_key);
   1252 +                              g_free (key_entry->description);
   1253 +	                      g_free (key_entry);
   1254 +                          }
   1255 +            
   1256 +                  }
   1257 +
   1258 +	      }
   1259 +            valid = gtk_tree_model_iter_next (model, &parent_iter);
   1260 +         }
   1261        g_object_unref (model);
   1262      }
   1263  
   1264 @@ -441,7 +439,8 @@
   1265  static void
   1266  append_keys_to_tree (GladeXML           *dialog,
   1267  		     const gchar        *title,
   1268 -		     const KeyListEntry *keys_list)
   1269 +		     const KeyListEntry *keys_list,
   1270 +		     gboolean            custom_binding)
   1271  {
   1272    GConfClient *client;
   1273    GtkTreeIter parent_iter;
   1274 @@ -461,57 +460,97 @@
   1275  
   1276    for (j = 0; keys_list[j].name != NULL; j++)
   1277      {
   1278 -      GConfEntry *entry;
   1279 +      GConfEntry *entry = NULL;
   1280        GConfSchema *schema = NULL;
   1281 -      KeyEntry *key_entry;
   1282 +      KeyEntry *key_entry = NULL;
   1283        GError *error = NULL;
   1284        GtkTreeIter iter;
   1285        const gchar *key_string;
   1286        gchar *key_value;
   1287  
   1288        if (!should_show_key (&keys_list[j]))
   1289 -	continue;
   1290 -      
   1291 -      key_string = keys_list[j].name;
   1292 +        continue;
   1293  
   1294 -      entry = gconf_client_get_entry (client,
   1295 -                                      key_string,
   1296 -				      NULL,
   1297 -				      TRUE,
   1298 -				      &error);
   1299 -      if (error || entry == NULL)
   1300 -	{
   1301 -	  /* We don't actually want to popup a dialog - just skip this one */
   1302 -	  if (error)
   1303 -	    g_error_free (error);
   1304 -	  continue;
   1305 -	}
   1306 +      if (!custom_binding)
   1307 +       {
   1308 +          key_string = keys_list[j].name;
   1309 +
   1310 +	  entry = gconf_client_get_entry (client,
   1311 +					  key_string,
   1312 +					  NULL,
   1313 +					  TRUE,
   1314 +					  &error);
   1315 +       }
   1316 +      else if (error || entry == NULL)
   1317 +       {
   1318 +          key_entry = custom_key_new ((char *)keys_list[j].name);
   1319 +          if (!key_entry)
   1320 +            continue;
   1321 +          key_string = key_entry->gconf_key;
   1322 +       }
   1323 +
   1324 +
   1325 +      if (!custom_binding)
   1326 +       {
   1327 +         if (error || entry == NULL)
   1328 +           {
   1329 +             /* We don't actually want to popup a dialog - just skip this one */
   1330 +             if (error)
   1331 +               g_error_free (error);
   1332 +             continue;
   1333 +           }
   1334  
   1335 -      if (gconf_entry_get_schema_name (entry))
   1336 -	schema = gconf_client_get_schema (client, gconf_entry_get_schema_name (entry), &error);
   1337 +         if (gconf_entry_get_schema_name (entry))
   1338 +           schema = gconf_client_get_schema (client, gconf_entry_get_schema_name (entry), &error);
   1339        
   1340 -      if (error || schema == NULL)
   1341 -	{
   1342 -	  /* We don't actually want to popup a dialog - just skip this one */
   1343 -	  if (error)
   1344 -	    g_error_free (error);
   1345 -	  continue;
   1346 +         if (error || schema == NULL)
   1347 +	   {
   1348 +	     /* We don't actually want to popup a dialog - just skip this one */
   1349 +	     if (error)
   1350 +	       g_error_free (error);
   1351 +		continue;
   1352 +           }
   1353  	}
   1354  
   1355 -      key_value = gconf_client_get_string (client, key_string, &error);
   1356 +      if (!custom_binding)
   1357 +        {
   1358  
   1359 -      key_entry = g_new0 (KeyEntry, 1);
   1360 -      key_entry->gconf_key = g_strdup (key_string);
   1361 -      key_entry->editable = gconf_entry_get_is_writable (entry);
   1362 -      key_entry->model = model;
   1363 -      gconf_client_add_dir (client, key_string, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
   1364 -      key_entry->gconf_cnxn = gconf_client_notify_add (client,
   1365 -						       key_string,
   1366 -						       (GConfClientNotifyFunc) &keybinding_key_changed,
   1367 -						       key_entry, NULL, NULL);
   1368 -      binding_from_string (key_value, &key_entry->keyval, &key_entry->keycode, &key_entry->mask);
   1369 -      g_free (key_value);
   1370 -      key_entry->description = g_strdup (gconf_schema_get_short_desc (schema));
   1371 +           key_entry = g_new0 (KeyEntry, 1);
   1372 +           key_value = gconf_client_get_string (client, key_string, &error);
   1373 +           key_entry->gconf_key = g_strdup (key_string);
   1374 +           key_entry->editable = gconf_entry_get_is_writable (entry);
   1375 +           key_entry->model = model;
   1376 +           gconf_client_add_dir (client, key_string, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
   1377 +           key_entry->gconf_cnxn = gconf_client_notify_add (client,
   1378 +						            key_string,
   1379 +						            (GConfClientNotifyFunc) &keybinding_key_changed,
   1380 +						            key_entry, NULL, NULL);
   1381 +           binding_from_string (key_value, &key_entry->keyval, &key_entry->keycode, &key_entry->mask);
   1382 +           g_free (key_value);
   1383 +           key_entry->description = g_strdup (gconf_schema_get_short_desc (schema));
   1384 +        }
   1385 +      else 
   1386 +        {
   1387 +           char *key_binding = g_strdup_printf ("%s/binding", key_entry->gconf_key);
   1388 +           char *cmd_binding = g_strdup_printf ("%s/action", key_entry->gconf_key);
   1389 +           key_entry->editable = TRUE;
   1390 +           key_entry->model = model;
   1391 +           gconf_client_add_dir (client, key_entry->gconf_key, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
   1392 +
   1393 +           key_entry->gconf_cnxn = gconf_client_notify_add (client,
   1394 +                                                            key_binding,
   1395 +                                                            (GConfClientNotifyFunc) &keybinding_key_changed,
   1396 +                                                            key_entry, NULL, NULL);
   1397 +           binding_from_string (key_entry->binding, &key_entry->keyval, &key_entry->keycode, &key_entry->mask);
   1398 +
   1399 +           key_entry->custom_key = TRUE;
   1400 +           key_entry->cmd_line_cnxn = gconf_client_notify_add (client, cmd_binding,
   1401 +                                                              (GConfClientNotifyFunc) &cmd_line_changed,
   1402 +                                                              key_entry, NULL, NULL);
   1403 +           key_entry->action = g_strdup (gconf_client_get_string (client, cmd_binding, &error));
   1404 +           g_free (key_binding);
   1405 +           g_free (cmd_binding);
   1406 +        }
   1407  
   1408        if (i == MAX_ELEMENTS_BEFORE_SCROLLING)
   1409  	{
   1410 @@ -524,20 +563,35 @@
   1411  	}
   1412        i++;
   1413        gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent_iter);
   1414 -      if (gconf_schema_get_short_desc (schema))
   1415 -	gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
   1416 -			    DESCRIPTION_COLUMN,
   1417 -                            key_entry->description,
   1418 -			    KEYENTRY_COLUMN, key_entry,
   1419 -			    -1);
   1420 -      else
   1421 -	gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
   1422 -			    DESCRIPTION_COLUMN, _("<Unknown Action>"),
   1423 -			    KEYENTRY_COLUMN, key_entry,
   1424 -			    -1);
   1425 +
   1426 +      if (!custom_binding)
   1427 +       {
   1428 +         if (gconf_schema_get_short_desc (schema))
   1429 +          gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
   1430 +      		        DESCRIPTION_COLUMN,
   1431 +                               key_entry->description,
   1432 +      		        KEYENTRY_COLUMN, key_entry,
   1433 +      		        -1);
   1434 +         else
   1435 +          gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
   1436 +      		        DESCRIPTION_COLUMN, _("<Unknown Action>"),
   1437 +      		        KEYENTRY_COLUMN, key_entry,
   1438 +      		        -1);
   1439 +       }
   1440 +      else {
   1441 +           gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
   1442 +                               DESCRIPTION_COLUMN, key_entry->action,
   1443 +                               KEYENTRY_COLUMN, key_entry,
   1444 +                               -1);
   1445 +      }
   1446 +
   1447        gtk_tree_view_expand_all (GTK_TREE_VIEW (WID ("shortcut_treeview")));
   1448 -      gconf_entry_free (entry);
   1449 -      gconf_schema_free (schema);
   1450 +
   1451 +      if (entry)
   1452 +        gconf_entry_free (entry);
   1453 +      if (schema)
   1454 +        gconf_schema_free (schema);
   1455 +   
   1456      }
   1457  
   1458    g_object_unref (client);
   1459 @@ -548,18 +602,20 @@
   1460        gtk_widget_show (WID ("shortcuts_vbox"));
   1461  }
   1462  
   1463 -static void
   1464 +void
   1465  reload_key_entries (gpointer wm_name, GladeXML *dialog)
   1466  {
   1467    clear_old_model (dialog, WID ("shortcut_treeview"));
   1468    
   1469 -  append_keys_to_tree (dialog, _("Desktop"), desktop_key_list);
   1470 -  append_keys_to_tree (dialog, _("Sound"), sounds_key_list);
   1471 +  append_keys_to_tree (dialog, _("Desktop"), desktop_key_list, FALSE);
   1472 +  append_keys_to_tree (dialog, _("Sound"), sounds_key_list, FALSE);
   1473    
   1474    if (strcmp((char *) wm_name, WM_COMMON_METACITY) == 0)
   1475      {
   1476 -      append_keys_to_tree (dialog, _("Window Management"), metacity_key_list);
   1477 +      append_keys_to_tree (dialog, _("Window Management"), metacity_key_list, FALSE);
   1478      }
   1479 + 
   1480 +  append_keys_to_tree (dialog, _("Custom Shortcuts"), custom_binding_list, TRUE);
   1481  }
   1482  
   1483  static void
   1484 @@ -627,7 +683,6 @@
   1485    /* sanity check */
   1486    if (key_entry == NULL)
   1487      return;
   1488 -
   1489    model = get_real_model (view);
   1490    tmp_key.model  = model;
   1491    tmp_key.keyval = keyval;
   1492 @@ -712,10 +767,22 @@
   1493    str = binding_name (keyval, keycode, mask, FALSE);
   1494  
   1495    client = gconf_client_get_default();
   1496 -  gconf_client_set_string (client,
   1497 -                           key_entry->gconf_key,
   1498 -                           str,
   1499 -                           &err);
   1500 +
   1501 +  if (!key_entry->custom_key)
   1502 +     gconf_client_set_string (gconf_client_get_default(),
   1503 +                             key_entry->gconf_key,
   1504 +                             str,
   1505 +                             &err);
   1506 +   else
   1507 +     {
   1508 +       char *key = g_strdup_printf ("%s/binding", key_entry->gconf_key);
   1509 +       gconf_client_set_string (gconf_client_get_default(),
   1510 +                               key,
   1511 +                               str,
   1512 +                               &err);
   1513 +       g_free (key);
   1514 +     }
   1515 +
   1516    g_free (str);
   1517    g_object_unref (G_OBJECT (client));
   1518  
   1519 @@ -763,6 +830,22 @@
   1520  
   1521    /* Unset the key */
   1522    client = gconf_client_get_default();
   1523 +
   1524 +  if (!key_entry->custom_key) {
   1525 +      gconf_client_set_string (gconf_client_get_default(),
   1526 +                             key_entry->gconf_key,
   1527 +                             "disabled",
   1528 +                             &err);
   1529 +    } else {
   1530 +      char *key = g_strdup_printf ("%s/binding", key_entry->gconf_key);
   1531 +      gconf_client_set_string (gconf_client_get_default(),
   1532 +                             key,
   1533 +                             "disabled",
   1534 +                             &err);
   1535 +      g_free (key);
   1536 +
   1537 +    }
   1538 +
   1539    gconf_client_set_string (client,
   1540  			   key_entry->gconf_key,
   1541  			   "disabled",
   1542 @@ -830,6 +913,8 @@
   1543  {
   1544    GtkTreePath *path;
   1545  
   1546 +  my_verbose ("In start_editing_cb\n");
   1547 +
   1548    if (event->window != gtk_tree_view_get_bin_window (tree_view))
   1549      return FALSE;
   1550  
   1551 @@ -878,11 +963,11 @@
   1552    client = gconf_client_get_default ();
   1553  
   1554    g_signal_connect (GTK_TREE_VIEW (WID ("shortcut_treeview")),
   1555 -		    "button_press_event",
   1556 -		    G_CALLBACK (start_editing_cb), dialog),
   1557 -	g_signal_connect (GTK_TREE_VIEW (WID ("shortcut_treeview")),
   1558 -	      "row-activated",
   1559 +	            "row-activated",
   1560  		    G_CALLBACK (start_editing_kb_cb), dialog),
   1561 +  g_signal_connect (GTK_TREE_VIEW (WID ("shortcut_treeview")),
   1562 +	            "cursor-changed",
   1563 +		    G_CALLBACK (cursor_changed_cb), dialog),
   1564  		    
   1565    column = gtk_tree_view_column_new_with_attributes (_("Action"),
   1566  						     gtk_cell_renderer_text_new (),
   1567 @@ -893,6 +978,7 @@
   1568    gtk_tree_view_append_column (GTK_TREE_VIEW (WID ("shortcut_treeview")), column);
   1569    gtk_tree_view_column_set_sort_column_id (column, DESCRIPTION_COLUMN);  
   1570    
   1571 +
   1572    renderer = (GtkCellRenderer *) g_object_new (EGG_TYPE_CELL_RENDERER_KEYS,
   1573  					       "editable", TRUE,
   1574  					       "accel_mode", EGG_CELL_RENDERER_KEYS_MODE_X,
   1575 @@ -918,12 +1004,14 @@
   1576    
   1577    gconf_client_add_dir (client, "/apps/gnome_keybinding_properties", GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
   1578    gconf_client_add_dir (client, "/apps/metacity/general", GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
   1579 +  gconf_client_add_dir (client, GCONF_CUSTOM_BINDING_DIR, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
   1580    gconf_client_notify_add (client,
   1581  			   "/apps/metacity/general/num_workspaces",
   1582  			   (GConfClientNotifyFunc) &key_entry_controlling_key_changed,
   1583  			   dialog, NULL, NULL);
   1584    g_object_unref (client);
   1585  
   1586 +  create_custom_bindings_list ();
   1587    /* set up the dialog */
   1588    reload_key_entries (wm_common_get_current_window_manager(), dialog);
   1589  
   1590 @@ -932,6 +1020,19 @@
   1591    gtk_widget_show (widget);
   1592  
   1593    g_signal_connect (G_OBJECT (widget), "response", G_CALLBACK(cb_dialog_response), NULL);
   1594 + 
   1595 +   /* set up custom bindings buttons and dialog*/
   1596 +   widget = WID ("disable_custom_button");
   1597 +   g_signal_connect (G_OBJECT (widget), "clicked", G_CALLBACK (disable_custom),
   1598 +                     GTK_TREE_VIEW (WID ("shortcut_treeview")));
   1599 +   gtk_widget_set_sensitive (widget, FALSE);
   1600 + 
   1601 +   widget = WID ("add_custom_button");
   1602 +   g_signal_connect (G_OBJECT (widget), "clicked", G_CALLBACK (add_custom), NULL);
   1603 + 
   1604 +   widget = WID ("edit_custom_button");
   1605 +   g_signal_connect (G_OBJECT (widget), "clicked", G_CALLBACK (edit_custom), NULL);
   1606 +   gtk_widget_set_sensitive (widget, FALSE);
   1607  }
   1608  
   1609  int
   1610