iconGrid: Cache visible children of pages

We need to access the visible children of a page in inside
vfunc_allocate(), and since getting those children is quite slow (it
involves iterating over all the children of the actor) let's avoid that
and cache the array instead.

This reduces average time spent in vfunc_allocate() of the iconGrid from
1.6 ms down to 1.4 ms.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1713>
This commit is contained in:
Jonas Dreßler 2021-02-23 19:52:46 +01:00 committed by Marge Bot
parent b3c46a33c0
commit 8e93806453

View File

@ -437,8 +437,9 @@ var IconGridLayout = GObject.registerClass({
return this._childrenMaxSize; return this._childrenMaxSize;
} }
_getVisibleChildrenForPage(pageIndex) { _updateVisibleChildrenForPage(pageIndex) {
return this._pages[pageIndex].children.filter(actor => actor.visible); this._pages[pageIndex].visibleChildren =
this._pages[pageIndex].children.filter(actor => actor.visible);
} }
_updatePages() { _updatePages() {
@ -476,14 +477,14 @@ var IconGridLayout = GObject.registerClass({
if (pageIndex >= this._pages.length - 1) if (pageIndex >= this._pages.length - 1)
return; return;
const visiblePageItems = this._getVisibleChildrenForPage(pageIndex); const visiblePageItems = this._pages[pageIndex].visibleChildren;
const itemsPerPage = this.columnsPerPage * this.rowsPerPage; const itemsPerPage = this.columnsPerPage * this.rowsPerPage;
// No reduce needed // No reduce needed
if (visiblePageItems.length === itemsPerPage) if (visiblePageItems.length === itemsPerPage)
return; return;
const visibleNextPageItems = this._getVisibleChildrenForPage(pageIndex + 1); const visibleNextPageItems = this._pages[pageIndex + 1].visibleChildren;
const nMissingItems = Math.min(itemsPerPage - visiblePageItems.length, visibleNextPageItems.length); const nMissingItems = Math.min(itemsPerPage - visiblePageItems.length, visibleNextPageItems.length);
// Append to the current page the first items of the next page // Append to the current page the first items of the next page
@ -505,8 +506,10 @@ var IconGridLayout = GObject.registerClass({
page.children.splice(itemIndex, 1); page.children.splice(itemIndex, 1);
this._updateVisibleChildrenForPage(pageIndex);
// Delete the page if this is the last icon in it // Delete the page if this is the last icon in it
const visibleItems = this._getVisibleChildrenForPage(pageIndex); const visibleItems = this._pages[pageIndex].visibleChildren;
if (visibleItems.length === 0) if (visibleItems.length === 0)
this._removePage(pageIndex); this._removePage(pageIndex);
@ -515,7 +518,7 @@ var IconGridLayout = GObject.registerClass({
} }
_relocateSurplusItems(pageIndex) { _relocateSurplusItems(pageIndex) {
const visiblePageItems = this._getVisibleChildrenForPage(pageIndex); const visiblePageItems = this._pages[pageIndex].visibleChildren;
const itemsPerPage = this.columnsPerPage * this.rowsPerPage; const itemsPerPage = this.columnsPerPage * this.rowsPerPage;
// No overflow needed // No overflow needed
@ -559,6 +562,8 @@ var IconGridLayout = GObject.registerClass({
visibleId: item.connect('notify::visible', () => { visibleId: item.connect('notify::visible', () => {
const itemData = this._items.get(item); const itemData = this._items.get(item);
this._updateVisibleChildrenForPage(itemData.pageIndex);
if (item.visible) if (item.visible)
this._relocateSurplusItems(itemData.pageIndex); this._relocateSurplusItems(itemData.pageIndex);
else if (!this.allowIncompletePages) else if (!this.allowIncompletePages)
@ -572,6 +577,7 @@ var IconGridLayout = GObject.registerClass({
item.icon.setIconSize(this._iconSize); item.icon.setIconSize(this._iconSize);
this._pages[pageIndex].children.splice(index, 0, item); this._pages[pageIndex].children.splice(index, 0, item);
this._updateVisibleChildrenForPage(pageIndex);
this._relocateSurplusItems(pageIndex); this._relocateSurplusItems(pageIndex);
} }
@ -779,21 +785,18 @@ var IconGridLayout = GObject.registerClass({
let nChangedIcons = 0; let nChangedIcons = 0;
this._pages.forEach((page, pageIndex) => { this._pages.forEach((page, pageIndex) => {
const visibleItems =
page.children.filter(actor => actor.visible);
if (isRtl && this._orientation === Clutter.Orientation.HORIZONTAL) if (isRtl && this._orientation === Clutter.Orientation.HORIZONTAL)
pageIndex = swap(pageIndex, this._pages.length); pageIndex = swap(pageIndex, this._pages.length);
visibleItems.forEach((item, itemIndex) => { page.visibleChildren.forEach((item, itemIndex) => {
const row = Math.floor(itemIndex / this.columnsPerPage); const row = Math.floor(itemIndex / this.columnsPerPage);
let column = itemIndex % this.columnsPerPage; let column = itemIndex % this.columnsPerPage;
if (isRtl) if (isRtl)
column = swap(column, this.columnsPerPage); column = swap(column, this.columnsPerPage);
const rowPadding = this._getRowPadding(visibleItems, itemIndex, const rowPadding = this._getRowPadding(page.visibleChildren,
childSize, hSpacing); itemIndex, childSize, hSpacing);
// Icon position // Icon position
let x = leftEmptySpace + rowPadding + column * (childSize + hSpacing); let x = leftEmptySpace + rowPadding + column * (childSize + hSpacing);
@ -929,7 +932,7 @@ var IconGridLayout = GObject.registerClass({
return [-1, -1]; return [-1, -1];
const itemData = this._items.get(item); const itemData = this._items.get(item);
const visibleItems = this._getVisibleChildrenForPage(itemData.pageIndex); const visibleItems = this._pages[itemData.pageIndex].visibleChildren;
return [itemData.pageIndex, visibleItems.indexOf(item)]; return [itemData.pageIndex, visibleItems.indexOf(item)];
} }
@ -947,7 +950,7 @@ var IconGridLayout = GObject.registerClass({
if (page < 0 || page >= this._pages.length) if (page < 0 || page >= this._pages.length)
return null; return null;
const visibleItems = this._getVisibleChildrenForPage(page); const visibleItems = this._pages[page].visibleChildren;
if (position < 0 || position >= visibleItems.length) if (position < 0 || position >= visibleItems.length)
return null; return null;
@ -1056,7 +1059,7 @@ var IconGridLayout = GObject.registerClass({
const halfHSpacing = hSpacing / 2; const halfHSpacing = hSpacing / 2;
const halfVSpacing = vSpacing / 2; const halfVSpacing = vSpacing / 2;
const visibleItems = this._getVisibleChildrenForPage(page); const visibleItems = this._pages[page].visibleChildren;
for (const item of visibleItems) { for (const item of visibleItems) {
const childBox = item.allocation.copy(); const childBox = item.allocation.copy();