Blob Blame History Raw
From b0f59711785d43d0d3dd76e09064e36bea516e1b Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 12 Nov 2014 11:27:50 -0500
Subject: [PATCH 1/5] Revert "loginDialog: make banner message more prominent."

This reverts commit 1f00c48feb75a8749b80a7cace94f622df825f7c.
---
 data/theme/gnome-shell.css | 13 ++++++++-----
 js/gdm/loginDialog.js      | 44 ++++++++++++++++++++++----------------------
 2 files changed, 30 insertions(+), 27 deletions(-)

diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index e12c78d..0db9d1e 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -2188,65 +2188,68 @@ StScrollBar StButton#vhandle:active {
     border-radius: 4px;
     background-color: rgba(255,255,255,0.1);
 }
 .candidate-page-button-box {
     height: 2em;
     width: 80px;
 }
 
 .vertical .candidate-page-button-box {
     padding-top: 0.5em;
 }
 
 .horizontal .candidate-page-button-box {
     padding-left: 0.5em;
 }
 
 .candidate-page-button-previous {
     border-radius: 4px 0px 0px 4px;
 }
 
 .candidate-page-button-next {
     border-radius: 0px 4px 4px 0px;
 }
 
 .candidate-page-button-icon {
     icon-size: 1em;
 }
 
 /* Login Dialog */
 .login-dialog-banner-view {
-    padding-top: 96px;
-    padding-left: 1em;
-    height: 14em;
-    max-width: 42em;
-    min-width: 25em;
+    padding-top: 10em;
+    height: 10em;
+}
+
+.login-dialog-banner {
+    font-size: 9pt;
+    color: #666666;
+    width: 30em;
 }
 
 .login-dialog-title {
     font-size: 14pt;
     font-weight: bold;
     color: #666666;
     padding-bottom: 2em;
 }
 
 .login-dialog {
     /* Reset border and background */
     border: none;
     background-color: transparent;
 }
 
 .login-dialog-button-box {
     spacing: 5px;
 }
 
 .login-dialog-user-list-view {
     -st-vfade-offset: 1em;
 }
 
 .login-dialog-user-list {
     spacing: 12px;
     padding: .2em;
     width: 23em;
 }
 
 .login-dialog-user-list-item {
diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js
index 8f5044f..aadc5a9 100644
--- a/js/gdm/loginDialog.js
+++ b/js/gdm/loginDialog.js
@@ -407,136 +407,136 @@ const LoginDialog = new Lang.Class({
         this._userManager = AccountsService.UserManager.get_default()
         let gdmClient = new Gdm.Client();
 
         if (GLib.getenv('GDM_GREETER_TEST') != '1') {
             this._greeter = gdmClient.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));
         }
 
         this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA });
 
         this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_KEY,
                                Lang.bind(this, this._updateBanner));
         this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_TEXT_KEY,
                                Lang.bind(this, this._updateBanner));
         this._settings.connect('changed::' + GdmUtil.DISABLE_USER_LIST_KEY,
                                Lang.bind(this, this._updateDisableUserList));
         this._settings.connect('changed::' + GdmUtil.LOGO_KEY,
                                Lang.bind(this, this._updateLogo));
 
         this._textureCache = St.TextureCache.get_default();
         this._textureCache.connect('texture-file-changed',
                                    Lang.bind(this, this._updateLogoTexture));
 
-        let outerBox = new St.BoxLayout({ x_align: Clutter.ActorAlign.CENTER,
-                                          y_align: Clutter.ActorAlign.START,
-                                          y_expand: true,
-                                          vertical: true });
-        table.pack(outerBox, 0, 0);
-        this._bannerView = new St.ScrollView({ style_class: 'login-dialog-banner-view',
-                                               opacity: 0,
-                                               vscrollbar_policy: Gtk.PolicyType.AUTOMATIC,
-                                               hscrollbar_policy: Gtk.PolicyType.NEVER });
-        outerBox.add_actor(this._bannerView);
-
-        let innerBox = new St.BoxLayout({ vertical: true });
-
-        this._bannerView.add_actor(innerBox);
-        this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner',
-                                           text: '' });
-        this._bannerLabel.clutter_text.line_wrap = true;
-        this._bannerLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
-        innerBox.add_child(this._bannerLabel);
-        this._updateBanner();
-
         this._userSelectionBox = new St.BoxLayout({ style_class: 'login-dialog-user-selection-box',
                                                     x_align: Clutter.ActorAlign.CENTER,
                                                     y_align: Clutter.ActorAlign.CENTER,
                                                     x_expand: true,
                                                     y_expand: true,
                                                     vertical: true,
                                                     visible: false });
         this._userList = new UserList();
         this._userSelectionBox.add(this._userList.actor,
                                    { expand: true,
                                      x_fill: true,
                                      y_fill: true });
 
         this._authPrompt = new AuthPrompt.AuthPrompt(gdmClient, AuthPrompt.AuthPromptMode.UNLOCK_OR_LOG_IN);
         this._authPrompt.connect('prompted', Lang.bind(this, this._onPrompted));
         this._authPrompt.connect('reset', Lang.bind(this, this._onReset));
         this._authPrompt.hide();
         this._authPrompt.actor.x_align = Clutter.ActorAlign.CENTER;
         this._authPrompt.actor.y_align = Clutter.ActorAlign.CENTER;
         this._authPrompt.actor.x_expand = false;
         this._authPrompt.actor.y_expand = false;
         table.pack(this._authPrompt.actor, 0, 0);
         table.set_span(this._authPrompt.actor, 1, 3);
 
         // 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.
         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',
                                                 button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
                                                 can_focus: true,
                                                 child: notListedLabel,
                                                 reactive: true,
                                                 x_align: St.Align.START,
                                                 x_fill: true });
 
         this._notListedButton.connect('clicked', Lang.bind(this, this._hideUserListAskForUsernameAndBeginVerification));
 
         this._notListedButton.hide();
 
         this._userSelectionBox.add(this._notListedButton,
                                    { expand: false,
                                      x_align: St.Align.START,
                                      x_fill: true });
 
         this._logoBin = new St.Widget({ style_class: 'login-dialog-logo-bin',
                                         x_align: Clutter.ActorAlign.CENTER,
                                         y_align: Clutter.ActorAlign.END,
                                         x_expand: true,
                                         y_expand: true });
 
         table.pack(this._userSelectionBox, 0, 0);
         table.set_span(this._userSelectionBox, 1, 3);
 
+        let outerBox = new St.BoxLayout({ x_align: Clutter.ActorAlign.CENTER,
+                                          y_align: Clutter.ActorAlign.CENTER,
+                                          vertical: true });
+        table.pack(outerBox, 0, 2);
+        table.set_span(outerBox, 1, 1);
+        this._bannerView = new St.ScrollView({ style_class: 'login-dialog-banner-view',
+                                               opacity: 0,
+                                               vscrollbar_policy: Gtk.PolicyType.AUTOMATIC,
+                                               hscrollbar_policy: Gtk.PolicyType.NEVER });
+        outerBox.add_actor(this._bannerView);
+
+        let innerBox = new St.BoxLayout({ vertical: true });
+
+        this._bannerView.add_actor(innerBox);
+        this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner',
+                                           text: '' });
+        this._bannerLabel.clutter_text.line_wrap = true;
+        this._bannerLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
+        innerBox.add_child(this._bannerLabel);
+        this._updateBanner();
+
         table.pack(this._logoBin, 0, 2);
         table.set_span(this._logoBin, 1, 1);
         this._updateLogo();
 
         // We have overlapping widgets to obtain the kind of centering we want.
         // We need to make sure the widgets that take input are on top of the
         // stack.
         this.actor.set_child_above_sibling(this._userSelectionBox, null);
         this.actor.set_child_above_sibling(this._authPrompt.actor, null);
 
         this._userList.connect('activate',
                                Lang.bind(this, function(userList, item) {
                                    this._onUserListActivated(item);
                                }));
 
 
         this._sessionMenuButton = new SessionMenuButton();
         this._sessionMenuButton.connect('session-activated',
                                   Lang.bind(this, function(list, sessionId) {
                                                 this._greeter.call_select_session_sync (sessionId, null);
                                             }));
         this._sessionMenuButton.actor.opacity = 0;
         this._sessionMenuButton.actor.show();
         this._authPrompt.addActorToDefaultButtonWell(this._sessionMenuButton.actor);
 
         this._disableUserList = undefined;
         this._userListLoaded = false;
 
         // If the user list is enabled, it should take key focus; make sure the
         // screen shield is initialized first to prevent it from stealing the
