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 ())
34 /* --- variables --- */
35 static GHashTable *binding_entry_hash_table = NULL;
36 static GSList *binding_set_list = NULL;
37 static const gchar *key_class_binding_set = "gtk-class-binding-set";
38 static guint key_id_class_binding_set = 0;
41 /* --- functions --- */
42 static GtkBindingSignal*
43 binding_signal_new (const gchar *signal_name,
46 GtkBindingSignal *signal;
48 signal = g_new (GtkBindingSignal, 1);
50 signal->signal_name = g_strdup (signal_name);
51 signal->n_args = n_args;
52 signal->args = g_new0 (GtkBindingArg, n_args);
58 binding_signal_free (GtkBindingSignal *sig)
62 for (i = 0; i < sig->n_args; i++)
64 if (sig->args[i].arg_type == GTK_BINDING_ARG_STRING)
65 g_free (sig->args[i].d.string_data);
68 g_free (sig->signal_name);
73 binding_entry_hash (g_const_pointer key)
75 register const GtkBindingEntry *e = key;
85 binding_entries_compare (g_const_pointer a,
88 register const GtkBindingEntry *ea = a;
89 register const GtkBindingEntry *eb = b;
91 return (ea->keyval == eb->keyval && ea->modifiers == eb->modifiers);
94 static GtkBindingEntry*
95 binding_entry_new (GtkBindingSet *binding_set,
99 GtkBindingEntry *entry;
101 if (!binding_entry_hash_table)
102 binding_entry_hash_table = g_hash_table_new (binding_entry_hash, binding_entries_compare);
104 entry = g_new (GtkBindingEntry, 1);
105 entry->keyval = keyval;
106 entry->modifiers = modifiers;
107 entry->binding_set = binding_set,
108 entry->destroyed = FALSE;
109 entry->in_emission = FALSE;
110 entry->signals = NULL;
112 entry->set_next = binding_set->entries;
113 binding_set->entries = entry;
115 entry->hash_next = g_hash_table_lookup (binding_entry_hash_table, entry);
116 g_hash_table_freeze (binding_entry_hash_table);
117 if (entry->hash_next)
118 g_hash_table_remove (binding_entry_hash_table, entry->hash_next);
119 g_hash_table_insert (binding_entry_hash_table, entry, entry);
120 g_hash_table_thaw (binding_entry_hash_table);
126 binding_entry_free (GtkBindingEntry *entry)
128 GtkBindingSignal *sig;
130 g_assert (entry->set_next == NULL &&
131 entry->hash_next == NULL &&
132 entry->in_emission == FALSE &&
133 entry->destroyed == TRUE);
135 entry->destroyed = FALSE;
137 sig = entry->signals;
140 GtkBindingSignal *prev;
144 binding_signal_free (prev);
150 binding_entry_destroy (GtkBindingEntry *entry)
152 GtkBindingEntry *o_entry;
153 register GtkBindingEntry *tmp;
154 GtkBindingEntry *begin;
155 register GtkBindingEntry *last;
157 /* unlink from binding set
160 tmp = entry->binding_set->entries;
166 last->set_next = entry->set_next;
168 entry->binding_set->entries = entry->set_next;
172 tmp = last->set_next;
174 entry->set_next = NULL;
176 o_entry = g_hash_table_lookup (binding_entry_hash_table, entry);
185 last->hash_next = entry->hash_next;
187 begin = entry->hash_next;
191 tmp = last->hash_next;
193 entry->hash_next = NULL;
196 g_hash_table_remove (binding_entry_hash_table, entry);
197 else if (begin != o_entry)
199 g_hash_table_freeze (binding_entry_hash_table);
200 g_hash_table_remove (binding_entry_hash_table, entry);
201 g_hash_table_insert (binding_entry_hash_table, begin, begin);
202 g_hash_table_thaw (binding_entry_hash_table);
205 entry->destroyed = TRUE;
207 if (!entry->in_emission)
208 binding_entry_free (entry);
211 static GtkBindingEntry*
212 binding_ht_lookup_list (guint keyval,
215 GtkBindingEntry lookup_entry = { 0 };
217 if (!binding_entry_hash_table)
220 lookup_entry.keyval = keyval;
221 lookup_entry.modifiers = modifiers;
223 return g_hash_table_lookup (binding_entry_hash_table, &lookup_entry);
226 static GtkBindingEntry*
227 binding_ht_lookup_entry (GtkBindingSet *set,
231 GtkBindingEntry lookup_entry = { 0 };
232 GtkBindingEntry *entry;
234 if (!binding_entry_hash_table)
237 lookup_entry.keyval = keyval;
238 lookup_entry.modifiers = modifiers;
240 entry = g_hash_table_lookup (binding_entry_hash_table, &lookup_entry);
241 for (; entry; entry = entry->hash_next)
242 if (entry->binding_set == set)
249 binding_compose_params (GtkBindingArg *args,
250 GtkSignalQuery *query,
254 const GtkType *types;
258 params = g_new0 (GtkArg, query->nparams);
261 types = query->params;
263 for (i = 0; i < query->nparams && valid; i++)
265 params->type = *types;
267 switch (args->arg_type)
269 case GTK_BINDING_ARG_STRING:
270 if (params->type == GTK_TYPE_STRING)
271 GTK_VALUE_STRING (*params) = args->d.string_data;
275 case GTK_BINDING_ARG_DOUBLE:
276 if (params->type == GTK_TYPE_FLOAT)
277 GTK_VALUE_FLOAT (*params) = args->d.double_data;
278 else if (params->type == GTK_TYPE_DOUBLE)
279 GTK_VALUE_DOUBLE (*params) = args->d.double_data;
283 case GTK_BINDING_ARG_LONG:
284 if (params->type == GTK_TYPE_BOOL &&
285 (args->d.long_data == 0 ||
286 args->d.long_data == 1))
287 GTK_VALUE_BOOL (*params) = args->d.long_data;
288 else if (params->type == GTK_TYPE_INT)
289 GTK_VALUE_INT (*params) = args->d.long_data;
290 else if (params->type == GTK_TYPE_UINT &&
291 args->d.long_data >= 0)
292 GTK_VALUE_UINT (*params) = args->d.long_data;
293 else if (params->type == GTK_TYPE_LONG)
294 GTK_VALUE_LONG (*params) = args->d.long_data;
295 else if (params->type == GTK_TYPE_ULONG &&
296 args->d.long_data >= 0)
297 GTK_VALUE_ULONG (*params) = args->d.long_data;
298 else if (params->type == GTK_TYPE_FLOAT)
299 GTK_VALUE_FLOAT (*params) = args->d.long_data;
300 else if (params->type == GTK_TYPE_DOUBLE)
301 GTK_VALUE_DOUBLE (*params) = args->d.long_data;
324 gtk_binding_entry_activate (GtkBindingEntry *entry,
327 GtkBindingSignal *sig;
328 gboolean old_emission;
330 old_emission = entry->in_emission;
331 entry->in_emission = TRUE;
333 gtk_object_ref (object);
335 for (sig = entry->signals; sig; sig = sig->next)
337 GtkSignalQuery *query;
339 GtkArg *params = NULL;
340 gchar *accelerator = NULL;
342 signal_id = gtk_signal_lookup (sig->signal_name, GTK_OBJECT_TYPE (object));
345 accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
346 g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
347 "could not find signal \"%s\" in the `%s' class ancestry",
348 entry->binding_set->set_name,
351 gtk_type_name (GTK_OBJECT_TYPE (object)));
352 g_free (accelerator);
356 query = gtk_signal_query (signal_id);
357 if (query->nparams != sig->n_args ||
358 query->return_val != GTK_TYPE_NONE ||
359 !binding_compose_params (sig->args, query, ¶ms))
361 accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
362 g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
363 "signature mismatch for signal \"%s\" in the `%s' class ancestry",
364 entry->binding_set->set_name,
367 gtk_type_name (GTK_OBJECT_TYPE (object)));
369 else if (!(query->signal_flags & GTK_RUN_ACTION))
371 accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers);
372 g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": "
373 "signal \"%s\" in the `%s' class ancestry cannot be used for action emissions",
374 entry->binding_set->set_name,
377 gtk_type_name (GTK_OBJECT_TYPE (object)));
379 g_free (accelerator);
384 gtk_signal_emitv (object, signal_id, params);
387 if (GTK_OBJECT_DESTROYED (object) || entry->destroyed)
391 gtk_object_unref (object);
393 entry->in_emission = old_emission;
394 if (entry->destroyed && !entry->in_emission)
395 binding_entry_free (entry);
399 gtk_binding_set_new (const gchar *set_name)
401 GtkBindingSet *binding_set;
403 g_return_val_if_fail (set_name != NULL, NULL);
405 binding_set = g_new (GtkBindingSet, 1);
406 binding_set->set_name = g_strdup (set_name);
407 binding_set->widget_path_pspecs = NULL;
408 binding_set->widget_class_pspecs = NULL;
409 binding_set->class_branch_pspecs = NULL;
410 binding_set->entries = NULL;
411 binding_set->current = NULL;
413 binding_set_list = g_slist_prepend (NULL, binding_set);
419 gtk_binding_set_by_class (gpointer object_class)
421 GtkObjectClass *class = object_class;
422 GtkBindingSet* binding_set;
424 g_return_val_if_fail (GTK_IS_OBJECT_CLASS (class), NULL);
426 if (!key_id_class_binding_set)
427 key_id_class_binding_set = g_dataset_force_id (key_class_binding_set);
429 binding_set = g_dataset_id_get_data (class, key_id_class_binding_set);
434 binding_set = gtk_binding_set_new (gtk_type_name (class->type));
435 gtk_binding_set_add_path (binding_set,
437 gtk_type_name (class->type),
439 g_dataset_id_set_data (class, key_id_class_binding_set, binding_set);
445 gtk_binding_set_find (const gchar *set_name)
449 g_return_val_if_fail (set_name != NULL, NULL);
451 for (slist = binding_set_list; slist; slist = slist->next)
453 GtkBindingSet *binding_set;
455 binding_set = slist->data;
456 if (g_str_equal (binding_set->set_name, (gpointer) set_name))
463 gtk_binding_set_activate (GtkBindingSet *binding_set,
468 GtkBindingEntry *entry;
470 g_return_val_if_fail (binding_set != NULL, FALSE);
471 g_return_val_if_fail (object != NULL, FALSE);
472 g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
474 keyval = gdk_keyval_to_lower (keyval);
475 modifiers = modifiers & BINDING_MOD_MASK ();
477 if (!GTK_OBJECT_DESTROYED (object))
479 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
482 gtk_binding_entry_activate (entry, object);
492 gtk_binding_entry_clear (GtkBindingSet *binding_set,
496 GtkBindingEntry *entry;
498 g_return_if_fail (binding_set != NULL);
500 keyval = gdk_keyval_to_lower (keyval);
501 modifiers = modifiers & BINDING_MOD_MASK ();
503 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
505 binding_entry_destroy (entry);
507 entry = binding_entry_new (binding_set, keyval, modifiers);
511 gtk_binding_entry_remove (GtkBindingSet *binding_set,
515 GtkBindingEntry *entry;
517 g_return_if_fail (binding_set != NULL);
519 keyval = gdk_keyval_to_lower (keyval);
520 modifiers = modifiers & BINDING_MOD_MASK ();
522 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
524 binding_entry_destroy (entry);
528 gtk_binding_entry_add_signall (GtkBindingSet *binding_set,
531 const gchar *signal_name,
532 GSList *binding_args)
534 GtkBindingEntry *entry;
535 GtkBindingSignal *signal, **signal_p;
540 g_return_if_fail (binding_set != NULL);
541 g_return_if_fail (signal_name != NULL);
543 keyval = gdk_keyval_to_lower (keyval);
544 modifiers = modifiers & BINDING_MOD_MASK ();
546 signal = binding_signal_new (signal_name, g_slist_length (binding_args));
549 for (slist = binding_args; slist; slist = slist->next)
551 GtkBindingArg *tmp_arg;
553 tmp_arg = slist->data;
556 g_warning ("gtk_binding_entry_add_signall(): arg[%u] is `NULL'", n);
557 binding_signal_free (signal);
560 arg->arg_type = tmp_arg->arg_type;
561 switch (tmp_arg->arg_type)
563 case GTK_BINDING_ARG_INT:
564 case GTK_BINDING_ARG_LONG:
565 arg->d.long_data = tmp_arg->d.long_data;
567 case GTK_BINDING_ARG_FLOAT:
568 case GTK_BINDING_ARG_DOUBLE:
569 arg->d.double_data = tmp_arg->d.double_data;
571 case GTK_BINDING_ARG_STRING:
572 if (!tmp_arg->d.string_data)
574 g_warning ("gtk_binding_entry_add_signall(): value of `string' arg[%u] is `NULL'", n);
575 arg->d.string_data = NULL;
576 binding_signal_free (signal);
579 arg->d.string_data = g_strdup (tmp_arg->d.string_data);
582 g_warning ("gtk_binding_entry_add_signall(): unsupported type `%s' for arg[%u]",
583 gtk_type_name (arg->arg_type), n);
584 binding_signal_free (signal);
591 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
594 gtk_binding_entry_add (binding_set, keyval, modifiers);
595 entry = binding_ht_lookup_entry (binding_set, keyval, modifiers);
597 signal_p = &entry->signals;
599 signal_p = &(*signal_p)->next;
604 gtk_binding_entry_add_signal (GtkBindingSet *binding_set,
607 const gchar *signal_name,
611 GSList *slist, *free_slist;
615 g_return_if_fail (binding_set != NULL);
616 g_return_if_fail (signal_name != NULL);
618 keyval = gdk_keyval_to_lower (keyval);
619 modifiers = modifiers & BINDING_MOD_MASK ();
621 va_start (args, n_args);
623 for (i = 0; i < n_args; i++)
627 arg = g_new0 (GtkBindingArg, 1);
628 slist = g_slist_prepend (slist, arg);
630 arg->arg_type = va_arg (args, GtkType);
631 switch (arg->arg_type)
633 case GTK_BINDING_ARG_INT:
634 arg->d.long_data = va_arg (args, gint);
636 case GTK_BINDING_ARG_LONG:
637 arg->d.long_data = va_arg (args, glong);
639 case GTK_BINDING_ARG_FLOAT:
640 arg->d.double_data = va_arg (args, gfloat);
642 case GTK_BINDING_ARG_DOUBLE:
643 arg->d.double_data = va_arg (args, gdouble);
645 case GTK_BINDING_ARG_STRING:
646 arg->d.string_data = va_arg (args, gchar*);
647 if (!arg->d.string_data)
649 g_warning ("gtk_binding_entry_add_signal(): value of `string' arg[%u] is `NULL'", i);
654 g_warning ("gtk_binding_entry_add_signal(): unsupported type `%s' for arg[%u]",
655 gtk_type_name (arg->arg_type), i);
662 if (i == n_args + 1 || i == 0)
664 slist = g_slist_reverse (slist);
665 gtk_binding_entry_add_signall (binding_set, keyval, modifiers, signal_name, slist);
671 g_free (slist->data);
674 g_slist_free (free_slist);
678 gtk_binding_set_add_path (GtkBindingSet *binding_set,
679 GtkPathType path_type,
680 const gchar *path_pattern,
681 GtkPathPriorityType priority)
683 GtkPatternSpec *pspec;
684 GSList **slist_p, *slist;
685 static guint seq_id = 0;
687 g_return_if_fail (binding_set != NULL);
688 g_return_if_fail (path_pattern != NULL);
690 priority &= GTK_PATH_PRIO_MASK;
694 case GTK_PATH_WIDGET:
695 slist_p = &binding_set->widget_path_pspecs;
697 case GTK_PATH_WIDGET_CLASS:
698 slist_p = &binding_set->widget_class_pspecs;
701 slist_p = &binding_set->class_branch_pspecs;
704 g_assert_not_reached ();
709 pspec = g_new (GtkPatternSpec, 1);
710 gtk_pattern_spec_init (pspec, path_pattern);
711 pspec->seq_id = seq_id++ & 0x0fffffff;
712 pspec->seq_id |= priority << 28;
713 pspec->user_data = binding_set;
718 GtkPatternSpec *tmp_pspec;
720 tmp_pspec = slist->data;
723 if (tmp_pspec->pattern_length == pspec->pattern_length &&
724 g_str_equal (tmp_pspec->pattern_reversed, pspec->pattern_reversed))
726 gtk_pattern_spec_free_segs (pspec);
732 *slist_p = g_slist_prepend (*slist_p, pspec);
735 static inline gboolean
736 binding_match_activate (GSList *pspec_list,
740 gchar *path_reversed)
744 for (slist = pspec_list; slist; slist = slist->next)
746 GtkPatternSpec *pspec;
749 if (gtk_pattern_match (pspec, path_length, path, path_reversed))
751 GtkBindingSet *binding_set;
753 binding_set = pspec->user_data;
755 gtk_binding_entry_activate (binding_set->current, object);
765 gtk_binding_pattern_compare (g_const_pointer a,
768 register const GtkPatternSpec *pa = a;
769 register const GtkPatternSpec *pb = b;
771 return pa->seq_id < pb->seq_id ? -1 : 1;
774 static inline GSList*
775 gtk_binding_entries_sort_patterns (GtkBindingEntry *entries,
783 register GtkBindingSet *binding_set;
784 GSList *slist = NULL;
786 binding_set = entries->binding_set;
787 binding_set->current = entries;
791 case GTK_PATH_WIDGET:
792 slist = binding_set->widget_path_pspecs;
794 case GTK_PATH_WIDGET_CLASS:
795 slist = binding_set->widget_class_pspecs;
798 slist = binding_set->class_branch_pspecs;
802 for (; slist; slist = slist->next)
804 GtkPatternSpec *pspec;
807 patterns = g_slist_insert_sorted (patterns, pspec, gtk_binding_pattern_compare);
810 entries = entries->hash_next;
818 gtk_bindings_activate (GtkObject *object,
822 GtkBindingEntry *entries;
824 gboolean handled = FALSE;
826 g_return_val_if_fail (object != NULL, FALSE);
827 g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
829 if (!GTK_IS_WIDGET (object) || GTK_OBJECT_DESTROYED (object))
832 widget = GTK_WIDGET (object);
834 keyval = gdk_keyval_to_lower (keyval);
835 modifiers = modifiers & BINDING_MOD_MASK ();
837 entries = binding_ht_lookup_list (keyval, modifiers);
845 gchar *path, *path_reversed;
848 gtk_widget_path (widget, &path_length, &path, &path_reversed);
849 patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET);
850 handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
851 g_slist_free (patterns);
853 g_free (path_reversed);
859 gchar *path, *path_reversed;
862 gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
863 patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_WIDGET_CLASS);
864 handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
865 g_slist_free (patterns);
867 g_free (path_reversed);
875 patterns = gtk_binding_entries_sort_patterns (entries, GTK_PATH_CLASS);
876 class_type = GTK_OBJECT_TYPE (object);
877 while (class_type && !handled)
880 gchar *path, *path_reversed;
882 path = gtk_type_name (class_type);
883 path_reversed = g_strdup (path);
884 g_strreverse (path_reversed);
885 path_length = strlen (path);
886 handled = binding_match_activate (patterns, object, path_length, path, path_reversed);
887 g_free (path_reversed);
889 class_type = gtk_type_parent (class_type);
891 g_slist_free (patterns);
909 static inline gboolean
910 gtk_pattern_ph_match (const gchar *match_pattern,
911 const gchar *match_string)
913 register const gchar *pattern, *string;
916 pattern = match_pattern;
917 string = match_string;
943 while (ch == '*' || ch == '?');
948 while (ch != *string)
955 if (gtk_pattern_ph_match (pattern, string))
977 gtk_pattern_match (GtkPatternSpec *pspec,
980 const gchar *string_reversed)
982 g_return_val_if_fail (pspec != NULL, FALSE);
983 g_return_val_if_fail (string != NULL, FALSE);
984 g_return_val_if_fail (string_reversed != NULL, FALSE);
986 switch (pspec->match_type)
989 return gtk_pattern_ph_match (pspec->pattern, string);
991 case GTK_MATCH_ALL_TAIL:
992 return gtk_pattern_ph_match (pspec->pattern_reversed, string_reversed);
995 if (pspec->pattern_length > string_length)
997 else if (pspec->pattern_length == string_length)
998 return strcmp (pspec->pattern, string) == 0;
999 else if (pspec->pattern_length)
1000 return strncmp (pspec->pattern, string, pspec->pattern_length) == 0;
1004 case GTK_MATCH_TAIL:
1005 if (pspec->pattern_length > string_length)
1007 else if (pspec->pattern_length == string_length)
1008 return strcmp (pspec->pattern_reversed, string_reversed) == 0;
1009 else if (pspec->pattern_length)
1010 return strncmp (pspec->pattern_reversed,
1012 pspec->pattern_length) == 0;
1016 case GTK_MATCH_EXACT:
1017 if (pspec->pattern_length != string_length)
1020 return strcmp (pspec->pattern_reversed, string_reversed) == 0;
1023 g_return_val_if_fail (pspec->match_type < GTK_MATCH_LAST, FALSE);
1029 gtk_pattern_spec_init (GtkPatternSpec *pspec,
1030 const gchar *pattern)
1034 g_return_if_fail (pspec != NULL);
1036 pspec->match_type = GTK_MATCH_ALL;
1038 pspec->user_data = NULL;
1043 pspec->pattern = g_strdup (pattern);
1044 pspec->pattern_length = strlen (pspec->pattern);
1045 pspec->pattern_reversed = g_strdup (pspec->pattern);
1046 g_strreverse (pspec->pattern_reversed);
1047 if (pspec->pattern_reversed[0] != '*')
1048 pspec->match_type = GTK_MATCH_ALL_TAIL;
1050 if (strchr (pspec->pattern, '?'))
1053 if (!strchr (pspec->pattern, '*'))
1055 pspec->match_type = GTK_MATCH_EXACT;
1062 if (p > pspec->pattern &&
1067 pspec->match_type = GTK_MATCH_TAIL;
1069 pspec->pattern = g_strdup (p);
1071 g_free (pspec->pattern_reversed);
1072 pspec->pattern_reversed = g_strdup (pspec->pattern);
1073 g_strreverse (pspec->pattern_reversed);
1074 pspec->pattern_length = strlen (pspec->pattern);
1078 p = pspec->pattern_reversed;
1081 if (p > pspec->pattern_reversed &&
1086 pspec->match_type = GTK_MATCH_HEAD;
1087 t = pspec->pattern_reversed;
1088 pspec->pattern_reversed = g_strdup (p);
1090 pspec->pattern = g_strdup (pspec->pattern_reversed);
1091 g_strreverse (pspec->pattern);
1092 pspec->pattern_length = strlen (pspec->pattern);
1097 gtk_pattern_match_string (GtkPatternSpec *pspec,
1098 const gchar *string)
1100 gchar *string_reversed;
1104 g_return_val_if_fail (pspec != NULL, FALSE);
1105 g_return_val_if_fail (string != NULL, FALSE);
1107 length = strlen (string);
1108 string_reversed = g_strdup (string);
1109 g_strreverse (string_reversed);
1111 ergo = gtk_pattern_match (pspec, length, string, string_reversed);
1112 g_free (string_reversed);
1118 gtk_pattern_match_simple (const gchar *pattern,
1119 const gchar *string)
1121 GtkPatternSpec pspec;
1124 g_return_val_if_fail (pattern != NULL, FALSE);
1125 g_return_val_if_fail (string != NULL, FALSE);
1127 gtk_pattern_spec_init (&pspec, pattern);
1128 ergo = gtk_pattern_match_string (&pspec, string);
1129 gtk_pattern_spec_free_segs (&pspec);
1135 gtk_pattern_spec_free_segs (GtkPatternSpec *pspec)
1137 g_return_if_fail (pspec != NULL);
1139 g_free (pspec->pattern);
1140 pspec->pattern = NULL;
1141 g_free (pspec->pattern_reversed);
1142 pspec->pattern_reversed = NULL;