Add UnlockDialog for unlocking the screen shield

When the screenshield is deactivated, instead of going back to the
session immediately, prompt the user for authentication.
This essentially reinstates what used to be provided by gnome-screensaver.

https://bugzilla.gnome.org/show_bug.cgi?id=619955
This commit is contained in:
Giovanni Campagna 2012-05-20 18:30:14 +02:00
parent 46db9edacc
commit 2c3ec7846f
6 changed files with 437 additions and 197 deletions

View File

@ -1,188 +0,0 @@
/* Copyright 2011, Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Login Dialog */
.login-dialog-banner {
font-size: 10pt;
font-weight: bold;
text-align: center;
color: #666666;
padding-bottom: 1em;
}
.login-dialog-title {
font-size: 14pt;
font-weight: bold;
color: #666666;
padding-bottom: 2em;
}
.login-dialog {
border-radius: 16px;
min-height: 150px;
max-height: 700px;
min-width: 350px;
}
.login-dialog-prompt-fingerprint-message {
font-size: 10.5pt;
}
.login-dialog-user-list-view {
-st-vfade-offset: 1em;
}
.login-dialog-user-list {
spacing: 12px;
}
.login-dialog-user-list-item {
color: #666666;
}
.login-dialog-user-list-item:ltr {
padding-right: 1em;
}
.login-dialog-user-list-item:rtl {
padding-left: 1em;
}
.login-dialog-user-list-item .login-dialog-user-list-item-name {
font-size: 20pt;
padding-left: 1em;
color: #666666;
}
.login-dialog-user-list-item:hover .login-dialog-user-list-item-name {
color: white;
}
.login-dialog-user-list-item:focus .login-dialog-user-list-item-name {
color: white;
text-shadow: black 0px 2px 2px;
}
.login-dialog-user-list-item-vertical-layout {
spacing: 2px;
}
.login-dialog-user-list-item .login-dialog-user-list-item-focus-bin {
background-color: rgba(0,0,0,0.0);
height: 2px;
}
.login-dialog-user-list-item:focus .login-dialog-user-list-item-focus-bin {
background-color: #666666;
}
.login-dialog-user-list-item-icon {
border: 2px solid #8b8b8b;
border-radius: 8px;
width: 64px;
height: 64px;
}
.login-dialog-not-listed-button {
padding-top: 2em;
}
.login-dialog-not-listed-label {
font-size: 14pt;
font-weight: bold;
color: #666666;
}
.login-dialog-not-listed-button:hover .login-dialog-not-listed-label {
color: white;
}
.login-dialog-prompt-layout {
padding-bottom: 32px;
}
.login-dialog-prompt-label {
color: white;
font-size: 20pt;
}
.login-dialog-prompt-entry {
padding: 4px;
border-radius: 4px;
border: 2px solid #5656cc;
color: black;
background-color: white;
caret-color: black;
caret-size: 1px;
width: 15em;
}
.login-dialog-prompt-entry .capslock-warning {
icon-size: 16px;
warning-color: #999;
}
.login-dialog-prompt-entry:insensitive {
color: rgba(0,0,0,0.7);
border: 2px solid #565656;
}
.login-dialog-session-list {
color: #ffffff;
font-size: 10.5pt;
}
.login-dialog-session-list-button {
padding: 4px;
}
.login-dialog-session-list-button:focus {
background-color: #4c4c4c;
}
.login-dialog-session-list-button:active {
background-color: #4c4c4c;
}
.login-dialog-session-list-button:hover {
font-weight: bold;
}
.login-dialog-session-list-scroll-view {
background-gradient-start: rgba(80,80,80,0.3);
background-gradient-end: rgba(80,80,80,0.7);
background-gradient-direction: vertical;
box-shadow: inset 0px 2px 4px rgba(0,0,0,0.9);
border-radius: 8px;
border: 1px solid rgba(80,80,80,1.0);
padding: .5em;
}
.login-dialog-session-list-item:focus {
background-color: #666666;
}
.login-dialog-session-list-triangle {
padding-right: .5em;
}
.login-dialog-session-list-item-box {
spacing: .25em;
}
.login-dialog-session-list-item-dot {
width: .75em;
height: .75em;
}

