From a6239811610a036af57a3f8f41e13658d0a5be8f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
Date: Mon, 12 Aug 2019 16:25:48 +0200
Subject: [PATCH 1/6] workspacesDisplay: Disconnect MetaLater and parent
signals on destroy
When the WorkspacesDisplay actor is destroyed we should remove the
ongoing later and parent widget connections to avoid accessing an
invalid object on callback.
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/700
---
js/ui/workspacesView.js | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js
index dd7bb0e2a..5dea68f5d 100644
--- a/js/ui/workspacesView.js
+++ b/js/ui/workspacesView.js
@@ -470,60 +470,76 @@ var WorkspacesDisplay = new Lang.Class({
panAction.connect('gesture-cancel', () => {
clickAction.release();
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].endSwipeScroll();
});
panAction.connect('gesture-end', () => {
clickAction.release();
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].endSwipeScroll();
});
Main.overview.addAction(panAction);
this.actor.bind_property('mapped', panAction, 'enabled', GObject.BindingFlags.SYNC_CREATE);
this._primaryIndex = Main.layoutManager.primaryIndex;
this._workspacesViews = [];
this._primaryScrollAdjustment = null;
this._settings = new Gio.Settings({ schema_id: OVERRIDE_SCHEMA });
this._settings.connect('changed::workspaces-only-on-primary',
this._workspacesOnlyOnPrimaryChanged.bind(this));
this._workspacesOnlyOnPrimaryChanged();
this._switchWorkspaceNotifyId = 0;
this._notifyOpacityId = 0;
this._scrollEventId = 0;
this._keyPressEventId = 0;
this._fullGeometry = null;
+
+ this.actor.connect('destroy', this._onDestroy.bind(this));
+ },
+
+ _onDestroy() {
+ if (this._notifyOpacityId) {
+ let parent = this.actor.get_parent();
+ if (parent)
+ parent.disconnect(this._notifyOpacityId);
+ this._notifyOpacityId = 0;
+ }
+
+ if (this._parentSetLater) {
+ Meta.later_remove(this._parentSetLater);
+ this._parentSetLater = 0;
+ }
},
_onPan(action) {
let [dist, dx, dy] = action.get_motion_delta(0);
let adjustment = this._scrollAdjustment;
if (global.screen.layout_rows == -1)
adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
else if (this.actor.text_direction == Clutter.TextDirection.RTL)
adjustment.value += (dx / this.actor.width) * adjustment.page_size;
else
adjustment.value -= (dx / this.actor.width) * adjustment.page_size;
return false;
},
navigateFocus(from, direction) {
return this._getPrimaryView().actor.navigate_focus(from, direction, false);
},
show(fadeOnPrimary) {
this._updateWorkspacesViews();
for (let i = 0; i < this._workspacesViews.length; i++) {
let animationType;
if (fadeOnPrimary && i == this._primaryIndex)
animationType = AnimationType.FADE;
else
animationType = AnimationType.ZOOM;
this._workspacesViews[i].animateToOverview(animationType);
}
this._restackedNotifyId =
@@ -612,61 +628,65 @@ var WorkspacesDisplay = new Lang.Class({
if (!adjustment)
continue;
// the adjustments work in terms of workspaces, so the
// values map directly
adjustment.value = this._scrollAdjustment.value;
}
},
_getMonitorIndexForEvent(event) {
let [x, y] = event.get_coords();
let rect = new Meta.Rectangle({ x: x, y: y, width: 1, height: 1 });
return global.screen.get_monitor_index_for_rect(rect);
},
_getPrimaryView() {
if (!this._workspacesViews.length)
return null;
return this._workspacesViews[this._primaryIndex];
},
activeWorkspaceHasMaximizedWindows() {
return this._getPrimaryView().getActiveWorkspace().hasMaximizedWindows();
},
_parentSet(actor, oldParent) {
if (oldParent && this._notifyOpacityId)
oldParent.disconnect(this._notifyOpacityId);
this._notifyOpacityId = 0;
- Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
+ if (this._parentSetLater)
+ return;
+
+ this._parentSetLater = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
+ this._parentSetLater = 0;
let newParent = this.actor.get_parent();
if (!newParent)
return;
// This is kinda hackish - we want the primary view to
// appear as parent of this.actor, though in reality it
// is added directly to Main.layoutManager.overviewGroup
this._notifyOpacityId = newParent.connect('notify::opacity', () => {
let opacity = this.actor.get_parent().opacity;
let primaryView = this._getPrimaryView();
if (!primaryView)
return;
primaryView.actor.opacity = opacity;
primaryView.actor.visible = opacity != 0;
});
});
},
// This geometry should always be the fullest geometry
// the workspaces switcher can ever be allocated, as if
// the sliding controls were never slid in at all.
setWorkspacesFullGeometry(geom) {
this._fullGeometry = geom;
this._updateWorkspacesFullGeometry();
},
_updateWorkspacesFullGeometry() {
if (!this._workspacesViews.length)
return;
--
2.26.2