From ac879843d0796bea474272842a4e129a2feab2f7 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 23 Mar 2006 23:21:30 +0000 Subject: [PATCH] Support subclasses in RC files. (#142417, Todd Berman, patch based on a 2006-03-23 Matthias Clasen Support subclasses in RC files. (#142417, Todd Berman, patch based on a patch by Benjamin Berg) * gtk/gtkrc.h: * gtk/gtkrc.c: Support elements in widget_class paths in rc files which match any classes derived from named class. (_gtk_rc_init): Use the new syntax in the default rc string. * gtk/gtkbindings.c: Support the new syntax for bindings too. * tests/testrc.c: Tests for widget_class path matching --- ChangeLog | 15 ++ ChangeLog.pre-2-10 | 15 ++ gtk/gtkbindings.c | 66 +++++--- gtk/gtkrc.c | 408 ++++++++++++++++++++++++++++++++++++++++----- gtk/gtkrc.h | 9 +- tests/testrc.c | 77 +++++++++ 6 files changed, 532 insertions(+), 58 deletions(-) create mode 100644 tests/testrc.c diff --git a/ChangeLog b/ChangeLog index 7768fa11b..ee7b54ed2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2006-03-23 Matthias Clasen + + Support subclasses in RC files. (#142417, Todd Berman, patch + based on a patch by Benjamin Berg) + + * gtk/gtkrc.h: + * gtk/gtkrc.c: Support elements in widget_class paths + in rc files which match any classes derived from named class. + + (_gtk_rc_init): Use the new syntax in the default rc string. + + * gtk/gtkbindings.c: Support the new syntax for bindings too. + + * tests/testrc.c: Tests for widget_class path matching + 2006-03-23 Carlos Garnacho * gtk/gtkdnd.c (gtk_drag_dest_motion): make sure that gdk_drag_event() diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 7768fa11b..ee7b54ed2 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,18 @@ +2006-03-23 Matthias Clasen + + Support subclasses in RC files. (#142417, Todd Berman, patch + based on a patch by Benjamin Berg) + + * gtk/gtkrc.h: + * gtk/gtkrc.c: Support elements in widget_class paths + in rc files which match any classes derived from named class. + + (_gtk_rc_init): Use the new syntax in the default rc string. + + * gtk/gtkbindings.c: Support the new syntax for bindings too. + + * tests/testrc.c: Tests for widget_class path matching + 2006-03-23 Carlos Garnacho * gtk/gtkdnd.c (gtk_drag_dest_motion): make sure that gdk_drag_event() diff --git a/gtk/gtkbindings.c b/gtk/gtkbindings.c index 9e2c46294..fcba62887 100644 --- a/gtk/gtkbindings.c +++ b/gtk/gtkbindings.c @@ -44,9 +44,11 @@ /* --- structures --- */ typedef struct { + GtkPathType type; GPatternSpec *pspec; - gpointer user_data; - guint seq_id; + GSList *path; + gpointer user_data; + guint seq_id; } PatternSpec; @@ -59,6 +61,15 @@ static GQuark key_id_class_binding_set = 0; /* --- functions --- */ +static void +pattern_spec_free (PatternSpec *pspec) +{ + _gtk_rc_free_widget_class_path (pspec->path); + if (pspec->pspec) + g_pattern_spec_free (pspec->pspec); + g_free (pspec); +} + static GtkBindingSignal* binding_signal_new (const gchar *signal_name, guint n_args) @@ -869,7 +880,18 @@ gtk_binding_set_add_path (GtkBindingSet *binding_set, } pspec = g_new (PatternSpec, 1); - pspec->pspec = g_pattern_spec_new (path_pattern); + pspec->type = path_type; + if (path_type == GTK_PATH_WIDGET_CLASS) + { + pspec->pspec = NULL; + pspec->path = _gtk_rc_parse_widget_class_path (path_pattern); + } + else + { + pspec->pspec = g_pattern_spec_new (path_pattern); + pspec->path = NULL; + } + pspec->seq_id = priority << 28; pspec->user_data = binding_set; @@ -885,8 +907,7 @@ gtk_binding_set_add_path (GtkBindingSet *binding_set, { GtkPathPriorityType lprio = tmp_pspec->seq_id >> 28; - g_pattern_spec_free (pspec->pspec); - g_free (pspec); + pattern_spec_free (pspec); pspec = NULL; if (lprio < priority) { @@ -907,25 +928,32 @@ static gboolean binding_match_activate (GSList *pspec_list, GtkObject *object, guint path_length, - const gchar *path, - const gchar *path_reversed) + gchar *path, + gchar *path_reversed) { GSList *slist; for (slist = pspec_list; slist; slist = slist->next) { PatternSpec *pspec; + GtkBindingSet *binding_set; + binding_set = NULL; pspec = slist->data; - if (g_pattern_match (pspec->pspec, path_length, path, path_reversed)) - { - GtkBindingSet *binding_set; - - binding_set = pspec->user_data; + + if (pspec->type == GTK_PATH_WIDGET_CLASS) + { + if (_gtk_rc_match_widget_class (pspec->path, path_length, path, path_reversed)) + binding_set = pspec->user_data; + } + else + { + if (g_pattern_match (pspec->pspec, path_length, path, path_reversed)) + binding_set = pspec->user_data; + } - if (gtk_binding_entry_activate (binding_set->current, object)) - return TRUE; - } + if (binding_set && gtk_binding_entry_activate (binding_set->current, object)) + return TRUE; } return FALSE; @@ -1052,14 +1080,15 @@ gtk_bindings_activate_list (GtkObject *object, while (class_type && !handled) { guint path_length; - const gchar *path; + gchar *path; gchar *path_reversed; - path = g_type_name (class_type); + path = g_strdup (g_type_name (class_type)); path_reversed = g_strdup (path); g_strreverse (path_reversed); path_length = strlen (path); handled = binding_match_activate (patterns, object, path_length, path, path_reversed); + g_free (path); g_free (path_reversed); class_type = g_type_parent (class_type); @@ -1417,8 +1446,7 @@ free_pattern_specs (GSList *pattern_specs) pspec = slist->data; - g_pattern_spec_free (pspec->pspec); - g_free (pspec); + pattern_spec_free (pspec); } g_slist_free (pattern_specs); diff --git a/gtk/gtkrc.c b/gtk/gtkrc.c index 0047dc5e0..933192a44 100644 --- a/gtk/gtkrc.c +++ b/gtk/gtkrc.c @@ -66,21 +66,43 @@ typedef struct _GtkRcSet GtkRcSet; typedef struct _GtkRcNode GtkRcNode; typedef struct _GtkRcFile GtkRcFile; +enum +{ + PATH_ELT_PSPEC, + PATH_ELT_UNRESOLVED, + PATH_ELT_TYPE +}; + +typedef struct +{ + gint type; + union + { + GType class_type; + gchar *class_name; + GPatternSpec *pspec; + } elt; +} PathElt; + struct _GtkRcSet { + GtkPathType type; + GPatternSpec *pspec; - GtkRcStyle *rc_style; - gint priority; + GSList *path; + + GtkRcStyle *rc_style; + gint priority; }; struct _GtkRcFile { - gboolean is_string; /* If TRUE, name is a string to parse with gtk_rc_parse_string() */ time_t mtime; gchar *name; gchar *canonical_name; gchar *directory; - guint reload; + guint reload : 1; + guint is_string : 1; /* If TRUE, name is a string to parse with gtk_rc_parse_string() */ }; #define GTK_RC_MAX_PIXMAP_PATHS 128 @@ -130,8 +152,8 @@ static GtkRcStyle* gtk_rc_style_find (GtkRcContext *context, static GSList * gtk_rc_styles_match (GSList *rc_styles, GSList *sets, guint path_length, - const gchar *path, - const gchar *path_reversed); + gchar *path, + gchar *path_reversed); static GtkStyle * gtk_rc_style_to_style (GtkRcContext *context, GtkRcStyle *rc_style); static GtkStyle* gtk_rc_init_style (GtkRcContext *context, @@ -213,6 +235,7 @@ static GtkRcStyle* gtk_rc_style_real_create_rc_style (GtkRcStyle *rc_style) static GtkStyle* gtk_rc_style_real_create_style (GtkRcStyle *rc_style); static gint gtk_rc_properties_cmp (gconstpointer bsearch_node1, gconstpointer bsearch_node2); +static void gtk_rc_set_free (GtkRcSet *rc_set); static gpointer parent_class = NULL; @@ -737,19 +760,8 @@ _gtk_rc_init (void) "\n" "class \"GtkProgressBar\" style : gtk \"gtk-default-progress-bar-style\"\n" "widget \"gtk-tooltips*\" style : gtk \"gtk-default-tooltips-style\"\n" - "class \"GtkMenuItem\" style : gtk \"gtk-default-menu-item-style\"\n" - "widget_class \"*.GtkMenuItem.*\" style : gtk \"gtk-default-menu-item-style\"\n" - "widget_class \"*.GtkAccelMenuItem.*\" style : gtk \"gtk-default-menu-item-style\"\n" - "widget_class \"*.GtkRadioMenuItem.*\" style : gtk \"gtk-default-menu-item-style\"\n" - "widget_class \"*.GtkCheckMenuItem.*\" style : gtk \"gtk-default-menu-item-style\"\n" - "widget_class \"*.GtkImageMenuItem.*\" style : gtk \"gtk-default-menu-item-style\"\n" - "widget_class \"*.GtkSeparatorMenuItem.*\" style : gtk \"gtk-default-menu-item-style\"\n" - "widget_class \"*.GtkCellViewMenuItem.*\" style : gtk \"gtk-default-menu-item-style\"\n" - "widget_class \"*GtkMenuBar*GtkMenuItem\" style : gtk \"gtk-default-menu-bar-item-style\"\n" - "widget_class \"*GtkMenuBar*GtkAccelMenuItem\" style : gtk \"gtk-default-menu-bar-item-style\"\n" - "widget_class \"*GtkMenuBar*GtkRadioMenuItem\" style : gtk \"gtk-default-menu-bar-item-style\"\n" - "widget_class \"*GtkMenuBar*GtkCheckMenuItem\" style : gtk \"gtk-default-menu-bar-item-style\"\n" - "widget_class \"*GtkMenuBar*GtkImageMenuItem\" style : gtk \"gtk-default-menu-bar-item-style\"\n" + "widget_class \"**\" style : gtk \"gtk-default-menu-item-style\"\n" + "widget_class \"**\" style : gtk \"gtk-default-menu-bar-item-style\"\n" ); } @@ -1329,8 +1341,7 @@ gtk_rc_free_rc_sets (GSList *slist) GtkRcSet *rc_set; rc_set = slist->data; - g_pattern_spec_free (rc_set->pspec); - g_free (rc_set); + gtk_rc_set_free (rc_set); slist = slist->next; } @@ -1623,8 +1634,8 @@ static GSList * gtk_rc_styles_match (GSList *rc_styles, GSList *sets, guint path_length, - const gchar *path, - const gchar *path_reversed) + gchar *path, + gchar *path_reversed) { GtkRcSet *rc_set; @@ -1634,10 +1645,18 @@ gtk_rc_styles_match (GSList *rc_styles, rc_set = sets->data; sets = sets->next; - if (g_pattern_match (rc_set->pspec, path_length, path, path_reversed)) - rc_styles = g_slist_append (rc_styles, rc_set); + if (rc_set->type == GTK_PATH_WIDGET_CLASS) + { + if (_gtk_rc_match_widget_class (rc_set->path, path_length, path, path_reversed)) + rc_styles = g_slist_append (rc_styles, rc_set); + } + else + { + if (g_pattern_match (rc_set->pspec, path_length, path, path_reversed)) + rc_styles = g_slist_append (rc_styles, rc_set); + } } - + return rc_styles; } @@ -1746,16 +1765,17 @@ gtk_rc_get_style (GtkWidget *widget) type = G_TYPE_FROM_INSTANCE (widget); while (type) { - const gchar *path; + gchar *path; gchar *path_reversed; guint path_length; - path = g_type_name (type); + path = g_strdup (g_type_name (type)); path_length = strlen (path); path_reversed = g_strdup (path); g_strreverse (path_reversed); rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_class, path_length, path, path_reversed); + g_free (path); g_free (path_reversed); type = g_type_parent (type); @@ -1832,27 +1852,33 @@ gtk_rc_get_style_by_paths (GtkSettings *settings, if (widget_path && context->rc_sets_widget) { + gchar *path; gchar *path_reversed; guint path_length; path_length = strlen (widget_path); + path = g_strdup (widget_path); path_reversed = g_strdup (widget_path); g_strreverse (path_reversed); - rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget, path_length, widget_path, path_reversed); + rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget, path_length, path, path_reversed); + g_free (path); g_free (path_reversed); } if (class_path && context->rc_sets_widget_class) { + gchar *path; gchar *path_reversed; guint path_length; + path = g_strdup (class_path); path_length = strlen (class_path); path_reversed = g_strdup (class_path); g_strreverse (path_reversed); - rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget_class, path_length, class_path, path_reversed); + rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget_class, path_length, path, path_reversed); + g_free (path); g_free (path_reversed); } @@ -1860,16 +1886,17 @@ gtk_rc_get_style_by_paths (GtkSettings *settings, { while (type) { - const gchar *path; + gchar *path; gchar *path_reversed; guint path_length; - path = g_type_name (type); + path = g_strdup (g_type_name (type)); path_length = strlen (path); path_reversed = g_strdup (path); g_strreverse (path_reversed); rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_class, path_length, path, path_reversed); + g_free (path); g_free (path_reversed); type = g_type_parent (type); @@ -1887,7 +1914,8 @@ gtk_rc_get_style_by_paths (GtkSettings *settings, static GSList * gtk_rc_add_rc_sets (GSList *slist, GtkRcStyle *rc_style, - const gchar *pattern) + const gchar *pattern, + GtkPathType path_type) { GtkRcStyle *new_style; GtkRcSet *rc_set; @@ -1903,7 +1931,19 @@ gtk_rc_add_rc_sets (GSList *slist, new_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]); rc_set = g_new (GtkRcSet, 1); - rc_set->pspec = g_pattern_spec_new (pattern); + rc_set->type = path_type; + + if (path_type == GTK_PATH_WIDGET_CLASS) + { + rc_set->pspec = NULL; + rc_set->path = _gtk_rc_parse_widget_class_path (pattern); + } + else + { + rc_set->pspec = g_pattern_spec_new (pattern); + rc_set->path = NULL; + } + rc_set->rc_style = rc_style; return g_slist_prepend (slist, rc_set); @@ -1920,7 +1960,7 @@ gtk_rc_add_widget_name_style (GtkRcStyle *rc_style, context = gtk_rc_context_get (gtk_settings_get_default ()); - context->rc_sets_widget = gtk_rc_add_rc_sets (context->rc_sets_widget, rc_style, pattern); + context->rc_sets_widget = gtk_rc_add_rc_sets (context->rc_sets_widget, rc_style, pattern, GTK_PATH_WIDGET); } void @@ -1934,7 +1974,7 @@ gtk_rc_add_widget_class_style (GtkRcStyle *rc_style, context = gtk_rc_context_get (gtk_settings_get_default ()); - context->rc_sets_widget_class = gtk_rc_add_rc_sets (context->rc_sets_widget_class, rc_style, pattern); + context->rc_sets_widget_class = gtk_rc_add_rc_sets (context->rc_sets_widget_class, rc_style, pattern, GTK_PATH_WIDGET_CLASS); } void @@ -1948,7 +1988,7 @@ gtk_rc_add_class_style (GtkRcStyle *rc_style, context = gtk_rc_context_get (gtk_settings_get_default ()); - context->rc_sets_class = gtk_rc_add_rc_sets (context->rc_sets_class, rc_style, pattern); + context->rc_sets_class = gtk_rc_add_rc_sets (context->rc_sets_class, rc_style, pattern, GTK_PATH_CLASS); } GScanner* @@ -3870,7 +3910,19 @@ gtk_rc_parse_path_pattern (GtkRcContext *context, } rc_set = g_new (GtkRcSet, 1); - rc_set->pspec = g_pattern_spec_new (pattern); + rc_set->type = path_type; + + if (path_type == GTK_PATH_WIDGET_CLASS) + { + rc_set->pspec = NULL; + rc_set->path = _gtk_rc_parse_widget_class_path (pattern); + } + else + { + rc_set->pspec = g_pattern_spec_new (pattern); + rc_set->path = NULL; + } + rc_set->rc_style = rc_style; rc_set->priority = priority; @@ -4215,6 +4267,286 @@ gtk_rc_parse_logical_color (GScanner *scanner, return G_TOKEN_NONE; } + +GSList * +_gtk_rc_parse_widget_class_path (const gchar *pattern) +{ + GSList *result; + PathElt *path_elt; + const gchar *current; + const gchar *class_start; + const gchar *class_end; + const gchar *pattern_end; + const gchar *pattern_start; + gchar *sub_pattern; + + result = NULL; + current = pattern; + while ((class_start = strchr (current, '<')) && + (class_end = strchr (class_start, '>'))) + { + /* Add patterns, but ignore single dots */ + if (!(class_start == current || + (class_start == current + 1 && current[0] == '.'))) + { + pattern_end = class_start - 1; + pattern_start = current; + + path_elt = g_new (PathElt, 1); + + sub_pattern = g_strndup (pattern_start, pattern_end - pattern_start + 1); + path_elt->type = PATH_ELT_PSPEC; + path_elt->elt.pspec = g_pattern_spec_new (sub_pattern); + g_free (sub_pattern); + + result = g_slist_prepend (result, path_elt); + } + + path_elt = g_new (PathElt, 1); + + /* The < > need to be removed from the string. */ + sub_pattern = g_strndup (class_start + 1, class_end - class_start - 1); + + path_elt->type = PATH_ELT_UNRESOLVED; + path_elt->elt.class_name = sub_pattern; + + result = g_slist_prepend (result, path_elt); + + current = class_end + 1; + } + + /* Add the rest, if anything is left */ + if (strlen (current) > 0) + { + path_elt = g_new (PathElt, 1); + path_elt->type = PATH_ELT_PSPEC; + path_elt->elt.pspec = g_pattern_spec_new (current); + + result = g_slist_prepend (result, path_elt); + } + + return g_slist_reverse (result); +} + +static void +free_path_elt (gpointer data, + gpointer user_data) +{ + PathElt *path_elt = data; + + switch (path_elt->type) + { + case PATH_ELT_PSPEC: + g_pattern_spec_free (path_elt->elt.pspec); + break; + case PATH_ELT_UNRESOLVED: + g_free (path_elt->elt.class_name); + break; + case PATH_ELT_TYPE: + break; + default: + g_assert_not_reached (); + } + + g_free (path_elt); +} + +void +_gtk_rc_free_widget_class_path (GSList *list) +{ + g_slist_foreach (list, free_path_elt, NULL); + g_slist_free (list); +} + +static void +gtk_rc_set_free (GtkRcSet *rc_set) +{ + if (rc_set->pspec) + g_pattern_spec_free (rc_set->pspec); + + _gtk_rc_free_widget_class_path (rc_set->path); + + g_free (rc_set); +} + +static gboolean +match_class (PathElt *path_elt, + gchar *type_name) +{ + GType type; + + if (path_elt->type == PATH_ELT_UNRESOLVED) + { + type = g_type_from_name (path_elt->elt.class_name); + if (type != G_TYPE_INVALID) + { + g_free (path_elt->elt.class_name); + path_elt->elt.class_type = type; + path_elt->type = PATH_ELT_TYPE; + } + else + return g_str_equal (type_name, path_elt->elt.class_name); + } + + return g_type_is_a (g_type_from_name (type_name), path_elt->elt.class_type); +} + +static gboolean +match_widget_class_recursive (GSList *list, + guint length, + gchar *path, + gchar *path_reversed) +{ + PathElt *path_elt; + + /* break out if we cannot match anymore. */ + if (list == NULL) + { + if (length > 0) + return FALSE; + else + return TRUE; + } + + /* there are two possibilities: + * 1. The next pattern should match the class. + * 2. First normal matching, and then maybe a class */ + + path_elt = list->data; + + if (path_elt->type != PATH_ELT_PSPEC) + { + gchar *class_start = path; + gchar *class_end; + + /* ignore leading dot */ + if (class_start[0] == '.') + class_start++; + class_end = strchr (class_start, '.'); + + if (class_end == NULL) + { + if (!match_class (path_elt, class_start)) + return FALSE; + else + return match_widget_class_recursive (list->next, 0, "", ""); + } + else + { + class_end[0] = '\0'; + if (!match_class (path_elt, class_start)) + { + class_end[0] = '.'; + return FALSE; + } + else + { + gboolean result; + gint new_length = length - (class_end - path); + gchar old_char = path_reversed[new_length]; + + class_end[0] = '.'; + + path_reversed[new_length] = '\0'; + result = match_widget_class_recursive (list->next, new_length, class_end, path_reversed); + path_reversed[new_length] = old_char; + + return result; + } + } + } + else + { + PathElt *class_elt; + gchar *class_start; + gchar *class_end; + gboolean result = FALSE; + + /* If there is nothing after this (ie. no class match), + * just compare the pspec. + */ + if (list->next == NULL) + return g_pattern_match (path_elt->elt.pspec, length, path, path_reversed); + + class_elt = (PathElt *)list->next->data; + g_assert (class_elt->type != PATH_ELT_PSPEC); + + class_start = path; + if (class_start[0] == '.') + class_start++; + + while (TRUE) + { + class_end = strchr (class_start, '.'); + + /* It should be cheaper to match the class first. (either the pattern + * is simple, and will match most of the times, or it may be complex + * and matching is slow) + */ + if (class_end == NULL) + { + result = match_class (class_elt, class_start); + } + else + { + class_end[0] = '\0'; + result = match_class (class_elt, class_start); + class_end[0] = '.'; + } + + if (result) + { + gchar old_char; + result = FALSE; + + /* terminate the string in front of the class. It does not matter + * that the class becomes unusable, because it is not needed + * inside the recursion + */ + old_char = class_start[0]; + class_start[0] = '\0'; + + if (g_pattern_match (path_elt->elt.pspec, class_start - path, path, path_reversed + length - (class_start - path))) + { + if (class_end != NULL) + { + gint new_length = length - (class_end - path); + gchar path_reversed_char = path_reversed[new_length]; + + path_reversed[new_length] = '\0'; + + result = match_widget_class_recursive (list->next->next, new_length, class_end, path_reversed); + + path_reversed[new_length] = path_reversed_char; + } + else + result = match_widget_class_recursive (list->next->next, 0, "", ""); + } + + class_start[0] = old_char; + } + + if (result) + return TRUE; + + /* get next class in path, or break out */ + if (class_end != NULL) + class_start = class_end + 1; + else + return FALSE; + } + } +} + +gboolean +_gtk_rc_match_widget_class (GSList *list, + gint length, + gchar *path, + gchar *path_reversed) +{ + return match_widget_class_recursive (list, length, path, path_reversed); +} + #ifdef G_OS_WIN32 /* DLL ABI stability backward compatibility versions */ diff --git a/gtk/gtkrc.h b/gtk/gtkrc.h index ea6ff2223..3b8e67e6c 100644 --- a/gtk/gtkrc.h +++ b/gtk/gtkrc.h @@ -126,7 +126,14 @@ struct _GtkRcStyleClass #define gtk_rc_parse gtk_rc_parse_utf8 #endif -void _gtk_rc_init (void); +void _gtk_rc_init (void); +GSList* _gtk_rc_parse_widget_class_path (const gchar *pattern); +void _gtk_rc_free_widget_class_path (GSList *list); +gboolean _gtk_rc_match_widget_class (GSList *list, + gint length, + gchar *path, + gchar *path_reversed); + void gtk_rc_add_default_file (const gchar *filename); void gtk_rc_set_default_files (gchar **filenames); gchar** gtk_rc_get_default_files (void); diff --git a/tests/testrc.c b/tests/testrc.c new file mode 100644 index 000000000..a019ae394 --- /dev/null +++ b/tests/testrc.c @@ -0,0 +1,77 @@ +/* GTK - The GIMP Toolkit + + Copyright (C) 2006 Red Hat, Inc. + Author: Matthias Clasen + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include +#include "gtk/gtk.h" + +/* NOTE to compile this test, GTK+ needs to be build without + * the _-prefix stripping. + */ +struct { + gchar *pattern; + gchar *test; + gboolean match; +} tests[] = { + { "", "", TRUE }, + { "", "GtkToggleButton", FALSE }, + { "", "GtkCheckButton", TRUE }, + { "", "GtkRadioButton", TRUE }, + { "abc*...*foo", "abcx.GtkToggleButton.GtkLabel.foo", TRUE }, + { "*abc..foo*", "abc.GtkToggleButton.bar", FALSE }, + { "*abc..foo*", "xabc.GtkToggleButton.fox", FALSE }, + { NULL, NULL, FALSE } +}; + +static void +load_types (void) +{ + volatile GType type; + + type = gtk_radio_button_get_type (); + type = gtk_label_get_type (); +} + +int +main (int argc, char *argv[]) +{ + gint i; + + gtk_init (&argc, &argv); + load_types (); + + for (i = 0; tests[i].test; i++) + { + GSList *list; + gchar *path, *rpath; + gboolean result; + + list = _gtk_rc_parse_widget_class_path (tests[i].pattern); + path = g_strdup (tests[i].test); + rpath = g_utf8_strreverse (path, -1); + result = _gtk_rc_match_widget_class (list, strlen (path), path, rpath); + g_print ("%d. \"%s\" \"%s\", expected %d, got %d\n", + i, tests[i].pattern, tests[i].test, tests[i].match, result); + g_assert (result == tests[i].match); + g_free (path); + } + + return 0; +} -- 2.43.2