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