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