1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * GtkBindingSet: Keybinding manager for GtkObjects.
5 * Copyright (C) 1998 Tim Janik
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.
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.
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.
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/.
32 #include <gdkkeysyms.h>
33 #include "gtkbindings.h"
34 #include "gtkkeyhash.h"
35 #include "gtksignal.h"
36 #include "gtkwidget.h"
41 #define BINDING_MOD_MASK() (gtk_accelerator_get_default_mod_mask () | GDK_RELEASE_MASK)
44 /* --- structures --- */
52 /* --- variables --- */
53 static GHashTable *binding_entry_hash_table = NULL;
54 static GSList *binding_key_hashes = NULL;
55 static GSList *binding_set_list = NULL;
56 static const gchar *key_class_binding_set = "gtk-class-binding-set";
57 static GQuark key_id_class_binding_set = 0;
60 /* --- functions --- */
61 static GtkBindingSignal*
62 binding_signal_new (const gchar *signal_name,
65 GtkBindingSignal *signal;
67 signal = g_new (GtkBindingSignal, 1);
69 signal->signal_name = g_strdup (signal_name);
70 signal->n_args = n_args;
71 signal->args = g_new0 (GtkBindingArg, n_args);
77 binding_signal_free (GtkBindingSignal *sig)
81 for (i = 0; i < sig->n_args; i++)
83 if (GTK_FUNDAMENTAL_TYPE (sig->args[i].arg_type) == GTK_TYPE_STRING)
84 g_free (sig->args[i].d.string_data);
87 g_free (sig->signal_name);
92 binding_entry_hash (gconstpointer key)
94 register const GtkBindingEntry *e = key;
104 binding_entries_compare (gconstpointer a,
107 register const GtkBindingEntry *ea = a;
108 register const GtkBindingEntry *eb = b;
110 return (ea->keyval == eb->keyval && ea->modifiers == eb->modifiers);
114 binding_key_hash_insert_entry (GtkKeyHash *key_hash,
115 GtkBindingEntry *entry)
117 guint keyval = entry->keyval;
119 /* We store lowercased accelerators. To deal with this, if <Shift>
120 * was specified, uppercase.
122 if (entry->modifiers & GDK_SHIFT_MASK)
124 if (keyval == GDK_Tab)
125 keyval = GDK_ISO_Left_Tab;
127 keyval = gdk_keyval_to_upper (keyval);
130 _gtk_key_hash_add_entry (key_hash, keyval, entry->modifiers & ~GDK_RELEASE_MASK, entry);
134 binding_key_hash_destroy (gpointer data)
136 GtkKeyHash *key_hash = data;
138 binding_key_hashes = g_slist_remove (binding_key_hashes, key_hash);
139 _gtk_key_hash_free (key_hash);
143 insert_entries_into_key_hash (gpointer key,
147 GtkKeyHash *key_hash = data;
148 GtkBindingEntry *entry = value;
150 for (; entry; entry = entry->hash_next)
151 binding_key_hash_insert_entry (key_hash, entry);
155 binding_key_hash_for_keymap (GdkKeymap *keymap)
157 static GQuark key_hash_quark = 0;
158 GtkKeyHash *key_hash;
161 key_hash_quark = g_quark_from_static_string ("gtk-binding-key-hash");
163 key_hash = g_object_get_qdata (G_OBJECT (keymap), key_hash_quark);
167 key_hash = _gtk_key_hash_new (keymap, NULL);
168 g_object_set_qdata_full (G_OBJECT (keymap), key_hash_quark, key_hash, binding_key_hash_destroy);
170 if (binding_entry_hash_table)
171 g_hash_table_foreach (binding_entry_hash_table,
172 insert_entries_into_key_hash,
175 binding_key_hashes = g_slist_prepend (binding_key_hashes, key_hash);
182 static GtkBindingEntry*
183 binding_entry_new (GtkBindingSet *binding_set,
185 GdkModifierType modifiers)
188 GtkBindingEntry *entry;
190 if (!binding_entry_hash_table)
191 binding_entry_hash_table = g_hash_table_new (binding_entry_hash, binding_entries_compare);
193 entry = g_new (GtkBindingEntry, 1);
194 entry->keyval = keyval;
195 entry->modifiers = modifiers;
196 entry->binding_set = binding_set,
197 entry->destroyed = FALSE;
198 entry->in_emission = FALSE;
199 entry->signals = NULL;
201 entry->set_next = binding_set->entries;
202 binding_set->entries = entry;
204 entry->hash_next = g_hash_table_lookup (binding_entry_hash_table, entry);
205 if (entry->hash_next)
206 g_hash_table_remove (binding_entry_hash_table, entry->hash_next);
207 g_hash_table_insert (binding_entry_hash_table, entry, entry);
209 for (tmp_list = binding_key_hashes; tmp_list; tmp_list = tmp_list->next)
211 GtkKeyHash *key_hash = tmp_list->data;
212 binding_key_hash_insert_entry (key_hash, entry);
219 binding_entry_free (GtkBindingEntry *entry)
221 GtkBindingSignal *sig;
223 g_assert (entry->set_next == NULL &&
224 entry->hash_next == NULL &&
225 entry->in_emission == FALSE &&
226 entry->destroyed == TRUE);
228 entry->destroyed = FALSE;
230 sig = entry->signals;
233 GtkBindingSignal *prev;
237 binding_signal_free (prev);
243 binding_entry_destroy (GtkBindingEntry *entry)
245 GtkBindingEntry *o_entry;
246 register GtkBindingEntry *tmp;
247 GtkBindingEntry *begin;
248 register GtkBindingEntry *last;
251 /* unlink from binding set
254 tmp = entry->binding_set->entries;
260 last->set_next = entry->set_next;
262 entry->binding_set->entries = entry->set_next;
266 tmp = last->set_next;
268 entry->set_next = NULL;
270 o_entry = g_hash_table_lookup (binding_entry_hash_table, entry);
279 last->hash_next = entry->hash_next;
281 begin = entry->hash_next;
285 tmp = last->hash_next;
287 entry->hash_next = NULL;
290 g_hash_table_remove (binding_entry_hash_table, entry);
291 else if (begin != o_entry)
293 g_hash_table_remove (binding_entry_hash_table, entry);
294 g_hash_table_insert (binding_entry_hash_table, begin, begin);
297 for (tmp_list = binding_key_hashes; tmp_list; tmp_list = tmp_list->next)
299 GtkKeyHash *key_hash = tmp_list->data;
300 _gtk_key_hash_remove_entry (key_hash, entry);
303 entry->destroyed = TRUE;
305 if (!entry->in_emission)
306 binding_entry_free (entry);
309 static GtkBindingEntry*
310 binding_ht_lookup_entry (GtkBindingSet *set,
312 GdkModifierType modifiers)
314 GtkBindingEntry lookup_entry = { 0 };
315 GtkBindingEntry *entry;
317 if (!binding_entry_hash_table)
320 lookup_entry.keyval = keyval;
321 lookup_entry.modifiers = modifiers;
323 entry = g_hash_table_lookup (binding_entry_hash_table, &lookup_entry);
324 for (; entry; entry = entry->hash_next)
325 if (entry->binding_set == set)
332 binding_compose_params (GtkObject *object,
342 params = g_new0 (GValue, query->n_params + 1);
345 /* The instance we emit on is the first object in the array
347 g_value_init (params, G_TYPE_OBJECT);
348 g_value_set_object (params, G_OBJECT (object));
351 types = query->param_types;
353 for (i = 1; i < query->n_params + 1 && valid; i++)
355 GValue tmp_value = { 0, };
357 g_value_init (params, *types);
359 switch (G_TYPE_FUNDAMENTAL (args->arg_type))
362 g_value_init (&tmp_value, G_TYPE_DOUBLE);
363 g_value_set_double (&tmp_value, args->d.double_data);
366 g_value_init (&tmp_value, G_TYPE_LONG);
367 g_value_set_long (&tmp_value, args->d.long_data);
370 /* gtk_rc_parse_flags/enum() has fancier parsing for this; we can't call
371 * that since we don't have a GParamSpec, so just do something simple
373 if (G_TYPE_FUNDAMENTAL (*types) == G_TYPE_ENUM)
375 GEnumClass *class = G_ENUM_CLASS (g_type_class_ref (*types));
379 if (args->arg_type == GTK_TYPE_IDENTIFIER)
381 GEnumValue *enum_value = NULL;
382 enum_value = g_enum_get_value_by_name (class, args->d.string_data);
384 enum_value = g_enum_get_value_by_nick (class, args->d.string_data);
387 g_value_init (&tmp_value, *types);
388 g_value_set_enum (&tmp_value, enum_value->value);
393 g_type_class_unref (class);
395 /* This is just a hack for compatibility with GTK+-1.2 where a string
396 * could be used for a single flag value / without the support for multiple
397 * values in gtk_rc_parse_flags(), this isn't very useful.
399 else if (G_TYPE_FUNDAMENTAL (*types) == G_TYPE_FLAGS)
401 GFlagsClass *class = G_FLAGS_CLASS (g_type_class_ref (*types));
405 if (args->arg_type == GTK_TYPE_IDENTIFIER)
407 GFlagsValue *flags_value = NULL;
408 flags_value = g_flags_get_value_by_name (class, args->d.string_data);
410 flags_value = g_flags_get_value_by_nick (class, args->d.string_data);
413 g_value_init (&tmp_value, *types);
414 g_value_set_flags (&tmp_value, flags_value->value);
419 g_type_class_unref (class);
423 g_value_init (&tmp_value, G_TYPE_STRING);
424 g_value_set_static_string (&tmp_value, args->d.string_data);
434 if (!g_value_transform (&tmp_value, params))
437 g_value_unset (&tmp_value);
449 for (j = 0; j < i; j++)
450 g_value_unset (&(*params_p)[j]);
460 gtk_binding_entry_activate (GtkBindingEntry *entry,
463 GtkBindingSignal *sig;
464 gboolean old_emission;
465 gboolean handled = FALSE;
468 old_emission = entry->in_emission;
469 entry->in_emission = TRUE;
471 g_object_ref (object);
473 for (sig = entry->signals; sig; sig = sig->next)
477 GValue *params = NULL;
478 GValue return_val = { 0, };
479 gchar *accelerator = NULL;
481 signal_id = g_signal_lookup (sig->signal_name, G_OBJECT_TYPE (object));
484 accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
485 g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
486 "could not find signal \"%s\" in the `%s' class ancestry",
487 entry->binding_set->set_name,
490 g_type_name (G_OBJECT_TYPE (object)));
491 g_free (accelerator);
495 g_signal_query (signal_id, &query);
496 if (query.n_params != sig->n_args ||
497 (query.return_type != G_TYPE_NONE && query.return_type != G_TYPE_BOOLEAN) ||
498 !binding_compose_params (object, sig->args, &query, ¶ms))
500 accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
501 g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
502 "signature mismatch for signal \"%s\" in the `%s' class ancestry",
503 entry->binding_set->set_name,
506 g_type_name (G_OBJECT_TYPE (object)));
508 else if (!(query.signal_flags & GTK_RUN_ACTION))
510 accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
511 g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
512 "signal \"%s\" in the `%s' class ancestry cannot be used for action emissions",
513 entry->binding_set->set_name,
516 g_type_name (G_OBJECT_TYPE (object)));
518 g_free (accelerator);
522 if (query.return_type == G_TYPE_BOOLEAN)
523 g_value_init (&return_val, G_TYPE_BOOLEAN);
525 g_signal_emitv (params, signal_id, 0, &return_val);
527 if (query.return_type == G_TYPE_BOOLEAN)
529 if (g_value_get_boolean (&return_val))
531 g_value_unset (&return_val);
536 for (i = 0; i < query.n_params + 1; i++)
537 g_value_unset (¶ms[i]);
540 if (entry->destroyed)
544 g_object_unref (object);
546 entry->in_emission = old_emission;
547 if (entry->destroyed && !entry->in_emission)
548 binding_entry_free (entry);
554 gtk_binding_set_new (const gchar *set_name)
556 GtkBindingSet *binding_set;
558 g_return_val_if_fail (set_name != NULL, NULL);
560 binding_set = g_new (GtkBindingSet, 1);
561 binding_set->set_name = g_strdup (set_name);
562 binding_set->widget_path_pspecs = NULL;
563 binding_set->widget_class_pspecs = NULL;
564 binding_set->class_branch_pspecs = NULL;
565 binding_set->entries = NULL;
566 binding_set->current = NULL;
568 binding_set_list = g_slist_prepend (binding_set_list, binding_set);
574 gtk_binding_set_by_class (gpointer object_class)
576 GtkObjectClass *class = object_class;
577 GtkBindingSet* binding_set;
579 g_return_val_if_fail (GTK_IS_OBJECT_CLASS (class), NULL);
581 if (!key_id_class_binding_set)
582 key_id_class_binding_set = g_quark_from_static_string (key_class_binding_set);
584 binding_set = g_dataset_id_get_data (class, key_id_class_binding_set);
589 binding_set = gtk_binding_set_new (gtk_type_name (GTK_CLASS_TYPE (class)));
590 gtk_binding_set_add_path (binding_set,
592 gtk_type_name (GTK_CLASS_TYPE (class)),
594 g_dataset_id_set_data (class, key_id_class_binding_set, binding_set);
600 gtk_binding_set_find (const gchar *set_name)
604 g_return_val_if_fail (set_name != NULL, NULL);
606 for (slist = binding_set_list; slist; slist = slist->next)
608 GtkBindingSet *binding_set;
610 binding_set = slist->data;
611 if (g_str_equal (binding_set->set_name, (gpointer) set_name))
618 gtk_binding_set_activate (GtkBindingSet *binding_set,
620 GdkModifierType modifiers,
623 GtkBindingEntry *entry;
625 g_return_val_if_fail (binding_set != NULL, FALSE);
626 g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
628 keyval = gdk_keyval_to_lower (keyval);
629 modifiers = modifiers & BINDING_MOD_MASK ();
631 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
633 return gtk_binding_entry_activate (entry, object);
639 gtk_binding_entry_clear (GtkBindingSet *binding_set,
641 GdkModifierType modifiers)
643 GtkBindingEntry *entry;
645 g_return_if_fail (binding_set != NULL);
647 keyval = gdk_keyval_to_lower (keyval);
648 modifiers = modifiers & BINDING_MOD_MASK ();
650 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
652 binding_entry_destroy (entry);
654 entry = binding_entry_new (binding_set, keyval, modifiers);
658 gtk_binding_entry_remove (GtkBindingSet *binding_set,
660 GdkModifierType modifiers)
662 GtkBindingEntry *entry;
664 g_return_if_fail (binding_set != NULL);
666 keyval = gdk_keyval_to_lower (keyval);
667 modifiers = modifiers & BINDING_MOD_MASK ();
669 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
671 binding_entry_destroy (entry);
675 gtk_binding_entry_add_signall (GtkBindingSet *binding_set,
677 GdkModifierType modifiers,
678 const gchar *signal_name,
679 GSList *binding_args)
681 GtkBindingEntry *entry;
682 GtkBindingSignal *signal, **signal_p;
687 g_return_if_fail (binding_set != NULL);
688 g_return_if_fail (signal_name != NULL);
690 keyval = gdk_keyval_to_lower (keyval);
691 modifiers = modifiers & BINDING_MOD_MASK ();
693 signal = binding_signal_new (signal_name, g_slist_length (binding_args));
696 for (slist = binding_args; slist; slist = slist->next)
698 GtkBindingArg *tmp_arg;
700 tmp_arg = slist->data;
703 g_warning ("gtk_binding_entry_add_signall(): arg[%u] is `NULL'", n);
704 binding_signal_free (signal);
707 switch (GTK_FUNDAMENTAL_TYPE (tmp_arg->arg_type))
710 arg->arg_type = GTK_TYPE_LONG;
711 arg->d.long_data = tmp_arg->d.long_data;
713 case GTK_TYPE_DOUBLE:
714 arg->arg_type = GTK_TYPE_DOUBLE;
715 arg->d.double_data = tmp_arg->d.double_data;
717 case GTK_TYPE_STRING:
718 if (tmp_arg->arg_type != GTK_TYPE_IDENTIFIER)
719 arg->arg_type = GTK_TYPE_STRING;
721 arg->arg_type = GTK_TYPE_IDENTIFIER;
722 arg->d.string_data = g_strdup (tmp_arg->d.string_data);
723 if (!arg->d.string_data)
725 g_warning ("gtk_binding_entry_add_signall(): value of `string' arg[%u] is `NULL'", n);
726 binding_signal_free (signal);
731 g_warning ("gtk_binding_entry_add_signall(): unsupported type `%s' for arg[%u]",
732 gtk_type_name (arg->arg_type), n);
733 binding_signal_free (signal);
740 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
743 gtk_binding_entry_add (binding_set, keyval, modifiers);
744 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
746 signal_p = &entry->signals;
748 signal_p = &(*signal_p)->next;
753 gtk_binding_entry_add_signal (GtkBindingSet *binding_set,
755 GdkModifierType modifiers,
756 const gchar *signal_name,
760 GSList *slist, *free_slist;
764 g_return_if_fail (binding_set != NULL);
765 g_return_if_fail (signal_name != NULL);
767 keyval = gdk_keyval_to_lower (keyval);
768 modifiers = modifiers & BINDING_MOD_MASK ();
770 va_start (args, n_args);
772 for (i = 0; i < n_args; i++)
776 arg = g_new0 (GtkBindingArg, 1);
777 slist = g_slist_prepend (slist, arg);
779 arg->arg_type = va_arg (args, GtkType);
780 switch (GTK_FUNDAMENTAL_TYPE (arg->arg_type))
782 /* for elaborated commenting about var args collection, take a look
783 * at gtk_arg_collect_value() in gtkargcollector.c
792 arg->arg_type = GTK_TYPE_LONG;
793 arg->d.long_data = va_arg (args, gint);
797 arg->arg_type = GTK_TYPE_LONG;
798 arg->d.long_data = va_arg (args, glong);
801 case GTK_TYPE_DOUBLE:
802 arg->arg_type = GTK_TYPE_DOUBLE;
803 arg->d.double_data = va_arg (args, gdouble);
805 case GTK_TYPE_STRING:
806 if (arg->arg_type != GTK_TYPE_IDENTIFIER)
807 arg->arg_type = GTK_TYPE_STRING;
808 arg->d.string_data = va_arg (args, gchar*);
809 if (!arg->d.string_data)
811 g_warning ("gtk_binding_entry_add_signal(): type `%s' arg[%u] is `NULL'",
812 gtk_type_name (arg->arg_type),
818 g_warning ("gtk_binding_entry_add_signal(): unsupported type `%s' for arg[%u]",
819 gtk_type_name (arg->arg_type), i);
826 if (i == n_args || i == 0)
828 slist = g_slist_reverse (slist);
829 gtk_binding_entry_add_signall (binding_set, keyval, modifiers, signal_name, slist);
835 g_free (slist->data);
838 g_slist_free (free_slist);
842 gtk_binding_set_add_path (GtkBindingSet *binding_set,
843 GtkPathType path_type,
844 const gchar *path_pattern,
845 GtkPathPriorityType priority)
848 GSList **slist_p, *slist;
849 static guint seq_id = 0;
851 g_return_if_fail (binding_set != NULL);
852 g_return_if_fail (path_pattern != NULL);
853 g_return_if_fail (priority <= GTK_PATH_PRIO_MASK);
855 priority &= GTK_PATH_PRIO_MASK;
859 case GTK_PATH_WIDGET:
860 slist_p = &binding_set->widget_path_pspecs;
862 case GTK_PATH_WIDGET_CLASS:
863 slist_p = &binding_set->widget_class_pspecs;
866 slist_p = &binding_set->class_branch_pspecs;
869 g_assert_not_reached ();
874 pspec = g_new (PatternSpec, 1);
875 pspec->pspec = g_pattern_spec_new (path_pattern);
876 pspec->seq_id = priority << 28;
877 pspec->user_data = binding_set;
882 PatternSpec *tmp_pspec;
884 tmp_pspec = slist->data;
887 if (g_pattern_spec_equal (tmp_pspec->pspec, pspec->pspec))
889 GtkPathPriorityType lprio = tmp_pspec->seq_id >> 28;
891 g_pattern_spec_free (pspec->pspec);
894 if (lprio < priority)
896 tmp_pspec->seq_id &= 0x0fffffff;
897 tmp_pspec->seq_id |= priority << 28;
904 pspec->seq_id |= seq_id++ & 0x0fffffff;
905 *slist_p = g_slist_prepend (*slist_p, pspec);
910 binding_match_activate (GSList *pspec_list,
914 const gchar *path_reversed)
918 for (slist = pspec_list; slist; slist = slist->next)
923 if (g_pattern_match (pspec->pspec, path_length, path, path_reversed))
925 GtkBindingSet *binding_set;
927 binding_set = pspec->user_data;
929 if (gtk_binding_entry_activate (binding_set->current, object))
938 gtk_binding_pattern_compare (gconstpointer new_pattern,
939 gconstpointer existing_pattern)
941 register const PatternSpec *np = new_pattern;
942 register const PatternSpec *ep = existing_pattern;
944 /* walk the list as long as the existing patterns have
948 return np->seq_id < ep->seq_id;
952 gtk_binding_entries_sort_patterns (GSList *entries,
960 for (tmp_list = entries; tmp_list; tmp_list = tmp_list->next)
962 GtkBindingEntry *entry = tmp_list->data;
963 GtkBindingSet *binding_set;
965 binding_set = entry->binding_set;
966 binding_set->current = NULL;
969 for (; entries; entries = entries->next)
971 GtkBindingEntry *entry = entries->data;
972 GtkBindingSet *binding_set;
973 GSList *slist = NULL;
975 if (is_release != ((entry->modifiers & GDK_RELEASE_MASK) != 0))
978 binding_set = entry->binding_set;
980 if (binding_set->current)
982 binding_set->current = entry;
986 case GTK_PATH_WIDGET:
987 slist = binding_set->widget_path_pspecs;
989 case GTK_PATH_WIDGET_CLASS:
990 slist = binding_set->widget_class_pspecs;
993 slist = binding_set->class_branch_pspecs;
997 for (; slist; slist = slist->next)
1001 pspec = slist->data;
1002 patterns = g_slist_insert_sorted (patterns, pspec, gtk_binding_pattern_compare);
1010 gtk_bindings_activate_list (GtkObject *object,
1012 gboolean is_release)
1014 GtkWidget *widget = GTK_WIDGET (object);
1015 gboolean handled = FALSE;
1023 gchar *path, *path_reversed;
1026 gtk_widget_path (widget, &path_length, &path, &path_reversed);
1027 patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET, is_release);
1028 handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
1029 g_slist_free (patterns);
1031 g_free (path_reversed);
1037 gchar *path, *path_reversed;
1040 gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
1041 patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET_CLASS, is_release);
1042 handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
1043 g_slist_free (patterns);
1045 g_free (path_reversed);
1053 patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_CLASS, is_release);
1054 class_type = GTK_OBJECT_TYPE (object);
1055 while (class_type && !handled)
1059 gchar *path_reversed;
1061 path = gtk_type_name (class_type);
1062 path_reversed = g_strdup (path);
1063 g_strreverse (path_reversed);
1064 path_length = strlen (path);
1065 handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
1066 g_free (path_reversed);
1068 class_type = gtk_type_parent (class_type);
1070 g_slist_free (patterns);
1077 gtk_bindings_activate (GtkObject *object,
1079 GdkModifierType modifiers)
1081 GSList *entries = NULL;
1082 GtkKeyHash *key_hash;
1083 gboolean handled = FALSE;
1084 gboolean is_release;
1086 g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
1088 if (!GTK_IS_WIDGET (object))
1091 is_release = (modifiers & GDK_RELEASE_MASK) != 0;
1092 modifiers = modifiers & BINDING_MOD_MASK () & ~GDK_RELEASE_MASK;
1094 key_hash = binding_key_hash_for_keymap (gdk_keymap_get_default ());
1095 entries = _gtk_key_hash_lookup_keyval (key_hash, keyval, modifiers);
1097 handled = gtk_bindings_activate_list (object, entries, is_release);
1099 g_slist_free (entries);
1105 * _gtk_bindings_activate_event:
1106 * @object: a #GtkObject (generally must be a widget)
1107 * @event: a #GdkEventKey
1109 * Looks up key bindings for @object to find one matching
1110 * @event, and if one was found, activate it.
1112 * Return value: %TRUE if a matching key binding was found
1115 _gtk_bindings_activate_event (GtkObject *object,
1118 GSList *entries = NULL;
1119 GtkKeyHash *key_hash;
1120 gboolean handled = FALSE;
1122 g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
1124 if (!GTK_IS_WIDGET (object))
1127 key_hash = binding_key_hash_for_keymap (gdk_keymap_get_default ());
1128 entries = _gtk_key_hash_lookup (key_hash,
1129 event->hardware_keycode,
1130 event->state & BINDING_MOD_MASK () & ~GDK_RELEASE_MASK,
1133 handled = gtk_bindings_activate_list (object, entries,
1134 event->type == GDK_KEY_RELEASE);
1136 g_slist_free (entries);
1142 gtk_binding_parse_signal (GScanner *scanner,
1143 GtkBindingSet *binding_set,
1145 GdkModifierType modifiers)
1148 guint expected_token = 0;
1154 gboolean seen_comma;
1156 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1158 g_scanner_get_next_token (scanner);
1159 if (scanner->token != G_TOKEN_STRING)
1160 return G_TOKEN_STRING;
1161 g_scanner_peek_next_token (scanner);
1162 if (scanner->next_token != '(')
1164 g_scanner_get_next_token (scanner);
1167 signal = g_strdup (scanner->value.v_string);
1168 g_scanner_get_next_token (scanner);
1175 scanner->config->scan_symbols = FALSE;
1179 expected_token = G_TOKEN_INT;
1181 expected_token = ')';
1182 g_scanner_get_next_token (scanner);
1183 switch (scanner->token)
1191 arg = g_new (GtkBindingArg, 1);
1192 arg->arg_type = GTK_TYPE_DOUBLE;
1193 arg->d.double_data = scanner->value.v_float;
1196 arg->d.double_data = - arg->d.double_data;
1199 args = g_slist_prepend (args, arg);
1208 arg = g_new (GtkBindingArg, 1);
1209 arg->arg_type = GTK_TYPE_LONG;
1210 arg->d.long_data = scanner->value.v_int;
1213 arg->d.long_data = - arg->d.long_data;
1216 args = g_slist_prepend (args, arg);
1221 case G_TOKEN_STRING:
1222 if (need_arg && !negate)
1225 arg = g_new (GtkBindingArg, 1);
1226 arg->arg_type = GTK_TYPE_STRING;
1227 arg->d.string_data = g_strdup (scanner->value.v_string);
1228 args = g_slist_prepend (args, arg);
1233 case G_TOKEN_IDENTIFIER:
1234 if (need_arg && !negate)
1237 arg = g_new (GtkBindingArg, 1);
1238 arg->arg_type = GTK_TYPE_IDENTIFIER;
1239 arg->d.string_data = g_strdup (scanner->value.v_identifier);
1240 args = g_slist_prepend (args, arg);
1250 expected_token = G_TOKEN_INT;
1264 if (!(need_arg && seen_comma) && !negate)
1266 args = g_slist_reverse (args);
1267 gtk_binding_entry_add_signall (binding_set,
1272 expected_token = G_TOKEN_NONE;
1282 scanner->config->scan_symbols = TRUE;
1284 for (slist = args; slist; slist = slist->next)
1289 if (GTK_FUNDAMENTAL_TYPE (arg->arg_type) == GTK_TYPE_STRING)
1290 g_free (arg->d.string_data);
1293 g_slist_free (args);
1296 return expected_token;
1300 gtk_binding_parse_bind (GScanner *scanner,
1301 GtkBindingSet *binding_set)
1304 GdkModifierType modifiers = 0;
1306 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1308 g_scanner_get_next_token (scanner);
1309 if (scanner->token != GTK_RC_TOKEN_BIND)
1310 return GTK_RC_TOKEN_BIND;
1311 g_scanner_get_next_token (scanner);
1312 if (scanner->token != G_TOKEN_STRING)
1313 return G_TOKEN_STRING;
1314 gtk_accelerator_parse (scanner->value.v_string, &keyval, &modifiers);
1315 modifiers &= BINDING_MOD_MASK ();
1317 return G_TOKEN_STRING;
1319 g_scanner_get_next_token (scanner);
1320 if (scanner->token != '{')
1323 gtk_binding_entry_clear (binding_set, keyval, modifiers);
1325 g_scanner_peek_next_token (scanner);
1326 while (scanner->next_token != '}')
1328 switch (scanner->next_token)
1330 guint expected_token;
1332 case G_TOKEN_STRING:
1333 expected_token = gtk_binding_parse_signal (scanner,
1337 if (expected_token != G_TOKEN_NONE)
1338 return expected_token;
1341 g_scanner_get_next_token (scanner);
1344 g_scanner_peek_next_token (scanner);
1346 g_scanner_get_next_token (scanner);
1348 return G_TOKEN_NONE;
1352 gtk_binding_parse_binding (GScanner *scanner)
1355 GtkBindingSet *binding_set;
1357 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1359 g_scanner_get_next_token (scanner);
1360 if (scanner->token != GTK_RC_TOKEN_BINDING)
1361 return GTK_RC_TOKEN_BINDING;
1362 g_scanner_get_next_token (scanner);
1363 if (scanner->token != G_TOKEN_STRING)
1364 return G_TOKEN_STRING;
1365 name = g_strdup (scanner->value.v_string);
1367 g_scanner_get_next_token (scanner);
1368 if (scanner->token != '{')
1371 return G_TOKEN_STRING;
1374 binding_set = gtk_binding_set_find (name);
1377 binding_set = gtk_binding_set_new (name);
1378 binding_set->parsed = 1;
1382 g_scanner_peek_next_token (scanner);
1383 while (scanner->next_token != '}')
1385 switch (scanner->next_token)
1387 guint expected_token;
1389 case GTK_RC_TOKEN_BIND:
1390 expected_token = gtk_binding_parse_bind (scanner, binding_set);
1391 if (expected_token != G_TOKEN_NONE)
1392 return expected_token;
1395 g_scanner_get_next_token (scanner);
1398 g_scanner_peek_next_token (scanner);
1400 g_scanner_get_next_token (scanner);
1402 return G_TOKEN_NONE;
1406 free_pattern_specs (GSList *pattern_specs)
1410 for (slist = pattern_specs; slist; slist = slist->next)
1414 pspec = slist->data;
1416 g_pattern_spec_free (pspec->pspec);
1420 g_slist_free (pattern_specs);
1424 binding_set_delete (GtkBindingSet *binding_set)
1426 GtkBindingEntry *entry, *next;
1428 entry = binding_set->entries;
1431 next = entry->set_next;
1432 binding_entry_destroy (entry);
1436 free_pattern_specs (binding_set->widget_path_pspecs);
1437 free_pattern_specs (binding_set->widget_class_pspecs);
1438 free_pattern_specs (binding_set->class_branch_pspecs);
1440 g_free (binding_set->set_name);
1441 g_free (binding_set);
1445 * _gtk_binding_reset_parsed:
1447 * Removing all binding sets that were added by
1448 * gtk_binding_parse_binding()
1451 _gtk_binding_reset_parsed (void)
1453 GSList *slist, *next;
1455 slist = binding_set_list;
1458 GtkBindingSet *binding_set;
1460 binding_set = slist->data;
1463 if (binding_set->parsed)
1465 binding_set_list = g_slist_delete_link (binding_set_list, slist);
1466 binding_set_delete (binding_set);