View File

@ -2008,3 +2008,189 @@ StScrollBar StButton#vhandle:hover
border-radius: 4px; border-radius: 4px;
background-color: rgba(255,255,255,0.33); background-color: rgba(255,255,255,0.33);
} }
/* Login Dialog */
.login-dialog-banner {
font-size: 10pt;
font-weight: bold;
text-align: center;
color: #666666;
padding-bottom: 1em;
}
.login-dialog-title {
font-size: 14pt;
font-weight: bold;
color: #666666;
padding-bottom: 2em;
}
.login-dialog {
border-radius: 16px;
min-height: 150px;
max-height: 700px;
min-width: 350px;
}
.login-dialog-prompt-fingerprint-message {
font-size: 10.5pt;
}
.login-dialog-user-list-view {
-st-vfade-offset: 1em;
}
.login-dialog-user-list {
spacing: 12px;
}
.login-dialog-user-list-item {
color: #666666;
}
.login-dialog-user-list-item:ltr {
padding-right: 1em;
}
.login-dialog-user-list-item:rtl {
padding-left: 1em;
}
.login-dialog-user-list-item .login-dialog-user-list-item-name {
font-size: 20pt;
padding-left: 1em;
color: #666666;
}
.login-dialog-user-list-item:hover .login-dialog-user-list-item-name {
color: white;
}
.login-dialog-user-list-item:focus .login-dialog-user-list-item-name {
color: white;
text-shadow: black 0px 2px 2px;
}
.login-dialog-user-list-item-vertical-layout {
spacing: 2px;
}
.login-dialog-user-list-item .login-dialog-user-list-item-focus-bin {
background-color: rgba(0,0,0,0.0);
height: 2px;
}
.login-dialog-user-list-item:focus .login-dialog-user-list-item-focus-bin {
background-color: #666666;
}
.login-dialog-user-list-item-icon {
border: 2px solid #8b8b8b;
border-radius: 8px;
width: 64px;
height: 64px;
}
.login-dialog-not-listed-label {
font-size: 14pt;
font-weight: bold;
color: #666666;
}
.login-dialog-not-listed-button:hover .login-dialog-not-listed-label {
color: #E8E8E8;
}
.login-dialog-prompt-layout {
padding-bottom: 32px;
}
.login-dialog-prompt-label {
color: white;
font-size: 20pt;
}
.login-dialog-prompt-entry {
padding: 4px;
border-radius: 4px;
border: 2px solid #5656cc;
color: black;
background-color: white;
caret-color: black;
caret-size: 1px;
width: 15em;
}
.login-dialog-prompt-entry .capslock-warning {
icon-size: 16px;
warning-color: #999;
}
.login-dialog-prompt-entry:insensitive {
color: rgba(0,0,0,0.7);
border: 2px solid #565656;
}
.login-dialog-session-list {
color: #ffffff;
font-size: 10.5pt;
}
.login-dialog-session-list-button {
padding: 4px;
}
.login-dialog-session-list-button:focus {
background-color: #4c4c4c;
}
.login-dialog-session-list-button:active {
background-color: #4c4c4c;
}
.login-dialog-session-list-button:hover {
font-weight: bold;
}
.login-dialog-session-list-scroll-view {
background-gradient-start: rgba(80,80,80,0.3);
background-gradient-end: rgba(80,80,80,0.7);
background-gradient-direction: vertical;
box-shadow: inset 0px 2px 4px rgba(0,0,0,0.9);
border-radius: 8px;
border: 1px solid rgba(80,80,80,1.0);
padding: .5em;
}
.login-dialog-session-list-item:focus {
background-color: #666666;
}
.login-dialog-session-list-triangle {
padding-right: .5em;
}
.login-dialog-session-list-item-box {
spacing: .25em;
}
.login-dialog-session-list-item-dot {
width: .75em;
height: .75em;
}
.unlock-dialog-user-name {
padding: 4px;
border-radius: 4px;
border: 2px solid #5656cc;
color: black;
background-color: white;
caret-color: black;
caret-size: 1px;
width: 15em;
text-align: right;
}
.unlock-dialog-user-name-container {
spacing: .4em;
}

