2012-03-16 04:14:41 +00:00
|
|
|
/* GTK - The GIMP Toolkit
|
|
|
|
* Copyright (C) 2012 Benjamin Otte <otte@gnome.org>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser 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
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include "gtkstylecascadeprivate.h"
|
|
|
|
|
|
|
|
#include "gtkstyleprovider.h"
|
|
|
|
#include "gtkstyleproviderprivate.h"
|
|
|
|
|
|
|
|
typedef struct _GtkStyleCascadeIter GtkStyleCascadeIter;
|
|
|
|
typedef struct _GtkStyleProviderData GtkStyleProviderData;
|
|
|
|
|
|
|
|
struct _GtkStyleCascadeIter {
|
|
|
|
int parent_index; /* pointing at last index that was returned, not next one that should be returned */
|
|
|
|
int index; /* pointing at last index that was returned, not next one that should be returned */
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _GtkStyleProviderData
|
|
|
|
{
|
|
|
|
GtkStyleProvider *provider;
|
|
|
|
guint priority;
|
|
|
|
};
|
|
|
|
|
|
|
|
static GtkStyleProvider *
|
|
|
|
gtk_style_cascade_iter_next (GtkStyleCascade *cascade,
|
|
|
|
GtkStyleCascadeIter *iter)
|
|
|
|
{
|
|
|
|
if (iter->parent_index > 0)
|
|
|
|
{
|
|
|
|
if (iter->index > 0)
|
|
|
|
{
|
|
|
|
GtkStyleProviderData *data, *parent_data;
|
|
|
|
|
|
|
|
data = &g_array_index (cascade->providers, GtkStyleProviderData, iter->index - 1);
|
|
|
|
parent_data = &g_array_index (cascade->parent->providers, GtkStyleProviderData, iter->parent_index - 1);
|
|
|
|
|
|
|
|
if (data->priority >= parent_data->priority)
|
|
|
|
{
|
|
|
|
iter->index--;
|
|
|
|
return data->provider;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
iter->parent_index--;
|
|
|
|
return parent_data->provider;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
iter->parent_index--;
|
|
|
|
return g_array_index (cascade->parent->providers, GtkStyleProviderData, iter->parent_index).provider;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (iter->index > 0)
|
|
|
|
{
|
|
|
|
iter->index--;
|
|
|
|
return g_array_index (cascade->providers, GtkStyleProviderData, iter->index).provider;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkStyleProvider *
|
|
|
|
gtk_style_cascade_iter_init (GtkStyleCascade *cascade,
|
|
|
|
GtkStyleCascadeIter *iter)
|
|
|
|
{
|
|
|
|
iter->parent_index = cascade->parent ? cascade->parent->providers->len : 0;
|
|
|
|
iter->index = cascade->providers->len;
|
|
|
|
|
|
|
|
return gtk_style_cascade_iter_next (cascade, iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkStyleProperties *
|
|
|
|
gtk_style_cascade_get_style (GtkStyleProvider *provider,
|
|
|
|
GtkWidgetPath *path)
|
|
|
|
{
|
|
|
|
/* This function is not used anymore by GTK and nobody
|
|
|
|
* else is ever supposed to call it */
|
|
|
|
g_warn_if_reached ();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
gtk_style_cascade_get_style_property (GtkStyleProvider *provider,
|
|
|
|
GtkWidgetPath *path,
|
|
|
|
GtkStateFlags state,
|
|
|
|
GParamSpec *pspec,
|
|
|
|
GValue *value)
|
|
|
|
{
|
|
|
|
GtkStyleCascade *cascade = GTK_STYLE_CASCADE (provider);
|
|
|
|
GtkStyleCascadeIter iter;
|
|
|
|
GtkStyleProvider *item;
|
|
|
|
|
|
|
|
for (item = gtk_style_cascade_iter_init (cascade, &iter);
|
|
|
|
item;
|
|
|
|
item = gtk_style_cascade_iter_next (cascade, &iter))
|
|
|
|
{
|
|
|
|
if (gtk_style_provider_get_style_property (item,
|
|
|
|
path,
|
|
|
|
state,
|
|
|
|
pspec,
|
|
|
|
value))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkIconFactory *
|
|
|
|
gtk_style_cascade_get_icon_factory (GtkStyleProvider *provider,
|
|
|
|
GtkWidgetPath *path)
|
|
|
|
{
|
|
|
|
/* If anyone ever implements get_icon_factory(), I'll
|
|
|
|
* look at this function. Until then I'll just: */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gtk_style_cascade_provider_iface_init (GtkStyleProviderIface *iface)
|
|
|
|
{
|
|
|
|
iface->get_style = gtk_style_cascade_get_style;
|
|
|
|
iface->get_style_property = gtk_style_cascade_get_style_property;
|
|
|
|
iface->get_icon_factory = gtk_style_cascade_get_icon_factory;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkSymbolicColor *
|
|
|
|
gtk_style_cascade_get_color (GtkStyleProviderPrivate *provider,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
GtkStyleCascade *cascade = GTK_STYLE_CASCADE (provider);
|
|
|
|
GtkStyleCascadeIter iter;
|
|
|
|
GtkSymbolicColor *symbolic;
|
|
|
|
GtkStyleProvider *item;
|
|
|
|
|
|
|
|
for (item = gtk_style_cascade_iter_init (cascade, &iter);
|
|
|
|
item;
|
|
|
|
item = gtk_style_cascade_iter_next (cascade, &iter))
|
|
|
|
{
|
|
|
|
if (GTK_IS_STYLE_PROVIDER_PRIVATE (item))
|
|
|
|
{
|
|
|
|
symbolic = _gtk_style_provider_private_get_color (GTK_STYLE_PROVIDER_PRIVATE (item), name);
|
|
|
|
if (symbolic)
|
|
|
|
return symbolic;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If somebody hits this code path, shout at them */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gtk_style_cascade_lookup (GtkStyleProviderPrivate *provider,
|
2012-03-17 01:36:11 +00:00
|
|
|
const GtkCssMatcher *matcher,
|
2012-03-16 04:14:41 +00:00
|
|
|
GtkCssLookup *lookup)
|
|
|
|
{
|
|
|
|
GtkStyleCascade *cascade = GTK_STYLE_CASCADE (provider);
|
|
|
|
GtkStyleCascadeIter iter;
|
|
|
|
GtkStyleProvider *item;
|
|
|
|
|
|
|
|
for (item = gtk_style_cascade_iter_init (cascade, &iter);
|
|
|
|
item;
|
|
|
|
item = gtk_style_cascade_iter_next (cascade, &iter))
|
|
|
|
{
|
|
|
|
if (GTK_IS_STYLE_PROVIDER_PRIVATE (item))
|
|
|
|
{
|
|
|
|
_gtk_style_provider_private_lookup (GTK_STYLE_PROVIDER_PRIVATE (item),
|
2012-03-17 01:36:11 +00:00
|
|
|
matcher,
|
2012-03-16 04:14:41 +00:00
|
|
|
lookup);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-03-17 01:36:11 +00:00
|
|
|
/* you lose */
|
|
|
|
g_warn_if_reached ();
|
2012-03-16 04:14:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-17 20:09:51 +00:00
|
|
|
static GtkCssChange
|
|
|
|
gtk_style_cascade_get_change (GtkStyleProviderPrivate *provider,
|
|
|
|
const GtkCssMatcher *matcher)
|
|
|
|
{
|
|
|
|
GtkStyleCascade *cascade = GTK_STYLE_CASCADE (provider);
|
|
|
|
GtkStyleCascadeIter iter;
|
|
|
|
GtkStyleProvider *item;
|
|
|
|
GtkCssChange change = 0;
|
|
|
|
|
|
|
|
for (item = gtk_style_cascade_iter_init (cascade, &iter);
|
|
|
|
item;
|
|
|
|
item = gtk_style_cascade_iter_next (cascade, &iter))
|
|
|
|
{
|
|
|
|
if (GTK_IS_STYLE_PROVIDER_PRIVATE (item))
|
|
|
|
{
|
|
|
|
change |= _gtk_style_provider_private_get_change (GTK_STYLE_PROVIDER_PRIVATE (item),
|
|
|
|
matcher);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_return_val_if_reached (GTK_CSS_CHANGE_ANY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return change;
|
|
|
|
}
|
|
|
|
|
2012-03-16 04:14:41 +00:00
|
|
|
static void
|
|
|
|
gtk_style_cascade_provider_private_iface_init (GtkStyleProviderPrivateInterface *iface)
|
|
|
|
{
|
|
|
|
iface->get_color = gtk_style_cascade_get_color;
|
|
|
|
iface->lookup = gtk_style_cascade_lookup;
|
2012-03-17 20:09:51 +00:00
|
|
|
iface->get_change = gtk_style_cascade_get_change;
|
2012-03-16 04:14:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
G_DEFINE_TYPE_EXTENDED (GtkStyleCascade, _gtk_style_cascade, G_TYPE_OBJECT, 0,
|
|
|
|
G_IMPLEMENT_INTERFACE (GTK_TYPE_STYLE_PROVIDER,
|
|
|
|
gtk_style_cascade_provider_iface_init)
|
|
|
|
G_IMPLEMENT_INTERFACE (GTK_TYPE_STYLE_PROVIDER_PRIVATE,
|
|
|
|
gtk_style_cascade_provider_private_iface_init));
|
|
|
|
|
|
|
|
static void
|
|
|
|
gtk_style_cascade_dispose (GObject *object)
|
|
|
|
{
|
|
|
|
GtkStyleCascade *cascade = GTK_STYLE_CASCADE (object);
|
|
|
|
|
|
|
|
_gtk_style_cascade_set_parent (cascade, NULL);
|
|
|
|
g_array_unref (cascade->providers);
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (_gtk_style_cascade_parent_class)->dispose (object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_gtk_style_cascade_class_init (GtkStyleCascadeClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
|
|
|
object_class->dispose = gtk_style_cascade_dispose;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
style_provider_data_clear (gpointer data_)
|
|
|
|
{
|
|
|
|
GtkStyleProviderData *data = data_;
|
|
|
|
|
|
|
|
g_object_unref (data->provider);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_gtk_style_cascade_init (GtkStyleCascade *cascade)
|
|
|
|
{
|
|
|
|
cascade->providers = g_array_new (FALSE, FALSE, sizeof (GtkStyleProviderData));
|
|
|
|
g_array_set_clear_func (cascade->providers, style_provider_data_clear);
|
|
|
|
}
|
|
|
|
|
|
|
|
GtkStyleCascade *
|
|
|
|
_gtk_style_cascade_new (void)
|
|
|
|
{
|
|
|
|
return g_object_new (GTK_TYPE_STYLE_CASCADE, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
GtkStyleCascade *
|
|
|
|
_gtk_style_cascade_get_for_screen (GdkScreen *screen)
|
|
|
|
{
|
|
|
|
GtkStyleCascade *cascade;
|
|
|
|
static GQuark quark = 0;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
|
|
|
|
|
|
|
|
if (G_UNLIKELY (!quark))
|
|
|
|
quark = g_quark_from_static_string ("gtk-style-cascade");
|
|
|
|
|
|
|
|
cascade = g_object_get_qdata (G_OBJECT (screen), quark);
|
|
|
|
if (cascade == NULL)
|
|
|
|
{
|
|
|
|
cascade = _gtk_style_cascade_new ();
|
|
|
|
g_object_set_qdata_full (G_OBJECT (screen), quark, cascade, g_object_unref);
|
|
|
|
}
|
|
|
|
|
|
|
|
return cascade;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_gtk_style_cascade_set_parent (GtkStyleCascade *cascade,
|
|
|
|
GtkStyleCascade *parent)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GTK_IS_STYLE_CASCADE (cascade));
|
|
|
|
g_return_if_fail (parent == NULL || GTK_IS_STYLE_CASCADE (parent));
|
|
|
|
if (parent)
|
|
|
|
g_return_if_fail (parent->parent == NULL);
|
|
|
|
|
|
|
|
if (cascade->parent == parent)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (parent)
|
|
|
|
g_object_ref (parent);
|
|
|
|
|
|
|
|
if (cascade->parent)
|
|
|
|
g_object_unref (cascade->parent);
|
|
|
|
|
|
|
|
cascade->parent = parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_gtk_style_cascade_add_provider (GtkStyleCascade *cascade,
|
|
|
|
GtkStyleProvider *provider,
|
|
|
|
guint priority)
|
|
|
|
{
|
|
|
|
GtkStyleProviderData data;
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
g_return_if_fail (GTK_IS_STYLE_CASCADE (cascade));
|
|
|
|
g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
|
|
|
|
g_return_if_fail (GTK_STYLE_PROVIDER (cascade) != provider);
|
|
|
|
|
|
|
|
data.provider = g_object_ref (provider);
|
|
|
|
data.priority = priority;
|
|
|
|
|
|
|
|
/* ensure it gets removed first */
|
|
|
|
_gtk_style_cascade_remove_provider (cascade, provider);
|
|
|
|
|
|
|
|
for (i = 0; i < cascade->providers->len; i++)
|
|
|
|
{
|
|
|
|
if (g_array_index (cascade->providers, GtkStyleProviderData, i).priority > priority)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
g_array_insert_val (cascade->providers, i, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_gtk_style_cascade_remove_provider (GtkStyleCascade *cascade,
|
|
|
|
GtkStyleProvider *provider)
|
|
|
|
{
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
g_return_if_fail (GTK_IS_STYLE_CASCADE (cascade));
|
|
|
|
g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
|
|
|
|
|
|
|
|
for (i = 0; i < cascade->providers->len; i++)
|
|
|
|
{
|
|
|
|
GtkStyleProviderData *data = &g_array_index (cascade->providers, GtkStyleProviderData, i);
|
|
|
|
|
|
|
|
if (data->provider == provider)
|
|
|
|
{
|
|
|
|
g_array_remove_index (cascade->providers, i);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|