1/*
2 * Copyright © 2019 Benjamin Otte
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors: Benjamin Otte <otte@gnome.org>
18 */
19
20#include "config.h"
21
22#include "gtkrendererpaintableprivate.h"
23
24#include <gtk/gtk.h>
25
26struct _GtkRendererPaintable
27{
28 GObject parent_instance;
29
30 GskRenderer *renderer;
31 GdkPaintable *paintable;
32};
33
34struct _GtkRendererPaintableClass
35{
36 GObjectClass parent_class;
37};
38
39enum {
40 PROP_0,
41 PROP_PAINTABLE,
42 PROP_RENDERER,
43 N_PROPS
44};
45
46static GParamSpec *properties[N_PROPS] = { NULL, };
47
48static void
49gtk_renderer_paintable_paintable_snapshot (GdkPaintable *paintable,
50 GdkSnapshot *snapshot,
51 double width,
52 double height)
53{
54 GtkRendererPaintable *self = GTK_RENDERER_PAINTABLE (ptr: paintable);
55 GtkSnapshot *node_snapshot;
56 GskRenderNode *node;
57 GdkTexture *texture;
58
59 if (self->paintable == NULL)
60 return;
61
62 if (self->renderer == NULL ||
63 !gsk_renderer_is_realized (renderer: self->renderer))
64 {
65 gdk_paintable_snapshot (paintable: self->paintable, snapshot, width, height);
66 return;
67 }
68
69 node_snapshot = gtk_snapshot_new ();
70 gdk_paintable_snapshot (paintable: self->paintable, snapshot: node_snapshot, width, height);
71 node = gtk_snapshot_free_to_node (snapshot: node_snapshot);
72 if (node == NULL)
73 return;
74
75 texture = gsk_renderer_render_texture (renderer: self->renderer,
76 root: node,
77 viewport: &GRAPHENE_RECT_INIT (0, 0, width, height));
78
79 gdk_paintable_snapshot (paintable: GDK_PAINTABLE (ptr: texture), snapshot, width, height);
80 g_object_unref (object: texture);
81}
82
83static int
84gtk_renderer_paintable_paintable_get_intrinsic_width (GdkPaintable *paintable)
85{
86 GtkRendererPaintable *self = GTK_RENDERER_PAINTABLE (ptr: paintable);
87
88 if (self->paintable == NULL)
89 return 0;
90
91 return gdk_paintable_get_intrinsic_width (paintable: self->paintable);
92}
93
94static int
95gtk_renderer_paintable_paintable_get_intrinsic_height (GdkPaintable *paintable)
96{
97 GtkRendererPaintable *self = GTK_RENDERER_PAINTABLE (ptr: paintable);
98
99 if (self->paintable == NULL)
100 return 0;
101
102 return gdk_paintable_get_intrinsic_height (paintable: self->paintable);
103}
104
105static double
106gtk_renderer_paintable_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
107{
108 GtkRendererPaintable *self = GTK_RENDERER_PAINTABLE (ptr: paintable);
109
110 if (self->paintable == NULL)
111 return 0.0;
112
113 return gdk_paintable_get_intrinsic_aspect_ratio (paintable: self->paintable);
114}
115
116static void
117gtk_renderer_paintable_paintable_init (GdkPaintableInterface *iface)
118{
119 iface->snapshot = gtk_renderer_paintable_paintable_snapshot;
120 iface->get_intrinsic_width = gtk_renderer_paintable_paintable_get_intrinsic_width;
121 iface->get_intrinsic_height = gtk_renderer_paintable_paintable_get_intrinsic_height;
122 iface->get_intrinsic_aspect_ratio = gtk_renderer_paintable_paintable_get_intrinsic_aspect_ratio;
123}
124
125G_DEFINE_TYPE_EXTENDED (GtkRendererPaintable, gtk_renderer_paintable, G_TYPE_OBJECT, 0,
126 G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
127 gtk_renderer_paintable_paintable_init))
128
129static void
130gtk_renderer_paintable_set_property (GObject *object,
131 guint prop_id,
132 const GValue *value,
133 GParamSpec *pspec)
134
135{
136 GtkRendererPaintable *self = GTK_RENDERER_PAINTABLE (ptr: object);
137
138 switch (prop_id)
139 {
140 case PROP_PAINTABLE:
141 gtk_renderer_paintable_set_paintable (self, paintable: g_value_get_object (value));
142 break;
143
144 case PROP_RENDERER:
145 gtk_renderer_paintable_set_renderer (self, renderer: g_value_get_object (value));
146 break;
147
148 default:
149 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
150 break;
151 }
152}
153
154static void
155gtk_renderer_paintable_get_property (GObject *object,
156 guint prop_id,
157 GValue *value,
158 GParamSpec *pspec)
159{
160 GtkRendererPaintable *self = GTK_RENDERER_PAINTABLE (ptr: object);
161
162 switch (prop_id)
163 {
164 case PROP_PAINTABLE:
165 g_value_set_object (value, v_object: self->paintable);
166 break;
167
168 case PROP_RENDERER:
169 g_value_set_object (value, v_object: self->renderer);
170 break;
171
172 default:
173 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
174 break;
175 }
176}
177
178static void
179gtk_renderer_paintable_unset_paintable (GtkRendererPaintable *self)
180{
181 guint flags;
182
183 if (self->paintable == NULL)
184 return;
185
186 flags = gdk_paintable_get_flags (paintable: self->paintable);
187
188 if ((flags & GDK_PAINTABLE_STATIC_CONTENTS) == 0)
189 g_signal_handlers_disconnect_by_func (self->paintable,
190 gdk_paintable_invalidate_contents,
191 self);
192
193 if ((flags & GDK_PAINTABLE_STATIC_SIZE) == 0)
194 g_signal_handlers_disconnect_by_func (self->paintable,
195 gdk_paintable_invalidate_size,
196 self);
197
198 g_clear_object (&self->paintable);
199}
200
201static void
202gtk_renderer_paintable_dispose (GObject *object)
203{
204 GtkRendererPaintable *self = GTK_RENDERER_PAINTABLE (ptr: object);
205
206 g_clear_object (&self->renderer);
207 gtk_renderer_paintable_unset_paintable (self);
208
209 G_OBJECT_CLASS (gtk_renderer_paintable_parent_class)->dispose (object);
210}
211
212static void
213gtk_renderer_paintable_class_init (GtkRendererPaintableClass *klass)
214{
215 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
216
217 gobject_class->get_property = gtk_renderer_paintable_get_property;
218 gobject_class->set_property = gtk_renderer_paintable_set_property;
219 gobject_class->dispose = gtk_renderer_paintable_dispose;
220
221 properties[PROP_PAINTABLE] =
222 g_param_spec_object (name: "paintable",
223 nick: "Paintable",
224 blurb: "The paintable to be shown",
225 GDK_TYPE_PAINTABLE,
226 flags: G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
227
228 properties[PROP_RENDERER] =
229 g_param_spec_object (name: "renderer",
230 nick: "Renderer",
231 blurb: "Renderer used to render the paintable",
232 GSK_TYPE_RENDERER,
233 flags: G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
234
235 g_object_class_install_properties (oclass: gobject_class, n_pspecs: N_PROPS, pspecs: properties);
236}
237
238static void
239gtk_renderer_paintable_init (GtkRendererPaintable *self)
240{
241}
242
243GdkPaintable *
244gtk_renderer_paintable_new (GskRenderer *renderer,
245 GdkPaintable *paintable)
246{
247 g_return_val_if_fail (renderer == NULL || GSK_IS_RENDERER (renderer), NULL);
248 g_return_val_if_fail (paintable == NULL || GDK_IS_PAINTABLE (paintable), NULL);
249
250 return g_object_new (GTK_TYPE_RENDERER_PAINTABLE,
251 first_property_name: "renderer", renderer,
252 "paintable", paintable,
253 NULL);
254}
255
256void
257gtk_renderer_paintable_set_renderer (GtkRendererPaintable *self,
258 GskRenderer *renderer)
259{
260 g_return_if_fail (GTK_IS_RENDERER_PAINTABLE (self));
261 g_return_if_fail (renderer == NULL || GSK_IS_RENDERER (renderer));
262
263 if (!g_set_object (&self->renderer, renderer))
264 return;
265
266 if (self->paintable)
267 gdk_paintable_invalidate_contents (paintable: GDK_PAINTABLE (ptr: self));
268
269 g_object_notify_by_pspec (G_OBJECT (self), pspec: properties[PROP_RENDERER]);
270}
271
272GskRenderer *
273gtk_renderer_paintable_get_renderer (GtkRendererPaintable *self)
274{
275 g_return_val_if_fail (GTK_IS_RENDERER_PAINTABLE (self), NULL);
276
277 return self->renderer;
278}
279
280void
281gtk_renderer_paintable_set_paintable (GtkRendererPaintable *self,
282 GdkPaintable *paintable)
283{
284 g_return_if_fail (GTK_IS_RENDERER_PAINTABLE (self));
285 g_return_if_fail (paintable == NULL || GDK_IS_PAINTABLE (paintable));
286
287 if (self->paintable == paintable)
288 return;
289
290 gtk_renderer_paintable_unset_paintable (self);
291
292 if (paintable)
293 {
294 const guint flags = gdk_paintable_get_flags (paintable);
295
296 self->paintable = g_object_ref (paintable);
297
298 if ((flags & GDK_PAINTABLE_STATIC_CONTENTS) == 0)
299 g_signal_connect_swapped (paintable,
300 "invalidate-contents",
301 G_CALLBACK (gdk_paintable_invalidate_contents),
302 self);
303 if ((flags & GDK_PAINTABLE_STATIC_SIZE) == 0)
304 g_signal_connect_swapped (paintable,
305 "invalidate-size",
306 G_CALLBACK (gdk_paintable_invalidate_size),
307 self);
308 }
309
310 gdk_paintable_invalidate_size (paintable: GDK_PAINTABLE (ptr: self));
311 gdk_paintable_invalidate_contents (paintable: GDK_PAINTABLE (ptr: self));
312
313 g_object_notify_by_pspec (G_OBJECT (self), pspec: properties[PROP_PAINTABLE]);
314}
315
316GdkPaintable *
317gtk_renderer_paintable_get_paintable (GtkRendererPaintable *self)
318{
319 g_return_val_if_fail (GTK_IS_RENDERER_PAINTABLE (self), NULL);
320
321 return self->paintable;
322}
323
324

source code of gtk/demos/node-editor/gtkrendererpaintable.c