2011-09-28 09:16:26 -04:00
|
|
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
|
|
/*
|
2011-08-23 22:12:57 -04:00
|
|
|
* Copyright 2011 Red Hat, Inc
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
|
|
* 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
const AccountsService = imports.gi.AccountsService;
|
|
|
|
const Clutter = imports.gi.Clutter;
|
|
|
|
const CtrlAltTab = imports.ui.ctrlAltTab;
|
|
|
|
const Gio = imports.gi.Gio;
|
|
|
|
const GLib = imports.gi.GLib;
|
|
|
|
const Gtk = imports.gi.Gtk;
|
|
|
|
const Mainloop = imports.mainloop;
|
|
|
|
const Lang = imports.lang;
|
|
|
|
const Pango = imports.gi.Pango;
|
|
|
|
const Signals = imports.signals;
|
|
|
|
const Shell = imports.gi.Shell;
|
|
|
|
const St = imports.gi.St;
|
2012-05-19 19:19:25 -04:00
|
|
|
const Gdm = imports.gi.Gdm;
|
2011-08-23 22:12:57 -04:00
|
|
|
|
2011-08-30 07:52:25 -04:00
|
|
|
const Batch = imports.gdm.batch;
|
2011-09-06 16:17:08 -04:00
|
|
|
const Fprint = imports.gdm.fingerprint;
|
2012-07-17 14:54:07 -04:00
|
|
|
const GdmUtil = imports.gdm.util;
|
2011-08-23 22:12:57 -04:00
|
|
|
const Lightbox = imports.ui.lightbox;
|
|
|
|
const Main = imports.ui.main;
|
|
|
|
const ModalDialog = imports.ui.modalDialog;
|
|
|
|
const Tweener = imports.ui.tweener;
|
|
|
|
|
|
|
|
const _RESIZE_ANIMATION_TIME = 0.25;
|
2012-07-25 13:08:29 -04:00
|
|
|
const _SCROLL_ANIMATION_TIME = 0.5;
|
2011-08-23 22:12:57 -04:00
|
|
|
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
|
2011-09-06 08:37:16 -04:00
|
|
|
const _LOGO_ICON_NAME_SIZE = 48;
|
2011-08-23 22:12:57 -04:00
|
|
|
|
|
|
|
let _loginDialog = null;
|
|
|
|
|
|
|
|
function _smoothlyResizeActor(actor, width, height) {
|
|
|
|
let finalWidth;
|
|
|
|
let finalHeight;
|
|
|
|
|
|
|
|
if (width < 0)
|
|
|
|
finalWidth = actor.width;
|
|
|
|
else
|
|
|
|
finalWidth = width;
|
|
|
|
|
|
|
|
if (height < 0)
|
|
|
|
finalHeight = actor.height;
|
|
|
|
else
|
|
|
|
finalHeight = height;
|
|
|
|
|
|
|
|
actor.set_size(actor.width, actor.height);
|
|
|
|
|
|
|
|
if (actor.width == finalWidth && actor.height == finalHeight)
|
|
|
|
return null;
|
|
|
|
|
|
|
|
let hold = new Batch.Hold();
|
|
|
|
|
|
|
|
Tweener.addTween(actor,
|
|
|
|
{ width: finalWidth,
|
|
|
|
height: finalHeight,
|
|
|
|
time: _RESIZE_ANIMATION_TIME,
|
|
|
|
transition: 'easeOutQuad',
|
|
|
|
onComplete: Lang.bind(this, function() {
|
|
|
|
hold.release();
|
|
|
|
})
|
|
|
|
});
|
|
|
|
return hold;
|
|
|
|
}
|
|
|
|
|
2011-11-20 12:56:27 -05:00
|
|
|
const UserListItem = new Lang.Class({
|
|
|
|
Name: 'UserListItem',
|
2011-08-23 22:12:57 -04:00
|
|
|
|
|
|
|
_init: function(user) {
|
|
|
|
this.user = user;
|
|
|
|
this._userChangedId = this.user.connect('changed',
|
|
|
|
Lang.bind(this, this._onUserChanged));
|
|
|
|
|
2012-07-13 18:43:58 -04:00
|
|
|
let layout = new St.BoxLayout({ vertical: false });
|
2011-08-23 22:12:57 -04:00
|
|
|
this.actor = new St.Button({ style_class: 'login-dialog-user-list-item',
|
|
|
|
can_focus: true,
|
2012-07-13 18:43:58 -04:00
|
|
|
child: layout,
|
2011-08-23 22:12:57 -04:00
|
|
|
reactive: true,
|
|
|
|
x_align: St.Align.START,
|
|
|
|
x_fill: true });
|
|
|
|
|
|
|
|
this._iconBin = new St.Bin();
|
|
|
|
layout.add(this._iconBin);
|
|
|
|
let textLayout = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-text-box',
|
|
|
|
vertical: true });
|
2012-07-13 18:43:58 -04:00
|
|
|
layout.add(textLayout, { expand: true });
|
2011-08-23 22:12:57 -04:00
|
|
|
|
|
|
|
this._nameLabel = new St.Label({ text: this.user.get_real_name(),
|
|
|
|
style_class: 'login-dialog-user-list-item-name' });
|
2012-07-13 18:43:58 -04:00
|
|
|
textLayout.add(this._nameLabel,
|
|
|
|
{ y_fill: false,
|
|
|
|
y_align: St.Align.MIDDLE,
|
|
|
|
expand: true });
|
|
|
|
|
|
|
|
this._timedLoginIndicator = new St.Bin({ style_class: 'login-dialog-timed-login-indicator',
|
|
|
|
scale_x: 0 });
|
|
|
|
textLayout.add(this._timedLoginIndicator,
|
|
|
|
{ x_fill: true,
|
|
|
|
x_align: St.Align.MIDDLE,
|
|
|
|
y_fill: false,
|
|
|
|
y_align: St.Align.END });
|
2011-08-23 22:12:57 -04:00
|
|
|
|
|
|
|
this._updateIcon();
|
2012-07-09 14:04:23 -04:00
|
|
|
this._updateLoggedIn();
|
2011-08-23 22:12:57 -04:00
|
|
|
|
|
|
|
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
|
|
|
},
|
|
|
|
|
|
|
|
_onUserChanged: function() {
|
|
|
|
this._nameLabel.set_text(this.user.get_real_name());
|
|
|
|
this._updateIcon();
|
2012-07-09 14:04:23 -04:00
|
|
|
this._updateLoggedIn();
|
2011-08-23 22:12:57 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
_setIconFromFile: function(iconFile, styleClass) {
|
|
|
|
if (styleClass)
|
|
|
|
this._iconBin.set_style_class_name(styleClass);
|
|
|
|
this._iconBin.set_style(null);
|
|
|
|
|
|
|
|
this._iconBin.child = null;
|
|
|
|
if (iconFile) {
|
|
|
|
this._iconBin.show();
|
|
|
|
// We use background-image instead of, say, St.TextureCache
|
|
|
|
// so the theme writers can add a rounded frame around the image
|
|
|
|
// and so theme writers can pick the icon size.
|
2012-01-09 19:48:14 -05:00
|
|
|
this._iconBin.set_style('background-image: url("' + iconFile + '");' +
|
|
|
|
'background-size: contain;');
|
2011-08-23 22:12:57 -04:00
|
|
|
} else {
|
|
|
|
this._iconBin.hide();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
_setIconFromName: function(iconName, styleClass) {
|
|
|
|
if (styleClass)
|
|
|
|
this._iconBin.set_style_class_name(styleClass);
|
|
|
|
this._iconBin.set_style(null);
|
|
|
|
|
|
|
|
if (iconName != null) {
|
|
|
|
let icon = new St.Icon();
|
|
|
|
icon.set_icon_name(iconName)
|
|
|
|
|
|
|
|
this._iconBin.child = icon;
|
|
|
|
this._iconBin.show();
|
|
|
|
} else {
|
|
|
|
this._iconBin.child = null;
|
|
|
|
this._iconBin.hide();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
_updateIcon: function() {
|
|
|
|
let iconFileName = this.user.get_icon_file();
|
|
|
|
let gicon = null;
|
|
|
|
|
|
|
|
if (GLib.file_test(iconFileName, GLib.FileTest.EXISTS))
|
|
|
|
this._setIconFromFile(iconFileName, 'login-dialog-user-list-item-icon');
|
|
|
|
else
|
|
|
|
this._setIconFromName('avatar-default', 'login-dialog-user-list-item-icon');
|
|
|
|
},
|
|
|
|
|
2012-07-09 17:46:35 -04:00
|
|
|
syncStyleClasses: function() {
|
2012-07-09 14:04:23 -04:00
|
|
|
this._updateLoggedIn();
|
|
|
|
|
2012-08-01 11:14:00 -04:00
|
|
|
if (global.stage.get_key_focus() == this.actor)
|
2012-07-09 17:46:35 -04:00
|
|
|
this.actor.add_style_pseudo_class('focus');
|
|
|
|
else
|
|
|
|
this.actor.remove_style_pseudo_class('focus');
|
|
|
|
},
|
|
|
|
|
2012-07-09 14:04:23 -04:00
|
|
|
_updateLoggedIn: function() {
|
|
|
|
if (this.user.is_logged_in())
|
|
|
|
this.actor.add_style_pseudo_class('logged-in');
|
|
|
|
else
|
|
|
|
this.actor.remove_style_pseudo_class('logged-in');
|
|
|
|
},
|
|
|
|
|
2011-08-23 22:12:57 -04:00
|
|
|
_onClicked: function() {
|
|
|
|
this.emit('activate');
|
|
|
|
},
|
|
|
|
|
|
|
|
fadeOutName: function() {
|
2012-07-17 14:54:07 -04:00
|
|
|
return GdmUtil.fadeOutActor(this._nameLabel);
|
2011-08-23 22:12:57 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
fadeInName: function() {
|
2012-07-17 14:54:07 -04:00
|
|
|
return GdmUtil.fadeInActor(this._nameLabel);
|
2011-08-23 22:12:57 -04:00
|
|
|
},
|
|
|
|
|
2012-07-13 18:43:58 -04:00
|
|
|
showTimedLoginIndicator: function(time) {
|
2011-08-23 22:12:57 -04:00
|
|
|
let hold = new Batch.Hold();
|
|
|
|
|
2012-07-13 18:43:58 -04:00
|
|
|
this.hideTimedLoginIndicator();
|
|
|
|
Tweener.addTween(this._timedLoginIndicator,
|
2012-07-12 13:49:31 -04:00
|
|
|
{ scale_x: 1.,
|
2011-08-23 22:12:57 -04:00
|
|
|
time: time,
|
|
|
|
transition: 'linear',
|
|
|
|
onComplete: function() {
|
|
|
|
hold.release();
|
|
|
|
},
|
|
|
|
onCompleteScope: this
|
|
|
|
});
|
|
|
|
return hold;
|
2012-07-13 18:43:58 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
hideTimedLoginIndicator: function() {
|
|
|
|
Tweener.removeTweens(this._timedLoginIndicator);
|
|
|
|
this._timedLoginIndicator.scale_x = 0.;
|
2011-08-23 22:12:57 -04:00
|
|
|
}
|
2011-11-20 12:56:27 -05:00
|
|
|
});
|
2011-08-23 22:12:57 -04:00
|
|
|
Signals.addSignalMethods(UserListItem.prototype);
|
|
|
|
|
2011-11-20 12:56:27 -05:00
|
|
|
const UserList = new Lang.Class({
|
|
|
|
Name: 'UserList',
|
2011-08-23 22:12:57 -04:00
|
|
|
|
|
|
|
_init: function() {
|
|
|
|
this.actor = new St.ScrollView({ style_class: 'login-dialog-user-list-view'});
|
|
|
|
this.actor.set_policy(Gtk.PolicyType.NEVER,
|
|
|
|
Gtk.PolicyType.AUTOMATIC);
|
|
|
|
|
|
|
|
this._box = new St.BoxLayout({ vertical: true,
|
2012-08-01 11:14:00 -04:00
|
|
|
style_class: 'login-dialog-user-list',
|
|
|
|
pseudo_class: 'expanded' });
|
2011-08-23 22:12:57 -04:00
|
|
|
|
2012-07-18 20:15:04 -04:00
|
|
|
this.actor.add_actor(this._box);
|
2011-08-23 22:12:57 -04:00
|
|
|
this._items = {};
|
2011-10-17 02:56:44 -04:00
|
|
|
|
|
|
|
this.actor.connect('key-focus-in', Lang.bind(this, this._moveFocusToItems));
|
|
|
|
},
|
|
|
|
|
|
|
|
_moveFocusToItems: function() {
|
|
|
|
let hasItems = Object.keys(this._items).length > 0;
|
|
|
|
|
|
|
|
if (!hasItems)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (global.stage.get_key_focus() != this.actor)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
2011-08-23 22:12:57 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
_showItem: function(item) {
|
|
|
|
let tasks = [function() {
|
2012-07-17 14:54:07 -04:00
|
|
|
return GdmUtil.fadeInActor(item.actor);
|
2011-08-23 22:12:57 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
function() {
|
|
|
|
return item.fadeInName();
|
|
|
|
}];
|
|
|
|
|
|
|
|
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
|
|
|
return batch.run();
|
|
|
|
},
|
|
|
|
|
|
|
|
_onItemActivated: function(activatedItem) {
|
|
|
|
this.emit('activate', activatedItem);
|
|
|
|
},
|
|
|
|
|
|
|
|
giveUpWhitespace: function() {
|
|
|
|
let container = this.actor.get_parent();
|
|
|
|
|
|
|
|
container.child_set(this.actor, { expand: false });
|
|
|
|
},
|
|
|
|
|
|
|
|
takeOverWhitespace: function() {
|
|
|
|
let container = this.actor.get_parent();
|
|
|
|
|
|
|
|
container.child_set(this.actor, { expand: true });
|
|
|
|
},
|
|
|
|
|
|
|
|
pinInPlace: function() {
|
|
|
|
this._box.set_size(this._box.width, this._box.height);
|
|
|
|
},
|
|
|
|
|
|
|
|
shrinkToNaturalHeight: function() {
|
|
|
|
let oldWidth = this._box.width;
|
|
|
|
let oldHeight = this._box.height;
|
|
|
|
this._box.set_size(-1, -1);
|
|
|
|
let [minHeight, naturalHeight] = this._box.get_preferred_height(-1);
|
|
|
|
this._box.set_size(oldWidth, oldHeight);
|
|
|
|
|
|
|
|
let batch = new Batch.ConsecutiveBatch(this,
|
|
|
|
[function() {
|
|
|
|
return _smoothlyResizeActor(this._box, -1, naturalHeight);
|
|
|
|
},
|
|
|
|
|
|
|
|
function() {
|
|
|
|
this._box.set_size(-1, -1);
|
|
|
|
}
|
|
|
|
]);
|
|
|
|
|
|
|
|
return batch.run();
|
|
|
|
},
|
|
|
|
|
|
|
|
hideItemsExcept: function(exception) {
|
|
|
|
let tasks = [];
|
|
|
|
|
|
|
|
for (let userName in this._items) {
|
|
|
|
let item = this._items[userName];
|
|
|
|
|
2012-07-09 17:46:35 -04:00
|
|
|
item.actor.set_hover(false);
|
|
|
|
item.actor.reactive = false;
|
2011-08-23 22:12:57 -04:00
|
|
|
item.actor.can_focus = false;
|
2012-07-09 17:46:35 -04:00
|
|
|
item.syncStyleClasses();
|
2012-07-13 18:43:58 -04:00
|
|
|
item._timedLoginIndicator.scale_x = 0.;
|
2011-08-23 22:12:57 -04:00
|
|
|
if (item != exception)
|
|
|
|
tasks.push(function() {
|
2012-07-17 14:54:07 -04:00
|
|
|
return GdmUtil.fadeOutActor(item.actor);
|
2011-08-23 22:12:57 -04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2012-08-01 11:14:00 -04:00
|
|
|
this._box.remove_style_pseudo_class('expanded');
|
2011-08-23 22:12:57 -04:00
|
|
|
let batch = new Batch.ConsecutiveBatch(this,
|
|
|
|
[function() {
|
2012-07-17 14:54:07 -04:00
|
|
|
return GdmUtil.fadeOutActor(this.actor.vscroll);
|
2011-08-23 22:12:57 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
new Batch.ConcurrentBatch(this, tasks)
|
|
|
|
]);
|
|
|
|
|
|
|
|
return batch.run();
|
|
|
|
},
|
|
|
|
|
|
|
|
hideItems: function() {
|
|
|
|
return this.hideItemsExcept(null);
|
|
|
|
},
|
|
|
|
|
|
|
|
_getExpandedHeight: function() {
|
|
|
|
let hiddenActors = [];
|
|
|
|
for (let userName in this._items) {
|
|
|
|
let item = this._items[userName];
|
|
|
|
if (!item.actor.visible) {
|
|
|
|
item.actor.show();
|
|
|
|
hiddenActors.push(item.actor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this._box.visible) {
|
|
|
|
this._box.show();
|
|
|
|
hiddenActors.push(this._box);
|
|
|
|
}
|
|
|
|
|
|
|
|
this._box.set_size(-1, -1);
|
|
|
|
let [minHeight, naturalHeight] = this._box.get_preferred_height(-1);
|
|
|
|
|
|
|
|
for (let i = 0; i < hiddenActors.length; i++) {
|
|
|
|
let actor = hiddenActors[i];
|
|
|
|
actor.hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
return naturalHeight;
|
|
|
|
},
|
|
|
|
|
|
|
|
showItems: function() {
|
|
|
|
let tasks = [];
|
|
|
|
|
|
|
|
for (let userName in this._items) {
|
|
|
|
let item = this._items[userName];
|
2012-07-09 17:46:35 -04:00
|
|
|
item.actor.sync_hover();
|
|
|
|
item.actor.reactive = true;
|
2011-08-23 22:12:57 -04:00
|
|
|
item.actor.can_focus = true;
|
2012-07-09 17:46:35 -04:00
|
|
|
item.syncStyleClasses();
|
2011-08-23 22:12:57 -04:00
|
|
|
tasks.push(function() {
|
|
|
|
return this._showItem(item);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2012-08-01 11:14:00 -04:00
|
|
|
this._box.add_style_pseudo_class('expanded');
|
2011-08-23 22:12:57 -04:00
|
|
|
let batch = new Batch.ConsecutiveBatch(this,
|
|
|
|
[function() {
|
|
|
|
this.takeOverWhitespace();
|
|
|
|
},
|
|
|
|
|
|
|
|
function() {
|
|
|
|
let fullHeight = this._getExpandedHeight();
|
|
|
|
return _smoothlyResizeActor(this._box, -1, fullHeight);
|
|
|
|
},
|
|
|
|
|
|
|
|
new Batch.ConcurrentBatch(this, tasks),
|
|
|
|
|
|
|
|
function() {
|
|
|
|
this.actor.set_size(-1, -1);
|
|
|
|
},
|
|
|
|
|
|
|
|
function() {
|
2012-07-17 14:54:07 -04:00
|
|
|
return GdmUtil.fadeInActor(this.actor.vscroll);
|
2011-08-23 22:12:57 -04:00
|
|
|
}]);
|
|
|
|
return batch.run();
|
|
|
|
},
|
|
|
|
|
|
|
|
scrollToItem: function(item) {
|
|
|
|
let box = item.actor.get_allocation_box();
|
|
|
|
|
|
|
|
let adjustment = this.actor.get_vscroll_bar().get_adjustment();
|
|
|
|
|
|
|
|
let value = (box.y1 + adjustment.step_increment / 2.0) - (adjustment.page_size / 2.0);
|
|
|
|
Tweener.removeTweens(adjustment);
|
|
|
|
Tweener.addTween (adjustment,
|
|
|
|
{ value: value,
|
|
|
|
time: _SCROLL_ANIMATION_TIME,
|
2012-07-25 13:08:29 -04:00
|
|
|
transition: 'easeOutQuad' });
|
2011-08-23 22:12:57 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
jumpToItem: function(item) {
|
|
|
|
let box = item.actor.get_allocation_box();
|
|
|
|
|
|
|
|
let adjustment = this.actor.get_vscroll_bar().get_adjustment();
|
|
|
|
|
|
|
|
let value = (box.y1 + adjustment.step_increment / 2.0) - (adjustment.page_size / 2.0);
|
|
|
|
|
|
|
|
adjustment.set_value(value);
|
|
|
|
},
|
|
|
|
|
|
|
|
getItemFromUserName: function(userName) {
|
|
|
|
let item = this._items[userName];
|
|
|
|
|
|
|
|
if (!item)
|
|
|
|
return null;
|
|
|
|
|
|
|
|
return item;
|
|
|
|
},
|
|
|
|
|
|
|
|
addUser: function(user) {
|
|
|
|
if (!user.is_loaded)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (user.is_system_account())
|
|
|
|
return;
|
|
|
|
|
2012-04-09 12:43:44 -04:00
|
|
|
if (user.locked)
|
|
|
|
return;
|
|
|
|
|
2011-08-23 22:12:57 -04:00
|
|
|
let userName = user.get_user_name();
|
|
|
|
|
|
|
|
if (!userName)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this.removeUser(user);
|
|
|
|
|
|
|
|
let item = new UserListItem(user);
|
|
|
|
this._box.add(item.actor, { x_fill: true });
|
|
|
|
|
|
|
|
this._items[userName] = item;
|
|
|
|
|
|
|
|
item.connect('activate',
|
|
|
|
Lang.bind(this, this._onItemActivated));
|
|
|
|
|
|
|
|
// Try to keep the focused item front-and-center
|
|
|
|
item.actor.connect('key-focus-in',
|
|
|
|
Lang.bind(this,
|
|
|
|
function() {
|
|
|
|
this.scrollToItem(item);
|
|
|
|
}));
|
|
|
|
|
2011-10-17 02:56:44 -04:00
|
|
|
this._moveFocusToItems();
|
|
|
|
|
2011-08-23 22:12:57 -04:00
|
|
|
this.emit('item-added', item);
|
|
|
|
},
|
|
|
|
|
|
|
|
removeUser: function(user) {
|
|
|
|
if (!user.is_loaded)
|
|
|
|
return;
|
|
|
|
|
|
|
|
let userName = user.get_user_name();
|
|
|
|
|
|
|
|
if (!userName)
|
|
|
|
return;
|
|
|
|
|
|
|
|
let item = this._items[userName];
|
|
|
|
|
|
|
|
if (!item)
|
|
|
|
return;
|
|
|
|
|
|
|
|
item.actor.destroy();
|
|
|
|
delete this._items[userName];
|
|
|
|
}
|
2011-11-20 12:56:27 -05:00
|
|
|
});
|
2011-08-23 22:12:57 -04:00
|
|
|
Signals.addSignalMethods(UserList.prototype);
|
|
|
|
|
2011-11-20 12:56:27 -05:00
|
|
|
const SessionListItem = new Lang.Class({
|
|
|
|
Name: 'SessionListItem',
|
2011-08-23 22:12:57 -04:00
|
|
|
|
|
|
|
_init: function(id, name) {
|
|
|
|
this.id = id;
|
|
|
|
|
|
|
|
this.actor = new St.Button({ style_class: 'login-dialog-session-list-item',
|
|
|
|
can_focus: true,
|
|
|
|
reactive: true,
|
|
|
|
x_fill: true,
|
|
|
|
x_align: St.Align.START });
|
|
|
|
|
|
|
|
this._box = new St.BoxLayout({ style_class: 'login-dialog-session-list-item-box' });
|
|
|
|
|
2012-07-18 20:15:04 -04:00
|
|
|
this.actor.add_actor(this._box);
|
2011-08-23 22:12:57 -04:00
|
|
|
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
|
|
|
|
|
|
|
this._dot = new St.DrawingArea({ style_class: 'login-dialog-session-list-item-dot' });
|
|
|
|
this._dot.connect('repaint', Lang.bind(this, this._onRepaintDot));
|
|
|
|
this._box.add_actor(this._dot);
|
|
|
|
this.setShowDot(false);
|
|
|
|
|
|
|
|
let label = new St.Label({ style_class: 'login-dialog-session-list-item-label',
|
|
|
|
text: name });
|
|
|
|
|
2012-07-18 20:15:04 -04:00
|
|
|
this._box.add_actor(label);
|
2011-08-23 22:12:57 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
setShowDot: function(show) {
|
|
|
|
if (show)
|
|
|
|
this._dot.opacity = 255;
|
|
|
|
else
|
|
|
|
this._dot.opacity = 0;
|
|
|
|
},
|
|
|
|
|
|
|
|
_onRepaintDot: function(area) {
|
|
|
|
let cr = area.get_context();
|
|
|
|
let [width, height] = area.get_surface_size();
|
|
|
|
let color = area.get_theme_node().get_foreground_color();
|
|
|
|
|
|
|
|
cr.setSourceRGBA (color.red / 255,
|
|
|
|
color.green / 255,
|
|
|
|
color.blue / 255,
|
|
|
|
color.alpha / 255);
|
|
|
|
cr.arc(width / 2, height / 2, width / 3, 0, 2 * Math.PI);
|
|
|
|
cr.fill();
|
|
|
|
},
|
|
|
|
|
|
|
|
_onClicked: function() {
|
|
|
|
this.emit('activate');
|
|
|
|
}
|
2011-11-20 12:56:27 -05:00
|
|
|
});
|
2011-08-23 22:12:57 -04:00
|
|
|
Signals.addSignalMethods(SessionListItem.prototype);
|
|
|
|
|
2011-11-20 12:56:27 -05:00
|
|
|
const SessionList = new Lang.Class({
|
|
|
|
Name: 'SessionList',
|
2011-08-23 22:12:57 -04:00
|
|
|
|
|
|
|
_init: function() {
|
2011-09-06 23:07:09 -04:00
|
|
|
this.actor = new St.Bin();
|
|
|
|
|
|
|
|
this._box = new St.BoxLayout({ style_class: 'login-dialog-session-list',
|
|
|
|
vertical: true});
|
|
|
|
this.actor.child = this._box;
|
2011-08-23 22:12:57 -04:00
|
|
|
|
|
|
|
this._button = new St.Button({ style_class: 'login-dialog-session-list-button',
|
|
|
|
can_focus: true,
|
|
|
|
x_fill: true,
|
|
|
|
y_fill: true });
|
|
|
|
let box = new St.BoxLayout();
|
2012-07-18 20:15:04 -04:00
|
|
|
this._button.add_actor(box);
|
2011-08-23 22:12:57 -04:00
|
|
|
|
|
|
|
this._triangle = new St.Label({ style_class: 'login-dialog-session-list-triangle',
|
|
|
|
text: '\u25B8' });
|
|
|
|
box.add_actor(this._triangle);
|
|
|
|
|
|
|
|
let label = new St.Label({ style_class: 'login-dialog-session-list-label',
|
|
|
|
text: _("Session...") });
|
2012-07-18 20:15:04 -04:00
|
|
|
box.add_actor(label);
|
2011-08-23 22:12:57 -04:00
|
|
|
|
|
|
|
this._button.connect('clicked',
|
|
|
|
Lang.bind(this, this._onClicked));
|
2012-07-18 20:15:04 -04:00
|
|
|
this._box.add_actor(this._button);
|
2011-08-23 22:12:57 -04:00
|
|
|
this._scrollView = new St.ScrollView({ style_class: 'login-dialog-session-list-scroll-view'});
|
|
|
|
this._scrollView.set_policy(Gtk.PolicyType.NEVER,
|
|
|
|
Gtk.PolicyType.AUTOMATIC);
|
2012-07-18 20:15:04 -04:00
|
|
|
this._box.add_actor(this._scrollView);
|
2011-08-23 22:12:57 -04:00
|
|
|
this._itemList = new St.BoxLayout({ style_class: 'login-dialog-session-item-list',
|
|
|
|
vertical: true });
|
2012-07-18 20:15:04 -04:00
|
|
|
this._scrollView.add_actor(this._itemList);
|
2011-08-23 22:12:57 -04:00
|
|
|
this._scrollView.hide();
|
|
|
|
this.isOpen = false;
|
|
|
|
this._populate();
|
|
|
|
},
|
|
|
|
|
|
|
|
open: function() {
|
|
|
|
if (this.isOpen)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this._button.add_style_pseudo_class('open');
|
|
|
|
this._scrollView.show();
|
|
|
|
this._triangle.set_text('\u25BE');
|
|
|
|
|
|
|
|
this.isOpen = true;
|
|
|
|
},
|
|
|
|
|
|
|
|
close: function() {
|
|
|
|
if (!this.isOpen)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this._button.remove_style_pseudo_class('open');
|
|
|
|
this._scrollView.hide();
|
|
|
|
this._triangle.set_text('\u25B8');
|
|
|
|
|
|
|
|
this.isOpen = false;
|
|
|
|
},
|
|
|
|
|
|
|
|
_onClicked: function() {
|
|
|
|
if (!this.isOpen)
|
|
|
|
this.open();
|
|
|
|
else
|
|
|
|
this.close();
|
|
|
|
},
|
|
|
|
|
|
|
|
setActiveSession: function(sessionId) {
|
|
|
|
if (sessionId == this._activeSessionId)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (this._activeSessionId)
|
|
|
|
this._items[this._activeSessionId].setShowDot(false);
|
|
|
|
|
|
|
|
this._items[sessionId].setShowDot(true);
|
|
|
|
this._activeSessionId = sessionId;
|
|
|
|
|
|
|
|
this.emit('session-activated', this._activeSessionId);
|
|
|
|
},
|
|
|
|
|
|
|
|
_populate: function() {
|
2012-02-16 13:27:09 -05:00
|
|
|
this._itemList.destroy_all_children();
|
2011-08-23 22:12:57 -04:00
|
|
|
this._activeSessionId = null;
|
|
|
|
this._items = {};
|
|
|
|
|
2012-05-19 19:19:25 -04:00
|
|
|
let ids = Gdm.get_session_ids();
|
2011-08-23 22:12:57 -04:00
|
|
|
ids.sort();
|
|
|
|
|
2011-10-11 13:34:04 -04:00
|
|
|
if (ids.length <= 1) {
|
2011-09-06 23:07:09 -04:00
|
|
|
this._box.hide();
|
2011-10-11 13:34:04 -04:00
|
|
|
this._button.hide();
|
|
|
|
} else {
|
|
|
|
this._button.show();
|
2011-09-06 23:07:09 -04:00
|
|
|
this._box.show();
|
2011-10-11 13:34:04 -04:00
|
|
|
}
|
2011-08-23 22:12:57 -04:00
|
|
|
|
|
|
|
for (let i = 0; i < ids.length; i++) {
|
2012-05-19 19:19:25 -04:00
|
|
|
let [sessionName, sessionDescription] = Gdm.get_session_name_and_description(ids[i]);
|
2011-08-23 22:12:57 -04:00
|
|
|
|
|
|
|
let item = new SessionListItem(ids[i], sessionName);
|
2012-07-18 20:15:04 -04:00
|
|
|
this._itemList.add_actor(item.actor);
|
2011-08-23 22:12:57 -04:00
|
|
|
this._items[ids[i]] = item;
|
|
|
|
|
|
|
|
if (!this._activeSessionId)
|
|
|
|
this.setActiveSession(ids[i]);
|
|
|
|
|
|
|
|
item.connect('activate',
|
|
|
|
Lang.bind(this, function() {
|
|
|
|
this.setActiveSession(item.id);
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
2011-11-20 12:56:27 -05:00
|
|
|
});
|
2011-08-23 22:12:57 -04:00
|
|
|
Signals.addSignalMethods(SessionList.prototype);
|
|
|
|
|
2011-11-20 10:32:59 -05:00
|
|
|
const LoginDialog = new Lang.Class({
|
|
|
|
Name: 'LoginDialog',
|
|
|
|
Extends: ModalDialog.ModalDialog,
|
2011-08-23 22:12:57 -04:00
|
|
|
|
2012-05-26 11:04:25 -04:00
|
|
|
_init: function(parentActor) {
|
|
|
|
this.parent({ shellReactive: true,
|
|
|
|
styleClass: 'login-dialog',
|
|
|
|
parentActor: parentActor
|
|
|
|
});
|
2011-08-23 22:12:57 -04:00
|
|
|
this.connect('destroy',
|
|
|
|
Lang.bind(this, this._onDestroy));
|
|
|
|
this.connect('opened',
|
|
|
|
Lang.bind(this, this._onOpened));
|
|
|
|
|
|
|
|
this._userManager = AccountsService.UserManager.get_default()
|
2012-05-19 19:19:25 -04:00
|
|
|
this._greeterClient = new Gdm.Client();
|
|
|
|
|
|
|
|
this._greeter = this._greeterClient.get_greeter_sync(null);
|
|
|
|
|
|
|
|
this._greeter.connect('default-session-name-changed',
|
|
|
|
Lang.bind(this, this._onDefaultSessionChanged));
|
|
|
|
|
|
|
|
this._greeter.connect('session-opened',
|
|
|
|
Lang.bind(this, this._onSessionOpened));
|
|
|
|
this._greeter.connect('timed-login-requested',
|
|
|
|
Lang.bind(this, this._onTimedLoginRequested));
|
2011-08-23 22:12:57 -04:00
|
|
|
|
2012-07-17 14:54:07 -04:00
|
|
|
this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient);
|
|
|
|
this._userVerifier.connect('ask-question', Lang.bind(this, this._askQuestion));
|
|
|
|
this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed));
|
|
|
|
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
|
|
|
|
|
2012-08-19 20:15:18 -04:00
|
|
|
this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint));
|
|
|
|
this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint));
|
2011-09-06 16:17:08 -04:00
|
|
|
|
2012-07-17 14:54:07 -04:00
|
|
|
this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA });
|
|
|
|
|
|
|
|
this._settings.connect('changed::' + GdmUtil.LOGO_KEY,
|
2011-09-06 08:37:16 -04:00
|
|
|
Lang.bind(this, this._updateLogo));
|
2012-07-17 14:54:07 -04:00
|
|
|
this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_KEY,
|
2012-07-05 21:11:22 -04:00
|
|
|
Lang.bind(this, this._updateBanner));
|
2012-07-17 14:54:07 -04:00
|
|
|
this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_TEXT_KEY,
|
2012-07-05 21:11:22 -04:00
|
|
|
Lang.bind(this, this._updateBanner));
|
2011-09-06 08:37:16 -04:00
|
|
|
|
|
|
|
this._logoBox = new St.Bin({ style_class: 'login-dialog-logo-box' });
|
|
|
|
this.contentLayout.add(this._logoBox);
|
|
|
|
this._updateLogo();
|
2011-09-06 16:17:08 -04:00
|
|
|
|
2012-07-05 21:11:22 -04:00
|
|
|
this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner',
|
|
|
|
text: '' });
|
|
|
|
this.contentLayout.add(this._bannerLabel);
|
|
|
|
this._updateBanner();
|
|
|
|
|
2011-08-23 22:12:57 -04:00
|
|
|
this._titleLabel = new St.Label({ style_class: 'login-dialog-title',
|
2011-09-09 16:46:23 -04:00
|
|
|
text: C_("title", "Sign In") });
|
2011-08-23 22:12:57 -04:00
|
|
|
|
|
|
|
this.contentLayout.add(this._titleLabel,
|
|
|
|
{ y_fill: false,
|
|
|
|
y_align: St.Align.START });
|
|
|
|
|
|
|
|
let mainContentBox = new St.BoxLayout({ vertical: false });
|
|
|
|
this.contentLayout.add(mainContentBox,
|
|
|
|
{ expand: true,
|
|
|
|
x_fill: true,
|
|
|
|
y_fill: false });
|
|
|
|
|
|
|
|
this._userList = new UserList();
|
|
|
|
mainContentBox.add(this._userList.actor,
|
|
|
|
{ expand: true,
|
|
|
|
x_fill: true,
|
|
|
|
y_fill: true });
|
|
|
|
|
|
|
|
this.setInitialKeyFocus(this._userList.actor);
|
|
|
|
|
|
|
|
this._promptBox = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout',
|
|
|
|
vertical: true });
|
|
|
|
mainContentBox.add(this._promptBox,
|
|
|
|
{ expand: true,
|
|
|
|
x_fill: true,
|
|
|
|
y_fill: true,
|
|
|
|
x_align: St.Align.START });
|
|
|
|
this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' });
|
|
|
|
|
|
|
|
this._mainContentBox = mainContentBox;
|
|
|
|
|
|
|
|
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._promptBox.add(this._promptEntry,
|
|
|
|
{ expand: true,
|
|
|
|
x_fill: true,
|
|
|
|
y_fill: false,
|
|
|
|
x_align: St.Align.START });
|
2012-08-19 20:15:18 -04:00
|
|
|
this._promptLoginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' });
|
|
|
|
this._promptLoginHint.hide();
|
|
|
|
this._promptBox.add(this._promptLoginHint);
|
2011-08-23 22:12:57 -04:00
|
|
|
|
|
|
|
this._sessionList = new SessionList();
|
|
|
|
this._sessionList.connect('session-activated',
|
|
|
|
Lang.bind(this, function(list, sessionId) {
|
2012-05-19 19:19:25 -04:00
|
|
|
this._greeter.call_select_session_sync (sessionId, null);
|
2011-08-23 22:12:57 -04:00
|
|
|
}));
|
|
|
|
|
|
|
|
this._promptBox.add(this._sessionList.actor,
|
2011-09-06 23:07:09 -04:00
|
|
|
{ expand: true,
|
|
|
|
x_fill: false,
|
|
|
|
y_fill: true,
|
|
|
|
x_align: St.Align.START });
|
2011-08-23 22:12:57 -04:00
|
|
|
this._promptBox.hide();
|
|
|
|
|
2011-10-29 12:36:51 -04:00
|
|
|
// 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.
|
2011-08-23 22:12:57 -04:00
|
|
|
let notListedLabel = new St.Label({ text: _("Not listed?"),
|
|
|
|
style_class: 'login-dialog-not-listed-label' });
|
|
|
|
this._notListedButton = new St.Button({ style_class: 'login-dialog-not-listed-button',
|
|
|
|
can_focus: true,
|
|
|
|
child: notListedLabel,
|
|
|
|
reactive: true,
|
|
|
|
x_align: St.Align.START,
|
|
|
|
x_fill: true });
|
|
|
|
|
|
|
|
this._notListedButton.connect('clicked', Lang.bind(this, this._onNotListedClicked));
|
|
|
|
|
|
|
|
this.contentLayout.add(this._notListedButton,
|
|
|
|
{ expand: false,
|
|
|
|
x_align: St.Align.START,
|
|
|
|
x_fill: true });
|
|
|
|
|
|
|
|
if (!this._userManager.is_loaded)
|
|
|
|
this._userManagerLoadedId = this._userManager.connect('notify::is-loaded',
|
|
|
|
Lang.bind(this, function() {
|
|
|
|
if (this._userManager.is_loaded) {
|
|
|
|
this._loadUserList();
|
|
|
|
this._userManager.disconnect(this._userManagerLoadedId);
|
|
|
|
this._userManagerLoadedId = 0;
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
else
|
|
|
|
this._loadUserList();
|
|
|
|
|
|
|
|
this._userList.connect('activate',
|
|
|
|
Lang.bind(this, function(userList, item) {
|
|
|
|
this._onUserListActivated(item);
|
|
|
|
}));
|
|
|
|
|
2011-09-06 16:17:08 -04:00
|
|
|
},
|
|
|
|
|
2011-09-06 08:37:16 -04:00
|
|
|
_updateLogo: function() {
|
|
|
|
this._logoBox.child = null;
|
2012-07-17 14:54:07 -04:00
|
|
|
let path = this._settings.get_string(GdmUtil.LOGO_KEY);
|
2011-09-06 08:37:16 -04:00
|
|
|
|
|
|
|
if (path) {
|
|
|
|
let file = Gio.file_new_for_path(path);
|
|
|
|
let uri = file.get_uri();
|
|
|
|
|
|
|
|
let textureCache = St.TextureCache.get_default();
|
|
|
|
this._logoBox.child = textureCache.load_uri_async(uri, -1, _LOGO_ICON_NAME_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
2012-07-05 21:11:22 -04:00
|
|
|
_updateBanner: function() {
|
2012-07-17 14:54:07 -04:00
|
|
|
let enabled = this._settings.get_boolean(GdmUtil.BANNER_MESSAGE_KEY);
|
|
|
|
let text = this._settings.get_string(GdmUtil.BANNER_MESSAGE_TEXT_KEY);
|
2012-07-05 21:11:22 -04:00
|
|
|
|
|
|
|
if (enabled && text) {
|
|
|
|
this._bannerLabel.set_text(text);
|
|
|
|
this._fadeInBanner();
|
|
|
|
} else {
|
|
|
|
this._fadeOutBanner();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2011-08-23 22:12:57 -04:00
|
|
|
_onReset: function(client, serviceName) {
|
|
|
|
let tasks = [this._hidePrompt,
|
|
|
|
|
|
|
|
new Batch.ConcurrentBatch(this, [this._fadeInTitleLabel,
|
2011-09-06 08:37:16 -04:00
|
|
|
this._fadeInNotListedButton,
|
|
|
|
this._fadeInLogo]),
|
2011-08-23 22:12:57 -04:00
|
|
|
|
|
|
|
function() {
|
|
|
|
this._sessionList.close();
|
2012-08-19 20:15:18 -04:00
|
|
|
this._promptLoginHint.hide();
|
2011-08-23 22:12:57 -04:00
|
|
|
this._userList.actor.show();
|
|
|
|
this._userList.actor.opacity = 255;
|
|
|
|
return this._userList.showItems();
|
|
|
|
},
|
|
|
|
|
|
|
|
function() {
|
|
|
|
this._userList.actor.reactive = true;
|
|
|
|
this._userList.actor.grab_key_focus();
|
|
|
|
}];
|
|
|
|
|
|
|
|
this._user = null;
|
|
|
|
|
|
|
|
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
|
|
|
batch.run();
|
|
|
|
},
|
|
|
|
|
|
|
|
_onDefaultSessionChanged: function(client, sessionId) {
|
|
|
|
this._sessionList.setActiveSession(sessionId);
|
|
|
|
},
|
|
|
|
|
2012-08-19 20:15:18 -04:00
|
|
|
_showLoginHint: function(verifier, message) {
|
|
|
|
this._promptLoginHint.set_text(message)
|
|
|
|
GdmUtil.fadeInActor(this._promptLoginHint);
|
2011-08-23 22:12:57 -04:00
|
|
|
},
|
|
|
|
|
2012-08-19 20:15:18 -04:00
|
|
|
_hideLoginHint: function() {
|
|
|
|
GdmUtil.fadeOutActor(this._promptLoginHint);
|
|
|
|
this._promptLoginHint.set_text('');
|
2012-07-21 14:08:04 -04:00
|
|
|
},
|
2011-08-23 22:12:57 -04:00
|
|
|
|
2012-05-26 11:04:25 -04:00
|
|
|
cancel: function() {
|
2012-07-17 14:54:07 -04:00
|
|
|
this._userVerifier.cancel();
|
2011-08-23 22:12:57 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
_fadeInPrompt: function() {
|
|
|
|
let tasks = [function() {
|
2012-07-17 14:54:07 -04:00
|
|
|
return GdmUtil.fadeInActor(this._promptLabel);
|
2011-08-23 22:12:57 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
function() {
|
2012-07-17 14:54:07 -04:00
|
|
|
return GdmUtil.fadeInActor(this._promptEntry);
|
2011-08-23 22:12:57 -04:00
|
|
|
},
|
|
|
|
|
2011-09-06 16:17:08 -04:00
|
|
|
function() {
|
2011-10-11 13:12:18 -04:00
|
|
|
// Show it with 0 opacity so we preallocate space for it
|
|
|
|
// in the event we need to fade in the message
|
2012-08-19 20:15:18 -04:00
|
|
|
this._promptLoginHint.opacity = 0;
|
|
|
|
this._promptLoginHint.show();
|
2011-09-06 16:17:08 -04:00
|
|
|
},
|
|
|
|
|
2011-08-23 22:12:57 -04:00
|
|
|
function() {
|
2012-07-17 14:54:07 -04:00
|
|
|
return GdmUtil.fadeInActor(this._promptBox);
|
2011-08-23 22:12:57 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
function() {
|
|
|
|
if (this._user && this._user.is_logged_in())
|
|
|
|
return null;
|
|
|
|
|
2012-07-17 14:54:07 -04:00
|
|
|
return GdmUtil.fadeInActor(this._sessionList.actor);
|
2011-08-23 22:12:57 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
function() {
|
|
|
|
this._promptEntry.grab_key_focus();
|
|
|
|
}];
|
|
|
|
|
|
|
|
this._sessionList.actor.hide();
|
|
|
|
let batch = new Batch.ConcurrentBatch(this, tasks);
|
|
|
|
return batch.run();
|
|
|
|
},
|
|
|
|
|
|
|
|
_showPrompt: function() {
|
|
|
|
let hold = new Batch.Hold();
|
|
|
|
|
2012-05-26 11:04:25 -04:00
|
|
|
let buttons = [{ action: Lang.bind(this, this.cancel),
|
2011-08-23 22:12:57 -04:00
|
|
|
label: _("Cancel"),
|
|
|
|
key: Clutter.Escape },
|
|
|
|
{ action: Lang.bind(this, function() {
|
|
|
|
hold.release();
|
|
|
|
}),
|
2012-07-19 09:32:59 -04:00
|
|
|
label: C_("button", "Sign In"),
|
|
|
|
default: true }];
|
2011-08-23 22:12:57 -04:00
|
|
|
|
|
|
|
this._promptEntryActivateCallbackId = this._promptEntry.clutter_text.connect('activate',
|
|
|
|
Lang.bind(this, function() {
|
|
|
|
hold.release();
|
|
|
|
}));
|
|
|
|
hold.connect('release', Lang.bind(this, function() {
|
|
|
|
this._promptEntry.clutter_text.disconnect(this._promptEntryActivateCallbackId);
|
|
|
|
this._promptEntryActivateCallbackId = null;
|
|
|
|
}));
|
|
|
|
|
|
|
|
let tasks = [function() {
|
|
|
|
return this._fadeInPrompt();
|
|
|
|
},
|
|
|
|
|
|
|
|
function() {
|
|
|
|
this.setButtons(buttons);
|
|
|
|
},
|
|
|
|
|
|
|
|
hold];
|
|
|
|
|
|
|
|
let batch = new Batch.ConcurrentBatch(this, tasks);
|
|
|
|
|
|
|
|
return batch.run();
|
|
|
|
},
|
|
|
|
|
|
|
|
_hidePrompt: function() {
|
|
|
|
if (this._promptEntryActivateCallbackId) {
|
|
|
|
this._promptEntry.clutter_text.disconnect(this._promptEntryActivateCallbackId);
|
|
|
|
this._promptEntryActivateCallbackId = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.setButtons([]);
|
|
|
|
|
|
|
|
let tasks = [function() {
|
2012-07-17 14:54:07 -04:00
|
|
|
return GdmUtil.fadeOutActor(this._promptBox);
|
2011-08-23 22:12:57 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
function() {
|
2012-08-19 20:15:18 -04:00
|
|
|
this._promptLoginHint.hide();
|
2011-10-17 01:51:02 -04:00
|
|
|
this._promptEntry.reactive = true;
|
2011-08-23 22:12:57 -04:00
|
|
|
this._promptEntry.set_text('');
|
|
|
|
}];
|
|
|
|
|
|
|
|
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
|
|
|
|
|
|
|
return batch.run();
|
|
|
|
},
|
|
|
|
|
2012-07-17 14:54:07 -04:00
|
|
|
_askQuestion: function(verifier, serviceName, question, passwordChar) {
|
2011-08-23 22:12:57 -04:00
|
|
|
this._promptLabel.set_text(question);
|
|
|
|
|
2012-07-17 14:54:07 -04:00
|
|
|
this._promptEntry.set_text('');
|
|
|
|
this._promptEntry.clutter_text.set_password_char(passwordChar);
|
|
|
|
|
2011-08-23 22:12:57 -04:00
|
|
|
let tasks = [this._showPrompt,
|
|
|
|
|
|
|
|
function() {
|
|
|
|
let _text = this._promptEntry.get_text();
|
2011-10-17 01:51:02 -04:00
|
|
|
this._promptEntry.reactive = false;
|
2012-07-17 14:54:07 -04:00
|
|
|
this._userVerifier.answerQuery(serviceName, _text);
|
2011-08-23 22:12:57 -04:00
|
|
|
}];
|
|
|
|
|
|
|
|
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
|
|
|
return batch.run();
|
|
|
|
},
|
|
|
|
|
|
|
|
_onSessionOpened: function(client, serviceName) {
|
2012-05-19 19:19:25 -04:00
|
|
|
this._greeter.call_start_session_when_ready_sync(serviceName, true, null);
|
2011-08-23 22:12:57 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
_waitForItemForUser: function(userName) {
|
|
|
|
let item = this._userList.getItemFromUserName(userName);
|
|
|
|
|
|
|
|
if (item)
|
|
|
|
return null;
|
|
|
|
|
|
|
|
let hold = new Batch.Hold();
|
|
|
|
let signalId = this._userList.connect('item-added',
|
|
|
|
Lang.bind(this, function() {
|
|
|
|
let item = this._userList.getItemFromUserName(userName);
|
|
|
|
|
|
|
|
if (item)
|
|
|
|
hold.release();
|
|
|
|
}));
|
|
|
|
|
|
|
|
hold.connect('release', Lang.bind(this, function() {
|
|
|
|
this._userList.disconnect(signalId);
|
|
|
|
}));
|
|
|
|
|
|
|
|
return hold;
|
|
|
|
},
|
|
|
|
|
|
|
|
_showTimedLoginAnimation: function() {
|
|
|
|
this._timedLoginItem.actor.grab_key_focus();
|
2012-07-13 18:43:58 -04:00
|
|
|
return this._timedLoginItem.showTimedLoginIndicator(this._timedLoginAnimationTime);
|
2011-08-23 22:12:57 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
_blockTimedLoginUntilIdle: function() {
|
|
|
|
// This blocks timed login from starting until a few
|
|
|
|
// seconds after the user stops interacting with the
|
|
|
|
// login screen.
|
|
|
|
//
|
|
|
|
// We skip this step if the timed login delay is very
|
|
|
|
// short.
|
|
|
|
if ((this._timedLoginDelay - _TIMED_LOGIN_IDLE_THRESHOLD) <= 0)
|
|
|
|
return null;
|
|
|
|
|
|
|
|
let hold = new Batch.Hold();
|
|
|
|
|
|
|
|
this._timedLoginIdleTimeOutId = Mainloop.timeout_add_seconds(_TIMED_LOGIN_IDLE_THRESHOLD,
|
|
|
|
function() {
|
|
|
|
this._timedLoginAnimationTime -= _TIMED_LOGIN_IDLE_THRESHOLD;
|
|
|
|
hold.release();
|
|
|
|
});
|
|
|
|
return hold;
|
|
|
|
},
|
|
|
|
|
|
|
|
_startTimedLogin: function(userName, delay) {
|
|
|
|
this._timedLoginItem = null;
|
|
|
|
this._timedLoginDelay = delay;
|
|
|
|
this._timedLoginAnimationTime = delay;
|
|
|
|
|
|
|
|
let tasks = [function() {
|
|
|
|
return this._waitForItemForUser(userName);
|
|
|
|
},
|
|
|
|
|
|
|
|
function() {
|
|
|
|
this._timedLoginItem = this._userList.getItemFromUserName(userName);
|
|
|
|
},
|
|
|
|
|
|
|
|
function() {
|
|
|
|
// If we're just starting out, start on the right
|
|
|
|
// item.
|
|
|
|
if (!this.is_loaded) {
|
|
|
|
this._userList.jumpToItem(this._timedLoginItem);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
this._blockTimedLoginUntilIdle,
|
|
|
|
|
|
|
|
function() {
|
|
|
|
this._userList.scrollToItem(this._timedLoginItem);
|
|
|
|
},
|
|
|
|
|
|
|
|
this._showTimedLoginAnimation,
|
|
|
|
|
|
|
|
function() {
|
|
|
|
this._timedLoginBatch = null;
|
2012-05-19 19:19:25 -04:00
|
|
|
this._greeter.call_begin_auto_login_sync(userName, null);
|
2011-08-23 22:12:57 -04:00
|
|
|
}];
|
|
|
|
|
|
|
|
this._timedLoginBatch = new Batch.ConsecutiveBatch(this, tasks);
|
|
|
|
|
|
|
|
return this._timedLoginBatch.run();
|
|
|
|
},
|
|
|
|
|
|
|
|
_resetTimedLogin: function() {
|
|
|
|
if (this._timedLoginBatch) {
|
|
|
|
this._timedLoginBatch.cancel();
|
|
|
|
this._timedLoginBatch = null;
|
|
|
|
}
|
|
|
|
|
2012-07-13 18:43:58 -04:00
|
|
|
if (this._timedLoginItem)
|
|
|
|
this._timedLoginItem.hideTimedLoginIndicator();
|
|
|
|
|
2011-08-23 22:12:57 -04:00
|
|
|
let userName = this._timedLoginItem.user.get_user_name();
|
|
|
|
|
|
|
|
if (userName)
|
|
|
|
this._startTimedLogin(userName, this._timedLoginDelay);
|
|
|
|
},
|
|
|
|
|
|
|
|
_onTimedLoginRequested: function(client, userName, seconds) {
|
|
|
|
this._startTimedLogin(userName, seconds);
|
|
|
|
|
|
|
|
global.stage.connect('captured-event',
|
|
|
|
Lang.bind(this, function(actor, event) {
|
|
|
|
if (this._timedLoginDelay == undefined)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (event.type() == Clutter.EventType.KEY_PRESS ||
|
|
|
|
event.type() == Clutter.EventType.BUTTON_PRESS) {
|
|
|
|
if (this._timedLoginBatch) {
|
|
|
|
this._timedLoginBatch.cancel();
|
|
|
|
this._timedLoginBatch = null;
|
|
|
|
}
|
|
|
|
} else if (event.type() == Clutter.EventType.KEY_RELEASE ||
|
|
|
|
event.type() == Clutter.EventType.BUTTON_RELEASE) {
|
|
|
|
this._resetTimedLogin();
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}));
|
|
|
|
},
|
|
|
|
|
2012-07-17 14:54:07 -04:00
|
|
|
_onVerificationFailed: function() {
|
|
|
|
this._userVerifier.cancel();
|
2011-08-23 22:12:57 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
_onNotListedClicked: function(user) {
|
|
|
|
let tasks = [function() {
|
|
|
|
return this._userList.hideItems();
|
|
|
|
},
|
|
|
|
|
|
|
|
function() {
|
|
|
|
return this._userList.giveUpWhitespace();
|
|
|
|
},
|
|
|
|
|
|
|
|
function() {
|
|
|
|
this._userList.actor.hide();
|
|
|
|
},
|
|
|
|
|
|
|
|
new Batch.ConcurrentBatch(this, [this._fadeOutTitleLabel,
|
2011-09-06 08:37:16 -04:00
|
|
|
this._fadeOutNotListedButton,
|
|
|
|
this._fadeOutLogo]),
|
2011-08-23 22:12:57 -04:00
|
|
|
|
|
|
|
function() {
|
2012-05-19 19:19:25 -04:00
|
|
|
let hold = new Batch.Hold();
|
|
|
|
|
2012-07-17 14:54:07 -04:00
|
|
|
this._userVerifier.begin(null, hold);
|
2012-05-19 19:19:25 -04:00
|
|
|
return hold;
|
2011-08-23 22:12:57 -04:00
|
|
|
}];
|
|
|
|
|
|
|
|
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
|
|
|
batch.run();
|
|
|
|
},
|
|
|
|
|
2011-09-06 08:37:16 -04:00
|
|
|
_fadeInLogo: function() {
|
2012-07-17 14:54:07 -04:00
|
|
|
return GdmUtil.fadeInActor(this._logoBox);
|
2011-09-06 08:37:16 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
_fadeOutLogo: function() {
|
2012-07-17 14:54:07 -04:00
|
|
|
return GdmUtil.fadeOutActor(this._logoBox);
|
2011-09-06 08:37:16 -04:00
|
|
|
},
|
|
|
|
|
2012-07-05 21:11:22 -04:00
|
|
|
_fadeInBanner: function() {
|
2012-07-17 14:54:07 -04:00
|
|
|
return GdmUtil.fadeInActor(this._bannerLabel);
|
2012-07-05 21:11:22 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
_fadeOutBanner: function() {
|
2012-07-17 14:54:07 -04:00
|
|
|
return GdmUtil.fadeOutActor(this._bannerLabel);
|
2012-07-05 21:11:22 -04:00
|
|
|
},
|
|
|
|
|
2011-08-23 22:12:57 -04:00
|
|
|
_fadeInTitleLabel: function() {
|
2012-07-17 14:54:07 -04:00
|
|
|
return GdmUtil.fadeInActor(this._titleLabel);
|
2011-08-23 22:12:57 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
_fadeOutTitleLabel: function() {
|
2012-07-17 14:54:07 -04:00
|
|
|
return GdmUtil.fadeOutActor(this._titleLabel);
|
2011-08-23 22:12:57 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
_fadeInNotListedButton: function() {
|
2012-07-17 14:54:07 -04:00
|
|
|
return GdmUtil.fadeInActor(this._notListedButton);
|
2011-08-23 22:12:57 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
_fadeOutNotListedButton: function() {
|
2012-07-17 14:54:07 -04:00
|
|
|
return GdmUtil.fadeOutActor(this._notListedButton);
|
2012-05-19 19:19:25 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
_beginVerificationForUser: function(userName) {
|
2012-07-17 14:54:07 -04:00
|
|
|
let hold = new Batch.Hold();
|
2012-05-19 19:19:25 -04:00
|
|
|
|
2012-07-17 14:54:07 -04:00
|
|
|
this._userVerifier.begin(userName, hold);
|
|
|
|
return hold;
|
2012-05-19 19:19:25 -04:00
|
|
|
},
|
|
|
|
|
2011-08-23 22:12:57 -04:00
|
|
|
_onUserListActivated: function(activatedItem) {
|
2012-05-19 19:19:25 -04:00
|
|
|
let userName;
|
|
|
|
|
2011-08-23 22:12:57 -04:00
|
|
|
let tasks = [function() {
|
|
|
|
this._userList.actor.reactive = false;
|
|
|
|
return this._userList.pinInPlace();
|
|
|
|
},
|
|
|
|
|
|
|
|
function() {
|
|
|
|
return this._userList.hideItemsExcept(activatedItem);
|
|
|
|
},
|
|
|
|
|
|
|
|
function() {
|
|
|
|
return this._userList.giveUpWhitespace();
|
|
|
|
},
|
|
|
|
|
|
|
|
function() {
|
|
|
|
return activatedItem.fadeOutName();
|
|
|
|
},
|
|
|
|
|
|
|
|
new Batch.ConcurrentBatch(this, [this._fadeOutTitleLabel,
|
2011-09-06 08:37:16 -04:00
|
|
|
this._fadeOutNotListedButton,
|
|
|
|
this._fadeOutLogo]),
|
2011-08-23 22:12:57 -04:00
|
|
|
|
|
|
|
function() {
|
|
|
|
return this._userList.shrinkToNaturalHeight();
|
|
|
|
},
|
|
|
|
|
|
|
|
function() {
|
2012-05-19 19:19:25 -04:00
|
|
|
userName = activatedItem.user.get_user_name();
|
2011-09-06 16:17:08 -04:00
|
|
|
|
2012-05-19 19:19:25 -04:00
|
|
|
return this._beginVerificationForUser(userName);
|
2011-08-23 22:12:57 -04:00
|
|
|
}];
|
|
|
|
|
|
|
|
this._user = activatedItem.user;
|
|
|
|
|
|
|
|
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
|
|
|
batch.run();
|
|
|
|
},
|
|
|
|
|
|
|
|
_onDestroy: function() {
|
|
|
|
if (this._userManagerLoadedId) {
|
|
|
|
this._userManager.disconnect(this._userManagerLoadedId);
|
|
|
|
this._userManagerLoadedId = 0;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
_loadUserList: function() {
|
|
|
|
let users = this._userManager.list_users();
|
|
|
|
|
|
|
|
for (let i = 0; i < users.length; i++) {
|
|
|
|
this._userList.addUser(users[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
this._userManager.connect('user-added',
|
|
|
|
Lang.bind(this, function(userManager, user) {
|
|
|
|
this._userList.addUser(user);
|
|
|
|
}));
|
|
|
|
|
|
|
|
this._userManager.connect('user-removed',
|
|
|
|
Lang.bind(this, function(userManager, user) {
|
|
|
|
this._userList.removeUser(user);
|
|
|
|
}));
|
|
|
|
|
|
|
|
// emitted in idle so caller doesn't have to explicitly check if
|
|
|
|
// it's loaded immediately after construction
|
|
|
|
// (since there's no way the caller could be listening for
|
|
|
|
// 'loaded' yet)
|
|
|
|
Mainloop.idle_add(Lang.bind(this, function() {
|
|
|
|
this.emit('loaded');
|
|
|
|
this.is_loaded = true;
|
|
|
|
}));
|
|
|
|
},
|
|
|
|
|
|
|
|
_onOpened: function() {
|
|
|
|
Main.ctrlAltTabManager.addGroup(this._mainContentBox,
|
|
|
|
_("Login Window"),
|
|
|
|
'dialog-password',
|
|
|
|
{ sortGroup: CtrlAltTab.SortGroup.MIDDLE });
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
close: function() {
|
2011-11-20 10:32:59 -05:00
|
|
|
this.parent();
|
2011-08-23 22:12:57 -04:00
|
|
|
|
|
|
|
Main.ctrlAltTabManager.removeGroup(this._group);
|
|
|
|
}
|
2011-11-20 10:32:59 -05:00
|
|
|
});
|