[gtk/wip/otte/paintable: 7/8] css: Add initial support for Houdini-style paint() images
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/otte/paintable: 7/8] css: Add initial support for Houdini-style paint() images
- Date: Sat, 17 Feb 2018 23:46:25 +0000 (UTC)
commit d568aec882f3e33285fe18668584e913e2099bd9
Author: Benjamin Otte <otte redhat com>
Date: Sun Feb 18 00:25:51 2018 +0100
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.
gtk/gtkcssimage.c | 8 ++-
gtk/gtkcssimagepaint.c | 147 ++++++++++++++++++++++++++++++++++++++++++
gtk/gtkcssimagepaintable.c | 2 +-
gtk/gtkcssimagepaintprivate.h | 53 +++++++++++++++
gtk/gtkstylecascade.c | 74 +++++++++++++++++++++
gtk/gtkstylecascadeprivate.h | 6 ++
gtk/gtkstylecontext.c | 28 ++++++++
gtk/gtkstylecontext.h | 7 ++
gtk/gtkstyleprovider.c | 16 +++++
gtk/gtkstyleproviderprivate.h | 10 ++-
gtk/meson.build | 1 +
11 files changed, 345 insertions(+), 7 deletions(-)
---
diff --git a/gtk/gtkcssimage.c b/gtk/gtkcssimage.c
index 9160333228..e84c2d5f68 100644
--- a/gtk/gtkcssimage.c
+++ b/gtk/gtkcssimage.c
@@ -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 },
diff --git a/gtk/gtkcssimagepaint.c b/gtk/gtkcssimagepaint.c
new file mode 100644
index 0000000000..5850dfe929
--- /dev/null
+++ b/gtk/gtkcssimagepaint.c
@@ -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)
+{
+}
+
diff --git a/gtk/gtkcssimagepaintable.c b/gtk/gtkcssimagepaintable.c
index 327ca90862..e25262bacd 100644
--- a/gtk/gtkcssimagepaintable.c
+++ b/gtk/gtkcssimagepaintable.c
@@ -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 *
diff --git a/gtk/gtkcssimagepaintprivate.h b/gtk/gtkcssimagepaintprivate.h
new file mode 100644
index 0000000000..514bb88042
--- /dev/null
+++ b/gtk/gtkcssimagepaintprivate.h
@@ -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__ */
diff --git a/gtk/gtkstylecascade.c b/gtk/gtkstylecascade.c
index 4c94696742..b879f46032 100644
--- a/gtk/gtkstylecascade.c
+++ b/gtk/gtkstylecascade.c
@@ -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;
+}
diff --git a/gtk/gtkstylecascadeprivate.h b/gtk/gtkstylecascadeprivate.h
index ad2f7e69d0..5748453d23 100644
--- a/gtk/gtkstylecascadeprivate.h
+++ b/gtk/gtkstylecascadeprivate.h
@@ -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
diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c
index 16897067d0..2a599db505 100644
--- a/gtk/gtkstylecontext.c
+++ b/gtk/gtkstylecontext.c
@@ -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
diff --git a/gtk/gtkstylecontext.h b/gtk/gtkstylecontext.h
index bfe513067f..f5f84cc407 100644
--- a/gtk/gtkstylecontext.h
+++ b/gtk/gtkstylecontext.h
@@ -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,
diff --git a/gtk/gtkstyleprovider.c b/gtk/gtkstyleprovider.c
index 3fb0f49afa..d9160d79d8 100644
--- a/gtk/gtkstyleprovider.c
+++ b/gtk/gtkstyleprovider.c
@@ -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,
diff --git a/gtk/gtkstyleproviderprivate.h b/gtk/gtkstyleproviderprivate.h
index c33438dd99..ed9ac36a5d 100644
--- a/gtk/gtkstyleproviderprivate.h
+++ b/gtk/gtkstyleproviderprivate.h
@@ -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);
diff --git a/gtk/meson.build b/gtk/meson.build
index 1f347dd2d4..89138ea2a7 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -48,6 +48,7 @@ gtk_private_sources = files([
'gtkcssimageicontheme.c',
'gtkcssimageinvalid.c',
'gtkcssimagelinear.c',
+ 'gtkcssimagepaint.c',
'gtkcssimagepaintable.c',
'gtkcssimageradial.c',
'gtkcssimagerecolor.c',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]