]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkbindings.c
Remove GtkItemFactory completely
[~andy/gtk] / gtk / gtkbindings.c
index 95ae875d87a15735711c235235ba96e0bb14a82b..c75e22058718770b78959004b553011802c75cc6 100644 (file)
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
+#include "config.h"
 #include <string.h>
 #include <stdarg.h>
 #include <gdkkeysyms.h>
+
 #include "gtkbindings.h"
 #include "gtkkeyhash.h"
-#include "gtksignal.h"
 #include "gtkwidget.h"
 #include "gtkrc.h"
+#include "gtkalias.h"
 
 
 /* --- defines --- */
 
 /* --- structures --- */
 typedef struct {
+  GtkPathType   type;
   GPatternSpec *pspec;
-  gpointer user_data;
-  guint seq_id;
+  GSList       *path;
+  gpointer      user_data;
+  guint         seq_id;
 } PatternSpec;
 
 
@@ -53,22 +57,31 @@ typedef struct {
 static GHashTable      *binding_entry_hash_table = NULL;
 static GSList           *binding_key_hashes = NULL;
 static GSList          *binding_set_list = NULL;
-static const gchar     *key_class_binding_set = "gtk-class-binding-set";
+static const gchar      key_class_binding_set[] = "gtk-class-binding-set";
 static GQuark           key_id_class_binding_set = 0;
 
 
 /* --- functions --- */
+static void
+pattern_spec_free (PatternSpec *pspec)
+{
+  _gtk_rc_free_widget_class_path (pspec->path);
+  if (pspec->pspec)
+    g_pattern_spec_free (pspec->pspec);
+  g_free (pspec);
+}
+
 static GtkBindingSignal*
 binding_signal_new (const gchar *signal_name,
                    guint        n_args)
 {
   GtkBindingSignal *signal;
-  
-  signal = g_new (GtkBindingSignal, 1);
+
+  signal = (GtkBindingSignal *) g_slice_alloc0 (sizeof (GtkBindingSignal) + n_args * sizeof (GtkBindingArg));
   signal->next = NULL;
-  signal->signal_name = g_strdup (signal_name);
+  signal->signal_name = (gchar *)g_intern_string (signal_name);
   signal->n_args = n_args;
-  signal->args = g_new0 (GtkBindingArg, n_args);
+  signal->args = (GtkBindingArg *)(signal + 1);
   
   return signal;
 }
@@ -80,12 +93,10 @@ binding_signal_free (GtkBindingSignal *sig)
   
   for (i = 0; i < sig->n_args; i++)
     {
-      if (GTK_FUNDAMENTAL_TYPE (sig->args[i].arg_type) == GTK_TYPE_STRING)
+      if (G_TYPE_FUNDAMENTAL (sig->args[i].arg_type) == G_TYPE_STRING)
        g_free (sig->args[i].d.string_data);
     }
-  g_free (sig->args);
-  g_free (sig->signal_name);
-  g_free (sig);
+  g_slice_free1 (sizeof (GtkBindingSignal) + sig->n_args * sizeof (GtkBindingArg), sig);
 }
 
 static guint
