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