[gnome-software/wip/feature-tile-narrow-mode] gs-feature-tile: Correct narrow mode switch on width change



commit 10452136cfe3e148c3628cb58723c97f37fe9b4d
Author: Milan Crha <mcrha redhat com>
Date:   Wed Feb 23 18:03:30 2022 +0100

    gs-feature-tile: Correct narrow mode switch on width change
    
    The GtkButton::size_allocate() is not called at all, thus the narrow
    mode switch did not work. The way to do it in gtk4 is to use a GtkLayoutManager.
    Unfortunately, the GtkBinLayout is not a derivable type, thus this copies
    it into the sources and adds the narrow mode code into the allocate()
    method.

 src/gs-feature-tile.c | 136 ++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 111 insertions(+), 25 deletions(-)
---
diff --git a/src/gs-feature-tile.c b/src/gs-feature-tile.c
index 0baf10bf9..7501b940d 100644
--- a/src/gs-feature-tile.c
+++ b/src/gs-feature-tile.c
@@ -29,8 +29,113 @@ struct _GsFeatureTile
        GtkCssProvider  *subtitle_provider;  /* (owned) (nullable) */
        GArray          *key_colors_cache;  /* (unowned) (nullable) */
        gboolean         narrow_mode;
+       guint            refresh_id;
 };
 
+#define GS_TYPE_BIN_LAYOUT (gs_bin_layout_get_type ())
+
+G_DECLARE_FINAL_TYPE (GsBinLayout, gs_bin_layout, GS, BIN_LAYOUT, GtkLayoutManager)
+
+/* This is a copy of GtkBitLayout, because cannot derive from it */
+struct _GsBinLayout
+{
+       GtkLayoutManager parent_instance;
+};
+
+G_DEFINE_TYPE (GsBinLayout, gs_bin_layout, GTK_TYPE_LAYOUT_MANAGER)
+
+static void
+gs_bin_layout_measure (GtkLayoutManager *layout_manager,
+                      GtkWidget        *widget,
+                      GtkOrientation    orientation,
+                      int               for_size,
+                      int              *minimum,
+                      int              *natural,
+                      int              *minimum_baseline,
+                      int              *natural_baseline)
+{
+       GtkWidget *child;
+
+       for (child = gtk_widget_get_first_child (widget);
+            child != NULL;
+            child = gtk_widget_get_next_sibling (child)) {
+               if (gtk_widget_should_layout (child)) {
+                       int child_min = 0;
+                       int child_nat = 0;
+                       int child_min_baseline = -1;
+                       int child_nat_baseline = -1;
+
+                       gtk_widget_measure (child, orientation, for_size,
+                                           &child_min, &child_nat,
+                                           &child_min_baseline, &child_nat_baseline);
+
+                       *minimum = MAX (*minimum, child_min);
+                       *natural = MAX (*natural, child_nat);
+
+                       if (child_min_baseline > -1)
+                               *minimum_baseline = MAX (*minimum_baseline, child_min_baseline);
+                       if (child_nat_baseline > -1)
+                               *natural_baseline = MAX (*natural_baseline, child_nat_baseline);
+               }
+       }
+}
+
+static void gs_feature_tile_refresh (GsAppTile *self);
+
+static gboolean
+gs_feature_tile_refresh_idle_cb (gpointer user_data)
+{
+       GsFeatureTile *tile = user_data;
+
+       tile->refresh_id = 0;
+
+       gs_feature_tile_refresh (GS_APP_TILE (tile));
+
+       return G_SOURCE_REMOVE;
+}
+
+static void
+gs_bin_layout_allocate (GtkLayoutManager *layout_manager,
+                       GtkWidget        *widget,
+                       int               width,
+                       int               height,
+                       int               baseline)
+{
+       GsFeatureTile *tile = GS_FEATURE_TILE (widget);
+       GtkWidget *child;
+       gboolean narrow_mode;
+
+       for (child = gtk_widget_get_first_child (widget);
+            child != NULL;
+            child = gtk_widget_get_next_sibling (child)) {
+               if (child && gtk_widget_should_layout (child))
+                       gtk_widget_allocate (child, width, height, baseline, NULL);
+       }
+
+       /* Engage ‘narrow mode’ if the allocation becomes too narrow. The exact
+        * choice of width is arbitrary here. */
+       narrow_mode = (width < 600);
+       if (tile->narrow_mode != narrow_mode) {
+               tile->narrow_mode = narrow_mode;
+               if (!tile->refresh_id)
+                       tile->refresh_id = g_idle_add (gs_feature_tile_refresh_idle_cb, tile);
+       }
+}
+
+static void
+gs_bin_layout_class_init (GsBinLayoutClass *klass)
+{
+       GtkLayoutManagerClass *layout_manager_class = GTK_LAYOUT_MANAGER_CLASS (klass);
+
+       layout_manager_class->measure = gs_bin_layout_measure;
+       layout_manager_class->allocate = gs_bin_layout_allocate;
+}
+
+static void
+gs_bin_layout_init (GsBinLayout *layout)
+{
+}
+
 /* A colour represented in hue, saturation, brightness form; with an additional
  * field for its contrast calculated with respect to some external colour.
  *
@@ -50,6 +155,11 @@ gs_feature_tile_dispose (GObject *object)
 {
        GsFeatureTile *tile = GS_FEATURE_TILE (object);
 
+       if (tile->refresh_id) {
+               g_source_remove (tile->refresh_id);
+               tile->refresh_id = 0;
+       }
+
        g_clear_object (&tile->tile_provider);
        g_clear_object (&tile->title_provider);
        g_clear_object (&tile->subtitle_provider);
@@ -440,30 +550,6 @@ gs_feature_tile_css_changed (GtkWidget         *widget,
        GTK_WIDGET_CLASS (gs_feature_tile_parent_class)->css_changed (widget, css_change);
 }
 
-static void
-gs_feature_tile_size_allocate (GtkWidget *widget,
-                               gint       width,
-                               gint       height,
-                               gint       baseline)
-{
-       GsFeatureTile *tile = GS_FEATURE_TILE (widget);
-       gboolean narrow_mode;
-
-       /* Chain up. */
-       GTK_WIDGET_CLASS (gs_feature_tile_parent_class)->size_allocate (widget,
-                                                                       width,
-                                                                       height,
-                                                                       baseline);
-
-       /* Engage ‘narrow mode’ if the allocation becomes too narrow. The exact
-        * choice of width is arbitrary here. */
-       narrow_mode = (width < 600);
-       if (tile->narrow_mode != narrow_mode) {
-               tile->narrow_mode = narrow_mode;
-               gs_feature_tile_refresh (GS_APP_TILE (tile));
-       }
-}
-
 static void
 gs_feature_tile_init (GsFeatureTile *tile)
 {
@@ -481,7 +567,6 @@ gs_feature_tile_class_init (GsFeatureTileClass *klass)
 
        widget_class->css_changed = gs_feature_tile_css_changed;
        widget_class->direction_changed = gs_feature_tile_direction_changed;
-       widget_class->size_allocate = gs_feature_tile_size_allocate;
 
        app_tile_class->refresh = gs_feature_tile_refresh;
 
@@ -493,6 +578,7 @@ gs_feature_tile_class_init (GsFeatureTileClass *klass)
        gtk_widget_class_bind_template_child (widget_class, GsFeatureTile, subtitle);
 
        gtk_widget_class_set_css_name (widget_class, "feature-tile");
+       gtk_widget_class_set_layout_manager_type (widget_class, GS_TYPE_BIN_LAYOUT);
 }
 
 GtkWidget *


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