css: Add initial support for Houdini-style paint() images
This adds gtk_style_context_add_paint_for_display() which allows to add a GdkPaintable with a name to the CSS machinery and then allows using it via "-gtk-paint(name)" inside the CSS as an image. This essentially allows applications to register snapshot functions for any part of the CSS machinery that is an image. I have no idea if this is a good idea, because it further blurs the lines between theme and application, but it *is* quite powerful. The inspiration was https://drafts.css-houdini.org/css-paint-api/ Though we do not support properties or a constructor, but so far require the constructed image directly.
This commit is contained in:
@@ -26,13 +26,14 @@
|
||||
|
||||
/* for the types only */
|
||||
#include "gtk/gtkcssimagecrossfadeprivate.h"
|
||||
#include "gtk/gtkcssimagefallbackprivate.h"
|
||||
#include "gtk/gtkcssimageiconthemeprivate.h"
|
||||
#include "gtk/gtkcssimagelinearprivate.h"
|
||||
#include "gtk/gtkcssimagepaintprivate.h"
|
||||
#include "gtk/gtkcssimageradialprivate.h"
|
||||
#include "gtk/gtkcssimageurlprivate.h"
|
||||
#include "gtk/gtkcssimagescaledprivate.h"
|
||||
#include "gtk/gtkcssimagerecolorprivate.h"
|
||||
#include "gtk/gtkcssimagefallbackprivate.h"
|
||||
#include "gtk/gtkcssimagescaledprivate.h"
|
||||
#include "gtk/gtkcssimageurlprivate.h"
|
||||
#include "gtk/gtkcssimagewin32private.h"
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE (GtkCssImage, _gtk_css_image, G_TYPE_OBJECT)
|
||||
@@ -501,6 +502,7 @@ gtk_css_image_get_parser_type (GtkCssParser *parser)
|
||||
} image_types[] = {
|
||||
{ "url", _gtk_css_image_url_get_type },
|
||||
{ "-gtk-icontheme", _gtk_css_image_icon_theme_get_type },
|
||||
{ "-gtk-paint", gtk_css_image_paint_get_type },
|
||||
{ "-gtk-scaled", _gtk_css_image_scaled_get_type },
|
||||
{ "-gtk-recolor", _gtk_css_image_recolor_get_type },
|
||||
{ "-gtk-win32-theme-part", _gtk_css_image_win32_get_type },
|
||||
|
||||
147
gtk/gtkcssimagepaint.c
Normal file
147
gtk/gtkcssimagepaint.c
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright © 2018 Benjamin Otte
|
||||
*
|
||||
* 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.1 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/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "gtkcssimagepaintprivate.h"
|
||||
|
||||
#include "gtkcssimageinvalidprivate.h"
|
||||
#include "gtkcssimagepaintableprivate.h"
|
||||
#include "gtkstyleproviderprivate.h"
|
||||
|
||||
G_DEFINE_TYPE (GtkCssImagePaint, gtk_css_image_paint, GTK_TYPE_CSS_IMAGE)
|
||||
|
||||
static void
|
||||
gtk_css_image_paint_snapshot (GtkCssImage *image,
|
||||
GtkSnapshot *snapshot,
|
||||
double width,
|
||||
double height)
|
||||
{
|
||||
}
|
||||
|
||||
static GtkCssImage *
|
||||
gtk_css_image_paint_compute (GtkCssImage *image,
|
||||
guint property_id,
|
||||
GtkStyleProvider *provider,
|
||||
GtkCssStyle *style,
|
||||
GtkCssStyle *parent_style)
|
||||
{
|
||||
GtkCssImagePaint *paint = GTK_CSS_IMAGE_PAINT (image);
|
||||
GdkPaintable *paintable, *static_paintable;
|
||||
GtkCssImage *result;
|
||||
|
||||
paintable = gtk_style_provider_get_paint (provider, paint->name);
|
||||
if (paintable == NULL)
|
||||
return gtk_css_image_invalid_new ();
|
||||
|
||||
static_paintable = gdk_paintable_get_current_image (paintable);
|
||||
result = gtk_css_image_paintable_new (paintable, static_paintable);
|
||||
g_object_unref (static_paintable);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_css_image_paint_equal (GtkCssImage *image1,
|
||||
GtkCssImage *image2)
|
||||
{
|
||||
GtkCssImagePaint *paint1 = GTK_CSS_IMAGE_PAINT (image1);
|
||||
GtkCssImagePaint *paint2 = GTK_CSS_IMAGE_PAINT (image2);
|
||||
|
||||
return g_str_equal (paint1->name, paint2->name);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_css_image_paint_parse (GtkCssImage *image,
|
||||
GtkCssParser *parser)
|
||||
{
|
||||
GtkCssImagePaint *paint = GTK_CSS_IMAGE_PAINT (image);
|
||||
|
||||
if (!_gtk_css_parser_try (parser, "-gtk-paint", TRUE))
|
||||
{
|
||||
_gtk_css_parser_error (parser, "'-gtk-paint'");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!_gtk_css_parser_try (parser, "(", TRUE))
|
||||
{
|
||||
_gtk_css_parser_error (parser, "Expected '(' after '-gtk-paint'");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
paint->name = _gtk_css_parser_try_ident (parser, TRUE);
|
||||
if (paint->name == NULL)
|
||||
{
|
||||
_gtk_css_parser_error (parser, "Expected the name of the paint");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!_gtk_css_parser_try (parser, ")", TRUE))
|
||||
{
|
||||
_gtk_css_parser_error (parser,
|
||||
"Expected ')' at end of '-gtk-paint'");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_image_paint_print (GtkCssImage *image,
|
||||
GString *string)
|
||||
{
|
||||
GtkCssImagePaint *paint = GTK_CSS_IMAGE_PAINT (image);
|
||||
|
||||
g_string_append (string, "paint (");
|
||||
g_string_append (string, paint->name);
|
||||
g_string_append (string, ")");
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_image_paint_dispose (GObject *object)
|
||||
{
|
||||
GtkCssImagePaint *paint = GTK_CSS_IMAGE_PAINT (object);
|
||||
|
||||
g_clear_pointer (&paint->name, g_free);
|
||||
|
||||
G_OBJECT_CLASS (gtk_css_image_paint_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_image_paint_class_init (GtkCssImagePaintClass *klass)
|
||||
{
|
||||
GtkCssImageClass *image_class = GTK_CSS_IMAGE_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
image_class->compute = gtk_css_image_paint_compute;
|
||||
image_class->snapshot = gtk_css_image_paint_snapshot;
|
||||
image_class->parse = gtk_css_image_paint_parse;
|
||||
image_class->print = gtk_css_image_paint_print;
|
||||
image_class->equal = gtk_css_image_paint_equal;
|
||||
|
||||
object_class->dispose = gtk_css_image_paint_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_image_paint_init (GtkCssImagePaint *image_paint)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ gtk_css_image_paintable_is_dynamic (GtkCssImage *image)
|
||||
{
|
||||
GtkCssImagePaintable *paintable = GTK_CSS_IMAGE_PAINTABLE (image);
|
||||
|
||||
return (gdk_paintable_get_flags (paintable->paintable) & GDK_PAINTABLE_IMMUTABLE) == GDK_PAINTABLE_IMMUTABLE;
|
||||
return (gdk_paintable_get_flags (paintable->paintable) & GDK_PAINTABLE_IMMUTABLE) != GDK_PAINTABLE_IMMUTABLE;
|
||||
}
|
||||
|
||||
static GtkCssImage *
|
||||
|
||||
53
gtk/gtkcssimagepaintprivate.h
Normal file
53
gtk/gtkcssimagepaintprivate.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright © 2018 Benjamin Otte
|
||||
*
|
||||
* 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.1 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/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_CSS_IMAGE_PAINT_PRIVATE_H__
|
||||
#define __GTK_CSS_IMAGE_PAINT_PRIVATE_H__
|
||||
|
||||
#include "gtk/gtkcssimageprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_CSS_IMAGE_PAINT (gtk_css_image_paint_get_type ())
|
||||
#define GTK_CSS_IMAGE_PAINT(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_IMAGE_PAINT, GtkCssImagePaint))
|
||||
#define GTK_CSS_IMAGE_PAINT_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_IMAGE_PAINT, GtkCssImagePaintClass))
|
||||
#define GTK_IS_CSS_IMAGE_PAINT(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_IMAGE_PAINT))
|
||||
#define GTK_IS_CSS_IMAGE_PAINT_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_IMAGE_PAINT))
|
||||
#define GTK_CSS_IMAGE_PAINT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_IMAGE_PAINT, GtkCssImagePaintClass))
|
||||
|
||||
typedef struct _GtkCssImagePaint GtkCssImagePaint;
|
||||
typedef struct _GtkCssImagePaintClass GtkCssImagePaintClass;
|
||||
|
||||
struct _GtkCssImagePaint
|
||||
{
|
||||
GtkCssImage parent;
|
||||
|
||||
char *name; /* the name of the paint */
|
||||
};
|
||||
|
||||
struct _GtkCssImagePaintClass
|
||||
{
|
||||
GtkCssImageClass parent_class;
|
||||
};
|
||||
|
||||
GType gtk_css_image_paint_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_CSS_IMAGE_PAINT_PRIVATE_H__ */
|
||||
@@ -155,6 +155,42 @@ gtk_style_cascade_get_color (GtkStyleProvider *provider,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GdkPaintable *
|
||||
gtk_style_cascade_get_paint (GtkStyleProvider *provider,
|
||||
const char *name)
|
||||
{
|
||||
GtkStyleCascade *cascade = GTK_STYLE_CASCADE (provider);
|
||||
GtkStyleCascadeIter iter;
|
||||
GdkPaintable *paintable;
|
||||
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 (item))
|
||||
{
|
||||
paintable = gtk_style_provider_get_paint (GTK_STYLE_PROVIDER (item), name);
|
||||
if (paintable)
|
||||
{
|
||||
gtk_style_cascade_iter_clear (&iter);
|
||||
return paintable;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If somebody hits this code path, shout at them */
|
||||
}
|
||||
}
|
||||
|
||||
gtk_style_cascade_iter_clear (&iter);
|
||||
|
||||
if (cascade->paints == NULL)
|
||||
return NULL;
|
||||
|
||||
return g_hash_table_lookup (cascade->paints, name);
|
||||
}
|
||||
|
||||
static int
|
||||
gtk_style_cascade_get_scale (GtkStyleProvider *provider)
|
||||
{
|
||||
@@ -227,6 +263,7 @@ static void
|
||||
gtk_style_cascade_provider_iface_init (GtkStyleProviderInterface *iface)
|
||||
{
|
||||
iface->get_color = gtk_style_cascade_get_color;
|
||||
iface->get_paint = gtk_style_cascade_get_paint;
|
||||
iface->get_settings = gtk_style_cascade_get_settings;
|
||||
iface->get_scale = gtk_style_cascade_get_scale;
|
||||
iface->get_keyframes = gtk_style_cascade_get_keyframes;
|
||||
@@ -244,6 +281,7 @@ gtk_style_cascade_dispose (GObject *object)
|
||||
|
||||
_gtk_style_cascade_set_parent (cascade, NULL);
|
||||
g_array_unref (cascade->providers);
|
||||
g_clear_pointer (&cascade->paints, g_hash_table_unref);
|
||||
|
||||
G_OBJECT_CLASS (_gtk_style_cascade_parent_class)->dispose (object);
|
||||
}
|
||||
@@ -386,3 +424,39 @@ _gtk_style_cascade_get_scale (GtkStyleCascade *cascade)
|
||||
|
||||
return cascade->scale;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_style_cascade_add_paint (GtkStyleCascade *cascade,
|
||||
const char *name,
|
||||
GdkPaintable *paintable)
|
||||
{
|
||||
if (cascade->paints == NULL)
|
||||
{
|
||||
cascade->paints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g_hash_table_contains (cascade->paints, name))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_hash_table_insert (cascade->paints, g_strdup (name), g_object_ref (paintable));
|
||||
gtk_style_provider_changed (GTK_STYLE_PROVIDER (cascade));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_style_cascade_remove_paint (GtkStyleCascade *cascade,
|
||||
const char *name)
|
||||
{
|
||||
gboolean result;
|
||||
|
||||
if (cascade->paints == NULL)
|
||||
return FALSE;
|
||||
|
||||
result = g_hash_table_remove (cascade->paints, name);
|
||||
if (result)
|
||||
gtk_style_provider_changed (GTK_STYLE_PROVIDER (cascade));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ struct _GtkStyleCascade
|
||||
GObject object;
|
||||
|
||||
GtkStyleCascade *parent;
|
||||
GHashTable *paints;
|
||||
GArray *providers;
|
||||
int scale;
|
||||
};
|
||||
@@ -62,6 +63,11 @@ void _gtk_style_cascade_add_provider (GtkStyleCascade
|
||||
guint priority);
|
||||
void _gtk_style_cascade_remove_provider (GtkStyleCascade *cascade,
|
||||
GtkStyleProvider *provider);
|
||||
gboolean gtk_style_cascade_add_paint (GtkStyleCascade *cascade,
|
||||
const char *name,
|
||||
GdkPaintable *paintable);
|
||||
gboolean gtk_style_cascade_remove_paint (GtkStyleCascade *cascade,
|
||||
const char *name);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -638,6 +638,34 @@ gtk_style_context_remove_provider_for_display (GdkDisplay *display,
|
||||
_gtk_style_cascade_remove_provider (cascade, provider);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_style_context_add_paint_for_display (GdkDisplay *display,
|
||||
const char *name,
|
||||
GdkPaintable *paintable)
|
||||
{
|
||||
GtkStyleCascade *cascade;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
|
||||
g_return_val_if_fail (name != NULL, FALSE);
|
||||
g_return_val_if_fail (GDK_IS_PAINTABLE (paintable), FALSE);
|
||||
|
||||
cascade = _gtk_settings_get_style_cascade (gtk_settings_get_for_display (display), 1);
|
||||
return gtk_style_cascade_add_paint (cascade, name, paintable);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_style_context_remove_paint_for_display (GdkDisplay *display,
|
||||
const char *name)
|
||||
{
|
||||
GtkStyleCascade *cascade;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
|
||||
g_return_val_if_fail (name != NULL, FALSE);
|
||||
|
||||
cascade = _gtk_settings_get_style_cascade (gtk_settings_get_for_display (display), 1);
|
||||
return gtk_style_cascade_remove_paint (cascade, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_style_context_get_section:
|
||||
* @context: a #GtkStyleContext
|
||||
|
||||
@@ -945,6 +945,13 @@ void gtk_style_context_add_provider_for_display (GdkDisplay *display,
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_style_context_remove_provider_for_display (GdkDisplay *display,
|
||||
GtkStyleProvider *provider);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_style_context_add_paint_for_display (GdkDisplay *display,
|
||||
const char *name,
|
||||
GdkPaintable *paintable);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_style_context_remove_paint_for_display(GdkDisplay *display,
|
||||
const char *name);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_style_context_add_provider (GtkStyleContext *context,
|
||||
|
||||
@@ -153,6 +153,22 @@ gtk_style_provider_get_scale (GtkStyleProvider *provider)
|
||||
return iface->get_scale (provider);
|
||||
}
|
||||
|
||||
GdkPaintable *
|
||||
gtk_style_provider_get_paint (GtkStyleProvider *provider,
|
||||
const char *name)
|
||||
{
|
||||
GtkStyleProviderInterface *iface;
|
||||
|
||||
gtk_internal_return_val_if_fail (GTK_IS_STYLE_PROVIDER (provider), NULL);
|
||||
|
||||
iface = GTK_STYLE_PROVIDER_GET_INTERFACE (provider);
|
||||
|
||||
if (!iface->get_paint)
|
||||
return NULL;
|
||||
|
||||
return iface->get_paint (provider, name);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_style_provider_emit_error (GtkStyleProvider *provider,
|
||||
GtkCssSection *section,
|
||||
|
||||
@@ -35,7 +35,9 @@ struct _GtkStyleProviderInterface
|
||||
{
|
||||
GTypeInterface g_iface;
|
||||
|
||||
GtkCssValue * (* get_color) (GtkStyleProvider *provider,
|
||||
GtkCssValue * (* get_color) (GtkStyleProvider *provider,
|
||||
const char *name);
|
||||
GdkPaintable * (* get_paint) (GtkStyleProvider *provider,
|
||||
const char *name);
|
||||
GtkSettings * (* get_settings) (GtkStyleProvider *provider);
|
||||
GtkCssKeyframes * (* get_keyframes) (GtkStyleProvider *provider,
|
||||
@@ -52,8 +54,10 @@ struct _GtkStyleProviderInterface
|
||||
void (* changed) (GtkStyleProvider *provider);
|
||||
};
|
||||
|
||||
GtkSettings * gtk_style_provider_get_settings (GtkStyleProvider *provider);
|
||||
GtkCssValue * gtk_style_provider_get_color (GtkStyleProvider *provider,
|
||||
GtkSettings * gtk_style_provider_get_settings (GtkStyleProvider *provider);
|
||||
GtkCssValue * gtk_style_provider_get_color (GtkStyleProvider *provider,
|
||||
const char *name);
|
||||
GdkPaintable * gtk_style_provider_get_paint (GtkStyleProvider *provider,
|
||||
const char *name);
|
||||
GtkCssKeyframes * gtk_style_provider_get_keyframes (GtkStyleProvider *provider,
|
||||
const char *name);
|
||||
|
||||
@@ -48,6 +48,7 @@ gtk_private_sources = files([
|
||||
'gtkcssimageicontheme.c',
|
||||
'gtkcssimageinvalid.c',
|
||||
'gtkcssimagelinear.c',
|
||||
'gtkcssimagepaint.c',
|
||||
'gtkcssimagepaintable.c',
|
||||
'gtkcssimageradial.c',
|
||||
'gtkcssimagerecolor.c',
|
||||
|
||||
Reference in New Issue
Block a user