]> Pileus Git - ~andy/gtk/blob - gtk/gtkbindings.c
Move GtkBindings docs inline
[~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 "gtkrc.h"
38 #include "gtkintl.h"
39
40 /**
41  * SECTION:gtkbindings
42  * @Title: GtkBindings
43  * @Short_description: Key bindings for individual widgets
44  * @See_also: <link linkend="gtk-keyboard-accelerators">Keyboard Accelerators</link>, #GtkCssProvider
45  *
46  * GtkBinding provides a mechanism for configuring GTK+ key bindings
47  * through CSS files. This eases key binding adjustments for application
48  * developers as well as users and provides GTK+ users or administrators
49  * with high key  binding configurability which requires no application
50  * or toolkit side changes.
51  *
52  * <refsect2 id="gtk-bindings-install">
53  * <title>Installing a key binding</title>
54  * <para>
55  * A CSS file binding consists of a 'binding-set' definition and a match
56  * statement to apply the binding set to specific widget types. Details
57  * on the matching mechanism are described under
58  * <link linkend="gtkcssprovider-selectors">Selectors</link>
59  * in the #GtkCssProvider documentation. Inside the binding-set definition,
60  * key combinations are bound to one or more specific signal emissions on
61  * the target widget. Key combinations are strings consisting of an optional
62  * #GdkModifierType name and <link linkend="gdk-Keyboard-Handling">key names</link>
63  * such as those defined in <filename>&lt;gdk/gdkkeysyms.h&gt;</filename>
64  * or returned from gdk_keyval_name(), they have to be parsable by
65  * gtk_accelerator_parse(). Specifications of signal emissions consist
66  * of a string identifying the signal name, and a list of signal specific
67  * arguments in parenthesis.
68  * </para>
69  * <para>
70  * For example for binding Control and the left or right cursor keys
71  * of a #GtkEntry widget to the #GtkEntry::move-cursor signal (so movement
72  * occurs in 3-character steps), the following binding can be used:
73  * <informalexample><programlisting>
74  * @binding-set "MoveCursor3"
75  * {
76  *   bind "&lt;Control&gt;Right" { "move-cursor" (visual-positions, 3, 0) };
77  *   bind "&lt;Control&gt;Left" { "move-cursor" (visual-positions, -3, 0) };
78  * };
79  * GtkEntry
80  * {
81  *   gtk-key-bindings: MoveCursor3
82  * }
83  * </programlisting></informalexample>
84  * </para>
85  * </refsect2>
86  * <refsect2 id="gtk-bindings-unbind">
87  * <title>Unbinding existing key bindings</title>
88  * <para>
89  * GTK+ already defines a number of useful bindings for the widgets
90  * it provides. Because custom bindings set up in CSS files take
91  * precedence over the default bindings shipped with GTK+, overriding
92  * existing bindings as demonstrated in
93  * <link linkend="gtk-bindings-install">Installing a key binding</link>
94  * works as expected. The same mechanism can not be used to "unbind"
95  * existing bindings, however.
96  * <informalexample><programlisting>
97  * @binding-set "MoveCursor3"
98  * {
99  *   bind "&lt;Control&gt;Right" {  };
100  *   bind "&lt;Control&gt;Left" {  };
101  * };
102  * GtkEntry
103  * {
104  *   gtk-key-bindings: MoveCursor3
105  * }
106  * </programlisting></informalexample>
107  * The above example will not have the desired effect of causing
108  * "&lt;Control&gt;Right" and "&lt;Control&gt;Left" key presses to
109  * be ignored by GTK+. Instead, it just causes any existing bindings
110  * from the bindings set "MoveCursor3" to be deleted, so when
111  * "&lt;Control&gt;Right" or "&lt;Control&gt;Left" are pressed, no
112  * binding for these keys is found in binding set "MoveCursor3".
113  * GTK+ will thus continue to search for matching key bindings, and will
114  * eventually lookup and find the default GTK+ bindings for entries which
115  * implement word movement. To keep GTK+ from activating its default
116  * bindings, the "unbind" keyword can be used like this:
117  * <informalexample><programlisting>
118  * @binding-set "MoveCursor3"
119  * {
120  *   unbind "&lt;Control&gt;Right";
121  *   unbind "&lt;Control&gt;Left";
122  * };
123  * GtkEntry
124  * {
125  *   gtk-key-bindings: MoveCursor3
126  * }
127  * </programlisting></informalexample>
128  * Now, GTK+ will find a match when looking up "&lt;Control&gt;Right"
129  * and "&lt;Control&gt;Left" key presses before it resorts to its default
130  * bindings, and the match instructs it to abort ("unbind") the search,
131  * so the key presses are not consumed by this widget. As usual, further
132  * processing of the key presses, e.g. by an entry's parent widget, is
133  * now possible.
134  * </para>
135  * </refsect2>
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 = { 0, };
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 = { 0, };
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   gtk_binding_set_add_path (binding_set,
739                             GTK_PATH_CLASS,
740                             g_type_name (G_OBJECT_CLASS_TYPE (class)),
741                             GTK_PATH_PRIO_GTK);
742   g_dataset_id_set_data (class, key_id_class_binding_set, binding_set);
743
744   return binding_set;
745 }
746
747 /**
748  * gtk_binding_set_find:
749  * @set_name: unique binding set name
750  *
751  * Find a binding set by its globally unique name.
752  *
753  * The @set_name can either be a name used for gtk_binding_set_new()
754  * or the type name of a class used in gtk_binding_set_by_class().
755  *
756  * Return value: (transfer none): %NULL or the specified binding set
757  */
758 GtkBindingSet*
759 gtk_binding_set_find (const gchar *set_name)
760 {
761   GSList *slist;
762
763   g_return_val_if_fail (set_name != NULL, NULL);
764
765   for (slist = binding_set_list; slist; slist = slist->next)
766     {
767       GtkBindingSet *binding_set;
768
769       binding_set = slist->data;
770       if (g_str_equal (binding_set->set_name, (gpointer) set_name))
771         return binding_set;
772     }
773   return NULL;
774 }
775
776 /**
777  * gtk_binding_set_activate:
778  * @binding_set: a #GtkBindingSet set to activate
779  * @keyval:      key value of the binding
780  * @modifiers:   key modifier of the binding
781  * @object:      object to activate when binding found
782  *
783  * Find a key binding matching @keyval and @modifiers within
784  * @binding_set and activate the binding on @object.
785  *
786  * Return value: %TRUE if a binding was found and activated
787  */
788 gboolean
789 gtk_binding_set_activate (GtkBindingSet  *binding_set,
790                           guint           keyval,
791                           GdkModifierType modifiers,
792                           GObject        *object)
793 {
794   GtkBindingEntry *entry;
795
796   g_return_val_if_fail (binding_set != NULL, FALSE);
797   g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
798
799   keyval = gdk_keyval_to_lower (keyval);
800   modifiers = modifiers & BINDING_MOD_MASK ();
801
802   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
803   if (entry)
804     return gtk_binding_entry_activate (entry, object);
805
806   return FALSE;
807 }
808
809 static void
810 gtk_binding_entry_clear_internal (GtkBindingSet  *binding_set,
811                                   guint           keyval,
812                                   GdkModifierType modifiers)
813 {
814   GtkBindingEntry *entry;
815
816   keyval = gdk_keyval_to_lower (keyval);
817   modifiers = modifiers & BINDING_MOD_MASK ();
818
819   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
820   if (entry)
821     binding_entry_destroy (entry);
822
823   entry = binding_entry_new (binding_set, keyval, modifiers);
824 }
825
826 /**
827  * gtk_binding_entry_skip:
828  * @binding_set: a #GtkBindingSet to skip an entry of
829  * @keyval:      key value of binding to skip
830  * @modifiers:   key modifier of binding to skip
831  *
832  * Install a binding on @binding_set which causes key lookups
833  * to be aborted, to prevent bindings from lower priority sets
834  * to be activated.
835  *
836  * Since: 2.12
837  */
838 void
839 gtk_binding_entry_skip (GtkBindingSet  *binding_set,
840                         guint           keyval,
841                         GdkModifierType modifiers)
842 {
843   GtkBindingEntry *entry;
844
845   g_return_if_fail (binding_set != NULL);
846
847   keyval = gdk_keyval_to_lower (keyval);
848   modifiers = modifiers & BINDING_MOD_MASK ();
849
850   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
851   if (entry)
852     binding_entry_destroy (entry);
853
854   entry = binding_entry_new (binding_set, keyval, modifiers);
855   entry->marks_unbound = TRUE;
856 }
857
858 /**
859  * gtk_binding_entry_remove:
860  * @binding_set: a #GtkBindingSet to remove an entry of
861  * @keyval:      key value of binding to remove
862  * @modifiers:   key modifier of binding to remove
863  *
864  * Remove a binding previously installed via
865  * gtk_binding_entry_add_signal() on @binding_set.
866  */
867 void
868 gtk_binding_entry_remove (GtkBindingSet  *binding_set,
869                           guint           keyval,
870                           GdkModifierType modifiers)
871 {
872   GtkBindingEntry *entry;
873
874   g_return_if_fail (binding_set != NULL);
875
876   keyval = gdk_keyval_to_lower (keyval);
877   modifiers = modifiers & BINDING_MOD_MASK ();
878
879   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
880   if (entry)
881     binding_entry_destroy (entry);
882 }
883
884 /**
885  * gtk_binding_entry_add_signall:
886  * @binding_set:  a #GtkBindingSet to add a signal to
887  * @keyval:       key value
888  * @modifiers:    key modifier
889  * @signal_name:  signal name to be bound
890  * @binding_args: (transfer none) (element-type GtkBindingArg):
891  *     list of #GtkBindingArg signal arguments
892  *
893  * Override or install a new key binding for @keyval with @modifiers on
894  * @binding_set.
895  */
896 void
897 gtk_binding_entry_add_signall (GtkBindingSet  *binding_set,
898                                guint           keyval,
899                                GdkModifierType modifiers,
900                                const gchar    *signal_name,
901                                GSList         *binding_args)
902 {
903   _gtk_binding_entry_add_signall (binding_set,
904                                   keyval, modifiers,
905                                   signal_name, binding_args);
906 }
907
908 void
909 _gtk_binding_entry_add_signall (GtkBindingSet  *binding_set,
910                                 guint          keyval,
911                                 GdkModifierType modifiers,
912                                 const gchar    *signal_name,
913                                 GSList        *binding_args)
914 {
915   GtkBindingEntry *entry;
916   GtkBindingSignal *signal, **signal_p;
917   GSList *slist;
918   guint n = 0;
919   GtkBindingArg *arg;
920
921   g_return_if_fail (binding_set != NULL);
922   g_return_if_fail (signal_name != NULL);
923
924   keyval = gdk_keyval_to_lower (keyval);
925   modifiers = modifiers & BINDING_MOD_MASK ();
926
927   signal = binding_signal_new (signal_name, g_slist_length (binding_args));
928
929   arg = signal->args;
930   for (slist = binding_args; slist; slist = slist->next)
931     {
932       GtkBindingArg *tmp_arg;
933
934       tmp_arg = slist->data;
935       if (!tmp_arg)
936         {
937           g_warning ("gtk_binding_entry_add_signall(): arg[%u] is `NULL'", n);
938           binding_signal_free (signal);
939           return;
940         }
941       switch (G_TYPE_FUNDAMENTAL (tmp_arg->arg_type))
942         {
943         case  G_TYPE_LONG:
944           arg->arg_type = G_TYPE_LONG;
945           arg->d.long_data = tmp_arg->d.long_data;
946           break;
947         case  G_TYPE_DOUBLE:
948           arg->arg_type = G_TYPE_DOUBLE;
949           arg->d.double_data = tmp_arg->d.double_data;
950           break;
951         case  G_TYPE_STRING:
952           if (tmp_arg->arg_type != GTK_TYPE_IDENTIFIER)
953             arg->arg_type = G_TYPE_STRING;
954           else
955             arg->arg_type = GTK_TYPE_IDENTIFIER;
956           arg->d.string_data = g_strdup (tmp_arg->d.string_data);
957           if (!arg->d.string_data)
958             {
959               g_warning ("gtk_binding_entry_add_signall(): value of `string' arg[%u] is `NULL'", n);
960               binding_signal_free (signal);
961               return;
962             }
963           break;
964         default:
965           g_warning ("gtk_binding_entry_add_signall(): unsupported type `%s' for arg[%u]",
966                      g_type_name (arg->arg_type), n);
967           binding_signal_free (signal);
968           return;
969         }
970       arg++;
971       n++;
972     }
973
974   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
975   if (!entry)
976     {
977       gtk_binding_entry_clear_internal (binding_set, keyval, modifiers);
978       entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
979     }
980   signal_p = &entry->signals;
981   while (*signal_p)
982     signal_p = &(*signal_p)->next;
983   *signal_p = signal;
984 }
985
986 /**
987  * gtk_binding_entry_add_signal:
988  * @binding_set: a #GtkBindingSet to install an entry for
989  * @keyval:      key value of binding to install
990  * @modifiers:   key modifier of binding to install
991  * @signal_name: signal to execute upon activation
992  * @n_args:      number of arguments to @signal_name
993  * @Varargs:     arguments to @signal_name
994  *
995  * Override or install a new key binding for @keyval with @modifiers on
996  * @binding_set. When the binding is activated, @signal_name will be
997  * emitted on the target widget, with @n_args @Varargs used as
998  * arguments.
999  */
1000 void
1001 gtk_binding_entry_add_signal (GtkBindingSet  *binding_set,
1002                               guint           keyval,
1003                               GdkModifierType modifiers,
1004                               const gchar    *signal_name,
1005                               guint           n_args,
1006                               ...)
1007 {
1008   GSList *slist, *free_slist;
1009   va_list args;
1010   guint i;
1011
1012   g_return_if_fail (binding_set != NULL);
1013   g_return_if_fail (signal_name != NULL);
1014
1015   va_start (args, n_args);
1016   slist = NULL;
1017   for (i = 0; i < n_args; i++)
1018     {
1019       GtkBindingArg *arg;
1020
1021       arg = g_slice_new0 (GtkBindingArg);
1022       slist = g_slist_prepend (slist, arg);
1023
1024       arg->arg_type = va_arg (args, GType);
1025       switch (G_TYPE_FUNDAMENTAL (arg->arg_type))
1026         {
1027         case G_TYPE_CHAR:
1028         case G_TYPE_UCHAR:
1029         case G_TYPE_INT:
1030         case G_TYPE_UINT:
1031         case G_TYPE_BOOLEAN:
1032         case G_TYPE_ENUM:
1033         case G_TYPE_FLAGS:
1034           arg->arg_type = G_TYPE_LONG;
1035           arg->d.long_data = va_arg (args, gint);
1036           break;
1037         case G_TYPE_LONG:
1038         case G_TYPE_ULONG:
1039           arg->arg_type = G_TYPE_LONG;
1040           arg->d.long_data = va_arg (args, glong);
1041           break;
1042         case G_TYPE_FLOAT:
1043         case G_TYPE_DOUBLE:
1044           arg->arg_type = G_TYPE_DOUBLE;
1045           arg->d.double_data = va_arg (args, gdouble);
1046           break;
1047         case G_TYPE_STRING:
1048           if (arg->arg_type != GTK_TYPE_IDENTIFIER)
1049             arg->arg_type = G_TYPE_STRING;
1050           arg->d.string_data = va_arg (args, gchar*);
1051           if (!arg->d.string_data)
1052             {
1053               g_warning ("gtk_binding_entry_add_signal(): type `%s' arg[%u] is `NULL'",
1054                          g_type_name (arg->arg_type),
1055                          i);
1056               i += n_args + 1;
1057             }
1058           break;
1059         default:
1060           g_warning ("gtk_binding_entry_add_signal(): unsupported type `%s' for arg[%u]",
1061                      g_type_name (arg->arg_type), i);
1062           i += n_args + 1;
1063           break;
1064         }
1065     }
1066   va_end (args);
1067
1068   if (i == n_args || i == 0)
1069     {
1070       slist = g_slist_reverse (slist);
1071       _gtk_binding_entry_add_signall (binding_set, keyval, modifiers, signal_name, slist);
1072     }
1073
1074   free_slist = slist;
1075   while (slist)
1076     {
1077       g_slice_free (GtkBindingArg, slist->data);
1078       slist = slist->next;
1079     }
1080   g_slist_free (free_slist);
1081 }
1082
1083 static guint
1084 gtk_binding_parse_signal (GScanner       *scanner,
1085                           GtkBindingSet  *binding_set,
1086                           guint           keyval,
1087                           GdkModifierType modifiers)
1088 {
1089   gchar *signal;
1090   guint expected_token = 0;
1091   GSList *args;
1092   GSList *slist;
1093   gboolean done;
1094   gboolean negate;
1095   gboolean need_arg;
1096   gboolean seen_comma;
1097
1098   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1099
1100   g_scanner_get_next_token (scanner);
1101
1102   if (scanner->token != G_TOKEN_STRING)
1103     return G_TOKEN_STRING;
1104
1105   g_scanner_peek_next_token (scanner);
1106
1107   if (scanner->next_token != '(')
1108     {
1109       g_scanner_get_next_token (scanner);
1110       return '(';
1111     }
1112
1113   signal = g_strdup (scanner->value.v_string);
1114   g_scanner_get_next_token (scanner);
1115
1116   negate = FALSE;
1117   args = NULL;
1118   done = FALSE;
1119   need_arg = TRUE;
1120   seen_comma = FALSE;
1121   scanner->config->scan_symbols = FALSE;
1122
1123   do
1124     {
1125       GtkBindingArg *arg;
1126
1127       if (need_arg)
1128         expected_token = G_TOKEN_INT;
1129       else
1130         expected_token = ')';
1131
1132       g_scanner_get_next_token (scanner);
1133
1134       switch ((guint) scanner->token)
1135         {
1136         case G_TOKEN_FLOAT:
1137           if (need_arg)
1138             {
1139               need_arg = FALSE;
1140               arg = g_new (GtkBindingArg, 1);
1141               arg->arg_type = G_TYPE_DOUBLE;
1142               arg->d.double_data = scanner->value.v_float;
1143
1144               if (negate)
1145                 {
1146                   arg->d.double_data = - arg->d.double_data;
1147                   negate = FALSE;
1148                 }
1149               args = g_slist_prepend (args, arg);
1150             }
1151           else
1152             done = TRUE;
1153
1154           break;
1155         case G_TOKEN_INT:
1156           if (need_arg)
1157             {
1158               need_arg = FALSE;
1159               arg = g_new (GtkBindingArg, 1);
1160               arg->arg_type = G_TYPE_LONG;
1161               arg->d.long_data = scanner->value.v_int;
1162
1163               if (negate)
1164                 {
1165                   arg->d.long_data = - arg->d.long_data;
1166                   negate = FALSE;
1167                 }
1168               args = g_slist_prepend (args, arg);
1169             }
1170           else
1171             done = TRUE;
1172           break;
1173         case G_TOKEN_STRING:
1174           if (need_arg && !negate)
1175             {
1176               need_arg = FALSE;
1177               arg = g_new (GtkBindingArg, 1);
1178               arg->arg_type = G_TYPE_STRING;
1179               arg->d.string_data = g_strdup (scanner->value.v_string);
1180               args = g_slist_prepend (args, arg);
1181             }
1182           else
1183             done = TRUE;
1184
1185           break;
1186         case G_TOKEN_IDENTIFIER:
1187           if (need_arg && !negate)
1188             {
1189               need_arg = FALSE;
1190               arg = g_new (GtkBindingArg, 1);
1191               arg->arg_type = GTK_TYPE_IDENTIFIER;
1192               arg->d.string_data = g_strdup (scanner->value.v_identifier);
1193               args = g_slist_prepend (args, arg);
1194             }
1195           else
1196             done = TRUE;
1197
1198           break;
1199         case '-':
1200           if (!need_arg)
1201             done = TRUE;
1202           else if (negate)
1203             {
1204               expected_token = G_TOKEN_INT;
1205               done = TRUE;
1206             }
1207           else
1208             negate = TRUE;
1209
1210           break;
1211         case ',':
1212           seen_comma = TRUE;
1213           if (need_arg)
1214             done = TRUE;
1215           else
1216             need_arg = TRUE;
1217
1218           break;
1219         case ')':
1220           if (!(need_arg && seen_comma) && !negate)
1221             {
1222               args = g_slist_reverse (args);
1223               _gtk_binding_entry_add_signall (binding_set,
1224                                               keyval,
1225                                               modifiers,
1226                                               signal,
1227                                               args);
1228               expected_token = G_TOKEN_NONE;
1229             }
1230
1231           done = TRUE;
1232           break;
1233         default:
1234           done = TRUE;
1235           break;
1236         }
1237     }
1238   while (!done);
1239
1240   scanner->config->scan_symbols = TRUE;
1241
1242   for (slist = args; slist; slist = slist->next)
1243     {
1244       GtkBindingArg *arg;
1245
1246       arg = slist->data;
1247
1248       if (G_TYPE_FUNDAMENTAL (arg->arg_type) == G_TYPE_STRING)
1249         g_free (arg->d.string_data);
1250       g_free (arg);
1251     }
1252
1253   g_slist_free (args);
1254   g_free (signal);
1255
1256   return expected_token;
1257 }
1258
1259 static inline guint
1260 gtk_binding_parse_bind (GScanner       *scanner,
1261                         GtkBindingSet  *binding_set)
1262 {
1263   guint keyval = 0;
1264   GdkModifierType modifiers = 0;
1265   gboolean unbind = FALSE;
1266
1267   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1268
1269   g_scanner_get_next_token (scanner);
1270
1271   if (scanner->token != G_TOKEN_SYMBOL)
1272     return G_TOKEN_SYMBOL;
1273
1274   if (scanner->value.v_symbol != GUINT_TO_POINTER (GTK_BINDING_TOKEN_BIND) &&
1275       scanner->value.v_symbol != GUINT_TO_POINTER (GTK_BINDING_TOKEN_UNBIND))
1276     return G_TOKEN_SYMBOL;
1277
1278   unbind = (scanner->value.v_symbol == GUINT_TO_POINTER (GTK_BINDING_TOKEN_UNBIND));
1279   g_scanner_get_next_token (scanner);
1280
1281   if (scanner->token != (guint) G_TOKEN_STRING)
1282     return G_TOKEN_STRING;
1283
1284   gtk_accelerator_parse (scanner->value.v_string, &keyval, &modifiers);
1285   modifiers &= BINDING_MOD_MASK ();
1286
1287   if (keyval == 0)
1288     return G_TOKEN_STRING;
1289
1290   if (unbind)
1291     {
1292       gtk_binding_entry_skip (binding_set, keyval, modifiers);
1293       return G_TOKEN_NONE;
1294     }
1295
1296   g_scanner_get_next_token (scanner);
1297
1298   if (scanner->token != '{')
1299     return '{';
1300
1301   gtk_binding_entry_clear_internal (binding_set, keyval, modifiers);
1302   g_scanner_peek_next_token (scanner);
1303
1304   while (scanner->next_token != '}')
1305     {
1306       guint expected_token;
1307
1308       switch (scanner->next_token)
1309         {
1310         case G_TOKEN_STRING:
1311           expected_token = gtk_binding_parse_signal (scanner,
1312                                                      binding_set,
1313                                                      keyval,
1314                                                      modifiers);
1315           if (expected_token != G_TOKEN_NONE)
1316             return expected_token;
1317           break;
1318         default:
1319           g_scanner_get_next_token (scanner);
1320           return '}';
1321         }
1322
1323       g_scanner_peek_next_token (scanner);
1324     }
1325
1326   g_scanner_get_next_token (scanner);
1327
1328   return G_TOKEN_NONE;
1329 }
1330
1331 static GScanner *
1332 create_signal_scanner (void)
1333 {
1334   GScanner *scanner;
1335
1336   scanner = g_scanner_new (NULL);
1337   scanner->config->cset_identifier_nth = G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "-_";
1338
1339   g_scanner_scope_add_symbol (scanner, 0, "bind", GUINT_TO_POINTER (GTK_BINDING_TOKEN_BIND));
1340   g_scanner_scope_add_symbol (scanner, 0, "unbind", GUINT_TO_POINTER (GTK_BINDING_TOKEN_UNBIND));
1341
1342   g_scanner_set_scope (scanner, 0);
1343
1344   return scanner;
1345 }
1346
1347 /**
1348  * gtk_binding_entry_add_signal_from_string:
1349  * @binding_set: a #GtkBindingSet
1350  * @signal_desc: a signal description
1351  *
1352  * Parses a signal description from @signal_desc and incorporates
1353  * it into @binding_set.
1354  *
1355  * signal descriptions may either bind a key combination to
1356  * one or more signals:
1357  * <informalexample><programlisting>
1358  *   bind <replaceable>key</replaceable> {
1359  *     <replaceable>signalname</replaceable> (<replaceable>param</replaceable>, ...)
1360  *     ...
1361  *   }
1362  * </programlisting></informalexample>
1363  *
1364  * Or they may also unbind a key combination:
1365  * <informalexample><programlisting>
1366  *   unbind <replaceable>key</replaceable>
1367  * </programlisting></informalexample>
1368  *
1369  * Key combinations must be in a format that can be parsed by
1370  * gtk_accelerator_parse().
1371  *
1372  * Returns: %G_TOKEN_NONE if the signal was successfully parsed and added,
1373  *     the expected token otherwise
1374  *
1375  * Since: 3.0
1376  */
1377 GTokenType
1378 gtk_binding_entry_add_signal_from_string (GtkBindingSet *binding_set,
1379                                           const gchar   *signal_desc)
1380 {
1381   static GScanner *scanner = NULL;
1382   GTokenType ret;
1383
1384   g_return_val_if_fail (binding_set != NULL, G_TOKEN_NONE);
1385   g_return_val_if_fail (signal_desc != NULL, G_TOKEN_NONE);
1386
1387   if (G_UNLIKELY (!scanner))
1388     scanner = create_signal_scanner ();
1389
1390   g_scanner_input_text (scanner, signal_desc,
1391                         (guint) strlen (signal_desc));
1392
1393   ret = gtk_binding_parse_bind (scanner, binding_set);
1394
1395   /* Reset for next use */
1396   g_scanner_set_scope (scanner, 0);
1397
1398   return ret;
1399 }
1400
1401 /**
1402  * gtk_binding_set_add_path:
1403  * @binding_set: a #GtkBindingSet to add a path to
1404  * @path_type: path type the pattern applies to
1405  * @path_pattern: the actual match pattern
1406  * @priority: binding priority
1407  *
1408  * This function is used internally by the GtkRC parsing mechanism to
1409  * assign match patterns to #GtkBindingSet structures.
1410  *
1411  * Deprecated: 3.0
1412  */
1413 void
1414 gtk_binding_set_add_path (GtkBindingSet       *binding_set,
1415                           GtkPathType          path_type,
1416                           const gchar         *path_pattern,
1417                           GtkPathPriorityType  priority)
1418 {
1419   PatternSpec *pspec;
1420   GSList **slist_p, *slist;
1421   static guint seq_id = 0;
1422
1423   g_return_if_fail (binding_set != NULL);
1424   g_return_if_fail (path_pattern != NULL);
1425   g_return_if_fail (priority <= GTK_PATH_PRIO_MASK);
1426
1427   priority &= GTK_PATH_PRIO_MASK;
1428
1429   switch (path_type)
1430     {
1431     case  GTK_PATH_WIDGET:
1432       slist_p = &binding_set->widget_path_pspecs;
1433       break;
1434     case  GTK_PATH_WIDGET_CLASS:
1435       slist_p = &binding_set->widget_class_pspecs;
1436       break;
1437     case  GTK_PATH_CLASS:
1438       slist_p = &binding_set->class_branch_pspecs;
1439       break;
1440     default:
1441       g_assert_not_reached ();
1442       slist_p = NULL;
1443       break;
1444     }
1445
1446   pspec = g_new (PatternSpec, 1);
1447   pspec->type = path_type;
1448   if (path_type == GTK_PATH_WIDGET_CLASS)
1449     pspec->pspec = NULL;
1450   else
1451     pspec->pspec = g_pattern_spec_new (path_pattern);
1452
1453   pspec->seq_id = priority << 28;
1454   pspec->user_data = binding_set;
1455
1456   slist = *slist_p;
1457   while (slist)
1458     {
1459       PatternSpec *tmp_pspec;
1460
1461       tmp_pspec = slist->data;
1462       slist = slist->next;
1463
1464       if (g_pattern_spec_equal (tmp_pspec->pspec, pspec->pspec))
1465         {
1466           GtkPathPriorityType lprio = tmp_pspec->seq_id >> 28;
1467
1468           pattern_spec_free (pspec);
1469           pspec = NULL;
1470           if (lprio < priority)
1471             {
1472               tmp_pspec->seq_id &= 0x0fffffff;
1473               tmp_pspec->seq_id |= priority << 28;
1474             }
1475           break;
1476         }
1477     }
1478   if (pspec)
1479     {
1480       pspec->seq_id |= seq_id++ & 0x0fffffff;
1481       *slist_p = g_slist_prepend (*slist_p, pspec);
1482     }
1483 }
1484
1485 static gint
1486 find_entry_with_binding (GtkBindingEntry *entry,
1487                          GtkBindingSet   *binding_set)
1488 {
1489   return (entry->binding_set == binding_set) ? 0 : 1;
1490 }
1491
1492 static gboolean
1493 binding_activate (GtkBindingSet *binding_set,
1494                   GSList        *entries,
1495                   GObject       *object,
1496                   gboolean       is_release,
1497                   gboolean      *unbound)
1498 {
1499   GtkBindingEntry *entry;
1500   GSList *elem;
1501
1502   elem = g_slist_find_custom (entries, binding_set,
1503                               (GCompareFunc) find_entry_with_binding);
1504
1505   if (!elem)
1506     return FALSE;
1507
1508   entry = elem->data;
1509
1510   if (is_release != ((entry->modifiers & GDK_RELEASE_MASK) != 0))
1511     return FALSE;
1512
1513   if (entry->marks_unbound)
1514     {
1515       *unbound = TRUE;
1516       return FALSE;
1517     }
1518
1519   if (gtk_binding_entry_activate (entry, object))
1520     return TRUE;
1521
1522   return FALSE;
1523 }
1524
1525 static gboolean
1526 gtk_bindings_activate_list (GObject  *object,
1527                             GSList   *entries,
1528                             gboolean  is_release)
1529 {
1530   GtkStyleContext *context;
1531   GtkBindingSet *binding_set;
1532   GtkStateFlags state;
1533   gboolean handled = FALSE;
1534   gboolean unbound = FALSE;
1535   GPtrArray *array;
1536
1537   if (!entries)
1538     return FALSE;
1539
1540   context = gtk_widget_get_style_context (GTK_WIDGET (object));
1541   state = gtk_widget_get_state_flags (GTK_WIDGET (object));
1542
1543   gtk_style_context_get (context, state,
1544                          "gtk-key-bindings", &array,
1545                          NULL);
1546   if (array)
1547     {
1548       gint i;
1549
1550       for (i = 0; i < array->len; i++)
1551         {
1552           binding_set = g_ptr_array_index (array, i);
1553           handled = binding_activate (binding_set, entries,
1554                                       object, is_release,
1555                                       &unbound);
1556           if (handled)
1557             break;
1558         }
1559
1560       g_ptr_array_unref (array);
1561
1562       if (unbound)
1563         return FALSE;
1564     }
1565
1566   if (!handled)
1567     {
1568       GType class_type;
1569
1570       class_type = G_TYPE_FROM_INSTANCE (object);
1571
1572       while (class_type && !handled)
1573         {
1574           binding_set = gtk_binding_set_find (g_type_name (class_type));
1575           class_type = g_type_parent (class_type);
1576
1577           if (!binding_set)
1578             continue;
1579
1580           handled = binding_activate (binding_set, entries,
1581                                       object, is_release,
1582                                       &unbound);
1583         }
1584
1585       if (unbound)
1586         return FALSE;
1587     }
1588
1589   return handled;
1590 }
1591
1592 /**
1593  * gtk_bindings_activate:
1594  * @object: object to activate when binding found
1595  * @keyval: key value of the binding
1596  * @modifiers: key modifier of the binding
1597  *
1598  * Find a key binding matching @keyval and @modifiers and activate the
1599  * binding on @object.
1600  *
1601  * Return value: %TRUE if a binding was found and activated
1602  */
1603 gboolean
1604 gtk_bindings_activate (GObject         *object,
1605                        guint            keyval,
1606                        GdkModifierType  modifiers)
1607 {
1608   GSList *entries = NULL;
1609   GdkDisplay *display;
1610   GtkKeyHash *key_hash;
1611   gboolean handled = FALSE;
1612   gboolean is_release;
1613
1614   if (!GTK_IS_WIDGET (object))
1615     return FALSE;
1616
1617   is_release = (modifiers & GDK_RELEASE_MASK) != 0;
1618   modifiers = modifiers & BINDING_MOD_MASK () & ~GDK_RELEASE_MASK;
1619
1620   display = gtk_widget_get_display (GTK_WIDGET (object));
1621   key_hash = binding_key_hash_for_keymap (gdk_keymap_get_for_display (display));
1622
1623   entries = _gtk_key_hash_lookup_keyval (key_hash, keyval, modifiers);
1624
1625   handled = gtk_bindings_activate_list (object, entries, is_release);
1626
1627   g_slist_free (entries);
1628
1629   return handled;
1630 }
1631
1632 /**
1633  * gtk_bindings_activate_event:
1634  * @object: a #GObject (generally must be a widget)
1635  * @event: a #GdkEventKey
1636  *
1637  * Looks up key bindings for @object to find one matching
1638  * @event, and if one was found, activate it.
1639  *
1640  * Return value: %TRUE if a matching key binding was found
1641  *
1642  * Since: 2.4
1643  */
1644 gboolean
1645 gtk_bindings_activate_event (GObject     *object,
1646                              GdkEventKey *event)
1647 {
1648   GSList *entries = NULL;
1649   GdkDisplay *display;
1650   GtkKeyHash *key_hash;
1651   gboolean handled = FALSE;
1652
1653   if (!GTK_IS_WIDGET (object))
1654     return FALSE;
1655
1656   display = gtk_widget_get_display (GTK_WIDGET (object));
1657   key_hash = binding_key_hash_for_keymap (gdk_keymap_get_for_display (display));
1658
1659   entries = _gtk_key_hash_lookup (key_hash,
1660                                   event->hardware_keycode,
1661                                   event->state,
1662                                   BINDING_MOD_MASK () & ~GDK_RELEASE_MASK,
1663                                   event->group);
1664
1665   handled = gtk_bindings_activate_list (object, entries,
1666                                         event->type == GDK_KEY_RELEASE);
1667
1668   g_slist_free (entries);
1669
1670   return handled;
1671 }