loginDialog: drop use of modal dialog

The login screen is no longer even remotely dialog-like, so
using ModalDialog is pretty weird. It also makes it difficult
to put the session list in the same place as the spinner.

This commit moves loginDialog away from using modal dialog.

https://bugzilla.gnome.org/show_bug.cgi?id=702818
This commit is contained in:
Ray Strode 2013-06-25 12:55:21 -04:00
parent 048d5dc914
commit ea02380c15
2 changed files with 137 additions and 59 deletions

View File

@ -383,6 +383,7 @@ StScrollBar StButton#vhandle:active {
/* Entries */ /* Entries */
#searchEntry, #searchEntry,
.login-dialog StEntry,
.notification StEntry, .notification StEntry,
.modal-dialog StEntry { .modal-dialog StEntry {
color: rgb(64, 64, 64); color: rgb(64, 64, 64);
@ -394,6 +395,7 @@ StScrollBar StButton#vhandle:active {
} }
#searchEntry, #searchEntry,
.login-dialog StEntry,
.run-dialog-entry, .run-dialog-entry,
.notification StEntry { .notification StEntry {
border: 2px solid rgba(245,245,245,0.2); border: 2px solid rgba(245,245,245,0.2);
@ -406,6 +408,7 @@ StScrollBar StButton#vhandle:active {
#searchEntry:focus, #searchEntry:focus,
#searchEntry:hover, #searchEntry:hover,
.login-dialog StEntry:focus,
.notification StEntry:focus, .notification StEntry:focus,
.modal-dialog StEntry { .modal-dialog StEntry {
border: 2px solid rgb(136,138,133); border: 2px solid rgb(136,138,133);
@ -415,6 +418,7 @@ StScrollBar StButton#vhandle:active {
box-shadow: inset 0px 2px 4px rgba(0,0,0,0.6); box-shadow: inset 0px 2px 4px rgba(0,0,0,0.6);
} }
.login-dialog StEntry:focus,
.notification StEntry:focus, .notification StEntry:focus,
.modal-dialog StEntry:focus { .modal-dialog StEntry:focus {
border: 2px solid #3465a4; border: 2px solid #3465a4;
@ -438,6 +442,7 @@ StScrollBar StButton#vhandle:active {
transition-duration: 0ms; transition-duration: 0ms;
} }
.login-dialog StEntry,
.notification StEntry, .notification StEntry,
.modal-dialog StEntry { .modal-dialog StEntry {
border-radius: 5px; border-radius: 5px;
@ -451,6 +456,7 @@ StScrollBar StButton#vhandle:active {
padding: 0 4px; padding: 0 4px;
} }
.login-dialog StEntry:insensitive,
.modal-dialog StEntry:insensitive { .modal-dialog StEntry:insensitive {
border-color: #666666; border-color: #666666;
color: #9f9f9f; color: #9f9f9f;

View File

@ -19,6 +19,7 @@
*/ */
const AccountsService = imports.gi.AccountsService; const AccountsService = imports.gi.AccountsService;
const Atk = imports.gi.Atk;
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const Gdm = imports.gi.Gdm; const Gdm = imports.gi.Gdm;
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
@ -31,17 +32,21 @@ const Shell = imports.gi.Shell;
const Signals = imports.signals; const Signals = imports.signals;
const St = imports.gi.St; const St = imports.gi.St;
const Animation = imports.ui.animation;
const Batch = imports.gdm.batch; const Batch = imports.gdm.batch;
const CtrlAltTab = imports.ui.ctrlAltTab; const CtrlAltTab = imports.ui.ctrlAltTab;
const GdmUtil = imports.gdm.util; const GdmUtil = imports.gdm.util;
const Layout = imports.ui.layout;
const Main = imports.ui.main; const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
const Realmd = imports.gdm.realmd; const Realmd = imports.gdm.realmd;
const Tweener = imports.ui.tweener; const Tweener = imports.ui.tweener;
const UserWidget = imports.ui.userWidget; const UserWidget = imports.ui.userWidget;
const _FADE_ANIMATION_TIME = 0.25; const _FADE_ANIMATION_TIME = 0.25;
const _SCROLL_ANIMATION_TIME = 0.5; const _SCROLL_ANIMATION_TIME = 0.5;
const _WORK_SPINNER_ICON_SIZE = 24;
const _WORK_SPINNER_ANIMATION_DELAY = 1.0;
const _WORK_SPINNER_ANIMATION_TIME = 0.3;
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0; const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
const _LOGO_ICON_HEIGHT = 48; const _LOGO_ICON_HEIGHT = 48;
@ -468,18 +473,15 @@ Signals.addSignalMethods(SessionList.prototype);
const LoginDialog = new Lang.Class({ const LoginDialog = new Lang.Class({
Name: 'LoginDialog', Name: 'LoginDialog',
Extends: ModalDialog.ModalDialog,
_init: function(parentActor) { _init: function(parentActor) {
this.parent({ shellReactive: true, this.actor = new St.Widget({ accessible_role: Atk.Role.WINDOW,
styleClass: 'login-dialog', style_class: 'login-dialog',
parentActor: parentActor, visible: false });
keybindingMode: Shell.KeyBindingMode.LOGIN_SCREEN,
shouldFadeIn: false }); this.actor.add_constraint(new Layout.MonitorConstraint({ primary: true }));
this.connect('destroy', this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
Lang.bind(this, this._onDestroy)); parentActor.add_child(this.actor);
this.connect('opened',
Lang.bind(this, this._onOpened));
this._userManager = AccountsService.UserManager.get_default() this._userManager = AccountsService.UserManager.get_default()
this._greeterClient = new Gdm.Client(); this._greeterClient = new Gdm.Client();
@ -522,7 +524,10 @@ const LoginDialog = new Lang.Class({
this._userSelectionBox = new St.BoxLayout({ style_class: 'login-dialog-user-selection-box', this._userSelectionBox = new St.BoxLayout({ style_class: 'login-dialog-user-selection-box',
vertical: true }); vertical: true });
this.contentLayout.add(this._userSelectionBox); this._userSelectionBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor,
align_axis: Clutter.AlignAxis.BOTH,
factor: 0.5 }));
this.actor.add_child(this._userSelectionBox);
this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner', this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner',
text: '' }); text: '' });
@ -535,15 +540,20 @@ const LoginDialog = new Lang.Class({
x_fill: true, x_fill: true,
y_fill: true }); y_fill: true });
this.setInitialKeyFocus(this._userList.actor);
this._promptBox = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', this._promptBox = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout',
vertical: true }); vertical: true });
this.contentLayout.add(this._promptBox,
{ expand: true, this._promptBox.connect('button-press-event',
x_fill: true, Lang.bind(this, function(actor, event) {
y_fill: true, if (event.get_key_symbol() == Clutter.KEY_Escape) {
x_align: St.Align.START }); this.cancel();
}
}));
this._promptBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor,
align_axis: Clutter.AlignAxis.BOTH,
factor: 0.5 }));
this.actor.add_child(this._promptBox);
this._promptUser = new St.Bin({ x_fill: true, this._promptUser = new St.Bin({ x_fill: true,
x_align: St.Align.START }); x_align: St.Align.START });
this._promptBox.add(this._promptUser, this._promptBox.add(this._promptUser,
@ -575,8 +585,6 @@ const LoginDialog = new Lang.Class({
this._promptLoginHint.hide(); this._promptLoginHint.hide();
this._promptBox.add(this._promptLoginHint); this._promptBox.add(this._promptLoginHint);
this._signInButton = null;
this._sessionList = new SessionList(); this._sessionList = new SessionList();
this._sessionList.connect('session-activated', this._sessionList.connect('session-activated',
Lang.bind(this, function(list, sessionId) { Lang.bind(this, function(list, sessionId) {
@ -588,6 +596,15 @@ const LoginDialog = new Lang.Class({
x_fill: false, x_fill: false,
y_fill: true, y_fill: true,
x_align: St.Align.START }); x_align: St.Align.START });
this._buttonBox = new St.BoxLayout({ style_class: 'modal-dialog-button-box',
vertical: false });
this._promptBox.add(this._buttonBox,
{ expand: true,
x_align: St.Align.MIDDLE,
y_align: St.Align.END });
this._cancelButton = null;
this._signInButton = null;
this._promptBox.hide(); this._promptBox.hide();
// translators: this message is shown below the user list on the // translators: this message is shown below the user list on the
@ -612,7 +629,13 @@ const LoginDialog = new Lang.Class({
this._logoBin = new St.Bin({ style_class: 'login-dialog-logo-bin', y_expand: true }); this._logoBin = new St.Bin({ style_class: 'login-dialog-logo-bin', y_expand: true });
this._logoBin.set_y_align(Clutter.ActorAlign.END); this._logoBin.set_y_align(Clutter.ActorAlign.END);
this.backgroundStack.add_actor(this._logoBin); this._logoBin.add_constraint(new Clutter.AlignConstraint({ source: this.actor,
align_axis: Clutter.AlignAxis.X_AXIS,
factor: 0.5 }));
this._logoBin.add_constraint(new Clutter.AlignConstraint({ source: this.actor,
align_axis: Clutter.AlignAxis.Y_AXIS,
factor: 1.0 }));
this.actor.add_child(this._logoBin);
this._updateLogo(); this._updateLogo();
if (!this._userManager.is_loaded) if (!this._userManager.is_loaded)
@ -693,11 +716,38 @@ const LoginDialog = new Lang.Class({
this._showUserList(); this._showUserList();
}, },
_setWorking: function(working) {
if (!this._workSpinner)
return;
Tweener.removeTweens(this._workSpinner.actor);
if (working) {
this._workSpinner.play();
Tweener.addTween(this._workSpinner.actor,
{ opacity: 255,
delay: _WORK_SPINNER_ANIMATION_DELAY,
time: _WORK_SPINNER_ANIMATION_TIME,
transition: 'linear'
});
} else {
Tweener.addTween(this._workSpinner.actor,
{ opacity: 0,
time: _WORK_SPINNER_ANIMATION_TIME,
transition: 'linear',
onCompleteScope: this,
onComplete: function() {
if (this._workSpinner)
this._workSpinner.stop();
}
});
}
},
_verificationFailed: function() { _verificationFailed: function() {
this._promptEntry.text = ''; this._promptEntry.text = '';
this._updateSensitivity(true); this._updateSensitivity(true);
this.setWorking(false); this._setWorking(false);
}, },
_onDefaultSessionChanged: function(client, sessionId) { _onDefaultSessionChanged: function(client, sessionId) {
@ -763,33 +813,52 @@ const LoginDialog = new Lang.Class({
}, },
_prepareDialog: function(forSecret, hold) { _prepareDialog: function(forSecret, hold) {
this.buttonLayout.visible = true; this._buttonBox.visible = true;
this.clearButtons(); this._buttonBox.destroy_all_children();
if (!this._disableUserList || this._verifyingUser) if (!this._disableUserList || this._verifyingUser) {
this.addButton({ action: Lang.bind(this, this.cancel), this._cancelButton = new St.Button({ style_class: 'modal-dialog-button',
label: _("Cancel"), button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
key: Clutter.Escape }, reactive: true,
can_focus: true,
label: _("Cancel") });
this._cancelButton.connect('clicked',
Lang.bind(this, function() {
this.cancel();
}));
this._buttonBox.add(this._cancelButton,
{ expand: true, { expand: true,
x_fill: false, x_fill: false,
y_fill: false, y_fill: false,
x_align: St.Align.START, x_align: St.Align.START,
y_align: St.Align.MIDDLE }); y_align: St.Align.END });
this.placeSpinner({ expand: false, }
x_fill: false,
y_fill: false, let spinnerIcon = global.datadir + '/theme/process-working.svg';
x_align: St.Align.END, this._workSpinner = new Animation.AnimatedIcon(spinnerIcon, _WORK_SPINNER_ICON_SIZE);
y_align: St.Align.MIDDLE }); this._workSpinner.actor.opacity = 0;
this._signInButton = this.addButton({ action: Lang.bind(this, function() { this._workSpinner.actor.show();
hold.release();
}), this._buttonBox.add(this._workSpinner.actor,
label: forSecret ? C_("button", "Sign In") : _("Next"),
default: true },
{ expand: false, { expand: false,
x_align: St.Align.END });
this._signInButton = new St.Button({ style_class: 'modal-dialog-button',
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
reactive: true,
can_focus: true,
label: forSecret ? C_("button", "Sign In") : _("Next") });
this._signInButton.connect('clicked',
Lang.bind(this, function() {
hold.release();
}));
this._signInButton.add_style_pseudo_class('default');
this._buttonBox.add(this._signInButton,
{ expand: true,
x_fill: false, x_fill: false,
y_fill: false, y_fill: false,
x_align: St.Align.END, x_align: St.Align.END,
y_align: St.Align.MIDDLE }); y_align: St.Align.END });
this._updateSignInButtonSensitivity(this._promptEntry.text.length > 0); this._updateSignInButtonSensitivity(this._promptEntry.text.length > 0);
@ -820,7 +889,7 @@ const LoginDialog = new Lang.Class({
}, },
_hidePrompt: function() { _hidePrompt: function() {
this.setButtons([]); this._buttonBox.destroy_all_children();
if (this._promptEntryTextChangedId > 0) { if (this._promptEntryTextChangedId > 0) {
this._promptEntry.clutter_text.disconnect(this._promptEntryTextChangedId); this._promptEntry.clutter_text.disconnect(this._promptEntryTextChangedId);
@ -832,7 +901,7 @@ const LoginDialog = new Lang.Class({
this._promptEntryActivateId = 0; this._promptEntryActivateId = 0;
} }
this.setWorking(false); this._setWorking(false);
this._promptBox.hide(); this._promptBox.hide();
this._promptLoginHint.hide(); this._promptLoginHint.hide();
@ -844,8 +913,9 @@ const LoginDialog = new Lang.Class({
this._sessionList.close(); this._sessionList.close();
this._promptLoginHint.hide(); this._promptLoginHint.hide();
this.clearButtons(); this._buttonBox.destroy_all_children();
this._signInButton = null; this._signInButton = null;
this._cancelButton = null;
}, },
_askQuestion: function(verifier, serviceName, question, passwordChar) { _askQuestion: function(verifier, serviceName, question, passwordChar) {
@ -862,7 +932,7 @@ const LoginDialog = new Lang.Class({
function() { function() {
let text = this._promptEntry.get_text(); let text = this._promptEntry.get_text();
this._updateSensitivity(false); this._updateSensitivity(false);
this.setWorking(true); this._setWorking(true);
this._userVerifier.answerQuery(serviceName, text); this._userVerifier.answerQuery(serviceName, text);
}]; }];
@ -911,7 +981,7 @@ const LoginDialog = new Lang.Class({
}, },
_startSession: function(serviceName) { _startSession: function(serviceName) {
Tweener.addTween(this.dialogLayout, Tweener.addTween(this.actor,
{ opacity: 0, { opacity: 0,
time: _FADE_ANIMATION_TIME, time: _FADE_ANIMATION_TIME,
transition: 'easeOutQuad', transition: 'easeOutQuad',
@ -920,7 +990,7 @@ const LoginDialog = new Lang.Class({
for (let i = 0; i < children.length; i++) { for (let i = 0; i < children.length; i++) {
if (children[i] != Main.layoutManager.screenShieldGroup) if (children[i] != Main.layoutManager.screenShieldGroup)
children[i].opacity = this.dialogLayout.opacity; children[i].opacity = this.actor.opacity;
} }
}, },
onUpdateScope: this, onUpdateScope: this,
@ -1148,17 +1218,18 @@ const LoginDialog = new Lang.Class({
})); }));
}, },
_onOpened: function() { open: function() {
Main.ctrlAltTabManager.addGroup(this.dialogLayout, Main.ctrlAltTabManager.addGroup(this.actor,
_("Login Window"), _("Login Window"),
'dialog-password-symbolic', 'dialog-password-symbolic',
{ sortGroup: CtrlAltTab.SortGroup.MIDDLE }); { sortGroup: CtrlAltTab.SortGroup.MIDDLE });
this._userList.actor.grab_key_focus();
this.actor.show();
return true;
}, },
close: function() { close: function() {
this.parent();
Main.ctrlAltTabManager.removeGroup(this.dialogLayout); Main.ctrlAltTabManager.removeGroup(this.dialogLayout);
}, },
@ -1166,3 +1237,4 @@ const LoginDialog = new Lang.Class({
this._promptEntry.clutter_text.insert_unichar(unichar); this._promptEntry.clutter_text.insert_unichar(unichar);
}, },
}); });
Signals.addSignalMethods(LoginDialog.prototype);