[gtk+/gtk-style-context: 98/490] GtkStyleContext: Add methods to get style property values.
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/gtk-style-context: 98/490] GtkStyleContext: Add methods to get style property values.
- Date: Wed, 24 Nov 2010 13:47:52 +0000 (UTC)
commit 602b565e1049b3060ecf09ed4f32b552bf211e37
Author: Carlos Garnacho <carlosg gnome org>
Date: Fri Jun 18 17:11:37 2010 +0200
GtkStyleContext: Add methods to get style property values.
gtk/gtkstylecontext.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++++-
gtk/gtkstylecontext.h | 9 +++
2 files changed, 187 insertions(+), 3 deletions(-)
---
diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c
index d760f7b..91ff093 100644
--- a/gtk/gtkstylecontext.c
+++ b/gtk/gtkstylecontext.c
@@ -20,17 +20,20 @@
#include "config.h"
#include <gdk/gdk.h>
+#include <stdlib.h>
#include "gtkstylecontext.h"
#include "gtktypebuiltins.h"
#include "gtkthemingengine.h"
#include "gtkintl.h"
+#include "gtkwidget.h"
#include "gtkalias.h"
typedef struct GtkStyleContextPrivate GtkStyleContextPrivate;
typedef struct GtkStyleProviderData GtkStyleProviderData;
typedef struct GtkChildClass GtkChildClass;
+typedef struct PropertyValue PropertyValue;
struct GtkChildClass
{
@@ -44,12 +47,23 @@ struct GtkStyleProviderData
guint priority;
};
+struct PropertyValue
+{
+ GType widget_type;
+ GParamSpec *pspec;
+ GValue value;
+};
+
struct GtkStyleContextPrivate
{
GList *providers;
+ GList *providers_last;
+
GtkStyleSet *store;
GtkWidgetPath *widget_path;
+ GArray *property_cache;
+
GtkStateFlags state_flags;
GList *style_classes;
GList *child_style_classes;
@@ -105,6 +119,30 @@ style_provider_data_free (GtkStyleProviderData *data)
}
static void
+clear_property_cache (GtkStyleContext *context)
+{
+ GtkStyleContextPrivate *priv;
+
+ priv = GTK_STYLE_CONTEXT_GET_PRIVATE (context);
+
+ if (priv->property_cache)
+ {
+ guint i;
+
+ for (i = 0; i < priv->property_cache->len; i++)
+ {
+ PropertyValue *node = &g_array_index (priv->property_cache, PropertyValue, i);
+
+ g_param_spec_unref (node->pspec);
+ g_value_unset (&node->value);
+ }
+
+ g_array_free (priv->property_cache, TRUE);
+ priv->property_cache = NULL;
+ }
+}
+
+static void
gtk_style_context_finalize (GObject *object)
{
GtkStyleContextPrivate *priv;
@@ -114,6 +152,8 @@ gtk_style_context_finalize (GObject *object)
g_list_foreach (priv->providers, (GFunc) style_provider_data_free, NULL);
g_list_free (priv->providers);
+ clear_property_cache (GTK_STYLE_CONTEXT (object));
+
G_OBJECT_CLASS (gtk_style_context_parent_class)->finalize (object);
}
@@ -205,8 +245,13 @@ gtk_style_context_add_provider (GtkStyleContext *context,
if (!added)
priv->providers = g_list_append (priv->providers, new_data);
+ priv->providers_last = g_list_last (priv->providers);
+
if (priv->widget_path)
- rebuild_properties (context);
+ {
+ rebuild_properties (context);
+ clear_property_cache (context);
+ }
}
void
@@ -243,8 +288,16 @@ gtk_style_context_remove_provider (GtkStyleContext *context,
list = list->next;
}
- if (removed && priv->widget_path)
- rebuild_properties (context);
+ if (removed)
+ {
+ priv->providers_last = g_list_last (priv->providers);
+
+ if (priv->widget_path)
+ {
+ rebuild_properties (context);
+ clear_property_cache (context);
+ }
+ }
}
void
@@ -371,6 +424,7 @@ gtk_style_context_set_path (GtkStyleContext *context,
{
priv->widget_path = gtk_widget_path_copy (path);
rebuild_properties (context);
+ clear_property_cache (context);
}
}
@@ -623,6 +677,127 @@ gtk_style_context_has_child_class (GtkStyleContext *context,
return FALSE;
}
+static gint
+style_property_values_cmp (gconstpointer bsearch_node1,
+ gconstpointer bsearch_node2)
+{
+ const PropertyValue *val1 = bsearch_node1;
+ const PropertyValue *val2 = bsearch_node2;
+
+ if (val1->widget_type == val2->widget_type)
+ return val1->pspec < val2->pspec ? -1 : val1->pspec == val2->pspec ? 0 : 1;
+ else
+ return val1->widget_type < val2->widget_type ? -1 : 1;
+}
+
+const GValue *
+_gtk_style_context_peek_style_property (GtkStyleContext *context,
+ GType widget_type,
+ GParamSpec *pspec)
+{
+ GtkStyleContextPrivate *priv;
+ PropertyValue *pcache, key = { 0 };
+ GList *list;
+ guint i;
+
+ priv = GTK_STYLE_CONTEXT_GET_PRIVATE (context);
+
+ key.widget_type = widget_type;
+ key.pspec = pspec;
+
+ /* need value cache array */
+ if (!priv->property_cache)
+ priv->property_cache = g_array_new (FALSE, FALSE, sizeof (PropertyValue));
+ else
+ {
+ pcache = bsearch (&key,
+ priv->property_cache->data, priv->property_cache->len,
+ sizeof (PropertyValue), style_property_values_cmp);
+ if (pcache)
+ return &pcache->value;
+ }
+
+ i = 0;
+ while (i < priv->property_cache->len &&
+ style_property_values_cmp (&key, &g_array_index (priv->property_cache, PropertyValue, i)) >= 0)
+ i++;
+
+ g_array_insert_val (priv->property_cache, i, key);
+ pcache = &g_array_index (priv->property_cache, PropertyValue, i);
+
+ /* cache miss, initialize value type, then set contents */
+ g_param_spec_ref (pcache->pspec);
+ g_value_init (&pcache->value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+
+ if (priv->widget_path)
+ {
+ for (list = priv->providers_last; list; list = list->prev)
+ {
+ GtkStyleProviderData *data;
+
+ data = list->data;
+
+ if (gtk_style_provider_get_style_property (data->provider, priv->widget_path,
+ pspec->name, &pcache->value))
+ return &pcache->value;
+ }
+ }
+
+ /* not supplied by any provider, revert to default */
+ g_param_value_set_default (pspec, &pcache->value);
+
+ return &pcache->value;
+}
+
+void
+gtk_style_context_get_style_property (GtkStyleContext *context,
+ const gchar *property_name,
+ GValue *value)
+{
+ GtkStyleContextPrivate *priv;
+ GtkWidgetClass *widget_class;
+ GParamSpec *pspec;
+ const GValue *peek_value;
+ GType widget_type;
+
+ g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
+ g_return_if_fail (property_name != NULL);
+ g_return_if_fail (value != NULL);
+
+ priv = GTK_STYLE_CONTEXT_GET_PRIVATE (context);
+
+ if (!priv->widget_path)
+ return;
+
+ widget_type = gtk_widget_path_get_widget_type (priv->widget_path);
+
+ widget_class = g_type_class_ref (widget_type);
+ pspec = gtk_widget_class_find_style_property (widget_class, property_name);
+ g_type_class_unref (widget_class);
+
+ if (!pspec)
+ {
+ g_warning ("%s: widget class `%s' has no style property named `%s'",
+ G_STRLOC,
+ g_type_name (widget_type),
+ property_name);
+ return;
+ }
+
+ peek_value = _gtk_style_context_peek_style_property (context,
+ widget_type,
+ pspec);
+
+ if (G_VALUE_TYPE (value) == G_VALUE_TYPE (peek_value))
+ g_value_copy (peek_value, value);
+ else if (g_value_type_transformable (G_VALUE_TYPE (peek_value), G_VALUE_TYPE (value)))
+ g_value_transform (peek_value, value);
+ else
+ g_warning ("can't retrieve style property `%s' of type `%s' as value of type `%s'",
+ pspec->name,
+ G_VALUE_TYPE_NAME (peek_value),
+ G_VALUE_TYPE_NAME (value));
+}
/* Paint methods */
void
diff --git a/gtk/gtkstylecontext.h b/gtk/gtkstylecontext.h
index 2ef9ee1..a968f00 100644
--- a/gtk/gtkstylecontext.h
+++ b/gtk/gtkstylecontext.h
@@ -95,6 +95,15 @@ gboolean gtk_style_context_has_child_class (GtkStyleContext *context,
const gchar *class_name,
GtkChildClassFlags *flags_return);
+void gtk_style_context_get_style_property (GtkStyleContext *context,
+ const gchar *property_name,
+ GValue *value);
+
+/* Semi-private API */
+const GValue * _gtk_style_context_peek_style_property (GtkStyleContext *context,
+ GType widget_type,
+ GParamSpec *pspec);
+
/* Paint methods */
void gtk_render_check (GtkStyleContext *context,
cairo_t *cr,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]