@@ -599,107 +599,107 @@ const LoginDialog = new Lang.Class({
         Tweener.addTween(this._bannerView,
                          { opacity: 255,
                            time: _FADE_ANIMATION_TIME,
                            transition: 'easeOutQuad' });
     },
 
     _hideBannerView: function() {
         Tweener.removeTweens(this._bannerView);
         this._bannerView.opacity = 0;
     },
 
     _updateLogoTexture: function(cache, uri) {
         if (this._logoFileUri != uri)
             return;
 
         this._logoBin.destroy_all_children();
         if (this._logoFileUri)
             this._logoBin.add_child(this._textureCache.load_uri_async(this._logoFileUri,
                                                                       -1, _LOGO_ICON_HEIGHT));
     },
 
     _updateLogo: function() {
         let path = this._settings.get_string(GdmUtil.LOGO_KEY);
 
         this._logoFileUri = path ? Gio.file_new_for_path(path).get_uri() : null;
         this._updateLogoTexture(this._textureCache, this._logoFileUri);
     },
 
     _onPrompted: function() {
         this._sessionMenuButton.updateSensitivity(true);
+        this._fadeInBannerView();
 
         if (this._shouldShowSessionMenuButton())
             this._authPrompt.setActorInDefaultButtonWell(this._sessionMenuButton.actor);
         this._showPrompt();
     },
 
     _onReset: function(authPrompt, beginRequest) {
         this._sessionMenuButton.updateSensitivity(true);
         this._hideBannerView();
 
         this._user = null;
 
         if (beginRequest == AuthPrompt.BeginRequestType.PROVIDE_USERNAME) {
             if (!this._disableUserList)
                 this._showUserList();
             else
                 this._hideUserListAskForUsernameAndBeginVerification();
         } else {
             this._hideUserListAndBeginVerification();
         }
     },
 
     _onDefaultSessionChanged: function(client, sessionId) {
         this._sessionMenuButton.setActiveSession(sessionId);
     },
 
     _shouldShowSessionMenuButton: function() {
         if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFYING &&
             this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFICATION_FAILED)
           return false;
 
         if (this._user && this._user.is_loaded && this._user.is_logged_in())
           return false;
 
         return true;
     },
 
     _showPrompt: function() {
         if (this._authPrompt.actor.visible)
             return;
         this._authPrompt.actor.opacity = 0;
         this._authPrompt.actor.show();
         Tweener.addTween(this._authPrompt.actor,
                          { opacity: 255,
                            time: _FADE_ANIMATION_TIME,
                            transition: 'easeOutQuad' });
-        this._fadeInBannerView();
     },
 
     _showRealmLoginHint: function(realmManager, hint) {
         if (!hint)
             return;
 
         hint = hint.replace(/%U/g, 'user');
         hint = hint.replace(/%D/g, 'DOMAIN');
         hint = hint.replace(/%[^UD]/g, '');
 
         // Translators: this message is shown below the username entry field
         // to clue the user in on how to login to the local network realm
         this._authPrompt.setMessage(_("(e.g., user or %s)").format(hint), GdmUtil.MessageType.HINT);
     },
 
     _askForUsernameAndBeginVerification: function() {
         this._authPrompt.setPasswordChar('');
         this._authPrompt.setQuestion(_("Username: "));
 
         let realmManager = new Realmd.Manager();
         let realmSignalId = realmManager.connect('login-format-changed',
                                                  Lang.bind(this, this._showRealmLoginHint));
         this._showRealmLoginHint(realmManager.loginFormat);
 
         let nextSignalId = this._authPrompt.connect('next',
                                                     Lang.bind(this, function() {
                                                         this._authPrompt.disconnect(nextSignalId);
                                                         this._authPrompt.updateSensitivity(false);
                                                         let answer = this._authPrompt.getAnswer();
                                                         this._user = this._userManager.get_user(answer);
-- 
2.1.0


From c5ef28f7ccc96bf6ed57c80fe98cd5fe31f4004d Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 12 Nov 2014 11:29:22 -0500
Subject: [PATCH 2/5] Revert "loginDialog: display banner message when
 disable-user-list=true"

This reverts commit b94289671424068d973a553fb610398830d25e21.

Conflicts:
	js/gdm/loginDialog.js
---
 data/theme/gnome-shell.css | 10 +++---
 js/gdm/loginDialog.js      | 76 +++++++++++++---------------------------------
 2 files changed, 25 insertions(+), 61 deletions(-)

diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index 0db9d1e..aa82632 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -2187,69 +2187,67 @@ StScrollBar StButton#vhandle:active {
 .candidate-box:hover {
     border-radius: 4px;
     background-color: rgba(255,255,255,0.1);
 }
 .candidate-page-button-box {
     height: 2em;
     width: 80px;
 }
 
 .vertical .candidate-page-button-box {
     padding-top: 0.5em;
 }
 
 .horizontal .candidate-page-button-box {
     padding-left: 0.5em;
 }
 
 .candidate-page-button-previous {
     border-radius: 4px 0px 0px 4px;
 }
 
 .candidate-page-button-next {
     border-radius: 0px 4px 4px 0px;
 }
 
 .candidate-page-button-icon {
     icon-size: 1em;
 }
 
 /* Login Dialog */
-.login-dialog-banner-view {
-    padding-top: 10em;
-    height: 10em;
-}
 
 .login-dialog-banner {
-    font-size: 9pt;
+    font-size: 10pt;
+    font-weight: bold;
+    text-align: center;
     color: #666666;
-    width: 30em;
+    padding-bottom: 1em;
 }
 
 .login-dialog-title {
     font-size: 14pt;
     font-weight: bold;
     color: #666666;
     padding-bottom: 2em;
 }
 
 .login-dialog {
     /* Reset border and background */
     border: none;
     background-color: transparent;
 }
 
 .login-dialog-button-box {
     spacing: 5px;
 }
 
 .login-dialog-user-list-view {
     -st-vfade-offset: 1em;
 }
 
 .login-dialog-user-list {
     spacing: 12px;
     padding: .2em;
     width: 23em;
 }
 
 .login-dialog-user-list-item {
diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js
index aadc5a9..f35921c 100644
--- a/js/gdm/loginDialog.js
+++ b/js/gdm/loginDialog.js
@@ -1,61 +1,60 @@
 // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 /*
  * 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 Atk = imports.gi.Atk;
 const Clutter = imports.gi.Clutter;
 const Gdm = imports.gi.Gdm;
 const Gio = imports.gi.Gio;
 const GLib = imports.gi.GLib;
 const Gtk = imports.gi.Gtk;
 const Lang = imports.lang;
 const Mainloop = imports.mainloop;
 const Meta = imports.gi.Meta;
-const Pango = imports.gi.Pango;
 const Shell = imports.gi.Shell;
 const Signals = imports.signals;
 const St = imports.gi.St;
 
 const AuthPrompt = imports.gdm.authPrompt;
 const Batch = imports.gdm.batch;
 const BoxPointer = imports.ui.boxpointer;
 const CtrlAltTab = imports.ui.ctrlAltTab;
 const GdmUtil = imports.gdm.util;
 const Layout = imports.ui.layout;
 const Main = imports.ui.main;
 const PopupMenu = imports.ui.popupMenu;
 const Realmd = imports.gdm.realmd;
 const Tweener = imports.ui.tweener;
 const UserMenu = imports.ui.userMenu;
 const UserWidget = imports.ui.userWidget;
 
 const _FADE_ANIMATION_TIME = 0.25;
 const _SCROLL_ANIMATION_TIME = 0.5;
 const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
 const _LOGO_ICON_HEIGHT = 48;
 
 let _loginDialog = null;
 
 const UserListItem = new Lang.Class({
     Name: 'UserListItem',
 
     _init: function(user) {
         this.user = user;
         this._userChangedId = this.user.connect('changed',
@@ -367,185 +366,166 @@ const SessionMenuButton = new Lang.Class({
         ids.sort();
 
         if (ids.length <= 1) {
             this._button.hide();
             return;
         }
 
         for (let i = 0; i < ids.length; i++) {
             let [sessionName, sessionDescription] = Gdm.get_session_name_and_description(ids[i]);
 
             let id = ids[i];
             let item = new PopupMenu.PopupMenuItem(sessionName);
             this._menu.addMenuItem(item);
             this._items[id] = item;
 
             if (!this._activeSessionId)
                 this.setActiveSession(id);
 
             item.connect('activate', Lang.bind(this, function() {
                 this.setActiveSession(id);
             }));
         }
     }
 });
 Signals.addSignalMethods(SessionMenuButton.prototype);
 
 const LoginDialog = new Lang.Class({
     Name: 'LoginDialog',
 
     _init: function(parentActor) {
-        let table = new Clutter.TableLayout();
         this.actor = new St.Widget({ accessible_role: Atk.Role.WINDOW,
-                                     layout_manager: table,
+                                     layout_manager: new Clutter.BinLayout(),
                                      style_class: 'login-dialog',
                                      visible: false });
 
         this.actor.add_constraint(new Layout.MonitorConstraint({ primary: true }));
         this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
         parentActor.add_child(this.actor);
 
         this._userManager = AccountsService.UserManager.get_default()
         let gdmClient = new Gdm.Client();
 
         if (GLib.getenv('GDM_GREETER_TEST') != '1') {
             this._greeter = gdmClient.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));
         }
 
         this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA });
 
         this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_KEY,
                                Lang.bind(this, this._updateBanner));
         this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_TEXT_KEY,
                                Lang.bind(this, this._updateBanner));
         this._settings.connect('changed::' + GdmUtil.DISABLE_USER_LIST_KEY,
                                Lang.bind(this, this._updateDisableUserList));
         this._settings.connect('changed::' + GdmUtil.LOGO_KEY,
                                Lang.bind(this, this._updateLogo));
 
         this._textureCache = St.TextureCache.get_default();
         this._textureCache.connect('texture-file-changed',
                                    Lang.bind(this, this._updateLogoTexture));
 
         this._userSelectionBox = new St.BoxLayout({ style_class: 'login-dialog-user-selection-box',
                                                     x_align: Clutter.ActorAlign.CENTER,
                                                     y_align: Clutter.ActorAlign.CENTER,
                                                     x_expand: true,
                                                     y_expand: true,
                                                     vertical: true,
                                                     visible: false });
+        this.actor.add_child(this._userSelectionBox);
+
+        this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner',
+                                           text: '' });
+        this._userSelectionBox.add(this._bannerLabel);
+        this._updateBanner();
+
         this._userList = new UserList();
         this._userSelectionBox.add(this._userList.actor,
                                    { expand: true,
                                      x_fill: true,
                                      y_fill: true });
 
         this._authPrompt = new AuthPrompt.AuthPrompt(gdmClient, AuthPrompt.AuthPromptMode.UNLOCK_OR_LOG_IN);
         this._authPrompt.connect('prompted', Lang.bind(this, this._onPrompted));
         this._authPrompt.connect('reset', Lang.bind(this, this._onReset));
         this._authPrompt.hide();
-        this._authPrompt.actor.x_align = Clutter.ActorAlign.CENTER;
-        this._authPrompt.actor.y_align = Clutter.ActorAlign.CENTER;
-        this._authPrompt.actor.x_expand = false;
-        this._authPrompt.actor.y_expand = false;
-        table.pack(this._authPrompt.actor, 0, 0);
-        table.set_span(this._authPrompt.actor, 1, 3);
+        this.actor.add_child(this._authPrompt.actor);
 
         // 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.
         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',
                                                 button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
                                                 can_focus: true,
                                                 child: notListedLabel,
                                                 reactive: true,
                                                 x_align: St.Align.START,
                                                 x_fill: true });
 
         this._notListedButton.connect('clicked', Lang.bind(this, this._hideUserListAskForUsernameAndBeginVerification));
 
         this._notListedButton.hide();
 
         this._userSelectionBox.add(this._notListedButton,
                                    { expand: false,
                                      x_align: St.Align.START,
                                      x_fill: true });
 
         this._logoBin = new St.Widget({ style_class: 'login-dialog-logo-bin',
                                         x_align: Clutter.ActorAlign.CENTER,
                                         y_align: Clutter.ActorAlign.END,
                                         x_expand: true,
                                         y_expand: true });
-
-        table.pack(this._userSelectionBox, 0, 0);
-        table.set_span(this._userSelectionBox, 1, 3);
-
-        let outerBox = new St.BoxLayout({ x_align: Clutter.ActorAlign.CENTER,
-                                          y_align: Clutter.ActorAlign.CENTER,
-                                          vertical: true });
-        table.pack(outerBox, 0, 2);
-        table.set_span(outerBox, 1, 1);
-        this._bannerView = new St.ScrollView({ style_class: 'login-dialog-banner-view',
-                                               opacity: 0,
-                                               vscrollbar_policy: Gtk.PolicyType.AUTOMATIC,
-                                               hscrollbar_policy: Gtk.PolicyType.NEVER });
-        outerBox.add_actor(this._bannerView);
-
-        let innerBox = new St.BoxLayout({ vertical: true });
-
-        this._bannerView.add_actor(innerBox);
-        this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner',
-                                           text: '' });
-        this._bannerLabel.clutter_text.line_wrap = true;
-        this._bannerLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
-        innerBox.add_child(this._bannerLabel);
-        this._updateBanner();
-
-        table.pack(this._logoBin, 0, 2);
-        table.set_span(this._logoBin, 1, 1);
+        this.actor.add_child(this._logoBin);
         this._updateLogo();
 
