diff --git a/js/ui/screenshot.js b/js/ui/screenshot.js index 7893456520..a36428bf01 100644 --- a/js/ui/screenshot.js +++ b/js/ui/screenshot.js @@ -405,6 +405,18 @@ class SelectArea { } _onButtonRelease(actor, event) { + // The selection is finished on the first release. Ignore any further + // press/release pairs arriving during the 100ms fade-out - each of + // them used to overwrite the result and schedule another _ungrab(), + // and the second popModal() would take the 'incorrect pop' error path + // after tearing down the X grab, aborting _ungrab() before + // this._group.destroy(): the fullscreen overlay stayed on screen and + // the panel appeared frozen. + if (!this.active || this._finishing) + return Clutter.EVENT_PROPAGATE; + + this._finishing = true; + this._result = this._getGeometry(); this._group.ease({ opacity: 0, @@ -419,6 +431,12 @@ class SelectArea { } _ungrab() { + // One-shot guard, NOT this.active: Escape legitimately calls + // _ungrab() before any selection started (active is still false). + if (this._ungrabbed) + return; + this._ungrabbed = true; + this.active = false; if (this.stage_event_id > 0) { @@ -522,6 +540,18 @@ class PickColor { } _onButtonRelease(actor, event) { + // The selection is finished on the first release. Ignore any further + // press/release pairs arriving during the 100ms fade-out - each of + // them used to overwrite the result and schedule another _ungrab(), + // and the second popModal() would take the 'incorrect pop' error path + // after tearing down the X grab, aborting _ungrab() before + // this._group.destroy(): the fullscreen overlay stayed on screen and + // the panel appeared frozen. + if (!this.active || this._finishing) + return Clutter.EVENT_PROPAGATE; + + this._finishing = true; + this._result = this._getGeometry(); this._group.ease({ opacity: 0, @@ -535,6 +565,12 @@ class PickColor { } _ungrab() { + // One-shot guard, NOT this.active: Escape legitimately calls + // _ungrab() before any selection started (active is still false). + if (this._ungrabbed) + return; + this._ungrabbed = true; + this.active = false; if (this.stage_event_id > 0) { @@ -657,6 +693,10 @@ class SelectWindow { if (window === null) return Clutter.EVENT_STOP; + if (this._finishing) + return Clutter.EVENT_STOP; + this._finishing = true; + this._result = window; this._group.ease({ opacity: 0, @@ -671,6 +711,10 @@ class SelectWindow { } _ungrab() { + if (this._ungrabbed) + return; + this._ungrabbed = true; + Main.popModal(this._group); global.unset_cursor(); this.emit('finished', this._result);