[gnome-software: 5/9] updates-section: Style it like other sections




commit 9a65a364492fda5651d2e0ae16e67494e352955c
Author: Adrien Plazas <kekun plazas laposte net>
Date:   Wed Jul 21 15:06:35 2021 +0200

    updates-section: Style it like other sections
    
    This moves the header out of the list box, complexifying its layout and
    making it not extend GtkListBox anymore.

 src/gnome-software.gresource.xml |   1 +
 src/gs-updates-page.ui           |   9 +-
 src/gs-updates-section.c         | 242 ++++++++++++++++++++-------------------
 src/gs-updates-section.h         |   2 +-
 src/gs-updates-section.ui        | 112 ++++++++++++++++++
 src/gtk-style.css                |   9 ++
 6 files changed, 255 insertions(+), 120 deletions(-)
---
diff --git a/src/gnome-software.gresource.xml b/src/gnome-software.gresource.xml
index 8d3e33be8..34c69140b 100644
--- a/src/gnome-software.gresource.xml
+++ b/src/gnome-software.gresource.xml
@@ -39,6 +39,7 @@
   <file preprocess="xml-stripblanks">gs-third-party-repo-row.ui</file>
   <file preprocess="xml-stripblanks">gs-update-dialog.ui</file>
   <file preprocess="xml-stripblanks">gs-updates-page.ui</file>
+  <file preprocess="xml-stripblanks">gs-updates-section.ui</file>
   <file preprocess="xml-stripblanks">gs-upgrade-banner.ui</file>
   <file preprocess="xml-stripblanks">org.freedesktop.PackageKit.xml</file>
   <file>gtk-style.css</file>
diff --git a/src/gs-updates-page.ui b/src/gs-updates-page.ui
index 127b273cf..fe6618853 100644
--- a/src/gs-updates-page.ui
+++ b/src/gs-updates-page.ui
@@ -126,11 +126,14 @@
                 <property name="hscrollbar_policy">never</property>
                 <property name="vscrollbar_policy">automatic</property>
                 <property name="shadow_type">none</property>
+                <style>
+                  <class name="list-page"/>
+                </style>
                 <child>
-                  <object class="GsFixedSizeBin" id="gs_fixed_bin">
+                  <object class="HdyClamp" id="gs_fixed_bin">
                     <property name="visible">True</property>
-                    <property name="preferred-width">860</property>
-                    <property name="border-width">24</property>
+                    <property name="maximum-size">860</property>
+                    <property name="tightening-threshold">860</property>
                     <child>
                       <object class="GtkBox" id="list_box_updates_box">
                         <property name="visible">True</property>
diff --git a/src/gs-updates-section.c b/src/gs-updates-section.c
index fe95710fe..b4227a71a 100644
--- a/src/gs-updates-section.c
+++ b/src/gs-updates-section.c
@@ -23,7 +23,18 @@
 
 struct _GsUpdatesSection
 {
-       GtkListBox               parent_instance;
+       GtkBox                   parent_instance;
+
+       GtkWidget               *button_cancel;
+       GtkWidget               *button_download;
+       GtkWidget               *button_stack;
+       GtkWidget               *button_update;
+       GtkWidget               *description;
+       GtkWidget               *listbox;
+       GtkWidget               *listbox_box;
+       GtkWidget               *section_header;
+       GtkWidget               *title;
+
        GsAppList               *list;
        GsUpdatesSectionKind     kind;
        GCancellable            *cancellable;
@@ -35,15 +46,10 @@ struct _GsUpdatesSection
        GtkSizeGroup            *sizegroup_button_label;
        GtkSizeGroup            *sizegroup_button_image;
        GtkSizeGroup            *sizegroup_header;
-       GtkWidget               *button_download;
-       GtkWidget               *button_update;
-       GtkWidget               *button_cancel;
-       GtkStack                *button_stack;
-       GtkWidget               *section_header;
        gboolean                 is_narrow;
 };
 
-G_DEFINE_TYPE (GsUpdatesSection, gs_updates_section, GTK_TYPE_LIST_BOX)
+G_DEFINE_TYPE (GsUpdatesSection, gs_updates_section, GTK_TYPE_BOX)
 
 typedef enum {
        PROP_IS_NARROW = 1,
@@ -57,6 +63,20 @@ gs_updates_section_get_list (GsUpdatesSection *self)
        return self->list;
 }
 