-        // We have overlapping widgets to obtain the kind of centering we want.
-        // We need to make sure the widgets that take input are on top of the
-        // stack.
-        this.actor.set_child_above_sibling(this._userSelectionBox, null);
-        this.actor.set_child_above_sibling(this._authPrompt.actor, null);
+        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);
                                }));
 
 
         this._sessionMenuButton = new SessionMenuButton();
         this._sessionMenuButton.connect('session-activated',
                                   Lang.bind(this, function(list, sessionId) {
                                                 this._greeter.call_select_session_sync (sessionId, null);
                                             }));
         this._sessionMenuButton.actor.opacity = 0;
         this._sessionMenuButton.actor.show();
         this._authPrompt.addActorToDefaultButtonWell(this._sessionMenuButton.actor);
 
         this._disableUserList = undefined;
         this._userListLoaded = false;
 
         // If the user list is enabled, it should take key focus; make sure the
         // screen shield is initialized first to prevent it from stealing the
         // focus later
         Main.layoutManager.connect('startup-complete',
                                    Lang.bind(this, this._updateDisableUserList));
     },
 
     _ensureUserListLoaded: function() {
         if (!this._userManager.is_loaded)
             this._userManagerLoadedId = this._userManager.connect('notify::is-loaded',
                                                                   Lang.bind(this, function() {
@@ -568,101 +548,87 @@ const LoginDialog = new Lang.Class({
             if (this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
                 this._authPrompt.reset();
         }
     },
 
     _updateCancelButton: function() {
         let cancelVisible;
 
         // Hide the cancel button if the user list is disabled and we're asking for
         // a username
         if (this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING && this._disableUserList)
             cancelVisible = false;
         else
             cancelVisible = true;
 
         this._authPrompt.cancelButton.visible = cancelVisible;
     },
 
     _updateBanner: function() {
         let enabled = this._settings.get_boolean(GdmUtil.BANNER_MESSAGE_KEY);
         let text = this._settings.get_string(GdmUtil.BANNER_MESSAGE_TEXT_KEY);
 
         if (enabled && text) {
             this._bannerLabel.set_text(text);
             this._bannerLabel.show();
         } else {
             this._bannerLabel.hide();
         }
     },
 
-    _fadeInBannerView: function() {
-        Tweener.addTween(this._bannerView,
-                         { opacity: 255,
-                           time: _FADE_ANIMATION_TIME,
-                           transition: 'easeOutQuad' });
-    },
-
-    _hideBannerView: function() {
-        Tweener.removeTweens(this._bannerView);
-        this._bannerView.opacity = 0;
-    },
-
     _updateLogoTexture: function(cache, uri) {
         if (this._logoFileUri != uri)
             return;
 
         this._logoBin.destroy_all_children();
         if (this._logoFileUri)
             this._logoBin.add_child(this._textureCache.load_uri_async(this._logoFileUri,
                                                                       -1, _LOGO_ICON_HEIGHT));
     },
 
     _updateLogo: function() {
         let path = this._settings.get_string(GdmUtil.LOGO_KEY);
 
         this._logoFileUri = path ? Gio.file_new_for_path(path).get_uri() : null;
         this._updateLogoTexture(this._textureCache, this._logoFileUri);
     },
 
     _onPrompted: function() {
         this._sessionMenuButton.updateSensitivity(true);
-        this._fadeInBannerView();
 
         if (this._shouldShowSessionMenuButton())
             this._authPrompt.setActorInDefaultButtonWell(this._sessionMenuButton.actor);
         this._showPrompt();
     },
 
     _onReset: function(authPrompt, beginRequest) {
         this._sessionMenuButton.updateSensitivity(true);
-        this._hideBannerView();
 
         this._user = null;
 
         if (beginRequest == AuthPrompt.BeginRequestType.PROVIDE_USERNAME) {
             if (!this._disableUserList)
                 this._showUserList();
             else
                 this._hideUserListAskForUsernameAndBeginVerification();
         } else {
             this._hideUserListAndBeginVerification();
         }
     },
 
     _onDefaultSessionChanged: function(client, sessionId) {
         this._sessionMenuButton.setActiveSession(sessionId);
     },
 
     _shouldShowSessionMenuButton: function() {
         if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFYING &&
             this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFICATION_FAILED)
           return false;
 
         if (this._user && this._user.is_loaded && this._user.is_logged_in())
           return false;
 
         return true;
     },
 
     _showPrompt: function() {
         if (this._authPrompt.actor.visible)
-- 
2.1.0


From 4535550f8780b244f3e79a048c61eef3b2ed8cc8 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Mon, 10 Nov 2014 14:36:07 -0500
Subject: [PATCH 3/5] loginDialog: allocate children manually

The login screen is pretty custom full screen container and the standard
layout managers aren't really a good fit for the kind of layout that's
happening. This will be even more problematic with upcoming changes
to login banners, so we need to switch techniques.

This commit moves login dialog over to using a custom allocate handler
that has specific domain knowledge of the parts of the login screen
and where they go.
---
 js/gdm/loginDialog.js | 94 ++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 85 insertions(+), 9 deletions(-)

diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js
index f35921c..4835199 100644
--- a/js/gdm/loginDialog.js
+++ b/js/gdm/loginDialog.js
@@ -366,192 +366,268 @@ const SessionMenuButton = new Lang.Class({
         ids.sort();
 
         if (ids.length <= 1) {
             this._button.hide();
             return;
         }
 
         for (let i = 0; i < ids.length; i++) {
             let [sessionName, sessionDescription] = Gdm.get_session_name_and_description(ids[i]);
 
             let id = ids[i];
             let item = new PopupMenu.PopupMenuItem(sessionName);
             this._menu.addMenuItem(item);
             this._items[id] = item;
 
             if (!this._activeSessionId)
                 this.setActiveSession(id);
 
             item.connect('activate', Lang.bind(this, function() {
                 this.setActiveSession(id);
             }));
         }
     }
 });
 Signals.addSignalMethods(SessionMenuButton.prototype);
 
 const LoginDialog = new Lang.Class({
     Name: 'LoginDialog',
 
     _init: function(parentActor) {
-        this.actor = new St.Widget({ accessible_role: Atk.Role.WINDOW,
-                                     layout_manager: new Clutter.BinLayout(),
-                                     style_class: 'login-dialog',
-                                     visible: false });
+        this.actor = new Shell.GenericContainer({ style_class: 'login-dialog',
+                                                  visible: false });
+        this.actor.get_accessible().set_role(Atk.Role.WINDOW);
 
         this.actor.add_constraint(new Layout.MonitorConstraint({ primary: true }));
+        this.actor.connect('allocate', Lang.bind(this, this._onAllocate));
         this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
         parentActor.add_child(this.actor);
 
         this._userManager = AccountsService.UserManager.get_default()
         let gdmClient = new Gdm.Client();
 
         if (GLib.getenv('GDM_GREETER_TEST') != '1') {
             this._greeter = gdmClient.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));
         }
 
         this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA });
 
         this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_KEY,
                                Lang.bind(this, this._updateBanner));
         this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_TEXT_KEY,
                                Lang.bind(this, this._updateBanner));
         this._settings.connect('changed::' + GdmUtil.DISABLE_USER_LIST_KEY,
                                Lang.bind(this, this._updateDisableUserList));
         this._settings.connect('changed::' + GdmUtil.LOGO_KEY,
                                Lang.bind(this, this._updateLogo));
 
         this._textureCache = St.TextureCache.get_default();
         this._textureCache.connect('texture-file-changed',
                                    Lang.bind(this, this._updateLogoTexture));
 
         this._userSelectionBox = new St.BoxLayout({ style_class: 'login-dialog-user-selection-box',
                                                     x_align: Clutter.ActorAlign.CENTER,
                                                     y_align: Clutter.ActorAlign.CENTER,
-                                                    x_expand: true,
-                                                    y_expand: true,
                                                     vertical: true,
                                                     visible: false });
         this.actor.add_child(this._userSelectionBox);
 
         this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner',
                                            text: '' });
         this._userSelectionBox.add(this._bannerLabel);
         this._updateBanner();
 
         this._userList = new UserList();
         this._userSelectionBox.add(this._userList.actor,
                                    { expand: true,
                                      x_fill: true,
                                      y_fill: true });
 
         this._authPrompt = new AuthPrompt.AuthPrompt(gdmClient, AuthPrompt.AuthPromptMode.UNLOCK_OR_LOG_IN);
         this._authPrompt.connect('prompted', Lang.bind(this, this._onPrompted));
         this._authPrompt.connect('reset', Lang.bind(this, this._onReset));
         this._authPrompt.hide();
         this.actor.add_child(this._authPrompt.actor);
 
         // 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.
         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',
                                                 button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
                                                 can_focus: true,
                                                 child: notListedLabel,
                                                 reactive: true,
                                                 x_align: St.Align.START,
                                                 x_fill: true });
 
         this._notListedButton.connect('clicked', Lang.bind(this, this._hideUserListAskForUsernameAndBeginVerification));
 
         this._notListedButton.hide();
 
         this._userSelectionBox.add(this._notListedButton,
                                    { expand: false,
                                      x_align: St.Align.START,
                                      x_fill: true });
 
         this._logoBin = new St.Widget({ style_class: 'login-dialog-logo-bin',
                                         x_align: Clutter.ActorAlign.CENTER,
-                                        y_align: Clutter.ActorAlign.END,
-                                        x_expand: true,
-                                        y_expand: true });
+                                        y_align: Clutter.ActorAlign.END });
         this.actor.add_child(this._logoBin);
         this._updateLogo();
 
         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);
                                }));
 
 
         this._sessionMenuButton = new SessionMenuButton();
         this._sessionMenuButton.connect('session-activated',
                                   Lang.bind(this, function(list, sessionId) {
                                                 this._greeter.call_select_session_sync (sessionId, null);
                                             }));
         this._sessionMenuButton.actor.opacity = 0;
         this._sessionMenuButton.actor.show();
         this._authPrompt.addActorToDefaultButtonWell(this._sessionMenuButton.actor);
 
         this._disableUserList = undefined;
         this._userListLoaded = false;
 
         // If the user list is enabled, it should take key focus; make sure the
         // screen shield is initialized first to prevent it from stealing the
         // focus later
         Main.layoutManager.connect('startup-complete',
                                    Lang.bind(this, this._updateDisableUserList));
     },
 
