[gnome-initial-setup/parental-controls: 4/4] WIP



commit 046f461d2420052c56b277dda7e8f956f5b4fc4f
Author: Philip Withnall <withnall endlessm com>
Date:   Tue Feb 4 13:17:52 2020 +0000

    WIP
    
    Signed-off-by: Philip Withnall <withnall endlessm com>

 gnome-initial-setup/gis-driver.c                   |  54 ++++++++
 gnome-initial-setup/gis-driver.h                   |  13 ++
 gnome-initial-setup/gnome-initial-setup.c          |   5 +-
 .../pages/account/gis-account-page-local.c         |  14 ++
 .../gis-parental-controls-page.ui                  |  19 +++
 .../pages/password/gis-password-page.c             | 148 ++++++++++++++++++++-
 .../pages/password/gis-password-page.h             |   1 +
 .../pages/password/gis-password-page.ui            |   5 +-
 8 files changed, 253 insertions(+), 6 deletions(-)
---
diff --git a/gnome-initial-setup/gis-driver.c b/gnome-initial-setup/gis-driver.c
index fd52a41..18046e7 100644
--- a/gnome-initial-setup/gis-driver.c
+++ b/gnome-initial-setup/gis-driver.c
@@ -78,6 +78,11 @@ struct _GisDriverPrivate {
   ActUser *user_account;
   gchar *user_password;
 
+  ActUser *parent_account;  /* (owned) (nullable) */
+  gchar *parent_password;  /* (owned) (nullable) */
+
+  gboolean parental_controls_enabled;
+
   gchar *lang_id;
   gchar *username;
 
@@ -119,6 +124,9 @@ gis_driver_finalize (GObject *object)
   g_clear_object (&priv->user_account);
   g_clear_pointer (&priv->vendor_conf_file, g_key_file_free);
 
+  g_clear_object (&priv->parent_account);
+  g_free (priv->parent_password);
+
   if (priv->locale != (locale_t) 0)
     {
       uselocale (LC_GLOBAL_LOCALE);
@@ -260,6 +268,33 @@ gis_driver_get_user_permissions (GisDriver    *driver,
   *password = priv->user_password;
 }
 
+/* TODO docs */
+void
+gis_driver_set_parent_permissions (GisDriver   *driver,
+                                   ActUser     *parent,
+                                   const gchar *password)
+{
+  GisDriverPrivate *priv = gis_driver_get_instance_private (driver);
+
+  g_set_object (&priv->parent_account, parent);
+  g_assert (priv->parent_password == NULL);
+  priv->parent_password = g_strdup (password);
+}
+
+/* TODO docs */
+void
+gis_driver_get_parent_permissions (GisDriver    *driver,
+                                   ActUser     **parent,
+                                   const gchar **password)
+{
+  GisDriverPrivate *priv = gis_driver_get_instance_private (driver);
+
+  if (parent != NULL)
+    *parent = priv->parent_account;
+  if (password != NULL)
+    *password = priv->parent_password;
+}
+
 void
 gis_driver_set_account_mode (GisDriver     *driver,
                              UmAccountMode  mode)
@@ -275,6 +310,25 @@ gis_driver_get_account_mode (GisDriver *driver)
   return priv->account_mode;
 }
 
+/* TODO docs */
+void
+gis_driver_set_parental_controls_enabled (GisDriver *driver,
+                                          gboolean   parental_controls_enabled)
+{
+  GisDriverPrivate *priv = gis_driver_get_instance_private (driver);
+
+  priv->parental_controls_enabled = parental_controls_enabled;
+}
+
+/* TODO docs */
+gboolean
+gis_driver_get_parental_controls_enabled (GisDriver *driver)
+{
+  GisDriverPrivate *priv = gis_driver_get_instance_private (driver);
+
+  return priv->parental_controls_enabled;
+}
+
 gboolean
 gis_driver_get_gdm_objects (GisDriver        *driver,
                             GdmGreeter      **greeter,
diff --git a/gnome-initial-setup/gis-driver.h b/gnome-initial-setup/gis-driver.h
index cd49ffd..c0474ca 100644
--- a/gnome-initial-setup/gis-driver.h
+++ b/gnome-initial-setup/gis-driver.h
@@ -75,11 +75,24 @@ void gis_driver_get_user_permissions (GisDriver    *driver,
                                       ActUser     **user,
                                       const gchar **password);
 
+void gis_driver_set_parent_permissions (GisDriver   *driver,
+                                        ActUser     *parent,
+                                        const gchar *password);
+
+void gis_driver_get_parent_permissions (GisDriver    *driver,
+                                        ActUser     **parent,
+                                        const gchar **password);
+
 void gis_driver_set_account_mode (GisDriver     *driver,
                                   UmAccountMode  mode);
 
 UmAccountMode gis_driver_get_account_mode (GisDriver *driver);
 
+void gis_driver_set_parental_controls_enabled (GisDriver *driver,
+                                               gboolean   parental_controls_enabled);
+
+gboolean gis_driver_get_parental_controls_enabled (GisDriver *driver);
+
 void gis_driver_set_user_language (GisDriver   *driver,
                                    const gchar *lang_id,
                                    gboolean     update_locale);
diff --git a/gnome-initial-setup/gnome-initial-setup.c b/gnome-initial-setup/gnome-initial-setup.c
index 673b17e..125ba5e 100644
--- a/gnome-initial-setup/gnome-initial-setup.c
+++ b/gnome-initial-setup/gnome-initial-setup.c
@@ -71,7 +71,8 @@ static PageData page_table[] = {
   PAGE (goa,      FALSE),
   PAGE (account,  TRUE),
   PAGE (password, TRUE),
-  PAGE (parental_controls, TRUE), /* TODO: new_user_only? */
+  PAGE (parental_controls, TRUE),
+  PAGE (parent_password, TRUE),
   PAGE (summary,  FALSE),
   { NULL },
 };
@@ -266,8 +267,10 @@ main (int argc, char *argv[])
    * the keyring manually so that we can pass the credentials
    * along to the new user in the handoff.
    */
+  /*
   if (mode == GIS_DRIVER_MODE_NEW_USER)
     gis_ensure_login_keyring ();
+   * */
 
   driver = gis_driver_new (mode);
   g_signal_connect (driver, "rebuild-pages", G_CALLBACK (rebuild_pages_cb), NULL);
diff --git a/gnome-initial-setup/pages/account/gis-account-page-local.c 
b/gnome-initial-setup/pages/account/gis-account-page-local.c
index f44d282..c777bbf 100644
--- a/gnome-initial-setup/pages/account/gis-account-page-local.c
+++ b/gnome-initial-setup/pages/account/gis-account-page-local.c
@@ -390,6 +390,18 @@ confirm (GisAccountPageLocal *page)
     g_signal_emit (page, signals[CONFIRM], 0);
 }
 
+static void
+enable_parental_controls_check_button_toggled_cb (GtkToggleButton *toggle_button,
+                                                  gpointer         user_data)
+{
+  GisAccountPageLocal *page = GIS_ACCOUNT_PAGE_LOCAL (user_data);
+  GisAccountPageLocalPrivate *priv = gis_account_page_local_get_instance_private (page);
+  gboolean parental_controls_enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON 
(priv->enable_parental_controls_check_button));
+
+  /* TODO: need to ensure administrator account is created first */
+  priv->account_type = parental_controls_enabled ? ACT_USER_ACCOUNT_TYPE_STANDARD : 
ACT_USER_ACCOUNT_TYPE_ADMINISTRATOR;
+}
+
 static void
 gis_account_page_local_constructed (GObject *object)
 {
@@ -415,6 +427,8 @@ gis_account_page_local_constructed (GObject *object)
                             "activate", G_CALLBACK (confirm), page);
   g_signal_connect_swapped (priv->fullname_entry, "activate",
                             G_CALLBACK (confirm), page);
