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.
25 #include "gtkbindings.h"
26 #include "gtksignal.h"
27 #include "gtkwidget.h"
31 #define BINDING_MOD_MASK() (gtk_accelerator_get_default_mod_mask () | GDK_RELEASE_MASK)
33 #define BINDING_TYPE_INT (GTK_TYPE_INT)
34 #define BINDING_TYPE_LONG (GTK_TYPE_LONG)
35 #define BINDING_TYPE_FLOAT (GTK_TYPE_FLOAT)
36 #define BINDING_TYPE_DOUBLE (GTK_TYPE_DOUBLE)
37 #define BINDING_TYPE_STRING (GTK_TYPE_STRING)
38 #define BINDING_TYPE_IDENTIFIER (42)
41 /* --- variables --- */
42 static GHashTable *binding_entry_hash_table = NULL;
43 static GSList *binding_set_list = NULL;
44 static const gchar *key_class_binding_set = "gtk-class-binding-set";
45 static GQuark key_id_class_binding_set = 0;
48 /* --- functions --- */
49 static GtkBindingSignal*
50 binding_signal_new (const gchar *signal_name,
53 GtkBindingSignal *signal;
55 signal = g_new (GtkBindingSignal, 1);
57 signal->signal_name = g_strdup (signal_name);
58 signal->n_args = n_args;
59 signal->args = g_new0 (GtkBindingArg, n_args);
65 binding_signal_free (GtkBindingSignal *sig)
69 for (i = 0; i < sig->n_args; i++)
71 if (sig->args[i].arg_type == BINDING_TYPE_STRING ||
72 sig->args[i].arg_type == BINDING_TYPE_IDENTIFIER)
73 g_free (sig->args[i].d.string_data);
76 g_free (sig->signal_name);
81 binding_entry_hash (gconstpointer key)
83 register const GtkBindingEntry *e = key;
93 binding_entries_compare (gconstpointer a,
96 register const GtkBindingEntry *ea = a;
97 register const GtkBindingEntry *eb = b;
99 return (ea->keyval == eb->keyval && ea->modifiers == eb->modifiers);
102 static GtkBindingEntry*
103 binding_entry_new (GtkBindingSet *binding_set,
107 GtkBindingEntry *entry;
109 if (!binding_entry_hash_table)
110 binding_entry_hash_table = g_hash_table_new (binding_entry_hash, binding_entries_compare);
112 entry = g_new (GtkBindingEntry, 1);
113 entry->keyval = keyval;
114 entry->modifiers = modifiers;
115 entry->binding_set = binding_set,
116 entry->destroyed = FALSE;
117 entry->in_emission = FALSE;
118 entry->signals = NULL;
120 entry->set_next = binding_set->entries;
121 binding_set->entries = entry;
123 entry->hash_next = g_hash_table_lookup (binding_entry_hash_table, entry);
124 g_hash_table_freeze (binding_entry_hash_table);
125 if (entry->hash_next)
126 g_hash_table_remove (binding_entry_hash_table, entry->hash_next);
127 g_hash_table_insert (binding_entry_hash_table, entry, entry);
128 g_hash_table_thaw (binding_entry_hash_table);
134 binding_entry_free (GtkBindingEntry *entry)
136 GtkBindingSignal *sig;
138 g_assert (entry->set_next == NULL &&
139 entry->hash_next == NULL &&
140 entry->in_emission == FALSE &&
141 entry->destroyed == TRUE);
143 entry->destroyed = FALSE;
145 sig = entry->signals;
148 GtkBindingSignal *prev;
152 binding_signal_free (prev);
158 binding_entry_destroy (GtkBindingEntry *entry)
160 GtkBindingEntry *o_entry;
161 register GtkBindingEntry *tmp;
162 GtkBindingEntry *begin;
163 register GtkBindingEntry *last;
165 /* unlink from binding set
168 tmp = entry->binding_set->entries;
174 last->set_next = entry->set_next;
176 entry->binding_set->entries = entry->set_next;
180 tmp = last->set_next;
182 entry->set_next = NULL;
184 o_entry = g_hash_table_lookup (binding_entry_hash_table, entry);
193 last->hash_next = entry->hash_next;
195 begin = entry->hash_next;
199 tmp = last->hash_next;
201 entry->hash_next = NULL;
204 g_hash_table_remove (binding_entry_hash_table, entry);
205 else if (begin != o_entry)
207 g_hash_table_freeze (binding_entry_hash_table);
208 g_hash_table_remove (binding_entry_hash_table, entry);
209 g_hash_table_insert (binding_entry_hash_table, begin, begin);
210 g_hash_table_thaw (binding_entry_hash_table);
213 entry->destroyed = TRUE;
215 if (!entry->in_emission)
216 binding_entry_free (entry);
219 static GtkBindingEntry*
220 binding_ht_lookup_list (guint keyval,
223 GtkBindingEntry lookup_entry = { 0 };
225 if (!binding_entry_hash_table)
228 lookup_entry.keyval = keyval;
229 lookup_entry.modifiers = modifiers;
231 return g_hash_table_lookup (binding_entry_hash_table, &lookup_entry);
234 static GtkBindingEntry*
235 binding_ht_lookup_entry (GtkBindingSet *set,
239 GtkBindingEntry lookup_entry = { 0 };
240 GtkBindingEntry *entry;
242 if (!binding_entry_hash_table)
245 lookup_entry.keyval = keyval;
246 lookup_entry.modifiers = modifiers;
248 entry = g_hash_table_lookup (binding_entry_hash_table, &lookup_entry);
249 for (; entry; entry = entry->hash_next)
250 if (entry->binding_set == set)
257 binding_compose_params (GtkBindingArg *args,
258 GtkSignalQuery *query,
262 const GtkType *types;
266 params = g_new0 (GtkArg, query->nparams);
269 types = query->params;
271 for (i = 0; i < query->nparams && valid; i++)
273 params->type = *types;
275 switch (args->arg_type)
277 case BINDING_TYPE_DOUBLE:
278 if (params->type == GTK_TYPE_FLOAT)
279 GTK_VALUE_FLOAT (*params) = args->d.double_data;
280 else if (params->type == GTK_TYPE_DOUBLE)
281 GTK_VALUE_DOUBLE (*params) = args->d.double_data;
285 case BINDING_TYPE_LONG:
286 if (params->type == GTK_TYPE_BOOL &&
287 (args->d.long_data == 0 ||
288 args->d.long_data == 1))
289 GTK_VALUE_BOOL (*params) = args->d.long_data;
290 else if (params->type == GTK_TYPE_INT)
291 GTK_VALUE_INT (*params) = args->d.long_data;
292 else if (params->type == GTK_TYPE_UINT &&
293 args->d.long_data >= 0)
294 GTK_VALUE_UINT (*params) = args->d.long_data;
295 else if (params->type == GTK_TYPE_LONG)
296 GTK_VALUE_LONG (*params) = args->d.long_data;
297 else if (params->type == GTK_TYPE_ULONG &&
298 args->d.long_data >= 0)
299 GTK_VALUE_ULONG (*params) = args->d.long_data;
300 else if (params->type == GTK_TYPE_FLOAT)
301 GTK_VALUE_FLOAT (*params) = args->d.long_data;
302 else if (params->type == GTK_TYPE_DOUBLE)
303 GTK_VALUE_DOUBLE (*params) = args->d.long_data;
307 case BINDING_TYPE_STRING:
308 if (params->type == GTK_TYPE_STRING)
309 GTK_VALUE_STRING (*params) = args->d.string_data;
313 case BINDING_TYPE_IDENTIFIER:
333 gtk_binding_entry_activate (GtkBindingEntry *entry,
336 GtkBindingSignal *sig;
337 gboolean old_emission;
339 old_emission = entry->in_emission;
340 entry->in_emission = TRUE;
342 gtk_object_ref (object);
344 for (sig = entry->signals; sig; sig = sig->next)
346 GtkSignalQuery *query;
348 GtkArg *params = NULL;
349 gchar *accelerator = NULL;
351 signal_id = gtk_signal_lookup (sig->signal_name, GTK_OBJECT_TYPE (object));
354 accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
355 g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
356 "could not find signal \"%s\" in the `%s' class ancestry",
357 entry->binding_set->set_name,
360 gtk_type_name (GTK_OBJECT_TYPE (object)));
361 g_free (accelerator);
365 query = gtk_signal_query (signal_id);
366 if (query->nparams != sig->n_args ||
367 query->return_val != GTK_TYPE_NONE ||
368 !binding_compose_params (sig->args, query, ¶ms))
370 accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
371 g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
372 "signature mismatch for signal \"%s\" in the `%s' class ancestry",
373 entry->binding_set->set_name,
376 gtk_type_name (GTK_OBJECT_TYPE (object)));
378 else if (!(query->signal_flags & GTK_RUN_ACTION))
380 accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
381 g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
382 "signal \"%s\" in the `%s' class ancestry cannot be used for action emissions",
383 entry->binding_set->set_name,
386 gtk_type_name (GTK_OBJECT_TYPE (object)));
388 g_free (accelerator);
393 gtk_signal_emitv (object, signal_id, params);
396 if (GTK_OBJECT_DESTROYED (object) || entry->destroyed)
400 gtk_object_unref (object);
402 entry->in_emission = old_emission;
403 if (entry->destroyed && !entry->in_emission)
404 binding_entry_free (entry);
408 gtk_binding_set_new (const gchar *set_name)
410 GtkBindingSet *binding_set;
412 g_return_val_if_fail (set_name != NULL, NULL);
414 binding_set = g_new (GtkBindingSet, 1);
415 binding_set->set_name = g_strdup (set_name);
416 binding_set->widget_path_pspecs = NULL;
417 binding_set->widget_class_pspecs = NULL;
418 binding_set->class_branch_pspecs = NULL;
419 binding_set->entries = NULL;
420 binding_set->current = NULL;
422 binding_set_list = g_slist_prepend (NULL, binding_set);
428 gtk_binding_set_by_class (gpointer object_class)
430 GtkObjectClass *class = object_class;
431 GtkBindingSet* binding_set;
433 g_return_val_if_fail (GTK_IS_OBJECT_CLASS (class), NULL);
435 if (!key_id_class_binding_set)
436 key_id_class_binding_set = g_quark_from_static_string (key_class_binding_set);
438 binding_set = g_dataset_id_get_data (class, key_id_class_binding_set);
443 binding_set = gtk_binding_set_new (gtk_type_name (class->type));
444 gtk_binding_set_add_path (binding_set,
446 gtk_type_name (class->type),
448 g_dataset_id_set_data (class, key_id_class_binding_set, binding_set);
454 gtk_binding_set_find (const gchar *set_name)
458 g_return_val_if_fail (set_name != NULL, NULL);
460 for (slist = binding_set_list; slist; slist = slist->next)
462 GtkBindingSet *binding_set;
464 binding_set = slist->data;
465 if (g_str_equal (binding_set->set_name, (gpointer) set_name))
472 gtk_binding_set_activate (GtkBindingSet *binding_set,
477 GtkBindingEntry *entry;
479 g_return_val_if_fail (binding_set != NULL, FALSE);
480 g_return_val_if_fail (object != NULL, FALSE);
481 g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
483 keyval = gdk_keyval_to_lower (keyval);
484 modifiers = modifiers & BINDING_MOD_MASK ();
486 if (!GTK_OBJECT_DESTROYED (object))
488 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
491 gtk_binding_entry_activate (entry, object);
501 gtk_binding_entry_clear (GtkBindingSet *binding_set,
505 GtkBindingEntry *entry;
507 g_return_if_fail (binding_set != NULL);
509 keyval = gdk_keyval_to_lower (keyval);
510 modifiers = modifiers & BINDING_MOD_MASK ();
512 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
514 binding_entry_destroy (entry);
516 entry = binding_entry_new (binding_set, keyval, modifiers);
520 gtk_binding_entry_remove (GtkBindingSet *binding_set,
524 GtkBindingEntry *entry;
526 g_return_if_fail (binding_set != NULL);
528 keyval = gdk_keyval_to_lower (keyval);
529 modifiers = modifiers & BINDING_MOD_MASK ();
531 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
533 binding_entry_destroy (entry);
537 gtk_binding_entry_add_signall (GtkBindingSet *binding_set,
540 const gchar *signal_name,
541 GSList *binding_args)
543 GtkBindingEntry *entry;
544 GtkBindingSignal *signal, **signal_p;
549 g_return_if_fail (binding_set != NULL);
550 g_return_if_fail (signal_name != NULL);
552 keyval = gdk_keyval_to_lower (keyval);
553 modifiers = modifiers & BINDING_MOD_MASK ();
555 signal = binding_signal_new (signal_name, g_slist_length (binding_args));
558 for (slist = binding_args; slist; slist = slist->next)
560 GtkBindingArg *tmp_arg;
562 tmp_arg = slist->data;
565 g_warning ("gtk_binding_entry_add_signall(): arg[%u] is `NULL'", n);
566 binding_signal_free (signal);
569 arg->arg_type = tmp_arg->arg_type;
570 switch (tmp_arg->arg_type)
572 case BINDING_TYPE_INT:
573 case BINDING_TYPE_LONG:
574 arg->d.long_data = tmp_arg->d.long_data;
576 case BINDING_TYPE_FLOAT:
577 case BINDING_TYPE_DOUBLE:
578 arg->d.double_data = tmp_arg->d.double_data;
580 case BINDING_TYPE_STRING:
581 if (!tmp_arg->d.string_data)
583 g_warning ("gtk_binding_entry_add_signall(): value of `string' arg[%u] is `NULL'", n);
584 arg->d.string_data = NULL;
585 binding_signal_free (signal);
588 arg->d.string_data = g_strdup (tmp_arg->d.string_data);
591 g_warning ("gtk_binding_entry_add_signall(): unsupported type `%s' for arg[%u]",
592 gtk_type_name (arg->arg_type), n);
593 binding_signal_free (signal);
600 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
603 gtk_binding_entry_add (binding_set, keyval, modifiers);
604 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
606 signal_p = &entry->signals;
608 signal_p = &(*signal_p)->next;
613 gtk_binding_entry_add_signal (GtkBindingSet *binding_set,
616 const gchar *signal_name,
620 GSList *slist, *free_slist;
624 g_return_if_fail (binding_set != NULL);
625 g_return_if_fail (signal_name != NULL);
627 keyval = gdk_keyval_to_lower (keyval);
628 modifiers = modifiers & BINDING_MOD_MASK ();
630 va_start (args, n_args);
632 for (i = 0; i < n_args; i++)
636 arg = g_new0 (GtkBindingArg, 1);
637 slist = g_slist_prepend (slist, arg);
639 arg->arg_type = va_arg (args, GtkType);
640 switch (arg->arg_type)
642 case BINDING_TYPE_INT:
643 arg->d.long_data = va_arg (args, gint);
645 case BINDING_TYPE_LONG:
646 arg->d.long_data = va_arg (args, glong);
648 case BINDING_TYPE_FLOAT:
649 arg->d.double_data = va_arg (args, gfloat);
651 case BINDING_TYPE_DOUBLE:
652 arg->d.double_data = va_arg (args, gdouble);
654 case BINDING_TYPE_STRING:
655 arg->d.string_data = va_arg (args, gchar*);
656 if (!arg->d.string_data)
658 g_warning ("gtk_binding_entry_add_signal(): value of `string' arg[%u] is `NULL'", i);
663 g_warning ("gtk_binding_entry_add_signal(): unsupported type `%s' for arg[%u]",
664 gtk_type_name (arg->arg_type), i);
671 if (i == n_args || i == 0)
673 slist = g_slist_reverse (slist);
674 gtk_binding_entry_add_signall (binding_set, keyval, modifiers, signal_name, slist);
680 g_free (slist->data);
683 g_slist_free (free_slist);
687 gtk_binding_set_add_path (GtkBindingSet *binding_set,
688 GtkPathType path_type,
689 const gchar *path_pattern,
690 GtkPathPriorityType priority)
692 GtkPatternSpec *pspec;
693 GSList **slist_p, *slist;
694 static guint seq_id = 0;
696 g_return_if_fail (binding_set != NULL);
697 g_return_if_fail (path_pattern != NULL);
699 priority &= GTK_PATH_PRIO_MASK;
703 case GTK_PATH_WIDGET:
704 slist_p = &binding_set->widget_path_pspecs;
706 case GTK_PATH_WIDGET_CLASS:
707 slist_p = &binding_set->widget_class_pspecs;
710 slist_p = &binding_set->class_branch_pspecs;
713 g_assert_not_reached ();
718 pspec = g_new (GtkPatternSpec, 1);
719 gtk_pattern_spec_init (pspec, path_pattern);
720 pspec->seq_id = seq_id++ & 0x0fffffff;
721 pspec->seq_id |= priority << 28;
722 pspec->user_data = binding_set;
727 GtkPatternSpec *tmp_pspec;
729 tmp_pspec = slist->data;
732 if (tmp_pspec->pattern_length == pspec->pattern_length &&
733 g_str_equal (tmp_pspec->pattern_reversed, pspec->pattern_reversed))
735 gtk_pattern_spec_free_segs (pspec);
741 *slist_p = g_slist_prepend (*slist_p, pspec);
744 static inline gboolean
745 binding_match_activate (GSList *pspec_list,
749 gchar *path_reversed)
753 for (slist = pspec_list; slist; slist = slist->next)
755 GtkPatternSpec *pspec;
758 if (gtk_pattern_match (pspec, path_length, path, path_reversed))
760 GtkBindingSet *binding_set;
762 binding_set = pspec->user_data;
764 gtk_binding_entry_activate (binding_set->current, object);
774 gtk_binding_pattern_compare (gconstpointer a,
777 register const GtkPatternSpec *pa = a;
778 register const GtkPatternSpec *pb = b;
780 return pa->seq_id < pb->seq_id ? -1 : 1;
783 static inline GSList*
784 gtk_binding_entries_sort_patterns (GtkBindingEntry *entries,
792 register GtkBindingSet *binding_set;
793 GSList *slist = NULL;
795 binding_set = entries->binding_set;
796 binding_set->current = entries;
800 case GTK_PATH_WIDGET:
801 slist = binding_set->widget_path_pspecs;
803 case GTK_PATH_WIDGET_CLASS:
804 slist = binding_set->widget_class_pspecs;
807 slist = binding_set->class_branch_pspecs;
811 for (; slist; slist = slist->next)
813 GtkPatternSpec *pspec;
816 patterns = g_slist_insert_sorted (patterns, pspec, gtk_binding_pattern_compare);
819 entries = entries->hash_next;
827 gtk_bindings_activate (GtkObject *object,
831 GtkBindingEntry *entries;
833 gboolean handled = FALSE;
835 g_return_val_if_fail (object != NULL, FALSE);
836 g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
838 if (!GTK_IS_WIDGET (object) || GTK_OBJECT_DESTROYED (object))
841 widget = GTK_WIDGET (object);
843 keyval = gdk_keyval_to_lower (keyval);
844 modifiers = modifiers & BINDING_MOD_MASK ();
846 entries = binding_ht_lookup_list (keyval, modifiers);
854 gchar *path, *path_reversed;
857 gtk_widget_path (widget, &path_length, &path, &path_reversed);
858 patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET);
859 handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
860 g_slist_free (patterns);
862 g_free (path_reversed);
868 gchar *path, *path_reversed;
871 gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
872 patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET_CLASS);
873 handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
874 g_slist_free (patterns);
876 g_free (path_reversed);
884 patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_CLASS);
885 class_type = GTK_OBJECT_TYPE (object);
886 while (class_type && !handled)
889 gchar *path, *path_reversed;
891 path = gtk_type_name (class_type);
892 path_reversed = g_strdup (path);
893 g_strreverse (path_reversed);
894 path_length = strlen (path);
895 handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
896 g_free (path_reversed);
898 class_type = gtk_type_parent (class_type);
900 g_slist_free (patterns);
918 static inline gboolean
919 gtk_pattern_ph_match (const gchar *match_pattern,
920 const gchar *match_string)
922 register const gchar *pattern, *string;
925 pattern = match_pattern;
926 string = match_string;
952 while (ch == '*' || ch == '?');
957 while (ch != *string)
964 if (gtk_pattern_ph_match (pattern, string))
986 gtk_pattern_match (GtkPatternSpec *pspec,
989 const gchar *string_reversed)
991 g_return_val_if_fail (pspec != NULL, FALSE);
992 g_return_val_if_fail (string != NULL, FALSE);
993 g_return_val_if_fail (string_reversed != NULL, FALSE);
995 switch (pspec->match_type)
998 return gtk_pattern_ph_match (pspec->pattern, string);
1000 case GTK_MATCH_ALL_TAIL:
1001 return gtk_pattern_ph_match (pspec->pattern_reversed, string_reversed);
1003 case GTK_MATCH_HEAD:
1004 if (pspec->pattern_length > string_length)
1006 else if (pspec->pattern_length == string_length)
1007 return strcmp (pspec->pattern, string) == 0;
1008 else if (pspec->pattern_length)
1009 return strncmp (pspec->pattern, string, pspec->pattern_length) == 0;
1013 case GTK_MATCH_TAIL:
1014 if (pspec->pattern_length > string_length)
1016 else if (pspec->pattern_length == string_length)
1017 return strcmp (pspec->pattern_reversed, string_reversed) == 0;
1018 else if (pspec->pattern_length)
1019 return strncmp (pspec->pattern_reversed,
1021 pspec->pattern_length) == 0;
1025 case GTK_MATCH_EXACT:
1026 if (pspec->pattern_length != string_length)
1029 return strcmp (pspec->pattern_reversed, string_reversed) == 0;
1032 g_return_val_if_fail (pspec->match_type < GTK_MATCH_LAST, FALSE);
1038 gtk_pattern_spec_init (GtkPatternSpec *pspec,
1039 const gchar *pattern)
1043 g_return_if_fail (pspec != NULL);
1045 pspec->match_type = GTK_MATCH_ALL;
1047 pspec->user_data = NULL;
1052 pspec->pattern = g_strdup (pattern);
1053 pspec->pattern_length = strlen (pspec->pattern);
1054 pspec->pattern_reversed = g_strdup (pspec->pattern);
1055 g_strreverse (pspec->pattern_reversed);
1056 if (pspec->pattern_reversed[0] != '*')
1057 pspec->match_type = GTK_MATCH_ALL_TAIL;
1059 if (strchr (pspec->pattern, '?'))
1062 if (!strchr (pspec->pattern, '*'))
1064 pspec->match_type = GTK_MATCH_EXACT;
1071 if (p > pspec->pattern &&
1076 pspec->match_type = GTK_MATCH_TAIL;
1078 pspec->pattern = g_strdup (p);
1080 g_free (pspec->pattern_reversed);
1081 pspec->pattern_reversed = g_strdup (pspec->pattern);
1082 g_strreverse (pspec->pattern_reversed);
1083 pspec->pattern_length = strlen (pspec->pattern);
1087 p = pspec->pattern_reversed;
1090 if (p > pspec->pattern_reversed &&
1095 pspec->match_type = GTK_MATCH_HEAD;
1096 t = pspec->pattern_reversed;
1097 pspec->pattern_reversed = g_strdup (p);
1099 pspec->pattern = g_strdup (pspec->pattern_reversed);
1100 g_strreverse (pspec->pattern);
1101 pspec->pattern_length = strlen (pspec->pattern);
1106 gtk_pattern_match_string (GtkPatternSpec *pspec,
1107 const gchar *string)
1109 gchar *string_reversed;
1113 g_return_val_if_fail (pspec != NULL, FALSE);
1114 g_return_val_if_fail (string != NULL, FALSE);
1116 length = strlen (string);
1117 string_reversed = g_strdup (string);
1118 g_strreverse (string_reversed);
1120 ergo = gtk_pattern_match (pspec, length, string, string_reversed);
1121 g_free (string_reversed);
1127 gtk_pattern_match_simple (const gchar *pattern,
1128 const gchar *string)
1130 GtkPatternSpec pspec;
1133 g_return_val_if_fail (pattern != NULL, FALSE);
1134 g_return_val_if_fail (string != NULL, FALSE);
1136 gtk_pattern_spec_init (&pspec, pattern);
1137 ergo = gtk_pattern_match_string (&pspec, string);
1138 gtk_pattern_spec_free_segs (&pspec);
1144 gtk_pattern_spec_free_segs (GtkPatternSpec *pspec)
1146 g_return_if_fail (pspec != NULL);
1148 g_free (pspec->pattern);
1149 pspec->pattern = NULL;
1150 g_free (pspec->pattern_reversed);
1151 pspec->pattern_reversed = NULL;