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>
35 #include "gtkbindings.h"
36 #include "gtkkeyhash.h"
37 #include "gtkwidget.h"
42 #define BINDING_MOD_MASK() (gtk_accelerator_get_default_mod_mask () | GDK_RELEASE_MASK)
45 /* --- structures --- */
53 /* --- variables --- */
54 static GHashTable *binding_entry_hash_table = NULL;
55 static GSList *binding_key_hashes = NULL;
56 static GSList *binding_set_list = NULL;
57 static const gchar *key_class_binding_set = "gtk-class-binding-set";
58 static GQuark key_id_class_binding_set = 0;
61 /* --- functions --- */
62 static GtkBindingSignal*
63 binding_signal_new (const gchar *signal_name,
66 GtkBindingSignal *signal;
68 signal = g_new (GtkBindingSignal, 1);
70 signal->signal_name = g_strdup (signal_name);
71 signal->n_args = n_args;
72 signal->args = g_new0 (GtkBindingArg, n_args);
78 binding_signal_free (GtkBindingSignal *sig)
82 for (i = 0; i < sig->n_args; i++)
84 if (G_TYPE_FUNDAMENTAL (sig->args[i].arg_type) == G_TYPE_STRING)
85 g_free (sig->args[i].d.string_data);
88 g_free (sig->signal_name);
93 binding_entry_hash (gconstpointer key)
95 register const GtkBindingEntry *e = key;
105 binding_entries_compare (gconstpointer a,
108 register const GtkBindingEntry *ea = a;
109 register const GtkBindingEntry *eb = b;
111 return (ea->keyval == eb->keyval && ea->modifiers == eb->modifiers);
115 binding_key_hash_insert_entry (GtkKeyHash *key_hash,
116 GtkBindingEntry *entry)
118 guint keyval = entry->keyval;
120 /* We store lowercased accelerators. To deal with this, if <Shift>
121 * was specified, uppercase.
123 if (entry->modifiers & GDK_SHIFT_MASK)
125 if (keyval == GDK_Tab)
126 keyval = GDK_ISO_Left_Tab;
128 keyval = gdk_keyval_to_upper (keyval);
131 _gtk_key_hash_add_entry (key_hash, keyval, entry->modifiers & ~GDK_RELEASE_MASK, entry);
135 binding_key_hash_destroy (gpointer data)
137 GtkKeyHash *key_hash = data;
139 binding_key_hashes = g_slist_remove (binding_key_hashes, key_hash);
140 _gtk_key_hash_free (key_hash);
144 insert_entries_into_key_hash (gpointer key,
148 GtkKeyHash *key_hash = data;
149 GtkBindingEntry *entry = value;
151 for (; entry; entry = entry->hash_next)
152 binding_key_hash_insert_entry (key_hash, entry);
156 binding_key_hash_for_keymap (GdkKeymap *keymap)
158 static GQuark key_hash_quark = 0;
159 GtkKeyHash *key_hash;
162 key_hash_quark = g_quark_from_static_string ("gtk-binding-key-hash");
164 key_hash = g_object_get_qdata (G_OBJECT (keymap), key_hash_quark);
168 key_hash = _gtk_key_hash_new (keymap, NULL);
169 g_object_set_qdata_full (G_OBJECT (keymap), key_hash_quark, key_hash, binding_key_hash_destroy);
171 if (binding_entry_hash_table)
172 g_hash_table_foreach (binding_entry_hash_table,
173 insert_entries_into_key_hash,
176 binding_key_hashes = g_slist_prepend (binding_key_hashes, key_hash);
183 static GtkBindingEntry*
184 binding_entry_new (GtkBindingSet *binding_set,
186 GdkModifierType modifiers)
189 GtkBindingEntry *entry;
191 if (!binding_entry_hash_table)
192 binding_entry_hash_table = g_hash_table_new (binding_entry_hash, binding_entries_compare);
194 entry = g_new (GtkBindingEntry, 1);
195 entry->keyval = keyval;
196 entry->modifiers = modifiers;
197 entry->binding_set = binding_set,
198 entry->destroyed = FALSE;
199 entry->in_emission = FALSE;
200 entry->signals = NULL;
202 entry->set_next = binding_set->entries;
203 binding_set->entries = entry;
205 entry->hash_next = g_hash_table_lookup (binding_entry_hash_table, entry);
206 if (entry->hash_next)
207 g_hash_table_remove (binding_entry_hash_table, entry->hash_next);
208 g_hash_table_insert (binding_entry_hash_table, entry, entry);
210 for (tmp_list = binding_key_hashes; tmp_list; tmp_list = tmp_list->next)
212 GtkKeyHash *key_hash = tmp_list->data;
213 binding_key_hash_insert_entry (key_hash, entry);
220 binding_entry_free (GtkBindingEntry *entry)
222 GtkBindingSignal *sig;
224 g_assert (entry->set_next == NULL &&
225 entry->hash_next == NULL &&
226 entry->in_emission == FALSE &&
227 entry->destroyed == TRUE);
229 entry->destroyed = FALSE;
231 sig = entry->signals;
234 GtkBindingSignal *prev;
238 binding_signal_free (prev);
244 binding_entry_destroy (GtkBindingEntry *entry)
246 GtkBindingEntry *o_entry;
247 register GtkBindingEntry *tmp;
248 GtkBindingEntry *begin;
249 register GtkBindingEntry *last;
252 /* unlink from binding set
255 tmp = entry->binding_set->entries;
261 last->set_next = entry->set_next;
263 entry->binding_set->entries = entry->set_next;
267 tmp = last->set_next;
269 entry->set_next = NULL;
271 o_entry = g_hash_table_lookup (binding_entry_hash_table, entry);
280 last->hash_next = entry->hash_next;
282 begin = entry->hash_next;
286 tmp = last->hash_next;
288 entry->hash_next = NULL;
291 g_hash_table_remove (binding_entry_hash_table, entry);
292 else if (begin != o_entry)
294 g_hash_table_remove (binding_entry_hash_table, entry);
295 g_hash_table_insert (binding_entry_hash_table, begin, begin);
298 for (tmp_list = binding_key_hashes; tmp_list; tmp_list = tmp_list->next)
300 GtkKeyHash *key_hash = tmp_list->data;
301 _gtk_key_hash_remove_entry (key_hash, entry);
304 entry->destroyed = TRUE;
306 if (!entry->in_emission)
307 binding_entry_free (entry);
310 static GtkBindingEntry*
311 binding_ht_lookup_entry (GtkBindingSet *set,
313 GdkModifierType modifiers)
315 GtkBindingEntry lookup_entry = { 0 };
316 GtkBindingEntry *entry;
318 if (!binding_entry_hash_table)
321 lookup_entry.keyval = keyval;
322 lookup_entry.modifiers = modifiers;
324 entry = g_hash_table_lookup (binding_entry_hash_table, &lookup_entry);
325 for (; entry; entry = entry->hash_next)
326 if (entry->binding_set == set)
333 binding_compose_params (GtkObject *object,
343 params = g_new0 (GValue, query->n_params + 1);
346 /* The instance we emit on is the first object in the array
348 g_value_init (params, G_TYPE_OBJECT);
349 g_value_set_object (params, G_OBJECT (object));
352 types = query->param_types;
354 for (i = 1; i < query->n_params + 1 && valid; i++)
356 GValue tmp_value = { 0, };
358 g_value_init (params, *types);
360 switch (G_TYPE_FUNDAMENTAL (args->arg_type))
363 g_value_init (&tmp_value, G_TYPE_DOUBLE);
364 g_value_set_double (&tmp_value, args->d.double_data);
367 g_value_init (&tmp_value, G_TYPE_LONG);
368 g_value_set_long (&tmp_value, args->d.long_data);
371 /* gtk_rc_parse_flags/enum() has fancier parsing for this; we can't call
372 * that since we don't have a GParamSpec, so just do something simple
374 if (G_TYPE_FUNDAMENTAL (*types) == G_TYPE_ENUM)
376 GEnumClass *class = G_ENUM_CLASS (g_type_class_ref (*types));
380 if (args->arg_type == GTK_TYPE_IDENTIFIER)
382 GEnumValue *enum_value = NULL;
383 enum_value = g_enum_get_value_by_name (class, args->d.string_data);
385 enum_value = g_enum_get_value_by_nick (class, args->d.string_data);
388 g_value_init (&tmp_value, *types);
389 g_value_set_enum (&tmp_value, enum_value->value);
394 g_type_class_unref (class);
396 /* This is just a hack for compatibility with GTK+-1.2 where a string
397 * could be used for a single flag value / without the support for multiple
398 * values in gtk_rc_parse_flags(), this isn't very useful.
400 else if (G_TYPE_FUNDAMENTAL (*types) == G_TYPE_FLAGS)
402 GFlagsClass *class = G_FLAGS_CLASS (g_type_class_ref (*types));
406 if (args->arg_type == GTK_TYPE_IDENTIFIER)
408 GFlagsValue *flags_value = NULL;
409 flags_value = g_flags_get_value_by_name (class, args->d.string_data);
411 flags_value = g_flags_get_value_by_nick (class, args->d.string_data);
414 g_value_init (&tmp_value, *types);
415 g_value_set_flags (&tmp_value, flags_value->value);
420 g_type_class_unref (class);
424 g_value_init (&tmp_value, G_TYPE_STRING);
425 g_value_set_static_string (&tmp_value, args->d.string_data);
435 if (!g_value_transform (&tmp_value, params))
438 g_value_unset (&tmp_value);
450 for (j = 0; j < i; j++)
451 g_value_unset (&(*params_p)[j]);
461 gtk_binding_entry_activate (GtkBindingEntry *entry,
464 GtkBindingSignal *sig;
465 gboolean old_emission;
466 gboolean handled = FALSE;
469 old_emission = entry->in_emission;
470 entry->in_emission = TRUE;
472 g_object_ref (object);
474 for (sig = entry->signals; sig; sig = sig->next)
478 GValue *params = NULL;
479 GValue return_val = { 0, };
480 gchar *accelerator = NULL;
482 signal_id = g_signal_lookup (sig->signal_name, G_OBJECT_TYPE (object));
485 accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
486 g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
487 "could not find signal \"%s\" in the `%s' class ancestry",
488 entry->binding_set->set_name,
491 g_type_name (G_OBJECT_TYPE (object)));
492 g_free (accelerator);
496 g_signal_query (signal_id, &query);
497 if (query.n_params != sig->n_args ||
498 (query.return_type != G_TYPE_NONE && query.return_type != G_TYPE_BOOLEAN) ||
499 !binding_compose_params (object, sig->args, &query, ¶ms))
501 accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
502 g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
503 "signature mismatch for signal \"%s\" in the `%s' class ancestry",
504 entry->binding_set->set_name,
507 g_type_name (G_OBJECT_TYPE (object)));
509 else if (!(query.signal_flags & G_SIGNAL_ACTION))
511 accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
512 g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
513 "signal \"%s\" in the `%s' class ancestry cannot be used for action emissions",
514 entry->binding_set->set_name,
517 g_type_name (G_OBJECT_TYPE (object)));
519 g_free (accelerator);
523 if (query.return_type == G_TYPE_BOOLEAN)
524 g_value_init (&return_val, G_TYPE_BOOLEAN);
526 g_signal_emitv (params, signal_id, 0, &return_val);
528 if (query.return_type == G_TYPE_BOOLEAN)
530 if (g_value_get_boolean (&return_val))
532 g_value_unset (&return_val);
537 for (i = 0; i < query.n_params + 1; i++)
538 g_value_unset (¶ms[i]);
541 if (entry->destroyed)
545 g_object_unref (object);
547 entry->in_emission = old_emission;
548 if (entry->destroyed && !entry->in_emission)
549 binding_entry_free (entry);
555 gtk_binding_set_new (const gchar *set_name)
557 GtkBindingSet *binding_set;
559 g_return_val_if_fail (set_name != NULL, NULL);
561 binding_set = g_new (GtkBindingSet, 1);
562 binding_set->set_name = g_strdup (set_name);
563 binding_set->widget_path_pspecs = NULL;
564 binding_set->widget_class_pspecs = NULL;
565 binding_set->class_branch_pspecs = NULL;
566 binding_set->entries = NULL;
567 binding_set->current = NULL;
568 binding_set->parsed = FALSE;
570 binding_set_list = g_slist_prepend (binding_set_list, binding_set);
576 gtk_binding_set_by_class (gpointer object_class)
578 GtkObjectClass *class = object_class;
579 GtkBindingSet* binding_set;
581 g_return_val_if_fail (GTK_IS_OBJECT_CLASS (class), NULL);
583 if (!key_id_class_binding_set)
584 key_id_class_binding_set = g_quark_from_static_string (key_class_binding_set);
586 binding_set = g_dataset_id_get_data (class, key_id_class_binding_set);
591 binding_set = gtk_binding_set_new (g_type_name (G_OBJECT_CLASS_TYPE (class)));
592 gtk_binding_set_add_path (binding_set,
594 g_type_name (G_OBJECT_CLASS_TYPE (class)),
596 g_dataset_id_set_data (class, key_id_class_binding_set, binding_set);
602 gtk_binding_set_find (const gchar *set_name)
606 g_return_val_if_fail (set_name != NULL, NULL);
608 for (slist = binding_set_list; slist; slist = slist->next)
610 GtkBindingSet *binding_set;
612 binding_set = slist->data;
613 if (g_str_equal (binding_set->set_name, (gpointer) set_name))
620 gtk_binding_set_activate (GtkBindingSet *binding_set,
622 GdkModifierType modifiers,
625 GtkBindingEntry *entry;
627 g_return_val_if_fail (binding_set != NULL, FALSE);
628 g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
630 keyval = gdk_keyval_to_lower (keyval);
631 modifiers = modifiers & BINDING_MOD_MASK ();
633 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
635 return gtk_binding_entry_activate (entry, object);
641 gtk_binding_entry_clear (GtkBindingSet *binding_set,
643 GdkModifierType modifiers)
645 GtkBindingEntry *entry;
647 g_return_if_fail (binding_set != NULL);
649 keyval = gdk_keyval_to_lower (keyval);
650 modifiers = modifiers & BINDING_MOD_MASK ();
652 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
654 binding_entry_destroy (entry);
656 entry = binding_entry_new (binding_set, keyval, modifiers);
660 gtk_binding_entry_remove (GtkBindingSet *binding_set,
662 GdkModifierType modifiers)
664 GtkBindingEntry *entry;
666 g_return_if_fail (binding_set != NULL);
668 keyval = gdk_keyval_to_lower (keyval);
669 modifiers = modifiers & BINDING_MOD_MASK ();
671 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
673 binding_entry_destroy (entry);
677 gtk_binding_entry_add_signall (GtkBindingSet *binding_set,
679 GdkModifierType modifiers,
680 const gchar *signal_name,
681 GSList *binding_args)
683 GtkBindingEntry *entry;
684 GtkBindingSignal *signal, **signal_p;
689 g_return_if_fail (binding_set != NULL);
690 g_return_if_fail (signal_name != NULL);
692 keyval = gdk_keyval_to_lower (keyval);
693 modifiers = modifiers & BINDING_MOD_MASK ();
695 signal = binding_signal_new (signal_name, g_slist_length (binding_args));
698 for (slist = binding_args; slist; slist = slist->next)
700 GtkBindingArg *tmp_arg;
702 tmp_arg = slist->data;
705 g_warning ("gtk_binding_entry_add_signall(): arg[%u] is `NULL'", n);
706 binding_signal_free (signal);
709 switch (G_TYPE_FUNDAMENTAL (tmp_arg->arg_type))
712 arg->arg_type = G_TYPE_LONG;
713 arg->d.long_data = tmp_arg->d.long_data;
716 arg->arg_type = G_TYPE_DOUBLE;
717 arg->d.double_data = tmp_arg->d.double_data;
720 if (tmp_arg->arg_type != GTK_TYPE_IDENTIFIER)
721 arg->arg_type = G_TYPE_STRING;
723 arg->arg_type = GTK_TYPE_IDENTIFIER;
724 arg->d.string_data = g_strdup (tmp_arg->d.string_data);
725 if (!arg->d.string_data)
727 g_warning ("gtk_binding_entry_add_signall(): value of `string' arg[%u] is `NULL'", n);
728 binding_signal_free (signal);
733 g_warning ("gtk_binding_entry_add_signall(): unsupported type `%s' for arg[%u]",
734 g_type_name (arg->arg_type), n);
735 binding_signal_free (signal);
742 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
745 gtk_binding_entry_add (binding_set, keyval, modifiers);
746 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
748 signal_p = &entry->signals;
750 signal_p = &(*signal_p)->next;
755 gtk_binding_entry_add_signal (GtkBindingSet *binding_set,
757 GdkModifierType modifiers,
758 const gchar *signal_name,
762 GSList *slist, *free_slist;
766 g_return_if_fail (binding_set != NULL);
767 g_return_if_fail (signal_name != NULL);
769 va_start (args, n_args);
771 for (i = 0; i < n_args; i++)
775 arg = g_new0 (GtkBindingArg, 1);
776 slist = g_slist_prepend (slist, arg);
778 arg->arg_type = va_arg (args, GtkType);
779 switch (G_TYPE_FUNDAMENTAL (arg->arg_type))
781 /* for elaborated commenting about var args collection, take a look
782 * at gtk_arg_collect_value() in gtkargcollector.c
791 arg->arg_type = G_TYPE_LONG;
792 arg->d.long_data = va_arg (args, gint);
796 arg->arg_type = G_TYPE_LONG;
797 arg->d.long_data = va_arg (args, glong);
801 arg->arg_type = G_TYPE_DOUBLE;
802 arg->d.double_data = va_arg (args, gdouble);
805 if (arg->arg_type != GTK_TYPE_IDENTIFIER)
806 arg->arg_type = G_TYPE_STRING;
807 arg->d.string_data = va_arg (args, gchar*);
808 if (!arg->d.string_data)
810 g_warning ("gtk_binding_entry_add_signal(): type `%s' arg[%u] is `NULL'",
811 g_type_name (arg->arg_type),
817 g_warning ("gtk_binding_entry_add_signal(): unsupported type `%s' for arg[%u]",
818 g_type_name (arg->arg_type), i);
825 if (i == n_args || i == 0)
827 slist = g_slist_reverse (slist);
828 gtk_binding_entry_add_signall (binding_set, keyval, modifiers, signal_name, slist);
834 g_free (slist->data);
837 g_slist_free (free_slist);
841 gtk_binding_set_add_path (GtkBindingSet *binding_set,
842 GtkPathType path_type,
843 const gchar *path_pattern,
844 GtkPathPriorityType priority)
847 GSList **slist_p, *slist;
848 static guint seq_id = 0;
850 g_return_if_fail (binding_set != NULL);
851 g_return_if_fail (path_pattern != NULL);
852 g_return_if_fail (priority <= GTK_PATH_PRIO_MASK);
854 priority &= GTK_PATH_PRIO_MASK;
858 case GTK_PATH_WIDGET:
859 slist_p = &binding_set->widget_path_pspecs;
861 case GTK_PATH_WIDGET_CLASS:
862 slist_p = &binding_set->widget_class_pspecs;
865 slist_p = &binding_set->class_branch_pspecs;
868 g_assert_not_reached ();
873 pspec = g_new (PatternSpec, 1);
874 pspec->pspec = g_pattern_spec_new (path_pattern);
875 pspec->seq_id = priority << 28;
876 pspec->user_data = binding_set;
881 PatternSpec *tmp_pspec;
883 tmp_pspec = slist->data;
886 if (g_pattern_spec_equal (tmp_pspec->pspec, pspec->pspec))
888 GtkPathPriorityType lprio = tmp_pspec->seq_id >> 28;
890 g_pattern_spec_free (pspec->pspec);
893 if (lprio < priority)
895 tmp_pspec->seq_id &= 0x0fffffff;
896 tmp_pspec->seq_id |= priority << 28;
903 pspec->seq_id |= seq_id++ & 0x0fffffff;
904 *slist_p = g_slist_prepend (*slist_p, pspec);
909 binding_match_activate (GSList *pspec_list,
913 const gchar *path_reversed)
917 for (slist = pspec_list; slist; slist = slist->next)
922 if (g_pattern_match (pspec->pspec, path_length, path, path_reversed))
924 GtkBindingSet *binding_set;
926 binding_set = pspec->user_data;
928 if (gtk_binding_entry_activate (binding_set->current, object))
937 gtk_binding_pattern_compare (gconstpointer new_pattern,
938 gconstpointer existing_pattern)
940 register const PatternSpec *np = new_pattern;
941 register const PatternSpec *ep = existing_pattern;
943 /* walk the list as long as the existing patterns have
947 return np->seq_id < ep->seq_id;
951 gtk_binding_entries_sort_patterns (GSList *entries,
959 for (tmp_list = entries; tmp_list; tmp_list = tmp_list->next)
961 GtkBindingEntry *entry = tmp_list->data;
962 GtkBindingSet *binding_set;
964 binding_set = entry->binding_set;
965 binding_set->current = NULL;
968 for (; entries; entries = entries->next)
970 GtkBindingEntry *entry = entries->data;
971 GtkBindingSet *binding_set;
972 GSList *slist = NULL;
974 if (is_release != ((entry->modifiers & GDK_RELEASE_MASK) != 0))
977 binding_set = entry->binding_set;
979 if (binding_set->current)
981 binding_set->current = entry;
985 case GTK_PATH_WIDGET:
986 slist = binding_set->widget_path_pspecs;
988 case GTK_PATH_WIDGET_CLASS:
989 slist = binding_set->widget_class_pspecs;
992 slist = binding_set->class_branch_pspecs;
996 for (; slist; slist = slist->next)
1000 pspec = slist->data;
1001 patterns = g_slist_insert_sorted (patterns, pspec, gtk_binding_pattern_compare);
1009 gtk_bindings_activate_list (GtkObject *object,
1011 gboolean is_release)
1013 GtkWidget *widget = GTK_WIDGET (object);
1014 gboolean handled = FALSE;
1022 gchar *path, *path_reversed;
1025 gtk_widget_path (widget, &path_length, &path, &path_reversed);
1026 patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET, is_release);
1027 handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
1028 g_slist_free (patterns);
1030 g_free (path_reversed);
1036 gchar *path, *path_reversed;
1039 gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
1040 patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET_CLASS, is_release);
1041 handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
1042 g_slist_free (patterns);
1044 g_free (path_reversed);
1052 patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_CLASS, is_release);
1053 class_type = G_TYPE_FROM_INSTANCE (object);
1054 while (class_type && !handled)
1058 gchar *path_reversed;
1060 path = g_type_name (class_type);
1061 path_reversed = g_strdup (path);
1062 g_strreverse (path_reversed);
1063 path_length = strlen (path);
1064 handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
1065 g_free (path_reversed);
1067 class_type = g_type_parent (class_type);
1069 g_slist_free (patterns);
1076 gtk_bindings_activate (GtkObject *object,
1078 GdkModifierType modifiers)
1080 GSList *entries = NULL;
1081 GdkDisplay *display;
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 display = gtk_widget_get_display (GTK_WIDGET (object));
1095 key_hash = binding_key_hash_for_keymap (gdk_keymap_get_for_display (display));
1097 entries = _gtk_key_hash_lookup_keyval (key_hash, keyval, modifiers);
1099 handled = gtk_bindings_activate_list (object, entries, is_release);
1101 g_slist_free (entries);
1107 * gtk_bindings_activate_event:
1108 * @object: a #GtkObject (generally must be a widget)
1109 * @event: a #GdkEventKey
1111 * Looks up key bindings for @object to find one matching
1112 * @event, and if one was found, activate it.
1114 * Return value: %TRUE if a matching key binding was found
1117 gtk_bindings_activate_event (GtkObject *object,
1120 GSList *entries = NULL;
1121 GdkDisplay *display;
1122 GtkKeyHash *key_hash;
1123 gboolean handled = FALSE;
1125 g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
1127 if (!GTK_IS_WIDGET (object))
1130 display = gtk_widget_get_display (GTK_WIDGET (object));
1131 key_hash = binding_key_hash_for_keymap (gdk_keymap_get_for_display (display));
1133 entries = _gtk_key_hash_lookup (key_hash,
1134 event->hardware_keycode,
1136 BINDING_MOD_MASK () & ~GDK_RELEASE_MASK,
1139 handled = gtk_bindings_activate_list (object, entries,
1140 event->type == GDK_KEY_RELEASE);
1142 g_slist_free (entries);
1148 gtk_binding_parse_signal (GScanner *scanner,
1149 GtkBindingSet *binding_set,
1151 GdkModifierType modifiers)
1154 guint expected_token = 0;
1160 gboolean seen_comma;
1162 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1164 g_scanner_get_next_token (scanner);
1165 if (scanner->token != G_TOKEN_STRING)
1166 return G_TOKEN_STRING;
1167 g_scanner_peek_next_token (scanner);
1168 if (scanner->next_token != '(')
1170 g_scanner_get_next_token (scanner);
1173 signal = g_strdup (scanner->value.v_string);
1174 g_scanner_get_next_token (scanner);
1181 scanner->config->scan_symbols = FALSE;
1185 expected_token = G_TOKEN_INT;
1187 expected_token = ')';
1188 g_scanner_get_next_token (scanner);
1189 switch (scanner->token)
1197 arg = g_new (GtkBindingArg, 1);
1198 arg->arg_type = G_TYPE_DOUBLE;
1199 arg->d.double_data = scanner->value.v_float;
1202 arg->d.double_data = - arg->d.double_data;
1205 args = g_slist_prepend (args, arg);
1214 arg = g_new (GtkBindingArg, 1);
1215 arg->arg_type = G_TYPE_LONG;
1216 arg->d.long_data = scanner->value.v_int;
1219 arg->d.long_data = - arg->d.long_data;
1222 args = g_slist_prepend (args, arg);
1227 case G_TOKEN_STRING:
1228 if (need_arg && !negate)
1231 arg = g_new (GtkBindingArg, 1);
1232 arg->arg_type = G_TYPE_STRING;
1233 arg->d.string_data = g_strdup (scanner->value.v_string);
1234 args = g_slist_prepend (args, arg);
1239 case G_TOKEN_IDENTIFIER:
1240 if (need_arg && !negate)
1243 arg = g_new (GtkBindingArg, 1);
1244 arg->arg_type = GTK_TYPE_IDENTIFIER;
1245 arg->d.string_data = g_strdup (scanner->value.v_identifier);
1246 args = g_slist_prepend (args, arg);
1256 expected_token = G_TOKEN_INT;
1270 if (!(need_arg && seen_comma) && !negate)
1272 args = g_slist_reverse (args);
1273 gtk_binding_entry_add_signall (binding_set,
1278 expected_token = G_TOKEN_NONE;
1288 scanner->config->scan_symbols = TRUE;
1290 for (slist = args; slist; slist = slist->next)
1295 if (G_TYPE_FUNDAMENTAL (arg->arg_type) == G_TYPE_STRING)
1296 g_free (arg->d.string_data);
1299 g_slist_free (args);
1302 return expected_token;
1306 gtk_binding_parse_bind (GScanner *scanner,
1307 GtkBindingSet *binding_set)
1310 GdkModifierType modifiers = 0;
1312 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1314 g_scanner_get_next_token (scanner);
1315 if (scanner->token != GTK_RC_TOKEN_BIND)
1316 return GTK_RC_TOKEN_BIND;
1317 g_scanner_get_next_token (scanner);
1318 if (scanner->token != G_TOKEN_STRING)
1319 return G_TOKEN_STRING;
1320 gtk_accelerator_parse (scanner->value.v_string, &keyval, &modifiers);
1321 modifiers &= BINDING_MOD_MASK ();
1323 return G_TOKEN_STRING;
1325 g_scanner_get_next_token (scanner);
1326 if (scanner->token != '{')
1329 gtk_binding_entry_clear (binding_set, keyval, modifiers);
1331 g_scanner_peek_next_token (scanner);
1332 while (scanner->next_token != '}')
1334 switch (scanner->next_token)
1336 guint expected_token;
1338 case G_TOKEN_STRING:
1339 expected_token = gtk_binding_parse_signal (scanner,
1343 if (expected_token != G_TOKEN_NONE)
1344 return expected_token;
1347 g_scanner_get_next_token (scanner);
1350 g_scanner_peek_next_token (scanner);
1352 g_scanner_get_next_token (scanner);
1354 return G_TOKEN_NONE;
1358 gtk_binding_parse_binding (GScanner *scanner)
1361 GtkBindingSet *binding_set;
1363 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1365 g_scanner_get_next_token (scanner);
1366 if (scanner->token != GTK_RC_TOKEN_BINDING)
1367 return GTK_RC_TOKEN_BINDING;
1368 g_scanner_get_next_token (scanner);
1369 if (scanner->token != G_TOKEN_STRING)
1370 return G_TOKEN_STRING;
1371 name = g_strdup (scanner->value.v_string);
1373 g_scanner_get_next_token (scanner);
1374 if (scanner->token != '{')
1377 return G_TOKEN_STRING;
1380 binding_set = gtk_binding_set_find (name);
1383 binding_set = gtk_binding_set_new (name);
1384 binding_set->parsed = 1;
1388 g_scanner_peek_next_token (scanner);
1389 while (scanner->next_token != '}')
1391 switch (scanner->next_token)
1393 guint expected_token;
1395 case GTK_RC_TOKEN_BIND:
1396 expected_token = gtk_binding_parse_bind (scanner, binding_set);
1397 if (expected_token != G_TOKEN_NONE)
1398 return expected_token;
1401 g_scanner_get_next_token (scanner);
1404 g_scanner_peek_next_token (scanner);
1406 g_scanner_get_next_token (scanner);
1408 return G_TOKEN_NONE;
1412 free_pattern_specs (GSList *pattern_specs)
1416 for (slist = pattern_specs; slist; slist = slist->next)
1420 pspec = slist->data;
1422 g_pattern_spec_free (pspec->pspec);
1426 g_slist_free (pattern_specs);
1430 binding_set_delete (GtkBindingSet *binding_set)
1432 GtkBindingEntry *entry, *next;
1434 entry = binding_set->entries;
1437 next = entry->set_next;
1438 binding_entry_destroy (entry);
1442 free_pattern_specs (binding_set->widget_path_pspecs);
1443 free_pattern_specs (binding_set->widget_class_pspecs);
1444 free_pattern_specs (binding_set->class_branch_pspecs);
1446 g_free (binding_set->set_name);
1447 g_free (binding_set);
1451 * _gtk_binding_reset_parsed:
1453 * Removing all binding sets that were added by
1454 * gtk_binding_parse_binding()
1457 _gtk_binding_reset_parsed (void)
1459 GSList *slist, *next;
1461 slist = binding_set_list;
1464 GtkBindingSet *binding_set;
1466 binding_set = slist->data;
1469 if (binding_set->parsed)
1471 binding_set_list = g_slist_delete_link (binding_set_list, slist);
1472 binding_set_delete (binding_set);
1480 _gtk_binding_signal_new (const gchar *signal_name,
1482 GSignalFlags signal_flags,
1484 GSignalAccumulator accumulator,
1486 GSignalCMarshaller c_marshaller,
1494 g_return_val_if_fail (signal_name != NULL, 0);
1496 va_start (args, n_params);
1498 signal_id = g_signal_new_valist (signal_name, itype, signal_flags,
1499 g_cclosure_new (handler, NULL, NULL),
1500 accumulator, accu_data, c_marshaller,
1501 return_type, n_params, args);