gnome-shell/js/ui/unlockDialog.js
Giovanni Campagna de93677271 Allow the shell to run without the screenshield
The screenshield requires gdm 3.5, which can be problematic in
jhbuild configurations, or distributions that don't use GDM as the display
manager. Allow transparent fallback to gnome-screensaver in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=683060
2012-09-18 20:25:09 +02:00

304 lines
11 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 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 ShellEntry = imports.ui.shellEntry;
const Tweener = imports.ui.tweener;
const UserMenu = imports.ui.userMenu;
const Batch = imports.gdm.batch;
const GdmUtil = imports.gdm.util;
// 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;
}
}
// A widget showing the user avatar and name
const UserWidget = new Lang.Class({
Name: 'UserWidget',
_init: function(user) {
this._user = user;
this.actor = new St.BoxLayout({ style_class: 'unlock-dialog-user-name-container',
vertical: false });
this._avatar = new UserMenu.UserAvatarWidget(user);
this.actor.add(this._avatar.actor,
{ x_fill: true, y_fill: true });
this._label = new St.Label({ style_class: 'login-dialog-username' });
this.actor.add(this._label,
{ expand: true,
x_fill: true,
y_fill: false,
y_align: St.Align.MIDDLE });
this._userLoadedId = this._user.connect('notify::is-loaded',
Lang.bind(this, this._updateUser));
this._userChangedId = this._user.connect('changed',
Lang.bind(this, this._updateUser));
if (this._user.is_loaded)
this._updateUser();
},
destroy: function() {
if (this._userLoadedId != 0) {
this._user.disconnect(this._userLoadedId);
this._userLoadedId = 0;
}
if (this._userChangedId != 0) {
this._user.disconnect(this._userChangedId);
this._userChangedId = 0;
}
this.actor.destroy();
},
_updateUser: function() {
if (this._user.is_loaded)
this._label.text = this._user.get_real_name();
else
this._label.text = '';
this._avatar.update();
}
});
const UnlockDialog = new Lang.Class({
Name: 'UnlockDialog',
Extends: ModalDialog.ModalDialog,
_init: function(parentActor) {
this.parent({ shellReactive: true,
styleClass: 'login-dialog',
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('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(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('activate', Lang.bind(this, this._doUnlock));
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);
let cancelButton = { label: _("Cancel"),
action: Lang.bind(this, this._escape),
key: Clutter.KEY_Escape };
this._okButton = { label: _("Unlock"),
action: Lang.bind(this, this._doUnlock),
default: true };
this.setButtons([cancelButton, this._okButton]);
this._updateOkButton(true);
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 });
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;
}));
this._idleMonitor = Shell.IdleMonitor.get();
// this dialog is only created after user activity (curtain drag or
// escape key press), so the timeout will fire after IDLE_TIMEOUT seconds of inactivity
this._idleWatchId = this._idleMonitor.add_watch(IDLE_TIMEOUT * 1000, Lang.bind(this, this._escape));
},
_updateOkButton: function(sensitive) {
this._okButton.button.reactive = sensitive;
this._okButton.button.can_focus = sensitive;
},
_showMessage: function(userVerifier, message, styleClass) {
this._promptMessage.text = message;
this._promptMessage.styleClass = styleClass;
GdmUtil.fadeInActor(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._updateOkButton(true);
},
_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._updateOkButton(false);
return;
}
if (!this._currentQuery)
return;
let query = this._currentQuery;
this._currentQuery = null;
this._updateOkButton(false);
this._userVerifier.answerQuery(query, this._promptEntry.text);
},
_onVerificationComplete: function() {
this._userVerifier.clear();
this.emit('unlocked');
},
_onReset: function() {
this.emit('failed');
},
_escape: function() {
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();
},
});