GtkStyleContext: Add gtk_style_context_save/restore().

This API will be used to have savepoints when adding and removing
style classes information.
This commit is contained in:
Carlos Garnacho 2010-07-03 20:53:50 +02:00
parent 4a465d279d
commit 475f0fc266
2 changed files with 224 additions and 95 deletions

View File

@ -33,6 +33,7 @@
typedef struct GtkStyleContextPrivate GtkStyleContextPrivate; typedef struct GtkStyleContextPrivate GtkStyleContextPrivate;
typedef struct GtkStyleProviderData GtkStyleProviderData; typedef struct GtkStyleProviderData GtkStyleProviderData;
typedef struct GtkStyleRegion GtkStyleRegion;
typedef struct GtkChildClass GtkChildClass; typedef struct GtkChildClass GtkChildClass;
typedef struct PropertyValue PropertyValue; typedef struct PropertyValue PropertyValue;
@ -55,6 +56,12 @@ struct PropertyValue
GValue value; GValue value;
}; };
struct GtkStyleRegion
{
GArray *style_classes;
GArray *child_style_classes;
};
struct GtkStyleContextPrivate struct GtkStyleContextPrivate
{ {
GdkScreen *screen; GdkScreen *screen;
@ -70,8 +77,7 @@ struct GtkStyleContextPrivate
GArray *property_cache; GArray *property_cache;
GtkStateFlags state_flags; GtkStateFlags state_flags;
GList *style_classes; GSList *regions;
GList *child_style_classes;
GtkThemingEngine *theming_engine; GtkThemingEngine *theming_engine;
}; };
@ -115,10 +121,47 @@ gtk_style_context_class_init (GtkStyleContextClass *klass)
g_type_class_add_private (object_class, sizeof (GtkStyleContextPrivate)); g_type_class_add_private (object_class, sizeof (GtkStyleContextPrivate));
} }
static GtkStyleRegion *
style_region_new (void)
{
GtkStyleRegion *region;
region = g_slice_new0 (GtkStyleRegion);
region->style_classes = g_array_new (FALSE, FALSE, sizeof (GQuark));
region->child_style_classes = g_array_new (FALSE, FALSE, sizeof (GtkChildClass));
return region;
}
static void
style_region_free (GtkStyleRegion *region)
{
g_array_free (region->style_classes, TRUE);
g_array_free (region->child_style_classes, TRUE);
g_slice_free (GtkStyleRegion, region);
}
static GtkStyleRegion *
style_region_copy (const GtkStyleRegion *region)
{
GtkStyleRegion *copy;
copy = style_region_new ();
g_array_insert_vals (copy->style_classes, 0,
region->style_classes->data,
region->style_classes->len);
g_array_insert_vals (copy->child_style_classes, 0,
region->child_style_classes->data,
region->child_style_classes->len);
return copy;
}
static void static void
gtk_style_context_init (GtkStyleContext *style_context) gtk_style_context_init (GtkStyleContext *style_context)
{ {
GtkStyleContextPrivate *priv; GtkStyleContextPrivate *priv;
GtkStyleRegion *region;
priv = style_context->priv = G_TYPE_INSTANCE_GET_PRIVATE (style_context, priv = style_context->priv = G_TYPE_INSTANCE_GET_PRIVATE (style_context,
GTK_TYPE_STYLE_CONTEXT, GTK_TYPE_STYLE_CONTEXT,
@ -126,6 +169,10 @@ gtk_style_context_init (GtkStyleContext *style_context)
priv->store = gtk_style_set_new (); priv->store = gtk_style_set_new ();
priv->theming_engine = (GtkThemingEngine *) gtk_theming_engine_load (NULL); priv->theming_engine = (GtkThemingEngine *) gtk_theming_engine_load (NULL);
/* Create default region */
region = style_region_new ();
priv->regions = g_slist_prepend (priv->regions, region);
} }
static GtkStyleProviderData * static GtkStyleProviderData *
@ -186,6 +233,9 @@ gtk_style_context_finalize (GObject *object)
clear_property_cache (GTK_STYLE_CONTEXT (object)); clear_property_cache (GTK_STYLE_CONTEXT (object));
g_slist_foreach (priv->regions, (GFunc) style_region_free, NULL);
g_slist_free (priv->regions);
g_slist_foreach (priv->icon_factories, (GFunc) g_object_unref, NULL); g_slist_foreach (priv->icon_factories, (GFunc) g_object_unref, NULL);
g_slist_free (priv->icon_factories); g_slist_free (priv->icon_factories);
@ -548,13 +598,125 @@ gtk_style_context_get_path (GtkStyleContext *context)
return priv->widget_path; return priv->widget_path;
} }
void
gtk_style_context_save (GtkStyleContext *context)
{
GtkStyleContextPrivate *priv;
GtkStyleRegion *region;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
priv = context->priv;
g_assert (priv->regions != NULL);
region = style_region_copy (priv->regions->data);
priv->regions = g_slist_prepend (priv->regions, region);
}
void
gtk_style_context_restore (GtkStyleContext *context)
{
GtkStyleContextPrivate *priv;
GtkStyleRegion *region;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
priv = context->priv;
if (priv->regions)
{
region = priv->regions->data;
priv->regions = g_slist_remove (priv->regions, region);
style_region_free (region);
}
if (!priv->regions)
{
g_warning ("Unpaired gtk_style_context_restore() call");
/* Create default region */
region = style_region_new ();
priv->regions = g_slist_prepend (priv->regions, region);
}
}
static gboolean
style_class_find (GArray *array,
GQuark class_quark,
guint *position)
{
guint min, max, mid;
gboolean found = FALSE;
min = 0;
max = array->len - 1;
mid = max - min / 2;
do
{
GQuark item;
mid = min + max / 2;
item = g_array_index (array, GQuark, mid);
if (class_quark == item)
found = TRUE;
else if (class_quark > item)
min = mid + 1;
else
max = mid - 1;
}
while (!found && min < max);
if (position)
*position = mid;
return found;
}
static gboolean
child_style_class_find (GArray *array,
GQuark class_quark,
guint *position)
{
guint min, max, mid;
gboolean found = FALSE;
min = 0;
max = array->len - 1;
mid = max - min / 2;
do
{
GtkChildClass *child_class;
mid = min + max / 2;
child_class = &g_array_index (array, GtkChildClass, mid);
if (child_class->class_quark == class_quark)
found = TRUE;
else if (child_class->class_quark > class_quark)
min = mid + 1;
else
max = mid - 1;
}
while (!found && min < max);
if (position)
*position = mid;
return found;
}
void void
gtk_style_context_set_class (GtkStyleContext *context, gtk_style_context_set_class (GtkStyleContext *context,
const gchar *class_name) const gchar *class_name)
{ {
GtkStyleContextPrivate *priv; GtkStyleContextPrivate *priv;
GtkStyleRegion *region;
GQuark class_quark; GQuark class_quark;
GList *link; guint position;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (class_name != NULL); g_return_if_fail (class_name != NULL);
@ -562,28 +724,11 @@ gtk_style_context_set_class (GtkStyleContext *context,
priv = context->priv; priv = context->priv;
class_quark = g_quark_from_string (class_name); class_quark = g_quark_from_string (class_name);
link = priv->style_classes; g_assert (priv->regions != NULL);
region = priv->regions->data;
while (link) if (!style_class_find (region->style_classes, class_quark, &position))
{ g_array_insert_val (region->style_classes, position, class_quark);
GQuark link_quark;
link_quark = GPOINTER_TO_UINT (link->data);
if (link_quark == class_quark)
return;
else if (link_quark > class_quark)
{
priv->style_classes = g_list_insert_before (priv->style_classes,
link, GUINT_TO_POINTER (class_quark));
return;
}
link = link->next;
}
priv->style_classes = g_list_append (priv->style_classes,
GUINT_TO_POINTER (class_quark));
} }
void void
@ -591,7 +736,9 @@ gtk_style_context_unset_class (GtkStyleContext *context,
const gchar *class_name) const gchar *class_name)
{ {
GtkStyleContextPrivate *priv; GtkStyleContextPrivate *priv;
GtkStyleRegion *region;
GQuark class_quark; GQuark class_quark;
guint position;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (class_name != NULL); g_return_if_fail (class_name != NULL);
@ -602,8 +749,12 @@ gtk_style_context_unset_class (GtkStyleContext *context,
return; return;
priv = context->priv; priv = context->priv;
priv->style_classes = g_list_remove (priv->style_classes,
GUINT_TO_POINTER (class_quark)); g_assert (priv->regions != NULL);
region = priv->regions->data;
if (style_class_find (region->style_classes, class_quark, &position))
g_array_remove_index (region->style_classes, position);
} }
gboolean gboolean
@ -611,6 +762,7 @@ gtk_style_context_has_class (GtkStyleContext *context,
const gchar *class_name) const gchar *class_name)
{ {
GtkStyleContextPrivate *priv; GtkStyleContextPrivate *priv;
GtkStyleRegion *region;
GQuark class_quark; GQuark class_quark;
g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE); g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
@ -623,47 +775,41 @@ gtk_style_context_has_class (GtkStyleContext *context,
priv = context->priv; priv = context->priv;
if (g_list_find (priv->style_classes, g_assert (priv->regions != NULL);
GUINT_TO_POINTER (class_quark))) region = priv->regions->data;
if (style_class_find (region->style_classes, class_quark, NULL))
return TRUE; return TRUE;
return FALSE; return FALSE;
} }
static gint
child_style_class_compare (gconstpointer p1,
gconstpointer p2)
{
const GtkChildClass *c1, *c2;
c1 = p1;
c2 = p2;
return (gint) c1->class_quark - c2->class_quark;
}
GList * GList *
gtk_style_context_list_child_classes (GtkStyleContext *context) gtk_style_context_list_child_classes (GtkStyleContext *context)
{ {
GtkStyleContextPrivate *priv; GtkStyleContextPrivate *priv;
GtkStyleRegion *region;
GList *classes = NULL; GList *classes = NULL;
GList *link; guint i;
g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL); g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
priv = context->priv; priv = context->priv;
link = priv->child_style_classes;
while (link) g_assert (priv->regions != NULL);
region = priv->regions->data;
for (i = 0; i < region->child_style_classes->len; i++)
{ {
GtkChildClass *link_class; GtkChildClass *child_class;
const gchar *child_class; const gchar *class_name;
link_class = link->data; child_class = &g_array_index (region->child_style_classes,
link = link->next; GtkChildClass,
i);
child_class = g_quark_to_string (link_class->class_quark); class_name = g_quark_to_string (child_class->class_quark);
classes = g_list_prepend (classes, (gchar *) child_class); classes = g_list_prepend (classes, (gchar *) class_name);
} }
return classes; return classes;
@ -675,43 +821,28 @@ gtk_style_context_set_child_class (GtkStyleContext *context,
GtkChildClassFlags flags) GtkChildClassFlags flags)
{ {
GtkStyleContextPrivate *priv; GtkStyleContextPrivate *priv;
GtkChildClass *child_class; GtkStyleRegion *region;
GQuark class_quark; GQuark class_quark;
GList *link; guint position;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (class_name != NULL); g_return_if_fail (class_name != NULL);
priv = context->priv; priv = context->priv;
class_quark = g_quark_from_string (class_name); class_quark = g_quark_from_string (class_name);
link = priv->child_style_classes;
while (link) g_assert (priv->regions != NULL);
region = priv->regions->data;
if (!child_style_class_find (region->child_style_classes, class_quark, &position))
{ {
GtkChildClass *link_class; GtkChildClass child_class;
link_class = link->data; child_class.class_quark = class_quark;
child_class.flags = flags;
if (link_class->class_quark == class_quark) g_array_insert_val (region->child_style_classes, position, child_class);
{
link_class->flags = flags;
return;
} }
else if (link_class->class_quark > class_quark)
break;
link = link->next;
}
child_class = g_slice_new0 (GtkChildClass);
child_class->class_quark = class_quark;
child_class->flags = flags;
if (link)
priv->child_style_classes = g_list_insert_before (priv->child_style_classes,
link, child_class);
else
priv->child_style_classes = g_list_append (priv->child_style_classes, child_class);
} }
void void
@ -719,9 +850,9 @@ gtk_style_context_unset_child_class (GtkStyleContext *context,
const gchar *class_name) const gchar *class_name)
{ {
GtkStyleContextPrivate *priv; GtkStyleContextPrivate *priv;
GtkChildClass child_class; GtkStyleRegion *region;
GQuark class_quark; GQuark class_quark;
GList *link; guint position;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (class_name != NULL); g_return_if_fail (class_name != NULL);
@ -732,17 +863,12 @@ gtk_style_context_unset_child_class (GtkStyleContext *context,
return; return;
priv = context->priv; priv = context->priv;
child_class.class_quark = class_quark;
link = g_list_find_custom (priv->child_style_classes, g_assert (priv->regions != NULL);
&child_class, child_style_class_compare); region = priv->regions->data;
if (link) if (child_style_class_find (region->child_style_classes, class_quark, &position))
{ g_array_remove_index (region->child_style_classes, position);
priv->child_style_classes = g_list_remove_link (priv->child_style_classes, link);
g_slice_free (GtkChildClass, link->data);
g_list_free1 (link);
}
} }
gboolean gboolean
@ -751,9 +877,9 @@ gtk_style_context_has_child_class (GtkStyleContext *context,
GtkChildClassFlags *flags_return) GtkChildClassFlags *flags_return)
{ {
GtkStyleContextPrivate *priv; GtkStyleContextPrivate *priv;
GtkChildClass child_class; GtkStyleRegion *region;
GQuark class_quark; GQuark class_quark;
GList *link; guint position;
g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE); g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
g_return_val_if_fail (class_name != NULL, FALSE); g_return_val_if_fail (class_name != NULL, FALSE);
@ -767,21 +893,21 @@ gtk_style_context_has_child_class (GtkStyleContext *context,
return FALSE; return FALSE;
priv = context->priv; priv = context->priv;
child_class.class_quark = class_quark;
link = g_list_find_custom (priv->child_style_classes, g_assert (priv->regions != NULL);
&child_class, child_style_class_compare); region = priv->regions->data;
if (link) if (child_style_class_find (region->child_style_classes, class_quark, &position))
{ {
if (flags_return) if (flags_return)
{ {
GtkChildClass *found_class; GtkChildClass *child_class;
found_class = link->data; child_class = &g_array_index (region->child_style_classes,
*flags_return = found_class->flags; GtkChildClass, position);
*flags_return = child_class->flags;
} }
return TRUE; return TRUE;
} }

View File

@ -56,6 +56,9 @@ void gtk_style_context_add_provider (GtkStyleContext *context,
void gtk_style_context_remove_provider (GtkStyleContext *context, void gtk_style_context_remove_provider (GtkStyleContext *context,
GtkStyleProvider *provider); GtkStyleProvider *provider);
void gtk_style_context_save (GtkStyleContext *context);
void gtk_style_context_restore (GtkStyleContext *context);
void gtk_style_context_get_property (GtkStyleContext *context, void gtk_style_context_get_property (GtkStyleContext *context,
const gchar *property, const gchar *property,
GtkStateType state, GtkStateType state,