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/.
33 #include <gdkkeysyms.h>
34 #include "gtkbindings.h"
35 #include "gtkkeyhash.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 (G_TYPE_FUNDAMENTAL (sig->args[i].arg_type) == G_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 & G_SIGNAL_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;
567 binding_set->parsed = FALSE;
569 binding_set_list = g_slist_prepend (binding_set_list, binding_set);
575 gtk_binding_set_by_class (gpointer object_class)
577 GtkObjectClass *class = object_class;
578 GtkBindingSet* binding_set;
580 g_return_val_if_fail (GTK_IS_OBJECT_CLASS (class), NULL);
582 if (!key_id_class_binding_set)
583 key_id_class_binding_set = g_quark_from_static_string (key_class_binding_set);
585 binding_set = g_dataset_id_get_data (class, key_id_class_binding_set);
590 binding_set = gtk_binding_set_new (g_type_name (G_OBJECT_CLASS_TYPE (class)));
591 gtk_binding_set_add_path (binding_set,
593 g_type_name (G_OBJECT_CLASS_TYPE (class)),
595 g_dataset_id_set_data (class, key_id_class_binding_set, binding_set);
601 gtk_binding_set_find (const gchar *set_name)
605 g_return_val_if_fail (set_name != NULL, NULL);
607 for (slist = binding_set_list; slist; slist = slist->next)
609 GtkBindingSet *binding_set;
611 binding_set = slist->data;
612 if (g_str_equal (binding_set->set_name, (gpointer) set_name))
619 gtk_binding_set_activate (GtkBindingSet *binding_set,
621 GdkModifierType modifiers,
624 GtkBindingEntry *entry;
626 g_return_val_if_fail (binding_set != NULL, FALSE);
627 g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
629 keyval = gdk_keyval_to_lower (keyval);
630 modifiers = modifiers & BINDING_MOD_MASK ();
632 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
634 return gtk_binding_entry_activate (entry, object);
640 gtk_binding_entry_clear (GtkBindingSet *binding_set,
642 GdkModifierType modifiers)
644 GtkBindingEntry *entry;
646 g_return_if_fail (binding_set != NULL);
648 keyval = gdk_keyval_to_lower (keyval);
649 modifiers = modifiers & BINDING_MOD_MASK ();
651 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
653 binding_entry_destroy (entry);
655 entry = binding_entry_new (binding_set, keyval, modifiers);
659 gtk_binding_entry_remove (GtkBindingSet *binding_set,
661 GdkModifierType modifiers)
663 GtkBindingEntry *entry;
665 g_return_if_fail (binding_set != NULL);
667 keyval = gdk_keyval_to_lower (keyval);
668 modifiers = modifiers & BINDING_MOD_MASK ();
670 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
672 binding_entry_destroy (entry);
676 gtk_binding_entry_add_signall (GtkBindingSet *binding_set,
678 GdkModifierType modifiers,
679 const gchar *signal_name,
680 GSList *binding_args)
682 GtkBindingEntry *entry;
683 GtkBindingSignal *signal, **signal_p;
688 g_return_if_fail (binding_set != NULL);
689 g_return_if_fail (signal_name != NULL);
691 keyval = gdk_keyval_to_lower (keyval);
692 modifiers = modifiers & BINDING_MOD_MASK ();
694 signal = binding_signal_new (signal_name, g_slist_length (binding_args));
697 for (slist = binding_args; slist; slist = slist->next)
699 GtkBindingArg *tmp_arg;
701 tmp_arg = slist->data;
704 g_warning ("gtk_binding_entry_add_signall(): arg[%u] is `NULL'", n);
705 binding_signal_free (signal);
708 switch (G_TYPE_FUNDAMENTAL (tmp_arg->arg_type))
711 arg->arg_type = G_TYPE_LONG;
712 arg->d.long_data = tmp_arg->d.long_data;
715 arg->arg_type = G_TYPE_DOUBLE;
716 arg->d.double_data = tmp_arg->d.double_data;
719 if (tmp_arg->arg_type != GTK_TYPE_IDENTIFIER)
720 arg->arg_type = G_TYPE_STRING;
722 arg->arg_type = GTK_TYPE_IDENTIFIER;
723 arg->d.string_data = g_strdup (tmp_arg->d.string_data);
724 if (!arg->d.string_data)
726 g_warning ("gtk_binding_entry_add_signall(): value of `string' arg[%u] is `NULL'", n);
727 binding_signal_free (signal);
732 g_warning ("gtk_binding_entry_add_signall(): unsupported type `%s' for arg[%u]",
733 g_type_name (arg->arg_type), n);
734 binding_signal_free (signal);
741 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
744 gtk_binding_entry_add (binding_set, keyval, modifiers);
745 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
747 signal_p = &entry->signals;
749 signal_p = &(*signal_p)->next;
754 gtk_binding_entry_add_signal (GtkBindingSet *binding_set,
756 GdkModifierType modifiers,
757 const gchar *signal_name,
761 GSList *slist, *free_slist;
765 g_return_if_fail (binding_set != NULL);
766 g_return_if_fail (signal_name != NULL);
768 va_start (args, n_args);
770 for (i = 0; i < n_args; i++)
774 arg = g_new0 (GtkBindingArg, 1);
775 slist = g_slist_prepend (slist, arg);
777 arg->arg_type = va_arg (args, GtkType);
778 switch (G_TYPE_FUNDAMENTAL (arg->arg_type))
780 /* for elaborated commenting about var args collection, take a look
781 * at gtk_arg_collect_value() in gtkargcollector.c
790 arg->arg_type = G_TYPE_LONG;
791 arg->d.long_data = va_arg (args, gint);
795 arg->arg_type = G_TYPE_LONG;
796 arg->d.long_data = va_arg (args, glong);
800 arg->arg_type = G_TYPE_DOUBLE;
801 arg->d.double_data = va_arg (args, gdouble);
804 if (arg->arg_type != GTK_TYPE_IDENTIFIER)
805 arg->arg_type = G_TYPE_STRING;
806 arg->d.string_data = va_arg (args, gchar*);
807 if (!arg->d.string_data)
809 g_warning ("gtk_binding_entry_add_signal(): type `%s' arg[%u] is `NULL'",
810 g_type_name (arg->arg_type),
816 g_warning ("gtk_binding_entry_add_signal(): unsupported type `%s' for arg[%u]",
817 g_type_name (arg->arg_type), i);
824 if (i == n_args || i == 0)
826 slist = g_slist_reverse (slist);
827 gtk_binding_entry_add_signall (binding_set, keyval, modifiers, signal_name, slist);
833 g_free (slist->data);
836 g_slist_free (free_slist);
840 gtk_binding_set_add_path (GtkBindingSet *binding_set,
841 GtkPathType path_type,
842 const gchar *path_pattern,
843 GtkPathPriorityType priority)
846 GSList **slist_p, *slist;
847 static guint seq_id = 0;
849 g_return_if_fail (binding_set != NULL);
850 g_return_if_fail (path_pattern != NULL);
851 g_return_if_fail (priority <= GTK_PATH_PRIO_MASK);
853 priority &= GTK_PATH_PRIO_MASK;
857 case GTK_PATH_WIDGET:
858 slist_p = &binding_set->widget_path_pspecs;
860 case GTK_PATH_WIDGET_CLASS:
861 slist_p = &binding_set->widget_class_pspecs;
864 slist_p = &binding_set->class_branch_pspecs;
867 g_assert_not_reached ();
872 pspec = g_new (PatternSpec, 1);
873 pspec->pspec = g_pattern_spec_new (path_pattern);
874 pspec->seq_id = priority << 28;
875 pspec->user_data = binding_set;
880 PatternSpec *tmp_pspec;
882 tmp_pspec = slist->data;
885 if (g_pattern_spec_equal (tmp_pspec->pspec, pspec->pspec))
887 GtkPathPriorityType lprio = tmp_pspec->seq_id >> 28;
889 g_pattern_spec_free (pspec->pspec);
892 if (lprio < priority)
894 tmp_pspec->seq_id &= 0x0fffffff;
895 tmp_pspec->seq_id |= priority << 28;
902 pspec->seq_id |= seq_id++ & 0x0fffffff;
903 *slist_p = g_slist_prepend (*slist_p, pspec);
908 binding_match_activate (GSList *pspec_list,
912 const gchar *path_reversed)
916 for (slist = pspec_list; slist; slist = slist->next)
921 if (g_pattern_match (pspec->pspec, path_length, path, path_reversed))
923 GtkBindingSet *binding_set;
925 binding_set = pspec->user_data;
927 if (gtk_binding_entry_activate (binding_set->current, object))
936 gtk_binding_pattern_compare (gconstpointer new_pattern,
937 gconstpointer existing_pattern)
939 register const PatternSpec *np = new_pattern;
940 register const PatternSpec *ep = existing_pattern;
942 /* walk the list as long as the existing patterns have
946 return np->seq_id < ep->seq_id;
950 gtk_binding_entries_sort_patterns (GSList *entries,
958 for (tmp_list = entries; tmp_list; tmp_list = tmp_list->next)
960 GtkBindingEntry *entry = tmp_list->data;
961 GtkBindingSet *binding_set;
963 binding_set = entry->binding_set;
964 binding_set->current = NULL;
967 for (; entries; entries = entries->next)
969 GtkBindingEntry *entry = entries->data;
970 GtkBindingSet *binding_set;
971 GSList *slist = NULL;
973 if (is_release != ((entry->modifiers & GDK_RELEASE_MASK) != 0))
976 binding_set = entry->binding_set;
978 if (binding_set->current)
980 binding_set->current = entry;
984 case GTK_PATH_WIDGET:
985 slist = binding_set->widget_path_pspecs;
987 case GTK_PATH_WIDGET_CLASS:
988 slist = binding_set->widget_class_pspecs;
991 slist = binding_set->class_branch_pspecs;
995 for (; slist; slist = slist->next)
1000 patterns = g_slist_insert_sorted (patterns, pspec, gtk_binding_pattern_compare);
1008 gtk_bindings_activate_list (GtkObject *object,
1010 gboolean is_release)
1012 GtkWidget *widget = GTK_WIDGET (object);
1013 gboolean handled = FALSE;
1021 gchar *path, *path_reversed;
1024 gtk_widget_path (widget, &path_length, &path, &path_reversed);
1025 patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET, is_release);
1026 handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
1027 g_slist_free (patterns);
1029 g_free (path_reversed);
1035 gchar *path, *path_reversed;
1038 gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
1039 patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET_CLASS, is_release);
1040 handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
1041 g_slist_free (patterns);
1043 g_free (path_reversed);
1051 patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_CLASS, is_release);
1052 class_type = G_TYPE_FROM_INSTANCE (object);
1053 while (class_type && !handled)
1057 gchar *path_reversed;
1059 path = g_type_name (class_type);
1060 path_reversed = g_strdup (path);
1061 g_strreverse (path_reversed);
1062 path_length = strlen (path);
1063 handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
1064 g_free (path_reversed);
1066 class_type = g_type_parent (class_type);
1068 g_slist_free (patterns);
1075 gtk_bindings_activate (GtkObject *object,
1077 GdkModifierType modifiers)
1079 GSList *entries = NULL;
1080 GdkDisplay *display;
1081 GtkKeyHash *key_hash;
1082 gboolean handled = FALSE;
1083 gboolean is_release;
1085 g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
1087 if (!GTK_IS_WIDGET (object))
1090 is_release = (modifiers & GDK_RELEASE_MASK) != 0;
1091 modifiers = modifiers & BINDING_MOD_MASK () & ~GDK_RELEASE_MASK;
1093 display = gtk_widget_get_display (GTK_WIDGET (object));
1094 key_hash = binding_key_hash_for_keymap (gdk_keymap_get_for_display (display));
1096 entries = _gtk_key_hash_lookup_keyval (key_hash, keyval, modifiers);
1098 handled = gtk_bindings_activate_list (object, entries, is_release);
1100 g_slist_free (entries);
1106 * gtk_bindings_activate_event:
1107 * @object: a #GtkObject (generally must be a widget)
1108 * @event: a #GdkEventKey
1110 * Looks up key bindings for @object to find one matching
1111 * @event, and if one was found, activate it.
1113 * Return value: %TRUE if a matching key binding was found
1116 gtk_bindings_activate_event (GtkObject *object,
1119 GSList *entries = NULL;
1120 GdkDisplay *display;
1121 GtkKeyHash *key_hash;
1122 gboolean handled = FALSE;
1124 g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
1126 if (!GTK_IS_WIDGET (object))
1129 display = gtk_widget_get_display (GTK_WIDGET (object));
1130 key_hash = binding_key_hash_for_keymap (gdk_keymap_get_for_display (display));
1132 entries = _gtk_key_hash_lookup (key_hash,
1133 event->hardware_keycode,
1135 BINDING_MOD_MASK () & ~GDK_RELEASE_MASK,
1138 handled = gtk_bindings_activate_list (object, entries,
1139 event->type == GDK_KEY_RELEASE);
1141 g_slist_free (entries);
1147 gtk_binding_parse_signal (GScanner *scanner,
1148 GtkBindingSet *binding_set,
1150 GdkModifierType modifiers)
1153 guint expected_token = 0;
1159 gboolean seen_comma;
1161 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1163 g_scanner_get_next_token (scanner);
1164 if (scanner->token != G_TOKEN_STRING)
1165 return G_TOKEN_STRING;
1166 g_scanner_peek_next_token (scanner);
1167 if (scanner->next_token != '(')
1169 g_scanner_get_next_token (scanner);
1172 signal = g_strdup (scanner->value.v_string);
1173 g_scanner_get_next_token (scanner);
1180 scanner->config->scan_symbols = FALSE;
1184 expected_token = G_TOKEN_INT;
1186 expected_token = ')';
1187 g_scanner_get_next_token (scanner);
1188 switch (scanner->token)
1196 arg = g_new (GtkBindingArg, 1);
1197 arg->arg_type = G_TYPE_DOUBLE;
1198 arg->d.double_data = scanner->value.v_float;
1201 arg->d.double_data = - arg->d.double_data;
1204 args = g_slist_prepend (args, arg);
1213 arg = g_new (GtkBindingArg, 1);
1214 arg->arg_type = G_TYPE_LONG;
1215 arg->d.long_data = scanner->value.v_int;
1218 arg->d.long_data = - arg->d.long_data;
1221 args = g_slist_prepend (args, arg);
1226 case G_TOKEN_STRING:
1227 if (need_arg && !negate)
1230 arg = g_new (GtkBindingArg, 1);
1231 arg->arg_type = G_TYPE_STRING;
1232 arg->d.string_data = g_strdup (scanner->value.v_string);
1233 args = g_slist_prepend (args, arg);
1238 case G_TOKEN_IDENTIFIER:
1239 if (need_arg && !negate)
1242 arg = g_new (GtkBindingArg, 1);
1243 arg->arg_type = GTK_TYPE_IDENTIFIER;
1244 arg->d.string_data = g_strdup (scanner->value.v_identifier);
1245 args = g_slist_prepend (args, arg);
1255 expected_token = G_TOKEN_INT;
1269 if (!(need_arg && seen_comma) && !negate)
1271 args = g_slist_reverse (args);
1272 gtk_binding_entry_add_signall (binding_set,
1277 expected_token = G_TOKEN_NONE;
1287 scanner->config->scan_symbols = TRUE;
1289 for (slist = args; slist; slist = slist->next)
1294 if (G_TYPE_FUNDAMENTAL (arg->arg_type) == G_TYPE_STRING)
1295 g_free (arg->d.string_data);
1298 g_slist_free (args);
1301 return expected_token;
1305 gtk_binding_parse_bind (GScanner *scanner,
1306 GtkBindingSet *binding_set)
1309 GdkModifierType modifiers = 0;
1311 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1313 g_scanner_get_next_token (scanner);
1314 if (scanner->token != GTK_RC_TOKEN_BIND)
1315 return GTK_RC_TOKEN_BIND;
1316 g_scanner_get_next_token (scanner);
1317 if (scanner->token != G_TOKEN_STRING)
1318 return G_TOKEN_STRING;
1319 gtk_accelerator_parse (scanner->value.v_string, &keyval, &modifiers);
1320 modifiers &= BINDING_MOD_MASK ();
1322 return G_TOKEN_STRING;
1324 g_scanner_get_next_token (scanner);
1325 if (scanner->token != '{')
1328 gtk_binding_entry_clear (binding_set, keyval, modifiers);
1330 g_scanner_peek_next_token (scanner);
1331 while (scanner->next_token != '}')
1333 switch (scanner->next_token)
1335 guint expected_token;
1337 case G_TOKEN_STRING:
1338 expected_token = gtk_binding_parse_signal (scanner,
1342 if (expected_token != G_TOKEN_NONE)
1343 return expected_token;
1346 g_scanner_get_next_token (scanner);
1349 g_scanner_peek_next_token (scanner);
1351 g_scanner_get_next_token (scanner);
1353 return G_TOKEN_NONE;
1357 gtk_binding_parse_binding (GScanner *scanner)
1360 GtkBindingSet *binding_set;
1362 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1364 g_scanner_get_next_token (scanner);
1365 if (scanner->token != GTK_RC_TOKEN_BINDING)
1366 return GTK_RC_TOKEN_BINDING;
1367 g_scanner_get_next_token (scanner);
1368 if (scanner->token != G_TOKEN_STRING)
1369 return G_TOKEN_STRING;
1370 name = g_strdup (scanner->value.v_string);
1372 g_scanner_get_next_token (scanner);
1373 if (scanner->token != '{')
1376 return G_TOKEN_STRING;
1379 binding_set = gtk_binding_set_find (name);
1382 binding_set = gtk_binding_set_new (name);
1383 binding_set->parsed = 1;
1387 g_scanner_peek_next_token (scanner);
1388 while (scanner->next_token != '}')
1390 switch (scanner->next_token)
1392 guint expected_token;
1394 case GTK_RC_TOKEN_BIND:
1395 expected_token = gtk_binding_parse_bind (scanner, binding_set);
1396 if (expected_token != G_TOKEN_NONE)
1397 return expected_token;
1400 g_scanner_get_next_token (scanner);
1403 g_scanner_peek_next_token (scanner);
1405 g_scanner_get_next_token (scanner);
1407 return G_TOKEN_NONE;
1411 free_pattern_specs (GSList *pattern_specs)
1415 for (slist = pattern_specs; slist; slist = slist->next)
1419 pspec = slist->data;
1421 g_pattern_spec_free (pspec->pspec);
1425 g_slist_free (pattern_specs);
1429 binding_set_delete (GtkBindingSet *binding_set)
1431 GtkBindingEntry *entry, *next;
1433 entry = binding_set->entries;
1436 next = entry->set_next;
1437 binding_entry_destroy (entry);
1441 free_pattern_specs (binding_set->widget_path_pspecs);
1442 free_pattern_specs (binding_set->widget_class_pspecs);
1443 free_pattern_specs (binding_set->class_branch_pspecs);
1445 g_free (binding_set->set_name);
1446 g_free (binding_set);
1450 * _gtk_binding_reset_parsed:
1452 * Removing all binding sets that were added by
1453 * gtk_binding_parse_binding()
1456 _gtk_binding_reset_parsed (void)
1458 GSList *slist, *next;
1460 slist = binding_set_list;
1463 GtkBindingSet *binding_set;
1465 binding_set = slist->data;
1468 if (binding_set->parsed)
1470 binding_set_list = g_slist_delete_link (binding_set_list, slist);
1471 binding_set_delete (binding_set);
1479 _gtk_binding_signal_new (const gchar *signal_name,
1481 GSignalFlags signal_flags,
1483 GSignalAccumulator accumulator,
1485 GSignalCMarshaller c_marshaller,
1493 g_return_val_if_fail (signal_name != NULL, 0);
1495 va_start (args, n_params);
1497 signal_id = g_signal_new_valist (signal_name, itype, signal_flags,
1498 g_cclosure_new (handler, NULL, NULL),
1499 accumulator, accu_data, c_marshaller,
1500 return_type, n_params, args);