From 9451c04a095f1cea25c0824f3ec7ece05d30d8b8 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 18 Jun 2013 07:28:49 -0400 Subject: [PATCH] loginDialog: start to move login dialog away from modal dialog --- data/theme/gnome-shell.css | 6 ++ js/ui/auth/loginDialog.js | 216 ++++++++++++++++++++++++------------- 2 files changed, 147 insertions(+), 75 deletions(-) diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css index 25852cc8b..fee16d0e6 100644 --- a/data/theme/gnome-shell.css +++ b/data/theme/gnome-shell.css @@ -381,6 +381,7 @@ StScrollBar StButton#vhandle:active { /* Entries */ #searchEntry, +.login-dialog StEntry, .notification StEntry, .modal-dialog StEntry { color: rgb(64, 64, 64); @@ -392,6 +393,7 @@ StScrollBar StButton#vhandle:active { } #searchEntry, +.login-dialog StEntry, .run-dialog-entry, .notification StEntry { border: 2px solid rgba(245,245,245,0.2); @@ -404,6 +406,7 @@ StScrollBar StButton#vhandle:active { #searchEntry:focus, #searchEntry:hover, +.login-dialog StEntry:focus, .notification StEntry:focus, .modal-dialog StEntry { border: 2px solid rgb(136,138,133); @@ -413,6 +416,7 @@ StScrollBar StButton#vhandle:active { box-shadow: inset 0px 2px 4px rgba(0,0,0,0.6); } +.login-dialog StEntry:focus, .notification StEntry:focus, .modal-dialog StEntry:focus { border: 2px solid #3465a4; @@ -436,6 +440,7 @@ StScrollBar StButton#vhandle:active { transition-duration: 0ms; } +.login-dialog StEntry, .notification StEntry, .modal-dialog StEntry { border-radius: 5px; @@ -449,6 +454,7 @@ StScrollBar StButton#vhandle:active { padding: 0 4px; } +.login-dialog StEntry:insensitive, .modal-dialog StEntry:insensitive { border-color: #666666; color: #9f9f9f; diff --git a/js/ui/auth/loginDialog.js b/js/ui/auth/loginDialog.js index 2aa582104..52c2a1407 100644 --- a/js/ui/auth/loginDialog.js +++ b/js/ui/auth/loginDialog.js @@ -19,6 +19,7 @@ */ const AccountsService = imports.gi.AccountsService; +const Atk = imports.gi.Atk; const Clutter = imports.gi.Clutter; const CtrlAltTab = imports.ui.ctrlAltTab; const Gio = imports.gi.Gio; @@ -34,9 +35,11 @@ const Shell = imports.gi.Shell; const St = imports.gi.St; const Gdm = imports.gi.Gdm; +const Animation = imports.ui.animation; const AuthUtil = imports.ui.auth.util; const Batch = imports.misc.batch; const Fprint = imports.ui.auth.fingerprint; +const Layout = imports.ui.layout; const Main = imports.ui.main; const ModalDialog = imports.ui.modalDialog; const SessionList = imports.ui.auth.sessionList; @@ -47,6 +50,9 @@ const UserWidget = imports.ui.userWidget; const _FADE_ANIMATION_TIME = 0.25; 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 _LOGO_ICON_HEIGHT = 48; @@ -54,19 +60,19 @@ let _loginDialog = null; const LoginDialog = new Lang.Class({ Name: 'LoginDialog', - Extends: ModalDialog.ModalDialog, _init: function(parentActor) { - this.parent({ shellReactive: true, - styleClass: 'login-dialog', - parentActor: parentActor, - keybindingMode: Shell.KeyBindingMode.LOGIN_SCREEN, - shouldFadeIn: false }); - this.connect('destroy', - Lang.bind(this, this._onDestroy)); - this.connect('opened', - Lang.bind(this, this._onOpened)); + this.actor = new St.Widget({ accessible_role: Atk.Role.WINDOW, + style_class: 'login-dialog' }); + this.actor.add_constraint(new Layout.MonitorConstraint({ primary: true })); + this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); + parentActor.add_child(this.actor); + + Main.ctrlAltTabManager.addGroup(this.actor, + _("Login Window"), + 'dialog-password-symbolic', + { sortGroup: CtrlAltTab.SortGroup.MIDDLE }); this._userManager = AccountsService.UserManager.get_default() this._greeterClient = new Gdm.Client(); @@ -108,7 +114,11 @@ const LoginDialog = new Lang.Class({ this._userSelectionBox = new St.BoxLayout({ style_class: 'login-dialog-user-selection-box', 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', text: '' }); @@ -121,15 +131,14 @@ const LoginDialog = new Lang.Class({ x_fill: true, y_fill: true }); - this.setInitialKeyFocus(this._userList.actor); + this._userList.actor.grab_key_focus(); this._promptBox = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', vertical: true }); - this.contentLayout.add(this._promptBox, - { expand: true, - x_fill: true, - y_fill: true, - x_align: St.Align.START }); + 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, x_align: St.Align.START }); this._promptBox.add(this._promptUser, @@ -149,10 +158,8 @@ const LoginDialog = new Lang.Class({ this._promptEntryTextChangedId = 0; this._promptEntryActivateId = 0; this._promptBox.add(this._promptEntry, - { expand: true, - x_fill: true, - y_fill: false, - x_align: St.Align.START }); + { expand: false, + x_fill: false }); this._promptMessage = new St.Label({ visible: false }); this._promptBox.add(this._promptMessage, { x_fill: true }); @@ -161,8 +168,6 @@ const LoginDialog = new Lang.Class({ this._promptLoginHint.hide(); this._promptBox.add(this._promptLoginHint); - this._signInButton = null; - this._sessionList = new SessionList.SessionList(); this._sessionList.connect('session-activated', Lang.bind(this, function(list, sessionId) { @@ -174,6 +179,16 @@ const LoginDialog = new Lang.Class({ x_fill: false, y_fill: true, 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(); // translators: this message is shown below the user list on the @@ -198,7 +213,13 @@ const LoginDialog = new Lang.Class({ this._logoBin = new St.Bin({ style_class: 'login-dialog-logo-bin', y_expand: true }); 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_actor(this._logoBin); this._updateLogo(); if (!this._userManager.is_loaded) @@ -279,11 +300,38 @@ const LoginDialog = new Lang.Class({ 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() { this._promptEntry.text = ''; this._updateSensitivity(true); - this.setWorking(false); + this._setWorking(false); }, _onDefaultSessionChanged: function(client, sessionId) { @@ -349,33 +397,62 @@ const LoginDialog = new Lang.Class({ }, _prepareDialog: function(forSecret, hold) { - this.buttonLayout.visible = true; - this.clearButtons(); + this._buttonBox.visible = true; + this._buttonBox.destroy_all_children(); - if (!this._disableUserList || this._verifyingUser) - this.addButton({ action: Lang.bind(this, this.cancel), - label: _("Cancel"), - key: Clutter.Escape }, - { expand: true, - x_fill: false, - y_fill: false, - x_align: St.Align.START, - y_align: St.Align.MIDDLE }); - this.placeSpinner({ expand: false, - x_fill: false, - y_fill: false, - x_align: St.Align.END, - y_align: St.Align.MIDDLE }); - this._signInButton = this.addButton({ action: Lang.bind(this, function() { - hold.release(); - }), - label: forSecret ? C_("button", "Sign In") : _("Next"), - default: true }, - { expand: false, - x_fill: false, - y_fill: false, - x_align: St.Align.END, - y_align: St.Align.MIDDLE }); + if (!this._disableUserList || this._verifyingUser) { + this._cancelButton = new St.Button({ style_class: 'modal-dialog-button', + button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, + reactive: true, + can_focus: true, + label: _("Cancel") }); + this._cancelButton.connect('clicked', + Lang.bind(this, function() { + this.cancel(); + })); + global.stage.connect('captured-event', + Lang.bind(this, function(actor, event) { + if (event.type() == Clutter.EventType.KEY_PRESS && + event.get_key_symbol() == Clutter.KEY_Escape) { + this.cancel(); + } + })); + this._buttonBox.add(this._cancelButton, + { expand: true, + x_fill: false, + y_fill: false, + x_align: St.Align.START, + y_align: St.Align.END }); + } + + let spinnerIcon = global.datadir + '/theme/process-working.svg'; + this._workSpinner = new Animation.AnimatedIcon(spinnerIcon, _WORK_SPINNER_ICON_SIZE); + this._workSpinner.actor.opacity = 0; + this._workSpinner.actor.show(); + + this._buttonBox.add(this._workSpinner.actor, + { expand: false, + x_fill: false, + y_fill: false, + x_align: St.Align.END, + y_align: St.Align.MIDDLE }); + + 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, + y_fill: false, + x_align: St.Align.END, + y_align: St.Align.END }); this._updateSignInButtonSensitivity(this._promptEntry.text.length > 0); @@ -385,10 +462,10 @@ const LoginDialog = new Lang.Class({ this._updateSignInButtonSensitivity(this._promptEntry.text.length > 0); })); - this._promptEntryActivateId = - this._promptEntry.clutter_text.connect('activate', function() { - hold.release(); - }); + this._promptEntryActivateId = + this._promptEntry.clutter_text.connect('activate', function() { + hold.release(); + }); }, _updateSensitivity: function(sensitive) { @@ -406,7 +483,7 @@ const LoginDialog = new Lang.Class({ }, _hidePrompt: function() { - this.setButtons([]); + this._buttonBox.destroy_all_children(); if (this._promptEntryTextChangedId > 0) { this._promptEntry.clutter_text.disconnect(this._promptEntryTextChangedId); @@ -418,7 +495,7 @@ const LoginDialog = new Lang.Class({ this._promptEntryActivateId = 0; } - this.setWorking(false); + this._setWorking(false); this._promptBox.hide(); this._promptLoginHint.hide(); @@ -430,8 +507,9 @@ const LoginDialog = new Lang.Class({ this._sessionList.close(); this._promptLoginHint.hide(); - this.clearButtons(); + this._buttonBox.destroy_all_children(); this._signInButton = null; + this._cancelButton = null; }, _askQuestion: function(verifier, serviceName, question, passwordChar) { @@ -448,7 +526,7 @@ const LoginDialog = new Lang.Class({ function() { let text = this._promptEntry.get_text(); this._updateSensitivity(false); - this.setWorking(true); + this._setWorking(true); this._userVerifier.answerQuery(serviceName, text); }]; @@ -497,7 +575,7 @@ const LoginDialog = new Lang.Class({ }, _startSession: function(serviceName) { - Tweener.addTween(this.dialogLayout, + Tweener.addTween(this.actor, { opacity: 0, time: _FADE_ANIMATION_TIME, transition: 'easeOutQuad', @@ -506,7 +584,7 @@ const LoginDialog = new Lang.Class({ for (let i = 0; i < children.length; i++) { if (children[i] != Main.layoutManager.screenShieldGroup) - children[i].opacity = this.dialogLayout.opacity; + children[i].opacity = this.actor.opacity; } }, onUpdateScope: this, @@ -712,6 +790,8 @@ const LoginDialog = new Lang.Class({ this._userManager.disconnect(this._userManagerLoadedId); this._userManagerLoadedId = 0; } + + Main.ctrlAltTabManager.removeGroup(this.actor); }, _loadUserList: function() { @@ -734,20 +814,6 @@ const LoginDialog = new Lang.Class({ })); }, - _onOpened: function() { - Main.ctrlAltTabManager.addGroup(this.dialogLayout, - _("Login Window"), - 'dialog-password-symbolic', - { sortGroup: CtrlAltTab.SortGroup.MIDDLE }); - - }, - - close: function() { - this.parent(); - - Main.ctrlAltTabManager.removeGroup(this.dialogLayout); - }, - addCharacter: function(unichar) { this._promptEntry.clutter_text.insert_unichar(unichar); },