windowPreview: Ignore leave events after being destroyed

When a WindowPreview is being destroyed, the class default handler for
the `destroy` signal is responsible for destroying its child actors.
This happens after the emission of the `destroy` signal, i.e. after
`WindowPreview::_onDestroy()` has been run.

The destruction of the WindowPreview's child actors now triggers a
re-pick, but due to WindowPreview having already being marked as
`CLUTTER_IN_DESTRUCTION`, it will not be picked, resulting in a `leave`
event if the cursor was on top of the WindowPreview at the time
`destroy()` was called on it.

So this leads to `WindowPreview::vfunc_leave_event()` being run after
`WindowPreview::_onDestroy()`, which means the idle started by the leave
event handler will not be removed and ends up accessing actors after
they have already been destroyed.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/5512
Closes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/6065
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2738>
This commit is contained in:
Sebastian Keller 2023-04-17 13:38:23 +02:00 committed by Marge Bot
parent 8bf06bfc9f
commit 4bbf6d497d

View File

@ -525,6 +525,7 @@ var WindowPreview = GObject.registerClass({
_onDestroy() { _onDestroy() {
this.metaWindow._delegate = null; this.metaWindow._delegate = null;
this._delegate = null; this._delegate = null;
this._destroyed = true;
if (this._longPressLater) { if (this._longPressLater) {
const laters = global.compositor.get_laters(); const laters = global.compositor.get_laters();
@ -554,6 +555,9 @@ var WindowPreview = GObject.registerClass({
} }
vfunc_leave_event(crossingEvent) { vfunc_leave_event(crossingEvent) {
if (this._destroyed)
return super.vfunc_leave_event(crossingEvent);
if ((crossingEvent.flags & Clutter.EventFlags.FLAG_GRAB_NOTIFY) !== 0 && if ((crossingEvent.flags & Clutter.EventFlags.FLAG_GRAB_NOTIFY) !== 0 &&
global.stage.get_grab_actor() === this._closeButton) global.stage.get_grab_actor() === this._closeButton)
return super.vfunc_leave_event(crossingEvent); return super.vfunc_leave_event(crossingEvent);