+  g_signal_connect (priv->enable_parental_controls_check_button, "toggled",
+                    G_CALLBACK (enable_parental_controls_check_button_toggled_cb), page);
 
   priv->valid_name = FALSE;
   priv->valid_username = FALSE;
diff --git a/gnome-initial-setup/pages/parental-controls/gis-parental-controls-page.ui 
b/gnome-initial-setup/pages/parental-controls/gis-parental-controls-page.ui
index 3a3aff1..114b491 100644
--- a/gnome-initial-setup/pages/parental-controls/gis-parental-controls-page.ui
+++ b/gnome-initial-setup/pages/parental-controls/gis-parental-controls-page.ui
@@ -13,6 +13,7 @@
             <property name="visible">True</property>
             <property name="valign">start</property>
             <property name="vexpand">True</property>
+
             <child>
               <object class="GtkBox">
                 <property name="visible">True</property>
@@ -22,7 +23,25 @@
                   </object>
                 </child>
               </object>
+              <packing>
+                <property name="name">user-controls</property>
+              </packing>
             </child>
+
+            <child>
+              <object class="GtkBox">
+                <property name="visible">True</property>
+                <child>
+                  <object class="MctUserControls" id="user_controls">
+                    <property name="visible">True</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="name">parent-password</property>
+              </packing>
+            </child>
+
           </object>
           <packing>
             <property name="expand">False</property>
