GCC Code Coverage Report


Directory: ./
File: panels/background/cc-background-preview.c
Date: 2024-05-03 09:46:52
Exec Total Coverage
Lines: 0 113 0.0%
Functions: 0 15 0.0%
Branches: 0 47 0.0%

Line Branch Exec Source
1 /* cc-background-preview.c
2 *
3 * Copyright 2019 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: GPL-3.0-or-later
19 */
20
21 #include <libgnome-desktop/gnome-desktop-thumbnail.h>
22
23 #include "cc-background-preview.h"
24 #include "cc-background-paintable.h"
25
26 #define THUMBNAIL_WIDTH 256 /* No use asking for more, gnome_bg caps at 256 */
27 #define THUMBNAIL_HEIGHT (THUMBNAIL_WIDTH * 3 / 4)
28
29 struct _CcBackgroundPreview
30 {
31 GtkWidget parent;
32
33 GtkWidget *picture;
34 GtkWidget *light_dark_window;
35 GtkWidget *dark_window;
36
37 GnomeDesktopThumbnailFactory *thumbnail_factory;
38
39 gboolean is_dark;
40 CcBackgroundItem *item;
41 };
42
43 G_DEFINE_TYPE (CcBackgroundPreview, cc_background_preview, GTK_TYPE_WIDGET)
44
45 enum
46 {
47 PROP_0,
48 PROP_IS_DARK,
49 PROP_ITEM,
50 N_PROPS
51 };
52
53 static GParamSpec *properties [N_PROPS];
54
55 /* GObject overrides */
56
57 static void
58 cc_background_preview_dispose (GObject *object)
59 {
60 CcBackgroundPreview *self = (CcBackgroundPreview *)object;
61
62 g_clear_pointer (&self->picture, gtk_widget_unparent);
63 g_clear_pointer (&self->light_dark_window, gtk_widget_unparent);
64 g_clear_pointer (&self->dark_window, gtk_widget_unparent);
65
66 G_OBJECT_CLASS (cc_background_preview_parent_class)->dispose (object);
67 }
68
69 static void
70 cc_background_preview_finalize (GObject *object)
71 {
72 CcBackgroundPreview *self = (CcBackgroundPreview *)object;
73
74 g_clear_object (&self->item);
75 g_clear_object (&self->thumbnail_factory);
76
77 G_OBJECT_CLASS (cc_background_preview_parent_class)->finalize (object);
78 }
79
80 static void
81 set_is_dark (CcBackgroundPreview *self,
82 gboolean is_dark)
83 {
84 self->is_dark = is_dark;
85
86 if (self->is_dark)
87 {
88 gtk_widget_add_css_class (self->light_dark_window, "dark");
89 gtk_widget_remove_css_class (self->light_dark_window, "light");
90 }
91 else
92 {
93 gtk_widget_add_css_class (self->light_dark_window, "light");
94 gtk_widget_remove_css_class (self->light_dark_window, "dark");
95 }
96 }
97
98 static void
99 cc_background_preview_get_property (GObject *object,
100 guint prop_id,
101 GValue *value,
102 GParamSpec *pspec)
103 {
104 CcBackgroundPreview *self = CC_BACKGROUND_PREVIEW (object);
105
106 switch (prop_id)
107 {
108 case PROP_IS_DARK:
109 g_value_set_boolean (value, self->is_dark);
110 break;
111
112 case PROP_ITEM:
113 g_value_set_object (value, self->item);
114 break;
115
116 default:
117 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
118 }
119 }
120
121 static void
122 cc_background_preview_set_property (GObject *object,
123 guint prop_id,
124 const GValue *value,
125 GParamSpec *pspec)
126 {
127 CcBackgroundPreview *self = CC_BACKGROUND_PREVIEW (object);
128
129 switch (prop_id)
130 {
131 case PROP_IS_DARK:
132 set_is_dark (self, g_value_get_boolean (value));
133 break;
134
135 case PROP_ITEM:
136 cc_background_preview_set_item (self, g_value_get_object (value));
137 break;
138
139 default:
140 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
141 }
142 }
143
144 static GtkSizeRequestMode
145 cc_background_preview_get_request_mode (GtkWidget *widget)
146 {
147 return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
148 }
149
150 static void
151 cc_background_preview_measure (GtkWidget *widget,
152 GtkOrientation orientation,
153 gint for_size,
154 gint *minimum,
155 gint *natural,
156 gint *minimum_baseline,
157 gint *natural_baseline)
158 {
159 GtkWidget *child;
160
161 if (orientation == GTK_ORIENTATION_HORIZONTAL)
162 {
163 *natural = THUMBNAIL_WIDTH;
164 *minimum = 0;
165 }
166 else
167 {
168 *natural = MAX (0, for_size * 3 / 4); /* 4:3 aspect ratio */
169 *minimum = *natural;
170 }
171
172 for (child = gtk_widget_get_first_child (widget);
173 child;
174 child = gtk_widget_get_next_sibling (child))
175 {
176 int child_min, child_nat;
177
178 gtk_widget_measure (child, orientation, for_size,
179 &child_min, &child_nat, NULL, NULL);
180
181 *minimum = MAX (*minimum, child_min);
182 *natural = MAX (*natural, child_nat);
183 }
184 }
185
186 static void
187 cc_background_preview_size_allocate (GtkWidget *widget,
188 gint width,
189 gint height,
190 gint baseline)
191 {
192 CcBackgroundPreview *self = CC_BACKGROUND_PREVIEW (widget);
193 int window_width, window_height, margin_x, margin_y;
194 int opposite_margin_x, opposite_margin_y;
195 GskTransform *front_transform, *back_transform;
196 gboolean is_rtl;
197
198 window_width = ceil (width * 0.5);
199 window_height = ceil (height * 0.5);
200 margin_x = floor (width * 0.15);
201 margin_y = floor (height * 0.15);
202 opposite_margin_x = width - window_width - margin_x;
203 opposite_margin_y = height - window_height - margin_y;
204 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
205
206 front_transform =
207 gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (is_rtl ? opposite_margin_x : margin_x,
208 opposite_margin_y));
209 back_transform =
210 gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (is_rtl ? margin_x : opposite_margin_x,
211 margin_y));
212
213 gtk_widget_allocate (self->picture, width, height, baseline, NULL);
214 gtk_widget_allocate (self->dark_window, window_width, window_height,
215 baseline, back_transform);
216 gtk_widget_allocate (self->light_dark_window, window_width, window_height,
217 baseline, front_transform);
218 }
219
220 static void
221 cc_background_preview_class_init (CcBackgroundPreviewClass *klass)
222 {
223 GObjectClass *object_class = G_OBJECT_CLASS (klass);
224 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
225
226 object_class->dispose = cc_background_preview_dispose;
227 object_class->finalize = cc_background_preview_finalize;
228 object_class->get_property = cc_background_preview_get_property;
229 object_class->set_property = cc_background_preview_set_property;
230
231 widget_class->get_request_mode = cc_background_preview_get_request_mode;
232 widget_class->measure = cc_background_preview_measure;
233 widget_class->size_allocate = cc_background_preview_size_allocate;
234
235 properties[PROP_IS_DARK] = g_param_spec_boolean ("is-dark",
236 "Is dark",
237 "Whether the preview is dark",
238 FALSE,
239 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
240
241 properties[PROP_ITEM] = g_param_spec_object ("item",
242 "Item",
243 "Background item",
244 CC_TYPE_BACKGROUND_ITEM,
245 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
246
247 g_object_class_install_properties (object_class, N_PROPS, properties);
248
249 gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/background/cc-background-preview.ui");
250
251 gtk_widget_class_bind_template_child (widget_class, CcBackgroundPreview, picture);
252 gtk_widget_class_bind_template_child (widget_class, CcBackgroundPreview, light_dark_window);
253 gtk_widget_class_bind_template_child (widget_class, CcBackgroundPreview, dark_window);
254
255 gtk_widget_class_set_css_name (widget_class, "background-preview");
256 }
257
258 static void
259 cc_background_preview_init (CcBackgroundPreview *self)
260 {
261 gtk_widget_init_template (GTK_WIDGET (self));
262
263 self->thumbnail_factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);
264 }
265
266 CcBackgroundItem*
267 cc_background_preview_get_item (CcBackgroundPreview *self)
268 {
269 g_return_val_if_fail (CC_IS_BACKGROUND_PREVIEW (self), NULL);
270
271 return self->item;
272 }
273
274 void
275 cc_background_preview_set_item (CcBackgroundPreview *self,
276 CcBackgroundItem *item)
277 {
278 g_autoptr(CcBackgroundPaintable) paintable;
279 CcBackgroundPaintFlags paint_flags;
280
281 g_return_if_fail (CC_IS_BACKGROUND_PREVIEW (self));
282 g_return_if_fail (CC_IS_BACKGROUND_ITEM (item));
283
284 if (!g_set_object (&self->item, item))
285 return;
286
287 paint_flags = self->is_dark ? CC_BACKGROUND_PAINT_DARK : CC_BACKGROUND_PAINT_LIGHT;
288
289 paintable = cc_background_paintable_new (self->thumbnail_factory,
290 item,
291 paint_flags,
292 THUMBNAIL_WIDTH,
293 THUMBNAIL_HEIGHT);
294
295 g_object_bind_property (self->picture, "scale-factor",
296 paintable, "scale-factor", G_BINDING_SYNC_CREATE);
297
298 gtk_picture_set_paintable (GTK_PICTURE (self->picture), GDK_PAINTABLE (paintable));
299
300 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ITEM]);
301 }
302