a3d3d81447
The user widget is the username and avatar shown on the unlock dialog. The login dialog has something very similar. This commit separates the user widget out to its own file, so we can use it from the login dialog in a later commit. https://bugzilla.gnome.org/show_bug.cgi?id=694062
337 lines
12 KiB
JavaScript
337 lines
12 KiB
JavaScript
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
|
|
const AccountsService = imports.gi.AccountsService;
|
|
const Clutter = imports.gi.Clutter;
|
|
const Gdm = imports.gi.Gdm;
|
|
const Gio = imports.gi.Gio;
|
|
const GLib = imports.gi.GLib;
|
|
const GnomeDesktop = imports.gi.GnomeDesktop;
|
|
const Gtk = imports.gi.Gtk;
|
|
const Lang = imports.lang;
|
|
const Signals = imports.signals;
|
|
const Shell = imports.gi.Shell;
|
|
const St = imports.gi.St;
|
|
|
|
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 UserMenu = imports.ui.userMenu;
|
|
const UserWidget = imports.ui.userWidget;
|
|
|
|
const Batch = imports.gdm.batch;
|
|
const GdmUtil = imports.gdm.util;
|
|
const LoginDialog = imports.gdm.loginDialog;
|
|
|
|
// The timeout before going back automatically to the lock screen (in seconds)
|
|
const IDLE_TIMEOUT = 2 * 60;
|
|
|
|
function versionCompare(required, reference) {
|
|
required = required.split('.');
|
|
reference = reference.split('.');
|
|
|
|
for (let i = 0; i < required.length; i++) {
|
|
if (required[i] != reference[i])
|
|
return required[i] < reference[i];
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function isSupported() {
|
|
try {
|
|
let params = GLib.Variant.new('(ss)', ['org.gnome.DisplayManager.Manager', 'Version']);
|
|
let result = Gio.DBus.system.call_sync('org.gnome.DisplayManager',
|
|
'/org/gnome/DisplayManager/Manager',
|
|
'org.freedesktop.DBus.Properties',
|
|
'Get', params, null,
|
|
Gio.DBusCallFlags.NONE,
|
|
-1, null);
|
|
|
|
let version = result.deep_unpack()[0].deep_unpack();
|
|
return versionCompare('3.5.91', version);
|
|
} catch(e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
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._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 });
|
|
|
|
this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion));
|
|
this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage));
|
|
this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete));
|
|
this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed));
|
|
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
|
|
|
|
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._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.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._workSpinner = new Panel.AnimatedIcon('process-working.svg', LoginDialog.WORK_SPINNER_ICON_SIZE);
|
|
this._workSpinner.actor.opacity = 0;
|
|
|
|
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.buttonLayout.add(this._workSpinner.actor,
|
|
{ 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')) {
|
|
let otherUserLabel = new St.Label({ text: _("Log in as another user"),
|
|
style_class: 'login-dialog-not-listed-label' });
|
|
this._otherUserButton = new St.Button({ style_class: 'login-dialog-not-listed-button',
|
|
can_focus: true,
|
|
child: otherUserLabel,
|
|
reactive: true,
|
|
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 });
|
|
} else {
|
|
this._otherUserButton = null;
|
|
}
|
|
|
|
this._updateSensitivity(true);
|
|
|
|
let batch = new Batch.Hold();
|
|
this._userVerifier.begin(this._userName, batch);
|
|
|
|
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
|
|
this.emit('loaded');
|
|
return false;
|
|
}));
|
|
|
|
Main.ctrlAltTabManager.addGroup(this.dialogLayout, _("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);
|
|
if (this._otherUserButton) {
|
|
this._otherUserButton.reactive = sensitive;
|
|
this._otherUserButton.can_focus = sensitive;
|
|
}
|
|
},
|
|
|
|
_updateOkButtonSensitivity: function(sensitive) {
|
|
this._okButton.reactive = sensitive;
|
|
this._okButton.can_focus = sensitive;
|
|
},
|
|
|
|
_setWorking: function(working) {
|
|
if (working) {
|
|
this._workSpinner.play();
|
|
Tweener.addTween(this._workSpinner.actor,
|
|
{ opacity: 255,
|
|
delay: LoginDialog.WORK_SPINNER_ANIMATION_DELAY,
|
|
time: LoginDialog.WORK_SPINNER_ANIMATION_TIME,
|
|
transition: 'linear'
|
|
});
|
|
} else {
|
|
Tweener.addTween(this._workSpinner.actor,
|
|
{ opacity: 0,
|
|
time: LoginDialog.WORK_SPINNER_ANIMATION_TIME,
|
|
transition: 'linear',
|
|
onCompleteScope: this,
|
|
onComplete: function() {
|
|
this._workSpinner.stop();
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
_showMessage: function(userVerifier, message, styleClass) {
|
|
if (message) {
|
|
this._promptMessage.text = message;
|
|
this._promptMessage.styleClass = styleClass;
|
|
GdmUtil.fadeInActor(this._promptMessage);
|
|
} else {
|
|
GdmUtil.fadeOutActor(this._promptMessage);
|
|
}
|
|
},
|
|
|
|
_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._updateSensitivity(true);
|
|
this._setWorking(false);
|
|
},
|
|
|
|
_showLoginHint: function(verifier, message) {
|
|
this._promptLoginHint.set_text(message)
|
|
GdmUtil.fadeInActor(this._promptLoginHint);
|
|
},
|
|
|
|
_hideLoginHint: function() {
|
|
GdmUtil.fadeOutActor(this._promptLoginHint);
|
|
},
|
|
|
|
_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;
|
|
|
|
let query = this._currentQuery;
|
|
this._currentQuery = null;
|
|
|
|
this._updateSensitivity(false);
|
|
this._setWorking(true);
|
|
|
|
this._userVerifier.answerQuery(query, this._promptEntry.text);
|
|
},
|
|
|
|
_onVerificationComplete: function() {
|
|
this._userVerifier.clear();
|
|
this.emit('unlocked');
|
|
},
|
|
|
|
_onReset: function() {
|
|
this.emit('failed');
|
|
},
|
|
|
|
_onVerificationFailed: function() {
|
|
this._currentQuery = null;
|
|
this._firstQuestion = true;
|
|
|
|
this._promptEntry.text = '';
|
|
this._promptEntry.clutter_text.set_password_char('\u25cf');
|
|
this._promptEntry.menu.isPassword = true;
|
|
|
|
this._updateSensitivity(false);
|
|
this._setWorking(false);
|
|
},
|
|
|
|
_escape: function() {
|
|
if (this.allowCancel) {
|
|
this._userVerifier.cancel();
|
|
this.emit('failed');
|
|
}
|
|
},
|
|
|
|
_otherUserClicked: function(button, event) {
|
|
Gdm.goto_login_session_sync(null);
|
|
|
|
this._userVerifier.cancel();
|
|
this.emit('failed');
|
|
},
|
|
|
|
destroy: function() {
|
|
this._userVerifier.clear();
|
|
|
|
if (this._idleWatchId) {
|
|
this._idleMonitor.remove_watch(this._idleWatchId);
|
|
this._idleWatchId = 0;
|
|
}
|
|
|
|
this.parent();
|
|
},
|
|
|
|
cancel: function() {
|
|
this._userVerifier.cancel(null);
|
|
|
|
this.destroy();
|
|
},
|
|
});
|