Compare commits

...

4 Commits

Author SHA1 Message Date
Ray Strode
b19cef9dd5 unlockDialog: Use GdmUtil.AuthPrompt instead of ModalDialog
commit ea02380c15 made the login
screen stop using ModalDialog. It makes sense for the unlock
code to also stop using ModalDialog, too (for similar reasons).

Now that the login screen's auth prompt code has been separated
out, the unlock dialog can use it to get the buttons and spinners
etc, that it was previously getting from ModalDialog.

This commit drops the ModalDialog usage in the unlock dialog, and
makes the unlock dialog use GdmUtil.AuthPrompt instead.
2013-07-16 14:13:05 -04:00
Ray Strode
2d4473c35a loginDialog: factor auth prompt code out to utils
Right now there is a lot of duplicated code between the unlock
dialog and the login dialog.

This commit moves the login dialog's auth prompt to a separate
class, so that it can (in a subsequent commit) be used by the
unlock dialog.
2013-07-16 14:13:02 -04:00
Ray Strode
6d9fb50207 loginDialog: handle typing at screenshield
If the screenshield is up and the user starts typing, we need to
keep track of it and replay it later, otherwise what they type
will be ignored.

This is useful when the user has disable-user-list set to TRUE,
and will also be useful to bring feature parity between the
login screen and unlock screen.

https://bugzilla.gnome.org/show_bug.cgi?id=702308
2013-07-16 14:04:57 -04:00
Ray Strode
86b8885d96 theme: fix spacing for "Log in as another user" button
At some point the Not Listed? button was moved to align it better
in the login screen.  That nudging made the "Log in as another user"
button (which uses the same style class) align worse.

This commit removes the padding at the unlock screen.

https://bugzilla.gnome.org/show_bug.cgi?id=704318
2013-07-16 10:53:59 -04:00
4 changed files with 468 additions and 393 deletions

View File

@@ -2320,6 +2320,9 @@ StScrollBar StButton#vhandle:active {
font-weight: bold; font-weight: bold;
color: #666666; color: #666666;
padding-top: 1em; padding-top: 1em;
}
.login-dialog-user-selection-box .login-dialog-not-listed-label {
padding-left: 2px; padding-left: 2px;
} }

View File

