[gnome-shell/gbsneto/remove-generic-container: 7/25] iconGrid: Stop using Shell.GenericContainer



commit d45081f1144776ba1cc996449446bfb077d7acfe
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Mon Jul 2 11:03:07 2018 -0300

    iconGrid: Stop using Shell.GenericContainer
    
    Removing Shell.GenericContainer from the IconGrid class was
    challenging because it needs the "skip paint" API from it.
    This API was added, too, as a workaround to the inability
    to override vfuncs from GJS.
    
    The overrides are largely copy-pasted and translated versions
    of the Shell.GenericContainer code.
    
    The IconGrid:key-focus-in signal was renamed to :child-focused
    to avoid clashing with ClutterActor:key-focus-in.
    
    In GridSearchResults, the internal IconGrid had it's y_expand
    set to false, so it doesn't push other search elements (the
    list results mainly) to the bottom of the screen.
    
    https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/153
    
    Because skip paint wasn't and still isn't a GObject property,
    rename it ti _skipPaint to reflect that.
    
    https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/153

 js/ui/appDisplay.js |  28 ++++-----
 js/ui/iconGrid.js   | 168 +++++++++++++++++++++++++++++++++++++---------------
 js/ui/search.js     |   3 +-
 3 files changed, 137 insertions(+), 62 deletions(-)
---
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index 9d648c92e..6f67127c4 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -130,7 +130,7 @@ var BaseAppView = new Lang.Class({
             this._childFocused(actor);
         });
         // Standard hack for ClutterBinLayout
-        this._grid.actor.x_expand = true;
+        this._grid.x_expand = true;
 
         this._items = {};
         this._allItems = [];