diff --git a/gnome-initial-setup/pages/password/gis-password-page.c 
b/gnome-initial-setup/pages/password/gis-password-page.c
index 4b32a3f..3d2de27 100644
--- a/gnome-initial-setup/pages/password/gis-password-page.c
+++ b/gnome-initial-setup/pages/password/gis-password-page.c
@@ -46,15 +46,57 @@ struct _GisPasswordPagePrivate
   GtkWidget *password_strength;
   GtkWidget *password_explanation;
   GtkWidget *confirm_explanation;
+  GtkWidget *header;
+
   gboolean valid_confirm;
   gboolean valid_password;
   guint timeout_id;
   const gchar *username;
+  gboolean parent_mode;
 };
 typedef struct _GisPasswordPagePrivate GisPasswordPagePrivate;
 
 G_DEFINE_TYPE_WITH_PRIVATE (GisPasswordPage, gis_password_page, GIS_TYPE_PAGE);
 
+typedef enum
+{
+  PROP_PARENT_MODE = 1,
+} GisPasswordPageProperty;
+
+static GParamSpec *obj_props[PROP_PARENT_MODE + 1];
+
+static void
+set_parent_mode (GisPasswordPage *page,
+                 gboolean         parent_mode)
+{
+  GisPasswordPagePrivate *priv = gis_password_page_get_instance_private (page);
+  const gchar *title, *subtitle;
+
+  g_return_if_fail (GIS_IS_PASSWORD_PAGE (page));
+
+  if (priv->parent_mode == parent_mode)
+    return;
+
+  if (!parent_mode)
+    {
+      title = _("Set a User Password");
+      subtitle = _("Be careful not to lose your password.");
+    }
+  else
+    {
+      title = _("Set a Parent Password");
+      subtitle = _("This password will control access to the parental controls for the child’s user 
account.");
+    }
+
+  g_object_set (G_OBJECT (priv->header),
+                "title", title,
+                "subtitle", subtitle,
+                NULL);
+
+  priv->parent_mode = parent_mode;
+  g_object_notify_by_pspec (G_OBJECT (page), obj_props[PROP_PARENT_MODE]);
+}
+
 static gboolean
 page_validate (GisPasswordPage *page)
 {
@@ -83,9 +125,14 @@ gis_password_page_save_data (GisPage *gis_page)
 
   account_mode = gis_driver_get_account_mode (gis_page->driver);
 
-  gis_driver_get_user_permissions (gis_page->driver, &act_user, &password);
+  if (!priv->parent_mode)
+    gis_driver_get_user_permissions (gis_page->driver, &act_user, &password);
+  else
+    gis_driver_get_parent_permissions (gis_page->driver, &act_user, &password);
 
   if (account_mode == UM_ENTERPRISE) {
+    g_assert (!priv->parent_mode);
+
     if (password != NULL)
       gis_update_login_keyring_password (password);
     return;
@@ -98,9 +145,13 @@ gis_password_page_save_data (GisPage *gis_page)
   else
     act_user_set_password (act_user, password, "");
 
-  gis_driver_set_user_permissions (gis_page->driver, act_user, password);
+  if (!priv->parent_mode)
+    gis_driver_set_user_permissions (gis_page->driver, act_user, password);
+  else
+    gis_driver_set_parent_permissions (gis_page->driver, act_user, password);
 
-  gis_update_login_keyring_password (password);
+  if (!priv->parent_mode)
+    gis_update_login_keyring_password (password);
 }
 
 static void
@@ -112,6 +163,20 @@ gis_password_page_shown (GisPage *gis_page)
   gtk_widget_grab_focus (priv->password_entry);
 }
 
+static gboolean
+gis_password_page_skip (GisPage *gis_page)
+{
+  GisPasswordPage *page = GIS_PASSWORD_PAGE (gis_page);
+  GisPasswordPagePrivate *priv = gis_password_page_get_instance_private (page);
+
+  /* Skip prompting for the parent password (`priv->parent_mode`) if parental
+   * controls aren’t enabled (`gis_driver_get_parental_controls_enabled()`). */
+  if (priv->parent_mode && !gis_driver_get_parental_controls_enabled (GIS_PAGE (page)->driver))
+    return TRUE;
+
+  return FALSE;
+}
+
 static gboolean
 validate (GisPasswordPage *page)
 {
@@ -154,6 +219,13 @@ validate (GisPasswordPage *page)
     }
   }
 
+  /*
+   * We deliberately don’t validate that the parent password and main user
+   * password are different. It’s more feasible that someone would usefully
+   * want to set their system up that way, than it is that the parent and child
+   * would accidentally choose the same password.
+   */
+
   update_page_validation (page);
 
   return FALSE;
@@ -256,6 +328,45 @@ gis_password_page_constructed (GObject *object)
   gtk_widget_show (GTK_WIDGET (page));
 }
 
