]> Pileus Git - ~andy/gtk/blob - gtk/gtkbindings.c
Fixes #136082 and #135265, patch by Morten Welinder.
[~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 GtkObjects.
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 #include <gdkkeysyms.h>
34 #include "gtkbindings.h"
35 #include "gtkkeyhash.h"
36 #include "gtkwidget.h"
37 #include "gtkrc.h"
38
39
40 /* --- defines --- */
41 #define BINDING_MOD_MASK()      (gtk_accelerator_get_default_mod_mask () | GDK_RELEASE_MASK)
42
43
44 /* --- structures --- */
45 typedef struct {
46   GPatternSpec *pspec;
47   gpointer user_data;
48   guint seq_id;
49 } PatternSpec;
50
51
52 /* --- variables --- */
53 static GHashTable       *binding_entry_hash_table = NULL;
54 static GSList           *binding_key_hashes = NULL;
55 static GSList           *binding_set_list = NULL;
56 static const gchar      *key_class_binding_set = "gtk-class-binding-set";
57 static GQuark            key_id_class_binding_set = 0;
58
59
60 /* --- functions --- */
61 static GtkBindingSignal*
62 binding_signal_new (const gchar *signal_name,
63                     guint        n_args)
64 {
65   GtkBindingSignal *signal;
66   
67   signal = g_new (GtkBindingSignal, 1);
68   signal->next = NULL;
69   signal->signal_name = g_strdup (signal_name);
70   signal->n_args = n_args;
71   signal->args = g_new0 (GtkBindingArg, n_args);
72   
73   return signal;
74 }
75
76 static void
77 binding_signal_free (GtkBindingSignal *sig)
78 {
79   guint i;
80   
81   for (i = 0; i < sig->n_args; i++)
82     {
83       if (G_TYPE_FUNDAMENTAL (sig->args[i].arg_type) == G_TYPE_STRING)
84         g_free (sig->args[i].d.string_data);
85     }
86   g_free (sig->args);
87   g_free (sig->signal_name);
88   g_free (sig);
89 }
90
91 static guint
92 binding_entry_hash (gconstpointer  key)
93 {
94   register const GtkBindingEntry *e = key;
95   register guint h;
96
97   h = e->keyval;
98   h ^= e->modifiers;
99
100   return h;
101 }
102
103 static gint
104 binding_entries_compare (gconstpointer  a,
105                          gconstpointer  b)
106 {
107   register const GtkBindingEntry *ea = a;
108   register const GtkBindingEntry *eb = b;
109
110   return (ea->keyval == eb->keyval && ea->modifiers == eb->modifiers);
111 }
112
113 static void
114 binding_key_hash_insert_entry (GtkKeyHash      *key_hash,
115                                GtkBindingEntry *entry)
116 {
117   guint keyval = entry->keyval;
118   
119   /* We store lowercased accelerators. To deal with this, if <Shift>
120    * was specified, uppercase.
121    */
122   if (entry->modifiers & GDK_SHIFT_MASK)
123     {
124       if (keyval == GDK_Tab)
125         keyval = GDK_ISO_Left_Tab;
126       else
127         keyval = gdk_keyval_to_upper (keyval);
128     }
129   
130   _gtk_key_hash_add_entry (key_hash, keyval, entry->modifiers & ~GDK_RELEASE_MASK, entry);
131 }
132
133 static void
134 binding_key_hash_destroy (gpointer data)
135 {
136   GtkKeyHash *key_hash = data;
137   
138   binding_key_hashes = g_slist_remove (binding_key_hashes, key_hash);
139   _gtk_key_hash_free (key_hash);
140 }
141
142 static void
143 insert_entries_into_key_hash (gpointer key,
144                               gpointer value,
145                               gpointer data)
146 {
147   GtkKeyHash *key_hash = data;
148   GtkBindingEntry *entry = value;
149
150   for (; entry; entry = entry->hash_next)
151     binding_key_hash_insert_entry (key_hash, entry);
152 }
153
154 static GtkKeyHash *
155 binding_key_hash_for_keymap (GdkKeymap *keymap)
156 {
157   static GQuark key_hash_quark = 0;
158   GtkKeyHash *key_hash;
159
160   if (!key_hash_quark)
161     key_hash_quark = g_quark_from_static_string ("gtk-binding-key-hash");
162   
163   key_hash = g_object_get_qdata (G_OBJECT (keymap), key_hash_quark);
164
165   if (!key_hash)
166     {
167       key_hash = _gtk_key_hash_new (keymap, NULL);
168       g_object_set_qdata_full (G_OBJECT (keymap), key_hash_quark, key_hash, binding_key_hash_destroy);
169
170       if (binding_entry_hash_table)
171         g_hash_table_foreach (binding_entry_hash_table,
172                               insert_entries_into_key_hash,
173                               key_hash);
174
175       binding_key_hashes = g_slist_prepend (binding_key_hashes, key_hash);
176     }
177
178   return key_hash;
179 }
180
181
182 static GtkBindingEntry*
183 binding_entry_new (GtkBindingSet  *binding_set,
184                    guint           keyval,
185                    GdkModifierType modifiers)
186 {
187   GSList *tmp_list;
188   GtkBindingEntry *entry;
189   
190   if (!binding_entry_hash_table)
191     binding_entry_hash_table = g_hash_table_new (binding_entry_hash, binding_entries_compare);
192
193   entry = g_new (GtkBindingEntry, 1);
194   entry->keyval = keyval;
195   entry->modifiers = modifiers;
196   entry->binding_set = binding_set,
197   entry->destroyed = FALSE;
198   entry->in_emission = FALSE;
199   entry->signals = NULL;
200
201   entry->set_next = binding_set->entries;
202   binding_set->entries = entry;
203
204   entry->hash_next = g_hash_table_lookup (binding_entry_hash_table, entry);
205   if (entry->hash_next)
206     g_hash_table_remove (binding_entry_hash_table, entry->hash_next);
207   g_hash_table_insert (binding_entry_hash_table, entry, entry);
208
209   for (tmp_list = binding_key_hashes; tmp_list; tmp_list = tmp_list->next)
210     {
211       GtkKeyHash *key_hash = tmp_list->data;
212       binding_key_hash_insert_entry (key_hash, entry);
213     }
214   
215   return entry;
216 }
217
218 static void
219 binding_entry_free (GtkBindingEntry *entry)
220 {
221   GtkBindingSignal *sig;
222
223   g_assert (entry->set_next == NULL &&
224             entry->hash_next == NULL &&
225             entry->in_emission == FALSE &&
226             entry->destroyed == TRUE);
227
228   entry->destroyed = FALSE;
229   
230   sig = entry->signals;
231   while (sig)
232     {
233       GtkBindingSignal *prev;
234       
235       prev = sig;
236       sig = prev->next;
237       binding_signal_free (prev);
238     }
239   g_free (entry);
240 }
241
242 static void
243 binding_entry_destroy (GtkBindingEntry *entry)
244 {
245   GtkBindingEntry *o_entry;
246   register GtkBindingEntry *tmp;
247   GtkBindingEntry *begin;
248   register GtkBindingEntry *last;
249   GSList *tmp_list;
250
251   /* unlink from binding set
252    */
253   last = NULL;
254   tmp = entry->binding_set->entries;
255   while (tmp)
256     {
257       if (tmp == entry)
258         {
259           if (last)
260             last->set_next = entry->set_next;
261           else
262             entry->binding_set->entries = entry->set_next;
263           break;
264         }
265       last = tmp;
266       tmp = last->set_next;
267     }
268   entry->set_next = NULL;
269   
270   o_entry = g_hash_table_lookup (binding_entry_hash_table, entry);
271   begin = o_entry;
272   last = NULL;
273   tmp = begin;
274   while (tmp)
275     {
276       if (tmp == entry)
277         {
278           if (last)
279             last->hash_next = entry->hash_next;
280           else
281             begin = entry->hash_next;
282           break;
283         }
284       last = tmp;
285       tmp = last->hash_next;
286     }
287   entry->hash_next = NULL;
288   
289   if (!begin)
290     g_hash_table_remove (binding_entry_hash_table, entry);
291   else if (begin != o_entry)
292     {
293       g_hash_table_remove (binding_entry_hash_table, entry);
294       g_hash_table_insert (binding_entry_hash_table, begin, begin);
295     }
296
297   for (tmp_list = binding_key_hashes; tmp_list; tmp_list = tmp_list->next)
298     {
299       GtkKeyHash *key_hash = tmp_list->data;
300       _gtk_key_hash_remove_entry (key_hash, entry);
301     }
302
303   entry->destroyed = TRUE;
304
305   if (!entry->in_emission)
306     binding_entry_free (entry);
307 }
308
309 static GtkBindingEntry*
310 binding_ht_lookup_entry (GtkBindingSet  *set,
311                          guint           keyval,
312                          GdkModifierType modifiers)
313 {
314   GtkBindingEntry lookup_entry = { 0 };
315   GtkBindingEntry *entry;
316   
317   if (!binding_entry_hash_table)
318     return NULL;
319   
320   lookup_entry.keyval = keyval;
321   lookup_entry.modifiers = modifiers;
322   
323   entry = g_hash_table_lookup (binding_entry_hash_table, &lookup_entry);
324   for (; entry; entry = entry->hash_next)
325     if (entry->binding_set == set)
326       return entry;
327
328   return NULL;
329 }
330
331 static gboolean
332 binding_compose_params (GtkObject       *object,
333                         GtkBindingArg   *args,
334                         GSignalQuery    *query,
335                         GValue         **params_p)
336 {
337   GValue *params;
338   const GType *types;
339   guint i;
340   gboolean valid;
341   
342   params = g_new0 (GValue, query->n_params + 1);
343   *params_p = params;
344
345   /* The instance we emit on is the first object in the array
346    */
347   g_value_init (params, G_TYPE_OBJECT);
348   g_value_set_object (params, G_OBJECT (object));
349   params++;
350   
351   types = query->param_types;
352   valid = TRUE;
353   for (i = 1; i < query->n_params + 1 && valid; i++)
354     {
355       GValue tmp_value = { 0, };
356
357       g_value_init (params, *types);
358
359       switch (G_TYPE_FUNDAMENTAL (args->arg_type))
360         {
361         case G_TYPE_DOUBLE:
362           g_value_init (&tmp_value, G_TYPE_DOUBLE);
363           g_value_set_double (&tmp_value, args->d.double_data);
364           break;
365         case G_TYPE_LONG:
366           g_value_init (&tmp_value, G_TYPE_LONG);
367           g_value_set_long (&tmp_value, args->d.long_data);
368           break;
369         case G_TYPE_STRING:
370           /* gtk_rc_parse_flags/enum() has fancier parsing for this; we can't call
371            * that since we don't have a GParamSpec, so just do something simple
372            */
373           if (G_TYPE_FUNDAMENTAL (*types) == G_TYPE_ENUM)
374             {
375               GEnumClass *class = G_ENUM_CLASS (g_type_class_ref (*types));
376               
377               valid = FALSE;
378               
379               if (args->arg_type == GTK_TYPE_IDENTIFIER)
380                 {
381                   GEnumValue *enum_value = NULL;
382                   enum_value = g_enum_get_value_by_name (class, args->d.string_data);
383                   if (!enum_value)
384                     enum_value = g_enum_get_value_by_nick (class, args->d.string_data);
385                   if (enum_value)
386                     {
387                       g_value_init (&tmp_value, *types);
388                       g_value_set_enum (&tmp_value, enum_value->value);
389                       valid = TRUE;
390                     }
391                 }
392
393               g_type_class_unref (class);
394             }
395           /* This is just a hack for compatibility with GTK+-1.2 where a string
396            * could be used for a single flag value / without the support for multiple
397            * values in gtk_rc_parse_flags(), this isn't very useful.
398            */
399           else if (G_TYPE_FUNDAMENTAL (*types) == G_TYPE_FLAGS)
400             {
401               GFlagsClass *class = G_FLAGS_CLASS (g_type_class_ref (*types));
402               
403               valid = FALSE;
404               
405               if (args->arg_type == GTK_TYPE_IDENTIFIER)
406                 {
407                   GFlagsValue *flags_value = NULL;
408                   flags_value = g_flags_get_value_by_name (class, args->d.string_data);
409                   if (!flags_value)
410                     flags_value = g_flags_get_value_by_nick (class, args->d.string_data);
411                   if (flags_value)
412                     {
413                       g_value_init (&tmp_value, *types);
414                       g_value_set_flags (&tmp_value, flags_value->value);
415                       valid = TRUE;
416                     }
417                 }
418
419               g_type_class_unref (class);
420             }
421           else
422             {
423               g_value_init (&tmp_value, G_TYPE_STRING);
424               g_value_set_static_string (&tmp_value, args->d.string_data);
425             }
426           break;
427         default:
428           valid = FALSE;
429           break;
430         }
431
432       if (valid)
433         {
434           if (!g_value_transform (&tmp_value, params))
435             valid = FALSE;
436
437           g_value_unset (&tmp_value);
438         }
439       
440       types++;
441       params++;
442       args++;
443     }
444   
445   if (!valid)
446     {
447       guint j;
448
449       for (j = 0; j < i; j++)
450         g_value_unset (&(*params_p)[j]);
451       
452       g_free (*params_p);
453       *params_p = NULL;
454     }
455   
456   return valid;
457 }
458
459 static gboolean
460 gtk_binding_entry_activate (GtkBindingEntry *entry,
461                             GtkObject       *object)
462 {
463   GtkBindingSignal *sig;
464   gboolean old_emission;
465   gboolean handled = FALSE;
466   gint i;
467   
468   old_emission = entry->in_emission;
469   entry->in_emission = TRUE;
470   
471   g_object_ref (object);
472   
473   for (sig = entry->signals; sig; sig = sig->next)
474     {
475       GSignalQuery query;
476       guint signal_id;
477       GValue *params = NULL;
478       GValue return_val = { 0, };
479       gchar *accelerator = NULL;
480       
481       signal_id = g_signal_lookup (sig->signal_name, G_OBJECT_TYPE (object));
482       if (!signal_id)
483         {
484           accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
485           g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
486                      "could not find signal \"%s\" in the `%s' class ancestry",
487                      entry->binding_set->set_name,
488                      accelerator,
489                      sig->signal_name,
490                      g_type_name (G_OBJECT_TYPE (object)));
491           g_free (accelerator);
492           continue;
493         }
494       
495       g_signal_query (signal_id, &query);
496       if (query.n_params != sig->n_args ||
497           (query.return_type != G_TYPE_NONE && query.return_type != G_TYPE_BOOLEAN) || 
498           !binding_compose_params (object, sig->args, &query, &params))
499         {
500           accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
501           g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
502                      "signature mismatch for signal \"%s\" in the `%s' class ancestry",
503                      entry->binding_set->set_name,
504                      accelerator,
505                      sig->signal_name,
506                      g_type_name (G_OBJECT_TYPE (object)));
507         }
508       else if (!(query.signal_flags & G_SIGNAL_ACTION))
509         {
510           accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
511           g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
512                      "signal \"%s\" in the `%s' class ancestry cannot be used for action emissions",
513                      entry->binding_set->set_name,
514                      accelerator,
515                      sig->signal_name,
516                      g_type_name (G_OBJECT_TYPE (object)));
517         }
518       g_free (accelerator);
519       if (accelerator)
520         continue;
521
522       if (query.return_type == G_TYPE_BOOLEAN)
523         g_value_init (&return_val, G_TYPE_BOOLEAN);
524       
525       g_signal_emitv (params, signal_id, 0, &return_val);
526
527       if (query.return_type == G_TYPE_BOOLEAN)
528         {
529           if (g_value_get_boolean (&return_val))
530             handled = TRUE;
531           g_value_unset (&return_val);
532         }
533       else
534         handled = TRUE;
535       
536       for (i = 0; i < query.n_params + 1; i++)
537         g_value_unset (&params[i]);
538       g_free (params);
539       
540       if (entry->destroyed)
541         break;
542     }
543   
544   g_object_unref (object);
545
546   entry->in_emission = old_emission;
547   if (entry->destroyed && !entry->in_emission)
548     binding_entry_free (entry);
549
550   return handled;
551 }
552
553 GtkBindingSet*
554 gtk_binding_set_new (const gchar    *set_name)
555 {
556   GtkBindingSet *binding_set;
557   
558   g_return_val_if_fail (set_name != NULL, NULL);
559   
560   binding_set = g_new (GtkBindingSet, 1);
561   binding_set->set_name = g_strdup (set_name);
562   binding_set->widget_path_pspecs = NULL;
563   binding_set->widget_class_pspecs = NULL;
564   binding_set->class_branch_pspecs = NULL;
565   binding_set->entries = NULL;
566   binding_set->current = NULL;
567   binding_set->parsed = FALSE;
568   
569   binding_set_list = g_slist_prepend (binding_set_list, binding_set);
570   
571   return binding_set;
572 }
573
574 GtkBindingSet*
575 gtk_binding_set_by_class (gpointer object_class)
576 {
577   GtkObjectClass *class = object_class;
578   GtkBindingSet* binding_set;
579
580   g_return_val_if_fail (GTK_IS_OBJECT_CLASS (class), NULL);
581
582   if (!key_id_class_binding_set)
583     key_id_class_binding_set = g_quark_from_static_string (key_class_binding_set);
584
585   binding_set = g_dataset_id_get_data (class, key_id_class_binding_set);
586
587   if (binding_set)
588     return binding_set;
589
590   binding_set = gtk_binding_set_new (g_type_name (G_OBJECT_CLASS_TYPE (class)));
591   gtk_binding_set_add_path (binding_set,
592                             GTK_PATH_CLASS,
593                             g_type_name (G_OBJECT_CLASS_TYPE (class)),
594                             GTK_PATH_PRIO_GTK);
595   g_dataset_id_set_data (class, key_id_class_binding_set, binding_set);
596
597   return binding_set;
598 }
599
600 GtkBindingSet*
601 gtk_binding_set_find (const gchar    *set_name)
602 {
603   GSList *slist;
604   
605   g_return_val_if_fail (set_name != NULL, NULL);
606   
607   for (slist = binding_set_list; slist; slist = slist->next)
608     {
609       GtkBindingSet *binding_set;
610       
611       binding_set = slist->data;
612       if (g_str_equal (binding_set->set_name, (gpointer) set_name))
613         return binding_set;
614     }
615   return NULL;
616 }
617
618 gboolean
619 gtk_binding_set_activate (GtkBindingSet  *binding_set,
620                           guint           keyval,
621                           GdkModifierType modifiers,
622                           GtkObject      *object)
623 {
624   GtkBindingEntry *entry;
625   
626   g_return_val_if_fail (binding_set != NULL, FALSE);
627   g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
628   
629   keyval = gdk_keyval_to_lower (keyval);
630   modifiers = modifiers & BINDING_MOD_MASK ();
631   
632   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
633   if (entry)
634     return gtk_binding_entry_activate (entry, object);
635   
636   return FALSE;
637 }
638
639 void
640 gtk_binding_entry_clear (GtkBindingSet  *binding_set,
641                          guint           keyval,
642                          GdkModifierType modifiers)
643 {
644   GtkBindingEntry *entry;
645   
646   g_return_if_fail (binding_set != NULL);
647   
648   keyval = gdk_keyval_to_lower (keyval);
649   modifiers = modifiers & BINDING_MOD_MASK ();
650   
651   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
652   if (entry)
653     binding_entry_destroy (entry);
654
655   entry = binding_entry_new (binding_set, keyval, modifiers);
656 }
657
658 void
659 gtk_binding_entry_remove (GtkBindingSet  *binding_set,
660                           guint           keyval,
661                           GdkModifierType modifiers)
662 {
663   GtkBindingEntry *entry;
664   
665   g_return_if_fail (binding_set != NULL);
666   
667   keyval = gdk_keyval_to_lower (keyval);
668   modifiers = modifiers & BINDING_MOD_MASK ();
669   
670   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
671   if (entry)
672     binding_entry_destroy (entry);
673 }
674
675 void
676 gtk_binding_entry_add_signall (GtkBindingSet  *binding_set,
677                                guint           keyval,
678                                GdkModifierType modifiers,
679                                const gchar    *signal_name,
680                                GSList         *binding_args)
681 {
682   GtkBindingEntry *entry;
683   GtkBindingSignal *signal, **signal_p;
684   GSList *slist;
685   guint n = 0;
686   GtkBindingArg *arg;
687   
688   g_return_if_fail (binding_set != NULL);
689   g_return_if_fail (signal_name != NULL);
690   
691   keyval = gdk_keyval_to_lower (keyval);
692   modifiers = modifiers & BINDING_MOD_MASK ();
693   
694   signal = binding_signal_new (signal_name, g_slist_length (binding_args));
695   
696   arg = signal->args;
697   for (slist = binding_args; slist; slist = slist->next)
698     {
699       GtkBindingArg *tmp_arg;
700       
701       tmp_arg = slist->data;
702       if (!tmp_arg)
703         {
704           g_warning ("gtk_binding_entry_add_signall(): arg[%u] is `NULL'", n);
705           binding_signal_free (signal);
706           return;
707         }
708       switch (G_TYPE_FUNDAMENTAL (tmp_arg->arg_type))
709         {
710         case  G_TYPE_LONG:
711           arg->arg_type = G_TYPE_LONG;
712           arg->d.long_data = tmp_arg->d.long_data;
713           break;
714         case  G_TYPE_DOUBLE:
715           arg->arg_type = G_TYPE_DOUBLE;
716           arg->d.double_data = tmp_arg->d.double_data;
717           break;
718         case  G_TYPE_STRING:
719           if (tmp_arg->arg_type != GTK_TYPE_IDENTIFIER)
720             arg->arg_type = G_TYPE_STRING;
721           else
722             arg->arg_type = GTK_TYPE_IDENTIFIER;
723           arg->d.string_data = g_strdup (tmp_arg->d.string_data);
724           if (!arg->d.string_data)
725             {
726               g_warning ("gtk_binding_entry_add_signall(): value of `string' arg[%u] is `NULL'", n);
727               binding_signal_free (signal);
728               return;
729             }
730           break;
731         default:
732           g_warning ("gtk_binding_entry_add_signall(): unsupported type `%s' for arg[%u]",
733                      g_type_name (arg->arg_type), n);
734           binding_signal_free (signal);
735           return;
736         }
737       arg++;
738       n++;
739     }
740   
741   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
742   if (!entry)
743     {
744       gtk_binding_entry_add (binding_set, keyval, modifiers);
745       entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
746     }
747   signal_p = &entry->signals;
748   while (*signal_p)
749     signal_p = &(*signal_p)->next;
750   *signal_p = signal;
751 }
752
753 void
754 gtk_binding_entry_add_signal (GtkBindingSet  *binding_set,
755                               guint           keyval,
756                               GdkModifierType modifiers,
757                               const gchar    *signal_name,
758                               guint           n_args,
759                               ...)
760 {
761   GSList *slist, *free_slist;
762   va_list args;
763   guint i;
764
765   g_return_if_fail (binding_set != NULL);
766   g_return_if_fail (signal_name != NULL);
767   
768   va_start (args, n_args);
769   slist = NULL;
770   for (i = 0; i < n_args; i++)
771     {
772       GtkBindingArg *arg;
773
774       arg = g_new0 (GtkBindingArg, 1);
775       slist = g_slist_prepend (slist, arg);
776
777       arg->arg_type = va_arg (args, GtkType);
778       switch (G_TYPE_FUNDAMENTAL (arg->arg_type))
779         {
780           /* for elaborated commenting about var args collection, take a look
781            * at gtk_arg_collect_value() in gtkargcollector.c
782            */
783         case G_TYPE_CHAR:
784         case G_TYPE_UCHAR:
785         case G_TYPE_INT:
786         case G_TYPE_UINT:
787         case G_TYPE_BOOLEAN:
788         case G_TYPE_ENUM:
789         case G_TYPE_FLAGS:
790           arg->arg_type = G_TYPE_LONG;
791           arg->d.long_data = va_arg (args, gint);
792           break;
793         case G_TYPE_LONG:
794         case G_TYPE_ULONG:
795           arg->arg_type = G_TYPE_LONG;
796           arg->d.long_data = va_arg (args, glong);
797           break;
798         case G_TYPE_FLOAT:
799         case G_TYPE_DOUBLE:
800           arg->arg_type = G_TYPE_DOUBLE;
801           arg->d.double_data = va_arg (args, gdouble);
802           break;
803         case G_TYPE_STRING:
804           if (arg->arg_type != GTK_TYPE_IDENTIFIER)
805             arg->arg_type = G_TYPE_STRING;
806           arg->d.string_data = va_arg (args, gchar*);
807           if (!arg->d.string_data)
808             {
809               g_warning ("gtk_binding_entry_add_signal(): type `%s' arg[%u] is `NULL'",
810                          g_type_name (arg->arg_type),
811                          i);
812               i += n_args + 1;
813             }
814           break;
815         default:
816           g_warning ("gtk_binding_entry_add_signal(): unsupported type `%s' for arg[%u]",
817                      g_type_name (arg->arg_type), i);
818           i += n_args + 1;
819           break;
820         }
821     }
822   va_end (args);
823
824   if (i == n_args || i == 0)
825     {
826       slist = g_slist_reverse (slist);
827       gtk_binding_entry_add_signall (binding_set, keyval, modifiers, signal_name, slist);
828     }
829
830   free_slist = slist;
831   while (slist)
832     {
833       g_free (slist->data);
834       slist = slist->next;
835     }
836   g_slist_free (free_slist);
837 }
838
839 void
840 gtk_binding_set_add_path (GtkBindingSet      *binding_set,
841                           GtkPathType         path_type,
842                           const gchar        *path_pattern,
843                           GtkPathPriorityType priority)
844 {
845   PatternSpec *pspec;
846   GSList **slist_p, *slist;
847   static guint seq_id = 0;
848   
849   g_return_if_fail (binding_set != NULL);
850   g_return_if_fail (path_pattern != NULL);
851   g_return_if_fail (priority <= GTK_PATH_PRIO_MASK);
852
853   priority &= GTK_PATH_PRIO_MASK;
854   
855   switch (path_type)
856     {
857     case  GTK_PATH_WIDGET:
858       slist_p = &binding_set->widget_path_pspecs;
859       break;
860     case  GTK_PATH_WIDGET_CLASS:
861       slist_p = &binding_set->widget_class_pspecs;
862       break;
863     case  GTK_PATH_CLASS:
864       slist_p = &binding_set->class_branch_pspecs;
865       break;
866     default:
867       g_assert_not_reached ();
868       slist_p = NULL;
869       break;
870     }
871   
872   pspec = g_new (PatternSpec, 1);
873   pspec->pspec = g_pattern_spec_new (path_pattern);
874   pspec->seq_id = priority << 28;
875   pspec->user_data = binding_set;
876   
877   slist = *slist_p;
878   while (slist)
879     {
880       PatternSpec *tmp_pspec;
881       
882       tmp_pspec = slist->data;
883       slist = slist->next;
884       
885       if (g_pattern_spec_equal (tmp_pspec->pspec, pspec->pspec))
886         {
887           GtkPathPriorityType lprio = tmp_pspec->seq_id >> 28;
888
889           g_pattern_spec_free (pspec->pspec);
890           g_free (pspec);
891           pspec = NULL;
892           if (lprio < priority)
893             {
894               tmp_pspec->seq_id &= 0x0fffffff;
895               tmp_pspec->seq_id |= priority << 28;
896             }
897           break;
898         }
899     }
900   if (pspec)
901     {
902       pspec->seq_id |= seq_id++ & 0x0fffffff;
903       *slist_p = g_slist_prepend (*slist_p, pspec);
904     }
905 }
906
907 static gboolean
908 binding_match_activate (GSList          *pspec_list,
909                         GtkObject       *object,
910                         guint            path_length,
911                         const gchar     *path,
912                         const gchar     *path_reversed)
913 {
914   GSList *slist;
915
916   for (slist = pspec_list; slist; slist = slist->next)
917     {
918       PatternSpec *pspec;
919
920       pspec = slist->data;
921       if (g_pattern_match (pspec->pspec, path_length, path, path_reversed))
922         {
923           GtkBindingSet *binding_set;
924
925           binding_set = pspec->user_data;
926
927           if (gtk_binding_entry_activate (binding_set->current, object))
928             return TRUE;
929         }
930     }
931
932   return FALSE;
933 }
934
935 static gint
936 gtk_binding_pattern_compare (gconstpointer new_pattern,
937                              gconstpointer existing_pattern)
938 {
939   register const PatternSpec *np  = new_pattern;
940   register const PatternSpec *ep  = existing_pattern;
941
942   /* walk the list as long as the existing patterns have
943    * higher priorities.
944    */
945
946   return np->seq_id < ep->seq_id;
947 }
948
949 static GSList*
950 gtk_binding_entries_sort_patterns (GSList      *entries,
951                                    GtkPathType  path_id,
952                                    gboolean     is_release)
953 {
954   GSList *patterns;
955   GSList *tmp_list;
956
957   patterns = NULL;
958   for (tmp_list = entries; tmp_list; tmp_list = tmp_list->next)
959     {
960       GtkBindingEntry *entry = tmp_list->data;
961       GtkBindingSet *binding_set;
962
963       binding_set = entry->binding_set;
964       binding_set->current = NULL;
965     }
966   
967   for (; entries; entries = entries->next)
968     {
969       GtkBindingEntry *entry = entries->data;
970       GtkBindingSet *binding_set;
971       GSList *slist = NULL;
972
973       if (is_release != ((entry->modifiers & GDK_RELEASE_MASK) != 0))
974         continue;
975
976       binding_set = entry->binding_set;
977
978       if (binding_set->current)
979         continue;
980       binding_set->current = entry;
981
982       switch (path_id)
983         {
984         case GTK_PATH_WIDGET:
985           slist = binding_set->widget_path_pspecs;
986           break;
987         case GTK_PATH_WIDGET_CLASS:
988           slist = binding_set->widget_class_pspecs;
989           break;
990         case GTK_PATH_CLASS:
991           slist = binding_set->class_branch_pspecs;
992           break;
993         }
994
995       for (; slist; slist = slist->next)
996         {
997           PatternSpec *pspec;
998
999           pspec = slist->data;
1000           patterns = g_slist_insert_sorted (patterns, pspec, gtk_binding_pattern_compare);
1001         }
1002     }
1003
1004   return patterns;
1005 }
1006
1007 static gboolean
1008 gtk_bindings_activate_list (GtkObject *object,
1009                             GSList    *entries,
1010                             gboolean   is_release)
1011 {
1012   GtkWidget *widget = GTK_WIDGET (object);
1013   gboolean handled = FALSE;
1014
1015   if (!entries)
1016     return FALSE;
1017
1018   if (!handled)
1019     {
1020       guint path_length;
1021       gchar *path, *path_reversed;
1022       GSList *patterns;
1023
1024       gtk_widget_path (widget, &path_length, &path, &path_reversed);
1025       patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET, is_release);
1026       handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
1027       g_slist_free (patterns);
1028       g_free (path);
1029       g_free (path_reversed);
1030     }
1031
1032   if (!handled)
1033     {
1034       guint path_length;
1035       gchar *path, *path_reversed;
1036       GSList *patterns;
1037
1038       gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
1039       patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET_CLASS, is_release);
1040       handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
1041       g_slist_free (patterns);
1042       g_free (path);
1043       g_free (path_reversed);
1044     }
1045
1046   if (!handled)
1047     {
1048       GSList *patterns;
1049       GType class_type;
1050       
1051       patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_CLASS, is_release);
1052       class_type = G_TYPE_FROM_INSTANCE (object);
1053       while (class_type && !handled)
1054         {
1055           guint path_length;
1056           const gchar *path;
1057           gchar *path_reversed;
1058           
1059           path = g_type_name (class_type);
1060           path_reversed = g_strdup (path);
1061           g_strreverse (path_reversed);
1062           path_length = strlen (path);
1063           handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
1064           g_free (path_reversed);
1065
1066           class_type = g_type_parent (class_type);
1067         }
1068       g_slist_free (patterns);
1069     }
1070
1071   return handled;
1072 }
1073
1074 gboolean
1075 gtk_bindings_activate (GtkObject      *object,
1076                        guint           keyval,
1077                        GdkModifierType modifiers)
1078 {
1079   GSList *entries = NULL;
1080   GdkDisplay *display;
1081   GtkKeyHash *key_hash;
1082   gboolean handled = FALSE;
1083   gboolean is_release;
1084
1085   g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
1086
1087   if (!GTK_IS_WIDGET (object))
1088     return FALSE;
1089
1090   is_release = (modifiers & GDK_RELEASE_MASK) != 0;
1091   modifiers = modifiers & BINDING_MOD_MASK () & ~GDK_RELEASE_MASK;
1092
1093   display = gtk_widget_get_display (GTK_WIDGET (object));
1094   key_hash = binding_key_hash_for_keymap (gdk_keymap_get_for_display (display));
1095   
1096   entries = _gtk_key_hash_lookup_keyval (key_hash, keyval, modifiers);
1097
1098   handled = gtk_bindings_activate_list (object, entries, is_release);
1099
1100   g_slist_free (entries);
1101
1102   return handled;
1103 }
1104
1105 /**
1106  * gtk_bindings_activate_event:
1107  * @object: a #GtkObject (generally must be a widget)
1108  * @event: a #GdkEventKey
1109  * 
1110  * Looks up key bindings for @object to find one matching
1111  * @event, and if one was found, activate it.
1112  * 
1113  * Return value: %TRUE if a matching key binding was found
1114  **/
1115 gboolean
1116 gtk_bindings_activate_event (GtkObject      *object,
1117                              GdkEventKey    *event)
1118 {
1119   GSList *entries = NULL;
1120   GdkDisplay *display;
1121   GtkKeyHash *key_hash;
1122   gboolean handled = FALSE;
1123
1124   g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
1125
1126   if (!GTK_IS_WIDGET (object))
1127     return FALSE;
1128
1129   display = gtk_widget_get_display (GTK_WIDGET (object));
1130   key_hash = binding_key_hash_for_keymap (gdk_keymap_get_for_display (display));
1131
1132   entries = _gtk_key_hash_lookup (key_hash,
1133                                   event->hardware_keycode,
1134                                   event->state,
1135                                   BINDING_MOD_MASK () & ~GDK_RELEASE_MASK,
1136                                   event->group);
1137   
1138   handled = gtk_bindings_activate_list (object, entries,
1139                                         event->type == GDK_KEY_RELEASE);
1140
1141   g_slist_free (entries);
1142
1143   return handled;
1144 }
1145
1146 static guint
1147 gtk_binding_parse_signal (GScanner       *scanner,
1148                           GtkBindingSet  *binding_set,
1149                           guint           keyval,
1150                           GdkModifierType modifiers)
1151 {
1152   gchar *signal;
1153   guint expected_token = 0;
1154   GSList *args;
1155   GSList *slist;
1156   gboolean done;
1157   gboolean negate;
1158   gboolean need_arg;
1159   gboolean seen_comma;
1160
1161   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1162   
1163   g_scanner_get_next_token (scanner);
1164   if (scanner->token != G_TOKEN_STRING)
1165     return G_TOKEN_STRING;
1166   g_scanner_peek_next_token (scanner);
1167   if (scanner->next_token != '(')
1168     {
1169       g_scanner_get_next_token (scanner);
1170       return '(';
1171     }
1172   signal = g_strdup (scanner->value.v_string);
1173   g_scanner_get_next_token (scanner);
1174
1175   negate = FALSE;
1176   args = NULL;
1177   done = FALSE;
1178   need_arg = TRUE;
1179   seen_comma = FALSE;
1180   scanner->config->scan_symbols = FALSE;
1181   do
1182     {
1183       if (need_arg)
1184         expected_token = G_TOKEN_INT;
1185       else
1186         expected_token = ')';
1187       g_scanner_get_next_token (scanner);
1188       switch (scanner->token)
1189         {
1190           GtkBindingArg *arg;
1191
1192         case G_TOKEN_FLOAT:
1193           if (need_arg)
1194             {
1195               need_arg = FALSE;
1196               arg = g_new (GtkBindingArg, 1);
1197               arg->arg_type = G_TYPE_DOUBLE;
1198               arg->d.double_data = scanner->value.v_float;
1199               if (negate)
1200                 {
1201                   arg->d.double_data = - arg->d.double_data;
1202                   negate = FALSE;
1203                 }
1204               args = g_slist_prepend (args, arg);
1205             }
1206           else
1207             done = TRUE;
1208           break;
1209         case G_TOKEN_INT:
1210           if (need_arg)
1211             {
1212               need_arg = FALSE;
1213               arg = g_new (GtkBindingArg, 1);
1214               arg->arg_type = G_TYPE_LONG;
1215               arg->d.long_data = scanner->value.v_int;
1216               if (negate)
1217                 {
1218                   arg->d.long_data = - arg->d.long_data;
1219                   negate = FALSE;
1220                 }
1221               args = g_slist_prepend (args, arg);
1222             }
1223           else
1224             done = TRUE;
1225           break;
1226         case G_TOKEN_STRING:
1227           if (need_arg && !negate)
1228             {
1229               need_arg = FALSE;
1230               arg = g_new (GtkBindingArg, 1);
1231               arg->arg_type = G_TYPE_STRING;
1232               arg->d.string_data = g_strdup (scanner->value.v_string);
1233               args = g_slist_prepend (args, arg);
1234             }
1235           else
1236             done = TRUE;
1237           break;
1238         case G_TOKEN_IDENTIFIER:
1239           if (need_arg && !negate)
1240             {
1241               need_arg = FALSE;
1242               arg = g_new (GtkBindingArg, 1);
1243               arg->arg_type = GTK_TYPE_IDENTIFIER;
1244               arg->d.string_data = g_strdup (scanner->value.v_identifier);
1245               args = g_slist_prepend (args, arg);
1246             }
1247           else
1248             done = TRUE;
1249           break;
1250         case '-':
1251           if (!need_arg)
1252             done = TRUE;
1253           else if (negate)
1254             {
1255               expected_token = G_TOKEN_INT;
1256               done = TRUE;
1257             }
1258           else
1259             negate = TRUE;
1260           break;
1261         case ',':
1262           seen_comma = TRUE;
1263           if (need_arg)
1264             done = TRUE;
1265           else
1266             need_arg = TRUE;
1267           break;
1268         case ')':
1269           if (!(need_arg && seen_comma) && !negate)
1270             {
1271               args = g_slist_reverse (args);
1272               gtk_binding_entry_add_signall (binding_set,
1273                                              keyval,
1274                                              modifiers,
1275                                              signal,
1276                                              args);
1277               expected_token = G_TOKEN_NONE;
1278             }
1279           done = TRUE;
1280           break;
1281         default:
1282           done = TRUE;
1283           break;
1284         }
1285     }
1286   while (!done);
1287   scanner->config->scan_symbols = TRUE;
1288   
1289   for (slist = args; slist; slist = slist->next)
1290     {
1291       GtkBindingArg *arg;
1292
1293       arg = slist->data;
1294       if (G_TYPE_FUNDAMENTAL (arg->arg_type) == G_TYPE_STRING)
1295         g_free (arg->d.string_data);
1296       g_free (arg);
1297     }
1298   g_slist_free (args);
1299   g_free (signal);
1300
1301   return expected_token;
1302 }
1303
1304 static inline guint
1305 gtk_binding_parse_bind (GScanner       *scanner,
1306                         GtkBindingSet  *binding_set)
1307 {
1308   guint keyval = 0;
1309   GdkModifierType modifiers = 0;
1310
1311   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1312   
1313   g_scanner_get_next_token (scanner);
1314   if (scanner->token != GTK_RC_TOKEN_BIND)
1315     return GTK_RC_TOKEN_BIND;
1316   g_scanner_get_next_token (scanner);
1317   if (scanner->token != G_TOKEN_STRING)
1318     return G_TOKEN_STRING;
1319   gtk_accelerator_parse (scanner->value.v_string, &keyval, &modifiers);
1320   modifiers &= BINDING_MOD_MASK ();
1321   if (keyval == 0)
1322     return G_TOKEN_STRING;
1323
1324   g_scanner_get_next_token (scanner);
1325   if (scanner->token != '{')
1326     return '{';
1327
1328   gtk_binding_entry_clear (binding_set, keyval, modifiers);
1329   
1330   g_scanner_peek_next_token (scanner);
1331   while (scanner->next_token != '}')
1332     {
1333       switch (scanner->next_token)
1334         {
1335           guint expected_token;
1336
1337         case G_TOKEN_STRING:
1338           expected_token = gtk_binding_parse_signal (scanner,
1339                                                      binding_set,
1340                                                      keyval,
1341                                                      modifiers);
1342           if (expected_token != G_TOKEN_NONE)
1343             return expected_token;
1344           break;
1345         default:
1346           g_scanner_get_next_token (scanner);
1347           return '}';
1348         }
1349       g_scanner_peek_next_token (scanner);
1350     }
1351   g_scanner_get_next_token (scanner);
1352
1353   return G_TOKEN_NONE;
1354 }
1355
1356 guint
1357 gtk_binding_parse_binding (GScanner       *scanner)
1358 {
1359   gchar *name;
1360   GtkBindingSet *binding_set;
1361
1362   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1363
1364   g_scanner_get_next_token (scanner);
1365   if (scanner->token != GTK_RC_TOKEN_BINDING)
1366     return GTK_RC_TOKEN_BINDING;
1367   g_scanner_get_next_token (scanner);
1368   if (scanner->token != G_TOKEN_STRING)
1369     return G_TOKEN_STRING;
1370   name = g_strdup (scanner->value.v_string);
1371
1372   g_scanner_get_next_token (scanner);
1373   if (scanner->token != '{')
1374     {
1375       g_free (name);
1376       return G_TOKEN_STRING;
1377     }
1378
1379   binding_set = gtk_binding_set_find (name);
1380   if (!binding_set)
1381     {
1382       binding_set = gtk_binding_set_new (name);
1383       binding_set->parsed = 1;
1384     }
1385   g_free (name);
1386
1387   g_scanner_peek_next_token (scanner);
1388   while (scanner->next_token != '}')
1389     {
1390       switch (scanner->next_token)
1391         {
1392           guint expected_token;
1393
1394         case GTK_RC_TOKEN_BIND:
1395           expected_token = gtk_binding_parse_bind (scanner, binding_set);
1396           if (expected_token != G_TOKEN_NONE)
1397             return expected_token;
1398           break;
1399         default:
1400           g_scanner_get_next_token (scanner);
1401           return '}';
1402         }
1403       g_scanner_peek_next_token (scanner);
1404     }
1405   g_scanner_get_next_token (scanner);
1406
1407   return G_TOKEN_NONE;
1408 }
1409
1410 static void
1411 free_pattern_specs (GSList *pattern_specs)
1412 {
1413   GSList *slist;
1414
1415   for (slist = pattern_specs; slist; slist = slist->next)
1416     {
1417       PatternSpec *pspec;
1418
1419       pspec = slist->data;
1420
1421       g_pattern_spec_free (pspec->pspec);
1422       g_free (pspec);
1423     }
1424
1425   g_slist_free (pattern_specs);
1426 }
1427
1428 static void
1429 binding_set_delete (GtkBindingSet *binding_set)
1430 {
1431   GtkBindingEntry *entry, *next;
1432
1433   entry = binding_set->entries;
1434   while (entry)
1435     {
1436       next = entry->set_next;
1437       binding_entry_destroy (entry);
1438       entry = next;
1439     }
1440   
1441   free_pattern_specs (binding_set->widget_path_pspecs);
1442   free_pattern_specs (binding_set->widget_class_pspecs);
1443   free_pattern_specs (binding_set->class_branch_pspecs);
1444
1445   g_free (binding_set->set_name);
1446   g_free (binding_set);
1447 }
1448
1449 /**
1450  * _gtk_binding_reset_parsed:
1451  * 
1452  * Removing all binding sets that were added by
1453  * gtk_binding_parse_binding()
1454  **/
1455 void
1456 _gtk_binding_reset_parsed (void)
1457 {
1458   GSList *slist, *next;
1459   
1460   slist = binding_set_list;
1461   while (slist)
1462     {
1463       GtkBindingSet *binding_set;
1464
1465       binding_set = slist->data;
1466       next = slist->next;
1467
1468       if (binding_set->parsed)
1469         {
1470           binding_set_list = g_slist_delete_link (binding_set_list, slist);
1471           binding_set_delete (binding_set);
1472         }
1473
1474       slist = next;
1475     }
1476 }
1477
1478 guint
1479 _gtk_binding_signal_new (const gchar        *signal_name,
1480                          GType               itype,
1481                          GSignalFlags        signal_flags,
1482                          GCallback           handler,
1483                          GSignalAccumulator  accumulator,
1484                          gpointer            accu_data,
1485                          GSignalCMarshaller  c_marshaller,
1486                          GType               return_type,
1487                          guint               n_params,
1488                          ...)
1489 {
1490   va_list args;
1491   guint signal_id;
1492
1493   g_return_val_if_fail (signal_name != NULL, 0);
1494   
1495   va_start (args, n_params);
1496
1497   signal_id = g_signal_new_valist (signal_name, itype, signal_flags,
1498                                    g_cclosure_new (handler, NULL, NULL),
1499                                    accumulator, accu_data, c_marshaller,
1500                                    return_type, n_params, args);
1501
1502   va_end (args);
1503  
1504   return signal_id;
1505 }