View File

@ -91,6 +91,7 @@ nobase_dist_js_DATA = \
ui/status/bluetooth.js \ ui/status/bluetooth.js \
ui/telepathyClient.js \ ui/telepathyClient.js \
ui/tweener.js \ ui/tweener.js \
ui/unlockDialog.js \
ui/userMenu.js \ ui/userMenu.js \
ui/viewSelector.js \ ui/viewSelector.js \
ui/wanda.js \ ui/wanda.js \

View File

@ -8,7 +8,7 @@ const St = imports.gi.St;
const GnomeSession = imports.misc.gnomeSession; const GnomeSession = imports.misc.gnomeSession;
const Lightbox = imports.ui.lightbox; const Lightbox = imports.ui.lightbox;
const LoginDialog = imports.gdm.loginDialog; const UnlockDialog = imports.ui.unlockDialog;
const Main = imports.ui.main; const Main = imports.ui.main;
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver'; const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
@ -48,8 +48,7 @@ const ScreenShield = new Lang.Class({
let constraint = new Clutter.BindConstraint({ source: global.stage, let constraint = new Clutter.BindConstraint({ source: global.stage,
coordinate: Clutter.BindCoordinate.POSITION | Clutter.BindCoordinate.SIZE }); coordinate: Clutter.BindCoordinate.POSITION | Clutter.BindCoordinate.SIZE });
this._group.add_constraint(constraint); this._group.add_constraint(constraint);
this._group.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
this._group.connect('button-press-event', Lang.bind(this, this._onButtonPressEvent));
this._lightbox = new Lightbox.Lightbox(this._group, this._lightbox = new Lightbox.Lightbox(this._group,
{ inhibitEvents: true, fadeInTime: 10, fadeFactor: 1 }); { inhibitEvents: true, fadeInTime: 10, fadeFactor: 1 });
this._background = Meta.BackgroundActor.new_for_screen(global.screen); this._background = Meta.BackgroundActor.new_for_screen(global.screen);
@ -71,6 +70,8 @@ const ScreenShield = new Lang.Class({
if (lightboxWasShown && this._settings.get_boolean(LOCK_ENABLED_KEY)) { if (lightboxWasShown && this._settings.get_boolean(LOCK_ENABLED_KEY)) {
this._background.show(); this._background.show();
this._background.raise_top(); this._background.raise_top();
this._showUnlockDialog();
} else { } else {
this._popModal(); this._popModal();
} }
@ -84,13 +85,32 @@ const ScreenShield = new Lang.Class({
this._background.hide(); this._background.hide();
}, },
_onKeyPressEvent: function(object, keyPressEvent) { _showUnlockDialog: function() {
log("in _onKeyPressEvent - lock is enabled: " + this._settings.get_boolean(LOCK_ENABLED_KEY)); if (this._dialog)
this._popModal(); return;
this._dialog = new UnlockDialog.UnlockDialog();
this._dialog.connect('failed', Lang.bind(this, this._onUnlockFailed));
this._dialog.connect('unlocked', Lang.bind(this, this._onUnlockSucceded));
this._dialog.open(global.get_current_time());
}, },
_onButtonPressEvent: function(object, buttonPressEvent) { _onUnlockFailed: function() {
log("in _onButtonPressEvent - lock is enabled: " + this._settings.get_boolean(LOCK_ENABLED_KEY)); // for now, on failure we just destroy the dialog and create a new
// one (this is what gnome-screensaver does)
// in the future, we may want to go back to the lock screen instead
this._dialog.destroy();
this._dialog = null;
this._showUnlockDialog();
},
_onUnlockSucceded: function() {
this._dialog.destroy();
this._dialog = null;
this._popModal(); this._popModal();
}, },
}); });