+static void
+gis_password_page_get_property (GObject    *object,
+                                guint       prop_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+  GisPasswordPage *page = GIS_PASSWORD_PAGE (object);
+  GisPasswordPagePrivate *priv = gis_password_page_get_instance_private (page);
+
+  switch ((GisPasswordPageProperty) prop_id)
+    {
+    case PROP_PARENT_MODE:
+      g_value_set_boolean (value, priv->parent_mode);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gis_password_page_set_property (GObject      *object,
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+  GisPasswordPage *page = GIS_PASSWORD_PAGE (object);
+
+  switch ((GisPasswordPageProperty) prop_id)
+    {
+    case PROP_PARENT_MODE:
+      set_parent_mode (page, g_value_get_boolean (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
 static void
 gis_password_page_dispose (GObject *object)
 {
@@ -278,6 +389,25 @@ gis_password_page_class_init (GisPasswordPageClass *klass)
   GisPageClass *page_class = GIS_PAGE_CLASS (klass);
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
+  /**
+   * GisPasswordPage:parent-mode:
+   *
+   * If %FALSE (the default), this page will collect a password for the main
+   * user account. If %TRUE, it will collect a password for controlling access
+   * to parental controls — this will affect where the password is stored, and
+   * the appearance of the page.
+   *
+   * Since: 3.36
+   */
+  obj_props[PROP_PARENT_MODE] =
+    g_param_spec_boolean ("parent-mode", "Parent Mode",
+                          "Whether to collect a password for the main user account or a parent account.",
+                          FALSE,
+                          G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE |
+                          G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY);
+
+  g_object_class_install_properties (object_class, G_N_ELEMENTS (obj_props), obj_props);
+
   gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass), 
"/org/gnome/initial-setup/gis-password-page.ui");
 
   gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisPasswordPage, password_entry);
@@ -285,13 +415,17 @@ gis_password_page_class_init (GisPasswordPageClass *klass)
   gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisPasswordPage, 
password_strength);
   gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisPasswordPage, 
password_explanation);
   gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisPasswordPage, 
confirm_explanation);
+  gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisPasswordPage, header);
 
   page_class->page_id = PAGE_ID;
   page_class->locale_changed = gis_password_page_locale_changed;
   page_class->save_data = gis_password_page_save_data;
   page_class->shown = gis_password_page_shown;
+  page_class->skip = gis_password_page_skip;
 
   object_class->constructed = gis_password_page_constructed;
+  object_class->get_property = gis_password_page_get_property;
+  object_class->set_property = gis_password_page_set_property;
   object_class->dispose = gis_password_page_dispose;
 }
 
@@ -321,3 +455,11 @@ gis_prepare_password_page (GisDriver *driver)
                        NULL);
 }
 
+GisPage *
+gis_prepare_parent_password_page (GisDriver *driver)
+{
+  return g_object_new (GIS_TYPE_PASSWORD_PAGE,
+                       "driver", driver,
+                       "parent-mode", TRUE,
+                       NULL);
+}
diff --git a/gnome-initial-setup/pages/password/gis-password-page.h 
b/gnome-initial-setup/pages/password/gis-password-page.h
index 954782f..2a4d1c6 100644
--- a/gnome-initial-setup/pages/password/gis-password-page.h
+++ b/gnome-initial-setup/pages/password/gis-password-page.h
@@ -51,6 +51,7 @@ struct _GisPasswordPageClass
 GType gis_password_page_get_type (void);
 
 GisPage *gis_prepare_password_page (GisDriver *driver);
+GisPage *gis_prepare_parent_password_page (GisDriver *driver);
 
 G_END_DECLS
 
diff --git a/gnome-initial-setup/pages/password/gis-password-page.ui 
b/gnome-initial-setup/pages/password/gis-password-page.ui
index 500d0d3..672d39d 100644
--- a/gnome-initial-setup/pages/password/gis-password-page.ui
+++ b/gnome-initial-setup/pages/password/gis-password-page.ui
@@ -13,8 +13,9 @@
           <object class="GisPageHeader" id="header">
             <property name="visible">True</property>
             <property name="margin_top">24</property>
-            <property name="title" translatable="yes">Set a Password</property>
-            <property name="subtitle" translatable="yes">Be careful not to lose your password.</property>
+            <!-- title and subtitle are set in code, so are not marked as translatable here -->
+            <property name="title">Set a Password</property>
+            <property name="subtitle">Be careful not to lose your password.</property>
             <property name="icon_name">dialog-password-symbolic</property>
             <property name="show_icon" bind-source="GisPasswordPage" bind-property="small-screen" 
bind-flags="invert-boolean|sync-create"/>
           </object>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]