+    _getLogoBinAllocation: function (dialogBox) {
+        let actorBox = new Clutter.ActorBox();
+
+        let [minWidth, minHeight, natWidth, natHeight] = this._logoBin.get_preferred_size();
+        let centerX = dialogBox.x1 + (dialogBox.x2 - dialogBox.x1) / 2;
+
+        actorBox.x1 = centerX - natWidth / 2;
+        actorBox.y1 = dialogBox.y2 - natHeight;
+        actorBox.x2 = actorBox.x1 + natWidth;
+        actorBox.y2 = actorBox.y1 + natHeight;
+
+        return actorBox;
+    },
+
+    _getCenterActorAllocation: function (dialogBox, actor) {
+        let actorBox = new Clutter.ActorBox();
+
+        let [minWidth, minHeight, natWidth, natHeight] = actor.get_preferred_size();
+        let centerX = dialogBox.x1 + (dialogBox.x2 - dialogBox.x1) / 2;
+        let centerY = dialogBox.y1 + (dialogBox.y2 - dialogBox.y1) / 2;
+
+        actorBox.x1 = centerX - natWidth / 2;
+        actorBox.y1 = centerY - natHeight / 2;
+        actorBox.x2 = actorBox.x1 + natWidth;
+        actorBox.y2 = actorBox.y1 + natHeight;
+
+        return actorBox;
+    },
+
+    _onAllocate: function (actor, dialogBox, flags) {
+        let dialogHeight = dialogBox.y2 - dialogBox.y1;
+
+        // First find out what space the children require
+        let authPromptAllocation = null;
+        if (this._authPrompt.actor.visible)
+            authPromptAllocation = this._getCenterActorAllocation(dialogBox, this._authPrompt.actor);
+
+        let userSelectionAllocation = null;
+        let userSelectionHeight = 0;
+        if (this._userSelectionBox.visible) {
+            userSelectionAllocation = this._getCenterActorAllocation(dialogBox, this._userSelectionBox);
+            userSelectionHeight = userSelectionAllocation.y2 - userSelectionAllocation.y1;
+        }
+
+        let logoAllocation = null;
+        let logoHeight = 0;
+        if (this._logoBin.visible) {
+            logoAllocation = this._getLogoBinAllocation(dialogBox);
+            logoHeight = logoAllocation.y2 - logoAllocation.y1;
+        }
+
+        // Then figure out what extra space we can hand out
+        let leftOverYSpace = dialogHeight - userSelectionHeight - logoHeight;
+        if (leftOverYSpace > 0) {
+            if (userSelectionAllocation) {
+                let topExpansion = leftOverYSpace / 2;
+
+                // Don't ever expand more than we have space for
+                if (userSelectionAllocation.y1 - topExpansion < 0)
+                    topExpansion = userSelectionAllocation.y1;
+
+                // Always expand the bottom the same as the top since it's centered
+                let bottomExpansion = topExpansion;
+
+                userSelectionAllocation.y1 -= topExpansion;
+                userSelectionAllocation.y2 += bottomExpansion;
+            }
+        }
+
+        // Finally hand out the allocations
+        if (authPromptAllocation)
+            this._authPrompt.actor.allocate(authPromptAllocation, flags);
+
+        if (userSelectionAllocation)
+            this._userSelectionBox.allocate(userSelectionAllocation, flags);
+
+        if (logoAllocation)
+            this._logoBin.allocate(logoAllocation, flags);
+    },
+
     _ensureUserListLoaded: function() {
         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
             GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, this._loadUserList));
     },
 
     _updateDisableUserList: function() {
         let disableUserList = this._settings.get_boolean(GdmUtil.DISABLE_USER_LIST_KEY);
 
         if (disableUserList != this._disableUserList) {
             this._disableUserList = disableUserList;
 
             if (this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
                 this._authPrompt.reset();
         }
     },
 
     _updateCancelButton: function() {
         let cancelVisible;
 
         // Hide the cancel button if the user list is disabled and we're asking for
         // a username
-- 
2.1.0


From f3b8445905e1b34140b5e903a81a27650d68230b Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 11 Nov 2014 09:11:01 -0500
Subject: [PATCH 4/5] loginDialog: display banner message when
 disable-user-list=true

The login screen supports showing a banner message which admins
can use to mention login rules or disclaimers.

This message only shows up currently if the user list is enabled.
Most people who want to show a banner message also want to disable
the user list.

This commit moves the banner message to display when the user is
prompted for login credentials instead of when showing the user
list. It also adds a scrollbar if the message is too long.
---
 data/theme/gnome-shell.css |   8 ++--
 js/gdm/loginDialog.js      | 105 +++++++++++++++++++++++++++++++++++++++------
 2 files changed, 95 insertions(+), 18 deletions(-)

diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index aa82632..90eb64f 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -2187,67 +2187,67 @@ StScrollBar StButton#vhandle:active {
 .candidate-box:hover {
     border-radius: 4px;
     background-color: rgba(255,255,255,0.1);
 }
 .candidate-page-button-box {
     height: 2em;
     width: 80px;
 }
 
 .vertical .candidate-page-button-box {
     padding-top: 0.5em;
 }
 
 .horizontal .candidate-page-button-box {
     padding-left: 0.5em;
 }
 
 .candidate-page-button-previous {
     border-radius: 4px 0px 0px 4px;
 }
 
 .candidate-page-button-next {
     border-radius: 0px 4px 4px 0px;
 }
 
 .candidate-page-button-icon {
     icon-size: 1em;
 }
 
 /* Login Dialog */
+.login-dialog-banner-view {
+    padding-top: 24px;
+    max-width: 23em;
+}
 
 .login-dialog-banner {
-    font-size: 10pt;
-    font-weight: bold;
-    text-align: center;
     color: #666666;
-    padding-bottom: 1em;
 }
 
 .login-dialog-title {
     font-size: 14pt;
     font-weight: bold;
     color: #666666;
     padding-bottom: 2em;
 }
 
 .login-dialog {
     /* Reset border and background */
     border: none;
     background-color: transparent;
 }
 
 .login-dialog-button-box {
     spacing: 5px;
 }
 
 .login-dialog-user-list-view {
     -st-vfade-offset: 1em;
 }
 
 .login-dialog-user-list {
     spacing: 12px;
     padding: .2em;
     width: 23em;
 }
 
 .login-dialog-user-list-item {
diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js
index 4835199..348798c 100644
--- a/js/gdm/loginDialog.js
+++ b/js/gdm/loginDialog.js
@@ -1,60 +1,61 @@
 // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 /*
  * 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 Atk = imports.gi.Atk;
 const Clutter = imports.gi.Clutter;
 const Gdm = imports.gi.Gdm;
 const Gio = imports.gi.Gio;
 const GLib = imports.gi.GLib;
 const Gtk = imports.gi.Gtk;
 const Lang = imports.lang;
 const Mainloop = imports.mainloop;
 const Meta = imports.gi.Meta;
+const Pango = imports.gi.Pango;
 const Shell = imports.gi.Shell;
 const Signals = imports.signals;
 const St = imports.gi.St;
 
 const AuthPrompt = imports.gdm.authPrompt;
 const Batch = imports.gdm.batch;
 const BoxPointer = imports.ui.boxpointer;
 const CtrlAltTab = imports.ui.ctrlAltTab;
 const GdmUtil = imports.gdm.util;
 const Layout = imports.ui.layout;
 const Main = imports.ui.main;
 const PopupMenu = imports.ui.popupMenu;
 const Realmd = imports.gdm.realmd;
 const Tweener = imports.ui.tweener;
 const UserMenu = imports.ui.userMenu;
 const UserWidget = imports.ui.userWidget;
 
 const _FADE_ANIMATION_TIME = 0.25;
 const _SCROLL_ANIMATION_TIME = 0.5;
 const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
 const _LOGO_ICON_HEIGHT = 48;
 
 let _loginDialog = null;
 
 const UserListItem = new Lang.Class({
     Name: 'UserListItem',
 
     _init: function(user) {
         this.user = user;
         this._userChangedId = this.user.connect('changed',
@@ -412,272 +413,346 @@ const LoginDialog = new Lang.Class({
                                   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));
         }
 
         this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA });
 
         this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_KEY,
                                Lang.bind(this, this._updateBanner));
         this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_TEXT_KEY,
                                Lang.bind(this, this._updateBanner));
         this._settings.connect('changed::' + GdmUtil.DISABLE_USER_LIST_KEY,
                                Lang.bind(this, this._updateDisableUserList));
         this._settings.connect('changed::' + GdmUtil.LOGO_KEY,
                                Lang.bind(this, this._updateLogo));
 
         this._textureCache = St.TextureCache.get_default();
         this._textureCache.connect('texture-file-changed',
                                    Lang.bind(this, this._updateLogoTexture));
 
         this._userSelectionBox = new St.BoxLayout({ style_class: 'login-dialog-user-selection-box',
                                                     x_align: Clutter.ActorAlign.CENTER,
                                                     y_align: Clutter.ActorAlign.CENTER,
                                                     vertical: true,
                                                     visible: false });
         this.actor.add_child(this._userSelectionBox);
 
-        this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner',
-                                           text: '' });
-        this._userSelectionBox.add(this._bannerLabel);
-        this._updateBanner();
-
         this._userList = new UserList();
         this._userSelectionBox.add(this._userList.actor,
                                    { expand: true,
                                      x_fill: true,
                                      y_fill: true });
 
         this._authPrompt = new AuthPrompt.AuthPrompt(gdmClient, AuthPrompt.AuthPromptMode.UNLOCK_OR_LOG_IN);
         this._authPrompt.connect('prompted', Lang.bind(this, this._onPrompted));
         this._authPrompt.connect('reset', Lang.bind(this, this._onReset));
         this._authPrompt.hide();
         this.actor.add_child(this._authPrompt.actor);
 
         // 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.
         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',
                                                 button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
                                                 can_focus: true,
                                                 child: notListedLabel,
                                                 reactive: true,
                                                 x_align: St.Align.START,
                                                 x_fill: true });
 
         this._notListedButton.connect('clicked', Lang.bind(this, this._hideUserListAskForUsernameAndBeginVerification));
 
         this._notListedButton.hide();
 
         this._userSelectionBox.add(this._notListedButton,
                                    { expand: false,
                                      x_align: St.Align.START,
                                      x_fill: true });
 
