]> Pileus Git - ~andy/gtk/blob - gtk/gtkbindings.c
Remove G_DISABLE_CONST_RETURNS.
[~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                    guint          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                         guint 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                          guint          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 (GtkBindingArg   *args,
263                         GSignalQuery    *query,
264                         GtkArg          **params_p)
265 {
266   GtkArg *params;
267   const GtkType *types;
268   guint i;
269   gboolean valid;
270   
271   params = g_new0 (GtkArg, query->n_params);
272   *params_p = params;
273   
274   types = query->param_types;
275   valid = TRUE;
276   for (i = 0; i < query->n_params && valid; i++)
277     {
278       GtkType param_ftype;
279
280       params->type = *types;
281       params->name = NULL;
282       param_ftype = GTK_FUNDAMENTAL_TYPE (params->type);
283       switch (GTK_FUNDAMENTAL_TYPE (args->arg_type))
284         {
285         case  GTK_TYPE_DOUBLE:
286           if (param_ftype == GTK_TYPE_FLOAT)
287             GTK_VALUE_FLOAT (*params) = args->d.double_data;
288           else if (param_ftype == GTK_TYPE_DOUBLE)
289             GTK_VALUE_DOUBLE (*params) = args->d.double_data;
290           else
291             valid = FALSE;
292           break;
293         case  GTK_TYPE_LONG:
294           if (param_ftype == GTK_TYPE_BOOL &&
295               (args->d.long_data == 0 ||
296                args->d.long_data == 1))
297             GTK_VALUE_BOOL (*params) = args->d.long_data;
298           else if (param_ftype == GTK_TYPE_INT ||
299                    param_ftype == GTK_TYPE_ENUM)
300             GTK_VALUE_INT (*params) = args->d.long_data;
301           else if ((param_ftype == GTK_TYPE_UINT ||
302                     param_ftype == GTK_TYPE_FLAGS) &&
303                    args->d.long_data >= 0)
304             GTK_VALUE_UINT (*params) = args->d.long_data;
305           else if (param_ftype == GTK_TYPE_LONG)
306             GTK_VALUE_LONG (*params) = args->d.long_data;
307           else if (param_ftype == GTK_TYPE_ULONG &&
308                    args->d.long_data >= 0)
309             GTK_VALUE_ULONG (*params) = args->d.long_data;
310           else if (param_ftype == GTK_TYPE_FLOAT)
311             GTK_VALUE_FLOAT (*params) = args->d.long_data;
312           else if (param_ftype == GTK_TYPE_DOUBLE)
313             GTK_VALUE_DOUBLE (*params) = args->d.long_data;
314           else
315             valid = FALSE;
316           break;
317         case  GTK_TYPE_STRING:
318           if (args->arg_type == GTK_TYPE_STRING &&
319               param_ftype == GTK_TYPE_STRING)
320             GTK_VALUE_STRING (*params) = args->d.string_data;
321           else if (args->arg_type == GTK_TYPE_IDENTIFIER &&
322                    (param_ftype == GTK_TYPE_ENUM ||
323                     param_ftype == GTK_TYPE_FLAGS))
324             {
325               GtkEnumValue *value;
326
327               value = gtk_type_enum_find_value (params->type, args->d.string_data);
328               if (value)
329                 GTK_VALUE_ENUM (*params) = value->value;
330               else
331                 valid = FALSE;
332             }
333           else
334             valid = FALSE;
335           break;
336         default:
337           valid = FALSE;
338           break;
339         }
340       types++;
341       params++;
342       args++;
343     }
344   
345   if (!valid)
346     {
347       g_free (*params_p);
348       *params_p = NULL;
349     }
350   
351   return valid;
352 }
353
354 static void
355 gtk_binding_entry_activate (GtkBindingEntry     *entry,
356                             GtkObject   *object)
357 {
358   GtkBindingSignal *sig;
359   gboolean old_emission;
360   
361   old_emission = entry->in_emission;
362   entry->in_emission = TRUE;
363   
364   gtk_object_ref (object);
365   
366   for (sig = entry->signals; sig; sig = sig->next)
367     {
368       GSignalQuery query;
369       guint signal_id;
370       GtkArg *params = NULL;
371       gchar *accelerator = NULL;
372       
373       signal_id = gtk_signal_lookup (sig->signal_name, GTK_OBJECT_TYPE (object));
374       if (!signal_id)
375         {
376           accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
377           g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
378                      "could not find signal \"%s\" in the `%s' class ancestry",
379                      entry->binding_set->set_name,
380                      accelerator,
381                      sig->signal_name,
382                      gtk_type_name (GTK_OBJECT_TYPE (object)));
383           g_free (accelerator);
384           continue;
385         }
386       
387       g_signal_query (signal_id, &query);
388       if (query.n_params != sig->n_args ||
389           query.return_type != G_TYPE_NONE ||
390           !binding_compose_params (sig->args, &query, &params))
391         {
392           accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
393           g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
394                      "signature mismatch for signal \"%s\" in the `%s' class ancestry",
395                      entry->binding_set->set_name,
396                      accelerator,
397                      sig->signal_name,
398                      gtk_type_name (GTK_OBJECT_TYPE (object)));
399         }
400       else if (!(query.signal_flags & GTK_RUN_ACTION))
401         {
402           accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
403           g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
404                      "signal \"%s\" in the `%s' class ancestry cannot be used for action emissions",
405                      entry->binding_set->set_name,
406                      accelerator,
407                      sig->signal_name,
408                      gtk_type_name (GTK_OBJECT_TYPE (object)));
409         }
410       g_free (accelerator);
411       if (accelerator)
412         continue;
413
414       gtk_signal_emitv (object, signal_id, params);
415       g_free (params);
416       
417       if (GTK_OBJECT_DESTROYED (object) || entry->destroyed)
418         break;
419     }
420   
421   gtk_object_unref (object);
422
423   entry->in_emission = old_emission;
424   if (entry->destroyed && !entry->in_emission)
425     binding_entry_free (entry);
426 }
427
428 GtkBindingSet*
429 gtk_binding_set_new (const gchar    *set_name)
430 {
431   GtkBindingSet *binding_set;
432   
433   g_return_val_if_fail (set_name != NULL, NULL);
434   
435   binding_set = g_new (GtkBindingSet, 1);
436   binding_set->set_name = g_strdup (set_name);
437   binding_set->widget_path_pspecs = NULL;
438   binding_set->widget_class_pspecs = NULL;
439   binding_set->class_branch_pspecs = NULL;
440   binding_set->entries = NULL;
441   binding_set->current = NULL;
442   
443   binding_set_list = g_slist_prepend (binding_set_list, binding_set);
444   
445   return binding_set;
446 }
447
448 GtkBindingSet*
449 gtk_binding_set_by_class (gpointer object_class)
450 {
451   GtkObjectClass *class = object_class;
452   GtkBindingSet* binding_set;
453
454   g_return_val_if_fail (GTK_IS_OBJECT_CLASS (class), NULL);
455
456   if (!key_id_class_binding_set)
457     key_id_class_binding_set = g_quark_from_static_string (key_class_binding_set);
458
459   binding_set = g_dataset_id_get_data (class, key_id_class_binding_set);
460
461   if (binding_set)
462     return binding_set;
463
464   binding_set = gtk_binding_set_new (gtk_type_name (GTK_CLASS_TYPE (class)));
465   gtk_binding_set_add_path (binding_set,
466                             GTK_PATH_CLASS,
467                             gtk_type_name (GTK_CLASS_TYPE (class)),
468                             GTK_PATH_PRIO_GTK);
469   g_dataset_id_set_data (class, key_id_class_binding_set, binding_set);
470
471   return binding_set;
472 }
473
474 GtkBindingSet*
475 gtk_binding_set_find (const gchar    *set_name)
476 {
477   GSList *slist;
478   
479   g_return_val_if_fail (set_name != NULL, NULL);
480   
481   for (slist = binding_set_list; slist; slist = slist->next)
482     {
483       GtkBindingSet *binding_set;
484       
485       binding_set = slist->data;
486       if (g_str_equal (binding_set->set_name, (gpointer) set_name))
487         return binding_set;
488     }
489   return NULL;
490 }
491
492 gboolean
493 gtk_binding_set_activate (GtkBindingSet  *binding_set,
494                           guint           keyval,
495                           guint           modifiers,
496                           GtkObject      *object)
497 {
498   GtkBindingEntry *entry;
499   
500   g_return_val_if_fail (binding_set != NULL, FALSE);
501   g_return_val_if_fail (object != NULL, FALSE);
502   g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
503   
504   keyval = gdk_keyval_to_lower (keyval);
505   modifiers = modifiers & BINDING_MOD_MASK ();
506   
507   if (!GTK_OBJECT_DESTROYED (object))
508     {
509       entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
510       if (entry)
511         {
512           gtk_binding_entry_activate (entry, object);
513           
514           return TRUE;
515         }
516     }
517   
518   return FALSE;
519 }
520
521 void
522 gtk_binding_entry_clear (GtkBindingSet  *binding_set,
523                          guint           keyval,
524                          guint           modifiers)
525 {
526   GtkBindingEntry *entry;
527   
528   g_return_if_fail (binding_set != NULL);
529   
530   keyval = gdk_keyval_to_lower (keyval);
531   modifiers = modifiers & BINDING_MOD_MASK ();
532   
533   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
534   if (entry)
535     binding_entry_destroy (entry);
536
537   entry = binding_entry_new (binding_set, keyval, modifiers);
538 }
539
540 void
541 gtk_binding_entry_remove (GtkBindingSet  *binding_set,
542                           guint           keyval,
543                           guint           modifiers)
544 {
545   GtkBindingEntry *entry;
546   
547   g_return_if_fail (binding_set != NULL);
548   
549   keyval = gdk_keyval_to_lower (keyval);
550   modifiers = modifiers & BINDING_MOD_MASK ();
551   
552   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
553   if (entry)
554     binding_entry_destroy (entry);
555 }
556
557 void
558 gtk_binding_entry_add_signall (GtkBindingSet  *binding_set,
559                                guint           keyval,
560                                guint           modifiers,
561                                const gchar    *signal_name,
562                                GSList         *binding_args)
563 {
564   GtkBindingEntry *entry;
565   GtkBindingSignal *signal, **signal_p;
566   GSList *slist;
567   guint n = 0;
568   GtkBindingArg *arg;
569   
570   g_return_if_fail (binding_set != NULL);
571   g_return_if_fail (signal_name != NULL);
572   
573   keyval = gdk_keyval_to_lower (keyval);
574   modifiers = modifiers & BINDING_MOD_MASK ();
575   
576   signal = binding_signal_new (signal_name, g_slist_length (binding_args));
577   
578   arg = signal->args;
579   for (slist = binding_args; slist; slist = slist->next)
580     {
581       GtkBindingArg *tmp_arg;
582       
583       tmp_arg = slist->data;
584       if (!tmp_arg)
585         {
586           g_warning ("gtk_binding_entry_add_signall(): arg[%u] is `NULL'", n);
587           binding_signal_free (signal);
588           return;
589         }
590       switch (GTK_FUNDAMENTAL_TYPE (tmp_arg->arg_type))
591         {
592         case  GTK_TYPE_LONG:
593           arg->arg_type = GTK_TYPE_LONG;
594           arg->d.long_data = tmp_arg->d.long_data;
595           break;
596         case  GTK_TYPE_DOUBLE:
597           arg->arg_type = GTK_TYPE_DOUBLE;
598           arg->d.double_data = tmp_arg->d.double_data;
599           break;
600         case  GTK_TYPE_STRING:
601           if (tmp_arg->arg_type != GTK_TYPE_IDENTIFIER)
602             arg->arg_type = GTK_TYPE_STRING;
603           else
604             arg->arg_type = GTK_TYPE_IDENTIFIER;
605           arg->d.string_data = g_strdup (tmp_arg->d.string_data);
606           if (!arg->d.string_data)
607             {
608               g_warning ("gtk_binding_entry_add_signall(): value of `string' arg[%u] is `NULL'", n);
609               binding_signal_free (signal);
610               return;
611             }
612           break;
613         default:
614           g_warning ("gtk_binding_entry_add_signall(): unsupported type `%s' for arg[%u]",
615                      gtk_type_name (arg->arg_type), n);
616           binding_signal_free (signal);
617           return;
618         }
619       arg++;
620       n++;
621     }
622   
623   entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
624   if (!entry)
625     {
626       gtk_binding_entry_add (binding_set, keyval, modifiers);
627       entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
628     }
629   signal_p = &entry->signals;
630   while (*signal_p)
631     signal_p = &(*signal_p)->next;
632   *signal_p = signal;
633 }
634
635 void
636 gtk_binding_entry_add_signal (GtkBindingSet  *binding_set,
637                               guint           keyval,
638                               guint           modifiers,
639                               const gchar    *signal_name,
640                               guint           n_args,
641                               ...)
642 {
643   GSList *slist, *free_slist;
644   va_list args;
645   guint i;
646
647   g_return_if_fail (binding_set != NULL);
648   g_return_if_fail (signal_name != NULL);
649   
650   keyval = gdk_keyval_to_lower (keyval);
651   modifiers = modifiers & BINDING_MOD_MASK ();
652
653   va_start (args, n_args);
654   slist = NULL;
655   for (i = 0; i < n_args; i++)
656     {
657       GtkBindingArg *arg;
658
659       arg = g_new0 (GtkBindingArg, 1);
660       slist = g_slist_prepend (slist, arg);
661
662       arg->arg_type = va_arg (args, GtkType);
663       switch (GTK_FUNDAMENTAL_TYPE (arg->arg_type))
664         {
665           /* for elaborated commenting about var args collection, take a look
666            * at gtk_arg_collect_value() in gtkargcollector.c
667            */
668         case GTK_TYPE_CHAR:
669         case GTK_TYPE_UCHAR:
670         case GTK_TYPE_INT:
671         case GTK_TYPE_UINT:
672         case GTK_TYPE_BOOL:
673         case GTK_TYPE_ENUM:
674         case GTK_TYPE_FLAGS:
675           arg->arg_type = GTK_TYPE_LONG;
676           arg->d.long_data = va_arg (args, gint);
677           break;
678         case GTK_TYPE_LONG:
679         case GTK_TYPE_ULONG:
680           arg->arg_type = GTK_TYPE_LONG;
681           arg->d.long_data = va_arg (args, glong);
682           break;
683         case GTK_TYPE_FLOAT:
684         case GTK_TYPE_DOUBLE:
685           arg->arg_type = GTK_TYPE_DOUBLE;
686           arg->d.double_data = va_arg (args, gdouble);
687           break;
688         case GTK_TYPE_STRING:
689           if (arg->arg_type != GTK_TYPE_IDENTIFIER)
690             arg->arg_type = GTK_TYPE_STRING;
691           arg->d.string_data = va_arg (args, gchar*);
692           if (!arg->d.string_data)
693             {
694               g_warning ("gtk_binding_entry_add_signal(): type `%s' arg[%u] is `NULL'",
695                          gtk_type_name (arg->arg_type),
696                          i);
697               i += n_args + 1;
698             }
699           break;
700         default:
701           g_warning ("gtk_binding_entry_add_signal(): unsupported type `%s' for arg[%u]",
702                      gtk_type_name (arg->arg_type), i);
703           i += n_args + 1;
704           break;
705         }
706     }
707   va_end (args);
708
709   if (i == n_args || i == 0)
710     {
711       slist = g_slist_reverse (slist);
712       gtk_binding_entry_add_signall (binding_set, keyval, modifiers, signal_name, slist);
713     }
714
715   free_slist = slist;
716   while (slist)
717     {
718       g_free (slist->data);
719       slist = slist->next;
720     }
721   g_slist_free (free_slist);
722 }
723
724 void
725 gtk_binding_set_add_path (GtkBindingSet      *binding_set,
726                           GtkPathType         path_type,
727                           const gchar        *path_pattern,
728                           GtkPathPriorityType priority)
729 {
730   PatternSpec *pspec;
731   GSList **slist_p, *slist;
732   static guint seq_id = 0;
733   
734   g_return_if_fail (binding_set != NULL);
735   g_return_if_fail (path_pattern != NULL);
736   g_return_if_fail (priority <= GTK_PATH_PRIO_MASK);
737
738   priority &= GTK_PATH_PRIO_MASK;
739   
740   switch (path_type)
741     {
742     case  GTK_PATH_WIDGET:
743       slist_p = &binding_set->widget_path_pspecs;
744       break;
745     case  GTK_PATH_WIDGET_CLASS:
746       slist_p = &binding_set->widget_class_pspecs;
747       break;
748     case  GTK_PATH_CLASS:
749       slist_p = &binding_set->class_branch_pspecs;
750       break;
751     default:
752       g_assert_not_reached ();
753       slist_p = NULL;
754       break;
755     }
756   
757   pspec = g_new (PatternSpec, 1);
758   pspec->pspec = g_pattern_spec_new (path_pattern);
759   pspec->seq_id = priority << 28;
760   pspec->user_data = binding_set;
761   
762   slist = *slist_p;
763   while (slist)
764     {
765       PatternSpec *tmp_pspec;
766       
767       tmp_pspec = slist->data;
768       slist = slist->next;
769       
770       if (g_pattern_spec_equal (tmp_pspec->pspec, pspec->pspec))
771         {
772           GtkPathPriorityType lprio = tmp_pspec->seq_id >> 28;
773
774           g_pattern_spec_free (pspec->pspec);
775           g_free (pspec);
776           pspec = NULL;
777           if (lprio < priority)
778             {
779               tmp_pspec->seq_id &= 0x0fffffff;
780               tmp_pspec->seq_id |= priority << 28;
781             }
782           break;
783         }
784     }
785   if (pspec)
786     {
787       pspec->seq_id |= seq_id++ & 0x0fffffff;
788       *slist_p = g_slist_prepend (*slist_p, pspec);
789     }
790 }
791
792 static inline gboolean
793 binding_match_activate (GSList          *pspec_list,
794                         GtkObject       *object,
795                         guint            path_length,
796                         const gchar     *path,
797                         const gchar     *path_reversed)
798 {
799   GSList *slist;
800
801   for (slist = pspec_list; slist; slist = slist->next)
802     {
803       PatternSpec *pspec;
804
805       pspec = slist->data;
806       if (g_pattern_match (pspec->pspec, path_length, path, path_reversed))
807         {
808           GtkBindingSet *binding_set;
809
810           binding_set = pspec->user_data;
811
812           gtk_binding_entry_activate (binding_set->current, object);
813
814           return TRUE;
815         }
816     }
817
818   return FALSE;
819 }
820
821 static gint
822 gtk_binding_pattern_compare (gconstpointer new_pattern,
823                              gconstpointer existing_pattern)
824 {
825   register const PatternSpec *np  = new_pattern;
826   register const PatternSpec *ep  = existing_pattern;
827
828   /* walk the list as long as the existing patterns have
829    * higher priorities.
830    */
831
832   return np->seq_id < ep->seq_id;
833 }
834
835 static inline GSList*
836 gtk_binding_entries_sort_patterns (GtkBindingEntry    *entries,
837                                    GtkPathType         path_id)
838 {
839   GSList *patterns;
840
841   patterns = NULL;
842   while (entries)
843     {
844       register GtkBindingSet *binding_set;
845       GSList *slist = NULL;
846
847       binding_set = entries->binding_set;
848       binding_set->current = entries;
849
850       switch (path_id)
851         {
852         case GTK_PATH_WIDGET:
853           slist = binding_set->widget_path_pspecs;
854           break;
855         case GTK_PATH_WIDGET_CLASS:
856           slist = binding_set->widget_class_pspecs;
857           break;
858         case GTK_PATH_CLASS:
859           slist = binding_set->class_branch_pspecs;
860           break;
861         }
862
863       for (; slist; slist = slist->next)
864         {
865           PatternSpec *pspec;
866
867           pspec = slist->data;
868           patterns = g_slist_insert_sorted (patterns, pspec, gtk_binding_pattern_compare);
869         }
870
871       entries = entries->hash_next;
872     }
873
874   return patterns;
875 }
876       
877
878 gboolean
879 gtk_bindings_activate (GtkObject      *object,
880                        guint           keyval,
881                        guint           modifiers)
882 {
883   GtkBindingEntry *entries;
884   GtkWidget *widget;
885   gboolean handled = FALSE;
886
887   g_return_val_if_fail (object != NULL, FALSE);
888   g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
889
890   if (!GTK_IS_WIDGET (object) || GTK_OBJECT_DESTROYED (object))
891     return FALSE;
892
893   widget = GTK_WIDGET (object);
894
895   keyval = gdk_keyval_to_lower (keyval);
896   modifiers = modifiers & BINDING_MOD_MASK ();
897
898   entries = binding_ht_lookup_list (keyval, modifiers);
899
900   if (!entries)
901     return FALSE;
902
903   if (!handled)
904     {
905       guint path_length;
906       gchar *path, *path_reversed;
907       GSList *patterns;
908
909       gtk_widget_path (widget, &path_length, &path, &path_reversed);
910       patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET);
911       handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
912       g_slist_free (patterns);
913       g_free (path);
914       g_free (path_reversed);
915     }
916
917   if (!handled)
918     {
919       guint path_length;
920       gchar *path, *path_reversed;
921       GSList *patterns;
922
923       gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
924       patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET_CLASS);
925       handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
926       g_slist_free (patterns);
927       g_free (path);
928       g_free (path_reversed);
929     }
930
931   if (!handled)
932     {
933       GSList *patterns;
934       GtkType class_type;
935       
936       patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_CLASS);
937       class_type = GTK_OBJECT_TYPE (object);
938       while (class_type && !handled)
939         {
940           guint path_length;
941           const gchar *path;
942           gchar *path_reversed;
943           
944           path = gtk_type_name (class_type);
945           path_reversed = g_strdup (path);
946           g_strreverse (path_reversed);
947           path_length = strlen (path);
948           handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
949           g_free (path_reversed);
950
951           class_type = gtk_type_parent (class_type);
952         }
953       g_slist_free (patterns);
954     }
955
956   return handled;
957 }
958
959 static guint
960 gtk_binding_parse_signal (GScanner       *scanner,
961                           GtkBindingSet  *binding_set,
962                           guint           keyval,
963                           guint           modifiers)
964 {
965   gchar *signal;
966   guint expected_token = 0;
967   GSList *args;
968   GSList *slist;
969   gboolean done;
970   gboolean negate;
971   gboolean need_arg;
972   gboolean seen_comma;
973
974   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
975   
976   g_scanner_get_next_token (scanner);
977   if (scanner->token != G_TOKEN_STRING)
978     return G_TOKEN_STRING;
979   g_scanner_peek_next_token (scanner);
980   if (scanner->next_token != '(')
981     {
982       g_scanner_get_next_token (scanner);
983       return '(';
984     }
985   signal = g_strdup (scanner->value.v_string);
986   g_scanner_get_next_token (scanner);
987
988   negate = FALSE;
989   args = NULL;
990   done = FALSE;
991   need_arg = TRUE;
992   seen_comma = FALSE;
993   scanner->config->scan_symbols = FALSE;
994   do
995     {
996       if (need_arg)
997         expected_token = G_TOKEN_INT;
998       else
999         expected_token = ')';
1000       g_scanner_get_next_token (scanner);
1001       switch (scanner->token)
1002         {
1003           GtkBindingArg *arg;
1004
1005         case G_TOKEN_FLOAT:
1006           if (need_arg)
1007             {
1008               need_arg = FALSE;
1009               arg = g_new (GtkBindingArg, 1);
1010               arg->arg_type = GTK_TYPE_DOUBLE;
1011               arg->d.double_data = scanner->value.v_float;
1012               if (negate)
1013                 {
1014                   arg->d.double_data = - arg->d.double_data;
1015                   negate = FALSE;
1016                 }
1017               args = g_slist_prepend (args, arg);
1018             }
1019           else
1020             done = TRUE;
1021           break;
1022         case G_TOKEN_INT:
1023           if (need_arg)
1024             {
1025               need_arg = FALSE;
1026               arg = g_new (GtkBindingArg, 1);
1027               arg->arg_type = GTK_TYPE_LONG;
1028               arg->d.long_data = scanner->value.v_int;
1029               if (negate)
1030                 {
1031                   arg->d.long_data = - arg->d.long_data;
1032                   negate = FALSE;
1033                 }
1034               args = g_slist_prepend (args, arg);
1035             }
1036           else
1037             done = TRUE;
1038           break;
1039         case G_TOKEN_STRING:
1040           if (need_arg && !negate)
1041             {
1042               need_arg = FALSE;
1043               arg = g_new (GtkBindingArg, 1);
1044               arg->arg_type = GTK_TYPE_STRING;
1045               arg->d.string_data = g_strdup (scanner->value.v_string);
1046               args = g_slist_prepend (args, arg);
1047             }
1048           else
1049             done = TRUE;
1050           break;
1051         case G_TOKEN_IDENTIFIER:
1052           if (need_arg && !negate)
1053             {
1054               need_arg = FALSE;
1055               arg = g_new (GtkBindingArg, 1);
1056               arg->arg_type = GTK_TYPE_IDENTIFIER;
1057               arg->d.string_data = g_strdup (scanner->value.v_identifier);
1058               args = g_slist_prepend (args, arg);
1059             }
1060           else
1061             done = TRUE;
1062           break;
1063         case '-':
1064           if (!need_arg)
1065             done = TRUE;
1066           else if (negate)
1067             {
1068               expected_token = G_TOKEN_INT;
1069               done = TRUE;
1070             }
1071           else
1072             negate = TRUE;
1073           break;
1074         case ',':
1075           seen_comma = TRUE;
1076           if (need_arg)
1077             done = TRUE;
1078           else
1079             need_arg = TRUE;
1080           break;
1081         case ')':
1082           if (!(need_arg && seen_comma) && !negate)
1083             {
1084               args = g_slist_reverse (args);
1085               gtk_binding_entry_add_signall (binding_set,
1086                                              keyval,
1087                                              modifiers,
1088                                              signal,
1089                                              args);
1090               expected_token = G_TOKEN_NONE;
1091             }
1092           done = TRUE;
1093           break;
1094         default:
1095           done = TRUE;
1096           break;
1097         }
1098     }
1099   while (!done);
1100   scanner->config->scan_symbols = TRUE;
1101   
1102   for (slist = args; slist; slist = slist->next)
1103     {
1104       GtkBindingArg *arg;
1105
1106       arg = slist->data;
1107       if (GTK_FUNDAMENTAL_TYPE (arg->arg_type) == GTK_TYPE_STRING)
1108         g_free (arg->d.string_data);
1109       g_free (arg);
1110     }
1111   g_slist_free (args);
1112   g_free (signal);
1113
1114   return expected_token;
1115 }
1116
1117 static inline guint
1118 gtk_binding_parse_bind (GScanner       *scanner,
1119                         GtkBindingSet  *binding_set)
1120 {
1121   guint keyval = 0;
1122   guint modifiers = 0;
1123
1124   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1125   
1126   g_scanner_get_next_token (scanner);
1127   if (scanner->token != GTK_RC_TOKEN_BIND)
1128     return GTK_RC_TOKEN_BIND;
1129   g_scanner_get_next_token (scanner);
1130   if (scanner->token != G_TOKEN_STRING)
1131     return G_TOKEN_STRING;
1132   gtk_accelerator_parse (scanner->value.v_string, &keyval, &modifiers);
1133   modifiers &= BINDING_MOD_MASK ();
1134   if (keyval == 0)
1135     return G_TOKEN_STRING;
1136
1137   g_scanner_get_next_token (scanner);
1138   if (scanner->token != '{')
1139     return '{';
1140
1141   gtk_binding_entry_clear (binding_set, keyval, modifiers);
1142   
1143   g_scanner_peek_next_token (scanner);
1144   while (scanner->next_token != '}')
1145     {
1146       switch (scanner->next_token)
1147         {
1148           guint expected_token;
1149
1150         case G_TOKEN_STRING:
1151           expected_token = gtk_binding_parse_signal (scanner,
1152                                                      binding_set,
1153                                                      keyval,
1154                                                      modifiers);
1155           if (expected_token != G_TOKEN_NONE)
1156             return expected_token;
1157           break;
1158         default:
1159           g_scanner_get_next_token (scanner);
1160           return '}';
1161         }
1162       g_scanner_peek_next_token (scanner);
1163     }
1164   g_scanner_get_next_token (scanner);
1165
1166   return G_TOKEN_NONE;
1167 }
1168
1169 guint
1170 gtk_binding_parse_binding (GScanner       *scanner)
1171 {
1172   gchar *name;
1173   GtkBindingSet *binding_set;
1174
1175   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1176
1177   g_scanner_get_next_token (scanner);
1178   if (scanner->token != GTK_RC_TOKEN_BINDING)
1179     return GTK_RC_TOKEN_BINDING;
1180   g_scanner_get_next_token (scanner);
1181   if (scanner->token != G_TOKEN_STRING)
1182     return G_TOKEN_STRING;
1183   name = g_strdup (scanner->value.v_string);
1184
1185   g_scanner_get_next_token (scanner);
1186   if (scanner->token != '{')
1187     {
1188       g_free (name);
1189       return G_TOKEN_STRING;
1190     }
1191
1192   binding_set = gtk_binding_set_find (name);
1193   if (!binding_set)
1194     binding_set = gtk_binding_set_new (name);
1195   g_free (name);
1196
1197   g_scanner_peek_next_token (scanner);
1198   while (scanner->next_token != '}')
1199     {
1200       switch (scanner->next_token)
1201         {
1202           guint expected_token;
1203
1204         case GTK_RC_TOKEN_BIND:
1205           expected_token = gtk_binding_parse_bind (scanner, binding_set);
1206           if (expected_token != G_TOKEN_NONE)
1207             return expected_token;
1208           break;
1209         default:
1210           g_scanner_get_next_token (scanner);
1211           return '}';
1212         }
1213       g_scanner_peek_next_token (scanner);
1214     }
1215   g_scanner_get_next_token (scanner);
1216
1217   return G_TOKEN_NONE;
1218 }