[gnome-shell] loginDialog, unlockDialog: Give user time to read messages
- From: Ray Strode <halfline src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] loginDialog, unlockDialog: Give user time to read messages
- Date: Mon, 18 Mar 2013 23:01:45 +0000 (UTC)
commit d097327bd820eb6fe612fbd730f2fab3394634ac
Author: Ray Strode <rstrode redhat com>
Date: Mon Mar 18 00:59:56 2013 -0400
loginDialog,unlockDialog: Give user time to read messages
Right now, if multiple messages come in, they just sort of
clobber each other.
This commit sets up a message queue, and introduces pauses
long enough for the user to hopefully be able to read those
messages.
https://bugzilla.gnome.org/show_bug.cgi?id=694688
js/gdm/loginDialog.js | 14 ++++++-
js/gdm/util.js | 114 +++++++++++++++++++++++++++++++++++++++++++------
js/ui/unlockDialog.js | 16 ++++++-
3 files changed, 127 insertions(+), 17 deletions(-)
---
diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js
index 0abd233..77bd2eb 100644
--- a/js/gdm/loginDialog.js
+++ b/js/gdm/loginDialog.js
@@ -930,7 +930,7 @@ const LoginDialog = new Lang.Class({
return batch.run();
},
- _onSessionOpened: function(client, serviceName) {
+ _startSession: function(serviceName) {
Tweener.addTween(this.dialogLayout,
{ opacity: 0,
time: _FADE_ANIMATION_TIME,
@@ -953,6 +953,18 @@ const LoginDialog = new Lang.Class({
onCompleteScope: this });
},
+ _onSessionOpened: function(client, serviceName) {
+ if (!this._userVerifier.hasPendingMessages) {
+ this._startSession(serviceName);
+ } else {
+ let signalId = this._userVerifier.connect('no-more-messages',
+ Lang.bind(this, function() {
+ this._userVerifier.disconnect(signalId);
+ this._startSession(serviceName);
+ }));
+ }
+ },
+
_waitForItemForUser: function(userName) {
let item = this._userList.getItemFromUserName(userName);
diff --git a/js/gdm/util.js b/js/gdm/util.js
index 4de22e4..36ee4ab 100644
--- a/js/gdm/util.js
+++ b/js/gdm/util.js
@@ -2,6 +2,7 @@
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
+const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
@@ -27,6 +28,9 @@ const ALLOWED_FAILURES_KEY = 'allowed-failures';
const LOGO_KEY = 'logo';
const DISABLE_USER_LIST_KEY = 'disable-user-list';
+// Give user 16ms to read each character of a PAM message
+const USER_READ_TIME = 16
+
function fadeInActor(actor) {
if (actor.opacity == 255 && actor.visible)
return null;
@@ -114,6 +118,9 @@ const ShellUserVerifier = new Lang.Class({
this._fprintManager = new Fprint.FprintManager();
this._realmManager = new Realmd.Manager();
+ this._messageQueue = [];
+ this._messageQueueTimeoutId = 0;
+ this.hasPendingMessages = false;
this._failCounter = 0;
},
@@ -153,13 +160,73 @@ const ShellUserVerifier = new Lang.Class({
this._userVerifier.run_dispose();
this._userVerifier = null;
}
+
+ this._clearMessageQueue();
},
answerQuery: function(serviceName, answer) {
- // Clear any previous message
- this.emit('show-message', null, null);
+ if (!this._userVerifier.hasPendingMessages) {
+ this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
+ } else {
+ let signalId = this._userVerifier.connect('no-more-messages',
+ Lang.bind(this, function() {
+ this._userVerifier.disconnect(signalId);
+ this._userVerifier.call_answer_query(serviceName,
answer, this._cancellable, null);
+ }));
+ }
+ },
+
+ _getIntervalForMessage: function(message) {
+ // We probably could be smarter here
+ return message.length * USER_READ_TIME;
+ },
+
+ finishMessageQueue: function() {
+ if (!this.hasPendingMessages)
+ return;
+
+ this._messageQueue = [];
- this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
+ this.hasPendingMessages = false;
+ this.emit('no-more-messages');
+ },
+
+ _queueMessageTimeout: function() {
+ if (this._messageQueue.length == 0) {
+ this.finishMessageQueue();
+ return;
+ }
+
+ if (this._messageQueueTimeoutId != 0)
+ return;
+
+ let message = this._messageQueue.shift();
+ this.emit('show-message', message.text, message.iconName);
+
+ this._messageQueueTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
+ message.interval,
+ Lang.bind(this, function() {
+ this._messageQueueTimeoutId = 0;
+ this._queueMessageTimeout();
+ }));
+ },
+
+ _queueMessage: function(message, iconName) {
+ let interval = this._getIntervalForMessage(message);
+
+ this.hasPendingMessages = true;
+ this._messageQueue.push({ text: message, interval: interval, iconName: iconName });
+ this._queueMessageTimeout();
+ },
+
+ _clearMessageQueue: function() {
+ this.finishMessageQueue();
+
+ if (this._messageQueueTimeoutId != 0) {
+ GLib.source_remove(this._messageQueueTimeoutId);
+ this._messageQueueTimeoutId = 0;
+ }
+ this.emit('show-message', null, null);
},
_checkForFingerprintReader: function() {
@@ -179,7 +246,7 @@ const ShellUserVerifier = new Lang.Class({
logError(error, where);
this._hold.release();
- this.emit('show-message', _("Authentication error"), 'login-dialog-message-warning');
+ this._queueMessage(_("Authentication error"), 'login-dialog-message-warning');
this._verificationFailed(false);
},
@@ -298,7 +365,7 @@ const ShellUserVerifier = new Lang.Class({
// to indicate the user can swipe their finger instead
this.emit('show-login-hint', _("(or swipe finger)"));
} else if (serviceName == PASSWORD_SERVICE_NAME) {
- this.emit('show-message', info, 'login-dialog-message-info');
+ this._queueMessage(info, 'login-dialog-message-info');
}
},
@@ -307,7 +374,7 @@ const ShellUserVerifier = new Lang.Class({
// users who haven't enrolled their fingerprint.
if (serviceName != PASSWORD_SERVICE_NAME)
return;
- this.emit('show-message', problem, 'login-dialog-message-warning');
+ this._queueMessage(problem, 'login-dialog-message-warning');
},
_showRealmLoginHint: function() {
@@ -356,6 +423,15 @@ const ShellUserVerifier = new Lang.Class({
this.emit('verification-complete');
},
+ _cancelAndReset: function() {
+ this.cancel();
+ this._onReset();
+ },
+
+ _retry: function() {
+ this.begin(this._userName, new Batch.Hold());
+ },
+
_verificationFailed: function(retry) {
// For Not Listed / enterprise logins, immediately reset
// the dialog
@@ -367,15 +443,25 @@ const ShellUserVerifier = new Lang.Class({
this._failCounter < this._settings.get_int(ALLOWED_FAILURES_KEY);
if (canRetry) {
- this.clear();
- this.begin(this._userName, new Batch.Hold());
+ if (!this._userVerifier.hasPendingMessages) {
+ this._retry();
+ } else {
+ let signalId = this._userVerifier.connect('no-more-messages',
+ Lang.bind(this, function() {
+ this._userVerifier.disconnect(signalId);
+ this._retry();
+ }));
+ }
} else {
- // Allow some time to see the message, then reset everything
- Mainloop.timeout_add(3000, Lang.bind(this, function() {
- this.cancel();
-
- this._onReset();
- }));
+ if (!this._userVerifier.hasPendingMessages) {
+ this._cancelAndReset();
+ } else {
+ let signalId = this._userVerifier.connect('no-more-messages',
+ Lang.bind(this, function() {
+ this._userVerifier.disconnect(signalId);
+ this._cancelAndReset();
+ }));
+ }
}
this.emit('verification-failed');
diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js
index f9227a3..727df61 100644
--- a/js/ui/unlockDialog.js
+++ b/js/ui/unlockDialog.js
@@ -250,12 +250,24 @@ const UnlockDialog = new Lang.Class({
this._userVerifier.answerQuery(query, this._promptEntry.text);
},
- _onVerificationComplete: function() {
- this._userVerified = true;
+ _finishUnlock: function() {
this._userVerifier.clear();
this.emit('unlocked');
},
+ _onVerificationComplete: function() {
+ this._userVerified = true;
+ if (!this._userVerifier.hasPendingMessages) {
+ this._finishUnlock();
+ } else {
+ let signalId = this._userVerifier.connect('no-more-messages',
+ Lang.bind(this, function() {
+ this._userVerifier.disconnect(signalId);
+ this._finishUnlock();
+ }));
+ }
+ },
+
_onReset: function() {
if (!this._userVerified) {
this._userVerifier.clear();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]