+        this._bannerView = new St.ScrollView({ style_class: 'login-dialog-banner-view',
+                                               opacity: 0,
+                                               vscrollbar_policy: Gtk.PolicyType.AUTOMATIC,
+                                               hscrollbar_policy: Gtk.PolicyType.NEVER });
+        this.actor.add_child(this._bannerView);
+
+        let bannerBox = new St.BoxLayout({ vertical: true });
+
+        this._bannerView.add_actor(bannerBox);
+        this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner',
+                                           text: '' });
+        this._bannerLabel.clutter_text.line_wrap = true;
+        this._bannerLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
+        bannerBox.add_child(this._bannerLabel);
+        this._updateBanner();
+
         this._logoBin = new St.Widget({ style_class: 'login-dialog-logo-bin',
                                         x_align: Clutter.ActorAlign.CENTER,
                                         y_align: Clutter.ActorAlign.END });
         this.actor.add_child(this._logoBin);
         this._updateLogo();
 
         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);
                                }));
 
 
         this._sessionMenuButton = new SessionMenuButton();
         this._sessionMenuButton.connect('session-activated',
                                   Lang.bind(this, function(list, sessionId) {
                                                 this._greeter.call_select_session_sync (sessionId, null);
                                             }));
         this._sessionMenuButton.actor.opacity = 0;
         this._sessionMenuButton.actor.show();
         this._authPrompt.addActorToDefaultButtonWell(this._sessionMenuButton.actor);
 
         this._disableUserList = undefined;
         this._userListLoaded = false;
 
         // If the user list is enabled, it should take key focus; make sure the
         // screen shield is initialized first to prevent it from stealing the
         // focus later
         Main.layoutManager.connect('startup-complete',
                                    Lang.bind(this, this._updateDisableUserList));
     },
 
