diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js index a07db65..7fad02c 100644 --- a/js/ui/appDisplay.js +++ b/js/ui/appDisplay.js @@ -143,10 +143,14 @@ class BaseAppView { return this._allItems; } + hasItem(id) { + return this._items[id] !== undefined; + } + addItem(icon) { let id = icon.id; - if (this._items[id] !== undefined) - return; + if (this.hasItem(id)) + throw new Error(`icon with id ${id} already added to view`) this._allItems.push(icon); this._items[id] = icon; @@ -296,6 +300,7 @@ var AllView = class AllView extends BaseAppView { this._eventBlocker.add_action(this._clickAction); this._displayingPopup = false; + this._currentPopupDestroyId = 0; this._availWidth = 0; this._availHeight = 0; @@ -340,6 +345,21 @@ var AllView = class AllView extends BaseAppView { super.removeAll(); } + _redisplay() { + let openFolderId = null; + if (this._displayingPopup && this._currentPopup) + openFolderId = this._currentPopup._source.id; + + super._redisplay(); + + if (openFolderId) { + let [folderToReopen] = this.folderIcons.filter(folder => folder.id == openFolderId); + + if (folderToReopen) + folderToReopen.open(); + } + } + _itemNameChanged(item) { // If an item's name changed, we can pluck it out of where it's // supposed to be and reinsert it where it's sorted. @@ -386,6 +406,8 @@ var AllView = class AllView extends BaseAppView { let folders = this._folderSettings.get_strv('folder-children'); folders.forEach(id => { + if (this.hasItem(id)) + return; let path = this._folderSettings.path + 'folders/' + id + '/'; let icon = new FolderIcon(id, path, this); icon.connect('name-changed', this._itemNameChanged.bind(this)); @@ -583,7 +605,22 @@ var AllView = class AllView extends BaseAppView { this._stack.add_actor(popup.actor); popup.connect('open-state-changed', (popup, isOpen) => { this._eventBlocker.reactive = isOpen; - this._currentPopup = isOpen ? popup : null; + + if (this._currentPopup) { + this._currentPopup.actor.disconnect(this._currentPopupDestroyId); + this._currentPopupDestroyId = 0; + } + + this._currentPopup = null; + + if (isOpen) { + this._currentPopup = popup; + this._currentPopupDestroyId = popup.actor.connect('destroy', () => { + this._currentPopup = null; + this._currentPopupDestroyId = 0; + this._eventBlocker.reactive = false; + }); + } this._updateIconOpacities(isOpen); if(!isOpen) this._closeSpaceForPopup(); @@ -1129,11 +1166,8 @@ var FolderIcon = class FolderIcon { this.view = new FolderView(); - this.actor.connect('clicked', () => { - this._ensurePopup(); - this.view.actor.vscroll.adjustment.value = 0; - this._openSpaceForPopup(); - }); + this.actor.connect('clicked', this.open.bind(this)); + this.actor.connect('destroy', this.onDestroy.bind(this)); this.actor.connect('notify::mapped', () => { if (!this.actor.mapped && this._popup) this._popup.popdown(); @@ -1143,6 +1177,24 @@ var FolderIcon = class FolderIcon { this._redisplay(); } + onDestroy() { + this.view.actor.destroy(); + + if (this._spaceReadySignalId) { + this._parentView.disconnect(this._spaceReadySignalId); + this._spaceReadySignalId = 0; + } + + if (this._popup) + this._popup.actor.destroy(); + } + + open() { + this._ensurePopup(); + this.view.actor.vscroll.adjustment.value = 0; + this._openSpaceForPopup(); + } + getAppIds() { return this.view.getAllItems().map(item => item.id); } @@ -1165,7 +1217,10 @@ var FolderIcon = class FolderIcon { let excludedApps = this._folder.get_strv('excluded-apps'); let appSys = Shell.AppSystem.get_default(); let addAppId = appId => { - if (excludedApps.indexOf(appId) >= 0) + if (this.view.hasItem(appId)) + return; + + if (excludedApps.includes(appId)) return; let app = appSys.lookup_app(appId); @@ -1207,8 +1262,9 @@ var FolderIcon = class FolderIcon { } _openSpaceForPopup() { - let id = this._parentView.connect('space-ready', () => { - this._parentView.disconnect(id); + this._spaceReadySignalId = this._parentView.connect('space-ready', () => { + this._parentView.disconnect(this._spaceReadySignalId); + this._spaceReadySignalId = 0; this._popup.popup(); this._updatePopupPosition(); }); @@ -1320,6 +1376,15 @@ var AppFolderPopup = class AppFolderPopup { }); this._grabHelper.addActor(Main.layoutManager.overviewGroup); this.actor.connect('key-press-event', this._onKeyPress.bind(this)); + this.actor.connect('destroy', this._onDestroy.bind(this)); + } + + _onDestroy() { + if (this._isOpen) { + this._isOpen = false; + this._grabHelper.ungrab({ actor: this.actor }); + this._grabHelper = null; + } } _onKeyPress(actor, event) { diff --git a/js/ui/iconGrid.js b/js/ui/iconGrid.js index d51a443..1f05e67 100644 --- a/js/ui/iconGrid.js +++ b/js/ui/iconGrid.js @@ -210,6 +210,8 @@ var IconGrid = GObject.registerClass({ this.rightPadding = 0; this.leftPadding = 0; + this._updateIconSizesLaterId = 0; + this._items = []; this._clonesAnimating = []; // Pulled from CSS, but hardcode some defaults here @@ -227,6 +229,14 @@ var IconGrid = GObject.registerClass({ this.connect('actor-added', this._childAdded.bind(this)); this.connect('actor-removed', this._childRemoved.bind(this)); + this.connect('destroy', this._onDestroy.bind(this)); + } + + _onDestroy() { + if (this._updateIconSizesLaterId) { + Meta.later_remove (this._updateIconSizesLaterId); + this._updateIconSizesLaterId = 0; + } } _keyFocusIn(actor) { @@ -757,12 +767,14 @@ var IconGrid = GObject.registerClass({ this._updateSpacingForSize(availWidth, availHeight); } - Meta.later_add(Meta.LaterType.BEFORE_REDRAW, - this._updateIconSizes.bind(this)); + if (!this._updateIconSizesLaterId) + this._updateIconSizesLaterId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, + this._updateIconSizes.bind(this)); } // Note that this is ICON_SIZE as used by BaseIcon, not elsewhere in IconGrid; it's a bit messed up _updateIconSizes() { + this._updateIconSizesLaterId = 0; let scale = Math.min(this._fixedHItemSize, this._fixedVItemSize) / Math.max(this._hItemSize, this._vItemSize); let newIconSize = Math.floor(ICON_SIZE * scale); for (let i in this._items) {