+static gboolean
+_listbox_keynav_failed_cb (GsAppRow *app_row, GtkDirectionType direction)
+{
+       GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (app_row));
+
+       if (!toplevel)
+               return FALSE;
+
+       if (direction != GTK_DIR_UP && direction != GTK_DIR_DOWN)
+               return FALSE;
+
+       return gtk_widget_child_focus (toplevel, direction == GTK_DIR_UP ? GTK_DIR_TAB_BACKWARD : 
GTK_DIR_TAB_FORWARD);
+}
+
 static void
 _app_row_button_clicked_cb (GsAppRow *app_row, GsUpdatesSection *self)
 {
@@ -284,7 +304,7 @@ _update_buttons (GsUpdatesSection *self)
        if (self->cancellable != NULL) {
                gtk_widget_set_sensitive (self->button_cancel,
                                          !g_cancellable_is_cancelled (self->cancellable));
-               gtk_stack_set_visible_child_name (self->button_stack, "cancel");
+               gtk_stack_set_visible_child_name (GTK_STACK (self->button_stack), "cancel");
                gtk_widget_show (GTK_WIDGET (self->button_stack));
                return;
        }
@@ -292,16 +312,16 @@ _update_buttons (GsUpdatesSection *self)
        if (self->kind == GS_UPDATES_SECTION_KIND_OFFLINE_FIRMWARE ||
            self->kind == GS_UPDATES_SECTION_KIND_OFFLINE) {
                if (_all_offline_updates_downloaded (self))
-                       gtk_stack_set_visible_child_name (self->button_stack, "update");
+                       gtk_stack_set_visible_child_name (GTK_STACK (self->button_stack), "update");
                else
-                       gtk_stack_set_visible_child_name (self->button_stack, "download");
+                       gtk_stack_set_visible_child_name (GTK_STACK (self->button_stack), "download");
 
                gtk_widget_show (GTK_WIDGET (self->button_stack));
                /* TRANSLATORS: This is the button for installing all
                 * offline updates */
                gtk_button_set_label (GTK_BUTTON (self->button_update), _("Restart & Update"));
        } else if (self->kind == GS_UPDATES_SECTION_KIND_ONLINE) {
-               gtk_stack_set_visible_child_name (self->button_stack, "update");
+               gtk_stack_set_visible_child_name (GTK_STACK (self->button_stack), "update");
                gtk_widget_show (GTK_WIDGET (self->button_stack));
                /* TRANSLATORS: This is the button for upgrading all
                 * online-updatable applications */
@@ -377,7 +397,7 @@ _download_finished_cb (GObject *object, GAsyncResult *res, gpointer user_data)
 }
 
 static void
-_button_download_clicked_cb (GtkButton *button, GsUpdatesSection *self)
+_button_download_clicked_cb (GsUpdatesSection *self)
 {
        g_autoptr(GCancellable) cancellable = g_cancellable_new ();
        g_autoptr(GsPluginJob) plugin_job = NULL;
@@ -396,7 +416,7 @@ _button_download_clicked_cb (GtkButton *button, GsUpdatesSection *self)
 }
 
 static void
-_button_update_all_clicked_cb (GtkButton *button, GsUpdatesSection *self)
+_button_update_all_clicked_cb (GsUpdatesSection *self)
 {
        g_autoptr(GCancellable) cancellable = g_cancellable_new ();
        g_autoptr(GsPluginJob) plugin_job = NULL;
@@ -425,110 +445,38 @@ _button_update_all_clicked_cb (GtkButton *button, GsUpdatesSection *self)
        _update_buttons (self);
 }
 
-static GtkWidget *
-_build_section_header (GsUpdatesSection *self)
+static void
+_setup_section_header (GsUpdatesSection *self)
 {
-       GtkStyleContext *context;
-       GtkWidget *header;
-       GtkWidget *label;
-
        /* get labels and buttons for everything */
-       if (self->kind == GS_UPDATES_SECTION_KIND_OFFLINE_FIRMWARE) {
+       switch (self->kind) {
+       case GS_UPDATES_SECTION_KIND_OFFLINE_FIRMWARE:
                /* TRANSLATORS: This is the header for system firmware that
                 * requires a reboot to apply */
-               label = gtk_label_new (_("Integrated Firmware"));
-       } else if (self->kind == GS_UPDATES_SECTION_KIND_OFFLINE) {
+               gtk_label_set_label (GTK_LABEL (self->title), _("Integrated Firmware"));
+               break;
+       case GS_UPDATES_SECTION_KIND_OFFLINE:
                /* TRANSLATORS: This is the header for offline OS and offline
                 * app updates that require a reboot to apply */
-               label = gtk_label_new (_("Requires Restart"));
-       } else if (self->kind == GS_UPDATES_SECTION_KIND_ONLINE) {
+               gtk_label_set_label (GTK_LABEL (self->title), _("Requires Restart"));
+               break;
+       case GS_UPDATES_SECTION_KIND_ONLINE:
                /* TRANSLATORS: This is the header for online runtime and
                 * app updates, typically flatpaks or snaps */
-               label = gtk_label_new (_("Application Updates"));
-       } else if (self->kind == GS_UPDATES_SECTION_KIND_ONLINE_FIRMWARE) {
+               gtk_label_set_label (GTK_LABEL (self->title), _("Application Updates"));
+               break;
+       case GS_UPDATES_SECTION_KIND_ONLINE_FIRMWARE:
                /* TRANSLATORS: This is the header for device firmware that can
                 * be installed online */
-               label = gtk_label_new (_("Device Firmware"));
-       } else {
+               gtk_label_set_label (GTK_LABEL (self->title), _("Device Firmware"));
+               break;
+       default:
                g_assert_not_reached ();
        }
-
-       /* create header */
-       header = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3);
-       context = gtk_widget_get_style_context (header);
-       gtk_style_context_add_class (context, "app-listbox-header");
-
-       /* put label into the header */
-       gtk_widget_set_hexpand (label, TRUE);
-       gtk_container_add (GTK_CONTAINER (header), label);
-       gtk_widget_set_visible (label, TRUE);
-       gtk_widget_set_margin_start (label, 6);
-       gtk_label_set_xalign (GTK_LABEL (label), 0.0);
-       context = gtk_widget_get_style_context (label);
-       gtk_style_context_add_class (context, "app-listbox-header-title");
-
-       /* use a stack so we can switch which buttons are showing without the
-        * sizegroup resizing */
-       self->button_stack = GTK_STACK (gtk_stack_new ());
-       gtk_container_add (GTK_CONTAINER (header), GTK_WIDGET (self->button_stack));
-       gtk_container_child_set (GTK_CONTAINER (header), GTK_WIDGET (self->button_stack), "pack-type", 
GTK_PACK_END, NULL);
-
-       /* add download button */
-       self->button_download = gs_progress_button_new ();
-       gtk_button_set_use_underline (GTK_BUTTON (self->button_download), TRUE);
-       gtk_button_set_label (GTK_BUTTON (self->button_download), _("_Download"));
-       context = gtk_widget_get_style_context (self->button_download);
-       gtk_style_context_add_class (context, GTK_STYLE_CLASS_SUGGESTED_ACTION);
-       g_signal_connect (self->button_download, "clicked",
-                         G_CALLBACK (_button_download_clicked_cb),
-                         self);
-       gtk_stack_add_named (self->button_stack, self->button_download, "download");
-       gtk_widget_set_visible (self->button_download, TRUE);
-
-       /* add update button */
-       self->button_update = gs_progress_button_new ();
-       context = gtk_widget_get_style_context (self->button_update);
-       gtk_style_context_add_class (context, GTK_STYLE_CLASS_SUGGESTED_ACTION);
-       g_signal_connect (self->button_update, "clicked",
-                         G_CALLBACK (_button_update_all_clicked_cb),
-                         self);
-       gtk_stack_add_named (self->button_stack, self->button_update, "update");
-       gtk_widget_set_visible (self->button_update, TRUE);
-
-       /* add cancel button */
-       self->button_cancel = gs_progress_button_new ();
-       gtk_button_set_label (GTK_BUTTON (self->button_cancel), _("Cancel"));
-       gs_progress_button_set_show_progress (GS_PROGRESS_BUTTON (self->button_cancel), TRUE);
-       g_signal_connect (self->button_cancel, "clicked",
-                         G_CALLBACK (_button_cancel_clicked_cb),
-                         self);
-       gtk_stack_add_named (self->button_stack, self->button_cancel, "cancel");
-       gtk_widget_set_visible (self->button_cancel, TRUE);
-
-       /* success */
-       return header;
 }
 
 static void
-_list_header_func (GtkListBoxRow *row, GtkListBoxRow *before, gpointer user_data)
-{
-       GsUpdatesSection *self = GS_UPDATES_SECTION (user_data);
-       GtkWidget *header;
-
-       /* section changed */
-       if (before == NULL) {
-               if (gtk_list_box_row_get_header (row) != self->section_header) {
-                       gtk_widget_unparent (self->section_header);
-               }
-               header = self->section_header;
-       } else {
-               header = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
-       }
-       gtk_list_box_row_set_header (row, header);
-}
-
-static void
-_app_row_activated_cb (GtkListBox *list_box, GtkListBoxRow *row, GsUpdatesSection *self)
+_app_row_activated_cb (GsUpdatesSection *self, GtkListBoxRow *row)
 {
        GsApp *app = gs_app_row_get_app (GS_APP_ROW (row));
        GtkWidget *dialog;
@@ -555,6 +503,56 @@ gs_updates_section_show (GtkWidget *widget)
        GTK_WIDGET_CLASS (gs_updates_section_parent_class)->show (widget);
 }
 
+static void
+gs_updates_section_forall (GtkContainer *container,
+                          gboolean include_internals,
+                          GtkCallback callback,
+                          gpointer callback_data)
+{
+       GsUpdatesSection *self = GS_UPDATES_SECTION (container);
+
+       if (include_internals) {
+               GTK_CONTAINER_CLASS (gs_updates_section_parent_class)->forall (GTK_CONTAINER (self), 
include_internals, callback, callback_data);
+
+               return;
+       }
+
+       if (self->listbox)
+               GTK_CONTAINER_GET_CLASS (self->listbox)->forall (GTK_CONTAINER (self->listbox), 
include_internals, callback, callback_data);
+}
+
+static void
+gs_updates_section_add (GtkContainer *container, GtkWidget *child)
+{
+       GsUpdatesSection *self = GS_UPDATES_SECTION (container);
+
+       if (self->section_header == NULL ||
+           self->description == NULL ||
+           self->listbox_box == NULL) {
+               /* Add internal children, used when building the widget. */
+               GTK_CONTAINER_CLASS (gs_updates_section_parent_class)->add (container, child);
+       } else {
+               /* Add external children to the listbox. */
+               gtk_container_add (GTK_CONTAINER (self->listbox), child);
+       }
+}
+
+static void
+gs_updates_section_remove (GtkContainer *container, GtkWidget *child)
+{
+       GsUpdatesSection *self = GS_UPDATES_SECTION (container);
+
+       if (child == self->section_header ||
+           child == self->description ||
+           child == self->listbox_box) {
+               /* Remove internal children, used when destroying the widget. */
+               GTK_CONTAINER_CLASS (gs_updates_section_parent_class)->remove (container, child);
+       } else {
+               /* Remove external children from the listbox. */
+               gtk_container_remove (GTK_CONTAINER (self->listbox), child);
+       }
+}
+
 static void
 gs_updates_section_get_property (GObject    *object,
                                  guint       prop_id,
@@ -610,7 +608,6 @@ gs_updates_section_dispose (GObject *object)
        self->button_update = NULL;
        self->button_cancel = NULL;
        self->button_stack = NULL;
-       g_clear_object (&self->section_header);
 
        G_OBJECT_CLASS (gs_updates_section_parent_class)->dispose (object);
 }
@@ -620,12 +617,17 @@ gs_updates_section_class_init (GsUpdatesSectionClass *klass)
 {
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+       GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
 
        object_class->get_property = gs_updates_section_get_property;
        object_class->set_property = gs_updates_section_set_property;
        object_class->dispose = gs_updates_section_dispose;
        widget_class->show = gs_updates_section_show;
 
+       container_class->add = gs_updates_section_add;
+       container_class->remove = gs_updates_section_remove;
+       container_class->forall = gs_updates_section_forall;
+
        /**
         * GsUpdatesSection:is-narrow:
         *
@@ -643,6 +645,23 @@ gs_updates_section_class_init (GsUpdatesSectionClass *klass)
                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
 
        g_object_class_install_properties (object_class, G_N_ELEMENTS (obj_props), obj_props);
+
+       gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/Software/gs-updates-section.ui");
+
+       gtk_widget_class_bind_template_child (widget_class, GsUpdatesSection, button_cancel);
+       gtk_widget_class_bind_template_child (widget_class, GsUpdatesSection, button_download);
+       gtk_widget_class_bind_template_child (widget_class, GsUpdatesSection, button_stack);
+       gtk_widget_class_bind_template_child (widget_class, GsUpdatesSection, button_update);
+       gtk_widget_class_bind_template_child (widget_class, GsUpdatesSection, description);
+       gtk_widget_class_bind_template_child (widget_class, GsUpdatesSection, listbox);
+       gtk_widget_class_bind_template_child (widget_class, GsUpdatesSection, listbox_box);
+       gtk_widget_class_bind_template_child (widget_class, GsUpdatesSection, section_header);
+       gtk_widget_class_bind_template_child (widget_class, GsUpdatesSection, title);
+       gtk_widget_class_bind_template_callback (widget_class, _app_row_activated_cb);
+       gtk_widget_class_bind_template_callback (widget_class, _button_cancel_clicked_cb);
+       gtk_widget_class_bind_template_callback (widget_class, _button_download_clicked_cb);
+       gtk_widget_class_bind_template_callback (widget_class, _button_update_all_clicked_cb);
+       gtk_widget_class_bind_template_callback (widget_class, _listbox_keynav_failed_cb);
 }
 
 void
@@ -706,7 +725,7 @@ gs_updates_section_app_state_changed_cb (GsAppList *list,
 static void
 gs_updates_section_init (GsUpdatesSection *self)
 {
-       GtkStyleContext *context;
+       gtk_widget_init_template (GTK_WIDGET (self));
 
        self->list = gs_app_list_new ();
        gs_app_list_add_flag (self->list,
@@ -716,20 +735,11 @@ gs_updates_section_init (GsUpdatesSection *self)
        g_signal_connect_object (self->list, "notify::progress",
                                 G_CALLBACK (gs_updates_section_progress_notify_cb),
                                 self, 0);
-       gtk_list_box_set_selection_mode (GTK_LIST_BOX (self),
+       gtk_list_box_set_selection_mode (GTK_LIST_BOX (self->listbox),
                                         GTK_SELECTION_NONE);
-       gtk_list_box_set_sort_func (GTK_LIST_BOX (self),
+       gtk_list_box_set_sort_func (GTK_LIST_BOX (self->listbox),
                                    _list_sort_func,
                                    self, NULL);
-       gtk_list_box_set_header_func (GTK_LIST_BOX (self),
-                                     _list_header_func,
-                                     self, NULL);
-       g_signal_connect (self, "row-activated",
-                         G_CALLBACK (_app_row_activated_cb), self);
-
-       /* make rounded edges */
-       context = gtk_widget_get_style_context (GTK_WIDGET (self));
-       gtk_style_context_add_class (context, "app-updates-section");
 }
 
 /**
@@ -783,7 +793,7 @@ gs_updates_section_new (GsUpdatesSectionKind kind,
        self->kind = kind;
        self->plugin_loader = g_object_ref (plugin_loader);
        self->page = g_object_ref (page);
-       self->section_header = g_object_ref_sink (_build_section_header (self));
+       _setup_section_header (self);
 
        if (self->kind == GS_UPDATES_SECTION_KIND_ONLINE) {
                g_signal_connect_object (self->list, "app-state-changed",
diff --git a/src/gs-updates-section.h b/src/gs-updates-section.h
index 683b49b20..7c6c382ff 100644
--- a/src/gs-updates-section.h
+++ b/src/gs-updates-section.h
@@ -19,7 +19,7 @@ G_BEGIN_DECLS
 
 #define GS_TYPE_UPDATES_SECTION (gs_updates_section_get_type ())
 
-G_DECLARE_FINAL_TYPE (GsUpdatesSection, gs_updates_section, GS, UPDATES_SECTION, GtkListBox)
+G_DECLARE_FINAL_TYPE (GsUpdatesSection, gs_updates_section, GS, UPDATES_SECTION, GtkBox)
 
 typedef enum {
        GS_UPDATES_SECTION_KIND_OFFLINE_FIRMWARE,
diff --git a/src/gs-updates-section.ui b/src/gs-updates-section.ui
new file mode 100644
index 000000000..67e10b31d
--- /dev/null
+++ b/src/gs-updates-section.ui
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface domain="libhandy">
+  <requires lib="gtk+" version="3.0"/>
+  <template class="GsUpdatesSection" parent="GtkBox">
+    <property name="orientation">vertical</property>
+    <style>
+      <class name="section"/>
+    </style>
+    <child>
+      <object class="GtkBox" id="section_header">
+        <property name="visible">True</property>
+        <child>
+          <object class="GtkLabel" id="title">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="ellipsize">end</property>
+            <property name="halign">start</property>
+            <property name="xalign">0</property>
+            <property name="no-show-all">True</property>
+            <style>
+              <class name="heading"/>
+            </style>
+            <accessibility>
+              <relation target="listbox_box" type="label-for"/>
+            </accessibility>
+          </object>
+        </child>
+        <child>
+          <object class="GtkStack" id="button_stack">
+            <property name="visible">True</property>
+            <child>
+              <object class="GsProgressButton" id="button_download">
+                <property name="visible">True</property>
+                <property name="use_underline">True</property>
+                <property name="label" translatable="yes">_Download</property>
+                <signal name="clicked" handler="_button_download_clicked_cb" swapped="yes"/>
+                <style>
+                  <class name="suggested-action"/>
+                </style>
+              </object>
+              <packing>
+                <property name="name">download</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GsProgressButton" id="button_update">
+                <property name="visible">True</property>
+                <signal name="clicked" handler="_button_update_all_clicked_cb" swapped="yes"/>
+                <style>
+                  <class name="suggested-action"/>
+                </style>
+              </object>
+              <packing>
+                <property name="name">update</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GsProgressButton" id="button_cancel">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Cancel</property>
+                <signal name="clicked" handler="_button_cancel_clicked_cb" swapped="yes"/>
+                <style>
+                  <class name="suggested-action"/>
+                  <class name="install-progress"/>
+                </style>
+              </object>
+              <packing>
+                <property name="name">cancel</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="pack-type">end</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkLabel" id="description">
+        <property name="can_focus">False</property>
+        <property name="halign">start</property>
+        <property name="wrap">True</property>
+        <property name="wrap-mode">word-char</property>
+        <property name="xalign">0</property>
+        <property name="no-show-all">True</property>
+        <style>
+          <class name="dim-label"/>
+        </style>
+      </object>
+    </child>
+    <child>
+      <object class="GtkBox" id="listbox_box">
+        <property name="orientation">vertical</property>
+        <property name="visible">True</property>
+        <accessibility>
+          <relation target="title" type="labelled-by"/>
+        </accessibility>
+        <child>
+          <object class="GtkListBox" id="listbox">
+            <property name="selection_mode">none</property>
+            <property name="visible">True</property>
+            <signal name="row-activated" handler="_app_row_activated_cb" swapped="yes"/>
+            <signal name="keynav-failed" handler="_listbox_keynav_failed_cb" swapped="yes"/>
+            <style>
+              <class name="content"/>
+            </style>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/gtk-style.css b/src/gtk-style.css
index dc5fa28a0..b073f05ff 100644
--- a/src/gtk-style.css
+++ b/src/gtk-style.css
@@ -576,6 +576,15 @@ scrolledwindow.list-page > viewport > clamp.large .section {
   margin-top: 18px;
 }
 
+/* The following style is taken from libhandy's HdyPreferencesGroup style, which
+ * implements the style for titled and described sections with a list box.
+ * FIXME: Drop this style if we use the successor of HdyPreferencesGroup in
+ * Libadwaita when porting to GTK 4. */
+
+.section > label:not(:first-child) { margin-top: 6px; }
+
+.section > box:not(:first-child) { margin-top: 12px; }
+
 /* The following style is taken from libhandy's HdyStatusPage style.
  * FIXME: Drop this style if HdyStatusPage or its GTK 4 successor allows setting
  * a spinner and the updates spinner page can be ported to it. */


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