@@ -32,7 +32,6 @@ const Shell = imports.gi.Shell;
const Signals = imports.signals; const Signals = imports.signals;
const St = imports.gi.St; const St = imports.gi.St;
const Animation = imports.ui.animation;
const Batch = imports.gdm.batch; const Batch = imports.gdm.batch;
const BoxPointer = imports.ui.boxpointer; const BoxPointer = imports.ui.boxpointer;
const CtrlAltTab = imports.ui.ctrlAltTab; const CtrlAltTab = imports.ui.ctrlAltTab;
@@ -46,20 +45,11 @@ const UserWidget = imports.ui.userWidget;
const _FADE_ANIMATION_TIME = 0.25; const _FADE_ANIMATION_TIME = 0.25;
const _SCROLL_ANIMATION_TIME = 0.5; const _SCROLL_ANIMATION_TIME = 0.5;
const _DEFAULT_BUTTON_WELL_ICON_SIZE = 24;
const _DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0;
const _DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3;
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0; const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
const _LOGO_ICON_HEIGHT = 48; const _LOGO_ICON_HEIGHT = 48;
let _loginDialog = null; let _loginDialog = null;
const DefaultButtonWellMode = {
NONE: 0,
SESSION_MENU_BUTTON: 1,
SPINNER: 2
};
const UserListItem = new Lang.Class({ const UserListItem = new Lang.Class({
Name: 'UserListItem', Name: 'UserListItem',
@@ -466,67 +456,20 @@ const LoginDialog = new Lang.Class({
x_fill: true, x_fill: true,
y_fill: true }); y_fill: true });
this._promptBox = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', this._authPrompt = new GdmUtil.AuthPrompt({ visible: false });
vertical: true }); this._authPrompt.connect('cancel',
Lang.bind(this, function() {
this._promptBox.connect('button-press-event',
Lang.bind(this, function(actor, event) {
if (event.get_key_symbol() == Clutter.KEY_Escape) {
this.cancel(); this.cancel();
}
})); }));
this._promptBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, this._authPrompt.actor.add_constraint(new Clutter.AlignConstraint({ source: this.actor,
align_axis: Clutter.AlignAxis.BOTH, align_axis: Clutter.AlignAxis.BOTH,
factor: 0.5 })); factor: 0.5 }));
this.actor.add_child(this._promptBox); this.actor.add_child(this._authPrompt.actor);
this._userList.actor.add_constraint(new Clutter.BindConstraint({ source: this._promptBox, this._userList.actor.add_constraint(new Clutter.BindConstraint({ source: this._authPrompt.actor,
coordinate: Clutter.BindCoordinate.WIDTH })); coordinate: Clutter.BindCoordinate.WIDTH }));
this._promptUser = new St.Bin({ x_fill: true,
x_align: St.Align.START });
this._promptBox.add(this._promptUser,
{ x_align: St.Align.START,
x_fill: true,
y_fill: true,
expand: true });
this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' });
this._promptBox.add(this._promptLabel,
{ expand: true,
x_fill: true,
y_fill: true,
x_align: St.Align.START });
this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry',
can_focus: true });
this._promptEntryTextChangedId = 0;
this._promptEntryActivateId = 0;
this._promptBox.add(this._promptEntry,
{ expand: true,
x_fill: true,
y_fill: false,
x_align: St.Align.START });
this._promptEntry.grab_key_focus();
this._promptMessage = new St.Label({ opacity: 0 });
this._promptBox.add(this._promptMessage, { x_fill: true });
this._promptLoginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' });
this._promptBox.add(this._promptLoginHint);
this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box',
vertical: false });
this._promptBox.add(this._buttonBox,
{ expand: true,
x_align: St.Align.MIDDLE,
y_align: St.Align.END });
this._cancelButton = null;
this._signInButton = null;
this._promptBox.hide();
// translators: this message is shown below the user list on the // translators: this message is shown below the user list on the
// login screen. It can be activated to reveal an entry for // login screen. It can be activated to reveal an entry for
// manually entering the username. // manually entering the username.
@@ -576,8 +519,6 @@ const LoginDialog = new Lang.Class({
this._onUserListActivated(item); this._onUserListActivated(item);
})); }));
this._defaultButtonWell = new St.Widget();
this._defaultButtonWellMode = DefaultButtonWellMode.NONE;
this._sessionMenuButton = new SessionMenuButton(); this._sessionMenuButton = new SessionMenuButton();
this._sessionMenuButton.connect('session-activated', this._sessionMenuButton.connect('session-activated',
@@ -586,17 +527,8 @@ const LoginDialog = new Lang.Class({
})); }));
this._sessionMenuButton.actor.opacity = 0; this._sessionMenuButton.actor.opacity = 0;
this._sessionMenuButton.actor.show(); this._sessionMenuButton.actor.show();
this._defaultButtonWell.add_child(this._sessionMenuButton.actor); this._authPrompt.addActorToDefaultButtonWell(this._sessionMenuButton.actor);
let spinnerIcon = global.datadir + '/theme/process-working.svg';
this._workSpinner = new Animation.AnimatedIcon(spinnerIcon, _DEFAULT_BUTTON_WELL_ICON_SIZE);
this._workSpinner.actor.opacity = 0;
this._workSpinner.actor.show();
this._defaultButtonWell.add_child(this._workSpinner.actor);
this._sessionMenuButton.actor.add_constraint(new Clutter.AlignConstraint({ source: this._workSpinner.actor,
align_axis: Clutter.AlignAxis.BOTH,
factor: 0.5 }));
}, },
_updateDisableUserList: function() { _updateDisableUserList: function() {
@@ -644,7 +576,8 @@ const LoginDialog = new Lang.Class({
this._userVerifier.clear(); this._userVerifier.clear();
this._updateSensitivity(true); this._updateSensitivity(true);
this._promptMessage.opacity = 0; this._authPrompt.reset();
this._user = null; this._user = null;
this._verifyingUser = false; this._verifyingUser = false;
@@ -654,73 +587,11 @@ const LoginDialog = new Lang.Class({
this._showUserList(); this._showUserList();
}, },
_getActorForDefaultButtonWellMode: function(mode) {
let actor;
if (mode == DefaultButtonWellMode.NONE)
actor = null;
else if (mode == DefaultButtonWellMode.SPINNER)
actor = this._workSpinner.actor;
else if (mode == DefaultButtonWellMode.SESSION_MENU_BUTTON)
actor = this._sessionMenuButton.actor;
return actor;
},
_setDefaultButtonWellMode: function(mode, immediately) {
if (this._defaultButtonWellMode == DefaultButtonWellMode.NONE &&
mode == DefaultButtonWellMode.NONE)
return;
let oldActor = this._getActorForDefaultButtonWellMode(this._defaultButtonWellMode);
if (oldActor)
Tweener.removeTweens(oldActor);
let actor = this._getActorForDefaultButtonWellMode(mode);
if (this._defaultButtonWellMode != mode && oldActor) {
if (immediately)
oldActor.opacity = 0;
else
Tweener.addTween(oldActor,
{ opacity: 0,
time: _DEFAULT_BUTTON_WELL_ANIMATION_TIME,
delay: _DEFAULT_BUTTON_WELL_ANIMATION_DELAY,
transition: 'linear',
onCompleteScope: this,
onComplete: function() {
if (mode == DefaultButtonWellMode.SPINNER) {
if (this._workSpinner)
this._workSpinner.stop();
}
}
});
}
if (actor) {
if (mode == DefaultButtonWellMode.SPINNER)
this._workSpinner.play();
if (immediately)
actor.opacity = 255;
else
Tweener.addTween(actor,
{ opacity: 255,
time: _DEFAULT_BUTTON_WELL_ANIMATION_TIME,
delay: _DEFAULT_BUTTON_WELL_ANIMATION_DELAY,
transition: 'linear' });
}
this._defaultButtonWellMode = mode;
},
_verificationFailed: function() { _verificationFailed: function() {
this._promptEntry.text = ''; this._authPrompt.clear();
this._updateSensitivity(true); this._updateSensitivity(true);
this._setDefaultButtonWellMode(DefaultButtonWellMode.NONE, true); this._authPrompt.setActorInDefaultButtonWell(null, true);
}, },
_onDefaultSessionChanged: function(client, sessionId) { _onDefaultSessionChanged: function(client, sessionId) {
@@ -728,23 +599,15 @@ const LoginDialog = new Lang.Class({
}, },
_showMessage: function(userVerifier, message, styleClass) { _showMessage: function(userVerifier, message, styleClass) {
if (message) { this._authPrompt.setMessage(message, styleClass);
this._promptMessage.text = message;
this._promptMessage.styleClass = styleClass;
this._promptMessage.opacity = 255;
} else {
this._promptMessage.opacity = 0;
}
}, },
_showLoginHint: function(verifier, message) { _showLoginHint: function(verifier, message) {
this._promptLoginHint.set_text(message) this._authPrompt.setHint(message);
this._promptLoginHint.opacity = 255;
}, },
_hideLoginHint: function() { _hideLoginHint: function() {
this._promptLoginHint.opacity = 0; this._authPrompt.setHint(null);
this._promptLoginHint.set_text('');
}, },
cancel: function() { cancel: function() {
@@ -768,27 +631,16 @@ const LoginDialog = new Lang.Class({
}, },
_showPrompt: function(forSecret) { _showPrompt: function(forSecret) {
this._promptLabel.show(); this._authPrompt.actor.opacity = 0;
this._promptEntry.show(); this._authPrompt.actor.show();
this._promptLoginHint.opacity = 0; Tweener.addTween(this._authPrompt.actor,
this._promptLoginHint.show();
this._promptBox.opacity = 0;
this._promptBox.show();
Tweener.addTween(this._promptBox,
{ opacity: 255, { opacity: 255,
time: _FADE_ANIMATION_TIME, time: _FADE_ANIMATION_TIME,
transition: 'easeOutQuad' }); transition: 'easeOutQuad' });
if (this._shouldShowSessionMenuButton())
this._setDefaultButtonWellMode(DefaultButtonWellMode.SESSION_MENU_BUTTON, true);
else
this._setDefaultButtonWellMode(DefaultButtonWellMode.NONE, true);
this._promptEntry.grab_key_focus();
let hold = new Batch.Hold(); let hold = new Batch.Hold();
let tasks = [function() { let tasks = [function() {
this._prepareDialog(forSecret, hold); this._preparePrompt(forSecret, hold);
}, },
hold]; hold];
@@ -798,122 +650,54 @@ const LoginDialog = new Lang.Class({
return batch.run(); return batch.run();
}, },
_prepareDialog: function(forSecret, hold) { _preparePrompt: function(forSecret, hold) {
this._buttonBox.visible = true; let cancelLabel;
this._buttonBox.remove_all_children();
if (!this._disableUserList || this._verifyingUser) { if (!this._disableUserList || this._verifyingUser) {
this._cancelButton = new St.Button({ style_class: 'modal-dialog-button', cancelLabel = _("Cancel");
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, } else {
reactive: true, cancelLabel = null;
can_focus: true,
label: _("Cancel") });
this._cancelButton.connect('clicked',
Lang.bind(this, function() {
this.cancel();
}));
this._buttonBox.add(this._cancelButton,
{ expand: false,
x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.END });
} }
this._buttonBox.add(this._defaultButtonWell, let nextLabel;
{ expand: true, if (forSecret) {
x_fill: false, nextLabel = C_("button", "Sign In");
y_fill: false, } else {
x_align: St.Align.END, nextLabel = _("Next");
y_align: St.Align.MIDDLE }); }
this._signInButton = new St.Button({ style_class: 'modal-dialog-button',
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
reactive: true,
can_focus: true,
label: forSecret ? C_("button", "Sign In") : _("Next") });
this._signInButton.connect('clicked',
Lang.bind(this, function() {
hold.release();
}));
this._signInButton.add_style_pseudo_class('default');
this._buttonBox.add(this._signInButton,
{ expand: false,
x_fill: false,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.END });
this._updateSignInButtonSensitivity(this._promptEntry.text.length > 0); let signalId = this._authPrompt.connect('next', Lang.bind(this, function() {
this._authPrompt.disconnect(signalId);
hold.release();
}));
this._promptEntryTextChangedId = this._authPrompt.resetButtons(cancelLabel, nextLabel);
this._promptEntry.clutter_text.connect('text-changed',
Lang.bind(this, function() {
this._updateSignInButtonSensitivity(this._promptEntry.text.length > 0);
}));
this._promptEntryActivateId =
this._promptEntry.clutter_text.connect('activate', function() {
hold.release();
});
}, },
_updateSensitivity: function(sensitive) { _updateSensitivity: function(sensitive) {
this._promptEntry.reactive = sensitive;
this._promptEntry.clutter_text.editable = sensitive;
this._sessionMenuButton.updateSensitivity(sensitive); this._sessionMenuButton.updateSensitivity(sensitive);
this._updateSignInButtonSensitivity(sensitive); this._authPrompt.updateSensitivity(sensitive);
},
_updateSignInButtonSensitivity: function(sensitive) {
if (this._signInButton) {
this._signInButton.reactive = sensitive;
this._signInButton.can_focus = sensitive;
}
},
_hidePrompt: function() {
if (this._promptEntryTextChangedId > 0) {
this._promptEntry.clutter_text.disconnect(this._promptEntryTextChangedId);
this._promptEntryTextChangedId = 0;
}
if (this._promptEntryActivateId > 0) {
this._promptEntry.clutter_text.disconnect(this._promptEntryActivateId);
this._promptEntryActivateId = 0;
}
this._setDefaultButtonWellMode(DefaultButtonWellMode.NONE, true);
this._promptBox.hide();
this._promptLoginHint.opacity = 0;
this._promptUser.set_child(null);
this._updateSensitivity(true);
this._promptEntry.set_text('');
this._sessionMenuButton.close();
this._promptLoginHint.opacity = 0;
this._buttonBox.remove_all_children();
this._signInButton = null;
this._cancelButton = null;
}, },
_askQuestion: function(verifier, serviceName, question, passwordChar) { _askQuestion: function(verifier, serviceName, question, passwordChar) {
this._promptLabel.set_text(question); this._authPrompt.setPasswordChar(passwordChar);
this._authPrompt.setQuestion(question);
this._updateSensitivity(true); this._updateSensitivity(true);
this._promptEntry.set_text('');
this._promptEntry.clutter_text.set_password_char(passwordChar); if (this._shouldShowSessionMenuButton())
this._authPrompt.setActorInDefaultButtonWell(this._sessionMenuButton.actor, true);
else
this._authPrompt.setActorInDefaultButtonWell(null, true);
let tasks = [function() { let tasks = [function() {
return this._showPrompt(!!passwordChar); return this._showPrompt(!!passwordChar);
}, },
function() { function() {
let text = this._promptEntry.get_text(); let text = this._authPrompt.getAnswer();
this._updateSensitivity(false); this._updateSensitivity(false);
this._setDefaultButtonWellMode(DefaultButtonWellMode.SPINNER, false); this._authPrompt.startSpinning();
this._userVerifier.answerQuery(serviceName, text); this._userVerifier.answerQuery(serviceName, text);
}]; }];
@@ -935,9 +719,8 @@ const LoginDialog = new Lang.Class({
}, },
_askForUsernameAndLogIn: function() { _askForUsernameAndLogIn: function() {
this._promptLabel.set_text(_("Username: ")); this._authPrompt.setPasswordChar('');
this._promptEntry.set_text(''); this._authPrompt.setQuestion(_("Username: "));
this._promptEntry.clutter_text.set_password_char('');
let realmManager = new Realmd.Manager(); let realmManager = new Realmd.Manager();
let signalId = realmManager.connect('login-format-changed', let signalId = realmManager.connect('login-format-changed',
@@ -947,8 +730,8 @@ const LoginDialog = new Lang.Class({
let tasks = [this._showPrompt, let tasks = [this._showPrompt,
function() { function() {
let userName = this._promptEntry.get_text(); let userName = this._authPrompt.getAnswer();
this._promptEntry.reactive = false; this._authPrompt._entry.reactive = false;
return this._beginVerificationForUser(userName); return this._beginVerificationForUser(userName);
}, },
@@ -1132,7 +915,8 @@ const LoginDialog = new Lang.Class({
}, },
_showUserList: function() { _showUserList: function() {
this._hidePrompt(); this._authPrompt.hide();
this._sessionMenuButton.close();
this._setUserListExpanded(true); this._setUserListExpanded(true);
this._notListedButton.show(); this._notListedButton.show();
this._userList.actor.grab_key_focus(); this._userList.actor.grab_key_focus();
@@ -1147,8 +931,7 @@ const LoginDialog = new Lang.Class({
}, },
_beginVerificationForItem: function(item) { _beginVerificationForItem: function(item) {
let userWidget = new UserWidget.UserWidget(item.user); this._authPrompt.setUser(item.user);
this._promptUser.set_child(userWidget.actor);
let tasks = [function() { let tasks = [function() {
let userName = item.user.get_user_name(); let userName = item.user.get_user_name();
@@ -1216,7 +999,7 @@ const LoginDialog = new Lang.Class({
}, },
addCharacter: function(unichar) { addCharacter: function(unichar) {
this._promptEntry.clutter_text.insert_unichar(unichar); this._authPrompt.addCharacter(unichar);
}, },
}); });
Signals.addSignalMethods(LoginDialog.prototype); Signals.addSignalMethods(LoginDialog.prototype);

View File

@@ -6,12 +6,16 @@ const GLib = imports.gi.GLib;
const Lang = imports.lang; const Lang = imports.lang;
const Mainloop = imports.mainloop; const Mainloop = imports.mainloop;
const Signals = imports.signals; const Signals = imports.signals;
const St = imports.gi.St;
const Animation = imports.ui.animation;
const Batch = imports.gdm.batch; const Batch = imports.gdm.batch;
const Fprint = imports.gdm.fingerprint; const Fprint = imports.gdm.fingerprint;
const Main = imports.ui.main; const Main = imports.ui.main;
const Params = imports.misc.params; const Params = imports.misc.params;
const ShellEntry = imports.ui.shellEntry;
const Tweener = imports.ui.tweener; const Tweener = imports.ui.tweener;
const UserWidget = imports.ui.userWidget;
const PASSWORD_SERVICE_NAME = 'gdm-password'; const PASSWORD_SERVICE_NAME = 'gdm-password';
const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint'; const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
@@ -30,6 +34,10 @@ const DISABLE_USER_LIST_KEY = 'disable-user-list';
// Give user 16ms to read each character of a PAM message // Give user 16ms to read each character of a PAM message
const USER_READ_TIME = 16 const USER_READ_TIME = 16
const DEFAULT_BUTTON_WELL_ICON_SIZE = 24;
const DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0;
const DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3;
function fadeInActor(actor) { function fadeInActor(actor) {
if (actor.opacity == 255 && actor.visible) if (actor.opacity == 255 && actor.visible)
return null; return null;
@@ -459,3 +467,337 @@ const ShellUserVerifier = new Lang.Class({
}, },
}); });
Signals.addSignalMethods(ShellUserVerifier.prototype); Signals.addSignalMethods(ShellUserVerifier.prototype);
const AuthPrompt = new Lang.Class({
Name: 'AuthPrompt',
_init: function(params) {
params = Params.parse(params,
{ style_class: 'login-dialog-prompt-layout',
vertical: true }, true);
this.actor = new St.BoxLayout(params);
this.actor.connect('button-press-event',
Lang.bind(this, function(actor, event) {
if (event.get_key_symbol() == Clutter.KEY_Escape) {
this.emit('cancel');
}
}));
this._userWell = new St.Bin({ x_fill: true,
x_align: St.Align.START });
this.actor.add(this._userWell,
{ x_align: St.Align.START,
x_fill: true,
y_fill: true,
expand: true });
this._label = new St.Label({ style_class: 'login-dialog-prompt-label' });
this.actor.add(this._label,
{ expand: true,
x_fill: true,
y_fill: true,
x_align: St.Align.START });
this._entry = new St.Entry({ style_class: 'login-dialog-prompt-entry',
can_focus: true });
ShellEntry.addContextMenu(this._entry, { isPassword: true });
this._entryTextChangedId = 0;
this._entryActivateId = 0;
this.actor.add(this._entry,
{ expand: true,
x_fill: true,
y_fill: false,
x_align: St.Align.START });
this._entry.grab_key_focus();
this._message = new St.Label({ opacity: 0 });
this.actor.add(this._message, { x_fill: true });
this._loginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' });
this.actor.add(this._loginHint);
this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box',
vertical: false });
this.actor.add(this._buttonBox,
{ expand: true,
x_align: St.Align.MIDDLE,
y_align: St.Align.END });
this._cancelButton = null;
this._nextButton = null;
this._defaultButtonWell = new St.Widget();
this._defaultButtonWellActor = null;
let spinnerIcon = global.datadir + '/theme/process-working.svg';
this._spinner = new Animation.AnimatedIcon(spinnerIcon, DEFAULT_BUTTON_WELL_ICON_SIZE);
this._spinner.actor.opacity = 0;
this._spinner.actor.show();
this._defaultButtonWell.add_child(this._spinner.actor);
},
addActorToDefaultButtonWell: function(actor) {
this._defaultButtonWell.add_child(actor);
actor.add_constraint(new Clutter.AlignConstraint({ source: this._spinner.actor,
align_axis: Clutter.AlignAxis.BOTH,
factor: 0.5 }));
},
setActorInDefaultButtonWell: function(actor, immediately) {
if (!this._defaultButtonWellActor &&
!actor)
return;
let oldActor = this._defaultButtonWellActor;
if (oldActor)
Tweener.removeTweens(oldActor);
let isWorkSpinner;
if (actor == this._spinner.actor)
isWorkSpinner = true;
else
isWorkSpinner = false;
if (this._defaultButtonWellActor != actor && oldActor) {
if (immediately)
oldActor.opacity = 0;
else
Tweener.addTween(oldActor,
{ opacity: 0,
time: DEFAULT_BUTTON_WELL_ANIMATION_TIME,
delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY,
transition: 'linear',
onCompleteScope: this,
onComplete: function() {
if (isWorkSpinner) {
if (this._spinner)
this._spinner.stop();
}
}
});
}
if (actor) {
if (isWorkSpinner)
this._spinner.play();
if (immediately)
actor.opacity = 255;
else
Tweener.addTween(actor,
{ opacity: 255,
time: DEFAULT_BUTTON_WELL_ANIMATION_TIME,
delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY,
transition: 'linear' });
}
this._defaultButtonWellActor = actor;
},
startSpinning: function() {
this.setActorInDefaultButtonWell(this._spinner.actor, true);
},
stopSpinning: function() {
this.setActorInDefaultButtonWell(null, true);
},
clear: function() {
this._entry.text = '';
},
setPasswordChar: function(passwordChar) {
this._entry.clutter_text.set_password_char(passwordChar);
this._entry.menu.isPassword = passwordChar != '';
},
setQuestion: function(question) {
if (!this._initialAnswer) {
this.clear();
} else if (this._initialAnswer['activate-id']) {
this._entry.clutter_text.disconnect(this._initialAnswer['activate-id']);
delete this._initialAnswer['activate-id'];
}
this._label.set_text(question);
this._label.show();
this._entry.show();
this._loginHint.opacity = 0;
this._loginHint.show();
this._entry.grab_key_focus();
},
getAnswer: function() {
let text;
if (this._initialAnswer && this._initialAnswer['text']) {
text = this._initialAnswer['text'];
this._initialAnswer = null;
} else {
text = this._entry.get_text();
}
return text;
},
setMessage: function(message, styleClass) {
if (message) {
this._message.text = message;
this._message.styleClass = styleClass;
this._message.opacity = 255;
} else {
this._message.opacity = 0;
}
},
resetButtons: function(cancelLabel, nextLabel) {
if (this._initialAnswer && this._initialAnswer['text']) {
this.emit('next');
return;
}
this._buttonBox.visible = true;
this._buttonBox.remove_all_children();
if (cancelLabel) {
this._cancelButton = new St.Button({ style_class: 'modal-dialog-button',
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
reactive: true,
can_focus: true,
label: cancelLabel });
this._cancelButton.connect('clicked',
Lang.bind(this, function() {
this.emit('cancel');
}));
this._buttonBox.add(this._cancelButton,
{ expand: false,
x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.END });
}
this._buttonBox.add(this._defaultButtonWell,
{ expand: true,
x_fill: false,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.MIDDLE });
this._nextButton = new St.Button({ style_class: 'modal-dialog-button',
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
reactive: true,
can_focus: true,
label: nextLabel });
this._nextButton.connect('clicked',
Lang.bind(this, function() {
this.emit('next');
}));
this._nextButton.add_style_pseudo_class('default');
this._buttonBox.add(this._nextButton,
{ expand: false,
x_fill: false,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.END });
this._updateNextButtonSensitivity(this._entry.text.length > 0);
this._entryTextChangedId =
this._entry.clutter_text.connect('text-changed',
Lang.bind(this, function() {
this._updateNextButtonSensitivity(this._entry.text.length > 0);
}));
this._entryActivateId =
this._entry.clutter_text.connect('activate', Lang.bind(this, function() {
this.emit('next');
}));
},
_updateNextButtonSensitivity: function(sensitive) {
if (this._nextButton) {
this._nextButton.reactive = sensitive;
this._nextButton.can_focus = sensitive;
}
},
updateSensitivity: function(sensitive) {
this._updateNextButtonSensitivity(sensitive);
this._entry.reactive = sensitive;
this._entry.clutter_text.editable = sensitive;
},
hide: function() {
if (this._entryTextChangedId > 0) {
this._entry.clutter_text.disconnect(this._entryTextChangedId);
this._entryTextChangedId = 0;
}
if (this._entryActivateId > 0) {
this._entry.clutter_text.disconnect(this._entryActivateId);
this._entryActivateId = 0;
}
this.setActorInDefaultButtonWell(null, true);
this.actor.hide();
this._loginHint.opacity = 0;
this.setUser(null);
this.updateSensitivity(true);
this._entry.set_text('');
this._buttonBox.remove_all_children();
this._nextButton = null;
this._cancelButton = null;
},
setUser: function(user) {
if (user) {
let userWidget = new UserWidget.UserWidget(user);
this._userWell.set_child(userWidget.actor);
} else {
this._userWell.set_child(null);
}
},
setHint: function(message) {
if (message) {
this._loginHint.set_text(message)
this._loginHint.opacity = 255;
} else {
this._loginHint.opacity = 0;
this._loginHint.set_text('');
}
},
reset: function() {
this._message.opacity = 0;
this.setUser(null);
},
addCharacter: function(unichar) {
if (!this._entry.visible)
return;
if (!this._initialAnswer)
this._initialAnswer = {};
this._entry.grab_key_focus();
this._entry.clutter_text.insert_unichar(unichar);
if (!this._initialAnswer['activate-id'])
this._initialAnswer['activate-id'] =
this._entry.clutter_text.connect('activate', Lang.bind(this, function() {
this._entry.clutter_text.disconnect(this._initialAnswer['activate-id']);
delete this._initialAnswer['activate-id'];
this._initialAnswer['text'] = this._entry.get_text();
}));
}
});
Signals.addSignalMethods(AuthPrompt.prototype);

View File

@@ -1,6 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const AccountsService = imports.gi.AccountsService; const AccountsService = imports.gi.AccountsService;
const Atk = imports.gi.Atk;
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const Gdm = imports.gi.Gdm; const Gdm = imports.gi.Gdm;
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
@@ -12,10 +13,9 @@ const Signals = imports.signals;
const Shell = imports.gi.Shell; const Shell = imports.gi.Shell;
const St = imports.gi.St; const St = imports.gi.St;
const Layout = imports.ui.layout;
const Main = imports.ui.main; const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
const Panel = imports.ui.panel; const Panel = imports.ui.panel;
const ShellEntry = imports.ui.shellEntry;
const Tweener = imports.ui.tweener; const Tweener = imports.ui.tweener;
const UserWidget = imports.ui.userWidget; const UserWidget = imports.ui.userWidget;
@@ -28,21 +28,20 @@ const IDLE_TIMEOUT = 2 * 60;
const UnlockDialog = new Lang.Class({ const UnlockDialog = new Lang.Class({
Name: 'UnlockDialog', Name: 'UnlockDialog',
Extends: ModalDialog.ModalDialog,
_init: function(parentActor) { _init: function(parentActor) {
this.parent({ shellReactive: true, this.actor = new St.Widget({ accessible_role: Atk.Role.WINDOW,
styleClass: 'login-dialog', style_class: 'login-dialog',
keybindingMode: Shell.KeyBindingMode.UNLOCK_SCREEN, visible: false });
parentActor: parentActor
}); this.actor.add_constraint(new Layout.MonitorConstraint({ primary: true }));
parentActor.add_child(this.actor);
this._userManager = AccountsService.UserManager.get_default(); this._userManager = AccountsService.UserManager.get_default();
this._userName = GLib.get_user_name(); this._userName = GLib.get_user_name();
this._user = this._userManager.get_user(this._userName); this._user = this._userManager.get_user(this._userName);
this._failCounter = 0; this._failCounter = 0;
this._firstQuestion = true;
this._greeterClient = new Gdm.Client(); this._greeterClient = new Gdm.Client();
this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient, { reauthenticationOnly: true }); this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient, { reauthenticationOnly: true });
@@ -57,62 +56,21 @@ const UnlockDialog = new Lang.Class({
this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint)); this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint));
this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint)); this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint));
this._userWidget = new UserWidget.UserWidget(this._user); this._promptBox = new St.BoxLayout({ vertical: true });
this.contentLayout.add_actor(this._userWidget.actor); this.actor.add_child(this._promptBox);
this._promptBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor,
align_axis: Clutter.AlignAxis.BOTH,
factor: 0.5 }));
this._promptLayout = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', this._authPrompt = new GdmUtil.AuthPrompt({ style_class: 'login-dialog-prompt-layout',
vertical: true }); vertical: true });
this._authPrompt.setUser(this._user);
this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' }); this._authPrompt.setPasswordChar('\u25cf');
this._promptLayout.add(this._promptLabel, this._authPrompt.resetButtons(_("Cancel"), _("Unlock"));
{ x_align: St.Align.START }); this._authPrompt.connect('cancel', Lang.bind(this, this._escape));
this._promptBox.add_child(this._authPrompt.actor);
this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry',
can_focus: true });
this._promptEntry.clutter_text.connect('activate', Lang.bind(this, this._doUnlock));
this._promptEntry.clutter_text.set_password_char('\u25cf');
ShellEntry.addContextMenu(this._promptEntry, { isPassword: true });
this.setInitialKeyFocus(this._promptEntry);
this._promptEntry.clutter_text.connect('text-changed', Lang.bind(this, function() {
this._updateOkButtonSensitivity(this._promptEntry.text.length > 0);
}));
this._promptLayout.add(this._promptEntry,
{ expand: true,
x_fill: true });
this.contentLayout.add_actor(this._promptLayout);
this._promptMessage = new St.Label({ visible: false });
this.contentLayout.add(this._promptMessage, { x_fill: true });
this._promptLoginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint' });
this._promptLoginHint.hide();
this.contentLayout.add_actor(this._promptLoginHint);
this.allowCancel = false; this.allowCancel = false;
this.buttonLayout.visible = true;
this.addButton({ label: _("Cancel"),
action: Lang.bind(this, this._escape),
key: Clutter.KEY_Escape },
{ expand: true,
x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.MIDDLE });
this.placeSpinner({ expand: false,
x_fill: false,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.MIDDLE });
this._okButton = this.addButton({ label: _("Unlock"),
action: Lang.bind(this, this._doUnlock),
default: true },
{ expand: false,
x_fill: false,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.MIDDLE });
let screenSaverSettings = new Gio.Settings({ schema: 'org.gnome.desktop.screensaver' }); let screenSaverSettings = new Gio.Settings({ schema: 'org.gnome.desktop.screensaver' });
if (screenSaverSettings.get_boolean('user-switch-enabled')) { if (screenSaverSettings.get_boolean('user-switch-enabled')) {
@@ -125,9 +83,7 @@ const UnlockDialog = new Lang.Class({
x_align: St.Align.START, x_align: St.Align.START,
x_fill: true }); x_fill: true });
this._otherUserButton.connect('clicked', Lang.bind(this, this._otherUserClicked)); this._otherUserButton.connect('clicked', Lang.bind(this, this._otherUserClicked));
this.dialogLayout.add(this._otherUserButton, this._promptBox.add_child(this._otherUserButton);
{ x_align: St.Align.START,
x_fill: false });
} else { } else {
this._otherUserButton = null; this._otherUserButton = null;
} }
@@ -137,80 +93,49 @@ const UnlockDialog = new Lang.Class({
let batch = new Batch.Hold(); let batch = new Batch.Hold();
this._userVerifier.begin(this._userName, batch); this._userVerifier.begin(this._userName, batch);
Main.ctrlAltTabManager.addGroup(this.dialogLayout, _("Unlock Window"), 'dialog-password-symbolic'); Main.ctrlAltTabManager.addGroup(this.actor, _("Unlock Window"), 'dialog-password-symbolic');
this._idleMonitor = new GnomeDesktop.IdleMonitor(); this._idleMonitor = new GnomeDesktop.IdleMonitor();
this._idleWatchId = this._idleMonitor.add_idle_watch(IDLE_TIMEOUT * 1000, Lang.bind(this, this._escape)); this._idleWatchId = this._idleMonitor.add_idle_watch(IDLE_TIMEOUT * 1000, Lang.bind(this, this._escape));
}, },
_updateSensitivity: function(sensitive) { _updateSensitivity: function(sensitive) {
this._promptEntry.reactive = sensitive; this._authPrompt.updateSensitivity(sensitive);
this._promptEntry.clutter_text.editable = sensitive;
this._updateOkButtonSensitivity(sensitive && this._promptEntry.text.length > 0);
if (this._otherUserButton) { if (this._otherUserButton) {
this._otherUserButton.reactive = sensitive; this._otherUserButton.reactive = sensitive;
this._otherUserButton.can_focus = sensitive; this._otherUserButton.can_focus = sensitive;
} }
}, },
_updateOkButtonSensitivity: function(sensitive) {
this._okButton.reactive = sensitive;
this._okButton.can_focus = sensitive;
},
_showMessage: function(userVerifier, message, styleClass) { _showMessage: function(userVerifier, message, styleClass) {
if (message) { this._authPrompt.setMessage(message, styleClass);
this._promptMessage.text = message;
this._promptMessage.styleClass = styleClass;
GdmUtil.fadeInActor(this._promptMessage);
} else {
GdmUtil.fadeOutActor(this._promptMessage);
}
}, },
_onAskQuestion: function(verifier, serviceName, question, passwordChar) { _onAskQuestion: function(verifier, serviceName, question, passwordChar) {
if (this._firstQuestion && this._firstQuestionAnswer) {
this._userVerifier.answerQuery(serviceName, this._firstQuestionAnswer);
this._firstQuestionAnswer = null;
this._firstQuestion = false;
return;
}
this._promptLabel.text = question;
if (!this._firstQuestion)
this._promptEntry.text = '';
else
this._firstQuestion = false;
this._promptEntry.clutter_text.set_password_char(passwordChar);
this._promptEntry.menu.isPassword = passwordChar != '';
this._currentQuery = serviceName; this._currentQuery = serviceName;
this._authPrompt.setPasswordChar(passwordChar);
this._authPrompt.setQuestion(question);
let signalId = this._authPrompt.connect('next', Lang.bind(this, function() {
this._authPrompt.disconnect(signalId);
this._doUnlock();
}));
this._updateSensitivity(true); this._updateSensitivity(true);
this.setWorking(false); this._authPrompt.stopSpinning();
}, },
_showLoginHint: function(verifier, message) { _showLoginHint: function(verifier, message) {
this._promptLoginHint.set_text(message) this._authPrompt.setHint(message);
GdmUtil.fadeInActor(this._promptLoginHint);
}, },
_hideLoginHint: function() { _hideLoginHint: function() {
GdmUtil.fadeOutActor(this._promptLoginHint); this._authPrompt.setHint(null);
}, },
_doUnlock: function() { _doUnlock: function() {
if (this._firstQuestion) {
// we haven't received a query yet, so stash the answer
// and make ourself non-reactive
// the actual reply to GDM will be sent as soon as asked
this._firstQuestionAnswer = this._promptEntry.text;
this._updateSensitivity(false);
this.setWorking(true);
return;
}
if (!this._currentQuery) if (!this._currentQuery)
return; return;
@@ -218,13 +143,16 @@ const UnlockDialog = new Lang.Class({
this._currentQuery = null; this._currentQuery = null;
this._updateSensitivity(false); this._updateSensitivity(false);
this.setWorking(true); this._authPrompt.startSpinning();
this._userVerifier.answerQuery(query, this._promptEntry.text); this._userVerifier.answerQuery(query, this._authPrompt.getAnswer());
}, },
_finishUnlock: function() { _finishUnlock: function() {
this._userVerifier.clear(); this._userVerifier.clear();
this._authPrompt.clear();
this._authPrompt.stopSpinning();
this._updateSensitivity(true);
this.emit('unlocked'); this.emit('unlocked');
}, },
@@ -253,12 +181,10 @@ const UnlockDialog = new Lang.Class({
this._firstQuestion = true; this._firstQuestion = true;
this._userVerified = false; this._userVerified = false;
this._promptEntry.text = ''; this._authPrompt.clear();
this._promptEntry.clutter_text.set_password_char('\u25cf');
this._promptEntry.menu.isPassword = true;
this._updateSensitivity(false); this._updateSensitivity(false);
this.setWorking(false); this._authPrompt.stopSpinning();
}, },
_escape: function() { _escape: function() {
@@ -282,8 +208,6 @@ const UnlockDialog = new Lang.Class({
this._idleMonitor.remove_watch(this._idleWatchId); this._idleMonitor.remove_watch(this._idleWatchId);
this._idleWatchId = 0; this._idleWatchId = 0;
} }
this.parent();
}, },
cancel: function() { cancel: function() {
@@ -293,6 +217,29 @@ const UnlockDialog = new Lang.Class({
}, },
addCharacter: function(unichar) { addCharacter: function(unichar) {
this._promptEntry.clutter_text.insert_unichar(unichar); this._authPrompt.addCharacter(unichar);
}, },
open: function(timestamp) {
this.actor.show();
if (this._isModal)
return true;
if (!Main.pushModal(this.actor, { timestamp: timestamp,
keybindingMode: Shell.KeyBindingMode.UNLOCK_SCREEN }))
return false;
this._isModal = true;
return true;
},
popModal: function(timestamp) {
if (this._isModal) {
Main.popModal(this.actor, timestamp);
this._isModal = false;
}
}
}); });
Signals.addSignalMethods(UnlockDialog.prototype);