From 067ae5de5b42169d0105ce1deb1147f640308d27 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 10 Nov 2014 14:36:07 -0500 Subject: [PATCH 01/19] 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. https://bugzilla.gnome.org/show_bug.cgi?id=703972 --- 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 7fbeb3e..ced6fc2 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js @@ -368,12 +368,12 @@ 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); @@ -409,8 +409,6 @@ const LoginDialog = new Lang.Class({ 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); @@ -456,9 +454,7 @@ const LoginDialog = new Lang.Class({ 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(); @@ -489,6 +485,86 @@ const LoginDialog = new Lang.Class({ 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', -- 2.5.0 From b9975d16c2d253bf5636d6ad95e0c22d2b93d05a Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 11 Nov 2014 09:11:01 -0500 Subject: [PATCH 02/19] 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. https://bugzilla.gnome.org/show_bug.cgi?id=703972 --- 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 04994fa..2ec51b2 100644 --- a/data/theme/gnome-shell.css +++ b/data/theme/gnome-shell.css @@ -2392,6 +2392,10 @@ StScrollBar StButton#vhandle:active { } /* Login Dialog */ +.login-dialog-banner-view { + padding-top: 24px; + max-width: 23em; +} .framed-user-icon { border: 2px solid #8b8b8b; @@ -2404,11 +2408,7 @@ StScrollBar StButton#vhandle:active { } .login-dialog-banner { - font-size: 10pt; - font-weight: bold; - text-align: center; color: #666666; - padding-bottom: 1em; } .login-dialog { diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js index ced6fc2..41aa89c 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js @@ -27,6 +27,7 @@ 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; @@ -413,11 +414,6 @@ const LoginDialog = new Lang.Class({ 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, @@ -452,6 +448,22 @@ const LoginDialog = new Lang.Class({ 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 }); @@ -485,6 +497,20 @@ const LoginDialog = new Lang.Class({ 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(); @@ -518,9 +544,21 @@ const LoginDialog = new Lang.Class({ 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; @@ -537,16 +575,37 @@ const LoginDialog = new Lang.Class({ } // 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; @@ -555,6 +614,10 @@ const LoginDialog = new Lang.Class({ } // Finally hand out the allocations + if (bannerAllocation) { + this._bannerView.allocate(bannerAllocation, flags); + } + if (authPromptAllocation) this._authPrompt.actor.allocate(authPromptAllocation, flags); @@ -617,6 +680,18 @@ const LoginDialog = new Lang.Class({ } }, + _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; @@ -684,6 +759,7 @@ const LoginDialog = new Lang.Class({ { opacity: 255, time: _FADE_ANIMATION_TIME, transition: 'easeOutQuad' }); + this._fadeInBannerView(); }, _showRealmLoginHint: function(realmManager, hint) { @@ -940,6 +1016,7 @@ const LoginDialog = new Lang.Class({ _showUserList: function() { this._ensureUserListLoaded(); this._authPrompt.hide(); + this._hideBannerView(); this._sessionMenuButton.close(); this._setUserListExpanded(true); this._notListedButton.show(); -- 2.5.0 From 5c2fb5d1d1ace07e2f9c27d563289e315fe53509 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 11 Nov 2014 09:11:01 -0500 Subject: [PATCH 03/19] 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. https://bugzilla.gnome.org/show_bug.cgi?id=703972 --- 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 41aa89c..575effa 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js @@ -541,6 +541,7 @@ const LoginDialog = new Lang.Class({ }, _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 @@ -555,9 +556,11 @@ const LoginDialog = new Lang.Class({ 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; @@ -574,7 +577,9 @@ const LoginDialog = new Lang.Class({ 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; @@ -588,17 +593,55 @@ const LoginDialog = new Lang.Class({ 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 -- 2.5.0 From f349bc2c4b437430dfc65d13bba24e39c5ab8c59 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Thu, 22 Jan 2015 14:00:01 -0500 Subject: [PATCH 04/19] loginDialog: fix reactivity of first user in user list After the login banner is shown and hidden, the first user in the user list becomes non-reactive. This is because the banner is given an opacity of 0, but still allocated. This commit fixes that by hiding the banner explicitly. https://bugzilla.gnome.org/show_bug.cgi?id=743370 --- js/gdm/loginDialog.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js index 575effa..930f82b 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js @@ -724,6 +724,7 @@ const LoginDialog = new Lang.Class({ }, _fadeInBannerView: function() { + this._bannerView.show(); Tweener.addTween(this._bannerView, { opacity: 255, time: _FADE_ANIMATION_TIME, @@ -733,6 +734,7 @@ const LoginDialog = new Lang.Class({ _hideBannerView: function() { Tweener.removeTweens(this._bannerView); this._bannerView.opacity = 0; + this._bannerView.hide(); }, _updateLogoTexture: function(cache, uri) { -- 2.5.0 From 4c16f0573d5b72ffb99261692353d004d4e13337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Gu=C3=A9rin?= Date: Fri, 27 Mar 2015 22:19:47 +0100 Subject: [PATCH 05/19] gdm: use integer coordinates for login dialog actors If the login screen actors aren't placed at pixel boundaries then they will show up blurred with fuzzy text. This commit ensures all actor allocations are floored to integer coordinates. https://bugzilla.gnome.org/show_bug.cgi?id=746912 --- js/gdm/loginDialog.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js index 930f82b..34bef7d 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js @@ -503,7 +503,7 @@ const LoginDialog = new Lang.Class({ 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.x1 = Math.floor(centerX - natWidth / 2); actorBox.y1 = dialogBox.y1 + Main.layoutManager.panelBox.height; actorBox.x2 = actorBox.x1 + natWidth; actorBox.y2 = actorBox.y1 + natHeight; @@ -517,7 +517,7 @@ const LoginDialog = new Lang.Class({ 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.x1 = Math.floor(centerX - natWidth / 2); actorBox.y1 = dialogBox.y2 - natHeight; actorBox.x2 = actorBox.x1 + natWidth; actorBox.y2 = actorBox.y1 + natHeight; @@ -532,8 +532,8 @@ const LoginDialog = new Lang.Class({ 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.x1 = Math.floor(centerX - natWidth / 2); + actorBox.y1 = Math.floor(centerY - natHeight / 2); actorBox.x2 = actorBox.x1 + natWidth; actorBox.y2 = actorBox.y1 + natHeight; @@ -588,7 +588,7 @@ const LoginDialog = new Lang.Class({ let leftOverTopSpace = leftOverYSpace / 2; // Then, shift the banner into the middle of that extra space - let yShift = leftOverTopSpace / 2; + let yShift = Math.floor(leftOverTopSpace / 2); bannerAllocation.y1 += yShift; bannerAllocation.y2 += yShift; @@ -614,8 +614,8 @@ const LoginDialog = new Lang.Class({ 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; + bannerAllocation.x2 = Math.floor(centerX - centerGap / 2); + bannerAllocation.x1 = Math.floor(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 @@ -623,11 +623,11 @@ const LoginDialog = new Lang.Class({ let maxWideHeight = dialogHeight - 3 * logoHeight; wideBannerHeight = Math.min(maxWideHeight, wideBannerHeight); - bannerAllocation.y1 = centerY - wideBannerHeight / 2; + bannerAllocation.y1 = Math.floor(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.x1 = Math.floor(centerX + centerGap / 2); authPromptAllocation.x2 = authPromptAllocation.x1 + authPromptWidth; } else { // If we aren't going to do a wide view, then we need to limit @@ -637,7 +637,7 @@ const LoginDialog = new Lang.Class({ leftOverYSpace += bannerHeight; // Then figure out how much of that space is up top - let availableTopSpace = leftOverYSpace / 2; + let availableTopSpace = Math.floor(leftOverYSpace / 2); // Then give all of that space to the banner bannerAllocation.y2 = bannerAllocation.y1 + availableTopSpace; @@ -648,7 +648,7 @@ const LoginDialog = new Lang.Class({ let leftOverYSpace = dialogHeight - userSelectionHeight - logoHeight; if (leftOverYSpace > 0) { - let topExpansion = leftOverYSpace / 2; + let topExpansion = Math.floor(leftOverYSpace / 2); let bottomExpansion = topExpansion; userSelectionAllocation.y1 -= topExpansion; -- 2.5.0 From a179abc0adf73f19aeb4ec8069ffaecd0b229179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Fri, 20 Mar 2015 14:29:40 +0100 Subject: [PATCH 06/19] loginDialog: Move long session-list menus to the side Currently the menu position below the button means that the menu can extend to roughly half the screen height before ending up partly off-screen. This is plenty of space for commonly installed sessions, but some users have a significantly higher number of sessions in the list. Move the menu to the side of the button in that case to maximize the vertical space the menu may take up. https://bugzilla.gnome.org/show_bug.cgi?id=734352 --- js/gdm/loginDialog.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js index 34bef7d..bf47c2d 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js @@ -49,6 +49,7 @@ const _FADE_ANIMATION_TIME = 0.25; const _SCROLL_ANIMATION_TIME = 0.5; const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0; const _LOGO_ICON_HEIGHT = 48; +const _MAX_BOTTOM_MENU_ITEMS = 5; const UserListItem = new Lang.Class({ Name: 'UserListItem', @@ -283,7 +284,16 @@ const SessionMenuButton = new Lang.Class({ this.actor = new St.Bin({ child: this._button }); - this._menu = new PopupMenu.PopupMenu(this._button, 0, St.Side.TOP); + let side = St.Side.TOP; + let align = 0; + if (Gdm.get_session_ids().length > _MAX_BOTTOM_MENU_ITEMS) { + if (this.actor.text_direction == Clutter.TextDirection.RTL) + side = St.Side.RIGHT; + else + side = St.Side.LEFT; + align = 0.5; + } + this._menu = new PopupMenu.PopupMenu(this._button, align, side); Main.uiGroup.add_actor(this._menu.actor); this._menu.actor.hide(); -- 2.5.0 From cd87ad4e3f9aa3e18f35f6f4069412412eeb1977 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 16 Mar 2015 07:38:04 -0400 Subject: [PATCH 07/19] gdm: fix empty user list on user switching There's some vestigial code for hiding the user list that runs at the same time its parent is hidden. Only the parent should be hidden, at this point, so there's situations where the user list hides and never comes back. This commit fixes that, by deleting the vestigial code. https://bugzilla.gnome.org/show_bug.cgi?id=719418 --- js/gdm/loginDialog.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js index bf47c2d..9ef7b2a 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js @@ -1090,18 +1090,11 @@ const LoginDialog = new Lang.Class({ }, _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), + let batch = new Batch.ConcurrentBatch(this, [GdmUtil.cloneAndFadeOutActor(this._userSelectionBox), this._beginVerificationForItem(activatedItem)]); batch.run(); }, -- 2.5.0 From 15559166cb1039289a3d81851d7834e3b74cc4cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Fri, 12 Jun 2015 14:14:46 +0200 Subject: [PATCH 08/19] theme: Make banner message more prominent Drop the dedicated dimmed font color for the banner message in favor of the brighter default, to make the banner message more prominent. --- data/theme/gnome-shell.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css index 2ec51b2..97634b1 100644 --- a/data/theme/gnome-shell.css +++ b/data/theme/gnome-shell.css @@ -2407,10 +2407,6 @@ StScrollBar StButton#vhandle:active { border: 2px solid #bbbbbb; } -.login-dialog-banner { - color: #666666; -} - .login-dialog { /* Reset border and background */ border: none; -- 2.5.0 From a3cf129242f79a598bfc0f699ccdfafe99eca754 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Thu, 25 Jun 2015 15:39:58 -0400 Subject: [PATCH 09/19] gdm: fix banner allocation computation The code to figure how how much room that banner had was wrong. This commit fixes it. --- js/gdm/loginDialog.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js index 9ef7b2a..d58daaa 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js @@ -591,7 +591,14 @@ const LoginDialog = new Lang.Class({ // try a different layout, or if we have what extra space we // can hand out if (bannerAllocation) { - let leftOverYSpace = dialogHeight - bannerHeight - authPromptHeight - logoHeight; + let bannerSpace; + + if (authPromptAllocation) + bannerSpace = authPromptAllocation.y1 - bannerAllocation.y1; + else + bannerSpace = 0; + + let leftOverYSpace = bannerSpace - bannerHeight; if (leftOverYSpace > 0) { // First figure out how much left over space is up top -- 2.5.0 From 03743107d8b630254d22533c404806bc48cdc44b Mon Sep 17 00:00:00 2001 From: David Liang Date: Thu, 26 Feb 2015 15:40:56 -0500 Subject: [PATCH 10/19] gdm: prevent nextSignalId from being connected multiply times The problem is caused by '_askForUsernameAndBeginVerification' being called multiply times. So when we click 'next', the old connected function will also be executed. --- js/gdm/loginDialog.js | 45 ++++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js index d58daaa..02c8201 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js @@ -498,6 +498,10 @@ const LoginDialog = new Lang.Class({ this._disableUserList = undefined; this._userListLoaded = false; + this._realmManager = new Realmd.Manager(); + this._realmSignalId = this._realmManager.connect('login-format-changed', + Lang.bind(this, this._showRealmLoginHint)); + LoginManager.getLoginManager().getCurrentSessionProxy(Lang.bind(this, this._gotGreeterSessionProxy)); // If the user list is enabled, it should take key focus; make sure the @@ -841,25 +845,22 @@ const LoginDialog = new Lang.Class({ 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); - this._authPrompt.clear(); - this._authPrompt.startSpinning(); - this._authPrompt.begin({ userName: answer }); - this._updateCancelButton(); - - realmManager.disconnect(realmSignalId) - realmManager.release(); - })); + this._showRealmLoginHint(this._realmManager.loginFormat); + + if (this._nextSignalId) + this._authPrompt.disconnect(this._nextSignalId); + this._nextSignalId = this._authPrompt.connect('next', + Lang.bind(this, function() { + this._authPrompt.disconnect(this._nextSignalId); + this._nextSignalId = 0; + this._authPrompt.updateSensitivity(false); + let answer = this._authPrompt.getAnswer(); + this._user = this._userManager.get_user(answer); + this._authPrompt.clear(); + this._authPrompt.startSpinning(); + this._authPrompt.begin({ userName: answer }); + this._updateCancelButton(); + })); this._updateCancelButton(); this._authPrompt.updateSensitivity(true); @@ -1135,6 +1136,12 @@ const LoginDialog = new Lang.Class({ this._greeterSessionProxy.disconnect(this._greeterSessionProxyChangedId); this._greeterSessionProxy = null; } + if (this._realmManager) { + this._realmManager.disconnect(this._realmSignalId); + this._realmSignalId = 0; + this._realmManager.release(); + this._realmManager = null; + } }, _loadUserList: function() { -- 2.5.0 From 284fef5e484a76d919e9dade90cdc8ea99a304f9 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 30 Jun 2015 12:51:59 -0400 Subject: [PATCH 11/19] gdm: fix cancel button when not listed is clicked We currently ignore cancellation attempts on the authprompt if the pam conversation isn't authenticating. Of course the authprompt asks questions before PAM gets involved, so that's wrong. This commit makes cancel work at the "Not Listed?" username screen. --- js/gdm/authPrompt.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js index a4d69d9..2ac0a54 100644 --- a/js/gdm/authPrompt.js +++ b/js/gdm/authPrompt.js @@ -501,7 +501,7 @@ const AuthPrompt = new Lang.Class({ }, cancel: function() { - if (this.verificationStatus == AuthPromptStatus.NOT_VERIFYING || this.verificationStatus == AuthPromptStatus.VERIFICATION_SUCCEEDED) { + if (this.verificationStatus == AuthPromptStatus.VERIFICATION_SUCCEEDED) { return; } this.reset(); -- 2.5.0 From b1f7ee30ae333a288528215b0f120d7b342ad448 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 14 Nov 2014 15:57:16 -0500 Subject: [PATCH 12/19] gdm: fix handling of removed smartcard at startup If a smartcard is missing from the reader when we start up, and the system is configured to disable password authentication, then we need to ask the user to insert their smartcard. This commit fixes that. https://bugzilla.gnome.org/show_bug.cgi?id=740143 --- js/gdm/util.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/gdm/util.js b/js/gdm/util.js index 4bfaf7c..6286b84 100644 --- a/js/gdm/util.js +++ b/js/gdm/util.js @@ -410,7 +410,7 @@ const ShellUserVerifier = new Lang.Class({ _updateDefaultService: function() { if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY)) this._defaultService = PASSWORD_SERVICE_NAME; - else if (this.smartcardDetected) + else if (this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY)) this._defaultService = SMARTCARD_SERVICE_NAME; else if (this._haveFingerprintReader) this._defaultService = FINGERPRINT_SERVICE_NAME; -- 2.5.0 From 4bf6c66b064b24161889900aa8cb3ba0fa2701df Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 1 Jul 2015 11:18:44 -0400 Subject: [PATCH 13/19] gdm: use password authentication if all schemes are disabled This prevents a traceback, at least. --- js/gdm/util.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/js/gdm/util.js b/js/gdm/util.js index 6286b84..dd04544 100644 --- a/js/gdm/util.js +++ b/js/gdm/util.js @@ -414,6 +414,11 @@ const ShellUserVerifier = new Lang.Class({ this._defaultService = SMARTCARD_SERVICE_NAME; else if (this._haveFingerprintReader) this._defaultService = FINGERPRINT_SERVICE_NAME; + + if (!this._defaultService) { + log("no authentication service is enabled, using password authentication"); + this._defaultService = PASSWORD_SERVICE_NAME; + } }, _startService: function(serviceName) { -- 2.5.0 From 9f99fbecd20cb1d1270138c1a207559a663a7c67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Fri, 10 Jul 2015 18:58:05 +0200 Subject: [PATCH 14/19] loginDialog: Limit user list to the available height We currently will always allocate the user list's preferred size, so it will grow indefinitely and never scroll; limit the height instead to get the desired scrolling behavior when necessary. --- js/gdm/loginDialog.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js index 02c8201..66b8fff 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js @@ -546,6 +546,8 @@ const LoginDialog = new Lang.Class({ let centerX = dialogBox.x1 + (dialogBox.x2 - dialogBox.x1) / 2; let centerY = dialogBox.y1 + (dialogBox.y2 - dialogBox.y1) / 2; + natHeight = Math.min(natHeight, dialogBox.y2 - dialogBox.y1); + actorBox.x1 = Math.floor(centerX - natWidth / 2); actorBox.y1 = Math.floor(centerY - natHeight / 2); actorBox.x2 = actorBox.x1 + natWidth; -- 2.5.0 From 1a10f4dde018a19226daeef95556c0582d3c39a9 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 15 Jul 2015 15:52:29 -0400 Subject: [PATCH 15/19] gdm: unconditionally cancel auth user verifier on reset We currently only cancel the user verifier on reset if verifying, but that means we don't properly cancel it when asking for a username at the Not Listed screen. The object already handles getting called when there is nothing to cancel, so just cancel it unconditionally. --- js/gdm/authPrompt.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js index 2ac0a54..22b102c 100644 --- a/js/gdm/authPrompt.js +++ b/js/gdm/authPrompt.js @@ -434,7 +434,7 @@ const AuthPrompt = new Lang.Class({ this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; this.cancelButton.reactive = true; - if (oldStatus == AuthPromptStatus.VERIFYING) + if (this._userVerifier) this._userVerifier.cancel(); this._queryingService = null; -- 2.5.0 From 8b5dfd5db42a9f5688edb304fd31f09fcbde129b Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 17 Jul 2015 12:57:21 -0400 Subject: [PATCH 16/19] authPrompt: set next button to next when asking for username If the next button ever gets set to Sign In, it won't get reset to next until the next question asked by pam. This commit ensures it gets reset to Next when asking for the username. --- js/gdm/authPrompt.js | 1 + 1 file changed, 1 insertion(+) diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js index 22b102c..c69ade4 100644 --- a/js/gdm/authPrompt.js +++ b/js/gdm/authPrompt.js @@ -433,6 +433,7 @@ const AuthPrompt = new Lang.Class({ let oldStatus = this.verificationStatus; this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; this.cancelButton.reactive = true; + this.nextButton.label = _("Next"); if (this._userVerifier) this._userVerifier.cancel(); -- 2.5.0 From 87eb68c1c9edd1c1a8c961669c9a4b01f29377d9 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 22 Jul 2015 14:52:22 -0400 Subject: [PATCH 17/19] authPrompt: don't allow next if entry is empty Normally the user isn't allowed to proceed past the username question until they've filled it in. To ensure this, the authprompt code desensitizes the next button when the number of characters change to zero. Unfortunately it fails to desensitize the next button up front when the entry starts out empty. This commit addresses that bug. --- js/gdm/authPrompt.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js index c69ade4..3e9eb9a 100644 --- a/js/gdm/authPrompt.js +++ b/js/gdm/authPrompt.js @@ -402,7 +402,7 @@ const AuthPrompt = new Lang.Class({ }, updateSensitivity: function(sensitive) { - this._updateNextButtonSensitivity(sensitive); + this._updateNextButtonSensitivity(sensitive && this._entry.text.length > 0); this._entry.reactive = sensitive; this._entry.clutter_text.editable = sensitive; }, -- 2.5.0 From 20d76a7dac49ece9477be410c243aedf79535bc4 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 4 Aug 2015 09:53:04 -0400 Subject: [PATCH 18/19] gdm: make user list fade-in on vt switch more reliable We fade out the authentication prompt when a user successfully logs into a user session. We reset it and fade it back in when the user switches back to the login screen VT. The problem is, we only fade it back in if the auth prompt status is VERIFICATION_SUCCEEDED. It's possible for it to be NOT_VERIFYING if the authprompt gets reset for some other reason in the interim. This commit changes the check to be more precise. We now only skip the fade-in, if we're already faded in, and we only skip the reset if we're already reset. https://bugzilla.gnome.org/show_bug.cgi?id=753181 --- js/gdm/loginDialog.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js index 66b8fff..a51ffd5 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js @@ -870,7 +870,7 @@ const LoginDialog = new Lang.Class({ }, _loginScreenSessionActivated: function() { - if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFICATION_SUCCEEDED) + if (this.actor.opacity == 255 && this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING) return; Tweener.addTween(this.actor, @@ -887,7 +887,8 @@ const LoginDialog = new Lang.Class({ }, onUpdateScope: this, onComplete: function() { - this._authPrompt.reset(); + if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.NOT_VERIFYING) + this._authPrompt.reset(); }, onCompleteScope: this }); }, -- 2.5.0 From eb2381cff936e62f68d72730dbff2d485408059f Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 3 Aug 2015 14:07:17 -0400 Subject: [PATCH 19/19] gdm: clear user verifier when finished with it We only need the user verifier for the purpose of user verification. Once it's complete we should clear it so it doesn't get in the way later. This fixes a bug introduced in commit 3c8c5a557059 that leads to the user session crashing when the login screen is reactivated. https://bugzilla.gnome.org/show_bug.cgi?id=753181 --- js/gdm/authPrompt.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js index 3e9eb9a..34ad7fb 100644 --- a/js/gdm/authPrompt.js +++ b/js/gdm/authPrompt.js @@ -490,6 +490,7 @@ const AuthPrompt = new Lang.Class({ finish: function(onComplete) { if (!this._userVerifier.hasPendingMessages) { + this._userVerifier.clear(); onComplete(); return; } @@ -497,6 +498,7 @@ const AuthPrompt = new Lang.Class({ let signalId = this._userVerifier.connect('no-more-messages', Lang.bind(this, function() { this._userVerifier.disconnect(signalId); + this._userVerifier.clear(); onComplete(); })); }, -- 2.5.0