1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * GtkBindingSet: Keybinding manager for GObjects.
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 "gtktypeutils.h"
38 #include "gtkwidget.h"
43 #define BINDING_MOD_MASK() (gtk_accelerator_get_default_mod_mask () | GDK_RELEASE_MASK)
46 /* --- structures --- */
55 /* --- variables --- */
56 static GHashTable *binding_entry_hash_table = NULL;
57 static GSList *binding_key_hashes = NULL;
58 static GSList *binding_set_list = NULL;
59 static const gchar key_class_binding_set[] = "gtk-class-binding-set";
60 static GQuark key_id_class_binding_set = 0;
63 /* --- functions --- */
65 pattern_spec_free (PatternSpec *pspec)
68 g_pattern_spec_free (pspec->pspec);
72 static GtkBindingSignal*
73 binding_signal_new (const gchar *signal_name,
76 GtkBindingSignal *signal;
78 signal = (GtkBindingSignal *) g_slice_alloc0 (sizeof (GtkBindingSignal) + n_args * sizeof (GtkBindingArg));
80 signal->signal_name = (gchar *)g_intern_string (signal_name);
81 signal->n_args = n_args;
82 signal->args = (GtkBindingArg *)(signal + 1);
88 binding_signal_free (GtkBindingSignal *sig)
92 for (i = 0; i < sig->n_args; i++)
94 if (G_TYPE_FUNDAMENTAL (sig->args[i].arg_type) == G_TYPE_STRING)
95 g_free (sig->args[i].d.string_data);
97 g_slice_free1 (sizeof (GtkBindingSignal) + sig->n_args * sizeof (GtkBindingArg), sig);
101 binding_entry_hash (gconstpointer key)
103 register const GtkBindingEntry *e = key;
113 binding_entries_compare (gconstpointer a,
116 register const GtkBindingEntry *ea = a;
117 register const GtkBindingEntry *eb = b;
119 return (ea->keyval == eb->keyval && ea->modifiers == eb->modifiers);
123 binding_key_hash_insert_entry (GtkKeyHash *key_hash,
124 GtkBindingEntry *entry)
126 guint keyval = entry->keyval;
128 /* We store lowercased accelerators. To deal with this, if <Shift>
129 * was specified, uppercase.
131 if (entry->modifiers & GDK_SHIFT_MASK)
133 if (keyval == GDK_KEY_Tab)
134 keyval = GDK_KEY_ISO_Left_Tab;
136 keyval = gdk_keyval_to_upper (keyval);
139 _gtk_key_hash_add_entry (key_hash, keyval, entry->modifiers & ~GDK_RELEASE_MASK, entry);
143 binding_key_hash_destroy (gpointer data)
145 GtkKeyHash *key_hash = data;
147 binding_key_hashes = g_slist_remove (binding_key_hashes, key_hash);
148 _gtk_key_hash_free (key_hash);
152 insert_entries_into_key_hash (gpointer key,
156 GtkKeyHash *key_hash = data;
157 GtkBindingEntry *entry = value;
159 for (; entry; entry = entry->hash_next)
160 binding_key_hash_insert_entry (key_hash, entry);
164 binding_key_hash_for_keymap (GdkKeymap *keymap)
166 static GQuark key_hash_quark = 0;
167 GtkKeyHash *key_hash;
170 key_hash_quark = g_quark_from_static_string ("gtk-binding-key-hash");
172 key_hash = g_object_get_qdata (G_OBJECT (keymap), key_hash_quark);
176 key_hash = _gtk_key_hash_new (keymap, NULL);
177 g_object_set_qdata_full (G_OBJECT (keymap), key_hash_quark, key_hash, binding_key_hash_destroy);
179 if (binding_entry_hash_table)
180 g_hash_table_foreach (binding_entry_hash_table,
181 insert_entries_into_key_hash,
184 binding_key_hashes = g_slist_prepend (binding_key_hashes, key_hash);
191 static GtkBindingEntry*
192 binding_entry_new (GtkBindingSet *binding_set,
194 GdkModifierType modifiers)
197 GtkBindingEntry *entry;
199 if (!binding_entry_hash_table)
200 binding_entry_hash_table = g_hash_table_new (binding_entry_hash, binding_entries_compare);
202 entry = g_new (GtkBindingEntry, 1);
203 entry->keyval = keyval;
204 entry->modifiers = modifiers;
205 entry->binding_set = binding_set,
206 entry->destroyed = FALSE;
207 entry->in_emission = FALSE;
208 entry->marks_unbound = FALSE;
209 entry->signals = NULL;
211 entry->set_next = binding_set->entries;
212 binding_set->entries = entry;
214 entry->hash_next = g_hash_table_lookup (binding_entry_hash_table, entry);
215 if (entry->hash_next)
216 g_hash_table_remove (binding_entry_hash_table, entry->hash_next);
217 g_hash_table_insert (binding_entry_hash_table, entry, entry);
219 for (tmp_list = binding_key_hashes; tmp_list; tmp_list = tmp_list->next)
221 GtkKeyHash *key_hash = tmp_list->data;
222 binding_key_hash_insert_entry (key_hash, entry);
229 binding_entry_free (GtkBindingEntry *entry)
231 GtkBindingSignal *sig;
233 g_assert (entry->set_next == NULL &&
234 entry->hash_next == NULL &&
235 entry->in_emission == FALSE &&
236 entry->destroyed == TRUE);
238 entry->destroyed = FALSE;
240 sig = entry->signals;
243 GtkBindingSignal *prev;
247 binding_signal_free (prev);
253 binding_entry_destroy (GtkBindingEntry *entry)
255 GtkBindingEntry *o_entry;
256 register GtkBindingEntry *tmp;
257 GtkBindingEntry *begin;
258 register GtkBindingEntry *last;
261 /* unlink from binding set
264 tmp = entry->binding_set->entries;
270 last->set_next = entry->set_next;
272 entry->binding_set->entries = entry->set_next;
276 tmp = last->set_next;
278 entry->set_next = NULL;
280 o_entry = g_hash_table_lookup (binding_entry_hash_table, entry);
289 last->hash_next = entry->hash_next;
291 begin = entry->hash_next;
295 tmp = last->hash_next;
297 entry->hash_next = NULL;
300 g_hash_table_remove (binding_entry_hash_table, entry);
301 else if (begin != o_entry)
303 g_hash_table_remove (binding_entry_hash_table, entry);
304 g_hash_table_insert (binding_entry_hash_table, begin, begin);
307 for (tmp_list = binding_key_hashes; tmp_list; tmp_list = tmp_list->next)
309 GtkKeyHash *key_hash = tmp_list->data;
310 _gtk_key_hash_remove_entry (key_hash, entry);
313 entry->destroyed = TRUE;
315 if (!entry->in_emission)
316 binding_entry_free (entry);
319 static GtkBindingEntry*
320 binding_ht_lookup_entry (GtkBindingSet *set,
322 GdkModifierType modifiers)
324 GtkBindingEntry lookup_entry = { 0 };
325 GtkBindingEntry *entry;
327 if (!binding_entry_hash_table)
330 lookup_entry.keyval = keyval;
331 lookup_entry.modifiers = modifiers;
333 entry = g_hash_table_lookup (binding_entry_hash_table, &lookup_entry);
334 for (; entry; entry = entry->hash_next)
335 if (entry->binding_set == set)
342 binding_compose_params (GObject *object,
352 params = g_new0 (GValue, query->n_params + 1);
355 /* The instance we emit on is the first object in the array
357 g_value_init (params, G_TYPE_OBJECT);
358 g_value_set_object (params, G_OBJECT (object));
361 types = query->param_types;
363 for (i = 1; i < query->n_params + 1 && valid; i++)
365 GValue tmp_value = { 0, };
367 g_value_init (params, *types);
369 switch (G_TYPE_FUNDAMENTAL (args->arg_type))
372 g_value_init (&tmp_value, G_TYPE_DOUBLE);
373 g_value_set_double (&tmp_value, args->d.double_data);
376 g_value_init (&tmp_value, G_TYPE_LONG);
377 g_value_set_long (&tmp_value, args->d.long_data);
380 /* gtk_rc_parse_flags/enum() has fancier parsing for this; we can't call
381 * that since we don't have a GParamSpec, so just do something simple
383 if (G_TYPE_FUNDAMENTAL (*types) == G_TYPE_ENUM)
385 GEnumClass *class = G_ENUM_CLASS (g_type_class_ref (*types));
389 if (args->arg_type == GTK_TYPE_IDENTIFIER)
391 GEnumValue *enum_value = NULL;
392 enum_value = g_enum_get_value_by_name (class, args->d.string_data);
394 enum_value = g_enum_get_value_by_nick (class, args->d.string_data);
397 g_value_init (&tmp_value, *types);
398 g_value_set_enum (&tmp_value, enum_value->value);
403 g_type_class_unref (class);
405 /* This is just a hack for compatibility with GTK+-1.2 where a string
406 * could be used for a single flag value / without the support for multiple
407 * values in gtk_rc_parse_flags(), this isn't very useful.
409 else if (G_TYPE_FUNDAMENTAL (*types) == G_TYPE_FLAGS)
411 GFlagsClass *class = G_FLAGS_CLASS (g_type_class_ref (*types));
415 if (args->arg_type == GTK_TYPE_IDENTIFIER)
417 GFlagsValue *flags_value = NULL;
418 flags_value = g_flags_get_value_by_name (class, args->d.string_data);
420 flags_value = g_flags_get_value_by_nick (class, args->d.string_data);
423 g_value_init (&tmp_value, *types);
424 g_value_set_flags (&tmp_value, flags_value->value);
429 g_type_class_unref (class);
433 g_value_init (&tmp_value, G_TYPE_STRING);
434 g_value_set_static_string (&tmp_value, args->d.string_data);
444 if (!g_value_transform (&tmp_value, params))
447 g_value_unset (&tmp_value);
459 for (j = 0; j < i; j++)
460 g_value_unset (&(*params_p)[j]);
470 gtk_binding_entry_activate (GtkBindingEntry *entry,
473 GtkBindingSignal *sig;
474 gboolean old_emission;
475 gboolean handled = FALSE;
478 old_emission = entry->in_emission;
479 entry->in_emission = TRUE;
481 g_object_ref (object);
483 for (sig = entry->signals; sig; sig = sig->next)
487 GValue *params = NULL;
488 GValue return_val = { 0, };
489 gchar *accelerator = NULL;
491 signal_id = g_signal_lookup (sig->signal_name, G_OBJECT_TYPE (object));
494 accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
495 g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
496 "could not find signal \"%s\" in the `%s' class ancestry",
497 entry->binding_set->set_name,
500 g_type_name (G_OBJECT_TYPE (object)));
501 g_free (accelerator);
505 g_signal_query (signal_id, &query);
506 if (query.n_params != sig->n_args ||
507 (query.return_type != G_TYPE_NONE && query.return_type != G_TYPE_BOOLEAN) ||
508 !binding_compose_params (object, sig->args, &query, ¶ms))
510 accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
511 g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
512 "signature mismatch for signal \"%s\" in the `%s' class ancestry",
513 entry->binding_set->set_name,
516 g_type_name (G_OBJECT_TYPE (object)));
518 else if (!(query.signal_flags & G_SIGNAL_ACTION))
520 accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
521 g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
522 "signal \"%s\" in the `%s' class ancestry cannot be used for action emissions",
523 entry->binding_set->set_name,
526 g_type_name (G_OBJECT_TYPE (object)));
528 g_free (accelerator);
532 if (query.return_type == G_TYPE_BOOLEAN)
533 g_value_init (&return_val, G_TYPE_BOOLEAN);
535 g_signal_emitv (params, signal_id, 0, &return_val);
537 if (query.return_type == G_TYPE_BOOLEAN)
539 if (g_value_get_boolean (&return_val))
541 g_value_unset (&return_val);
546 for (i = 0; i < query.n_params + 1; i++)
547 g_value_unset (¶ms[i]);
550 if (entry->destroyed)
554 g_object_unref (object);
556 entry->in_emission = old_emission;
557 if (entry->destroyed && !entry->in_emission)
558 binding_entry_free (entry);
564 * gtk_binding_set_new:
565 * @set_name: unique name of this binding set
567 * GTK+ maintains a global list of binding sets. Each binding set has
568 * a unique name which needs to be specified upon creation.
570 * Return value: new binding set
573 gtk_binding_set_new (const gchar *set_name)
575 GtkBindingSet *binding_set;
577 g_return_val_if_fail (set_name != NULL, NULL);
579 binding_set = g_new (GtkBindingSet, 1);
580 binding_set->set_name = (gchar *) g_intern_string (set_name);
581 binding_set->widget_path_pspecs = NULL;
582 binding_set->widget_class_pspecs = NULL;
583 binding_set->class_branch_pspecs = NULL;
584 binding_set->entries = NULL;
585 binding_set->current = NULL;
586 binding_set->parsed = FALSE;
588 binding_set_list = g_slist_prepend (binding_set_list, binding_set);
594 * gtk_binding_set_by_class:
595 * @object_class: a valid #GObject class
597 * This function returns the binding set named after the type name of
598 * the passed in class structure. New binding sets are created on
599 * demand by this function.
601 * Return value: the binding set corresponding to @object_class
604 gtk_binding_set_by_class (gpointer object_class)
606 GObjectClass *class = object_class;
607 GtkBindingSet* binding_set;
609 g_return_val_if_fail (G_IS_OBJECT_CLASS (class), NULL);
611 if (!key_id_class_binding_set)
612 key_id_class_binding_set = g_quark_from_static_string (key_class_binding_set);
614 binding_set = g_dataset_id_get_data (class, key_id_class_binding_set);
619 binding_set = gtk_binding_set_new (g_type_name (G_OBJECT_CLASS_TYPE (class)));
620 gtk_binding_set_add_path (binding_set,
622 g_type_name (G_OBJECT_CLASS_TYPE (class)),
624 g_dataset_id_set_data (class, key_id_class_binding_set, binding_set);
630 * gtk_binding_set_find:
631 * @set_name: unique binding set name
633 * Find a binding set by its globally unique name. The @set_name can
634 * either be a name used for gtk_binding_set_new() or the type name of
635 * a class used in gtk_binding_set_by_class().
637 * Return value: %NULL or the specified binding set
640 gtk_binding_set_find (const gchar *set_name)
644 g_return_val_if_fail (set_name != NULL, NULL);
646 for (slist = binding_set_list; slist; slist = slist->next)
648 GtkBindingSet *binding_set;
650 binding_set = slist->data;
651 if (g_str_equal (binding_set->set_name, (gpointer) set_name))
658 * gtk_binding_set_activate:
659 * @binding_set: a #GtkBindingSet set to activate
660 * @keyval: key value of the binding
661 * @modifiers: key modifier of the binding
662 * @object: object to activate when binding found
664 * Find a key binding matching @keyval and @modifiers within
665 * @binding_set and activate the binding on @object.
667 * Return value: %TRUE if a binding was found and activated
670 gtk_binding_set_activate (GtkBindingSet *binding_set,
672 GdkModifierType modifiers,
675 GtkBindingEntry *entry;
677 g_return_val_if_fail (binding_set != NULL, FALSE);
678 g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
680 keyval = gdk_keyval_to_lower (keyval);
681 modifiers = modifiers & BINDING_MOD_MASK ();
683 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
685 return gtk_binding_entry_activate (entry, object);
691 gtk_binding_entry_clear_internal (GtkBindingSet *binding_set,
693 GdkModifierType modifiers)
695 GtkBindingEntry *entry;
697 keyval = gdk_keyval_to_lower (keyval);
698 modifiers = modifiers & BINDING_MOD_MASK ();
700 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
702 binding_entry_destroy (entry);
704 entry = binding_entry_new (binding_set, keyval, modifiers);
708 * gtk_binding_entry_skip:
709 * @binding_set: a #GtkBindingSet to skip an entry of
710 * @keyval: key value of binding to skip
711 * @modifiers: key modifier of binding to skip
713 * Install a binding on @binding_set which causes key lookups
714 * to be aborted, to prevent bindings from lower priority sets
720 gtk_binding_entry_skip (GtkBindingSet *binding_set,
722 GdkModifierType modifiers)
724 GtkBindingEntry *entry;
726 g_return_if_fail (binding_set != NULL);
728 keyval = gdk_keyval_to_lower (keyval);
729 modifiers = modifiers & BINDING_MOD_MASK ();
731 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
733 binding_entry_destroy (entry);
735 entry = binding_entry_new (binding_set, keyval, modifiers);
736 entry->marks_unbound = TRUE;
740 * gtk_binding_entry_remove:
741 * @binding_set: a #GtkBindingSet to remove an entry of
742 * @keyval: key value of binding to remove
743 * @modifiers: key modifier of binding to remove
745 * Remove a binding previously installed via
746 * gtk_binding_entry_add_signal() on @binding_set.
749 gtk_binding_entry_remove (GtkBindingSet *binding_set,
751 GdkModifierType modifiers)
753 GtkBindingEntry *entry;
755 g_return_if_fail (binding_set != NULL);
757 keyval = gdk_keyval_to_lower (keyval);
758 modifiers = modifiers & BINDING_MOD_MASK ();
760 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
762 binding_entry_destroy (entry);
766 * gtk_binding_entry_add_signall:
767 * @binding_set: a #GtkBindingSet to add a signal to
769 * @modifiers: key modifier
770 * @signal_name: signal name to be bound
771 * @binding_args: (transfer none) (element-type GtkBindingArg):
772 * list of #GtkBindingArg signal arguments
774 * Override or install a new key binding for @keyval with @modifiers on
778 gtk_binding_entry_add_signall (GtkBindingSet *binding_set,
780 GdkModifierType modifiers,
781 const gchar *signal_name,
782 GSList *binding_args)
784 _gtk_binding_entry_add_signall (binding_set,
786 signal_name, binding_args);
790 _gtk_binding_entry_add_signall (GtkBindingSet *binding_set,
792 GdkModifierType modifiers,
793 const gchar *signal_name,
794 GSList *binding_args)
796 GtkBindingEntry *entry;
797 GtkBindingSignal *signal, **signal_p;
802 g_return_if_fail (binding_set != NULL);
803 g_return_if_fail (signal_name != NULL);
805 keyval = gdk_keyval_to_lower (keyval);
806 modifiers = modifiers & BINDING_MOD_MASK ();
808 signal = binding_signal_new (signal_name, g_slist_length (binding_args));
811 for (slist = binding_args; slist; slist = slist->next)
813 GtkBindingArg *tmp_arg;
815 tmp_arg = slist->data;
818 g_warning ("gtk_binding_entry_add_signall(): arg[%u] is `NULL'", n);
819 binding_signal_free (signal);
822 switch (G_TYPE_FUNDAMENTAL (tmp_arg->arg_type))
825 arg->arg_type = G_TYPE_LONG;
826 arg->d.long_data = tmp_arg->d.long_data;
829 arg->arg_type = G_TYPE_DOUBLE;
830 arg->d.double_data = tmp_arg->d.double_data;
833 if (tmp_arg->arg_type != GTK_TYPE_IDENTIFIER)
834 arg->arg_type = G_TYPE_STRING;
836 arg->arg_type = GTK_TYPE_IDENTIFIER;
837 arg->d.string_data = g_strdup (tmp_arg->d.string_data);
838 if (!arg->d.string_data)
840 g_warning ("gtk_binding_entry_add_signall(): value of `string' arg[%u] is `NULL'", n);
841 binding_signal_free (signal);
846 g_warning ("gtk_binding_entry_add_signall(): unsupported type `%s' for arg[%u]",
847 g_type_name (arg->arg_type), n);
848 binding_signal_free (signal);
855 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
858 gtk_binding_entry_clear_internal (binding_set, keyval, modifiers);
859 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
861 signal_p = &entry->signals;
863 signal_p = &(*signal_p)->next;
868 * gtk_binding_entry_add_signal:
869 * @binding_set: a #GtkBindingSet to install an entry for
870 * @keyval: key value of binding to install
871 * @modifiers: key modifier of binding to install
872 * @signal_name: signal to execute upon activation
873 * @n_args: number of arguments to @signal_name
874 * @Varargs: arguments to @signal_name
876 * Override or install a new key binding for @keyval with @modifiers on
877 * @binding_set. When the binding is activated, @signal_name will be
878 * emitted on the target widget, with @n_args @Varargs used as
882 gtk_binding_entry_add_signal (GtkBindingSet *binding_set,
884 GdkModifierType modifiers,
885 const gchar *signal_name,
889 GSList *slist, *free_slist;
893 g_return_if_fail (binding_set != NULL);
894 g_return_if_fail (signal_name != NULL);
896 va_start (args, n_args);
898 for (i = 0; i < n_args; i++)
902 arg = g_slice_new0 (GtkBindingArg);
903 slist = g_slist_prepend (slist, arg);
905 arg->arg_type = va_arg (args, GType);
906 switch (G_TYPE_FUNDAMENTAL (arg->arg_type))
915 arg->arg_type = G_TYPE_LONG;
916 arg->d.long_data = va_arg (args, gint);
920 arg->arg_type = G_TYPE_LONG;
921 arg->d.long_data = va_arg (args, glong);
925 arg->arg_type = G_TYPE_DOUBLE;
926 arg->d.double_data = va_arg (args, gdouble);
929 if (arg->arg_type != GTK_TYPE_IDENTIFIER)
930 arg->arg_type = G_TYPE_STRING;
931 arg->d.string_data = va_arg (args, gchar*);
932 if (!arg->d.string_data)
934 g_warning ("gtk_binding_entry_add_signal(): type `%s' arg[%u] is `NULL'",
935 g_type_name (arg->arg_type),
941 g_warning ("gtk_binding_entry_add_signal(): unsupported type `%s' for arg[%u]",
942 g_type_name (arg->arg_type), i);
949 if (i == n_args || i == 0)
951 slist = g_slist_reverse (slist);
952 _gtk_binding_entry_add_signall (binding_set, keyval, modifiers, signal_name, slist);
958 g_slice_free (GtkBindingArg, slist->data);
961 g_slist_free (free_slist);
965 * gtk_binding_set_add_path:
966 * @binding_set: a #GtkBindingSet to add a path to
967 * @path_type: path type the pattern applies to
968 * @path_pattern: the actual match pattern
969 * @priority: binding priority
971 * This function is used internally by the GtkRC parsing mechanism to
972 * assign match patterns to #GtkBindingSet structures.
977 gtk_binding_set_add_path (GtkBindingSet *binding_set,
978 GtkPathType path_type,
979 const gchar *path_pattern,
980 GtkPathPriorityType priority)
983 GSList **slist_p, *slist;
984 static guint seq_id = 0;
986 g_return_if_fail (binding_set != NULL);
987 g_return_if_fail (path_pattern != NULL);
988 g_return_if_fail (priority <= GTK_PATH_PRIO_MASK);
990 priority &= GTK_PATH_PRIO_MASK;
994 case GTK_PATH_WIDGET:
995 slist_p = &binding_set->widget_path_pspecs;
997 case GTK_PATH_WIDGET_CLASS:
998 slist_p = &binding_set->widget_class_pspecs;
1000 case GTK_PATH_CLASS:
1001 slist_p = &binding_set->class_branch_pspecs;
1004 g_assert_not_reached ();
1009 pspec = g_new (PatternSpec, 1);
1010 pspec->type = path_type;
1011 if (path_type == GTK_PATH_WIDGET_CLASS)
1012 pspec->pspec = NULL;
1014 pspec->pspec = g_pattern_spec_new (path_pattern);
1016 pspec->seq_id = priority << 28;
1017 pspec->user_data = binding_set;
1022 PatternSpec *tmp_pspec;
1024 tmp_pspec = slist->data;
1025 slist = slist->next;
1027 if (g_pattern_spec_equal (tmp_pspec->pspec, pspec->pspec))
1029 GtkPathPriorityType lprio = tmp_pspec->seq_id >> 28;
1031 pattern_spec_free (pspec);
1033 if (lprio < priority)
1035 tmp_pspec->seq_id &= 0x0fffffff;
1036 tmp_pspec->seq_id |= priority << 28;
1043 pspec->seq_id |= seq_id++ & 0x0fffffff;
1044 *slist_p = g_slist_prepend (*slist_p, pspec);
1049 binding_match_activate (GSList *pspec_list,
1053 gchar *path_reversed,
1060 for (slist = pspec_list; slist; slist = slist->next)
1063 GtkBindingSet *binding_set;
1066 pspec = slist->data;
1068 if (pspec->type != GTK_PATH_WIDGET_CLASS)
1070 if (g_pattern_match (pspec->pspec, path_length, path, path_reversed))
1071 binding_set = pspec->user_data;
1076 if (binding_set->current->marks_unbound)
1082 if (gtk_binding_entry_activate (binding_set->current, object))
1091 gtk_binding_pattern_compare (gconstpointer new_pattern,
1092 gconstpointer existing_pattern)
1094 register const PatternSpec *np = new_pattern;
1095 register const PatternSpec *ep = existing_pattern;
1097 /* walk the list as long as the existing patterns have
1098 * higher priorities.
1101 return np->seq_id < ep->seq_id;
1105 gtk_binding_entries_sort_patterns (GSList *entries,
1106 GtkPathType path_id,
1107 gboolean is_release)
1113 for (tmp_list = entries; tmp_list; tmp_list = tmp_list->next)
1115 GtkBindingEntry *entry = tmp_list->data;
1116 GtkBindingSet *binding_set;
1118 binding_set = entry->binding_set;
1119 binding_set->current = NULL;
1122 for (; entries; entries = entries->next)
1124 GtkBindingEntry *entry = entries->data;
1125 GtkBindingSet *binding_set;
1126 GSList *slist = NULL;
1128 if (is_release != ((entry->modifiers & GDK_RELEASE_MASK) != 0))
1131 binding_set = entry->binding_set;
1133 if (binding_set->current)
1135 binding_set->current = entry;
1139 case GTK_PATH_WIDGET:
1140 slist = binding_set->widget_path_pspecs;
1142 case GTK_PATH_WIDGET_CLASS:
1143 slist = binding_set->widget_class_pspecs;
1145 case GTK_PATH_CLASS:
1146 slist = binding_set->class_branch_pspecs;
1150 for (; slist; slist = slist->next)
1154 pspec = slist->data;
1155 patterns = g_slist_insert_sorted (patterns, pspec, gtk_binding_pattern_compare);
1163 gtk_bindings_activate_list (GObject *object,
1165 gboolean is_release)
1167 gboolean handled = FALSE;
1172 /* FIXME: Add back binding parsing from user config files */
1178 gboolean unbound = FALSE;
1180 patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_CLASS, is_release);
1181 class_type = G_TYPE_FROM_INSTANCE (object);
1182 while (class_type && !handled)
1186 gchar *path_reversed;
1188 path = g_strdup (g_type_name (class_type));
1189 path_reversed = g_strdup (path);
1190 g_strreverse (path_reversed);
1191 path_length = strlen (path);
1192 handled = binding_match_activate (patterns, object, path_length, path, path_reversed, &unbound);
1194 g_free (path_reversed);
1199 class_type = g_type_parent (class_type);
1201 g_slist_free (patterns);
1211 * gtk_bindings_activate:
1212 * @object: object to activate when binding found
1213 * @keyval: key value of the binding
1214 * @modifiers: key modifier of the binding
1216 * Find a key binding matching @keyval and @modifiers and activate the
1217 * binding on @object.
1219 * Return value: %TRUE if a binding was found and activated
1222 gtk_bindings_activate (GObject *object,
1224 GdkModifierType modifiers)
1226 GSList *entries = NULL;
1227 GdkDisplay *display;
1228 GtkKeyHash *key_hash;
1229 gboolean handled = FALSE;
1230 gboolean is_release;
1232 if (!GTK_IS_WIDGET (object))
1235 is_release = (modifiers & GDK_RELEASE_MASK) != 0;
1236 modifiers = modifiers & BINDING_MOD_MASK () & ~GDK_RELEASE_MASK;
1238 display = gtk_widget_get_display (GTK_WIDGET (object));
1239 key_hash = binding_key_hash_for_keymap (gdk_keymap_get_for_display (display));
1241 entries = _gtk_key_hash_lookup_keyval (key_hash, keyval, modifiers);
1243 handled = gtk_bindings_activate_list (object, entries, is_release);
1245 g_slist_free (entries);
1251 * gtk_bindings_activate_event:
1252 * @object: a #GObject (generally must be a widget)
1253 * @event: a #GdkEventKey
1255 * Looks up key bindings for @object to find one matching
1256 * @event, and if one was found, activate it.
1258 * Return value: %TRUE if a matching key binding was found
1263 gtk_bindings_activate_event (GObject *object,
1266 GSList *entries = NULL;
1267 GdkDisplay *display;
1268 GtkKeyHash *key_hash;
1269 gboolean handled = FALSE;
1271 if (!GTK_IS_WIDGET (object))
1274 display = gtk_widget_get_display (GTK_WIDGET (object));
1275 key_hash = binding_key_hash_for_keymap (gdk_keymap_get_for_display (display));
1277 entries = _gtk_key_hash_lookup (key_hash,
1278 event->hardware_keycode,
1280 BINDING_MOD_MASK () & ~GDK_RELEASE_MASK,
1283 handled = gtk_bindings_activate_list (object, entries,
1284 event->type == GDK_KEY_RELEASE);
1286 g_slist_free (entries);