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 Library 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 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library 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-1999. 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 "gtkbindings.h"
34 #include "gtksignal.h"
35 #include "gtkwidget.h"
40 #define BINDING_MOD_MASK() (gtk_accelerator_get_default_mod_mask () | GDK_RELEASE_MASK)
43 /* --- variables --- */
44 static GHashTable *binding_entry_hash_table = NULL;
45 static GSList *binding_set_list = NULL;
46 static const gchar *key_class_binding_set = "gtk-class-binding-set";
47 static GQuark key_id_class_binding_set = 0;
50 /* --- functions --- */
51 static GtkBindingSignal*
52 binding_signal_new (const gchar *signal_name,
55 GtkBindingSignal *signal;
57 signal = g_new (GtkBindingSignal, 1);
59 signal->signal_name = g_strdup (signal_name);
60 signal->n_args = n_args;
61 signal->args = g_new0 (GtkBindingArg, n_args);
67 binding_signal_free (GtkBindingSignal *sig)
71 for (i = 0; i < sig->n_args; i++)
73 if (GTK_FUNDAMENTAL_TYPE (sig->args[i].arg_type) == GTK_TYPE_STRING)
74 g_free (sig->args[i].d.string_data);
77 g_free (sig->signal_name);
82 binding_entry_hash (gconstpointer key)
84 register const GtkBindingEntry *e = key;
94 binding_entries_compare (gconstpointer a,
97 register const GtkBindingEntry *ea = a;
98 register const GtkBindingEntry *eb = b;
100 return (ea->keyval == eb->keyval && ea->modifiers == eb->modifiers);
103 static GtkBindingEntry*
104 binding_entry_new (GtkBindingSet *binding_set,
108 GtkBindingEntry *entry;
110 if (!binding_entry_hash_table)
111 binding_entry_hash_table = g_hash_table_new (binding_entry_hash, binding_entries_compare);
113 entry = g_new (GtkBindingEntry, 1);
114 entry->keyval = keyval;
115 entry->modifiers = modifiers;
116 entry->binding_set = binding_set,
117 entry->destroyed = FALSE;
118 entry->in_emission = FALSE;
119 entry->signals = NULL;
121 entry->set_next = binding_set->entries;
122 binding_set->entries = entry;
124 entry->hash_next = g_hash_table_lookup (binding_entry_hash_table, entry);
125 g_hash_table_freeze (binding_entry_hash_table);
126 if (entry->hash_next)
127 g_hash_table_remove (binding_entry_hash_table, entry->hash_next);
128 g_hash_table_insert (binding_entry_hash_table, entry, entry);
129 g_hash_table_thaw (binding_entry_hash_table);
135 binding_entry_free (GtkBindingEntry *entry)
137 GtkBindingSignal *sig;
139 g_assert (entry->set_next == NULL &&
140 entry->hash_next == NULL &&
141 entry->in_emission == FALSE &&
142 entry->destroyed == TRUE);
144 entry->destroyed = FALSE;
146 sig = entry->signals;
149 GtkBindingSignal *prev;
153 binding_signal_free (prev);
159 binding_entry_destroy (GtkBindingEntry *entry)
161 GtkBindingEntry *o_entry;
162 register GtkBindingEntry *tmp;
163 GtkBindingEntry *begin;
164 register GtkBindingEntry *last;
166 /* unlink from binding set
169 tmp = entry->binding_set->entries;
175 last->set_next = entry->set_next;
177 entry->binding_set->entries = entry->set_next;
181 tmp = last->set_next;
183 entry->set_next = NULL;
185 o_entry = g_hash_table_lookup (binding_entry_hash_table, entry);
194 last->hash_next = entry->hash_next;
196 begin = entry->hash_next;
200 tmp = last->hash_next;
202 entry->hash_next = NULL;
205 g_hash_table_remove (binding_entry_hash_table, entry);
206 else if (begin != o_entry)
208 g_hash_table_freeze (binding_entry_hash_table);
209 g_hash_table_remove (binding_entry_hash_table, entry);
210 g_hash_table_insert (binding_entry_hash_table, begin, begin);
211 g_hash_table_thaw (binding_entry_hash_table);
214 entry->destroyed = TRUE;
216 if (!entry->in_emission)
217 binding_entry_free (entry);
220 static GtkBindingEntry*
221 binding_ht_lookup_list (guint keyval,
224 GtkBindingEntry lookup_entry = { 0 };
226 if (!binding_entry_hash_table)
229 lookup_entry.keyval = keyval;
230 lookup_entry.modifiers = modifiers;
232 return g_hash_table_lookup (binding_entry_hash_table, &lookup_entry);
235 static GtkBindingEntry*
236 binding_ht_lookup_entry (GtkBindingSet *set,
240 GtkBindingEntry lookup_entry = { 0 };
241 GtkBindingEntry *entry;
243 if (!binding_entry_hash_table)
246 lookup_entry.keyval = keyval;
247 lookup_entry.modifiers = modifiers;
249 entry = g_hash_table_lookup (binding_entry_hash_table, &lookup_entry);
250 for (; entry; entry = entry->hash_next)
251 if (entry->binding_set == set)
258 binding_compose_params (GtkBindingArg *args,
259 GtkSignalQuery *query,
263 const GtkType *types;
267 params = g_new0 (GtkArg, query->nparams);
270 types = query->params;
272 for (i = 0; i < query->nparams && valid; i++)
276 params->type = *types;
278 param_ftype = GTK_FUNDAMENTAL_TYPE (params->type);
279 switch (GTK_FUNDAMENTAL_TYPE (args->arg_type))
281 case GTK_TYPE_DOUBLE:
282 if (param_ftype == GTK_TYPE_FLOAT)
283 GTK_VALUE_FLOAT (*params) = args->d.double_data;
284 else if (param_ftype == GTK_TYPE_DOUBLE)
285 GTK_VALUE_DOUBLE (*params) = args->d.double_data;
290 if (param_ftype == GTK_TYPE_BOOL &&
291 (args->d.long_data == 0 ||
292 args->d.long_data == 1))
293 GTK_VALUE_BOOL (*params) = args->d.long_data;
294 else if (param_ftype == GTK_TYPE_INT ||
295 param_ftype == GTK_TYPE_ENUM)
296 GTK_VALUE_INT (*params) = args->d.long_data;
297 else if ((param_ftype == GTK_TYPE_UINT ||
298 param_ftype == GTK_TYPE_FLAGS) &&
299 args->d.long_data >= 0)
300 GTK_VALUE_UINT (*params) = args->d.long_data;
301 else if (param_ftype == GTK_TYPE_LONG)
302 GTK_VALUE_LONG (*params) = args->d.long_data;
303 else if (param_ftype == GTK_TYPE_ULONG &&
304 args->d.long_data >= 0)
305 GTK_VALUE_ULONG (*params) = args->d.long_data;
306 else if (param_ftype == GTK_TYPE_FLOAT)
307 GTK_VALUE_FLOAT (*params) = args->d.long_data;
308 else if (param_ftype == GTK_TYPE_DOUBLE)
309 GTK_VALUE_DOUBLE (*params) = args->d.long_data;
313 case GTK_TYPE_STRING:
314 if (args->arg_type == GTK_TYPE_STRING &&
315 param_ftype == GTK_TYPE_STRING)
316 GTK_VALUE_STRING (*params) = args->d.string_data;
317 else if (args->arg_type == GTK_TYPE_IDENTIFIER &&
318 (param_ftype == GTK_TYPE_ENUM ||
319 param_ftype == GTK_TYPE_FLAGS))
323 value = gtk_type_enum_find_value (params->type, args->d.string_data);
325 GTK_VALUE_ENUM (*params) = value->value;
351 gtk_binding_entry_activate (GtkBindingEntry *entry,
354 GtkBindingSignal *sig;
355 gboolean old_emission;
357 old_emission = entry->in_emission;
358 entry->in_emission = TRUE;
360 gtk_object_ref (object);
362 for (sig = entry->signals; sig; sig = sig->next)
364 GtkSignalQuery *query;
366 GtkArg *params = NULL;
367 gchar *accelerator = NULL;
369 signal_id = gtk_signal_lookup (sig->signal_name, GTK_OBJECT_TYPE (object));
372 accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
373 g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
374 "could not find signal \"%s\" in the `%s' class ancestry",
375 entry->binding_set->set_name,
378 gtk_type_name (GTK_OBJECT_TYPE (object)));
379 g_free (accelerator);
383 query = gtk_signal_query (signal_id);
384 if (query->nparams != sig->n_args ||
385 query->return_val != GTK_TYPE_NONE ||
386 !binding_compose_params (sig->args, query, ¶ms))
388 accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
389 g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
390 "signature mismatch for signal \"%s\" in the `%s' class ancestry",
391 entry->binding_set->set_name,
394 gtk_type_name (GTK_OBJECT_TYPE (object)));
396 else if (!(query->signal_flags & GTK_RUN_ACTION))
398 accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
399 g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
400 "signal \"%s\" in the `%s' class ancestry cannot be used for action emissions",
401 entry->binding_set->set_name,
404 gtk_type_name (GTK_OBJECT_TYPE (object)));
406 g_free (accelerator);
411 gtk_signal_emitv (object, signal_id, params);
414 if (GTK_OBJECT_DESTROYED (object) || entry->destroyed)
418 gtk_object_unref (object);
420 entry->in_emission = old_emission;
421 if (entry->destroyed && !entry->in_emission)
422 binding_entry_free (entry);
426 gtk_binding_set_new (const gchar *set_name)
428 GtkBindingSet *binding_set;
430 g_return_val_if_fail (set_name != NULL, NULL);
432 binding_set = g_new (GtkBindingSet, 1);
433 binding_set->set_name = g_strdup (set_name);
434 binding_set->widget_path_pspecs = NULL;
435 binding_set->widget_class_pspecs = NULL;
436 binding_set->class_branch_pspecs = NULL;
437 binding_set->entries = NULL;
438 binding_set->current = NULL;
440 binding_set_list = g_slist_prepend (binding_set_list, binding_set);
446 gtk_binding_set_by_class (gpointer object_class)
448 GtkObjectClass *class = object_class;
449 GtkBindingSet* binding_set;
451 g_return_val_if_fail (GTK_IS_OBJECT_CLASS (class), NULL);
453 if (!key_id_class_binding_set)
454 key_id_class_binding_set = g_quark_from_static_string (key_class_binding_set);
456 binding_set = g_dataset_id_get_data (class, key_id_class_binding_set);
461 binding_set = gtk_binding_set_new (gtk_type_name (class->type));
462 gtk_binding_set_add_path (binding_set,
464 gtk_type_name (class->type),
466 g_dataset_id_set_data (class, key_id_class_binding_set, binding_set);
472 gtk_binding_set_find (const gchar *set_name)
476 g_return_val_if_fail (set_name != NULL, NULL);
478 for (slist = binding_set_list; slist; slist = slist->next)
480 GtkBindingSet *binding_set;
482 binding_set = slist->data;
483 if (g_str_equal (binding_set->set_name, (gpointer) set_name))
490 gtk_binding_set_activate (GtkBindingSet *binding_set,
495 GtkBindingEntry *entry;
497 g_return_val_if_fail (binding_set != NULL, FALSE);
498 g_return_val_if_fail (object != NULL, FALSE);
499 g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
501 keyval = gdk_keyval_to_lower (keyval);
502 modifiers = modifiers & BINDING_MOD_MASK ();
504 if (!GTK_OBJECT_DESTROYED (object))
506 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
509 gtk_binding_entry_activate (entry, object);
519 gtk_binding_entry_clear (GtkBindingSet *binding_set,
523 GtkBindingEntry *entry;
525 g_return_if_fail (binding_set != NULL);
527 keyval = gdk_keyval_to_lower (keyval);
528 modifiers = modifiers & BINDING_MOD_MASK ();
530 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
532 binding_entry_destroy (entry);
534 entry = binding_entry_new (binding_set, keyval, modifiers);
538 gtk_binding_entry_remove (GtkBindingSet *binding_set,
542 GtkBindingEntry *entry;
544 g_return_if_fail (binding_set != NULL);
546 keyval = gdk_keyval_to_lower (keyval);
547 modifiers = modifiers & BINDING_MOD_MASK ();
549 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
551 binding_entry_destroy (entry);
555 gtk_binding_entry_add_signall (GtkBindingSet *binding_set,
558 const gchar *signal_name,
559 GSList *binding_args)
561 GtkBindingEntry *entry;
562 GtkBindingSignal *signal, **signal_p;
567 g_return_if_fail (binding_set != NULL);
568 g_return_if_fail (signal_name != NULL);
570 keyval = gdk_keyval_to_lower (keyval);
571 modifiers = modifiers & BINDING_MOD_MASK ();
573 signal = binding_signal_new (signal_name, g_slist_length (binding_args));
576 for (slist = binding_args; slist; slist = slist->next)
578 GtkBindingArg *tmp_arg;
580 tmp_arg = slist->data;
583 g_warning ("gtk_binding_entry_add_signall(): arg[%u] is `NULL'", n);
584 binding_signal_free (signal);
587 switch (GTK_FUNDAMENTAL_TYPE (tmp_arg->arg_type))
590 arg->arg_type = GTK_TYPE_LONG;
591 arg->d.long_data = tmp_arg->d.long_data;
593 case GTK_TYPE_DOUBLE:
594 arg->arg_type = GTK_TYPE_DOUBLE;
595 arg->d.double_data = tmp_arg->d.double_data;
597 case GTK_TYPE_STRING:
598 if (tmp_arg->arg_type != GTK_TYPE_IDENTIFIER)
599 arg->arg_type = GTK_TYPE_STRING;
601 arg->arg_type = GTK_TYPE_IDENTIFIER;
602 arg->d.string_data = g_strdup (tmp_arg->d.string_data);
603 if (!arg->d.string_data)
605 g_warning ("gtk_binding_entry_add_signall(): value of `string' arg[%u] is `NULL'", n);
606 binding_signal_free (signal);
611 g_warning ("gtk_binding_entry_add_signall(): unsupported type `%s' for arg[%u]",
612 gtk_type_name (arg->arg_type), n);
613 binding_signal_free (signal);
620 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
623 gtk_binding_entry_add (binding_set, keyval, modifiers);
624 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
626 signal_p = &entry->signals;
628 signal_p = &(*signal_p)->next;
633 gtk_binding_entry_add_signal (GtkBindingSet *binding_set,
636 const gchar *signal_name,
640 GSList *slist, *free_slist;
644 g_return_if_fail (binding_set != NULL);
645 g_return_if_fail (signal_name != NULL);
647 keyval = gdk_keyval_to_lower (keyval);
648 modifiers = modifiers & BINDING_MOD_MASK ();
650 va_start (args, n_args);
652 for (i = 0; i < n_args; i++)
656 arg = g_new0 (GtkBindingArg, 1);
657 slist = g_slist_prepend (slist, arg);
659 arg->arg_type = va_arg (args, GtkType);
660 switch (GTK_FUNDAMENTAL_TYPE (arg->arg_type))
662 /* for elaborated commenting about var args collection, take a look
663 * at gtk_arg_collect_value() in gtkargcollector.c
672 arg->arg_type = GTK_TYPE_LONG;
673 arg->d.long_data = va_arg (args, gint);
677 arg->arg_type = GTK_TYPE_LONG;
678 arg->d.long_data = va_arg (args, glong);
681 case GTK_TYPE_DOUBLE:
682 arg->arg_type = GTK_TYPE_DOUBLE;
683 arg->d.double_data = va_arg (args, gdouble);
685 case GTK_TYPE_STRING:
686 if (arg->arg_type != GTK_TYPE_IDENTIFIER)
687 arg->arg_type = GTK_TYPE_STRING;
688 arg->d.string_data = va_arg (args, gchar*);
689 if (!arg->d.string_data)
691 g_warning ("gtk_binding_entry_add_signal(): type `%s' arg[%u] is `NULL'",
692 gtk_type_name (arg->arg_type),
698 g_warning ("gtk_binding_entry_add_signal(): unsupported type `%s' for arg[%u]",
699 gtk_type_name (arg->arg_type), i);
706 if (i == n_args || i == 0)
708 slist = g_slist_reverse (slist);
709 gtk_binding_entry_add_signall (binding_set, keyval, modifiers, signal_name, slist);
715 g_free (slist->data);
718 g_slist_free (free_slist);
722 gtk_binding_set_add_path (GtkBindingSet *binding_set,
723 GtkPathType path_type,
724 const gchar *path_pattern,
725 GtkPathPriorityType priority)
727 GtkPatternSpec *pspec;
728 GSList **slist_p, *slist;
729 static guint seq_id = 0;
731 g_return_if_fail (binding_set != NULL);
732 g_return_if_fail (path_pattern != NULL);
734 priority &= GTK_PATH_PRIO_MASK;
738 case GTK_PATH_WIDGET:
739 slist_p = &binding_set->widget_path_pspecs;
741 case GTK_PATH_WIDGET_CLASS:
742 slist_p = &binding_set->widget_class_pspecs;
745 slist_p = &binding_set->class_branch_pspecs;
748 g_assert_not_reached ();
753 pspec = g_new (GtkPatternSpec, 1);
754 gtk_pattern_spec_init (pspec, path_pattern);
755 pspec->seq_id = seq_id++ & 0x0fffffff;
756 pspec->seq_id |= priority << 28;
757 pspec->user_data = binding_set;
762 GtkPatternSpec *tmp_pspec;
764 tmp_pspec = slist->data;
767 if (tmp_pspec->pattern_length == pspec->pattern_length &&
768 g_str_equal (tmp_pspec->pattern_reversed, pspec->pattern_reversed))
770 gtk_pattern_spec_free_segs (pspec);
777 *slist_p = g_slist_prepend (*slist_p, pspec);
780 static inline gboolean
781 binding_match_activate (GSList *pspec_list,
785 gchar *path_reversed)
789 for (slist = pspec_list; slist; slist = slist->next)
791 GtkPatternSpec *pspec;
794 if (gtk_pattern_match (pspec, path_length, path, path_reversed))
796 GtkBindingSet *binding_set;
798 binding_set = pspec->user_data;
800 gtk_binding_entry_activate (binding_set->current, object);
810 gtk_binding_pattern_compare (gconstpointer new_pattern,
811 gconstpointer existing_pattern)
813 register const GtkPatternSpec *np = new_pattern;
814 register const GtkPatternSpec *ep = existing_pattern;
816 /* walk the list as long as the existing patterns have
820 return np->seq_id < ep->seq_id;
823 static inline GSList*
824 gtk_binding_entries_sort_patterns (GtkBindingEntry *entries,
832 register GtkBindingSet *binding_set;
833 GSList *slist = NULL;
835 binding_set = entries->binding_set;
836 binding_set->current = entries;
840 case GTK_PATH_WIDGET:
841 slist = binding_set->widget_path_pspecs;
843 case GTK_PATH_WIDGET_CLASS:
844 slist = binding_set->widget_class_pspecs;
847 slist = binding_set->class_branch_pspecs;
851 for (; slist; slist = slist->next)
853 GtkPatternSpec *pspec;
856 patterns = g_slist_insert_sorted (patterns, pspec, gtk_binding_pattern_compare);
859 entries = entries->hash_next;
867 gtk_bindings_activate (GtkObject *object,
871 GtkBindingEntry *entries;
873 gboolean handled = FALSE;
875 g_return_val_if_fail (object != NULL, FALSE);
876 g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
878 if (!GTK_IS_WIDGET (object) || GTK_OBJECT_DESTROYED (object))
881 widget = GTK_WIDGET (object);
883 keyval = gdk_keyval_to_lower (keyval);
884 modifiers = modifiers & BINDING_MOD_MASK ();
886 entries = binding_ht_lookup_list (keyval, modifiers);
894 gchar *path, *path_reversed;
897 gtk_widget_path (widget, &path_length, &path, &path_reversed);
898 patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET);
899 handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
900 g_slist_free (patterns);
902 g_free (path_reversed);
908 gchar *path, *path_reversed;
911 gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
912 patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET_CLASS);
913 handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
914 g_slist_free (patterns);
916 g_free (path_reversed);
924 patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_CLASS);
925 class_type = GTK_OBJECT_TYPE (object);
926 while (class_type && !handled)
929 gchar *path, *path_reversed;
931 path = gtk_type_name (class_type);
932 path_reversed = g_strdup (path);
933 g_strreverse (path_reversed);
934 path_length = strlen (path);
935 handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
936 g_free (path_reversed);
938 class_type = gtk_type_parent (class_type);
940 g_slist_free (patterns);
958 static inline gboolean
959 gtk_pattern_ph_match (const gchar *match_pattern,
960 const gchar *match_string)
962 register const gchar *pattern, *string;
965 pattern = match_pattern;
966 string = match_string;
992 while (ch == '*' || ch == '?');
997 while (ch != *string)
1004 if (gtk_pattern_ph_match (pattern, string))
1022 return *string == 0;
1026 gtk_pattern_match (GtkPatternSpec *pspec,
1027 guint string_length,
1028 const gchar *string,
1029 const gchar *string_reversed)
1031 g_return_val_if_fail (pspec != NULL, FALSE);
1032 g_return_val_if_fail (string != NULL, FALSE);
1033 g_return_val_if_fail (string_reversed != NULL, FALSE);
1035 switch (pspec->match_type)
1038 return gtk_pattern_ph_match (pspec->pattern, string);
1040 case GTK_MATCH_ALL_TAIL:
1041 return gtk_pattern_ph_match (pspec->pattern_reversed, string_reversed);
1043 case GTK_MATCH_HEAD:
1044 if (pspec->pattern_length > string_length)
1046 else if (pspec->pattern_length == string_length)
1047 return strcmp (pspec->pattern, string) == 0;
1048 else if (pspec->pattern_length)
1049 return strncmp (pspec->pattern, string, pspec->pattern_length) == 0;
1053 case GTK_MATCH_TAIL:
1054 if (pspec->pattern_length > string_length)
1056 else if (pspec->pattern_length == string_length)
1057 return strcmp (pspec->pattern_reversed, string_reversed) == 0;
1058 else if (pspec->pattern_length)
1059 return strncmp (pspec->pattern_reversed,
1061 pspec->pattern_length) == 0;
1065 case GTK_MATCH_EXACT:
1066 if (pspec->pattern_length != string_length)
1069 return strcmp (pspec->pattern_reversed, string_reversed) == 0;
1072 g_return_val_if_fail (pspec->match_type < GTK_MATCH_LAST, FALSE);
1078 gtk_pattern_spec_init (GtkPatternSpec *pspec,
1079 const gchar *pattern)
1083 g_return_if_fail (pspec != NULL);
1085 pspec->match_type = GTK_MATCH_ALL;
1087 pspec->user_data = NULL;
1092 pspec->pattern = g_strdup (pattern);
1093 pspec->pattern_length = strlen (pspec->pattern);
1094 pspec->pattern_reversed = g_strdup (pspec->pattern);
1095 g_strreverse (pspec->pattern_reversed);
1096 if (pspec->pattern_reversed[0] != '*')
1097 pspec->match_type = GTK_MATCH_ALL_TAIL;
1099 if (strchr (pspec->pattern, '?'))
1102 if (!strchr (pspec->pattern, '*'))
1104 pspec->match_type = GTK_MATCH_EXACT;
1111 if (p > pspec->pattern &&
1116 pspec->match_type = GTK_MATCH_TAIL;
1118 pspec->pattern = g_strdup (p);
1120 g_free (pspec->pattern_reversed);
1121 pspec->pattern_reversed = g_strdup (pspec->pattern);
1122 g_strreverse (pspec->pattern_reversed);
1123 pspec->pattern_length = strlen (pspec->pattern);
1127 p = pspec->pattern_reversed;
1130 if (p > pspec->pattern_reversed &&
1135 pspec->match_type = GTK_MATCH_HEAD;
1136 t = pspec->pattern_reversed;
1137 pspec->pattern_reversed = g_strdup (p);
1139 pspec->pattern = g_strdup (pspec->pattern_reversed);
1140 g_strreverse (pspec->pattern);
1141 pspec->pattern_length = strlen (pspec->pattern);
1146 gtk_pattern_match_string (GtkPatternSpec *pspec,
1147 const gchar *string)
1149 gchar *string_reversed;
1153 g_return_val_if_fail (pspec != NULL, FALSE);
1154 g_return_val_if_fail (string != NULL, FALSE);
1156 length = strlen (string);
1157 string_reversed = g_strdup (string);
1158 g_strreverse (string_reversed);
1160 ergo = gtk_pattern_match (pspec, length, string, string_reversed);
1161 g_free (string_reversed);
1167 gtk_pattern_match_simple (const gchar *pattern,
1168 const gchar *string)
1170 GtkPatternSpec pspec;
1173 g_return_val_if_fail (pattern != NULL, FALSE);
1174 g_return_val_if_fail (string != NULL, FALSE);
1176 gtk_pattern_spec_init (&pspec, pattern);
1177 ergo = gtk_pattern_match_string (&pspec, string);
1178 gtk_pattern_spec_free_segs (&pspec);
1184 gtk_pattern_spec_free_segs (GtkPatternSpec *pspec)
1186 g_return_if_fail (pspec != NULL);
1188 g_free (pspec->pattern);
1189 pspec->pattern = NULL;
1190 g_free (pspec->pattern_reversed);
1191 pspec->pattern_reversed = NULL;
1195 gtk_binding_parse_signal (GScanner *scanner,
1196 GtkBindingSet *binding_set,
1201 guint expected_token = 0;
1207 gboolean seen_comma;
1209 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1211 g_scanner_get_next_token (scanner);
1212 if (scanner->token != G_TOKEN_STRING)
1213 return G_TOKEN_STRING;
1214 g_scanner_peek_next_token (scanner);
1215 if (scanner->next_token != '(')
1217 g_scanner_get_next_token (scanner);
1220 signal = g_strdup (scanner->value.v_string);
1221 g_scanner_get_next_token (scanner);
1228 scanner->config->scan_symbols = FALSE;
1232 expected_token = G_TOKEN_INT;
1234 expected_token = ')';
1235 g_scanner_get_next_token (scanner);
1236 switch (scanner->token)
1244 arg = g_new (GtkBindingArg, 1);
1245 arg->arg_type = GTK_TYPE_DOUBLE;
1246 arg->d.double_data = scanner->value.v_float;
1249 arg->d.double_data = - arg->d.double_data;
1252 args = g_slist_prepend (args, arg);
1261 arg = g_new (GtkBindingArg, 1);
1262 arg->arg_type = GTK_TYPE_LONG;
1263 arg->d.long_data = scanner->value.v_int;
1266 arg->d.long_data = - arg->d.long_data;
1269 args = g_slist_prepend (args, arg);
1274 case G_TOKEN_STRING:
1275 if (need_arg && !negate)
1278 arg = g_new (GtkBindingArg, 1);
1279 arg->arg_type = GTK_TYPE_STRING;
1280 arg->d.string_data = g_strdup (scanner->value.v_string);
1281 args = g_slist_prepend (args, arg);
1286 case G_TOKEN_IDENTIFIER:
1287 if (need_arg && !negate)
1290 arg = g_new (GtkBindingArg, 1);
1291 arg->arg_type = GTK_TYPE_IDENTIFIER;
1292 arg->d.string_data = g_strdup (scanner->value.v_identifier);
1293 args = g_slist_prepend (args, arg);
1303 expected_token = G_TOKEN_INT;
1317 if (!(need_arg && seen_comma) && !negate)
1319 args = g_slist_reverse (args);
1320 gtk_binding_entry_add_signall (binding_set,
1325 expected_token = G_TOKEN_NONE;
1335 scanner->config->scan_symbols = TRUE;
1337 for (slist = args; slist; slist = slist->next)
1342 if (GTK_FUNDAMENTAL_TYPE (arg->arg_type) == GTK_TYPE_STRING)
1343 g_free (arg->d.string_data);
1346 g_slist_free (args);
1349 return expected_token;
1353 gtk_binding_parse_bind (GScanner *scanner,
1354 GtkBindingSet *binding_set)
1357 guint modifiers = 0;
1359 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1361 g_scanner_get_next_token (scanner);
1362 if (scanner->token != GTK_RC_TOKEN_BIND)
1363 return GTK_RC_TOKEN_BIND;
1364 g_scanner_get_next_token (scanner);
1365 if (scanner->token != G_TOKEN_STRING)
1366 return G_TOKEN_STRING;
1367 gtk_accelerator_parse (scanner->value.v_string, &keyval, &modifiers);
1368 modifiers &= BINDING_MOD_MASK ();
1370 return G_TOKEN_STRING;
1372 g_scanner_get_next_token (scanner);
1373 if (scanner->token != '{')
1376 gtk_binding_entry_clear (binding_set, keyval, modifiers);
1378 g_scanner_peek_next_token (scanner);
1379 while (scanner->next_token != '}')
1381 switch (scanner->next_token)
1383 guint expected_token;
1385 case G_TOKEN_STRING:
1386 expected_token = gtk_binding_parse_signal (scanner,
1390 if (expected_token != G_TOKEN_NONE)
1391 return expected_token;
1394 g_scanner_get_next_token (scanner);
1397 g_scanner_peek_next_token (scanner);
1399 g_scanner_get_next_token (scanner);
1401 return G_TOKEN_NONE;
1405 gtk_binding_parse_binding (GScanner *scanner)
1408 GtkBindingSet *binding_set;
1410 g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1412 g_scanner_get_next_token (scanner);
1413 if (scanner->token != GTK_RC_TOKEN_BINDING)
1414 return GTK_RC_TOKEN_BINDING;
1415 g_scanner_get_next_token (scanner);
1416 if (scanner->token != G_TOKEN_STRING)
1417 return G_TOKEN_STRING;
1418 name = g_strdup (scanner->value.v_string);
1420 g_scanner_get_next_token (scanner);
1421 if (scanner->token != '{')
1424 return G_TOKEN_STRING;
1427 binding_set = gtk_binding_set_find (name);
1429 binding_set = gtk_binding_set_new (name);
1432 g_scanner_peek_next_token (scanner);
1433 while (scanner->next_token != '}')
1435 switch (scanner->next_token)
1437 guint expected_token;
1439 case GTK_RC_TOKEN_BIND:
1440 expected_token = gtk_binding_parse_bind (scanner, binding_set);
1441 if (expected_token != G_TOKEN_NONE)
1442 return expected_token;
1445 g_scanner_get_next_token (scanner);
1448 g_scanner_peek_next_token (scanner);
1450 g_scanner_get_next_token (scanner);
1452 return G_TOKEN_NONE;