/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright © 2020 Endless Mobile, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*
* Written by:
* Philip Withnall
*/
/* Parental controls page {{{1 */
#define PAGE_ID "parental-controls"
#include "config.h"
#include
#include
#include
#include
#include
#include
#include "parental-controls-resources.h"
#include "gis-page-header.h"
#include "gis-parental-controls-page.h"
struct _GisParentalControlsPage
{
GisPage parent_instance;
GtkWidget *header;
GtkWidget *user_controls;
};
G_DEFINE_TYPE (GisParentalControlsPage, gis_parental_controls_page, GIS_TYPE_PAGE)
static gboolean
gis_parental_controls_page_save_data (GisPage *gis_page,
GError **error)
{
GisParentalControlsPage *page = GIS_PARENTAL_CONTROLS_PAGE (gis_page);
g_autoptr(GDBusConnection) system_bus = NULL;
g_autoptr(MctManager) manager = NULL;
g_auto(MctAppFilterBuilder) builder = MCT_APP_FILTER_BUILDER_INIT ();
g_autoptr(MctAppFilter) app_filter = NULL;
ActUser *main_user;
/* The parent and child users are created by the #GisAccountPage earlier in
* the save_data() process. We now need to set the parental controls on the
* child user. The earlier step in the process must have succeeded. */
gis_driver_get_user_permissions (gis_page->driver, &main_user, NULL);
g_return_val_if_fail (main_user != NULL, FALSE);
mct_user_controls_build_app_filter (MCT_USER_CONTROLS (page->user_controls), &builder);
app_filter = mct_app_filter_builder_end (&builder);
/* FIXME: should become asynchronous */
system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error);
if (system_bus == NULL)
return FALSE;
manager = mct_manager_new (system_bus);
if (!mct_manager_set_app_filter (manager,
act_user_get_uid (main_user),
app_filter,
MCT_MANAGER_SET_VALUE_FLAGS_NONE,
NULL,
error))
return FALSE;
return TRUE;
}
static void
gis_parental_controls_page_shown (GisPage *gis_page)
{
GisParentalControlsPage *page = GIS_PARENTAL_CONTROLS_PAGE (gis_page);
gtk_widget_grab_focus (page->user_controls);
}
static void
update_header (GisParentalControlsPage *page)
{
g_autofree gchar *title = NULL;
const gchar *subtitle, *icon_name;
GdkPaintable *paintable;
/* Translators: The placeholder is the user’s full name. */
title = g_strdup_printf (_("Parental Controls for %s"),
gis_driver_get_full_name (GIS_PAGE (page)->driver));
subtitle = _("Set restrictions on what this user can run or install.");
paintable = gis_driver_get_avatar (GIS_PAGE (page)->driver);
icon_name = (paintable != NULL) ? NULL : "dialog-password-symbolic";
g_object_set (G_OBJECT (page->header),
"title", title,
"subtitle", subtitle,
NULL);
if (paintable != NULL)
g_object_set (G_OBJECT (page->header), "paintable", paintable, NULL);
else if (icon_name != NULL)
g_object_set (G_OBJECT (page->header), "icon-name", icon_name, NULL);
}
static void
update_user_controls (GisParentalControlsPage *page)
{
mct_user_controls_set_user_locale (MCT_USER_CONTROLS (page->user_controls),
gis_driver_get_user_language (GIS_PAGE (page)->driver));
mct_user_controls_set_user_display_name (MCT_USER_CONTROLS (page->user_controls),
gis_driver_get_full_name (GIS_PAGE (page)->driver));
}
static void
user_details_changed_cb (GObject *obj,
GParamSpec *pspec,
gpointer user_data)
{
GisParentalControlsPage *page = GIS_PARENTAL_CONTROLS_PAGE (user_data);
update_user_controls (page);
update_header (page);
}
static void
gis_parental_controls_page_constructed (GObject *object)
{
GisParentalControlsPage *page = GIS_PARENTAL_CONTROLS_PAGE (object);
g_autoptr(GPermission) permission = NULL;
g_auto(MctAppFilterBuilder) builder = MCT_APP_FILTER_BUILDER_INIT ();
g_autoptr(MctAppFilter) app_filter = NULL;
G_OBJECT_CLASS (gis_parental_controls_page_parent_class)->constructed (object);
/* No validation needed. */
gis_page_set_complete (GIS_PAGE (page), TRUE);
/* Set up the user controls. We can’t set #MctUserControls:user because
* there’s no way to represent a not-yet-created user using an #ActUser. */
mct_user_controls_set_user_account_type (MCT_USER_CONTROLS (page->user_controls),
ACT_USER_ACCOUNT_TYPE_STANDARD);
update_user_controls (page);
app_filter = mct_app_filter_builder_end (&builder);
mct_user_controls_set_app_filter (MCT_USER_CONTROLS (page->user_controls), app_filter);
/* The gnome-initial-setup user should always be allowed to set parental
* controls. */
permission = g_simple_permission_new (TRUE);
mct_user_controls_set_permission (MCT_USER_CONTROLS (page->user_controls), permission);
/* Connect to signals. */
g_signal_connect (GIS_PAGE (page)->driver, "notify::full-name",
G_CALLBACK (user_details_changed_cb), page);
g_signal_connect (GIS_PAGE (page)->driver, "notify::avatar",
G_CALLBACK (user_details_changed_cb), page);
g_signal_connect (GIS_PAGE (page)->driver, "notify::user-locale",
G_CALLBACK (user_details_changed_cb), page);
g_signal_connect (GIS_PAGE (page)->driver, "notify::user-display-name",
G_CALLBACK (user_details_changed_cb), page);
update_header (page);
gtk_widget_show (GTK_WIDGET (page));
}
static void
gis_parental_controls_page_dispose (GObject *object)
{
GisParentalControlsPage *page = GIS_PARENTAL_CONTROLS_PAGE (object);
if (GIS_PAGE (object)->driver != NULL)
{
g_signal_handlers_disconnect_by_func (GIS_PAGE (page)->driver,
user_details_changed_cb, page);
}
G_OBJECT_CLASS (gis_parental_controls_page_parent_class)->dispose (object);
}
static void
gis_parental_controls_page_locale_changed (GisPage *gis_page)
{
GisParentalControlsPage *page = GIS_PARENTAL_CONTROLS_PAGE (gis_page);
gis_page_set_title (gis_page, _("Parental Controls"));
update_header (page);
}
static void
gis_parental_controls_page_class_init (GisParentalControlsPageClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GisPageClass *page_class = GIS_PAGE_CLASS (klass);
object_class->constructed = gis_parental_controls_page_constructed;
object_class->dispose = gis_parental_controls_page_dispose;
page_class->page_id = PAGE_ID;
page_class->locale_changed = gis_parental_controls_page_locale_changed;
page_class->save_data = gis_parental_controls_page_save_data;
page_class->shown = gis_parental_controls_page_shown;
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/initial-setup/gis-parental-controls-page.ui");
gtk_widget_class_bind_template_child (widget_class, GisParentalControlsPage, header);
gtk_widget_class_bind_template_child (widget_class, GisParentalControlsPage, user_controls);
}
static void
gis_parental_controls_page_init (GisParentalControlsPage *page)
{
g_resources_register (parental_controls_get_resource ());
/* Ensure types exist for widgets in the UI file. */
g_type_ensure (GIS_TYPE_PAGE_HEADER);
g_type_ensure (MCT_TYPE_USER_CONTROLS);
gtk_widget_init_template (GTK_WIDGET (page));
}
GisPage *
gis_prepare_parental_controls_page (GisDriver *driver)
{
/* Skip parental controls if they’re not enabled. */
if (!gis_driver_get_parental_controls_enabled (driver))
return NULL;
return g_object_new (GIS_TYPE_PARENTAL_CONTROLS_PAGE,
"driver", driver,
NULL);
}