Blame SOURCES/fix-app-view-leaks.patch

441107
From a518c9f57e5fe9c6b5ece5c6cb0534a83f0b2f2d Mon Sep 17 00:00:00 2001
441107
From: Ray Strode <rstrode@redhat.com>
441107
Date: Mon, 15 Jul 2019 13:52:58 -0400
441107
Subject: [PATCH 1/8] appDisplay: Don't leak duplicate items in AppView
441107
441107
If an icon already exists in an app view with the same id, the
441107
duplicate is not added on a call to addItem.  Unfortunately,
441107
since it's not added, the icon actor gets orphaned and leaked.
441107
441107
This commit address the problem by introducing a new hasItem
441107
method and disallowing callers to call addItem with a duplicate
441107
in the first place.
441107
441107
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/628
441107
---
441107
 js/ui/appDisplay.js | 15 ++++++++++++---
441107
 1 file changed, 12 insertions(+), 3 deletions(-)
441107
441107
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
441107
index a07db6573..fa22f47e0 100644
441107
--- a/js/ui/appDisplay.js
441107
+++ b/js/ui/appDisplay.js
441107
@@ -143,10 +143,14 @@ class BaseAppView {
441107
         return this._allItems;
441107
     }
441107
 
441107
+    hasItem(id) {
441107
+        return this._items[id] !== undefined;
441107
+    }
441107
+
441107
     addItem(icon) {
441107
         let id = icon.id;
441107
-        if (this._items[id] !== undefined)
441107
-            return;
441107
+	if (this.hasItem(id))
441107
+            throw new Error(`icon with id ${id} already added to view`)
441107
 
441107
         this._allItems.push(icon);
441107
         this._items[id] = icon;
441107
@@ -386,6 +390,8 @@ var AllView = class AllView extends BaseAppView {
441107
 
441107
         let folders = this._folderSettings.get_strv('folder-children');
441107
         folders.forEach(id => {
441107
+            if (this.hasItem(id))
441107
+                return;
441107
             let path = this._folderSettings.path + 'folders/' + id + '/';
441107
             let icon = new FolderIcon(id, path, this);
441107
             icon.connect('name-changed', this._itemNameChanged.bind(this));
441107
@@ -1165,7 +1171,10 @@ var FolderIcon = class FolderIcon {
441107
         let excludedApps = this._folder.get_strv('excluded-apps');
441107
         let appSys = Shell.AppSystem.get_default();
441107
         let addAppId = appId => {
441107
-            if (excludedApps.indexOf(appId) >= 0)
441107
+            if (this.view.hasItem(appId))
441107
+                return;
441107
+
441107
+            if (excludedApps.includes(appId))
441107
                 return;
441107
 
441107
             let app = appSys.lookup_app(appId);
441107
-- 
441107
2.23.0
441107
441107
441107
From 2b6aa9aed98c4854c2ad015879ddcb8d2bf91e9e Mon Sep 17 00:00:00 2001
441107
From: Ray Strode <rstrode@redhat.com>
441107
Date: Mon, 22 Jul 2019 11:06:30 -0400
441107
Subject: [PATCH 2/8] iconGrid: Clear meta_later callback on destruction
441107
441107
The IconGrid code sometimes sets up a callback to be invoked
441107
later right before being destroyed.
441107
441107
This commit adds a destroy handler to cancel the callback.
441107
441107
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/628
441107
---
441107
 js/ui/iconGrid.js | 16 ++++++++++++++--
441107
 1 file changed, 14 insertions(+), 2 deletions(-)
441107
441107
diff --git a/js/ui/iconGrid.js b/js/ui/iconGrid.js
441107
index d51a443e8..1f05e67f3 100644
441107
--- a/js/ui/iconGrid.js
441107
+++ b/js/ui/iconGrid.js
441107
@@ -210,6 +210,8 @@ var IconGrid = GObject.registerClass({
441107
         this.rightPadding = 0;
441107
         this.leftPadding = 0;
441107
 
441107
+        this._updateIconSizesLaterId = 0;
441107
+
441107
         this._items = [];
441107
         this._clonesAnimating = [];
441107
         // Pulled from CSS, but hardcode some defaults here
441107
@@ -227,6 +229,14 @@ var IconGrid = GObject.registerClass({
441107
 
441107
         this.connect('actor-added', this._childAdded.bind(this));
441107
         this.connect('actor-removed', this._childRemoved.bind(this));
441107
+        this.connect('destroy', this._onDestroy.bind(this));
441107
+    }
441107
+
441107
+    _onDestroy() {
441107
+        if (this._updateIconSizesLaterId) {
441107
+            Meta.later_remove (this._updateIconSizesLaterId);
441107
+            this._updateIconSizesLaterId = 0;
441107
+        }
441107
     }
441107
 
441107
     _keyFocusIn(actor) {
441107
@@ -757,12 +767,14 @@ var IconGrid = GObject.registerClass({
441107
 
441107
             this._updateSpacingForSize(availWidth, availHeight);
441107
         }
441107
-        Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
441107
-                       this._updateIconSizes.bind(this));
441107
+        if (!this._updateIconSizesLaterId)
441107
+            this._updateIconSizesLaterId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
441107
+                                                          this._updateIconSizes.bind(this));
441107
     }
441107
 
441107
     // Note that this is ICON_SIZE as used by BaseIcon, not elsewhere in IconGrid; it's a bit messed up
441107
     _updateIconSizes() {
441107
+        this._updateIconSizesLaterId = 0;
441107
         let scale = Math.min(this._fixedHItemSize, this._fixedVItemSize) / Math.max(this._hItemSize, this._vItemSize);
441107
         let newIconSize = Math.floor(ICON_SIZE * scale);
441107
         for (let i in this._items) {
441107
-- 
441107
2.23.0
441107
441107
441107
From 14a2650548a5104d6a3ec7a1174a23264d79030a Mon Sep 17 00:00:00 2001
441107
From: Ray Strode <rstrode@redhat.com>
441107
Date: Mon, 22 Jul 2019 11:02:10 -0400
441107
Subject: [PATCH 3/8] appDisplay: Add AppFolderPopup destroy handler
441107
441107
At the moment AppFolderPopup calls popdown on destruction,
441107
which leads to open-state-changed getting emitted after
441107
the actor associated with the popup is destroyed.
441107
441107
This commit handles ungrabbing and closing from an
441107
actor destroy handler to side-step the open-state-changed
441107
signal.
441107
441107
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/628
441107
---
441107
 js/ui/appDisplay.js | 9 +++++++++
441107
 1 file changed, 9 insertions(+)
441107
441107
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
441107
index fa22f47e0..b75d095d5 100644
441107
--- a/js/ui/appDisplay.js
441107
+++ b/js/ui/appDisplay.js
441107
@@ -1329,6 +1329,15 @@ var AppFolderPopup = class AppFolderPopup {
441107
         });
441107
         this._grabHelper.addActor(Main.layoutManager.overviewGroup);
441107
         this.actor.connect('key-press-event', this._onKeyPress.bind(this));
441107
+        this.actor.connect('destroy', this._onDestroy.bind(this));
441107
+    }
441107
+
441107
+    _onDestroy() {
441107
+        if (this._isOpen) {
441107
+            this._isOpen = false;
441107
+            this._grabHelper.ungrab({ actor: this.actor });
441107
+            this._grabHelper = null;
441107
+        }
441107
     }
441107
 
441107
     _onKeyPress(actor, event) {
441107
-- 
441107
2.23.0
441107
441107
441107
From c9fcb2d23141694ffa2182df20ba75687b01dacc Mon Sep 17 00:00:00 2001
441107
From: Ray Strode <rstrode@redhat.com>
441107
Date: Thu, 18 Jul 2019 10:06:38 -0400
441107
Subject: [PATCH 4/8] appDisplay: Clear AllView reference to current popup when
441107
 destroyed
441107
441107
AllView contains a reference to the current popup that lingers after
441107
the popup is destroyed.
441107
441107
This commit fixes that, by explicitly nullifying when appropriate.
441107
441107
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/628
441107
---
441107
 js/ui/appDisplay.js | 18 +++++++++++++++++-
441107
 1 file changed, 17 insertions(+), 1 deletion(-)
441107
441107
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
441107
index b75d095d5..dabf63bfd 100644
441107
--- a/js/ui/appDisplay.js
441107
+++ b/js/ui/appDisplay.js
441107
@@ -300,6 +300,7 @@ var AllView = class AllView extends BaseAppView {
441107
         this._eventBlocker.add_action(this._clickAction);
441107
 
441107
         this._displayingPopup = false;
441107
+        this._currentPopupDestroyId = 0;
441107
 
441107
         this._availWidth = 0;
441107
         this._availHeight = 0;
441107
@@ -589,7 +590,22 @@ var AllView = class AllView extends BaseAppView {
441107
         this._stack.add_actor(popup.actor);
441107
         popup.connect('open-state-changed', (popup, isOpen) => {
441107
             this._eventBlocker.reactive = isOpen;
441107
-            this._currentPopup = isOpen ? popup : null;
441107
+
441107
+            if (this._currentPopup) {
441107
+                this._currentPopup.actor.disconnect(this._currentPopupDestroyId);
441107
+                this._currentPopupDestroyId = 0;
441107
+            }
441107
+
441107
+            this._currentPopup = null;
441107
+
441107
+            if (isOpen) {
441107
+                this._currentPopup = popup;
441107
+                this._currentPopupDestroyId = popup.actor.connect('destroy', () => {
441107
+                    this._currentPopup = null;
441107
+                    this._currentPopupDestroyId = 0;
441107
+                    this._eventBlocker.reactive = false;
441107
+                });
441107
+            }
441107
             this._updateIconOpacities(isOpen);
441107
             if(!isOpen)
441107
                 this._closeSpaceForPopup();
441107
-- 
441107
2.23.0
441107
441107
441107
From b7a3fd7fa4527ba9411dcd18debe6ccf88c34dc0 Mon Sep 17 00:00:00 2001
441107
From: Ray Strode <rstrode@redhat.com>
441107
Date: Mon, 22 Jul 2019 10:57:57 -0400
441107
Subject: [PATCH 5/8] appDisplay: Add destroy handler for FolderIcon
441107
441107
It is important that the FolderView of a FolderIcon always
441107
gets destroyed before the AppFolderPopup, since the view
441107
may or may not be in the popup, and the view should
441107
get cleaned up exactly once in either case.
441107
441107
This commit adds a destroy handler on FolderIcon to ensure
441107
things get taken down in the right order, and to make sure
441107
the view isn't leaked if it's not yet part of the popup.
441107
441107
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/628
441107
---
441107
 js/ui/appDisplay.js | 8 ++++++++
441107
 1 file changed, 8 insertions(+)
441107
441107
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
441107
index dabf63bfd..5a8f4f1bf 100644
441107
--- a/js/ui/appDisplay.js
441107
+++ b/js/ui/appDisplay.js
441107
@@ -1156,6 +1156,7 @@ var FolderIcon = class FolderIcon {
441107
             this.view.actor.vscroll.adjustment.value = 0;
441107
             this._openSpaceForPopup();
441107
         });
441107
+        this.actor.connect('destroy', this.onDestroy.bind(this));
441107
         this.actor.connect('notify::mapped', () => {
441107
             if (!this.actor.mapped && this._popup)
441107
                 this._popup.popdown();
441107
@@ -1165,6 +1166,13 @@ var FolderIcon = class FolderIcon {
441107
         this._redisplay();
441107
     }
441107
 
441107
+    onDestroy() {
441107
+        this.view.actor.destroy();
441107
+
441107
+        if (this._popup)
441107
+            this._popup.actor.destroy();
441107
+    }
441107
+
441107
     getAppIds() {
441107
         return this.view.getAllItems().map(item => item.id);
441107
     }
441107
-- 
441107
2.23.0
441107
441107
441107
From a90d7a97d21ffa596747cc8ecd0e3f500cb8a77c Mon Sep 17 00:00:00 2001
441107
From: Ray Strode <rstrode@redhat.com>
441107
Date: Thu, 18 Jul 2019 14:49:30 -0400
441107
Subject: [PATCH 6/8] appDisplay: Stop watching FolderIcon parent view when
441107
 destroyed
441107
441107
When a FolderIcon is opened, it asks the parent view to allocate
441107
space for it, which takes time.  Eventually, the space-ready
441107
signal is emitted on the view and the icon can make use of the new
441107
space with its popup.  If the icon gets destroyed in the
441107
interim, though, space-ready signal handler still fires.
441107
441107
This commit disconnects the signal handler so it doesn't get called
441107
on a destroyed icon.
441107
441107
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/628
441107
---
441107
 js/ui/appDisplay.js | 10 ++++++++--
441107
 1 file changed, 8 insertions(+), 2 deletions(-)
441107
441107
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
441107
index 5a8f4f1bf..062ff222c 100644
441107
--- a/js/ui/appDisplay.js
441107
+++ b/js/ui/appDisplay.js
441107
@@ -1169,6 +1169,11 @@ var FolderIcon = class FolderIcon {
441107
     onDestroy() {
441107
         this.view.actor.destroy();
441107
 
441107
+        if (this._spaceReadySignalId) {
441107
+            this._parentView.disconnect(this._spaceReadySignalId);
441107
+            this._spaceReadySignalId = 0;
441107
+        }
441107
+
441107
         if (this._popup)
441107
             this._popup.actor.destroy();
441107
     }
441107
@@ -1240,8 +1245,9 @@ var FolderIcon = class FolderIcon {
441107
     }
441107
 
441107
     _openSpaceForPopup() {
441107
-        let id = this._parentView.connect('space-ready', () => {
441107
-            this._parentView.disconnect(id);
441107
+        this._spaceReadySignalId = this._parentView.connect('space-ready', () => {
441107
+            this._parentView.disconnect(this._spaceReadySignalId);
441107
+            this._spaceReadySignalId = 0;
441107
             this._popup.popup();
441107
             this._updatePopupPosition();
441107
         });
441107
-- 
441107
2.23.0
441107
441107
441107
From b57ab33dadf0f31c5bf2c800806593e94784050c Mon Sep 17 00:00:00 2001
441107
From: Ray Strode <rstrode@redhat.com>
441107
Date: Thu, 18 Jul 2019 10:19:13 -0400
441107
Subject: [PATCH 7/8] appDisplay: Add open method to FolderIcon
441107
441107
At the moment the only way to open a folder icon is to click on it;
441107
there's no API to open the icon programmatically.
441107
441107
This commits adds an open method and makes the click handler use
441107
it.
441107
441107
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/628
441107
---
441107
 js/ui/appDisplay.js | 12 +++++++-----
441107
 1 file changed, 7 insertions(+), 5 deletions(-)
441107
441107
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
441107
index 062ff222c..c0c6e3663 100644
441107
--- a/js/ui/appDisplay.js
441107
+++ b/js/ui/appDisplay.js
441107
@@ -1151,11 +1151,7 @@ var FolderIcon = class FolderIcon {
441107
 
441107
         this.view = new FolderView();
441107
 
441107
-        this.actor.connect('clicked', () => {
441107
-            this._ensurePopup();
441107
-            this.view.actor.vscroll.adjustment.value = 0;
441107
-            this._openSpaceForPopup();
441107
-        });
441107
+        this.actor.connect('clicked', this.open.bind(this));
441107
         this.actor.connect('destroy', this.onDestroy.bind(this));
441107
         this.actor.connect('notify::mapped', () => {
441107
             if (!this.actor.mapped && this._popup)
441107
@@ -1178,6 +1174,12 @@ var FolderIcon = class FolderIcon {
441107
             this._popup.actor.destroy();
441107
     }
441107
 
441107
+    open() {
441107
+        this._ensurePopup();
441107
+        this.view.actor.vscroll.adjustment.value = 0;
441107
+        this._openSpaceForPopup();
441107
+    }
441107
+
441107
     getAppIds() {
441107
         return this.view.getAllItems().map(item => item.id);
441107
     }
441107
-- 
441107
2.23.0
441107
441107
441107
From baacab7922a56957d041aa59944c419b82e7a7e1 Mon Sep 17 00:00:00 2001
441107
From: Ray Strode <rstrode@redhat.com>
441107
Date: Thu, 18 Jul 2019 11:13:27 -0400
441107
Subject: [PATCH 8/8] appDisplay: Keep popup open on refresh
441107
441107
If the list of applications is refreshed we currently close
441107
the open app folder.
441107
441107
This commit adds logic to reopen the app folder on reload.
441107
441107
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/628
441107
---
441107
 js/ui/appDisplay.js | 15 +++++++++++++++
441107
 1 file changed, 15 insertions(+)
441107
441107
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
441107
index c0c6e3663..7fad02cd0 100644
441107
--- a/js/ui/appDisplay.js
441107
+++ b/js/ui/appDisplay.js
441107
@@ -345,6 +345,21 @@ var AllView = class AllView extends BaseAppView {
441107
         super.removeAll();
441107
     }
441107
 
441107
+    _redisplay() {
441107
+        let openFolderId = null;
441107
+        if (this._displayingPopup && this._currentPopup)
441107
+            openFolderId = this._currentPopup._source.id;
441107
+
441107
+        super._redisplay();
441107
+
441107
+        if (openFolderId) {
441107
+            let [folderToReopen] = this.folderIcons.filter(folder => folder.id == openFolderId);
441107
+
441107
+            if (folderToReopen)
441107
+                folderToReopen.open();
441107
+        }
441107
+    }
441107
+
441107
     _itemNameChanged(item) {
441107
         // If an item's name changed, we can pluck it out of where it's
441107
         // supposed to be and reinsert it where it's sorted.
441107
-- 
441107
2.23.0
441107