Branch data Line data Source code
1 : : /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 : : *
3 : : * Copyright 2025 GNOME Foundation, Inc.
4 : : *
5 : : * SPDX-License-Identifier: GPL-2.0-or-later
6 : : *
7 : : * This program is free software; you can redistribute it and/or modify
8 : : * it under the terms of the GNU General Public License as published by
9 : : * the Free Software Foundation; either version 2 of the License, or
10 : : * (at your option) any later version.
11 : : *
12 : : * This program is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : : * GNU General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU General Public License
18 : : * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 : : *
20 : : * Authors:
21 : : * - Ignacy Kuchciński <ignacykuchcinski@gnome.org>
22 : : */
23 : :
24 : : #include "config.h"
25 : :
26 : : #include <glib/gi18n-lib.h>
27 : : #include <libmalcontent/manager.h>
28 : :
29 : : #include "time-page.h"
30 : : #include "cc-duration-row.h"
31 : : #include "screen-time-statistics-row.h"
32 : : #include "cc-time-row.h"
33 : :
34 : : static gboolean update_session_limits_cb (gpointer data);
35 : :
36 : : /**
37 : : * MctTimePage:
38 : : *
39 : : * A widget which shows parental controls for screen time limits
40 : : * for the selected user.
41 : : *
42 : : * Since: 0.14.0
43 : : */
44 : : struct _MctTimePage
45 : : {
46 : : AdwNavigationPage parent;
47 : :
48 : : AdwWindowTitle *time_window_title;
49 : : AdwPreferencesGroup *preferences_group;
50 : : AdwPreferencesPage *preferences_page;
51 : : AdwSwitchRow *screen_time_limit_row;
52 : : AdwSwitchRow *bedtime_schedule_row;
53 : : CcDurationRow *daily_time_limit_row;
54 : : CcTimeRow *bedtime_row;
55 : :
56 : : unsigned int update_session_limits_source_id;
57 : : unsigned long session_limits_changed_id;
58 : : unsigned long user_notify_id;
59 : : gboolean flushed_on_dispose;
60 : : GCancellable *cancellable; /* (owned) */
61 : : MctSessionLimits *limits; /* (owned) */
62 : : MctSessionLimits *last_saved_limits; /* (owned); updated each time we internally time out and save the session limits */
63 : : MctScreenTimeStatisticsRow *row;
64 : :
65 : : MctUser *user; /* (owned) */
66 : : GDBusConnection *connection; /* (owned) */
67 : : MctManager *policy_manager; /* (owned) */
68 : : };
69 : :
70 [ # # # # : 0 : G_DEFINE_TYPE (MctTimePage, mct_time_page, ADW_TYPE_NAVIGATION_PAGE)
# # ]
71 : :
72 : : typedef enum
73 : : {
74 : : PROP_USER = 1,
75 : : PROP_CONNECTION,
76 : : PROP_POLICY_MANAGER,
77 : : } MctTimePageProperty;
78 : :
79 : : static GParamSpec *properties[PROP_POLICY_MANAGER + 1];
80 : :
81 : : static void
82 : 0 : schedule_update_session_limits (MctTimePage *self)
83 : : {
84 [ # # ]: 0 : if (self->update_session_limits_source_id > 0)
85 : 0 : return;
86 : :
87 : : /* Use a timeout to batch multiple quick changes into a single
88 : : * update. 1 second is an arbitrary sufficiently small number */
89 : 0 : self->update_session_limits_source_id =
90 : 0 : g_timeout_add_seconds (1, update_session_limits_cb, self);
91 : : }
92 : :
93 : : static void
94 : 0 : flush_update_session_limits (MctTimePage *self)
95 : : {
96 [ # # ]: 0 : if (self->update_session_limits_source_id > 0)
97 : : {
98 : : /* Remove the timer and forcefully call the timer callback. */
99 : 0 : g_source_remove (self->update_session_limits_source_id);
100 : 0 : self->update_session_limits_source_id = 0;
101 : :
102 : 0 : update_session_limits_cb (self);
103 : : }
104 : 0 : }
105 : :
106 : : static void
107 : 0 : setup_time_page (MctTimePage *self)
108 : : {
109 : : gboolean daily_limit, daily_schedule;
110 : : unsigned int limit_secs, bedtime_secs;
111 : :
112 : 0 : daily_limit = mct_session_limits_get_daily_limit (self->limits, &limit_secs);
113 : 0 : daily_schedule = mct_session_limits_get_daily_schedule (self->limits,
114 : : NULL,
115 : : &bedtime_secs);
116 : :
117 : 0 : adw_switch_row_set_active (self->screen_time_limit_row, daily_limit);
118 : 0 : adw_switch_row_set_active (self->bedtime_schedule_row, daily_schedule);
119 : 0 : cc_duration_row_set_duration (self->daily_time_limit_row, limit_secs / 60);
120 [ # # ]: 0 : if (daily_schedule)
121 : 0 : cc_time_row_set_time (self->bedtime_row, bedtime_secs / 60);
122 : 0 : }
123 : :
124 : : static void
125 : 0 : get_session_limits_cb (GObject *obj,
126 : : GAsyncResult *result,
127 : : gpointer user_data)
128 : : {
129 : 0 : MctTimePage *self = MCT_TIME_PAGE (user_data);
130 [ # # ]: 0 : g_autoptr(GError) error = NULL;
131 : :
132 [ # # ]: 0 : g_clear_pointer (&self->limits, mct_session_limits_unref);
133 [ # # ]: 0 : g_clear_pointer (&self->last_saved_limits, mct_session_limits_unref);
134 : 0 : self->limits = mct_manager_get_session_limits_finish (self->policy_manager,
135 : : result,
136 : : &error);
137 : :
138 [ # # ]: 0 : if (error)
139 : : {
140 : 0 : g_warning ("Error retrieving session limits for user '%s': %s",
141 : : mct_user_get_username (self->user),
142 : : error->message);
143 : 0 : return;
144 : : }
145 : :
146 : 0 : self->last_saved_limits = mct_session_limits_ref (self->limits);
147 : :
148 : 0 : g_debug ("Retrieved new session limits for user '%s'",
149 : : mct_user_get_username (self->user));
150 : :
151 : 0 : setup_time_page (self);
152 : : }
153 : :
154 : : static void
155 : 0 : set_session_limits_cb (GObject *obj,
156 : : GAsyncResult *result,
157 : : gpointer user_data)
158 : : {
159 : 0 : MctTimePage *self = MCT_TIME_PAGE (user_data);
160 : : gboolean success;
161 : 0 : g_autoptr(GError) error = NULL;
162 : :
163 : 0 : success = mct_manager_set_session_limits_finish (self->policy_manager,
164 : : result,
165 : : &error);
166 [ # # ]: 0 : if (!success)
167 : : {
168 : 0 : g_warning ("Error updating session limits: %s", error->message);
169 : 0 : setup_time_page (self);
170 : : }
171 : 0 : }
172 : :
173 : : static gboolean
174 : 0 : update_session_limits_cb (gpointer data)
175 : : {
176 : 0 : g_auto(MctSessionLimitsBuilder) builder = MCT_SESSION_LIMITS_BUILDER_INIT ();
177 : 0 : g_autoptr(MctSessionLimits) new_limits = NULL;
178 : 0 : g_autoptr(GError) error = NULL;
179 : 0 : MctTimePage *self = data;
180 : : guint limit, daily_schedule_start, daily_schedule_end, bedtime_minutes, bedtime_hours;
181 : : gboolean screen_time_limit, bedtime_schedule;
182 : :
183 : 0 : self->update_session_limits_source_id = 0;
184 : :
185 : 0 : screen_time_limit = adw_switch_row_get_active (self->screen_time_limit_row);
186 [ # # ]: 0 : if (screen_time_limit)
187 : : {
188 : 0 : limit = cc_duration_row_get_duration (self->daily_time_limit_row);
189 : 0 : mct_session_limits_builder_set_daily_limit (&builder, limit * 60);
190 : : }
191 : :
192 : 0 : bedtime_schedule = adw_switch_row_get_active (self->bedtime_schedule_row);
193 [ # # ]: 0 : if (bedtime_schedule)
194 : : {
195 : 0 : bedtime_minutes = cc_time_row_get_time (self->bedtime_row);
196 : 0 : bedtime_hours = bedtime_minutes / 60;
197 : 0 : const unsigned int sleep_time_hours = 6;
198 : 0 : const unsigned int midnight = 24;
199 : :
200 : : /* Calculate the start and the end of the daily schedule in seconds.
201 : : * Ensure at least 6 hours of sleep time for late bedtimes. For early
202 : : * bedtimes, the start of the daily schedule would need to be after
203 : : * the end, but split days aren't supported yet, so set it to zero
204 : : * for now. Also make sure the end of the daily schedule is non zero.*/
205 [ # # ]: 0 : if (bedtime_hours + sleep_time_hours >= midnight)
206 : 0 : daily_schedule_start = (bedtime_hours + sleep_time_hours) % midnight * 60 * 60;
207 : : else
208 : 0 : daily_schedule_start = 0;
209 : :
210 [ # # ]: 0 : if (bedtime_minutes != 0)
211 : 0 : daily_schedule_end = bedtime_minutes * 60;
212 : : else
213 : 0 : daily_schedule_end = 1;
214 : :
215 : 0 : mct_session_limits_builder_set_daily_schedule (&builder,
216 : : daily_schedule_start,
217 : : daily_schedule_end);
218 : : }
219 : :
220 : 0 : new_limits = mct_session_limits_builder_end (&builder);
221 : :
222 : : /* Don't bother saving the session limit (which could result in asking the
223 : : * user for admin permission) if it hasn't changed. */
224 [ # # # # ]: 0 : if (self->last_saved_limits != NULL &&
225 : 0 : mct_session_limits_equal (new_limits, self->last_saved_limits))
226 : : {
227 : 0 : g_debug ("Not saving session limits as they haven't changed");
228 : 0 : return G_SOURCE_REMOVE;
229 : : }
230 : :
231 : 0 : mct_manager_set_session_limits_async (self->policy_manager,
232 : : mct_user_get_uid (self->user),
233 : : new_limits,
234 : : MCT_MANAGER_SET_VALUE_FLAGS_INTERACTIVE,
235 : : self->cancellable,
236 : : set_session_limits_cb,
237 : : self);
238 : :
239 : : /* Update the cached copy */
240 [ # # ]: 0 : g_clear_pointer (&self->last_saved_limits, mct_session_limits_unref);
241 : 0 : self->last_saved_limits = g_steal_pointer (&new_limits);
242 : :
243 : 0 : return G_SOURCE_REMOVE;
244 : : }
245 : :
246 : : static void
247 : 0 : screen_time_limit_row_notify_active_cb (MctTimePage *self)
248 : : {
249 : 0 : schedule_update_session_limits (self);
250 : 0 : }
251 : :
252 : : static void
253 : 0 : bedtime_schedule_row_notify_active_cb (MctTimePage *self)
254 : : {
255 : 0 : schedule_update_session_limits (self);
256 : 0 : }
257 : :
258 : : static void
259 : 0 : bedtime_row_notify_time_cb (CcTimeRow *row,
260 : : GParamSpec *pspec,
261 : : gpointer user_data)
262 : : {
263 : 0 : MctTimePage *self = MCT_TIME_PAGE (user_data);
264 : :
265 : 0 : schedule_update_session_limits (self);
266 : 0 : }
267 : :
268 : : static void
269 : 0 : daily_time_limit_row_notify_duration_cb (CcDurationRow *row,
270 : : GParamSpec *pspec,
271 : : gpointer user_data)
272 : : {
273 : 0 : MctTimePage *self = MCT_TIME_PAGE (user_data);
274 : :
275 : 0 : schedule_update_session_limits (self);
276 : 0 : }
277 : :
278 : : static void
279 : 0 : session_limits_changed_cb (MctManager *policy_manager,
280 : : uid_t uid,
281 : : void *user_data)
282 : : {
283 : 0 : MctTimePage *self = MCT_TIME_PAGE (user_data);
284 : :
285 [ # # ]: 0 : if (uid != mct_user_get_uid (self->user))
286 : 0 : return;
287 : :
288 : 0 : mct_manager_get_session_limits_async (self->policy_manager,
289 : : mct_user_get_uid (self->user),
290 : : MCT_MANAGER_GET_VALUE_FLAGS_NONE,
291 : : self->cancellable,
292 : : get_session_limits_cb,
293 : : self);
294 : : }
295 : :
296 : : static void
297 : 0 : mct_time_page_get_property (GObject *object,
298 : : guint prop_id,
299 : : GValue *value,
300 : : GParamSpec *pspec)
301 : : {
302 : 0 : MctTimePage *self = MCT_TIME_PAGE (object);
303 : :
304 [ # # # # ]: 0 : switch ((MctTimePageProperty) prop_id)
305 : : {
306 : 0 : case PROP_USER:
307 : 0 : g_value_set_object (value, self->user);
308 : 0 : break;
309 : :
310 : 0 : case PROP_CONNECTION:
311 : 0 : g_value_set_object (value, self->connection);
312 : 0 : break;
313 : :
314 : 0 : case PROP_POLICY_MANAGER:
315 : 0 : g_value_set_object (value, self->policy_manager);
316 : 0 : break;
317 : :
318 : 0 : default:
319 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
320 : : }
321 : 0 : }
322 : :
323 : : static void
324 : 0 : mct_time_page_set_property (GObject *object,
325 : : guint prop_id,
326 : : const GValue *value,
327 : : GParamSpec *pspec)
328 : : {
329 : 0 : MctTimePage *self = MCT_TIME_PAGE (object);
330 : :
331 [ # # # # ]: 0 : switch ((MctTimePageProperty) prop_id)
332 : : {
333 : 0 : case PROP_USER:
334 : 0 : mct_time_page_set_user (self, g_value_get_object (value));
335 : 0 : break;
336 : :
337 : 0 : case PROP_CONNECTION:
338 : : /* Construct-only. May not be %NULL. */
339 : 0 : g_assert (self->connection == NULL);
340 : 0 : self->connection = g_value_dup_object (value);
341 : 0 : g_assert (self->connection != NULL);
342 : 0 : break;
343 : :
344 : 0 : case PROP_POLICY_MANAGER:
345 : : /* Construct only. */
346 : 0 : g_assert (self->policy_manager == NULL);
347 : 0 : self->policy_manager = g_value_dup_object (value);
348 : 0 : break;
349 : :
350 : 0 : default:
351 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
352 : : }
353 : 0 : }
354 : :
355 : : static void
356 : 0 : mct_time_page_constructed (GObject *object)
357 : : {
358 : 0 : MctTimePage *self = MCT_TIME_PAGE (object);
359 : :
360 : : /* Chain up. */
361 : 0 : G_OBJECT_CLASS (mct_time_page_parent_class)->constructed (object);
362 : :
363 : : /* Check our construct properties. */
364 : 0 : g_assert (self->connection != NULL);
365 : 0 : g_assert (MCT_IS_MANAGER (self->policy_manager));
366 : :
367 : 0 : self->session_limits_changed_id =
368 : 0 : g_signal_connect (self->policy_manager,
369 : : "session-limits-changed",
370 : : G_CALLBACK (session_limits_changed_cb),
371 : : self);
372 : 0 : }
373 : :
374 : : static void
375 : 0 : mct_time_page_dispose (GObject *object)
376 : : {
377 : 0 : MctTimePage *self = MCT_TIME_PAGE (object);
378 : :
379 : : /* Since GTK calls g_object_run_dispose(), dispose() may be called multiple
380 : : * times. We definitely want to save any unsaved changes, but don’t need to
381 : : * do it multiple times, and after the first g_object_run_dispose() call,
382 : : * none of our child widgets are still around to extract data from anyway. */
383 [ # # ]: 0 : if (!self->flushed_on_dispose)
384 : 0 : flush_update_session_limits (self);
385 : 0 : self->flushed_on_dispose = TRUE;
386 : :
387 : 0 : adw_preferences_group_remove (self->preferences_group,
388 : 0 : GTK_WIDGET (self->row));
389 [ # # ]: 0 : g_clear_object (&self->connection);
390 : :
391 : 0 : G_OBJECT_CLASS (mct_time_page_parent_class)->dispose (object);
392 : 0 : }
393 : :
394 : : static void
395 : 0 : mct_time_page_finalize (GObject *object)
396 : : {
397 : 0 : MctTimePage *self = MCT_TIME_PAGE (object);
398 : :
399 : 0 : g_assert (self->update_session_limits_source_id == 0);
400 : :
401 : 0 : g_cancellable_cancel (self->cancellable);
402 [ # # ]: 0 : g_clear_object (&self->cancellable);
403 [ # # ]: 0 : g_clear_signal_handler (&self->user_notify_id, self->user);
404 [ # # ]: 0 : g_clear_object (&self->user);
405 [ # # ]: 0 : g_clear_pointer (&self->limits, mct_session_limits_unref);
406 [ # # ]: 0 : g_clear_pointer (&self->last_saved_limits, mct_session_limits_unref);
407 [ # # ]: 0 : g_clear_signal_handler (&self->session_limits_changed_id, self->policy_manager);
408 [ # # ]: 0 : g_clear_object (&self->policy_manager);
409 : :
410 : : /* Hopefully we don’t have data loss. */
411 : 0 : g_assert (self->flushed_on_dispose);
412 : :
413 : 0 : G_OBJECT_CLASS (mct_time_page_parent_class)->finalize (object);
414 : 0 : }
415 : :
416 : : static void
417 : 0 : mct_time_page_class_init (MctTimePageClass *klass)
418 : : {
419 : 0 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
420 : 0 : GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
421 : :
422 : 0 : object_class->get_property = mct_time_page_get_property;
423 : 0 : object_class->set_property = mct_time_page_set_property;
424 : 0 : object_class->constructed = mct_time_page_constructed;
425 : 0 : object_class->dispose = mct_time_page_dispose;
426 : 0 : object_class->finalize = mct_time_page_finalize;
427 : :
428 : : /**
429 : : * MctTimePage:user:
430 : : *
431 : : * The currently selected user account.
432 : : *
433 : : * Since 0.14.0
434 : : */
435 : 0 : properties[PROP_USER] =
436 : 0 : g_param_spec_object ("user",
437 : : "User",
438 : : "The currently selected user account.",
439 : : MCT_TYPE_USER,
440 : : G_PARAM_READWRITE |
441 : : G_PARAM_STATIC_STRINGS |
442 : : G_PARAM_EXPLICIT_NOTIFY);
443 : :
444 : : /**
445 : : * MctTimePage:connection: (not nullable)
446 : : *
447 : : * A connection to the system bus, where malcontent-timerd runs. It’s
448 : : * provided to allow an existing connection to be re-used and for testing
449 : : * purposes.
450 : : *
451 : : * Since 0.14.0
452 : : */
453 : 0 : properties[PROP_CONNECTION] = g_param_spec_object ("connection", NULL, NULL,
454 : : G_TYPE_DBUS_CONNECTION,
455 : : G_PARAM_READWRITE |
456 : : G_PARAM_CONSTRUCT_ONLY |
457 : : G_PARAM_STATIC_STRINGS);
458 : :
459 : : /**
460 : : * MctTimePage:policy-manager:
461 : : *
462 : : * Policy manager to provider users’ parental controls policies.
463 : : *
464 : : * Since 0.14.0
465 : : */
466 : 0 : properties[PROP_POLICY_MANAGER] =
467 : 0 : g_param_spec_object ("policy-manager", NULL, NULL,
468 : : MCT_TYPE_MANAGER,
469 : : G_PARAM_READWRITE |
470 : : G_PARAM_CONSTRUCT_ONLY |
471 : : G_PARAM_STATIC_STRINGS);
472 : :
473 : 0 : g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties);
474 : :
475 : 0 : g_type_ensure (CC_TYPE_DURATION_ROW);
476 : 0 : g_type_ensure (CC_TYPE_TIME_ROW);
477 : 0 : g_type_ensure (MCT_TYPE_SCREEN_TIME_STATISTICS_ROW);
478 : :
479 : 0 : gtk_widget_class_set_template_from_resource (widget_class, "/org/freedesktop/MalcontentControl/ui/time-page.ui");
480 : :
481 : 0 : gtk_widget_class_bind_template_child (widget_class, MctTimePage, time_window_title);
482 : 0 : gtk_widget_class_bind_template_child (widget_class, MctTimePage, preferences_group);
483 : 0 : gtk_widget_class_bind_template_child (widget_class, MctTimePage, preferences_page);
484 : 0 : gtk_widget_class_bind_template_child (widget_class, MctTimePage, screen_time_limit_row);
485 : 0 : gtk_widget_class_bind_template_child (widget_class, MctTimePage, bedtime_schedule_row);
486 : 0 : gtk_widget_class_bind_template_child (widget_class, MctTimePage, daily_time_limit_row);
487 : 0 : gtk_widget_class_bind_template_child (widget_class, MctTimePage, bedtime_row);
488 : :
489 : 0 : gtk_widget_class_bind_template_callback (widget_class, screen_time_limit_row_notify_active_cb);
490 : 0 : gtk_widget_class_bind_template_callback (widget_class, bedtime_schedule_row_notify_active_cb);
491 : 0 : gtk_widget_class_bind_template_callback (widget_class, bedtime_row_notify_time_cb);
492 : 0 : gtk_widget_class_bind_template_callback (widget_class, daily_time_limit_row_notify_duration_cb);
493 : 0 : }
494 : :
495 : : static void
496 : 0 : mct_time_page_init (MctTimePage *self)
497 : : {
498 : 0 : g_autoptr(GtkCssProvider) provider = NULL;
499 : :
500 : 0 : gtk_widget_init_template (GTK_WIDGET (self));
501 : :
502 : 0 : provider = gtk_css_provider_new ();
503 : 0 : gtk_css_provider_load_from_resource (provider, "/org/freedesktop/MalcontentControl/ui/wellbeing.css");
504 : 0 : gtk_style_context_add_provider_for_display (gdk_display_get_default (),
505 : 0 : GTK_STYLE_PROVIDER (provider),
506 : : GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
507 : :
508 : 0 : self->cancellable = g_cancellable_new ();
509 : 0 : }
510 : :
511 : : /**
512 : : * mct_time_page_new:
513 : : * @policy_manager: (transfer none): policy manager for querying user parental
514 : : * controls policies
515 : : * @connection: (transfer none): a #GDBusConnection to use
516 : : *
517 : : * Create a new #MctTimePage widget.
518 : : *
519 : : * Returns: (transfer full): a new time page
520 : : * Since: 0.14.0
521 : : */
522 : : MctTimePage *
523 : 0 : mct_time_page_new (MctManager *policy_manager, GDBusConnection *connection)
524 : : {
525 : 0 : g_return_val_if_fail (MCT_IS_MANAGER (policy_manager), NULL);
526 : 0 : g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
527 : :
528 : 0 : return g_object_new (MCT_TYPE_TIME_PAGE,
529 : : "policy-manager", policy_manager,
530 : : "connection", connection,
531 : : NULL);
532 : : }
533 : :
534 : : /**
535 : : * mct_time_page_get_user:
536 : : * @self: an #MctTimePage
537 : : * @user: an #MctUser
538 : : *
539 : : * Get the currently selected user.
540 : : *
541 : : * Returns: (transfer none): the currently selected user
542 : : * Since: 0.14.0
543 : : */
544 : : MctUser *
545 : 0 : mct_time_page_get_user (MctTimePage *self)
546 : : {
547 : 0 : g_return_val_if_fail (MCT_IS_TIME_PAGE (self), NULL);
548 : :
549 : 0 : return self->user;
550 : : }
551 : :
552 : : static void
553 : 0 : user_notify_cb (GObject *object,
554 : : GParamSpec *pspec,
555 : : void *user_data)
556 : : {
557 : 0 : MctUser *user = MCT_USER (object);
558 : 0 : MctTimePage *self = MCT_TIME_PAGE (user_data);
559 : :
560 : 0 : g_autofree gchar *help_label = NULL;
561 : 0 : adw_window_title_set_subtitle (self->time_window_title,
562 : : mct_user_get_display_name (user));
563 : :
564 : : /* Translators: Replace the link to commonsensemedia.org with some
565 : : * localised guidance for parents/carers on how to set restrictions on
566 : : * their child/caree in a responsible way which is in keeping with the
567 : : * best practice and culture of the region. If no suitable localised
568 : : * guidance exists, and if the default commonsensemedia.org link is not
569 : : * suitable, please file an issue against malcontent so we can discuss
570 : : * further!
571 : : * https://gitlab.freedesktop.org/pwithnall/malcontent/-/issues/new
572 : : */
573 : 0 : help_label = g_strdup_printf (_("It’s recommended that Screen Time "
574 : : "limits and schedules are set as part of "
575 : : "an ongoing conversation with %s. <a href='https://www.commonsensemedia.org/privacy-and-internet-safety'>"
576 : : "Read guidance</a> on what to consider."),
577 : : mct_user_get_display_name (user));
578 : 0 : adw_preferences_page_set_description (self->preferences_page, help_label);
579 : 0 : }
580 : :
581 : : /**
582 : : * mct_time_page_set_user:
583 : : * @self: an #MctTimePage
584 : : * @user: an #MctUser
585 : : *
586 : : * Set the currently selected user.
587 : : *
588 : : * Since: 0.14.0
589 : : */
590 : : void
591 : 0 : mct_time_page_set_user (MctTimePage *self,
592 : : MctUser *user)
593 : : {
594 : 0 : g_return_if_fail (MCT_IS_TIME_PAGE (self));
595 : 0 : g_return_if_fail (MCT_IS_USER (user));
596 : :
597 : 0 : g_autoptr(MctUser) old_user = NULL;
598 : : uid_t uid;
599 : :
600 : : /* If we have pending unsaved changes from the previous user, force them to be
601 : : * saved first. */
602 : 0 : flush_update_session_limits (self);
603 : :
604 [ # # ]: 0 : old_user = (self->user != NULL) ? g_object_ref (self->user) : NULL;
605 : :
606 [ # # ]: 0 : if (g_set_object (&self->user, user))
607 : : {
608 [ # # ]: 0 : if (old_user != NULL)
609 [ # # ]: 0 : g_clear_signal_handler (&self->user_notify_id, old_user);
610 : :
611 [ # # ]: 0 : if (user != NULL)
612 : : {
613 : 0 : self->user_notify_id = g_signal_connect (user,
614 : : "notify",
615 : : G_CALLBACK (user_notify_cb),
616 : : self);
617 : 0 : user_notify_cb (G_OBJECT (user), NULL, self);
618 : : }
619 : :
620 : : /* Set a default bedtime of 20:00 */
621 : 0 : cc_time_row_set_time (self->bedtime_row, 20 * 60);
622 : :
623 : 0 : mct_manager_get_session_limits_async (self->policy_manager,
624 : : mct_user_get_uid (self->user),
625 : : MCT_MANAGER_GET_VALUE_FLAGS_NONE,
626 : : self->cancellable,
627 : : get_session_limits_cb,
628 : : self);
629 : :
630 [ # # ]: 0 : if (self->row != NULL)
631 : : {
632 : 0 : adw_preferences_group_remove (self->preferences_group,
633 : 0 : GTK_WIDGET (self->row));
634 : : }
635 : :
636 : 0 : uid = mct_user_get_uid (self->user);
637 : 0 : self->row = mct_screen_time_statistics_row_new (self->connection, uid);
638 : 0 : g_object_bind_property (self->daily_time_limit_row, "duration",
639 : 0 : self->row, "daily-limit",
640 : : G_BINDING_SYNC_CREATE);
641 : :
642 : 0 : adw_preferences_group_add (self->preferences_group,
643 : 0 : GTK_WIDGET (self->row));
644 : :
645 : 0 : g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_USER]);
646 : : }
647 : : }
|