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