From 358cad3a24593f997dc0949f27ed9abb23462694 Mon Sep 17 00:00:00 2001 From: Christopher Davis Date: Mon, 8 Feb 2021 05:27:49 -0800 Subject: [PATCH] user-controls: Use HdyPreferencesPage and HdyActionRow API This allows us to get styling consistent with HdyPreferencesWindow and similar content across GNOME. Part of a consistency push for GNOME 40 --- libmalcontent-ui/meson.build | 1 + libmalcontent-ui/user-controls.c | 175 +++++----- libmalcontent-ui/user-controls.h | 6 +- libmalcontent-ui/user-controls.ui | 549 +++++++----------------------- malcontent-control/application.c | 3 +- malcontent-control/main.ui | 38 +-- 6 files changed, 216 insertions(+), 556 deletions(-) diff --git a/libmalcontent-ui/meson.build b/libmalcontent-ui/meson.build index 9df7b91..7fc0ad7 100644 --- a/libmalcontent-ui/meson.build +++ b/libmalcontent-ui/meson.build @@ -29,6 +29,7 @@ libmalcontent_ui_public_deps = [ dependency('glib-2.0', version: '>= 2.54.2'), dependency('gobject-2.0', version: '>= 2.54'), dependency('gtk+-3.0', version: '>= 3.24'), + dependency('libhandy-1', version: '>= 1.1.0'), libmalcontent_dep, ] libmalcontent_ui_private_deps = [ diff --git a/libmalcontent-ui/user-controls.c b/libmalcontent-ui/user-controls.c index cc9cd2c..3d22b9d 100644 --- a/libmalcontent-ui/user-controls.c +++ b/libmalcontent-ui/user-controls.c @@ -75,20 +75,18 @@ struct _MctUserControls { GtkGrid parent_instance; + GtkLabel *description_label; GMenu *age_menu; GtkSwitch *restrict_software_installation_switch; - GtkLabel *restrict_software_installation_description; + HdyActionRow *restrict_software_installation_row; GtkSwitch *restrict_web_browsers_switch; - GtkLabel *restrict_web_browsers_description; + HdyActionRow *restrict_web_browsers_row; GtkButton *oars_button; GtkLabel *oars_button_label; GtkPopover *oars_popover; MctRestrictApplicationsDialog *restrict_applications_dialog; GtkLabel *restrict_applications_description; - GtkListBoxRow *restrict_applications_row; - - GtkListBox *application_usage_permissions_listbox; - GtkListBox *software_installation_permissions_listbox; + HdyActionRow *restrict_applications_row; GSimpleActionGroup *action_group; /* (owned) */ @@ -111,6 +109,7 @@ struct _MctUserControls ActUserAccountType user_account_type; gchar *user_locale; /* (nullable) (owned) */ gchar *user_display_name; /* (nullable) (owned) */ + gchar *description; /* (nullable) (owned) */ }; static gboolean blocklist_apps_cb (gpointer data); @@ -123,8 +122,9 @@ static void on_restrict_web_browsers_switch_active_changed_cb (GtkSwitch GParamSpec *pspec, MctUserControls *self); -static void on_restrict_applications_button_clicked_cb (GtkButton *button, - gpointer user_data); +static void on_restrict_applications_action_activated (GSimpleAction *action, + GVariant *param, + gpointer user_data); static gboolean on_restrict_applications_dialog_delete_event_cb (GtkWidget *widget, GdkEvent *event, @@ -134,10 +134,6 @@ static void on_restrict_applications_dialog_response_cb (GtkDialog *dialog, gint response_id, gpointer user_data); -static void on_application_usage_permissions_listbox_activated_cb (GtkListBox *list_box, - GtkListBoxRow *row, - gpointer user_data); - static void on_set_age_action_activated (GSimpleAction *action, GVariant *param, gpointer user_data); @@ -146,7 +142,7 @@ static void on_permission_allowed_cb (GObject *obj, GParamSpec *pspec, gpointer user_data); -G_DEFINE_TYPE (MctUserControls, mct_user_controls, GTK_TYPE_GRID) +G_DEFINE_TYPE (MctUserControls, mct_user_controls, GTK_TYPE_BIN) typedef enum { @@ -157,12 +153,14 @@ typedef enum PROP_USER_LOCALE, PROP_USER_DISPLAY_NAME, PROP_DBUS_CONNECTION, + PROP_DESCRIPTION, } MctUserControlsProperty; -static GParamSpec *properties[PROP_DBUS_CONNECTION + 1]; +static GParamSpec *properties[PROP_DESCRIPTION + 1]; static const GActionEntry actions[] = { - { "set-age", on_set_age_action_activated, "u", NULL, NULL, { 0, }} + { "set-age", on_set_age_action_activated, "u", NULL, NULL, { 0, }}, + { "restrict-applications", on_restrict_applications_action_activated, NULL, NULL, NULL, { 0, }} }; /* Auxiliary methods */ @@ -472,19 +470,21 @@ update_labels_from_name (MctUserControls *self) { g_autofree gchar *l = NULL; + gtk_label_set_markup (self->description_label, self->description); + /* Translators: The placeholder is a user’s display name. */ l = g_strdup_printf (_("Prevents %s from running web browsers. Limited web content may still be available in other applications."), self->user_display_name); - gtk_label_set_label (self->restrict_web_browsers_description, l); + hdy_action_row_set_subtitle (self->restrict_web_browsers_row, l); g_clear_pointer (&l, g_free); /* Translators: The placeholder is a user’s display name. */ l = g_strdup_printf (_("Prevents specified applications from being used by %s."), self->user_display_name); - gtk_label_set_label (self->restrict_applications_description, l); + hdy_action_row_set_subtitle (self->restrict_applications_row, l); g_clear_pointer (&l, g_free); /* Translators: The placeholder is a user’s display name. */ l = g_strdup_printf (_("Prevents %s from installing applications."), self->user_display_name); - gtk_label_set_label (self->restrict_software_installation_description, l); + hdy_action_row_set_subtitle (self->restrict_software_installation_row, l); g_clear_pointer (&l, g_free); } @@ -585,8 +585,9 @@ on_restrict_web_browsers_switch_active_changed_cb (GtkSwitch *s, } static void -on_restrict_applications_button_clicked_cb (GtkButton *button, - gpointer user_data) +on_restrict_applications_action_activated (GSimpleAction *action, + GVariant *param, + gpointer user_data) { MctUserControls *self = MCT_USER_CONTROLS (user_data); GtkWidget *toplevel; @@ -632,17 +633,6 @@ on_restrict_applications_dialog_response_cb (GtkDialog *dialog, on_restrict_applications_dialog_delete_event_cb (GTK_WIDGET (dialog), NULL, self); } -static void -on_application_usage_permissions_listbox_activated_cb (GtkListBox *list_box, - GtkListBoxRow *row, - gpointer user_data) -{ - MctUserControls *self = MCT_USER_CONTROLS (user_data); - - if (row == self->restrict_applications_row) - on_restrict_applications_button_clicked_cb (NULL, self); -} - static void on_set_age_action_activated (GSimpleAction *action, GVariant *param, @@ -688,53 +678,6 @@ on_set_age_action_activated (GSimpleAction *action, schedule_update_blocklisted_apps (self); } -static void -list_box_header_func (GtkListBoxRow *row, - GtkListBoxRow *before, - gpointer user_data) -{ - GtkWidget *current; - - if (before == NULL) - { - gtk_list_box_row_set_header (row, NULL); - return; - } - - current = gtk_list_box_row_get_header (row); - if (current == NULL) - { - current = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); - gtk_widget_show (current); - gtk_list_box_row_set_header (row, current); - } -} - -static gboolean -on_keynav_failed (GtkWidget *listbox, - GtkDirectionType direction, - gpointer user_data) -{ - MctUserControls *self = MCT_USER_CONTROLS (user_data); - GtkWidget *new_widget = NULL; - - /* There are currently two listboxes, so don’t over-complicate this function. */ - if (listbox == GTK_WIDGET (self->application_usage_permissions_listbox) && - direction == GTK_DIR_DOWN) - new_widget = GTK_WIDGET (self->software_installation_permissions_listbox); - else if (listbox == GTK_WIDGET (self->software_installation_permissions_listbox) && - direction == GTK_DIR_UP) - new_widget = GTK_WIDGET (self->application_usage_permissions_listbox); - - if (new_widget != NULL) - { - gtk_widget_child_focus (new_widget, direction); - return TRUE; - } - - return FALSE; -} - /* GObject overrides */ static void @@ -850,6 +793,10 @@ mct_user_controls_get_property (GObject *object, g_value_set_object (value, self->dbus_connection); break; + case PROP_DESCRIPTION: + g_value_set_string (value, self->description); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -895,6 +842,10 @@ mct_user_controls_set_property (GObject *object, self->dbus_connection = g_value_dup_object (value); break; + case PROP_DESCRIPTION: + mct_user_controls_set_description (self, g_value_get_string (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -1013,6 +964,25 @@ mct_user_controls_class_init (MctUserControlsClass *klass) G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + /** + * MctUserControls:description: (nullable) + * + * The description for the currently selected user account, or %NULL if no + * user is selected. + * + * If set, it must be valid UTF-8 and non-empty. + * + * Since: 0.11.0 + */ + properties[PROP_DESCRIPTION] = + g_param_spec_string ("description", + "Description", + "The description 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:dbus-connection: (not nullable) * @@ -1036,26 +1006,21 @@ mct_user_controls_class_init (MctUserControlsClass *klass) gtk_widget_class_set_template_from_resource (widget_class, "/org/freedesktop/MalcontentUi/ui/user-controls.ui"); gtk_widget_class_bind_template_child (widget_class, MctUserControls, age_menu); + gtk_widget_class_bind_template_child (widget_class, MctUserControls, description_label); gtk_widget_class_bind_template_child (widget_class, MctUserControls, restrict_software_installation_switch); - gtk_widget_class_bind_template_child (widget_class, MctUserControls, restrict_software_installation_description); + gtk_widget_class_bind_template_child (widget_class, MctUserControls, restrict_software_installation_row); gtk_widget_class_bind_template_child (widget_class, MctUserControls, restrict_web_browsers_switch); - gtk_widget_class_bind_template_child (widget_class, MctUserControls, restrict_web_browsers_description); + gtk_widget_class_bind_template_child (widget_class, MctUserControls, restrict_web_browsers_row); gtk_widget_class_bind_template_child (widget_class, MctUserControls, oars_button); gtk_widget_class_bind_template_child (widget_class, MctUserControls, oars_button_label); gtk_widget_class_bind_template_child (widget_class, MctUserControls, oars_popover); gtk_widget_class_bind_template_child (widget_class, MctUserControls, restrict_applications_dialog); - gtk_widget_class_bind_template_child (widget_class, MctUserControls, restrict_applications_description); gtk_widget_class_bind_template_child (widget_class, MctUserControls, restrict_applications_row); - gtk_widget_class_bind_template_child (widget_class, MctUserControls, application_usage_permissions_listbox); - gtk_widget_class_bind_template_child (widget_class, MctUserControls, software_installation_permissions_listbox); gtk_widget_class_bind_template_callback (widget_class, on_restrict_installation_switch_active_changed_cb); gtk_widget_class_bind_template_callback (widget_class, on_restrict_web_browsers_switch_active_changed_cb); - gtk_widget_class_bind_template_callback (widget_class, on_restrict_applications_button_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, on_restrict_applications_dialog_delete_event_cb); gtk_widget_class_bind_template_callback (widget_class, on_restrict_applications_dialog_response_cb); - gtk_widget_class_bind_template_callback (widget_class, on_application_usage_permissions_listbox_activated_cb); - gtk_widget_class_bind_template_callback (widget_class, on_keynav_failed); } static void @@ -1091,12 +1056,6 @@ mct_user_controls_init (MctUserControls *self) G_ACTION_GROUP (self->action_group)); gtk_popover_bind_model (self->oars_popover, G_MENU_MODEL (self->age_menu), NULL); - - /* Automatically add separators between rows. */ - gtk_list_box_set_header_func (self->application_usage_permissions_listbox, - list_box_header_func, NULL, NULL); - gtk_list_box_set_header_func (self->software_installation_permissions_listbox, - list_box_header_func, NULL, NULL); } /** @@ -1461,6 +1420,38 @@ mct_user_controls_set_user_display_name (MctUserControls *self, g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_USER_DISPLAY_NAME]); } +/** + * mct_user_controls_set_description: + * @self: an #MctUserControls + * @description: (nullable) (transfer none): the description shown + * above the controls, or %NULL if none. + * + * Set the value of #MctUserControls:description. + * + * Since: 0.11.0 + */ +void +mct_user_controls_set_description (MctUserControls *self, + const gchar *description) +{ + g_return_if_fail (MCT_IS_USER_CONTROLS (self)); + g_return_if_fail (description != NULL); + + /* If we have pending unsaved changes from the previous user, force them to be + * saved first. */ + flush_update_blocklisted_apps (self); + + if (g_strcmp0 (self->description, description) == 0) + return; + + g_clear_pointer (&self->description, g_free); + self->description = g_strdup (description); + + setup_parental_control_settings (self); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DESCRIPTION]); +} + /** * mct_user_controls_build_app_filter: * @self: an #MctUserControls diff --git a/libmalcontent-ui/user-controls.h b/libmalcontent-ui/user-controls.h index 91e0863..a8b2847 100644 --- a/libmalcontent-ui/user-controls.h +++ b/libmalcontent-ui/user-controls.h @@ -27,13 +27,14 @@ #include #include #include +#include #include G_BEGIN_DECLS #define MCT_TYPE_USER_CONTROLS (mct_user_controls_get_type()) -G_DECLARE_FINAL_TYPE (MctUserControls, mct_user_controls, MCT, USER_CONTROLS, GtkGrid) +G_DECLARE_FINAL_TYPE (MctUserControls, mct_user_controls, MCT, USER_CONTROLS, GtkBin) ActUser *mct_user_controls_get_user (MctUserControls *self); void mct_user_controls_set_user (MctUserControls *self, @@ -59,6 +60,9 @@ 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_set_description (MctUserControls *self, + const gchar *description); + void mct_user_controls_build_app_filter (MctUserControls *self, MctAppFilterBuilder *builder); diff --git a/libmalcontent-ui/user-controls.ui b/libmalcontent-ui/user-controls.ui index b699871..e2cff1b 100644 --- a/libmalcontent-ui/user-controls.ui +++ b/libmalcontent-ui/user-controls.ui @@ -2,454 +2,159 @@ -