From b98ec83e665a5cdf8e720fd90b0294f18a1b9a07 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Feb 2020 10:54:14 +0000 Subject: [PATCH 01/11] libmalcontent-ui: Add GIR dependency on libmalcontent This was missing and causing some problems with GIR compilation for the UI library. Signed-off-by: Philip Withnall --- libmalcontent-ui/meson.build | 4 ++-- libmalcontent/meson.build | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libmalcontent-ui/meson.build b/libmalcontent-ui/meson.build index 06208a3..31241ed 100644 --- a/libmalcontent-ui/meson.build +++ b/libmalcontent-ui/meson.build @@ -70,14 +70,14 @@ pkgconfig.generate(libmalcontent_ui, libraries_private: libmalcontent_ui_private_deps, ) -gnome.generate_gir(libmalcontent_ui, +libmalcontent_ui_gir = gnome.generate_gir(libmalcontent_ui, sources: libmalcontent_ui_sources + libmalcontent_ui_headers + libmalcontent_ui_private_headers, nsversion: libmalcontent_ui_api_version, namespace: 'MalcontentUi', symbol_prefix: 'mct_', identifier_prefix: 'Mct', export_packages: 'libmalcontent-ui', - includes: ['AccountsService-1.0', 'Gio-2.0', 'GObject-2.0', 'Gtk-3.0'], + includes: ['AccountsService-1.0', 'Gio-2.0', 'GObject-2.0', 'Gtk-3.0', libmalcontent_gir[0]], install: true, dependencies: libmalcontent_ui_dep, ) diff --git a/libmalcontent/meson.build b/libmalcontent/meson.build index 1aa0c45..a312823 100644 --- a/libmalcontent/meson.build +++ b/libmalcontent/meson.build @@ -56,7 +56,7 @@ pkgconfig.generate(libmalcontent, libraries_private: libmalcontent_private_deps, ) -gnome.generate_gir(libmalcontent, +libmalcontent_gir = gnome.generate_gir(libmalcontent, sources: libmalcontent_sources + libmalcontent_headers + libmalcontent_private_headers, nsversion: libmalcontent_api_version, namespace: 'Malcontent', From acf402dcc55b72961ac1624956c78f02b3723e50 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Feb 2020 10:55:47 +0000 Subject: [PATCH 02/11] restrict-applications-dialog: Allow :user to be set at any point MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It doesn’t actually need to be construct-only. Signed-off-by: Philip Withnall --- libmalcontent-ui/restrict-applications-dialog.c | 1 - 1 file changed, 1 deletion(-) diff --git a/libmalcontent-ui/restrict-applications-dialog.c b/libmalcontent-ui/restrict-applications-dialog.c index 98f663a..9eecfd0 100644 --- a/libmalcontent-ui/restrict-applications-dialog.c +++ b/libmalcontent-ui/restrict-applications-dialog.c @@ -180,7 +180,6 @@ mct_restrict_applications_dialog_class_init (MctRestrictApplicationsDialogClass "The currently selected user account, or %NULL if no user is selected.", ACT_TYPE_USER, G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); From 6b45ad9f765906c73b7094a8dd7744cf9582afc0 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Feb 2020 11:54:44 +0000 Subject: [PATCH 03/11] restrict-applications-dialog: Drop accountsservice dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of taking an `ActUser` as a property of the `MctRestrictApplicationsDialog`, take the display name which we would have queried from it. This will allow the restrict applications dialog to be used in situations where an `ActUser` isn’t available, such as when setting the parental controls for a yet-to-be-created user. This breaks the `MctRestrictApplicationsDialog` API, but the previous API hadn’t yet been released. Signed-off-by: Philip Withnall --- .../restrict-applications-dialog.c | 116 +++++++++--------- .../restrict-applications-dialog.h | 9 +- libmalcontent-ui/user-controls.c | 21 +++- 3 files changed, 79 insertions(+), 67 deletions(-) diff --git a/libmalcontent-ui/restrict-applications-dialog.c b/libmalcontent-ui/restrict-applications-dialog.c index 9eecfd0..d231466 100644 --- a/libmalcontent-ui/restrict-applications-dialog.c +++ b/libmalcontent-ui/restrict-applications-dialog.c @@ -19,7 +19,6 @@ * - Philip Withnall */ -#include #include #include #include @@ -55,7 +54,7 @@ struct _MctRestrictApplicationsDialog GtkLabel *description; MctAppFilter *app_filter; /* (owned) (not nullable) */ - ActUser *user; /* (owned) (nullable) */ + gchar *user_display_name; /* (owned) (nullable) */ }; G_DEFINE_TYPE (MctRestrictApplicationsDialog, mct_restrict_applications_dialog, GTK_TYPE_DIALOG) @@ -63,10 +62,10 @@ G_DEFINE_TYPE (MctRestrictApplicationsDialog, mct_restrict_applications_dialog, typedef enum { PROP_APP_FILTER = 1, - PROP_USER, + PROP_USER_DISPLAY_NAME, } MctRestrictApplicationsDialogProperty; -static GParamSpec *properties[PROP_USER + 1]; +static GParamSpec *properties[PROP_USER_DISPLAY_NAME + 1]; static void mct_restrict_applications_dialog_constructed (GObject *obj) @@ -74,7 +73,9 @@ mct_restrict_applications_dialog_constructed (GObject *obj) MctRestrictApplicationsDialog *self = MCT_RESTRICT_APPLICATIONS_DIALOG (obj); g_assert (self->app_filter != NULL); - g_assert (self->user == NULL || ACT_IS_USER (self->user)); + g_assert (self->user_display_name == NULL || + (*self->user_display_name != '\0' && + g_utf8_validate (self->user_display_name, -1, NULL))); G_OBJECT_CLASS (mct_restrict_applications_dialog_parent_class)->constructed (obj); } @@ -93,8 +94,8 @@ mct_restrict_applications_dialog_get_property (GObject *object, g_value_set_boxed (value, self->app_filter); break; - case PROP_USER: - g_value_set_object (value, self->user); + case PROP_USER_DISPLAY_NAME: + g_value_set_string (value, self->user_display_name); break; default: @@ -116,8 +117,8 @@ mct_restrict_applications_dialog_set_property (GObject *object, mct_restrict_applications_dialog_set_app_filter (self, g_value_get_boxed (value)); break; - case PROP_USER: - mct_restrict_applications_dialog_set_user (self, g_value_get_object (value)); + case PROP_USER_DISPLAY_NAME: + mct_restrict_applications_dialog_set_user_display_name (self, g_value_get_string (value)); break; default: @@ -131,7 +132,7 @@ mct_restrict_applications_dialog_dispose (GObject *object) MctRestrictApplicationsDialog *self = (MctRestrictApplicationsDialog *)object; g_clear_pointer (&self->app_filter, mct_app_filter_unref); - g_clear_object (&self->user); + g_clear_pointer (&self->user_display_name, g_free); G_OBJECT_CLASS (mct_restrict_applications_dialog_parent_class)->dispose (object); } @@ -168,17 +169,21 @@ mct_restrict_applications_dialog_class_init (MctRestrictApplicationsDialogClass G_PARAM_EXPLICIT_NOTIFY); /** - * MctRestrictApplicationsDialog:user: (nullable) + * MctRestrictApplicationsDialog:user-display-name: (nullable) * - * The currently selected user account, or %NULL if no user is selected. + * The display name for the currently selected user account, or %NULL if no + * user is selected. This will typically be the user’s full name (if known) + * or their username. + * + * If set, it must be valid UTF-8 and non-empty. * * Since: 0.5.0 */ - properties[PROP_USER] = - g_param_spec_object ("user", - "User", - "The currently selected user account, or %NULL if no user is selected.", - ACT_TYPE_USER, + properties[PROP_USER_DISPLAY_NAME] = + g_param_spec_string ("user-display-name", + "User Display Name", + "The display name for the currently selected user account, or %NULL if no user is selected.", + NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); @@ -200,31 +205,12 @@ mct_restrict_applications_dialog_init (MctRestrictApplicationsDialog *self) gtk_widget_init_template (GTK_WIDGET (self)); } -static const gchar * -get_user_display_name (ActUser *user) -{ - const gchar *display_name; - - g_return_val_if_fail (ACT_IS_USER (user), _("unknown")); - - display_name = act_user_get_real_name (user); - if (display_name != NULL) - return display_name; - - display_name = act_user_get_user_name (user); - if (display_name != NULL) - return display_name; - - /* Translators: this is the full name for an unknown user account. */ - return _("unknown"); -} - static void update_description (MctRestrictApplicationsDialog *self) { g_autofree gchar *description = NULL; - if (self->user == NULL) + if (self->user_display_name == NULL) { gtk_widget_hide (GTK_WIDGET (self->description)); return; @@ -232,7 +218,7 @@ update_description (MctRestrictApplicationsDialog *self) /* Translators: the placeholder is a user’s full name */ description = g_strdup_printf (_("Allow %s to use the following installed applications."), - get_user_display_name (self->user)); + self->user_display_name); gtk_label_set_text (self->description, description); gtk_widget_show (GTK_WIDGET (self->description)); } @@ -240,7 +226,8 @@ update_description (MctRestrictApplicationsDialog *self) /** * mct_restrict_applications_dialog_new: * @app_filter: (transfer none): the initial app filter configuration to show - * @user: (transfer none) (nullable): the user to show the app filter for + * @user_display_name: (transfer none) (nullable): the display name of the user + * to show the app filter for, or %NULL if no user is selected * * Create a new #MctRestrictApplicationsDialog widget. * @@ -249,14 +236,16 @@ update_description (MctRestrictApplicationsDialog *self) */ MctRestrictApplicationsDialog * mct_restrict_applications_dialog_new (MctAppFilter *app_filter, - ActUser *user) + const gchar *user_display_name) { g_return_val_if_fail (app_filter != NULL, NULL); - g_return_val_if_fail (user == NULL || ACT_IS_USER (user), NULL); + g_return_val_if_fail (user_display_name == NULL || + (*user_display_name != '\0' && + g_utf8_validate (user_display_name, -1, NULL)), NULL); return g_object_new (MCT_TYPE_RESTRICT_APPLICATIONS_DIALOG, "app-filter", app_filter, - "user", user, + "user-display-name", user_display_name, NULL); } @@ -317,45 +306,50 @@ mct_restrict_applications_dialog_set_app_filter (MctRestrictApplicationsDialog * } /** - * mct_restrict_applications_dialog_get_user: + * mct_restrict_applications_dialog_get_user_display_name: * @self: an #MctRestrictApplicationsDialog * - * Get the value of #MctRestrictApplicationsDialog:user. + * Get the value of #MctRestrictApplicationsDialog:user-display-name. * - * Returns: (transfer none) (nullable): the user the dialog is configured for, - * or %NULL if unknown + * Returns: (transfer none) (nullable): the display name of the user the dialog + * is configured for, or %NULL if unknown * Since: 0.5.0 */ -ActUser * -mct_restrict_applications_dialog_get_user (MctRestrictApplicationsDialog *self) +const gchar * +mct_restrict_applications_dialog_get_user_display_name (MctRestrictApplicationsDialog *self) { g_return_val_if_fail (MCT_IS_RESTRICT_APPLICATIONS_DIALOG (self), NULL); - return self->user; + return self->user_display_name; } /** - * mct_restrict_applications_dialog_set_user: + * mct_restrict_applications_dialog_set_user_display_name: * @self: an #MctRestrictApplicationsDialog - * @user: (nullable) (transfer none): the user to configure the dialog for, - * or %NULL if unknown + * @user_display_name: (nullable) (transfer none): the display name of the user + * to configure the dialog for, or %NULL if unknown * - * Set the value of #MctRestrictApplicationsDialog:user. + * Set the value of #MctRestrictApplicationsDialog:user-display-name. * * Since: 0.5.0 */ void -mct_restrict_applications_dialog_set_user (MctRestrictApplicationsDialog *self, - ActUser *user) +mct_restrict_applications_dialog_set_user_display_name (MctRestrictApplicationsDialog *self, + const gchar *user_display_name) { g_return_if_fail (MCT_IS_RESTRICT_APPLICATIONS_DIALOG (self)); - g_return_if_fail (user == NULL || ACT_IS_USER (user)); + g_return_if_fail (user_display_name == NULL || + (*user_display_name != '\0' && + g_utf8_validate (user_display_name, -1, NULL))); - if (g_set_object (&self->user, user)) - { - update_description (self); - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_USER]); - } + if (g_strcmp0 (self->user_display_name, user_display_name) == 0) + return; + + g_clear_pointer (&self->user_display_name, g_free); + self->user_display_name = g_strdup (user_display_name); + + update_description (self); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_USER_DISPLAY_NAME]); } /** diff --git a/libmalcontent-ui/restrict-applications-dialog.h b/libmalcontent-ui/restrict-applications-dialog.h index b4a5ed3..b96b335 100644 --- a/libmalcontent-ui/restrict-applications-dialog.h +++ b/libmalcontent-ui/restrict-applications-dialog.h @@ -21,7 +21,6 @@ #pragma once -#include #include #include #include @@ -34,15 +33,15 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE (MctRestrictApplicationsDialog, mct_restrict_applications_dialog, MCT, RESTRICT_APPLICATIONS_DIALOG, GtkDialog) MctRestrictApplicationsDialog *mct_restrict_applications_dialog_new (MctAppFilter *app_filter, - ActUser *user); + const gchar *user_display_name); MctAppFilter *mct_restrict_applications_dialog_get_app_filter (MctRestrictApplicationsDialog *self); void mct_restrict_applications_dialog_set_app_filter (MctRestrictApplicationsDialog *self, MctAppFilter *app_filter); -ActUser *mct_restrict_applications_dialog_get_user (MctRestrictApplicationsDialog *self); -void mct_restrict_applications_dialog_set_user (MctRestrictApplicationsDialog *self, - ActUser *user); +const gchar *mct_restrict_applications_dialog_get_user_display_name (MctRestrictApplicationsDialog *self); +void mct_restrict_applications_dialog_set_user_display_name (MctRestrictApplicationsDialog *self, + const gchar *user_display_name); void mct_restrict_applications_dialog_build_app_filter (MctRestrictApplicationsDialog *self, MctAppFilterBuilder *builder); diff --git a/libmalcontent-ui/user-controls.c b/libmalcontent-ui/user-controls.c index e9310fb..0e22835 100644 --- a/libmalcontent-ui/user-controls.c +++ b/libmalcontent-ui/user-controls.c @@ -155,6 +155,25 @@ get_content_rating_system (ActUser *user) return gs_utils_content_rating_system_from_locale (user_language); } +static const gchar * +get_user_display_name (ActUser *user) +{ + const gchar *display_name; + + g_return_val_if_fail (ACT_IS_USER (user), _("unknown")); + + display_name = act_user_get_real_name (user); + if (display_name != NULL) + return display_name; + + display_name = act_user_get_user_name (user); + if (display_name != NULL) + return display_name; + + /* Translators: this is the full name for an unknown user account. */ + return _("unknown"); +} + static void schedule_update_blacklisted_apps (MctUserControls *self) { @@ -549,7 +568,7 @@ on_restrict_applications_button_clicked_cb (GtkButton *button, gtk_window_set_transient_for (GTK_WINDOW (self->restrict_applications_dialog), GTK_WINDOW (toplevel)); - mct_restrict_applications_dialog_set_user (self->restrict_applications_dialog, self->user); + mct_restrict_applications_dialog_set_user_display_name (self->restrict_applications_dialog, get_user_display_name (self->user)); mct_restrict_applications_dialog_set_app_filter (self->restrict_applications_dialog, self->filter); gtk_widget_show (GTK_WIDGET (self->restrict_applications_dialog)); From 0f2c8d66014d0d8ad178fbff48b4c8e907b6512d Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Feb 2020 11:56:23 +0000 Subject: [PATCH 04/11] restrict-applications-selector: Drop unnecessary include Signed-off-by: Philip Withnall --- libmalcontent-ui/restrict-applications-selector.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libmalcontent-ui/restrict-applications-selector.h b/libmalcontent-ui/restrict-applications-selector.h index 702a594..e02a10a 100644 --- a/libmalcontent-ui/restrict-applications-selector.h +++ b/libmalcontent-ui/restrict-applications-selector.h @@ -21,7 +21,6 @@ #pragma once -#include #include #include #include From 608444891fa2e0ee7bfe4f7152580bcb594e93b4 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Feb 2020 11:57:40 +0000 Subject: [PATCH 05/11] user-controls: Modernise GObject property code This introduces no functional changes, but does make the code work better with `-Wswitch-enum`. Signed-off-by: Philip Withnall --- libmalcontent-ui/user-controls.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/libmalcontent-ui/user-controls.c b/libmalcontent-ui/user-controls.c index 0e22835..888d16c 100644 --- a/libmalcontent-ui/user-controls.c +++ b/libmalcontent-ui/user-controls.c @@ -96,14 +96,13 @@ static void on_permission_allowed_cb (GObject *obj, G_DEFINE_TYPE (MctUserControls, mct_user_controls, GTK_TYPE_GRID) -enum +typedef enum { PROP_USER = 1, PROP_PERMISSION, - N_PROPS -}; +} MctUserControlsProperty; -static GParamSpec *properties [N_PROPS]; +static GParamSpec *properties[PROP_PERMISSION + 1]; static const GActionEntry actions[] = { { "set-age", on_set_age_action_activated, "u", NULL, NULL, { 0, }} @@ -701,7 +700,7 @@ mct_user_controls_get_property (GObject *object, { MctUserControls *self = MCT_USER_CONTROLS (object); - switch (prop_id) + switch ((MctUserControlsProperty) prop_id) { case PROP_USER: g_value_set_object (value, self->user); @@ -724,7 +723,7 @@ mct_user_controls_set_property (GObject *object, { MctUserControls *self = MCT_USER_CONTROLS (object); - switch (prop_id) + switch ((MctUserControlsProperty) prop_id) { case PROP_USER: mct_user_controls_set_user (self, g_value_get_object (value)); @@ -766,7 +765,7 @@ mct_user_controls_class_init (MctUserControlsClass *klass) G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); - g_object_class_install_properties (object_class, N_PROPS, properties); + g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties); gtk_widget_class_set_template_from_resource (widget_class, "/org/freedesktop/MalcontentUi/ui/user-controls.ui"); From 3519ac2dc17f114c76fd3d1df51248ed8375c213 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Feb 2020 12:00:14 +0000 Subject: [PATCH 06/11] user-controls: Tweak the API of an internal helper function Make it take a `MctUserControls` rather than a member of it. This introduces no functional changes, but will make some upcoming refactoring easier. Signed-off-by: Philip Withnall --- libmalcontent-ui/user-controls.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libmalcontent-ui/user-controls.c b/libmalcontent-ui/user-controls.c index 888d16c..07d3c0c 100644 --- a/libmalcontent-ui/user-controls.c +++ b/libmalcontent-ui/user-controls.c @@ -145,11 +145,11 @@ static const gchar * const oars_categories[] = /* Auxiliary methods */ static GsContentRatingSystem -get_content_rating_system (ActUser *user) +get_content_rating_system (MctUserControls *self) { const gchar *user_language; - user_language = act_user_get_language (user); + user_language = act_user_get_language (self->user); return gs_utils_content_rating_system_from_locale (user_language); } @@ -244,7 +244,7 @@ update_categories_from_language (MctUserControls *self) gsize i; g_autofree gchar *disabled_action = NULL; - rating_system = get_content_rating_system (self->user); + rating_system = get_content_rating_system (self); rating_system_str = gs_content_rating_system_to_str (rating_system); g_debug ("Using rating system %s", rating_system_str); @@ -324,7 +324,7 @@ update_oars_level (MctUserControls *self) g_debug ("Effective age for this user: %u; %s", maximum_age, all_categories_unset ? "all categories unset" : "some categories set"); - rating_system = get_content_rating_system (self->user); + rating_system = get_content_rating_system (self); rating_age_category = gs_utils_content_rating_age_to_str (rating_system, maximum_age); /* Unrestricted? */ @@ -616,7 +616,7 @@ on_set_age_action_activated (GSimpleAction *action, self = MCT_USER_CONTROLS (user_data); age = g_variant_get_uint32 (param); - rating_system = get_content_rating_system (self->user); + rating_system = get_content_rating_system (self); entries = gs_utils_content_rating_get_values (rating_system); ages = gs_utils_content_rating_get_ages (rating_system); From e3f923b2947671c9f38e348849e68598ebbc260e Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Feb 2020 12:01:50 +0000 Subject: [PATCH 07/11] =?UTF-8?q?user-controls:=20Don=E2=80=99t=20clear=20?= =?UTF-8?q?filter=20if=20updating=20it=20is=20a=20no-op?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If `self->user == NULL`, don’t clear the app filter, as that leaves us in a worse-off position than before. Rename the method to make it clearer that it queries the filter from the user. Signed-off-by: Philip Withnall --- libmalcontent-ui/user-controls.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/libmalcontent-ui/user-controls.c b/libmalcontent-ui/user-controls.c index 07d3c0c..151d73e 100644 --- a/libmalcontent-ui/user-controls.c +++ b/libmalcontent-ui/user-controls.c @@ -198,12 +198,10 @@ flush_update_blacklisted_apps (MctUserControls *self) } static void -update_app_filter (MctUserControls *self) +update_app_filter_from_user (MctUserControls *self) { g_autoptr(GError) error = NULL; - g_clear_pointer (&self->filter, mct_app_filter_unref); - if (self->user == NULL) return; @@ -217,6 +215,7 @@ update_app_filter (MctUserControls *self) return; /* FIXME: make it asynchronous */ + g_clear_pointer (&self->filter, mct_app_filter_unref); self->filter = mct_manager_get_app_filter (self->manager, act_user_get_uid (self->user), MCT_MANAGER_GET_VALUE_FLAGS_NONE, @@ -847,7 +846,7 @@ mct_user_controls_set_user (MctUserControls *self, if (g_set_object (&self->user, user)) { - update_app_filter (self); + update_app_filter_from_user (self); setup_parental_control_settings (self); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_USER]); @@ -861,7 +860,7 @@ on_permission_allowed_cb (GObject *obj, { MctUserControls *self = MCT_USER_CONTROLS (user_data); - update_app_filter (self); + update_app_filter_from_user (self); setup_parental_control_settings (self); } @@ -901,7 +900,7 @@ mct_user_controls_set_permission (MctUserControls *self, } /* Handle changes. */ - update_app_filter (self); + update_app_filter_from_user (self); setup_parental_control_settings (self); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PERMISSION]); From 7dfd03907dbe7b642296a520c60e85a3b35355d2 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Feb 2020 12:06:03 +0000 Subject: [PATCH 08/11] user-controls: Split out app filter construction into a new method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This means that calling code can extract the app filter manually rather than having to rely on the `MctUserControls` to save it. This will be useful in a few commits’ time when support is added for using `MctUserControls` for not-yet-created users. Signed-off-by: Philip Withnall --- libmalcontent-ui/user-controls.c | 128 ++++++++++++++++++------------- libmalcontent-ui/user-controls.h | 4 + 2 files changed, 78 insertions(+), 54 deletions(-) diff --git a/libmalcontent-ui/user-controls.c b/libmalcontent-ui/user-controls.c index 151d73e..b534243 100644 --- a/libmalcontent-ui/user-controls.c +++ b/libmalcontent-ui/user-controls.c @@ -444,63 +444,10 @@ blacklist_apps_cb (gpointer data) g_autoptr(MctAppFilter) new_filter = NULL; g_autoptr(GError) error = NULL; MctUserControls *self = data; - gboolean allow_web_browsers; - gsize i; self->blacklist_apps_source_id = 0; - g_debug ("Building parental controls settings…"); - - /* Blacklist */ - - g_debug ("\t → Blacklisting apps"); - - mct_restrict_applications_dialog_build_app_filter (self->restrict_applications_dialog, &builder); - - /* Maturity level */ - - g_debug ("\t → Maturity level"); - - if (self->selected_age == oars_disabled_age) - g_debug ("\t\t → Disabled"); - - for (i = 0; self->selected_age != oars_disabled_age && oars_categories[i] != NULL; i++) - { - MctAppFilterOarsValue oars_value; - const gchar *oars_category; - - oars_category = oars_categories[i]; - oars_value = as_content_rating_id_csm_age_to_value (oars_category, self->selected_age); - - g_debug ("\t\t → %s: %s", oars_category, oars_value_to_string (oars_value)); - - mct_app_filter_builder_set_oars_value (&builder, oars_category, oars_value); - } - - /* Web browsers */ - allow_web_browsers = gtk_switch_get_active (self->allow_web_browsers_switch); - - g_debug ("\t → %s web browsers", allow_web_browsers ? "Enabling" : "Disabling"); - - if (!allow_web_browsers) - mct_app_filter_builder_blacklist_content_type (&builder, WEB_BROWSERS_CONTENT_TYPE); - - /* App installation */ - if (act_user_get_account_type (self->user) != ACT_USER_ACCOUNT_TYPE_ADMINISTRATOR) - { - gboolean allow_system_installation; - gboolean allow_user_installation; - - allow_system_installation = gtk_switch_get_active (self->allow_system_installation_switch); - allow_user_installation = gtk_switch_get_active (self->allow_user_installation_switch); - - g_debug ("\t → %s system installation", allow_system_installation ? "Enabling" : "Disabling"); - g_debug ("\t → %s user installation", allow_user_installation ? "Enabling" : "Disabling"); - - mct_app_filter_builder_set_allow_user_installation (&builder, allow_user_installation); - mct_app_filter_builder_set_allow_system_installation (&builder, allow_system_installation); - } - + mct_user_controls_build_app_filter (self, &builder); new_filter = mct_app_filter_builder_end (&builder); /* FIXME: should become asynchronous */ @@ -905,3 +852,76 @@ mct_user_controls_set_permission (MctUserControls *self, g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PERMISSION]); } + +/** + * mct_user_controls_build_app_filter: + * @self: an #MctUserControls + * @builder: an existing #MctAppFilterBuilder to modify + * + * Get the app filter settings currently configured in the user controls, by + * modifying the given @builder. This can be used to save the settings manually. + * + * Since: 0.5.0 + */ +void +mct_user_controls_build_app_filter (MctUserControls *self, + MctAppFilterBuilder *builder) +{ + gboolean allow_web_browsers; + gsize i; + + g_return_if_fail (MCT_IS_USER_CONTROLS (self)); + g_return_if_fail (builder != NULL); + + g_debug ("Building parental controls settings…"); + + /* Blacklist */ + + g_debug ("\t → Blacklisting apps"); + + mct_restrict_applications_dialog_build_app_filter (self->restrict_applications_dialog, builder); + + /* Maturity level */ + + g_debug ("\t → Maturity level"); + + if (self->selected_age == oars_disabled_age) + g_debug ("\t\t → Disabled"); + + for (i = 0; self->selected_age != oars_disabled_age && oars_categories[i] != NULL; i++) + { + MctAppFilterOarsValue oars_value; + const gchar *oars_category; + + oars_category = oars_categories[i]; + oars_value = as_content_rating_id_csm_age_to_value (oars_category, self->selected_age); + + g_debug ("\t\t → %s: %s", oars_category, oars_value_to_string (oars_value)); + + mct_app_filter_builder_set_oars_value (builder, oars_category, oars_value); + } + + /* Web browsers */ + allow_web_browsers = gtk_switch_get_active (self->allow_web_browsers_switch); + + g_debug ("\t → %s web browsers", allow_web_browsers ? "Enabling" : "Disabling"); + + if (!allow_web_browsers) + mct_app_filter_builder_blacklist_content_type (builder, WEB_BROWSERS_CONTENT_TYPE); + + /* App installation */ + if (self->user_account_type != ACT_USER_ACCOUNT_TYPE_ADMINISTRATOR) + { + gboolean allow_system_installation; + gboolean allow_user_installation; + + allow_system_installation = gtk_switch_get_active (self->allow_system_installation_switch); + allow_user_installation = gtk_switch_get_active (self->allow_user_installation_switch); + + g_debug ("\t → %s system installation", allow_system_installation ? "Enabling" : "Disabling"); + g_debug ("\t → %s user installation", allow_user_installation ? "Enabling" : "Disabling"); + + mct_app_filter_builder_set_allow_user_installation (builder, allow_user_installation); + mct_app_filter_builder_set_allow_system_installation (builder, allow_system_installation); + } +} diff --git a/libmalcontent-ui/user-controls.h b/libmalcontent-ui/user-controls.h index a18d1c9..c01f55e 100644 --- a/libmalcontent-ui/user-controls.h +++ b/libmalcontent-ui/user-controls.h @@ -24,6 +24,7 @@ #include #include +#include G_BEGIN_DECLS @@ -39,4 +40,7 @@ GPermission *mct_user_controls_get_permission (MctUserControls *self); void mct_user_controls_set_permission (MctUserControls *self, GPermission *permission); +void mct_user_controls_build_app_filter (MctUserControls *self, + MctAppFilterBuilder *builder); + G_END_DECLS From e4fbb570af7d8f036de56146080cd739d5163eca Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Feb 2020 12:07:58 +0000 Subject: [PATCH 09/11] user-controls: Add some missing documentation comments The annotations in these fix some GIR warnings. Signed-off-by: Philip Withnall --- libmalcontent-ui/user-controls.c | 46 ++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/libmalcontent-ui/user-controls.c b/libmalcontent-ui/user-controls.c index b534243..abff7ea 100644 --- a/libmalcontent-ui/user-controls.c +++ b/libmalcontent-ui/user-controls.c @@ -772,6 +772,16 @@ mct_user_controls_init (MctUserControls *self) G_BINDING_DEFAULT); } +/** + * mct_user_controls_get_user: + * @self: an #MctUserControls + * + * Get the value of #MctUserControls:user. + * + * Returns: (transfer none) (nullable): the user the controls are configured for, + * or %NULL if unknown + * Since: 0.5.0 + */ ActUser * mct_user_controls_get_user (MctUserControls *self) { @@ -780,6 +790,16 @@ mct_user_controls_get_user (MctUserControls *self) return self->user; } +/** + * mct_user_controls_set_user: + * @self: an #MctUserControls + * @user: (nullable) (transfer none): the user to configure the controls for, + * or %NULL if unknown + * + * Set the value of #MctUserControls:user. + * + * Since: 0.5.0 + */ void mct_user_controls_set_user (MctUserControls *self, ActUser *user) @@ -811,7 +831,18 @@ on_permission_allowed_cb (GObject *obj, setup_parental_control_settings (self); } -GPermission * /* (nullable) */ +/** + * mct_user_controls_get_permission: + * @self: an #MctUserControls + * + * Get the value of #MctUserControls:permission. + * + * Returns: (transfer none) (nullable): a #GPermission indicating whether the + * current user has permission to view or change parental controls, or %NULL + * if permission is not allowed or is unknown + * Since: 0.5.0 + */ +GPermission * mct_user_controls_get_permission (MctUserControls *self) { g_return_val_if_fail (MCT_IS_USER_CONTROLS (self), NULL); @@ -819,9 +850,20 @@ mct_user_controls_get_permission (MctUserControls *self) return self->permission; } +/** + * mct_user_controls_set_permission: + * @self: an #MctUserControls + * @permission: (nullable) (transfer none): the #GPermission indicating whether + * the current user has permission to view or change parental controls, or + * %NULL if permission is not allowed or is unknown + * + * Set the value of #MctUserControls:permission. + * + * Since: 0.5.0 + */ void mct_user_controls_set_permission (MctUserControls *self, - GPermission *permission /* (nullable) */) + GPermission *permission) { g_return_if_fail (MCT_IS_USER_CONTROLS (self)); g_return_if_fail (permission == NULL || G_IS_PERMISSION (permission)); From fc9ba76331c5a44feb115fa7ebabae2f9cb85481 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Feb 2020 12:08:28 +0000 Subject: [PATCH 10/11] user-controls: Add some missing includes to the header Signed-off-by: Philip Withnall --- libmalcontent-ui/user-controls.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libmalcontent-ui/user-controls.h b/libmalcontent-ui/user-controls.h index c01f55e..b564138 100644 --- a/libmalcontent-ui/user-controls.h +++ b/libmalcontent-ui/user-controls.h @@ -23,6 +23,9 @@ #pragma once #include +#include +#include +#include #include #include From 1c033f82df284789b361258f5dbbf56e3c97fff7 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Feb 2020 12:26:55 +0000 Subject: [PATCH 11/11] user-controls: Allow widgets to be used without an `ActUser` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow the user controls widget to be used for user accounts which don’t currently exist. This is necessary for using them in gnome-initial-setup. See the big new documentation comment at the top of the widget for details of how the new semantics work. This adds API, but does not break existing API. Signed-off-by: Philip Withnall --- libmalcontent-ui/user-controls.c | 422 ++++++++++++++++++++++++++++++- libmalcontent-ui/user-controls.h | 16 ++ 2 files changed, 429 insertions(+), 9 deletions(-) diff --git a/libmalcontent-ui/user-controls.c b/libmalcontent-ui/user-controls.c index abff7ea..20ab0ba 100644 --- a/libmalcontent-ui/user-controls.c +++ b/libmalcontent-ui/user-controls.c @@ -21,6 +21,7 @@ */ #include +#include #include #include #include @@ -37,6 +38,38 @@ /* The value which we store as an age to indicate that OARS filtering is disabled. */ static const guint32 oars_disabled_age = (guint32) -1; +/** + * MctUserControls: + * + * A group of widgets which allow setting the parental controls for a given + * user. + * + * If #MctUserControls:user is set, the current parental controls settings for + * that user will be loaded and displayed, and any changes made via the controls + * will be automatically saved for that user (potentially after a short + * timeout). + * + * If #MctUserControls:user is unset (for example, if setting the parental + * controls for a user account which hasn’t yet been created), the controls can + * be initialised by setting: + * * #MctUserControls:app-filter + * * #MctUserControls:user-account-type + * * #MctUserControls:user-locale + * * #MctUserControls:user-display-name + * + * When #MctUserControls:user is unset, changes made to the parental controls + * cannot be saved automatically, and must be queried using + * mct_user_controls_build_app_filter(), then saved by the calling code. + * + * As parental controls are system settings, privileges are needed to view and + * edit them (for the current user or for other users). These can be acquired + * using polkit. #MctUserControls:permission is used to query the current + * permissions for getting/setting parental controls. If it’s %NULL, or if + * permissions are not currently granted, the #MctUserControls will be + * insensitive. + * + * Since: 0.5.0 + */ struct _MctUserControls { GtkGrid parent_instance; @@ -58,11 +91,15 @@ struct _MctUserControls GCancellable *cancellable; /* (owned) */ MctManager *manager; /* (owned) */ - MctAppFilter *filter; /* (owned) */ + MctAppFilter *filter; /* (owned) (nullable) */ guint selected_age; /* @oars_disabled_age to disable OARS */ guint blacklist_apps_source_id; gboolean flushed_on_dispose; + + ActUserAccountType user_account_type; + gchar *user_locale; /* (nullable) (owned) */ + gchar *user_display_name; /* (nullable) (owned) */ }; static gboolean blacklist_apps_cb (gpointer data); @@ -100,9 +137,13 @@ typedef enum { PROP_USER = 1, PROP_PERMISSION, + PROP_APP_FILTER, + PROP_USER_ACCOUNT_TYPE, + PROP_USER_LOCALE, + PROP_USER_DISPLAY_NAME, } MctUserControlsProperty; -static GParamSpec *properties[PROP_PERMISSION + 1]; +static GParamSpec *properties[PROP_USER_DISPLAY_NAME + 1]; static const GActionEntry actions[] = { { "set-age", on_set_age_action_activated, "u", NULL, NULL, { 0, }} @@ -147,11 +188,32 @@ static const gchar * const oars_categories[] = static GsContentRatingSystem get_content_rating_system (MctUserControls *self) { - const gchar *user_language; + if (self->user_locale == NULL) + return GS_CONTENT_RATING_SYSTEM_UNKNOWN; - user_language = act_user_get_language (self->user); + return gs_utils_content_rating_system_from_locale (self->user_locale); +} - return gs_utils_content_rating_system_from_locale (user_language); +static const gchar * +get_user_locale (ActUser *user) +{ + const gchar *locale; + + g_return_val_if_fail (ACT_IS_USER (user), "C"); + + /* accounts-service can return %NULL if loading over D-Bus failed. */ + locale = act_user_get_language (user); + if (locale == NULL) + return NULL; + + /* It can return the empty string if the user uses the system default locale. */ + if (*locale == '\0') + locale = setlocale (LC_MESSAGES, NULL); + + if (locale == NULL || *locale == '\0') + locale = "C"; + + return locale; } static const gchar * @@ -340,7 +402,7 @@ update_allow_app_installation (MctUserControls *self) gboolean allow_user_installation; gboolean non_admin_user = TRUE; - if (act_user_get_account_type (self->user) == ACT_USER_ACCOUNT_TYPE_ADMINISTRATOR) + if (self->user_account_type == ACT_USER_ACCOUNT_TYPE_ADMINISTRATOR) non_admin_user = FALSE; /* Admins are always allowed to install apps for all users. This behaviour is governed @@ -351,8 +413,8 @@ update_allow_app_installation (MctUserControls *self) /* If user is admin, we are done here, bail out. */ if (!non_admin_user) { - g_debug ("User %s is administrator, hiding app installation controls", - act_user_get_user_name (self->user)); + g_debug ("User ‘%s’ is an administrator, hiding app installation controls", + self->user_display_name); return; } @@ -447,6 +509,12 @@ blacklist_apps_cb (gpointer data) self->blacklist_apps_source_id = 0; + if (self->user == NULL) + { + g_debug ("Not saving app filter as user is unset"); + return G_SOURCE_REMOVE; + } + mct_user_controls_build_app_filter (self, &builder); new_filter = mct_app_filter_builder_end (&builder); @@ -513,7 +581,7 @@ on_restrict_applications_button_clicked_cb (GtkButton *button, gtk_window_set_transient_for (GTK_WINDOW (self->restrict_applications_dialog), GTK_WINDOW (toplevel)); - mct_restrict_applications_dialog_set_user_display_name (self->restrict_applications_dialog, get_user_display_name (self->user)); + mct_restrict_applications_dialog_set_user_display_name (self->restrict_applications_dialog, self->user_display_name); mct_restrict_applications_dialog_set_app_filter (self->restrict_applications_dialog, self->filter); gtk_widget_show (GTK_WIDGET (self->restrict_applications_dialog)); @@ -604,6 +672,8 @@ mct_user_controls_finalize (GObject *object) g_clear_object (&self->action_group); g_clear_object (&self->cancellable); g_clear_object (&self->user); + g_clear_pointer (&self->user_locale, g_free); + g_clear_pointer (&self->user_display_name, g_free); if (self->permission != NULL && self->permission_allowed_id != 0) { @@ -656,6 +726,22 @@ mct_user_controls_get_property (GObject *object, g_value_set_object (value, self->permission); break; + case PROP_APP_FILTER: + g_value_set_boxed (value, self->filter); + break; + + case PROP_USER_ACCOUNT_TYPE: + g_value_set_enum (value, self->user_account_type); + break; + + case PROP_USER_LOCALE: + g_value_set_string (value, self->user_locale); + break; + + case PROP_USER_DISPLAY_NAME: + g_value_set_string (value, self->user_display_name); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -679,6 +765,22 @@ mct_user_controls_set_property (GObject *object, mct_user_controls_set_permission (self, g_value_get_object (value)); break; + case PROP_APP_FILTER: + mct_user_controls_set_app_filter (self, g_value_get_boxed (value)); + break; + + case PROP_USER_ACCOUNT_TYPE: + mct_user_controls_set_user_account_type (self, g_value_get_enum (value)); + break; + + case PROP_USER_LOCALE: + mct_user_controls_set_user_locale (self, g_value_get_string (value)); + break; + + case PROP_USER_DISPLAY_NAME: + mct_user_controls_set_user_display_name (self, g_value_get_string (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -711,6 +813,91 @@ mct_user_controls_class_init (MctUserControlsClass *klass) G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + /** + * MctUserControls:app-filter: (nullable) + * + * The user’s current app filter, used to set up the user controls. As app + * filters are immutable, it is not updated as the user controls are changed. + * Use mct_user_controls_build_app_filter() to build the new app filter. + * + * This may be %NULL if the app filter is unknown, or if querying it from + * #MctUserControls:user fails. + * + * Since: 0.5.0 + */ + properties[PROP_APP_FILTER] = + g_param_spec_boxed ("app-filter", + "App Filter", + "The user’s current app filter, used to set up the user controls, or %NULL if unknown.", + MCT_TYPE_APP_FILTER, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + /** + * MctUserControls:user-account-type: + * + * The type of the currently selected user account. + * + * Since: 0.5.0 + */ + properties[PROP_USER_ACCOUNT_TYPE] = + g_param_spec_enum ("user-account-type", + "User Account Type", + "The type of the currently selected user account.", + /* FIXME: Not a typo here; libaccountsservice uses the wrong namespace. + * See: https://gitlab.freedesktop.org/accountsservice/accountsservice/issues/84 */ + ACT_USER_TYPE_USER_ACCOUNT_TYPE, + ACT_USER_ACCOUNT_TYPE_STANDARD, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + /** + * MctUserControls:user-locale: (nullable) + * + * The locale for the currently selected user account, or %NULL if no + * user is selected. + * + * If set, it must be in the format documented by [`setlocale()`](man:setlocale(3)): + * ``` + * language[_territory][.codeset][@modifier] + * ``` + * where `language` is an ISO 639 language code, `territory` is an ISO 3166 + * country code, and `codeset` is a character set or encoding identifier like + * `ISO-8859-1` or `UTF-8`. + * + * Since: 0.5.0 + */ + properties[PROP_USER_LOCALE] = + g_param_spec_string ("user-locale", + "User Locale", + "The locale for the currently selected user account, or %NULL if no user is selected.", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + /** + * MctUserControls:user-display-name: (nullable) + * + * The display name for the currently selected user account, or %NULL if no + * user is selected. This will typically be the user’s full name (if known) + * or their username. + * + * If set, it must be valid UTF-8 and non-empty. + * + * Since: 0.5.0 + */ + properties[PROP_USER_DISPLAY_NAME] = + g_param_spec_string ("user-display-name", + "User Display Name", + "The display name for the currently selected user account, or %NULL if no user is selected.", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties); gtk_widget_class_set_template_from_resource (widget_class, "/org/freedesktop/MalcontentUi/ui/user-controls.ui"); @@ -813,10 +1000,21 @@ mct_user_controls_set_user (MctUserControls *self, if (g_set_object (&self->user, user)) { + g_object_freeze_notify (G_OBJECT (self)); + + /* Update the starting widget state from the user. */ + if (user != NULL) + { + mct_user_controls_set_user_account_type (self, act_user_get_account_type (user)); + mct_user_controls_set_user_locale (self, get_user_locale (user)); + mct_user_controls_set_user_display_name (self, get_user_display_name (user)); + } + update_app_filter_from_user (self); setup_parental_control_settings (self); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_USER]); + g_object_thaw_notify (G_OBJECT (self)); } } @@ -895,6 +1093,212 @@ mct_user_controls_set_permission (MctUserControls *self, g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PERMISSION]); } +/** + * mct_user_controls_get_app_filter: + * @self: an #MctUserControls + * + * Get the value of #MctUserControls:app-filter. If the app filter is unknown + * or could not be retrieved from #MctUserControls:user, this will be %NULL. + * + * Returns: (transfer none) (nullable): the initial app filter used to + * populate the user controls, or %NULL if unknown + * Since: 0.5.0 + */ +MctAppFilter * +mct_user_controls_get_app_filter (MctUserControls *self) +{ + g_return_val_if_fail (MCT_IS_USER_CONTROLS (self), NULL); + + return self->filter; +} + +/** + * mct_user_controls_set_app_filter: + * @self: an #MctUserControls + * @app_filter: (nullable) (transfer none): the app filter to configure the user + * controls from, or %NULL if unknown + * + * Set the value of #MctUserControls:app-filter. + * + * This will overwrite any user changes to the controls, so they should be saved + * first using mct_user_controls_build_app_filter() if desired. They will be + * saved automatically if #MctUserControls:user is set. + * + * Since: 0.5.0 + */ +void +mct_user_controls_set_app_filter (MctUserControls *self, + MctAppFilter *app_filter) +{ + g_return_if_fail (MCT_IS_USER_CONTROLS (self)); + + /* If we have pending unsaved changes from the previous configuration, force + * them to be saved first. */ + flush_update_blacklisted_apps (self); + + if (self->filter == app_filter) + return; + + g_clear_pointer (&self->filter, mct_app_filter_unref); + if (app_filter != NULL) + self->filter = mct_app_filter_ref (app_filter); + + g_debug ("Set new app filter from caller"); + setup_parental_control_settings (self); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_APP_FILTER]); +} + +/** + * mct_user_controls_get_user_account_type: + * @self: an #MctUserControls + * + * Get the value of #MctUserControls:user-account-type. + * + * Returns: the account type of the user the controls are configured for + * Since: 0.5.0 + */ +ActUserAccountType +mct_user_controls_get_user_account_type (MctUserControls *self) +{ + g_return_val_if_fail (MCT_IS_USER_CONTROLS (self), ACT_USER_ACCOUNT_TYPE_STANDARD); + + return self->user_account_type; +} + +/** + * mct_user_controls_set_user_account_type: + * @self: an #MctUserControls + * @user_account_type: the account type of the user to configure the controls for + * + * Set the value of #MctUserControls:user-account-type. + * + * Since: 0.5.0 + */ +void +mct_user_controls_set_user_account_type (MctUserControls *self, + ActUserAccountType user_account_type) +{ + g_return_if_fail (MCT_IS_USER_CONTROLS (self)); + + /* If we have pending unsaved changes from the previous user, force them to be + * saved first. */ + flush_update_blacklisted_apps (self); + + if (self->user_account_type == user_account_type) + return; + + self->user_account_type = user_account_type; + + setup_parental_control_settings (self); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_USER_ACCOUNT_TYPE]); +} + +/** + * mct_user_controls_get_user_locale: + * @self: an #MctUserControls + * + * Get the value of #MctUserControls:user-locale. + * + * Returns: (transfer none) (nullable): the locale of the user the controls + * are configured for, or %NULL if unknown + * Since: 0.5.0 + */ +const gchar * +mct_user_controls_get_user_locale (MctUserControls *self) +{ + g_return_val_if_fail (MCT_IS_USER_CONTROLS (self), NULL); + + return self->user_locale; +} + +/** + * mct_user_controls_set_user_locale: + * @self: an #MctUserControls + * @user_locale: (nullable) (transfer none): the locale of the user + * to configure the controls for, or %NULL if unknown + * + * Set the value of #MctUserControls:user-locale. + * + * Since: 0.5.0 + */ +void +mct_user_controls_set_user_locale (MctUserControls *self, + const gchar *user_locale) +{ + g_return_if_fail (MCT_IS_USER_CONTROLS (self)); + g_return_if_fail (user_locale == NULL || + (*user_locale != '\0' && + g_utf8_validate (user_locale, -1, NULL))); + + /* If we have pending unsaved changes from the previous user, force them to be + * saved first. */ + flush_update_blacklisted_apps (self); + + if (g_strcmp0 (self->user_locale, user_locale) == 0) + return; + + g_clear_pointer (&self->user_locale, g_free); + self->user_locale = g_strdup (user_locale); + + setup_parental_control_settings (self); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_USER_LOCALE]); +} + +/** + * mct_user_controls_get_user_display_name: + * @self: an #MctUserControls + * + * Get the value of #MctUserControls:user-display-name. + * + * Returns: (transfer none) (nullable): the display name of the user the controls + * are configured for, or %NULL if unknown + * Since: 0.5.0 + */ +const gchar * +mct_user_controls_get_user_display_name (MctUserControls *self) +{ + g_return_val_if_fail (MCT_IS_USER_CONTROLS (self), NULL); + + return self->user_display_name; +} + +/** + * mct_user_controls_set_user_display_name: + * @self: an #MctUserControls + * @user_display_name: (nullable) (transfer none): the display name of the user + * to configure the controls for, or %NULL if unknown + * + * Set the value of #MctUserControls:user-display-name. + * + * Since: 0.5.0 + */ +void +mct_user_controls_set_user_display_name (MctUserControls *self, + const gchar *user_display_name) +{ + g_return_if_fail (MCT_IS_USER_CONTROLS (self)); + g_return_if_fail (user_display_name == NULL || + (*user_display_name != '\0' && + g_utf8_validate (user_display_name, -1, NULL))); + + /* If we have pending unsaved changes from the previous user, force them to be + * saved first. */ + flush_update_blacklisted_apps (self); + + if (g_strcmp0 (self->user_display_name, user_display_name) == 0) + return; + + g_clear_pointer (&self->user_display_name, g_free); + self->user_display_name = g_strdup (user_display_name); + + setup_parental_control_settings (self); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_USER_DISPLAY_NAME]); +} + /** * mct_user_controls_build_app_filter: * @self: an #MctUserControls diff --git a/libmalcontent-ui/user-controls.h b/libmalcontent-ui/user-controls.h index b564138..91e0863 100644 --- a/libmalcontent-ui/user-controls.h +++ b/libmalcontent-ui/user-controls.h @@ -43,6 +43,22 @@ GPermission *mct_user_controls_get_permission (MctUserControls *self); void mct_user_controls_set_permission (MctUserControls *self, GPermission *permission); +MctAppFilter *mct_user_controls_get_app_filter (MctUserControls *self); +void mct_user_controls_set_app_filter (MctUserControls *self, + MctAppFilter *app_filter); + +ActUserAccountType mct_user_controls_get_user_account_type (MctUserControls *self); +void mct_user_controls_set_user_account_type (MctUserControls *self, + ActUserAccountType user_account_type); + +const gchar *mct_user_controls_get_user_locale (MctUserControls *self); +void mct_user_controls_set_user_locale (MctUserControls *self, + const gchar *user_locale); + +const gchar *mct_user_controls_get_user_display_name (MctUserControls *self); +void mct_user_controls_set_user_display_name (MctUserControls *self, + const gchar *user_display_name); + void mct_user_controls_build_app_filter (MctUserControls *self, MctAppFilterBuilder *builder);