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