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 : : #define GNOME_DESKTOP_USE_UNSTABLE_API
28 : : #include <libgnome-desktop/gnome-wall-clock.h>
29 : : #include <libmalcontent-ui/malcontent-ui.h>
30 : : #include <stdint.h>
31 : :
32 : : #include "user-page.h"
33 : : #include "user-image.h"
34 : : #include "access-page.h"
35 : :
36 : : #define CLOCK_SCHEMA "org.gnome.desktop.interface"
37 : : #define CLOCK_FORMAT_KEY "clock-format"
38 : :
39 : : static void user_page_clock_changed_cb (GSettings *settings, char *key, void *user_data);
40 : : static void update_last_login_label (MctUserPage *self);
41 : : static void update_screen_time_level_bar (MctUserPage *self);
42 : :
43 : : /* Copied from panels/wellbeing/cc-screen-time-statistics-row.c
44 : : * in gnome-control-center */
45 : : static char *
46 : 0 : format_hours_and_minutes (unsigned int minutes,
47 : : gboolean omit_minutes_if_zero)
48 : : {
49 : 0 : unsigned int hours = minutes / 60;
50 : 0 : minutes %= 60;
51 : :
52 : : /* Technically we should be formatting these units as per the SI Brochure,
53 : : * table 8 and §5.4.3: with a 0+00A0 (non-breaking space) between the value
54 : : * and unit; and using ‘min’ as the unit for minutes, not ‘m’.
55 : : *
56 : : * However, space is very restricted here, so we’re optimising for that.
57 : : * Given that the whole panel is about screen *time*, hopefully the meaning of
58 : : * the numbers should be obvious. */
59 : :
60 [ # # # # ]: 0 : if (hours == 0 && minutes > 0)
61 : : {
62 : : /* Translators: This is a duration in minutes, for example ‘15m’ for 15 minutes.
63 : : * Use whatever shortest unit label is used for minutes in your locale. */
64 : 0 : return g_strdup_printf (_("%um"), minutes);
65 : : }
66 [ # # ]: 0 : else if (minutes == 0)
67 : : {
68 : : /* Translators: This is a duration in hours, for example ‘2h’ for 2 hours.
69 : : * Use whatever shortest unit label is used for hours in your locale. */
70 : 0 : return g_strdup_printf (_("%uh"), hours);
71 : : }
72 : : else
73 : : {
74 : : /* Translators: This is a duration in hours and minutes, for example
75 : : * ‘3h 15m’ for 3 hours and 15 minutes. Use whatever shortest unit label
76 : : * is used for hours and minutes in your locale. */
77 : 0 : return g_strdup_printf (_("%uh %um"), hours, minutes);
78 : : }
79 : : }
80 : :
81 : : /**
82 : : * MctUserPage:
83 : : *
84 : : * A widget which shows available parental controls for the selected user.
85 : : *
86 : : * [property@Malcontent.UserPage:user] may be `NULL`, in which case the
87 : : * contents of the widget are undefined and it should not be shown.
88 : : *
89 : : * Since: 0.14.0
90 : : */
91 : : struct _MctUserPage
92 : : {
93 : : AdwNavigationPage parent;
94 : :
95 : : MctUserImage *user_image;
96 : : GtkLabel *name_label;
97 : : GtkLabel *date_label;
98 : : GtkLabel *screen_time_label;
99 : : GtkLabel *last_login_label;
100 : : GtkLevelBar *screen_time_level_bar;
101 : : GSettings *clock_settings; /* (owned) */
102 : : GCancellable *cancellable; /* (owned) */
103 : : unsigned long user_notify_id;
104 : : unsigned int daily_limit_secs;
105 : : gboolean daily_limit_enabled;
106 : : uint64_t active_today_time_secs;
107 : :
108 : : unsigned long clock_changed_id;
109 : : unsigned long session_limits_changed_id;
110 : : unsigned int usage_changed_id;
111 : :
112 : : MctUser *user; /* (owned) (nullable) */
113 : : GDBusConnection *connection; /* (owned) */
114 : : MctManager *policy_manager; /* (owned) */
115 : : };
116 : :
117 [ # # # # : 0 : G_DEFINE_TYPE (MctUserPage, mct_user_page, ADW_TYPE_NAVIGATION_PAGE)
# # ]
118 : :
119 : : typedef enum
120 : : {
121 : : PROP_USER = 1,
122 : : PROP_CONNECTION,
123 : : PROP_POLICY_MANAGER,
124 : : } MctUserPageProperties;
125 : :
126 : : static GParamSpec *properties[PROP_POLICY_MANAGER + 1];
127 : :
128 : : static void
129 : 0 : mct_user_page_get_property (GObject *object,
130 : : guint prop_id,
131 : : GValue *value,
132 : : GParamSpec *pspec)
133 : : {
134 : 0 : MctUserPage *self = MCT_USER_PAGE (object);
135 : :
136 [ # # # # ]: 0 : switch ((MctUserPageProperties) prop_id)
137 : : {
138 : 0 : case PROP_USER:
139 : 0 : g_value_set_object (value, self->user);
140 : 0 : break;
141 : :
142 : 0 : case PROP_CONNECTION:
143 : 0 : g_value_set_object (value, self->connection);
144 : 0 : break;
145 : :
146 : 0 : case PROP_POLICY_MANAGER:
147 : 0 : g_value_set_object (value, self->policy_manager);
148 : 0 : break;
149 : :
150 : 0 : default:
151 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
152 : : }
153 : 0 : }
154 : :
155 : : static void
156 : 0 : mct_user_page_set_property (GObject *object,
157 : : guint prop_id,
158 : : const GValue *value,
159 : : GParamSpec *pspec)
160 : : {
161 : 0 : MctUserPage *self = MCT_USER_PAGE (object);
162 : :
163 [ # # # # ]: 0 : switch ((MctUserPageProperties) prop_id)
164 : : {
165 : 0 : case PROP_USER:
166 : 0 : mct_user_page_set_user (self, g_value_get_object (value), NULL);
167 : 0 : break;
168 : :
169 : 0 : case PROP_CONNECTION:
170 : : /* Construct-only. May not be %NULL. */
171 : 0 : g_assert (self->connection == NULL);
172 : 0 : self->connection = g_value_dup_object (value);
173 : 0 : g_assert (self->connection != NULL);
174 : 0 : break;
175 : :
176 : 0 : case PROP_POLICY_MANAGER:
177 : : /* Construct-only. May not be %NULL. */
178 : 0 : g_assert (self->policy_manager == NULL);
179 : 0 : self->policy_manager = g_value_dup_object (value);
180 : 0 : g_assert (self->policy_manager != NULL);
181 : 0 : break;
182 : :
183 : 0 : default:
184 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
185 : : }
186 : 0 : }
187 : :
188 : : static void
189 : 0 : mct_user_page_constructed (GObject *object)
190 : : {
191 : 0 : MctUserPage *self = MCT_USER_PAGE (object);
192 : :
193 : 0 : g_assert (self->connection != NULL);
194 : :
195 : 0 : G_OBJECT_CLASS (mct_user_page_parent_class)->constructed (object);
196 : 0 : }
197 : :
198 : : static void
199 : 0 : mct_user_page_dispose (GObject *object)
200 : : {
201 : 0 : MctUserPage *self = MCT_USER_PAGE (object);
202 : :
203 [ # # ]: 0 : g_clear_object (&self->cancellable);
204 [ # # ]: 0 : g_clear_signal_handler (&self->user_notify_id, self->user);
205 [ # # ]: 0 : g_clear_object (&self->user);
206 [ # # ]: 0 : g_clear_signal_handler (&self->clock_changed_id, self->clock_settings);
207 [ # # ]: 0 : g_clear_signal_handler (&self->session_limits_changed_id, self->policy_manager);
208 : :
209 [ # # # # ]: 0 : if (self->connection != NULL && self->usage_changed_id != 0)
210 : : {
211 : 0 : g_dbus_connection_signal_unsubscribe (self->connection, self->usage_changed_id);
212 : 0 : self->usage_changed_id = 0;
213 : : }
214 : :
215 [ # # ]: 0 : g_clear_object (&self->clock_settings);
216 [ # # ]: 0 : g_clear_object (&self->connection);
217 [ # # ]: 0 : g_clear_object (&self->policy_manager);
218 : :
219 : 0 : G_OBJECT_CLASS (mct_user_page_parent_class)->dispose (object);
220 : 0 : }
221 : :
222 : : static void
223 : 0 : mct_user_page_class_init (MctUserPageClass *klass)
224 : : {
225 : 0 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
226 : 0 : GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
227 : :
228 : 0 : g_type_ensure (MCT_TYPE_USER_IMAGE);
229 : :
230 : 0 : object_class->get_property = mct_user_page_get_property;
231 : 0 : object_class->set_property = mct_user_page_set_property;
232 : 0 : object_class->constructed = mct_user_page_constructed;
233 : 0 : object_class->dispose = mct_user_page_dispose;
234 : :
235 : : /**
236 : : * MctUserPage:user: (nullable)
237 : : *
238 : : * The currently selected user account.
239 : : *
240 : : * Since 0.14.0
241 : : */
242 : 0 : properties[PROP_USER] =
243 : 0 : g_param_spec_object ("user", NULL, NULL,
244 : : MCT_TYPE_USER,
245 : : G_PARAM_READWRITE |
246 : : G_PARAM_STATIC_STRINGS |
247 : : G_PARAM_EXPLICIT_NOTIFY);
248 : :
249 : : /**
250 : : * MctUserPage:connection: (not nullable)
251 : : *
252 : : * A connection to the system bus, where malcontent-timerd runs.
253 : : *
254 : : * It’s provided to allow an existing connection to be re-used and for testing
255 : : * purposes.
256 : : *
257 : : * Since 0.14.0
258 : : */
259 : 0 : properties[PROP_CONNECTION] =
260 : 0 : g_param_spec_object ("connection", NULL, NULL,
261 : : G_TYPE_DBUS_CONNECTION,
262 : : G_PARAM_READWRITE |
263 : : G_PARAM_CONSTRUCT_ONLY |
264 : : G_PARAM_STATIC_STRINGS);
265 : :
266 : : /**
267 : : * MctUserPage:policy-manager: (not nullable)
268 : : *
269 : : * The policy manager providing the data for the widget.
270 : : *
271 : : * Since: 0.14.0
272 : : */
273 : 0 : properties[PROP_POLICY_MANAGER] =
274 : 0 : g_param_spec_object ("policy-manager", NULL, NULL,
275 : : MCT_TYPE_MANAGER,
276 : : G_PARAM_READWRITE |
277 : : G_PARAM_CONSTRUCT_ONLY |
278 : : G_PARAM_STATIC_STRINGS);
279 : :
280 : 0 : g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties);
281 : :
282 : 0 : gtk_widget_class_set_template_from_resource (widget_class, "/org/freedesktop/MalcontentControl/ui/user-page.ui");
283 : :
284 : 0 : gtk_widget_class_bind_template_child (widget_class, MctUserPage, user_image);
285 : 0 : gtk_widget_class_bind_template_child (widget_class, MctUserPage, name_label);
286 : 0 : gtk_widget_class_bind_template_child (widget_class, MctUserPage, date_label);
287 : 0 : gtk_widget_class_bind_template_child (widget_class, MctUserPage, screen_time_label);
288 : 0 : gtk_widget_class_bind_template_child (widget_class, MctUserPage, last_login_label);
289 : 0 : gtk_widget_class_bind_template_child (widget_class, MctUserPage, screen_time_level_bar);
290 : 0 : }
291 : :
292 : : static void
293 : 0 : mct_user_page_init (MctUserPage *self)
294 : : {
295 : 0 : gtk_widget_init_template (GTK_WIDGET (self));
296 : :
297 : 0 : self->cancellable = g_cancellable_new ();
298 : :
299 : 0 : self->clock_settings = g_settings_new (CLOCK_SCHEMA);
300 : :
301 : 0 : self->clock_changed_id = g_signal_connect (self->clock_settings,
302 : : "changed::" CLOCK_FORMAT_KEY,
303 : : G_CALLBACK (user_page_clock_changed_cb),
304 : : self);
305 : 0 : }
306 : :
307 : : static void
308 : 0 : update_date_label (MctUserPage *self)
309 : : {
310 : 0 : g_autoptr (GDateTime) now_date_time = NULL;
311 : : GDate today_date;
312 : 0 : char today_date_text[100] = { 0, };
313 : :
314 : 0 : now_date_time = g_date_time_new_now_local ();
315 : 0 : g_date_set_time_t (&today_date, g_date_time_to_unix (now_date_time));
316 : 0 : g_date_strftime (today_date_text, sizeof (today_date_text), _("Today, %-d %B"), &today_date);
317 : 0 : gtk_label_set_label (self->date_label, today_date_text);
318 : 0 : }
319 : :
320 : : static void
321 : 0 : update_screen_time_label (MctUserPage *self)
322 : : {
323 : 0 : g_autofree char *active_today_time_text = NULL;
324 : :
325 : 0 : active_today_time_text = format_hours_and_minutes (self->active_today_time_secs / 60, FALSE);
326 : 0 : gtk_label_set_label (self->screen_time_label, active_today_time_text);
327 : 0 : }
328 : :
329 : : static void
330 : 0 : update_screen_time_level_bar (MctUserPage *self)
331 : : {
332 : : double max_value;
333 : :
334 : 0 : max_value = self->daily_limit_secs;
335 : :
336 : : /* If the daily limit is not set, use 24 hours as
337 : : * a maximum in the level bar. */
338 [ # # ]: 0 : if (self->daily_limit_secs == 0)
339 : : {
340 : 0 : max_value = 24 * 60 * 60;
341 : : }
342 : :
343 [ # # # # ]: 0 : gtk_level_bar_set_value (self->screen_time_level_bar, CLAMP (self->active_today_time_secs, 1, max_value));
344 : 0 : gtk_level_bar_set_max_value (self->screen_time_level_bar, max_value);
345 : 0 : }
346 : :
347 : : static void
348 : 0 : update_last_login_label (MctUserPage *self)
349 : : {
350 : : GDesktopClockFormat clock_format;
351 : : uint64_t login_time;
352 [ # # ]: 0 : g_autoptr (GDateTime) date_time = NULL;
353 [ # # ]: 0 : g_autofree char *last_login = NULL;
354 [ # # ]: 0 : g_autofree char *last_login_label = NULL;
355 : :
356 : 0 : clock_format = g_settings_get_enum (self->clock_settings, CLOCK_FORMAT_KEY);
357 : 0 : login_time = mct_user_get_login_time (self->user);
358 : :
359 [ # # ]: 0 : if (login_time == 0)
360 : : {
361 : 0 : gtk_widget_set_visible (GTK_WIDGET (self->last_login_label), FALSE);
362 : 0 : return;
363 : : }
364 : : else
365 : : {
366 : 0 : gtk_widget_set_visible (GTK_WIDGET (self->last_login_label), TRUE);
367 : : }
368 : :
369 : 0 : date_time = g_date_time_new_from_unix_local (login_time);
370 : :
371 [ # # ]: 0 : if (clock_format == G_DESKTOP_CLOCK_FORMAT_12H)
372 : : {
373 : : /* Translators: This is the full date and time format used in 12-hour mode. */
374 : 0 : last_login = g_date_time_format (date_time, _("%-e %B %Y, %-l:%M %P"));
375 : : }
376 : : else
377 : : {
378 : : /* Translators: This is the full date and time format used in 24-hour mode. */
379 : 0 : last_login = g_date_time_format (date_time, _("%-e %B %Y, %-k:%M"));
380 : : }
381 : :
382 : 0 : last_login_label = g_strdup_printf (_("Last logged in: %s"), last_login);
383 : 0 : gtk_label_set_label (self->last_login_label, last_login_label);
384 : : }
385 : :
386 : : static void
387 : : query_usage_cb (GObject *object,
388 : : GAsyncResult *result,
389 : : void *user_data);
390 : :
391 : : static void
392 : : get_session_limits_cb (GObject *object,
393 : : GAsyncResult *result,
394 : : void *user_data);
395 : :
396 : : static void
397 : 0 : update_cached_usage (MctUserPage *self)
398 : : {
399 : 0 : g_dbus_connection_call (self->connection,
400 : : "org.freedesktop.MalcontentTimer1",
401 : : "/org/freedesktop/MalcontentTimer1",
402 : : "org.freedesktop.MalcontentTimer1.Parent",
403 : : "QueryUsage",
404 : : g_variant_new ("(uss)",
405 : : mct_user_get_uid (self->user),
406 : : "login-session",
407 : : ""),
408 : : (const GVariantType *) "(a(tt))",
409 : : G_DBUS_CALL_FLAGS_NONE,
410 : : -1,
411 : : self->cancellable,
412 : : query_usage_cb,
413 : : self);
414 : 0 : }
415 : :
416 : : static void
417 : 0 : update_cached_limits (MctUserPage *self)
418 : : {
419 : 0 : mct_manager_get_session_limits_async (self->policy_manager,
420 : : mct_user_get_uid (self->user),
421 : : MCT_MANAGER_GET_VALUE_FLAGS_NONE,
422 : : self->cancellable,
423 : : get_session_limits_cb,
424 : : self);
425 : 0 : }
426 : :
427 : : static void
428 : 0 : get_session_limits_cb (GObject *object,
429 : : GAsyncResult *result,
430 : : void *user_data)
431 : : {
432 : 0 : MctUserPage *self = MCT_USER_PAGE (user_data);
433 [ # # ]: 0 : g_autoptr (MctSessionLimits) limits = NULL;
434 [ # # ]: 0 : g_autoptr (GError) local_error = NULL;
435 : :
436 : 0 : limits = mct_manager_get_session_limits_finish (self->policy_manager,
437 : : result,
438 : : &local_error);
439 : :
440 [ # # ]: 0 : if (limits == NULL)
441 : : {
442 : 0 : g_warning ("Error getting session limits: %s", local_error->message);
443 : 0 : return;
444 : : }
445 : :
446 : 0 : self->daily_limit_enabled = mct_session_limits_get_daily_limit (limits, &self->daily_limit_secs);
447 : :
448 : 0 : update_screen_time_level_bar (self);
449 : : }
450 : :
451 : : static void
452 : 0 : policy_manager_session_limits_changed_cb (GObject *object,
453 : : uid_t uid,
454 : : void *user_data)
455 : : {
456 : 0 : MctUserPage *self = MCT_USER_PAGE (user_data);
457 : :
458 : 0 : update_cached_limits (self);
459 : 0 : }
460 : :
461 : : static void
462 : 0 : query_usage_cb (GObject *object,
463 : : GAsyncResult *result,
464 : : void *user_data)
465 : : {
466 : 0 : MctUserPage *self = MCT_USER_PAGE (user_data);
467 [ # # ]: 0 : g_autoptr (GDateTime) now_date_time = NULL;
468 : : GDate today_date;
469 [ # # ]: 0 : g_autoptr (GVariant) result_variant = NULL;
470 [ # # ]: 0 : g_autoptr (GError) local_error = NULL;
471 [ # # ]: 0 : g_autoptr (GVariantIter) entries_iter = NULL;
472 : : uint64_t start_wall_time_secs, end_wall_time_secs;
473 : :
474 : 0 : now_date_time = g_date_time_new_now_local ();
475 : 0 : g_date_set_time_t (&today_date, g_date_time_to_unix (now_date_time));
476 : :
477 : 0 : result_variant = g_dbus_connection_call_finish (self->connection,
478 : : result,
479 : : &local_error);
480 : :
481 [ # # ]: 0 : if (result_variant == NULL)
482 : : {
483 : 0 : g_warning ("Failed to get usage data for the level bar: %s", local_error->message);
484 : 0 : return;
485 : : }
486 : :
487 : 0 : g_variant_get (result_variant, "(a(tt))", &entries_iter);
488 : :
489 : 0 : self->active_today_time_secs = 0;
490 : :
491 [ # # ]: 0 : while (g_variant_iter_loop (entries_iter, "(tt)", &start_wall_time_secs, &end_wall_time_secs))
492 : : {
493 : : GDate start_date, end_date;
494 : :
495 : 0 : g_date_set_time_t (&start_date, start_wall_time_secs);
496 : 0 : g_date_set_time_t (&end_date, end_wall_time_secs);
497 : :
498 [ # # ]: 0 : if (g_date_compare (&end_date, &today_date) != 0)
499 : : {
500 : 0 : continue;
501 : : }
502 : :
503 : : /* If the recorded usage entry began on an earlier day than today,
504 : : * clamp it to the beginning of today */
505 [ # # ]: 0 : if (g_date_compare (&start_date, &end_date) != 0)
506 : : {
507 : 0 : g_autoptr (GDateTime) date_time = NULL;
508 : 0 : g_autoptr (GTimeZone) time_zone = NULL;
509 : :
510 : 0 : time_zone = g_time_zone_new_local ();
511 : 0 : date_time = g_date_time_new (time_zone,
512 : 0 : g_date_get_year (&end_date),
513 : 0 : g_date_get_month (&end_date),
514 : 0 : g_date_get_day (&end_date),
515 : : 0, 0, 0.0);
516 : 0 : start_wall_time_secs = g_date_time_to_unix (date_time);
517 : : }
518 : :
519 : 0 : self->active_today_time_secs += end_wall_time_secs - start_wall_time_secs;
520 : : }
521 : :
522 : 0 : update_date_label (self);
523 : 0 : update_screen_time_level_bar (self);
524 : 0 : update_screen_time_label (self);
525 : : }
526 : :
527 : : static void
528 : 0 : usage_changed_cb (GDBusConnection *connection,
529 : : const char *sender_name,
530 : : const char *object_path,
531 : : const char *interface_name,
532 : : const char *signal_name,
533 : : GVariant *parameters,
534 : : void *user_data)
535 : : {
536 : 0 : MctUserPage *self = MCT_USER_PAGE (user_data);
537 : :
538 : 0 : update_cached_usage (self);
539 : 0 : }
540 : :
541 : : static void
542 : 0 : user_page_clock_changed_cb (GSettings *settings,
543 : : char *key,
544 : : void *user_data)
545 : : {
546 : 0 : MctUserPage *self = MCT_USER_PAGE (user_data);
547 : :
548 : 0 : update_last_login_label (self);
549 : 0 : }
550 : :
551 : : /**
552 : : * mct_user_page_new:
553 : : * @connection: (transfer none): a D-Bus connection to use
554 : : * @policy-manager: (transfer none): a policy manager to use
555 : : *
556 : : * Create a new [class@Malcontent.UserPage] widget.
557 : : *
558 : : * Returns: (transfer full): a new user page
559 : : * Since: 0.14.0
560 : : */
561 : : MctUserPage *
562 : 0 : mct_user_page_new (GDBusConnection *connection,
563 : : MctManager *policy_manager)
564 : : {
565 : 0 : return g_object_new (MCT_TYPE_USER_PAGE,
566 : : "connection", connection,
567 : : "policy-manager", policy_manager,
568 : : NULL);
569 : : }
570 : :
571 : : /**
572 : : * mct_user_page_get_user:
573 : : * @self: a user page
574 : : *
575 : : * Get the currently selected user.
576 : : *
577 : : * Returns: (transfer none) (nullable): the currently selected user
578 : : * Since: 0.14.0
579 : : */
580 : : MctUser *
581 : 0 : mct_user_page_get_user (MctUserPage *self)
582 : : {
583 : 0 : g_return_val_if_fail (MCT_IS_USER_PAGE (self), NULL);
584 : :
585 : 0 : return self->user;
586 : : }
587 : :
588 : : static void
589 : 0 : user_notify_cb (GObject *object,
590 : : GParamSpec *pspec,
591 : : void *user_data)
592 : : {
593 : 0 : MctUser *user = MCT_USER (object);
594 : 0 : MctUserPage *self = MCT_USER_PAGE (user_data);
595 : :
596 : 0 : gtk_label_set_label (self->name_label, mct_user_get_display_name (user));
597 : 0 : update_last_login_label (self);
598 : 0 : }
599 : :
600 : : /**
601 : : * mct_user_page_set_user:
602 : : * @self: a user page
603 : : * @user: (nullable): a user
604 : : * @permission: (nullable) (transfer none): the [class@Gio.Permission]
605 : : * indicating whether the current user has permission to view or change
606 : : * parental controls, or `NULL` if permission is not allowed or is unknown
607 : : *
608 : : * Set the currently selected user
609 : : *
610 : : * Since: 0.14.0
611 : : */
612 : : void
613 : 0 : mct_user_page_set_user (MctUserPage *self,
614 : : MctUser *user,
615 : : GPermission *permission)
616 : : {
617 : 0 : g_return_if_fail (MCT_IS_USER_PAGE (self));
618 : 0 : g_return_if_fail (MCT_IS_USER (user));
619 : 0 : g_return_if_fail (permission == NULL || G_IS_PERMISSION (permission));
620 : :
621 [ # # ]: 0 : if (g_set_object (&self->user, user))
622 : : {
623 [ # # ]: 0 : if (user != NULL)
624 : : {
625 : 0 : mct_user_image_set_user (self->user_image, user);
626 : 0 : mct_user_image_set_size (self->user_image, 128);
627 : 0 : gtk_widget_set_margin_top (GTK_WIDGET (self->user_image), 24);
628 : 0 : gtk_widget_set_margin_bottom (GTK_WIDGET (self->user_image), 18);
629 : :
630 : 0 : self->user_notify_id = g_signal_connect (user,
631 : : "notify",
632 : : G_CALLBACK (user_notify_cb),
633 : : self);
634 : 0 : user_notify_cb (G_OBJECT (user), NULL, self);
635 : :
636 : 0 : update_cached_limits (self);
637 : 0 : self->session_limits_changed_id =
638 : 0 : g_signal_connect (self->policy_manager,
639 : : "session-limits-changed",
640 : : G_CALLBACK (policy_manager_session_limits_changed_cb),
641 : : self);
642 : :
643 : 0 : update_cached_usage (self);
644 : 0 : self->usage_changed_id =
645 : 0 : g_dbus_connection_signal_subscribe (self->connection,
646 : : "org.freedesktop.MalcontentTimer1",
647 : : "org.freedesktop.MalcontentTimer1.Parent",
648 : : "UsageChanged",
649 : : "/org/freedesktop/MalcontentTimer1",
650 : : NULL,
651 : : G_DBUS_SIGNAL_FLAGS_NONE,
652 : : usage_changed_cb,
653 : : self,
654 : : NULL);
655 : : }
656 : :
657 : 0 : g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_USER]);
658 : : }
659 : : }
|