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, see <http://www.gnu.org/licenses/>.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
32 #include "gtkbindingsprivate.h"
33 #include "gtkkeyhash.h"
34 #include "gtkwidget.h"
40 * @Short_description: Key bindings for individual widgets
41 * @See_also: Keyboard Accelerators, Mnemonics, #GtkCssProvider
43 * #GtkBindingSet provides a mechanism for configuring GTK+ key bindings
44 * through CSS files. This eases key binding adjustments for application
45 * developers as well as users and provides GTK+ users or administrators
46 * with high key binding configurability which requires no application
47 * or toolkit side changes.
49 * <refsect2 id="gtk-bindings-install">
50 * <title>Installing a key binding</title>
52 * A CSS file binding consists of a 'binding-set' definition and a match
53 * statement to apply the binding set to specific widget types. Details
54 * on the matching mechanism are described under
55 * <link linkend="gtkcssprovider-selectors">Selectors</link>
56 * in the #GtkCssProvider documentation. Inside the binding set definition,
57 * key combinations are bound to one or more specific signal emissions on
58 * the target widget. Key combinations are strings consisting of an optional
59 * #GdkModifierType name and <link linkend="gdk-Keyboard-Handling">key names</link>
60 * such as those defined in <filename><gdk/gdkkeysyms.h></filename>
61 * or returned from gdk_keyval_name(), they have to be parsable by
62 * gtk_accelerator_parse(). Specifications of signal emissions consist
63 * of a string identifying the signal name, and a list of signal specific
64 * arguments in parenthesis.
67 * For example for binding Control and the left or right cursor keys
68 * of a #GtkEntry widget to the #GtkEntry::move-cursor signal (so movement
69 * occurs in 3-character steps), the following binding can be used:
70 * <informalexample><programlisting>
71 * @binding-set MoveCursor3
73 * bind "<Control>Right" { "move-cursor" (visual-positions, 3, 0) };
74 * bind "<Control>Left" { "move-cursor" (visual-positions, -3, 0) };
78 * gtk-key-bindings: MoveCursor3
80 * </programlisting></informalexample>
83 * <refsect2 id="gtk-bindings-unbind">
84 * <title>Unbinding existing key bindings</title>
86 * GTK+ already defines a number of useful bindings for the widgets
87 * it provides. Because custom bindings set up in CSS files take
88 * precedence over the default bindings shipped with GTK+, overriding
89 * existing bindings as demonstrated in
90 * <link linkend="gtk-bindings-install">Installing a key binding</link>
91 * works as expected. The same mechanism can not be used to "unbind"
92 * existing bindings, however.
93 * <informalexample><programlisting>
94 * @binding-set MoveCursor3
96 * bind "<Control>Right" { };
97 * bind "<Control>Left" { };
101 * gtk-key-bindings: MoveCursor3
103 * </programlisting></informalexample>
104 * The above example will not have the desired effect of causing
105 * "<Control>Right" and "<Control>Left" key presses to
106 * be ignored by GTK+. Instead, it just causes any existing bindings
107 * from the bindings set "MoveCursor3" to be deleted, so when
108 * "<Control>Right" or "<Control>Left" are pressed, no
109 * binding for these keys is found in binding set "MoveCursor3".
110 * GTK+ will thus continue to search for matching key bindings, and will
111 * eventually lookup and find the default GTK+ bindings for entries which
112 * implement word movement. To keep GTK+ from activating its default
113 * bindings, the "unbind" keyword can be used like this:
114 * <informalexample><programlisting>
115 * @binding-set MoveCursor3
117 * unbind "<Control>Right";
118 * unbind "<Control>Left";
122 * gtk-key-bindings: MoveCursor3
124 * </programlisting></informalexample>
125 * Now, GTK+ will find a match when looking up "<Control>Right"
126 * and "<Control>Left" key presses before it resorts to its default
127 * bindings, and the match instructs it to abort ("unbind") the search,
128 * so the key presses are not consumed by this widget. As usual, further
129 * processing of the key presses, e.g. by an entry's parent widget, is
135 /* --- defines --- */
136 #define BINDING_MOD_MASK() (gtk_accelerator_get_default_mod_mask () | GDK_RELEASE_MASK)
139 #define GTK_TYPE_IDENTIFIER (gtk_identifier_get_type ())
140 GType gtk_identifier_get_type (void) G_GNUC_CONST;
143 /* --- structures --- */
152 GTK_BINDING_TOKEN_BIND,
153 GTK_BINDING_TOKEN_UNBIND
156 /* --- variables --- */
157 static GHashTable *binding_entry_hash_table = NULL;
158 static GSList *binding_key_hashes = NULL;
159 static GSList *binding_set_list = NULL;
160 static const gchar key_class_binding_set[] = "gtk-class-binding-set";
161 static GQuark key_id_class_binding_set = 0;
164 /* --- functions --- */
166 gtk_identifier_get_type (void)
168 static GType our_type = 0;
172 GTypeInfo tinfo = { 0, };
173 our_type = g_type_register_static (G_TYPE_STRING, I_("GtkIdentifier"), &tinfo, 0);
180 pattern_spec_free (PatternSpec *pspec)
183 g_pattern_spec_free (pspec->pspec);
187 static GtkBindingSignal*
188 binding_signal_new (const gchar *signal_name,
191 GtkBindingSignal *signal;
193 signal = (GtkBindingSignal *) g_slice_alloc0 (sizeof (GtkBindingSignal) + n_args * sizeof (GtkBindingArg));
195 signal->signal_name = (gchar *)g_intern_string (signal_name);
196 signal->n_args = n_args;
197 signal->args = (GtkBindingArg *)(signal + 1);
203 binding_signal_free (GtkBindingSignal *sig)
207 for (i = 0; i < sig->n_args; i++)
209 if (G_TYPE_FUNDAMENTAL (sig->args[i].arg_type) == G_TYPE_STRING)
210 g_free (sig->args[i].d.string_data);
212 g_slice_free1 (sizeof (GtkBindingSignal) + sig->n_args * sizeof (GtkBindingArg), sig);
216 binding_entry_hash (gconstpointer key)
218 register const GtkBindingEntry *e = key;
228 binding_entries_compare (gconstpointer a,
231 register const GtkBindingEntry *ea = a;
232 register const GtkBindingEntry *eb = b;
234 return (ea->keyval == eb->keyval && ea->modifiers == eb->modifiers);
238 binding_key_hash_insert_entry (GtkKeyHash *key_hash,
239 GtkBindingEntry *entry)
241 guint keyval = entry->keyval;
243 /* We store lowercased accelerators. To deal with this, if <Shift>
244 * was specified, uppercase.
246 if (entry->modifiers & GDK_SHIFT_MASK)
248 if (keyval == GDK_KEY_Tab)
249 keyval = GDK_KEY_ISO_Left_Tab;
251 keyval = gdk_keyval_to_upper (keyval);
254 _gtk_key_hash_add_entry (key_hash, keyval, entry->modifiers & ~GDK_RELEASE_MASK, entry);
258 binding_key_hash_destroy (gpointer data)
260 GtkKeyHash *key_hash = data;
262 binding_key_hashes = g_slist_remove (binding_key_hashes, key_hash);
263 _gtk_key_hash_free (key_hash);
267 insert_entries_into_key_hash (gpointer key,
271 GtkKeyHash *key_hash = data;
272 GtkBindingEntry *entry = value;
274 for (; entry; entry = entry->hash_next)
275 binding_key_hash_insert_entry (key_hash, entry);
279 binding_key_hash_for_keymap (GdkKeymap *keymap)
281 static GQuark key_hash_quark = 0;
282 GtkKeyHash *key_hash;
285 key_hash_quark = g_quark_from_static_string ("gtk-binding-key-hash");
287 key_hash = g_object_get_qdata (G_OBJECT (keymap), key_hash_quark);
291 key_hash = _gtk_key_hash_new (keymap, NULL);
292 g_object_set_qdata_full (G_OBJECT (keymap), key_hash_quark, key_hash, binding_key_hash_destroy);
294 if (binding_entry_hash_table)
295 g_hash_table_foreach (binding_entry_hash_table,
296 insert_entries_into_key_hash,
299 binding_key_hashes = g_slist_prepend (binding_key_hashes, key_hash);
306 static GtkBindingEntry*
307 binding_entry_new (GtkBindingSet *binding_set,
309 GdkModifierType modifiers)
312 GtkBindingEntry *entry;
314 if (!binding_entry_hash_table)
315 binding_entry_hash_table = g_hash_table_new (binding_entry_hash, binding_entries_compare);
317 entry = g_new (GtkBindingEntry, 1);
318 entry->keyval = keyval;
319 entry->modifiers = modifiers;
320 entry->binding_set = binding_set,
321 entry->destroyed = FALSE;
322 entry->in_emission = FALSE;
323 entry->marks_unbound = FALSE;
324 entry->signals = NULL;
326 entry->set_next = binding_set->entries;
327 binding_set->entries = entry;
329 entry->hash_next = g_hash_table_lookup (binding_entry_hash_table, entry);
330 if (entry->hash_next)
331 g_hash_table_remove (binding_entry_hash_table, entry->hash_next);
332 g_hash_table_insert (binding_entry_hash_table, entry, entry);
334 for (tmp_list = binding_key_hashes; tmp_list; tmp_list = tmp_list->next)
336 GtkKeyHash *key_hash = tmp_list->data;
337 binding_key_hash_insert_entry (key_hash, entry);
344 binding_entry_free (GtkBindingEntry *entry)
346 GtkBindingSignal *sig;
348 g_assert (entry->set_next == NULL &&
349 entry->hash_next == NULL &&
350 entry->in_emission == FALSE &&
351 entry->destroyed == TRUE);
353 entry->destroyed = FALSE;
355 sig = entry->signals;
358 GtkBindingSignal *prev;
362 binding_signal_free (prev);
368 binding_entry_destroy (GtkBindingEntry *entry)
370 GtkBindingEntry *o_entry;
371 register GtkBindingEntry *tmp;
372 GtkBindingEntry *begin;
373 register GtkBindingEntry *last;
376 /* unlink from binding set
379 tmp = entry->binding_set->entries;
385 last->set_next = entry->set_next;
387 entry->binding_set->entries = entry->set_next;
391 tmp = last->set_next;
393 entry->set_next = NULL;
395 o_entry = g_hash_table_lookup (binding_entry_hash_table, entry);
404 last->hash_next = entry->hash_next;
406 begin = entry->hash_next;
410 tmp = last->hash_next;
412 entry->hash_next = NULL;
415 g_hash_table_remove (binding_entry_hash_table, entry);
416 else if (begin != o_entry)
418 g_hash_table_remove (binding_entry_hash_table, entry);
419 g_hash_table_insert (binding_entry_hash_table, begin, begin);
422 for (tmp_list = binding_key_hashes; tmp_list; tmp_list = tmp_list->next)
424 GtkKeyHash *key_hash = tmp_list->data;
425 _gtk_key_hash_remove_entry (key_hash, entry);
428 entry->destroyed = TRUE;
430 if (!entry->in_emission)
431 binding_entry_free (entry);
434 static GtkBindingEntry*
435 binding_ht_lookup_entry (GtkBindingSet *set,
437 GdkModifierType modifiers)
439 GtkBindingEntry lookup_entry = { 0 };
440 GtkBindingEntry *entry;
442 if (!binding_entry_hash_table)
445 lookup_entry.keyval = keyval;
446 lookup_entry.modifiers = modifiers;
448 entry = g_hash_table_lookup (binding_entry_hash_table, &lookup_entry);
449 for (; entry; entry = entry->hash_next)
450 if (entry->binding_set == set)
457 binding_compose_params (GObject *object,
467 params = g_new0 (GValue, query->n_params + 1);
470 /* The instance we emit on is the first object in the array
472 g_value_init (params, G_TYPE_OBJECT);
473 g_value_set_object (params, G_OBJECT (object));
476 types = query->param_types;
478 for (i = 1; i < query->n_params + 1 && valid; i++)
480 GValue tmp_value = G_VALUE_INIT;
482 g_value_init (params, *types);
484 switch (G_TYPE_FUNDAMENTAL (args->arg_type))
487 g_value_init (&tmp_value, G_TYPE_DOUBLE);
488 g_value_set_double (&tmp_value, args->d.double_data);
491 g_value_init (&tmp_value, G_TYPE_LONG);
492 g_value_set_long (&tmp_value, args->d.long_data);
495 /* gtk_rc_parse_flags/enum() has fancier parsing for this; we can't call
496 * that since we don't have a GParamSpec, so just do something simple
498 if (G_TYPE_FUNDAMENTAL (*types) == G_TYPE_ENUM)
500 GEnumClass *class = G_ENUM_CLASS (g_type_class_ref (*types));
504 if (args->arg_type == GTK_TYPE_IDENTIFIER)
506 GEnumValue *enum_value = NULL;
507 enum_value = g_enum_get_value_by_name (class, args->d.string_data);
509 enum_value = g_enum_get_value_by_nick (class, args->d.string_data);
512 g_value_init (&tmp_value, *types);
513 g_value_set_enum (&tmp_value, enum_value->value);
518 g_type_class_unref (class);
520 /* This is just a hack for compatibility with GTK+-1.2 where a string
521 * could be used for a single flag value / without the support for multiple
522 * values in gtk_rc_parse_flags(), this isn't very useful.
524 else if (G_TYPE_FUNDAMENTAL (*types) == G_TYPE_FLAGS)
526 GFlagsClass *class = G_FLAGS_CLASS (g_type_class_ref (*types));
530 if (args->arg_type == GTK_TYPE_IDENTIFIER)
532 GFlagsValue *flags_value = NULL;
533 flags_value = g_flags_get_value_by_name (class, args->d.string_data);
535 flags_value = g_flags_get_value_by_nick (class, args->d.string_data);
538 g_value_init (&tmp_value, *types);
539 g_value_set_flags (&tmp_value, flags_value->value);
544 g_type_class_unref (class);
548 g_value_init (&tmp_value, G_TYPE_STRING);
549 g_value_set_static_string (&tmp_value, args->d.string_data);
559 if (!g_value_transform (&tmp_value, params))
562 g_value_unset (&tmp_value);
574 for (j = 0; j < i; j++)
575 g_value_unset (&(*params_p)[j]);
585 gtk_binding_entry_activate (GtkBindingEntry *entry,
588 GtkBindingSignal *sig;
589 gboolean old_emission;
590 gboolean handled = FALSE;
593 old_emission = entry->in_emission;
594 entry->in_emission = TRUE;
596 g_object_ref (object);
598 for (sig = entry->signals; sig; sig = sig->next)
602 GValue *params = NULL;
603 GValue return_val = G_VALUE_INIT;
604 gchar *accelerator = NULL;
606 signal_id = g_signal_lookup (sig->signal_name, G_OBJECT_TYPE (object));
609 accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
610 g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
611 "could not find signal \"%s\" in the `%s' class ancestry",
612 entry->binding_set->set_name,
615 g_type_name (G_OBJECT_TYPE (object)));
616 g_free (accelerator);
620 g_signal_query (signal_id, &query);
621 if (query.n_params != sig->n_args ||
622 (query.return_type != G_TYPE_NONE && query.return_type != G_TYPE_BOOLEAN) ||
623 !binding_compose_params (object, sig->args, &query, ¶ms))
625 accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
626 g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
627 "signature mismatch for signal \"%s\" in the `%s' class ancestry",
628 entry->binding_set->set_name,
631 g_type_name (G_OBJECT_TYPE (object)));
633 else if (!(query.signal_flags & G_SIGNAL_ACTION))
635 accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
636 g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
637 "signal \"%s\" in the `%s' class ancestry cannot be used for action emissions",
638 entry->binding_set->set_name,
641 g_type_name (G_OBJECT_TYPE (object)));
643 g_free (accelerator);
647 if (query.return_type == G_TYPE_BOOLEAN)
648 g_value_init (&return_val, G_TYPE_BOOLEAN);
650 g_signal_emitv (params, signal_id, 0, &return_val);
652 if (query.return_type == G_TYPE_BOOLEAN)
654 if (g_value_get_boolean (&return_val))
656 g_value_unset (&return_val);
661 for (i = 0; i < query.n_params + 1; i++)
662 g_value_unset (¶ms[i]);
665 if (entry->destroyed)
669 g_object_unref (object);
671 entry->in_emission = old_emission;
672 if (entry->destroyed && !entry->in_emission)
673 binding_entry_free (entry);
679 * gtk_binding_set_new: (skip)
680 * @set_name: unique name of this binding set
682 * GTK+ maintains a global list of binding sets. Each binding set has
683 * a unique name which needs to be specified upon creation.
685 * Return value: (transfer full): new binding set
688 gtk_binding_set_new (const gchar *set_name)
690 GtkBindingSet *binding_set;
692 g_return_val_if_fail (set_name != NULL, NULL);
694 binding_set = g_new (GtkBindingSet, 1);
695 binding_set->set_name = (gchar *) g_intern_string (set_name);
696 binding_set->widget_path_pspecs = NULL;
697 binding_set->widget_class_pspecs = NULL;
698 binding_set->class_branch_pspecs = NULL;
699 binding_set->entries = NULL;
700 binding_set->current = NULL;
701 binding_set->parsed = FALSE;
703 binding_set_list = g_slist_prepend (binding_set_list, binding_set);
709 * gtk_binding_set_by_class: (skip)
710 * @object_class: a valid #GObject class
712 * This function returns the binding set named after the type name of
713 * the passed in class structure. New binding sets are created on
714 * demand by this function.
716 * Return value: (transfer full): the binding set corresponding to
720 gtk_binding_set_by_class (gpointer object_class)
722 GObjectClass *class = object_class;
723 GtkBindingSet* binding_set;
725 g_return_val_if_fail (G_IS_OBJECT_CLASS (class), NULL);
727 if (!key_id_class_binding_set)
728 key_id_class_binding_set = g_quark_from_static_string (key_class_binding_set);
730 binding_set = g_dataset_id_get_data (class, key_id_class_binding_set);
735 binding_set = gtk_binding_set_new (g_type_name (G_OBJECT_CLASS_TYPE (class)));
736 g_dataset_id_set_data (class, key_id_class_binding_set, binding_set);
741 static GtkBindingSet*
742 gtk_binding_set_find_interned (const gchar *set_name)
746 for (slist = binding_set_list; slist; slist = slist->next)
748 GtkBindingSet *binding_set;
750 binding_set = slist->data;
751 if (binding_set->set_name == set_name)
759 * gtk_binding_set_find:
760 * @set_name: unique binding set name
762 * Find a binding set by its globally unique name.
764 * The @set_name can either be a name used for gtk_binding_set_new()
765 * or the type name of a class used in gtk_binding_set_by_class().
767 * Return value: (transfer none): %NULL or the specified binding set
770 gtk_binding_set_find (const gchar *set_name)
772 g_return_val_if_fail (set_name != NULL, NULL);
774 return gtk_binding_set_find_interned (g_intern_string (set_name));
778 * gtk_binding_set_activate:
779 * @binding_set: a #GtkBindingSet set to activate
780 * @keyval: key value of the binding
781 * @modifiers: key modifier of the binding
782 * @object: object to activate when binding found
784 * Find a key binding matching @keyval and @modifiers within
785 * @binding_set and activate the binding on @object.
787 * Return value: %TRUE if a binding was found and activated
790 gtk_binding_set_activate (GtkBindingSet *binding_set,
792 GdkModifierType modifiers,
795 GtkBindingEntry *entry;
797 g_return_val_if_fail (binding_set != NULL, FALSE);
798 g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
800 keyval = gdk_keyval_to_lower (keyval);
801 modifiers = modifiers & BINDING_MOD_MASK ();
803 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
805 return gtk_binding_entry_activate (entry, object);
811 gtk_binding_entry_clear_internal (GtkBindingSet *binding_set,
813 GdkModifierType modifiers)
815 GtkBindingEntry *entry;
817 keyval = gdk_keyval_to_lower (keyval);
818 modifiers = modifiers & BINDING_MOD_MASK ();
820 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
822 binding_entry_destroy (entry);
824 entry = binding_entry_new (binding_set, keyval, modifiers);
828 * gtk_binding_entry_skip:
829 * @binding_set: a #GtkBindingSet to skip an entry of
830 * @keyval: key value of binding to skip
831 * @modifiers: key modifier of binding to skip
833 * Install a binding on @binding_set which causes key lookups
834 * to be aborted, to prevent bindings from lower priority sets
840 gtk_binding_entry_skip (GtkBindingSet *binding_set,
842 GdkModifierType modifiers)
844 GtkBindingEntry *entry;
846 g_return_if_fail (binding_set != NULL);
848 keyval = gdk_keyval_to_lower (keyval);
849 modifiers = modifiers & BINDING_MOD_MASK ();
851 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
853 binding_entry_destroy (entry);
855 entry = binding_entry_new (binding_set, keyval, modifiers);
856 entry->marks_unbound = TRUE;
860 * gtk_binding_entry_remove:
861 * @binding_set: a #GtkBindingSet to remove an entry of
862 * @keyval: key value of binding to remove
863 * @modifiers: key modifier of binding to remove
865 * Remove a binding previously installed via
866 * gtk_binding_entry_add_signal() on @binding_set.
869 gtk_binding_entry_remove (GtkBindingSet *binding_set,
871 GdkModifierType modifiers)
873 GtkBindingEntry *entry;
875 g_return_if_fail (binding_set != NULL);
877 keyval = gdk_keyval_to_lower (keyval);
878 modifiers = modifiers & BINDING_MOD_MASK ();
880 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
882 binding_entry_destroy (entry);
886 * gtk_binding_entry_add_signall:
887 * @binding_set: a #GtkBindingSet to add a signal to
889 * @modifiers: key modifier
890 * @signal_name: signal name to be bound
891 * @binding_args: (transfer none) (element-type GtkBindingArg):
892 * list of #GtkBindingArg signal arguments
894 * Override or install a new key binding for @keyval with @modifiers on
898 gtk_binding_entry_add_signall (GtkBindingSet *binding_set,
900 GdkModifierType modifiers,
901 const gchar *signal_name,
902 GSList *binding_args)
904 _gtk_binding_entry_add_signall (binding_set,
906 signal_name, binding_args);
910 _gtk_binding_entry_add_signall (GtkBindingSet *binding_set,
912 GdkModifierType modifiers,
913 const gchar *signal_name,
914 GSList *binding_args)
916 GtkBindingEntry *entry;
917 GtkBindingSignal *signal, **signal_p;
922 g_return_if_fail (binding_set != NULL);
923 g_return_if_fail (signal_name != NULL);
925 keyval = gdk_keyval_to_lower (keyval);
926 modifiers = modifiers & BINDING_MOD_MASK ();
928 signal = binding_signal_new (signal_name, g_slist_length (binding_args));
931 for (slist = binding_args; slist; slist = slist->next)
933 GtkBindingArg *tmp_arg;
935 tmp_arg = slist->data;
938 g_warning ("gtk_binding_entry_add_signall(): arg[%u] is `NULL'", n);
939 binding_signal_free (signal);
942 switch (G_TYPE_FUNDAMENTAL (tmp_arg->arg_type))
945 arg->arg_type = G_TYPE_LONG;
946 arg->d.long_data = tmp_arg->d.long_data;
949 arg->arg_type = G_TYPE_DOUBLE;
950 arg->d.double_data = tmp_arg->d.double_data;
953 if (tmp_arg->arg_type != GTK_TYPE_IDENTIFIER)
954 arg->arg_type = G_TYPE_STRING;
956 arg->arg_type = GTK_TYPE_IDENTIFIER;
957 arg->d.string_data = g_strdup (tmp_arg->d.string_data);
958 if (!arg->d.string_data)
960 g_warning ("gtk_binding_entry_add_signall(): value of `string' arg[%u] is `NULL'", n);
961 binding_signal_free (signal);
966 g_warning ("gtk_binding_entry_add_signall(): unsupported type `%s' for arg[%u]",
967 g_type_name (arg->arg_type), n);
968 binding_signal_free (signal);
975 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
978 gtk_binding_entry_clear_internal (binding_set, keyval, modifiers);
979 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
981 signal_p = &entry->signals;
983 signal_p = &(*signal_p)->next;
988 * gtk_binding_entry_add_signal:
989 * @binding_set: a #GtkBindingSet to install an entry for
990 * @keyval: key value of binding to install
991 * @modifiers: key modifier of binding to install
992 * @signal_name: signal to execute upon activation
993 * @n_args: number of arguments to @signal_name
994 * @...: arguments to @signal_name
996 * Override or install a new key binding for @keyval with @modifiers on
997 * @binding_set. When the binding is activated, @signal_name will be
998 * emitted on the target widget, with @n_args @Varargs used as
1002 gtk_binding_entry_add_signal (GtkBindingSet *binding_set,
1004 GdkModifierType modifiers,
1005 const gchar *signal_name,
1009 GSList *slist, *free_slist;
1013 g_return_if_fail (binding_set != NULL);
1014 g_return_if_fail (signal_name != NULL);
1016 va_start (args, n_args);
1018 for (i = 0; i < n_args; i++)
1022 arg = g_slice_new0 (GtkBindingArg);
1023 slist = g_slist_prepend (slist, arg);
1025 arg->arg_type = va_arg (args, GType);
1026 switch (G_TYPE_FUNDAMENTAL (arg->arg_type))
1032 case G_TYPE_BOOLEAN:
1035 arg->arg_type = G_TYPE_LONG;
1036 arg->d.long_data = va_arg (args, gint);
1040 arg->arg_type = G_TYPE_LONG;
1041 arg->d.long_data = va_arg (args, glong);
1045 arg->arg_type = G_TYPE_DOUBLE;
1046 arg->d.double_data = va_arg (args, gdouble);
1049 if (arg->arg_type != GTK_TYPE_IDENTIFIER)
1050 arg->arg_type = G_TYPE_STRING;
1051 arg->d.string_data = va_arg (args, gchar*);
1052 if (!arg->d.string_data)
1054 g_warning ("gtk_binding_entry_add_signal(): type `%s' arg[%u] is `NULL'",
1055 g_type_name (arg->arg_type),
1061 g_warning ("gtk_binding_entry_add_signal(): unsupported type `%s' for arg[%u]",
1062 g_type_name (arg->arg_type), i);
1069 if (i == n_args || i == 0)
1071 slist = g_slist_reverse (slist);
1072 _gtk_binding_entry_add_signall (binding_set, keyval, modifiers, signal_name, slist);
1078 g_slice_free (GtkBindingArg, slist->data);
1079 slist = slist->next;
1081 g_slist_free (free_slist);
1085 gtk_binding_parse_signal (GScanner *scanner,
1086 GtkBindingSet *binding_set,
1088 GdkModifierType modifiers)
1091 guint expected_token = 0;
1097 gboolean seen_comma;
1099 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1101 g_scanner_get_next_token (scanner);
1103 if (scanner->token != G_TOKEN_STRING)
1104 return G_TOKEN_STRING;
1106 g_scanner_peek_next_token (scanner);
1108 if (scanner->next_token != '(')
1110 g_scanner_get_next_token (scanner);
1114 signal = g_strdup (scanner->value.v_string);
1115 g_scanner_get_next_token (scanner);
1122 scanner->config->scan_symbols = FALSE;
1129 expected_token = G_TOKEN_INT;
1131 expected_token = ')';
1133 g_scanner_get_next_token (scanner);
1135 switch ((guint) scanner->token)
1141 arg = g_new (GtkBindingArg, 1);
1142 arg->arg_type = G_TYPE_DOUBLE;
1143 arg->d.double_data = scanner->value.v_float;
1147 arg->d.double_data = - arg->d.double_data;
1150 args = g_slist_prepend (args, arg);
1160 arg = g_new (GtkBindingArg, 1);
1161 arg->arg_type = G_TYPE_LONG;
1162 arg->d.long_data = scanner->value.v_int;
1166 arg->d.long_data = - arg->d.long_data;
1169 args = g_slist_prepend (args, arg);
1174 case G_TOKEN_STRING:
1175 if (need_arg && !negate)
1178 arg = g_new (GtkBindingArg, 1);
1179 arg->arg_type = G_TYPE_STRING;
1180 arg->d.string_data = g_strdup (scanner->value.v_string);
1181 args = g_slist_prepend (args, arg);
1187 case G_TOKEN_IDENTIFIER:
1188 if (need_arg && !negate)
1191 arg = g_new (GtkBindingArg, 1);
1192 arg->arg_type = GTK_TYPE_IDENTIFIER;
1193 arg->d.string_data = g_strdup (scanner->value.v_identifier);
1194 args = g_slist_prepend (args, arg);
1205 expected_token = G_TOKEN_INT;
1221 if (!(need_arg && seen_comma) && !negate)
1223 args = g_slist_reverse (args);
1224 _gtk_binding_entry_add_signall (binding_set,
1229 expected_token = G_TOKEN_NONE;
1241 scanner->config->scan_symbols = TRUE;
1243 for (slist = args; slist; slist = slist->next)
1249 if (G_TYPE_FUNDAMENTAL (arg->arg_type) == G_TYPE_STRING)
1250 g_free (arg->d.string_data);
1254 g_slist_free (args);
1257 return expected_token;
1261 gtk_binding_parse_bind (GScanner *scanner,
1262 GtkBindingSet *binding_set)
1265 GdkModifierType modifiers = 0;
1266 gboolean unbind = FALSE;
1268 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1270 g_scanner_get_next_token (scanner);
1272 if (scanner->token != G_TOKEN_SYMBOL)
1273 return G_TOKEN_SYMBOL;
1275 if (scanner->value.v_symbol != GUINT_TO_POINTER (GTK_BINDING_TOKEN_BIND) &&
1276 scanner->value.v_symbol != GUINT_TO_POINTER (GTK_BINDING_TOKEN_UNBIND))
1277 return G_TOKEN_SYMBOL;
1279 unbind = (scanner->value.v_symbol == GUINT_TO_POINTER (GTK_BINDING_TOKEN_UNBIND));
1280 g_scanner_get_next_token (scanner);
1282 if (scanner->token != (guint) G_TOKEN_STRING)
1283 return G_TOKEN_STRING;
1285 gtk_accelerator_parse (scanner->value.v_string, &keyval, &modifiers);
1286 modifiers &= BINDING_MOD_MASK ();
1289 return G_TOKEN_STRING;
1293 gtk_binding_entry_skip (binding_set, keyval, modifiers);
1294 return G_TOKEN_NONE;
1297 g_scanner_get_next_token (scanner);
1299 if (scanner->token != '{')
1302 gtk_binding_entry_clear_internal (binding_set, keyval, modifiers);
1303 g_scanner_peek_next_token (scanner);
1305 while (scanner->next_token != '}')
1307 guint expected_token;
1309 switch (scanner->next_token)
1311 case G_TOKEN_STRING:
1312 expected_token = gtk_binding_parse_signal (scanner,
1316 if (expected_token != G_TOKEN_NONE)
1317 return expected_token;
1320 g_scanner_get_next_token (scanner);
1324 g_scanner_peek_next_token (scanner);
1327 g_scanner_get_next_token (scanner);
1329 return G_TOKEN_NONE;
1333 create_signal_scanner (void)
1337 scanner = g_scanner_new (NULL);
1338 scanner->config->cset_identifier_nth = G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "-_";
1340 g_scanner_scope_add_symbol (scanner, 0, "bind", GUINT_TO_POINTER (GTK_BINDING_TOKEN_BIND));
1341 g_scanner_scope_add_symbol (scanner, 0, "unbind", GUINT_TO_POINTER (GTK_BINDING_TOKEN_UNBIND));
1343 g_scanner_set_scope (scanner, 0);
1349 * gtk_binding_entry_add_signal_from_string:
1350 * @binding_set: a #GtkBindingSet
1351 * @signal_desc: a signal description
1353 * Parses a signal description from @signal_desc and incorporates
1354 * it into @binding_set.
1356 * Signal descriptions may either bind a key combination to
1357 * one or more signals:
1358 * <informalexample><programlisting>
1360 * "signalname" (param, ...)
1363 * </programlisting></informalexample>
1365 * Or they may also unbind a key combination:
1366 * <informalexample><programlisting>
1368 * </programlisting></informalexample>
1370 * Key combinations must be in a format that can be parsed by
1371 * gtk_accelerator_parse().
1373 * Returns: %G_TOKEN_NONE if the signal was successfully parsed and added,
1374 * the expected token otherwise
1379 gtk_binding_entry_add_signal_from_string (GtkBindingSet *binding_set,
1380 const gchar *signal_desc)
1382 static GScanner *scanner = NULL;
1385 g_return_val_if_fail (binding_set != NULL, G_TOKEN_NONE);
1386 g_return_val_if_fail (signal_desc != NULL, G_TOKEN_NONE);
1388 if (G_UNLIKELY (!scanner))
1389 scanner = create_signal_scanner ();
1391 g_scanner_input_text (scanner, signal_desc,
1392 (guint) strlen (signal_desc));
1394 ret = gtk_binding_parse_bind (scanner, binding_set);
1396 /* Reset for next use */
1397 g_scanner_set_scope (scanner, 0);
1403 * gtk_binding_set_add_path:
1404 * @binding_set: a #GtkBindingSet to add a path to
1405 * @path_type: path type the pattern applies to
1406 * @path_pattern: the actual match pattern
1407 * @priority: binding priority
1409 * This function was used internally by the GtkRC parsing mechanism
1410 * to assign match patterns to #GtkBindingSet structures.
1412 * In GTK+ 3, these match patterns are unused.
1417 gtk_binding_set_add_path (GtkBindingSet *binding_set,
1418 GtkPathType path_type,
1419 const gchar *path_pattern,
1420 GtkPathPriorityType priority)
1423 GSList **slist_p, *slist;
1424 static guint seq_id = 0;
1426 g_return_if_fail (binding_set != NULL);
1427 g_return_if_fail (path_pattern != NULL);
1428 g_return_if_fail (priority <= GTK_PATH_PRIO_MASK);
1430 priority &= GTK_PATH_PRIO_MASK;
1434 case GTK_PATH_WIDGET:
1435 slist_p = &binding_set->widget_path_pspecs;
1437 case GTK_PATH_WIDGET_CLASS:
1438 slist_p = &binding_set->widget_class_pspecs;
1440 case GTK_PATH_CLASS:
1441 slist_p = &binding_set->class_branch_pspecs;
1444 g_assert_not_reached ();
1449 pspec = g_new (PatternSpec, 1);
1450 pspec->type = path_type;
1451 if (path_type == GTK_PATH_WIDGET_CLASS)
1452 pspec->pspec = NULL;
1454 pspec->pspec = g_pattern_spec_new (path_pattern);
1456 pspec->seq_id = priority << 28;
1457 pspec->user_data = binding_set;
1462 PatternSpec *tmp_pspec;
1464 tmp_pspec = slist->data;
1465 slist = slist->next;
1467 if (g_pattern_spec_equal (tmp_pspec->pspec, pspec->pspec))
1469 GtkPathPriorityType lprio = tmp_pspec->seq_id >> 28;
1471 pattern_spec_free (pspec);
1473 if (lprio < priority)
1475 tmp_pspec->seq_id &= 0x0fffffff;
1476 tmp_pspec->seq_id |= priority << 28;
1483 pspec->seq_id |= seq_id++ & 0x0fffffff;
1484 *slist_p = g_slist_prepend (*slist_p, pspec);
1489 find_entry_with_binding (GtkBindingEntry *entry,
1490 GtkBindingSet *binding_set)
1492 return (entry->binding_set == binding_set) ? 0 : 1;
1496 binding_activate (GtkBindingSet *binding_set,
1499 gboolean is_release,
1502 GtkBindingEntry *entry;
1505 elem = g_slist_find_custom (entries, binding_set,
1506 (GCompareFunc) find_entry_with_binding);
1513 if (is_release != ((entry->modifiers & GDK_RELEASE_MASK) != 0))
1516 if (entry->marks_unbound)
1522 if (gtk_binding_entry_activate (entry, object))
1529 gtk_bindings_activate_list (GObject *object,
1531 gboolean is_release)
1533 GtkStyleContext *context;
1534 GtkBindingSet *binding_set;
1535 GtkStateFlags state;
1536 gboolean handled = FALSE;
1537 gboolean unbound = FALSE;
1543 context = gtk_widget_get_style_context (GTK_WIDGET (object));
1544 state = gtk_widget_get_state_flags (GTK_WIDGET (object));
1546 gtk_style_context_get (context, state,
1547 "gtk-key-bindings", &array,
1553 for (i = 0; i < array->len; i++)
1555 binding_set = g_ptr_array_index (array, i);
1556 handled = binding_activate (binding_set, entries,
1563 g_ptr_array_unref (array);
1573 class_type = G_TYPE_FROM_INSTANCE (object);
1575 while (class_type && !handled)
1577 binding_set = gtk_binding_set_find_interned (g_type_name (class_type));
1578 class_type = g_type_parent (class_type);
1583 handled = binding_activate (binding_set, entries,
1596 * gtk_bindings_activate:
1597 * @object: object to activate when binding found
1598 * @keyval: key value of the binding
1599 * @modifiers: key modifier of the binding
1601 * Find a key binding matching @keyval and @modifiers and activate the
1602 * binding on @object.
1604 * Return value: %TRUE if a binding was found and activated
1607 gtk_bindings_activate (GObject *object,
1609 GdkModifierType modifiers)
1611 GSList *entries = NULL;
1612 GdkDisplay *display;
1613 GtkKeyHash *key_hash;
1614 gboolean handled = FALSE;
1615 gboolean is_release;
1617 if (!GTK_IS_WIDGET (object))
1620 is_release = (modifiers & GDK_RELEASE_MASK) != 0;
1621 modifiers = modifiers & BINDING_MOD_MASK () & ~GDK_RELEASE_MASK;
1623 display = gtk_widget_get_display (GTK_WIDGET (object));
1624 key_hash = binding_key_hash_for_keymap (gdk_keymap_get_for_display (display));
1626 entries = _gtk_key_hash_lookup_keyval (key_hash, keyval, modifiers);
1628 handled = gtk_bindings_activate_list (object, entries, is_release);
1630 g_slist_free (entries);
1636 * gtk_bindings_activate_event:
1637 * @object: a #GObject (generally must be a widget)
1638 * @event: a #GdkEventKey
1640 * Looks up key bindings for @object to find one matching
1641 * @event, and if one was found, activate it.
1643 * Return value: %TRUE if a matching key binding was found
1648 gtk_bindings_activate_event (GObject *object,
1651 GSList *entries = NULL;
1652 GdkDisplay *display;
1653 GtkKeyHash *key_hash;
1654 gboolean handled = FALSE;
1656 if (!GTK_IS_WIDGET (object))
1659 display = gtk_widget_get_display (GTK_WIDGET (object));
1660 key_hash = binding_key_hash_for_keymap (gdk_keymap_get_for_display (display));
1662 entries = _gtk_key_hash_lookup (key_hash,
1663 event->hardware_keycode,
1665 BINDING_MOD_MASK () & ~GDK_RELEASE_MASK,
1668 handled = gtk_bindings_activate_list (object, entries,
1669 event->type == GDK_KEY_RELEASE);
1671 g_slist_free (entries);