1/*
2 * Copyright © 2018 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 "gtkscalerprivate.h"
23
24#include "gtksnapshot.h"
25
26struct _GtkScaler
27{
28 GObject parent_instance;
29
30 GdkPaintable *paintable;
31 double scale_factor;
32};
33
34struct _GtkScalerClass
35{
36 GObjectClass parent_class;
37};
38
39static void
40gtk_scaler_paintable_snapshot (GdkPaintable *paintable,
41 GdkSnapshot *snapshot,
42 double width,
43 double height)
44{
45 GtkScaler *self = GTK_SCALER (ptr: paintable);
46
47 gtk_snapshot_save (snapshot);
48
49 gtk_snapshot_scale (snapshot, factor_x: 1.0 / self->scale_factor, factor_y: 1.0 / self->scale_factor);
50
51 gdk_paintable_snapshot (paintable: self->paintable,
52 snapshot,
53 width: width * self->scale_factor,
54 height: height * self->scale_factor);
55
56 gtk_snapshot_restore (snapshot);
57}
58
59static GdkPaintable *
60gtk_scaler_paintable_get_current_image (GdkPaintable *paintable)
61{
62 GtkScaler *self = GTK_SCALER (ptr: paintable);
63 GdkPaintable *current_paintable, *current_self;
64
65 current_paintable = gdk_paintable_get_current_image (paintable: self->paintable);
66 current_self = gtk_scaler_new (paintable: current_paintable, scale_factor: self->scale_factor);
67 g_object_unref (object: current_paintable);
68
69 return current_self;
70}
71
72static GdkPaintableFlags
73gtk_scaler_paintable_get_flags (GdkPaintable *paintable)
74{
75 GtkScaler *self = GTK_SCALER (ptr: paintable);
76
77 return gdk_paintable_get_flags (paintable: self->paintable);
78}
79
80static int
81gtk_scaler_paintable_get_intrinsic_width (GdkPaintable *paintable)
82{
83 GtkScaler *self = GTK_SCALER (ptr: paintable);
84
85 return gdk_paintable_get_intrinsic_width (paintable: self->paintable) / self->scale_factor;
86}
87
88static int
89gtk_scaler_paintable_get_intrinsic_height (GdkPaintable *paintable)
90{
91 GtkScaler *self = GTK_SCALER (ptr: paintable);
92
93 return gdk_paintable_get_intrinsic_height (paintable: self->paintable) / self->scale_factor;
94}
95
96static double gtk_scaler_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
97{
98 GtkScaler *self = GTK_SCALER (ptr: paintable);
99
100 return gdk_paintable_get_intrinsic_aspect_ratio (paintable: self->paintable);
101};
102
103static void
104gtk_scaler_paintable_init (GdkPaintableInterface *iface)
105{
106 iface->snapshot = gtk_scaler_paintable_snapshot;
107 iface->get_current_image = gtk_scaler_paintable_get_current_image;
108 iface->get_flags = gtk_scaler_paintable_get_flags;
109 iface->get_intrinsic_width = gtk_scaler_paintable_get_intrinsic_width;
110 iface->get_intrinsic_height = gtk_scaler_paintable_get_intrinsic_height;
111 iface->get_intrinsic_aspect_ratio = gtk_scaler_paintable_get_intrinsic_aspect_ratio;
112}
113
114G_DEFINE_TYPE_EXTENDED (GtkScaler, gtk_scaler, G_TYPE_OBJECT, 0,
115 G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
116 gtk_scaler_paintable_init))
117
118static void
119gtk_scaler_dispose (GObject *object)
120{
121 GtkScaler *self = GTK_SCALER (ptr: object);
122
123 if (self->paintable)
124 {
125 const guint flags = gdk_paintable_get_flags (paintable: self->paintable);
126
127 if ((flags & GDK_PAINTABLE_STATIC_CONTENTS) == 0)
128 g_signal_handlers_disconnect_by_func (self->paintable, gdk_paintable_invalidate_contents, self);
129
130 if ((flags & GDK_PAINTABLE_STATIC_SIZE) == 0)
131 g_signal_handlers_disconnect_by_func (self->paintable, gdk_paintable_invalidate_size, self);
132
133 g_clear_object (&self->paintable);
134 }
135
136 G_OBJECT_CLASS (gtk_scaler_parent_class)->dispose (object);
137}
138
139static void
140gtk_scaler_class_init (GtkScalerClass *klass)
141{
142 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
143
144 gobject_class->dispose = gtk_scaler_dispose;
145}
146
147static void
148gtk_scaler_init (GtkScaler *self)
149{
150 self->scale_factor = 1.0;
151}
152
153GdkPaintable *
154gtk_scaler_new (GdkPaintable *paintable,
155 double scale_factor)
156{
157 GtkScaler *self;
158 guint flags;
159
160 g_return_val_if_fail (GDK_IS_PAINTABLE (paintable), NULL);
161 g_return_val_if_fail (scale_factor > 0.0, NULL);
162
163 self = g_object_new (GTK_TYPE_SCALER, NULL);
164
165 self->paintable = g_object_ref (paintable);
166 flags = gdk_paintable_get_flags (paintable);
167
168 if ((flags & GDK_PAINTABLE_STATIC_CONTENTS) == 0)
169 g_signal_connect_swapped (paintable, "invalidate-contents", G_CALLBACK (gdk_paintable_invalidate_contents), self);
170
171 if ((flags & GDK_PAINTABLE_STATIC_SIZE) == 0)
172 g_signal_connect_swapped (paintable, "invalidate-size", G_CALLBACK (gdk_paintable_invalidate_size), self);
173
174 self->scale_factor = scale_factor;
175
176 return GDK_PAINTABLE (ptr: self);
177}
178

source code of gtk/gtk/gtkscaler.c