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.

Because skip paint wasn't and still isn't a GObject property,
rename it to _skipPaint to reflect that.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/153
This commit is contained in:
Georges Basile Stavracas Neto 2018-07-02 11:03:07 -03:00
parent 034a723677
commit 197c0eee29
No known key found for this signature in database
GPG Key ID: 886C17EE170D1385
3 changed files with 137 additions and 62 deletions

View File

@ -130,7 +130,7 @@ var BaseAppView = new Lang.Class({
this._childFocused(actor); this._childFocused(actor);
}); });
// Standard hack for ClutterBinLayout // Standard hack for ClutterBinLayout
this._grid.actor.x_expand = true; this._grid.x_expand = true;
this._items = {}; this._items = {};
this._allItems = []; this._allItems = [];
@ -203,7 +203,7 @@ var BaseAppView = new Lang.Class({
}, },
_doSpringAnimation(animationDirection) { _doSpringAnimation(animationDirection) {
this._grid.actor.opacity = 255; this._grid.opacity = 255;
this._grid.animateSpring(animationDirection, this._grid.animateSpring(animationDirection,
Main.overview.getShowAppsButton()); Main.overview.getShowAppsButton());
}, },
@ -217,8 +217,8 @@ var BaseAppView = new Lang.Class({
} }
if (animationDirection == IconGrid.AnimationDirection.IN) { if (animationDirection == IconGrid.AnimationDirection.IN) {
let id = this._grid.actor.connect('paint', () => { let id = this._grid.connect('paint', () => {
this._grid.actor.disconnect(id); this._grid.disconnect(id);
this._doSpringAnimation(animationDirection); this._doSpringAnimation(animationDirection);
}); });
} else { } else {
@ -228,7 +228,7 @@ var BaseAppView = new Lang.Class({
animateSwitch(animationDirection) { animateSwitch(animationDirection) {
Tweener.removeTweens(this.actor); Tweener.removeTweens(this.actor);
Tweener.removeTweens(this._grid.actor); Tweener.removeTweens(this._grid);
let params = { time: VIEWS_SWITCH_TIME, let params = { time: VIEWS_SWITCH_TIME,
transition: 'easeOutQuad' }; transition: 'easeOutQuad' };
@ -242,7 +242,7 @@ var BaseAppView = new Lang.Class({
params.onComplete = () => { this.actor.hide(); }; params.onComplete = () => { this.actor.hide(); };
} }
Tweener.addTween(this._grid.actor, params); Tweener.addTween(this._grid, params);
} }
}); });
Signals.addSignalMethods(BaseAppView.prototype); Signals.addSignalMethods(BaseAppView.prototype);
@ -396,7 +396,7 @@ var AllView = new Lang.Class({
let box = new St.BoxLayout({ vertical: true }); let box = new St.BoxLayout({ vertical: true });
this._grid.currentPage = 0; 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._eventBlocker = new St.Widget({ x_expand: true, y_expand: true });
this._stack.add_actor(this._eventBlocker); this._stack.add_actor(this._eventBlocker);
@ -745,7 +745,7 @@ var AllView = new Lang.Class({
box.y2 = height; box.y2 = height;
box = this.actor.get_theme_node().get_content_box(box); box = this.actor.get_theme_node().get_content_box(box);
box = this._scrollView.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 availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1; let availHeight = box.y2 - box.y1;
let oldNPages = this._grid.nPages(); let oldNPages = this._grid.nPages();
@ -794,9 +794,9 @@ var FrequentView = new Lang.Class({
y_align: Clutter.ActorAlign.CENTER, y_align: Clutter.ActorAlign.CENTER,
y_expand: true }); 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.actor.add_actor(this._noFrequentAppsLabel);
this._noFrequentAppsLabel.hide(); this._noFrequentAppsLabel.hide();
@ -843,7 +843,7 @@ var FrequentView = new Lang.Class({
box.x2 = width; box.x2 = width;
box.y2 = height; box.y2 = height;
box = this.actor.get_theme_node().get_content_box(box); 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 availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1; let availHeight = box.y2 - box.y1;
this._grid.adaptToSize(availWidth, availHeight); this._grid.adaptToSize(availWidth, availHeight);
@ -1141,12 +1141,12 @@ var FolderView = new Lang.Class({
this.parent(null, null); this.parent(null, null);
// If it not expand, the parent doesn't take into account its preferred_width when allocating // 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" // 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 = new St.ScrollView({ overlay_scrollbars: true });
this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
let scrollableContainer = new St.BoxLayout({ vertical: true, reactive: true }); 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); this.actor.add_actor(scrollableContainer);
let action = new Clutter.PanAction({ interpolate: true }); let action = new Clutter.PanAction({ interpolate: true });
@ -1369,7 +1369,7 @@ var FolderIcon = new Lang.Class({
_updatePopupSize() { _updatePopupSize() {
// StWidget delays style calculation until needed, make sure we use the correct values // 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) + let offsetForEachSide = Math.ceil((this._popup.getOffset(St.Side.TOP) +
this._popup.getOffset(St.Side.BOTTOM) - this._popup.getOffset(St.Side.BOTTOM) -

View File

@ -189,8 +189,16 @@ function zoomOutActor(actor) {
var IconGrid = new Lang.Class({ var IconGrid = new Lang.Class({
Name: 'IconGrid', Name: 'IconGrid',
Extends: St.Widget,
Signals: {'animation-done': {},
'child-focused': { param_types: [Clutter.Actor.$gtype]} },
_init(params) { _init(params) {
this.parent({ style_class: 'icon-grid',
y_align: Clutter.ActorAlign.START });
this.actor = this;
params = Params.parse(params, { rowLimit: null, params = Params.parse(params, { rowLimit: null,
columnLimit: null, columnLimit: null,
minRows: 1, minRows: 1,
@ -211,30 +219,23 @@ var IconGrid = new Lang.Class({
this.rightPadding = 0; this.rightPadding = 0;
this.leftPadding = 0; this.leftPadding = 0;
this.actor = new St.BoxLayout({ style_class: 'icon-grid',
vertical: true });
this._items = []; this._items = [];
this._clonesAnimating = []; this._clonesAnimating = [];
// Pulled from CSS, but hardcode some defaults here // Pulled from CSS, but hardcode some defaults here
this._spacing = 0; this._spacing = 0;
this._hItemSize = this._vItemSize = ICON_SIZE; this._hItemSize = this._vItemSize = ICON_SIZE;
this._fixedHItemSize = this._fixedVItemSize = undefined; this._fixedHItemSize = this._fixedVItemSize = undefined;
this._grid = new Shell.GenericContainer(); this.connect('style-changed', this._onStyleChanged.bind(this));
this.actor.add(this._grid, { expand: true, y_align: St.Align.START });
this.actor.connect('style-changed', this._onStyleChanged.bind(this));
// Cancel animations when hiding the overview, to avoid icons // Cancel animations when hiding the overview, to avoid icons
// swarming into the void ... // swarming into the void ...
this.actor.connect('notify::mapped', () => { this.connect('notify::mapped', () => {
if (!this.actor.mapped) if (!this.mapped)
this._cancelAnimation(); this._cancelAnimation();
}); });
this._grid.connect('get-preferred-width', this._getPreferredWidth.bind(this)); this.connect('actor-added', this._childAdded.bind(this));
this._grid.connect('get-preferred-height', this._getPreferredHeight.bind(this)); this.connect('actor-removed', this._childRemoved.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));
}, },
_keyFocusIn(actor) { _keyFocusIn(actor) {
@ -249,13 +250,13 @@ var IconGrid = new Lang.Class({
child.disconnect(child._iconGridKeyFocusInId); child.disconnect(child._iconGridKeyFocusInId);
}, },
_getPreferredWidth(grid, forHeight, alloc) { vfunc_get_preferred_width(forHeight) {
if (this._fillParent) if (this._fillParent)
// Ignore all size requests of children and request a size of 0; // Ignore all size requests of children and request a size of 0;
// later we'll allocate as many children as fit the parent // 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, let nColumns = this._colLimit ? Math.min(this._colLimit,
nChildren) nChildren)
: nChildren; : nChildren;
@ -263,22 +264,28 @@ var IconGrid = new Lang.Class({
// Kind of a lie, but not really an issue right now. If // Kind of a lie, but not really an issue right now. If
// we wanted to support some sort of hidden/overflow that would // we wanted to support some sort of hidden/overflow that would
// need higher level design // need higher level design
alloc.min_size = this._getHItemSize() + this.leftPadding + this.rightPadding; let minSize = this._getHItemSize() + this.leftPadding + this.rightPadding;
alloc.natural_size = nColumns * this._getHItemSize() + totalSpacing + 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() { _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) if (this._fillParent)
// Ignore all size requests of children and request a size of 0; // Ignore all size requests of children and request a size of 0;
// later we'll allocate as many children as fit the parent // 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 children = this._getVisibleChildren();
let nColumns; let nColumns;
forWidth = themeNode.adjust_for_width(forWidth);
if (forWidth < 0) if (forWidth < 0)
nColumns = children.length; nColumns = children.length;
else else
@ -293,16 +300,21 @@ var IconGrid = new Lang.Class({
nRows = Math.min(nRows, this._rowLimit); nRows = Math.min(nRows, this._rowLimit);
let totalSpacing = Math.max(0, nRows - 1) * this._getSpacing(); let totalSpacing = Math.max(0, nRows - 1) * this._getSpacing();
let height = nRows * this._getVItemSize() + totalSpacing + this.topPadding + this.bottomPadding; 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) { if (this._fillParent) {
// Reset the passed in box to fill the parent // Reset the passed in box to fill the parent
let parentBox = this.actor.get_parent().allocation; let parentBox = this.get_parent().allocation;
let gridBox = this.actor.get_theme_node().get_content_box(parentBox); let gridBox = themeNode.get_content_box(parentBox);
box = this._grid.get_theme_node().get_content_box(gridBox); box = themeNode.get_content_box(gridBox);
} }
let children = this._getVisibleChildren(); let children = this._getVisibleChildren();
@ -332,10 +344,10 @@ var IconGrid = new Lang.Class({
if (this._rowLimit && rowIndex >= this._rowLimit || if (this._rowLimit && rowIndex >= this._rowLimit ||
this._fillParent && childBox.y2 > availHeight - this.bottomPadding) { this._fillParent && childBox.y2 > availHeight - this.bottomPadding) {
this._grid.set_skip_paint(children[i], true); children[i]._skipPaint = true;
} else { } else {
children[i].allocate(childBox, flags); children[i].allocate(childBox, flags);
this._grid.set_skip_paint(children[i], false); children[i]._skipPaint = false;
} }
columnIndex++; 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 * Intended to be override by subclasses if they need a different
* set of items to be animated. * set of items to be animated.
@ -589,11 +661,11 @@ var IconGrid = new Lang.Class({
}, },
_onStyleChanged() { _onStyleChanged() {
let themeNode = this.actor.get_theme_node(); let themeNode = this.get_theme_node();
this._spacing = themeNode.get_length('spacing'); this._spacing = themeNode.get_length('spacing');
this._hItemSize = themeNode.get_length('-shell-grid-horizontal-item-size') || ICON_SIZE; 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._vItemSize = themeNode.get_length('-shell-grid-vertical-item-size') || ICON_SIZE;
this._grid.queue_relayout(); this.queue_relayout();
}, },
nRows(forWidth) { nRows(forWidth) {
@ -625,12 +697,12 @@ var IconGrid = new Lang.Class({
removeAll() { removeAll() {
this._items = []; this._items = [];
this._grid.remove_all_children(); this.remove_all_children();
}, },
destroyAll() { destroyAll() {
this._items = []; this._items = [];
this._grid.destroy_all_children(); this.destroy_all_children();
}, },
addItem(item, index) { addItem(item, index) {
@ -639,21 +711,21 @@ var IconGrid = new Lang.Class({
this._items.push(item); this._items.push(item);
if (index !== undefined) if (index !== undefined)
this._grid.insert_child_at_index(item.actor, index); this.insert_child_at_index(item.actor, index);
else else
this._grid.add_actor(item.actor); this.add_actor(item.actor);
}, },
removeItem(item) { removeItem(item) {
this._grid.remove_child(item.actor); this.remove_child(item.actor);
}, },
getItemAtIndex(index) { getItemAtIndex(index) {
return this._grid.get_child_at_index(index); return this.get_child_at_index(index);
}, },
visibleItemsCount() { visibleItemsCount() {
return this._grid.get_n_children() - this._grid.get_n_skip_paint(); return this.get_children().filter(c => !c._skipPaint).length;
}, },
setSpacing(spacing) { setSpacing(spacing) {
@ -739,11 +811,12 @@ var IconGrid = new Lang.Class({
} }
} }
}); });
Signals.addSignalMethods(IconGrid.prototype);
var PaginatedIconGrid = new Lang.Class({ var PaginatedIconGrid = new Lang.Class({
Name: 'PaginatedIconGrid', Name: 'PaginatedIconGrid',
Extends: IconGrid, Extends: IconGrid,
Signals: {'space-opened': {},
'space-closed': {} },
_init(params) { _init(params) {
this.parent(params); this.parent(params);
@ -754,20 +827,22 @@ var PaginatedIconGrid = new Lang.Class({
this._childrenPerPage = 0; this._childrenPerPage = 0;
}, },
_getPreferredHeight(grid, forWidth, alloc) { vfunc_get_preferred_height(forWidth) {
alloc.min_size = (this._availableHeightPerPageForItems() + this.bottomPadding + this.topPadding) * this._nPages + this._spaceBetweenPages * this._nPages; let height = (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; return [height, height];
}, },
_allocate(grid, box, flags) { vfunc_allocate(box, flags) {
if (this._childrenPerPage == 0) if (this._childrenPerPage == 0)
log('computePages() must be called before allocate(); pagination will not work.'); log('computePages() must be called before allocate(); pagination will not work.');
this.set_allocation(box, flags);
if (this._fillParent) { if (this._fillParent) {
// Reset the passed in box to fill the parent // Reset the passed in box to fill the parent
let parentBox = this.actor.get_parent().allocation; let parentBox = this.get_parent().allocation;
let gridBox = this.actor.get_theme_node().get_content_box(parentBox); let gridBox = this.get_theme_node().get_content_box(parentBox);
box = this._grid.get_theme_node().get_content_box(gridBox); box = this.get_theme_node().get_content_box(gridBox);
} }
let children = this._getVisibleChildren(); let children = this._getVisibleChildren();
let availWidth = box.x2 - box.x1; let availWidth = box.x2 - box.x1;
@ -795,7 +870,7 @@ var PaginatedIconGrid = new Lang.Class({
for (let i = 0; i < children.length; i++) { for (let i = 0; i < children.length; i++) {
let childBox = this._calculateChildBox(children[i], x, y, box); let childBox = this._calculateChildBox(children[i], x, y, box);
children[i].allocate(childBox, flags); children[i].allocate(childBox, flags);
this._grid.set_skip_paint(children[i], false); children[i]._skipPaint = false;
columnIndex++; columnIndex++;
if (columnIndex == nColumns) { if (columnIndex == nColumns) {
@ -966,4 +1041,3 @@ var PaginatedIconGrid = new Lang.Class({
} }
} }
}); });
Signals.addSignalMethods(PaginatedIconGrid.prototype);

View File

@ -363,8 +363,9 @@ var GridSearchResults = new Lang.Class({
this._grid = new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS, this._grid = new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS,
xAlign: St.Align.START }); xAlign: St.Align.START });
this._bin = new St.Bin({ x_align: St.Align.MIDDLE }); 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); this._resultDisplayBin.set_child(this._bin);
}, },