diff --git a/gtk/gtkcssimage.c b/gtk/gtkcssimage.c index c61c3ee4a5..5561dbe606 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 . + * + * Authors: Benjamin Otte + */ + +#include "config.h" + +#include + +#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 . + * + * Authors: Benjamin Otte + */ + +#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 c06b5aa075..59f343d576 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',