Compare commits
6 Commits
citadel
...
wip/screen
Author | SHA1 | Date | |
---|---|---|---|
|
352ad8f558 | ||
|
d5dc886748 | ||
|
17044adf96 | ||
|
9dfd805be2 | ||
|
bbbb6b685f | ||
|
71c0d5f82d |
@ -1715,7 +1715,7 @@ StScrollBar StButton#vhandle:hover
|
||||
}
|
||||
|
||||
.lightbox {
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.flashspot {
|
||||
|
@ -78,6 +78,7 @@ nobase_dist_js_DATA = \
|
||||
ui/popupMenu.js \
|
||||
ui/remoteSearch.js \
|
||||
ui/runDialog.js \
|
||||
ui/screenShield.js \
|
||||
ui/scripting.js \
|
||||
ui/search.js \
|
||||
ui/searchDisplay.js \
|
||||
@ -91,6 +92,7 @@ nobase_dist_js_DATA = \
|
||||
ui/status/bluetooth.js \
|
||||
ui/telepathyClient.js \
|
||||
ui/tweener.js \
|
||||
ui/unlockDialog.js \
|
||||
ui/userMenu.js \
|
||||
ui/viewSelector.js \
|
||||
ui/wanda.js \
|
||||
|
@ -39,8 +39,8 @@ const Main = imports.ui.main;
|
||||
const ModalDialog = imports.ui.modalDialog;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const _PASSWORD_SERVICE_NAME = 'gdm-password';
|
||||
const _FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
|
||||
const PASSWORD_SERVICE_NAME = 'gdm-password';
|
||||
const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
|
||||
const _FADE_ANIMATION_TIME = 0.16;
|
||||
const _RESIZE_ANIMATION_TIME = 0.25;
|
||||
const _SCROLL_ANIMATION_TIME = 2.0;
|
||||
@ -747,15 +747,13 @@ const LoginDialog = new Lang.Class({
|
||||
Lang.bind(this, this._onOpened));
|
||||
|
||||
this._userManager = AccountsService.UserManager.get_default()
|
||||
this._greeterClient = new GdmGreeter.Client();
|
||||
this._greeterClient = GdmGreeter.Server.new_for_greeter_sync(null);
|
||||
|
||||
this._greeterClient.open_connection();
|
||||
|
||||
this._greeterClient.call_start_conversation(_PASSWORD_SERVICE_NAME);
|
||||
this._greeterClient.call_start_conversation_sync(PASSWORD_SERVICE_NAME, null);
|
||||
|
||||
this._greeterClient.connect('reset',
|
||||
Lang.bind(this, this._onReset));
|
||||
this._greeterClient.connect('default-session-changed',
|
||||
this._greeterClient.connect('default-session-name-changed',
|
||||
Lang.bind(this, this._onDefaultSessionChanged));
|
||||
this._greeterClient.connect('info',
|
||||
Lang.bind(this, this._onInfo));
|
||||
@ -769,8 +767,6 @@ const LoginDialog = new Lang.Class({
|
||||
Lang.bind(this, this._onSessionOpened));
|
||||
this._greeterClient.connect('timed-login-requested',
|
||||
Lang.bind(this, this._onTimedLoginRequested));
|
||||
this._greeterClient.connect('authentication-failed',
|
||||
Lang.bind(this, this._onAuthenticationFailed));
|
||||
this._greeterClient.connect('conversation-stopped',
|
||||
Lang.bind(this, this._onConversationStopped));
|
||||
|
||||
@ -899,7 +895,7 @@ const LoginDialog = new Lang.Class({
|
||||
this._haveFingerprintReader = true;
|
||||
|
||||
if (this._haveFingerprintReader)
|
||||
this._greeterClient.call_start_conversation(_FINGERPRINT_SERVICE_NAME);
|
||||
this._greeterClient.call_start_conversation_sync(FINGERPRINT_SERVICE_NAME, null);
|
||||
}));
|
||||
},
|
||||
|
||||
@ -918,7 +914,7 @@ const LoginDialog = new Lang.Class({
|
||||
},
|
||||
|
||||
_onReset: function(client, serviceName) {
|
||||
this._greeterClient.call_start_conversation(_PASSWORD_SERVICE_NAME);
|
||||
this._greeterClient.call_start_conversation_sync(PASSWORD_SERVICE_NAME, null);
|
||||
this._startFingerprintConversationIfNeeded();
|
||||
|
||||
let tasks = [this._hidePrompt,
|
||||
@ -954,7 +950,7 @@ const LoginDialog = new Lang.Class({
|
||||
// We don't display fingerprint messages, because they
|
||||
// have words like UPEK in them. Instead we use the messages
|
||||
// as a cue to display our own message.
|
||||
if (serviceName == _FINGERPRINT_SERVICE_NAME &&
|
||||
if (serviceName == FINGERPRINT_SERVICE_NAME &&
|
||||
this._haveFingerprintReader &&
|
||||
(!this._promptFingerprintMessage.visible ||
|
||||
this._promptFingerprintMessage.opacity != 255)) {
|
||||
@ -963,7 +959,7 @@ const LoginDialog = new Lang.Class({
|
||||
return;
|
||||
}
|
||||
|
||||
if (serviceName != _PASSWORD_SERVICE_NAME)
|
||||
if (serviceName != PASSWORD_SERVICE_NAME)
|
||||
return;
|
||||
Main.notifyError(info);
|
||||
},
|
||||
@ -971,13 +967,13 @@ const LoginDialog = new Lang.Class({
|
||||
_onProblem: function(client, serviceName, problem) {
|
||||
// we don't want to show auth failed messages to
|
||||
// users who haven't enrolled their fingerprint.
|
||||
if (serviceName != _PASSWORD_SERVICE_NAME)
|
||||
if (serviceName != PASSWORD_SERVICE_NAME)
|
||||
return;
|
||||
Main.notifyError(problem);
|
||||
},
|
||||
|
||||
_onCancel: function(client) {
|
||||
this._greeterClient.call_cancel();
|
||||
this._greeterClient.call_cancel_sync(null);
|
||||
},
|
||||
|
||||
_fadeInPrompt: function() {
|
||||
@ -1084,7 +1080,7 @@ const LoginDialog = new Lang.Class({
|
||||
let _text = this._promptEntry.get_text();
|
||||
this._promptEntry.reactive = false;
|
||||
this._promptEntry.add_style_pseudo_class('insensitive');
|
||||
this._greeterClient.call_answer_query(serviceName, _text);
|
||||
this._greeterClient.call_answer_query_sync(serviceName, _text, null);
|
||||
}];
|
||||
|
||||
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
||||
@ -1092,7 +1088,7 @@ const LoginDialog = new Lang.Class({
|
||||
},
|
||||
_onInfoQuery: function(client, serviceName, question) {
|
||||
// We only expect questions to come from the main auth service
|
||||
if (serviceName != _PASSWORD_SERVICE_NAME)
|
||||
if (serviceName != PASSWORD_SERVICE_NAME)
|
||||
return;
|
||||
|
||||
this._promptEntry.set_text('');
|
||||
@ -1102,7 +1098,7 @@ const LoginDialog = new Lang.Class({
|
||||
|
||||
_onSecretInfoQuery: function(client, serviceName, secretQuestion) {
|
||||
// We only expect secret requests to come from the main auth service
|
||||
if (serviceName != _PASSWORD_SERVICE_NAME)
|
||||
if (serviceName != PASSWORD_SERVICE_NAME)
|
||||
return;
|
||||
|
||||
this._promptEntry.set_text('');
|
||||
@ -1111,7 +1107,7 @@ const LoginDialog = new Lang.Class({
|
||||
},
|
||||
|
||||
_onSessionOpened: function(client, serviceName) {
|
||||
this._greeterClient.call_start_session_when_ready(serviceName, true);
|
||||
this._greeterClient.call_start_session_when_ready_sync(serviceName, true, null);
|
||||
},
|
||||
|
||||
_waitForItemForUser: function(userName) {
|
||||
@ -1193,7 +1189,7 @@ const LoginDialog = new Lang.Class({
|
||||
|
||||
function() {
|
||||
this._timedLoginBatch = null;
|
||||
this._greeterClient.call_begin_auto_login(userName);
|
||||
this._greeterClient.call_begin_auto_login_sync(userName, null);
|
||||
}];
|
||||
|
||||
this._timedLoginBatch = new Batch.ConsecutiveBatch(this, tasks);
|
||||
@ -1236,17 +1232,13 @@ const LoginDialog = new Lang.Class({
|
||||
}));
|
||||
},
|
||||
|
||||
_onAuthenticationFailed: function(client) {
|
||||
this._greeterClient.call_cancel();
|
||||
},
|
||||
|
||||
_onConversationStopped: function(client, serviceName) {
|
||||
// if the password service fails, then cancel everything.
|
||||
// But if, e.g., fingerprint fails, still give
|
||||
// password authentication a chance to succeed
|
||||
if (serviceName == _PASSWORD_SERVICE_NAME) {
|
||||
this._greeterClient.call_cancel();
|
||||
} else if (serviceName == _FINGERPRINT_SERVICE_NAME) {
|
||||
if (serviceName == PASSWORD_SERVICE_NAME) {
|
||||
this._greeterClient.call_cancel_sync(null);
|
||||
} else if (serviceName == FINGERPRINT_SERVICE_NAME) {
|
||||
_fadeOutActor(this._promptFingerprintMessage);
|
||||
}
|
||||
},
|
||||
@ -1269,7 +1261,7 @@ const LoginDialog = new Lang.Class({
|
||||
this._fadeOutLogo]),
|
||||
|
||||
function() {
|
||||
this._greeterClient.call_begin_verification(_PASSWORD_SERVICE_NAME);
|
||||
this._greeterClient.call_begin_verification_sync(PASSWORD_SERVICE_NAME, null);
|
||||
}];
|
||||
|
||||
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
||||
@ -1328,11 +1320,11 @@ const LoginDialog = new Lang.Class({
|
||||
|
||||
function() {
|
||||
let userName = activatedItem.user.get_user_name();
|
||||
this._greeterClient.call_begin_verification_for_user(_PASSWORD_SERVICE_NAME,
|
||||
userName);
|
||||
this._greeterClient.call_begin_verification_for_user_sync(PASSWORD_SERVICE_NAME,
|
||||
userName, null);
|
||||
|
||||
if (this._haveFingerprintReader)
|
||||
this._greeterClient.call_begin_verification_for_user(_FINGERPRINT_SERVICE_NAME, userName);
|
||||
this._greeterClient.call_begin_verification_for_user_sync(_FINGERPRINT_SERVICE_NAME, userName, null);
|
||||
}];
|
||||
|
||||
this._user = activatedItem.user;
|
||||
|
@ -8,6 +8,8 @@ const St = imports.gi.St;
|
||||
const Params = imports.misc.params;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const DEFAULT_FADE_FACTOR = 0.4;
|
||||
|
||||
/**
|
||||
* Lightbox:
|
||||
* @container: parent Clutter.Container
|
||||
@ -15,7 +17,8 @@ const Tweener = imports.ui.tweener;
|
||||
* - inhibitEvents: whether to inhibit events for @container
|
||||
* - width: shade actor width
|
||||
* - height: shade actor height
|
||||
* - fadeTime: seconds used to fade in/out
|
||||
* - fadeInTime: seconds used to fade in
|
||||
* - fadeOutTime: seconds used to fade out
|
||||
*
|
||||
* Lightbox creates a dark translucent "shade" actor to hide the
|
||||
* contents of @container, and allows you to specify particular actors
|
||||
@ -38,12 +41,16 @@ const Lightbox = new Lang.Class({
|
||||
params = Params.parse(params, { inhibitEvents: false,
|
||||
width: null,
|
||||
height: null,
|
||||
fadeTime: null
|
||||
fadeInTime: null,
|
||||
fadeOutTime: null,
|
||||
fadeFactor: DEFAULT_FADE_FACTOR
|
||||
});
|
||||
|
||||
this._container = container;
|
||||
this._children = container.get_children();
|
||||
this._fadeTime = params.fadeTime;
|
||||
this._fadeInTime = params.fadeInTime;
|
||||
this._fadeOutTime = params.fadeOutTime;
|
||||
this._fadeFactor = params.fadeFactor;
|
||||
this.actor = new St.Bin({ x: 0,
|
||||
y: 0,
|
||||
style_class: 'lightbox',
|
||||
@ -52,6 +59,7 @@ const Lightbox = new Lang.Class({
|
||||
container.add_actor(this.actor);
|
||||
this.actor.raise_top();
|
||||
this.actor.hide();
|
||||
this.shown = false;
|
||||
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
|
||||
@ -93,24 +101,30 @@ const Lightbox = new Lang.Class({
|
||||
},
|
||||
|
||||
show: function() {
|
||||
if (this._fadeTime) {
|
||||
if (this._fadeInTime) {
|
||||
this.shown = false;
|
||||
this.actor.opacity = 0;
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 255,
|
||||
time: this._fadeTime,
|
||||
transition: 'easeOutQuad'
|
||||
{ opacity: 255 * this._fadeFactor,
|
||||
time: this._fadeInTime,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this, function() {
|
||||
this.shown = true;
|
||||
})
|
||||
});
|
||||
} else {
|
||||
this.actor.opacity = 255;
|
||||
this.actor.opacity = 255 * this._fadeFactor;
|
||||
this.shown = true;
|
||||
}
|
||||
this.actor.show();
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
if (this._fadeTime) {
|
||||
this.shown = false;
|
||||
if (this._fadeOutTime) {
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 0,
|
||||
time: this._fadeTime,
|
||||
time: this._fadeOutTime,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this, function() {
|
||||
this.actor.hide();
|
||||
|
@ -29,6 +29,7 @@ const LookingGlass = imports.ui.lookingGlass;
|
||||
const NetworkAgent = imports.ui.networkAgent;
|
||||
const NotificationDaemon = imports.ui.notificationDaemon;
|
||||
const WindowAttentionHandler = imports.ui.windowAttentionHandler;
|
||||
const ScreenShield = imports.ui.screenShield;
|
||||
const Scripting = imports.ui.scripting;
|
||||
const ShellDBus = imports.ui.shellDBus;
|
||||
const TelepathyClient = imports.ui.telepathyClient;
|
||||
@ -51,6 +52,7 @@ let runDialog = null;
|
||||
let lookingGlass = null;
|
||||
let wm = null;
|
||||
let messageTray = null;
|
||||
let screenShield = null;
|
||||
let notificationDaemon = null;
|
||||
let windowAttentionHandler = null;
|
||||
let telepathyClient = null;
|
||||
@ -216,6 +218,7 @@ function start() {
|
||||
panel = new Panel.Panel();
|
||||
wm = new WindowManager.WindowManager();
|
||||
messageTray = new MessageTray.MessageTray();
|
||||
screenShield = new ScreenShield.ScreenShield();
|
||||
keyboard = new Keyboard.Keyboard();
|
||||
notificationDaemon = new NotificationDaemon.NotificationDaemon();
|
||||
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
|
||||
@ -491,7 +494,7 @@ function loadTheme() {
|
||||
|
||||
let theme = new St.Theme ({ application_stylesheet: cssStylesheet });
|
||||
|
||||
if (global.session_type == Shell.SessionType.GDM)
|
||||
// FIXME: merge back into main stylesheet
|
||||
theme.load_stylesheet(_gdmCssStylesheet);
|
||||
|
||||
if (previousTheme) {
|
||||
@ -621,6 +624,10 @@ function _findModal(actor) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
function isInModalStack(actor) {
|
||||
return _findModal(actor) != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* pushModal:
|
||||
* @actor: #ClutterActor which will be given keyboard focus
|
||||
@ -661,7 +668,7 @@ function pushModal(actor, timestamp, options) {
|
||||
let actorDestroyId = actor.connect('destroy', function() {
|
||||
let index = _findModal(actor);
|
||||
if (index >= 0)
|
||||
modalActorFocusStack.splice(index, 1);
|
||||
popModal(actor);
|
||||
});
|
||||
let curFocus = global.stage.get_key_focus();
|
||||
let curFocusDestroyId;
|
||||
|
142
js/ui/screenShield.js
Normal file
142
js/ui/screenShield.js
Normal file
@ -0,0 +1,142 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const Meta = imports.gi.Meta;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const GnomeSession = imports.misc.gnomeSession;
|
||||
const Lightbox = imports.ui.lightbox;
|
||||
const UnlockDialog = imports.ui.unlockDialog;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
|
||||
const LOCK_ENABLED_KEY = 'lock-enabled';
|
||||
|
||||
/**
|
||||
* To test screen shield, make sure to kill gnome-screensaver.
|
||||
*
|
||||
* If you are setting org.gnome.desktop.session.idle-delay directly in dconf,
|
||||
* rather than through System Settings, you also need to set
|
||||
* org.gnome.settings-daemon.plugins.power.sleep-display-ac and
|
||||
* org.gnome.settings-daemon.plugins.power.sleep-display-battery to the same value.
|
||||
* This will ensure that the screen blanks at the right time when it fades out.
|
||||
* https://bugzilla.gnome.org/show_bug.cgi?id=668703 explains the dependance.
|
||||
*/
|
||||
const ScreenShield = new Lang.Class({
|
||||
Name: 'ScreenShield',
|
||||
|
||||
_init: function() {
|
||||
this._presence = new GnomeSession.Presence(Lang.bind(this, function(proxy, error) {
|
||||
this._onStatusChanged(proxy.status);
|
||||
}));
|
||||
this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) {
|
||||
this._onStatusChanged(status);
|
||||
}));
|
||||
|
||||
this._settings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA });
|
||||
|
||||
this._isModal = false;
|
||||
this._isLocked = false;
|
||||
this._group = new St.Widget({ x: 0,
|
||||
y: 0 });
|
||||
Main.uiGroup.add_actor(this._group);
|
||||
let constraint = new Clutter.BindConstraint({ source: global.stage,
|
||||
coordinate: Clutter.BindCoordinate.POSITION | Clutter.BindCoordinate.SIZE });
|
||||
this._group.add_constraint(constraint);
|
||||
|
||||
this._lightbox = new Lightbox.Lightbox(this._group,
|
||||
{ inhibitEvents: true, fadeInTime: 10, fadeFactor: 1 });
|
||||
this._background = Meta.BackgroundActor.new_for_screen(global.screen);
|
||||
this._background.hide();
|
||||
Main.uiGroup.add_actor(this._background);
|
||||
},
|
||||
|
||||
_onStatusChanged: function(status) {
|
||||
log ("in _onStatusChanged");
|
||||
if (status == GnomeSession.PresenceStatus.IDLE) {
|
||||
log("session gone idle");
|
||||
|
||||
if (this._dialog) {
|
||||
log('canceling existing dialog');
|
||||
this._dialog.cancel();
|
||||
this._dialog = null;
|
||||
}
|
||||
|
||||
this._group.reactive = true;
|
||||
if (!this._isModal) {
|
||||
Main.pushModal(this._group);
|
||||
this._isModal = true;
|
||||
}
|
||||
|
||||
this._group.raise_top();
|
||||
this._lightbox.show();
|
||||
} else {
|
||||
log('status is now ' + status);
|
||||
|
||||
let lightboxWasShown = this._lightbox.shown;
|
||||
log("this._lightbox.shown " + this._lightbox.shown);
|
||||
this._lightbox.hide();
|
||||
|
||||
let shouldLock = lightboxWasShown && this._settings.get_boolean(LOCK_ENABLED_KEY);
|
||||
if (shouldLock || this._isLocked) {
|
||||
this._isLocked = true;
|
||||
this._background.show();
|
||||
this._background.raise_top();
|
||||
|
||||
this._showUnlockDialog();
|
||||
} else if (this._isModal) {
|
||||
this._popModal();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_popModal: function() {
|
||||
this._group.reactive = false;
|
||||
Main.popModal(this._group);
|
||||
|
||||
this._background.hide();
|
||||
},
|
||||
|
||||
_showUnlockDialog: function() {
|
||||
if (this._dialog) {
|
||||
log ('_showUnlockDialog called again when the dialog was already there');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this._dialog = new UnlockDialog.UnlockDialog();
|
||||
this._dialog.connect('failed', Lang.bind(this, this._onUnlockFailed));
|
||||
this._dialog.connect('unlocked', Lang.bind(this, this._onUnlockSucceded));
|
||||
|
||||
if (!this._dialog.open(global.get_current_time()))
|
||||
throw new Error('open failed!')
|
||||
|
||||
this._dialog._group.raise_top();
|
||||
} catch(e) {
|
||||
// FIXME: this is for debugging purposes
|
||||
logError(e, 'error while creating unlock dialog');
|
||||
|
||||
this._popModal();
|
||||
}
|
||||
},
|
||||
|
||||
_onUnlockFailed: function() {
|
||||
// FIXME: 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();
|
||||
},
|
||||
});
|
363
js/ui/unlockDialog.js
Normal file
363
js/ui/unlockDialog.js
Normal file
@ -0,0 +1,363 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const AccountsService = imports.gi.AccountsService;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GdmGreeter = imports.gi.GdmGreeter;
|
||||
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 ModalDialog = imports.ui.modalDialog;
|
||||
|
||||
const Fprint = imports.gdm.fingerprint;
|
||||
const GdmLoginDialog = imports.gdm.loginDialog;
|
||||
|
||||
function _fadeInActor(actor) {
|
||||
if (actor.opacity == 255 && actor.visible)
|
||||
return;
|
||||
|
||||
actor.show();
|
||||
let [minHeight, naturalHeight] = actor.get_preferred_height(-1);
|
||||
|
||||
actor.opacity = 0;
|
||||
actor.set_height(0);
|
||||
Tweener.addTween(actor,
|
||||
{ opacity: 255,
|
||||
height: naturalHeight,
|
||||
time: _FADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: function() {
|
||||
this.set_height(-1);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function _fadeOutActor(actor) {
|
||||
if (!actor.visible || actor.opacity == 0) {
|
||||
actor.opacity = 0;
|
||||
actor.hide();
|
||||
}
|
||||
|
||||
Tweener.addTween(actor,
|
||||
{ opacity: 0,
|
||||
height: 0,
|
||||
time: _FADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: function() {
|
||||
this.hide();
|
||||
this.set_height(-1);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 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: 'status-chooser',
|
||||
vertical: false,
|
||||
reactive: false
|
||||
});
|
||||
|
||||
this._iconBin = new St.Bin({ style_class: 'status-chooser-user-icon' });
|
||||
this.actor.add(this._iconBin,
|
||||
{ x_fill: true,
|
||||
y_fill: true });
|
||||
|
||||
this._label = new St.Label({ style_class: 'login-dialog-prompt-label',
|
||||
// FIXME:
|
||||
style: 'text-align: right' });
|
||||
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));
|
||||
this.actor.connect('notify::mapped', Lang.bind(this, function() {
|
||||
if (this.actor.mapped)
|
||||
this._updateUser();
|
||||
}));
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
// clean up signal handlers
|
||||
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() {
|
||||
let iconFile = null;
|
||||
if (this._user.is_loaded) {
|
||||
this._label.text = this._user.get_real_name();
|
||||
iconFile = this._user.get_icon_file();
|
||||
if (!GLib.file_test(iconFile, GLib.FileTest.EXISTS))
|
||||
iconFile = null;
|
||||
} else {
|
||||
this._label.text = "";
|
||||
}
|
||||
|
||||
if (iconFile)
|
||||
this._setIconFromFile(iconFile);
|
||||
else
|
||||
this._setIconFromName('avatar-default');
|
||||
},
|
||||
|
||||
// XXX: a GFileIcon instead?
|
||||
_setIconFromFile: function(iconFile) {
|
||||
this._iconBin.set_style('background-image: url("' + iconFile + '");' +
|
||||
'background-size: contain;');
|
||||
this._iconBin.child = null;
|
||||
},
|
||||
|
||||
_setIconFromName: function(iconName) {
|
||||
this._iconBin.set_style(null);
|
||||
|
||||
if (iconName != null) {
|
||||
let icon = new St.Icon({ icon_name: iconName,
|
||||
icon_type: St.IconType.SYMBOLIC,
|
||||
icon_size: DIALOG_ICON_SIZE });
|
||||
this._iconBin.child = icon;
|
||||
this._iconBin.show();
|
||||
} else {
|
||||
this._iconBin.child = null;
|
||||
this._iconBin.hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
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 = GdmGreeter.Server.new_for_display_sync(null, null);
|
||||
|
||||
this._greeterClient.call_start_conversation_sync(GdmLoginDialog.PASSWORD_SERVICE_NAME, null);
|
||||
|
||||
this._greeterClient.connect('reset',
|
||||
Lang.bind(this, this._onReset));
|
||||
this._greeterClient.connect('ready',
|
||||
Lang.bind(this, this._onReady));
|
||||
this._greeterClient.connect('info',
|
||||
Lang.bind(this, this._onInfo));
|
||||
this._greeterClient.connect('problem',
|
||||
Lang.bind(this, this._onProblem));
|
||||
this._greeterClient.connect('info-query',
|
||||
Lang.bind(this, this._onInfoQuery));
|
||||
this._greeterClient.connect('secret-info-query',
|
||||
Lang.bind(this, this._onSecretInfoQuery));
|
||||
this._greeterClient.connect('session-opened',
|
||||
Lang.bind(this, this._onSessionOpened));
|
||||
this._greeterClient.connect('conversation-stopped',
|
||||
Lang.bind(this, this._onConversationStopped));
|
||||
|
||||
this._fprintManager = new Fprint.FprintManager();
|
||||
this._startFingerprintConversationIfNeeded();
|
||||
|
||||
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 });
|
||||
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);
|
||||
|
||||
this._okButton = { label: _("Unlock"),
|
||||
action: Lang.bind(this, this._doUnlock),
|
||||
key: Clutter.KEY_Return,
|
||||
};
|
||||
this.setButtons([this._okButton]);
|
||||
|
||||
this._updateOkButton(true);
|
||||
},
|
||||
|
||||
_updateOkButton: function(sensitive) {
|
||||
this._okButton.button.reactive = sensitive;
|
||||
this._okButton.button.can_focus = sensitive;
|
||||
if (sensitive)
|
||||
this._okButton.button.remove_style_pseudo_class('disabled');
|
||||
else
|
||||
this._okButton.button.add_style_pseudo_class('disabled');
|
||||
},
|
||||
|
||||
_onReset: function() {
|
||||
// I'm not sure this is emitted for external greeters...
|
||||
|
||||
this._greeterClient.call_start_conversation_sync(GdmLoginDialog.PASSWORD_SERVICE_NAME, null);
|
||||
this._startFingerprintConversationIfNeeded();
|
||||
},
|
||||
|
||||
_startFingerprintConversationIfNeeded: function() {
|
||||
this._haveFingerprintReader = false;
|
||||
|
||||
// FIXME: the greeter has a GSettings key for disabling fingerprint auth
|
||||
|
||||
this._fprintManager.GetDefaultDeviceRemote(Lang.bind(this,
|
||||
function(device, error) {
|
||||
if (!error && device)
|
||||
this._haveFingerprintReader = true;
|
||||
|
||||
if (this._haveFingerprintReader)
|
||||
this._greeterClient.call_start_conversation_sync(GdmLoginDialog.FINGERPRINT_SERVICE_NAME, null);
|
||||
}));
|
||||
},
|
||||
|
||||
_onReady: function(greeter, serviceName) {
|
||||
greeter.call_begin_verification_for_user_sync(serviceName, this._userName, null);
|
||||
},
|
||||
|
||||
_onInfo: function(greeter, serviceName, info) {
|
||||
// We don't display fingerprint messages, because they
|
||||
// have words like UPEK in them. Instead we use the messages
|
||||
// as a cue to display our own message.
|
||||
if (serviceName == GdmLoginDialog.FINGERPRINT_SERVICE_NAME &&
|
||||
this._haveFingerprintReader &&
|
||||
(!this._promptFingerprintMessage.visible ||
|
||||
this._promptFingerprintMessage.opacity != 255)) {
|
||||
|
||||
_fadeInActor(this._promptFingerprintMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (serviceName != GdmLoginDialog.PASSWORD_SERVICE_NAME)
|
||||
return;
|
||||
Main.notify(info);
|
||||
},
|
||||
|
||||
_onProblem: function(client, serviceName, problem) {
|
||||
// we don't want to show auth failed messages to
|
||||
// users who haven't enrolled their fingerprint.
|
||||
if (serviceName != GdmLoginDialog.PASSWORD_SERVICE_NAME)
|
||||
return;
|
||||
Main.notifyError(problem);
|
||||
},
|
||||
|
||||
_onInfoQuery: function(client, serviceName, question) {
|
||||
// We only expect questions to come from the main auth service
|
||||
if (serviceName != GdmLoginDialog.PASSWORD_SERVICE_NAME)
|
||||
return;
|
||||
|
||||
this._promptLabel.text = question;
|
||||
this._promptEntry.text = '';
|
||||
this._promptEntry.clutter_text.set_password_char('');
|
||||
|
||||
this._currentQuery = serviceName;
|
||||
this._updateOkButton(true);
|
||||
},
|
||||
|
||||
_onSecretInfoQuery: function(client, serviceName, secretQuestion) {
|
||||
// We only expect secret requests to come from the main auth service
|
||||
if (serviceName != GdmLoginDialog.PASSWORD_SERVICE_NAME)
|
||||
return;
|
||||
|
||||
this._promptLabel.text = secretQuestion;
|
||||
this._promptEntry.text = '';
|
||||
this._promptEntry.clutter_text.set_password_char('\u25cf');
|
||||
|
||||
this._currentQuery = serviceName;
|
||||
this._updateOkButton(true);
|
||||
},
|
||||
|
||||
_doUnlock: function() {
|
||||
if (!this._currentQuery)
|
||||
return;
|
||||
|
||||
let query = this._currentQuery;
|
||||
this._currentQuery = null;
|
||||
|
||||
this._updateOkButton(false);
|
||||
|
||||
this._greeterClient.call_answer_query_sync(query, this._promptEntry.text, null);
|
||||
},
|
||||
|
||||
_onConversationStopped: function(client, serviceName) {
|
||||
// if the password service fails, then cancel everything.
|
||||
// But if, e.g., fingerprint fails, still give
|
||||
// password authentication a chance to succeed
|
||||
if (serviceName == GdmLoginDialog.PASSWORD_SERVICE_NAME) {
|
||||
this._greeterClient.call_cancel_sync(null);
|
||||
this.emit('failed');
|
||||
} else if (serviceName == GdmLoginDialog.FINGERPRINT_SERVICE_NAME) {
|
||||
_fadeOutActor(this._promptFingerprintMessage);
|
||||
}
|
||||
},
|
||||
|
||||
_onSessionOpened: function(client, serviceName) {
|
||||
// For external greeters, SessionOpened means we succeded
|
||||
// in the authentication process
|
||||
|
||||
// Close the greeter proxy
|
||||
this._greeterClient.run_dispose();
|
||||
this._greeterClient = null;
|
||||
|
||||
this.emit('unlocked');
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
if (this._greeterClient) {
|
||||
this._greeterClient.run_dispose();
|
||||
this._greeterClient = null;
|
||||
}
|
||||
|
||||
this.parent();
|
||||
},
|
||||
|
||||
cancel: function() {
|
||||
this._greeterClient.call_cancel_sync(null);
|
||||
|
||||
this.destroy();
|
||||
},
|
||||
});
|
@ -301,7 +301,8 @@ const WindowClone = new Lang.Class({
|
||||
|
||||
if (!this._zoomLightbox)
|
||||
this._zoomLightbox = new Lightbox.Lightbox(Main.uiGroup,
|
||||
{ fadeTime: LIGHTBOX_FADE_TIME });
|
||||
{ fadeInTime: LIGHTBOX_FADE_TIME,
|
||||
fadeOutTime: LIGHTBOX_FADE_TIME });
|
||||
this._zoomLightbox.show();
|
||||
|
||||
this._zoomLocalOrig = new ScaledPoint(this.actor.x, this.actor.y, this.actor.scale_x, this.actor.scale_y);
|
||||
|
Loading…
Reference in New Issue
Block a user