GCC Code Coverage Report


Directory: ./
File: panels/common/cc-time-editor.c
Date: 2024-05-04 07:58:27
Exec Total Coverage
Lines: 0 140 0.0%
Functions: 0 22 0.0%
Branches: 0 59 0.0%

Line Branch Exec Source
1 /* -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*- */
2 /* cc-time-editor.c
3 *
4 * Copyright 2020 Purism SPC
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author(s):
20 * Mohammed Sadiq <sadiq@sadiqpk.org>
21 *
22 * SPDX-License-Identifier: GPL-3.0-or-later
23 */
24
25 #undef G_LOG_DOMAIN
26 #define G_LOG_DOMAIN "cc-time-editor"
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #define GNOME_DESKTOP_USE_UNSTABLE_API
33 #include <libgnome-desktop/gnome-wall-clock.h>
34 #include <gtk/gtk.h>
35 #include <glib/gi18n.h>
36
37 #include "cc-time-entry.h"
38 #include "cc-time-editor.h"
39
40
41 #define TIMEOUT_INITIAL 500
42 #define TIMEOUT_REPEAT 50
43
44 #define FILECHOOSER_SCHEMA "org.gtk.Settings.FileChooser"
45 #define CLOCK_SCHEMA "org.gnome.desktop.interface"
46 #define CLOCK_FORMAT_KEY "clock-format"
47 #define SECONDS_PER_MINUTE (60)
48 #define SECONDS_PER_HOUR (60 * 60)
49 #define SECONDS_PER_DAY (60 * 60 * 24)
50
51
52 struct _CcTimeEditor
53 {
54 AdwBin parent_instance;
55
56 GtkButton *am_pm_button;
57 GtkStack *am_pm_stack;
58 GtkLabel *am_label;
59 GtkLabel *pm_label;
60 GtkButton *hour_up_button;
61 GtkButton *hour_down_button;
62 GtkButton *minute_up_button;
63 GtkButton *minute_down_button;
64 CcTimeEntry *time_entry;
65
66 GtkButton *clicked_button; /* The button currently being clicked */
67 GSettings *clock_settings;
68 GSettings *filechooser_settings;
69
70 guint timer_id;
71 };
72
73 G_DEFINE_TYPE (CcTimeEditor, cc_time_editor, ADW_TYPE_BIN)
74
75
76 enum {
77 TIME_CHANGED,
78 N_SIGNALS
79 };
80
81 static guint signals[N_SIGNALS];
82
83 static void
84 time_editor_clock_changed_cb (CcTimeEditor *self)
85 {
86 GDesktopClockFormat value;
87 gboolean is_am_pm;
88
89 g_assert (CC_IS_TIME_EDITOR (self));
90
91 value = g_settings_get_enum (self->clock_settings, CLOCK_FORMAT_KEY);
92
93 is_am_pm = value == G_DESKTOP_CLOCK_FORMAT_12H;
94 cc_time_entry_set_am_pm (self->time_entry, is_am_pm);
95 gtk_widget_set_visible (GTK_WIDGET (self->am_pm_button), is_am_pm);
96
97 if (is_am_pm)
98 {
99 if (cc_time_entry_get_is_am (self->time_entry))
100 gtk_stack_set_visible_child (self->am_pm_stack, GTK_WIDGET (self->am_label));
101 else
102 gtk_stack_set_visible_child (self->am_pm_stack, GTK_WIDGET (self->pm_label));
103 }
104 }
105
106 static void
107 time_editor_time_changed_cb (CcTimeEditor *self)
108 {
109 g_assert (CC_IS_TIME_EDITOR (self));
110
111 time_editor_clock_changed_cb (self);
112 g_signal_emit (self, signals[TIME_CHANGED], 0);
113 }
114
115 static void
116 editor_change_time_clicked_cb (CcTimeEditor *self,
117 GtkButton *button)
118 {
119 g_assert (CC_IS_TIME_EDITOR (self));
120
121 if (button == NULL)
122 return;
123
124 if (button == self->hour_up_button)
125 {
126 gtk_editable_set_position (GTK_EDITABLE (self->time_entry), 0);
127 g_signal_emit_by_name (self->time_entry, "change-value", GTK_SCROLL_STEP_UP);
128 }
129 else if (button == self->hour_down_button)
130 {
131 gtk_editable_set_position (GTK_EDITABLE (self->time_entry), 0);
132 g_signal_emit_by_name (self->time_entry, "change-value", GTK_SCROLL_STEP_DOWN);
133 }
134 else if (button == self->minute_up_button)
135 {
136 gtk_editable_set_position (GTK_EDITABLE (self->time_entry), 3);
137 g_signal_emit_by_name (self->time_entry, "change-value", GTK_SCROLL_STEP_UP);
138 }
139 else if (button == self->minute_down_button)
140 {
141 gtk_editable_set_position (GTK_EDITABLE (self->time_entry), 3);
142 g_signal_emit_by_name (self->time_entry, "change-value", GTK_SCROLL_STEP_DOWN);
143 }
144 }
145
146 static gboolean
147 editor_change_time_repeat (CcTimeEditor *self)
148 {
149 if (self->clicked_button == NULL)
150 {
151 self->timer_id = 0;
152
153 return G_SOURCE_REMOVE;
154 }
155
156 editor_change_time_clicked_cb (self, self->clicked_button);
157
158 return G_SOURCE_CONTINUE;
159 }
160
161 static gboolean
162 editor_change_time_cb (CcTimeEditor *self)
163 {
164 g_assert (CC_IS_TIME_EDITOR (self));
165 g_clear_handle_id (&self->timer_id, g_source_remove);
166
167 editor_change_time_clicked_cb (self, self->clicked_button);
168 self->timer_id = g_timeout_add (TIMEOUT_REPEAT,
169 (GSourceFunc)editor_change_time_repeat,
170 self);
171 return G_SOURCE_REMOVE;
172 }
173
174 static gboolean
175 editor_change_time_pressed_cb (CcTimeEditor *self,
176 gint n_press,
177 gdouble x,
178 gdouble y,
179 GtkGestureClick *click_gesture)
180 {
181 GtkWidget *button;
182
183 g_assert (CC_IS_TIME_EDITOR (self));
184
185 button = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (click_gesture));
186
187 self->clicked_button = GTK_BUTTON (button);
188 /* Keep changing time until the press is released */
189 self->timer_id = g_timeout_add (TIMEOUT_INITIAL,
190 (GSourceFunc)editor_change_time_cb,
191 self);
192 editor_change_time_clicked_cb (self, GTK_BUTTON (button));
193 return FALSE;
194 }
195
196 static gboolean
197 editor_change_time_released_cb (CcTimeEditor *self)
198 {
199 self->clicked_button = NULL;
200 g_clear_handle_id (&self->timer_id, g_source_remove);
201
202 return FALSE;
203 }
204
205 static void
206 editor_am_pm_button_clicked_cb (CcTimeEditor *self)
207 {
208 gboolean is_am;
209
210 g_assert (CC_IS_TIME_EDITOR (self));
211 g_assert (cc_time_entry_get_am_pm (self->time_entry));
212
213 is_am = cc_time_entry_get_is_am (self->time_entry);
214 /* Toggle AM PM */
215 cc_time_entry_set_is_am (self->time_entry, !is_am);
216 time_editor_clock_changed_cb (self);
217 }
218
219 static void
220 editor_am_pm_stack_changed_cb (CcTimeEditor *self)
221 {
222 GtkWidget *label;
223 const gchar *text;
224
225 g_assert (CC_IS_TIME_EDITOR (self));
226
227 label = gtk_stack_get_visible_child (self->am_pm_stack);
228 text = gtk_label_get_text (GTK_LABEL (label));
229 gtk_accessible_update_property (GTK_ACCESSIBLE (self->am_pm_button),
230 GTK_ACCESSIBLE_PROPERTY_LABEL, text,
231 -1);
232 }
233
234 static void
235 cc_time_editor_constructed (GObject *object)
236 {
237 CcTimeEditor *self = (CcTimeEditor *)object;
238 GDateTime *date;
239 GtkWidget *grid;
240 char *label;
241
242 G_OBJECT_CLASS (cc_time_editor_parent_class)->constructed (object);
243
244 /* Set localized identifier for AM */
245 date = g_date_time_new_utc (1, 1, 1, 0, 0, 0);
246 label = g_date_time_format (date, "%p");
247 gtk_label_set_label (self->am_label, label);
248 g_date_time_unref (date);
249 g_free (label);
250
251 /* Set localized identifier for PM */
252 date = g_date_time_new_utc (1, 1, 1, 12, 0, 0);
253 label = g_date_time_format (date, "%p");
254 gtk_label_set_label (self->pm_label, label);
255 g_date_time_unref (date);
256 g_free (label);
257
258 /* Force LTR so we don't reorder clock buttons for RTL languages */
259 grid = gtk_widget_get_parent (GTK_WIDGET (self->hour_up_button));
260 gtk_widget_set_direction (grid, GTK_TEXT_DIR_LTR);
261 }
262
263 static void
264 cc_time_editor_finalize (GObject *object)
265 {
266 CcTimeEditor *self = (CcTimeEditor *)object;
267
268 g_clear_handle_id (&self->timer_id, g_source_remove);
269 g_clear_object (&self->clock_settings);
270 g_clear_object (&self->filechooser_settings);
271
272 G_OBJECT_CLASS (cc_time_editor_parent_class)->finalize (object);
273 }
274
275 static void
276 cc_time_editor_class_init (CcTimeEditorClass *klass)
277 {
278 GObjectClass *object_class = G_OBJECT_CLASS (klass);
279 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
280
281 object_class->constructed = cc_time_editor_constructed;
282 object_class->finalize = cc_time_editor_finalize;
283
284 signals[TIME_CHANGED] =
285 g_signal_new ("time-changed",
286 G_TYPE_FROM_CLASS (klass),
287 G_SIGNAL_RUN_FIRST,
288 0, NULL, NULL,
289 NULL,
290 G_TYPE_NONE, 0);
291
292 gtk_widget_class_set_template_from_resource (widget_class,
293 "/org/gnome/control-center/"
294 "common/cc-time-editor.ui");
295
296 gtk_widget_class_bind_template_child (widget_class, CcTimeEditor, am_pm_button);
297 gtk_widget_class_bind_template_child (widget_class, CcTimeEditor, am_pm_stack);
298 gtk_widget_class_bind_template_child (widget_class, CcTimeEditor, am_label);
299 gtk_widget_class_bind_template_child (widget_class, CcTimeEditor, pm_label);
300 gtk_widget_class_bind_template_child (widget_class, CcTimeEditor, hour_up_button);
301 gtk_widget_class_bind_template_child (widget_class, CcTimeEditor, hour_down_button);
302 gtk_widget_class_bind_template_child (widget_class, CcTimeEditor, minute_up_button);
303 gtk_widget_class_bind_template_child (widget_class, CcTimeEditor, minute_down_button);
304 gtk_widget_class_bind_template_child (widget_class, CcTimeEditor, time_entry);
305
306 gtk_widget_class_bind_template_callback (widget_class, editor_change_time_pressed_cb);
307 gtk_widget_class_bind_template_callback (widget_class, editor_change_time_released_cb);
308 gtk_widget_class_bind_template_callback (widget_class, editor_am_pm_button_clicked_cb);
309 gtk_widget_class_bind_template_callback (widget_class, editor_am_pm_stack_changed_cb);
310
311 g_type_ensure (CC_TYPE_TIME_ENTRY);
312 }
313
314 static void
315 cc_time_editor_init (CcTimeEditor *self)
316 {
317 gtk_widget_init_template (GTK_WIDGET (self));
318
319 self->clock_settings = g_settings_new (CLOCK_SCHEMA);
320 self->filechooser_settings = g_settings_new (FILECHOOSER_SCHEMA);
321
322 g_signal_connect_object (self->clock_settings, "changed::" CLOCK_FORMAT_KEY,
323 G_CALLBACK (time_editor_clock_changed_cb), self,
324 G_CONNECT_SWAPPED);
325 g_signal_connect_swapped (self->time_entry, "time-changed",
326 G_CALLBACK (time_editor_time_changed_cb), self);
327 time_editor_clock_changed_cb (self);
328 }
329
330 CcTimeEditor *
331 cc_time_editor_new (void)
332 {
333 return g_object_new (CC_TYPE_TIME_EDITOR, NULL);
334 }
335
336 void
337 cc_time_editor_set_time (CcTimeEditor *self,
338 guint hour,
339 guint minute)
340 {
341 g_return_if_fail (CC_IS_TIME_EDITOR (self));
342
343 cc_time_entry_set_time (self->time_entry, hour, minute);
344 }
345
346 guint
347 cc_time_editor_get_hour (CcTimeEditor *self)
348 {
349 g_return_val_if_fail (CC_IS_TIME_EDITOR (self), 0);
350
351 return cc_time_entry_get_hour (self->time_entry);
352 }
353
354 guint
355 cc_time_editor_get_minute (CcTimeEditor *self)
356 {
357 g_return_val_if_fail (CC_IS_TIME_EDITOR (self), 0);
358
359 return cc_time_entry_get_minute (self->time_entry);
360 }
361
362 gboolean
363 cc_time_editor_get_am_pm (CcTimeEditor *self)
364 {
365 g_return_val_if_fail (CC_IS_TIME_EDITOR (self), TRUE);
366
367 return TRUE;
368 }
369
370 void
371 cc_time_editor_set_am_pm (CcTimeEditor *self,
372 gboolean is_am_pm)
373 {
374 g_return_if_fail (CC_IS_TIME_EDITOR (self));
375
376 cc_time_entry_set_am_pm (self->time_entry, is_am_pm);
377 }
378