@@ -203,7 +203,7 @@ var BaseAppView = new Lang.Class({
     },
 
     _doSpringAnimation(animationDirection) {
-        this._grid.actor.opacity = 255;
+        this._grid.opacity = 255;
         this._grid.animateSpring(animationDirection,
                                  Main.overview.getShowAppsButton());
     },
@@ -217,8 +217,8 @@ var BaseAppView = new Lang.Class({
         }
 
         if (animationDirection == IconGrid.AnimationDirection.IN) {
-            let id = this._grid.actor.connect('paint', () => {
-                this._grid.actor.disconnect(id);
+            let id = this._grid.connect('paint', () => {
+                this._grid.disconnect(id);
                 this._doSpringAnimation(animationDirection);
             });
         } else {
@@ -228,7 +228,7 @@ var BaseAppView = new Lang.Class({
 
     animateSwitch(animationDirection) {
         Tweener.removeTweens(this.actor);
-        Tweener.removeTweens(this._grid.actor);
+        Tweener.removeTweens(this._grid);
 
         let params = { time: VIEWS_SWITCH_TIME,
                        transition: 'easeOutQuad' };
@@ -242,7 +242,7 @@ var BaseAppView = new Lang.Class({
             params.onComplete = () => { this.actor.hide(); };
         }
 
-        Tweener.addTween(this._grid.actor, params);
+        Tweener.addTween(this._grid, params);
     }
 });
 Signals.addSignalMethods(BaseAppView.prototype);
@@ -396,7 +396,7 @@ var AllView = new Lang.Class({
         let box = new St.BoxLayout({ vertical: true });
 
         this._grid.currentPage = 0;
-        this._stack.add_actor(this._grid.actor);
+        this._stack.add_actor(this._grid);
         this._eventBlocker = new St.Widget({ x_expand: true, y_expand: true });
         this._stack.add_actor(this._eventBlocker);
 
@@ -745,7 +745,7 @@ var AllView = new Lang.Class({
         box.y2 = height;
         box = this.actor.get_theme_node().get_content_box(box);
         box = this._scrollView.get_theme_node().get_content_box(box);
-        box = this._grid.actor.get_theme_node().get_content_box(box);
+        box = this._grid.get_theme_node().get_content_box(box);
         let availWidth = box.x2 - box.x1;
         let availHeight = box.y2 - box.y1;
         let oldNPages = this._grid.nPages();
@@ -794,9 +794,9 @@ var FrequentView = new Lang.Class({
                                                    y_align: Clutter.ActorAlign.CENTER,
                                                    y_expand: true });
 
-        this._grid.actor.y_expand = true;
+        this._grid.y_expand = true;
 
-        this.actor.add_actor(this._grid.actor);
+        this.actor.add_actor(this._grid);
         this.actor.add_actor(this._noFrequentAppsLabel);
         this._noFrequentAppsLabel.hide();
 
@@ -843,7 +843,7 @@ var FrequentView = new Lang.Class({
         box.x2 = width;
         box.y2 = height;
         box = this.actor.get_theme_node().get_content_box(box);
-        box = this._grid.actor.get_theme_node().get_content_box(box);
+        box = this._grid.get_theme_node().get_content_box(box);
         let availWidth = box.x2 - box.x1;
         let availHeight = box.y2 - box.y1;
         this._grid.adaptToSize(availWidth, availHeight);
@@ -1141,12 +1141,12 @@ var FolderView = new Lang.Class({
         this.parent(null, null);
         // If it not expand, the parent doesn't take into account its preferred_width when allocating
         // the second time it allocates, so we apply the "Standard hack for ClutterBinLayout"
-        this._grid.actor.x_expand = true;
+        this._grid.x_expand = true;
 
         this.actor = new St.ScrollView({ overlay_scrollbars: true });
         this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
         let scrollableContainer = new St.BoxLayout({ vertical: true, reactive: true });
-        scrollableContainer.add_actor(this._grid.actor);
+        scrollableContainer.add_actor(this._grid);
         this.actor.add_actor(scrollableContainer);
 
         let action = new Clutter.PanAction({ interpolate: true });
@@ -1369,7 +1369,7 @@ var FolderIcon = new Lang.Class({
 
     _updatePopupSize() {
         // StWidget delays style calculation until needed, make sure we use the correct values
-        this.view._grid.actor.ensure_style();
+        this.view._grid.ensure_style();
 
         let offsetForEachSide = Math.ceil((this._popup.getOffset(St.Side.TOP) +
                                            this._popup.getOffset(St.Side.BOTTOM) -
diff --git a/js/ui/iconGrid.js b/js/ui/iconGrid.js
index a0d008386..cbfeb05f4 100644
--- a/js/ui/iconGrid.js
+++ b/js/ui/iconGrid.js
@@ -189,8 +189,16 @@ function zoomOutActor(actor) {
 
 var IconGrid = new Lang.Class({
     Name: 'IconGrid',
+    Extends: St.Widget,
+    Signals: {'animation-done': {},
+              'child-focused': { param_types: [Clutter.Actor.$gtype]} },
 
     _init(params) {
+        this.parent({ style_class: 'icon-grid',
+                      y_align: Clutter.ActorAlign.START });
+
+        this.actor = this;
+
         params = Params.parse(params, { rowLimit: null,
                                         columnLimit: null,
                                         minRows: 1,
@@ -211,30 +219,23 @@ var IconGrid = new Lang.Class({
         this.rightPadding = 0;
         this.leftPadding = 0;
 
-        this.actor = new St.BoxLayout({ style_class: 'icon-grid',
-                                        vertical: true });
         this._items = [];
         this._clonesAnimating = [];
         // Pulled from CSS, but hardcode some defaults here
         this._spacing = 0;
         this._hItemSize = this._vItemSize = ICON_SIZE;
         this._fixedHItemSize = this._fixedVItemSize = undefined;
-        this._grid = new Shell.GenericContainer();
-        this.actor.add(this._grid, { expand: true, y_align: St.Align.START });
-        this.actor.connect('style-changed', this._onStyleChanged.bind(this));
+        this.connect('style-changed', this._onStyleChanged.bind(this));
 
         // Cancel animations when hiding the overview, to avoid icons
         // swarming into the void ...
-        this.actor.connect('notify::mapped', () => {
-            if (!this.actor.mapped)
+        this.connect('notify::mapped', () => {
+            if (!this.mapped)
                 this._cancelAnimation();
         });
 
-        this._grid.connect('get-preferred-width', this._getPreferredWidth.bind(this));
-        this._grid.connect('get-preferred-height', this._getPreferredHeight.bind(this));
-        this._grid.connect('allocate', this._allocate.bind(this));
-        this._grid.connect('actor-added', this._childAdded.bind(this));
-        this._grid.connect('actor-removed', this._childRemoved.bind(this));
+        this.connect('actor-added', this._childAdded.bind(this));
+        this.connect('actor-removed', this._childRemoved.bind(this));
     },
 
     _keyFocusIn(actor) {
@@ -249,13 +250,13 @@ var IconGrid = new Lang.Class({
         child.disconnect(child._iconGridKeyFocusInId);
     },
 
-    _getPreferredWidth(grid, forHeight, alloc) {
+    vfunc_get_preferred_width(forHeight) {
         if (this._fillParent)
             // Ignore all size requests of children and request a size of 0;
             // later we'll allocate as many children as fit the parent
-            return;
+            return [0, 0];
 
-        let nChildren = this._grid.get_n_children();
+        let nChildren = this.get_n_children();
         let nColumns = this._colLimit ? Math.min(this._colLimit,
                                                  nChildren)
                                       : nChildren;
@@ -263,22 +264,28 @@ var IconGrid = new Lang.Class({
         // Kind of a lie, but not really an issue right now.  If
         // we wanted to support some sort of hidden/overflow that would
         // need higher level design
-        alloc.min_size = this._getHItemSize() + this.leftPadding + this.rightPadding;
-        alloc.natural_size = nColumns * this._getHItemSize() + totalSpacing + this.leftPadding + 
this.rightPadding;
+        let minSize = this._getHItemSize() + this.leftPadding + this.rightPadding;
+        let natSize = nColumns * this._getHItemSize() + totalSpacing + this.leftPadding + this.rightPadding;
+
+        return this.get_theme_node().adjust_preferred_width(minSize, natSize);
     },
 
     _getVisibleChildren() {
-        return this._grid.get_children().filter(actor => actor.visible);
+        return this.get_children().filter(actor => actor.visible);
     },
 
-    _getPreferredHeight(grid, forWidth, alloc) {
+    vfunc_get_preferred_height(forWidth) {
         if (this._fillParent)
             // Ignore all size requests of children and request a size of 0;
             // later we'll allocate as many children as fit the parent
-            return;
+            return [0, 0];
 
+        let themeNode = this.get_theme_node();
         let children = this._getVisibleChildren();
         let nColumns;
+
+        forWidth = themeNode.adjust_for_width(forWidth);
+
         if (forWidth < 0)
             nColumns = children.length;
         else
@@ -293,16 +300,21 @@ var IconGrid = new Lang.Class({
             nRows = Math.min(nRows, this._rowLimit);
         let totalSpacing = Math.max(0, nRows - 1) * this._getSpacing();
         let height = nRows * this._getVItemSize() + totalSpacing + this.topPadding + this.bottomPadding;
-        alloc.min_size = height;
-        alloc.natural_size = height;
+
+        return themeNode.adjust_preferred_height(height, height);
     },
 
-    _allocate(grid, box, flags) {
+    vfunc_allocate(box, flags) {
+        this.set_allocation(box, flags);
+
+        let themeNode = this.get_theme_node();
+        box = themeNode.get_content_box(box);
+
         if (this._fillParent) {
             // Reset the passed in box to fill the parent
-            let parentBox = this.actor.get_parent().allocation;
-            let gridBox = this.actor.get_theme_node().get_content_box(parentBox);
-            box = this._grid.get_theme_node().get_content_box(gridBox);
+            let parentBox = this.get_parent().allocation;
+            let gridBox = themeNode.get_content_box(parentBox);
+            box = themeNode.get_content_box(gridBox);
         }
 
         let children = this._getVisibleChildren();
@@ -332,10 +344,10 @@ var IconGrid = new Lang.Class({
 
             if (this._rowLimit && rowIndex >= this._rowLimit ||
                 this._fillParent && childBox.y2 > availHeight - this.bottomPadding) {
-                this._grid.set_skip_paint(children[i], true);
+                children[i]._skipPaint = true;
             } else {
                 children[i].allocate(childBox, flags);
-                this._grid.set_skip_paint(children[i], false);
+                children[i]._skipPaint = false;
             }
 
             columnIndex++;
@@ -353,6 +365,66 @@ var IconGrid = new Lang.Class({
         }
     },
 
+    vfunc_paint() {
+        this.paint_background();
+
+        this.get_children().forEach(c => {
+            if (!c._skipPaint)
+                c.paint();
+        });
+    },
+
+    vfunc_pick(color) {
+        this.parent(color);
+
+        this.get_children().forEach(c => {
+            if (!c._skipPaint)
+                c.paint();
+        });
+    },
+
+    vfunc_get_paint_volume(paintVolume) {
+        // Setting the paint volume does not make sense when we don't have
+        // any allocation
+        if (!this.has_allocation())
+            return false;
+
+        let themeNode = this.get_theme_node();
+        let allocationBox = this.get_allocation_box();
+        let paintBox = themeNode.get_paint_box(allocationBox);
+
+        let origin = new Clutter.Vertex();
+        origin.x = paintBox.x1 - allocationBox.x1;
+        origin.y = paintBox.y1 - allocationBox.y1;
+        origin.z = 0.0;
+
+        paintVolume.set_origin(origin);
+        paintVolume.set_width(paintBox.x2 - paintBox.x1);
+        paintVolume.set_height(paintBox.y2 - paintBox.y1);
+
+        if (this.get_clip_to_allocation())
+            return true;
+
+        for (let child = this.get_first_child();
+             child != null;
+             child = child.get_next_sibling()) {
+
+            if (!child.visible)
+                continue;
+
+            if (child._skipPaint)
+                continue;
+
+            let childVolume = child.get_transformed_paint_volume(this);
+            if (!childVolume)
+                return false
+
+            paintVolume.union(childVolume);
+        }
+
+        return true;
+    },
+
     /**
      * Intended to be override by subclasses if they need a different
      * set of items to be animated.
@@ -589,11 +661,11 @@ var IconGrid = new Lang.Class({
     },
 
     _onStyleChanged() {
-        let themeNode = this.actor.get_theme_node();
+        let themeNode = this.get_theme_node();
         this._spacing = themeNode.get_length('spacing');
         this._hItemSize = themeNode.get_length('-shell-grid-horizontal-item-size') || ICON_SIZE;
         this._vItemSize = themeNode.get_length('-shell-grid-vertical-item-size') || ICON_SIZE;
-        this._grid.queue_relayout();
+        this.queue_relayout();
     },
 
     nRows(forWidth) {
@@ -625,12 +697,12 @@ var IconGrid = new Lang.Class({
 
     removeAll() {
         this._items = [];
-        this._grid.remove_all_children();
+        this.remove_all_children();
     },
 
     destroyAll() {
         this._items = [];
-        this._grid.destroy_all_children();
+        this.destroy_all_children();
     },
 
     addItem(item, index) {
@@ -639,21 +711,21 @@ var IconGrid = new Lang.Class({
 
         this._items.push(item);
         if (index !== undefined)
-            this._grid.insert_child_at_index(item.actor, index);
+            this.insert_child_at_index(item.actor, index);
         else
-            this._grid.add_actor(item.actor);
+            this.add_actor(item.actor);
     },
 
     removeItem(item) {
-        this._grid.remove_child(item.actor);
+        this.remove_child(item.actor);
     },
 
     getItemAtIndex(index) {
-        return this._grid.get_child_at_index(index);
+        return this.get_child_at_index(index);
     },
 
     visibleItemsCount() {
-        return this._grid.get_n_children() - this._grid.get_n_skip_paint();
+        return this.get_children().filter(c => !c._skipPaint).length;
     },
 
     setSpacing(spacing) {
@@ -739,11 +811,12 @@ var IconGrid = new Lang.Class({
         }
     }
 });
-Signals.addSignalMethods(IconGrid.prototype);
 
 var PaginatedIconGrid = new Lang.Class({
     Name: 'PaginatedIconGrid',
     Extends: IconGrid,
+    Signals: {'space-opened': {},
+              'space-closed': {} },
 
     _init(params) {
         this.parent(params);
@@ -754,20 +827,22 @@ var PaginatedIconGrid = new Lang.Class({
         this._childrenPerPage = 0;
     },
 
-    _getPreferredHeight(grid, forWidth, alloc) {
-        alloc.min_size = (this._availableHeightPerPageForItems() + this.bottomPadding + this.topPadding) * 
this._nPages + this._spaceBetweenPages * this._nPages;
-        alloc.natural_size = (this._availableHeightPerPageForItems() + this.bottomPadding + this.topPadding) 
* this._nPages + this._spaceBetweenPages * this._nPages;
+    vfunc_get_preferred_height(forWidth) {
+        let height = (this._availableHeightPerPageForItems() + this.bottomPadding + this.topPadding) * 
this._nPages + this._spaceBetweenPages * this._nPages;
+        return [height, height];
     },
 
-    _allocate(grid, box, flags) {
+    vfunc_allocate(box, flags) {
          if (this._childrenPerPage == 0)
             log('computePages() must be called before allocate(); pagination will not work.');
 
+        this.set_allocation(box, flags);
+
         if (this._fillParent) {
             // Reset the passed in box to fill the parent
-            let parentBox = this.actor.get_parent().allocation;
-            let gridBox = this.actor.get_theme_node().get_content_box(parentBox);
-            box = this._grid.get_theme_node().get_content_box(gridBox);
+            let parentBox = this.get_parent().allocation;
+            let gridBox = this.get_theme_node().get_content_box(parentBox);
+            box = this.get_theme_node().get_content_box(gridBox);
         }
         let children = this._getVisibleChildren();
         let availWidth = box.x2 - box.x1;
@@ -795,7 +870,7 @@ var PaginatedIconGrid = new Lang.Class({
         for (let i = 0; i < children.length; i++) {
             let childBox = this._calculateChildBox(children[i], x, y, box);
             children[i].allocate(childBox, flags);
-            this._grid.set_skip_paint(children[i], false);
+            children[i]._skipPaint = false;
 
             columnIndex++;
             if (columnIndex == nColumns) {
@@ -966,4 +1041,3 @@ var PaginatedIconGrid = new Lang.Class({
         }
     }
 });
-Signals.addSignalMethods(PaginatedIconGrid.prototype);
diff --git a/js/ui/search.js b/js/ui/search.js
index 97e18c058..4adf50217 100644
--- a/js/ui/search.js
+++ b/js/ui/search.js
@@ -363,8 +363,9 @@ var GridSearchResults = new Lang.Class({
 
         this._grid = new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS,
                                              xAlign: St.Align.START });
+
         this._bin = new St.Bin({ x_align: St.Align.MIDDLE });
-        this._bin.set_child(this._grid.actor);
+        this._bin.set_child(this._grid);
 
         this._resultDisplayBin.set_child(this._bin);
     },


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