diff --git a/js/ui/lightbox.js b/js/ui/lightbox.js index d6b0f5d1d..b876d97d7 100644 --- a/js/ui/lightbox.js +++ b/js/ui/lightbox.js @@ -101,6 +101,7 @@ const Lightbox = new Lang.Class({ }, show: function() { + Tweener.removeTweens(this.actor); if (this._fadeInTime) { this.shown = false; this.actor.opacity = 0; @@ -110,17 +111,20 @@ const Lightbox = new Lang.Class({ transition: 'easeOutQuad', onComplete: Lang.bind(this, function() { this.shown = true; + this.emit('shown'); }) }); } else { this.actor.opacity = 255 * this._fadeFactor; this.shown = true; + this.emit('shown'); } this.actor.show(); }, hide: function() { this.shown = false; + Tweener.removeTweens(this.actor); if (this._fadeOutTime) { Tweener.addTween(this.actor, { opacity: 0, @@ -197,3 +201,4 @@ const Lightbox = new Lang.Class({ this.highlight(null); } }); +Signals.addSignalMethods(Lightbox.prototype); diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js index 73bf1370a..7d86b9669 100644 --- a/js/ui/screenShield.js +++ b/js/ui/screenShield.js @@ -537,11 +537,13 @@ const ScreenShield = new Lang.Class({ this._isActive = false; this._inUnlockAnimation = false; this._activationTime = 0; + this._becameActiveId = 0; this._lightbox = new Lightbox.Lightbox(Main.uiGroup, { inhibitEvents: true, fadeInTime: STANDARD_FADE_TIME, fadeFactor: 1 }); + this._lightbox.connect('shown', Lang.bind(this, this._onLightboxShown)); this.idleMonitor = new GnomeDesktop.IdleMonitor(); }, @@ -682,37 +684,75 @@ const ScreenShield = new Lang.Class({ if (!this._isModal) { Main.pushModal(this.actor, { keybindingMode: Main.KeybindingMode.LOCK_SCREEN }); this._isModal = true; + } + + if (this._lightbox.actor.visible || + this._isActive) { + // We're either shown and active, or in the process of + // showing. + // The latter is a very unlikely condition (it requires + // idle-delay < 20), but in any case we have nothing + // to do at this point: either isActive is true, or + // it will soon be. + // isActive can also be true if the lightbox is hidden, + // in case the shield is down and the user hasn't unlocked yet + return; } - if (!this._isActive) { - this._lightbox.show(); + this._lightbox.show(); - if (this._activationTime == 0) - this._activationTime = GLib.get_monotonic_time(); + if (this._activationTime == 0) + this._activationTime = GLib.get_monotonic_time(); - this._becameActiveId = this.idleMonitor.connect('became-active', Lang.bind(this, function() { - this.idleMonitor.disconnect(this._becameActiveId); + if (this._becameActiveId == 0) + this._becameActiveId = this.idleMonitor.connect('became-active', + Lang.bind(this, this._onUserBecameActive)); + }, - let lightboxWasShown = this._lightbox.shown; - this._lightbox.hide(); + _onUserBecameActive: function() { + // This function gets called here when the user becomes active + // after gnome-session changed the status to IDLE + // There are four possibilities here: + // - we're called when already locked; isActive and isLocked are true, + // we just go back to the lock screen curtain + // - we're called before the lightbox is fully shown; at this point + // isActive is false, so we just hide the ligthbox, reset the activationTime + // and go back to the unlocked desktop + // - we're called after showing the lightbox, but before the lock + // delay; this is mostly like the case above, but isActive is true now + // so we need to notify gnome-settings-daemon to go back to the normal + // policies for blanking + // (they're handled by the same code, and we emit one extra ActiveChanged + // signal in the case above) + // - we're called after showing the lightbox and after lock-delay; the + // session is effectivelly locked now, it's time to build and show + // the lock screen - // GLib.get_monotonic_time() returns microseconds, convert to seconds - let elapsedTime = (GLib.get_monotonic_time() - this._activationTime) / 1000000; - let shouldLock = lightboxWasShown && - this._settings.get_boolean(LOCK_ENABLED_KEY) && - (elapsedTime >= this._settings.get_uint(LOCK_DELAY_KEY)); - if (shouldLock || this._isLocked) { - this.lock(false); - } else if (this._isActive) { - this.unlock(); - } - })); + this.idleMonitor.disconnect(this._becameActiveId); + this._becameActiveId = 0; - this._isActive = true; - this.emit('lock-status-changed'); + let lightboxWasShown = this._lightbox.shown; + this._lightbox.hide(); + + // GLib.get_monotonic_time() returns microseconds, convert to seconds + let elapsedTime = (GLib.get_monotonic_time() - this._activationTime) / 1000000; + let shouldLock = lightboxWasShown && this._settings.get_boolean(LOCK_ENABLED_KEY) && + (elapsedTime >= this._settings.get_uint(LOCK_DELAY_KEY)); + + if (this._isLocked || shouldLock) { + this.lock(false); + } else { + // We're not really locked here, but unlock() will do what we need + // and ensure we reset all state + this.unlock(); } }, + _onLightboxShown: function() { + this._isActive = true; + this.emit('lock-status-changed'); + }, + showDialog: function() { // Ensure that the stage window is mapped, before taking a grab // otherwise X errors out @@ -989,6 +1029,11 @@ const ScreenShield = new Lang.Class({ if (Main.sessionMode.currentMode == 'unlock-dialog') Main.sessionMode.popMode('unlock-dialog'); + if (this._becameActiveId != 0) { + this.idleMonitor.disconnect(this._becameActiveId); + this._becameActiveId = 0; + } + this._activationTime = 0; this._isActive = false; this._isLocked = false;