+    _getBannerAllocation: function (dialogBox) {
+        let actorBox = new Clutter.ActorBox();
+
+        let [minWidth, minHeight, natWidth, natHeight] = this._bannerView.get_preferred_size();
+        let centerX = dialogBox.x1 + (dialogBox.x2 - dialogBox.x1) / 2;
+
+        actorBox.x1 = centerX - natWidth / 2;
+        actorBox.y1 = dialogBox.y1 + Main.layoutManager.panelBox.height;
+        actorBox.x2 = actorBox.x1 + natWidth;
+        actorBox.y2 = actorBox.y1 + natHeight;
+
+        return actorBox;
+    },
+
     _getLogoBinAllocation: function (dialogBox) {
         let actorBox = new Clutter.ActorBox();
 
         let [minWidth, minHeight, natWidth, natHeight] = this._logoBin.get_preferred_size();
         let centerX = dialogBox.x1 + (dialogBox.x2 - dialogBox.x1) / 2;
 
         actorBox.x1 = centerX - natWidth / 2;
         actorBox.y1 = dialogBox.y2 - natHeight;
         actorBox.x2 = actorBox.x1 + natWidth;
         actorBox.y2 = actorBox.y1 + natHeight;
 
         return actorBox;
     },
 
     _getCenterActorAllocation: function (dialogBox, actor) {
         let actorBox = new Clutter.ActorBox();
 
         let [minWidth, minHeight, natWidth, natHeight] = actor.get_preferred_size();
         let centerX = dialogBox.x1 + (dialogBox.x2 - dialogBox.x1) / 2;
         let centerY = dialogBox.y1 + (dialogBox.y2 - dialogBox.y1) / 2;
 
         actorBox.x1 = centerX - natWidth / 2;
         actorBox.y1 = centerY - natHeight / 2;
         actorBox.x2 = actorBox.x1 + natWidth;
         actorBox.y2 = actorBox.y1 + natHeight;
 
         return actorBox;
     },
 
     _onAllocate: function (actor, dialogBox, flags) {
         let dialogHeight = dialogBox.y2 - dialogBox.y1;
 
         // First find out what space the children require
+        let bannerAllocation = null;
+        let bannerHeight = 0;
+        let bannerWidth = 0;
+        if (this._bannerView.visible) {
+            bannerAllocation = this._getBannerAllocation(dialogBox, this._bannerView);
+            bannerHeight = bannerAllocation.y2 - bannerAllocation.y1;
+            bannerWidth = bannerAllocation.x2 - bannerAllocation.x1;
+        }
+
         let authPromptAllocation = null;
-        if (this._authPrompt.actor.visible)
+        let authPromptHeight = 0;
+        if (this._authPrompt.actor.visible) {
             authPromptAllocation = this._getCenterActorAllocation(dialogBox, this._authPrompt.actor);
+            authPromptHeight = authPromptAllocation.y2 - authPromptAllocation.y1;
+        }
 
         let userSelectionAllocation = null;
         let userSelectionHeight = 0;
         if (this._userSelectionBox.visible) {
             userSelectionAllocation = this._getCenterActorAllocation(dialogBox, this._userSelectionBox);
             userSelectionHeight = userSelectionAllocation.y2 - userSelectionAllocation.y1;
         }
 
         let logoAllocation = null;
         let logoHeight = 0;
         if (this._logoBin.visible) {
             logoAllocation = this._getLogoBinAllocation(dialogBox);
             logoHeight = logoAllocation.y2 - logoAllocation.y1;
         }
 
         // Then figure out what extra space we can hand out
-        let leftOverYSpace = dialogHeight - userSelectionHeight - logoHeight;
-        if (leftOverYSpace > 0) {
-            if (userSelectionAllocation) {
-                let topExpansion = leftOverYSpace / 2;
+        if (bannerAllocation) {
+            let leftOverYSpace = dialogHeight - bannerHeight - authPromptHeight - logoHeight;
+
+            if (leftOverYSpace > 0) {
+                 // First figure out how much left over space is up top
+                 let leftOverTopSpace = leftOverYSpace / 2;
 
-                // Don't ever expand more than we have space for
-                if (userSelectionAllocation.y1 - topExpansion < 0)
-                    topExpansion = userSelectionAllocation.y1;
+                 // Then, shift the banner into the middle of that extra space
+                 let yShift = leftOverTopSpace / 2;
+
+                 bannerAllocation.y1 += yShift;
+                 bannerAllocation.y2 += yShift;
+            } else {
+                 // recompute banner height to be constrained if there's no room for its
+                 // requested height
+
+                 // First figure out how much space there is without the banner
+                 leftOverYSpace += bannerHeight;
+
+                 // Then figure out how much of that space is up top
+                 let availableTopSpace = leftOverYSpace / 2;
+
+                 // Then give all of that space to the banner
+                 bannerAllocation.y2 = bannerAllocation.y1 + availableTopSpace;
+            }
+        } else if (userSelectionAllocation) {
+            // Grow the user list to fill the space
+            let leftOverYSpace = dialogHeight - userSelectionHeight - logoHeight;
 
-                // Always expand the bottom the same as the top since it's centered
+            if (leftOverYSpace > 0) {
+                let topExpansion = leftOverYSpace / 2;
                 let bottomExpansion = topExpansion;
 
                 userSelectionAllocation.y1 -= topExpansion;
                 userSelectionAllocation.y2 += bottomExpansion;
             }
         }
 
         // Finally hand out the allocations
+        if (bannerAllocation) {
+            this._bannerView.allocate(bannerAllocation, flags);
+        }
+
         if (authPromptAllocation)
             this._authPrompt.actor.allocate(authPromptAllocation, flags);
 
         if (userSelectionAllocation)
             this._userSelectionBox.allocate(userSelectionAllocation, flags);
 
         if (logoAllocation)
             this._logoBin.allocate(logoAllocation, flags);
     },
 
     _ensureUserListLoaded: function() {
         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
             GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, this._loadUserList));
     },
 
     _updateDisableUserList: function() {
         let disableUserList = this._settings.get_boolean(GdmUtil.DISABLE_USER_LIST_KEY);
 
         if (disableUserList != this._disableUserList) {
             this._disableUserList = disableUserList;
 
             if (this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
                 this._authPrompt.reset();
         }
     },
 
     _updateCancelButton: function() {
         let cancelVisible;
 
         // Hide the cancel button if the user list is disabled and we're asking for
         // a username
         if (this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING && this._disableUserList)
             cancelVisible = false;
         else
             cancelVisible = true;
 
         this._authPrompt.cancelButton.visible = cancelVisible;
     },
 
     _updateBanner: function() {
         let enabled = this._settings.get_boolean(GdmUtil.BANNER_MESSAGE_KEY);
         let text = this._settings.get_string(GdmUtil.BANNER_MESSAGE_TEXT_KEY);
 
         if (enabled && text) {
             this._bannerLabel.set_text(text);
             this._bannerLabel.show();
         } else {
             this._bannerLabel.hide();
         }
     },
 
+    _fadeInBannerView: function() {
+        Tweener.addTween(this._bannerView,
+                         { opacity: 255,
+                           time: _FADE_ANIMATION_TIME,
+                           transition: 'easeOutQuad' });
+    },
+
+    _hideBannerView: function() {
+        Tweener.removeTweens(this._bannerView);
+        this._bannerView.opacity = 0;
+    },
+
     _updateLogoTexture: function(cache, uri) {
         if (this._logoFileUri != uri)
             return;
 
         this._logoBin.destroy_all_children();
         if (this._logoFileUri)
             this._logoBin.add_child(this._textureCache.load_uri_async(this._logoFileUri,
                                                                       -1, _LOGO_ICON_HEIGHT));
     },
 
     _updateLogo: function() {
         let path = this._settings.get_string(GdmUtil.LOGO_KEY);
 
         this._logoFileUri = path ? Gio.file_new_for_path(path).get_uri() : null;
         this._updateLogoTexture(this._textureCache, this._logoFileUri);
     },
 
     _onPrompted: function() {
         this._sessionMenuButton.updateSensitivity(true);
 
         if (this._shouldShowSessionMenuButton())
             this._authPrompt.setActorInDefaultButtonWell(this._sessionMenuButton.actor);
         this._showPrompt();
     },
 
     _onReset: function(authPrompt, beginRequest) {
         this._sessionMenuButton.updateSensitivity(true);
 
         this._user = null;
 
@@ -688,60 +763,61 @@ const LoginDialog = new Lang.Class({
                 this._hideUserListAskForUsernameAndBeginVerification();
         } else {
             this._hideUserListAndBeginVerification();
         }
     },
 
     _onDefaultSessionChanged: function(client, sessionId) {
         this._sessionMenuButton.setActiveSession(sessionId);
     },
 
     _shouldShowSessionMenuButton: function() {
         if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFYING &&
             this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFICATION_FAILED)
           return false;
 
         if (this._user && this._user.is_loaded && this._user.is_logged_in())
           return false;
 
         return true;
     },
 
     _showPrompt: function() {
         if (this._authPrompt.actor.visible)
             return;
         this._authPrompt.actor.opacity = 0;
         this._authPrompt.actor.show();
         Tweener.addTween(this._authPrompt.actor,
                          { opacity: 255,
                            time: _FADE_ANIMATION_TIME,
                            transition: 'easeOutQuad' });
+        this._fadeInBannerView();
     },
 
     _showRealmLoginHint: function(realmManager, hint) {
         if (!hint)
             return;
 
         hint = hint.replace(/%U/g, 'user');
         hint = hint.replace(/%D/g, 'DOMAIN');
         hint = hint.replace(/%[^UD]/g, '');
 
         // Translators: this message is shown below the username entry field
         // to clue the user in on how to login to the local network realm
         this._authPrompt.setMessage(_("(e.g., user or %s)").format(hint), GdmUtil.MessageType.HINT);
     },
 
     _askForUsernameAndBeginVerification: function() {
         this._authPrompt.setPasswordChar('');
         this._authPrompt.setQuestion(_("Username: "));
 
         let realmManager = new Realmd.Manager();
         let realmSignalId = realmManager.connect('login-format-changed',
                                                  Lang.bind(this, this._showRealmLoginHint));
         this._showRealmLoginHint(realmManager.loginFormat);
 
         let nextSignalId = this._authPrompt.connect('next',
                                                     Lang.bind(this, function() {
                                                         this._authPrompt.disconnect(nextSignalId);
                                                         this._authPrompt.updateSensitivity(false);
                                                         let answer = this._authPrompt.getAnswer();
                                                         this._user = this._userManager.get_user(answer);
@@ -909,60 +985,61 @@ const LoginDialog = new Lang.Class({
                                 }
 
                                 return false;
                              }));
     },
 
     _setUserListExpanded: function(expanded) {
         this._userList.updateStyle(expanded);
         this._userSelectionBox.visible = expanded;
     },
 
     _hideUserList: function() {
         this._setUserListExpanded(false);
         if (this._userSelectionBox.visible)
             GdmUtil.cloneAndFadeOutActor(this._userSelectionBox);
     },
 
     _hideUserListAskForUsernameAndBeginVerification: function() {
         this._hideUserList();
         this._askForUsernameAndBeginVerification();
     },
 
     _hideUserListAndBeginVerification: function() {
         this._hideUserList();
         this._authPrompt.begin();
     },
 
     _showUserList: function() {
         this._ensureUserListLoaded();
         this._authPrompt.hide();
+        this._hideBannerView();
         this._sessionMenuButton.close();
         this._setUserListExpanded(true);
         this._notListedButton.show();
         this._userList.actor.grab_key_focus();
     },
 
     _beginVerificationForItem: function(item) {
         this._authPrompt.setUser(item.user);
 
         let userName = item.user.get_user_name();
         let hold = new Batch.Hold();
 
         this._authPrompt.begin({ userName: userName,
                                  hold: hold });
         return hold;
     },
 
     _onUserListActivated: function(activatedItem) {
         let tasks = [function() {
                          return GdmUtil.cloneAndFadeOutActor(this._userSelectionBox);
                      },
                      function() {
                          this._setUserListExpanded(false);
                      }];
 
         this._user = activatedItem.user;
 
         this._updateCancelButton();
 
         let batch = new Batch.ConcurrentBatch(this, [new Batch.ConsecutiveBatch(this, tasks),
-- 
2.1.0


From 9bdce53329817e3453baa85cbc4d899511630154 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 11 Nov 2014 09:11:01 -0500
Subject: [PATCH 5/5] loginDialog: use two column view if banner message long

Frequently banner messages are longer than can reasonable
fit in a one column view, which leads to a smooshed layout.

This commit changes the layout to a two column view, with the
banner on the left and the prompt on the right, if the banner
message is long enough that it can't fit well above the prompt.
If there isn't enough space for two columns then we keep the
one column layout but add scrollbars.
---
 js/gdm/loginDialog.js | 67 ++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 55 insertions(+), 12 deletions(-)

diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js
index 348798c..9ee259f 100644
--- a/js/gdm/loginDialog.js
+++ b/js/gdm/loginDialog.js
@@ -550,118 +550,161 @@ const LoginDialog = new Lang.Class({
     _getLogoBinAllocation: function (dialogBox) {
         let actorBox = new Clutter.ActorBox();
 
         let [minWidth, minHeight, natWidth, natHeight] = this._logoBin.get_preferred_size();
         let centerX = dialogBox.x1 + (dialogBox.x2 - dialogBox.x1) / 2;
 
         actorBox.x1 = centerX - natWidth / 2;
         actorBox.y1 = dialogBox.y2 - natHeight;
         actorBox.x2 = actorBox.x1 + natWidth;
         actorBox.y2 = actorBox.y1 + natHeight;
 
         return actorBox;
     },
 
     _getCenterActorAllocation: function (dialogBox, actor) {
         let actorBox = new Clutter.ActorBox();
 
         let [minWidth, minHeight, natWidth, natHeight] = actor.get_preferred_size();
         let centerX = dialogBox.x1 + (dialogBox.x2 - dialogBox.x1) / 2;
         let centerY = dialogBox.y1 + (dialogBox.y2 - dialogBox.y1) / 2;
 
         actorBox.x1 = centerX - natWidth / 2;
         actorBox.y1 = centerY - natHeight / 2;
         actorBox.x2 = actorBox.x1 + natWidth;
         actorBox.y2 = actorBox.y1 + natHeight;
 
         return actorBox;
     },
 
     _onAllocate: function (actor, dialogBox, flags) {
+        let dialogWidth = dialogBox.x2 - dialogBox.x1;
         let dialogHeight = dialogBox.y2 - dialogBox.y1;
 
         // First find out what space the children require
         let bannerAllocation = null;
         let bannerHeight = 0;
         let bannerWidth = 0;
         if (this._bannerView.visible) {
             bannerAllocation = this._getBannerAllocation(dialogBox, this._bannerView);
             bannerHeight = bannerAllocation.y2 - bannerAllocation.y1;
             bannerWidth = bannerAllocation.x2 - bannerAllocation.x1;
         }
 
         let authPromptAllocation = null;
         let authPromptHeight = 0;
+        let authPromptWidth = 0;
         if (this._authPrompt.actor.visible) {
             authPromptAllocation = this._getCenterActorAllocation(dialogBox, this._authPrompt.actor);
             authPromptHeight = authPromptAllocation.y2 - authPromptAllocation.y1;
+            authPromptWidth = authPromptAllocation.x2 - authPromptAllocation.x1;
         }
 
         let userSelectionAllocation = null;
         let userSelectionHeight = 0;
         if (this._userSelectionBox.visible) {
             userSelectionAllocation = this._getCenterActorAllocation(dialogBox, this._userSelectionBox);
             userSelectionHeight = userSelectionAllocation.y2 - userSelectionAllocation.y1;
         }
 
         let logoAllocation = null;
         let logoHeight = 0;
         if (this._logoBin.visible) {
             logoAllocation = this._getLogoBinAllocation(dialogBox);
             logoHeight = logoAllocation.y2 - logoAllocation.y1;
         }
 
-        // Then figure out what extra space we can hand out
+        // Then figure out if we're overly constrained and need to
+        // try a different layout, or if we have what extra space we
+        // can hand out
         if (bannerAllocation) {
             let leftOverYSpace = dialogHeight - bannerHeight - authPromptHeight - logoHeight;
 
             if (leftOverYSpace > 0) {
                  // First figure out how much left over space is up top
                  let leftOverTopSpace = leftOverYSpace / 2;
 
                  // Then, shift the banner into the middle of that extra space
                  let yShift = leftOverTopSpace / 2;
 
                  bannerAllocation.y1 += yShift;
                  bannerAllocation.y2 += yShift;
             } else {
-                 // recompute banner height to be constrained if there's no room for its
-                 // requested height
-
-                 // First figure out how much space there is without the banner
-                 leftOverYSpace += bannerHeight;
-
-                 // Then figure out how much of that space is up top
-                 let availableTopSpace = leftOverYSpace / 2;
-
-                 // Then give all of that space to the banner
-                 bannerAllocation.y2 = bannerAllocation.y1 + availableTopSpace;
+                 // Then figure out how much space there would be if we switched to a
+                 // wide layout with banner on one side and authprompt on the other.
+                 let leftOverXSpace = dialogWidth - authPromptWidth;
+
+                 // In a wide view, half of the available space goes to the banner,
+                 // and the other half goes to the margins.
+                 let wideBannerWidth = leftOverXSpace / 2;
+                 let wideSpacing  = leftOverXSpace - wideBannerWidth;
+
+                 // If we do go with a wide layout, we need there to be at least enough
+                 // space for the banner and the auth prompt to be the same width,
+                 // so it doesn't look unbalanced.
+                 if (authPromptWidth > 0 && wideBannerWidth > authPromptWidth) {
+                     let centerX = dialogBox.x1 + dialogWidth / 2;
+                     let centerY = dialogBox.y1 + dialogHeight / 2;
+
+                     // A small portion of the spacing goes down the center of the
+                     // screen to help delimit the two columns of the wide view
+                     let centerGap = wideSpacing / 8;
+
+                     // place the banner along the left edge of the center margin
+                     bannerAllocation.x2 = centerX - centerGap / 2;
+                     bannerAllocation.x1 = bannerAllocation.x2 - wideBannerWidth;
+
+                     // figure out how tall it would like to be and try to accomodate
+                     // but don't let it get too close to the logo
+                     let [wideMinHeight, wideBannerHeight] = this._bannerView.get_preferred_height(wideBannerWidth);
+
+                     let maxWideHeight = dialogHeight - 3 * logoHeight;
+                     wideBannerHeight = Math.min(maxWideHeight, wideBannerHeight);
+                     bannerAllocation.y1 = centerY - wideBannerHeight / 2;
+                     bannerAllocation.y2 = bannerAllocation.y1 + wideBannerHeight;
+
+                     // place the auth prompt along the right edge of the center margin
+                     authPromptAllocation.x1 = centerX + centerGap / 2;
+                     authPromptAllocation.x2 = authPromptAllocation.x1 + authPromptWidth;
+                 } else {
+                     // If we aren't going to do a wide view, then we need to limit
+                     // the height of the banner so it will present scrollbars
+
+                     // First figure out how much space there is without the banner
+                     leftOverYSpace += bannerHeight;
+
+                     // Then figure out how much of that space is up top
+                     let availableTopSpace = leftOverYSpace / 2;
+
+                     // Then give all of that space to the banner
+                     bannerAllocation.y2 = bannerAllocation.y1 + availableTopSpace;
+                 }
             }
         } else if (userSelectionAllocation) {
             // Grow the user list to fill the space
             let leftOverYSpace = dialogHeight - userSelectionHeight - logoHeight;
 
             if (leftOverYSpace > 0) {
                 let topExpansion = leftOverYSpace / 2;
                 let bottomExpansion = topExpansion;
 
                 userSelectionAllocation.y1 -= topExpansion;
                 userSelectionAllocation.y2 += bottomExpansion;
             }
         }
 
         // Finally hand out the allocations
         if (bannerAllocation) {
             this._bannerView.allocate(bannerAllocation, flags);
         }
 
         if (authPromptAllocation)
             this._authPrompt.actor.allocate(authPromptAllocation, flags);
 
         if (userSelectionAllocation)
             this._userSelectionBox.allocate(userSelectionAllocation, flags);
 
         if (logoAllocation)
             this._logoBin.allocate(logoAllocation, flags);
     },
 
     _ensureUserListLoaded: function() {
-- 
2.1.0