@@ -196,6 +207,7 @@ binding_entry_new (GtkBindingSet  *binding_set,
   entry->binding_set = binding_set,
   entry->destroyed = FALSE;
   entry->in_emission = FALSE;
+  entry->marks_unbound = FALSE;
   entry->signals = NULL;
 
   entry->set_next = binding_set->entries;
@@ -362,11 +374,11 @@ binding_compose_params (GtkObject       *object,
          g_value_init (&tmp_value, G_TYPE_DOUBLE);
          g_value_set_double (&tmp_value, args->d.double_data);
          break;
-       case  G_TYPE_LONG:
+       case G_TYPE_LONG:
          g_value_init (&tmp_value, G_TYPE_LONG);
          g_value_set_long (&tmp_value, args->d.long_data);
          break;
-       case  G_TYPE_STRING:
+       case G_TYPE_STRING:
          /* gtk_rc_parse_flags/enum() has fancier parsing for this; we can't call
           * that since we don't have a GParamSpec, so just do something simple
           */
@@ -505,7 +517,7 @@ gtk_binding_entry_activate (GtkBindingEntry *entry,
                     sig->signal_name,
                     g_type_name (G_OBJECT_TYPE (object)));
        }
-      else if (!(query.signal_flags & GTK_RUN_ACTION))
+      else if (!(query.signal_flags & G_SIGNAL_ACTION))
        {
          accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
          g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
@@ -550,26 +562,46 @@ gtk_binding_entry_activate (GtkBindingEntry *entry,
   return handled;
 }
 
+/**
+ * gtk_binding_set_new:
+ * @set_name: unique name of this binding set
+ *
+ * GTK+ maintains a global list of binding sets. Each binding set has
+ * a unique name which needs to be specified upon creation.
+ *
+ * Return value: new binding set
+ */
 GtkBindingSet*
-gtk_binding_set_new (const gchar    *set_name)
+gtk_binding_set_new (const gchar *set_name)
 {
   GtkBindingSet *binding_set;
   
   g_return_val_if_fail (set_name != NULL, NULL);
   
   binding_set = g_new (GtkBindingSet, 1);
-  binding_set->set_name = g_strdup (set_name);
+  binding_set->set_name = (gchar *) g_intern_string (set_name);
   binding_set->widget_path_pspecs = NULL;
   binding_set->widget_class_pspecs = NULL;
   binding_set->class_branch_pspecs = NULL;
   binding_set->entries = NULL;
   binding_set->current = NULL;
+  binding_set->parsed = FALSE;
   
   binding_set_list = g_slist_prepend (binding_set_list, binding_set);
   
   return binding_set;
 }
 
+/**
+ * gtk_binding_set_by_class:
+ * @object_class: a valid #GtkObject class
+ *
+ * This function returns the binding set named after the type name of
+ * the passed in class structure. New binding sets are created on
+ * demand by this function.
+ *
+ * Return value: the binding set corresponding to @object_class
+ */
 GtkBindingSet*
 gtk_binding_set_by_class (gpointer object_class)
 {
@@ -586,18 +618,28 @@ gtk_binding_set_by_class (gpointer object_class)
   if (binding_set)
     return binding_set;
 
-  binding_set = gtk_binding_set_new (gtk_type_name (GTK_CLASS_TYPE (class)));
+  binding_set = gtk_binding_set_new (g_type_name (G_OBJECT_CLASS_TYPE (class)));
   gtk_binding_set_add_path (binding_set,
                            GTK_PATH_CLASS,
-                           gtk_type_name (GTK_CLASS_TYPE (class)),
+                           g_type_name (G_OBJECT_CLASS_TYPE (class)),
                            GTK_PATH_PRIO_GTK);
   g_dataset_id_set_data (class, key_id_class_binding_set, binding_set);
 
   return binding_set;
 }
 
+/**
+ * gtk_binding_set_find:
+ * @set_name: unique binding set name
+ *
+ * Find a binding set by its globally unique name. The @set_name can
+ * either be a name used for gtk_binding_set_new() or the type name of
+ * a class used in gtk_binding_set_by_class().
+ *
+ * Return value: %NULL or the specified binding set
+ */
 GtkBindingSet*
-gtk_binding_set_find (const gchar    *set_name)
+gtk_binding_set_find (const gchar *set_name)
 {
   GSList *slist;
   
@@ -614,6 +656,18 @@ gtk_binding_set_find (const gchar    *set_name)
   return NULL;
 }
 
+/**
+ * gtk_binding_set_activate:
+ * @binding_set: a #GtkBindingSet set to activate
+ * @keyval:      key value of the binding
+ * @modifiers:   key modifier of the binding
+ * @object:      object to activate when binding found
+ *
+ * Find a key binding matching @keyval and @modifiers within
+ * @binding_set and activate the binding on @object.
+ *
+ * Return value: %TRUE if a binding was found and activated
+ */
 gboolean
 gtk_binding_set_activate (GtkBindingSet         *binding_set,
                          guint           keyval,
@@ -635,25 +689,64 @@ gtk_binding_set_activate (GtkBindingSet    *binding_set,
   return FALSE;
 }
 
+static void
+gtk_binding_entry_clear_internal (GtkBindingSet  *binding_set,
+                                  guint           keyval,
+                                  GdkModifierType modifiers)
+{
+  GtkBindingEntry *entry;
+
+  keyval = gdk_keyval_to_lower (keyval);
+  modifiers = modifiers & BINDING_MOD_MASK ();
+
+  entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
+  if (entry)
+    binding_entry_destroy (entry);
+
+  entry = binding_entry_new (binding_set, keyval, modifiers);
+}
+
+/**
+ * gtk_binding_entry_skip:
+ * @binding_set: a #GtkBindingSet to skip an entry of
+ * @keyval:      key value of binding to skip
+ * @modifiers:   key modifier of binding to skip
+ *
+ * Install a binding on @binding_set which causes key lookups
+ * to be aborted, to prevent bindings from lower priority sets
+ * to be activated.
+ *
+ * Since: 2.12
+ */
 void
-gtk_binding_entry_clear (GtkBindingSet *binding_set,
-                        guint           keyval,
-                        GdkModifierType modifiers)
+gtk_binding_entry_skip (GtkBindingSet  *binding_set,
+                        guint           keyval,
+                        GdkModifierType modifiers)
 {
   GtkBindingEntry *entry;
-  
+
   g_return_if_fail (binding_set != NULL);
-  
+
   keyval = gdk_keyval_to_lower (keyval);
   modifiers = modifiers & BINDING_MOD_MASK ();
-  
+
   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
   if (entry)
     binding_entry_destroy (entry);
 
   entry = binding_entry_new (binding_set, keyval, modifiers);
+  entry->marks_unbound = TRUE;
 }
 
+/**
+ * gtk_binding_entry_remove:
+ * @binding_set: a #GtkBindingSet to remove an entry of
+ * @keyval:      key value of binding to remove
+ * @modifiers:   key modifier of binding to remove
+ *
+ * Remove a binding previously installed via
+ * gtk_binding_entry_add_signal() on @binding_set.
+ */
 void
 gtk_binding_entry_remove (GtkBindingSet         *binding_set,
                          guint           keyval,
@@ -671,12 +764,35 @@ gtk_binding_entry_remove (GtkBindingSet    *binding_set,
     binding_entry_destroy (entry);
 }
 
+/**
+ * gtk_binding_entry_add_signall:
+ * @binding_set:  a #GtkBindingSet to add a signal to
+ * @keyval:       key value
+ * @modifiers:    key modifier
+ * @signal_name:  signal name to be bound
+ * @binding_args: list of #GtkBindingArg signal arguments
+ *
+ * Override or install a new key binding for @keyval with @modifiers on
+ * @binding_set.
+ */
 void
 gtk_binding_entry_add_signall (GtkBindingSet  *binding_set,
-                              guint           keyval,
-                              GdkModifierType modifiers,
-                              const gchar    *signal_name,
-                              GSList         *binding_args)
+                               guint          keyval,
+                               GdkModifierType modifiers,
+                               const gchar    *signal_name,
+                               GSList        *binding_args)
+{
+  _gtk_binding_entry_add_signall (binding_set,
+                                  keyval, modifiers,
+                                  signal_name, binding_args);
+}
+
+void
+_gtk_binding_entry_add_signall (GtkBindingSet  *binding_set,
+                                guint         keyval,
+                                GdkModifierType modifiers,
+                                const gchar    *signal_name,
+                                GSList       *binding_args)
 {
   GtkBindingEntry *entry;
   GtkBindingSignal *signal, **signal_p;
@@ -704,19 +820,19 @@ gtk_binding_entry_add_signall (GtkBindingSet  *binding_set,
          binding_signal_free (signal);
          return;
        }
-      switch (GTK_FUNDAMENTAL_TYPE (tmp_arg->arg_type))
+      switch (G_TYPE_FUNDAMENTAL (tmp_arg->arg_type))
        {
-       case  GTK_TYPE_LONG:
-         arg->arg_type = GTK_TYPE_LONG;
+       case  G_TYPE_LONG:
+         arg->arg_type = G_TYPE_LONG;
          arg->d.long_data = tmp_arg->d.long_data;
          break;
-       case  GTK_TYPE_DOUBLE:
-         arg->arg_type = GTK_TYPE_DOUBLE;
+       case  G_TYPE_DOUBLE:
+         arg->arg_type = G_TYPE_DOUBLE;
          arg->d.double_data = tmp_arg->d.double_data;
          break;
-       case  GTK_TYPE_STRING:
+       case  G_TYPE_STRING:
           if (tmp_arg->arg_type != GTK_TYPE_IDENTIFIER)
-           arg->arg_type = GTK_TYPE_STRING;
+           arg->arg_type = G_TYPE_STRING;
          else
            arg->arg_type = GTK_TYPE_IDENTIFIER;
          arg->d.string_data = g_strdup (tmp_arg->d.string_data);
@@ -729,7 +845,7 @@ gtk_binding_entry_add_signall (GtkBindingSet  *binding_set,
          break;
        default:
          g_warning ("gtk_binding_entry_add_signall(): unsupported type `%s' for arg[%u]",
-                    gtk_type_name (arg->arg_type), n);
+                    g_type_name (arg->arg_type), n);
          binding_signal_free (signal);
          return;
        }
@@ -740,7 +856,7 @@ gtk_binding_entry_add_signall (GtkBindingSet  *binding_set,
   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
   if (!entry)
     {
-      gtk_binding_entry_add (binding_set, keyval, modifiers);
+      gtk_binding_entry_clear_internal (binding_set, keyval, modifiers);
       entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
     }
   signal_p = &entry->signals;
@@ -749,6 +865,20 @@ gtk_binding_entry_add_signall (GtkBindingSet  *binding_set,
   *signal_p = signal;
 }
 
+/**
+ * gtk_binding_entry_add_signal:
+ * @binding_set: a #GtkBindingSet to install an entry for
+ * @keyval:      key value of binding to install
+ * @modifiers:   key modifier of binding to install
+ * @signal_name: signal to execute upon activation
+ * @n_args:      number of arguments to @signal_name
+ * @Varargs:     arguments to @signal_name
+ *
+ * Override or install a new key binding for @keyval with @modifiers on
+ * @binding_set. When the binding is activated, @signal_name will be
+ * emitted on the target widget, with @n_args @Varargs used as
+ * arguments.
+ */
 void
 gtk_binding_entry_add_signal (GtkBindingSet  *binding_set,
                              guint           keyval,
@@ -764,59 +894,53 @@ gtk_binding_entry_add_signal (GtkBindingSet  *binding_set,
   g_return_if_fail (binding_set != NULL);
   g_return_if_fail (signal_name != NULL);
   
-  keyval = gdk_keyval_to_lower (keyval);
-  modifiers = modifiers & BINDING_MOD_MASK ();
-
   va_start (args, n_args);
   slist = NULL;
   for (i = 0; i < n_args; i++)
     {
       GtkBindingArg *arg;
 
-      arg = g_new0 (GtkBindingArg, 1);
+      arg = g_slice_new0 (GtkBindingArg);
       slist = g_slist_prepend (slist, arg);
 
-      arg->arg_type = va_arg (args, GtkType);
-      switch (GTK_FUNDAMENTAL_TYPE (arg->arg_type))
+      arg->arg_type = va_arg (args, GType);
+      switch (G_TYPE_FUNDAMENTAL (arg->arg_type))
        {
-         /* for elaborated commenting about var args collection, take a look
-          * at gtk_arg_collect_value() in gtkargcollector.c
-          */
-       case GTK_TYPE_CHAR:
-       case GTK_TYPE_UCHAR:
-       case GTK_TYPE_INT:
-       case GTK_TYPE_UINT:
-       case GTK_TYPE_BOOL:
-       case GTK_TYPE_ENUM:
-       case GTK_TYPE_FLAGS:
-         arg->arg_type = GTK_TYPE_LONG;
+       case G_TYPE_CHAR:
+       case G_TYPE_UCHAR:
+       case G_TYPE_INT:
+       case G_TYPE_UINT:
+       case G_TYPE_BOOLEAN:
+       case G_TYPE_ENUM:
+       case G_TYPE_FLAGS:
+         arg->arg_type = G_TYPE_LONG;
          arg->d.long_data = va_arg (args, gint);
          break;
-       case GTK_TYPE_LONG:
-       case GTK_TYPE_ULONG:
-         arg->arg_type = GTK_TYPE_LONG;
+       case G_TYPE_LONG:
+       case G_TYPE_ULONG:
+         arg->arg_type = G_TYPE_LONG;
          arg->d.long_data = va_arg (args, glong);
          break;
-       case GTK_TYPE_FLOAT:
-       case GTK_TYPE_DOUBLE:
-         arg->arg_type = GTK_TYPE_DOUBLE;
+       case G_TYPE_FLOAT:
+       case G_TYPE_DOUBLE:
+         arg->arg_type = G_TYPE_DOUBLE;
          arg->d.double_data = va_arg (args, gdouble);
          break;
-       case GTK_TYPE_STRING:
+       case G_TYPE_STRING:
          if (arg->arg_type != GTK_TYPE_IDENTIFIER)
-           arg->arg_type = GTK_TYPE_STRING;
+           arg->arg_type = G_TYPE_STRING;
          arg->d.string_data = va_arg (args, gchar*);
          if (!arg->d.string_data)
            {
              g_warning ("gtk_binding_entry_add_signal(): type `%s' arg[%u] is `NULL'",
-                        gtk_type_name (arg->arg_type),
+                        g_type_name (arg->arg_type),
                         i);
              i += n_args + 1;
            }
          break;
        default:
          g_warning ("gtk_binding_entry_add_signal(): unsupported type `%s' for arg[%u]",
-                    gtk_type_name (arg->arg_type), i);
+                    g_type_name (arg->arg_type), i);
          i += n_args + 1;
          break;
        }
@@ -826,18 +950,28 @@ gtk_binding_entry_add_signal (GtkBindingSet  *binding_set,
   if (i == n_args || i == 0)
     {
       slist = g_slist_reverse (slist);
-      gtk_binding_entry_add_signall (binding_set, keyval, modifiers, signal_name, slist);
+      _gtk_binding_entry_add_signall (binding_set, keyval, modifiers, signal_name, slist);
     }
 
   free_slist = slist;
   while (slist)
     {
-      g_free (slist->data);
+      g_slice_free (GtkBindingArg, slist->data);
       slist = slist->next;
     }
   g_slist_free (free_slist);
 }
 
+/**
+ * gtk_binding_set_add_path:
+ * @binding_set:  a #GtkBindingSet to add a path to
+ * @path_type:    path type the pattern applies to
+ * @path_pattern: the actual match pattern
+ * @priority:     binding priority
+ *
+ * This function is used internally by the GtkRC parsing mechanism to
+ * assign match patterns to #GtkBindingSet structures.
+ */
 void
 gtk_binding_set_add_path (GtkBindingSet             *binding_set,
                          GtkPathType         path_type,
@@ -872,7 +1006,18 @@ gtk_binding_set_add_path (GtkBindingSet        *binding_set,
     }
   
   pspec = g_new (PatternSpec, 1);
-  pspec->pspec = g_pattern_spec_new (path_pattern);
+  pspec->type = path_type;
+  if (path_type == GTK_PATH_WIDGET_CLASS)
+    {
+      pspec->pspec = NULL;
+      pspec->path = _gtk_rc_parse_widget_class_path (path_pattern);
+    }
+  else
+    {
+      pspec->pspec = g_pattern_spec_new (path_pattern);
+      pspec->path = NULL;
+    }
+    
   pspec->seq_id = priority << 28;
   pspec->user_data = binding_set;
   
@@ -888,8 +1033,7 @@ gtk_binding_set_add_path (GtkBindingSet         *binding_set,
        {
          GtkPathPriorityType lprio = tmp_pspec->seq_id >> 28;
 
-         g_pattern_spec_free (pspec->pspec);
-         g_free (pspec);
+         pattern_spec_free (pspec);
          pspec = NULL;
          if (lprio < priority)
            {
@@ -910,25 +1054,44 @@ static gboolean
 binding_match_activate (GSList          *pspec_list,
                        GtkObject       *object,
                        guint            path_length,
-                       const gchar     *path,
-                       const gchar     *path_reversed)
+                       gchar           *path,
+                       gchar           *path_reversed,
+                        gboolean        *unbound)
 {
   GSList *slist;
 
+  *unbound = FALSE;
+
   for (slist = pspec_list; slist; slist = slist->next)
     {
       PatternSpec *pspec;
+      GtkBindingSet *binding_set;
 
+      binding_set = NULL;
       pspec = slist->data;
-      if (g_pattern_match (pspec->pspec, path_length, path, path_reversed))
-       {
-         GtkBindingSet *binding_set;
-
-         binding_set = pspec->user_data;
-
-         if (gtk_binding_entry_activate (binding_set->current, object))
-           return TRUE;
-       }
+      
+      if (pspec->type == GTK_PATH_WIDGET_CLASS)
+        {
+          if (_gtk_rc_match_widget_class (pspec->path, path_length, path, path_reversed))
+           binding_set = pspec->user_data;
+        }
+      else
+        {
+          if (g_pattern_match (pspec->pspec, path_length, path, path_reversed))
+           binding_set = pspec->user_data;
+        }
+
+      if (binding_set)
+        {
+          if (binding_set->current->marks_unbound)
+            {
+              *unbound = TRUE;
+              return FALSE;
+            }
+
+          if (gtk_binding_entry_activate (binding_set->current, object))
+            return TRUE;
+        }
     }
 
   return FALSE;
@@ -954,8 +1117,18 @@ gtk_binding_entries_sort_patterns (GSList      *entries,
                                   gboolean     is_release)
 {
   GSList *patterns;
+  GSList *tmp_list;
 
   patterns = NULL;
+  for (tmp_list = entries; tmp_list; tmp_list = tmp_list->next)
+    {
+      GtkBindingEntry *entry = tmp_list->data;
+      GtkBindingSet *binding_set;
+
+      binding_set = entry->binding_set;
+      binding_set->current = NULL;
+    }
+  
   for (; entries; entries = entries->next)
     {
       GtkBindingEntry *entry = entries->data;
@@ -966,6 +1139,9 @@ gtk_binding_entries_sort_patterns (GSList      *entries,
        continue;
 
       binding_set = entry->binding_set;
+
+      if (binding_set->current)
+       continue;
       binding_set->current = entry;
 
       switch (path_id)
@@ -1009,13 +1185,17 @@ gtk_bindings_activate_list (GtkObject *object,
       guint path_length;
       gchar *path, *path_reversed;
       GSList *patterns;
+      gboolean unbound;
 
       gtk_widget_path (widget, &path_length, &path, &path_reversed);
       patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET, is_release);
-      handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
+      handled = binding_match_activate (patterns, object, path_length, path, path_reversed, &unbound);
       g_slist_free (patterns);
       g_free (path);
       g_free (path_reversed);
+
+      if (unbound)
+        return FALSE;
     }
 
   if (!handled)
@@ -1023,49 +1203,73 @@ gtk_bindings_activate_list (GtkObject *object,
       guint path_length;
       gchar *path, *path_reversed;
       GSList *patterns;
+      gboolean unbound;
 
       gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
       patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET_CLASS, is_release);
-      handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
+      handled = binding_match_activate (patterns, object, path_length, path, path_reversed, &unbound);
       g_slist_free (patterns);
       g_free (path);
       g_free (path_reversed);
+
+      if (unbound)
+        return FALSE;
     }
 
   if (!handled)
     {
       GSList *patterns;
-      GtkType class_type;
-      
+      GType class_type;
+      gboolean unbound = FALSE;
+
       patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_CLASS, is_release);
-      class_type = GTK_OBJECT_TYPE (object);
+      class_type = G_TYPE_FROM_INSTANCE (object);
       while (class_type && !handled)
        {
          guint path_length;
-         const gchar *path;
+         gchar *path;
          gchar *path_reversed;
-         
-         path = gtk_type_name (class_type);
+
+         path = g_strdup (g_type_name (class_type));
          path_reversed = g_strdup (path);
          g_strreverse (path_reversed);
          path_length = strlen (path);
-         handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
+         handled = binding_match_activate (patterns, object, path_length, path, path_reversed, &unbound);
+         g_free (path);
          g_free (path_reversed);
 
-         class_type = gtk_type_parent (class_type);
+          if (unbound)
+            break;
+
+         class_type = g_type_parent (class_type);
        }
       g_slist_free (patterns);
+
+      if (unbound)
+        return FALSE;
     }
 
   return handled;
 }
 
+/**
+ * gtk_bindings_activate:
+ * @object: object to activate when binding found
+ * @keyval: key value of the binding
+ * @modifiers: key modifier of the binding
+ *
+ * Find a key binding matching @keyval and @modifiers and activate the
+ * binding on @object.
+ *
+ * Return value: %TRUE if a binding was found and activated
+ */
 gboolean
-gtk_bindings_activate (GtkObject      *object,
-                      guint           keyval,
-                      GdkModifierType modifiers)
+gtk_bindings_activate (GtkObject       *object,
+                      guint            keyval,
+                      GdkModifierType  modifiers)
 {
   GSList *entries = NULL;
+  GdkDisplay *display;
   GtkKeyHash *key_hash;
   gboolean handled = FALSE;
   gboolean is_release;
@@ -1075,10 +1279,12 @@ gtk_bindings_activate (GtkObject      *object,
   if (!GTK_IS_WIDGET (object))
     return FALSE;
 
-  is_release = (BINDING_MOD_MASK () & GDK_RELEASE_MASK) != 0;
+  is_release = (modifiers & GDK_RELEASE_MASK) != 0;
   modifiers = modifiers & BINDING_MOD_MASK () & ~GDK_RELEASE_MASK;
 
-  key_hash = binding_key_hash_for_keymap (gdk_keymap_get_default ());
+  display = gtk_widget_get_display (GTK_WIDGET (object));
+  key_hash = binding_key_hash_for_keymap (gdk_keymap_get_for_display (display));
+  
   entries = _gtk_key_hash_lookup_keyval (key_hash, keyval, modifiers);
 
   handled = gtk_bindings_activate_list (object, entries, is_release);
@@ -1089,7 +1295,7 @@ gtk_bindings_activate (GtkObject      *object,
 }
 
 /**
- * _gtk_bindings_activate_event:
+ * gtk_bindings_activate_event:
  * @object: a #GtkObject (generally must be a widget)
  * @event: a #GdkEventKey
  * 
@@ -1097,12 +1303,15 @@ gtk_bindings_activate (GtkObject      *object,
  * @event, and if one was found, activate it.
  * 
  * Return value: %TRUE if a matching key binding was found
- **/
+ *
+ * Since: 2.4
+ */
 gboolean
-_gtk_bindings_activate_event (GtkObject      *object,
-                             GdkEventKey    *event)
+gtk_bindings_activate_event (GtkObject   *object,
+                             GdkEventKey *event)
 {
   GSList *entries = NULL;
+  GdkDisplay *display;
   GtkKeyHash *key_hash;
   gboolean handled = FALSE;
 
@@ -1111,10 +1320,13 @@ _gtk_bindings_activate_event (GtkObject      *object,
   if (!GTK_IS_WIDGET (object))
     return FALSE;
 
-  key_hash = binding_key_hash_for_keymap (gdk_keymap_get_default ());
+  display = gtk_widget_get_display (GTK_WIDGET (object));
+  key_hash = binding_key_hash_for_keymap (gdk_keymap_get_for_display (display));
+
   entries = _gtk_key_hash_lookup (key_hash,
                                  event->hardware_keycode,
-                                 event->state & BINDING_MOD_MASK () & ~GDK_RELEASE_MASK,
+                                 event->state,
+                                 BINDING_MOD_MASK () & ~GDK_RELEASE_MASK,
                                  event->group);
   
   handled = gtk_bindings_activate_list (object, entries,
@@ -1176,7 +1388,7 @@ gtk_binding_parse_signal (GScanner       *scanner,
            {
              need_arg = FALSE;
              arg = g_new (GtkBindingArg, 1);
-             arg->arg_type = GTK_TYPE_DOUBLE;
+             arg->arg_type = G_TYPE_DOUBLE;
              arg->d.double_data = scanner->value.v_float;
              if (negate)
                {
@@ -1193,7 +1405,7 @@ gtk_binding_parse_signal (GScanner       *scanner,
            {
              need_arg = FALSE;
              arg = g_new (GtkBindingArg, 1);
-             arg->arg_type = GTK_TYPE_LONG;
+             arg->arg_type = G_TYPE_LONG;
              arg->d.long_data = scanner->value.v_int;
              if (negate)
                {
@@ -1210,7 +1422,7 @@ gtk_binding_parse_signal (GScanner       *scanner,
            {
              need_arg = FALSE;
              arg = g_new (GtkBindingArg, 1);
-             arg->arg_type = GTK_TYPE_STRING;
+             arg->arg_type = G_TYPE_STRING;
              arg->d.string_data = g_strdup (scanner->value.v_string);
              args = g_slist_prepend (args, arg);
            }
@@ -1251,11 +1463,11 @@ gtk_binding_parse_signal (GScanner       *scanner,
          if (!(need_arg && seen_comma) && !negate)
            {
              args = g_slist_reverse (args);
-             gtk_binding_entry_add_signall (binding_set,
-                                            keyval,
-                                            modifiers,
-                                            signal,
-                                            args);
+             _gtk_binding_entry_add_signall (binding_set,
+                                              keyval,
+                                              modifiers,
+                                              signal,
+                                              args);
              expected_token = G_TOKEN_NONE;
            }
          done = TRUE;
@@ -1273,7 +1485,7 @@ gtk_binding_parse_signal (GScanner       *scanner,
       GtkBindingArg *arg;
 
       arg = slist->data;
-      if (GTK_FUNDAMENTAL_TYPE (arg->arg_type) == GTK_TYPE_STRING)
+      if (G_TYPE_FUNDAMENTAL (arg->arg_type) == G_TYPE_STRING)
        g_free (arg->d.string_data);
       g_free (arg);
     }
@@ -1289,12 +1501,15 @@ gtk_binding_parse_bind (GScanner       *scanner,
 {
   guint keyval = 0;
   GdkModifierType modifiers = 0;
+  gboolean unbind = FALSE;
 
   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
   
   g_scanner_get_next_token (scanner);
-  if (scanner->token != GTK_RC_TOKEN_BIND)
+  if (scanner->token != GTK_RC_TOKEN_BIND &&
+      scanner->token != GTK_RC_TOKEN_UNBIND)
     return GTK_RC_TOKEN_BIND;
+  unbind = scanner->token == GTK_RC_TOKEN_UNBIND;
   g_scanner_get_next_token (scanner);
   if (scanner->token != G_TOKEN_STRING)
     return G_TOKEN_STRING;
@@ -1303,12 +1518,19 @@ gtk_binding_parse_bind (GScanner       *scanner,
   if (keyval == 0)
     return G_TOKEN_STRING;
 
+  if (unbind)
+    {
+      gtk_binding_entry_skip (binding_set, keyval, modifiers);
+      return G_TOKEN_NONE;
+    }
+
   g_scanner_get_next_token (scanner);
+
   if (scanner->token != '{')
     return '{';
 
-  gtk_binding_entry_clear (binding_set, keyval, modifiers);
-  
+  gtk_binding_entry_clear_internal (binding_set, keyval, modifiers);
+
   g_scanner_peek_next_token (scanner);
   while (scanner->next_token != '}')
     {
@@ -1336,7 +1558,7 @@ gtk_binding_parse_bind (GScanner       *scanner,
 }
 
 guint
-gtk_binding_parse_binding (GScanner       *scanner)
+_gtk_binding_parse_binding (GScanner *scanner)
 {
   gchar *name;
   GtkBindingSet *binding_set;
@@ -1374,6 +1596,7 @@ gtk_binding_parse_binding (GScanner       *scanner)
          guint expected_token;
 
        case GTK_RC_TOKEN_BIND:
+       case GTK_RC_TOKEN_UNBIND:
          expected_token = gtk_binding_parse_bind (scanner, binding_set);
          if (expected_token != G_TOKEN_NONE)
            return expected_token;
@@ -1400,8 +1623,7 @@ free_pattern_specs (GSList *pattern_specs)
 
       pspec = slist->data;
 
-      g_pattern_spec_free (pspec->pspec);
-      g_free (pspec);
+      pattern_spec_free (pspec);
     }
 
   g_slist_free (pattern_specs);
@@ -1424,16 +1646,14 @@ binding_set_delete (GtkBindingSet *binding_set)
   free_pattern_specs (binding_set->widget_class_pspecs);
   free_pattern_specs (binding_set->class_branch_pspecs);
 
-  g_free (binding_set->set_name);
   g_free (binding_set);
 }
 
 /**
  * _gtk_binding_reset_parsed:
  * 
- * Removing all binding sets that were added by
- * gtk_binding_parse_binding()
- **/
+ * Remove all binding sets that were added by gtk_binding_parse_binding().
+ */
 void
 _gtk_binding_reset_parsed (void)
 {
@@ -1456,3 +1676,6 @@ _gtk_binding_reset_parsed (void)
       slist = next;
     }
 }
+
+#define __GTK_BINDINGS_C__
+#include "gtkaliasdef.c"