View File

@ -39,7 +39,7 @@ const _modes = {
hasRunDialog: false, hasRunDialog: false,
hasWorkspaces: false, hasWorkspaces: false,
createSession: Main.createGDMSession, createSession: Main.createGDMSession,
extraStylesheet: global.datadir + '/theme/gdm.css', extraStylesheet: null,
statusArea: { statusArea: {
order: [ order: [
'a11y', 'display', 'keyboard', 'a11y', 'display', 'keyboard',

221
js/ui/unlockDialog.js Normal file
View File

@ -0,0 +1,221 @@
// -*- 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 Mainloop = imports.mainloop;
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;
// 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: 'unlock-dialog-user-name' });
this.actor.add(this._label,
{ expand: true,
x_fill: true,
y_fill: true });
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() {
this.parent({ shellReactive: true,
styleClass: 'login-dialog' });
this._userManager = AccountsService.UserManager.get_default();
this._userName = GLib.get_user_name();
this._user = this._userManager.get_user(this._userName);
this._greeterClient = new Gdm.Client();
this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient);
this._userVerifier.connect('reset', Lang.bind(this, this._reset));
this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion));
this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete));
this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed));
this._userVerifier.connect('show-fingerprint-prompt', Lang.bind(this, this._showFingerprintPrompt));
this._userVerifier.connect('hide-fingerprint-prompt', Lang.bind(this, this._hideFingerprintPrompt));
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: false });
this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' });
this._promptLayout.add(this._promptLabel,
{ expand: false,
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 });
ShellEntry.addContextMenu(this._promptEntry);
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,
y_fill: false,
x_align: St.Align.START });
this.contentLayout.add_actor(this._promptLayout);
// Translators: this message is shown below the password entry field
// to indicate the user can swipe their finger instead
this._promptFingerprintMessage = new St.Label({ text: _("(or swipe finger)"),
style_class: 'login-dialog-prompt-fingerprint-message' });
this._promptFingerprintMessage.hide();
this.contentLayout.add_actor(this._promptFingerprintMessage);
let otherUserLabel = new St.Label({ text: _("Login 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.contentLayout.add(this._otherUserButton,
{ x_align: St.Align.START,
x_fill: false });
this._okButton = { label: _("Unlock"),
action: Lang.bind(this, this._doUnlock),
default: true };
this.setButtons([this._okButton]);
this._updateOkButton(false);
this._reset();
},
_updateOkButton: function(sensitive) {
this._okButton.button.reactive = sensitive;
},
_reset: function() {
this._userVerifier.begin(this._userName, new Batch.Hold());
},
_onAskQuestion: function(verifier, serviceName, question, passwordChar) {
this._promptLabel.text = question;
this._promptEntry.text = '';
this._promptEntry.clutter_text.set_password_char(passwordChar);
this._promptEntry.menu.isPassword = passwordChar != '';
this._currentQuery = serviceName;
this._updateOkButton(true);
},
_showFingerprintPrompt: function() {
GdmUtil.fadeInActor(this._promptFingerprintMessage);
},
_hideFingerprintPrompt: function() {
GdmUtil.fadeOutActor(this._promptFingerprintMessage);
},
_doUnlock: function() {
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');
},
_onVerificationFailed: function() {
this._userVerifier.cancel();
this.emit('failed');
},
_otherUserClicked: function(button, event) {
this._userManager.goto_login_session();
this._userVerifier.cancel();
this.emit('failed');
},
destroy: function() {
this._userVerifier.clear();
this.parent();
},
cancel: function() {
this._userVerifier.cancel(null);
this.destroy();
},
});