[gnome-software: 95/110] gs-description-box: Subclass GtkWidget




commit 3332c288c718e97201c04ed8cfc97b2b55836b0e
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Fri Aug 27 16:42:14 2021 -0300

    gs-description-box: Subclass GtkWidget
    
    GsDescriptionBox currently subclasses GtkBox, which
    in GTK4 has a layout manager set. This is problematic
    for us because having a layout manager means GTK won't
    call GtkWidget.size_allocate, and GsDescriptionBox
    relies on this vfunc being called.
    
    Work around this by subclassing GtkWidget directly, and
    implementing a very rudimentary size_allocate and
    measure vfuncs. Add a new GtkBox child to GsDescriptionBox
    doing what the very class was doing before.
    
    Update the description box in idle after size_allocate is
    called, otherwise we potentially run into a layout loop,
    and GTK4 stops it all there.

 src/gs-description-box.c | 66 ++++++++++++++++++++++++++++++++++++++----------
 src/gs-description-box.h |  2 +-
 src/gs-details-page.ui   |  2 --
 3 files changed, 54 insertions(+), 16 deletions(-)
---
diff --git a/src/gs-description-box.c b/src/gs-description-box.c
index f60198b84..e42cb89b8 100644
--- a/src/gs-description-box.c
+++ b/src/gs-description-box.c
@@ -27,7 +27,8 @@
 #define MAX_COLLAPSED_LINES 4
 
 struct _GsDescriptionBox {
-       GtkBox parent;
+       GtkWidget parent;
+       GtkWidget *box;
        GtkLabel *label;
        GtkButton *button;
        gchar *text;
@@ -35,9 +36,10 @@ struct _GsDescriptionBox {
        gboolean needs_recalc;
        gint last_width;
        gint last_height;
+       guint idle_update_id;
 };
 
-G_DEFINE_TYPE (GsDescriptionBox, gs_description_box, GTK_TYPE_BOX)
+G_DEFINE_TYPE (GsDescriptionBox, gs_description_box, GTK_TYPE_WIDGET)
 
 static void
 gs_description_box_update_content (GsDescriptionBox *box)
@@ -115,6 +117,35 @@ gs_description_box_read_button_clicked_cb (GtkButton *button,
        gs_description_box_update_content (box);
 }
 
+static void
+gs_description_box_measure (GtkWidget      *widget,
+                            GtkOrientation  orientation,
+                            gint            for_size,
+                            gint           *minimum,
+                            gint           *natural,
+                            gint           *minimum_baseline,
+                            gint           *natural_baseline)
+{
+       GsDescriptionBox *box = GS_DESCRIPTION_BOX (widget);
+
+       gtk_widget_measure (box->box, orientation,
+                           for_size,
+                           minimum, natural,
+                           minimum_baseline,
+                           natural_baseline);
+}
+
+static gboolean
+update_description_in_idle_cb (gpointer data)
+{
+       GsDescriptionBox *box = GS_DESCRIPTION_BOX (data);
+
+       gs_description_box_update_content (box);
+       box->idle_update_id = 0;
+
+       return G_SOURCE_REMOVE;
+}
+
 static void
 gs_description_box_size_allocate (GtkWidget *widget,
                                   int        width,
@@ -123,12 +154,19 @@ gs_description_box_size_allocate (GtkWidget *widget,
 {
        GsDescriptionBox *box = GS_DESCRIPTION_BOX (widget);
 
-       GTK_WIDGET_CLASS (gs_description_box_parent_class)->size_allocate (widget,
-                                                                          width,
-                                                                          height,
-                                                                          baseline);
+       gtk_widget_allocate (box->box, width, height, baseline, NULL);
+       box->idle_update_id = g_idle_add (update_description_in_idle_cb, box);
+}
 
-       gs_description_box_update_content (box);
+static void
+gs_description_box_dispose (GObject *object)
+{
+       GsDescriptionBox *box = GS_DESCRIPTION_BOX (object);
+
+       g_clear_handle_id (&box->idle_update_id, g_source_remove);
+       g_clear_pointer (&box->box, gtk_widget_unparent);
+
+       G_OBJECT_CLASS (gs_description_box_parent_class)->dispose (object);
 }
 
 static void
@@ -149,6 +187,9 @@ gs_description_box_init (GsDescriptionBox *box)
 
        box->is_collapsed = TRUE;
 
+       box->box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 24);
+       gtk_widget_set_parent (GTK_WIDGET (box->box), GTK_WIDGET (box));
+
        style_context = gtk_widget_get_style_context (GTK_WIDGET (box));
        gtk_style_context_add_class (style_context, "application-details-description");
 
@@ -166,7 +207,7 @@ gs_description_box_init (GsDescriptionBox *box)
                "xalign", 0.0,
                NULL);
 
-       gtk_box_append (GTK_BOX (box), widget);
+       gtk_box_append (GTK_BOX (box->box), widget);
 
        style_context = gtk_widget_get_style_context (widget);
        gtk_style_context_add_class (style_context, "label");
@@ -183,7 +224,7 @@ gs_description_box_init (GsDescriptionBox *box)
                "visible", TRUE,
                NULL);
 
-       gtk_box_append (GTK_BOX (box), widget);
+       gtk_box_append (GTK_BOX (box->box), widget);
 
        style_context = gtk_widget_get_style_context (widget);
        gtk_style_context_add_class (style_context, "button");
@@ -202,19 +243,18 @@ gs_description_box_class_init (GsDescriptionBoxClass *klass)
        GtkWidgetClass *widget_class;
 
        object_class = G_OBJECT_CLASS (klass);
+       object_class->dispose = gs_description_box_dispose;
        object_class->finalize = gs_description_box_finalize;
 
        widget_class = GTK_WIDGET_CLASS (klass);
+       widget_class->measure = gs_description_box_measure;
        widget_class->size_allocate = gs_description_box_size_allocate;
 }
 
 GtkWidget *
 gs_description_box_new (void)
 {
-       return g_object_new (GS_TYPE_DESCRIPTION_BOX,
-               "orientation", GTK_ORIENTATION_VERTICAL,
-               "spacing", 24,
-               NULL);
+       return g_object_new (GS_TYPE_DESCRIPTION_BOX, NULL);
 }
 
 const gchar *
diff --git a/src/gs-description-box.h b/src/gs-description-box.h
index ebcb60174..667b2143d 100644
--- a/src/gs-description-box.h
+++ b/src/gs-description-box.h
@@ -14,7 +14,7 @@ G_BEGIN_DECLS
 
 #define GS_TYPE_DESCRIPTION_BOX (gs_description_box_get_type ())
 
-G_DECLARE_FINAL_TYPE (GsDescriptionBox, gs_description_box, GS, DESCRIPTION_BOX, GtkBox)
+G_DECLARE_FINAL_TYPE (GsDescriptionBox, gs_description_box, GS, DESCRIPTION_BOX, GtkWidget)
 
 GtkWidget      *gs_description_box_new         (void);
 const gchar    *gs_description_box_get_text    (GsDescriptionBox *box);
diff --git a/src/gs-details-page.ui b/src/gs-details-page.ui
index 9a157c410..dfd120826 100644
--- a/src/gs-details-page.ui
+++ b/src/gs-details-page.ui
@@ -414,8 +414,6 @@
                                     </child>
                                     <child>
                                       <object class="GsDescriptionBox" id="box_details_description">
-                                        <property name="orientation">vertical</property>
-                                        <property name="spacing">12</property>
                                         <property name="halign">fill</property>
                                         <property name="hexpand">True</property>
                                         <property name="valign">start</property>


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