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