]> Pileus Git - ~andy/gtk/blob - gtk/gtkbindings.c
6f1fed57a54f2ebd298c7994bb9776950f576b20
[~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 <string.h>
31 #include <stdarg.h>
32 #include <gdkkeysyms.h>
33 #include "gtkbindings.h"
34 #include "gtkkeyhash.h"
35 #include "gtksignal.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 (GTK_FUNDAMENTAL_TYPE (sig->args[i].arg_type) == GTK_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 & GTK_RUN_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   
568   binding_set_list = g_slist_prepend (binding_set_list, binding_set);
569   
570   return binding_set;
571 }
572
573 GtkBindingSet*
574 gtk_binding_set_by_class (gpointer object_class)
575 {
576   GtkObjectClass *class = object_class;
577   GtkBindingSet* binding_set;
578
579   g_return_val_if_fail (GTK_IS_OBJECT_CLASS (class), NULL);
580
581   if (!key_id_class_binding_set)
582     key_id_class_binding_set = g_quark_from_static_string (key_class_binding_set);
583
584   binding_set = g_dataset_id_get_data (class, key_id_class_binding_set);
585
586   if (binding_set)
587     return binding_set;
588
589   binding_set = gtk_binding_set_new (gtk_type_name (GTK_CLASS_TYPE (class)));
590   gtk_binding_set_add_path (binding_set,
591                             GTK_PATH_CLASS,
592                             gtk_type_name (GTK_CLASS_TYPE (class)),
593                             GTK_PATH_PRIO_GTK);
594   g_dataset_id_set_data (class, key_id_class_binding_set, binding_set);
595
596   return binding_set;
597 }
598
599 GtkBindingSet*
600 gtk_binding_set_find (const gchar    *set_name)
601 {
602   GSList *slist;
603   
604   g_return_val_if_fail (set_name != NULL, NULL);
605   
606   for (slist = binding_set_list; slist; slist = slist->next)
607     {
608       GtkBindingSet *binding_set;
609       
610       binding_set = slist->data;
611       if (g_str_equal (binding_set->set_name, (gpointer) set_name))
612         return binding_set;
613     }
614   return NULL;
615 }
616
617 gboolean
618 gtk_binding_set_activate (GtkBindingSet  *binding_set,
619                           guint           keyval,
620                           GdkModifierType modifiers,
621                           GtkObject      *object)
622 {
623   GtkBindingEntry *entry;
624   
625   g_return_val_if_fail (binding_set != NULL, FALSE);
626   g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
627   
628   keyval = gdk_keyval_to_lower (keyval);
629   modifiers = modifiers & BINDING_MOD_MASK ();
630   
631   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
632   if (entry)
633     return gtk_binding_entry_activate (entry, object);
634   
635   return FALSE;
636 }
637
638 void
639 gtk_binding_entry_clear (GtkBindingSet  *binding_set,
640                          guint           keyval,
641                          GdkModifierType modifiers)
642 {
643   GtkBindingEntry *entry;
644   
645   g_return_if_fail (binding_set != NULL);
646   
647   keyval = gdk_keyval_to_lower (keyval);
648   modifiers = modifiers & BINDING_MOD_MASK ();
649   
650   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
651   if (entry)
652     binding_entry_destroy (entry);
653
654   entry = binding_entry_new (binding_set, keyval, modifiers);
655 }
656
657 void
658 gtk_binding_entry_remove (GtkBindingSet  *binding_set,
659                           guint           keyval,
660                           GdkModifierType modifiers)
661 {
662   GtkBindingEntry *entry;
663   
664   g_return_if_fail (binding_set != NULL);
665   
666   keyval = gdk_keyval_to_lower (keyval);
667   modifiers = modifiers & BINDING_MOD_MASK ();
668   
669   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
670   if (entry)
671     binding_entry_destroy (entry);
672 }
673
674 void
675 gtk_binding_entry_add_signall (GtkBindingSet  *binding_set,
676                                guint           keyval,
677                                GdkModifierType modifiers,
678                                const gchar    *signal_name,
679                                GSList         *binding_args)
680 {
681   GtkBindingEntry *entry;
682   GtkBindingSignal *signal, **signal_p;
683   GSList *slist;
684   guint n = 0;
685   GtkBindingArg *arg;
686   
687   g_return_if_fail (binding_set != NULL);
688   g_return_if_fail (signal_name != NULL);
689   
690   keyval = gdk_keyval_to_lower (keyval);
691   modifiers = modifiers & BINDING_MOD_MASK ();
692   
693   signal = binding_signal_new (signal_name, g_slist_length (binding_args));
694   
695   arg = signal->args;
696   for (slist = binding_args; slist; slist = slist->next)
697     {
698       GtkBindingArg *tmp_arg;
699       
700       tmp_arg = slist->data;
701       if (!tmp_arg)
702         {
703           g_warning ("gtk_binding_entry_add_signall(): arg[%u] is `NULL'", n);
704           binding_signal_free (signal);
705           return;
706         }
707       switch (GTK_FUNDAMENTAL_TYPE (tmp_arg->arg_type))
708         {
709         case  GTK_TYPE_LONG:
710           arg->arg_type = GTK_TYPE_LONG;
711           arg->d.long_data = tmp_arg->d.long_data;
712           break;
713         case  GTK_TYPE_DOUBLE:
714           arg->arg_type = GTK_TYPE_DOUBLE;
715           arg->d.double_data = tmp_arg->d.double_data;
716           break;
717         case  GTK_TYPE_STRING:
718           if (tmp_arg->arg_type != GTK_TYPE_IDENTIFIER)
719             arg->arg_type = GTK_TYPE_STRING;
720           else
721             arg->arg_type = GTK_TYPE_IDENTIFIER;
722           arg->d.string_data = g_strdup (tmp_arg->d.string_data);
723           if (!arg->d.string_data)
724             {
725               g_warning ("gtk_binding_entry_add_signall(): value of `string' arg[%u] is `NULL'", n);
726               binding_signal_free (signal);
727               return;
728             }
729           break;
730         default:
731           g_warning ("gtk_binding_entry_add_signall(): unsupported type `%s' for arg[%u]",
732                      gtk_type_name (arg->arg_type), n);
733           binding_signal_free (signal);
734           return;
735         }
736       arg++;
737       n++;
738     }
739   
740   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
741   if (!entry)
742     {
743       gtk_binding_entry_add (binding_set, keyval, modifiers);
744       entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
745     }
746   signal_p = &entry->signals;
747   while (*signal_p)
748     signal_p = &(*signal_p)->next;
749   *signal_p = signal;
750 }
751
752 void
753 gtk_binding_entry_add_signal (GtkBindingSet  *binding_set,
754                               guint           keyval,
755                               GdkModifierType modifiers,
756                               const gchar    *signal_name,
757                               guint           n_args,
758                               ...)
759 {
760   GSList *slist, *free_slist;
761   va_list args;
762   guint i;
763
764   g_return_if_fail (binding_set != NULL);
765   g_return_if_fail (signal_name != NULL);
766   
767   keyval = gdk_keyval_to_lower (keyval);
768   modifiers = modifiers & BINDING_MOD_MASK ();
769
770   va_start (args, n_args);
771   slist = NULL;
772   for (i = 0; i < n_args; i++)
773     {
774       GtkBindingArg *arg;
775
776       arg = g_new0 (GtkBindingArg, 1);
777       slist = g_slist_prepend (slist, arg);
778
779       arg->arg_type = va_arg (args, GtkType);
780       switch (GTK_FUNDAMENTAL_TYPE (arg->arg_type))
781         {
782           /* for elaborated commenting about var args collection, take a look
783            * at gtk_arg_collect_value() in gtkargcollector.c
784            */
785         case GTK_TYPE_CHAR:
786         case GTK_TYPE_UCHAR:
787         case GTK_TYPE_INT:
788         case GTK_TYPE_UINT:
789         case GTK_TYPE_BOOL:
790         case GTK_TYPE_ENUM:
791         case GTK_TYPE_FLAGS:
792           arg->arg_type = GTK_TYPE_LONG;
793           arg->d.long_data = va_arg (args, gint);
794           break;
795         case GTK_TYPE_LONG:
796         case GTK_TYPE_ULONG:
797           arg->arg_type = GTK_TYPE_LONG;
798           arg->d.long_data = va_arg (args, glong);
799           break;
800         case GTK_TYPE_FLOAT:
801         case GTK_TYPE_DOUBLE:
802           arg->arg_type = GTK_TYPE_DOUBLE;
803           arg->d.double_data = va_arg (args, gdouble);
804           break;
805         case GTK_TYPE_STRING:
806           if (arg->arg_type != GTK_TYPE_IDENTIFIER)
807             arg->arg_type = GTK_TYPE_STRING;
808           arg->d.string_data = va_arg (args, gchar*);
809           if (!arg->d.string_data)
810             {
811               g_warning ("gtk_binding_entry_add_signal(): type `%s' arg[%u] is `NULL'",
812                          gtk_type_name (arg->arg_type),
813                          i);
814               i += n_args + 1;
815             }
816           break;
817         default:
818           g_warning ("gtk_binding_entry_add_signal(): unsupported type `%s' for arg[%u]",
819                      gtk_type_name (arg->arg_type), i);
820           i += n_args + 1;
821           break;
822         }
823     }
824   va_end (args);
825
826   if (i == n_args || i == 0)
827     {
828       slist = g_slist_reverse (slist);
829       gtk_binding_entry_add_signall (binding_set, keyval, modifiers, signal_name, slist);
830     }
831
832   free_slist = slist;
833   while (slist)
834     {
835       g_free (slist->data);
836       slist = slist->next;
837     }
838   g_slist_free (free_slist);
839 }
840
841 void
842 gtk_binding_set_add_path (GtkBindingSet      *binding_set,
843                           GtkPathType         path_type,
844                           const gchar        *path_pattern,
845                           GtkPathPriorityType priority)
846 {
847   PatternSpec *pspec;
848   GSList **slist_p, *slist;
849   static guint seq_id = 0;
850   
851   g_return_if_fail (binding_set != NULL);
852   g_return_if_fail (path_pattern != NULL);
853   g_return_if_fail (priority <= GTK_PATH_PRIO_MASK);
854
855   priority &= GTK_PATH_PRIO_MASK;
856   
857   switch (path_type)
858     {
859     case  GTK_PATH_WIDGET:
860       slist_p = &binding_set->widget_path_pspecs;
861       break;
862     case  GTK_PATH_WIDGET_CLASS:
863       slist_p = &binding_set->widget_class_pspecs;
864       break;
865     case  GTK_PATH_CLASS:
866       slist_p = &binding_set->class_branch_pspecs;
867       break;
868     default:
869       g_assert_not_reached ();
870       slist_p = NULL;
871       break;
872     }
873   
874   pspec = g_new (PatternSpec, 1);
875   pspec->pspec = g_pattern_spec_new (path_pattern);
876   pspec->seq_id = priority << 28;
877   pspec->user_data = binding_set;
878   
879   slist = *slist_p;
880   while (slist)
881     {
882       PatternSpec *tmp_pspec;
883       
884       tmp_pspec = slist->data;
885       slist = slist->next;
886       
887       if (g_pattern_spec_equal (tmp_pspec->pspec, pspec->pspec))
888         {
889           GtkPathPriorityType lprio = tmp_pspec->seq_id >> 28;
890
891           g_pattern_spec_free (pspec->pspec);
892           g_free (pspec);
893           pspec = NULL;
894           if (lprio < priority)
895             {
896               tmp_pspec->seq_id &= 0x0fffffff;
897               tmp_pspec->seq_id |= priority << 28;
898             }
899           break;
900         }
901     }
902   if (pspec)
903     {
904       pspec->seq_id |= seq_id++ & 0x0fffffff;
905       *slist_p = g_slist_prepend (*slist_p, pspec);
906     }
907 }
908
909 static gboolean
910 binding_match_activate (GSList          *pspec_list,
911                         GtkObject       *object,
912                         guint            path_length,
913                         const gchar     *path,
914                         const gchar     *path_reversed)
915 {
916   GSList *slist;
917
918   for (slist = pspec_list; slist; slist = slist->next)
919     {
920       PatternSpec *pspec;
921
922       pspec = slist->data;
923       if (g_pattern_match (pspec->pspec, path_length, path, path_reversed))
924         {
925           GtkBindingSet *binding_set;
926
927           binding_set = pspec->user_data;
928
929           if (gtk_binding_entry_activate (binding_set->current, object))
930             return TRUE;
931         }
932     }
933
934   return FALSE;
935 }
936
937 static gint
938 gtk_binding_pattern_compare (gconstpointer new_pattern,
939                              gconstpointer existing_pattern)
940 {
941   register const PatternSpec *np  = new_pattern;
942   register const PatternSpec *ep  = existing_pattern;
943
944   /* walk the list as long as the existing patterns have
945    * higher priorities.
946    */
947
948   return np->seq_id < ep->seq_id;
949 }
950
951 static GSList*
952 gtk_binding_entries_sort_patterns (GSList      *entries,
953                                    GtkPathType  path_id,
954                                    gboolean     is_release)
955 {
956   GSList *patterns;
957   GSList *tmp_list;
958
959   patterns = NULL;
960   for (tmp_list = entries; tmp_list; tmp_list = tmp_list->next)
961     {
962       GtkBindingEntry *entry = tmp_list->data;
963       GtkBindingSet *binding_set;
964
965       binding_set = entry->binding_set;
966       binding_set->current = NULL;
967     }
968   
969   for (; entries; entries = entries->next)
970     {
971       GtkBindingEntry *entry = entries->data;
972       GtkBindingSet *binding_set;
973       GSList *slist = NULL;
974
975       if (is_release != ((entry->modifiers & GDK_RELEASE_MASK) != 0))
976         continue;
977
978       binding_set = entry->binding_set;
979
980       if (binding_set->current)
981         continue;
982       binding_set->current = entry;
983
984       switch (path_id)
985         {
986         case GTK_PATH_WIDGET:
987           slist = binding_set->widget_path_pspecs;
988           break;
989         case GTK_PATH_WIDGET_CLASS:
990           slist = binding_set->widget_class_pspecs;
991           break;
992         case GTK_PATH_CLASS:
993           slist = binding_set->class_branch_pspecs;
994           break;
995         }
996
997       for (; slist; slist = slist->next)
998         {
999           PatternSpec *pspec;
1000
1001           pspec = slist->data;
1002           patterns = g_slist_insert_sorted (patterns, pspec, gtk_binding_pattern_compare);
1003         }
1004     }
1005
1006   return patterns;
1007 }
1008
1009 static gboolean
1010 gtk_bindings_activate_list (GtkObject *object,
1011                             GSList    *entries,
1012                             gboolean   is_release)
1013 {
1014   GtkWidget *widget = GTK_WIDGET (object);
1015   gboolean handled = FALSE;
1016
1017   if (!entries)
1018     return FALSE;
1019
1020   if (!handled)
1021     {
1022       guint path_length;
1023       gchar *path, *path_reversed;
1024       GSList *patterns;
1025
1026       gtk_widget_path (widget, &path_length, &path, &path_reversed);
1027       patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET, is_release);
1028       handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
1029       g_slist_free (patterns);
1030       g_free (path);
1031       g_free (path_reversed);
1032     }
1033
1034   if (!handled)
1035     {
1036       guint path_length;
1037       gchar *path, *path_reversed;
1038       GSList *patterns;
1039
1040       gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
1041       patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET_CLASS, is_release);
1042       handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
1043       g_slist_free (patterns);
1044       g_free (path);
1045       g_free (path_reversed);
1046     }
1047
1048   if (!handled)
1049     {
1050       GSList *patterns;
1051       GtkType class_type;
1052       
1053       patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_CLASS, is_release);
1054       class_type = GTK_OBJECT_TYPE (object);
1055       while (class_type && !handled)
1056         {
1057           guint path_length;
1058           const gchar *path;
1059           gchar *path_reversed;
1060           
1061           path = gtk_type_name (class_type);
1062           path_reversed = g_strdup (path);
1063           g_strreverse (path_reversed);
1064           path_length = strlen (path);
1065           handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
1066           g_free (path_reversed);
1067
1068           class_type = gtk_type_parent (class_type);
1069         }
1070       g_slist_free (patterns);
1071     }
1072
1073   return handled;
1074 }
1075
1076 gboolean
1077 gtk_bindings_activate (GtkObject      *object,
1078                        guint           keyval,
1079                        GdkModifierType modifiers)
1080 {
1081   GSList *entries = NULL;
1082   GtkKeyHash *key_hash;
1083   gboolean handled = FALSE;
1084   gboolean is_release;
1085
1086   g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
1087
1088   if (!GTK_IS_WIDGET (object))
1089     return FALSE;
1090
1091   is_release = (modifiers & GDK_RELEASE_MASK) != 0;
1092   modifiers = modifiers & BINDING_MOD_MASK () & ~GDK_RELEASE_MASK;
1093
1094   key_hash = binding_key_hash_for_keymap (gdk_keymap_get_default ());
1095   entries = _gtk_key_hash_lookup_keyval (key_hash, keyval, modifiers);
1096
1097   handled = gtk_bindings_activate_list (object, entries, is_release);
1098
1099   g_slist_free (entries);
1100
1101   return handled;
1102 }
1103
1104 /**
1105  * _gtk_bindings_activate_event:
1106  * @object: a #GtkObject (generally must be a widget)
1107  * @event: a #GdkEventKey
1108  * 
1109  * Looks up key bindings for @object to find one matching
1110  * @event, and if one was found, activate it.
1111  * 
1112  * Return value: %TRUE if a matching key binding was found
1113  **/
1114 gboolean
1115 _gtk_bindings_activate_event (GtkObject      *object,
1116                               GdkEventKey    *event)
1117 {
1118   GSList *entries = NULL;
1119   GtkKeyHash *key_hash;
1120   gboolean handled = FALSE;
1121
1122   g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
1123
1124   if (!GTK_IS_WIDGET (object))
1125     return FALSE;
1126
1127   key_hash = binding_key_hash_for_keymap (gdk_keymap_get_default ());
1128   entries = _gtk_key_hash_lookup (key_hash,
1129                                   event->hardware_keycode,
1130                                   event->state & BINDING_MOD_MASK () & ~GDK_RELEASE_MASK,
1131                                   event->group);
1132   
1133   handled = gtk_bindings_activate_list (object, entries,
1134                                         event->type == GDK_KEY_RELEASE);
1135
1136   g_slist_free (entries);
1137
1138   return handled;
1139 }
1140
1141 static guint
1142 gtk_binding_parse_signal (GScanner       *scanner,
1143                           GtkBindingSet  *binding_set,
1144                           guint           keyval,
1145                           GdkModifierType modifiers)
1146 {
1147   gchar *signal;
1148   guint expected_token = 0;
1149   GSList *args;
1150   GSList *slist;
1151   gboolean done;
1152   gboolean negate;
1153   gboolean need_arg;
1154   gboolean seen_comma;
1155
1156   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1157   
1158   g_scanner_get_next_token (scanner);
1159   if (scanner->token != G_TOKEN_STRING)
1160     return G_TOKEN_STRING;
1161   g_scanner_peek_next_token (scanner);
1162   if (scanner->next_token != '(')
1163     {
1164       g_scanner_get_next_token (scanner);
1165       return '(';
1166     }
1167   signal = g_strdup (scanner->value.v_string);
1168   g_scanner_get_next_token (scanner);
1169
1170   negate = FALSE;
1171   args = NULL;
1172   done = FALSE;
1173   need_arg = TRUE;
1174   seen_comma = FALSE;
1175   scanner->config->scan_symbols = FALSE;
1176   do
1177     {
1178       if (need_arg)
1179         expected_token = G_TOKEN_INT;
1180       else
1181         expected_token = ')';
1182       g_scanner_get_next_token (scanner);
1183       switch (scanner->token)
1184         {
1185           GtkBindingArg *arg;
1186
1187         case G_TOKEN_FLOAT:
1188           if (need_arg)
1189             {
1190               need_arg = FALSE;
1191               arg = g_new (GtkBindingArg, 1);
1192               arg->arg_type = GTK_TYPE_DOUBLE;
1193               arg->d.double_data = scanner->value.v_float;
1194               if (negate)
1195                 {
1196                   arg->d.double_data = - arg->d.double_data;
1197                   negate = FALSE;
1198                 }
1199               args = g_slist_prepend (args, arg);
1200             }
1201           else
1202             done = TRUE;
1203           break;
1204         case G_TOKEN_INT:
1205           if (need_arg)
1206             {
1207               need_arg = FALSE;
1208               arg = g_new (GtkBindingArg, 1);
1209               arg->arg_type = GTK_TYPE_LONG;
1210               arg->d.long_data = scanner->value.v_int;
1211               if (negate)
1212                 {
1213                   arg->d.long_data = - arg->d.long_data;
1214                   negate = FALSE;
1215                 }
1216               args = g_slist_prepend (args, arg);
1217             }
1218           else
1219             done = TRUE;
1220           break;
1221         case G_TOKEN_STRING:
1222           if (need_arg && !negate)
1223             {
1224               need_arg = FALSE;
1225               arg = g_new (GtkBindingArg, 1);
1226               arg->arg_type = GTK_TYPE_STRING;
1227               arg->d.string_data = g_strdup (scanner->value.v_string);
1228               args = g_slist_prepend (args, arg);
1229             }
1230           else
1231             done = TRUE;
1232           break;
1233         case G_TOKEN_IDENTIFIER:
1234           if (need_arg && !negate)
1235             {
1236               need_arg = FALSE;
1237               arg = g_new (GtkBindingArg, 1);
1238               arg->arg_type = GTK_TYPE_IDENTIFIER;
1239               arg->d.string_data = g_strdup (scanner->value.v_identifier);
1240               args = g_slist_prepend (args, arg);
1241             }
1242           else
1243             done = TRUE;
1244           break;
1245         case '-':
1246           if (!need_arg)
1247             done = TRUE;
1248           else if (negate)
1249             {
1250               expected_token = G_TOKEN_INT;
1251               done = TRUE;
1252             }
1253           else
1254             negate = TRUE;
1255           break;
1256         case ',':
1257           seen_comma = TRUE;
1258           if (need_arg)
1259             done = TRUE;
1260           else
1261             need_arg = TRUE;
1262           break;
1263         case ')':
1264           if (!(need_arg && seen_comma) && !negate)
1265             {
1266               args = g_slist_reverse (args);
1267               gtk_binding_entry_add_signall (binding_set,
1268                                              keyval,
1269                                              modifiers,
1270                                              signal,
1271                                              args);
1272               expected_token = G_TOKEN_NONE;
1273             }
1274           done = TRUE;
1275           break;
1276         default:
1277           done = TRUE;
1278           break;
1279         }
1280     }
1281   while (!done);
1282   scanner->config->scan_symbols = TRUE;
1283   
1284   for (slist = args; slist; slist = slist->next)
1285     {
1286       GtkBindingArg *arg;
1287
1288       arg = slist->data;
1289       if (GTK_FUNDAMENTAL_TYPE (arg->arg_type) == GTK_TYPE_STRING)
1290         g_free (arg->d.string_data);
1291       g_free (arg);
1292     }
1293   g_slist_free (args);
1294   g_free (signal);
1295
1296   return expected_token;
1297 }
1298
1299 static inline guint
1300 gtk_binding_parse_bind (GScanner       *scanner,
1301                         GtkBindingSet  *binding_set)
1302 {
1303   guint keyval = 0;
1304   GdkModifierType modifiers = 0;
1305
1306   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1307   
1308   g_scanner_get_next_token (scanner);
1309   if (scanner->token != GTK_RC_TOKEN_BIND)
1310     return GTK_RC_TOKEN_BIND;
1311   g_scanner_get_next_token (scanner);
1312   if (scanner->token != G_TOKEN_STRING)
1313     return G_TOKEN_STRING;
1314   gtk_accelerator_parse (scanner->value.v_string, &keyval, &modifiers);
1315   modifiers &= BINDING_MOD_MASK ();
1316   if (keyval == 0)
1317     return G_TOKEN_STRING;
1318
1319   g_scanner_get_next_token (scanner);
1320   if (scanner->token != '{')
1321     return '{';
1322
1323   gtk_binding_entry_clear (binding_set, keyval, modifiers);
1324   
1325   g_scanner_peek_next_token (scanner);
1326   while (scanner->next_token != '}')
1327     {
1328       switch (scanner->next_token)
1329         {
1330           guint expected_token;
1331
1332         case G_TOKEN_STRING:
1333           expected_token = gtk_binding_parse_signal (scanner,
1334                                                      binding_set,
1335                                                      keyval,
1336                                                      modifiers);
1337           if (expected_token != G_TOKEN_NONE)
1338             return expected_token;
1339           break;
1340         default:
1341           g_scanner_get_next_token (scanner);
1342           return '}';
1343         }
1344       g_scanner_peek_next_token (scanner);
1345     }
1346   g_scanner_get_next_token (scanner);
1347
1348   return G_TOKEN_NONE;
1349 }
1350
1351 guint
1352 gtk_binding_parse_binding (GScanner       *scanner)
1353 {
1354   gchar *name;
1355   GtkBindingSet *binding_set;
1356
1357   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1358
1359   g_scanner_get_next_token (scanner);
1360   if (scanner->token != GTK_RC_TOKEN_BINDING)
1361     return GTK_RC_TOKEN_BINDING;
1362   g_scanner_get_next_token (scanner);
1363   if (scanner->token != G_TOKEN_STRING)
1364     return G_TOKEN_STRING;
1365   name = g_strdup (scanner->value.v_string);
1366
1367   g_scanner_get_next_token (scanner);
1368   if (scanner->token != '{')
1369     {
1370       g_free (name);
1371       return G_TOKEN_STRING;
1372     }
1373
1374   binding_set = gtk_binding_set_find (name);
1375   if (!binding_set)
1376     {
1377       binding_set = gtk_binding_set_new (name);
1378       binding_set->parsed = 1;
1379     }
1380   g_free (name);
1381
1382   g_scanner_peek_next_token (scanner);
1383   while (scanner->next_token != '}')
1384     {
1385       switch (scanner->next_token)
1386         {
1387           guint expected_token;
1388
1389         case GTK_RC_TOKEN_BIND:
1390           expected_token = gtk_binding_parse_bind (scanner, binding_set);
1391           if (expected_token != G_TOKEN_NONE)
1392             return expected_token;
1393           break;
1394         default:
1395           g_scanner_get_next_token (scanner);
1396           return '}';
1397         }
1398       g_scanner_peek_next_token (scanner);
1399     }
1400   g_scanner_get_next_token (scanner);
1401
1402   return G_TOKEN_NONE;
1403 }
1404
1405 static void
1406 free_pattern_specs (GSList *pattern_specs)
1407 {
1408   GSList *slist;
1409
1410   for (slist = pattern_specs; slist; slist = slist->next)
1411     {
1412       PatternSpec *pspec;
1413
1414       pspec = slist->data;
1415
1416       g_pattern_spec_free (pspec->pspec);
1417       g_free (pspec);
1418     }
1419
1420   g_slist_free (pattern_specs);
1421 }
1422
1423 static void
1424 binding_set_delete (GtkBindingSet *binding_set)
1425 {
1426   GtkBindingEntry *entry, *next;
1427
1428   entry = binding_set->entries;
1429   while (entry)
1430     {
1431       next = entry->set_next;
1432       binding_entry_destroy (entry);
1433       entry = next;
1434     }
1435   
1436   free_pattern_specs (binding_set->widget_path_pspecs);
1437   free_pattern_specs (binding_set->widget_class_pspecs);
1438   free_pattern_specs (binding_set->class_branch_pspecs);
1439
1440   g_free (binding_set->set_name);
1441   g_free (binding_set);
1442 }
1443
1444 /**
1445  * _gtk_binding_reset_parsed:
1446  * 
1447  * Removing all binding sets that were added by
1448  * gtk_binding_parse_binding()
1449  **/
1450 void
1451 _gtk_binding_reset_parsed (void)
1452 {
1453   GSList *slist, *next;
1454   
1455   slist = binding_set_list;
1456   while (slist)
1457     {
1458       GtkBindingSet *binding_set;
1459
1460       binding_set = slist->data;
1461       next = slist->next;
1462
1463       if (binding_set->parsed)
1464         {
1465           binding_set_list = g_slist_delete_link (binding_set_list, slist);
1466           binding_set_delete (binding_set);
1467         }
1468
1469       slist = next;
1470     }
1471 }