]> Pileus Git - ~andy/gtk/blob - gtk/gtkbindings.c
5c5144cb9be35d109fcb9a9a38b4de44175b9e78
[~andy/gtk] / gtk / gtkbindings.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * GtkBindingSet: Keybinding manager for GObjects.
5  * Copyright (C) 1998 Tim Janik
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /*
24  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
25  * file for a list of people on the GTK+ Team.  See the ChangeLog
26  * files for a list of changes.  These files are distributed with
27  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
28  */
29
30 #include "config.h"
31 #include <string.h>
32 #include <stdarg.h>
33
34 #include "gtkbindingsprivate.h"
35 #include "gtkkeyhash.h"
36 #include "gtkwidget.h"
37 #include "gtkintl.h"
38
39 /**
40  * SECTION:gtkbindings
41  * @Title: Bindings
42  * @Short_description: Key bindings for individual widgets
43  * @See_also: Keyboard Accelerators, Mnemonics, #GtkCssProvider
44  *
45  * #GtkBindingSet provides a mechanism for configuring GTK+ key bindings
46  * through CSS files. This eases key binding adjustments for application
47  * developers as well as users and provides GTK+ users or administrators
48  * with high key  binding configurability which requires no application
49  * or toolkit side changes.
50  *
51  * <refsect2 id="gtk-bindings-install">
52  * <title>Installing a key binding</title>
53  * <para>
54  * A CSS file binding consists of a 'binding-set' definition and a match
55  * statement to apply the binding set to specific widget types. Details
56  * on the matching mechanism are described under
57  * <link linkend="gtkcssprovider-selectors">Selectors</link>
58  * in the #GtkCssProvider documentation. Inside the binding set definition,
59  * key combinations are bound to one or more specific signal emissions on
60  * the target widget. Key combinations are strings consisting of an optional
61  * #GdkModifierType name and <link linkend="gdk-Keyboard-Handling">key names</link>
62  * such as those defined in <filename>&lt;gdk/gdkkeysyms.h&gt;</filename>
63  * or returned from gdk_keyval_name(), they have to be parsable by
64  * gtk_accelerator_parse(). Specifications of signal emissions consist
65  * of a string identifying the signal name, and a list of signal specific
66  * arguments in parenthesis.
67  * </para>
68  * <para>
69  * For example for binding Control and the left or right cursor keys
70  * of a #GtkEntry widget to the #GtkEntry::move-cursor signal (so movement
71  * occurs in 3-character steps), the following binding can be used:
72  * <informalexample><programlisting>
73  * @binding-set MoveCursor3
74  * {
75  *   bind "&lt;Control&gt;Right" { "move-cursor" (visual-positions, 3, 0) };
76  *   bind "&lt;Control&gt;Left" { "move-cursor" (visual-positions, -3, 0) };
77  * };
78  * GtkEntry
79  * {
80  *   gtk-key-bindings: MoveCursor3
81  * }
82  * </programlisting></informalexample>
83  * </para>
84  * </refsect2>
85  * <refsect2 id="gtk-bindings-unbind">
86  * <title>Unbinding existing key bindings</title>
87  * <para>
88  * GTK+ already defines a number of useful bindings for the widgets
89  * it provides. Because custom bindings set up in CSS files take
90  * precedence over the default bindings shipped with GTK+, overriding
91  * existing bindings as demonstrated in
92  * <link linkend="gtk-bindings-install">Installing a key binding</link>
93  * works as expected. The same mechanism can not be used to "unbind"
94  * existing bindings, however.
95  * <informalexample><programlisting>
96  * @binding-set MoveCursor3
97  * {
98  *   bind "&lt;Control&gt;Right" {  };
99  *   bind "&lt;Control&gt;Left" {  };
100  * };
101  * GtkEntry
102  * {
103  *   gtk-key-bindings: MoveCursor3
104  * }
105  * </programlisting></informalexample>
106  * The above example will not have the desired effect of causing
107  * "&lt;Control&gt;Right" and "&lt;Control&gt;Left" key presses to
108  * be ignored by GTK+. Instead, it just causes any existing bindings
109  * from the bindings set "MoveCursor3" to be deleted, so when
110  * "&lt;Control&gt;Right" or "&lt;Control&gt;Left" are pressed, no
111  * binding for these keys is found in binding set "MoveCursor3".
112  * GTK+ will thus continue to search for matching key bindings, and will
113  * eventually lookup and find the default GTK+ bindings for entries which
114  * implement word movement. To keep GTK+ from activating its default
115  * bindings, the "unbind" keyword can be used like this:
116  * <informalexample><programlisting>
117  * @binding-set MoveCursor3
118  * {
119  *   unbind "&lt;Control&gt;Right";
120  *   unbind "&lt;Control&gt;Left";
121  * };
122  * GtkEntry
123  * {
124  *   gtk-key-bindings: MoveCursor3
125  * }
126  * </programlisting></informalexample>
127  * Now, GTK+ will find a match when looking up "&lt;Control&gt;Right"
128  * and "&lt;Control&gt;Left" key presses before it resorts to its default
129  * bindings, and the match instructs it to abort ("unbind") the search,
130  * so the key presses are not consumed by this widget. As usual, further
131  * processing of the key presses, e.g. by an entry's parent widget, is
132  * now possible.
133  * </para>
134  * </refsect2>
135  */
136
137 /* --- defines --- */
138 #define BINDING_MOD_MASK() (gtk_accelerator_get_default_mod_mask () | GDK_RELEASE_MASK)
139
140
141 #define GTK_TYPE_IDENTIFIER (gtk_identifier_get_type ())
142 GType gtk_identifier_get_type (void) G_GNUC_CONST;
143
144
145 /* --- structures --- */
146 typedef struct {
147   GtkPathType   type;
148   GPatternSpec *pspec;
149   gpointer      user_data;
150   guint         seq_id;
151 } PatternSpec;
152
153 typedef enum {
154   GTK_BINDING_TOKEN_BIND,
155   GTK_BINDING_TOKEN_UNBIND
156 } GtkBindingTokens;
157
158 /* --- variables --- */
159 static GHashTable       *binding_entry_hash_table = NULL;
160 static GSList           *binding_key_hashes = NULL;
161 static GSList           *binding_set_list = NULL;
162 static const gchar       key_class_binding_set[] = "gtk-class-binding-set";
163 static GQuark            key_id_class_binding_set = 0;
164
165
166 /* --- functions --- */
167 GType
168 gtk_identifier_get_type (void)
169 {
170   static GType our_type = 0;
171
172   if (our_type == 0)
173     {
174       GTypeInfo tinfo = { 0, };
175       our_type = g_type_register_static (G_TYPE_STRING, I_("GtkIdentifier"), &tinfo, 0);
176     }
177
178   return our_type;
179 }
180
181 static void
182 pattern_spec_free (PatternSpec *pspec)
183 {
184   if (pspec->pspec)
185     g_pattern_spec_free (pspec->pspec);
186   g_free (pspec);
187 }
188
189 static GtkBindingSignal*
190 binding_signal_new (const gchar *signal_name,
191                     guint        n_args)
192 {
193   GtkBindingSignal *signal;
194
195   signal = (GtkBindingSignal *) g_slice_alloc0 (sizeof (GtkBindingSignal) + n_args * sizeof (GtkBindingArg));
196   signal->next = NULL;
197   signal->signal_name = (gchar *)g_intern_string (signal_name);
198   signal->n_args = n_args;
199   signal->args = (GtkBindingArg *)(signal + 1);
200
201   return signal;
202 }
203
204 static void
205 binding_signal_free (GtkBindingSignal *sig)
206 {
207   guint i;
208
209   for (i = 0; i < sig->n_args; i++)
210     {
211       if (G_TYPE_FUNDAMENTAL (sig->args[i].arg_type) == G_TYPE_STRING)
212         g_free (sig->args[i].d.string_data);
213     }
214   g_slice_free1 (sizeof (GtkBindingSignal) + sig->n_args * sizeof (GtkBindingArg), sig);
215 }
216
217 static guint
218 binding_entry_hash (gconstpointer  key)
219 {
220   register const GtkBindingEntry *e = key;
221   register guint h;
222
223   h = e->keyval;
224   h ^= e->modifiers;
225
226   return h;
227 }
228
229 static gint
230 binding_entries_compare (gconstpointer  a,
231                          gconstpointer  b)
232 {
233   register const GtkBindingEntry *ea = a;
234   register const GtkBindingEntry *eb = b;
235
236   return (ea->keyval == eb->keyval && ea->modifiers == eb->modifiers);
237 }
238
239 static void
240 binding_key_hash_insert_entry (GtkKeyHash      *key_hash,
241                                GtkBindingEntry *entry)
242 {
243   guint keyval = entry->keyval;
244
245   /* We store lowercased accelerators. To deal with this, if <Shift>
246    * was specified, uppercase.
247    */
248   if (entry->modifiers & GDK_SHIFT_MASK)
249     {
250       if (keyval == GDK_KEY_Tab)
251         keyval = GDK_KEY_ISO_Left_Tab;
252       else
253         keyval = gdk_keyval_to_upper (keyval);
254     }
255
256   _gtk_key_hash_add_entry (key_hash, keyval, entry->modifiers & ~GDK_RELEASE_MASK, entry);
257 }
258
259 static void
260 binding_key_hash_destroy (gpointer data)
261 {
262   GtkKeyHash *key_hash = data;
263
264   binding_key_hashes = g_slist_remove (binding_key_hashes, key_hash);
265   _gtk_key_hash_free (key_hash);
266 }
267
268 static void
269 insert_entries_into_key_hash (gpointer key,
270                               gpointer value,
271                               gpointer data)
272 {
273   GtkKeyHash *key_hash = data;
274   GtkBindingEntry *entry = value;
275
276   for (; entry; entry = entry->hash_next)
277     binding_key_hash_insert_entry (key_hash, entry);
278 }
279
280 static GtkKeyHash *
281 binding_key_hash_for_keymap (GdkKeymap *keymap)
282 {
283   static GQuark key_hash_quark = 0;
284   GtkKeyHash *key_hash;
285
286   if (!key_hash_quark)
287     key_hash_quark = g_quark_from_static_string ("gtk-binding-key-hash");
288
289   key_hash = g_object_get_qdata (G_OBJECT (keymap), key_hash_quark);
290
291   if (!key_hash)
292     {
293       key_hash = _gtk_key_hash_new (keymap, NULL);
294       g_object_set_qdata_full (G_OBJECT (keymap), key_hash_quark, key_hash, binding_key_hash_destroy);
295
296       if (binding_entry_hash_table)
297         g_hash_table_foreach (binding_entry_hash_table,
298                               insert_entries_into_key_hash,
299                               key_hash);
300
301       binding_key_hashes = g_slist_prepend (binding_key_hashes, key_hash);
302     }
303
304   return key_hash;
305 }
306
307
308 static GtkBindingEntry*
309 binding_entry_new (GtkBindingSet  *binding_set,
310                    guint           keyval,
311                    GdkModifierType modifiers)
312 {
313   GSList *tmp_list;
314   GtkBindingEntry *entry;
315
316   if (!binding_entry_hash_table)
317     binding_entry_hash_table = g_hash_table_new (binding_entry_hash, binding_entries_compare);
318
319   entry = g_new (GtkBindingEntry, 1);
320   entry->keyval = keyval;
321   entry->modifiers = modifiers;
322   entry->binding_set = binding_set,
323   entry->destroyed = FALSE;
324   entry->in_emission = FALSE;
325   entry->marks_unbound = FALSE;
326   entry->signals = NULL;
327
328   entry->set_next = binding_set->entries;
329   binding_set->entries = entry;
330
331   entry->hash_next = g_hash_table_lookup (binding_entry_hash_table, entry);
332   if (entry->hash_next)
333     g_hash_table_remove (binding_entry_hash_table, entry->hash_next);
334   g_hash_table_insert (binding_entry_hash_table, entry, entry);
335
336   for (tmp_list = binding_key_hashes; tmp_list; tmp_list = tmp_list->next)
337     {
338       GtkKeyHash *key_hash = tmp_list->data;
339       binding_key_hash_insert_entry (key_hash, entry);
340     }
341
342   return entry;
343 }
344
345 static void
346 binding_entry_free (GtkBindingEntry *entry)
347 {
348   GtkBindingSignal *sig;
349
350   g_assert (entry->set_next == NULL &&
351             entry->hash_next == NULL &&
352             entry->in_emission == FALSE &&
353             entry->destroyed == TRUE);
354
355   entry->destroyed = FALSE;
356
357   sig = entry->signals;
358   while (sig)
359     {
360       GtkBindingSignal *prev;
361
362       prev = sig;
363       sig = prev->next;
364       binding_signal_free (prev);
365     }
366   g_free (entry);
367 }
368
369 static void
370 binding_entry_destroy (GtkBindingEntry *entry)
371 {
372   GtkBindingEntry *o_entry;
373   register GtkBindingEntry *tmp;
374   GtkBindingEntry *begin;
375   register GtkBindingEntry *last;
376   GSList *tmp_list;
377
378   /* unlink from binding set
379    */
380   last = NULL;
381   tmp = entry->binding_set->entries;
382   while (tmp)
383     {
384       if (tmp == entry)
385         {
386           if (last)
387             last->set_next = entry->set_next;
388           else
389             entry->binding_set->entries = entry->set_next;
390           break;
391         }
392       last = tmp;
393       tmp = last->set_next;
394     }
395   entry->set_next = NULL;
396
397   o_entry = g_hash_table_lookup (binding_entry_hash_table, entry);
398   begin = o_entry;
399   last = NULL;
400   tmp = begin;
401   while (tmp)
402     {
403       if (tmp == entry)
404         {
405           if (last)
406             last->hash_next = entry->hash_next;
407           else
408             begin = entry->hash_next;
409           break;
410         }
411       last = tmp;
412       tmp = last->hash_next;
413     }
414   entry->hash_next = NULL;
415
416   if (!begin)
417     g_hash_table_remove (binding_entry_hash_table, entry);
418   else if (begin != o_entry)
419     {
420       g_hash_table_remove (binding_entry_hash_table, entry);
421       g_hash_table_insert (binding_entry_hash_table, begin, begin);
422     }
423
424   for (tmp_list = binding_key_hashes; tmp_list; tmp_list = tmp_list->next)
425     {
426       GtkKeyHash *key_hash = tmp_list->data;
427       _gtk_key_hash_remove_entry (key_hash, entry);
428     }
429
430   entry->destroyed = TRUE;
431
432   if (!entry->in_emission)
433     binding_entry_free (entry);
434 }
435
436 static GtkBindingEntry*
437 binding_ht_lookup_entry (GtkBindingSet  *set,
438                          guint           keyval,
439                          GdkModifierType modifiers)
440 {
441   GtkBindingEntry lookup_entry = { 0 };
442   GtkBindingEntry *entry;
443
444   if (!binding_entry_hash_table)
445     return NULL;
446
447   lookup_entry.keyval = keyval;
448   lookup_entry.modifiers = modifiers;
449
450   entry = g_hash_table_lookup (binding_entry_hash_table, &lookup_entry);
451   for (; entry; entry = entry->hash_next)
452     if (entry->binding_set == set)
453       return entry;
454
455   return NULL;
456 }
457
458 static gboolean
459 binding_compose_params (GObject         *object,
460                         GtkBindingArg   *args,
461                         GSignalQuery    *query,
462                         GValue         **params_p)
463 {
464   GValue *params;
465   const GType *types;
466   guint i;
467   gboolean valid;
468
469   params = g_new0 (GValue, query->n_params + 1);
470   *params_p = params;
471
472   /* The instance we emit on is the first object in the array
473    */
474   g_value_init (params, G_TYPE_OBJECT);
475   g_value_set_object (params, G_OBJECT (object));
476   params++;
477
478   types = query->param_types;
479   valid = TRUE;
480   for (i = 1; i < query->n_params + 1 && valid; i++)
481     {
482       GValue tmp_value = G_VALUE_INIT;
483
484       g_value_init (params, *types);
485
486       switch (G_TYPE_FUNDAMENTAL (args->arg_type))
487         {
488         case G_TYPE_DOUBLE:
489           g_value_init (&tmp_value, G_TYPE_DOUBLE);
490           g_value_set_double (&tmp_value, args->d.double_data);
491           break;
492         case G_TYPE_LONG:
493           g_value_init (&tmp_value, G_TYPE_LONG);
494           g_value_set_long (&tmp_value, args->d.long_data);
495           break;
496         case G_TYPE_STRING:
497           /* gtk_rc_parse_flags/enum() has fancier parsing for this; we can't call
498            * that since we don't have a GParamSpec, so just do something simple
499            */
500           if (G_TYPE_FUNDAMENTAL (*types) == G_TYPE_ENUM)
501             {
502               GEnumClass *class = G_ENUM_CLASS (g_type_class_ref (*types));
503
504               valid = FALSE;
505
506               if (args->arg_type == GTK_TYPE_IDENTIFIER)
507                 {
508                   GEnumValue *enum_value = NULL;
509                   enum_value = g_enum_get_value_by_name (class, args->d.string_data);
510                   if (!enum_value)
511                     enum_value = g_enum_get_value_by_nick (class, args->d.string_data);
512                   if (enum_value)
513                     {
514                       g_value_init (&tmp_value, *types);
515                       g_value_set_enum (&tmp_value, enum_value->value);
516                       valid = TRUE;
517                     }
518                 }
519
520               g_type_class_unref (class);
521             }
522           /* This is just a hack for compatibility with GTK+-1.2 where a string
523            * could be used for a single flag value / without the support for multiple
524            * values in gtk_rc_parse_flags(), this isn't very useful.
525            */
526           else if (G_TYPE_FUNDAMENTAL (*types) == G_TYPE_FLAGS)
527             {
528               GFlagsClass *class = G_FLAGS_CLASS (g_type_class_ref (*types));
529
530               valid = FALSE;
531
532               if (args->arg_type == GTK_TYPE_IDENTIFIER)
533                 {
534                   GFlagsValue *flags_value = NULL;
535                   flags_value = g_flags_get_value_by_name (class, args->d.string_data);
536                   if (!flags_value)
537                     flags_value = g_flags_get_value_by_nick (class, args->d.string_data);
538                   if (flags_value)
539                     {
540                       g_value_init (&tmp_value, *types);
541                       g_value_set_flags (&tmp_value, flags_value->value);
542                       valid = TRUE;
543                     }
544                 }
545
546               g_type_class_unref (class);
547             }
548           else
549             {
550               g_value_init (&tmp_value, G_TYPE_STRING);
551               g_value_set_static_string (&tmp_value, args->d.string_data);
552             }
553           break;
554         default:
555           valid = FALSE;
556           break;
557         }
558
559       if (valid)
560         {
561           if (!g_value_transform (&tmp_value, params))
562             valid = FALSE;
563
564           g_value_unset (&tmp_value);
565         }
566
567       types++;
568       params++;
569       args++;
570     }
571
572   if (!valid)
573     {
574       guint j;
575
576       for (j = 0; j < i; j++)
577         g_value_unset (&(*params_p)[j]);
578
579       g_free (*params_p);
580       *params_p = NULL;
581     }
582
583   return valid;
584 }
585
586 static gboolean
587 gtk_binding_entry_activate (GtkBindingEntry *entry,
588                             GObject         *object)
589 {
590   GtkBindingSignal *sig;
591   gboolean old_emission;
592   gboolean handled = FALSE;
593   gint i;
594
595   old_emission = entry->in_emission;
596   entry->in_emission = TRUE;
597
598   g_object_ref (object);
599
600   for (sig = entry->signals; sig; sig = sig->next)
601     {
602       GSignalQuery query;
603       guint signal_id;
604       GValue *params = NULL;
605       GValue return_val = G_VALUE_INIT;
606       gchar *accelerator = NULL;
607
608       signal_id = g_signal_lookup (sig->signal_name, G_OBJECT_TYPE (object));
609       if (!signal_id)
610         {
611           accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
612           g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
613                      "could not find signal \"%s\" in the `%s' class ancestry",
614                      entry->binding_set->set_name,
615                      accelerator,
616                      sig->signal_name,
617                      g_type_name (G_OBJECT_TYPE (object)));
618           g_free (accelerator);
619           continue;
620         }
621
622       g_signal_query (signal_id, &query);
623       if (query.n_params != sig->n_args ||
624           (query.return_type != G_TYPE_NONE && query.return_type != G_TYPE_BOOLEAN) ||
625           !binding_compose_params (object, sig->args, &query, &params))
626         {
627           accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
628           g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
629                      "signature mismatch for signal \"%s\" in the `%s' class ancestry",
630                      entry->binding_set->set_name,
631                      accelerator,
632                      sig->signal_name,
633                      g_type_name (G_OBJECT_TYPE (object)));
634         }
635       else if (!(query.signal_flags & G_SIGNAL_ACTION))
636         {
637           accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
638           g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
639                      "signal \"%s\" in the `%s' class ancestry cannot be used for action emissions",
640                      entry->binding_set->set_name,
641                      accelerator,
642                      sig->signal_name,
643                      g_type_name (G_OBJECT_TYPE (object)));
644         }
645       g_free (accelerator);
646       if (accelerator)
647         continue;
648
649       if (query.return_type == G_TYPE_BOOLEAN)
650         g_value_init (&return_val, G_TYPE_BOOLEAN);
651
652       g_signal_emitv (params, signal_id, 0, &return_val);
653
654       if (query.return_type == G_TYPE_BOOLEAN)
655         {
656           if (g_value_get_boolean (&return_val))
657             handled = TRUE;
658           g_value_unset (&return_val);
659         }
660       else
661         handled = TRUE;
662
663       for (i = 0; i < query.n_params + 1; i++)
664         g_value_unset (&params[i]);
665       g_free (params);
666
667       if (entry->destroyed)
668         break;
669     }
670
671   g_object_unref (object);
672
673   entry->in_emission = old_emission;
674   if (entry->destroyed && !entry->in_emission)
675     binding_entry_free (entry);
676
677   return handled;
678 }
679
680 /**
681  * gtk_binding_set_new: (skip)
682  * @set_name: unique name of this binding set
683  *
684  * GTK+ maintains a global list of binding sets. Each binding set has
685  * a unique name which needs to be specified upon creation.
686  *
687  * Return value: (transfer full): new binding set
688  */
689 GtkBindingSet*
690 gtk_binding_set_new (const gchar *set_name)
691 {
692   GtkBindingSet *binding_set;
693
694   g_return_val_if_fail (set_name != NULL, NULL);
695
696   binding_set = g_new (GtkBindingSet, 1);
697   binding_set->set_name = (gchar *) g_intern_string (set_name);
698   binding_set->widget_path_pspecs = NULL;
699   binding_set->widget_class_pspecs = NULL;
700   binding_set->class_branch_pspecs = NULL;
701   binding_set->entries = NULL;
702   binding_set->current = NULL;
703   binding_set->parsed = FALSE;
704
705   binding_set_list = g_slist_prepend (binding_set_list, binding_set);
706
707   return binding_set;
708 }
709
710 /**
711  * gtk_binding_set_by_class: (skip)
712  * @object_class: a valid #GObject class
713  *
714  * This function returns the binding set named after the type name of
715  * the passed in class structure. New binding sets are created on
716  * demand by this function.
717  *
718  * Return value: (transfer full): the binding set corresponding to
719  *     @object_class
720  */
721 GtkBindingSet*
722 gtk_binding_set_by_class (gpointer object_class)
723 {
724   GObjectClass *class = object_class;
725   GtkBindingSet* binding_set;
726
727   g_return_val_if_fail (G_IS_OBJECT_CLASS (class), NULL);
728
729   if (!key_id_class_binding_set)
730     key_id_class_binding_set = g_quark_from_static_string (key_class_binding_set);
731
732   binding_set = g_dataset_id_get_data (class, key_id_class_binding_set);
733
734   if (binding_set)
735     return binding_set;
736
737   binding_set = gtk_binding_set_new (g_type_name (G_OBJECT_CLASS_TYPE (class)));
738   g_dataset_id_set_data (class, key_id_class_binding_set, binding_set);
739
740   return binding_set;
741 }
742
743 static GtkBindingSet*
744 gtk_binding_set_find_interned (const gchar *set_name)
745 {
746   GSList *slist;
747
748   for (slist = binding_set_list; slist; slist = slist->next)
749     {
750       GtkBindingSet *binding_set;
751
752       binding_set = slist->data;
753       if (binding_set->set_name == set_name)
754         return binding_set;
755     }
756
757   return NULL;
758 }
759
760 /**
761  * gtk_binding_set_find:
762  * @set_name: unique binding set name
763  *
764  * Find a binding set by its globally unique name.
765  *
766  * The @set_name can either be a name used for gtk_binding_set_new()
767  * or the type name of a class used in gtk_binding_set_by_class().
768  *
769  * Return value: (transfer none): %NULL or the specified binding set
770  */
771 GtkBindingSet*
772 gtk_binding_set_find (const gchar *set_name)
773 {
774   g_return_val_if_fail (set_name != NULL, NULL);
775
776   return gtk_binding_set_find_interned (g_intern_string (set_name));
777 }
778
779 /**
780  * gtk_binding_set_activate:
781  * @binding_set: a #GtkBindingSet set to activate
782  * @keyval:      key value of the binding
783  * @modifiers:   key modifier of the binding
784  * @object:      object to activate when binding found
785  *
786  * Find a key binding matching @keyval and @modifiers within
787  * @binding_set and activate the binding on @object.
788  *
789  * Return value: %TRUE if a binding was found and activated
790  */
791 gboolean
792 gtk_binding_set_activate (GtkBindingSet  *binding_set,
793                           guint           keyval,
794                           GdkModifierType modifiers,
795                           GObject        *object)
796 {
797   GtkBindingEntry *entry;
798
799   g_return_val_if_fail (binding_set != NULL, FALSE);
800   g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
801
802   keyval = gdk_keyval_to_lower (keyval);
803   modifiers = modifiers & BINDING_MOD_MASK ();
804
805   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
806   if (entry)
807     return gtk_binding_entry_activate (entry, object);
808
809   return FALSE;
810 }
811
812 static void
813 gtk_binding_entry_clear_internal (GtkBindingSet  *binding_set,
814                                   guint           keyval,
815                                   GdkModifierType modifiers)
816 {
817   GtkBindingEntry *entry;
818
819   keyval = gdk_keyval_to_lower (keyval);
820   modifiers = modifiers & BINDING_MOD_MASK ();
821
822   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
823   if (entry)
824     binding_entry_destroy (entry);
825
826   entry = binding_entry_new (binding_set, keyval, modifiers);
827 }
828
829 /**
830  * gtk_binding_entry_skip:
831  * @binding_set: a #GtkBindingSet to skip an entry of
832  * @keyval:      key value of binding to skip
833  * @modifiers:   key modifier of binding to skip
834  *
835  * Install a binding on @binding_set which causes key lookups
836  * to be aborted, to prevent bindings from lower priority sets
837  * to be activated.
838  *
839  * Since: 2.12
840  */
841 void
842 gtk_binding_entry_skip (GtkBindingSet  *binding_set,
843                         guint           keyval,
844                         GdkModifierType modifiers)
845 {
846   GtkBindingEntry *entry;
847
848   g_return_if_fail (binding_set != NULL);
849
850   keyval = gdk_keyval_to_lower (keyval);
851   modifiers = modifiers & BINDING_MOD_MASK ();
852
853   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
854   if (entry)
855     binding_entry_destroy (entry);
856
857   entry = binding_entry_new (binding_set, keyval, modifiers);
858   entry->marks_unbound = TRUE;
859 }
860
861 /**
862  * gtk_binding_entry_remove:
863  * @binding_set: a #GtkBindingSet to remove an entry of
864  * @keyval:      key value of binding to remove
865  * @modifiers:   key modifier of binding to remove
866  *
867  * Remove a binding previously installed via
868  * gtk_binding_entry_add_signal() on @binding_set.
869  */
870 void
871 gtk_binding_entry_remove (GtkBindingSet  *binding_set,
872                           guint           keyval,
873                           GdkModifierType modifiers)
874 {
875   GtkBindingEntry *entry;
876
877   g_return_if_fail (binding_set != NULL);
878
879   keyval = gdk_keyval_to_lower (keyval);
880   modifiers = modifiers & BINDING_MOD_MASK ();
881
882   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
883   if (entry)
884     binding_entry_destroy (entry);
885 }
886
887 /**
888  * gtk_binding_entry_add_signall:
889  * @binding_set:  a #GtkBindingSet to add a signal to
890  * @keyval:       key value
891  * @modifiers:    key modifier
892  * @signal_name:  signal name to be bound
893  * @binding_args: (transfer none) (element-type GtkBindingArg):
894  *     list of #GtkBindingArg signal arguments
895  *
896  * Override or install a new key binding for @keyval with @modifiers on
897  * @binding_set.
898  */
899 void
900 gtk_binding_entry_add_signall (GtkBindingSet  *binding_set,
901                                guint           keyval,
902                                GdkModifierType modifiers,
903                                const gchar    *signal_name,
904                                GSList         *binding_args)
905 {
906   _gtk_binding_entry_add_signall (binding_set,
907                                   keyval, modifiers,
908                                   signal_name, binding_args);
909 }
910
911 void
912 _gtk_binding_entry_add_signall (GtkBindingSet  *binding_set,
913                                 guint          keyval,
914                                 GdkModifierType modifiers,
915                                 const gchar    *signal_name,
916                                 GSList        *binding_args)
917 {
918   GtkBindingEntry *entry;
919   GtkBindingSignal *signal, **signal_p;
920   GSList *slist;
921   guint n = 0;
922   GtkBindingArg *arg;
923
924   g_return_if_fail (binding_set != NULL);
925   g_return_if_fail (signal_name != NULL);
926
927   keyval = gdk_keyval_to_lower (keyval);
928   modifiers = modifiers & BINDING_MOD_MASK ();
929
930   signal = binding_signal_new (signal_name, g_slist_length (binding_args));
931
932   arg = signal->args;
933   for (slist = binding_args; slist; slist = slist->next)
934     {
935       GtkBindingArg *tmp_arg;
936
937       tmp_arg = slist->data;
938       if (!tmp_arg)
939         {
940           g_warning ("gtk_binding_entry_add_signall(): arg[%u] is `NULL'", n);
941           binding_signal_free (signal);
942           return;
943         }
944       switch (G_TYPE_FUNDAMENTAL (tmp_arg->arg_type))
945         {
946         case  G_TYPE_LONG:
947           arg->arg_type = G_TYPE_LONG;
948           arg->d.long_data = tmp_arg->d.long_data;
949           break;
950         case  G_TYPE_DOUBLE:
951           arg->arg_type = G_TYPE_DOUBLE;
952           arg->d.double_data = tmp_arg->d.double_data;
953           break;
954         case  G_TYPE_STRING:
955           if (tmp_arg->arg_type != GTK_TYPE_IDENTIFIER)
956             arg->arg_type = G_TYPE_STRING;
957           else
958             arg->arg_type = GTK_TYPE_IDENTIFIER;
959           arg->d.string_data = g_strdup (tmp_arg->d.string_data);
960           if (!arg->d.string_data)
961             {
962               g_warning ("gtk_binding_entry_add_signall(): value of `string' arg[%u] is `NULL'", n);
963               binding_signal_free (signal);
964               return;
965             }
966           break;
967         default:
968           g_warning ("gtk_binding_entry_add_signall(): unsupported type `%s' for arg[%u]",
969                      g_type_name (arg->arg_type), n);
970           binding_signal_free (signal);
971           return;
972         }
973       arg++;
974       n++;
975     }
976
977   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
978   if (!entry)
979     {
980       gtk_binding_entry_clear_internal (binding_set, keyval, modifiers);
981       entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
982     }
983   signal_p = &entry->signals;
984   while (*signal_p)
985     signal_p = &(*signal_p)->next;
986   *signal_p = signal;
987 }
988
989 /**
990  * gtk_binding_entry_add_signal:
991  * @binding_set: a #GtkBindingSet to install an entry for
992  * @keyval:      key value of binding to install
993  * @modifiers:   key modifier of binding to install
994  * @signal_name: signal to execute upon activation
995  * @n_args:      number of arguments to @signal_name
996  * @...:         arguments to @signal_name
997  *
998  * Override or install a new key binding for @keyval with @modifiers on
999  * @binding_set. When the binding is activated, @signal_name will be
1000  * emitted on the target widget, with @n_args @Varargs used as
1001  * arguments.
1002  */
1003 void
1004 gtk_binding_entry_add_signal (GtkBindingSet  *binding_set,
1005                               guint           keyval,
1006                               GdkModifierType modifiers,
1007                               const gchar    *signal_name,
1008                               guint           n_args,
1009                               ...)
1010 {
1011   GSList *slist, *free_slist;
1012   va_list args;
1013   guint i;
1014
1015   g_return_if_fail (binding_set != NULL);
1016   g_return_if_fail (signal_name != NULL);
1017
1018   va_start (args, n_args);
1019   slist = NULL;
1020   for (i = 0; i < n_args; i++)
1021     {
1022       GtkBindingArg *arg;
1023
1024       arg = g_slice_new0 (GtkBindingArg);
1025       slist = g_slist_prepend (slist, arg);
1026
1027       arg->arg_type = va_arg (args, GType);
1028       switch (G_TYPE_FUNDAMENTAL (arg->arg_type))
1029         {
1030         case G_TYPE_CHAR:
1031         case G_TYPE_UCHAR:
1032         case G_TYPE_INT:
1033         case G_TYPE_UINT:
1034         case G_TYPE_BOOLEAN:
1035         case G_TYPE_ENUM:
1036         case G_TYPE_FLAGS:
1037           arg->arg_type = G_TYPE_LONG;
1038           arg->d.long_data = va_arg (args, gint);
1039           break;
1040         case G_TYPE_LONG:
1041         case G_TYPE_ULONG:
1042           arg->arg_type = G_TYPE_LONG;
1043           arg->d.long_data = va_arg (args, glong);
1044           break;
1045         case G_TYPE_FLOAT:
1046         case G_TYPE_DOUBLE:
1047           arg->arg_type = G_TYPE_DOUBLE;
1048           arg->d.double_data = va_arg (args, gdouble);
1049           break;
1050         case G_TYPE_STRING:
1051           if (arg->arg_type != GTK_TYPE_IDENTIFIER)
1052             arg->arg_type = G_TYPE_STRING;
1053           arg->d.string_data = va_arg (args, gchar*);
1054           if (!arg->d.string_data)
1055             {
1056               g_warning ("gtk_binding_entry_add_signal(): type `%s' arg[%u] is `NULL'",
1057                          g_type_name (arg->arg_type),
1058                          i);
1059               i += n_args + 1;
1060             }
1061           break;
1062         default:
1063           g_warning ("gtk_binding_entry_add_signal(): unsupported type `%s' for arg[%u]",
1064                      g_type_name (arg->arg_type), i);
1065           i += n_args + 1;
1066           break;
1067         }
1068     }
1069   va_end (args);
1070
1071   if (i == n_args || i == 0)
1072     {
1073       slist = g_slist_reverse (slist);
1074       _gtk_binding_entry_add_signall (binding_set, keyval, modifiers, signal_name, slist);
1075     }
1076
1077   free_slist = slist;
1078   while (slist)
1079     {
1080       g_slice_free (GtkBindingArg, slist->data);
1081       slist = slist->next;
1082     }
1083   g_slist_free (free_slist);
1084 }
1085
1086 static guint
1087 gtk_binding_parse_signal (GScanner       *scanner,
1088                           GtkBindingSet  *binding_set,
1089                           guint           keyval,
1090                           GdkModifierType modifiers)
1091 {
1092   gchar *signal;
1093   guint expected_token = 0;
1094   GSList *args;
1095   GSList *slist;
1096   gboolean done;
1097   gboolean negate;
1098   gboolean need_arg;
1099   gboolean seen_comma;
1100
1101   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1102
1103   g_scanner_get_next_token (scanner);
1104
1105   if (scanner->token != G_TOKEN_STRING)
1106     return G_TOKEN_STRING;
1107
1108   g_scanner_peek_next_token (scanner);
1109
1110   if (scanner->next_token != '(')
1111     {
1112       g_scanner_get_next_token (scanner);
1113       return '(';
1114     }
1115
1116   signal = g_strdup (scanner->value.v_string);
1117   g_scanner_get_next_token (scanner);
1118
1119   negate = FALSE;
1120   args = NULL;
1121   done = FALSE;
1122   need_arg = TRUE;
1123   seen_comma = FALSE;
1124   scanner->config->scan_symbols = FALSE;
1125
1126   do
1127     {
1128       GtkBindingArg *arg;
1129
1130       if (need_arg)
1131         expected_token = G_TOKEN_INT;
1132       else
1133         expected_token = ')';
1134
1135       g_scanner_get_next_token (scanner);
1136
1137       switch ((guint) scanner->token)
1138         {
1139         case G_TOKEN_FLOAT:
1140           if (need_arg)
1141             {
1142               need_arg = FALSE;
1143               arg = g_new (GtkBindingArg, 1);
1144               arg->arg_type = G_TYPE_DOUBLE;
1145               arg->d.double_data = scanner->value.v_float;
1146
1147               if (negate)
1148                 {
1149                   arg->d.double_data = - arg->d.double_data;
1150                   negate = FALSE;
1151                 }
1152               args = g_slist_prepend (args, arg);
1153             }
1154           else
1155             done = TRUE;
1156
1157           break;
1158         case G_TOKEN_INT:
1159           if (need_arg)
1160             {
1161               need_arg = FALSE;
1162               arg = g_new (GtkBindingArg, 1);
1163               arg->arg_type = G_TYPE_LONG;
1164               arg->d.long_data = scanner->value.v_int;
1165
1166               if (negate)
1167                 {
1168                   arg->d.long_data = - arg->d.long_data;
1169                   negate = FALSE;
1170                 }
1171               args = g_slist_prepend (args, arg);
1172             }
1173           else
1174             done = TRUE;
1175           break;
1176         case G_TOKEN_STRING:
1177           if (need_arg && !negate)
1178             {
1179               need_arg = FALSE;
1180               arg = g_new (GtkBindingArg, 1);
1181               arg->arg_type = G_TYPE_STRING;
1182               arg->d.string_data = g_strdup (scanner->value.v_string);
1183               args = g_slist_prepend (args, arg);
1184             }
1185           else
1186             done = TRUE;
1187
1188           break;
1189         case G_TOKEN_IDENTIFIER:
1190           if (need_arg && !negate)
1191             {
1192               need_arg = FALSE;
1193               arg = g_new (GtkBindingArg, 1);
1194               arg->arg_type = GTK_TYPE_IDENTIFIER;
1195               arg->d.string_data = g_strdup (scanner->value.v_identifier);
1196               args = g_slist_prepend (args, arg);
1197             }
1198           else
1199             done = TRUE;
1200
1201           break;
1202         case '-':
1203           if (!need_arg)
1204             done = TRUE;
1205           else if (negate)
1206             {
1207               expected_token = G_TOKEN_INT;
1208               done = TRUE;
1209             }
1210           else
1211             negate = TRUE;
1212
1213           break;
1214         case ',':
1215           seen_comma = TRUE;
1216           if (need_arg)
1217             done = TRUE;
1218           else
1219             need_arg = TRUE;
1220
1221           break;
1222         case ')':
1223           if (!(need_arg && seen_comma) && !negate)
1224             {
1225               args = g_slist_reverse (args);
1226               _gtk_binding_entry_add_signall (binding_set,
1227                                               keyval,
1228                                               modifiers,
1229                                               signal,
1230                                               args);
1231               expected_token = G_TOKEN_NONE;
1232             }
1233
1234           done = TRUE;
1235           break;
1236         default:
1237           done = TRUE;
1238           break;
1239         }
1240     }
1241   while (!done);
1242
1243   scanner->config->scan_symbols = TRUE;
1244
1245   for (slist = args; slist; slist = slist->next)
1246     {
1247       GtkBindingArg *arg;
1248
1249       arg = slist->data;
1250
1251       if (G_TYPE_FUNDAMENTAL (arg->arg_type) == G_TYPE_STRING)
1252         g_free (arg->d.string_data);
1253       g_free (arg);
1254     }
1255
1256   g_slist_free (args);
1257   g_free (signal);
1258
1259   return expected_token;
1260 }
1261
1262 static inline guint
1263 gtk_binding_parse_bind (GScanner       *scanner,
1264                         GtkBindingSet  *binding_set)
1265 {
1266   guint keyval = 0;
1267   GdkModifierType modifiers = 0;
1268   gboolean unbind = FALSE;
1269
1270   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1271
1272   g_scanner_get_next_token (scanner);
1273
1274   if (scanner->token != G_TOKEN_SYMBOL)
1275     return G_TOKEN_SYMBOL;
1276
1277   if (scanner->value.v_symbol != GUINT_TO_POINTER (GTK_BINDING_TOKEN_BIND) &&
1278       scanner->value.v_symbol != GUINT_TO_POINTER (GTK_BINDING_TOKEN_UNBIND))
1279     return G_TOKEN_SYMBOL;
1280
1281   unbind = (scanner->value.v_symbol == GUINT_TO_POINTER (GTK_BINDING_TOKEN_UNBIND));
1282   g_scanner_get_next_token (scanner);
1283
1284   if (scanner->token != (guint) G_TOKEN_STRING)
1285     return G_TOKEN_STRING;
1286
1287   gtk_accelerator_parse (scanner->value.v_string, &keyval, &modifiers);
1288   modifiers &= BINDING_MOD_MASK ();
1289
1290   if (keyval == 0)
1291     return G_TOKEN_STRING;
1292
1293   if (unbind)
1294     {
1295       gtk_binding_entry_skip (binding_set, keyval, modifiers);
1296       return G_TOKEN_NONE;
1297     }
1298
1299   g_scanner_get_next_token (scanner);
1300
1301   if (scanner->token != '{')
1302     return '{';
1303
1304   gtk_binding_entry_clear_internal (binding_set, keyval, modifiers);
1305   g_scanner_peek_next_token (scanner);
1306
1307   while (scanner->next_token != '}')
1308     {
1309       guint expected_token;
1310
1311       switch (scanner->next_token)
1312         {
1313         case G_TOKEN_STRING:
1314           expected_token = gtk_binding_parse_signal (scanner,
1315                                                      binding_set,
1316                                                      keyval,
1317                                                      modifiers);
1318           if (expected_token != G_TOKEN_NONE)
1319             return expected_token;
1320           break;
1321         default:
1322           g_scanner_get_next_token (scanner);
1323           return '}';
1324         }
1325
1326       g_scanner_peek_next_token (scanner);
1327     }
1328
1329   g_scanner_get_next_token (scanner);
1330
1331   return G_TOKEN_NONE;
1332 }
1333
1334 static GScanner *
1335 create_signal_scanner (void)
1336 {
1337   GScanner *scanner;
1338
1339   scanner = g_scanner_new (NULL);
1340   scanner->config->cset_identifier_nth = G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "-_";
1341
1342   g_scanner_scope_add_symbol (scanner, 0, "bind", GUINT_TO_POINTER (GTK_BINDING_TOKEN_BIND));
1343   g_scanner_scope_add_symbol (scanner, 0, "unbind", GUINT_TO_POINTER (GTK_BINDING_TOKEN_UNBIND));
1344
1345   g_scanner_set_scope (scanner, 0);
1346
1347   return scanner;
1348 }
1349
1350 /**
1351  * gtk_binding_entry_add_signal_from_string:
1352  * @binding_set: a #GtkBindingSet
1353  * @signal_desc: a signal description
1354  *
1355  * Parses a signal description from @signal_desc and incorporates
1356  * it into @binding_set.
1357  *
1358  * Signal descriptions may either bind a key combination to
1359  * one or more signals:
1360  * <informalexample><programlisting>
1361  *   bind "key" {
1362  *     "signalname" (param, ...)
1363  *     ...
1364  *   }
1365  * </programlisting></informalexample>
1366  *
1367  * Or they may also unbind a key combination:
1368  * <informalexample><programlisting>
1369  *   unbind "key"
1370  * </programlisting></informalexample>
1371  *
1372  * Key combinations must be in a format that can be parsed by
1373  * gtk_accelerator_parse().
1374  *
1375  * Returns: %G_TOKEN_NONE if the signal was successfully parsed and added,
1376  *     the expected token otherwise
1377  *
1378  * Since: 3.0
1379  */
1380 GTokenType
1381 gtk_binding_entry_add_signal_from_string (GtkBindingSet *binding_set,
1382                                           const gchar   *signal_desc)
1383 {
1384   static GScanner *scanner = NULL;
1385   GTokenType ret;
1386
1387   g_return_val_if_fail (binding_set != NULL, G_TOKEN_NONE);
1388   g_return_val_if_fail (signal_desc != NULL, G_TOKEN_NONE);
1389
1390   if (G_UNLIKELY (!scanner))
1391     scanner = create_signal_scanner ();
1392
1393   g_scanner_input_text (scanner, signal_desc,
1394                         (guint) strlen (signal_desc));
1395
1396   ret = gtk_binding_parse_bind (scanner, binding_set);
1397
1398   /* Reset for next use */
1399   g_scanner_set_scope (scanner, 0);
1400
1401   return ret;
1402 }
1403
1404 /**
1405  * gtk_binding_set_add_path:
1406  * @binding_set: a #GtkBindingSet to add a path to
1407  * @path_type: path type the pattern applies to
1408  * @path_pattern: the actual match pattern
1409  * @priority: binding priority
1410  *
1411  * This function was used internally by the GtkRC parsing mechanism
1412  * to assign match patterns to #GtkBindingSet structures.
1413  *
1414  * In GTK+ 3, these match patterns are unused.
1415  *
1416  * Deprecated: 3.0
1417  */
1418 void
1419 gtk_binding_set_add_path (GtkBindingSet       *binding_set,
1420                           GtkPathType          path_type,
1421                           const gchar         *path_pattern,
1422                           GtkPathPriorityType  priority)
1423 {
1424   PatternSpec *pspec;
1425   GSList **slist_p, *slist;
1426   static guint seq_id = 0;
1427
1428   g_return_if_fail (binding_set != NULL);
1429   g_return_if_fail (path_pattern != NULL);
1430   g_return_if_fail (priority <= GTK_PATH_PRIO_MASK);
1431
1432   priority &= GTK_PATH_PRIO_MASK;
1433
1434   switch (path_type)
1435     {
1436     case  GTK_PATH_WIDGET:
1437       slist_p = &binding_set->widget_path_pspecs;
1438       break;
1439     case  GTK_PATH_WIDGET_CLASS:
1440       slist_p = &binding_set->widget_class_pspecs;
1441       break;
1442     case  GTK_PATH_CLASS:
1443       slist_p = &binding_set->class_branch_pspecs;
1444       break;
1445     default:
1446       g_assert_not_reached ();
1447       slist_p = NULL;
1448       break;
1449     }
1450
1451   pspec = g_new (PatternSpec, 1);
1452   pspec->type = path_type;
1453   if (path_type == GTK_PATH_WIDGET_CLASS)
1454     pspec->pspec = NULL;
1455   else
1456     pspec->pspec = g_pattern_spec_new (path_pattern);
1457
1458   pspec->seq_id = priority << 28;
1459   pspec->user_data = binding_set;
1460
1461   slist = *slist_p;
1462   while (slist)
1463     {
1464       PatternSpec *tmp_pspec;
1465
1466       tmp_pspec = slist->data;
1467       slist = slist->next;
1468
1469       if (g_pattern_spec_equal (tmp_pspec->pspec, pspec->pspec))
1470         {
1471           GtkPathPriorityType lprio = tmp_pspec->seq_id >> 28;
1472
1473           pattern_spec_free (pspec);
1474           pspec = NULL;
1475           if (lprio < priority)
1476             {
1477               tmp_pspec->seq_id &= 0x0fffffff;
1478               tmp_pspec->seq_id |= priority << 28;
1479             }
1480           break;
1481         }
1482     }
1483   if (pspec)
1484     {
1485       pspec->seq_id |= seq_id++ & 0x0fffffff;
1486       *slist_p = g_slist_prepend (*slist_p, pspec);
1487     }
1488 }
1489
1490 static gint
1491 find_entry_with_binding (GtkBindingEntry *entry,
1492                          GtkBindingSet   *binding_set)
1493 {
1494   return (entry->binding_set == binding_set) ? 0 : 1;
1495 }
1496
1497 static gboolean
1498 binding_activate (GtkBindingSet *binding_set,
1499                   GSList        *entries,
1500                   GObject       *object,
1501                   gboolean       is_release,
1502                   gboolean      *unbound)
1503 {
1504   GtkBindingEntry *entry;
1505   GSList *elem;
1506
1507   elem = g_slist_find_custom (entries, binding_set,
1508                               (GCompareFunc) find_entry_with_binding);
1509
1510   if (!elem)
1511     return FALSE;
1512
1513   entry = elem->data;
1514
1515   if (is_release != ((entry->modifiers & GDK_RELEASE_MASK) != 0))
1516     return FALSE;
1517
1518   if (entry->marks_unbound)
1519     {
1520       *unbound = TRUE;
1521       return FALSE;
1522     }
1523
1524   if (gtk_binding_entry_activate (entry, object))
1525     return TRUE;
1526
1527   return FALSE;
1528 }
1529
1530 static gboolean
1531 gtk_bindings_activate_list (GObject  *object,
1532                             GSList   *entries,
1533                             gboolean  is_release)
1534 {
1535   GtkStyleContext *context;
1536   GtkBindingSet *binding_set;
1537   GtkStateFlags state;
1538   gboolean handled = FALSE;
1539   gboolean unbound = FALSE;
1540   GPtrArray *array;
1541
1542   if (!entries)
1543     return FALSE;
1544
1545   context = gtk_widget_get_style_context (GTK_WIDGET (object));
1546   state = gtk_widget_get_state_flags (GTK_WIDGET (object));
1547
1548   gtk_style_context_get (context, state,
1549                          "gtk-key-bindings", &array,
1550                          NULL);
1551   if (array)
1552     {
1553       gint i;
1554
1555       for (i = 0; i < array->len; i++)
1556         {
1557           binding_set = g_ptr_array_index (array, i);
1558           handled = binding_activate (binding_set, entries,
1559                                       object, is_release,
1560                                       &unbound);
1561           if (handled)
1562             break;
1563         }
1564
1565       g_ptr_array_unref (array);
1566
1567       if (unbound)
1568         return FALSE;
1569     }
1570
1571   if (!handled)
1572     {
1573       GType class_type;
1574
1575       class_type = G_TYPE_FROM_INSTANCE (object);
1576
1577       while (class_type && !handled)
1578         {
1579           binding_set = gtk_binding_set_find_interned (g_type_name (class_type));
1580           class_type = g_type_parent (class_type);
1581
1582           if (!binding_set)
1583             continue;
1584
1585           handled = binding_activate (binding_set, entries,
1586                                       object, is_release,
1587                                       &unbound);
1588         }
1589
1590       if (unbound)
1591         return FALSE;
1592     }
1593
1594   return handled;
1595 }
1596
1597 /**
1598  * gtk_bindings_activate:
1599  * @object: object to activate when binding found
1600  * @keyval: key value of the binding
1601  * @modifiers: key modifier of the binding
1602  *
1603  * Find a key binding matching @keyval and @modifiers and activate the
1604  * binding on @object.
1605  *
1606  * Return value: %TRUE if a binding was found and activated
1607  */
1608 gboolean
1609 gtk_bindings_activate (GObject         *object,
1610                        guint            keyval,
1611                        GdkModifierType  modifiers)
1612 {
1613   GSList *entries = NULL;
1614   GdkDisplay *display;
1615   GtkKeyHash *key_hash;
1616   gboolean handled = FALSE;
1617   gboolean is_release;
1618
1619   if (!GTK_IS_WIDGET (object))
1620     return FALSE;
1621
1622   is_release = (modifiers & GDK_RELEASE_MASK) != 0;
1623   modifiers = modifiers & BINDING_MOD_MASK () & ~GDK_RELEASE_MASK;
1624
1625   display = gtk_widget_get_display (GTK_WIDGET (object));
1626   key_hash = binding_key_hash_for_keymap (gdk_keymap_get_for_display (display));
1627
1628   entries = _gtk_key_hash_lookup_keyval (key_hash, keyval, modifiers);
1629
1630   handled = gtk_bindings_activate_list (object, entries, is_release);
1631
1632   g_slist_free (entries);
1633
1634   return handled;
1635 }
1636
1637 /**
1638  * gtk_bindings_activate_event:
1639  * @object: a #GObject (generally must be a widget)
1640  * @event: a #GdkEventKey
1641  *
1642  * Looks up key bindings for @object to find one matching
1643  * @event, and if one was found, activate it.
1644  *
1645  * Return value: %TRUE if a matching key binding was found
1646  *
1647  * Since: 2.4
1648  */
1649 gboolean
1650 gtk_bindings_activate_event (GObject     *object,
1651                              GdkEventKey *event)
1652 {
1653   GSList *entries = NULL;
1654   GdkDisplay *display;
1655   GtkKeyHash *key_hash;
1656   gboolean handled = FALSE;
1657
1658   if (!GTK_IS_WIDGET (object))
1659     return FALSE;
1660
1661   display = gtk_widget_get_display (GTK_WIDGET (object));
1662   key_hash = binding_key_hash_for_keymap (gdk_keymap_get_for_display (display));
1663
1664   entries = _gtk_key_hash_lookup (key_hash,
1665                                   event->hardware_keycode,
1666                                   event->state,
1667                                   BINDING_MOD_MASK () & ~GDK_RELEASE_MASK,
1668                                   event->group);
1669
1670   handled = gtk_bindings_activate_list (object, entries,
1671                                         event->type == GDK_KEY_RELEASE);
1672
1673   g_slist_free (entries);
1674
1675   return handled;
1676 }