Branch data Line data Source code
1 : : /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 : : *
3 : : * Copyright © 2019 Endless Mobile, 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 : : * - Philip Withnall <withnall@endlessm.com>
22 : : */
23 : :
24 : : #include "config.h"
25 : :
26 : : #include <glib.h>
27 : : #include <glib-object.h>
28 : : #include <glib/gi18n-lib.h>
29 : : #include <gio/gio.h>
30 : : #include <gtk/gtk.h>
31 : : #include <adwaita.h>
32 : : #include <locale.h>
33 : : #include <polkit/polkit.h>
34 : :
35 : : #include "application.h"
36 : : #include "user-selector.h"
37 : : #include "user-page.h"
38 : : #include "access-page.h"
39 : : #include "time-page.h"
40 : :
41 : :
42 : : static void user_selector_notify_selected_user_cb (GObject *obj,
43 : : GParamSpec *pspec,
44 : : gpointer user_data);
45 : : static void user_selector_notify_n_users_cb (GObject *obj,
46 : : GParamSpec *pspec,
47 : : gpointer user_data);
48 : : static void user_manager_notify_is_loaded_cb (GObject *obj,
49 : : GParamSpec *pspec,
50 : : void *user_data);
51 : : static void user_manager_loaded_cb (GObject *object,
52 : : GAsyncResult *result,
53 : : void *user_data);
54 : : static void user_manager_loaded_user_cb (GObject *object,
55 : : GAsyncResult *result,
56 : : void *user_data);
57 : : static void user_manager_user_removed_cb (MctUserManager *user_manager,
58 : : MctUser *removed_user,
59 : : void *user_data);
60 : : static void permission_new_cb (GObject *source_object,
61 : : GAsyncResult *result,
62 : : gpointer user_data);
63 : : static void permission_notify_allowed_cb (GObject *obj,
64 : : GParamSpec *pspec,
65 : : gpointer user_data);
66 : : static void command_line_permission_notify_allowed_cb (GObject *obj,
67 : : GParamSpec *pspec,
68 : : gpointer user_data);
69 : : static void user_accounts_panel_button_clicked_cb (GtkButton *button,
70 : : gpointer user_data);
71 : : static void about_action_cb (GSimpleAction *action, GVariant *parameters, gpointer user_data);
72 : : static void help_action_cb (GSimpleAction *action, GVariant *parameters, gpointer user_data);
73 : : static void quit_action_cb (GSimpleAction *action, GVariant *parameters, gpointer user_data);
74 : : static void update_main_stack (MctApplication *self);
75 : : static void select_user_by_command_line_username (MctApplication *self);
76 : :
77 : :
78 : : /**
79 : : * MctApplication:
80 : : *
81 : : * A top-level object representing the parental controls application.
82 : : *
83 : : * Since: 0.5.0
84 : : */
85 : : struct _MctApplication
86 : : {
87 : : GtkApplication parent_instance;
88 : :
89 : : GCancellable *cancellable; /* (owned) */
90 : :
91 : : GDBusConnection *dbus_connection; /* (owned) */
92 : : MctManager *policy_manager; /* (owned) */
93 : : MctUserManager *user_manager; /* (owned) */
94 : : GError *user_manager_load_error; /* (nullable) (owned) */
95 : :
96 : : GPermission *permission; /* (owned) */
97 : : GError *permission_error; /* (nullable) (owned) */
98 : :
99 : : char *command_line_username; /* (owned) (nullable) */
100 : : unsigned long user_manager_notify_is_loaded_id;
101 : : unsigned long user_manager_user_removed_id;
102 : : unsigned long command_line_permission_notify_allowed_id;
103 : :
104 : : AdwNavigationView *navigation;
105 : : MctUserSelector *user_selector;
106 : : MctAccessPage *access_page;
107 : : MctTimePage *time_page;
108 : : GtkStack *main_stack;
109 : : AdwStatusPage *error_page;
110 : : GtkLockButton *lock_button;
111 : : GtkButton *user_accounts_panel_button;
112 : : GtkLabel *help_label;
113 : : };
114 : :
115 [ # # # # : 0 : G_DEFINE_TYPE (MctApplication, mct_application, GTK_TYPE_APPLICATION)
# # ]
116 : :
117 : : static void
118 : 0 : mct_application_init (MctApplication *self)
119 : : {
120 : 0 : self->cancellable = g_cancellable_new ();
121 : 0 : }
122 : :
123 : : static void
124 : 0 : mct_application_constructed (GObject *object)
125 : : {
126 : 0 : GApplication *application = G_APPLICATION (object);
127 : 0 : const GOptionEntry options[] =
128 : : {
129 : : { "user", 'u', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, NULL,
130 : : /* Translators: This documents the --user command line option to malcontent-control: */
131 : : N_("User to select in the UI"),
132 : : /* Translators: This is a placeholder for a command line argument value: */
133 : : N_("USERNAME") },
134 : : { NULL, },
135 : : };
136 : :
137 : 0 : g_application_set_application_id (application, "org.freedesktop.MalcontentControl");
138 : :
139 : 0 : g_application_add_main_option_entries (application, options);
140 : 0 : g_application_set_flags (application, g_application_get_flags (application) | G_APPLICATION_HANDLES_COMMAND_LINE);
141 : :
142 : : /* Translators: This is a summary of what the application does, displayed when
143 : : * it’s run with --help: */
144 : 0 : g_application_set_option_context_parameter_string (application,
145 : : N_("— view and edit parental controls"));
146 : :
147 : : /* Localisation */
148 : 0 : setlocale (LC_ALL, "");
149 : 0 : bindtextdomain ("malcontent", PACKAGE_LOCALE_DIR);
150 : 0 : bind_textdomain_codeset ("malcontent", "UTF-8");
151 : 0 : textdomain ("malcontent");
152 : :
153 : 0 : g_set_application_name (_("Parental Controls"));
154 : 0 : gtk_window_set_default_icon_name ("org.freedesktop.MalcontentControl");
155 : :
156 : 0 : G_OBJECT_CLASS (mct_application_parent_class)->constructed (object);
157 : 0 : }
158 : :
159 : : static void
160 : 0 : mct_application_dispose (GObject *object)
161 : : {
162 : 0 : MctApplication *self = MCT_APPLICATION (object);
163 : :
164 : 0 : g_cancellable_cancel (self->cancellable);
165 : :
166 : 0 : g_clear_signal_handler (&self->user_manager_notify_is_loaded_id, self->user_manager);
167 : 0 : g_clear_signal_handler (&self->user_manager_user_removed_id, self->user_manager);
168 : 0 : g_clear_object (&self->policy_manager);
169 : 0 : g_clear_object (&self->user_manager);
170 : 0 : g_clear_pointer (&self->command_line_username, g_free);
171 : 0 : g_clear_signal_handler (&self->command_line_permission_notify_allowed_id,
172 : : self->permission);
173 : :
174 [ # # ]: 0 : if (self->permission != NULL)
175 : : {
176 : 0 : g_signal_handlers_disconnect_by_func (self->permission,
177 : : permission_notify_allowed_cb, self);
178 : 0 : g_clear_object (&self->permission);
179 : : }
180 : :
181 : 0 : g_clear_object (&self->dbus_connection);
182 : 0 : g_clear_error (&self->permission_error);
183 : 0 : g_clear_error (&self->user_manager_load_error);
184 : 0 : g_clear_object (&self->cancellable);
185 : :
186 : 0 : G_OBJECT_CLASS (mct_application_parent_class)->dispose (object);
187 : 0 : }
188 : :
189 : : static GtkWindow *
190 : 0 : mct_application_get_main_window (MctApplication *self)
191 : : {
192 : 0 : return gtk_application_get_active_window (GTK_APPLICATION (self));
193 : : }
194 : :
195 : : static void
196 : 0 : mct_application_activate (GApplication *application)
197 : : {
198 : 0 : MctApplication *self = MCT_APPLICATION (application);
199 : 0 : GtkWindow *window = NULL;
200 : :
201 : 0 : window = mct_application_get_main_window (self);
202 : :
203 [ # # ]: 0 : if (window == NULL)
204 : : {
205 [ # # ]: 0 : g_autoptr(GtkBuilder) builder = NULL;
206 [ # # ]: 0 : g_autoptr(GError) local_error = NULL;
207 : :
208 : : /* Ensure the types used in the UI are registered. */
209 : 0 : g_type_ensure (MCT_TYPE_USER_SELECTOR);
210 : 0 : g_type_ensure (MCT_TYPE_ACCESS_PAGE);
211 : 0 : g_type_ensure (MCT_TYPE_TIME_PAGE);
212 : :
213 : : /* Start loading the permission */
214 : 0 : polkit_permission_new ("org.freedesktop.MalcontentControl.administration",
215 : : NULL, self->cancellable,
216 : : permission_new_cb, self);
217 : :
218 : 0 : builder = gtk_builder_new ();
219 : :
220 : 0 : g_assert (self->dbus_connection == NULL);
221 : 0 : self->dbus_connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, self->cancellable, &local_error);
222 [ # # ]: 0 : if (self->dbus_connection == NULL)
223 : : {
224 : 0 : g_error ("Error getting system bus: %s", local_error->message);
225 : : return;
226 : : }
227 : :
228 : 0 : g_assert (self->policy_manager == NULL);
229 : 0 : self->policy_manager = mct_manager_new (self->dbus_connection);
230 : :
231 : 0 : g_assert (self->user_manager == NULL);
232 : 0 : self->user_manager = mct_user_manager_new (self->dbus_connection);
233 : 0 : self->user_manager_user_removed_id = g_signal_connect (self->user_manager,
234 : : "user-removed",
235 : : G_CALLBACK (user_manager_user_removed_cb),
236 : : self);
237 : :
238 : 0 : gtk_builder_set_translation_domain (builder, "malcontent");
239 : 0 : gtk_builder_expose_object (builder, "policy_manager", G_OBJECT (self->policy_manager));
240 : 0 : gtk_builder_expose_object (builder, "user_manager", G_OBJECT (self->user_manager));
241 : 0 : gtk_builder_expose_object (builder, "dbus_connection", G_OBJECT (self->dbus_connection));
242 : :
243 : 0 : gtk_builder_add_from_resource (builder, "/org/freedesktop/MalcontentControl/ui/main.ui", &local_error);
244 : 0 : g_assert (local_error == NULL);
245 : :
246 : : /* Set up the main window. */
247 : 0 : window = GTK_WINDOW (gtk_builder_get_object (builder, "main_window"));
248 : 0 : gtk_window_set_application (window, GTK_APPLICATION (application));
249 : :
250 : 0 : self->navigation = ADW_NAVIGATION_VIEW (gtk_builder_get_object (builder, "navigation"));
251 : 0 : self->main_stack = GTK_STACK (gtk_builder_get_object (builder, "main_stack"));
252 : 0 : self->user_selector = MCT_USER_SELECTOR (gtk_builder_get_object (builder, "user_selector"));
253 : 0 : self->access_page = MCT_ACCESS_PAGE (gtk_builder_get_object (builder, "access_page"));
254 : 0 : self->time_page = MCT_TIME_PAGE (gtk_builder_get_object (builder, "time_page"));
255 : 0 : self->error_page = ADW_STATUS_PAGE (gtk_builder_get_object (builder, "error_page"));
256 : 0 : self->lock_button = GTK_LOCK_BUTTON (gtk_builder_get_object (builder, "lock_button"));
257 : 0 : self->user_accounts_panel_button = GTK_BUTTON (gtk_builder_get_object (builder, "user_accounts_panel_button"));
258 : :
259 : : /* Connect signals. */
260 : 0 : g_signal_connect_object (self->user_selector, "notify::selected-user",
261 : : G_CALLBACK (user_selector_notify_selected_user_cb),
262 : : self, G_CONNECT_DEFAULT);
263 : 0 : g_signal_connect_object (self->user_selector, "notify::n-users",
264 : : G_CALLBACK (user_selector_notify_n_users_cb),
265 : : self, G_CONNECT_DEFAULT);
266 : 0 : g_signal_connect_object (self->user_accounts_panel_button, "clicked",
267 : : G_CALLBACK (user_accounts_panel_button_clicked_cb),
268 : : self, G_CONNECT_DEFAULT);
269 : :
270 : : /* Show the loading page and start loading the users. */
271 : 0 : update_main_stack (self);
272 : 0 : mct_user_manager_load_async (self->user_manager, self->cancellable,
273 : : user_manager_loaded_cb, self);
274 : :
275 : 0 : gtk_window_present (GTK_WINDOW (window));
276 : : }
277 : :
278 : : /* Bring the window to the front. */
279 : 0 : gtk_window_present (window);
280 : : }
281 : :
282 : : static void
283 : 0 : mct_application_startup (GApplication *application)
284 : : {
285 : 0 : const GActionEntry app_entries[] =
286 : : {
287 : : { "about", about_action_cb, NULL, NULL, NULL, { 0, } },
288 : : { "help", help_action_cb, NULL, NULL, NULL, { 0, } },
289 : : { "quit", quit_action_cb, NULL, NULL, NULL, { 0, } },
290 : : };
291 : : GtkIconTheme *theme;
292 : :
293 : : /* Chain up. */
294 : 0 : G_APPLICATION_CLASS (mct_application_parent_class)->startup (application);
295 : :
296 : 0 : adw_init ();
297 : :
298 : 0 : theme = gtk_icon_theme_get_for_display (gdk_display_get_default ());
299 : 0 : gtk_icon_theme_add_resource_path (theme, "/org/freedesktop/MalcontentUi/icons");
300 : :
301 : 0 : g_action_map_add_action_entries (G_ACTION_MAP (application), app_entries,
302 : : G_N_ELEMENTS (app_entries), application);
303 : :
304 : 0 : gtk_application_set_accels_for_action (GTK_APPLICATION (application),
305 : 0 : "app.help", (const gchar * const[]) { "F1", NULL });
306 : 0 : gtk_application_set_accels_for_action (GTK_APPLICATION (application),
307 : 0 : "app.quit", (const gchar * const[]) { "<Primary>q", "<Primary>w", NULL });
308 : 0 : }
309 : :
310 : : static gint
311 : 0 : mct_application_command_line (GApplication *application,
312 : : GApplicationCommandLine *command_line)
313 : : {
314 : 0 : MctApplication *self = MCT_APPLICATION (application);
315 : 0 : GVariantDict *options = g_application_command_line_get_options_dict (command_line);
316 : : const gchar *username;
317 : :
318 : : /* Show the application. */
319 : 0 : g_application_activate (application);
320 : :
321 : : /* Select a user if requested. */
322 [ # # ]: 0 : if (g_variant_dict_lookup (options, "user", "&s", &username))
323 : : {
324 : 0 : self->command_line_username = g_strdup (username);
325 [ # # ]: 0 : if (!mct_user_manager_get_is_loaded (self->user_manager))
326 : : {
327 : 0 : self->user_manager_notify_is_loaded_id =
328 : 0 : g_signal_connect (self->user_manager,
329 : : "notify::is-loaded",
330 : : G_CALLBACK (user_manager_notify_is_loaded_cb),
331 : : self);
332 : : }
333 [ # # ]: 0 : else if (!g_permission_get_allowed (self->permission))
334 : : {
335 : 0 : g_clear_signal_handler (&self->command_line_permission_notify_allowed_id,
336 : : self->permission);
337 : :
338 : 0 : self->command_line_permission_notify_allowed_id =
339 : 0 : g_signal_connect (self->permission,
340 : : "notify::allowed",
341 : : G_CALLBACK (command_line_permission_notify_allowed_cb),
342 : : self);
343 : : }
344 : : else
345 : : {
346 : 0 : select_user_by_command_line_username (self);
347 : : }
348 : : }
349 : :
350 : 0 : return 0; /* exit status */
351 : : }
352 : :
353 : : static void
354 : 0 : mct_application_class_init (MctApplicationClass *klass)
355 : : {
356 : 0 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
357 : 0 : GApplicationClass *application_class = G_APPLICATION_CLASS (klass);
358 : :
359 : 0 : object_class->constructed = mct_application_constructed;
360 : 0 : object_class->dispose = mct_application_dispose;
361 : :
362 : 0 : application_class->activate = mct_application_activate;
363 : 0 : application_class->startup = mct_application_startup;
364 : 0 : application_class->command_line = mct_application_command_line;
365 : 0 : }
366 : :
367 : : static void
368 : 0 : about_action_cb (GSimpleAction *action, GVariant *parameters, gpointer user_data)
369 : : {
370 : 0 : MctApplication *self = MCT_APPLICATION (user_data);
371 : 0 : const gchar *developers[] =
372 : : {
373 : : "Philip Withnall <withnall@endlessm.com>",
374 : : "Georges Basile Stavracas Neto <georges@endlessm.com>",
375 : : "Andre Moreira Magalhaes <andre@endlessm.com>",
376 : : NULL
377 : : };
378 : :
379 : 0 : adw_show_about_dialog (GTK_WIDGET (mct_application_get_main_window (self)),
380 : : "application-name", g_get_application_name (),
381 : : "application-icon", "org.freedesktop.MalcontentControl",
382 : : "version", VERSION,
383 : : "website", "https://gitlab.freedesktop.org/pwithnall/malcontent",
384 : : "developers", developers,
385 : 0 : "translator-credits", _("translator-credits"),
386 : : "license-type", GTK_LICENSE_GPL_2_0,
387 : 0 : "copyright", _("Copyright © 2019, 2021–2022 Endless Mobile, Inc.\n"
388 : : "Copyright © 2022–2025 GNOME Foundation, Inc. and malcontent contributors"),
389 : : NULL);
390 : 0 : }
391 : :
392 : : static void
393 : 0 : on_malcontent_help_shown_finished_cb (GObject *source,
394 : : GAsyncResult *result,
395 : : gpointer user_data)
396 : : {
397 : 0 : MctApplication *self = MCT_APPLICATION (user_data);
398 : 0 : GtkUriLauncher *launcher = GTK_URI_LAUNCHER (source);
399 : 0 : g_autoptr(GError) local_error = NULL;
400 : :
401 [ # # ]: 0 : if (!gtk_uri_launcher_launch_finish (launcher,
402 : : result,
403 : : &local_error))
404 : : {
405 : 0 : g_autoptr(GtkAlertDialog) dialog = NULL;
406 : :
407 : 0 : dialog = gtk_alert_dialog_new (_("The help contents could not be displayed"));
408 : 0 : gtk_alert_dialog_set_detail (dialog, local_error->message);
409 : 0 : gtk_alert_dialog_set_modal (dialog, TRUE);
410 : 0 : gtk_alert_dialog_show (dialog, mct_application_get_main_window (self));
411 : : }
412 : 0 : }
413 : :
414 : : static void
415 : 0 : help_action_cb (GSimpleAction *action, GVariant *parameters, gpointer user_data)
416 : : {
417 : 0 : MctApplication *self = MCT_APPLICATION (user_data);
418 : 0 : g_autoptr(GtkUriLauncher) launcher = NULL;
419 : :
420 : 0 : launcher = gtk_uri_launcher_new ("help:malcontent");
421 : 0 : gtk_uri_launcher_launch (launcher,
422 : : mct_application_get_main_window (self),
423 : : NULL,
424 : : on_malcontent_help_shown_finished_cb,
425 : : self);
426 : 0 : }
427 : :
428 : : static void
429 : 0 : quit_action_cb (GSimpleAction *action, GVariant *parameters, gpointer user_data)
430 : : {
431 : 0 : MctApplication *self = MCT_APPLICATION (user_data);
432 : :
433 : 0 : g_application_quit (G_APPLICATION (self));
434 : 0 : }
435 : :
436 : : static void select_user_by_command_line_username_cb (GObject *object,
437 : : GAsyncResult *result,
438 : : void *user_data);
439 : :
440 : : static void
441 : 0 : select_user_by_command_line_username (MctApplication *self)
442 : : {
443 : 0 : mct_user_manager_get_user_by_username_async (self->user_manager,
444 : 0 : self->command_line_username,
445 : : self->cancellable,
446 : : select_user_by_command_line_username_cb,
447 : : self);
448 : 0 : }
449 : :
450 : : static void
451 : 0 : select_user_by_command_line_username_cb (GObject *object,
452 : : GAsyncResult *result,
453 : : void *user_data)
454 : : {
455 : 0 : MctUserManager *user_manager = MCT_USER_MANAGER (object);
456 : 0 : MctApplication *self = MCT_APPLICATION (user_data);
457 [ # # ]: 0 : g_autoptr(GError) local_error = NULL;
458 [ # # ]: 0 : g_autoptr(MctUser) user = NULL;
459 : :
460 : 0 : user = mct_user_manager_get_user_by_username_finish (user_manager,
461 : : result, &local_error);
462 [ # # ]: 0 : if (user == NULL)
463 : : {
464 : 0 : g_warning ("Failed to select user ‘%s’: %s", self->command_line_username, local_error->message);
465 : 0 : return;
466 : : }
467 : :
468 : 0 : adw_navigation_view_set_animate_transitions (self->navigation, FALSE);
469 : 0 : adw_navigation_view_pop_to_tag (self->navigation, "main_page");
470 : :
471 [ # # ]: 0 : if (!mct_user_selector_select_user (self->user_selector, user))
472 : 0 : g_warning ("Failed to select user ‘%s’", self->command_line_username);
473 : :
474 : 0 : adw_navigation_view_set_animate_transitions (self->navigation, TRUE);
475 : : }
476 : :
477 : : static void
478 : 0 : update_main_stack (MctApplication *self)
479 : : {
480 : : gboolean is_user_manager_loaded, is_permission_loaded, has_permission;
481 : : const gchar *new_page_name, *old_page_name;
482 : : GtkWidget *new_focus_widget;
483 : : guint n_users;
484 : :
485 : : /* The implementation of #MctUserManager guarantees that once is-loaded is
486 : : * true, it is never reset to false. */
487 [ # # # # ]: 0 : is_user_manager_loaded = (mct_user_manager_get_is_loaded (self->user_manager) || self->user_manager_load_error != NULL);
488 [ # # # # ]: 0 : is_permission_loaded = (self->permission != NULL || self->permission_error != NULL);
489 [ # # # # ]: 0 : has_permission = (self->permission != NULL && g_permission_get_allowed (self->permission));
490 : 0 : n_users = mct_user_selector_get_n_users (self->user_selector);
491 : :
492 : : /* Handle any loading errors (including those from getting the permission). */
493 [ # # # # ]: 0 : if (self->user_manager_load_error != NULL || self->permission_error != NULL)
494 : : {
495 : 0 : adw_status_page_set_title (self->error_page,
496 : 0 : _("Failed to load user data from the system"));
497 : 0 : adw_status_page_set_description (self->error_page,
498 : 0 : _("Please make sure that the AccountsService is installed and enabled."));
499 : :
500 : 0 : new_page_name = "error";
501 : 0 : new_focus_widget = NULL;
502 : : }
503 [ # # # # ]: 0 : else if (is_user_manager_loaded && n_users == 0)
504 : : {
505 : 0 : new_page_name = "no-other-users";
506 : 0 : new_focus_widget = GTK_WIDGET (self->user_accounts_panel_button);
507 : : }
508 [ # # # # ]: 0 : else if (is_permission_loaded && !has_permission)
509 : : {
510 : : G_GNUC_BEGIN_IGNORE_DEPRECATIONS
511 : 0 : gtk_lock_button_set_permission (self->lock_button, self->permission);
512 : : G_GNUC_END_IGNORE_DEPRECATIONS
513 : :
514 : 0 : new_page_name = "unlock";
515 : 0 : new_focus_widget = GTK_WIDGET (self->lock_button);
516 : : }
517 [ # # # # ]: 0 : else if (is_permission_loaded && is_user_manager_loaded)
518 : : {
519 : 0 : new_page_name = "controls";
520 : 0 : new_focus_widget = GTK_WIDGET (self->user_selector);
521 : : }
522 : : else
523 : : {
524 : 0 : new_page_name = "loading";
525 : 0 : new_focus_widget = NULL;
526 : : }
527 : :
528 : 0 : old_page_name = gtk_stack_get_visible_child_name (self->main_stack);
529 : 0 : gtk_stack_set_visible_child_name (self->main_stack, new_page_name);
530 : :
531 [ # # # # ]: 0 : if (new_focus_widget != NULL && !g_str_equal (old_page_name, new_page_name))
532 : 0 : gtk_widget_grab_focus (new_focus_widget);
533 : 0 : }
534 : :
535 : : static void
536 : 0 : user_selector_notify_selected_user_cb (GObject *obj,
537 : : GParamSpec *pspec,
538 : : gpointer user_data)
539 : : {
540 : 0 : MctApplication *self = MCT_APPLICATION (user_data);
541 : :
542 : : MctUser *user;
543 : : MctUserPage *user_page;
544 : :
545 : 0 : user = mct_user_selector_get_selected_user (self->user_selector);
546 : :
547 : 0 : mct_access_page_set_user (self->access_page, user, self->permission);
548 : 0 : mct_time_page_set_user (self->time_page, user);
549 : :
550 : 0 : user_page = mct_user_page_new (self->dbus_connection, self->policy_manager);
551 : 0 : mct_user_page_set_user (user_page, user, self->permission);
552 : 0 : adw_navigation_view_push (self->navigation, ADW_NAVIGATION_PAGE (user_page));
553 : :
554 : 0 : update_main_stack (self);
555 : 0 : }
556 : :
557 : : static void
558 : 0 : user_selector_notify_n_users_cb (GObject *obj,
559 : : GParamSpec *pspec,
560 : : gpointer user_data)
561 : : {
562 : 0 : MctApplication *self = MCT_APPLICATION (user_data);
563 : :
564 : 0 : update_main_stack (self);
565 : 0 : }
566 : :
567 : : static void
568 : 0 : user_manager_notify_is_loaded_cb (GObject *obj,
569 : : GParamSpec *pspec,
570 : : void *user_data)
571 : : {
572 : 0 : MctApplication *self = MCT_APPLICATION (user_data);
573 : :
574 : 0 : g_clear_signal_handler (&self->user_manager_notify_is_loaded_id, self->user_manager);
575 : :
576 [ # # ]: 0 : if (!g_permission_get_allowed (self->permission))
577 : : {
578 : 0 : self->command_line_permission_notify_allowed_id =
579 : 0 : g_signal_connect (self->permission,
580 : : "notify::allowed",
581 : : G_CALLBACK (command_line_permission_notify_allowed_cb),
582 : : self);
583 : : }
584 : : else
585 : : {
586 : 0 : select_user_by_command_line_username (self);
587 : : }
588 : 0 : }
589 : :
590 : : static void
591 : 0 : user_manager_loaded_cb (GObject *object,
592 : : GAsyncResult *result,
593 : : void *user_data)
594 : : {
595 : 0 : MctUserManager *user_manager = MCT_USER_MANAGER (object);
596 : 0 : MctApplication *self = MCT_APPLICATION (user_data);
597 : 0 : g_autoptr(GError) local_error = NULL;
598 : :
599 [ # # ]: 0 : if (!mct_user_manager_load_finish (user_manager, result, &local_error))
600 : : {
601 : 0 : g_assert (self->user_manager_load_error == NULL);
602 : 0 : self->user_manager_load_error = g_steal_pointer (&local_error);
603 : 0 : g_debug ("Error loading users: %s", self->user_manager_load_error->message);
604 : : }
605 : :
606 : 0 : mct_user_manager_get_user_by_uid_async (self->user_manager, getuid (), self->cancellable,
607 : : user_manager_loaded_user_cb, self);
608 : 0 : }
609 : :
610 : : static void
611 : 0 : user_manager_loaded_user_cb (GObject *object,
612 : : GAsyncResult *result,
613 : : void *user_data)
614 : : {
615 : 0 : MctUserManager *user_manager = MCT_USER_MANAGER (object);
616 : 0 : MctApplication *self = MCT_APPLICATION (user_data);
617 : 0 : g_autoptr(MctUser) current_user = NULL;
618 : 0 : g_autoptr(GError) local_error = NULL;
619 : :
620 : 0 : current_user = mct_user_manager_get_user_by_uid_finish (user_manager, result, &local_error);
621 [ # # ]: 0 : if (current_user != NULL)
622 : 0 : mct_user_selector_set_current_user (self->user_selector, current_user);
623 : : else
624 : 0 : g_debug ("Error loading current user: %s", local_error->message);
625 : :
626 : 0 : update_main_stack (self);
627 : 0 : }
628 : :
629 : : static void
630 : 0 : user_manager_user_removed_cb (MctUserManager *user_manager,
631 : : MctUser *removed_user,
632 : : void *user_data)
633 : : {
634 : 0 : MctApplication *self = MCT_APPLICATION (user_data);
635 : :
636 [ # # ]: 0 : if (mct_user_equal (mct_access_page_get_user (self->access_page), removed_user))
637 : 0 : adw_navigation_view_pop_to_tag (self->navigation, "main_page");
638 : :
639 : 0 : update_main_stack (self);
640 : 0 : }
641 : :
642 : : static void
643 : 0 : permission_new_cb (GObject *source_object,
644 : : GAsyncResult *result,
645 : : gpointer user_data)
646 : : {
647 : 0 : MctApplication *self = MCT_APPLICATION (user_data);
648 : 0 : g_autoptr(GPermission) permission = NULL;
649 : 0 : g_autoptr(GError) local_error = NULL;
650 : :
651 : 0 : permission = polkit_permission_new_finish (result, &local_error);
652 [ # # ]: 0 : if (permission == NULL)
653 : : {
654 : 0 : g_assert (self->permission_error == NULL);
655 : 0 : self->permission_error = g_steal_pointer (&local_error);
656 : 0 : g_debug ("Error getting permission: %s", self->permission_error->message);
657 : : }
658 : : else
659 : : {
660 : 0 : g_assert (self->permission == NULL);
661 : 0 : self->permission = g_steal_pointer (&permission);
662 : :
663 : 0 : g_signal_connect (self->permission, "notify::allowed",
664 : : G_CALLBACK (permission_notify_allowed_cb), self);
665 : : }
666 : :
667 : : /* Recalculate the UI. */
668 : 0 : update_main_stack (self);
669 : 0 : }
670 : :
671 : : static void
672 : 0 : permission_notify_allowed_cb (GObject *obj,
673 : : GParamSpec *pspec,
674 : : gpointer user_data)
675 : : {
676 : 0 : MctApplication *self = MCT_APPLICATION (user_data);
677 : :
678 : 0 : update_main_stack (self);
679 : 0 : }
680 : :
681 : : static void
682 : 0 : command_line_permission_notify_allowed_cb (GObject *obj,
683 : : GParamSpec *pspec,
684 : : gpointer user_data)
685 : : {
686 : 0 : MctApplication *self = MCT_APPLICATION (user_data);
687 : :
688 : 0 : g_clear_signal_handler (&self->command_line_permission_notify_allowed_id,
689 : : self->permission);
690 : :
691 : 0 : select_user_by_command_line_username (self);
692 : 0 : }
693 : :
694 : : static void
695 : 0 : user_accounts_panel_button_clicked_cb (GtkButton *button,
696 : : gpointer user_data)
697 : : {
698 [ # # ]: 0 : g_autoptr(GError) local_error = NULL;
699 : :
700 [ # # ]: 0 : if (!g_spawn_command_line_async ("gnome-control-center system users", &local_error))
701 : : {
702 : 0 : g_warning ("Error opening GNOME Control Center: %s",
703 : : local_error->message);
704 : 0 : return;
705 : : }
706 : : }
707 : :
708 : : /**
709 : : * mct_application_new:
710 : : *
711 : : * Create a new [class@Malcontent.Application].
712 : : *
713 : : * Returns: (transfer full): a new application object
714 : : * Since: 0.5.0
715 : : */
716 : : MctApplication *
717 : 0 : mct_application_new (void)
718 : : {
719 : 0 : return g_object_new (MCT_TYPE_APPLICATION, NULL);
720 : : }
|