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;
color: #666666;
padding-top: 1em;
}
.login-dialog-user-selection-box .login-dialog-not-listed-label {
padding-left: 2px;
}

View File

@ -32,7 +32,6 @@ const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
const Animation = imports.ui.animation;
const Batch = imports.gdm.batch;
const BoxPointer = imports.ui.boxpointer;
const CtrlAltTab = imports.ui.ctrlAltTab;
@ -46,20 +45,11 @@ const UserWidget = imports.ui.userWidget;
const _FADE_ANIMATION_TIME = 0.25;
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 _LOGO_ICON_HEIGHT = 48;
let _loginDialog = null;
const DefaultButtonWellMode = {
NONE: 0,
SESSION_MENU_BUTTON: 1,
SPINNER: 2
};
const UserListItem = new Lang.Class({
Name: 'UserListItem',
@ -466,67 +456,20 @@ const LoginDialog = new Lang.Class({
x_fill: true,
y_fill: true });
this._promptBox = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout',
vertical: true });
this._promptBox.connect('button-press-event',
Lang.bind(this, function(actor, event) {
if (event.get_key_symbol() == Clutter.KEY_Escape) {
this._authPrompt = new GdmUtil.AuthPrompt({ visible: false });
this._authPrompt.connect('cancel',
Lang.bind(this, function() {
this.cancel();
}
}));
this._promptBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor,
align_axis: Clutter.AlignAxis.BOTH,
factor: 0.5 }));
this._authPrompt.actor.add_constraint(new Clutter.AlignConstraint({ source: this.actor,
align_axis: Clutter.AlignAxis.BOTH,
factor: 0.5 }));
this.actor.add_child(this._promptBox);
this._userList.actor.add_constraint(new Clutter.BindConstraint({ source: this._promptBox,
this.actor.add_child(this._authPrompt.actor);
this._userList.actor.add_constraint(new Clutter.BindConstraint({ source: this._authPrompt.actor,
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
// login screen. It can be activated to reveal an entry for
// manually entering the username.
@ -576,8 +519,6 @@ const LoginDialog = new Lang.Class({
this._onUserListActivated(item);
}));
this._defaultButtonWell = new St.Widget();
this._defaultButtonWellMode = DefaultButtonWellMode.NONE;
this._sessionMenuButton = new SessionMenuButton();
this._sessionMenuButton.connect('session-activated',
@ -586,17 +527,8 @@ const LoginDialog = new Lang.Class({
}));
this._sessionMenuButton.actor.opacity = 0;
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() {
@ -644,7 +576,8 @@ const LoginDialog = new Lang.Class({
this._userVerifier.clear();
this._updateSensitivity(true);
this._promptMessage.opacity = 0;
this._authPrompt.reset();
this._user = null;
this._verifyingUser = false;
@ -654,73 +587,11 @@ const LoginDialog = new Lang.Class({
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() {
this._promptEntry.text = '';
this._authPrompt.clear();
this._updateSensitivity(true);
this._setDefaultButtonWellMode(DefaultButtonWellMode.NONE, true);
this._authPrompt.setActorInDefaultButtonWell(null, true);
},
_onDefaultSessionChanged: function(client, sessionId) {
@ -728,23 +599,15 @@ const LoginDialog = new Lang.Class({
},
_showMessage: function(userVerifier, message, styleClass) {
if (message) {
this._promptMessage.text = message;
this._promptMessage.styleClass = styleClass;
this._promptMessage.opacity = 255;
} else {
this._promptMessage.opacity = 0;
}
this._authPrompt.setMessage(message, styleClass);
},
_showLoginHint: function(verifier, message) {
this._promptLoginHint.set_text(message)
this._promptLoginHint.opacity = 255;
this._authPrompt.setHint(message);
},
_hideLoginHint: function() {
this._promptLoginHint.opacity = 0;
this._promptLoginHint.set_text('');
this._authPrompt.setHint(null);
},
cancel: function() {
@ -768,27 +631,16 @@ const LoginDialog = new Lang.Class({
},
_showPrompt: function(forSecret) {
this._promptLabel.show();
this._promptEntry.show();
this._promptLoginHint.opacity = 0;
this._promptLoginHint.show();
this._promptBox.opacity = 0;
this._promptBox.show();
Tweener.addTween(this._promptBox,
this._authPrompt.actor.opacity = 0;
this._authPrompt.actor.show();
Tweener.addTween(this._authPrompt.actor,
{ opacity: 255,
time: _FADE_ANIMATION_TIME,
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 tasks = [function() {
this._prepareDialog(forSecret, hold);
this._preparePrompt(forSecret, hold);
},
hold];
@ -798,122 +650,54 @@ const LoginDialog = new Lang.Class({
return batch.run();
},
_prepareDialog: function(forSecret, hold) {
this._buttonBox.visible = true;
this._buttonBox.remove_all_children();
_preparePrompt: function(forSecret, hold) {
let cancelLabel;
if (!this._disableUserList || this._verifyingUser) {
this._cancelButton = new St.Button({ style_class: 'modal-dialog-button',
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
reactive: true,
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 });
cancelLabel = _("Cancel");
} else {
cancelLabel = null;
}
this._buttonBox.add(this._defaultButtonWell,
{ expand: true,
x_fill: false,
y_fill: false,
x_align: St.Align.END,
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 });
let nextLabel;
if (forSecret) {
nextLabel = C_("button", "Sign In");
} else {
nextLabel = _("Next");
}
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._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();
});
this._authPrompt.resetButtons(cancelLabel, nextLabel);
},
_updateSensitivity: function(sensitive) {
this._promptEntry.reactive = sensitive;
this._promptEntry.clutter_text.editable = sensitive;
this._sessionMenuButton.updateSensitivity(sensitive);
this._updateSignInButtonSensitivity(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;
this._authPrompt.updateSensitivity(sensitive);
},
_askQuestion: function(verifier, serviceName, question, passwordChar) {
this._promptLabel.set_text(question);
this._authPrompt.setPasswordChar(passwordChar);
this._authPrompt.setQuestion(question);
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() {
return this._showPrompt(!!passwordChar);
},
function() {
let text = this._promptEntry.get_text();
let text = this._authPrompt.getAnswer();
this._updateSensitivity(false);
this._setDefaultButtonWellMode(DefaultButtonWellMode.SPINNER, false);
this._authPrompt.startSpinning();
this._userVerifier.answerQuery(serviceName, text);
}];
@ -935,9 +719,8 @@ const LoginDialog = new Lang.Class({
},
_askForUsernameAndLogIn: function() {
this._promptLabel.set_text(_("Username: "));
this._promptEntry.set_text('');
this._promptEntry.clutter_text.set_password_char('');
this._authPrompt.setPasswordChar('');
this._authPrompt.setQuestion(_("Username: "));
let realmManager = new Realmd.Manager();
let signalId = realmManager.connect('login-format-changed',
@ -947,8 +730,8 @@ const LoginDialog = new Lang.Class({
let tasks = [this._showPrompt,
function() {
let userName = this._promptEntry.get_text();
this._promptEntry.reactive = false;
let userName = this._authPrompt.getAnswer();
this._authPrompt._entry.reactive = false;
return this._beginVerificationForUser(userName);
},
@ -1132,7 +915,8 @@ const LoginDialog = new Lang.Class({
},
_showUserList: function() {
this._hidePrompt();
this._authPrompt.hide();
this._sessionMenuButton.close();
this._setUserListExpanded(true);
this._notListedButton.show();
this._userList.actor.grab_key_focus();
@ -1147,8 +931,7 @@ const LoginDialog = new Lang.Class({
},
_beginVerificationForItem: function(item) {
let userWidget = new UserWidget.UserWidget(item.user);
this._promptUser.set_child(userWidget.actor);
this._authPrompt.setUser(item.user);
let tasks = [function() {
let userName = item.user.get_user_name();
@ -1216,7 +999,7 @@ const LoginDialog = new Lang.Class({
},
addCharacter: function(unichar) {
this._promptEntry.clutter_text.insert_unichar(unichar);
this._authPrompt.addCharacter(unichar);
},
});
Signals.addSignalMethods(LoginDialog.prototype);

View File

@ -6,12 +6,16 @@ const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const St = imports.gi.St;
const Animation = imports.ui.animation;
const Batch = imports.gdm.batch;
const Fprint = imports.gdm.fingerprint;
const Main = imports.ui.main;
const Params = imports.misc.params;
const ShellEntry = imports.ui.shellEntry;
const Tweener = imports.ui.tweener;
const UserWidget = imports.ui.userWidget;
const PASSWORD_SERVICE_NAME = 'gdm-password';
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
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) {
if (actor.opacity == 255 && actor.visible)
return null;
@ -459,3 +467,337 @@ const ShellUserVerifier = new Lang.Class({
},
});
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 -*-
const AccountsService = imports.gi.AccountsService;
const Atk = imports.gi.Atk;
const Clutter = imports.gi.Clutter;
const Gdm = imports.gi.Gdm;
const Gio = imports.gi.Gio;
@ -12,10 +13,9 @@ const Signals = imports.signals;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Layout = imports.ui.layout;
const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
const Panel = imports.ui.panel;
const ShellEntry = imports.ui.shellEntry;
const Tweener = imports.ui.tweener;
const UserWidget = imports.ui.userWidget;
@ -28,21 +28,20 @@ const IDLE_TIMEOUT = 2 * 60;
const UnlockDialog = new Lang.Class({
Name: 'UnlockDialog',
Extends: ModalDialog.ModalDialog,
_init: function(parentActor) {
this.parent({ shellReactive: true,
styleClass: 'login-dialog',
keybindingMode: Shell.KeyBindingMode.UNLOCK_SCREEN,
parentActor: parentActor
});
this.actor = new St.Widget({ accessible_role: Atk.Role.WINDOW,
style_class: 'login-dialog',
visible: false });
this.actor.add_constraint(new Layout.MonitorConstraint({ primary: true }));
parentActor.add_child(this.actor);
this._userManager = AccountsService.UserManager.get_default();
this._userName = GLib.get_user_name();
this._user = this._userManager.get_user(this._userName);
this._failCounter = 0;
this._firstQuestion = true;
this._greeterClient = new Gdm.Client();
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('hide-login-hint', Lang.bind(this, this._hideLoginHint));
this._userWidget = new UserWidget.UserWidget(this._user);
this.contentLayout.add_actor(this._userWidget.actor);
this._promptBox = new St.BoxLayout({ vertical: true });
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',
vertical: true });
this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' });
this._promptLayout.add(this._promptLabel,
{ x_align: St.Align.START });
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._authPrompt = new GdmUtil.AuthPrompt({ style_class: 'login-dialog-prompt-layout',
vertical: true });
this._authPrompt.setUser(this._user);
this._authPrompt.setPasswordChar('\u25cf');
this._authPrompt.resetButtons(_("Cancel"), _("Unlock"));
this._authPrompt.connect('cancel', Lang.bind(this, this._escape));
this._promptBox.add_child(this._authPrompt.actor);
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' });
if (screenSaverSettings.get_boolean('user-switch-enabled')) {
@ -125,9 +83,7 @@ const UnlockDialog = new Lang.Class({
x_align: St.Align.START,
x_fill: true });
this._otherUserButton.connect('clicked', Lang.bind(this, this._otherUserClicked));
this.dialogLayout.add(this._otherUserButton,
{ x_align: St.Align.START,
x_fill: false });
this._promptBox.add_child(this._otherUserButton);
} else {
this._otherUserButton = null;
}
@ -137,80 +93,49 @@ const UnlockDialog = new Lang.Class({
let batch = new Batch.Hold();
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._idleWatchId = this._idleMonitor.add_idle_watch(IDLE_TIMEOUT * 1000, Lang.bind(this, this._escape));
},
_updateSensitivity: function(sensitive) {
this._promptEntry.reactive = sensitive;
this._promptEntry.clutter_text.editable = sensitive;
this._updateOkButtonSensitivity(sensitive && this._promptEntry.text.length > 0);
this._authPrompt.updateSensitivity(sensitive);
if (this._otherUserButton) {
this._otherUserButton.reactive = sensitive;
this._otherUserButton.can_focus = sensitive;
}
},
_updateOkButtonSensitivity: function(sensitive) {
this._okButton.reactive = sensitive;
this._okButton.can_focus = sensitive;
},
_showMessage: function(userVerifier, message, styleClass) {
if (message) {
this._promptMessage.text = message;
this._promptMessage.styleClass = styleClass;
GdmUtil.fadeInActor(this._promptMessage);
} else {
GdmUtil.fadeOutActor(this._promptMessage);
}
this._authPrompt.setMessage(message, styleClass);
},
_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._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.setWorking(false);
this._authPrompt.stopSpinning();
},
_showLoginHint: function(verifier, message) {
this._promptLoginHint.set_text(message)
GdmUtil.fadeInActor(this._promptLoginHint);
this._authPrompt.setHint(message);
},
_hideLoginHint: function() {
GdmUtil.fadeOutActor(this._promptLoginHint);
this._authPrompt.setHint(null);
},
_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)
return;
@ -218,13 +143,16 @@ const UnlockDialog = new Lang.Class({
this._currentQuery = null;
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() {
this._userVerifier.clear();
this._authPrompt.clear();
this._authPrompt.stopSpinning();
this._updateSensitivity(true);
this.emit('unlocked');
},
@ -253,12 +181,10 @@ const UnlockDialog = new Lang.Class({
this._firstQuestion = true;
this._userVerified = false;
this._promptEntry.text = '';
this._promptEntry.clutter_text.set_password_char('\u25cf');
this._promptEntry.menu.isPassword = true;
this._authPrompt.clear();
this._updateSensitivity(false);
this.setWorking(false);
this._authPrompt.stopSpinning();
},
_escape: function() {
@ -282,8 +208,6 @@ const UnlockDialog = new Lang.Class({
this._idleMonitor.remove_watch(this._idleWatchId);
this._idleWatchId = 0;
}
this.parent();
},
cancel: function() {
@ -293,6 +217,29 @@ const UnlockDialog = new Lang.Class({
},
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);