From 580c0560105a0f018b62a7e0bdf42eca9b9032f1 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Nov 19 2015 03:42:53 +0000 Subject: import gnome-shell-3.14.4-37.el7 --- diff --git a/.gitignore b/.gitignore index c5e006b..41500b4 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/gnome-shell-3.8.4.tar.xz +SOURCES/gnome-shell-3.14.4.tar.xz diff --git a/.gnome-shell.metadata b/.gnome-shell.metadata index a502ece..12bac15 100644 --- a/.gnome-shell.metadata +++ b/.gnome-shell.metadata @@ -1 +1 @@ -2674fb6d75f5a9726bd8be2b9f675f391c7712cb SOURCES/gnome-shell-3.8.4.tar.xz +1a7684829e3b44a06bee7083955d4fca42888e5e SOURCES/gnome-shell-3.14.4.tar.xz diff --git a/SOURCES/0001-Add-support-for-meta_restart-and-MetaDisplay-restart.patch b/SOURCES/0001-Add-support-for-meta_restart-and-MetaDisplay-restart.patch deleted file mode 100644 index 0b46ba4..0000000 --- a/SOURCES/0001-Add-support-for-meta_restart-and-MetaDisplay-restart.patch +++ /dev/null @@ -1,338 +0,0 @@ -From 3e707f08e1b8687abb093d020b78dc571c68df06 Mon Sep 17 00:00:00 2001 -From: "Owen W. Taylor" -Date: Thu, 8 May 2014 18:56:23 -0400 -Subject: [PATCH] Add support for meta_restart() and MetaDisplay::restart - -Support was added to Mutter to allow it to trigger a restart -to allow for restarts when switching in or out of stereo mode. - -Hook up to the new signals on MetaDisplay to show the restart -message and reexec. Meta.is_restart() is used to suppress -the startup animation. - -This also allows us to do 'Alt-F2 r' restarts more cleanly -without a visual flash and animation. ---- - data/theme/gnome-shell.css | 5 ++ - js/ui/layout.js | 115 +++++++++++++++++++++++++++------------------ - js/ui/main.js | 36 ++++++++++++++ - js/ui/modalDialog.js | 35 ++++++++------ - js/ui/runDialog.js | 14 +++--- - 5 files changed, 138 insertions(+), 67 deletions(-) - -diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css -index f4ea781..66346a1 100644 ---- a/data/theme/gnome-shell.css -+++ b/data/theme/gnome-shell.css -@@ -1920,6 +1920,11 @@ StScrollBar StButton#vhandle:active { - color: #444444; - } - -+/* Restart message */ -+.restart-message { -+ font-size: 14pt; -+} -+ - /* ShellMountOperation Dialogs */ - .shell-mount-operation-icon { - icon-size: 48px; -diff --git a/js/ui/layout.js b/js/ui/layout.js -index 141eecc..223a0e2 100644 ---- a/js/ui/layout.js -+++ b/js/ui/layout.js -@@ -560,56 +560,75 @@ const LayoutManager = new Lang.Class({ - // so events don't get delivered to X11 windows (which are distorted by the animation) - global.stage_input_mode = Shell.StageInputMode.FULLSCREEN; - -- if (Main.sessionMode.isGreeter) { -- this.panelBox.translation_y = -this.panelBox.height; -+ let background; -+ if (Meta.is_restart()) { -+ // On restart, we don't do an animation, so start loading the primary -+ // background now. -+ this._createPrimaryBackground(); -+ background = this._bgManagers[this.primaryIndex].background; - } else { -- // We need to force an update of the regions now before we scale -- // the UI group to get the coorect allocation for the struts. -- this._updateRegions(); -- -- this.trayBox.hide(); -- this.keyboardBox.hide(); -- -- let monitor = this.primaryMonitor; -- let x = monitor.x + monitor.width / 2.0; -- let y = monitor.y + monitor.height / 2.0; -- -- this.uiGroup.set_pivot_point(x / global.screen_width, -- y / global.screen_height); -- this.uiGroup.scale_x = this.uiGroup.scale_y = 0.5; -- this.uiGroup.opacity = 0; -- global.window_group.set_clip(monitor.x, monitor.y, monitor.width, monitor.height); -- } -- -- this._systemBackground = new Background.SystemBackground(); -- this._systemBackground.actor.hide(); -- -- global.stage.insert_child_below(this._systemBackground.actor, null); -+ if (Main.sessionMode.isGreeter) { -+ this.panelBox.translation_y = -this.panelBox.height; -+ } else { -+ // We need to force an update of the regions now before we scale -+ // the UI group to get the coorect allocation for the struts. -+ this._updateRegions(); -+ -+ this.trayBox.hide(); -+ this.keyboardBox.hide(); -+ -+ let monitor = this.primaryMonitor; -+ let x = monitor.x + monitor.width / 2.0; -+ let y = monitor.y + monitor.height / 2.0; -+ -+ this.uiGroup.set_pivot_point(x / global.screen_width, -+ y / global.screen_height); -+ this.uiGroup.scale_x = this.uiGroup.scale_y = 0.5; -+ this.uiGroup.opacity = 0; -+ global.window_group.set_clip(monitor.x, monitor.y, monitor.width, monitor.height); -+ } - -- let constraint = new Clutter.BindConstraint({ source: global.stage, -- coordinate: Clutter.BindCoordinate.ALL }); -- this._systemBackground.actor.add_constraint(constraint); -+ this._systemBackground = new Background.SystemBackground(); -+ this._systemBackground.actor.hide(); - -- let signalId = this._systemBackground.connect('loaded', -- Lang.bind(this, function() { -- this._systemBackground.disconnect(signalId); -- this._systemBackground.actor.show(); -- global.stage.show(); -+ global.stage.insert_child_below(this._systemBackground.actor, null); - -- this.emit('startup-prepared'); -+ let constraint = new Clutter.BindConstraint({ source: global.stage, -+ coordinate: Clutter.BindCoordinate.ALL }); -+ this._systemBackground.actor.add_constraint(constraint); -+ background = this._systemBackground; -+ } - -- // We're mostly prepared for the startup animation -- // now, but since a lot is going on asynchronously -- // during startup, let's defer the startup animation -- // until the event loop is uncontended and idle. -- // This helps to prevent us from running the animation -- // when the system is bogged down -- GLib.idle_add(GLib.PRIORITY_LOW, -- Lang.bind(this, function() { -- this._startupAnimation(); -- return false; -- })); -- })); -+ let signalId = background.connect('loaded', -+ Lang.bind(this, function() { -+ background.disconnect(signalId); -+ if (this._systemBackground) -+ this._systemBackground.actor.show(); -+ global.stage.show(); -+ -+ this.emit('startup-prepared'); -+ -+ // We're mostly prepared for the startup animation -+ // now, but since a lot is going on asynchronously -+ // during startup, let's defer the startup animation -+ // until the event loop is uncontended and idle. -+ // This helps to prevent us from running the animation -+ // when the system is bogged down. Don't wait on -+ // restart, since it might take a long time for us -+ // to go idle, and we don't show an animation. Just -+ // finish immediately. -+ if (Meta.is_restart()) { -+ // Nothing else will do this reliably -+ this._queueUpdateRegions(); -+ this._startupAnimationComplete(); -+ } else { -+ GLib.idle_add(GLib.PRIORITY_LOW, -+ Lang.bind(this, function() { -+ this._startupAnimation(); -+ return false; -+ })); -+ } -+ })); - }, - - _startupAnimation: function() { -@@ -647,8 +666,10 @@ const LayoutManager = new Lang.Class({ - - global.stage_input_mode = Shell.StageInputMode.NORMAL; - -- this._systemBackground.actor.destroy(); -- this._systemBackground = null; -+ if (this._systemBackground) { -+ this._systemBackground.actor.destroy(); -+ this._systemBackground = null; -+ } - - this._startingUp = false; - -diff --git a/js/ui/main.js b/js/ui/main.js -index bd5dc47..a3b73f0 100644 ---- a/js/ui/main.js -+++ b/js/ui/main.js -@@ -18,6 +18,7 @@ const ExtensionSystem = imports.ui.extensionSystem; - const ExtensionDownloader = imports.ui.extensionDownloader; - const Keyboard = imports.ui.keyboard; - const MessageTray = imports.ui.messageTray; -+const ModalDialog = imports.ui.modalDialog; - const OsdWindow = imports.ui.osdWindow; - const Overview = imports.ui.overview; - const Panel = imports.ui.panel; -@@ -176,6 +177,16 @@ function _initializeUI() { - false, -1, 1); - global.display.connect('overlay-key', Lang.bind(overview, overview.toggle)); - -+ global.display.connect('show-restart-message', function(display, message) { -+ showRestartMessage(message); -+ return true; -+ }); -+ -+ global.display.connect('restart', function() { -+ global.reexec_self(); -+ return true; -+ }); -+ - // Provide the bus object for gnome-session to - // initiate logouts. - EndSessionDialog.init(); -@@ -800,3 +811,28 @@ function queueDeferredWork(workId) { - }); - } - } -+ -+const RestartMessage = new Lang.Class({ -+ Name: 'RestartMessage', -+ Extends: ModalDialog.ModalDialog, -+ -+ _init : function(message) { -+ this.parent({ shellReactive: true, -+ styleClass: 'restart-message', -+ shouldFadeIn: false, -+ destroyOnClose: true }); -+ -+ let label = new St.Label({ text: message }); -+ -+ this.contentLayout.add(label, { x_fill: false, -+ y_fill: false, -+ x_align: St.Align.MIDDLE, -+ y_align: St.Align.MIDDLE }); -+ this.buttonLayout.hide(); -+ } -+}); -+ -+function showRestartMessage(message) { -+ let restartMessage = new RestartMessage(message); -+ restartMessage.open(); -+} -diff --git a/js/ui/modalDialog.js b/js/ui/modalDialog.js -index f770faf..aba7758 100644 ---- a/js/ui/modalDialog.js -+++ b/js/ui/modalDialog.js -@@ -43,6 +43,7 @@ const ModalDialog = new Lang.Class({ - parentActor: Main.uiGroup, - keybindingMode: Shell.KeyBindingMode.SYSTEM_MODAL, - shouldFadeIn: true, -+ shouldFadeOut: true, - destroyOnClose: true }); - - this.state = State.CLOSED; -@@ -50,6 +51,7 @@ const ModalDialog = new Lang.Class({ - this._keybindingMode = params.keybindingMode; - this._shellReactive = params.shellReactive; - this._shouldFadeIn = params.shouldFadeIn; -+ this._shouldFadeOut = params.shouldFadeOut; - this._destroyOnClose = params.destroyOnClose; - - this._group = new St.Widget({ visible: false, -@@ -303,6 +305,15 @@ const ModalDialog = new Lang.Class({ - return true; - }, - -+ _closeComplete: function() { -+ this.state = State.CLOSED; -+ this._group.hide(); -+ this.emit('closed'); -+ -+ if (this._destroyOnClose) -+ this.destroy(); -+ }, -+ - close: function(timestamp) { - if (this.state == State.CLOSED || this.state == State.CLOSING) - return; -@@ -311,20 +322,16 @@ const ModalDialog = new Lang.Class({ - this.popModal(timestamp); - this._savedKeyFocus = null; - -- Tweener.addTween(this._group, -- { opacity: 0, -- time: OPEN_AND_CLOSE_TIME, -- transition: 'easeOutQuad', -- onComplete: Lang.bind(this, -- function() { -- this.state = State.CLOSED; -- this._group.hide(); -- this.emit('closed'); -- -- if (this._destroyOnClose) -- this.destroy(); -- }) -- }); -+ if (this._shouldFadeOut) -+ Tweener.addTween(this._group, -+ { opacity: 0, -+ time: OPEN_AND_CLOSE_TIME, -+ transition: 'easeOutQuad', -+ onComplete: Lang.bind(this, -+ this._closeComplete) -+ }) -+ else -+ this._closeComplete(); - }, - - // Drop modal status without closing the dialog; this makes the -diff --git a/js/ui/runDialog.js b/js/ui/runDialog.js -index 7b753a7..1901296 100644 ---- a/js/ui/runDialog.js -+++ b/js/ui/runDialog.js -@@ -50,14 +50,10 @@ const RunDialog = new Lang.Class({ - Main.createLookingGlass().open(); - }), - -- 'r': Lang.bind(this, function() { -- global.reexec_self(); -- }), -+ 'r': Lang.bind(this, this._restart), - - // Developer brain backwards compatibility -- 'restart': Lang.bind(this, function() { -- global.reexec_self(); -- }), -+ 'restart': Lang.bind(this, this._restart), - - 'debugexit': Lang.bind(this, function() { - Meta.quit(Meta.ExitCode.ERROR); -@@ -267,6 +263,12 @@ const RunDialog = new Lang.Class({ - } - }, - -+ _restart: function() { -+ this._shouldFadeOut = false; -+ this.close(); -+ Meta.restart('Restarting...'); -+ }, -+ - open: function() { - this._history.lastItem(); - this._errorBox.hide(); --- -1.8.3.1 - diff --git a/SOURCES/0001-app-Fall-back-to-window-title-instead-of-WM_CLASS.patch b/SOURCES/0001-app-Fall-back-to-window-title-instead-of-WM_CLASS.patch new file mode 100644 index 0000000..a319633 --- /dev/null +++ b/SOURCES/0001-app-Fall-back-to-window-title-instead-of-WM_CLASS.patch @@ -0,0 +1,28 @@ +From 75ae1a91dd112faef56bb4bf0459c87acc3c09d6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 20 May 2015 16:44:00 +0200 +Subject: [PATCH] app: Fall back to window title instead of WM_CLASS + +It's a bad fallback as it's clearly window-specific (rather than +app-specific), but it likely looks prettier when we fail to associate +a .desktop file ... +--- + src/shell-app.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shell-app.c b/src/shell-app.c +index dea610e..f1b71d9 100644 +--- a/src/shell-app.c ++++ b/src/shell-app.c +@@ -420,7 +420,7 @@ shell_app_get_name (ShellApp *app) + MetaWindow *window = window_backed_app_get_window (app); + const char *name; + +- name = meta_window_get_wm_class (window); ++ name = meta_window_get_title (window); + if (!name) + name = C_("program", "Unknown"); + return name; +-- +2.3.6 + diff --git a/SOURCES/0001-appSwitcher-Add-option-to-limit-to-the-current-works.patch b/SOURCES/0001-appSwitcher-Add-option-to-limit-to-the-current-works.patch deleted file mode 100644 index 3511495..0000000 --- a/SOURCES/0001-appSwitcher-Add-option-to-limit-to-the-current-works.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 4baaf4cccb723968637580e70ce1b6f4fcee1e39 Mon Sep 17 00:00:00 2001 -From: Adel Gadllah -Date: Thu, 4 Jul 2013 19:24:30 +0200 -Subject: [PATCH] appSwitcher: Add option to limit to the current workspace - -Add an option to limit the appSwitcher to the current workspace. For users -that use workspaces for task separation this more convient then current -behviour. While having to add an option is unfortunate there is no way to make -both groups happy as workspaces usage differes between different users / types -of users. - -https://bugzilla.gnome.org/show_bug.cgi?id=703538 ---- - data/org.gnome.shell.gschema.xml.in.in | 13 +++++++++++++ - js/ui/altTab.js | 9 +++++++-- - 2 files changed, 20 insertions(+), 2 deletions(-) - -diff --git a/data/org.gnome.shell.gschema.xml.in.in b/data/org.gnome.shell.gschema.xml.in.in -index 04d150c..81809d8 100644 ---- a/data/org.gnome.shell.gschema.xml.in.in -+++ b/data/org.gnome.shell.gschema.xml.in.in -@@ -189,6 +189,19 @@ value here is from the GsmPresenceStatus enumeration. - - - -+ -+ -+ false -+ Limit switcher to current workspace. -+ -+ If true, only applications that have windows on the current workspace are shown in the switcher. -+ Otherwise, all applications are included. -+ -+ -+ -+ - - - -diff --git a/js/ui/altTab.js b/js/ui/altTab.js -index 34d83e4..9d47d1e 100644 ---- a/js/ui/altTab.js -+++ b/js/ui/altTab.js -@@ -436,8 +436,11 @@ const AppSwitcher = new Lang.Class({ - this._arrows = []; - - let windowTracker = Shell.WindowTracker.get_default(); -+ let settings = new Gio.Settings({ schema: 'org.gnome.shell.app-switcher' }); -+ let workspace = settings.get_boolean('current-workspace-only') ? global.screen.get_active_workspace() -+ : null; - let allWindows = global.display.get_tab_list(Meta.TabList.NORMAL, -- global.screen, null); -+ global.screen, workspace); - - // Construct the AppIcons, add to the popup - for (let i = 0; i < apps.length; i++) { -@@ -447,7 +450,9 @@ const AppSwitcher = new Lang.Class({ - appIcon.cachedWindows = allWindows.filter(function(w) { - return windowTracker.get_window_app (w) == appIcon.app; - }); -- this._addIcon(appIcon); -+ if (workspace == null || appIcon.cachedWindows.length > 0) { -+ this._addIcon(appIcon); -+ } - } - - this._curApp = -1; --- -2.1.0 - diff --git a/SOURCES/0001-catch-more-errors-on-extensions-enable-and-disable.patch b/SOURCES/0001-catch-more-errors-on-extensions-enable-and-disable.patch deleted file mode 100644 index 03ef93f..0000000 --- a/SOURCES/0001-catch-more-errors-on-extensions-enable-and-disable.patch +++ /dev/null @@ -1,132 +0,0 @@ -From fdc15b08eb034ea2be03c16510475891516ff6f2 Mon Sep 17 00:00:00 2001 -From: Sebastien Lafargue -Date: Fri, 25 Oct 2013 15:28:11 +0200 -Subject: [PATCH] catch more errors on extensions enable() and disable() - -https://bugzilla.gnome.org/show_bug.cgi?id=688331 ---- - js/ui/extensionSystem.js | 50 +++++++++++++++++++++++++++--------------------- - 1 file changed, 28 insertions(+), 22 deletions(-) - -diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js -index 8c12e97..8a75392 100644 ---- a/js/ui/extensionSystem.js -+++ b/js/ui/extensionSystem.js -@@ -76,7 +76,11 @@ function disableExtension(uuid) { - theme.unload_stylesheet(extension.stylesheet.get_path()); - } - -- extension.stateObj.disable(); -+ try { -+ extension.stateObj.disable(); -+ } catch(e) { -+ logExtensionError(uuid, e); -+ } - - for (let i = 0; i < order.length; i++) { - let uuid = order[i]; -@@ -89,8 +93,10 @@ function disableExtension(uuid) { - - extensionOrder.splice(orderIdx, 1); - -- extension.state = ExtensionState.DISABLED; -- _signals.emit('extension-state-changed', extension); -+ if ( extension.state != ExtensionState.ERROR ) { -+ extension.state = ExtensionState.DISABLED; -+ _signals.emit('extension-state-changed', extension); -+ } - } - - function enableExtension(uuid) { -@@ -117,10 +123,15 @@ function enableExtension(uuid) { - } - } - -- extension.stateObj.enable(); -- -- extension.state = ExtensionState.ENABLED; -- _signals.emit('extension-state-changed', extension); -+ try { -+ extension.stateObj.enable(); -+ extension.state = ExtensionState.ENABLED; -+ _signals.emit('extension-state-changed', extension); -+ return; -+ } catch(e) { -+ logExtensionError(uuid, e); -+ return; -+ } - } - - function logExtensionError(uuid, error) { -@@ -150,7 +161,8 @@ function loadExtension(extension) { - } else { - let enabled = enabledExtensions.indexOf(extension.uuid) != -1; - if (enabled) { -- initExtension(extension.uuid); -+ if (!initExtension(extension.uuid)) -+ return; - if (extension.state == ExtensionState.DISABLED) - enableExtension(extension.uuid); - } else { -@@ -205,7 +217,12 @@ function initExtension(uuid) { - extensionModule = extension.imports.extension; - - if (extensionModule.init) { -- extensionState = extensionModule.init(extension); -+ try { -+ extensionState = extensionModule.init(extension); -+ } catch(e) { -+ logExtensionError(uuid, e); -+ return false; -+ } - } - - if (!extensionState) -@@ -214,6 +231,7 @@ function initExtension(uuid) { - - extension.state = ExtensionState.DISABLED; - _signals.emit('extension-loaded', uuid); -+ return true; - } - - function getEnabledExtensions() { -@@ -235,11 +253,7 @@ function onEnabledExtensionsChanged() { - newEnabledExtensions.filter(function(uuid) { - return enabledExtensions.indexOf(uuid) == -1; - }).forEach(function(uuid) { -- try { - enableExtension(uuid); -- } catch(e) { -- logExtensionError(uuid, e); -- } - }); - - // Find and disable all the newly disabled extensions: UUIDs found in the -@@ -247,11 +261,7 @@ function onEnabledExtensionsChanged() { - enabledExtensions.filter(function(item) { - return newEnabledExtensions.indexOf(item) == -1; - }).forEach(function(uuid) { -- try { - disableExtension(uuid); -- } catch(e) { -- logExtensionError(uuid, e); -- } - }); - - enabledExtensions = newEnabledExtensions; -@@ -263,11 +273,7 @@ function _loadExtensions() { - - let finder = new ExtensionUtils.ExtensionFinder(); - finder.connect('extension-found', function(signals, extension) { -- try { -- loadExtension(extension); -- } catch(e) { -- logExtensionError(extension.uuid, e); -- } -+ loadExtension(extension); - }); - finder.scanExtensions(); - } --- -1.8.4.2 - diff --git a/SOURCES/0001-dateMenu-Try-to-use-the-default-calendar-application.patch b/SOURCES/0001-dateMenu-Try-to-use-the-default-calendar-application.patch deleted file mode 100644 index 17255c5..0000000 --- a/SOURCES/0001-dateMenu-Try-to-use-the-default-calendar-application.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 3d27dda8915fee31fa25c992649b01ab9dd02e7b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Thu, 16 Jan 2014 07:41:46 -0500 -Subject: [PATCH] dateMenu: Try to use the default calendar application - -Commit 14ceb10555699 changed the "Open Calendar" item to open the -"recommended" calendar application rather than the default one to -avoid problems with MIME subclassing (namely falling back to the -default text editor when no calendar app is installed). -With this change however, the application launched does no longer -necessarily match the one configured in Settings, which is unexpected. -To avoid both problems, use the default calendar application again, -but only if it is in the list of recommended applications. - -https://bugzilla.gnome.org/show_bug.cgi?id=722333 ---- - js/ui/dateMenu.js | 9 ++++++--- - 1 file changed, 6 insertions(+), 3 deletions(-) - -diff --git a/js/ui/dateMenu.js b/js/ui/dateMenu.js -index 32fdd59..232af27 100644 ---- a/js/ui/dateMenu.js -+++ b/js/ui/dateMenu.js -@@ -223,10 +223,13 @@ const DateMenuButton = new Lang.Class({ - return this._calendarApp; - - let apps = Gio.AppInfo.get_recommended_for_type('text/calendar'); -- if (apps && (apps.length > 0)) -- this._calendarApp = apps[0]; -- else -+ if (apps && (apps.length > 0)) { -+ let app = Gio.AppInfo.get_default_for_type('text/calendar', false); -+ let defaultInRecommended = apps.some(function(a) { return a.equal(app); }); -+ this._calendarApp = defaultInRecommended ? app : apps[0]; -+ } else { - this._calendarApp = null; -+ } - return this._calendarApp; - }, - --- -2.1.0 - diff --git a/SOURCES/0001-extensionSystem-Notify-about-extension-issues-on-upd.patch b/SOURCES/0001-extensionSystem-Notify-about-extension-issues-on-upd.patch new file mode 100644 index 0000000..c7a44aa --- /dev/null +++ b/SOURCES/0001-extensionSystem-Notify-about-extension-issues-on-upd.patch @@ -0,0 +1,69 @@ +From 04ef143e61be7445bc643298cd1cbd99f9c57383 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Mon, 21 Sep 2015 20:18:12 +0200 +Subject: [PATCH] extensionSystem: Notify about extension issues on update + +--- + js/ui/extensionSystem.js | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js +index a69308d..b5e189c 100644 +--- a/js/ui/extensionSystem.js ++++ b/js/ui/extensionSystem.js +@@ -7,6 +7,7 @@ const GLib = imports.gi.GLib; + const Gio = imports.gi.Gio; + const St = imports.gi.St; + ++const Config = imports.misc.config; + const ExtensionUtils = imports.misc.extensionUtils; + const Main = imports.ui.main; + +@@ -286,6 +287,36 @@ function _onVersionValidationChanged() { + } + } + ++function _doUpdateCheck() { ++ let version = Config.PACKAGE_VERSION.split('.'); ++ if (parseInt(version[1]) % 2 == 0) ++ version.pop(); ++ ++ let pkgCacheDir = GLib.get_user_cache_dir() + '/gnome-shell/'; ++ let updateStamp = Gio.file_new_for_path(pkgCacheDir + ++ 'update-check-' + version.join('.')); ++ if (updateStamp.query_exists(null)) ++ return; ++ ++ GLib.mkdir_with_parents (pkgCacheDir, 0755); ++ updateStamp.create(0, null).close(null); ++ ++ let nOutdated = enabledExtensions.reduce(function(n, uuid) { ++ let extension = ExtensionUtils.extensions[uuid]; ++ if (extension && extension.state == ExtensionState.OUT_OF_DATE) ++ n++; ++ return n; ++ }, 0); ++ ++ if (nOutdated == 0) ++ return; ++ ++ Main.notify(ngettext("%d extension is out of date", ++ "%d extensions are out of date", ++ nOutdated).format(nOutdated), ++ _("You can visit http://extensions.gnome.org for updates")); ++} ++ + function _loadExtensions() { + global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged); + global.settings.connect('changed::' + EXTENSION_DISABLE_VERSION_CHECK_KEY, _onVersionValidationChanged); +@@ -299,6 +330,7 @@ function _loadExtensions() { + extension.type = ExtensionUtils.ExtensionType.SESSION_MODE; + }); + finder.scanExtensions(); ++ _doUpdateCheck(); + } + + function enableAllExtensions() { +-- +2.5.0 + diff --git a/SOURCES/0001-gdm-honor-timed-login-delay-even-if-animations-disab.patch b/SOURCES/0001-gdm-honor-timed-login-delay-even-if-animations-disab.patch new file mode 100644 index 0000000..487e9c3 --- /dev/null +++ b/SOURCES/0001-gdm-honor-timed-login-delay-even-if-animations-disab.patch @@ -0,0 +1,125 @@ +From 266607d2b5ce7bb74f5954897460261af21b9ff0 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Tue, 18 Aug 2015 12:02:17 -0400 +Subject: [PATCH] gdm: honor timed login delay even if animations disabled + +gnome-shell currently initiates an automatic login attempt if +timed login is enabled and the timed login animation completes. + +Unfortunately, if animations are disabled (as is the case for +virtual machines) then the timed login animation will complete +instantly, and timed login will proceed immediately after gnome-shell +has noticed the user is idle for 5 seconds. + +This commit addresses that problem by initiating timed login and the +animation from a main loop timeout, instead of using the tweener api. +--- + js/gdm/loginDialog.js | 38 ++++++++++++++++++++++++++++---------- + src/gvc | 2 +- + 2 files changed, 29 insertions(+), 11 deletions(-) + +diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js +index a51ffd5..4b4d232 100644 +--- a/js/gdm/loginDialog.js ++++ b/js/gdm/loginDialog.js +@@ -80,74 +80,90 @@ const UserListItem = new Lang.Class({ + scale_x: 0 }); + layout.add(this._timedLoginIndicator); + + this.actor.connect('clicked', Lang.bind(this, this._onClicked)); + this._onUserChanged(); + }, + + _onUserChanged: function() { + this._updateLoggedIn(); + }, + + _updateLoggedIn: function() { + if (this.user.is_logged_in()) + this.actor.add_style_pseudo_class('logged-in'); + else + this.actor.remove_style_pseudo_class('logged-in'); + }, + + _onDestroy: function() { + this._user.disconnect(this._userChangedId); + }, + + _onClicked: function() { + this.emit('activate'); + }, + + showTimedLoginIndicator: function(time) { + let hold = new Batch.Hold(); + + this.hideTimedLoginIndicator(); +- Tweener.addTween(this._timedLoginIndicator, +- { scale_x: 1., +- time: time, +- transition: 'linear', +- onComplete: function() { +- hold.release(); +- }, +- onCompleteScope: this +- }); ++ ++ let startTime = GLib.get_monotonic_time(); ++ ++ this._timedLoginTimeoutId = GLib.timeout_add (GLib.PRIORITY_DEFAULT, ++ 33, ++ Lang.bind(this, function() { ++ let currentTime = GLib.get_monotonic_time(); ++ let elapsedTime = (currentTime - startTime) / GLib.USEC_PER_SEC; ++ this._timedLoginIndicator.scale_x = elapsedTime / time; ++ log("elasped time: " + elapsedTime + " time: " + time); ++ if (elapsedTime >= time) { ++ log("releasing hold"); ++ this._timedLoginTimeoutId = 0; ++ hold.release(); ++ return GLib.SOURCE_REMOVE; ++ } ++ ++ return GLib.SOURCE_CONTINUE; ++ })); ++ ++ GLib.Source.set_name_by_id(this._timedLoginTimeoutId, '[gnome-shell] this._timedLoginTimeoutId'); ++ + return hold; + }, + + hideTimedLoginIndicator: function() { +- Tweener.removeTweens(this._timedLoginIndicator); ++ if (this._timedLoginTimeoutId) { ++ GLib.source_remove(this._timedLoginTimeoutId); ++ this._timedLoginTimeoutId = 0; ++ } + this._timedLoginIndicator.scale_x = 0.; + } + }); + Signals.addSignalMethods(UserListItem.prototype); + + const UserList = new Lang.Class({ + Name: 'UserList', + + _init: function() { + this.actor = new St.ScrollView({ style_class: 'login-dialog-user-list-view'}); + this.actor.set_policy(Gtk.PolicyType.NEVER, + Gtk.PolicyType.AUTOMATIC); + + this._box = new St.BoxLayout({ vertical: true, + style_class: 'login-dialog-user-list', + pseudo_class: 'expanded' }); + + this.actor.add_actor(this._box); + this._items = {}; + + this.actor.connect('key-focus-in', Lang.bind(this, this._moveFocusToItems)); + }, + + _moveFocusToItems: function() { + let hasItems = Object.keys(this._items).length > 0; + + if (!hasItems) + return; + + if (global.stage.get_key_focus() != this.actor) diff --git a/SOURCES/0001-keyring-Don-t-unregister-the-prompt-when-disabled.patch b/SOURCES/0001-keyring-Don-t-unregister-the-prompt-when-disabled.patch deleted file mode 100644 index 5f8c49f..0000000 --- a/SOURCES/0001-keyring-Don-t-unregister-the-prompt-when-disabled.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 17c5b2b32b99185beb7565856d0bc247b7ba9ed4 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Wed, 18 Sep 2013 17:53:26 +0200 -Subject: [PATCH 1/2] keyring: Don't unregister the prompt when disabled - -gnome-keyring provides a fallback in case our builtin prompt fails -to register, so keyring dialogs may still pop up even when they -are supposed to be disabled. -Instead, keep the prompt registered but cancel requests immediately -while disabled. - -https://bugzilla.gnome.org/show_bug.cgi?id=708187 ---- - js/ui/components/keyring.js | 41 ++++++++++++++++++++++++++++++++--------- - 1 file changed, 32 insertions(+), 9 deletions(-) - -diff --git a/js/ui/components/keyring.js b/js/ui/components/keyring.js -index 299ecc6..6de3965 100644 ---- a/js/ui/components/keyring.js -+++ b/js/ui/components/keyring.js -@@ -221,27 +221,50 @@ const KeyringDialog = new Lang.Class({ - }, - }); - -+const KeyringDummyDialog = new Lang.Class({ -+ Name: 'KeyringDummyDialog', -+ -+ _init: function() { -+ this.prompt = new Shell.KeyringPrompt(); -+ this.prompt.connect('show-password', -+ Lang.bind(this, this._cancelPrompt)); -+ this.prompt.connect('show-confirm', Lang.bind(this, -+ this._cancelPrompt)); -+ }, -+ -+ _cancelPrompt: function() { -+ this.prompt.cancel(); -+ } -+}); -+ - const KeyringPrompter = new Lang.Class({ - Name: 'KeyringPrompter', - - _init: function() { - this._prompter = new Gcr.SystemPrompter(); -- this._prompter.connect('new-prompt', function(prompter) { -- let dialog = new KeyringDialog(); -- return dialog.prompt; -- }); -+ this._prompter.connect('new-prompt', Lang.bind(this, -+ function() { -+ let dialog = this._enabled ? new KeyringDialog() -+ : new KeyringDummyDialog(); -+ return dialog.prompt; -+ })); - this._dbusId = null; -+ this._registered = false; -+ this._enabled = false; - }, - - enable: function() { -- this._prompter.register(Gio.DBus.session); -- this._dbusId = Gio.DBus.session.own_name('org.gnome.keyring.SystemPrompter', -- Gio.BusNameOwnerFlags.ALLOW_REPLACEMENT, null, null); -+ if (!this._registered) { -+ this._prompter.register(Gio.DBus.session); -+ this._dbusId = Gio.DBus.session.own_name('org.gnome.keyring.SystemPrompter', -+ Gio.BusNameOwnerFlags.ALLOW_REPLACEMENT, null, null); -+ this._registered = true; -+ } -+ this._enabled = true; - }, - - disable: function() { -- this._prompter.unregister(false); -- Gio.DBus.session.unown_name(this._dbusId); -+ this._enabled = false; - } - }); - --- -1.8.4.2 - diff --git a/SOURCES/0001-magnifier-don-t-spew-to-console-when-focus-moves-aro.patch b/SOURCES/0001-magnifier-don-t-spew-to-console-when-focus-moves-aro.patch new file mode 100644 index 0000000..8e70092 --- /dev/null +++ b/SOURCES/0001-magnifier-don-t-spew-to-console-when-focus-moves-aro.patch @@ -0,0 +1,115 @@ +From 46e5ac207a244960840a1d8108b780dd95a8146a Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Tue, 15 Sep 2015 14:04:07 -0400 +Subject: [PATCH] magnifier: don't spew to console when focus moves around + +We currently ship at-spi2 2.8 in 7.2 but gnome-shell 3.14 which +depends on function names shipped in later versions of at-spi2. + +This commit works around the problem by using the names of the functions, +as they existed in 2.8. +--- + js/ui/magnifier.js | 17 +++++++++++++++-- + 1 file changed, 15 insertions(+), 2 deletions(-) + +diff --git a/js/ui/magnifier.js b/js/ui/magnifier.js +index 101c14c..2fe99c6 100644 +--- a/js/ui/magnifier.js ++++ b/js/ui/magnifier.js +@@ -690,78 +690,91 @@ const ZoomRegion = new Lang.Class({ + this._background = null; + this._uiGroupClone = null; + this._mouseSourceActor = mouseSourceActor; + this._mouseActor = null; + this._crossHairs = null; + this._crossHairsActor = null; + + this._viewPortX = 0; + this._viewPortY = 0; + this._viewPortWidth = global.screen_width; + this._viewPortHeight = global.screen_height; + this._xCenter = this._viewPortWidth / 2; + this._yCenter = this._viewPortHeight / 2; + this._xMagFactor = 1; + this._yMagFactor = 1; + this._followingCursor = false; + this._xFocus = 0; + this._yFocus = 0; + this._xCaret = 0; + this._yCaret = 0; + + Main.layoutManager.connect('monitors-changed', + Lang.bind(this, this._monitorsChanged)); + this._focusCaretTracker.connect('caret-moved', + Lang.bind(this, this._updateCaret)); + this._focusCaretTracker.connect('focus-changed', + Lang.bind(this, this._updateFocus)); + }, + + _updateFocus: function(caller, event) { +- let component = event.source.get_component_iface(); ++ let component; ++ ++ if (typeof event.source.get_component_iface === "function") { ++ component = event.source.get_component_iface(); ++ } else if (typeof event.source.get_component === "function") { ++ component = event.source.get_component(); ++ } ++ + if (!component || event.detail1 != 1) + return; + let extents; + try { + extents = component.get_extents(Atspi.CoordType.SCREEN); + } catch(e) { + log('Failed to read extents of focused component: ' + e.message); + return; + } + + [this._xFocus, this._yFocus] = [extents.x + (extents.width / 2), + extents.y + (extents.height / 2)]; + this._centerFromFocusPosition(); + }, + + _updateCaret: function(caller, event) { +- let text = event.source.get_text_iface(); ++ let text; ++ ++ if (typeof event.source.get_text_iface === "function") { ++ text = event.source.get_text_iface(); ++ } else if (typeof event.source.get_text === "function") { ++ text = event.source.get_text(); ++ } + if (!text) + return; + let extents; + try { + extents = text.get_character_extents(text.get_caret_offset(), 0); + } catch(e) { + log('Failed to read extents of text caret: ' + e.message); + return; + } + + [this._xCaret, this._yCaret] = [extents.x, extents.y]; + this._centerFromCaretPosition(); + }, + + /** + * setActive: + * @activate: Boolean to show/hide the ZoomRegion. + */ + setActive: function(activate) { + if (activate == this.isActive()) + return; + + if (activate) { + this._createActors(); + if (this._isMouseOverRegion()) + this._magnifier.hideSystemCursor(); + this._updateMagViewGeometry(); + this._updateCloneGeometry(); + this._updateMousePosition(); + } else { +-- +2.5.0 + diff --git a/SOURCES/0001-main-Actually-respect-hasWorkspaces.patch b/SOURCES/0001-main-Actually-respect-hasWorkspaces.patch deleted file mode 100644 index 473d5a7..0000000 --- a/SOURCES/0001-main-Actually-respect-hasWorkspaces.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 9472b2a2d951be19df5069cca073ab7e7085c769 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Fri, 1 Nov 2013 00:49:22 +0100 -Subject: [PATCH] main: Actually respect hasWorkspaces - -We've long had the hasWorkspaces property, but it doesn't seem like -it was ever used. Implement it so that we don't have workspaces in -initial-setup mode. ---- - js/ui/main.js | 2 +- - js/ui/windowManager.js | 14 +++++++++++++- - 2 files changed, 14 insertions(+), 2 deletions(-) - -diff --git a/js/ui/main.js b/js/ui/main.js -index bd5dc47..2f0e28a 100644 ---- a/js/ui/main.js -+++ b/js/ui/main.js -@@ -233,7 +233,7 @@ function _checkWorkspaces() { - let i; - let emptyWorkspaces = []; - -- if (!Meta.prefs_get_dynamic_workspaces()) { -+ if (!sessionMode.hasWorkspaces || !Meta.prefs_get_dynamic_workspaces()) { - _checkWorkspacesId = 0; - return false; - } -diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js -index b8ea36b..e4de557 100644 ---- a/js/ui/windowManager.js -+++ b/js/ui/windowManager.js -@@ -568,7 +568,7 @@ const WindowManager = new Lang.Class({ - }, - - _switchWorkspace : function(shellwm, from, to, direction) { -- if (!this._shouldAnimate()) { -+ if (!Main.sessionMode.hasWorkspaces || !this._shouldAnimate()) { - shellwm.completed_switch_workspace(); - return; - } -@@ -721,6 +721,9 @@ const WindowManager = new Lang.Class({ - }, - - _showWorkspaceSwitcher : function(display, screen, window, binding) { -+ if (!Main.sessionMode.hasWorkspaces) -+ return; -+ - if (screen.n_workspaces == 1) - return; - -@@ -738,6 +741,9 @@ const WindowManager = new Lang.Class({ - else - newWs = this.actionMoveWindow(window, direction); - -+ if (!newWs) -+ return; -+ - if (!Main.overview.visible) { - if (this._workspaceSwitcherPopup == null) { - this._workspaceSwitcherPopup = new WorkspaceSwitcherPopup.WorkspaceSwitcherPopup(); -@@ -750,6 +756,9 @@ const WindowManager = new Lang.Class({ - }, - - actionMoveWorkspace: function(direction) { -+ if (!Main.sessionMode.hasWorkspaces) -+ return null; -+ - let activeWorkspace = global.screen.get_active_workspace(); - let toActivate = activeWorkspace.get_neighbor(direction); - -@@ -760,6 +769,9 @@ const WindowManager = new Lang.Class({ - }, - - actionMoveWindow: function(window, direction) { -+ if (!Main.sessionMode.hasWorkspaces) -+ return null; -+ - let activeWorkspace = global.screen.get_active_workspace(); - let toActivate = activeWorkspace.get_neighbor(direction); - --- -1.8.3.1 - diff --git a/SOURCES/0001-main-Close-runDialog-as-necessary-on-session-mode-ch.patch b/SOURCES/0001-main-Close-runDialog-as-necessary-on-session-mode-ch.patch deleted file mode 100644 index 6795de6..0000000 --- a/SOURCES/0001-main-Close-runDialog-as-necessary-on-session-mode-ch.patch +++ /dev/null @@ -1,36 +0,0 @@ -From d1eb56f4ad154f8bada35b5b9d13fbdb325be1a6 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Wed, 18 Sep 2013 19:47:59 +0200 -Subject: [PATCH] main: Close runDialog as necessary on session mode changes - -We already do this for looking glass, but it makes even less sense -for the normal run dialog - if a mode sets runDialog to false, the -intention is to not allow executing aribitrary commands. - -https://bugzilla.gnome.org/show_bug.cgi?id=708218 ---- - js/ui/main.js | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - -diff --git a/js/ui/main.js b/js/ui/main.js -index bd5dc47..ff8cd2c 100644 ---- a/js/ui/main.js -+++ b/js/ui/main.js -@@ -84,8 +84,12 @@ function _sessionUpdated() { - Shell.KeyBindingMode.OVERVIEW, - sessionMode.hasRunDialog ? openRunDialog : null); - -- if (!sessionMode.hasRunDialog && lookingGlass) -- lookingGlass.close(); -+ if (!sessionMode.hasRunDialog) { -+ if (runDialog) -+ runDialog.close(); -+ if (lookingGlass) -+ lookingGlass.close(); -+ } - } - - function start() { --- -1.8.4.2 - diff --git a/SOURCES/0001-main-allow-session-mode-to-be-specified-in-the-envir.patch b/SOURCES/0001-main-allow-session-mode-to-be-specified-in-the-envir.patch deleted file mode 100644 index ca8a982..0000000 --- a/SOURCES/0001-main-allow-session-mode-to-be-specified-in-the-envir.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 55fa78bacbb4537cdc2fb090cb2f607476cae780 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 7 Jan 2014 13:14:31 -0500 -Subject: [PATCH] main: allow session mode to be specified in the environment - -Specifying the session mode on the command-line doesn't play -well with session management (since the saved session desktop -file well either drop the specified session mode, or force it -always, even if the user picked a different mode at the login -screen) - -This commit adds support for specifying the session mode via an -enviroment variable. For now, keep the old command line interface -for backward compatibility ---- - src/main.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/src/main.c b/src/main.c -index 9f7f890..1c42667 100644 ---- a/src/main.c -+++ b/src/main.c -@@ -334,60 +334,62 @@ GOptionEntry gnome_shell_options[] = { - N_("Mode used by GDM for login screen"), - NULL - }, - { - "mode", 0, 0, G_OPTION_ARG_STRING, - &session_mode, - N_("Use a specific mode, e.g. \"gdm\" for login screen"), - "MODE" - }, - { - "list-modes", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, - list_modes, - N_("List possible modes"), - NULL - }, - { NULL } - }; - - int - main (int argc, char **argv) - { - GOptionContext *ctx; - GError *error = NULL; - int ecode; - TpDebugSender *sender; - - bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); - textdomain (GETTEXT_PACKAGE); - -+ session_mode = (char *) g_getenv ("GNOME_SHELL_SESSION_MODE"); -+ - ctx = meta_get_option_context (); - g_option_context_add_main_entries (ctx, gnome_shell_options, GETTEXT_PACKAGE); - if (!g_option_context_parse (ctx, &argc, &argv, &error)) - { - g_printerr ("%s: %s\n", argv[0], error->message); - exit (1); - } - - g_option_context_free (ctx); - - meta_plugin_manager_set_plugin_type (gnome_shell_plugin_get_type ()); - - meta_set_wm_name (WM_NAME); - meta_set_gnome_wm_keybindings (GNOME_WM_KEYBINDINGS); - - /* Prevent meta_init() from causing gtk to load gail and at-bridge */ - g_setenv ("NO_AT_BRIDGE", "1", TRUE); - meta_init (); - g_unsetenv ("NO_AT_BRIDGE"); - - /* FIXME: Add gjs API to set this stuff and don't depend on the - * environment. These propagate to child processes. - */ - g_setenv ("GJS_DEBUG_OUTPUT", "stderr", TRUE); - g_setenv ("GJS_DEBUG_TOPICS", "JS ERROR;JS LOG", TRUE); - - shell_dbus_init (meta_get_replace_current_wm ()); - shell_a11y_init (); - shell_perf_log_init (); - shell_introspection_init (); --- -1.8.3.1 - diff --git a/SOURCES/0001-messageTray-Emit-signal-when-notifications-are-enabl.patch b/SOURCES/0001-messageTray-Emit-signal-when-notifications-are-enabl.patch new file mode 100644 index 0000000..825bf7f --- /dev/null +++ b/SOURCES/0001-messageTray-Emit-signal-when-notifications-are-enabl.patch @@ -0,0 +1,32 @@ +From e598852366619893def62b0a99ef69bc7cfc5c0f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Tue, 12 May 2015 21:27:59 +0200 +Subject: [PATCH] messageTray: Emit signal when notifications are + enabled/disabled + +Since the introduction of per-source notification policy in commit +098bd4509ba0, the NotificationPolicy::enable-changed signal has been +used to track the 'enable' settings. However as we never actually +emitted that signal, this never worked without a restart - oops. + +https://bugzilla.gnome.org/show_bug.cgi?id=749279 +--- + js/ui/messageTray.js | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/js/ui/messageTray.js b/js/ui/messageTray.js +index a034fc3..f1ce7f2 100644 +--- a/js/ui/messageTray.js ++++ b/js/ui/messageTray.js +@@ -392,6 +392,8 @@ const NotificationApplicationPolicy = new Lang.Class({ + + _changed: function(settings, key) { + this.emit('policy-changed', key); ++ if (key == 'enable') ++ this.emit('enable-changed'); + }, + + _canonicalizeId: function(id) { +-- +2.3.6 + diff --git a/SOURCES/0001-network-Do-not-use-timestamp-to-identify-connections.patch b/SOURCES/0001-network-Do-not-use-timestamp-to-identify-connections.patch deleted file mode 100644 index f69913a..0000000 --- a/SOURCES/0001-network-Do-not-use-timestamp-to-identify-connections.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 95550e5a90d65b049dabcd31b7168612c9802327 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Mon, 4 Nov 2013 20:09:45 +0100 -Subject: [PATCH] network: Do not use timestamp to identify connections - -Connections have UUIDs to uniquely identify connections, bringing -in timestamps just messes things up unnecessarily (and was dropped -upstream in 3.10). -Patch by Dan Williams. ---- - js/ui/status/network.js | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/js/ui/status/network.js b/js/ui/status/network.js -index bfd07fd..0a8871c 100644 ---- a/js/ui/status/network.js -+++ b/js/ui/status/network.js -@@ -231,9 +231,7 @@ const NMConnectionBased = new Lang.Class({ - if (exists) { - let existing = this._connections[pos]; - -- // Check if connection changed name or id -- similar = existing.name == connection.get_id() && -- existing.timestamp == connection._timestamp; -+ similar = existing.name == connection.get_id(); - } - - if (exists && valid && similar) { --- -1.8.4.2 - diff --git a/SOURCES/0001-network-Don-t-disable-switch-in-wifi-section-while-c.patch b/SOURCES/0001-network-Don-t-disable-switch-in-wifi-section-while-c.patch deleted file mode 100644 index d09ec51..0000000 --- a/SOURCES/0001-network-Don-t-disable-switch-in-wifi-section-while-c.patch +++ /dev/null @@ -1,113 +0,0 @@ -From aaecd03d5f14fe3332659ab4997b39448814abcd Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Thu, 5 Sep 2013 15:37:12 +0200 -Subject: [PATCH] network: Don't disable switch in wifi section while - connecting - -Establishing a wireless connection may take some time during which -users may change their mind and want to disable it (again). -This is currently impossible, as we overlay the device status if -the device is not fully (dis)connected. Instead, display this status -on the active AP and leave the switch alone. ---- - js/ui/status/network.js | 57 ++++++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 56 insertions(+), 1 deletion(-) - -diff --git a/js/ui/status/network.js b/js/ui/status/network.js -index ca4e462..370afa0 100644 ---- a/js/ui/status/network.js -+++ b/js/ui/status/network.js -@@ -1,4 +1,5 @@ - // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -+const Clutter = imports.gi.Clutter; - const GLib = imports.gi.GLib; - const GObject = imports.gi.GObject; - const Gio = imports.gi.Gio; -@@ -122,8 +123,10 @@ const NMNetworkMenuItem = new Lang.Class({ - this._label = new St.Label({ text: title }); - this.actor.label_actor = this._label; - this.addActor(this._label); -+ this._stack = new St.Widget({ layout_manager: new Clutter.BinLayout() }); -+ this.addActor(this._stack, { align: St.Align.END }); - this._icons = new St.BoxLayout({ style_class: 'nm-menu-item-icons' }); -- this.addActor(this._icons, { align: St.Align.END }); -+ this._stack.add_actor(this._icons); - - this._signalIcon = new St.Icon({ icon_name: this._getIcon(), - style_class: 'popup-menu-icon' }); -@@ -134,6 +137,8 @@ const NMNetworkMenuItem = new Lang.Class({ - this.bestAP._secType != NMAccessPointSecurity.NONE) - this._secureIcon.icon_name = 'network-wireless-encrypted-symbolic'; - this._icons.add_actor(this._secureIcon); -+ this._statusLabel = new St.Label({ visible: false }); -+ this._stack.add_actor(this._statusLabel, { align: St.Align.END }); - }, - - updateBestAP: function(ap) { -@@ -141,6 +146,14 @@ const NMNetworkMenuItem = new Lang.Class({ - this._signalIcon.icon_name = this._getIcon(); - }, - -+ setStatus: function(status) { -+ let visible = status != null; -+ this._statusLabel.visible = visible; -+ this._icons.visible = !visible; -+ -+ this._statusLabel.text = status; -+ }, -+ - _getIcon: function() { - if (this.bestAP.mode == NM80211Mode.ADHOC) - return 'network-workgroup-symbolic'; -@@ -1372,6 +1385,48 @@ const NMDeviceWireless = new Lang.Class({ - 'network-wireless-connected-symbolic', - { reactive: false }); - this._activeConnectionItem.setShowDot(true); -+ -+ if (this._activeNetwork) -+ this._activeConnectionItem.setStatus(this.getActiveStatusLabel()); -+ }, -+ -+ getStatusLabel: function() { -+ if (!this.device) -+ return null; -+ -+ switch(this.device.state) { -+ case NetworkManager.DeviceState.DEACTIVATING: -+ case NetworkManager.DeviceState.PREPARE: -+ case NetworkManager.DeviceState.CONFIG: -+ case NetworkManager.DeviceState.IP_CONFIG: -+ case NetworkManager.DeviceState.IP_CHECK: -+ case NetworkManager.DeviceState.SECONDARIES: -+ case NetworkManager.DeviceState.NEED_AUTH: -+ return null; -+ default: -+ return this.parent(); -+ } -+ }, -+ -+ getActiveStatusLabel: function() { -+ if (!this.device) -+ return null; -+ -+ switch(this.device.state) { -+ case NetworkManager.DeviceState.DEACTIVATING: -+ return _("disconnecting..."); -+ case NetworkManager.DeviceState.PREPARE: -+ case NetworkManager.DeviceState.CONFIG: -+ case NetworkManager.DeviceState.IP_CONFIG: -+ case NetworkManager.DeviceState.IP_CHECK: -+ case NetworkManager.DeviceState.SECONDARIES: -+ return _("connecting..."); -+ case NetworkManager.DeviceState.NEED_AUTH: -+ /* Translators: this is for network connections that require some kind of key or password */ -+ return _("authentication required"); -+ default: -+ return null; -+ } - }, - - _createAutomaticConnection: function(apObj) { --- -1.8.4.2 - diff --git a/SOURCES/0001-panel-add-an-icon-to-the-ActivitiesButton.patch b/SOURCES/0001-panel-add-an-icon-to-the-ActivitiesButton.patch index d741b9a..edff1ca 100644 --- a/SOURCES/0001-panel-add-an-icon-to-the-ActivitiesButton.patch +++ b/SOURCES/0001-panel-add-an-icon-to-the-ActivitiesButton.patch @@ -1,4 +1,4 @@ -From cfff54659c516eef0813e3940606642a64b698d0 Mon Sep 17 00:00:00 2001 +From 16febef9581d3689fc61861086432e188d4dcb2d Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 15 Jan 2014 16:45:34 -0500 Subject: [PATCH] panel: add an icon to the ActivitiesButton @@ -10,37 +10,10 @@ Requested by brand 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css -index 3727197..4191817 100644 +index 8f84c44..c8a1bd9 100644 --- a/data/theme/gnome-shell.css +++ b/data/theme/gnome-shell.css -@@ -567,60 +567,65 @@ StScrollBar StButton#vhandle:active { - #panel.login-screen .panel-button:focus { - color: white; - } - - .panel-button:hover { - color: white; - text-shadow: black 0px 2px 2px; - } - - .panel-button:active, - .panel-button:overview, - .panel-button:focus { - border-image: url("panel-button-border.svg") 6 10 0 2; - background-image: url("panel-button-highlight-wide.svg"); - color: white; - text-shadow: black 0px 2px 2px; - } - - .panel-status-button:active, - .panel-status-button:checked, - .panel-status-button:focus { - background-image: url("panel-button-highlight-narrow.svg"); - } - - .panel-button:active > .system-status-icon, - .panel-button:checked > .system-status-icon, - .panel-button:focus > .system-status-icon { +@@ -713,6 +713,11 @@ StScrollBar StButton#vhandle:active { icon-shadow: black 0px 2px 2px; } @@ -52,65 +25,11 @@ index 3727197..4191817 100644 .panel-menu { -boxpointer-gap: 4px; } - - .panel-status-button-box { - spacing: 4px; - } - - .lock-screen-status-button-box { - spacing: 8px; - } - - /* User Menu */ - - #panelUserMenu { - spacing: 4px; - } - - .status-chooser { - spacing: .4em; - } - - .status-chooser .popup-menu-item, - .status-chooser-combo .popup-menu-item { - padding: .4em; - } - - .status-chooser-user-icon { - border: 2px solid #8b8b8b; - border-radius: 5px; diff --git a/js/ui/panel.js b/js/ui/panel.js -index a6f73a5..afea8c8 100644 +index 05d43f9..dd04601 100644 --- a/js/ui/panel.js +++ b/js/ui/panel.js -@@ -655,64 +655,71 @@ const AppMenuButton = new Lang.Class({ - } - if (this._overviewHidingId > 0) { - Main.overview.disconnect(this._overviewHidingId); - this._overviewHidingId = 0; - } - if (this._overviewShowingId > 0) { - Main.overview.disconnect(this._overviewShowingId); - this._overviewShowingId = 0; - } - if (this._switchWorkspaceNotifyId > 0) { - global.window_manager.disconnect(this._switchWorkspaceNotifyId); - this._switchWorkspaceNotifyId = 0; - } - - this.parent(); - } - }); - - Signals.addSignalMethods(AppMenuButton.prototype); - - const ActivitiesButton = new Lang.Class({ - Name: 'ActivitiesButton', - Extends: PanelMenu.Button, - - _init: function() { - this.parent(0.0, null, true); - this.actor.accessible_role = Atk.Role.TOGGLE_BUTTON; +@@ -562,11 +562,18 @@ const ActivitiesButton = new Lang.Class({ this.actor.name = 'panelActivities'; @@ -123,39 +42,13 @@ index a6f73a5..afea8c8 100644 + /* Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview". */ - this._label = new St.Label({ text: _("Activities") }); + this._label = new St.Label({ text: _("Activities"), + y_align: Clutter.ActorAlign.CENTER }); - this.actor.add_actor(this._label); + box.add_actor(this._label); this.actor.label_actor = this._label; - this.actor.connect('captured-event', Lang.bind(this, this._onCapturedEvent)); - this.actor.connect_after('button-release-event', Lang.bind(this, this._onButtonRelease)); - this.actor.connect_after('key-release-event', Lang.bind(this, this._onKeyRelease)); - - Main.overview.connect('showing', Lang.bind(this, function() { - this.actor.add_style_pseudo_class('overview'); - this.actor.add_accessible_state (Atk.StateType.CHECKED); - })); - Main.overview.connect('hiding', Lang.bind(this, function() { - this.actor.remove_style_pseudo_class('overview'); - this.actor.remove_accessible_state (Atk.StateType.CHECKED); - })); - - this._xdndTimeOut = 0; - }, - - handleDragOver: function(source, actor, x, y, time) { - if (source != Main.xdndHandler) - return DND.DragMotionResult.CONTINUE; - - if (this._xdndTimeOut != 0) - Mainloop.source_remove(this._xdndTimeOut); - this._xdndTimeOut = Mainloop.timeout_add(BUTTON_DND_ACTIVATION_TIMEOUT, - Lang.bind(this, this._xdndToggleOverview, actor)); - - return DND.DragMotionResult.CONTINUE; - }, -- -1.8.3.1 +2.3.3 diff --git a/SOURCES/0001-popupMenu-Fix-removing-the-active-menu-from-PopupMen.patch b/SOURCES/0001-popupMenu-Fix-removing-the-active-menu-from-PopupMen.patch deleted file mode 100644 index a2bb375..0000000 --- a/SOURCES/0001-popupMenu-Fix-removing-the-active-menu-from-PopupMen.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 820f689f7789be074595ce470d39828db771ed66 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Wed, 6 Nov 2013 23:40:22 +0100 -Subject: [PATCH] popupMenu: Fix removing the active menu from PopupMenuManager - -Commit b42af9aa991eba5 changed the parameter list of _closeMenu() -to account for changes in the GrabHelper ungrab mechanism, but -didn't update other callers. - -https://bugzilla.gnome.org/show_bug.cgi?id=709806 ---- - js/ui/popupMenu.js | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js -index 9456b79..81d8ab9 100644 ---- a/js/ui/popupMenu.js -+++ b/js/ui/popupMenu.js -@@ -2106,7 +2106,7 @@ const PopupMenuManager = new Lang.Class({ - - removeMenu: function(menu) { - if (menu == this.activeMenu) -- this._closeMenu(menu); -+ this._closeMenu(false, menu); - - let position = this._findMenu(menu); - if (position == -1) // not a menu we manage --- -1.8.4.2 - diff --git a/SOURCES/0001-screenShield-unblank-when-inserting-smartcard.patch b/SOURCES/0001-screenShield-unblank-when-inserting-smartcard.patch new file mode 100644 index 0000000..5fb4c30 --- /dev/null +++ b/SOURCES/0001-screenShield-unblank-when-inserting-smartcard.patch @@ -0,0 +1,87 @@ +From ba5eacc70a296d9753bfc2b8de14e08726212b69 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Fri, 3 Jul 2015 13:54:36 -0400 +Subject: [PATCH] screenShield: unblank when inserting smartcard + +If a user inserts the smartcard when the screen is locked/blanked +we should ask them their pin right away. + +At the moment they have to wiggle the mouse or do some other +action to get the screen to unblank. +--- + js/ui/screenShield.js | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js +index 3a84468..ad7ce54 100644 +--- a/js/ui/screenShield.js ++++ b/js/ui/screenShield.js +@@ -510,62 +510,64 @@ const ScreenShield = new Lang.Class({ + this._dragAction.connect('gesture-progress', Lang.bind(this, this._onDragMotion)); + this._dragAction.connect('gesture-end', Lang.bind(this, this._onDragEnd)); + this._lockScreenGroup.add_action(this._dragAction); + + this._lockDialogGroup = new St.Widget({ x_expand: true, + y_expand: true, + reactive: true, + pivot_point: new Clutter.Point({ x: 0.5, y: 0.5 }), + name: 'lockDialogGroup' }); + + this.actor.add_actor(this._lockDialogGroup); + this.actor.add_actor(this._lockScreenGroup); + + this._presence = new GnomeSession.Presence(Lang.bind(this, function(proxy, error) { + if (error) { + logError(error, 'Error while reading gnome-session presence'); + return; + } + + this._onStatusChanged(proxy.status); + })); + this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) { + this._onStatusChanged(status); + })); + + this._screenSaverDBus = new ShellDBus.ScreenSaverDBus(this); + + this._smartcardManager = SmartcardManager.getSmartcardManager(); + this._smartcardManager.connect('smartcard-inserted', + Lang.bind(this, function(manager, token) { +- if (this._isLocked && token.UsedToLogin) ++ if (this._isLocked && token.UsedToLogin) { ++ this._wakeUpScreen(); + this._liftShield(true, 0); ++ } + })); + + this._oVirtCredentialsManager = OVirt.getOVirtCredentialsManager(); + this._oVirtCredentialsManager.connect('user-authenticated', + Lang.bind(this, function() { + if (this._isLocked) + this._liftShield(true, 0); + })); + + this._inhibitor = null; + this._aboutToSuspend = false; + this._loginManager = LoginManager.getLoginManager(); + this._loginManager.connect('prepare-for-sleep', + Lang.bind(this, this._prepareForSleep)); + this._inhibitSuspend(); + + this._loginManager.getCurrentSessionProxy(Lang.bind(this, + function(sessionProxy) { + this._loginSession = sessionProxy; + this._loginSession.connectSignal('Lock', Lang.bind(this, function() { this.lock(false); })); + this._loginSession.connectSignal('Unlock', Lang.bind(this, function() { this.deactivate(false); })); + })); + + this._settings = new Gio.Settings({ schema_id: SCREENSAVER_SCHEMA }); + + this._isModal = false; + this._hasLockScreen = false; + this._isGreeter = false; + this._isActive = false; + this._isLocked = false; +-- +2.3.7 + diff --git a/SOURCES/0001-screenshot-Also-validate-parameters-to-FlashArea.patch b/SOURCES/0001-screenshot-Also-validate-parameters-to-FlashArea.patch deleted file mode 100644 index 22ecd7f..0000000 --- a/SOURCES/0001-screenshot-Also-validate-parameters-to-FlashArea.patch +++ /dev/null @@ -1,69 +0,0 @@ -From daf661fbffb3e4c6afd082785721f199f992eab0 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Wed, 4 Jun 2014 16:26:06 +0200 -Subject: [PATCH] screenshot: Also validate parameters to FlashArea() - -Apply the same parameter validation to FlashArea() we already use -for ScreenshotArea(). - -https://bugzilla.gnome.org/show_bug.cgi?id=731220 ---- - js/ui/screenshot.js | 26 ++++++++++++++++++++------ - 1 file changed, 20 insertions(+), 6 deletions(-) - -diff --git a/js/ui/screenshot.js b/js/ui/screenshot.js -index 3c5c831..f85c62e 100644 ---- a/js/ui/screenshot.js -+++ b/js/ui/screenshot.js -@@ -64,6 +64,13 @@ const ScreenshotService = new Lang.Class({ - Gio.DBus.session.own_name('org.gnome.Shell.Screenshot', Gio.BusNameOwnerFlags.REPLACE, null, null); - }, - -+ _checkArea: function(x, y, width, height) { -+ return x >= 0 && y >= 0 && -+ width > 0 && height > 0 && -+ x + width <= global.screen_width && -+ y + height <= global.screen_height; -+ }, -+ - _onScreenshotComplete: function(obj, result, area, filenameUsed, flash, invocation) { - if (flash && result) { - let flashspot = new Flashspot(area); -@@ -76,11 +83,10 @@ const ScreenshotService = new Lang.Class({ - - ScreenshotAreaAsync : function (params, invocation) { - let [x, y, width, height, flash, filename, callback] = params; -- if (x < 0 || y < 0 || -- width <= 0 || height <= 0 || -- x + width > global.screen_width || y + height > global.screen_height) { -- invocation.return_error_literal(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED, -- "Invalid params"); -+ if (!this._checkArea(x, y, width, height)) { -+ invocation.return_error_literal(Gio.IOErrorEnum, -+ Gio.IOErrorEnum.CANCELLED, -+ "Invalid params"); - return; - } - let screenshot = new Shell.Screenshot(); -@@ -122,9 +128,17 @@ const ScreenshotService = new Lang.Class({ - })); - }, - -- FlashArea: function(x, y, width, height) { -+ FlashAreaAsync: function(params, invocation) { -+ let [x, y, width, height] = params; -+ if (!this._checkArea(x, y, width, height)) { -+ invocation.return_error_literal(Gio.IOErrorEnum, -+ Gio.IOErrorEnum.CANCELLED, -+ "Invalid params"); -+ return; -+ } - let flashspot = new Flashspot({ x : x, y : y, width: width, height: height}); - flashspot.fire(); -+ invocation.return_value(null); - } - }); - --- -2.1.0 - diff --git a/SOURCES/0001-screenshot-Extend-ScreenshotArea-parameter-validatio.patch b/SOURCES/0001-screenshot-Extend-ScreenshotArea-parameter-validatio.patch deleted file mode 100644 index b9b86e4..0000000 --- a/SOURCES/0001-screenshot-Extend-ScreenshotArea-parameter-validatio.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 3430f0cb832a489ce8dee1e9294ca7a724f367af Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Mon, 4 Nov 2013 11:14:44 +0100 -Subject: [PATCH 1/3] screenshot: Extend ScreenshotArea parameter validation - -We currently only ensure that width and height are positive, so it -is still possible to pass in values that don't make any sense at all -(which may even result in a crash when exceeding limits imposed by -X11). -There is nothing to screenshot outside the actual screen area, so -restrict the parameters to that. - -https://bugzilla.gnome.org/show_bug.cgi?id=699752 ---- - js/ui/screenshot.js | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/js/ui/screenshot.js b/js/ui/screenshot.js -index 2219a89..3c5c831 100644 ---- a/js/ui/screenshot.js -+++ b/js/ui/screenshot.js -@@ -76,7 +76,9 @@ const ScreenshotService = new Lang.Class({ - - ScreenshotAreaAsync : function (params, invocation) { - let [x, y, width, height, flash, filename, callback] = params; -- if (height <= 0 || width <= 0) { -+ if (x < 0 || y < 0 || -+ width <= 0 || height <= 0 || -+ x + width > global.screen_width || y + height > global.screen_height) { - invocation.return_error_literal(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED, - "Invalid params"); - return; --- -1.8.4.2 - diff --git a/SOURCES/0001-shell-screenshot-Only-allow-one-screenshot-request-a.patch b/SOURCES/0001-shell-screenshot-Only-allow-one-screenshot-request-a.patch deleted file mode 100644 index 67ce2a5..0000000 --- a/SOURCES/0001-shell-screenshot-Only-allow-one-screenshot-request-a.patch +++ /dev/null @@ -1,552 +0,0 @@ -From a13c4a9a6e26b4446d9233637dc88ced61858f35 Mon Sep 17 00:00:00 2001 -From: Adel Gadllah -Date: Sat, 27 Sep 2014 13:35:22 +0200 -Subject: [PATCH] shell-screenshot: Only allow one screenshot request at a time - per sender - -We currently allow infinite number of screenshot requests to be active at -the same time, which can "dos" the system and cause OOM. - -So fail subsequent requests for the same sender when a screenshot operation -is already running. - -https://bugzilla.gnome.org/show_bug.cgi?id=737456 ---- - js/ui/screenshot.js | 61 +++++++++++++-- - src/shell-screenshot.c | 203 ++++++++++++++++++++++++++----------------------- - src/shell-screenshot.h | 5 +- - 3 files changed, 165 insertions(+), 104 deletions(-) - -diff --git a/js/ui/screenshot.js b/js/ui/screenshot.js -index f85c62e..dd6448e 100644 ---- a/js/ui/screenshot.js -+++ b/js/ui/screenshot.js -@@ -10,6 +10,7 @@ const Shell = imports.gi.Shell; - const Signals = imports.signals; - const St = imports.gi.St; - -+const Hash = imports.misc.hash; - const Lightbox = imports.ui.lightbox; - const Main = imports.ui.main; - const Tweener = imports.ui.tweener; -@@ -61,9 +62,41 @@ const ScreenshotService = new Lang.Class({ - this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ScreenshotIface, this); - this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/Screenshot'); - -+ this._screenShooter = new Hash.Map(); -+ - Gio.DBus.session.own_name('org.gnome.Shell.Screenshot', Gio.BusNameOwnerFlags.REPLACE, null, null); - }, - -+ _createScreenshot: function(invocation) { -+ let sender = invocation.get_sender(); -+ if (this._screenShooter.has(sender)) { -+ invocation.return_value(GLib.Variant.new('(bs)', [false, ''])); -+ return null; -+ } -+ -+ let shooter = new Shell.Screenshot(); -+ shooter._watchNameId = -+ Gio.bus_watch_name(Gio.BusType.SESSION, sender, 0, null, -+ Lang.bind(this, this._onNameVanished)); -+ -+ this._screenShooter.set(sender, shooter); -+ -+ return shooter; -+ }, -+ -+ _onNameVanished: function(connection, name) { -+ this._removeShooterForSender(name); -+ }, -+ -+ _removeShooterForSender: function(sender) { -+ let shooter = this._screenShooter.get(sender); -+ if (!shooter) -+ return; -+ -+ Gio.bus_unwatch_name(shooter._watchNameId); -+ this._screenShooter.delete(sender); -+ }, -+ - _checkArea: function(x, y, width, height) { - return x >= 0 && y >= 0 && - width > 0 && height > 0 && -@@ -72,9 +105,15 @@ const ScreenshotService = new Lang.Class({ - }, - - _onScreenshotComplete: function(obj, result, area, filenameUsed, flash, invocation) { -- if (flash && result) { -- let flashspot = new Flashspot(area); -- flashspot.fire(); -+ if (result) { -+ if (flash) { -+ let flashspot = new Flashspot(area); -+ flashspot.fire(Lang.bind(this, function() { -+ this._removeShooterForSender(invocation.get_sender()); -+ })); -+ } -+ else -+ this._removeShooterForSender(invocation.get_sender()); - } - - let retval = GLib.Variant.new('(bs)', [result, filenameUsed]); -@@ -89,7 +128,9 @@ const ScreenshotService = new Lang.Class({ - "Invalid params"); - return; - } -- let screenshot = new Shell.Screenshot(); -+ let screenshot = this._createScreenshot(invocation); -+ if (!screenshot) -+ return; - screenshot.screenshot_area (x, y, width, height, filename, - Lang.bind(this, this._onScreenshotComplete, - flash, invocation)); -@@ -97,7 +138,9 @@ const ScreenshotService = new Lang.Class({ - - ScreenshotWindowAsync : function (params, invocation) { - let [include_frame, include_cursor, flash, filename] = params; -- let screenshot = new Shell.Screenshot(); -+ let screenshot = this._createScreenshot(invocation); -+ if (!screenshot) -+ return; - screenshot.screenshot_window (include_frame, include_cursor, filename, - Lang.bind(this, this._onScreenshotComplete, - flash, invocation)); -@@ -105,7 +148,9 @@ const ScreenshotService = new Lang.Class({ - - ScreenshotAsync : function (params, invocation) { - let [include_cursor, flash, filename] = params; -- let screenshot = new Shell.Screenshot(); -+ let screenshot = this._createScreenshot(invocation); -+ if (!screenshot) -+ return; - screenshot.screenshot(include_cursor, filename, - Lang.bind(this, this._onScreenshotComplete, - flash, invocation)); -@@ -278,7 +323,7 @@ const Flashspot = new Lang.Class({ - this.actor.set_position(area.x, area.y); - }, - -- fire: function() { -+ fire: function(doneCallback) { - this.actor.show(); - this.actor.opacity = 255; - Tweener.addTween(this.actor, -@@ -286,6 +331,8 @@ const Flashspot = new Lang.Class({ - time: FLASHSPOT_ANIMATION_OUT_TIME, - transition: 'easeOutQuad', - onComplete: Lang.bind(this, function() { -+ if (doneCallback) -+ doneCallback(); - this.destroy(); - }) - }); -diff --git a/src/shell-screenshot.c b/src/shell-screenshot.c -index b68c3b0..5630726 100644 ---- a/src/shell-screenshot.c -+++ b/src/shell-screenshot.c -@@ -27,12 +27,12 @@ struct _ShellScreenshot - { - GObject parent_instance; - -- ShellGlobal *global; -+ ShellScreenshotPrivate *priv; - }; - --/* Used for async screenshot grabbing */ --typedef struct _screenshot_data { -- ShellScreenshot *screenshot; -+struct _ShellScreenshotPrivate -+{ -+ ShellGlobal *global; - - char *filename; - char *filename_used; -@@ -43,20 +43,23 @@ typedef struct _screenshot_data { - gboolean include_cursor; - - ShellScreenshotCallback callback; --} _screenshot_data; -+}; - --G_DEFINE_TYPE(ShellScreenshot, shell_screenshot, G_TYPE_OBJECT); -+G_DEFINE_TYPE (ShellScreenshot, shell_screenshot, G_TYPE_OBJECT); -+ -+#define SHELL_SCREENSHOT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), SHELL_TYPE_SCREENSHOT, ShellScreenshotPrivate)) - - static void - shell_screenshot_class_init (ShellScreenshotClass *screenshot_class) - { -- (void) screenshot_class; -+ g_type_class_add_private (screenshot_class, sizeof (ShellScreenshotPrivate)); - } - - static void - shell_screenshot_init (ShellScreenshot *screenshot) - { -- screenshot->global = shell_global_get (); -+ screenshot->priv = SHELL_SCREENSHOT_GET_PRIVATE (screenshot); -+ screenshot->priv->global = shell_global_get (); - } - - static void -@@ -64,18 +67,18 @@ on_screenshot_written (GObject *source, - GAsyncResult *result, - gpointer user_data) - { -- _screenshot_data *screenshot_data = (_screenshot_data*) user_data; -- if (screenshot_data->callback) -- screenshot_data->callback (screenshot_data->screenshot, -- g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (result)), -- &screenshot_data->screenshot_area, -- screenshot_data->filename_used); -- -- cairo_surface_destroy (screenshot_data->image); -- g_object_unref (screenshot_data->screenshot); -- g_free (screenshot_data->filename); -- g_free (screenshot_data->filename_used); -- g_free (screenshot_data); -+ ShellScreenshot *screenshot = SHELL_SCREENSHOT (source); -+ ShellScreenshotPrivate *priv = screenshot->priv; -+ -+ if (priv->callback) -+ priv->callback (screenshot, -+ g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (result)), -+ &priv->screenshot_area, -+ priv->filename_used); -+ -+ g_clear_pointer (&priv->image, cairo_surface_destroy); -+ g_clear_pointer (&priv->filename, g_free); -+ g_clear_pointer (&priv->filename_used, g_free); - } - - /* called in an I/O thread */ -@@ -174,12 +177,15 @@ write_screenshot_thread (GSimpleAsyncResult *result, - { - cairo_status_t status; - GOutputStream *stream; -- _screenshot_data *screenshot_data = g_async_result_get_user_data (G_ASYNC_RESULT (result)); -+ ShellScreenshot *screenshot = SHELL_SCREENSHOT (object); -+ ShellScreenshotPrivate *priv; -+ -+ g_assert (screenshot != NULL); - -- g_assert (screenshot_data != NULL); -+ priv = screenshot->priv; - -- stream = prepare_write_stream (screenshot_data->filename, -- &screenshot_data->filename_used); -+ stream = prepare_write_stream (priv->filename, -+ &priv->filename_used); - - if (stream == NULL) - status = CAIRO_STATUS_FILE_NOT_FOUND; -@@ -187,10 +193,10 @@ write_screenshot_thread (GSimpleAsyncResult *result, - { - GdkPixbuf *pixbuf; - -- pixbuf = gdk_pixbuf_get_from_surface (screenshot_data->image, -+ pixbuf = gdk_pixbuf_get_from_surface (priv->image, - 0, 0, -- cairo_image_surface_get_width (screenshot_data->image), -- cairo_image_surface_get_height (screenshot_data->image)); -+ cairo_image_surface_get_width (priv->image), -+ cairo_image_surface_get_height (priv->image)); - - if (gdk_pixbuf_save_to_stream (pixbuf, stream, "png", NULL, NULL, - "tEXt::Software", "gnome-screenshot", NULL)) -@@ -208,7 +214,7 @@ write_screenshot_thread (GSimpleAsyncResult *result, - } - - static void --do_grab_screenshot (_screenshot_data *screenshot_data, -+do_grab_screenshot (ShellScreenshot *screenshot, - int x, - int y, - int width, -@@ -219,16 +225,17 @@ do_grab_screenshot (_screenshot_data *screenshot_data, - CoglContext *context; - int stride; - guchar *data; -+ ShellScreenshotPrivate *priv = screenshot->priv; - - backend = clutter_get_default_backend (); - context = clutter_backend_get_cogl_context (backend); - -- screenshot_data->image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, -- width, height); -+ priv->image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, -+ width, height); - - -- data = cairo_image_surface_get_data (screenshot_data->image); -- stride = cairo_image_surface_get_stride (screenshot_data->image); -+ data = cairo_image_surface_get_data (priv->image); -+ stride = cairo_image_surface_get_stride (priv->image); - - bitmap = cogl_bitmap_new_for_data (context, - width, -@@ -241,7 +248,7 @@ do_grab_screenshot (_screenshot_data *screenshot_data, - COGL_READ_PIXELS_COLOR_BUFFER, - bitmap); - -- cairo_surface_mark_dirty (screenshot_data->image); -+ cairo_surface_mark_dirty (priv->image); - cogl_object_unref (bitmap); - } - -@@ -302,16 +309,18 @@ _draw_cursor_image (cairo_surface_t *surface, - - static void - grab_screenshot (ClutterActor *stage, -- _screenshot_data *screenshot_data) -+ ShellScreenshot *screenshot) - { -- MetaScreen *screen = shell_global_get_screen (screenshot_data->screenshot->global); -+ MetaScreen *screen; - int width, height; - GSimpleAsyncResult *result; - GSettings *settings; -+ ShellScreenshotPrivate *priv = screenshot->priv; - -+ screen = shell_global_get_screen (priv->global); - meta_screen_get_size (screen, &width, &height); - -- do_grab_screenshot (screenshot_data, 0, 0, width, height); -+ do_grab_screenshot (screenshot, 0, 0, width, height); - - if (meta_screen_get_n_monitors (screen) > 1) - { -@@ -337,7 +346,7 @@ grab_screenshot (ClutterActor *stage, - cairo_region_xor (stage_region, screen_region); - cairo_region_destroy (screen_region); - -- cr = cairo_create (screenshot_data->image); -+ cr = cairo_create (priv->image); - - for (i = 0; i < cairo_region_num_rectangles (stage_region); i++) - { -@@ -351,38 +360,39 @@ grab_screenshot (ClutterActor *stage, - cairo_region_destroy (stage_region); - } - -- screenshot_data->screenshot_area.x = 0; -- screenshot_data->screenshot_area.y = 0; -- screenshot_data->screenshot_area.width = width; -- screenshot_data->screenshot_area.height = height; -+ priv->screenshot_area.x = 0; -+ priv->screenshot_area.y = 0; -+ priv->screenshot_area.width = width; -+ priv->screenshot_area.height = height; - - settings = g_settings_new (A11Y_APPS_SCHEMA); -- if (screenshot_data->include_cursor && -+ if (priv->include_cursor && - !g_settings_get_boolean (settings, MAGNIFIER_ACTIVE_KEY)) -- _draw_cursor_image (screenshot_data->image, screenshot_data->screenshot_area); -+ _draw_cursor_image (priv->image, priv->screenshot_area); - g_object_unref (settings); - -- g_signal_handlers_disconnect_by_func (stage, (void *)grab_screenshot, (gpointer)screenshot_data); -+ g_signal_handlers_disconnect_by_func (stage, (void *)grab_screenshot, (gpointer)screenshot); - -- result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, grab_screenshot); -+ result = g_simple_async_result_new (G_OBJECT (screenshot), on_screenshot_written, NULL, grab_screenshot); - g_simple_async_result_run_in_thread (result, write_screenshot_thread, G_PRIORITY_DEFAULT, NULL); - g_object_unref (result); - } - - static void - grab_area_screenshot (ClutterActor *stage, -- _screenshot_data *screenshot_data) -+ ShellScreenshot *screenshot) - { - GSimpleAsyncResult *result; -+ ShellScreenshotPrivate *priv = screenshot->priv; - -- do_grab_screenshot (screenshot_data, -- screenshot_data->screenshot_area.x, -- screenshot_data->screenshot_area.y, -- screenshot_data->screenshot_area.width, -- screenshot_data->screenshot_area.height); -+ do_grab_screenshot (screenshot, -+ priv->screenshot_area.x, -+ priv->screenshot_area.y, -+ priv->screenshot_area.width, -+ priv->screenshot_area.height); - -- g_signal_handlers_disconnect_by_func (stage, (void *)grab_area_screenshot, (gpointer)screenshot_data); -- result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, grab_area_screenshot); -+ g_signal_handlers_disconnect_by_func (stage, (void *)grab_area_screenshot, (gpointer)screenshot); -+ result = g_simple_async_result_new (G_OBJECT (screenshot), on_screenshot_written, NULL, grab_area_screenshot); - g_simple_async_result_run_in_thread (result, write_screenshot_thread, G_PRIORITY_DEFAULT, NULL); - g_object_unref (result); - } -@@ -406,16 +416,21 @@ shell_screenshot_screenshot (ShellScreenshot *screenshot, - ShellScreenshotCallback callback) - { - ClutterActor *stage; -- _screenshot_data *data = g_new0 (_screenshot_data, 1); -+ ShellScreenshotPrivate *priv = screenshot->priv; -+ -+ if (priv->filename != NULL) { -+ if (callback) -+ callback (screenshot, FALSE, NULL, ""); -+ return; -+ } - -- data->screenshot = g_object_ref (screenshot); -- data->filename = g_strdup (filename); -- data->callback = callback; -- data->include_cursor = include_cursor; -+ priv->filename = g_strdup (filename); -+ priv->callback = callback; -+ priv->include_cursor = include_cursor; - -- stage = CLUTTER_ACTOR (shell_global_get_stage (screenshot->global)); -+ stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global)); - -- g_signal_connect_after (stage, "paint", G_CALLBACK (grab_screenshot), (gpointer)data); -+ g_signal_connect_after (stage, "paint", G_CALLBACK (grab_screenshot), (gpointer)screenshot); - - clutter_actor_queue_redraw (stage); - } -@@ -445,19 +460,24 @@ shell_screenshot_screenshot_area (ShellScreenshot *screenshot, - ShellScreenshotCallback callback) - { - ClutterActor *stage; -- _screenshot_data *data = g_new0 (_screenshot_data, 1); -+ ShellScreenshotPrivate *priv = screenshot->priv; - -- data->screenshot = g_object_ref (screenshot); -- data->filename = g_strdup (filename); -- data->screenshot_area.x = x; -- data->screenshot_area.y = y; -- data->screenshot_area.width = width; -- data->screenshot_area.height = height; -- data->callback = callback; -+ if (priv->filename != NULL) { -+ if (callback) -+ callback (screenshot, FALSE, NULL, ""); -+ return; -+ } -+ -+ priv->filename = g_strdup (filename); -+ priv->screenshot_area.x = x; -+ priv->screenshot_area.y = y; -+ priv->screenshot_area.width = width; -+ priv->screenshot_area.height = height; -+ priv->callback = callback; - -- stage = CLUTTER_ACTOR (shell_global_get_stage (screenshot->global)); -+ stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global)); - -- g_signal_connect_after (stage, "paint", G_CALLBACK (grab_area_screenshot), (gpointer)data); -+ g_signal_connect_after (stage, "paint", G_CALLBACK (grab_area_screenshot), (gpointer)screenshot); - - clutter_actor_queue_redraw (stage); - } -@@ -484,10 +504,9 @@ shell_screenshot_screenshot_window (ShellScreenshot *screenshot, - { - GSimpleAsyncResult *result; - GSettings *settings; -+ ShellScreenshotPrivate *priv = screenshot->priv; - -- _screenshot_data *screenshot_data = g_new0 (_screenshot_data, 1); -- -- MetaScreen *screen = shell_global_get_screen (screenshot->global); -+ MetaScreen *screen = shell_global_get_screen (priv->global); - MetaDisplay *display = meta_screen_get_display (screen); - MetaWindow *window = meta_display_get_focus_window (display); - ClutterActor *window_actor; -@@ -496,20 +515,14 @@ shell_screenshot_screenshot_window (ShellScreenshot *screenshot, - MetaRectangle rect; - cairo_rectangle_int_t clip; - -- screenshot_data->screenshot = g_object_ref (screenshot); -- screenshot_data->filename = g_strdup (filename); -- screenshot_data->callback = callback; -- -- if (!window) -- { -- screenshot_data->filename_used = g_strdup (""); -- result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, shell_screenshot_screenshot_window); -- g_simple_async_result_set_op_res_gboolean (result, FALSE); -- g_simple_async_result_complete (result); -- g_object_unref (result); -+ if (priv->filename != NULL || !window) { -+ if (callback) -+ callback (screenshot, FALSE, NULL, ""); -+ return; -+ } - -- return; -- } -+ priv->filename = g_strdup (filename); -+ priv->callback = callback; - - window_actor = CLUTTER_ACTOR (meta_window_get_compositor_private (window)); - clutter_actor_get_position (window_actor, &actor_x, &actor_y); -@@ -518,8 +531,8 @@ shell_screenshot_screenshot_window (ShellScreenshot *screenshot, - { - meta_window_get_outer_rect (window, &rect); - -- screenshot_data->screenshot_area.x = rect.x; -- screenshot_data->screenshot_area.y = rect.y; -+ priv->screenshot_area.x = rect.x; -+ priv->screenshot_area.y = rect.y; - - clip.x = rect.x - (gint) actor_x; - clip.y = rect.y - (gint) actor_y; -@@ -528,25 +541,25 @@ shell_screenshot_screenshot_window (ShellScreenshot *screenshot, - { - rect = *meta_window_get_rect (window); - -- screenshot_data->screenshot_area.x = (gint) actor_x + rect.x; -- screenshot_data->screenshot_area.y = (gint) actor_y + rect.y; -+ priv->screenshot_area.x = (gint) actor_x + rect.x; -+ priv->screenshot_area.y = (gint) actor_y + rect.y; - - clip.x = rect.x; - clip.y = rect.y; - } - -- clip.width = screenshot_data->screenshot_area.width = rect.width; -- clip.height = screenshot_data->screenshot_area.height = rect.height; -+ clip.width = priv->screenshot_area.width = rect.width; -+ clip.height = priv->screenshot_area.height = rect.height; - - stex = META_SHAPED_TEXTURE (meta_window_actor_get_texture (META_WINDOW_ACTOR (window_actor))); -- screenshot_data->image = meta_shaped_texture_get_image (stex, &clip); -+ priv->image = meta_shaped_texture_get_image (stex, &clip); - - settings = g_settings_new (A11Y_APPS_SCHEMA); - if (include_cursor && !g_settings_get_boolean (settings, MAGNIFIER_ACTIVE_KEY)) -- _draw_cursor_image (screenshot_data->image, screenshot_data->screenshot_area); -+ _draw_cursor_image (priv->image, priv->screenshot_area); - g_object_unref (settings); - -- result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, shell_screenshot_screenshot_window); -+ result = g_simple_async_result_new (G_OBJECT (screenshot), on_screenshot_written, NULL, shell_screenshot_screenshot_window); - g_simple_async_result_run_in_thread (result, write_screenshot_thread, G_PRIORITY_DEFAULT, NULL); - g_object_unref (result); - } -diff --git a/src/shell-screenshot.h b/src/shell-screenshot.h -index 76925f3..0b8ab1c 100644 ---- a/src/shell-screenshot.h -+++ b/src/shell-screenshot.h -@@ -11,8 +11,9 @@ - * - */ - --typedef struct _ShellScreenshot ShellScreenshot; --typedef struct _ShellScreenshotClass ShellScreenshotClass; -+typedef struct _ShellScreenshot ShellScreenshot; -+typedef struct _ShellScreenshotPrivate ShellScreenshotPrivate; -+typedef struct _ShellScreenshotClass ShellScreenshotClass; - - #define SHELL_TYPE_SCREENSHOT (shell_screenshot_get_type ()) - #define SHELL_SCREENSHOT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SHELL_TYPE_SCREENSHOT, ShellScreenshot)) --- -2.1.0 - diff --git a/SOURCES/0001-shellDBus-Add-a-DBus-method-to-load-a-single-extensi.patch b/SOURCES/0001-shellDBus-Add-a-DBus-method-to-load-a-single-extensi.patch index 0c239d7..ee69cd9 100644 --- a/SOURCES/0001-shellDBus-Add-a-DBus-method-to-load-a-single-extensi.patch +++ b/SOURCES/0001-shellDBus-Add-a-DBus-method-to-load-a-single-extensi.patch @@ -1,4 +1,4 @@ -From 193ac75919f663122fd3a9ef3bd5342fffe79dde Mon Sep 17 00:00:00 2001 +From daf38420dcdd70c090cf146973f0b3f4522a532c Mon Sep 17 00:00:00 2001 From: Rui Matos Date: Fri, 8 Nov 2013 11:36:04 +0100 Subject: [PATCH 1/2] shellDBus: Add a DBus method to load a single extension @@ -10,21 +10,21 @@ file and load it into the running shell. 1 file changed, 20 insertions(+) diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js -index 84597fd..d3a3a05 100644 +index a87ea41..f8b05f4 100644 --- a/js/ui/shellDBus.js +++ b/js/ui/shellDBus.js -@@ -266,6 +266,10 @@ const GnomeShellExtensionsIface = - - - -+ -+ -+ -+ - - ; - -@@ -365,6 +369,22 @@ const GnomeShellExtensions = new Lang.Class({ +@@ -283,6 +283,10 @@ const GnomeShellExtensionsIface = ' \ + \ + \ + \ ++ \ ++ \ ++ \ ++ \ + \ + \ + '; +@@ -385,6 +389,22 @@ const GnomeShellExtensions = new Lang.Class({ ExtensionDownloader.checkForUpdates(); }, @@ -48,5 +48,5 @@ index 84597fd..d3a3a05 100644 _extensionStateChanged: function(_, newState) { -- -1.8.3.1 +2.3.3 diff --git a/SOURCES/0001-shell_dbus_acquire_name-Don-t-leak-error.patch b/SOURCES/0001-shell_dbus_acquire_name-Don-t-leak-error.patch new file mode 100644 index 0000000..3a4d677 --- /dev/null +++ b/SOURCES/0001-shell_dbus_acquire_name-Don-t-leak-error.patch @@ -0,0 +1,26 @@ +From 7f1a258ff9fc768a7fc13e5c37e1fd6d7ab5c33b Mon Sep 17 00:00:00 2001 +From: Matthias Clasen +Date: Thu, 24 Sep 2015 13:16:56 -0400 +Subject: [PATCH 1/3] shell_dbus_acquire_name: Don't leak error + +If fatal is not set, we return from this function in the error +case. Don't leak the GError if that happens. +--- + src/main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/main.c b/src/main.c +index d984eec..fb0ea43 100644 +--- a/src/main.c ++++ b/src/main.c +@@ -69,6 +69,7 @@ shell_dbus_acquire_name (GDBusProxy *bus, + &error))) + { + g_printerr ("failed to acquire %s: %s\n", name, error->message); ++ g_clear_error (&error); + if (!fatal) + return; + exit (1); +-- +2.5.3 + diff --git a/SOURCES/0002-extensions-Add-a-SESSION_MODE-extension-type.patch b/SOURCES/0002-extensions-Add-a-SESSION_MODE-extension-type.patch index da469ee..06d4eca 100644 --- a/SOURCES/0002-extensions-Add-a-SESSION_MODE-extension-type.patch +++ b/SOURCES/0002-extensions-Add-a-SESSION_MODE-extension-type.patch @@ -1,4 +1,4 @@ -From 5389581bdba7f5c84c4cd550b0a04f3854ef8bb9 Mon Sep 17 00:00:00 2001 +From dcdf2c26467818b2ee9999dc103242b3e3cd1416 Mon Sep 17 00:00:00 2001 From: Rui Matos Date: Fri, 8 Nov 2013 13:58:09 +0100 Subject: [PATCH 2/2] extensions: Add a SESSION_MODE extension type @@ -11,7 +11,7 @@ different way since they can't be disabled. 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/js/misc/extensionUtils.js b/js/misc/extensionUtils.js -index 7c6769a..a46929a 100644 +index afdc3cd..8541cf6 100644 --- a/js/misc/extensionUtils.js +++ b/js/misc/extensionUtils.js @@ -15,7 +15,8 @@ const FileUtils = imports.misc.fileUtils; @@ -25,12 +25,12 @@ index 7c6769a..a46929a 100644 // Maps uuid -> metadata object diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js -index 8c12e97..ba5db46 100644 +index 11a75c6..a69308d 100644 --- a/js/ui/extensionSystem.js +++ b/js/ui/extensionSystem.js -@@ -274,6 +274,8 @@ function _loadExtensions() { +@@ -295,6 +295,8 @@ function _loadExtensions() { let finder = new ExtensionUtils.ExtensionFinder(); - finder.connect('extension-found', function(signals, extension) { + finder.connect('extension-found', function(finder, extension) { loadExtension(extension); + if (Main.sessionMode.enabledExtensions.indexOf(extension.uuid) != -1) + extension.type = ExtensionUtils.ExtensionType.SESSION_MODE; @@ -38,5 +38,5 @@ index 8c12e97..ba5db46 100644 finder.scanExtensions(); } -- -1.8.3.1 +2.3.3 diff --git a/SOURCES/0002-keyring-Cancel-active-prompts-on-disable.patch b/SOURCES/0002-keyring-Cancel-active-prompts-on-disable.patch deleted file mode 100644 index a741ad1..0000000 --- a/SOURCES/0002-keyring-Cancel-active-prompts-on-disable.patch +++ /dev/null @@ -1,50 +0,0 @@ -From ba64565bf9be6d827fbbf4dd4de1998b770956ed Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Fri, 27 Sep 2013 16:04:25 +0200 -Subject: [PATCH 2/2] keyring: Cancel active prompts on disable() - -Since commit 1242a16265d5bf2, we will use a fake prompt which -cancels alls requests without dialog when the keyring component -is disabled. However this does only apply to new requests, dialogs -that are already active when the session mode changes are kept -open. This is not quite as expected, so cancel the prompt in that -case. - -https://bugzilla.gnome.org/show_bug.cgi?id=708910 ---- - js/ui/components/keyring.js | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/js/ui/components/keyring.js b/js/ui/components/keyring.js -index 6de3965..5f7813b 100644 ---- a/js/ui/components/keyring.js -+++ b/js/ui/components/keyring.js -@@ -246,11 +246,13 @@ const KeyringPrompter = new Lang.Class({ - function() { - let dialog = this._enabled ? new KeyringDialog() - : new KeyringDummyDialog(); -- return dialog.prompt; -+ this._currentPrompt = dialog.prompt; -+ return this._currentPrompt; - })); - this._dbusId = null; - this._registered = false; - this._enabled = false; -+ this._currentPrompt = null; - }, - - enable: function() { -@@ -265,6 +267,10 @@ const KeyringPrompter = new Lang.Class({ - - disable: function() { - this._enabled = false; -+ -+ if (this._prompter.prompting) -+ this._currentPrompt.cancel(); -+ this._currentPrompt = null; - } - }); - --- -1.8.4.2 - diff --git a/SOURCES/0002-screencast-Fix-disabling-screencasts-via-session-mod.patch b/SOURCES/0002-screencast-Fix-disabling-screencasts-via-session-mod.patch deleted file mode 100644 index e9699d9..0000000 --- a/SOURCES/0002-screencast-Fix-disabling-screencasts-via-session-mod.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 158fe31bb3cb1c38830681c864714bb31ee77c7e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Mon, 4 Nov 2013 14:06:33 +0100 -Subject: [PATCH 2/3] screencast: Fix disabling screencasts via session mode - -If screencasts are disabled, we return a DBus error, but still start -the recording happily - add early returns in that case. - -https://bugzilla.gnome.org/show_bug.cgi?id=699752 ---- - js/ui/screencast.js | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - -diff --git a/js/ui/screencast.js b/js/ui/screencast.js -index 4a14933..7d8d767 100644 ---- a/js/ui/screencast.js -+++ b/js/ui/screencast.js -@@ -95,8 +95,10 @@ const ScreencastService = new Lang.Class({ - - ScreencastAsync: function(params, invocation) { - let returnValue = [false, '']; -- if (!Main.sessionMode.allowScreencast) -+ if (!Main.sessionMode.allowScreencast) { - invocation.return_value(GLib.Variant.new('(bs)', returnValue)); -+ return; -+ } - - let sender = invocation.get_sender(); - let recorder = this._ensureRecorderForSender(sender); -@@ -114,8 +116,10 @@ const ScreencastService = new Lang.Class({ - - ScreencastAreaAsync: function(params, invocation) { - let returnValue = [false, '']; -- if (!Main.sessionMode.allowScreencast) -+ if (!Main.sessionMode.allowScreencast) { - invocation.return_value(GLib.Variant.new('(bs)', returnValue)); -+ return; -+ } - - let sender = invocation.get_sender(); - let recorder = this._ensureRecorderForSender(sender); --- -1.8.4.2 - diff --git a/SOURCES/0002-shell_dbus_acquire_name-Don-t-leak-the-result.patch b/SOURCES/0002-shell_dbus_acquire_name-Don-t-leak-the-result.patch new file mode 100644 index 0000000..3b43a48 --- /dev/null +++ b/SOURCES/0002-shell_dbus_acquire_name-Don-t-leak-the-result.patch @@ -0,0 +1,26 @@ +From 3f0fbae7e213b2fbe7267b9d25ac7fcfaa8afcff Mon Sep 17 00:00:00 2001 +From: Matthias Clasen +Date: Thu, 24 Sep 2015 13:17:36 -0400 +Subject: [PATCH 2/3] shell_dbus_acquire_name: Don't leak the result + +The GVariant returned by g_dbus_proxy_call_sync must be +freed with g_variant_unref, to prevent a leak. +--- + src/main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/main.c b/src/main.c +index fb0ea43..b33d4bf 100644 +--- a/src/main.c ++++ b/src/main.c +@@ -75,6 +75,7 @@ shell_dbus_acquire_name (GDBusProxy *bus, + exit (1); + } + g_variant_get (request_name_variant, "(u)", request_name_result); ++ g_variant_unref (request_name_variant); + } + + static void +-- +2.5.3 + diff --git a/SOURCES/0003-Check-error-of-g_dbus_proxy_new_sync-call.patch b/SOURCES/0003-Check-error-of-g_dbus_proxy_new_sync-call.patch new file mode 100644 index 0000000..be625c3 --- /dev/null +++ b/SOURCES/0003-Check-error-of-g_dbus_proxy_new_sync-call.patch @@ -0,0 +1,30 @@ +From 18c713823719c9876a9824ba4bd0ba5c41cc07be Mon Sep 17 00:00:00 2001 +From: Matthias Clasen +Date: Thu, 24 Sep 2015 13:31:07 -0400 +Subject: [PATCH 3/3] Check error of g_dbus_proxy_new_sync call + +Otherwise errors pile up and we crash later on. +--- + src/main.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/main.c b/src/main.c +index b33d4bf..e8ac998 100644 +--- a/src/main.c ++++ b/src/main.c +@@ -132,6 +132,12 @@ shell_dbus_init (gboolean replace) + NULL, /* cancellable */ + &error); + ++ if (!bus) ++ { ++ g_printerr ("Failed to get a session bus proxy: %s", error->message); ++ exit (1); ++ } ++ + request_name_flags = G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT; + if (replace) + request_name_flags |= DBUS_NAME_FLAG_REPLACE_EXISTING; +-- +2.5.3 + diff --git a/SOURCES/0003-screencast-Validate-parameters-of-ScreencastArea.patch b/SOURCES/0003-screencast-Validate-parameters-of-ScreencastArea.patch deleted file mode 100644 index e562fd1..0000000 --- a/SOURCES/0003-screencast-Validate-parameters-of-ScreencastArea.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 9712b5f8ce73aa40f74c33108cca12c35b50aee8 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Mon, 4 Nov 2013 14:09:19 +0100 -Subject: [PATCH 3/3] screencast: Validate parameters of ScreencastArea - -... just as we do for screenshots. - -https://bugzilla.gnome.org/show_bug.cgi?id=699752 ---- - js/ui/screencast.js | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/js/ui/screencast.js b/js/ui/screencast.js -index 7d8d767..168f589 100644 ---- a/js/ui/screencast.js -+++ b/js/ui/screencast.js -@@ -127,6 +127,16 @@ const ScreencastService = new Lang.Class({ - if (!recorder.is_recording()) { - let [x, y, width, height, fileTemplate, options] = params; - -+ if (x < 0 || y < 0 || -+ width <= 0 || height <= 0 || -+ x + width > global.screen_width || -+ y + height > global.screen_height) { -+ invocation.return_error_literal(Gio.IOErrorEnum, -+ Gio.IOErrorEnum.CANCELLED, -+ "Invalid params"); -+ return; -+ } -+ - recorder.set_file_template(fileTemplate); - recorder.set_area(x, y, width, height); - this._applyOptionalParameters(recorder, options); --- -1.8.4.2 - diff --git a/SOURCES/disable-unlock-entry-until-question.patch b/SOURCES/disable-unlock-entry-until-question.patch new file mode 100644 index 0000000..9872e71 --- /dev/null +++ b/SOURCES/disable-unlock-entry-until-question.patch @@ -0,0 +1,609 @@ +From 68c280c3bcf8a67a90eb25c30b2e6c2493d7d4d9 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Wed, 30 Sep 2015 12:47:01 -0400 +Subject: [PATCH 1/4] authPrompt: use correct service name when answering + preemptively + +If the user hits enter before a question is asked, we try to answer +that question as soon as it comes in. + +This doesn't work right now because we only answer the question if +there's a query service, but there won't ever be one until the +question is asked. + +This commit corrects the code to it's intention, which is to answer +the first service that asks a question, as as soon as possible. +--- + js/gdm/authPrompt.js | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js +index 34ad7fb..816c69c 100644 +--- a/js/gdm/authPrompt.js ++++ b/js/gdm/authPrompt.js +@@ -167,62 +167,61 @@ const AuthPrompt = new Lang.Class({ + can_focus: true, + label: _("Next") }); + this.nextButton.connect('clicked', + Lang.bind(this, function() { + this.emit('next'); + })); + this.nextButton.add_style_pseudo_class('default'); + this._buttonBox.add(this.nextButton, + { expand: false, + x_fill: false, + y_fill: false, + x_align: St.Align.END, + y_align: St.Align.END }); + + this._updateNextButtonSensitivity(this._entry.text.length > 0); + + this._entry.clutter_text.connect('text-changed', + Lang.bind(this, function() { + if (!this._userVerifier.hasPendingMessages) + this._fadeOutMessage(); + + this._updateNextButtonSensitivity(this._entry.text.length > 0); + })); + this._entry.clutter_text.connect('activate', Lang.bind(this, function() { + this.emit('next'); + })); + }, + + _onAskQuestion: function(verifier, serviceName, question, passwordChar) { + if (this._preemptiveAnswer) { +- if (this._queryingService) +- this._userVerifier.answerQuery(this._queryingService, this._preemptiveAnswer); ++ this._userVerifier.answerQuery(serviceName, this._preemptiveAnswer); + this._preemptiveAnswer = null; + return; + } + + if (this._queryingService) + this.clear(); + + this._queryingService = serviceName; + this.setPasswordChar(passwordChar); + this.setQuestion(question); + + if (passwordChar) { + if (this._userVerifier.reauthenticating) + this.nextButton.label = _("Unlock"); + else + this.nextButton.label = C_("button", "Sign In"); + } else { + this.nextButton.label = _("Next"); + } + + this.updateSensitivity(true); + this.emit('prompted'); + }, + + _onOVirtUserAuthenticated: function() { + if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) + this.reset(); + }, + + _onSmartcardStatusChanged: function() { +-- +2.5.0 + + +From 1b7fa7ad6874208873eb8ce1e8b03dc07cb01217 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Wed, 30 Sep 2015 12:51:24 -0400 +Subject: [PATCH 2/4] authPrompt: don't fade out auth messages if user types + password up front + +Right now we fade out any stale auth messages as soon as the user starts +typing. This behavior doesn't really make sense if the user is typing up +front, before a password is asked. +--- + 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 816c69c..11b6a23 100644 +--- a/js/gdm/authPrompt.js ++++ b/js/gdm/authPrompt.js +@@ -155,61 +155,61 @@ const AuthPrompt = new Lang.Class({ + x_align: St.Align.START, + y_align: St.Align.END }); + + this._buttonBox.add(this._defaultButtonWell, + { expand: true, + x_fill: false, + y_fill: false, + x_align: St.Align.END, + y_align: St.Align.MIDDLE }); + this.nextButton = new St.Button({ style_class: 'modal-dialog-button', + button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, + reactive: true, + can_focus: true, + label: _("Next") }); + this.nextButton.connect('clicked', + Lang.bind(this, function() { + this.emit('next'); + })); + this.nextButton.add_style_pseudo_class('default'); + this._buttonBox.add(this.nextButton, + { expand: false, + x_fill: false, + y_fill: false, + x_align: St.Align.END, + y_align: St.Align.END }); + + this._updateNextButtonSensitivity(this._entry.text.length > 0); + + this._entry.clutter_text.connect('text-changed', + Lang.bind(this, function() { +- if (!this._userVerifier.hasPendingMessages) ++ if (!this._userVerifier.hasPendingMessages && this._queryingService && !this._preemptiveAnswer) + this._fadeOutMessage(); + + this._updateNextButtonSensitivity(this._entry.text.length > 0); + })); + this._entry.clutter_text.connect('activate', Lang.bind(this, function() { + this.emit('next'); + })); + }, + + _onAskQuestion: function(verifier, serviceName, question, passwordChar) { + if (this._preemptiveAnswer) { + this._userVerifier.answerQuery(serviceName, this._preemptiveAnswer); + this._preemptiveAnswer = null; + return; + } + + if (this._queryingService) + this.clear(); + + this._queryingService = serviceName; + this.setPasswordChar(passwordChar); + this.setQuestion(question); + + if (passwordChar) { + if (this._userVerifier.reauthenticating) + this.nextButton.label = _("Unlock"); + else + this.nextButton.label = C_("button", "Sign In"); + } else { + this.nextButton.label = _("Next"); +-- +2.5.0 + + +From 3b767c0a55b136b53b7c85aff2095969fb230ce4 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Wed, 30 Sep 2015 14:36:33 -0400 +Subject: [PATCH 3/4] authPrompt: don't spin unless answering question + +--- + 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 11b6a23..875f9c5 100644 +--- a/js/gdm/authPrompt.js ++++ b/js/gdm/authPrompt.js +@@ -37,62 +37,62 @@ const BeginRequestType = { + }; + + const AuthPrompt = new Lang.Class({ + Name: 'AuthPrompt', + + _init: function(gdmClient, mode) { + this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; + + this._gdmClient = gdmClient; + this._mode = mode; + + let reauthenticationOnly; + if (this._mode == AuthPromptMode.UNLOCK_ONLY) + reauthenticationOnly = true; + else if (this._mode == AuthPromptMode.UNLOCK_OR_LOG_IN) + reauthenticationOnly = false; + + this._userVerifier = new GdmUtil.ShellUserVerifier(this._gdmClient, { reauthenticationOnly: reauthenticationOnly }); + + this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion)); + this._userVerifier.connect('show-message', Lang.bind(this, this._onShowMessage)); + this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed)); + this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); + this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); + this._userVerifier.connect('smartcard-status-changed', Lang.bind(this, this._onSmartcardStatusChanged)); + this._userVerifier.connect('ovirt-user-authenticated', Lang.bind(this, this._onOVirtUserAuthenticated)); + this.smartcardDetected = this._userVerifier.smartcardDetected; + + this.connect('next', Lang.bind(this, function() { + this.updateSensitivity(false); +- this.startSpinning(); + if (this._queryingService) { ++ this.startSpinning(); + this._userVerifier.answerQuery(this._queryingService, this._entry.text); + } else { + this._preemptiveAnswer = this._entry.text; + } + })); + + this.actor = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', + vertical: true }); + this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); + this.actor.connect('key-press-event', + Lang.bind(this, function(actor, event) { + if (event.get_key_symbol() == Clutter.KEY_Escape) { + this.cancel(); + } + return Clutter.EVENT_PROPAGATE; + })); + + this._userWell = new St.Bin({ x_fill: true, + x_align: St.Align.START }); + this.actor.add(this._userWell, + { x_align: St.Align.START, + x_fill: true, + y_fill: true, + expand: true }); + this._label = new St.Label({ style_class: 'login-dialog-prompt-label' }); + + this.actor.add(this._label, + { expand: true, + x_fill: false, + y_fill: true, +-- +2.5.0 + + +From 22d618c293906defbac877925491af13f8def9a3 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Mon, 5 Oct 2015 15:26:18 -0400 +Subject: [PATCH 4/4] authPrompt: stop accepting preemptive answer if user stops + typing + +We only want to allow the user to type the preemptive password in +one smooth motion. If they start to type, and then stop typing, +we should discard their preemptive password as expired. + +Typing ahead the password is just a convenience for users who don't +want to manually lift the shift before typing their passwords, after +all. +--- + js/gdm/authPrompt.js | 38 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 38 insertions(+) + +diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js +index 875f9c5..fe80519 100644 +--- a/js/gdm/authPrompt.js ++++ b/js/gdm/authPrompt.js +@@ -1,101 +1,109 @@ + // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + + const Clutter = imports.gi.Clutter; + const Lang = imports.lang; + const Signals = imports.signals; + const St = imports.gi.St; + + const Animation = imports.ui.animation; + const Batch = imports.gdm.batch; + const GdmUtil = imports.gdm.util; ++const Meta = imports.gi.Meta; + const Params = imports.misc.params; + const ShellEntry = imports.ui.shellEntry; + const Tweener = imports.ui.tweener; + const UserWidget = imports.ui.userWidget; + + const DEFAULT_BUTTON_WELL_ICON_SIZE = 24; + const DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0; + const DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3; + + const MESSAGE_FADE_OUT_ANIMATION_TIME = 0.5; + + const AuthPromptMode = { + UNLOCK_ONLY: 0, + UNLOCK_OR_LOG_IN: 1 + }; + + const AuthPromptStatus = { + NOT_VERIFYING: 0, + VERIFYING: 1, + VERIFICATION_FAILED: 2, + VERIFICATION_SUCCEEDED: 3 + }; + + const BeginRequestType = { + PROVIDE_USERNAME: 0, + DONT_PROVIDE_USERNAME: 1 + }; + + const AuthPrompt = new Lang.Class({ + Name: 'AuthPrompt', + + _init: function(gdmClient, mode) { + this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; + + this._gdmClient = gdmClient; + this._mode = mode; + ++ this._idleMonitor = Meta.IdleMonitor.get_core(); ++ + let reauthenticationOnly; + if (this._mode == AuthPromptMode.UNLOCK_ONLY) + reauthenticationOnly = true; + else if (this._mode == AuthPromptMode.UNLOCK_OR_LOG_IN) + reauthenticationOnly = false; + + this._userVerifier = new GdmUtil.ShellUserVerifier(this._gdmClient, { reauthenticationOnly: reauthenticationOnly }); + + this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion)); + this._userVerifier.connect('show-message', Lang.bind(this, this._onShowMessage)); + this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed)); + this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); + this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); + this._userVerifier.connect('smartcard-status-changed', Lang.bind(this, this._onSmartcardStatusChanged)); + this._userVerifier.connect('ovirt-user-authenticated', Lang.bind(this, this._onOVirtUserAuthenticated)); + this.smartcardDetected = this._userVerifier.smartcardDetected; + + this.connect('next', Lang.bind(this, function() { + this.updateSensitivity(false); + if (this._queryingService) { + this.startSpinning(); + this._userVerifier.answerQuery(this._queryingService, this._entry.text); + } else { + this._preemptiveAnswer = this._entry.text; ++ ++ if (this._preemptiveAnswerWatchId) { ++ this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId); ++ this._preemptiveAnswerWatchId = 0; ++ } + } + })); + + this.actor = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', + vertical: true }); + this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); + this.actor.connect('key-press-event', + Lang.bind(this, function(actor, event) { + if (event.get_key_symbol() == Clutter.KEY_Escape) { + this.cancel(); + } + return Clutter.EVENT_PROPAGATE; + })); + + this._userWell = new St.Bin({ x_fill: true, + x_align: St.Align.START }); + this.actor.add(this._userWell, + { x_align: St.Align.START, + x_fill: true, + y_fill: true, + expand: true }); + this._label = new St.Label({ style_class: 'login-dialog-prompt-label' }); + + this.actor.add(this._label, + { expand: true, + x_fill: false, + y_fill: true, + x_align: St.Align.START }); + this._entry = new St.Entry({ style_class: 'login-dialog-prompt-entry', + can_focus: true }); +@@ -107,60 +115,65 @@ const AuthPrompt = new Lang.Class({ + y_fill: false, + x_align: St.Align.START }); + + this._entry.grab_key_focus(); + + this._message = new St.Label({ opacity: 0, + styleClass: 'login-dialog-message' }); + this._message.clutter_text.line_wrap = true; + this.actor.add(this._message, { x_fill: false, x_align: St.Align.START, y_align: St.Align.START }); + + this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box', + vertical: false }); + this.actor.add(this._buttonBox, + { expand: true, + x_align: St.Align.MIDDLE, + y_align: St.Align.END }); + + this._defaultButtonWell = new St.Widget({ layout_manager: new Clutter.BinLayout() }); + this._defaultButtonWellActor = null; + + this._initButtons(); + + let spinnerIcon = global.datadir + '/theme/process-working.svg'; + this._spinner = new Animation.AnimatedIcon(spinnerIcon, DEFAULT_BUTTON_WELL_ICON_SIZE); + this._spinner.actor.opacity = 0; + this._spinner.actor.show(); + this._defaultButtonWell.add_child(this._spinner.actor); + }, + + _onDestroy: function() { ++ if (this._preemptiveAnswerWatchId) { ++ this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId); ++ this._preemptiveAnswerWatchId = 0; ++ } ++ + this._userVerifier.destroy(); + this._userVerifier = null; + }, + + _initButtons: function() { + this.cancelButton = new St.Button({ style_class: 'modal-dialog-button', + button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, + reactive: true, + can_focus: true, + label: _("Cancel") }); + this.cancelButton.connect('clicked', + Lang.bind(this, function() { + this.cancel(); + })); + this._buttonBox.add(this.cancelButton, + { expand: false, + x_fill: false, + y_fill: false, + x_align: St.Align.START, + y_align: St.Align.END }); + + this._buttonBox.add(this._defaultButtonWell, + { expand: true, + x_fill: false, + y_fill: false, + x_align: St.Align.END, + y_align: St.Align.MIDDLE }); + this.nextButton = new St.Button({ style_class: 'modal-dialog-button', + button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, + reactive: true, +@@ -316,60 +329,65 @@ const AuthPrompt = new Lang.Class({ + else + Tweener.addTween(actor, + { opacity: 255, + time: DEFAULT_BUTTON_WELL_ANIMATION_TIME, + delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY, + transition: 'linear' }); + } + + this._defaultButtonWellActor = actor; + }, + + startSpinning: function() { + this.setActorInDefaultButtonWell(this._spinner.actor, true); + }, + + stopSpinning: function() { + this.setActorInDefaultButtonWell(null, false); + }, + + clear: function() { + this._entry.text = ''; + this.stopSpinning(); + }, + + setPasswordChar: function(passwordChar) { + this._entry.clutter_text.set_password_char(passwordChar); + this._entry.menu.isPassword = passwordChar != ''; + }, + + setQuestion: function(question) { ++ if (this._preemptiveAnswerWatchId) { ++ this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId); ++ this._preemptiveAnswerWatchId = 0; ++ } ++ + this._label.set_text(question); + + this._label.show(); + this._entry.show(); + + this._entry.grab_key_focus(); + }, + + getAnswer: function() { + let text; + + if (this._preemptiveAnswer) { + text = this._preemptiveAnswer; + this._preemptiveAnswer = null; + } else { + text = this._entry.get_text(); + } + + return text; + }, + + _fadeOutMessage: function() { + if (this._message.opacity == 0) + return; + Tweener.removeTweens(this._message); + Tweener.addTween(this._message, + { opacity: 0, + time: MESSAGE_FADE_OUT_ANIMATION_TIME, + transition: 'easeOutQuad' + }); +@@ -401,66 +419,86 @@ const AuthPrompt = new Lang.Class({ + }, + + updateSensitivity: function(sensitive) { + this._updateNextButtonSensitivity(sensitive && this._entry.text.length > 0); + this._entry.reactive = sensitive; + this._entry.clutter_text.editable = sensitive; + }, + + hide: function() { + this.setActorInDefaultButtonWell(null, true); + this.actor.hide(); + this._message.opacity = 0; + + this.setUser(null); + + this.updateSensitivity(true); + this._entry.set_text(''); + }, + + setUser: function(user) { + let oldChild = this._userWell.get_child(); + if (oldChild) + oldChild.destroy(); + + if (user) { + let userWidget = new UserWidget.UserWidget(user); + this._userWell.set_child(userWidget.actor); + } + }, + ++ _onUserStoppedTypePreemptiveAnswer: function() { ++ if (!this._preemptiveAnswerWatchId || ++ this._preemptiveAnswer || ++ this._queryingService) ++ return; ++ ++ this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId); ++ this._preemptiveAnswerWatchId = 0; ++ ++ this._entry.text = ''; ++ this.updateSensitivity(false); ++ }, ++ + reset: function() { + let oldStatus = this.verificationStatus; + this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; + this.cancelButton.reactive = true; + this.nextButton.label = _("Next"); + ++ if (this._preemptiveAnswerWatchId) { ++ this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId); ++ } ++ this._preemptiveAnswerWatchId = this._idleMonitor.add_idle_watch (500, ++ Lang.bind(this, ++ this._onUserStoppedTypePreemptiveAnswer)); ++ + if (this._userVerifier) + this._userVerifier.cancel(); + + this._queryingService = null; + this.clear(); + this._message.opacity = 0; + this.setUser(null); + this.stopSpinning(); + + if (oldStatus == AuthPromptStatus.VERIFICATION_FAILED) + this.emit('failed'); + + let beginRequestType; + + if (this._mode == AuthPromptMode.UNLOCK_ONLY) { + // The user is constant at the unlock screen, so it will immediately + // respond to the request with the username + beginRequestType = BeginRequestType.PROVIDE_USERNAME; + } else if (this._userVerifier.serviceIsForeground(GdmUtil.OVIRT_SERVICE_NAME) || + this._userVerifier.serviceIsForeground(GdmUtil.SMARTCARD_SERVICE_NAME)) { + // We don't need to know the username if the user preempted the login screen + // with a smartcard or with preauthenticated oVirt credentials + beginRequestType = BeginRequestType.DONT_PROVIDE_USERNAME; + } else { + // In all other cases, we should get the username up front. + beginRequestType = BeginRequestType.PROVIDE_USERNAME; + } + + this.emit('reset', beginRequestType); + }, +-- +2.5.0 + diff --git a/SOURCES/disallow-cancel-after-success.patch b/SOURCES/disallow-cancel-after-success.patch deleted file mode 100644 index e02d39a..0000000 --- a/SOURCES/disallow-cancel-after-success.patch +++ /dev/null @@ -1,185 +0,0 @@ -From 6dd24af0a881aa7440f127036f42d8f521628c24 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Sun, 5 Oct 2014 16:27:00 -0400 -Subject: [PATCH] gdm: disallow cancel after verification succeeds - -Once verification has succeeded, the train's already -left the building and we shouldn't allow canceling. - -This commit renders the cancel button non-reactive -and makes the cancel function be a noop after -verification succeeds. ---- - js/gdm/authPrompt.js | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index fd02c4d..d82b2b2 100644 ---- a/js/gdm/authPrompt.js -+++ b/js/gdm/authPrompt.js -@@ -232,60 +232,61 @@ const AuthPrompt = new Lang.Class({ - // a smartcard. Smartcard insertion "preempts" what the user was - // doing, and smartcard removal aborts the preemption. - // The exceptions are: 1) Don't reset on smartcard insertion if we're already verifying - // with a smartcard - // 2) Don't reset if we've already succeeded at verification and - // the user is getting logged in. - if (this._userVerifier.serviceIsDefault(GdmUtil.SMARTCARD_SERVICE_NAME) && - this.verificationStatus == AuthPromptStatus.VERIFYING && - this.smartcardDetected) - return; - - if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) - this.reset(); - }, - - _onShowMessage: function(userVerifier, message, type) { - this.setMessage(message, type); - this.emit('prompted'); - }, - - _onVerificationFailed: function() { - this.clear(); - - this.updateSensitivity(true); - this.setActorInDefaultButtonWell(null); - this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED; - }, - - _onVerificationComplete: function() { - this.verificationStatus = AuthPromptStatus.VERIFICATION_SUCCEEDED; -+ this.cancelButton.reactive = false; - }, - - _onReset: function() { - if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) { - this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; - this.reset(); - } - }, - - addActorToDefaultButtonWell: function(actor) { - this._defaultButtonWell.add_child(actor); - }, - - setActorInDefaultButtonWell: function(actor, animate) { - if (!this._defaultButtonWellActor && - !actor) - return; - - let oldActor = this._defaultButtonWellActor; - - if (oldActor) - Tweener.removeTweens(oldActor); - - let isSpinner; - if (actor == this._spinner.actor) - isSpinner = true; - else - isSpinner = false; - - if (this._defaultButtonWellActor != actor && oldActor) { -@@ -403,60 +404,61 @@ const AuthPrompt = new Lang.Class({ - - updateSensitivity: function(sensitive) { - this._updateNextButtonSensitivity(sensitive); - this._entry.reactive = sensitive; - this._entry.clutter_text.editable = sensitive; - }, - - hide: function() { - this.setActorInDefaultButtonWell(null, true); - this.actor.hide(); - this._message.opacity = 0; - - this.setUser(null); - - this.updateSensitivity(true); - this._entry.set_text(''); - }, - - setUser: function(user) { - if (user) { - let userWidget = new UserWidget.UserWidget(user); - this._userWell.set_child(userWidget.actor); - } else { - this._userWell.set_child(null); - } - }, - - reset: function() { - let oldStatus = this.verificationStatus; - this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; -+ this.cancelButton.reactive = true; - - if (oldStatus == AuthPromptStatus.VERIFYING) - this._userVerifier.cancel(); - - this._queryingService = null; - this.clear(); - this._message.opacity = 0; - this.setUser(null); - this.stopSpinning(); - - if (oldStatus == AuthPromptStatus.VERIFICATION_FAILED) - this.emit('failed'); - - let beginRequestType; - - if (this._mode == AuthPromptMode.UNLOCK_ONLY) { - // The user is constant at the unlock screen, so it will immediately - // respond to the request with the username - beginRequestType = BeginRequestType.PROVIDE_USERNAME; - } else if (this._userVerifier.serviceIsForeground(GdmUtil.OVIRT_SERVICE_NAME) || - this._userVerifier.serviceIsForeground(GdmUtil.SMARTCARD_SERVICE_NAME)) { - // We don't need to know the username if the user preempted the login screen - // with a smartcard or with preauthenticated oVirt credentials - beginRequestType = BeginRequestType.DONT_PROVIDE_USERNAME; - } else { - // In all other cases, we should get the username up front. - beginRequestType = BeginRequestType.PROVIDE_USERNAME; - } - - this.emit('reset', beginRequestType); -@@ -472,35 +474,38 @@ const AuthPrompt = new Lang.Class({ - }, - - begin: function(params) { - params = Params.parse(params, { userName: null, - hold: null }); - - this.updateSensitivity(false); - - let hold = params.hold; - if (!hold) - hold = new Batch.Hold(); - - this._userVerifier.begin(params.userName, hold); - this.verificationStatus = AuthPromptStatus.VERIFYING; - }, - - finish: function(onComplete) { - if (!this._userVerifier.hasPendingMessages) { - onComplete(); - return; - } - - let signalId = this._userVerifier.connect('no-more-messages', - Lang.bind(this, function() { - this._userVerifier.disconnect(signalId); - onComplete(); - })); - }, - - cancel: function() { -+ if (this.verificationStatus == AuthPromptStatus.NOT_VERIFYING || this.verificationStatus == AuthPromptStatus.VERIFICATION_SUCCEEDED) { -+ return; -+ } - this.reset(); - this.emit('cancelled'); - } - }); - Signals.addSignalMethods(AuthPrompt.prototype); --- -2.1.0 - diff --git a/SOURCES/dont-load-user-list-when-disabled.patch b/SOURCES/dont-load-user-list-when-disabled.patch deleted file mode 100644 index 260b9ac..0000000 --- a/SOURCES/dont-load-user-list-when-disabled.patch +++ /dev/null @@ -1,130 +0,0 @@ -From c23b174119abf62fec5c05b461cc3c5a7ec4bc08 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Fri, 7 Mar 2014 16:16:20 +0100 -Subject: [PATCH 1/2] loginDialog: Add missing return value - -_loadUserList() may be used as idle handler, so we should explicitly -return a boolean. - -https://bugzilla.gnome.org/show_bug.cgi?id=725905 ---- - js/gdm/loginDialog.js | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index ee0199c..98dd7b2 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -940,6 +940,8 @@ const LoginDialog = new Lang.Class({ - Lang.bind(this, function(userManager, user) { - this._userList.removeUser(user); - })); -+ -+ return false; - }, - - open: function() { --- -1.9.0 - - -From 5517e6bdbbc42347e03068d823dd215e9c86eb4d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Sat, 8 Mar 2014 00:05:24 +0100 -Subject: [PATCH 2/2] loginDialog: Defer loading user list until needed - -Loading the user list can be expensive, for instance when there is -a large number of users and/or their avatars have to be fetched over -the network. In case the user list is disabled anyway, there is no -point in doing that work just to hide it, so stop doing that. - -https://bugzilla.gnome.org/show_bug.cgi?id=725905 ---- - js/gdm/loginDialog.js | 44 +++++++++++++++++++++++++++++--------------- - 1 file changed, 29 insertions(+), 15 deletions(-) - -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index 98dd7b2..b4487e6 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -520,18 +520,6 @@ const LoginDialog = new Lang.Class({ - 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 -- GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, this._loadUserList)); -- - this._userList.connect('activate', - Lang.bind(this, function(userList, item) { - this._onUserListActivated(item); -@@ -547,7 +535,29 @@ const LoginDialog = new Lang.Class({ - 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() { -+ 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); -@@ -880,6 +890,7 @@ const LoginDialog = new Lang.Class({ - }, - - _showUserList: function() { -+ this._ensureUserListLoaded(); - this._authPrompt.hide(); - this._sessionMenuButton.close(); - this._setUserListExpanded(true); -@@ -923,14 +934,17 @@ const LoginDialog = new Lang.Class({ - }, - - _loadUserList: function() { -+ if (this._userListLoaded) -+ return false; -+ -+ this._userListLoaded = true; -+ - let users = this._userManager.list_users(); - - for (let i = 0; i < users.length; i++) { - this._userList.addUser(users[i]); - } - -- this._updateDisableUserList(); -- - this._userManager.connect('user-added', - Lang.bind(this, function(userManager, user) { - this._userList.addUser(user); --- -1.9.0 - diff --git a/SOURCES/drop-gsystem-dependency.patch b/SOURCES/drop-gsystem-dependency.patch new file mode 100644 index 0000000..ebbd050 --- /dev/null +++ b/SOURCES/drop-gsystem-dependency.patch @@ -0,0 +1,159 @@ +From 61233d3703071993a1505570de765d8ef1bf7ee2 Mon Sep 17 00:00:00 2001 +From: Colin Walters +Date: Fri, 13 Feb 2015 04:27:27 -0500 +Subject: [PATCH 1/2] Drop use of libgsystem, move single API call into + shell-global.c + +See https://mail.gnome.org/archives/desktop-devel-list/2015-February/msg00121.html + +We presently only indirectly link to it via this one call; until GLib +gains structured logging, simply import the code to wrap the journal +logging in an introspectable API into Shell. + +https://bugzilla.gnome.org/show_bug.cgi?id=744457 +--- + js/ui/main.js | 12 +++--------- + src/shell-global.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + src/shell-global.h | 3 +++ + 3 files changed, 58 insertions(+), 9 deletions(-) + +diff --git a/js/ui/main.js b/js/ui/main.js +index 2459069..45df8b4 100644 +--- a/js/ui/main.js ++++ b/js/ui/main.js +@@ -208,16 +208,10 @@ function _initializeUI() { + if (screenShield) { + screenShield.lockIfWasLocked(); + } +- if (LoginManager.haveSystemd() && +- sessionMode.currentMode != 'gdm' && ++ if (sessionMode.currentMode != 'gdm' && + sessionMode.currentMode != 'initial-setup') { +- // Do not import globally to not depend +- // on systemd on non-systemd systems. +- let GSystem = imports.gi.GSystem; +- GSystem.log_structured_print('GNOME Shell started at ' + _startDate, +- ['MESSAGE_ID=' + GNOMESHELL_STARTED_MESSAGE_ID]); +- } else { +- log('GNOME Shell started at ' + _startDate); ++ Shell.log_structured_print('GNOME Shell started at ' + _startDate, ++ ['MESSAGE_ID=' + GNOMESHELL_STARTED_MESSAGE_ID]); + } + }); + } +diff --git a/src/shell-global.c b/src/shell-global.c +index d90ceaf..3a27f31 100644 +--- a/src/shell-global.c ++++ b/src/shell-global.c +@@ -28,6 +28,12 @@ + #include + #include + ++#ifdef HAVE_SYSTEMD ++#include ++#include ++#include ++#endif ++ + /* Memory report bits */ + #ifdef HAVE_MALLINFO + #include +@@ -1307,6 +1313,52 @@ shell_global_reexec_self (ShellGlobal *global) + } + + /** ++ * shell_global_log_structured: ++ * @message: A message to print ++ * @keys: (allow-none) (array zero-terminated=1) (element-type utf8): Optional structured data ++ * ++ * Log structured data in an operating-system specific fashion. The ++ * parameter @opts should be an array of UTF-8 KEY=VALUE strings. ++ * This function does not support binary data. See ++ * http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html ++ * or more information about fields that can be used on a systemd ++ * system. ++ * ++ */ ++void ++shell_global_log_structured (const char *message, ++ const char *const *keys) ++{ ++#ifdef HAVE_SYSTEMD ++ const char *const*iter; ++ char *msgkey; ++ guint i, n_opts; ++ struct iovec *iovs; ++ ++ for (n_opts = 0, iter = keys; *iter; iter++, n_opts++) ++ ; ++ ++ n_opts++; /* Add one for MESSAGE= */ ++ iovs = g_alloca (sizeof (struct iovec) * n_opts); ++ ++ for (i = 0, iter = keys; *iter; iter++, i++) { ++ iovs[i].iov_base = (char*)keys[i]; ++ iovs[i].iov_len = strlen (keys[i]); ++ } ++ g_assert(i == n_opts-1); ++ msgkey = g_strconcat ("MESSAGE=", message, NULL); ++ iovs[i].iov_base = msgkey; ++ iovs[i].iov_len = strlen (msgkey); ++ ++ // The code location isn't useful since we're wrapping ++ sd_journal_sendv (iovs, n_opts); ++ g_free (msgkey); ++#else ++ g_print ("%s\n", message); ++#endif ++} ++ ++/** + * shell_global_notify_error: + * @global: a #ShellGlobal + * @msg: Error message +diff --git a/src/shell-global.h b/src/shell-global.h +index a5630ec..25afe17 100644 +--- a/src/shell-global.h ++++ b/src/shell-global.h +@@ -126,6 +126,9 @@ void shell_global_init_xdnd (ShellGlobal *global); + + void shell_global_reexec_self (ShellGlobal *global); + ++void shell_global_log_structured (const char *message, ++ const char *const *keys); ++ + const char * shell_global_get_session_mode (ShellGlobal *global); + + void shell_global_set_runtime_state (ShellGlobal *global, +-- +2.3.6 + + +From 1fe15cf0dbd98afb7b1084c5556f6b6b9a0e62f8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Fri, 13 Feb 2015 23:02:06 +0100 +Subject: [PATCH 2/2] main: Fix structured_log() call + +Meh, I should have caught that one in review ... +--- + js/ui/main.js | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/js/ui/main.js b/js/ui/main.js +index 45df8b4..6865c41 100644 +--- a/js/ui/main.js ++++ b/js/ui/main.js +@@ -210,8 +210,8 @@ function _initializeUI() { + } + if (sessionMode.currentMode != 'gdm' && + sessionMode.currentMode != 'initial-setup') { +- Shell.log_structured_print('GNOME Shell started at ' + _startDate, +- ['MESSAGE_ID=' + GNOMESHELL_STARTED_MESSAGE_ID]); ++ Shell.Global.log_structured('GNOME Shell started at ' + _startDate, ++ ['MESSAGE_ID=' + GNOMESHELL_STARTED_MESSAGE_ID]); + } + }); + } +-- +2.3.6 + diff --git a/SOURCES/enforce-smartcard-at-unlock.patch b/SOURCES/enforce-smartcard-at-unlock.patch new file mode 100644 index 0000000..e28cb1f --- /dev/null +++ b/SOURCES/enforce-smartcard-at-unlock.patch @@ -0,0 +1,308 @@ +From d1aaebbb268df2f53f909028d9ae83c1849db103 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Mon, 28 Sep 2015 10:57:02 -0400 +Subject: [PATCH 1/3] smartcardManager: add way to detect if user logged using + (any) token + +If a user uses a token at login time, we need to make sure they continue +to use the token at unlock time. + +As a prerequisite for addressing that problem we need to know up front +if a user logged in with a token at all. + +This commit adds the necessary api to detect that case. +--- + js/misc/smartcardManager.js | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/js/misc/smartcardManager.js b/js/misc/smartcardManager.js +index 674efc9..bfe8a26 100644 +--- a/js/misc/smartcardManager.js ++++ b/js/misc/smartcardManager.js +@@ -86,34 +86,41 @@ const SmartcardManager = new Lang.Class({ + if (token.IsInserted) + this.emit('smartcard-inserted', token); + }, + + _removeToken: function(token) { + let objectPath = token.get_object_path(); + + if (this._insertedTokens[objectPath] == token) { + delete this._insertedTokens[objectPath]; + this.emit('smartcard-removed', token); + } + + if (this._loginToken == token) + this._loginToken = null; + + token.disconnectAll(); + }, + + hasInsertedTokens: function() { + return Object.keys(this._insertedTokens).length > 0; + }, + + hasInsertedLoginToken: function() { + if (!this._loginToken) + return false; + + if (!this._loginToken.IsInserted) + return false; + + return true; ++ }, ++ ++ loggedInWithToken: function() { ++ if (this._loginToken) ++ return true; ++ ++ return false; + } + + }); + Signals.addSignalMethods(SmartcardManager.prototype); +-- +2.5.0 + + +From 090c0f85b01e95d953b287f21d8aa33335a014c1 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Mon, 28 Sep 2015 19:56:53 -0400 +Subject: [PATCH 2/3] gdm: only unlock with smartcard, if smartcard used for + login + +If a smartcard is used for login, we need to make sure the smartcard +gets used for unlock, too. +--- + js/gdm/util.js | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/js/gdm/util.js b/js/gdm/util.js +index dd04544..776b76d 100644 +--- a/js/gdm/util.js ++++ b/js/gdm/util.js +@@ -104,71 +104,72 @@ function cloneAndFadeOutActor(actor) { + Main.uiGroup.add_child(clone); + + let [x, y] = actor.get_transformed_position(); + clone.set_position(x, y); + + let hold = new Batch.Hold(); + Tweener.addTween(clone, + { opacity: 0, + time: CLONE_FADE_ANIMATION_TIME, + transition: 'easeOutQuad', + onComplete: function() { + clone.destroy(); + hold.release(); + } + }); + return hold; + } + + const ShellUserVerifier = new Lang.Class({ + Name: 'ShellUserVerifier', + + _init: function(client, params) { + params = Params.parse(params, { reauthenticationOnly: false }); + this._reauthOnly = params.reauthenticationOnly; + + this._client = client; + + this._settings = new Gio.Settings({ schema_id: LOGIN_SCREEN_SCHEMA }); + this._settings.connect('changed', + Lang.bind(this, this._updateDefaultService)); +- this._updateDefaultService(); + + this._fprintManager = new Fprint.FprintManager(); + this._smartcardManager = SmartcardManager.getSmartcardManager(); + + // We check for smartcards right away, since an inserted smartcard + // at startup should result in immediately initiating authentication. + // This is different than fingeprint readers, where we only check them + // after a user has been picked. + this._checkForSmartcard(); + ++ this._updateDefaultService(); ++ + this._smartcardInsertedId = this._smartcardManager.connect('smartcard-inserted', + Lang.bind(this, this._checkForSmartcard)); + this._smartcardRemovedId = this._smartcardManager.connect('smartcard-removed', + Lang.bind(this, this._checkForSmartcard)); + + this._messageQueue = []; + this._messageQueueTimeoutId = 0; + this.hasPendingMessages = false; + this.reauthenticating = false; + + this._failCounter = 0; + + this._oVirtCredentialsManager = OVirt.getOVirtCredentialsManager(); + + if (this._oVirtCredentialsManager.hasToken()) + this._oVirtUserAuthenticated(this._oVirtCredentialsManager.getToken()); + + this._oVirtUserAuthenticatedId = this._oVirtCredentialsManager.connect('user-authenticated', + Lang.bind(this, this._oVirtUserAuthenticated)); + }, + + begin: function(userName, hold) { + this._cancellable = new Gio.Cancellable(); + this._hold = hold; + this._userName = userName; + this.reauthenticating = false; + + this._checkForFingerprintReader(); + + if (userName) { +@@ -381,61 +382,63 @@ const ShellUserVerifier = new Lang.Class({ + this._beginVerification(); + this._hold.release(); + }, + + _connectSignals: function() { + this._userVerifier.connect('info', Lang.bind(this, this._onInfo)); + this._userVerifier.connect('problem', Lang.bind(this, this._onProblem)); + this._userVerifier.connect('info-query', Lang.bind(this, this._onInfoQuery)); + this._userVerifier.connect('secret-info-query', Lang.bind(this, this._onSecretInfoQuery)); + this._userVerifier.connect('conversation-stopped', Lang.bind(this, this._onConversationStopped)); + this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); + this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); + }, + + _getForegroundService: function() { + if (this._preemptingService) + return this._preemptingService; + + return this._defaultService; + }, + + serviceIsForeground: function(serviceName) { + return serviceName == this._getForegroundService(); + }, + + serviceIsDefault: function(serviceName) { + return serviceName == this._defaultService; + }, + + _updateDefaultService: function() { +- if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY)) ++ if (this._smartcardManager.loggedInWithToken()) ++ this._defaultService = SMARTCARD_SERVICE_NAME; ++ else if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY)) + this._defaultService = PASSWORD_SERVICE_NAME; + else if (this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY)) + 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) { + this._hold.acquire(); + if (this._userName) { + this._userVerifier.call_begin_verification_for_user(serviceName, + this._userName, + this._cancellable, + Lang.bind(this, function(obj, result) { + try { + obj.call_begin_verification_for_user_finish(result); + } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { + return; + } catch(e) { + this._reportInitError('Failed to start verification for user', e); + return; + } + + this._hold.release(); + })); +-- +2.5.0 + + +From cc8f8795d9a4bdf4b7893b07bb1a1a5585443ef7 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Mon, 28 Sep 2015 19:57:36 -0400 +Subject: [PATCH 3/3] gdm: update default service when smartcard inserted + +Early on at start up we may not know if a smartcard is +available. Make sure we reupdate the default service +after we get a smartcard insertion event. +--- + js/gdm/util.js | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/js/gdm/util.js b/js/gdm/util.js +index 776b76d..8723d59 100644 +--- a/js/gdm/util.js ++++ b/js/gdm/util.js +@@ -304,60 +304,62 @@ const ShellUserVerifier = new Lang.Class({ + if (!error && device) { + this._haveFingerprintReader = true; + this._updateDefaultService(); + } + })); + }, + + _oVirtUserAuthenticated: function(token) { + this._preemptingService = OVIRT_SERVICE_NAME; + this.emit('ovirt-user-authenticated'); + }, + + _checkForSmartcard: function() { + let smartcardDetected; + + if (!this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY)) + smartcardDetected = false; + else if (this._reauthOnly) + smartcardDetected = this._smartcardManager.hasInsertedLoginToken(); + else + smartcardDetected = this._smartcardManager.hasInsertedTokens(); + + if (smartcardDetected != this.smartcardDetected) { + this.smartcardDetected = smartcardDetected; + + if (this.smartcardDetected) + this._preemptingService = SMARTCARD_SERVICE_NAME; + else if (this._preemptingService == SMARTCARD_SERVICE_NAME) + this._preemptingService = null; + ++ this._updateDefaultService(); ++ + this.emit('smartcard-status-changed'); + } + }, + + _reportInitError: function(where, error) { + logError(error, where); + this._hold.release(); + + this._queueMessage(_("Authentication error"), MessageType.ERROR); + this._verificationFailed(false); + }, + + _reauthenticationChannelOpened: function(client, result) { + try { + this._clearUserVerifier(); + this._userVerifier = client.open_reauthentication_channel_finish(result); + } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { + return; + } catch(e if e.matches(Gio.DBusError, Gio.DBusError.ACCESS_DENIED) && + !this._reauthOnly) { + // Gdm emits org.freedesktop.DBus.Error.AccessDenied when there is + // no session to reauthenticate. Fall back to performing verification + // from this login session + client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot)); + return; + } catch(e) { + this._reportInitError('Failed to open reauthentication channel', e); + return; + } + +-- +2.5.0 + diff --git a/SOURCES/fix-background-leaks.patch b/SOURCES/fix-background-leaks.patch index 640be41..57bdef2 100644 --- a/SOURCES/fix-background-leaks.patch +++ b/SOURCES/fix-background-leaks.patch @@ -1,226 +1,17 @@ -From cdee11381cfb10a93fb41d014b989a4968068b0c Mon Sep 17 00:00:00 2001 -From: Adel Gadllah -Date: Thu, 15 Aug 2013 21:51:46 +0200 -Subject: [PATCH 01/13] Revert "background: fix asynchronous management of - background loading operations" - -This reverts commit 1020d8a0f8523a04d8336b1348388b8b242e414f. - -https://bugzilla.gnome.org/show_bug.cgi?id=704646 ---- - js/ui/background.js | 69 +++++++++++++++++++---------------------------------- - 1 file changed, 25 insertions(+), 44 deletions(-) - -diff --git a/js/ui/background.js b/js/ui/background.js -index 13343c6..1d9ab7c 100644 ---- a/js/ui/background.js -+++ b/js/ui/background.js -@@ -142,40 +142,33 @@ const BackgroundCache = new Lang.Class({ - cancellable: null, - onFinished: null }); - -- let fileLoad = { filename: params.filename, -- style: params.style, -- shouldCopy: false, -- monitorIndex: params.monitorIndex, -- effects: params.effects, -- onFinished: params.onFinished, -- cancellable: new Gio.Cancellable(), }; -- this._pendingFileLoads.push(fileLoad); -- -- if (params.cancellable) { -- params.cancellable.connect(Lang.bind(this, function(c) { -- fileLoad.cancellable.cancel(); -- })); -+ for (let i = 0; i < this._pendingFileLoads.length; i++) { -+ if (this._pendingFileLoads[i].filename == params.filename && -+ this._pendingFileLoads[i].style == params.style) { -+ this._pendingFileLoads[i].callers.push({ shouldCopy: true, -+ monitorIndex: params.monitorIndex, -+ effects: params.effects, -+ onFinished: params.onFinished }); -+ return; -+ } - } - -+ this._pendingFileLoads.push({ filename: params.filename, -+ style: params.style, -+ callers: [{ shouldCopy: false, -+ monitorIndex: params.monitorIndex, -+ effects: params.effects, -+ onFinished: params.onFinished }] }); -+ - let content = new Meta.Background({ meta_screen: global.screen, - monitor: params.monitorIndex, - effects: params.effects }); - - content.load_file_async(params.filename, - params.style, -- fileLoad.cancellable, -+ params.cancellable, - Lang.bind(this, - function(object, result) { -- if (fileLoad.cancellable.is_cancelled()) { -- if (params.cancellable && params.cancellable.is_cancelled()) { -- if (params.onFinished) -- params.onFinished(null); -- this._removePendingFileLoad(fileLoad); -- return; -- } -- return; -- } -- - try { - content.load_file_finish(result); - -@@ -185,25 +178,22 @@ const BackgroundCache = new Lang.Class({ - content = null; - } - -- let needsCopy = false; - for (let i = 0; i < this._pendingFileLoads.length; i++) { - let pendingLoad = this._pendingFileLoads[i]; - if (pendingLoad.filename != params.filename || - pendingLoad.style != params.style) - continue; - -- if (pendingLoad.cancellable.is_cancelled()) -- continue; -+ for (let j = 0; j < pendingLoad.callers.length; j++) { -+ if (pendingLoad.callers[j].onFinished) { -+ if (content && pendingLoad.callers[j].shouldCopy) { -+ content = object.copy(pendingLoad.callers[j].monitorIndex, -+ pendingLoad.callers[j].effects); - -- pendingLoad.cancellable.cancel(); -- if (pendingLoad.onFinished) { -- if (content && needsCopy) { -- content = object.copy(pendingLoad.monitorIndex, -- pendingLoad.effects); -- } -+ } - -- needsCopy = true; -- pendingLoad.onFinished(content); -+ pendingLoad.callers[j].onFinished(content); -+ } - } - - this._pendingFileLoads.splice(i, 1); -@@ -211,15 +201,6 @@ const BackgroundCache = new Lang.Class({ - })); - }, - -- _removePendingFileLoad: function(fileLoad) { -- for (let i = 0; i < this._pendingFileLoads.length; i++) { -- if (this._pendingFileLoads[i].cancellable == fileLoad.cancellable) { -- this._pendingFileLoads.splice(i, 1); -- break; -- } -- } -- }, -- - getImageContent: function(params) { - params = Params.parse(params, { monitorIndex: 0, - style: null, --- -1.9.0 - - -From 980a8618e1b89911c93183c461528bc9c3d465de Mon Sep 17 00:00:00 2001 -From: Adel Gadllah -Date: Wed, 2 Oct 2013 15:29:30 +0200 -Subject: [PATCH 02/13] background: Disconnect settings signal handler on - destroy - -We connect to the changed signal in _init() but never actually disconnect from -it. The callback has a reference to "this" which results into the background -object not getting garbage collected. - -Fix that leaks by disconnecting in _destroy() - -https://bugzilla.gnome.org/show_bug.cgi?id=709263 ---- - js/ui/background.js | 10 +++++++--- - 1 file changed, 7 insertions(+), 3 deletions(-) - -diff --git a/js/ui/background.js b/js/ui/background.js -index 1d9ab7c..b855b4e 100644 ---- a/js/ui/background.js -+++ b/js/ui/background.js -@@ -318,9 +318,9 @@ const Background = new Lang.Class({ - this._cancellable = new Gio.Cancellable(); - this.isLoaded = false; - -- this._settings.connect('changed', Lang.bind(this, function() { -- this.emit('changed'); -- })); -+ this._settingsChangedSignalId = this._settings.connect('changed', Lang.bind(this, function() { -+ this.emit('changed'); -+ })); - - this._load(); - }, -@@ -361,6 +361,10 @@ const Background = new Lang.Class({ - - this.actor.disconnect(this._destroySignalId); - this._destroySignalId = 0; -+ -+ if (this._settingsChangedSignalId != 0) -+ this._settings.disconnect(this._settingsChangedSignalId); -+ this._settingsChangedSignalId = 0; - }, - - _setLoaded: function() { --- -1.9.0 - - -From cfe72aa21a0aa8ea96dac81bfd6e532af62e9081 Mon Sep 17 00:00:00 2001 -From: Adel Gadllah -Date: Wed, 2 Oct 2013 15:48:39 +0200 -Subject: [PATCH 03/13] layout: Use monitor index when adding bg managers - -Don't assume that this._bgManagers.push() (i.e adding to the end) is always -correct. - -On startup we call _createPrimaryBackground which passes in the primary index -which may not be 0. ---- - js/ui/layout.js | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/js/ui/layout.js b/js/ui/layout.js -index e25b3bd..141eecc 100644 ---- a/js/ui/layout.js -+++ b/js/ui/layout.js -@@ -347,7 +347,7 @@ const LayoutManager = new Lang.Class({ - BackgroundMenu.addBackgroundMenu(bgManager.background.actor); - })); - -- this._bgManagers.push(bgManager); -+ this._bgManagers[monitorIndex] = bgManager; - - return bgManager.background; - }, --- -1.9.0 - - -From 304c11552766963f51343d97f8257096e62abb15 Mon Sep 17 00:00:00 2001 +From 1975387a50888ad911e303a58933527ed6c48e3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Fri, 14 Mar 2014 18:09:22 +0100 -Subject: [PATCH 04/13] background: Force a GC run after removing a background +Subject: [PATCH] background: Force a GC run after removing a background --- js/ui/background.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/js/ui/background.js b/js/ui/background.js -index b855b4e..0e4ff5d 100644 +index ad0cacc..a48934e 100644 --- a/js/ui/background.js +++ b/js/ui/background.js -@@ -6,8 +6,10 @@ const Gio = imports.gi.Gio; +@@ -99,8 +99,10 @@ const Gio = imports.gi.Gio; const GLib = imports.gi.GLib; const GnomeDesktop = imports.gi.GnomeDesktop; const Lang = imports.lang; @@ -231,547 +22,21 @@ index b855b4e..0e4ff5d 100644 const Main = imports.ui.main; const Params = imports.misc.params; -@@ -119,6 +121,14 @@ const BackgroundCache = new Lang.Class({ - - if (index >= 0) - contentList.splice(index, 1); -+ -+ if (!this._gcId) -+ this._gcId = Mainloop.idle_add(Lang.bind(this, -+ function() { -+ System.gc(); -+ this._gcId = 0; -+ return false; -+ })); - }, - - removePatternContent: function(content) { --- -1.9.0 - - -From 1cd71c438f3ee5dc6ccbc68ef646d42128e6883b Mon Sep 17 00:00:00 2001 -From: "Jasper St. Pierre" -Date: Tue, 3 Dec 2013 18:08:42 -0500 -Subject: [PATCH 05/13] background: Clarify the intent of the code - -Stomping on local variables and trying to keep loop state isn't -too fun. Just use a new variable here so we aren't too confused -with what we're doing. - -https://bugzilla.gnome.org/show_bug.cgi?id=719803 ---- - js/ui/background.js | 11 +++++++---- - 1 file changed, 7 insertions(+), 4 deletions(-) - -diff --git a/js/ui/background.js b/js/ui/background.js -index 0e4ff5d..80a3bba 100644 ---- a/js/ui/background.js -+++ b/js/ui/background.js -@@ -196,13 +196,16 @@ const BackgroundCache = new Lang.Class({ - - for (let j = 0; j < pendingLoad.callers.length; j++) { - if (pendingLoad.callers[j].onFinished) { -- if (content && pendingLoad.callers[j].shouldCopy) { -- content = object.copy(pendingLoad.callers[j].monitorIndex, -- pendingLoad.callers[j].effects); -+ let newContent; - -+ if (content && pendingLoad.callers[j].shouldCopy) { -+ newContent = content.copy(pendingLoad.callers[j].monitorIndex, -+ pendingLoad.callers[j].effects); -+ } else { -+ newContent = content; - } - -- pendingLoad.callers[j].onFinished(content); -+ pendingLoad.callers[j].onFinished(newContent); - } - } - --- -1.9.0 - - -From f86064aaf8753050582ead02d329aa9c36d0447c Mon Sep 17 00:00:00 2001 -From: "Jasper St. Pierre" -Date: Tue, 3 Dec 2013 18:09:23 -0500 -Subject: [PATCH 06/13] background: Add copied content from pending image loads - to the cache - -https://bugzilla.gnome.org/show_bug.cgi?id=719803 ---- - js/ui/background.js | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/js/ui/background.js b/js/ui/background.js -index 80a3bba..6349148 100644 ---- a/js/ui/background.js -+++ b/js/ui/background.js -@@ -201,6 +201,7 @@ const BackgroundCache = new Lang.Class({ - if (content && pendingLoad.callers[j].shouldCopy) { - newContent = content.copy(pendingLoad.callers[j].monitorIndex, - pendingLoad.callers[j].effects); -+ this._images.push(newContent); - } else { - newContent = content; - } --- -1.9.0 - - -From 8964898af8dde2e425d5fde711d2e572d87249d3 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 26 Feb 2014 14:35:38 -0500 -Subject: [PATCH 07/13] background: always copy background content when loading - into cache - -Copying is actually a lightweight operation, so trying to avoid it just adds -code complexity for little gain. - -Based on work from Jasper St. Pierre - -https://bugzilla.gnome.org/show_bug.cgi?id=722149 ---- - js/ui/background.js | 15 ++++----------- - 1 file changed, 4 insertions(+), 11 deletions(-) - -diff --git a/js/ui/background.js b/js/ui/background.js -index 6349148..1e4d2ae 100644 ---- a/js/ui/background.js -+++ b/js/ui/background.js -@@ -155,8 +155,7 @@ const BackgroundCache = new Lang.Class({ - for (let i = 0; i < this._pendingFileLoads.length; i++) { - if (this._pendingFileLoads[i].filename == params.filename && - this._pendingFileLoads[i].style == params.style) { -- this._pendingFileLoads[i].callers.push({ shouldCopy: true, -- monitorIndex: params.monitorIndex, -+ this._pendingFileLoads[i].callers.push({ monitorIndex: params.monitorIndex, - effects: params.effects, - onFinished: params.onFinished }); - return; -@@ -165,14 +164,11 @@ const BackgroundCache = new Lang.Class({ - - this._pendingFileLoads.push({ filename: params.filename, - style: params.style, -- callers: [{ shouldCopy: false, -- monitorIndex: params.monitorIndex, -+ callers: [{ monitorIndex: params.monitorIndex, - effects: params.effects, - onFinished: params.onFinished }] }); - -- let content = new Meta.Background({ meta_screen: global.screen, -- monitor: params.monitorIndex, -- effects: params.effects }); -+ let content = new Meta.Background({ meta_screen: global.screen }); - - content.load_file_async(params.filename, - params.style, -@@ -183,7 +179,6 @@ const BackgroundCache = new Lang.Class({ - content.load_file_finish(result); - - this._monitorFile(params.filename); -- this._images.push(content); - } catch(e) { - content = null; - } -@@ -198,12 +193,10 @@ const BackgroundCache = new Lang.Class({ - if (pendingLoad.callers[j].onFinished) { - let newContent; - -- if (content && pendingLoad.callers[j].shouldCopy) { -+ if (content) { - newContent = content.copy(pendingLoad.callers[j].monitorIndex, - pendingLoad.callers[j].effects); - this._images.push(newContent); -- } else { -- newContent = content; - } - - pendingLoad.callers[j].onFinished(newContent); --- -1.9.0 - - -From 0975134611b07d35cc9dff9c1451c1dc8a2cbafc Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 26 Feb 2014 15:13:21 -0500 -Subject: [PATCH 08/13] background: refactor file loading - -This commit moves the code around a bit such that the -caller gets allocated up front and then a file load is either -found or created to attach the caller to. - -Functionally, the code is the same, it's just now factored in a way -that will make it easier to fix a bug with cancellation later. - -https://bugzilla.gnome.org/show_bug.cgi?id=722149 ---- - js/ui/background.js | 27 +++++++++++++++++---------- - 1 file changed, 17 insertions(+), 10 deletions(-) - -diff --git a/js/ui/background.js b/js/ui/background.js -index 1e4d2ae..63b62a0 100644 ---- a/js/ui/background.js -+++ b/js/ui/background.js -@@ -144,6 +144,10 @@ const BackgroundCache = new Lang.Class({ - this._removeContent(this._images, content); - }, - -+ _attachCallerToFileLoad: function(caller, fileLoad) { -+ fileLoad.callers.push(caller); -+ }, -+ - _loadImageContent: function(params) { - params = Params.parse(params, { monitorIndex: 0, - style: null, -@@ -152,21 +156,24 @@ const BackgroundCache = new Lang.Class({ - cancellable: null, - onFinished: null }); - -+ let caller = { monitorIndex: params.monitorIndex, -+ effects: params.effects, -+ onFinished: params.onFinished }; -+ - for (let i = 0; i < this._pendingFileLoads.length; i++) { -- if (this._pendingFileLoads[i].filename == params.filename && -- this._pendingFileLoads[i].style == params.style) { -- this._pendingFileLoads[i].callers.push({ monitorIndex: params.monitorIndex, -- effects: params.effects, -- onFinished: params.onFinished }); -+ let fileLoad = this._pendingFileLoads[i]; -+ -+ if (fileLoad.filename == params.filename && -+ fileLoad.style == params.style) { -+ this._attachCallerToFileLoad(caller, fileLoad); - return; +@@ -202,6 +204,14 @@ const BackgroundCache = new Lang.Class({ + if (source._useCount == 0) { + delete this._backgroundSources[settingsSchema]; + source.destroy(); ++ ++ if (!this._gcId) ++ this._gcId = Mainloop.idle_add(Lang.bind(this, ++ function() { ++ System.gc(); ++ this._gcId = 0; ++ return false; ++ })); } } - -- this._pendingFileLoads.push({ filename: params.filename, -- style: params.style, -- callers: [{ monitorIndex: params.monitorIndex, -- effects: params.effects, -- onFinished: params.onFinished }] }); -+ let fileLoad = { filename: params.filename, -+ style: params.style, -+ callers: [] }; -+ this._attachCallerToFileLoad(caller, fileLoad); - - let content = new Meta.Background({ meta_screen: global.screen }); - --- -1.9.0 - - -From d5fdad361b7224e811921004be0d096cffb18f41 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 26 Feb 2014 16:09:26 -0500 -Subject: [PATCH 09/13] background: get rid of nested loop when finishing file - loading - -At the moment when a file is loaded, we iterate through the list of -pending file loads and ignore any unrelated to the file, then iterate -all the callers of the related file loads and finish them. - -In fact, there can only ever be one pending file load related to the -file, and we already know it, so we can avoid the ugly nested loops. - -https://bugzilla.gnome.org/show_bug.cgi?id=722149 ---- - js/ui/background.js | 32 +++++++++++++------------------- - 1 file changed, 13 insertions(+), 19 deletions(-) - -diff --git a/js/ui/background.js b/js/ui/background.js -index 63b62a0..417f70d 100644 ---- a/js/ui/background.js -+++ b/js/ui/background.js -@@ -190,28 +190,22 @@ const BackgroundCache = new Lang.Class({ - content = null; - } - -- for (let i = 0; i < this._pendingFileLoads.length; i++) { -- let pendingLoad = this._pendingFileLoads[i]; -- if (pendingLoad.filename != params.filename || -- pendingLoad.style != params.style) -- continue; -- -- for (let j = 0; j < pendingLoad.callers.length; j++) { -- if (pendingLoad.callers[j].onFinished) { -- let newContent; -- -- if (content) { -- newContent = content.copy(pendingLoad.callers[j].monitorIndex, -- pendingLoad.callers[j].effects); -- this._images.push(newContent); -- } -- -- pendingLoad.callers[j].onFinished(newContent); -+ for (let i = 0; i < fileLoad.callers.length; i++) { -+ let caller = fileLoad.callers[i]; -+ if (caller.onFinished) { -+ let newContent; -+ -+ if (content) { -+ newContent = content.copy(caller.monitorIndex, caller.effects); -+ this._images.push(newContent); - } -- } - -- this._pendingFileLoads.splice(i, 1); -+ caller.onFinished(newContent); -+ } - } -+ -+ let idx = this._pendingFileLoads.indexOf(fileLoad); -+ this._pendingFileLoads.splice(idx, 1); - })); - }, - --- -1.9.0 - - -From ef3fe7c12368f05e5187b89eb88a7454b9d43193 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 26 Feb 2014 15:45:14 -0500 -Subject: [PATCH 10/13] background: fix cancellable issue - -If we have the following sequence: - - cache.getImageContent({ filename: "foo", cancellable: cancellable1 }); - cache.getImageContent({ filename: "foo", cancellable: cancellable2 }); - cancellable1.cancel(); - -Then the second load will complete with "null" as its content, even though -it was never cancelled, and we'll see a blank image. Meanwhile, since the -second load simply appends to the list of callers for the second load, -cancellable2 does absolutely nothing: cancelling it won't stop the load, -and it will still receive onFinished handling. - -To prevent this from happening, give the actual load operation its own -Gio.Cancellable, which is "ref-counted" -- only cancel it when all the other -possible callers cancel. - -Based on work from Jasper St. Pierre - -https://bugzilla.gnome.org/show_bug.cgi?id=722149 ---- - js/ui/background.js | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/js/ui/background.js b/js/ui/background.js -index 417f70d..5d6d615 100644 ---- a/js/ui/background.js -+++ b/js/ui/background.js -@@ -146,6 +146,21 @@ const BackgroundCache = new Lang.Class({ - - _attachCallerToFileLoad: function(caller, fileLoad) { - fileLoad.callers.push(caller); -+ -+ if (!caller.cancellable) -+ return; -+ -+ caller.cancellable.connect(Lang.bind(this, function() { -+ let idx = fileLoad.callers.indexOf(caller); -+ fileLoad.callers.splice(idx, 1); -+ -+ if (fileLoad.callers.length == 0) { -+ fileLoad.cancellable.cancel(); -+ -+ let idx = this._pendingFileLoads.indexOf(fileLoad); -+ this._pendingFileLoads.splice(idx, 1); -+ } -+ })); - }, - - _loadImageContent: function(params) { -@@ -158,6 +173,7 @@ const BackgroundCache = new Lang.Class({ - - let caller = { monitorIndex: params.monitorIndex, - effects: params.effects, -+ cancellable: params.cancellable, - onFinished: params.onFinished }; - - for (let i = 0; i < this._pendingFileLoads.length; i++) { -@@ -172,6 +188,7 @@ const BackgroundCache = new Lang.Class({ - - let fileLoad = { filename: params.filename, - style: params.style, -+ cancellable: new Gio.Cancellable(), - callers: [] }; - this._attachCallerToFileLoad(caller, fileLoad); - --- -1.9.0 - - -From b9c8c220ea0cdd1f3d1b8ddefb9fc0e43d9e004f Mon Sep 17 00:00:00 2001 -From: "Jasper St. Pierre" -Date: Tue, 3 Dec 2013 15:41:42 -0500 -Subject: [PATCH 11/13] background: Fix the check for spanning backgrounds - -this._monitorIndex does not exist, and neither does -MetaBackground.monitor_index... - -https://bugzilla.gnome.org/show_bug.cgi?id=719803 ---- - js/ui/background.js | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/js/ui/background.js b/js/ui/background.js -index 5d6d615..0ac4ddc 100644 ---- a/js/ui/background.js -+++ b/js/ui/background.js -@@ -247,7 +247,7 @@ const BackgroundCache = new Lang.Class({ - continue; - - if (params.style == GDesktopEnums.BackgroundStyle.SPANNED && -- this._images[i].monitor_index != this._monitorIndex) -+ this._images[i].monitor != params.monitorIndex) - continue; - - candidateContent = this._images[i]; --- -1.9.0 - - -From 3466eb95898adb14a28f32740dde559b460a3ca2 Mon Sep 17 00:00:00 2001 -From: "Jasper St. Pierre" -Date: Tue, 3 Dec 2013 15:56:12 -0500 -Subject: [PATCH 12/13] background: Don't wait for gdk-pixbuf to fail before - loading animations - -We don't have any better way of determining whether something is a slideshow -animation, so discriminate on the .xml filename instead of waiting for -gdk-pixbuf to determine whether it can load a file or not. - -https://bugzilla.gnome.org/show_bug.cgi?id=719803 ---- - js/ui/background.js | 17 +++++++++-------- - 1 file changed, 9 insertions(+), 8 deletions(-) - -diff --git a/js/ui/background.js b/js/ui/background.js -index 0ac4ddc..0c22a0d 100644 ---- a/js/ui/background.js -+++ b/js/ui/background.js -@@ -568,24 +568,25 @@ const Background = new Lang.Class({ - }); - }, - -- _loadFile: function(filename) { -+ _loadImage: function(filename) { - this._cache.getImageContent({ monitorIndex: this._monitorIndex, - effects: this._effects, - style: this._style, - filename: filename, - cancellable: this._cancellable, - onFinished: Lang.bind(this, function(content) { -- if (!content) { -- if (!this._cancellable.is_cancelled()) -- this._loadAnimation(filename); -- return; -- } -- -- this._addImage(content, 0, filename); -+ if (content) -+ this._addImage(content, 0, filename); - this._setLoaded(); - }) - }); -+ }, - -+ _loadFile: function(filename) { -+ if (filename.indexOf('.xml', filename.length - 4) !== -1) -+ this._loadAnimation(filename); -+ else -+ this._loadImage(filename); - }, - - _load: function () { --- -1.9.0 - - -From b44299e03981125c2877082226cc2276ad5b47bd Mon Sep 17 00:00:00 2001 -From: "Jasper St. Pierre" -Date: Tue, 3 Dec 2013 17:25:57 -0500 -Subject: [PATCH 13/13] background: Simplify animation code - -https://bugzilla.gnome.org/show_bug.cgi?id=719803 ---- - js/ui/background.js | 31 ++++++++++++++----------------- - 1 file changed, 14 insertions(+), 17 deletions(-) - -diff --git a/js/ui/background.js b/js/ui/background.js -index 0c22a0d..5575815 100644 ---- a/js/ui/background.js -+++ b/js/ui/background.js -@@ -439,29 +439,27 @@ const Background = new Lang.Class({ - this._fileWatches[filename] = signalId; - }, - -- _addImage: function(content, index, filename) { -- content.saturation = this._saturation; -- content.brightness = this._brightness; -- content.vignette_sharpness = this._vignetteSharpness; -+ _ensureImage: function(index) { -+ if (this._images[index]) -+ return; - - let actor = new Meta.BackgroundActor(); -- actor.content = content; - - // The background pattern is the first actor in - // the group, and all images should be above that. - this.actor.insert_child_at_index(actor, index + 1); -- - this._images[index] = actor; -- this._watchCacheFile(filename); - }, - -- _updateImage: function(content, index, filename) { -+ _updateImage: function(index, content, filename) { - content.saturation = this._saturation; - content.brightness = this._brightness; - content.vignette_sharpness = this._vignetteSharpness; - -- this._cache.removeImageContent(this._images[index].content); -- this._images[index].content = content; -+ let image = this._images[index]; -+ if (image.content) -+ this._cache.removeImageContent(content); -+ image.content = content; - this._watchCacheFile(filename); - }, - -@@ -509,11 +507,8 @@ const Background = new Lang.Class({ - return; - } - -- if (!this._images[i]) { -- this._addImage(content, i, files[i]); -- } else { -- this._updateImage(content, i, files[i]); -- } -+ this._ensureImage(i); -+ this._updateImage(i, content, files[i]); - - if (numPendingImages == 0) { - this._setLoaded(); -@@ -575,8 +570,10 @@ const Background = new Lang.Class({ - filename: filename, - cancellable: this._cancellable, - onFinished: Lang.bind(this, function(content) { -- if (content) -- this._addImage(content, 0, filename); -+ if (content) { -+ this._ensureImage(0); -+ this._updateImage(0, content, filename); -+ } - this._setLoaded(); - }) - }); + } -- -1.9.0 +2.3.3 diff --git a/SOURCES/fix-cancel-sensitivity.patch b/SOURCES/fix-cancel-sensitivity.patch deleted file mode 100644 index 6747bdc..0000000 --- a/SOURCES/fix-cancel-sensitivity.patch +++ /dev/null @@ -1,89 +0,0 @@ -From e8d452420d80f34c767bffc98303c0769da54ed5 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 7 Oct 2014 14:30:34 -0400 -Subject: [PATCH] gdm: fix sensitivity of auth prompt when cancelling early and - user list is disabled - -If the user list is disabled and the user clicks cancel quickly enough -after typing their username, they can get in a state where the -auth prompt gets stuck in the insensitive state. - -This is because the login dialog code makes the prompt insensitive -while while pam is processing the provided username, but the prompt -only makes itself sensitive again when it is hidden. - -This commit makes it sensitive right before asking for a username again. ---- - js/gdm/loginDialog.js | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index b4487e6..893ab31 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -685,60 +685,62 @@ const LoginDialog = new Lang.Class({ - - // 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); - this._authPrompt.clear(); - this._authPrompt.startSpinning(); - this._authPrompt.begin({ userName: answer }); - this._updateCancelButton(); - - realmManager.disconnect(realmSignalId) - realmManager.release(); - })); - this._updateCancelButton(); -+ -+ this._authPrompt.updateSensitivity(true); - this._showPrompt(); - }, - - _startSession: function(serviceName) { - Tweener.addTween(this.actor, - { opacity: 0, - time: _FADE_ANIMATION_TIME, - transition: 'easeOutQuad', - onUpdate: function() { - let children = Main.layoutManager.uiGroup.get_children(); - - for (let i = 0; i < children.length; i++) { - if (children[i] != Main.layoutManager.screenShieldGroup) - children[i].opacity = this.actor.opacity; - } - }, - onUpdateScope: this, - onComplete: function() { - Mainloop.idle_add(Lang.bind(this, function() { - this._greeter.call_start_session_when_ready_sync(serviceName, true, null); - return false; - })); - }, - onCompleteScope: this }); - }, - - _onSessionOpened: function(client, serviceName) { - this._authPrompt.finish(Lang.bind(this, function() { - this._startSession(serviceName); - })); --- -1.8.3.1 - diff --git a/SOURCES/fix-login-screen-focus.patch b/SOURCES/fix-login-screen-focus.patch deleted file mode 100644 index 7ac50ec..0000000 --- a/SOURCES/fix-login-screen-focus.patch +++ /dev/null @@ -1,218 +0,0 @@ -From f936c6e5e2566e6a665b61b1610c249e7ec5479b Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Mon, 6 Oct 2014 16:38:03 -0400 -Subject: [PATCH 1/2] screenShield: focus login screen after lifting shield - -This commit ensures the login screen gets focused after -the screen shield is raised. - -The code affects the unlock screen as well, but it's -less important since the unlock screen gets destroyed -and recreated each time the curtain moves, so it -has an opportunity to take focus on its own. ---- - js/ui/screenShield.js | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js -index 089333b..4473b72 100644 ---- a/js/ui/screenShield.js -+++ b/js/ui/screenShield.js -@@ -1,37 +1,38 @@ - // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - - const Cairo = imports.cairo; - const Clutter = imports.gi.Clutter; - const Gio = imports.gi.Gio; - const GLib = imports.gi.GLib; - const GnomeDesktop = imports.gi.GnomeDesktop; -+const Gtk = imports.gi.Gtk; - const Lang = imports.lang; - const Mainloop = imports.mainloop; - const Meta = imports.gi.Meta; - const Shell = imports.gi.Shell; - const Signals = imports.signals; - const St = imports.gi.St; - const TweenerEquations = imports.tweener.equations; - - const Background = imports.ui.background; - const GnomeSession = imports.misc.gnomeSession; - const Hash = imports.misc.hash; - const Layout = imports.ui.layout; - const OVirt = imports.gdm.oVirt; - const LoginManager = imports.misc.loginManager; - const Lightbox = imports.ui.lightbox; - const Main = imports.ui.main; - const Overview = imports.ui.overview; - const MessageTray = imports.ui.messageTray; - const ShellDBus = imports.ui.shellDBus; - const SmartcardManager = imports.misc.smartcardManager; - const Tweener = imports.ui.tweener; - const Util = imports.misc.util; - - const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver'; - const LOCK_ENABLED_KEY = 'lock-enabled'; - const LOCK_DELAY_KEY = 'lock-delay'; - - // fraction of screen height the arrow must reach before completing - // the slide up automatically - const ARROW_DRAG_THRESHOLD = 0.1; -@@ -851,60 +852,63 @@ const ScreenShield = new Lang.Class({ - _onLightboxShown: function() { - this.activate(false); - }, - - showDialog: function() { - // Ensure that the stage window is mapped, before taking a grab - // otherwise X errors out - Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() { - if (!this._becomeModal()) { - // In the login screen, this is a hard error. Fail-whale - log('Could not acquire modal grab for the login screen. Aborting login process.'); - Meta.quit(Meta.ExitCode.ERROR); - } - - return false; - })); - - this.actor.show(); - this._isGreeter = Main.sessionMode.isGreeter; - this._isLocked = true; - this._ensureUnlockDialog(true, true); - this._hideLockScreen(false, 0); - }, - - _hideLockScreenComplete: function() { - if (Main.sessionMode.currentMode == 'lock-screen') - Main.sessionMode.popMode('lock-screen'); - - this._lockScreenState = MessageTray.State.HIDDEN; - this._lockScreenGroup.hide(); -+ -+ this._dialog.actor.grab_key_focus(); -+ this._dialog.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false); - }, - - _hideLockScreen: function(animate, velocity) { - if (this._lockScreenState == MessageTray.State.HIDDEN) - return; - - this._lockScreenState = MessageTray.State.HIDING; - - Tweener.removeTweens(this._lockScreenGroup); - - if (animate) { - // Tween the lock screen out of screen - // if velocity is not specified (i.e. we come here from pressing ESC), - // use the same speed regardless of original position - // if velocity is specified, it's in pixels per milliseconds - let h = global.stage.height; - let delta = (h + this._lockScreenGroup.y); - let min_velocity = global.stage.height / (CURTAIN_SLIDE_TIME * 1000); - - velocity = Math.max(min_velocity, velocity); - let time = (delta / velocity) / 1000; - - Tweener.addTween(this._lockScreenGroup, - { y: -h, - time: time, - transition: 'easeInQuad', - onComplete: Lang.bind(this, this._hideLockScreenComplete), - }); - } else { - this._hideLockScreenComplete(); --- -2.1.0 - - -From e5c2ad5e29ae1dd691f1762ff1a5e94f0dff8eb5 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 8 Oct 2014 09:39:44 -0400 -Subject: [PATCH 2/2] screenShield: fix trace back when unlocking session from - another vt - -commit 1d374ac8bd496f6fa6f4c55ffd207bd30bd50075 introduced a bug that -prevents unlock from working when initiated from another VT -(user switching). - -This commit fixes the exception raised. - -https://bugzilla.gnome.org/show_bug.cgi?id=708105 ---- - js/ui/screenShield.js | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js -index 4473b72..033ed2c 100644 ---- a/js/ui/screenShield.js -+++ b/js/ui/screenShield.js -@@ -853,62 +853,64 @@ const ScreenShield = new Lang.Class({ - this.activate(false); - }, - - showDialog: function() { - // Ensure that the stage window is mapped, before taking a grab - // otherwise X errors out - Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() { - if (!this._becomeModal()) { - // In the login screen, this is a hard error. Fail-whale - log('Could not acquire modal grab for the login screen. Aborting login process.'); - Meta.quit(Meta.ExitCode.ERROR); - } - - return false; - })); - - this.actor.show(); - this._isGreeter = Main.sessionMode.isGreeter; - this._isLocked = true; - this._ensureUnlockDialog(true, true); - this._hideLockScreen(false, 0); - }, - - _hideLockScreenComplete: function() { - if (Main.sessionMode.currentMode == 'lock-screen') - Main.sessionMode.popMode('lock-screen'); - - this._lockScreenState = MessageTray.State.HIDDEN; - this._lockScreenGroup.hide(); - -- this._dialog.actor.grab_key_focus(); -- this._dialog.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false); -+ if (this._dialog) { -+ this._dialog.actor.grab_key_focus(); -+ this._dialog.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false); -+ } - }, - - _hideLockScreen: function(animate, velocity) { - if (this._lockScreenState == MessageTray.State.HIDDEN) - return; - - this._lockScreenState = MessageTray.State.HIDING; - - Tweener.removeTweens(this._lockScreenGroup); - - if (animate) { - // Tween the lock screen out of screen - // if velocity is not specified (i.e. we come here from pressing ESC), - // use the same speed regardless of original position - // if velocity is specified, it's in pixels per milliseconds - let h = global.stage.height; - let delta = (h + this._lockScreenGroup.y); - let min_velocity = global.stage.height / (CURTAIN_SLIDE_TIME * 1000); - - velocity = Math.max(min_velocity, velocity); - let time = (delta / velocity) / 1000; - - Tweener.addTween(this._lockScreenGroup, - { y: -h, - time: time, - transition: 'easeInQuad', - onComplete: Lang.bind(this, this._hideLockScreenComplete), - }); - } else { - this._hideLockScreenComplete(); --- -2.1.0 - diff --git a/SOURCES/fix-menu-ornament-oddities.patch b/SOURCES/fix-menu-ornament-oddities.patch new file mode 100644 index 0000000..95d2776 --- /dev/null +++ b/SOURCES/fix-menu-ornament-oddities.patch @@ -0,0 +1,66 @@ +From d9b3a28a579ba1969e6fa3cb83d487f7742e6765 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 30 Jul 2015 17:25:59 +0200 +Subject: [PATCH 1/2] theme: Make menu ornament slightly wider + +The existing width works well enough for a narrow character like the dot, +but doesn't leave any whitespace for a wider one like the checkmark. + +https://bugzilla.gnome.org/show_bug.cgi?id=741366 +--- + data/theme/gnome-shell.css | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css +index 80dff57..97634b1 100644 +--- a/data/theme/gnome-shell.css ++++ b/data/theme/gnome-shell.css +@@ -140,7 +140,7 @@ StScrollBar StButton#vhandle:active { + + .popup-menu-ornament { + text-align: right; +- width: 1em; ++ width: 1.2em; + } + + .popup-menu-boxpointer, +-- +2.4.3 + + +From 1e5fc64944e9259782d060032e48bb7e6aaaabd3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 30 Jul 2015 15:54:16 +0200 +Subject: [PATCH 2/2] windowMenu: Use CHECK ornament rather than DOT + +The dot suggests a radio action, while the items are actually toggles; +in the app menu we use checkmarks in that case, so do the same here. +--- + js/ui/windowMenu.js | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/js/ui/windowMenu.js b/js/ui/windowMenu.js +index 3d378fa..43f6125 100644 +--- a/js/ui/windowMenu.js ++++ b/js/ui/windowMenu.js +@@ -74,7 +74,7 @@ const WindowMenu = new Lang.Class({ + window.make_above(); + })); + if (window.is_above()) +- item.setOrnament(PopupMenu.Ornament.DOT); ++ item.setOrnament(PopupMenu.Ornament.CHECK); + if (window.get_maximized() == Meta.MaximizeFlags.BOTH || + type == Meta.WindowType.DOCK || + type == Meta.WindowType.DESKTOP || +@@ -93,7 +93,7 @@ const WindowMenu = new Lang.Class({ + window.stick(); + })); + if (isSticky) +- item.setOrnament(PopupMenu.Ornament.DOT); ++ item.setOrnament(PopupMenu.Ornament.CHECK); + if (window.is_always_on_all_workspaces()) + item.setSensitive(false); + +-- +2.4.3 + diff --git a/SOURCES/fix-remote-search-provider-loading.patch b/SOURCES/fix-remote-search-provider-loading.patch deleted file mode 100644 index d6be5f9..0000000 --- a/SOURCES/fix-remote-search-provider-loading.patch +++ /dev/null @@ -1,296 +0,0 @@ -From 8f05bb1332ef7ad25e599b9a7d998733564cc3c8 Mon Sep 17 00:00:00 2001 -From: "Jasper St. Pierre" -Date: Thu, 11 Jul 2013 14:25:08 -0400 -Subject: [PATCH 1/3] search: Ensure that we correctly remove remote search - providers - -When we reload the remote search providers, we currently try to remove -all remote providers, and then re-scan. It turns out that we sometimes -remove the wrong providers from the remote provider list, causing us to -have some providers not correctly unloaded. - -https://bugzilla.gnome.org/show_bug.cgi?id=700283 ---- - js/ui/search.js | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/js/ui/search.js b/js/ui/search.js -index 3dd59d7..2cc8693 100644 ---- a/js/ui/search.js -+++ b/js/ui/search.js -@@ -31,7 +31,7 @@ const SearchSystem = new Lang.Class({ - - let remoteIndex = this._remoteProviders.indexOf(provider); - if (remoteIndex != -1) -- this._remoteProviders.splice(index, 1); -+ this._remoteProviders.splice(remoteIndex, 1); - }, - - getProviders: function() { --- -1.9.0 - - -From ab6694662aa79819d5140083b4eee15b312d3807 Mon Sep 17 00:00:00 2001 -From: "Jasper St. Pierre" -Date: Fri, 26 Jul 2013 18:36:31 -0400 -Subject: [PATCH 2/3] remoteSearch: Load remote search providers synchronously - -As we only reload search providers on startup or when the sort order changes, -and given the small number of search providers we'll actually load, I doubt -we'll see any speed decrease. - -The simplicity of synchronous code is also much clearer, and fully avoids -all the possible bugs about in-flight requests or similar. - -This also prevents issues with multiple search providers showing up at once, -which happen when multiple requests to reload search providers get called -immediately, with the existing in-flight async requests never cancelled. - -https://bugzilla.gnome.org/show_bug.cgi?id=700283 ---- - js/ui/remoteSearch.js | 154 +++++++++++++++++++++++++------------------------- - 1 file changed, 76 insertions(+), 78 deletions(-) - -diff --git a/js/ui/remoteSearch.js b/js/ui/remoteSearch.js -index e7cd6fe..323db5e 100644 ---- a/js/ui/remoteSearch.js -+++ b/js/ui/remoteSearch.js -@@ -7,7 +7,6 @@ const Lang = imports.lang; - const St = imports.gi.St; - const Shell = imports.gi.Shell; - --const FileUtils = imports.misc.fileUtils; - const Search = imports.ui.search; - - const KEY_FILE_GROUP = 'Shell Search Provider'; -@@ -60,108 +59,107 @@ var SearchProviderProxy = Gio.DBusProxy.makeProxyWrapper(SearchProviderIface); - var SearchProvider2Proxy = Gio.DBusProxy.makeProxyWrapper(SearchProvider2Iface); - - function loadRemoteSearchProviders(addProviderCallback) { -- let data = { loadedProviders: [], -- objectPaths: {}, -- addProviderCallback: addProviderCallback }; -- FileUtils.collectFromDatadirsAsync('search-providers', -- { loadedCallback: remoteProvidersLoaded, -- processFile: loadRemoteSearchProvider, -- data: data -- }); --} -- --function loadRemoteSearchProvider(file, info, data) { -- let keyfile = new GLib.KeyFile(); -- let path = file.get_path(); -- -- try { -- keyfile.load_from_file(path, 0); -- } catch(e) { -- return; -- } -- -- if (!keyfile.has_group(KEY_FILE_GROUP)) -- return; -+ let objectPaths = {}; -+ let loadedProviders = []; - -- let remoteProvider; -- try { -- let group = KEY_FILE_GROUP; -- let busName = keyfile.get_string(group, 'BusName'); -- let objectPath = keyfile.get_string(group, 'ObjectPath'); -+ function loadRemoteSearchProvider(file) { -+ let keyfile = new GLib.KeyFile(); -+ let path = file.get_path(); - -- if (data.objectPaths[objectPath]) -- return; -- -- let appInfo = null; - try { -- let desktopId = keyfile.get_string(group, 'DesktopId'); -- appInfo = Gio.DesktopAppInfo.new(desktopId); -- } catch (e) { -- log('Ignoring search provider ' + path + ': missing DesktopId'); -+ keyfile.load_from_file(path, 0); -+ } catch(e) { - return; - } - -- let version = '1'; -+ if (!keyfile.has_group(KEY_FILE_GROUP)) -+ return; -+ -+ let remoteProvider; - try { -- version = keyfile.get_string(group, 'Version'); -- } catch (e) { -- // ignore error -- } -+ let group = KEY_FILE_GROUP; -+ let busName = keyfile.get_string(group, 'BusName'); -+ let objectPath = keyfile.get_string(group, 'ObjectPath'); -+ -+ if (objectPaths[objectPath]) -+ return; -+ -+ let appInfo = null; -+ try { -+ let desktopId = keyfile.get_string(group, 'DesktopId'); -+ appInfo = Gio.DesktopAppInfo.new(desktopId); -+ } catch (e) { -+ log('Ignoring search provider ' + path + ': missing DesktopId'); -+ return; -+ } - -- if (version >= 2) -- remoteProvider = new RemoteSearchProvider2(appInfo, busName, objectPath); -- else -- remoteProvider = new RemoteSearchProvider(appInfo, busName, objectPath); -+ let version = '1'; -+ try { -+ version = keyfile.get_string(group, 'Version'); -+ } catch (e) { -+ // ignore error -+ } - -- data.objectPaths[objectPath] = remoteProvider; -- data.loadedProviders.push(remoteProvider); -- } catch(e) { -- log('Failed to add search provider %s: %s'.format(path, e.toString())); -+ if (version >= 2) -+ remoteProvider = new RemoteSearchProvider2(appInfo, busName, objectPath); -+ else -+ remoteProvider = new RemoteSearchProvider(appInfo, busName, objectPath); -+ -+ objectPaths[objectPath] = remoteProvider; -+ loadedProviders.push(remoteProvider); -+ } catch(e) { -+ log('Failed to add search provider %s: %s'.format(path, e.toString())); -+ } - } --} - --function remoteProvidersLoaded(loadState) { -+ let dataDirs = GLib.get_system_data_dirs(); -+ dataDirs.forEach(function(dataDir) { -+ let path = GLib.build_filenamev([dataDir, 'gnome-shell', 'search-providers']); -+ let dir = Gio.File.new_for_path(path); -+ let fileEnum = dir.enumerate_children('standard::name,standard::type', -+ Gio.FileQueryInfoFlags.NONE, null); -+ let info; -+ while ((info = fileEnum.next_file(null))) -+ loadRemoteSearchProvider(fileEnum.get_child(info)); -+ }); -+ - let searchSettings = new Gio.Settings({ schema: Search.SEARCH_PROVIDERS_SCHEMA }); - let sortOrder = searchSettings.get_strv('sort-order'); - - // Special case gnome-control-center to be always active and always first - sortOrder.unshift('gnome-control-center.desktop'); - -- loadState.loadedProviders.sort( -- function(providerA, providerB) { -- let idxA, idxB; -- let appIdA, appIdB; -+ loadedProviders.sort(function(providerA, providerB) { -+ let idxA, idxB; -+ let appIdA, appIdB; - -- appIdA = providerA.appInfo.get_id(); -- appIdB = providerB.appInfo.get_id(); -+ appIdA = providerA.appInfo.get_id(); -+ appIdB = providerB.appInfo.get_id(); - -- idxA = sortOrder.indexOf(appIdA); -- idxB = sortOrder.indexOf(appIdB); -+ idxA = sortOrder.indexOf(appIdA); -+ idxB = sortOrder.indexOf(appIdB); - -- // if no provider is found in the order, use alphabetical order -- if ((idxA == -1) && (idxB == -1)) { -- let nameA = providerA.appInfo.get_name(); -- let nameB = providerB.appInfo.get_name(); -+ // if no provider is found in the order, use alphabetical order -+ if ((idxA == -1) && (idxB == -1)) { -+ let nameA = providerA.appInfo.get_name(); -+ let nameB = providerB.appInfo.get_name(); - -- return GLib.utf8_collate(nameA, nameB); -- } -+ return GLib.utf8_collate(nameA, nameB); -+ } - -- // if providerA isn't found, it's sorted after providerB -- if (idxA == -1) -- return 1; -+ // if providerA isn't found, it's sorted after providerB -+ if (idxA == -1) -+ return 1; - -- // if providerB isn't found, it's sorted after providerA -- if (idxB == -1) -- return -1; -+ // if providerB isn't found, it's sorted after providerA -+ if (idxB == -1) -+ return -1; - -- // finally, if both providers are found, return their order in the list -- return (idxA - idxB); -- }); -+ // finally, if both providers are found, return their order in the list -+ return (idxA - idxB); -+ }); - -- loadState.loadedProviders.forEach( -- function(provider) { -- loadState.addProviderCallback(provider); -- }); -+ loadedProviders.forEach(addProviderCallback); - } - - const RemoteSearchProvider = new Lang.Class({ --- -1.9.0 - - -From d47c0ff65deb9301458c054ffd82ac3d398a79d5 Mon Sep 17 00:00:00 2001 -From: Colin Walters -Date: Sat, 27 Jul 2013 10:55:57 -0400 -Subject: [PATCH 3/3] search: Don't throw if provider directories don't exist - -There's no /usr/local/share/gnome-shell/search-providers, so don't -throw if we don't find it. ---- - js/ui/remoteSearch.js | 15 +++++++++++---- - 1 file changed, 11 insertions(+), 4 deletions(-) - -diff --git a/js/ui/remoteSearch.js b/js/ui/remoteSearch.js -index 323db5e..25e379c 100644 ---- a/js/ui/remoteSearch.js -+++ b/js/ui/remoteSearch.js -@@ -116,11 +116,18 @@ function loadRemoteSearchProviders(addProviderCallback) { - dataDirs.forEach(function(dataDir) { - let path = GLib.build_filenamev([dataDir, 'gnome-shell', 'search-providers']); - let dir = Gio.File.new_for_path(path); -- let fileEnum = dir.enumerate_children('standard::name,standard::type', -+ let fileEnum; -+ try { -+ fileEnum = dir.enumerate_children('standard::name,standard::type', - Gio.FileQueryInfoFlags.NONE, null); -- let info; -- while ((info = fileEnum.next_file(null))) -- loadRemoteSearchProvider(fileEnum.get_child(info)); -+ } catch (e) { -+ fileEnum = null; -+ } -+ if (fileEnum != null) { -+ let info; -+ while ((info = fileEnum.next_file(null))) -+ loadRemoteSearchProvider(fileEnum.get_child(info)); -+ } - }); - - let searchSettings = new Gio.Settings({ schema: Search.SEARCH_PROVIDERS_SCHEMA }); --- -1.9.0 - diff --git a/SOURCES/fix-session-activation.patch b/SOURCES/fix-session-activation.patch deleted file mode 100644 index 4b8f364..0000000 --- a/SOURCES/fix-session-activation.patch +++ /dev/null @@ -1,120 +0,0 @@ -From 7f19d43041c8402904012c89c53060208efe5016 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Thu, 13 Nov 2014 09:26:52 -0500 -Subject: [PATCH] loginDialog: only emit session-activated on user action - -Right now we emit session-activated any time the bullet -moves in the session menu. That includes at start up when -picking an item arbitrarily, and any time GDM reports the -session was read from the user's account settings. - -session-activated informs GDM about the newly selected session, -so emitting it in response to GDM reporting a session is a -bad idea (it's not only pointless, but it can least to -oscillations) - -This commit changes the code to only emit session-activated when -the user explicitly activates a session item from the gear menu. ---- - js/gdm/loginDialog.js | 6 +----- - 1 file changed, 1 insertion(+), 5 deletions(-) - -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index 9ee259f..ec88c73 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -327,90 +327,86 @@ const SessionMenuButton = new Lang.Class({ - this._menu.toggle(); - })); - - this._items = {}; - this._activeSessionId = null; - this._populate(); - }, - - updateSensitivity: function(sensitive) { - this._button.reactive = sensitive; - this._button.can_focus = sensitive; - this._menu.close(BoxPointer.PopupAnimation.NONE); - }, - - _updateOrnament: function() { - let itemIds = Object.keys(this._items); - for (let i = 0; i < itemIds.length; i++) { - if (itemIds[i] == this._activeSessionId) - this._items[itemIds[i]].setShowDot(true); - else - this._items[itemIds[i]].setShowDot(false); - } - }, - - setActiveSession: function(sessionId) { - if (sessionId == this._activeSessionId) - return; - - this._activeSessionId = sessionId; - this._updateOrnament(); -- -- this.emit('session-activated', this._activeSessionId); - }, - - close: function() { - this._menu.close(); - }, - - _populate: function() { - let ids = Gdm.get_session_ids(); - 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); -+ this.emit('session-activated', this._activeSessionId); - })); - } - } - }); - Signals.addSignalMethods(SessionMenuButton.prototype); - - const LoginDialog = new Lang.Class({ - Name: 'LoginDialog', - - _init: function(parentActor) { - 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)); --- -2.1.0 - diff --git a/SOURCES/fix-thumbail-box-shrinking.patch b/SOURCES/fix-thumbail-box-shrinking.patch deleted file mode 100644 index bd70203..0000000 --- a/SOURCES/fix-thumbail-box-shrinking.patch +++ /dev/null @@ -1,676 +0,0 @@ -From 2446c4bdb9bcea36234108303c7bf33b3d238fa3 Mon Sep 17 00:00:00 2001 -From: "Jasper St. Pierre" -Date: Mon, 25 Feb 2013 18:05:45 -0500 -Subject: [PATCH 1/8] overview: Move the group construction to the controls - manager - -Instead of creating a bunch of random actors and then passing -them off to the controls manager, let the controls manager -construct them. This leaves the controls manager in charge -of the ordeal. - -https://bugzilla.gnome.org/show_bug.cgi?id=694469 ---- - js/ui/overview.js | 37 ++++-------------------------- - js/ui/overviewControls.js | 58 ++++++++++++++++++++++++++++++++--------------- - 2 files changed, 45 insertions(+), 50 deletions(-) - -diff --git a/js/ui/overview.js b/js/ui/overview.js -index 02b23c7..ab4845c 100644 ---- a/js/ui/overview.js -+++ b/js/ui/overview.js -@@ -11,7 +11,6 @@ const Shell = imports.gi.Shell; - const Gdk = imports.gi.Gdk; - - const Background = imports.ui.background; --const Dash = imports.ui.dash; - const DND = imports.ui.dnd; - const LayoutManager = imports.ui.layout; - const Main = imports.ui.main; -@@ -20,8 +19,6 @@ const OverviewControls = imports.ui.overviewControls; - const Panel = imports.ui.panel; - const Params = imports.misc.params; - const Tweener = imports.ui.tweener; --const ViewSelector = imports.ui.viewSelector; --const WorkspaceThumbnail = imports.ui.workspaceThumbnail; - - // Time for initial animation going into Overview mode - const ANIMATION_TIME = 0.25; -@@ -133,14 +130,6 @@ const Overview = new Lang.Class({ - y_expand: true }); - this._overview._delegate = this; - -- this._groupStack = new St.Widget({ layout_manager: new Clutter.BinLayout(), -- x_expand: true, y_expand: true, -- clip_to_allocation: true }); -- this._group = new St.BoxLayout({ name: 'overview-group', -- reactive: true, -- x_expand: true, y_expand: true }); -- this._groupStack.add_actor(this._group); -- - this._backgroundGroup = new Meta.BackgroundGroup(); - global.overlay_group.add_child(this._backgroundGroup); - this._backgroundGroup.hide(); -@@ -177,7 +166,6 @@ const Overview = new Lang.Class({ - Main.xdndHandler.connect('drag-end', Lang.bind(this, this._onDragEnd)); - - global.screen.connect('restacked', Lang.bind(this, this._onRestacked)); -- this._group.connect('scroll-event', Lang.bind(this, this._onScrollEvent)); - - this._windowSwitchTimeoutId = 0; - this._windowSwitchTimestamp = 0; -@@ -276,28 +264,13 @@ const Overview = new Lang.Class({ - this._overview.add_actor(this._searchEntryBin); - - // Create controls -- this._dash = new Dash.Dash(); -- this._viewSelector = new ViewSelector.ViewSelector(this._searchEntry, -- this._dash.showAppsButton); -- this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox(); -- this._controls = new OverviewControls.ControlsManager(this._dash, -- this._thumbnailsBox, -- this._viewSelector); -- -- this._controls.dashActor.x_align = Clutter.ActorAlign.START; -- this._controls.dashActor.y_expand = true; -- -- // Put the dash in a separate layer to allow content to be centered -- this._groupStack.add_actor(this._controls.dashActor); -- -- // Pack all the actors into the group -- this._group.add_actor(this._controls.dashSpacer); -- this._group.add(this._viewSelector.actor, { x_fill: true, -- expand: true }); -- this._group.add_actor(this._controls.thumbnailsActor); -+ this._controls = new OverviewControls.ControlsManager(this._searchEntry); -+ this._dash = this._controls.dash; -+ this._viewSelector = this._controls.viewSelector; - - // Add our same-line elements after the search entry -- this._overview.add(this._groupStack, { y_fill: true, expand: true }); -+ this._overview.add(this._controls.actor, { y_fill: true, expand: true }); -+ this._controls.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent)); - - this._stack.add_actor(this._controls.indicatorActor); - -diff --git a/js/ui/overviewControls.js b/js/ui/overviewControls.js -index ba5c7a8..b3eb5d3 100644 ---- a/js/ui/overviewControls.js -+++ b/js/ui/overviewControls.js -@@ -6,10 +6,12 @@ const Meta = imports.gi.Meta; - const St = imports.gi.St; - const Shell = imports.gi.Shell; - -+const Dash = imports.ui.dash; - const Main = imports.ui.main; - const Params = imports.misc.params; - const Tweener = imports.ui.tweener; - const ViewSelector = imports.ui.viewSelector; -+const WorkspaceThumbnail = imports.ui.workspaceThumbnail; - - const SIDE_CONTROLS_ANIMATION_TIME = 0.16; - -@@ -309,6 +311,10 @@ const DashSlider = new Lang.Class({ - // available allocation - this._dash.actor.x_expand = true; - this._dash.actor.y_expand = true; -+ -+ this.actor.x_align = Clutter.ActorAlign.START; -+ this.actor.y_expand = true; -+ - this.actor.add_actor(this._dash.actor); - - this._dash.connect('icon-size-changed', Lang.bind(this, this.updateSlide)); -@@ -479,36 +485,52 @@ const MessagesIndicator = new Lang.Class({ - const ControlsManager = new Lang.Class({ - Name: 'ControlsManager', - -- _init: function(dash, thumbnails, viewSelector) { -- this._dashSlider = new DashSlider(dash); -- this.dashActor = this._dashSlider.actor; -- this.dashSpacer = new DashSpacer(); -- this.dashSpacer.setDashActor(this.dashActor); -+ _init: function(searchEntry) { -+ this.dash = new Dash.Dash(); -+ this._dashSlider = new DashSlider(this.dash); -+ this._dashSpacer = new DashSpacer(); -+ this._dashSpacer.setDashActor(this._dashSlider.actor); -+ -+ this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox(); -+ this._thumbnailsSlider = new ThumbnailsSlider(this._thumbnailsBox); - -- this._thumbnailsSlider = new ThumbnailsSlider(thumbnails); -- this.thumbnailsActor = this._thumbnailsSlider.actor; -+ this.viewSelector = new ViewSelector.ViewSelector(searchEntry, -+ this.dash.showAppsButton); -+ this.viewSelector.connect('page-changed', Lang.bind(this, this._setVisibility)); -+ this.viewSelector.connect('page-empty', Lang.bind(this, this._onPageEmpty)); - -- this._indicator = new MessagesIndicator(viewSelector); -+ this._indicator = new MessagesIndicator(this.viewSelector); - this.indicatorActor = this._indicator.actor; - -- this._viewSelector = viewSelector; -- this._viewSelector.connect('page-changed', Lang.bind(this, this._setVisibility)); -- this._viewSelector.connect('page-empty', Lang.bind(this, this._onPageEmpty)); -+ this.actor = new St.Widget({ layout_manager: new Clutter.BinLayout(), -+ x_expand: true, y_expand: true, -+ clip_to_allocation: true }); -+ this._group = new St.BoxLayout({ name: 'overview-group', -+ reactive: true, -+ x_expand: true, y_expand: true }); -+ this.actor.add_actor(this._group); -+ -+ this.actor.add_actor(this._dashSlider.actor); -+ -+ this._group.add_actor(this._dashSpacer); -+ this._group.add(this.viewSelector.actor, { x_fill: true, -+ expand: true }); -+ this._group.add_actor(this._thumbnailsSlider.actor); - - Main.overview.connect('showing', Lang.bind(this, this._updateSpacerVisibility)); - Main.overview.connect('item-drag-begin', Lang.bind(this, - function() { -- let activePage = this._viewSelector.getActivePage(); -+ let activePage = this.viewSelector.getActivePage(); - if (activePage != ViewSelector.ViewPage.WINDOWS) -- this._viewSelector.fadeHalf(); -+ this.viewSelector.fadeHalf(); - })); - Main.overview.connect('item-drag-end', Lang.bind(this, - function() { -- this._viewSelector.fadeIn(); -+ this.viewSelector.fadeIn(); - })); - Main.overview.connect('item-drag-cancelled', Lang.bind(this, - function() { -- this._viewSelector.fadeIn(); -+ this.viewSelector.fadeIn(); - })); - }, - -@@ -521,7 +543,7 @@ const ControlsManager = new Lang.Class({ - (Main.overview.animationInProgress && !Main.overview.visibleTarget)) - return; - -- let activePage = this._viewSelector.getActivePage(); -+ let activePage = this.viewSelector.getActivePage(); - let dashVisible = (activePage == ViewSelector.ViewPage.WINDOWS || - activePage == ViewSelector.ViewPage.APPS); - let thumbnailsVisible = (activePage == ViewSelector.ViewPage.WINDOWS); -@@ -541,8 +563,8 @@ const ControlsManager = new Lang.Class({ - if (Main.overview.animationInProgress && !Main.overview.visibleTarget) - return; - -- let activePage = this._viewSelector.getActivePage(); -- this.dashSpacer.visible = (activePage == ViewSelector.ViewPage.WINDOWS); -+ let activePage = this.viewSelector.getActivePage(); -+ this._dashSpacer.visible = (activePage == ViewSelector.ViewPage.WINDOWS); - }, - - _onPageEmpty: function() { --- -2.1.0 - - -From 83330f59c82da874ef381ad81e79c7796bb228d1 Mon Sep 17 00:00:00 2001 -From: "Jasper St. Pierre" -Date: Wed, 18 Sep 2013 19:42:41 -0400 -Subject: [PATCH 2/8] overviewControls: Correct the use of x2 in SlidingControl - -The x2 here needs to be more than just the width; it needs to -be added onto the x1. - -https://bugzilla.gnome.org/show_bug.cgi?id=694881 ---- - js/ui/overviewControls.js | 9 +++++---- - 1 file changed, 5 insertions(+), 4 deletions(-) - -diff --git a/js/ui/overviewControls.js b/js/ui/overviewControls.js -index b3eb5d3..2b8977d 100644 ---- a/js/ui/overviewControls.js -+++ b/js/ui/overviewControls.js -@@ -62,10 +62,11 @@ const SlideLayout = new Lang.Class({ - let translationX = (realDirection == SlideDirection.LEFT) ? - (availWidth - natWidth) : (natWidth - availWidth); - -- let actorBox = new Clutter.ActorBox({ x1: translationX, -- y1: 0, -- x2: child.x_expand ? availWidth : natWidth, -- y2: child.y_expand ? availHeight : natHeight }); -+ let actorBox = new Clutter.ActorBox(); -+ actorBox.x1 = translationX; -+ actorBox.x2 = actorBox.x1 + child.x_expand ? availWidth : natWidth; -+ actorBox.y1 = 0; -+ actorBox.y2 = actorBox.y1 + child.y_expand ? availHeight : natHeight; - - child.allocate(actorBox, flags); - }, --- -2.1.0 - - -From d603fda86689db852ff204048a57805bcded5f1b Mon Sep 17 00:00:00 2001 -From: "Jasper St. Pierre" -Date: Wed, 18 Sep 2013 19:48:22 -0400 -Subject: [PATCH 3/8] overviewControls: Clarify some code with a comment - -translationX is sort of a bad name, since it confuses with the -actor's translation, which is used for sliding without allocation. - -https://bugzilla.gnome.org/show_bug.cgi?id=694881 ---- - js/ui/overviewControls.js | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - -diff --git a/js/ui/overviewControls.js b/js/ui/overviewControls.js -index 2b8977d..50a7f8b 100644 ---- a/js/ui/overviewControls.js -+++ b/js/ui/overviewControls.js -@@ -58,12 +58,14 @@ const SlideLayout = new Lang.Class({ - let availWidth = Math.round(box.x2 - box.x1); - let availHeight = Math.round(box.y2 - box.y1); - -+ // Align the actor inside the clipped box, as the actor's alignment -+ // flags only determine what to do if the allocated box is bigger -+ // than the actor's box. - let realDirection = getRtlSlideDirection(this._direction, child); -- let translationX = (realDirection == SlideDirection.LEFT) ? -- (availWidth - natWidth) : (natWidth - availWidth); -+ let alignX = (realDirection == SlideDirection.LEFT) ? (availWidth - natWidth) : (natWidth - availWidth); - - let actorBox = new Clutter.ActorBox(); -- actorBox.x1 = translationX; -+ actorBox.x1 = alignX; - actorBox.x2 = actorBox.x1 + child.x_expand ? availWidth : natWidth; - actorBox.y1 = 0; - actorBox.y2 = actorBox.y1 + child.y_expand ? availHeight : natHeight; --- -2.1.0 - - -From b311522ecc172e1ca7f46cf46492b6fd7f847e23 Mon Sep 17 00:00:00 2001 -From: "Jasper St. Pierre" -Date: Wed, 18 Sep 2013 19:48:51 -0400 -Subject: [PATCH 4/8] overviewControls: Don't try to align something sliding to - the right - -0 is already the correct value. - -https://bugzilla.gnome.org/show_bug.cgi?id=694881 ---- - js/ui/overviewControls.js | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/js/ui/overviewControls.js b/js/ui/overviewControls.js -index 50a7f8b..0841715 100644 ---- a/js/ui/overviewControls.js -+++ b/js/ui/overviewControls.js -@@ -62,7 +62,7 @@ const SlideLayout = new Lang.Class({ - // flags only determine what to do if the allocated box is bigger - // than the actor's box. - let realDirection = getRtlSlideDirection(this._direction, child); -- let alignX = (realDirection == SlideDirection.LEFT) ? (availWidth - natWidth) : (natWidth - availWidth); -+ let alignX = (realDirection == SlideDirection.LEFT) ? (availWidth - natWidth) : 0; - - let actorBox = new Clutter.ActorBox(); - actorBox.x1 = alignX; --- -2.1.0 - - -From 38a92b4a0dc60f475c30e00ae9987e1e320950d0 Mon Sep 17 00:00:00 2001 -From: "Jasper St. Pierre" -Date: Fri, 11 Oct 2013 22:36:49 -0400 -Subject: [PATCH 5/8] overviewControls: Don't use the child's preferred size to - slide from - -In order for the workspace thumbnails box to have the correct size, -we need to constrain the width of the thumbnails box to the height we're -given, instead of assuming an unlimited height. - -https://bugzilla.gnome.org/show_bug.cgi?id=694881 ---- - js/ui/overviewControls.js | 10 ++-------- - 1 file changed, 2 insertions(+), 8 deletions(-) - -diff --git a/js/ui/overviewControls.js b/js/ui/overviewControls.js -index 0841715..aafb905 100644 ---- a/js/ui/overviewControls.js -+++ b/js/ui/overviewControls.js -@@ -54,9 +54,9 @@ const SlideLayout = new Lang.Class({ - vfunc_allocate: function(container, box, flags) { - let child = container.get_first_child(); - -- let [, , natWidth, natHeight] = child.get_preferred_size(); - let availWidth = Math.round(box.x2 - box.x1); - let availHeight = Math.round(box.y2 - box.y1); -+ let [, natWidth] = child.get_preferred_width(availHeight); - - // Align the actor inside the clipped box, as the actor's alignment - // flags only determine what to do if the allocated box is bigger -@@ -68,7 +68,7 @@ const SlideLayout = new Lang.Class({ - actorBox.x1 = alignX; - actorBox.x2 = actorBox.x1 + child.x_expand ? availWidth : natWidth; - actorBox.y1 = 0; -- actorBox.y2 = actorBox.y1 + child.y_expand ? availHeight : natHeight; -+ actorBox.y2 = actorBox.y1 + availHeight; - - child.allocate(actorBox, flags); - }, -@@ -237,11 +237,6 @@ const ThumbnailsSlider = new Lang.Class({ - - this._thumbnailsBox = thumbnailsBox; - -- // SlideLayout reads the actor's expand flags to decide -- // whether to allocate the natural size to its child, or the whole -- // available allocation -- this._thumbnailsBox.actor.y_expand = true; -- - this.actor.request_mode = Clutter.RequestMode.WIDTH_FOR_HEIGHT; - this.actor.reactive = true; - this.actor.track_hover = true; -@@ -313,7 +308,6 @@ const DashSlider = new Lang.Class({ - // whether to allocate the natural size to its child, or the whole - // available allocation - this._dash.actor.x_expand = true; -- this._dash.actor.y_expand = true; - - this.actor.x_align = Clutter.ActorAlign.START; - this.actor.y_expand = true; --- -2.1.0 - - -From 9bc20a14840beaa4c308a11000e2a6b737f5c208 Mon Sep 17 00:00:00 2001 -From: "Jasper St. Pierre" -Date: Fri, 11 Oct 2013 21:27:59 -0400 -Subject: [PATCH 6/8] workspaceThumbnail: Drop the _background hack - -The _background hack was added because the old way the zooming animation -worked, it set the allocation of the workspaces view and thumbnails box -to the final position and used animations to smoothly animate. - -During the 3.6 cycle when we added the new search view, Cosimo changed the -way the zoom animation works so that rather than set the final allocation -and animate, we actually do adjust the allocation of the workspaces view -and thumbnails box. - -So, as the hack is no longer necessary, we can drop it. - -https://bugzilla.gnome.org/show_bug.cgi?id=694881 ---- - data/theme/gnome-shell.css | 11 +++---- - js/ui/workspaceThumbnail.js | 77 +++++++++++++-------------------------------- - 2 files changed, 25 insertions(+), 63 deletions(-) - -diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css -index 532c8a5..80c929e 100644 ---- a/data/theme/gnome-shell.css -+++ b/data/theme/gnome-shell.css -@@ -673,7 +673,9 @@ StScrollBar StButton#vhandle:active { - padding-bottom: 32px; - } - --.workspace-thumbnails-background { -+.workspace-thumbnails { -+ spacing: 11px; -+ visible-width: 32px; /* Amount visible before hovering */ - border: 1px solid rgba(128, 128, 128, 0.4); - border-right: 0px; - border-radius: 9px 0px 0px 9px; -@@ -681,18 +683,13 @@ StScrollBar StButton#vhandle:active { - padding: 11px 7px 11px 11px; - } - --.workspace-thumbnails-background:rtl { -+.workspace-thumbnails:rtl { - border-right: 1px; - border-left: 0px; - border-radius: 0px 9px 9px 0px; - padding: 11px 11px 11px 7px; - } - --.workspace-thumbnails { -- spacing: 11px; -- visible-width: 32px; /* Amount visible before hovering */ --} -- - .workspace-thumbnail-indicator { - border: 4px solid rgba(255,255,255,0.7); - border-radius: 4px; -diff --git a/js/ui/workspaceThumbnail.js b/js/ui/workspaceThumbnail.js -index 6b631d1..d4374f2 100644 ---- a/js/ui/workspaceThumbnail.js -+++ b/js/ui/workspaceThumbnail.js -@@ -536,20 +536,6 @@ const ThumbnailsBox = new Lang.Class({ - this.actor.connect('allocate', Lang.bind(this, this._allocate)); - this.actor._delegate = this; - -- // When we animate the scale, we don't animate the requested size of the thumbnails, rather -- // we ask for our final size and then animate within that size. This slightly simplifies the -- // interaction with the main workspace windows (instead of constantly reallocating them -- // to a new size, they get a new size once, then use the standard window animation code -- // allocate the windows to their new positions), however it causes problems for drawing -- // the background and border wrapped around the thumbnail as we animate - we can't just pack -- // the container into a box and set style properties on the box since that box would wrap -- // around the final size not the animating size. So instead we fake the background with -- // an actor underneath the content and adjust the allocation of our children to leave space -- // for the border and padding of the background actor. -- this._background = new St.Bin({ style_class: 'workspace-thumbnails-background' }); -- -- this.actor.add_actor(this._background); -- - let indicator = new St.Bin({ style_class: 'workspace-thumbnail-indicator' }); - - // We don't want the indicator to affect drag-and-drop -@@ -1038,9 +1024,6 @@ const ThumbnailsBox = new Lang.Class({ - }, - - _getPreferredHeight: function(actor, forWidth, alloc) { -- // See comment about this._background in _init() -- let themeNode = this._background.get_theme_node(); -- - // Note that for getPreferredWidth/Height we cheat a bit and skip propagating - // the size request to our children because we know how big they are and know - // that the actors aren't depending on the virtual functions being called. -@@ -1048,24 +1031,21 @@ const ThumbnailsBox = new Lang.Class({ - if (this._thumbnails.length == 0) - return; - -- let spacing = this.actor.get_theme_node().get_length('spacing'); -+ let themeNode = this.actor.get_theme_node(); -+ -+ let spacing = themeNode.get_length('spacing'); - let nWorkspaces = global.screen.n_workspaces; - let totalSpacing = (nWorkspaces - 1) * spacing; - -- [alloc.min_size, alloc.natural_size] = -- themeNode.adjust_preferred_height(totalSpacing, -- totalSpacing + nWorkspaces * this._porthole.height * MAX_THUMBNAIL_SCALE); -+ alloc.min_size = totalSpacing; -+ alloc.natural_size = totalSpacing + nWorkspaces * this._porthole.height * MAX_THUMBNAIL_SCALE; - }, - - _getPreferredWidth: function(actor, forHeight, alloc) { -- // See comment about this._background in _init() -- let themeNode = this._background.get_theme_node(); -- - if (this._thumbnails.length == 0) - return; - -- // We don't animate our preferred width, which is always reported according -- // to the actual number of current workspaces, we just animate within that -+ let themeNode = this.actor.get_theme_node(); - - let spacing = this.actor.get_theme_node().get_length('spacing'); - let nWorkspaces = global.screen.n_workspaces; -@@ -1077,28 +1057,26 @@ const ThumbnailsBox = new Lang.Class({ - scale = Math.min(scale, MAX_THUMBNAIL_SCALE); - - let width = Math.round(this._porthole.width * scale); -- [alloc.min_size, alloc.natural_size] = -- themeNode.adjust_preferred_width(width, width); -+ alloc.min_size = width; -+ alloc.natural_size = width; - }, - - _allocate: function(actor, box, flags) { - let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL); - -- // See comment about this._background in _init() -- let themeNode = this._background.get_theme_node(); -- let contentBox = themeNode.get_content_box(box); -- - if (this._thumbnails.length == 0) // not visible - return; - -+ let themeNode = this.actor.get_theme_node(); -+ - let portholeWidth = this._porthole.width; - let portholeHeight = this._porthole.height; -- let spacing = this.actor.get_theme_node().get_length('spacing'); -+ let spacing = themeNode.get_length('spacing'); - - // Compute the scale we'll need once everything is updated - let nWorkspaces = global.screen.n_workspaces; - let totalSpacing = (nWorkspaces - 1) * spacing; -- let avail = (contentBox.y2 - contentBox.y1) - totalSpacing; -+ let avail = (box.y2 - box.y1) - totalSpacing; - - let newScale = (avail / nWorkspaces) / portholeHeight; - newScale = Math.min(newScale, MAX_THUMBNAIL_SCALE); -@@ -1127,21 +1105,6 @@ const ThumbnailsBox = new Lang.Class({ - else - slideOffset = thumbnailWidth + themeNode.get_padding(St.Side.RIGHT); - -- let childBox = new Clutter.ActorBox(); -- -- // The background is horizontally restricted to correspond to the current thumbnail size -- // but otherwise covers the entire allocation -- if (rtl) { -- childBox.x1 = box.x1; -- childBox.x2 = box.x2 - ((contentBox.x2 - contentBox.x1) - thumbnailWidth); -- } else { -- childBox.x1 = box.x1 + ((contentBox.x2 - contentBox.x1) - thumbnailWidth); -- childBox.x2 = box.x2; -- } -- childBox.y1 = box.y1; -- childBox.y2 = box.y2; -- this._background.allocate(childBox, flags); -- - let indicatorY1 = this._indicatorY; - let indicatorY2; - // when not animating, the workspace position overrides this._indicatorY -@@ -1153,7 +1116,7 @@ const ThumbnailsBox = new Lang.Class({ - let indicatorLeftFullBorder = indicatorThemeNode.get_padding(St.Side.LEFT) + indicatorThemeNode.get_border_width(St.Side.LEFT); - let indicatorRightFullBorder = indicatorThemeNode.get_padding(St.Side.RIGHT) + indicatorThemeNode.get_border_width(St.Side.RIGHT); - -- let y = contentBox.y1; -+ let y = box.y1; - - if (this._dropPlaceholderPos == -1) { - Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() { -@@ -1161,6 +1124,8 @@ const ThumbnailsBox = new Lang.Class({ - })); - } - -+ let childBox = new Clutter.ActorBox(); -+ - for (let i = 0; i < this._thumbnails.length; i++) { - let thumbnail = this._thumbnails[i]; - -@@ -1169,10 +1134,10 @@ const ThumbnailsBox = new Lang.Class({ - - let x1, x2; - if (rtl) { -- x1 = contentBox.x1 + slideOffset * thumbnail.slidePosition; -+ x1 = box.x1 + slideOffset * thumbnail.slidePosition; - x2 = x1 + thumbnailWidth; - } else { -- x1 = contentBox.x2 - thumbnailWidth + slideOffset * thumbnail.slidePosition; -+ x1 = box.x2 - thumbnailWidth + slideOffset * thumbnail.slidePosition; - x2 = x1 + thumbnailWidth; - } - -@@ -1219,11 +1184,11 @@ const ThumbnailsBox = new Lang.Class({ - } - - if (rtl) { -- childBox.x1 = contentBox.x1; -- childBox.x2 = contentBox.x1 + thumbnailWidth; -+ childBox.x1 = box.x1; -+ childBox.x2 = box.x1 + thumbnailWidth; - } else { -- childBox.x1 = contentBox.x2 - thumbnailWidth; -- childBox.x2 = contentBox.x2; -+ childBox.x1 = box.x2 - thumbnailWidth; -+ childBox.x2 = box.x2; - } - childBox.x1 -= indicatorLeftFullBorder; - childBox.x2 += indicatorRightFullBorder; --- -2.1.0 - - -From a391e6dd3ed64517fefeaf5876fa5c838e1eb58f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Thu, 9 Oct 2014 14:07:22 +0200 -Subject: [PATCH 7/8] overviewControls: Fix thinko in SlideLayout - -Controls that slide left are located on the left, so the offset to -align them with the corresponding edge is always 0. It's controls -on the right that need a different offset when the available width -exceeds the child's width. - -https://bugzilla.gnome.org/show_bug.cgi?id=728899 ---- - js/ui/overviewControls.js | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/js/ui/overviewControls.js b/js/ui/overviewControls.js -index aafb905..1d1c550 100644 ---- a/js/ui/overviewControls.js -+++ b/js/ui/overviewControls.js -@@ -62,7 +62,7 @@ const SlideLayout = new Lang.Class({ - // flags only determine what to do if the allocated box is bigger - // than the actor's box. - let realDirection = getRtlSlideDirection(this._direction, child); -- let alignX = (realDirection == SlideDirection.LEFT) ? (availWidth - natWidth) : 0; -+ let alignX = (realDirection == SlideDirection.RIGHT) ? (availWidth - natWidth) : 0; - - let actorBox = new Clutter.ActorBox(); - actorBox.x1 = alignX; --- -2.1.0 - - -From ae265eb3f7d1b8c4f480e61bbc8d3a01dbed34db Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Fri, 10 Oct 2014 10:58:42 +0200 -Subject: [PATCH 8/8] overviewControls: Really fix x align - -Commit a4475465f1f2 fixed the wrong alignment for the fully visible -control, but regressed the partially slid-out one; take the slideX -factor into account to get the right offset for both cases. ---- - js/ui/overviewControls.js | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/js/ui/overviewControls.js b/js/ui/overviewControls.js -index 1d1c550..4f5bb7f 100644 ---- a/js/ui/overviewControls.js -+++ b/js/ui/overviewControls.js -@@ -62,7 +62,8 @@ const SlideLayout = new Lang.Class({ - // flags only determine what to do if the allocated box is bigger - // than the actor's box. - let realDirection = getRtlSlideDirection(this._direction, child); -- let alignX = (realDirection == SlideDirection.RIGHT) ? (availWidth - natWidth) : 0; -+ let alignX = (realDirection == SlideDirection.LEFT) ? (availWidth - natWidth) -+ : (availWidth - natWidth * this._slideX); - - let actorBox = new Clutter.ActorBox(); - actorBox.x1 = alignX; --- -2.1.0 - diff --git a/SOURCES/gdm-support-pre-authenticated-logins-from-oVirt.patch b/SOURCES/gdm-support-pre-authenticated-logins-from-oVirt.patch deleted file mode 100644 index 7f7ff46..0000000 --- a/SOURCES/gdm-support-pre-authenticated-logins-from-oVirt.patch +++ /dev/null @@ -1,290 +0,0 @@ -From 70c1cc7ed45ff4f6fa3cf0601c98ca40a168ac57 Mon Sep 17 00:00:00 2001 -From: Vinzenz Feenstra -Date: Thu, 10 Oct 2013 10:21:47 +0200 -Subject: [PATCH] gdm: support pre-authenticated logins from oVirt - -oVirt is software for managing medium-to-large scale deployments of -virtual machine guests across multiple hosts. It supports a feature -where users can authenticate with a central server and get -transparently connected to a guest system and then automatically get logged -into that guest to an associated user session. - -Guests using old versions of GDM support this single-sign-on capability -by means of a greeter plugin, using the old greeter's extension -API. - -This commit adds similar support to the gnome-shell based login screen. - -How it works: - -* The OVirtCredentialsManager singleton listens for - - 'org.ovirt.vdsm.Credentials.UserAuthenticated' - - D-Bus signal on the system bus from the - - 'org.ovirt.vdsm.Credentials' - - bus name. The service that provides that bus name is called - the oVirt guest agent. It is also responsible for interacting - with the the central server to get user credentials. - -* This UserAuthenticated signal passes, as a parameter, the a token - which needs to be passed through to the PAM service that is specifically - set up to integrate with the oVirt authentication architecture. - The singleton object keeps the token internally so it can be queried - later on. - -* The OVirtCredentialsManager emits a signal 'user-authenticated' on - it's object once the dbus signal is triggered - -* When the 'user-authenticated' signal is emitted, the login screen - tells GDM to start user verification using the PAM service. The - authentication stack of the service includes a PAM module - provided by oVirt that securely retrieves user credentials - from the oVirt guest agent. The PAM module then forwards those - credentials on to other modules in the stack so, e.g., - the user's gnome keyring can be automatically unlocked. - -* In case of the screen shield being visible, it also will react on that - 'user-authenticated' signal and lift the shield. - In that case the login screen will check on construction time if - the signal has already been triggered, and a token is available. - If a token is available it will immediately trigger the functionality - as described above. - -Upstream-Bug-Url: https://bugzilla.gnome.org/show_bug.cgi?id=702162 -Signed-off-by: Vinzenz Feenstra -Bug-Url: https://bugzilla.redhat.com/854712 ---- - js/Makefile.am | 1 + - js/gdm/authPrompt.js | 13 ++++++++--- - js/gdm/oVirt.js | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++ - js/gdm/util.js | 31 ++++++++++++++++++++++++++ - js/ui/screenShield.js | 8 +++++++ - 5 files changed, 112 insertions(+), 3 deletions(-) - create mode 100644 js/gdm/oVirt.js - -diff --git a/js/Makefile.am b/js/Makefile.am -index 425b6fb..bfcc714 100644 ---- a/js/Makefile.am -+++ b/js/Makefile.am -@@ -21,6 +21,7 @@ nobase_dist_js_DATA = \ - gdm/batch.js \ - gdm/fingerprint.js \ - gdm/loginDialog.js \ -+ gdm/oVirt.js \ - gdm/powerMenu.js \ - gdm/realmd.js \ - gdm/util.js \ -diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index 2121f2e..ba66c42 100644 ---- a/js/gdm/authPrompt.js -+++ b/js/gdm/authPrompt.js -@@ -59,6 +59,7 @@ const AuthPrompt = new Lang.Class({ - this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); - this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); - this._userVerifier.connect('smartcard-status-changed', Lang.bind(this, this._onSmartcardStatusChanged)); -+ this._userVerifier.connect('ovirt-user-authenticated', Lang.bind(this, this._onOVirtUserAuthenticated)); - this.smartcardDetected = this._userVerifier.smartcardDetected; - - this.connect('next', Lang.bind(this, function() { -@@ -219,6 +220,11 @@ const AuthPrompt = new Lang.Class({ - this.emit('prompted'); - }, - -+ _onOVirtUserAuthenticated: function() { -+ if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) -+ this.reset(); -+ }, -+ - _onSmartcardStatusChanged: function() { - this.smartcardDetected = this._userVerifier.smartcardDetected; - -@@ -443,9 +449,10 @@ const AuthPrompt = new Lang.Class({ - // The user is constant at the unlock screen, so it will immediately - // respond to the request with the username - beginRequestType = BeginRequestType.PROVIDE_USERNAME; -- } else if (this._userVerifier.serviceIsForeground(GdmUtil.SMARTCARD_SERVICE_NAME)) { -+ } else if (this._userVerifier.serviceIsForeground(GdmUtil.OVIRT_SERVICE_NAME) || -+ this._userVerifier.serviceIsForeground(GdmUtil.SMARTCARD_SERVICE_NAME)) { - // We don't need to know the username if the user preempted the login screen -- // with a smartcard. -+ // with a smartcard or with preauthenticated oVirt credentials - beginRequestType = BeginRequestType.DONT_PROVIDE_USERNAME; - } else { - // In all other cases, we should get the username up front. -diff --git a/js/gdm/oVirt.js b/js/gdm/oVirt.js -new file mode 100644 -index 0000000..1a31f43 ---- /dev/null -+++ b/js/gdm/oVirt.js -@@ -0,0 +1,62 @@ -+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -+ -+const Gio = imports.gi.Gio; -+const Lang = imports.lang; -+const Signals = imports.signals; -+ -+const OVirtCredentialsIface = -+ -+ -+ -+; -+ -+const OVirtCredentialsInfo = Gio.DBusInterfaceInfo.new_for_xml(OVirtCredentialsIface); -+ -+let _oVirtCredentialsManager = null; -+ -+function OVirtCredentials() { -+ var self = new Gio.DBusProxy({ g_connection: Gio.DBus.system, -+ g_interface_name: OVirtCredentialsInfo.name, -+ g_interface_info: OVirtCredentialsInfo, -+ g_name: 'org.ovirt.vdsm.Credentials', -+ g_object_path: '/org/ovirt/vdsm/Credentials', -+ g_flags: (Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) }); -+ self.init(null); -+ return self; -+} -+ -+const OVirtCredentialsManager = new Lang.Class({ -+ Name: 'OVirtCredentialsManager', -+ _init: function() { -+ this._token = null; -+ -+ this._credentials = new OVirtCredentials(); -+ this._credentials.connectSignal('UserAuthenticated', -+ Lang.bind(this, this._onUserAuthenticated)); -+ }, -+ -+ _onUserAuthenticated: function(proxy, sender, [token]) { -+ this._token = token; -+ this.emit('user-authenticated', token); -+ }, -+ -+ hasToken: function() { -+ return this._token != null; -+ }, -+ -+ getToken: function() { -+ return this._token; -+ }, -+ -+ resetToken: function() { -+ this._token = null; -+ } -+}); -+Signals.addSignalMethods(OVirtCredentialsManager.prototype); -+ -+function getOVirtCredentialsManager() { -+ if (!_oVirtCredentialsManager) -+ _oVirtCredentialsManager = new OVirtCredentialsManager(); -+ -+ return _oVirtCredentialsManager; -+} -diff --git a/js/gdm/util.js b/js/gdm/util.js -index f421902..66852fd 100644 ---- a/js/gdm/util.js -+++ b/js/gdm/util.js -@@ -10,6 +10,7 @@ const St = imports.gi.St; - - const Batch = imports.gdm.batch; - const Fprint = imports.gdm.fingerprint; -+const OVirt = imports.gdm.oVirt; - const Main = imports.ui.main; - const Params = imports.misc.params; - const ShellEntry = imports.ui.shellEntry; -@@ -19,6 +20,7 @@ const Tweener = imports.ui.tweener; - const PASSWORD_SERVICE_NAME = 'gdm-password'; - const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint'; - const SMARTCARD_SERVICE_NAME = 'gdm-smartcard'; -+const OVIRT_SERVICE_NAME = 'gdm-ovirtcred'; - const FADE_ANIMATION_TIME = 0.16; - const CLONE_FADE_ANIMATION_TIME = 0.25; - -@@ -151,6 +153,14 @@ const ShellUserVerifier = new Lang.Class({ - this.reauthenticating = false; - - this._failCounter = 0; -+ -+ this._oVirtCredentialsManager = OVirt.getOVirtCredentialsManager(); -+ -+ if (this._oVirtCredentialsManager.hasToken()) -+ this._oVirtUserAuthenticated(this._oVirtCredentialsManager.getToken()); -+ -+ this._oVirtCredentialsManager.connect('user-authenticated', -+ Lang.bind(this, this._oVirtUserAuthenticated)); - }, - - begin: function(userName, hold) { -@@ -277,6 +287,11 @@ const ShellUserVerifier = new Lang.Class({ - })); - }, - -+ _oVirtUserAuthenticated: function(token) { -+ this._preemptingService = OVIRT_SERVICE_NAME; -+ this.emit('ovirt-user-authenticated'); -+ }, -+ - _checkForSmartcard: function() { - let smartcardDetected; - -@@ -455,6 +470,12 @@ const ShellUserVerifier = new Lang.Class({ - if (!this.serviceIsForeground(serviceName)) - return; - -+ if (serviceName == OVIRT_SERVICE_NAME) { -+ // The only question asked by this service is "Token?" -+ this.answerQuery(serviceName, this._oVirtCredentialsManager.getToken()); -+ return; -+ } -+ - this.emit('ask-question', serviceName, secretQuestion, '\u25cf'); - }, - -@@ -515,6 +536,16 @@ const ShellUserVerifier = new Lang.Class({ - }, - - _onConversationStopped: function(client, serviceName) { -+ // If the login failed with the preauthenticated oVirt credentials -+ // then discard the credentials and revert to default authentication -+ // mechanism. -+ if (this.serviceIsForeground(OVIRT_SERVICE_NAME)) { -+ this._oVirtCredentialsManager.resetToken(); -+ this._preemptingService = null; -+ this._verificationFailed(false); -+ return; -+ } -+ - // if the password service fails, then cancel everything. - // But if, e.g., fingerprint fails, still give - // password authentication a chance to succeed -diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js -index 1d296a2..ecc0bfa 100644 ---- a/js/ui/screenShield.js -+++ b/js/ui/screenShield.js -@@ -17,6 +17,7 @@ const Background = imports.ui.background; - const GnomeSession = imports.misc.gnomeSession; - const Hash = imports.misc.hash; - const Layout = imports.ui.layout; -+const OVirt = imports.gdm.oVirt; - const LoginManager = imports.misc.loginManager; - const Lightbox = imports.ui.lightbox; - const Main = imports.ui.main; -@@ -514,6 +515,13 @@ const ScreenShield = new Lang.Class({ - this._liftShield(true, 0); - })); - -+ this._oVirtCredentialsManager = OVirt.getOVirtCredentialsManager(); -+ this._oVirtCredentialsManager.connect('user-authenticated', -+ Lang.bind(this, function() { -+ if (this._isLocked) -+ this._liftShield(true, 0); -+ })); -+ - this._inhibitor = null; - this._aboutToSuspend = false; - this._loginManager = LoginManager.getLoginManager(); --- -1.8.3.1 - diff --git a/SOURCES/gnome-shell-favourite-apps-empathy.patch b/SOURCES/gnome-shell-favourite-apps-empathy.patch deleted file mode 100644 index 52c19f5..0000000 --- a/SOURCES/gnome-shell-favourite-apps-empathy.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -up gnome-shell-3.8.4/data/org.gnome.shell.gschema.xml.in.in.empathy gnome-shell-3.8.4/data/org.gnome.shell.gschema.xml.in.in ---- gnome-shell-3.8.4/data/org.gnome.shell.gschema.xml.in.in.empathy 2013-12-04 19:59:30.805795688 -0500 -+++ gnome-shell-3.8.4/data/org.gnome.shell.gschema.xml.in.in 2013-12-04 19:59:53.021745970 -0500 -@@ -32,7 +32,7 @@ - - - -- [ 'firefox.desktop', 'evolution.desktop', 'empathy.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'libreoffice-writer.desktop', 'nautilus.desktop', 'gnome-documents.desktop', 'yelp.desktop', 'gnome-terminal.desktop' ] -+ [ 'firefox.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'libreoffice-writer.desktop', 'nautilus.desktop', 'gnome-documents.desktop', 'yelp.desktop', 'gnome-terminal.desktop' ] - <_summary>List of desktop file IDs for favorite applications - <_description> - The applications corresponding to these identifiers diff --git a/SOURCES/gnome-shell-favourite-apps-firefox.patch b/SOURCES/gnome-shell-favourite-apps-firefox.patch index 206880a..7964871 100644 --- a/SOURCES/gnome-shell-favourite-apps-firefox.patch +++ b/SOURCES/gnome-shell-favourite-apps-firefox.patch @@ -1,26 +1,21 @@ ---- gnome-shell-3.1.91/data/org.gnome.shell.gschema.xml.in.in.firefox 2011-09-07 19:50:20.167547963 +0300 -+++ gnome-shell-3.1.91/data/org.gnome.shell.gschema.xml.in.in 2011-09-07 19:51:32.067106738 +0300 +--- gnome-shell-3.13.90/data/org.gnome.shell.gschema.xml.in.in.firefox 2014-08-20 20:28:07.601133033 +0200 ++++ gnome-shell-3.13.90/data/org.gnome.shell.gschema.xml.in.in 2014-08-20 20:28:41.741503518 +0200 @@ -31,7 +31,7 @@ -- [ 'epiphany.desktop', 'evolution.desktop', 'empathy.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'libreoffice-writer.desktop', 'nautilus.desktop', 'gnome-documents.desktop' ] -+ [ 'firefox.desktop', 'evolution.desktop', 'empathy.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'libreoffice-writer.desktop', 'nautilus.desktop', 'gnome-documents.desktop' ] +- [ 'epiphany.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ] ++ [ 'firefox.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ] <_summary>List of desktop file IDs for favorite applications <_description> The applications corresponding to these identifiers --- a/js/ui/appFavorites.js +++ b/js/ui/appFavorites.js -@@ -24,6 +24,12 @@ const AppFavorites = new Lang.Class({ - - _reload: function() { - let ids = global.settings.get_strv(this.FAVORITE_APPS_KEY); -+ // Fedora: Replace old mozilla-firefox.desktop with firefox.desktop, -+ for (let i = 0; i < ids.length; i++) { -+ if (ids[i] == 'mozilla-firefox.desktop') -+ ids[i] = 'firefox.desktop' -+ } -+ - let appSys = Shell.AppSystem.get_default(); - let apps = ids.map(function (id) { - return appSys.lookup_app(id); +@@ -31,6 +31,7 @@ const RENAMED_DESKTOP_IDS = { + 'gnotravex.desktop': 'gnome-tetravex.desktop', + 'gnotski.desktop': 'gnome-klotski.desktop', + 'gtali.desktop': 'tali.desktop', ++ 'mozilla-firefox.desktop': 'firefox.desktop', + 'nautilus.desktop': 'org.gnome.Nautilus.desktop', + 'polari.desktop': 'org.gnome.Polari.desktop', + 'totem.desktop': 'org.gnome.Totem.desktop', diff --git a/SOURCES/gnome-shell-favourite-apps-terminal.patch b/SOURCES/gnome-shell-favourite-apps-terminal.patch index a94c9ea..7b4e835 100644 --- a/SOURCES/gnome-shell-favourite-apps-terminal.patch +++ b/SOURCES/gnome-shell-favourite-apps-terminal.patch @@ -5,8 +5,8 @@ diff -up gnome-shell-3.8.4/data/org.gnome.shell.gschema.xml.in.in.terminal gnome -- [ 'firefox.desktop', 'evolution.desktop', 'empathy.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'libreoffice-writer.desktop', 'nautilus.desktop', 'gnome-documents.desktop', 'yelp.desktop' ] -+ [ 'firefox.desktop', 'evolution.desktop', 'empathy.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'libreoffice-writer.desktop', 'nautilus.desktop', 'gnome-documents.desktop', 'yelp.desktop', 'gnome-terminal.desktop' ] +- [ 'firefox.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop', 'yelp.desktop' ] ++ [ 'firefox.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop', 'yelp.desktop', 'gnome-terminal.desktop' ] <_summary>List of desktop file IDs for favorite applications <_description> The applications corresponding to these identifiers diff --git a/SOURCES/gnome-shell-favourite-apps-yelp.patch b/SOURCES/gnome-shell-favourite-apps-yelp.patch index 876b64f..7d68117 100644 --- a/SOURCES/gnome-shell-favourite-apps-yelp.patch +++ b/SOURCES/gnome-shell-favourite-apps-yelp.patch @@ -16,8 +16,8 @@ index 27adddc..eee70b1 100644 -- [ 'firefox.desktop', 'evolution.desktop', 'empathy.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'libreoffice-writer.desktop', 'nautilus.desktop', 'gnome-documents.desktop' ] -+ [ 'firefox.desktop', 'evolution.desktop', 'empathy.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'libreoffice-writer.desktop', 'nautilus.desktop', 'gnome-documents.desktop', 'yelp.desktop' ] +- [ 'firefox.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ] ++ [ 'firefox.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop', 'yelp.desktop' ] <_summary>List of desktop file IDs for favorite applications <_description> The applications corresponding to these identifiers diff --git a/SOURCES/login-banner-fixes.patch b/SOURCES/login-banner-fixes.patch deleted file mode 100644 index 55bb72b..0000000 --- a/SOURCES/login-banner-fixes.patch +++ /dev/null @@ -1,1989 +0,0 @@ -From b0f59711785d43d0d3dd76e09064e36bea516e1b Mon Sep 17 00:00:00 2001 -From: Ray Strode -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 -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 -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 -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 -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 - diff --git a/SOURCES/login-screen-backport.patch b/SOURCES/login-screen-backport.patch index 08c265c..a5d976f 100644 --- a/SOURCES/login-screen-backport.patch +++ b/SOURCES/login-screen-backport.patch @@ -1,18181 +1,1221 @@ -From c41bf58d6214f585c29394e6a1a87b6650e20bce Mon Sep 17 00:00:00 2001 +From 067ae5de5b42169d0105ce1deb1147f640308d27 Mon Sep 17 00:00:00 2001 From: Ray Strode -Date: Fri, 14 Jun 2013 08:14:34 -0400 -Subject: [PATCH 01/69] loginDialog: clean up import lines +Date: Mon, 10 Nov 2014 14:36:07 -0500 +Subject: [PATCH 01/19] loginDialog: allocate children manually -There are a few unused imports, and some import lines -out of order. +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 tries to clean it all up. +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=702818 +https://bugzilla.gnome.org/show_bug.cgi?id=703972 --- - js/gdm/loginDialog.js | 14 +++++--------- - 1 file changed, 5 insertions(+), 9 deletions(-) + 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 4355c1d..c3e26fa 100644 +index 7fbeb3e..ced6fc2 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js -@@ -1,73 +1,69 @@ - // -*- 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 Clutter = imports.gi.Clutter; --const CtrlAltTab = imports.ui.ctrlAltTab; -+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 Lang = imports.lang; --const Pango = imports.gi.Pango; --const Realmd = imports.gdm.realmd; --const Signals = imports.signals; - const Shell = imports.gi.Shell; -+const Signals = imports.signals; - const St = imports.gi.St; --const Gdm = imports.gi.Gdm; - - const Batch = imports.gdm.batch; --const Fprint = imports.gdm.fingerprint; -+const CtrlAltTab = imports.ui.ctrlAltTab; - const GdmUtil = imports.gdm.util; --const Lightbox = imports.ui.lightbox; - const Main = imports.ui.main; - const ModalDialog = imports.ui.modalDialog; --const PanelMenu = imports.ui.panelMenu; -+const Realmd = imports.gdm.realmd; - const Tweener = imports.ui.tweener; - const UserMenu = imports.ui.userMenu; - const UserWidget = imports.ui.userWidget; +@@ -368,12 +368,12 @@ const LoginDialog = new Lang.Class({ + Name: 'LoginDialog', - const _FADE_ANIMATION_TIME = 0.25; - const _SCROLL_ANIMATION_TIME = 0.5; - const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0; - const _LOGO_ICON_HEIGHT = 48; + _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); - let _loginDialog = null; + 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); - const UserListItem = new Lang.Class({ - Name: 'UserListItem', +@@ -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({ - _init: function(user) { - this.user = user; - this._userChangedId = this.user.connect('changed', - Lang.bind(this, this._onUserChanged)); + 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(); - let layout = new St.BoxLayout({ vertical: false }); - this.actor = new St.Button({ style_class: 'login-dialog-user-list-item', - button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, - can_focus: true, - child: layout, - reactive: true, - x_align: St.Align.START, - x_fill: true }); +@@ -489,6 +485,86 @@ const LoginDialog = new Lang.Class({ + Lang.bind(this, this._updateDisableUserList)); + }, - this._userAvatar = new UserMenu.UserAvatarWidget(this.user, - { styleClass: 'login-dialog-user-list-item-icon' }); ++ _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', -- -1.8.3.1 +2.5.0 -From 18fe9560aea74461b0c6e77ec7c888f5b5d447f8 Mon Sep 17 00:00:00 2001 +From b9975d16c2d253bf5636d6ad95e0c22d2b93d05a Mon Sep 17 00:00:00 2001 From: Ray Strode -Date: Tue, 25 Jun 2013 12:55:21 -0400 -Subject: [PATCH 02/69] loginDialog: drop use of modal dialog +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. -The login screen is no longer even remotely dialog-like, so -using ModalDialog is pretty weird. It also makes it difficult -to put the session list in the same place as the spinner. +This 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 loginDialog away from using modal dialog. +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=702818 +https://bugzilla.gnome.org/show_bug.cgi?id=703972 --- - data/theme/gnome-shell.css | 6 ++ - js/gdm/loginDialog.js | 192 +++++++++++++++++++++++++++++++-------------- - 2 files changed, 138 insertions(+), 60 deletions(-) + 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 34a4cb2..7dac907 100644 +index 04994fa..2ec51b2 100644 --- a/data/theme/gnome-shell.css +++ b/data/theme/gnome-shell.css -@@ -350,128 +350,134 @@ StScrollBar StButton#vhandle:active { - border-color: #666666; - color: #9f9f9f; - background-gradient-direction: none; - background-color: rgba(102, 102, 102, 0.15); - } - - /* Common radii */ - - #searchEntry, - .modal-dialog-button, - .notification-button, - .hotplug-notification-item, - .app-view-controls { - border-radius: 18px; - } - - .app-view-control:first-child:ltr, - .app-view-control:last-child:rtl { - border-radius: 18px 0px 0px 18px; - border-right-width: 0px; - } - - .app-view-control:last-child:ltr, - .app-view-control:first-child:rtl { - border-radius: 0px 18px 18px 0px; - } - - /* Entries */ - - #searchEntry, -+.login-dialog StEntry, - .notification StEntry, - .modal-dialog StEntry { - color: rgb(64, 64, 64); - caret-color: rgb(64, 64, 64); - font-size: 12pt; - caret-size: 1px; - selected-color: white; - padding: 4px 12px; - } - - #searchEntry, -+.login-dialog StEntry, - .run-dialog-entry, - .notification StEntry { - border: 2px solid rgba(245,245,245,0.2); - background-gradient-start: rgba(5,5,6,0.1); - background-gradient-end: rgba(254,254,254,0.1); - background-gradient-direction: vertical; - transition-duration: 300ms; - box-shadow: inset 0px 2px 4px rgba(0,0,0,0.6); - } - - #searchEntry:focus, - #searchEntry:hover, -+.login-dialog StEntry:focus, - .notification StEntry:focus, - .modal-dialog StEntry { - border: 2px solid rgb(136,138,133); - background-gradient-start: rgb(200,200,200); - background-gradient-end: white; - background-gradient-direction: vertical; - box-shadow: inset 0px 2px 4px rgba(0,0,0,0.6); - } - -+.login-dialog StEntry:focus, - .notification StEntry:focus, - .modal-dialog StEntry:focus { - border: 2px solid #3465a4; - } - - #searchEntry { - border-color: rgba(245,245,245,0.3); - color: rgb(192, 192, 192); - caret-color: rgb(192, 192, 192); - } - - #searchEntry:hover { - color: rgb(128, 128, 128); - caret-color: rgb(128, 128, 128); - } - - #searchEntry:focus { - color: rgb(64, 64, 64); - caret-color: rgb(64, 64, 64); - font-weight: bold; - transition-duration: 0ms; - } - -+.login-dialog StEntry, - .notification StEntry, - .modal-dialog StEntry { - border-radius: 5px; - padding: 4px 4px; - } - - .prompt-dialog-password-entry .capslock-warning, - .login-dialog-prompt-entry .capslock-warning { - icon-size: 16px; - warning-color: #999; - padding: 0 4px; - } - -+.login-dialog StEntry:insensitive, - .modal-dialog StEntry:insensitive { - border-color: #666666; - color: #9f9f9f; - border: 2px solid #9f9f9f; - background-gradient-direction: none; - background-color: rgba(102, 102, 102, 0.15); - box-shadow: inset 0 0 rgba(0,0,0,1.0); - } - - /* Panel */ - - #panel { - background-color: black; - font-weight: bold; - height: 1.86em; +@@ -2392,6 +2392,10 @@ StScrollBar StButton#vhandle:active { } - #panel.lock-screen { - background-color: rgba(0,0,0,0.3); - } + /* Login Dialog */ ++.login-dialog-banner-view { ++ padding-top: 24px; ++ max-width: 23em; ++} - #panel.unlock-screen, - #panel.login-screen { - background-color: transparent; + .framed-user-icon { + border: 2px solid #8b8b8b; +@@ -2404,11 +2408,7 @@ StScrollBar StButton#vhandle:active { } - #panelLeft, #panelCenter { - spacing: 4px; + .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 c3e26fa..6b36b45 100644 +index ced6fc2..41aa89c 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js -@@ -1,75 +1,80 @@ - // -*- 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; +@@ -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); -+const Panel = imports.ui.panel; - const Batch = imports.gdm.batch; - const CtrlAltTab = imports.ui.ctrlAltTab; - const GdmUtil = imports.gdm.util; -+const Layout = imports.ui.layout; - const Main = imports.ui.main; --const ModalDialog = imports.ui.modalDialog; - 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 _WORK_SPINNER_ICON_SIZE = 24; -+const _WORK_SPINNER_ANIMATION_DELAY = 1.0; -+const _WORK_SPINNER_ANIMATION_TIME = 0.3; - const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0; - const _LOGO_ICON_HEIGHT = 48; - - let _loginDialog = null; - - const UserListItem = new Lang.Class({ - Name: 'UserListItem', - - _init: function(user) { - this.user = user; - this._userChangedId = this.user.connect('changed', - Lang.bind(this, this._onUserChanged)); - - let layout = new St.BoxLayout({ vertical: false }); - this.actor = new St.Button({ style_class: 'login-dialog-user-list-item', - button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, - can_focus: true, - child: layout, - reactive: true, +- 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._userAvatar = new UserMenu.UserAvatarWidget(this.user, - { styleClass: 'login-dialog-user-list-item-icon' }); - layout.add(this._userAvatar.actor); - let textLayout = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-text-box', - vertical: true }); - layout.add(textLayout, { expand: true }); - - this._nameLabel = new St.Label({ style_class: 'login-dialog-user-list-item-name' }); -@@ -442,205 +447,223 @@ const SessionList = new Lang.Class({ - - if (ids.length <= 1) { - this._box.hide(); - this._button.hide(); - } else { - this._button.show(); - this._box.show(); - } - - for (let i = 0; i < ids.length; i++) { - let [sessionName, sessionDescription] = Gdm.get_session_name_and_description(ids[i]); - - let item = new SessionListItem(ids[i], sessionName); - this._itemList.add_actor(item.actor); - this._items[ids[i]] = item; - - if (!this._activeSessionId) - this.setActiveSession(ids[i]); - - item.connect('activate', - Lang.bind(this, function() { - this.setActiveSession(item.id); - })); - } - } - }); - Signals.addSignalMethods(SessionList.prototype); - - const LoginDialog = new Lang.Class({ - Name: 'LoginDialog', -- Extends: ModalDialog.ModalDialog, - - _init: function(parentActor) { -- this.parent({ shellReactive: true, -- styleClass: 'login-dialog', -- parentActor: parentActor, -- keybindingMode: Shell.KeyBindingMode.LOGIN_SCREEN, -- shouldFadeIn: false }); -- this.connect('destroy', -- Lang.bind(this, this._onDestroy)); -- this.connect('opened', -- Lang.bind(this, this._onOpened)); -+ this.actor = new St.Widget({ accessible_role: Atk.Role.WINDOW, -+ style_class: 'login-dialog', -+ visible: false }); ++ 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.actor.add_constraint(new Layout.MonitorConstraint({ primary: true })); -+ this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); -+ parentActor.add_child(this.actor); + 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)); + }, - this._userManager = AccountsService.UserManager.get_default() - this._greeterClient = new Gdm.Client(); ++ _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(); - if (GLib.getenv('GDM_GREETER_TEST') != '1') { - this._greeter = this._greeterClient.get_greeter_sync(null); +@@ -518,9 +544,21 @@ const LoginDialog = new Lang.Class({ + let dialogHeight = dialogBox.y2 - dialogBox.y1; - this._greeter.connect('default-session-name-changed', - Lang.bind(this, this._onDefaultSessionChanged)); + // 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; ++ } - this._greeter.connect('session-opened', - Lang.bind(this, this._onSessionOpened)); - this._greeter.connect('timed-login-requested', - Lang.bind(this, this._onTimedLoginRequested)); + let userSelectionAllocation = null; + let userSelectionHeight = 0; +@@ -537,16 +575,37 @@ const LoginDialog = new Lang.Class({ } - this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient); - this._userVerifier.connect('ask-question', Lang.bind(this, this._askQuestion)); - this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage)); - this._userVerifier.connect('verification-failed', Lang.bind(this, this._verificationFailed)); - this._userVerifier.connect('reset', Lang.bind(this, this._reset)); - this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint)); - this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint)); - this._verifyingUser = false; - - 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', - vertical: true }); -- this.contentLayout.add(this._userSelectionBox); -+ this._userSelectionBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, -+ align_axis: Clutter.AlignAxis.BOTH, -+ factor: 0.5 })); -+ this.actor.add_child(this._userSelectionBox); - - this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner', - text: '' }); - 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 }); + // 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; -- this.setInitialKeyFocus(this._userList.actor); -- - this._promptBox = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', - vertical: true }); -- this.contentLayout.add(this._promptBox, -- { expand: true, -- x_fill: true, -- y_fill: true, -- x_align: St.Align.START }); +- // 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; + -+ this._promptBox.connect('button-press-event', -+ Lang.bind(this, function(actor, event) { -+ if (event.get_key_symbol() == Clutter.KEY_Escape) { -+ this.cancel(); -+ } -+ })); ++ bannerAllocation.y1 += yShift; ++ bannerAllocation.y2 += yShift; ++ } else { ++ // recompute banner height to be constrained if there's no room for its ++ // requested height + -+ this._promptBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, -+ align_axis: Clutter.AlignAxis.BOTH, -+ factor: 0.5 })); -+ this.actor.add_child(this._promptBox); - this._promptUser = new St.Bin({ x_fill: true, - x_align: St.Align.START }); - this._promptBox.add(this._promptUser, - { x_align: St.Align.START, - x_fill: true, - y_fill: true, - expand: true }); - this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' }); - - this._promptBox.add(this._promptLabel, - { expand: true, - x_fill: true, - y_fill: true, - x_align: St.Align.START }); - this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry', - can_focus: true }); - this._promptEntryTextChangedId = 0; - this._promptEntryActivateId = 0; - this._promptBox.add(this._promptEntry, - { expand: true, - x_fill: true, - y_fill: false, - x_align: St.Align.START }); - - this._promptMessage = new St.Label({ visible: false }); - this._promptBox.add(this._promptMessage, { x_fill: true }); - - this._promptLoginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' }); - this._promptLoginHint.hide(); - this._promptBox.add(this._promptLoginHint); - -- this._signInButton = null; -- - this._sessionList = new SessionList(); - this._sessionList.connect('session-activated', - Lang.bind(this, function(list, sessionId) { - this._greeter.call_select_session_sync (sessionId, null); - })); - - this._promptBox.add(this._sessionList.actor, - { expand: true, - x_fill: false, - y_fill: true, - x_align: St.Align.START }); -+ this._buttonBox = new St.BoxLayout({ style_class: 'modal-dialog-button-box', -+ vertical: false }); -+ this._promptBox.add(this._buttonBox, -+ { expand: true, -+ x_align: St.Align.MIDDLE, -+ y_align: St.Align.END }); -+ this._cancelButton = null; -+ this._signInButton = null; ++ // First figure out how much space there is without the banner ++ leftOverYSpace += bannerHeight; + - this._promptBox.hide(); - - // 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._hideUserListAndLogIn)); - - this._userSelectionBox.add(this._notListedButton, - { expand: false, - x_align: St.Align.START, - x_fill: true }); - - this._logoBin = new St.Bin({ style_class: 'login-dialog-logo-bin', y_expand: true }); - this._logoBin.set_y_align(Clutter.ActorAlign.END); -- this.backgroundStack.add_actor(this._logoBin); -+ this._logoBin.add_constraint(new Clutter.AlignConstraint({ source: this.actor, -+ align_axis: Clutter.AlignAxis.X_AXIS, -+ factor: 0.5 })); -+ this._logoBin.add_constraint(new Clutter.AlignConstraint({ source: this.actor, -+ align_axis: Clutter.AlignAxis.Y_AXIS, -+ factor: 1.0 })); -+ this.actor.add_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); - })); - - }, - - _updateDisableUserList: function() { - let disableUserList = this._settings.get_boolean(GdmUtil.DISABLE_USER_LIST_KEY); - - // If this is the first time around, set initial focus - if (this._disableUserList == undefined && disableUserList) - this.setInitialKeyFocus(this._promptEntry); - - if (disableUserList != this._disableUserList) { - this._disableUserList = disableUserList; -@@ -667,65 +690,92 @@ const LoginDialog = new Lang.Class({ - return; - - let icon = null; - if (this._logoFileUri) - icon = this._textureCache.load_uri_async(this._logoFileUri, - -1, _LOGO_ICON_HEIGHT); - this._logoBin.set_child(icon); - }, - - _updateLogo: function() { - let path = this._settings.get_string(GdmUtil.LOGO_KEY); ++ // 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; - this._logoFileUri = path ? Gio.file_new_for_path(path).get_uri() : null; - this._updateLogoTexture(this._textureCache, this._logoFileUri); - }, +- // Always expand the bottom the same as the top since it's centered ++ if (leftOverYSpace > 0) { ++ let topExpansion = leftOverYSpace / 2; + let bottomExpansion = topExpansion; - _reset: function() { - this._userVerifier.clear(); + userSelectionAllocation.y1 -= topExpansion; +@@ -555,6 +614,10 @@ const LoginDialog = new Lang.Class({ + } - this._updateSensitivity(true); - this._promptMessage.hide(); - this._user = null; - this._verifyingUser = false; + // Finally hand out the allocations ++ if (bannerAllocation) { ++ this._bannerView.allocate(bannerAllocation, flags); ++ } ++ + if (authPromptAllocation) + this._authPrompt.actor.allocate(authPromptAllocation, flags); - if (this._disableUserList) - this._hideUserListAndLogIn(); - else - this._showUserList(); +@@ -617,6 +680,18 @@ const LoginDialog = new Lang.Class({ + } }, -+ _setWorking: function(working) { -+ if (!this._workSpinner) -+ return; ++ _fadeInBannerView: function() { ++ Tweener.addTween(this._bannerView, ++ { opacity: 255, ++ time: _FADE_ANIMATION_TIME, ++ transition: 'easeOutQuad' }); ++ }, + -+ Tweener.removeTweens(this._workSpinner.actor); -+ if (working) { -+ this._workSpinner.play(); -+ Tweener.addTween(this._workSpinner.actor, -+ { opacity: 255, -+ delay: _WORK_SPINNER_ANIMATION_DELAY, -+ time: _WORK_SPINNER_ANIMATION_TIME, -+ transition: 'linear' -+ }); -+ } else { -+ Tweener.addTween(this._workSpinner.actor, -+ { opacity: 0, -+ time: _WORK_SPINNER_ANIMATION_TIME, -+ transition: 'linear', -+ onCompleteScope: this, -+ onComplete: function() { -+ if (this._workSpinner) -+ this._workSpinner.stop(); -+ } -+ }); -+ } ++ _hideBannerView: function() { ++ Tweener.removeTweens(this._bannerView); ++ this._bannerView.opacity = 0; + }, + - _verificationFailed: function() { - this._promptEntry.text = ''; - - this._updateSensitivity(true); -- this.setWorking(false); -+ this._setWorking(false); - }, - - _onDefaultSessionChanged: function(client, sessionId) { - this._sessionList.setActiveSession(sessionId); + _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(); }, - _showMessage: function(userVerifier, message, styleClass) { - if (message) { - this._promptMessage.text = message; - this._promptMessage.styleClass = styleClass; - this._promptMessage.show(); - } else { - this._promptMessage.hide(); - } + _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({ }, - _showLoginHint: function(verifier, message) { - this._promptLoginHint.set_text(message) - this._promptLoginHint.show(); - this._promptLoginHint.opacity = 255; - }, + _onAllocate: function (actor, dialogBox, flags) { ++ let dialogWidth = dialogBox.x2 - dialogBox.x1; + let dialogHeight = dialogBox.y2 - dialogBox.y1; - _hideLoginHint: function() { - this._promptLoginHint.hide(); - this._promptLoginHint.set_text(''); - }, + // First find out what space the children require +@@ -555,9 +556,11 @@ const LoginDialog = new Lang.Class({ - cancel: function() { - if (this._verifyingUser) - this._userVerifier.cancel(); -@@ -737,218 +787,238 @@ const LoginDialog = new Lang.Class({ - this._sessionList.actor.hide(); - this._promptLabel.show(); - this._promptEntry.show(); - this._promptLoginHint.opacity = 0; - this._promptLoginHint.show(); - this._promptBox.opacity = 0; - this._promptBox.show(); - Tweener.addTween(this._promptBox, - { opacity: 255, - time: _FADE_ANIMATION_TIME, - transition: 'easeOutQuad' }); + 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; + } - if ((this._user && !this._user.is_logged_in()) || this._verifyingUser) - this._sessionList.actor.show(); + let userSelectionAllocation = null; +@@ -574,7 +577,9 @@ const LoginDialog = new Lang.Class({ + logoHeight = logoAllocation.y2 - logoAllocation.y1; + } - this._promptEntry.grab_key_focus(); +- // 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; - let hold = new Batch.Hold(); - let tasks = [function() { - this._prepareDialog(forSecret, hold); - }, - - hold]; - - let batch = new Batch.ConcurrentBatch(this, tasks); - - return batch.run(); - }, - - _prepareDialog: function(forSecret, hold) { -- this.buttonLayout.visible = true; -- this.clearButtons(); -- -- if (!this._disableUserList || this._verifyingUser) -- this.addButton({ action: Lang.bind(this, this.cancel), -- label: _("Cancel"), -- key: Clutter.Escape }, -- { expand: true, -- x_fill: false, -- y_fill: false, -- x_align: St.Align.START, -- y_align: St.Align.MIDDLE }); -- this.placeSpinner({ expand: false, -- x_fill: false, -- y_fill: false, -- x_align: St.Align.END, -- y_align: St.Align.MIDDLE }); -- this._signInButton = this.addButton({ action: Lang.bind(this, function() { -- hold.release(); -- }), -- label: forSecret ? C_("button", "Sign In") : _("Next"), -- default: true }, -- { expand: false, -- x_fill: false, -- y_fill: false, -- x_align: St.Align.END, -- y_align: St.Align.MIDDLE }); -+ this._buttonBox.visible = true; -+ this._buttonBox.destroy_all_children(); -+ -+ if (!this._disableUserList || this._verifyingUser) { -+ this._cancelButton = new St.Button({ style_class: 'modal-dialog-button', -+ button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, -+ reactive: true, -+ can_focus: true, -+ label: _("Cancel") }); -+ this._cancelButton.connect('clicked', -+ Lang.bind(this, function() { -+ this.cancel(); -+ })); -+ this._buttonBox.add(this._cancelButton, -+ { expand: true, -+ x_fill: false, -+ y_fill: false, -+ x_align: St.Align.START, -+ y_align: St.Align.END }); -+ } -+ -+ let spinnerIcon = global.datadir + '/theme/process-working.svg'; -+ this._workSpinner = new Panel.AnimatedIcon(spinnerIcon, _WORK_SPINNER_ICON_SIZE); -+ this._workSpinner.actor.opacity = 0; -+ this._workSpinner.actor.show(); -+ -+ this._buttonBox.add(this._workSpinner.actor, -+ { expand: false, -+ x_align: St.Align.END }); -+ -+ this._signInButton = new St.Button({ style_class: 'modal-dialog-button', -+ button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, -+ reactive: true, -+ can_focus: true, -+ label: forSecret ? C_("button", "Sign In") : _("Next") }); -+ this._signInButton.connect('clicked', -+ Lang.bind(this, function() { -+ hold.release(); -+ })); -+ this._signInButton.add_style_pseudo_class('default'); -+ this._buttonBox.add(this._signInButton, -+ { expand: true, -+ x_fill: false, -+ y_fill: false, -+ x_align: St.Align.END, -+ y_align: St.Align.END }); - - this._updateSignInButtonSensitivity(this._promptEntry.text.length > 0); - - this._promptEntryTextChangedId = - this._promptEntry.clutter_text.connect('text-changed', - Lang.bind(this, function() { - this._updateSignInButtonSensitivity(this._promptEntry.text.length > 0); - })); - - this._promptEntryActivateId = - this._promptEntry.clutter_text.connect('activate', function() { - hold.release(); - }); - }, - - _updateSensitivity: function(sensitive) { - this._promptEntry.reactive = sensitive; - this._promptEntry.clutter_text.editable = sensitive; - this._sessionList.updateSensitivity(sensitive); - this._updateSignInButtonSensitivity(sensitive); - }, - - _updateSignInButtonSensitivity: function(sensitive) { - if (this._signInButton) { - this._signInButton.reactive = sensitive; - this._signInButton.can_focus = sensitive; - } - }, - - _hidePrompt: function() { -- this.setButtons([]); -+ this._buttonBox.destroy_all_children(); - - if (this._promptEntryTextChangedId > 0) { - this._promptEntry.clutter_text.disconnect(this._promptEntryTextChangedId); - this._promptEntryTextChangedId = 0; - } - - if (this._promptEntryActivateId > 0) { - this._promptEntry.clutter_text.disconnect(this._promptEntryActivateId); - this._promptEntryActivateId = 0; - } - -- this.setWorking(false); -+ this._setWorking(false); - this._promptBox.hide(); - this._promptLoginHint.hide(); - - this._promptUser.set_child(null); - - this._updateSensitivity(true); - this._promptEntry.set_text(''); - - this._sessionList.close(); - this._promptLoginHint.hide(); - -- this.clearButtons(); -+ this._buttonBox.destroy_all_children(); - this._signInButton = null; -+ this._cancelButton = null; - }, - - _askQuestion: function(verifier, serviceName, question, passwordChar) { - this._promptLabel.set_text(question); - - this._updateSensitivity(true); - this._promptEntry.set_text(''); - this._promptEntry.clutter_text.set_password_char(passwordChar); - - let tasks = [function() { - return this._showPrompt(!!passwordChar); - }, - - function() { - let text = this._promptEntry.get_text(); - this._updateSensitivity(false); -- this.setWorking(true); -+ this._setWorking(true); - this._userVerifier.answerQuery(serviceName, text); - }]; - - let batch = new Batch.ConsecutiveBatch(this, tasks); - return batch.run(); - }, - - _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._showLoginHint(null, _("(e.g., user or %s)").format(hint)); - }, - - _askForUsernameAndLogIn: function() { - this._promptLabel.set_text(_("Username: ")); - this._promptEntry.set_text(''); - this._promptEntry.clutter_text.set_password_char(''); - - let realmManager = new Realmd.Manager(); - let signalId = realmManager.connect('login-format-changed', - Lang.bind(this, this._showRealmLoginHint)); - this._showRealmLoginHint(realmManager.loginFormat); - - let tasks = [this._showPrompt, - - function() { - let userName = this._promptEntry.get_text(); - this._promptEntry.reactive = false; - return this._beginVerificationForUser(userName); - }, - - function() { - realmManager.disconnect(signalId) - realmManager.release(); - }]; - - let batch = new Batch.ConsecutiveBatch(this, tasks); - return batch.run(); - }, - - _startSession: function(serviceName) { -- Tweener.addTween(this.dialogLayout, -+ Tweener.addTween(this.actor, - { opacity: 0, - time: _FADE_ANIMATION_TIME, - transition: 'easeOutQuad', - onUpdate: function() { - let children = Main.layoutManager.uiGroup.get_children(); - - for (let i = 0; i < children.length; i++) { - if (children[i] != Main.layoutManager.screenShieldGroup) -- children[i].opacity = this.dialogLayout.opacity; -+ children[i].opacity = this.actor.opacity; - } - }, - onUpdateScope: this, - onComplete: function() { - Mainloop.idle_add(Lang.bind(this, function() { - this._greeter.call_start_session_when_ready_sync(serviceName, true, null); - return false; - })); - }, - onCompleteScope: this }); - }, - - _onSessionOpened: function(client, serviceName) { - if (!this._userVerifier.hasPendingMessages) { - this._startSession(serviceName); - } else { - let signalId = this._userVerifier.connect('no-more-messages', - Lang.bind(this, function() { - this._userVerifier.disconnect(signalId); - this._startSession(serviceName); - })); - } - }, - - _waitForItemForUser: function(userName) { - let item = this._userList.getItemFromUserName(userName); - - if (item) - return null; - -@@ -1122,48 +1192,50 @@ const LoginDialog = new Lang.Class({ - batch.run(); - }, - - _onDestroy: function() { - if (this._userManagerLoadedId) { - this._userManager.disconnect(this._userManagerLoadedId); - this._userManagerLoadedId = 0; - } - }, - - _loadUserList: function() { - let users = this._userManager.list_users(); - - for (let i = 0; i < users.length; i++) { - this._userList.addUser(users[i]); - } - - this._updateDisableUserList(); - - this._userManager.connect('user-added', - Lang.bind(this, function(userManager, user) { - this._userList.addUser(user); - })); - - this._userManager.connect('user-removed', - Lang.bind(this, function(userManager, user) { - this._userList.removeUser(user); - })); - }, - -- _onOpened: function() { -- Main.ctrlAltTabManager.addGroup(this.dialogLayout, -+ open: function() { -+ Main.ctrlAltTabManager.addGroup(this.actor, - _("Login Window"), - 'dialog-password-symbolic', - { sortGroup: CtrlAltTab.SortGroup.MIDDLE }); -+ this._userList.actor.grab_key_focus(); -+ this.actor.show(); - -+ return true; - }, - - close: function() { -- this.parent(); -- - Main.ctrlAltTabManager.removeGroup(this.dialogLayout); - }, - - addCharacter: function(unichar) { - this._promptEntry.clutter_text.insert_unichar(unichar); - }, - }); -+Signals.addSignalMethods(LoginDialog.prototype); +@@ -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 -- -1.8.3.1 +2.5.0 -From f23e8a56ea95b904d5fc87bbdb9e440a8676e717 Mon Sep 17 00:00:00 2001 +From f349bc2c4b437430dfc65d13bba24e39c5ab8c59 Mon Sep 17 00:00:00 2001 From: Ray Strode -Date: Wed, 26 Jun 2013 10:52:02 -0400 -Subject: [PATCH 03/69] loginDialog: don't show Not Listed? button before user - list +Date: Thu, 22 Jan 2015 14:00:01 -0500 +Subject: [PATCH 04/19] loginDialog: fix reactivity of first user in user list -Right now, there's a weird flicker at start up where the -Not Listed? button shows up before the user list, which looks -pretty bad if you're watching for it. +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 problem by hiding the Not Listed button -initially and showing it at the appropriate time. +This commit fixes that by hiding the banner explicitly. -https://bugzilla.gnome.org/show_bug.cgi?id=703132 +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 6b36b45..4cbb0c9 100644 +index 575effa..930f82b 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js -@@ -595,60 +595,61 @@ const LoginDialog = new Lang.Class({ - this._promptBox.add(this._sessionList.actor, - { expand: true, - x_fill: false, - y_fill: true, - x_align: St.Align.START }); - this._buttonBox = new St.BoxLayout({ style_class: 'modal-dialog-button-box', - vertical: false }); - this._promptBox.add(this._buttonBox, - { expand: true, - x_align: St.Align.MIDDLE, - y_align: St.Align.END }); - this._cancelButton = null; - this._signInButton = null; - - this._promptBox.hide(); - - // translators: this message is shown below the user list on the - // 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._hideUserListAndLogIn)); -+ this._notListedButton.hide(); - - this._userSelectionBox.add(this._notListedButton, - { expand: false, - x_align: St.Align.START, - x_fill: true }); - - this._logoBin = new St.Bin({ style_class: 'login-dialog-logo-bin', y_expand: true }); - this._logoBin.set_y_align(Clutter.ActorAlign.END); - this._logoBin.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.X_AXIS, - factor: 0.5 })); - this._logoBin.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.Y_AXIS, - factor: 1.0 })); - this.actor.add_child(this._logoBin); - this._updateLogo(); - - 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', -@@ -1127,60 +1128,61 @@ const LoginDialog = new Lang.Class({ - - if (event.type() == Clutter.EventType.KEY_PRESS || - event.type() == Clutter.EventType.BUTTON_PRESS) { - if (this._timedLoginBatch) { - this._timedLoginBatch.cancel(); - this._timedLoginBatch = null; - } - } else if (event.type() == Clutter.EventType.KEY_RELEASE || - event.type() == Clutter.EventType.BUTTON_RELEASE) { - this._resetTimedLogin(); - } - - return false; - })); - }, - - _setUserListExpanded: function(expanded) { - this._userList.updateStyle(expanded); - this._userSelectionBox.visible = expanded; - }, - - _hideUserListAndLogIn: function() { - this._setUserListExpanded(false); - GdmUtil.cloneAndFadeOutActor(this._userSelectionBox); - this._askForUsernameAndLogIn(); +@@ -724,6 +724,7 @@ const LoginDialog = new Lang.Class({ }, - _showUserList: function() { - this._hidePrompt(); - this._setUserListExpanded(true); -+ this._notListedButton.show(); - this._userList.actor.grab_key_focus(); + _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(); }, - _beginVerificationForUser: function(userName) { - let hold = new Batch.Hold(); + _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; - this._userVerifier.begin(userName, hold); - this._verifyingUser = true; - return hold; - }, + const UserListItem = new Lang.Class({ + Name: 'UserListItem', +@@ -283,7 +284,16 @@ const SessionMenuButton = new Lang.Class({ - _beginVerificationForItem: function(item) { - let userWidget = new UserWidget.UserWidget(item.user); - this._promptUser.set_child(userWidget.actor); + this.actor = new St.Bin({ child: this._button }); - let tasks = [function() { - let userName = item.user.get_user_name(); - return this._beginVerificationForUser(userName); - }]; - let batch = new Batch.ConsecutiveBatch(this, tasks); - return batch.run(); - }, +- 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(); - _onUserListActivated: function(activatedItem) { - let tasks = [function() { - return GdmUtil.cloneAndFadeOutActor(this._userSelectionBox); - }, - function() { - this._setUserListExpanded(false); - }]; -- -1.8.3.1 +2.5.0 -From b05ad741f1489eee41099ec28e79fd3cea295962 Mon Sep 17 00:00:00 2001 +From cd87ad4e3f9aa3e18f35f6f4069412412eeb1977 Mon Sep 17 00:00:00 2001 From: Ray Strode -Date: Sun, 23 Jun 2013 23:14:10 -0400 -Subject: [PATCH 04/69] loginDialog: Move the session list to a PopupMenu +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. -There are some issues with the existing session menu. First, it looks -kinda bad. It seems like it's hanging around there, but it doesn't really know -what to do with itself. +Only the parent should be hidden, at this point, so +there's situations where the user list hides and +never comes back. -Second, when it expands down it requires that the buttons below move -down with it. This kind of movement is awkward and looks a bit weird. +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(-) -Third, its current position makes the "dialog" tall and unwieldy when -you add things like messages for fingerprint readers or authentication errors. +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 -This commit moves the session list to a menu behind a button to address -the above problems. -Based on a patch by Jasper St. Pierre. +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 -https://bugzilla.gnome.org/show_bug.cgi?id=702818 +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 | 38 ++------ - js/gdm/loginDialog.js | 229 ++++++++++++++------------------------------- - 2 files changed, 78 insertions(+), 189 deletions(-) + 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 7dac907..9f9830a 100644 +index 2ec51b2..97634b1 100644 --- a/data/theme/gnome-shell.css +++ b/data/theme/gnome-shell.css -@@ -2327,97 +2327,71 @@ StScrollBar StButton#vhandle:active { - } - - .login-dialog-not-listed-button:focus .login-dialog-not-listed-label, - .login-dialog-not-listed-button:hover .login-dialog-not-listed-label { - color: #E8E8E8; - } - - .login-dialog-username { - font-size: 16pt; - font-weight: bold; - text-align: left; - padding-left: 15px; - text-shadow: black 0px 4px 3px 0px; - } - - .login-dialog-prompt-layout { - padding-top: 24px; - padding-bottom: 12px; - spacing: 8px; - } - - .login-dialog-prompt-label { - color: #eeeeee; - font-size: 14px; +@@ -2407,10 +2407,6 @@ StScrollBar StButton#vhandle:active { + border: 2px solid #bbbbbb; } - .login-dialog-prompt-entry { - width: 15em; - } - --.login-dialog-session-list, --.login-dialog-session-list-item { -- color: #babdb6; --} -- --.login-dialog-session-list-button:focus, --.login-dialog-session-list-button:active, --.login-dialog-session-list-button:hover, --.login-dialog-session-list-item:focus, --.login-dialog-session-list-item:hover { -- color: white; -+.login-dialog-session-list-button StIcon { -+ icon-size: 1.25em; - } - - .login-dialog-session-list-button { -- padding: 4px; -+ color: #8b8b8b; - } - --.login-dialog-session-list-scroll-view { -- padding: 6px; --} -- --.login-dialog-session-list-item { -- padding-bottom: 6px; --} -- --.login-dialog-session-list-triangle { -- padding-right: 6px; --} -- --.login-dialog-session-list-item-box { -- padding-left: 6px; -- spacing: 6px; +-.login-dialog-banner { +- color: #666666; -} - --.login-dialog-session-list-item-dot { -- width: 10px; -- height: 10px; -+.login-dialog-session-list-button:hover, -+.login-dialog-session-list-button:active { -+ color: white; - } - - .login-dialog-logo-bin { - padding: 24px 0px; - } - - .login-dialog .modal-dialog-button-box { - spacing: 3px; - } - - .login-dialog .modal-dialog-button { - border-radius: 5px; - padding: 3px 18px; - } - - .login-dialog .modal-dialog-button:focus { - padding: 2px 17px; - } - - .login-dialog .modal-dialog-button:default { - background-gradient-start: #6793c4; - background-gradient-end: #335d8f; - background-gradient-direction: vertical; - border-color: #16335d; - } - - .login-dialog .modal-dialog-button:default:focus { - border: 2px solid #377fe7; - } - + .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 4cbb0c9..5557db9 100644 +index 9ef7b2a..d58daaa 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js -@@ -7,64 +7,66 @@ - * 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 Shell = imports.gi.Shell; - const Signals = imports.signals; - const St = imports.gi.St; - - const Panel = imports.ui.panel; - 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 _WORK_SPINNER_ICON_SIZE = 24; - const _WORK_SPINNER_ANIMATION_DELAY = 1.0; - const _WORK_SPINNER_ANIMATION_TIME = 0.3; - const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0; - const _LOGO_ICON_HEIGHT = 48; - - let _loginDialog = null; +@@ -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; - const UserListItem = new Lang.Class({ - Name: 'UserListItem', + 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; - _init: function(user) { - this.user = user; - this._userChangedId = this.user.connect('changed', - Lang.bind(this, this._onUserChanged)); ++ 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)); - let layout = new St.BoxLayout({ vertical: false }); - this.actor = new St.Button({ style_class: 'login-dialog-user-list-item', - button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, - can_focus: true, - child: layout, - reactive: true, - x_align: St.Align.START, -@@ -262,242 +264,160 @@ const UserList = new Lang.Class({ - Lang.bind(this, - function() { - this.scrollToItem(item); - })); + // 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: ")); - this._moveFocusToItems(); +- 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.emit('item-added', item); + 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; ++ } }, - removeUser: function(user) { - if (!user.is_loaded) - return; - - let userName = user.get_user_name(); - - if (!userName) - return; - - let item = this._items[userName]; - - if (!item) - return; - - item.actor.destroy(); - delete this._items[userName]; - } - }); - Signals.addSignalMethods(UserList.prototype); - --const SessionListItem = new Lang.Class({ -- Name: 'SessionListItem', -- -- _init: function(id, name) { -- this.id = id; -- -- this.actor = new St.Button({ style_class: 'login-dialog-session-list-item', -- button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, -- can_focus: true, -- reactive: true, -- x_fill: true, -- x_align: St.Align.START }); -- -- this._box = new St.BoxLayout({ style_class: 'login-dialog-session-list-item-box' }); -- -- this.actor.add_actor(this._box); -- this.actor.connect('clicked', Lang.bind(this, this._onClicked)); -- -- this._dot = new St.DrawingArea({ style_class: 'login-dialog-session-list-item-dot' }); -- this._dot.connect('repaint', Lang.bind(this, this._onRepaintDot)); -- this._box.add_actor(this._dot); -- this.setShowDot(false); -- -- let label = new St.Label({ style_class: 'login-dialog-session-list-item-label', -- text: name }); -- this.actor.label_actor = label; -- -- this._box.add_actor(label); -- }, -- -- setShowDot: function(show) { -- if (show) -- this._dot.opacity = 255; -- else -- this._dot.opacity = 0; -- }, -- -- _onRepaintDot: function(area) { -- let cr = area.get_context(); -- let [width, height] = area.get_surface_size(); -- let color = area.get_theme_node().get_foreground_color(); -- -- cr.setSourceRGBA (color.red / 255, -- color.green / 255, -- color.blue / 255, -- color.alpha / 255); -- cr.arc(width / 2, height / 2, width / 3, 0, 2 * Math.PI); -- cr.fill(); -- cr.$dispose(); -- }, -- -- _onClicked: function() { -- this.emit('activate'); -- } --}); --Signals.addSignalMethods(SessionListItem.prototype); -- --const SessionList = new Lang.Class({ -- Name: 'SessionList', -+const SessionMenuButton = new Lang.Class({ -+ Name: 'SessionMenuButton', - - _init: function() { -- this.actor = new St.Bin(); -- -- this._box = new St.BoxLayout({ style_class: 'login-dialog-session-list', -- vertical: true}); -- this.actor.child = this._box; -- -+ let gearIcon = new St.Icon({ icon_name: 'emblem-system-symbolic' }); - this._button = new St.Button({ style_class: 'login-dialog-session-list-button', -- button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, -+ reactive: true, -+ track_hover: true, - can_focus: true, -- x_fill: true, -- y_fill: true }); -- let box = new St.BoxLayout(); -- this._button.add_actor(box); -- -- this._triangle = new St.Label({ style_class: 'login-dialog-session-list-triangle', -- text: '\u25B8' }); -- box.add_actor(this._triangle); -- -- let label = new St.Label({ style_class: 'login-dialog-session-list-label', -- text: _("Session…") }); -- box.add_actor(label); -- -- this._button.connect('clicked', -- Lang.bind(this, this._onClicked)); -- this._box.add_actor(this._button); -- this._scrollView = new St.ScrollView({ style_class: 'login-dialog-session-list-scroll-view'}); -- this._scrollView.set_policy(Gtk.PolicyType.NEVER, -- Gtk.PolicyType.AUTOMATIC); -- this._box.add_actor(this._scrollView); -- this._itemList = new St.BoxLayout({ style_class: 'login-dialog-session-item-list', -- vertical: true }); -- this._scrollView.add_actor(this._itemList); -- this._scrollView.hide(); -- this.isOpen = false; -- this._populate(); -- }, -+ accessible_name: _("Choose Session"), -+ accessible_role: Atk.Role.MENU, -+ child: gearIcon }); - -- open: function() { -- if (this.isOpen) -- return; -+ this.actor = new St.Bin({ child: this._button }); - -- this._button.add_style_pseudo_class('open'); -- this._scrollView.show(); -- this._triangle.set_text('\u25BE'); -+ this._menu = new PopupMenu.PopupMenu(this._button, 0, St.Side.TOP); -+ Main.uiGroup.add_actor(this._menu.actor); -+ this._menu.actor.hide(); - -- this.isOpen = true; -- }, -+ this._menu.connect('open-state-changed', -+ Lang.bind(this, function(menu, isOpen) { -+ if (isOpen) -+ this._button.add_style_pseudo_class('active'); -+ else -+ this._button.remove_style_pseudo_class('active'); -+ })); - -- close: function() { -- if (!this.isOpen) -- return; -+ let subtitle = new PopupMenu.PopupMenuItem(_("Session"), { style_class: 'popup-subtitle-menu-item', -+ reactive: false }); -+ this._menu.addMenuItem(subtitle); - -- this._button.remove_style_pseudo_class('open'); -- this._scrollView.hide(); -- this._triangle.set_text('\u25B8'); -+ this._manager = new PopupMenu.PopupMenuManager({ actor: this._button }); -+ this._manager.addMenu(this._menu); - -- this.isOpen = false; -- }, -+ this._button.connect('clicked', Lang.bind(this, function() { -+ this._menu.toggle(); -+ })); - -- _onClicked: function() { -- if (!this.isOpen) -- this.open(); -- else -- this.close(); -+ this._items = {}; -+ this._activeSessionId = null; -+ this._populate(); - }, - - updateSensitivity: function(sensitive) { - this._button.reactive = sensitive; - this._button.can_focus = sensitive; -+ this._menu.close(BoxPointer.PopupAnimation.NONE); -+ }, - -- for (let id in this._items) -- this._items[id].actor.reactive = sensitive; -+ _updateOrnament: function() { -+ let itemIds = Object.keys(this._items); -+ for (let i = 0; i < itemIds.length; i++) { -+ if (itemIds[i] == this._activeSessionId) -+ this._items[itemIds[i]].setShowDot(true); -+ else -+ this._items[itemIds[i]].setShowDot(false); -+ } - }, - - setActiveSession: function(sessionId) { - if (sessionId == this._activeSessionId) - return; - -- if (this._activeSessionId) -- this._items[this._activeSessionId].setShowDot(false); -- -- this._items[sessionId].setShowDot(true); - this._activeSessionId = sessionId; -+ this._updateOrnament(); - - this.emit('session-activated', this._activeSessionId); - }, - -- _populate: function() { -- this._itemList.destroy_all_children(); -- this._activeSessionId = null; -- this._items = {}; -+ close: function() { -+ this._menu.close(); -+ }, - -+ _populate: function() { - let ids = Gdm.get_session_ids(); - ids.sort(); - - if (ids.length <= 1) { -- this._box.hide(); - this._button.hide(); -- } else { -- this._button.show(); -- this._box.show(); -+ return; - } - - for (let i = 0; i < ids.length; i++) { - let [sessionName, sessionDescription] = Gdm.get_session_name_and_description(ids[i]); - -- let item = new SessionListItem(ids[i], sessionName); -- this._itemList.add_actor(item.actor); -- this._items[ids[i]] = item; -+ let id = ids[i]; -+ let item = new PopupMenu.PopupMenuItem(sessionName); -+ this._menu.addMenuItem(item); -+ this._items[id] = item; - - if (!this._activeSessionId) -- this.setActiveSession(ids[i]); -+ this.setActiveSession(id); - -- item.connect('activate', -- Lang.bind(this, function() { -- this.setActiveSession(item.id); -- })); -+ item.connect('activate', Lang.bind(this, function() { -+ this.setActiveSession(id); -+ })); - } - } - }); --Signals.addSignalMethods(SessionList.prototype); -+Signals.addSignalMethods(SessionMenuButton.prototype); - - const LoginDialog = new Lang.Class({ - Name: 'LoginDialog', - - _init: function(parentActor) { - this.actor = new St.Widget({ accessible_role: Atk.Role.WINDOW, - 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() - this._greeterClient = new Gdm.Client(); - - if (GLib.getenv('GDM_GREETER_TEST') != '1') { - this._greeter = this._greeterClient.get_greeter_sync(null); - - this._greeter.connect('default-session-name-changed', - Lang.bind(this, this._onDefaultSessionChanged)); - - this._greeter.connect('session-opened', - Lang.bind(this, this._onSessionOpened)); - this._greeter.connect('timed-login-requested', - Lang.bind(this, this._onTimedLoginRequested)); - } - - this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient); - this._userVerifier.connect('ask-question', Lang.bind(this, this._askQuestion)); -@@ -559,131 +479,125 @@ const LoginDialog = new Lang.Class({ - x_align: St.Align.START }); - this._promptBox.add(this._promptUser, - { x_align: St.Align.START, - x_fill: true, - y_fill: true, - expand: true }); - this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' }); - - this._promptBox.add(this._promptLabel, - { expand: true, - x_fill: true, - y_fill: true, - x_align: St.Align.START }); - this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry', - can_focus: true }); - this._promptEntryTextChangedId = 0; - this._promptEntryActivateId = 0; - this._promptBox.add(this._promptEntry, - { expand: true, - x_fill: true, - y_fill: false, - x_align: St.Align.START }); - - this._promptMessage = new St.Label({ visible: false }); - this._promptBox.add(this._promptMessage, { x_fill: true }); - - this._promptLoginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' }); - this._promptLoginHint.hide(); - this._promptBox.add(this._promptLoginHint); - -- this._sessionList = new SessionList(); -- this._sessionList.connect('session-activated', -- Lang.bind(this, function(list, sessionId) { -- this._greeter.call_select_session_sync (sessionId, null); -- })); -- -- this._promptBox.add(this._sessionList.actor, -- { expand: true, -- x_fill: false, -- y_fill: true, -- x_align: St.Align.START }); - this._buttonBox = new St.BoxLayout({ style_class: 'modal-dialog-button-box', - vertical: false }); - this._promptBox.add(this._buttonBox, - { expand: true, - x_align: St.Align.MIDDLE, - y_align: St.Align.END }); - this._cancelButton = null; - this._signInButton = null; - - this._promptBox.hide(); - - // translators: this message is shown below the user list on the - // 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._hideUserListAndLogIn)); - this._notListedButton.hide(); - - this._userSelectionBox.add(this._notListedButton, - { expand: false, - x_align: St.Align.START, - x_fill: true }); - - this._logoBin = new St.Bin({ style_class: 'login-dialog-logo-bin', y_expand: true }); - this._logoBin.set_y_align(Clutter.ActorAlign.END); - this._logoBin.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.X_AXIS, - factor: 0.5 })); - this._logoBin.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.Y_AXIS, - factor: 1.0 })); - this.actor.add_child(this._logoBin); - this._updateLogo(); - - 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(button, sessionId) { -+ this._greeter.call_select_session_sync (sessionId, null); -+ })); - }, - - _updateDisableUserList: function() { - let disableUserList = this._settings.get_boolean(GdmUtil.DISABLE_USER_LIST_KEY); - - // If this is the first time around, set initial focus - if (this._disableUserList == undefined && disableUserList) - this.setInitialKeyFocus(this._promptEntry); - - if (disableUserList != this._disableUserList) { - this._disableUserList = disableUserList; - - if (!this._verifyingUser) - this._reset(); - } - }, - - _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(); - } - }, - - _updateLogoTexture: function(cache, uri) { -@@ -726,223 +640,224 @@ const LoginDialog = new Lang.Class({ - if (working) { - this._workSpinner.play(); - Tweener.addTween(this._workSpinner.actor, - { opacity: 255, - delay: _WORK_SPINNER_ANIMATION_DELAY, - time: _WORK_SPINNER_ANIMATION_TIME, - transition: 'linear' - }); - } else { - Tweener.addTween(this._workSpinner.actor, - { opacity: 0, - time: _WORK_SPINNER_ANIMATION_TIME, - transition: 'linear', - onCompleteScope: this, - onComplete: function() { - if (this._workSpinner) - this._workSpinner.stop(); - } - }); - } - }, - - _verificationFailed: function() { - this._promptEntry.text = ''; - - this._updateSensitivity(true); - this._setWorking(false); - }, - - _onDefaultSessionChanged: function(client, sessionId) { -- this._sessionList.setActiveSession(sessionId); -+ this._sessionMenuButton.setActiveSession(sessionId); - }, - - _showMessage: function(userVerifier, message, styleClass) { - if (message) { - this._promptMessage.text = message; - this._promptMessage.styleClass = styleClass; - this._promptMessage.show(); - } else { - this._promptMessage.hide(); - } - }, - - _showLoginHint: function(verifier, message) { - this._promptLoginHint.set_text(message) - this._promptLoginHint.show(); - this._promptLoginHint.opacity = 255; - }, - - _hideLoginHint: function() { - this._promptLoginHint.hide(); - this._promptLoginHint.set_text(''); - }, - - cancel: function() { - if (this._verifyingUser) - this._userVerifier.cancel(); - else - this._reset(); - }, - - _showPrompt: function(forSecret) { -- this._sessionList.actor.hide(); -+ this._sessionMenuButton.actor.hide(); - this._promptLabel.show(); - this._promptEntry.show(); - this._promptLoginHint.opacity = 0; - this._promptLoginHint.show(); - this._promptBox.opacity = 0; - this._promptBox.show(); - Tweener.addTween(this._promptBox, - { opacity: 255, - time: _FADE_ANIMATION_TIME, - transition: 'easeOutQuad' }); - - if ((this._user && !this._user.is_logged_in()) || this._verifyingUser) -- this._sessionList.actor.show(); -+ this._sessionMenuButton.actor.show(); - - this._promptEntry.grab_key_focus(); - - let hold = new Batch.Hold(); - let tasks = [function() { - this._prepareDialog(forSecret, hold); - }, - - hold]; - - let batch = new Batch.ConcurrentBatch(this, tasks); - - return batch.run(); - }, - - _prepareDialog: function(forSecret, hold) { - this._buttonBox.visible = true; -- this._buttonBox.destroy_all_children(); -+ this._buttonBox.remove_all_children(); - - if (!this._disableUserList || this._verifyingUser) { - this._cancelButton = new St.Button({ style_class: 'modal-dialog-button', - button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, - reactive: true, - can_focus: true, - label: _("Cancel") }); - this._cancelButton.connect('clicked', - Lang.bind(this, function() { - this.cancel(); - })); - this._buttonBox.add(this._cancelButton, - { expand: true, - x_fill: false, - y_fill: false, - x_align: St.Align.START, - y_align: St.Align.END }); - } - - let spinnerIcon = global.datadir + '/theme/process-working.svg'; - this._workSpinner = new Panel.AnimatedIcon(spinnerIcon, _WORK_SPINNER_ICON_SIZE); - this._workSpinner.actor.opacity = 0; - this._workSpinner.actor.show(); - - this._buttonBox.add(this._workSpinner.actor, - { expand: false, - x_align: St.Align.END }); - -+ this._buttonBox.add(this._sessionMenuButton.actor, -+ { expand: false, -+ x_align: St.Align.END }); - this._signInButton = new St.Button({ style_class: 'modal-dialog-button', - button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, - reactive: true, - can_focus: true, - label: forSecret ? C_("button", "Sign In") : _("Next") }); - this._signInButton.connect('clicked', - Lang.bind(this, function() { - hold.release(); - })); - this._signInButton.add_style_pseudo_class('default'); - this._buttonBox.add(this._signInButton, - { expand: true, - x_fill: false, - y_fill: false, - x_align: St.Align.END, - y_align: St.Align.END }); - - this._updateSignInButtonSensitivity(this._promptEntry.text.length > 0); - - this._promptEntryTextChangedId = - this._promptEntry.clutter_text.connect('text-changed', - Lang.bind(this, function() { - this._updateSignInButtonSensitivity(this._promptEntry.text.length > 0); - })); - - this._promptEntryActivateId = - this._promptEntry.clutter_text.connect('activate', function() { - hold.release(); - }); - }, - - _updateSensitivity: function(sensitive) { - this._promptEntry.reactive = sensitive; - this._promptEntry.clutter_text.editable = sensitive; -- this._sessionList.updateSensitivity(sensitive); -+ this._sessionMenuButton.updateSensitivity(sensitive); - this._updateSignInButtonSensitivity(sensitive); - }, - - _updateSignInButtonSensitivity: function(sensitive) { - if (this._signInButton) { - this._signInButton.reactive = sensitive; - this._signInButton.can_focus = sensitive; - } - }, - - _hidePrompt: function() { -- this._buttonBox.destroy_all_children(); -- - if (this._promptEntryTextChangedId > 0) { - this._promptEntry.clutter_text.disconnect(this._promptEntryTextChangedId); - this._promptEntryTextChangedId = 0; - } - - if (this._promptEntryActivateId > 0) { - this._promptEntry.clutter_text.disconnect(this._promptEntryActivateId); - this._promptEntryActivateId = 0; - } - - this._setWorking(false); - this._promptBox.hide(); - this._promptLoginHint.hide(); - - this._promptUser.set_child(null); - - this._updateSensitivity(true); - this._promptEntry.set_text(''); - -- this._sessionList.close(); -+ this._sessionMenuButton.close(); - this._promptLoginHint.hide(); - -- this._buttonBox.destroy_all_children(); -+ this._buttonBox.remove_all_children(); - this._signInButton = null; - this._cancelButton = null; - }, - - _askQuestion: function(verifier, serviceName, question, passwordChar) { - this._promptLabel.set_text(question); - - this._updateSensitivity(true); - this._promptEntry.set_text(''); - this._promptEntry.clutter_text.set_password_char(passwordChar); - - let tasks = [function() { - return this._showPrompt(!!passwordChar); - }, - - function() { - let text = this._promptEntry.get_text(); - this._updateSensitivity(false); - this._setWorking(true); - this._userVerifier.answerQuery(serviceName, text); - }]; - - let batch = new Batch.ConsecutiveBatch(this, tasks); - return batch.run(); - }, - - _showRealmLoginHint: function(realmManager, hint) { - if (!hint) - return; - --- -1.8.3.1 - - -From 4c0d3a19e59d556158cfdb4c58dc31b501d9a9e2 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 25 Jun 2013 13:35:38 -0400 -Subject: [PATCH 05/69] loginDialog: make spinner and session menu button share - position - -They never need to be shown at the same time, and the design has -the UI fade between them. - -This commit implements that. - -https://bugzilla.gnome.org/show_bug.cgi?id=702818 ---- - js/gdm/loginDialog.js | 161 +++++++++++++++++++++++++++++++++++--------------- - 1 file changed, 113 insertions(+), 48 deletions(-) - -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index 5557db9..f127460 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -20,68 +20,74 @@ - - 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 Shell = imports.gi.Shell; - const Signals = imports.signals; - const St = imports.gi.St; - - const Panel = imports.ui.panel; - 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 _WORK_SPINNER_ICON_SIZE = 24; --const _WORK_SPINNER_ANIMATION_DELAY = 1.0; --const _WORK_SPINNER_ANIMATION_TIME = 0.3; -+const _DEFAULT_BUTTON_WELL_ICON_SIZE = 24; -+const _DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0; -+const _DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3; - const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0; - const _LOGO_ICON_HEIGHT = 48; - - let _loginDialog = null; - -+const DefaultButtonWellMode = { -+ NONE: 0, -+ SESSION_MENU_BUTTON: 1, -+ SPINNER: 2 -+}; -+ - const UserListItem = new Lang.Class({ - Name: 'UserListItem', - - _init: function(user) { - this.user = user; - this._userChangedId = this.user.connect('changed', - Lang.bind(this, this._onUserChanged)); - - let layout = new St.BoxLayout({ vertical: false }); - this.actor = new St.Button({ style_class: 'login-dialog-user-list-item', - button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, - can_focus: true, - child: layout, - reactive: true, - x_align: St.Align.START, - x_fill: true }); - - this._userAvatar = new UserMenu.UserAvatarWidget(this.user, - { styleClass: 'login-dialog-user-list-item-icon' }); - layout.add(this._userAvatar.actor); - let textLayout = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-text-box', - vertical: true }); - layout.add(textLayout, { expand: true }); - - this._nameLabel = new St.Label({ style_class: 'login-dialog-user-list-item-name' }); - this.actor.label_actor = this._nameLabel; - textLayout.add(this._nameLabel, - { y_fill: false, - y_align: St.Align.MIDDLE, - expand: true }); -@@ -539,65 +545,81 @@ const LoginDialog = new Lang.Class({ - x_fill: true }); - - this._logoBin = new St.Bin({ style_class: 'login-dialog-logo-bin', y_expand: true }); - this._logoBin.set_y_align(Clutter.ActorAlign.END); - this._logoBin.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.X_AXIS, - factor: 0.5 })); - this._logoBin.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.Y_AXIS, - factor: 1.0 })); - this.actor.add_child(this._logoBin); - this._updateLogo(); - - 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._defaultButtonWell = new St.Widget(); -+ this._defaultButtonWellMode = DefaultButtonWellMode.NONE; -+ - this._sessionMenuButton = new SessionMenuButton(); - this._sessionMenuButton.connect('session-activated', -- Lang.bind(this, function(button, sessionId) { -- this._greeter.call_select_session_sync (sessionId, null); -- })); -+ Lang.bind(this, function(list, sessionId) { -+ this._greeter.call_select_session_sync (sessionId, null); -+ })); -+ this._sessionMenuButton.actor.opacity = 0; -+ this._sessionMenuButton.actor.show(); -+ this._defaultButtonWell.add_child(this._sessionMenuButton.actor); -+ -+ let spinnerIcon = global.datadir + '/theme/process-working.svg'; -+ this._workSpinner = new Panel.AnimatedIcon(spinnerIcon, _DEFAULT_BUTTON_WELL_ICON_SIZE); -+ this._workSpinner.actor.opacity = 0; -+ this._workSpinner.actor.show(); -+ -+ this._defaultButtonWell.add_child(this._workSpinner.actor); -+ this._sessionMenuButton.actor.add_constraint(new Clutter.AlignConstraint({ source: this._workSpinner.actor, -+ align_axis: Clutter.AlignAxis.BOTH, -+ factor: 0.5 })); - }, - - _updateDisableUserList: function() { - let disableUserList = this._settings.get_boolean(GdmUtil.DISABLE_USER_LIST_KEY); - - // If this is the first time around, set initial focus - if (this._disableUserList == undefined && disableUserList) - this.setInitialKeyFocus(this._promptEntry); - - if (disableUserList != this._disableUserList) { - this._disableUserList = disableUserList; - - if (!this._verifyingUser) - this._reset(); - } - }, - - _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(); - } - }, - - _updateLogoTexture: function(cache, uri) { -@@ -605,278 +627,321 @@ const LoginDialog = new Lang.Class({ - return; - - let icon = null; - if (this._logoFileUri) - icon = this._textureCache.load_uri_async(this._logoFileUri, - -1, _LOGO_ICON_HEIGHT); - this._logoBin.set_child(icon); - }, - - _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); - }, - - _reset: function() { - this._userVerifier.clear(); - - this._updateSensitivity(true); - this._promptMessage.hide(); - this._user = null; - this._verifyingUser = false; - - if (this._disableUserList) - this._hideUserListAndLogIn(); - else - this._showUserList(); - }, - -- _setWorking: function(working) { -- if (!this._workSpinner) -+ _getActorForDefaultButtonWellMode: function(mode) { -+ let actor; -+ -+ if (mode == DefaultButtonWellMode.NONE) -+ actor = null; -+ else if (mode == DefaultButtonWellMode.SPINNER) -+ actor = this._workSpinner.actor; -+ else if (mode == DefaultButtonWellMode.SESSION_MENU_BUTTON) -+ actor = this._sessionMenuButton.actor; -+ -+ return actor; -+ }, -+ -+ _setDefaultButtonWellMode: function(mode, immediately) { -+ if (this._defaultButtonWellMode == DefaultButtonWellMode.NONE && -+ mode == DefaultButtonWellMode.NONE) - return; - -- Tweener.removeTweens(this._workSpinner.actor); -- if (working) { -- this._workSpinner.play(); -- Tweener.addTween(this._workSpinner.actor, -- { opacity: 255, -- delay: _WORK_SPINNER_ANIMATION_DELAY, -- time: _WORK_SPINNER_ANIMATION_TIME, -- transition: 'linear' -- }); -- } else { -- Tweener.addTween(this._workSpinner.actor, -- { opacity: 0, -- time: _WORK_SPINNER_ANIMATION_TIME, -- transition: 'linear', -- onCompleteScope: this, -- onComplete: function() { -- if (this._workSpinner) -- this._workSpinner.stop(); -- } -- }); -+ let oldActor = this._getActorForDefaultButtonWellMode(this._defaultButtonWellMode); -+ -+ if (oldActor) -+ Tweener.removeTweens(oldActor); -+ -+ let actor = this._getActorForDefaultButtonWellMode(mode); -+ -+ if (this._defaultButtonWellMode != mode && oldActor) { -+ if (immediately) -+ oldActor.opacity = 0; -+ else -+ Tweener.addTween(oldActor, -+ { opacity: 0, -+ time: _DEFAULT_BUTTON_WELL_ANIMATION_TIME, -+ delay: _DEFAULT_BUTTON_WELL_ANIMATION_DELAY, -+ transition: 'linear', -+ onCompleteScope: this, -+ onComplete: function() { -+ if (mode == DefaultButtonWellMode.SPINNER) { -+ if (this._workSpinner) -+ this._workSpinner.stop(); -+ } -+ } -+ }); -+ -+ } -+ -+ if (actor) { -+ if (mode == DefaultButtonWellMode.SPINNER) -+ this._workSpinner.play(); -+ -+ if (immediately) -+ actor.opacity = 255; -+ else -+ Tweener.addTween(actor, -+ { opacity: 255, -+ time: _DEFAULT_BUTTON_WELL_ANIMATION_TIME, -+ delay: _DEFAULT_BUTTON_WELL_ANIMATION_DELAY, -+ transition: 'linear' }); - } -+ -+ this._defaultButtonWellMode = mode; - }, - - _verificationFailed: function() { - this._promptEntry.text = ''; - - this._updateSensitivity(true); -- this._setWorking(false); -+ this._setDefaultButtonWellMode(DefaultButtonWellMode.NONE, true); - }, - - _onDefaultSessionChanged: function(client, sessionId) { - this._sessionMenuButton.setActiveSession(sessionId); - }, - - _showMessage: function(userVerifier, message, styleClass) { - if (message) { - this._promptMessage.text = message; - this._promptMessage.styleClass = styleClass; - this._promptMessage.show(); - } else { - this._promptMessage.hide(); - } - }, - - _showLoginHint: function(verifier, message) { - this._promptLoginHint.set_text(message) - this._promptLoginHint.show(); - this._promptLoginHint.opacity = 255; - }, - - _hideLoginHint: function() { - this._promptLoginHint.hide(); - this._promptLoginHint.set_text(''); - }, - - cancel: function() { - if (this._verifyingUser) - this._userVerifier.cancel(); - else - this._reset(); - }, - -+ _shouldShowSessionMenuButton: function() { -+ if (this._verifyingUser) -+ return true; -+ -+ if (!this._user) -+ return false; -+ -+ if (this._user.is_logged_in) -+ return false; -+ -+ return true; -+ }, -+ - _showPrompt: function(forSecret) { -- this._sessionMenuButton.actor.hide(); - this._promptLabel.show(); - this._promptEntry.show(); - this._promptLoginHint.opacity = 0; - this._promptLoginHint.show(); - this._promptBox.opacity = 0; - this._promptBox.show(); - Tweener.addTween(this._promptBox, - { opacity: 255, - time: _FADE_ANIMATION_TIME, - transition: 'easeOutQuad' }); - -- if ((this._user && !this._user.is_logged_in()) || this._verifyingUser) -- this._sessionMenuButton.actor.show(); -+ if (this._shouldShowSessionMenuButton()) -+ this._setDefaultButtonWellMode(DefaultButtonWellMode.SESSION_MENU_BUTTON, true); -+ else -+ this._setDefaultButtonWellMode(DefaultButtonWellMode.NONE, true); - - this._promptEntry.grab_key_focus(); - - let hold = new Batch.Hold(); - let tasks = [function() { - this._prepareDialog(forSecret, hold); - }, - - hold]; - - let batch = new Batch.ConcurrentBatch(this, tasks); - - return batch.run(); - }, - - _prepareDialog: function(forSecret, hold) { - this._buttonBox.visible = true; - this._buttonBox.remove_all_children(); - - if (!this._disableUserList || this._verifyingUser) { - this._cancelButton = new St.Button({ style_class: 'modal-dialog-button', - button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, - reactive: true, - can_focus: true, - label: _("Cancel") }); - this._cancelButton.connect('clicked', - Lang.bind(this, function() { - this.cancel(); - })); - this._buttonBox.add(this._cancelButton, -- { expand: true, -+ { expand: false, - x_fill: false, - y_fill: false, - x_align: St.Align.START, - y_align: St.Align.END }); - } - -- let spinnerIcon = global.datadir + '/theme/process-working.svg'; -- this._workSpinner = new Panel.AnimatedIcon(spinnerIcon, _WORK_SPINNER_ICON_SIZE); -- this._workSpinner.actor.opacity = 0; -- this._workSpinner.actor.show(); -- -- this._buttonBox.add(this._workSpinner.actor, -- { expand: false, -- x_align: St.Align.END }); -- -- this._buttonBox.add(this._sessionMenuButton.actor, -- { expand: false, -- x_align: St.Align.END }); -+ this._buttonBox.add(this._defaultButtonWell, -+ { expand: true, -+ x_fill: false, -+ y_fill: false, -+ x_align: St.Align.END, -+ y_align: St.Align.MIDDLE }); - this._signInButton = new St.Button({ style_class: 'modal-dialog-button', - button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, - reactive: true, - can_focus: true, - label: forSecret ? C_("button", "Sign In") : _("Next") }); - this._signInButton.connect('clicked', - Lang.bind(this, function() { - hold.release(); - })); - this._signInButton.add_style_pseudo_class('default'); - this._buttonBox.add(this._signInButton, -- { expand: true, -+ { expand: false, - x_fill: false, - y_fill: false, - x_align: St.Align.END, - y_align: St.Align.END }); - - this._updateSignInButtonSensitivity(this._promptEntry.text.length > 0); - - this._promptEntryTextChangedId = - this._promptEntry.clutter_text.connect('text-changed', - Lang.bind(this, function() { - this._updateSignInButtonSensitivity(this._promptEntry.text.length > 0); - })); - - this._promptEntryActivateId = - this._promptEntry.clutter_text.connect('activate', function() { - hold.release(); - }); - }, - - _updateSensitivity: function(sensitive) { - this._promptEntry.reactive = sensitive; - this._promptEntry.clutter_text.editable = sensitive; - this._sessionMenuButton.updateSensitivity(sensitive); - this._updateSignInButtonSensitivity(sensitive); - }, - - _updateSignInButtonSensitivity: function(sensitive) { - if (this._signInButton) { - this._signInButton.reactive = sensitive; - this._signInButton.can_focus = sensitive; - } - }, - - _hidePrompt: function() { - if (this._promptEntryTextChangedId > 0) { - this._promptEntry.clutter_text.disconnect(this._promptEntryTextChangedId); - this._promptEntryTextChangedId = 0; - } - - if (this._promptEntryActivateId > 0) { - this._promptEntry.clutter_text.disconnect(this._promptEntryActivateId); - this._promptEntryActivateId = 0; - } - -- this._setWorking(false); -+ this._setDefaultButtonWellMode(DefaultButtonWellMode.NONE, true); - this._promptBox.hide(); - this._promptLoginHint.hide(); - - this._promptUser.set_child(null); - - this._updateSensitivity(true); - this._promptEntry.set_text(''); - - this._sessionMenuButton.close(); - this._promptLoginHint.hide(); - - this._buttonBox.remove_all_children(); - this._signInButton = null; - this._cancelButton = null; - }, - - _askQuestion: function(verifier, serviceName, question, passwordChar) { - this._promptLabel.set_text(question); - - this._updateSensitivity(true); - this._promptEntry.set_text(''); - this._promptEntry.clutter_text.set_password_char(passwordChar); - - let tasks = [function() { - return this._showPrompt(!!passwordChar); - }, - - function() { - let text = this._promptEntry.get_text(); - this._updateSensitivity(false); -- this._setWorking(true); -+ this._setDefaultButtonWellMode(DefaultButtonWellMode.SPINNER, false); - this._userVerifier.answerQuery(serviceName, text); - }]; - - let batch = new Batch.ConsecutiveBatch(this, tasks); - return batch.run(); - }, - - _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._showLoginHint(null, _("(e.g., user or %s)").format(hint)); - }, - - _askForUsernameAndLogIn: function() { - this._promptLabel.set_text(_("Username: ")); - this._promptEntry.set_text(''); - this._promptEntry.clutter_text.set_password_char(''); - - let realmManager = new Realmd.Manager(); - let signalId = realmManager.connect('login-format-changed', - Lang.bind(this, this._showRealmLoginHint)); - this._showRealmLoginHint(realmManager.loginFormat); - --- -1.8.3.1 - - -From b9a4dfe6cc5056a2a0f81c20a28574e65e993684 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 9 Jul 2013 10:05:55 -0400 -Subject: [PATCH 06/69] loginDialog: don't call nonexistent setInitialKeyFocus - function - -commit ea02380c1524c28e6538ffedb789a12c298742ab changed the login -dialog to not use ModalDialog anymore. There's still one lingering -setInitialKeyFocus method call in the source, which will cause an -exception to be thrown when users have their user list disabled. - -This commit fixes that. - -https://bugzilla.gnome.org/show_bug.cgi?id=703874 ---- - js/gdm/loginDialog.js | 6 ++---- - 1 file changed, 2 insertions(+), 4 deletions(-) - -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index f127460..9f90664 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -478,60 +478,62 @@ const LoginDialog = new Lang.Class({ - })); - - this._promptBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - this.actor.add_child(this._promptBox); - this._promptUser = new St.Bin({ x_fill: true, - x_align: St.Align.START }); - this._promptBox.add(this._promptUser, - { x_align: St.Align.START, - x_fill: true, - y_fill: true, - expand: true }); - this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' }); - - this._promptBox.add(this._promptLabel, - { expand: true, - x_fill: true, - y_fill: true, - x_align: St.Align.START }); - this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry', - can_focus: true }); - this._promptEntryTextChangedId = 0; - this._promptEntryActivateId = 0; - this._promptBox.add(this._promptEntry, - { expand: true, - x_fill: true, - y_fill: false, - x_align: St.Align.START }); - -+ this._promptEntry.grab_key_focus(); -+ - this._promptMessage = new St.Label({ visible: false }); - this._promptBox.add(this._promptMessage, { x_fill: true }); - - this._promptLoginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' }); - this._promptLoginHint.hide(); - this._promptBox.add(this._promptLoginHint); - - this._buttonBox = new St.BoxLayout({ style_class: 'modal-dialog-button-box', - vertical: false }); - this._promptBox.add(this._buttonBox, - { expand: true, - x_align: St.Align.MIDDLE, - y_align: St.Align.END }); - this._cancelButton = null; - this._signInButton = null; - - this._promptBox.hide(); - - // translators: this message is shown below the user list on the - // 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 }); -@@ -571,64 +573,60 @@ const LoginDialog = new Lang.Class({ - Lang.bind(this, function(userList, item) { - this._onUserListActivated(item); - })); - - this._defaultButtonWell = new St.Widget(); - this._defaultButtonWellMode = DefaultButtonWellMode.NONE; - - 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._defaultButtonWell.add_child(this._sessionMenuButton.actor); - - let spinnerIcon = global.datadir + '/theme/process-working.svg'; - this._workSpinner = new Panel.AnimatedIcon(spinnerIcon, _DEFAULT_BUTTON_WELL_ICON_SIZE); - this._workSpinner.actor.opacity = 0; - this._workSpinner.actor.show(); - - this._defaultButtonWell.add_child(this._workSpinner.actor); - this._sessionMenuButton.actor.add_constraint(new Clutter.AlignConstraint({ source: this._workSpinner.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - }, - - _updateDisableUserList: function() { - let disableUserList = this._settings.get_boolean(GdmUtil.DISABLE_USER_LIST_KEY); - -- // If this is the first time around, set initial focus -- if (this._disableUserList == undefined && disableUserList) -- this.setInitialKeyFocus(this._promptEntry); -- - if (disableUserList != this._disableUserList) { - this._disableUserList = disableUserList; - - if (!this._verifyingUser) - this._reset(); - } - }, - - _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(); - } - }, - - _updateLogoTexture: function(cache, uri) { - if (this._logoFileUri != uri) - return; - - let icon = null; - if (this._logoFileUri) - icon = this._textureCache.load_uri_async(this._logoFileUri, - -1, _LOGO_ICON_HEIGHT); - this._logoBin.set_child(icon); - }, --- -1.8.3.1 - - -From a758d6e837f5a99dd2b1507d92c40d7dd09d7bdd Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 19 Jun 2013 12:56:23 -0400 -Subject: [PATCH 07/69] loginDialog: pre-allocate prompt message height - -Right now things jump around if a message comes in. -This commit makes sure there's room for a message to start. - -https://bugzilla.gnome.org/show_bug.cgi?id=702308 ---- - js/gdm/loginDialog.js | 16 +++++++--------- - 1 file changed, 7 insertions(+), 9 deletions(-) - -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index 9f90664..538364c 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -480,65 +480,64 @@ const LoginDialog = new Lang.Class({ - this._promptBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - this.actor.add_child(this._promptBox); - this._promptUser = new St.Bin({ x_fill: true, - x_align: St.Align.START }); - this._promptBox.add(this._promptUser, - { x_align: St.Align.START, - x_fill: true, - y_fill: true, - expand: true }); - this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' }); - - this._promptBox.add(this._promptLabel, - { expand: true, - x_fill: true, - y_fill: true, - x_align: St.Align.START }); - this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry', - can_focus: true }); - this._promptEntryTextChangedId = 0; - this._promptEntryActivateId = 0; - this._promptBox.add(this._promptEntry, - { expand: true, - x_fill: true, - y_fill: false, - x_align: St.Align.START }); - - this._promptEntry.grab_key_focus(); - -- this._promptMessage = new St.Label({ visible: false }); -+ this._promptMessage = new St.Label({ opacity: 0 }); - this._promptBox.add(this._promptMessage, { x_fill: true }); - - this._promptLoginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' }); -- this._promptLoginHint.hide(); - this._promptBox.add(this._promptLoginHint); - - this._buttonBox = new St.BoxLayout({ style_class: 'modal-dialog-button-box', - vertical: false }); - this._promptBox.add(this._buttonBox, - { expand: true, - x_align: St.Align.MIDDLE, - y_align: St.Align.END }); - this._cancelButton = null; - this._signInButton = null; - - this._promptBox.hide(); - - // translators: this message is shown below the user list on the - // 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._hideUserListAndLogIn)); - this._notListedButton.hide(); - - this._userSelectionBox.add(this._notListedButton, -@@ -615,61 +614,61 @@ const LoginDialog = new Lang.Class({ - if (enabled && text) { - this._bannerLabel.set_text(text); - this._bannerLabel.show(); - } else { - this._bannerLabel.hide(); - } - }, - - _updateLogoTexture: function(cache, uri) { - if (this._logoFileUri != uri) - return; - - let icon = null; - if (this._logoFileUri) - icon = this._textureCache.load_uri_async(this._logoFileUri, - -1, _LOGO_ICON_HEIGHT); - this._logoBin.set_child(icon); - }, - - _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); - }, - - _reset: function() { - this._userVerifier.clear(); - - this._updateSensitivity(true); -- this._promptMessage.hide(); -+ this._promptMessage.opacity = 0; - this._user = null; - this._verifyingUser = false; - - if (this._disableUserList) - this._hideUserListAndLogIn(); - else - this._showUserList(); - }, - - _getActorForDefaultButtonWellMode: function(mode) { - let actor; - - if (mode == DefaultButtonWellMode.NONE) - actor = null; - else if (mode == DefaultButtonWellMode.SPINNER) - actor = this._workSpinner.actor; - else if (mode == DefaultButtonWellMode.SESSION_MENU_BUTTON) - actor = this._sessionMenuButton.actor; - - return actor; - }, - - _setDefaultButtonWellMode: function(mode, immediately) { - if (this._defaultButtonWellMode == DefaultButtonWellMode.NONE && - mode == DefaultButtonWellMode.NONE) - return; - - let oldActor = this._getActorForDefaultButtonWellMode(this._defaultButtonWellMode); - - if (oldActor) -@@ -702,74 +701,73 @@ const LoginDialog = new Lang.Class({ - this._workSpinner.play(); - - if (immediately) - actor.opacity = 255; - else - Tweener.addTween(actor, - { opacity: 255, - time: _DEFAULT_BUTTON_WELL_ANIMATION_TIME, - delay: _DEFAULT_BUTTON_WELL_ANIMATION_DELAY, - transition: 'linear' }); - } - - this._defaultButtonWellMode = mode; - }, - - _verificationFailed: function() { - this._promptEntry.text = ''; - - this._updateSensitivity(true); - this._setDefaultButtonWellMode(DefaultButtonWellMode.NONE, true); - }, - - _onDefaultSessionChanged: function(client, sessionId) { - this._sessionMenuButton.setActiveSession(sessionId); - }, - - _showMessage: function(userVerifier, message, styleClass) { - if (message) { - this._promptMessage.text = message; - this._promptMessage.styleClass = styleClass; -- this._promptMessage.show(); -+ this._promptMessage.opacity = 255; - } else { -- this._promptMessage.hide(); -+ this._promptMessage.opacity = 0; - } - }, - - _showLoginHint: function(verifier, message) { - this._promptLoginHint.set_text(message) -- this._promptLoginHint.show(); - this._promptLoginHint.opacity = 255; - }, - - _hideLoginHint: function() { -- this._promptLoginHint.hide(); -+ this._promptLoginHint.opacity = 0; - this._promptLoginHint.set_text(''); - }, - - cancel: function() { - if (this._verifyingUser) - this._userVerifier.cancel(); - else - this._reset(); - }, - - _shouldShowSessionMenuButton: function() { - if (this._verifyingUser) - return true; - - if (!this._user) - return false; - - if (this._user.is_logged_in) - return false; - - return true; - }, - - _showPrompt: function(forSecret) { - this._promptLabel.show(); - this._promptEntry.show(); - this._promptLoginHint.opacity = 0; - this._promptLoginHint.show(); - this._promptBox.opacity = 0; - this._promptBox.show(); -@@ -856,69 +854,69 @@ const LoginDialog = new Lang.Class({ - }); - }, - - _updateSensitivity: function(sensitive) { - this._promptEntry.reactive = sensitive; - this._promptEntry.clutter_text.editable = sensitive; - this._sessionMenuButton.updateSensitivity(sensitive); - this._updateSignInButtonSensitivity(sensitive); - }, - - _updateSignInButtonSensitivity: function(sensitive) { - if (this._signInButton) { - this._signInButton.reactive = sensitive; - this._signInButton.can_focus = sensitive; - } - }, - - _hidePrompt: function() { - if (this._promptEntryTextChangedId > 0) { - this._promptEntry.clutter_text.disconnect(this._promptEntryTextChangedId); - this._promptEntryTextChangedId = 0; - } - - if (this._promptEntryActivateId > 0) { - this._promptEntry.clutter_text.disconnect(this._promptEntryActivateId); - this._promptEntryActivateId = 0; - } - - this._setDefaultButtonWellMode(DefaultButtonWellMode.NONE, true); - this._promptBox.hide(); -- this._promptLoginHint.hide(); -+ this._promptLoginHint.opacity = 0; - - this._promptUser.set_child(null); - - this._updateSensitivity(true); - this._promptEntry.set_text(''); - - this._sessionMenuButton.close(); -- this._promptLoginHint.hide(); -+ this._promptLoginHint.opacity = 0; - - this._buttonBox.remove_all_children(); - this._signInButton = null; - this._cancelButton = null; - }, - - _askQuestion: function(verifier, serviceName, question, passwordChar) { - this._promptLabel.set_text(question); - - this._updateSensitivity(true); - this._promptEntry.set_text(''); - this._promptEntry.clutter_text.set_password_char(passwordChar); - - let tasks = [function() { - return this._showPrompt(!!passwordChar); - }, - - function() { - let text = this._promptEntry.get_text(); - this._updateSensitivity(false); - this._setDefaultButtonWellMode(DefaultButtonWellMode.SPINNER, false); - this._userVerifier.answerQuery(serviceName, text); - }]; - - let batch = new Batch.ConsecutiveBatch(this, tasks); - return batch.run(); - }, - - _showRealmLoginHint: function(realmManager, hint) { - if (!hint) --- -1.8.3.1 - - -From b0d83be8ac98f254796dfca3eb0777a445727441 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 19 Jun 2013 09:23:14 -0400 -Subject: [PATCH 08/69] loginDialog: drop padding between buttons and entry - -Now that we preallocate space for the prompt message there is -a lot of loose space between the entry and the buttons. - -This commit helps tighten things up by getting rid -of the large top padding set above the login buttons. - -https://bugzilla.gnome.org/show_bug.cgi?id=702308 ---- - data/theme/gnome-shell.css | 4 ++++ - js/gdm/loginDialog.js | 2 +- - 2 files changed, 5 insertions(+), 1 deletion(-) - -diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css -index 9f9830a..2a1fe1d 100644 ---- a/data/theme/gnome-shell.css -+++ b/data/theme/gnome-shell.css -@@ -2215,60 +2215,64 @@ StScrollBar StButton#vhandle:active { - - .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; - - padding-bottom: 80px; - padding-top: 80px; - - border-radius: 16px; - min-height: 150px; - max-height: 700px; - min-width: 350px; - } - -+.login-dialog-button-box { -+ spacing: 5px; -+} -+ - .login-dialog-prompt-login-hint-message { - font-size: 10.5pt; - } - - .login-dialog-user-list-view { - -st-vfade-offset: 1em; - } - - .login-dialog-user-list { - spacing: 12px; - padding: .2em; - } - - .login-dialog-user-list-item { - border-radius: 10px; - padding: .2em; - } - - .login-dialog-user-list-item:ltr { - padding-right: 1em; - } - - .login-dialog-user-list-item:rtl { - padding-left: 1em; - } - - .login-dialog-user-list-item .login-dialog-user-list-item-name { - font-size: 20pt; - padding-left: 1em; - } -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index 538364c..365b45f 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -486,61 +486,61 @@ const LoginDialog = new Lang.Class({ - this._promptBox.add(this._promptUser, - { x_align: St.Align.START, - x_fill: true, - y_fill: true, - expand: true }); - this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' }); - - this._promptBox.add(this._promptLabel, - { expand: true, - x_fill: true, - y_fill: true, - x_align: St.Align.START }); - this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry', - can_focus: true }); - this._promptEntryTextChangedId = 0; - this._promptEntryActivateId = 0; - this._promptBox.add(this._promptEntry, - { expand: true, - x_fill: true, - y_fill: false, - x_align: St.Align.START }); - - this._promptEntry.grab_key_focus(); - - this._promptMessage = new St.Label({ opacity: 0 }); - this._promptBox.add(this._promptMessage, { x_fill: true }); - - this._promptLoginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' }); - this._promptBox.add(this._promptLoginHint); - -- this._buttonBox = new St.BoxLayout({ style_class: 'modal-dialog-button-box', -+ this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box', - vertical: false }); - this._promptBox.add(this._buttonBox, - { expand: true, - x_align: St.Align.MIDDLE, - y_align: St.Align.END }); - this._cancelButton = null; - this._signInButton = null; - - this._promptBox.hide(); - - // translators: this message is shown below the user list on the - // 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._hideUserListAndLogIn)); - this._notListedButton.hide(); - - this._userSelectionBox.add(this._notListedButton, - { expand: false, - x_align: St.Align.START, - x_fill: true }); --- -1.8.3.1 - - -From 53cc7380b0945166cf3c27c1f5751289e69d0bd7 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 26 Jun 2013 22:32:07 -0400 -Subject: [PATCH 09/69] loginDialog: make prompt entry wider - -This makes it match mock ups better and looks more visually -pleasing. - -https://bugzilla.gnome.org/show_bug.cgi?id=702308 ---- - data/theme/gnome-shell.css | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css -index 2a1fe1d..c42c19e 100644 ---- a/data/theme/gnome-shell.css -+++ b/data/theme/gnome-shell.css -@@ -2328,61 +2328,61 @@ StScrollBar StButton#vhandle:active { - color: #666666; - padding-top: 1em; - padding-left: 2px; - } - - .login-dialog-not-listed-button:focus .login-dialog-not-listed-label, - .login-dialog-not-listed-button:hover .login-dialog-not-listed-label { - color: #E8E8E8; - } - - .login-dialog-username { - font-size: 16pt; - font-weight: bold; - text-align: left; - padding-left: 15px; - text-shadow: black 0px 4px 3px 0px; - } - - .login-dialog-prompt-layout { - padding-top: 24px; - padding-bottom: 12px; - spacing: 8px; - } - - .login-dialog-prompt-label { - color: #eeeeee; - font-size: 14px; - } - - .login-dialog-prompt-entry { -- width: 15em; -+ width: 20em; - } - - .login-dialog-session-list-button StIcon { - icon-size: 1.25em; - } - - .login-dialog-session-list-button { - color: #8b8b8b; - } - - .login-dialog-session-list-button:hover, - .login-dialog-session-list-button:active { - color: white; - } - - .login-dialog-logo-bin { - padding: 24px 0px; - } - - .login-dialog .modal-dialog-button-box { - spacing: 3px; - } - - .login-dialog .modal-dialog-button { - border-radius: 5px; - padding: 3px 18px; - } - - .login-dialog .modal-dialog-button:focus { - padding: 2px 17px; --- -1.8.3.1 - - -From 21ab83972347f2ca1f3c44c014ed7514c7d25580 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 26 Jun 2013 12:36:10 -0400 -Subject: [PATCH 10/69] loginDialog: force user list and prompt to be the same - width - ---- - js/gdm/loginDialog.js | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index 365b45f..15a2e0a 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -453,61 +453,65 @@ const LoginDialog = new Lang.Class({ - vertical: true }); - this._userSelectionBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - this.actor.add_child(this._userSelectionBox); - - this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner', - text: '' }); - 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._promptBox = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', - vertical: true }); - - this._promptBox.connect('button-press-event', - Lang.bind(this, function(actor, event) { - if (event.get_key_symbol() == Clutter.KEY_Escape) { - this.cancel(); - } - })); - - this._promptBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); -+ - this.actor.add_child(this._promptBox); -+ this._userList.actor.add_constraint(new Clutter.BindConstraint({ source: this._promptBox, -+ coordinate: Clutter.BindCoordinate.WIDTH })); -+ - this._promptUser = new St.Bin({ x_fill: true, - x_align: St.Align.START }); - this._promptBox.add(this._promptUser, - { x_align: St.Align.START, - x_fill: true, - y_fill: true, - expand: true }); - this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' }); - - this._promptBox.add(this._promptLabel, - { expand: true, - x_fill: true, - y_fill: true, - x_align: St.Align.START }); - this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry', - can_focus: true }); - this._promptEntryTextChangedId = 0; - this._promptEntryActivateId = 0; - this._promptBox.add(this._promptEntry, - { expand: true, - x_fill: true, - y_fill: false, - x_align: St.Align.START }); - - this._promptEntry.grab_key_focus(); - - this._promptMessage = new St.Label({ opacity: 0 }); - this._promptBox.add(this._promptMessage, { x_fill: true }); - - this._promptLoginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' }); --- -1.8.3.1 - - -From d899057a7d0b9326dcaede62b88711fbff3a1e15 Mon Sep 17 00:00:00 2001 -From: "Jasper St. Pierre" -Date: Tue, 16 Jul 2013 15:48:27 -0400 -Subject: [PATCH 11/69] util: Fix hasPendingMessages - -While the UserVerifier does indeed have a _userVerifier inside -it, the hasPendingMessages property is on ourselves, not -_userVerifier. - -https://bugzilla.gnome.org/show_bug.cgi?id=704347 ---- - js/gdm/util.js | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/js/gdm/util.js b/js/gdm/util.js -index cae3e1b..c79958d 100644 ---- a/js/gdm/util.js -+++ b/js/gdm/util.js -@@ -136,61 +136,61 @@ const ShellUserVerifier = new Lang.Class({ - this._client.open_reauthentication_channel(userName, this._cancellable, - Lang.bind(this, this._reauthenticationChannelOpened)); - } else { - this._client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot)); - } - }, - - cancel: function() { - if (this._cancellable) - this._cancellable.cancel(); - - if (this._userVerifier) - this._userVerifier.call_cancel_sync(null); - }, - - clear: function() { - if (this._cancellable) { - this._cancellable.cancel(); - this._cancellable = null; - } - - if (this._userVerifier) { - this._userVerifier.run_dispose(); - this._userVerifier = null; - } - - this._clearMessageQueue(); - }, - - answerQuery: function(serviceName, answer) { -- if (!this._userVerifier.hasPendingMessages) { -+ if (!this.hasPendingMessages) { - this._clearMessageQueue(); - this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null); - } else { - let signalId = this._userVerifier.connect('no-more-messages', - Lang.bind(this, function() { - this._userVerifier.disconnect(signalId); - this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null); - })); - } - }, - - _getIntervalForMessage: function(message) { - // We probably could be smarter here - return message.length * USER_READ_TIME; - }, - - finishMessageQueue: function() { - if (!this.hasPendingMessages) - return; - - this._messageQueue = []; - - this.hasPendingMessages = false; - this.emit('no-more-messages'); - }, - - _queueMessageTimeout: function() { - if (this._messageQueue.length == 0) { - this.finishMessageQueue(); - return; -@@ -396,66 +396,66 @@ const ShellUserVerifier = new Lang.Class({ - // Clear previous attempts to authenticate - this._failCounter = 0; - - this.emit('reset'); - }, - - _onVerificationComplete: function() { - this.emit('verification-complete'); - }, - - _cancelAndReset: function() { - this.cancel(); - this._onReset(); - }, - - _retry: function() { - this.begin(this._userName, new Batch.Hold()); - }, - - _verificationFailed: function(retry) { - // For Not Listed / enterprise logins, immediately reset - // the dialog - // Otherwise, we allow ALLOWED_FAILURES attempts. After that, we - // go back to the welcome screen. - - this._failCounter++; - let canRetry = retry && this._userName && - this._failCounter < this._settings.get_int(ALLOWED_FAILURES_KEY); - - if (canRetry) { -- if (!this._userVerifier.hasPendingMessages) { -+ if (!this.hasPendingMessages) { - this._retry(); - } else { - let signalId = this._userVerifier.connect('no-more-messages', - Lang.bind(this, function() { - this._userVerifier.disconnect(signalId); - this._retry(); - })); - } - } else { -- if (!this._userVerifier.hasPendingMessages) { -+ if (!this.hasPendingMessages) { - this._cancelAndReset(); - } else { - let signalId = this._userVerifier.connect('no-more-messages', - Lang.bind(this, function() { - this._userVerifier.disconnect(signalId); - this._cancelAndReset(); - })); - } - } - - this.emit('verification-failed'); - }, - - _onConversationStopped: function(client, serviceName) { - // if the password service fails, then cancel everything. - // But if, e.g., fingerprint fails, still give - // password authentication a chance to succeed - if (serviceName == PASSWORD_SERVICE_NAME) { - this._verificationFailed(true); - } - - this.emit('hide-login-hint'); - }, - }); - Signals.addSignalMethods(ShellUserVerifier.prototype); --- -1.8.3.1 - - -From 4f31c7e209346ef4cbd2e5d833eea1250b29e165 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 17 Jul 2013 13:06:10 -0400 -Subject: [PATCH 12/69] util: Fix no-more-messages signal - -Now thas hasPendingMessages is fixed, we need to also fix the associated -signal "no-more-messages" - -https://bugzilla.gnome.org/show_bug.cgi?id=704347 ---- - js/gdm/util.js | 30 +++++++++++++++--------------- - 1 file changed, 15 insertions(+), 15 deletions(-) - -diff --git a/js/gdm/util.js b/js/gdm/util.js -index c79958d..04b2d49 100644 ---- a/js/gdm/util.js -+++ b/js/gdm/util.js -@@ -140,65 +140,65 @@ const ShellUserVerifier = new Lang.Class({ - } - }, - - cancel: function() { - if (this._cancellable) - this._cancellable.cancel(); - - if (this._userVerifier) - this._userVerifier.call_cancel_sync(null); - }, - - clear: function() { - if (this._cancellable) { - this._cancellable.cancel(); - this._cancellable = null; - } - - if (this._userVerifier) { - this._userVerifier.run_dispose(); - this._userVerifier = null; - } - - this._clearMessageQueue(); - }, - - answerQuery: function(serviceName, answer) { - if (!this.hasPendingMessages) { - this._clearMessageQueue(); - this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null); - } else { -- let signalId = this._userVerifier.connect('no-more-messages', -- Lang.bind(this, function() { -- this._userVerifier.disconnect(signalId); -- this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null); -- })); -+ let signalId = this.connect('no-more-messages', -+ Lang.bind(this, function() { -+ this.disconnect(signalId); -+ this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null); -+ })); - } - }, - - _getIntervalForMessage: function(message) { - // We probably could be smarter here - return message.length * USER_READ_TIME; - }, - - finishMessageQueue: function() { - if (!this.hasPendingMessages) - return; - - this._messageQueue = []; - - this.hasPendingMessages = false; - this.emit('no-more-messages'); - }, - - _queueMessageTimeout: function() { - if (this._messageQueue.length == 0) { - this.finishMessageQueue(); - return; - } - - if (this._messageQueueTimeoutId != 0) - return; - - let message = this._messageQueue.shift(); - this.emit('show-message', message.text, message.iconName); - -@@ -399,63 +399,63 @@ const ShellUserVerifier = new Lang.Class({ - this.emit('reset'); - }, - - _onVerificationComplete: function() { - this.emit('verification-complete'); - }, - - _cancelAndReset: function() { - this.cancel(); - this._onReset(); - }, - - _retry: function() { - this.begin(this._userName, new Batch.Hold()); - }, - - _verificationFailed: function(retry) { - // For Not Listed / enterprise logins, immediately reset - // the dialog - // Otherwise, we allow ALLOWED_FAILURES attempts. After that, we - // go back to the welcome screen. - - this._failCounter++; - let canRetry = retry && this._userName && - this._failCounter < this._settings.get_int(ALLOWED_FAILURES_KEY); - - if (canRetry) { - if (!this.hasPendingMessages) { - this._retry(); - } else { -- let signalId = this._userVerifier.connect('no-more-messages', -- Lang.bind(this, function() { -- this._userVerifier.disconnect(signalId); -- this._retry(); -- })); -+ let signalId = this.connect('no-more-messages', -+ Lang.bind(this, function() { -+ this.disconnect(signalId); -+ this._retry(); -+ })); - } - } else { - if (!this.hasPendingMessages) { - this._cancelAndReset(); - } else { -- let signalId = this._userVerifier.connect('no-more-messages', -- Lang.bind(this, function() { -- this._userVerifier.disconnect(signalId); -- this._cancelAndReset(); -- })); -+ let signalId = this.connect('no-more-messages', -+ Lang.bind(this, function() { -+ this.disconnect(signalId); -+ this._cancelAndReset(); -+ })); - } - } - - this.emit('verification-failed'); - }, - - _onConversationStopped: function(client, serviceName) { - // if the password service fails, then cancel everything. - // But if, e.g., fingerprint fails, still give - // password authentication a chance to succeed - if (serviceName == PASSWORD_SERVICE_NAME) { - this._verificationFailed(true); - } - - this.emit('hide-login-hint'); - }, - }); - Signals.addSignalMethods(ShellUserVerifier.prototype); --- -1.8.3.1 - - -From 955d95254975d3aca7ccfda7225cbc02e4d700f9 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 17 Jul 2013 16:02:55 -0400 -Subject: [PATCH 13/69] util: drop call that can't do anything - -this._clearMessageQueue() is a noop when this.hasPendingMessages is -false so calling it in that case doesn't make sense. - -This commit drops that call. - -https://bugzilla.gnome.org/show_bug.cgi?id=704347 ---- - js/gdm/util.js | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/js/gdm/util.js b/js/gdm/util.js -index 04b2d49..c9af991 100644 ---- a/js/gdm/util.js -+++ b/js/gdm/util.js -@@ -137,61 +137,60 @@ const ShellUserVerifier = new Lang.Class({ - Lang.bind(this, this._reauthenticationChannelOpened)); - } else { - this._client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot)); - } - }, - - cancel: function() { - if (this._cancellable) - this._cancellable.cancel(); - - if (this._userVerifier) - this._userVerifier.call_cancel_sync(null); - }, - - clear: function() { - if (this._cancellable) { - this._cancellable.cancel(); - this._cancellable = null; - } - - if (this._userVerifier) { - this._userVerifier.run_dispose(); - this._userVerifier = null; - } - - this._clearMessageQueue(); - }, - - answerQuery: function(serviceName, answer) { - if (!this.hasPendingMessages) { -- this._clearMessageQueue(); - this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null); - } else { - let signalId = this.connect('no-more-messages', - Lang.bind(this, function() { - this.disconnect(signalId); - this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null); - })); - } - }, - - _getIntervalForMessage: function(message) { - // We probably could be smarter here - return message.length * USER_READ_TIME; - }, - - finishMessageQueue: function() { - if (!this.hasPendingMessages) - return; - - this._messageQueue = []; - - this.hasPendingMessages = false; - this.emit('no-more-messages'); - }, - - _queueMessageTimeout: function() { - if (this._messageQueue.length == 0) { - this.finishMessageQueue(); - return; - } --- -1.8.3.1 - - -From 63ca46cfff83937c3daf38ddfa9c651a9df94f04 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 17 Jul 2013 16:42:33 -0400 -Subject: [PATCH 14/69] unlockDialog: don't unlock explicitly on - verification-complete - -logind sends out an "unlock" signal separately when -verification completes and we already listen for that, -so we don't need to unlock on verification-complete, too. - -https://bugzilla.gnome.org/show_bug.cgi?id=704347 ---- - js/ui/screenShield.js | 5 ----- - js/ui/unlockDialog.js | 14 -------------- - 2 files changed, 19 deletions(-) - -diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js -index 4264f01..0aa9758 100644 ---- a/js/ui/screenShield.js -+++ b/js/ui/screenShield.js -@@ -889,74 +889,69 @@ const ScreenShield = new Lang.Class({ - onComplete: Lang.bind(this, this._hideLockScreenComplete), - }); - } else { - this._hideLockScreenComplete(); - } - - global.stage.show_cursor(); - }, - - _ensureUnlockDialog: function(onPrimary, allowCancel) { - if (!this._dialog) { - let constructor = Main.sessionMode.unlockDialog; - if (!constructor) { - // This session mode has no locking capabilities - this.deactivate(true); - return; - } - - this._dialog = new constructor(this._lockDialogGroup); - - - let time = global.get_current_time(); - if (!this._dialog.open(time, onPrimary)) { - // This is kind of an impossible error: we're already modal - // by the time we reach this... - log('Could not open login dialog: failed to acquire grab'); - this.deactivate(true); - } - - this._dialog.connect('failed', Lang.bind(this, this._onUnlockFailed)); -- this._dialog.connect('unlocked', Lang.bind(this, this._onUnlockSucceded)); - } - - this._dialog.allowCancel = allowCancel; - }, - - _onUnlockFailed: function() { - this._resetLockScreen(true, false); - }, - -- _onUnlockSucceded: function() { -- this.deactivate(true); -- }, -- - _resetLockScreen: function(animateLockScreen, animateLockDialog) { - // Don't reset the lock screen unless it is completely hidden - // This prevents the shield going down if the lock-delay timeout - // fires while the user is dragging (which has the potential - // to confuse our state) - if (this._lockScreenState != MessageTray.State.HIDDEN) - return; - - this._ensureLockScreen(); - this._lockDialogGroup.scale_x = 1; - this._lockDialogGroup.scale_y = 1; - - this._lockScreenGroup.show(); - this._lockScreenState = MessageTray.State.SHOWING; - - if (animateLockScreen) { - this._lockScreenGroup.y = -global.screen_height; - Tweener.removeTweens(this._lockScreenGroup); - Tweener.addTween(this._lockScreenGroup, - { y: 0, - time: MANUAL_FADE_TIME, - transition: 'easeOutQuad', - onComplete: function() { - this._lockScreenShown(); - }, - onCompleteScope: this - }); - } else { - this._lockScreenGroup.fixed_position_set = false; - this._lockScreenShown(); -diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js -index 16fdbfa..1d60448 100644 ---- a/js/ui/unlockDialog.js -+++ b/js/ui/unlockDialog.js -@@ -197,76 +197,62 @@ const UnlockDialog = new Lang.Class({ - GdmUtil.fadeInActor(this._promptLoginHint); - }, - - _hideLoginHint: function() { - GdmUtil.fadeOutActor(this._promptLoginHint); - }, - - _doUnlock: function() { - if (this._firstQuestion) { - // we haven't received a query yet, so stash the answer - // and make ourself non-reactive - // the actual reply to GDM will be sent as soon as asked - this._firstQuestionAnswer = this._promptEntry.text; - this._updateSensitivity(false); - this.setWorking(true); - return; - } - - if (!this._currentQuery) - return; - - let query = this._currentQuery; - this._currentQuery = null; - - this._updateSensitivity(false); - this.setWorking(true); - - this._userVerifier.answerQuery(query, this._promptEntry.text); - }, - -- _finishUnlock: function() { -- this._userVerifier.clear(); -- this.emit('unlocked'); -- }, -- - _onVerificationComplete: function() { - this._userVerified = true; -- if (!this._userVerifier.hasPendingMessages) { -- this._finishUnlock(); -- } else { -- let signalId = this._userVerifier.connect('no-more-messages', -- Lang.bind(this, function() { -- this._userVerifier.disconnect(signalId); -- this._finishUnlock(); -- })); -- } - }, - - _onReset: function() { - if (!this._userVerified) { - this._userVerifier.clear(); - this.emit('failed'); - } - }, - - _onVerificationFailed: function() { - this._currentQuery = null; - this._firstQuestion = true; - this._userVerified = false; - - this._promptEntry.text = ''; - this._promptEntry.clutter_text.set_password_char('\u25cf'); - this._promptEntry.menu.isPassword = true; - - this._updateSensitivity(false); - this.setWorking(false); - }, - - _escape: function() { - if (this.allowCancel) { - this._userVerifier.cancel(); - this.emit('failed'); - } - }, - - _otherUserClicked: function(button, event) { --- -1.8.3.1 - - -From 45505ac56533a30aa81ba63fcfdc47302facd1ab Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Thu, 18 Jul 2013 08:58:58 -0400 -Subject: [PATCH 15/69] screenShield: defer deactivation until all messages are - shown - -Right now when a user types their password to unlock their session -we end up getting an unlock signal from GDM right away. We then -proceed to deactivate the screensaver before the user has a chance -to read his messages. - -This commit makes sure we clear out the message queue before processing -the deactivation request. - -https://bugzilla.gnome.org/show_bug.cgi?id=704347 ---- - js/ui/screenShield.js | 6 ++++++ - js/ui/unlockDialog.js | 14 ++++++++++++++ - 2 files changed, 20 insertions(+) - -diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js -index 0aa9758..d9fe883 100644 ---- a/js/ui/screenShield.js -+++ b/js/ui/screenShield.js -@@ -1083,60 +1083,66 @@ const ScreenShield = new Lang.Class({ - - _clearLockScreen: function() { - this._clock.destroy(); - this._clock = null; - - if (this._notificationsBox) { - this._notificationsBox.destroy(); - this._notificationsBox = null; - } - - this._stopArrowAnimation(); - - this._lockScreenContentsBox.destroy(); - - this._hasLockScreen = false; - }, - - get locked() { - return this._isLocked; - }, - - get active() { - return this._isActive; - }, - - get activationTime() { - return this._activationTime; - }, - - deactivate: function(animate) { -+ this._dialog.finish(Lang.bind(this, function() { -+ this._finishDeactivate(animate); -+ })); -+ }, -+ -+ _finishDeactivate: function(animate) { - this._hideLockScreen(animate, 0); - - if (this._hasLockScreen) - this._clearLockScreen(); - - if (Main.sessionMode.currentMode == 'lock-screen') - Main.sessionMode.popMode('lock-screen'); - if (Main.sessionMode.currentMode == 'unlock-dialog') - Main.sessionMode.popMode('unlock-dialog'); - - Tweener.addTween(this._lockDialogGroup, { - scale_x: 0, - scale_y: 0, - time: animate ? Overview.ANIMATION_TIME : 0, - transition: 'easeOutQuad', - onComplete: Lang.bind(this, this._completeDeactivate), - onCompleteScope: this - }); - }, - - _completeDeactivate: function() { - if (this._dialog && !this._isGreeter) { - this._dialog.destroy(); - this._dialog = null; - } - - this._lightbox.hide(); - - if (this._isModal) { - Main.popModal(this.actor); -diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js -index 1d60448..25bd92c 100644 ---- a/js/ui/unlockDialog.js -+++ b/js/ui/unlockDialog.js -@@ -255,31 +255,45 @@ const UnlockDialog = new Lang.Class({ - } - }, - - _otherUserClicked: function(button, event) { - Gdm.goto_login_session_sync(null); - - this._userVerifier.cancel(); - this.emit('failed'); - }, - - destroy: function() { - this._userVerifier.clear(); - - if (this._idleWatchId) { - this._idleMonitor.remove_watch(this._idleWatchId); - this._idleWatchId = 0; - } - - this.parent(); - }, - - cancel: function() { - this._userVerifier.cancel(null); - - this.destroy(); - }, - - addCharacter: function(unichar) { - this._promptEntry.clutter_text.insert_unichar(unichar); - }, -+ -+ finish: function(onComplete) { -+ if (!this._userVerifier.hasPendingMessages) { -+ onComplete(); -+ return; -+ } -+ -+ let signalId = this._userVerifier.connect('no-more-messages', -+ Lang.bind(this, function() { -+ this._userVerifier.disconnect(signalId); -+ onComplete(); -+ })); -+ -+ } - }); --- -1.8.3.1 - - -From 816db83b95882fb8b63fccf07c7561c43e284904 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Thu, 18 Jul 2013 10:13:32 -0400 -Subject: [PATCH 16/69] loginDialog: avoid blinking user list when - disable-user-list=true - -Right now if disable-user-list is true we show it briefly, just so -that we can fade it out to the user entry. - -This commit avoids the fade in that case. - -https://bugzilla.gnome.org/show_bug.cgi?id=704471 ---- - js/gdm/loginDialog.js | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index 15a2e0a..e132c72 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -423,61 +423,62 @@ const LoginDialog = new Lang.Class({ - Lang.bind(this, this._onSessionOpened)); - this._greeter.connect('timed-login-requested', - Lang.bind(this, this._onTimedLoginRequested)); - } - - this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient); - this._userVerifier.connect('ask-question', Lang.bind(this, this._askQuestion)); - this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage)); - this._userVerifier.connect('verification-failed', Lang.bind(this, this._verificationFailed)); - this._userVerifier.connect('reset', Lang.bind(this, this._reset)); - this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint)); - this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint)); - this._verifyingUser = false; - - 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', -- vertical: true }); -+ vertical: true, -+ visible: false }); - this._userSelectionBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - this.actor.add_child(this._userSelectionBox); - - this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner', - text: '' }); - 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._promptBox = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', - vertical: true }); - - this._promptBox.connect('button-press-event', - Lang.bind(this, function(actor, event) { - if (event.get_key_symbol() == Clutter.KEY_Escape) { - this.cancel(); - } - })); - - this._promptBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - -@@ -1101,61 +1102,62 @@ const LoginDialog = new Lang.Class({ - _onTimedLoginRequested: function(client, userName, seconds) { - this._startTimedLogin(userName, seconds); - - global.stage.connect('captured-event', - Lang.bind(this, function(actor, event) { - if (this._timedLoginDelay == undefined) - return false; - - if (event.type() == Clutter.EventType.KEY_PRESS || - event.type() == Clutter.EventType.BUTTON_PRESS) { - if (this._timedLoginBatch) { - this._timedLoginBatch.cancel(); - this._timedLoginBatch = null; - } - } else if (event.type() == Clutter.EventType.KEY_RELEASE || - event.type() == Clutter.EventType.BUTTON_RELEASE) { - this._resetTimedLogin(); - } - - return false; - })); - }, - - _setUserListExpanded: function(expanded) { - this._userList.updateStyle(expanded); - this._userSelectionBox.visible = expanded; - }, - - _hideUserListAndLogIn: function() { - this._setUserListExpanded(false); -- GdmUtil.cloneAndFadeOutActor(this._userSelectionBox); -+ if (this._userSelectionBox.visible) -+ GdmUtil.cloneAndFadeOutActor(this._userSelectionBox); - this._askForUsernameAndLogIn(); - }, - - _showUserList: function() { - this._hidePrompt(); - this._setUserListExpanded(true); - this._notListedButton.show(); - this._userList.actor.grab_key_focus(); - }, - - _beginVerificationForUser: function(userName) { - let hold = new Batch.Hold(); - - this._userVerifier.begin(userName, hold); - this._verifyingUser = true; - return hold; - }, - - _beginVerificationForItem: function(item) { - let userWidget = new UserWidget.UserWidget(item.user); - this._promptUser.set_child(userWidget.actor); - - let tasks = [function() { - let userName = item.user.get_user_name(); - return this._beginVerificationForUser(userName); - }]; - let batch = new Batch.ConsecutiveBatch(this, tasks); - return batch.run(); - }, - --- -1.8.3.1 - - -From 1faa288bd144570af05cbc7497a81fb9af62b9bc Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 17 Jul 2013 11:58:05 -0400 -Subject: [PATCH 17/69] unlockDialog: drop unused variable - -https://bugzilla.gnome.org/show_bug.cgi?id=702308 ---- - js/ui/unlockDialog.js | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js -index 25bd92c..50e9502 100644 ---- a/js/ui/unlockDialog.js -+++ b/js/ui/unlockDialog.js -@@ -15,61 +15,60 @@ const St = imports.gi.St; - const Main = imports.ui.main; - const ModalDialog = imports.ui.modalDialog; - const Panel = imports.ui.panel; - const ShellEntry = imports.ui.shellEntry; - const Tweener = imports.ui.tweener; - const UserMenu = imports.ui.userMenu; - const UserWidget = imports.ui.userWidget; - - const Batch = imports.gdm.batch; - const GdmUtil = imports.gdm.util; - const LoginDialog = imports.gdm.loginDialog; - - // The timeout before going back automatically to the lock screen (in seconds) - const IDLE_TIMEOUT = 2 * 60; - - const UnlockDialog = new Lang.Class({ - Name: 'UnlockDialog', - Extends: ModalDialog.ModalDialog, - - _init: function(parentActor) { - this.parent({ shellReactive: true, - styleClass: 'login-dialog', - keybindingMode: Shell.KeyBindingMode.UNLOCK_SCREEN, - parentActor: parentActor - }); - - this._userManager = AccountsService.UserManager.get_default(); - this._userName = GLib.get_user_name(); - this._user = this._userManager.get_user(this._userName); - -- this._failCounter = 0; - this._firstQuestion = true; - - this._greeterClient = new Gdm.Client(); - this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient, { reauthenticationOnly: true }); - this._userVerified = false; - - this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion)); - this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage)); - this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); - this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed)); - this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); - - this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint)); - this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint)); - - this._userWidget = new UserWidget.UserWidget(this._user); - this.contentLayout.add_actor(this._userWidget.actor); - - this._promptLayout = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', - vertical: true }); - - this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' }); - this._promptLayout.add(this._promptLabel, - { x_align: St.Align.START }); - - this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry', - can_focus: true }); - this._promptEntry.clutter_text.connect('activate', Lang.bind(this, this._doUnlock)); - this._promptEntry.clutter_text.set_password_char('\u25cf'); - ShellEntry.addContextMenu(this._promptEntry, { isPassword: true }); --- -1.8.3.1 - - -From 858be94cb8c6793ffb6488f64dda087acdeaeace Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 17 Jul 2013 09:54:03 -0400 -Subject: [PATCH 18/69] loginDialog: s/button-press-event/key-press-event/ - -A bug got introduced when moving the login dialog away from modal -dialog, such that it listens for escape key presses in a mouse -event handler instead of a keyboard event handler. - -This commit fixes that code to correctly listen for key-press-event -instead of button-press-event. - -https://bugzilla.gnome.org/show_bug.cgi?id=702308 ---- - js/gdm/loginDialog.js | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index e132c72..a9ca615 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -444,61 +444,61 @@ const LoginDialog = new Lang.Class({ - 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', - vertical: true, - visible: false }); - this._userSelectionBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - this.actor.add_child(this._userSelectionBox); - - this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner', - text: '' }); - 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._promptBox = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', - vertical: true }); - -- this._promptBox.connect('button-press-event', -+ this._promptBox.connect('key-press-event', - Lang.bind(this, function(actor, event) { - if (event.get_key_symbol() == Clutter.KEY_Escape) { - this.cancel(); - } - })); - - this._promptBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - - this.actor.add_child(this._promptBox); - this._userList.actor.add_constraint(new Clutter.BindConstraint({ source: this._promptBox, - coordinate: Clutter.BindCoordinate.WIDTH })); - - this._promptUser = new St.Bin({ x_fill: true, - x_align: St.Align.START }); - this._promptBox.add(this._promptUser, - { x_align: St.Align.START, - x_fill: true, - y_fill: true, - expand: true }); - this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' }); - - this._promptBox.add(this._promptLabel, - { expand: true, - x_fill: true, - y_fill: true, - x_align: St.Align.START }); - this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry', - can_focus: true }); --- -1.8.3.1 - - -From 0ec3099c58ffa2b68c58fd472a593921326e7c85 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Mon, 15 Jul 2013 17:56:44 -0400 -Subject: [PATCH 19/69] loginDialog: factor auth prompt code out to utils - -Right now there is a lot of duplicated code between the unlock -dialog and the login dialog. - -This commit moves the login dialog's auth prompt to a separate -class, so that it can (in a subsequent commit) be used by the -unlock dialog. - -https://bugzilla.gnome.org/show_bug.cgi?id=702308 ---- - js/gdm/loginDialog.js | 328 +++++++++----------------------------------------- - js/gdm/util.js | 283 +++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 337 insertions(+), 274 deletions(-) - -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index a9ca615..e9dd6b2 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -5,89 +5,79 @@ - * 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 Shell = imports.gi.Shell; - const Signals = imports.signals; - const St = imports.gi.St; - --const Panel = imports.ui.panel; - 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 _DEFAULT_BUTTON_WELL_ICON_SIZE = 24; --const _DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0; --const _DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3; - const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0; - const _LOGO_ICON_HEIGHT = 48; - - let _loginDialog = null; - --const DefaultButtonWellMode = { -- NONE: 0, -- SESSION_MENU_BUTTON: 1, -- SPINNER: 2 --}; -- - const UserListItem = new Lang.Class({ - Name: 'UserListItem', - - _init: function(user) { - this.user = user; - this._userChangedId = this.user.connect('changed', - Lang.bind(this, this._onUserChanged)); - - let layout = new St.BoxLayout({ vertical: false }); - this.actor = new St.Button({ style_class: 'login-dialog-user-list-item', - button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, - can_focus: true, - child: layout, - reactive: true, - x_align: St.Align.START, - x_fill: true }); - - this._userAvatar = new UserMenu.UserAvatarWidget(this.user, - { styleClass: 'login-dialog-user-list-item-icon' }); - layout.add(this._userAvatar.actor); - let textLayout = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-text-box', - vertical: true }); - layout.add(textLayout, { expand: true }); - - this._nameLabel = new St.Label({ style_class: 'login-dialog-user-list-item-name' }); - this.actor.label_actor = this._nameLabel; - textLayout.add(this._nameLabel, - { y_fill: false, - y_align: St.Align.MIDDLE, - expand: true }); -@@ -441,543 +431,333 @@ const LoginDialog = new Lang.Class({ - 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', - vertical: true, - visible: false }); - this._userSelectionBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - this.actor.add_child(this._userSelectionBox); - - this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner', - text: '' }); - 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._promptBox = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', -- vertical: true }); -- -- this._promptBox.connect('key-press-event', -- Lang.bind(this, function(actor, event) { -- if (event.get_key_symbol() == Clutter.KEY_Escape) { -+ this._authPrompt = new GdmUtil.AuthPrompt(); -+ this._authPrompt.hide(); -+ this._authPrompt.connect('cancel', -+ Lang.bind(this, function() { - this.cancel(); -- } - })); - -- this._promptBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, -- align_axis: Clutter.AlignAxis.BOTH, -- factor: 0.5 })); -+ this._authPrompt.actor.add_constraint(new Clutter.AlignConstraint({ source: this.actor, -+ align_axis: Clutter.AlignAxis.BOTH, -+ factor: 0.5 })); - -- this.actor.add_child(this._promptBox); -- this._userList.actor.add_constraint(new Clutter.BindConstraint({ source: this._promptBox, -+ this.actor.add_child(this._authPrompt.actor); -+ this._userList.actor.add_constraint(new Clutter.BindConstraint({ source: this._authPrompt.actor, - coordinate: Clutter.BindCoordinate.WIDTH })); - -- this._promptUser = new St.Bin({ x_fill: true, -- x_align: St.Align.START }); -- this._promptBox.add(this._promptUser, -- { x_align: St.Align.START, -- x_fill: true, -- y_fill: true, -- expand: true }); -- this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' }); -- -- this._promptBox.add(this._promptLabel, -- { expand: true, -- x_fill: true, -- y_fill: true, -- x_align: St.Align.START }); -- this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry', -- can_focus: true }); -- this._promptEntryTextChangedId = 0; -- this._promptEntryActivateId = 0; -- this._promptBox.add(this._promptEntry, -- { expand: true, -- x_fill: true, -- y_fill: false, -- x_align: St.Align.START }); -- -- this._promptEntry.grab_key_focus(); -- -- this._promptMessage = new St.Label({ opacity: 0 }); -- this._promptBox.add(this._promptMessage, { x_fill: true }); -- -- this._promptLoginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' }); -- this._promptBox.add(this._promptLoginHint); -- -- this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box', -- vertical: false }); -- this._promptBox.add(this._buttonBox, -- { expand: true, -- x_align: St.Align.MIDDLE, -- y_align: St.Align.END }); -- this._cancelButton = null; -- this._signInButton = null; -- -- this._promptBox.hide(); -- - // translators: this message is shown below the user list on the - // 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._hideUserListAndLogIn)); - this._notListedButton.hide(); - - this._userSelectionBox.add(this._notListedButton, - { expand: false, - x_align: St.Align.START, - x_fill: true }); - - this._logoBin = new St.Bin({ style_class: 'login-dialog-logo-bin', y_expand: true }); - this._logoBin.set_y_align(Clutter.ActorAlign.END); - this._logoBin.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.X_AXIS, - factor: 0.5 })); - this._logoBin.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.Y_AXIS, - factor: 1.0 })); - this.actor.add_child(this._logoBin); - this._updateLogo(); - - 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._defaultButtonWell = new St.Widget(); -- this._defaultButtonWellMode = DefaultButtonWellMode.NONE; - - 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._defaultButtonWell.add_child(this._sessionMenuButton.actor); -+ this._authPrompt.addActorToDefaultButtonWell(this._sessionMenuButton.actor); - -- let spinnerIcon = global.datadir + '/theme/process-working.svg'; -- this._workSpinner = new Panel.AnimatedIcon(spinnerIcon, _DEFAULT_BUTTON_WELL_ICON_SIZE); -- this._workSpinner.actor.opacity = 0; -- this._workSpinner.actor.show(); -- -- this._defaultButtonWell.add_child(this._workSpinner.actor); -- this._sessionMenuButton.actor.add_constraint(new Clutter.AlignConstraint({ source: this._workSpinner.actor, -- align_axis: Clutter.AlignAxis.BOTH, -- factor: 0.5 })); - }, - - _updateDisableUserList: function() { - let disableUserList = this._settings.get_boolean(GdmUtil.DISABLE_USER_LIST_KEY); - - if (disableUserList != this._disableUserList) { - this._disableUserList = disableUserList; - - if (!this._verifyingUser) - this._reset(); - } - }, - - _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(); - } - }, - - _updateLogoTexture: function(cache, uri) { - if (this._logoFileUri != uri) - return; - - let icon = null; - if (this._logoFileUri) - icon = this._textureCache.load_uri_async(this._logoFileUri, - -1, _LOGO_ICON_HEIGHT); - this._logoBin.set_child(icon); - }, - - _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); - }, - - _reset: function() { - this._userVerifier.clear(); - - this._updateSensitivity(true); -- this._promptMessage.opacity = 0; -+ this._authPrompt.reset(); -+ - this._user = null; - this._verifyingUser = false; - - if (this._disableUserList) - this._hideUserListAndLogIn(); - else - this._showUserList(); - }, - -- _getActorForDefaultButtonWellMode: function(mode) { -- let actor; -- -- if (mode == DefaultButtonWellMode.NONE) -- actor = null; -- else if (mode == DefaultButtonWellMode.SPINNER) -- actor = this._workSpinner.actor; -- else if (mode == DefaultButtonWellMode.SESSION_MENU_BUTTON) -- actor = this._sessionMenuButton.actor; -- -- return actor; -- }, -- -- _setDefaultButtonWellMode: function(mode, immediately) { -- if (this._defaultButtonWellMode == DefaultButtonWellMode.NONE && -- mode == DefaultButtonWellMode.NONE) -- return; -- -- let oldActor = this._getActorForDefaultButtonWellMode(this._defaultButtonWellMode); -- -- if (oldActor) -- Tweener.removeTweens(oldActor); -- -- let actor = this._getActorForDefaultButtonWellMode(mode); -- -- if (this._defaultButtonWellMode != mode && oldActor) { -- if (immediately) -- oldActor.opacity = 0; -- else -- Tweener.addTween(oldActor, -- { opacity: 0, -- time: _DEFAULT_BUTTON_WELL_ANIMATION_TIME, -- delay: _DEFAULT_BUTTON_WELL_ANIMATION_DELAY, -- transition: 'linear', -- onCompleteScope: this, -- onComplete: function() { -- if (mode == DefaultButtonWellMode.SPINNER) { -- if (this._workSpinner) -- this._workSpinner.stop(); -- } -- } -- }); -- -- } -- -- if (actor) { -- if (mode == DefaultButtonWellMode.SPINNER) -- this._workSpinner.play(); -- -- if (immediately) -- actor.opacity = 255; -- else -- Tweener.addTween(actor, -- { opacity: 255, -- time: _DEFAULT_BUTTON_WELL_ANIMATION_TIME, -- delay: _DEFAULT_BUTTON_WELL_ANIMATION_DELAY, -- transition: 'linear' }); -- } -- -- this._defaultButtonWellMode = mode; -- }, -- - _verificationFailed: function() { -- this._promptEntry.text = ''; -+ this._authPrompt.clear(); - - this._updateSensitivity(true); -- this._setDefaultButtonWellMode(DefaultButtonWellMode.NONE, true); -+ this._authPrompt.setActorInDefaultButtonWell(null); - }, - - _onDefaultSessionChanged: function(client, sessionId) { - this._sessionMenuButton.setActiveSession(sessionId); - }, - - _showMessage: function(userVerifier, message, styleClass) { -- if (message) { -- this._promptMessage.text = message; -- this._promptMessage.styleClass = styleClass; -- this._promptMessage.opacity = 255; -- } else { -- this._promptMessage.opacity = 0; -- } -+ this._authPrompt.setMessage(message, styleClass); - }, - - _showLoginHint: function(verifier, message) { -- this._promptLoginHint.set_text(message) -- this._promptLoginHint.opacity = 255; -+ this._authPrompt.setHint(message); - }, - - _hideLoginHint: function() { -- this._promptLoginHint.opacity = 0; -- this._promptLoginHint.set_text(''); -+ this._authPrompt.setHint(null); - }, - - cancel: function() { - if (this._verifyingUser) - this._userVerifier.cancel(); - else - this._reset(); - }, - - _shouldShowSessionMenuButton: function() { - if (this._verifyingUser) - return true; - - if (!this._user) - return false; - - if (this._user.is_logged_in) - return false; - - return true; - }, - - _showPrompt: function(forSecret) { -- this._promptLabel.show(); -- this._promptEntry.show(); -- this._promptLoginHint.opacity = 0; -- this._promptLoginHint.show(); -- this._promptBox.opacity = 0; -- this._promptBox.show(); -- Tweener.addTween(this._promptBox, -+ this._authPrompt.actor.opacity = 0; -+ this._authPrompt.actor.show(); -+ Tweener.addTween(this._authPrompt.actor, - { opacity: 255, - time: _FADE_ANIMATION_TIME, - transition: 'easeOutQuad' }); - -- if (this._shouldShowSessionMenuButton()) -- this._setDefaultButtonWellMode(DefaultButtonWellMode.SESSION_MENU_BUTTON, true); -- else -- this._setDefaultButtonWellMode(DefaultButtonWellMode.NONE, true); -- -- this._promptEntry.grab_key_focus(); -- - let hold = new Batch.Hold(); - let tasks = [function() { -- this._prepareDialog(forSecret, hold); -+ this._preparePrompt(forSecret, hold); - }, - - hold]; - - let batch = new Batch.ConcurrentBatch(this, tasks); - - return batch.run(); - }, - -- _prepareDialog: function(forSecret, hold) { -- this._buttonBox.visible = true; -- this._buttonBox.remove_all_children(); -- -+ _preparePrompt: function(forSecret, hold) { - if (!this._disableUserList || this._verifyingUser) { -- this._cancelButton = new St.Button({ style_class: 'modal-dialog-button', -- button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, -- reactive: true, -- can_focus: true, -- label: _("Cancel") }); -- this._cancelButton.connect('clicked', -- Lang.bind(this, function() { -- this.cancel(); -- })); -- this._buttonBox.add(this._cancelButton, -- { expand: false, -- x_fill: false, -- y_fill: false, -- x_align: St.Align.START, -- y_align: St.Align.END }); -+ this._authPrompt.cancelButton.show(); -+ } else { -+ this._authPrompt.cancelButton.hide(); - } - -- this._buttonBox.add(this._defaultButtonWell, -- { expand: true, -- x_fill: false, -- y_fill: false, -- x_align: St.Align.END, -- y_align: St.Align.MIDDLE }); -- this._signInButton = new St.Button({ style_class: 'modal-dialog-button', -- button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, -- reactive: true, -- can_focus: true, -- label: forSecret ? C_("button", "Sign In") : _("Next") }); -- this._signInButton.connect('clicked', -- Lang.bind(this, function() { -- hold.release(); -- })); -- this._signInButton.add_style_pseudo_class('default'); -- this._buttonBox.add(this._signInButton, -- { expand: false, -- x_fill: false, -- y_fill: false, -- x_align: St.Align.END, -- y_align: St.Align.END }); -- -- this._updateSignInButtonSensitivity(this._promptEntry.text.length > 0); -- -- this._promptEntryTextChangedId = -- this._promptEntry.clutter_text.connect('text-changed', -- Lang.bind(this, function() { -- this._updateSignInButtonSensitivity(this._promptEntry.text.length > 0); -- })); -- -- this._promptEntryActivateId = -- this._promptEntry.clutter_text.connect('activate', function() { -- hold.release(); -- }); -+ if (forSecret) { -+ this._authPrompt.nextButton.label = C_("button", "Sign In"); -+ } else { -+ this._authPrompt.nextButton.label = _("Next"); -+ } -+ -+ let signalId = this._authPrompt.connect('next', Lang.bind(this, function() { -+ this._authPrompt.disconnect(signalId); -+ hold.release(); -+ })); - }, - - _updateSensitivity: function(sensitive) { -- this._promptEntry.reactive = sensitive; -- this._promptEntry.clutter_text.editable = sensitive; - this._sessionMenuButton.updateSensitivity(sensitive); -- this._updateSignInButtonSensitivity(sensitive); -- }, -- -- _updateSignInButtonSensitivity: function(sensitive) { -- if (this._signInButton) { -- this._signInButton.reactive = sensitive; -- this._signInButton.can_focus = sensitive; -- } -- }, -- -- _hidePrompt: function() { -- if (this._promptEntryTextChangedId > 0) { -- this._promptEntry.clutter_text.disconnect(this._promptEntryTextChangedId); -- this._promptEntryTextChangedId = 0; -- } -- -- if (this._promptEntryActivateId > 0) { -- this._promptEntry.clutter_text.disconnect(this._promptEntryActivateId); -- this._promptEntryActivateId = 0; -- } -- -- this._setDefaultButtonWellMode(DefaultButtonWellMode.NONE, true); -- this._promptBox.hide(); -- this._promptLoginHint.opacity = 0; -- -- this._promptUser.set_child(null); -- -- this._updateSensitivity(true); -- this._promptEntry.set_text(''); -- -- this._sessionMenuButton.close(); -- this._promptLoginHint.opacity = 0; -- -- this._buttonBox.remove_all_children(); -- this._signInButton = null; -- this._cancelButton = null; -+ this._authPrompt.updateSensitivity(sensitive); - }, - - _askQuestion: function(verifier, serviceName, question, passwordChar) { -- this._promptLabel.set_text(question); -+ this._authPrompt.setPasswordChar(passwordChar); -+ this._authPrompt.setQuestion(question); - - this._updateSensitivity(true); -- this._promptEntry.set_text(''); -- this._promptEntry.clutter_text.set_password_char(passwordChar); -+ -+ if (this._shouldShowSessionMenuButton()) -+ this._authPrompt.setActorInDefaultButtonWell(this._sessionMenuButton.actor); -+ else -+ this._authPrompt.setActorInDefaultButtonWell(null); - - let tasks = [function() { - return this._showPrompt(!!passwordChar); - }, - - function() { -- let text = this._promptEntry.get_text(); -+ let text = this._authPrompt.getAnswer(); -+ - this._updateSensitivity(false); -- this._setDefaultButtonWellMode(DefaultButtonWellMode.SPINNER, false); -+ this._authPrompt.startSpinning(); - this._userVerifier.answerQuery(serviceName, text); - }]; - - let batch = new Batch.ConsecutiveBatch(this, tasks); - return batch.run(); - }, - - _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._showLoginHint(null, _("(e.g., user or %s)").format(hint)); - }, - - _askForUsernameAndLogIn: function() { -- this._promptLabel.set_text(_("Username: ")); -- this._promptEntry.set_text(''); -- this._promptEntry.clutter_text.set_password_char(''); -+ this._authPrompt.setPasswordChar(''); -+ this._authPrompt.setQuestion(_("Username: ")); - - let realmManager = new Realmd.Manager(); - let signalId = realmManager.connect('login-format-changed', - Lang.bind(this, this._showRealmLoginHint)); - this._showRealmLoginHint(realmManager.loginFormat); - - let tasks = [this._showPrompt, - - function() { -- let userName = this._promptEntry.get_text(); -- this._promptEntry.reactive = false; -+ let userName = this._authPrompt.getAnswer(); -+ this._authPrompt._entry.reactive = false; - return this._beginVerificationForUser(userName); - }, - - function() { - realmManager.disconnect(signalId) - realmManager.release(); - }]; - - let batch = new Batch.ConsecutiveBatch(this, tasks); - return batch.run(); - }, - - _startSession: function(serviceName) { - Tweener.addTween(this.actor, - { opacity: 0, - time: _FADE_ANIMATION_TIME, - transition: 'easeOutQuad', - onUpdate: function() { - let children = Main.layoutManager.uiGroup.get_children(); - - for (let i = 0; i < children.length; i++) { - if (children[i] != Main.layoutManager.screenShieldGroup) - children[i].opacity = this.actor.opacity; - } - }, - onUpdateScope: this, - onComplete: function() { - Mainloop.idle_add(Lang.bind(this, function() { - this._greeter.call_start_session_when_ready_sync(serviceName, true, null); - return false; -@@ -1108,77 +888,77 @@ const LoginDialog = new Lang.Class({ - return false; - - if (event.type() == Clutter.EventType.KEY_PRESS || - event.type() == Clutter.EventType.BUTTON_PRESS) { - if (this._timedLoginBatch) { - this._timedLoginBatch.cancel(); - this._timedLoginBatch = null; - } - } else if (event.type() == Clutter.EventType.KEY_RELEASE || - event.type() == Clutter.EventType.BUTTON_RELEASE) { - this._resetTimedLogin(); - } - - return false; - })); - }, - - _setUserListExpanded: function(expanded) { - this._userList.updateStyle(expanded); - this._userSelectionBox.visible = expanded; - }, - - _hideUserListAndLogIn: function() { - this._setUserListExpanded(false); - if (this._userSelectionBox.visible) - GdmUtil.cloneAndFadeOutActor(this._userSelectionBox); - this._askForUsernameAndLogIn(); - }, - - _showUserList: function() { -- this._hidePrompt(); -+ this._authPrompt.hide(); -+ this._sessionMenuButton.close(); - this._setUserListExpanded(true); - this._notListedButton.show(); - this._userList.actor.grab_key_focus(); - }, - - _beginVerificationForUser: function(userName) { - let hold = new Batch.Hold(); - - this._userVerifier.begin(userName, hold); - this._verifyingUser = true; - return hold; - }, - - _beginVerificationForItem: function(item) { -- let userWidget = new UserWidget.UserWidget(item.user); -- this._promptUser.set_child(userWidget.actor); -+ this._authPrompt.setUser(item.user); - - let tasks = [function() { - let userName = item.user.get_user_name(); - return this._beginVerificationForUser(userName); - }]; - let batch = new Batch.ConsecutiveBatch(this, tasks); - return batch.run(); - }, - - _onUserListActivated: function(activatedItem) { - let tasks = [function() { - return GdmUtil.cloneAndFadeOutActor(this._userSelectionBox); - }, - function() { - this._setUserListExpanded(false); - }]; - - this._user = activatedItem.user; - - let batch = new Batch.ConcurrentBatch(this, [new Batch.ConsecutiveBatch(this, tasks), - this._beginVerificationForItem(activatedItem)]); - batch.run(); - }, - - _onDestroy: function() { - if (this._userManagerLoadedId) { - this._userManager.disconnect(this._userManagerLoadedId); - this._userManagerLoadedId = 0; - } - }, -@@ -1192,34 +972,34 @@ const LoginDialog = new Lang.Class({ - - this._updateDisableUserList(); - - this._userManager.connect('user-added', - Lang.bind(this, function(userManager, user) { - this._userList.addUser(user); - })); - - this._userManager.connect('user-removed', - Lang.bind(this, function(userManager, user) { - this._userList.removeUser(user); - })); - }, - - open: function() { - Main.ctrlAltTabManager.addGroup(this.actor, - _("Login Window"), - 'dialog-password-symbolic', - { sortGroup: CtrlAltTab.SortGroup.MIDDLE }); - this._userList.actor.grab_key_focus(); - this.actor.show(); - - return true; - }, - - close: function() { - Main.ctrlAltTabManager.removeGroup(this.dialogLayout); - }, - - addCharacter: function(unichar) { -- this._promptEntry.clutter_text.insert_unichar(unichar); -+ this._authPrompt.addCharacter(unichar); - }, - }); - Signals.addSignalMethods(LoginDialog.prototype); -diff --git a/js/gdm/util.js b/js/gdm/util.js -index c9af991..fbbbae0 100644 ---- a/js/gdm/util.js -+++ b/js/gdm/util.js -@@ -1,62 +1,69 @@ - // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - - const Clutter = imports.gi.Clutter; - const Gio = imports.gi.Gio; - const GLib = imports.gi.GLib; - const Lang = imports.lang; - const Mainloop = imports.mainloop; - const Signals = imports.signals; -+const St = imports.gi.St; - -+const Panel = imports.ui.panel; - const Batch = imports.gdm.batch; - const Fprint = imports.gdm.fingerprint; - const Main = imports.ui.main; - const Params = imports.misc.params; - const Tweener = imports.ui.tweener; -+const UserWidget = imports.ui.userWidget; - - const PASSWORD_SERVICE_NAME = 'gdm-password'; - const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint'; - const FADE_ANIMATION_TIME = 0.16; - const CLONE_FADE_ANIMATION_TIME = 0.25; - - const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen'; - const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication'; - const BANNER_MESSAGE_KEY = 'banner-message-enable'; - const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text'; - const ALLOWED_FAILURES_KEY = 'allowed-failures'; - - const LOGO_KEY = 'logo'; - const DISABLE_USER_LIST_KEY = 'disable-user-list'; - - // Give user 16ms to read each character of a PAM message - const USER_READ_TIME = 16 - -+const DEFAULT_BUTTON_WELL_ICON_SIZE = 24; -+const DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0; -+const DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3; -+ - function fadeInActor(actor) { - if (actor.opacity == 255 && actor.visible) - return null; - - let hold = new Batch.Hold(); - actor.show(); - let [minHeight, naturalHeight] = actor.get_preferred_height(-1); - - actor.opacity = 0; - actor.set_height(0); - Tweener.addTween(actor, - { opacity: 255, - height: naturalHeight, - time: FADE_ANIMATION_TIME, - transition: 'easeOutQuad', - onComplete: function() { - this.set_height(-1); - hold.release(); - }, - }); - - return hold; - } - - function fadeOutActor(actor) { - if (!actor.visible || actor.opacity == 0) { - actor.opacity = 0; - actor.hide(); - return null; - } -@@ -431,30 +438,306 @@ const ShellUserVerifier = new Lang.Class({ - this._retry(); - })); - } - } else { - if (!this.hasPendingMessages) { - this._cancelAndReset(); - } else { - let signalId = this.connect('no-more-messages', - Lang.bind(this, function() { - this.disconnect(signalId); - this._cancelAndReset(); - })); - } - } - - this.emit('verification-failed'); - }, - - _onConversationStopped: function(client, serviceName) { - // if the password service fails, then cancel everything. - // But if, e.g., fingerprint fails, still give - // password authentication a chance to succeed - if (serviceName == PASSWORD_SERVICE_NAME) { - this._verificationFailed(true); - } - - this.emit('hide-login-hint'); - }, - }); - Signals.addSignalMethods(ShellUserVerifier.prototype); -+ -+const AuthPrompt = new Lang.Class({ -+ Name: 'AuthPrompt', -+ -+ _init: function() { -+ this.actor = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', -+ vertical: true }); -+ this.actor.connect('key-press-event', -+ Lang.bind(this, function(actor, event) { -+ if (event.get_key_symbol() == Clutter.KEY_Escape) { -+ this.emit('cancel'); -+ } -+ })); -+ -+ this._userWell = new St.Bin({ x_fill: true, -+ x_align: St.Align.START }); -+ this.actor.add(this._userWell, -+ { x_align: St.Align.START, -+ x_fill: true, -+ y_fill: true, -+ expand: true }); -+ this._label = new St.Label({ style_class: 'login-dialog-prompt-label' }); -+ -+ this.actor.add(this._label, -+ { expand: true, -+ x_fill: true, -+ y_fill: true, -+ x_align: St.Align.START }); -+ this._entry = new St.Entry({ style_class: 'login-dialog-prompt-entry', -+ can_focus: true }); -+ this.actor.add(this._entry, -+ { expand: true, -+ x_fill: true, -+ y_fill: false, -+ x_align: St.Align.START }); -+ -+ this._entry.grab_key_focus(); -+ -+ this._message = new St.Label({ opacity: 0 }); -+ this.actor.add(this._message, { x_fill: true }); -+ -+ this._loginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' }); -+ this.actor.add(this._loginHint); -+ -+ this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box', -+ vertical: false }); -+ this.actor.add(this._buttonBox, -+ { expand: true, -+ x_align: St.Align.MIDDLE, -+ y_align: St.Align.END }); -+ -+ this._defaultButtonWell = new St.Widget(); -+ this._defaultButtonWellActor = null; -+ -+ this._initButtons(); -+ -+ let spinnerIcon = global.datadir + '/theme/process-working.svg'; -+ this._spinner = new Panel.AnimatedIcon(spinnerIcon, DEFAULT_BUTTON_WELL_ICON_SIZE); -+ this._spinner.actor.opacity = 0; -+ this._spinner.actor.show(); -+ this._defaultButtonWell.add_child(this._spinner.actor); -+ }, -+ -+ _initButtons: function() { -+ this.cancelButton = new St.Button({ style_class: 'modal-dialog-button', -+ button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, -+ reactive: true, -+ can_focus: true, -+ label: _("Cancel") }); -+ this.cancelButton.connect('clicked', -+ Lang.bind(this, function() { -+ this.emit('cancel'); -+ })); -+ this._buttonBox.add(this.cancelButton, -+ { expand: false, -+ x_fill: false, -+ y_fill: false, -+ x_align: St.Align.START, -+ y_align: St.Align.END }); -+ -+ this._buttonBox.add(this._defaultButtonWell, -+ { expand: true, -+ x_fill: false, -+ y_fill: false, -+ x_align: St.Align.END, -+ y_align: St.Align.MIDDLE }); -+ this.nextButton = new St.Button({ style_class: 'modal-dialog-button', -+ button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, -+ reactive: true, -+ can_focus: true, -+ label: _("Next") }); -+ this.nextButton.connect('clicked', -+ Lang.bind(this, function() { -+ this.emit('next'); -+ })); -+ this.nextButton.add_style_pseudo_class('default'); -+ this._buttonBox.add(this.nextButton, -+ { expand: false, -+ x_fill: false, -+ y_fill: false, -+ x_align: St.Align.END, -+ y_align: St.Align.END }); -+ -+ this._updateNextButtonSensitivity(this._entry.text.length > 0); -+ -+ this._entry.clutter_text.connect('text-changed', -+ Lang.bind(this, function() { -+ this._updateNextButtonSensitivity(this._entry.text.length > 0); -+ })); -+ this._entry.clutter_text.connect('activate', Lang.bind(this, function() { -+ this.emit('next'); -+ })); -+ }, -+ -+ addActorToDefaultButtonWell: function(actor) { -+ this._defaultButtonWell.add_child(actor); -+ -+ actor.add_constraint(new Clutter.AlignConstraint({ source: this._spinner.actor, -+ align_axis: Clutter.AlignAxis.BOTH, -+ factor: 0.5 })); -+ }, -+ -+ setActorInDefaultButtonWell: function(actor, animate) { -+ if (!this._defaultButtonWellActor && -+ !actor) -+ return; -+ -+ let oldActor = this._defaultButtonWellActor; -+ -+ if (oldActor) -+ Tweener.removeTweens(oldActor); -+ -+ let isSpinner; -+ if (actor == this._spinner.actor) -+ isSpinner = true; -+ else -+ isSpinner = false; -+ -+ if (this._defaultButtonWellActor != actor && oldActor) { -+ if (!animate) { -+ oldActor.opacity = 0; -+ } else { -+ Tweener.addTween(oldActor, -+ { opacity: 0, -+ time: DEFAULT_BUTTON_WELL_ANIMATION_TIME, -+ delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY, -+ transition: 'linear', -+ onCompleteScope: this, -+ onComplete: function() { -+ if (isSpinner) { -+ if (this._spinner) -+ this._spinner.stop(); -+ } -+ } -+ }); -+ } -+ } -+ -+ if (actor) { -+ if (isSpinner) -+ this._spinner.play(); -+ -+ if (!animate) -+ actor.opacity = 255; -+ else -+ Tweener.addTween(actor, -+ { opacity: 255, -+ time: DEFAULT_BUTTON_WELL_ANIMATION_TIME, -+ delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY, -+ transition: 'linear' }); -+ } -+ -+ this._defaultButtonWellActor = actor; -+ }, -+ -+ startSpinning: function() { -+ this.setActorInDefaultButtonWell(this._spinner.actor, true); -+ }, -+ -+ stopSpinning: function() { -+ this.setActorInDefaultButtonWell(null, false); -+ }, -+ -+ clear: function() { -+ this._entry.text = ''; -+ this.stopSpinning(); -+ }, -+ -+ setPasswordChar: function(passwordChar) { -+ this._entry.clutter_text.set_password_char(passwordChar); -+ }, -+ -+ setQuestion: function(question) { -+ this._label.set_text(question); -+ -+ this._label.show(); -+ this._entry.show(); -+ -+ this._loginHint.opacity = 0; -+ this._loginHint.show(); -+ -+ this._entry.grab_key_focus(); -+ }, -+ -+ getAnswer: function() { -+ let text = this._entry.get_text(); -+ -+ return text; -+ }, -+ -+ setMessage: function(message, styleClass) { -+ if (message) { -+ this._message.text = message; -+ this._message.styleClass = styleClass; -+ this._message.opacity = 255; -+ } else { -+ this._message.opacity = 0; -+ } -+ }, -+ -+ _updateNextButtonSensitivity: function(sensitive) { -+ this.nextButton.reactive = sensitive; -+ this.nextButton.can_focus = sensitive; -+ }, -+ -+ updateSensitivity: function(sensitive) { -+ this._updateNextButtonSensitivity(sensitive); -+ this._entry.reactive = sensitive; -+ this._entry.clutter_text.editable = sensitive; -+ }, -+ -+ hide: function() { -+ this.setActorInDefaultButtonWell(null, true); -+ this.actor.hide(); -+ this._loginHint.opacity = 0; -+ -+ this.setUser(null); -+ -+ this.updateSensitivity(true); -+ this._entry.set_text(''); -+ }, -+ -+ setUser: function(user) { -+ if (user) { -+ let userWidget = new UserWidget.UserWidget(user); -+ this._userWell.set_child(userWidget.actor); -+ } else { -+ this._userWell.set_child(null); -+ } -+ }, -+ -+ setHint: function(message) { -+ if (message) { -+ this._loginHint.set_text(message) -+ this._loginHint.opacity = 255; -+ } else { -+ this._loginHint.opacity = 0; -+ this._loginHint.set_text(''); -+ } -+ }, -+ -+ reset: function() { -+ this._message.opacity = 0; -+ this.setUser(null); -+ this.stopSpinning(); -+ }, -+ -+ addCharacter: function(unichar) { -+ if (!this._entry.visible) -+ return; -+ -+ this._entry.grab_key_focus(); -+ this._entry.clutter_text.insert_unichar(unichar); -+ } -+}); -+Signals.addSignalMethods(AuthPrompt.prototype); --- -1.8.3.1 - - -From 664f9f789a46491da201319d72009a61ac79115e Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Thu, 18 Jul 2013 14:40:10 -0400 -Subject: [PATCH 20/69] util: add shell entry menu to auth prompt - -This brings us parity with the unlock dialog, and is a prerequisite -for eventually moving the unlock dialog over to using the auth -prompt. - -https://bugzilla.gnome.org/show_bug.cgi?id=702308 ---- - js/gdm/util.js | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/js/gdm/util.js b/js/gdm/util.js -index fbbbae0..084bc7b 100644 ---- a/js/gdm/util.js -+++ b/js/gdm/util.js -@@ -1,45 +1,46 @@ - // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - - const Clutter = imports.gi.Clutter; - const Gio = imports.gi.Gio; - const GLib = imports.gi.GLib; - const Lang = imports.lang; - const Mainloop = imports.mainloop; - const Signals = imports.signals; - const St = imports.gi.St; - - const Panel = imports.ui.panel; - const Batch = imports.gdm.batch; - const Fprint = imports.gdm.fingerprint; - const Main = imports.ui.main; - const Params = imports.misc.params; -+const ShellEntry = imports.ui.shellEntry; - const Tweener = imports.ui.tweener; - const UserWidget = imports.ui.userWidget; - - const PASSWORD_SERVICE_NAME = 'gdm-password'; - const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint'; - const FADE_ANIMATION_TIME = 0.16; - const CLONE_FADE_ANIMATION_TIME = 0.25; - - const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen'; - const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication'; - const BANNER_MESSAGE_KEY = 'banner-message-enable'; - const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text'; - const ALLOWED_FAILURES_KEY = 'allowed-failures'; - - const LOGO_KEY = 'logo'; - const DISABLE_USER_LIST_KEY = 'disable-user-list'; - - // Give user 16ms to read each character of a PAM message - const USER_READ_TIME = 16 - - const DEFAULT_BUTTON_WELL_ICON_SIZE = 24; - const DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0; - const DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3; - - function fadeInActor(actor) { - if (actor.opacity == 255 && actor.visible) - return null; - - let hold = new Batch.Hold(); - actor.show(); -@@ -468,60 +469,62 @@ Signals.addSignalMethods(ShellUserVerifier.prototype); - - const AuthPrompt = new Lang.Class({ - Name: 'AuthPrompt', - - _init: function() { - this.actor = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', - vertical: true }); - this.actor.connect('key-press-event', - Lang.bind(this, function(actor, event) { - if (event.get_key_symbol() == Clutter.KEY_Escape) { - this.emit('cancel'); - } - })); - - this._userWell = new St.Bin({ x_fill: true, - x_align: St.Align.START }); - this.actor.add(this._userWell, - { x_align: St.Align.START, - x_fill: true, - y_fill: true, - expand: true }); - this._label = new St.Label({ style_class: 'login-dialog-prompt-label' }); - - this.actor.add(this._label, - { expand: true, - x_fill: true, - y_fill: true, - x_align: St.Align.START }); - this._entry = new St.Entry({ style_class: 'login-dialog-prompt-entry', - can_focus: true }); -+ ShellEntry.addContextMenu(this._entry, { isPassword: true }); -+ - this.actor.add(this._entry, - { expand: true, - x_fill: true, - y_fill: false, - x_align: St.Align.START }); - - this._entry.grab_key_focus(); - - this._message = new St.Label({ opacity: 0 }); - this.actor.add(this._message, { x_fill: true }); - - this._loginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' }); - this.actor.add(this._loginHint); - - this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box', - vertical: false }); - this.actor.add(this._buttonBox, - { expand: true, - x_align: St.Align.MIDDLE, - y_align: St.Align.END }); - - this._defaultButtonWell = new St.Widget(); - this._defaultButtonWellActor = null; - - this._initButtons(); - - let spinnerIcon = global.datadir + '/theme/process-working.svg'; - this._spinner = new Panel.AnimatedIcon(spinnerIcon, DEFAULT_BUTTON_WELL_ICON_SIZE); - this._spinner.actor.opacity = 0; - this._spinner.actor.show(); -@@ -628,60 +631,61 @@ const AuthPrompt = new Lang.Class({ - this._spinner.play(); - - if (!animate) - actor.opacity = 255; - else - Tweener.addTween(actor, - { opacity: 255, - time: DEFAULT_BUTTON_WELL_ANIMATION_TIME, - delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY, - transition: 'linear' }); - } - - this._defaultButtonWellActor = actor; - }, - - startSpinning: function() { - this.setActorInDefaultButtonWell(this._spinner.actor, true); - }, - - stopSpinning: function() { - this.setActorInDefaultButtonWell(null, false); - }, - - clear: function() { - this._entry.text = ''; - this.stopSpinning(); - }, - - setPasswordChar: function(passwordChar) { - this._entry.clutter_text.set_password_char(passwordChar); -+ this._entry.menu.isPassword = passwordChar != ''; - }, - - setQuestion: function(question) { - this._label.set_text(question); - - this._label.show(); - this._entry.show(); - - this._loginHint.opacity = 0; - this._loginHint.show(); - - this._entry.grab_key_focus(); - }, - - getAnswer: function() { - let text = this._entry.get_text(); - - return text; - }, - - setMessage: function(message, styleClass) { - if (message) { - this._message.text = message; - this._message.styleClass = styleClass; - this._message.opacity = 255; - } else { - this._message.opacity = 0; - } - }, - --- -1.8.3.1 - - -From 7a92988dd7c65f020a2c986dfa6e73b79ba8410c Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 16 Jul 2013 07:31:22 -0400 -Subject: [PATCH 21/69] unlockDialog: Use GdmUtil.AuthPrompt instead of - ModalDialog - -commit ea02380c1524c28e6538ffedb789a12c298742ab made the login -screen stop using ModalDialog. It makes sense for the unlock -code to also stop using ModalDialog, too (for similar reasons). - -Now that the login screen's auth prompt code has been separated -out, the unlock dialog can use it to get the buttons and spinners -etc, that it was previously getting from ModalDialog. - -This commit drops the ModalDialog usage in the unlock dialog, and -makes the unlock dialog use GdmUtil.AuthPrompt instead. - -https://bugzilla.gnome.org/show_bug.cgi?id=702308 ---- - js/ui/unlockDialog.js | 157 +++++++++++++++++++------------------------------- - 1 file changed, 60 insertions(+), 97 deletions(-) - -diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js -index 50e9502..4a36cd3 100644 ---- a/js/ui/unlockDialog.js -+++ b/js/ui/unlockDialog.js -@@ -1,298 +1,261 @@ - // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - - 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 GnomeDesktop = imports.gi.GnomeDesktop; - const Gtk = imports.gi.Gtk; - const Lang = imports.lang; - const Signals = imports.signals; - const Shell = imports.gi.Shell; - const St = imports.gi.St; - -+const Layout = imports.ui.layout; - const Main = imports.ui.main; --const ModalDialog = imports.ui.modalDialog; - const Panel = imports.ui.panel; --const ShellEntry = imports.ui.shellEntry; - const Tweener = imports.ui.tweener; - const UserMenu = imports.ui.userMenu; - const UserWidget = imports.ui.userWidget; - - const Batch = imports.gdm.batch; - const GdmUtil = imports.gdm.util; - const LoginDialog = imports.gdm.loginDialog; - - // The timeout before going back automatically to the lock screen (in seconds) - const IDLE_TIMEOUT = 2 * 60; - - const UnlockDialog = new Lang.Class({ - Name: 'UnlockDialog', -- Extends: ModalDialog.ModalDialog, - - _init: function(parentActor) { -- this.parent({ shellReactive: true, -- styleClass: 'login-dialog', -- keybindingMode: Shell.KeyBindingMode.UNLOCK_SCREEN, -- parentActor: parentActor -- }); -+ this.actor = new St.Widget({ accessible_role: Atk.Role.WINDOW, -+ style_class: 'login-dialog', -+ visible: false }); -+ -+ this.actor.add_constraint(new Layout.MonitorConstraint({ primary: true })); -+ parentActor.add_child(this.actor); - - this._userManager = AccountsService.UserManager.get_default(); - this._userName = GLib.get_user_name(); - this._user = this._userManager.get_user(this._userName); - - this._firstQuestion = true; - - this._greeterClient = new Gdm.Client(); - this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient, { reauthenticationOnly: true }); - this._userVerified = false; - - this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion)); - this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage)); - this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); - this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed)); - this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); - - this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint)); - this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint)); - -- this._userWidget = new UserWidget.UserWidget(this._user); -- this.contentLayout.add_actor(this._userWidget.actor); -- -- this._promptLayout = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', -- vertical: true }); -- -- this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' }); -- this._promptLayout.add(this._promptLabel, -- { x_align: St.Align.START }); -- -- this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry', -- can_focus: true }); -- this._promptEntry.clutter_text.connect('activate', Lang.bind(this, this._doUnlock)); -- this._promptEntry.clutter_text.set_password_char('\u25cf'); -- ShellEntry.addContextMenu(this._promptEntry, { isPassword: true }); -- this.setInitialKeyFocus(this._promptEntry); -- this._promptEntry.clutter_text.connect('text-changed', Lang.bind(this, function() { -- this._updateOkButtonSensitivity(this._promptEntry.text.length > 0); -- })); -- -- this._promptLayout.add(this._promptEntry, -- { expand: true, -- x_fill: true }); -- -- this.contentLayout.add_actor(this._promptLayout); -+ this._promptBox = new St.BoxLayout({ vertical: true }); -+ this.actor.add_child(this._promptBox); -+ this._promptBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, -+ align_axis: Clutter.AlignAxis.BOTH, -+ factor: 0.5 })); - -- this._promptMessage = new St.Label({ visible: false }); -- this.contentLayout.add(this._promptMessage, { x_fill: true }); -+ this._authPrompt = new GdmUtil.AuthPrompt(); -+ this._authPrompt.setUser(this._user); -+ this._authPrompt.setPasswordChar('\u25cf'); -+ this._authPrompt.nextButton.label = _("Unlock"); -+ this._authPrompt.connect('cancel', Lang.bind(this, this._escape)); -+ this._authPrompt.connect('next', Lang.bind(this, this._doUnlock)); - -- this._promptLoginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint' }); -- this._promptLoginHint.hide(); -- this.contentLayout.add_actor(this._promptLoginHint); -+ this._promptBox.add_child(this._authPrompt.actor); - - this.allowCancel = false; -- this.buttonLayout.visible = true; -- this.addButton({ label: _("Cancel"), -- action: Lang.bind(this, this._escape), -- key: Clutter.KEY_Escape }, -- { expand: true, -- x_fill: false, -- y_fill: false, -- x_align: St.Align.START, -- y_align: St.Align.MIDDLE }); -- this.placeSpinner({ expand: false, -- x_fill: false, -- y_fill: false, -- x_align: St.Align.END, -- y_align: St.Align.MIDDLE }); -- this._okButton = this.addButton({ label: _("Unlock"), -- action: Lang.bind(this, this._doUnlock), -- default: true }, -- { expand: false, -- x_fill: false, -- y_fill: false, -- x_align: St.Align.END, -- y_align: St.Align.MIDDLE }); - - let screenSaverSettings = new Gio.Settings({ schema: 'org.gnome.desktop.screensaver' }); - if (screenSaverSettings.get_boolean('user-switch-enabled')) { - let otherUserLabel = new St.Label({ text: _("Log in as another user"), - style_class: 'login-dialog-not-listed-label' }); - this._otherUserButton = new St.Button({ style_class: 'login-dialog-not-listed-button', - can_focus: true, - child: otherUserLabel, - reactive: true, - x_align: St.Align.START, - x_fill: true }); - this._otherUserButton.connect('clicked', Lang.bind(this, this._otherUserClicked)); -- this.dialogLayout.add(this._otherUserButton, -- { x_align: St.Align.START, -- x_fill: false }); -+ this._promptBox.add_child(this._otherUserButton); - } else { - this._otherUserButton = null; - } - - this._updateSensitivity(true); - - let batch = new Batch.Hold(); - this._userVerifier.begin(this._userName, batch); - -- Main.ctrlAltTabManager.addGroup(this.dialogLayout, _("Unlock Window"), 'dialog-password-symbolic'); -+ Main.ctrlAltTabManager.addGroup(this.actor, _("Unlock Window"), 'dialog-password-symbolic'); - - this._idleMonitor = new GnomeDesktop.IdleMonitor(); - this._idleWatchId = this._idleMonitor.add_idle_watch(IDLE_TIMEOUT * 1000, Lang.bind(this, this._escape)); - }, - - _updateSensitivity: function(sensitive) { -- this._promptEntry.reactive = sensitive; -- this._promptEntry.clutter_text.editable = sensitive; -- this._updateOkButtonSensitivity(sensitive && this._promptEntry.text.length > 0); -+ this._authPrompt.updateSensitivity(sensitive); -+ - if (this._otherUserButton) { - this._otherUserButton.reactive = sensitive; - this._otherUserButton.can_focus = sensitive; - } - }, - -- _updateOkButtonSensitivity: function(sensitive) { -- this._okButton.reactive = sensitive; -- this._okButton.can_focus = sensitive; -- }, -- - _showMessage: function(userVerifier, message, styleClass) { -- if (message) { -- this._promptMessage.text = message; -- this._promptMessage.styleClass = styleClass; -- GdmUtil.fadeInActor(this._promptMessage); -- } else { -- GdmUtil.fadeOutActor(this._promptMessage); -- } -+ this._authPrompt.setMessage(message, styleClass); - }, - - _onAskQuestion: function(verifier, serviceName, question, passwordChar) { - if (this._firstQuestion && this._firstQuestionAnswer) { - this._userVerifier.answerQuery(serviceName, this._firstQuestionAnswer); - this._firstQuestionAnswer = null; - this._firstQuestion = false; - return; - } - -- this._promptLabel.text = question; -- - if (!this._firstQuestion) - this._promptEntry.text = ''; - else - this._firstQuestion = false; - -- this._promptEntry.clutter_text.set_password_char(passwordChar); -- this._promptEntry.menu.isPassword = passwordChar != ''; -+ this._authPrompt.setPasswordChar(passwordChar); -+ this._authPrompt.setQuestion(question); - - this._currentQuery = serviceName; -+ - this._updateSensitivity(true); -- this.setWorking(false); -+ this._authPrompt.stopSpinning(); - }, - - _showLoginHint: function(verifier, message) { -- this._promptLoginHint.set_text(message) -- GdmUtil.fadeInActor(this._promptLoginHint); -+ this._authPrompt.setHint(message); - }, - - _hideLoginHint: function() { -- GdmUtil.fadeOutActor(this._promptLoginHint); -+ this._authPrompt.setHint(null); - }, - - _doUnlock: function() { - if (this._firstQuestion) { - // we haven't received a query yet, so stash the answer - // and make ourself non-reactive - // the actual reply to GDM will be sent as soon as asked - this._firstQuestionAnswer = this._promptEntry.text; - this._updateSensitivity(false); -- this.setWorking(true); -+ this._authPrompt.startSpinning(); - return; - } - - if (!this._currentQuery) - return; - - let query = this._currentQuery; - this._currentQuery = null; - - this._updateSensitivity(false); -- this.setWorking(true); -+ this._authPrompt.startSpinning(); - -- this._userVerifier.answerQuery(query, this._promptEntry.text); -+ this._userVerifier.answerQuery(query, this._authPrompt.getAnswer()); - }, - - _onVerificationComplete: function() { - this._userVerified = true; - }, - - _onReset: function() { - if (!this._userVerified) { - this._userVerifier.clear(); - this.emit('failed'); - } - }, - - _onVerificationFailed: function() { - this._currentQuery = null; - this._firstQuestion = true; - this._userVerified = false; - -- this._promptEntry.text = ''; -- this._promptEntry.clutter_text.set_password_char('\u25cf'); -- this._promptEntry.menu.isPassword = true; -+ this._authPrompt.clear(); - - this._updateSensitivity(false); -- this.setWorking(false); -+ this._authPrompt.stopSpinning(); - }, - - _escape: function() { - if (this.allowCancel) { - this._userVerifier.cancel(); - this.emit('failed'); - } - }, - - _otherUserClicked: function(button, event) { - Gdm.goto_login_session_sync(null); - - this._userVerifier.cancel(); - this.emit('failed'); - }, - - destroy: function() { - this._userVerifier.clear(); -+ this.actor.destroy(); - - if (this._idleWatchId) { - this._idleMonitor.remove_watch(this._idleWatchId); - this._idleWatchId = 0; - } -- -- this.parent(); - }, - - cancel: function() { - this._userVerifier.cancel(null); - - this.destroy(); - }, - - addCharacter: function(unichar) { -- this._promptEntry.clutter_text.insert_unichar(unichar); -+ this._authPrompt.addCharacter(unichar); - }, - - finish: function(onComplete) { - if (!this._userVerifier.hasPendingMessages) { - onComplete(); - return; - } - - let signalId = this._userVerifier.connect('no-more-messages', - Lang.bind(this, function() { - this._userVerifier.disconnect(signalId); - onComplete(); - })); -+ }, -+ -+ open: function(timestamp) { -+ this.actor.show(); -+ -+ if (this._isModal) -+ return true; - -+ if (!Main.pushModal(this.actor, { timestamp: timestamp, -+ keybindingMode: Shell.KeyBindingMode.UNLOCK_SCREEN })) -+ return false; -+ -+ this._isModal = true; -+ -+ return true; -+ }, -+ -+ popModal: function(timestamp) { -+ if (this._isModal) { -+ Main.popModal(this.actor, timestamp); -+ this._isModal = false; -+ } - } - }); -+Signals.addSignalMethods(UnlockDialog.prototype); --- -1.8.3.1 - - -From 8e8f1e524eb010414379b0a2f1ca62cbe238c777 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 23 Jul 2013 20:37:42 -0400 -Subject: [PATCH 22/69] gdmUtil: separate AuthPrompt out into its own file - -It's cleaner to have it in its own file than to cram it into -util.js, so this commit moves it. - -https://bugzilla.gnome.org/show_bug.cgi?id=704707 ---- - js/Makefile.am | 1 + - js/gdm/authPrompt.js | 294 ++++++++++++++++++++++++++++++++++++++++++++++++++ - js/gdm/loginDialog.js | 3 +- - js/gdm/util.js | 285 ------------------------------------------------ - js/ui/unlockDialog.js | 3 +- - 5 files changed, 299 insertions(+), 287 deletions(-) - create mode 100644 js/gdm/authPrompt.js - -diff --git a/js/Makefile.am b/js/Makefile.am -index e8dd927..57f08e2 100644 ---- a/js/Makefile.am -+++ b/js/Makefile.am -@@ -1,49 +1,50 @@ - NULL = - - EXTRA_DIST = misc/config.js.in - CLEANFILES = misc/config.js - - misc/config.js: misc/config.js.in Makefile - [ -d $(@D) ] || $(mkdir_p) $(@D) ; \ - sed -e "s|[@]PACKAGE_NAME@|$(PACKAGE_NAME)|g" \ - -e "s|[@]PACKAGE_VERSION@|$(PACKAGE_VERSION)|g" \ - -e "s|[@]HAVE_BLUETOOTH@|$(HAVE_BLUETOOTH)|g" \ - -e "s|[@]GETTEXT_PACKAGE@|$(GETTEXT_PACKAGE)|g" \ - -e "s|[@]datadir@|$(datadir)|g" \ - -e "s|[@]libexecdir@|$(libexecdir)|g" \ - -e "s|[@]sysconfdir@|$(sysconfdir)|g" \ - $< > $@ - - jsdir = $(pkgdatadir)/js - - nobase_dist_js_DATA = \ -+ gdm/authPrompt.js \ - gdm/batch.js \ - gdm/fingerprint.js \ - gdm/loginDialog.js \ - gdm/powerMenu.js \ - gdm/realmd.js \ - gdm/util.js \ - extensionPrefs/main.js \ - misc/config.js \ - misc/extensionUtils.js \ - misc/fileUtils.js \ - misc/gnomeSession.js \ - misc/hash.js \ - misc/history.js \ - misc/jsParse.js \ - misc/loginManager.js \ - misc/modemManager.js \ - misc/params.js \ - misc/util.js \ - perf/core.js \ - ui/altTab.js \ - ui/appDisplay.js \ - ui/appFavorites.js \ - ui/backgroundMenu.js \ - ui/background.js \ - ui/boxpointer.js \ - ui/calendar.js \ - ui/checkBox.js \ - ui/ctrlAltTab.js \ - ui/dash.js \ - ui/dateMenu.js \ -diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -new file mode 100644 -index 0000000..bb59d96 ---- /dev/null -+++ b/js/gdm/authPrompt.js -@@ -0,0 +1,294 @@ -+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -+ -+const Clutter = imports.gi.Clutter; -+const Lang = imports.lang; -+const Signals = imports.signals; -+const St = imports.gi.St; -+ -+const Panel = imports.ui.panel; -+const ShellEntry = imports.ui.shellEntry; -+const Tweener = imports.ui.tweener; -+const UserWidget = imports.ui.userWidget; -+ -+const DEFAULT_BUTTON_WELL_ICON_SIZE = 24; -+const DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0; -+const DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3; -+ -+const AuthPrompt = new Lang.Class({ -+ Name: 'AuthPrompt', -+ -+ _init: function() { -+ this.actor = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', -+ vertical: true }); -+ this.actor.connect('key-press-event', -+ Lang.bind(this, function(actor, event) { -+ if (event.get_key_symbol() == Clutter.KEY_Escape) { -+ this.emit('cancel'); -+ } -+ })); -+ -+ this._userWell = new St.Bin({ x_fill: true, -+ x_align: St.Align.START }); -+ this.actor.add(this._userWell, -+ { x_align: St.Align.START, -+ x_fill: true, -+ y_fill: true, -+ expand: true }); -+ this._label = new St.Label({ style_class: 'login-dialog-prompt-label' }); -+ -+ this.actor.add(this._label, -+ { expand: true, -+ x_fill: true, -+ y_fill: true, -+ x_align: St.Align.START }); -+ this._entry = new St.Entry({ style_class: 'login-dialog-prompt-entry', -+ can_focus: true }); -+ ShellEntry.addContextMenu(this._entry, { isPassword: true }); -+ -+ this.actor.add(this._entry, -+ { expand: true, -+ x_fill: true, -+ y_fill: false, -+ x_align: St.Align.START }); -+ -+ this._entry.grab_key_focus(); -+ -+ this._message = new St.Label({ opacity: 0 }); -+ this.actor.add(this._message, { x_fill: true }); -+ -+ this._loginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' }); -+ this.actor.add(this._loginHint); -+ -+ this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box', -+ vertical: false }); -+ this.actor.add(this._buttonBox, -+ { expand: true, -+ x_align: St.Align.MIDDLE, -+ y_align: St.Align.END }); -+ -+ this._defaultButtonWell = new St.Widget(); -+ this._defaultButtonWellActor = null; -+ -+ this._initButtons(); -+ -+ let spinnerIcon = global.datadir + '/theme/process-working.svg'; -+ this._spinner = new Panel.AnimatedIcon(spinnerIcon, DEFAULT_BUTTON_WELL_ICON_SIZE); -+ this._spinner.actor.opacity = 0; -+ this._spinner.actor.show(); -+ this._defaultButtonWell.add_child(this._spinner.actor); -+ }, -+ -+ _initButtons: function() { -+ this.cancelButton = new St.Button({ style_class: 'modal-dialog-button', -+ button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, -+ reactive: true, -+ can_focus: true, -+ label: _("Cancel") }); -+ this.cancelButton.connect('clicked', -+ Lang.bind(this, function() { -+ this.emit('cancel'); -+ })); -+ this._buttonBox.add(this.cancelButton, -+ { expand: false, -+ x_fill: false, -+ y_fill: false, -+ x_align: St.Align.START, -+ y_align: St.Align.END }); -+ -+ this._buttonBox.add(this._defaultButtonWell, -+ { expand: true, -+ x_fill: false, -+ y_fill: false, -+ x_align: St.Align.END, -+ y_align: St.Align.MIDDLE }); -+ this.nextButton = new St.Button({ style_class: 'modal-dialog-button', -+ button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, -+ reactive: true, -+ can_focus: true, -+ label: _("Next") }); -+ this.nextButton.connect('clicked', -+ Lang.bind(this, function() { -+ this.emit('next'); -+ })); -+ this.nextButton.add_style_pseudo_class('default'); -+ this._buttonBox.add(this.nextButton, -+ { expand: false, -+ x_fill: false, -+ y_fill: false, -+ x_align: St.Align.END, -+ y_align: St.Align.END }); -+ -+ this._updateNextButtonSensitivity(this._entry.text.length > 0); -+ -+ this._entry.clutter_text.connect('text-changed', -+ Lang.bind(this, function() { -+ this._updateNextButtonSensitivity(this._entry.text.length > 0); -+ })); -+ this._entry.clutter_text.connect('activate', Lang.bind(this, function() { -+ this.emit('next'); -+ })); -+ }, -+ -+ addActorToDefaultButtonWell: function(actor) { -+ this._defaultButtonWell.add_child(actor); -+ -+ actor.add_constraint(new Clutter.AlignConstraint({ source: this._spinner.actor, -+ align_axis: Clutter.AlignAxis.BOTH, -+ factor: 0.5 })); -+ }, -+ -+ setActorInDefaultButtonWell: function(actor, animate) { -+ if (!this._defaultButtonWellActor && -+ !actor) -+ return; -+ -+ let oldActor = this._defaultButtonWellActor; -+ -+ if (oldActor) -+ Tweener.removeTweens(oldActor); -+ -+ let isSpinner; -+ if (actor == this._spinner.actor) -+ isSpinner = true; -+ else -+ isSpinner = false; -+ -+ if (this._defaultButtonWellActor != actor && oldActor) { -+ if (!animate) { -+ oldActor.opacity = 0; -+ } else { -+ Tweener.addTween(oldActor, -+ { opacity: 0, -+ time: DEFAULT_BUTTON_WELL_ANIMATION_TIME, -+ delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY, -+ transition: 'linear', -+ onCompleteScope: this, -+ onComplete: function() { -+ if (isSpinner) { -+ if (this._spinner) -+ this._spinner.stop(); -+ } -+ } -+ }); -+ } -+ } -+ -+ if (actor) { -+ if (isSpinner) -+ this._spinner.play(); -+ -+ if (!animate) -+ actor.opacity = 255; -+ else -+ Tweener.addTween(actor, -+ { opacity: 255, -+ time: DEFAULT_BUTTON_WELL_ANIMATION_TIME, -+ delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY, -+ transition: 'linear' }); -+ } -+ -+ this._defaultButtonWellActor = actor; -+ }, -+ -+ startSpinning: function() { -+ this.setActorInDefaultButtonWell(this._spinner.actor, true); -+ }, -+ -+ stopSpinning: function() { -+ this.setActorInDefaultButtonWell(null, false); -+ }, -+ -+ clear: function() { -+ this._entry.text = ''; -+ this.stopSpinning(); -+ }, -+ -+ setPasswordChar: function(passwordChar) { -+ this._entry.clutter_text.set_password_char(passwordChar); -+ this._entry.menu.isPassword = passwordChar != ''; -+ }, -+ -+ setQuestion: function(question) { -+ this._label.set_text(question); -+ -+ this._label.show(); -+ this._entry.show(); -+ -+ this._loginHint.opacity = 0; -+ this._loginHint.show(); -+ -+ this._entry.grab_key_focus(); -+ }, -+ -+ getAnswer: function() { -+ let text = this._entry.get_text(); -+ -+ return text; -+ }, -+ -+ setMessage: function(message, styleClass) { -+ if (message) { -+ this._message.text = message; -+ this._message.styleClass = styleClass; -+ this._message.opacity = 255; -+ } else { -+ this._message.opacity = 0; -+ } -+ }, -+ -+ _updateNextButtonSensitivity: function(sensitive) { -+ this.nextButton.reactive = sensitive; -+ this.nextButton.can_focus = sensitive; -+ }, -+ -+ updateSensitivity: function(sensitive) { -+ this._updateNextButtonSensitivity(sensitive); -+ this._entry.reactive = sensitive; -+ this._entry.clutter_text.editable = sensitive; -+ }, -+ -+ hide: function() { -+ this.setActorInDefaultButtonWell(null, true); -+ this.actor.hide(); -+ this._loginHint.opacity = 0; -+ -+ this.setUser(null); -+ -+ this.updateSensitivity(true); -+ this._entry.set_text(''); -+ }, -+ -+ setUser: function(user) { -+ if (user) { -+ let userWidget = new UserWidget.UserWidget(user); -+ this._userWell.set_child(userWidget.actor); -+ } else { -+ this._userWell.set_child(null); -+ } -+ }, -+ -+ setHint: function(message) { -+ if (message) { -+ this._loginHint.set_text(message) -+ this._loginHint.opacity = 255; -+ } else { -+ this._loginHint.opacity = 0; -+ this._loginHint.set_text(''); -+ } -+ }, -+ -+ reset: function() { -+ this._message.opacity = 0; -+ this.setUser(null); -+ this.stopSpinning(); -+ }, -+ -+ addCharacter: function(unichar) { -+ if (!this._entry.visible) -+ return; -+ -+ this._entry.grab_key_focus(); -+ this._entry.clutter_text.insert_unichar(unichar); -+ } -+}); -+Signals.addSignalMethods(AuthPrompt.prototype); -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index e9dd6b2..d9e3898 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -5,60 +5,61 @@ - * 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 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', - Lang.bind(this, this._onUserChanged)); - - let layout = new St.BoxLayout({ vertical: false }); - this.actor = new St.Button({ style_class: 'login-dialog-user-list-item', - button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, -@@ -431,61 +432,61 @@ const LoginDialog = new Lang.Class({ - 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', - vertical: true, - visible: false }); - this._userSelectionBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - this.actor.add_child(this._userSelectionBox); - - this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner', - text: '' }); - 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 GdmUtil.AuthPrompt(); -+ this._authPrompt = new AuthPrompt.AuthPrompt(); - this._authPrompt.hide(); - this._authPrompt.connect('cancel', - Lang.bind(this, function() { - this.cancel(); - })); - - this._authPrompt.actor.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - - this.actor.add_child(this._authPrompt.actor); - this._userList.actor.add_constraint(new Clutter.BindConstraint({ source: this._authPrompt.actor, - coordinate: Clutter.BindCoordinate.WIDTH })); - - // 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._hideUserListAndLogIn)); - this._notListedButton.hide(); - -diff --git a/js/gdm/util.js b/js/gdm/util.js -index 084bc7b..20540b7 100644 ---- a/js/gdm/util.js -+++ b/js/gdm/util.js -@@ -1,70 +1,64 @@ - // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - - const Clutter = imports.gi.Clutter; - const Gio = imports.gi.Gio; - const GLib = imports.gi.GLib; - const Lang = imports.lang; - const Mainloop = imports.mainloop; - const Signals = imports.signals; - const St = imports.gi.St; - --const Panel = imports.ui.panel; - const Batch = imports.gdm.batch; - const Fprint = imports.gdm.fingerprint; - const Main = imports.ui.main; - const Params = imports.misc.params; - const ShellEntry = imports.ui.shellEntry; - const Tweener = imports.ui.tweener; --const UserWidget = imports.ui.userWidget; - - const PASSWORD_SERVICE_NAME = 'gdm-password'; - const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint'; - const FADE_ANIMATION_TIME = 0.16; - const CLONE_FADE_ANIMATION_TIME = 0.25; - - const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen'; - const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication'; - const BANNER_MESSAGE_KEY = 'banner-message-enable'; - const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text'; - const ALLOWED_FAILURES_KEY = 'allowed-failures'; - - const LOGO_KEY = 'logo'; - const DISABLE_USER_LIST_KEY = 'disable-user-list'; - - // Give user 16ms to read each character of a PAM message - const USER_READ_TIME = 16 - --const DEFAULT_BUTTON_WELL_ICON_SIZE = 24; --const DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0; --const DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3; -- - function fadeInActor(actor) { - if (actor.opacity == 255 && actor.visible) - return null; - - let hold = new Batch.Hold(); - actor.show(); - let [minHeight, naturalHeight] = actor.get_preferred_height(-1); - - actor.opacity = 0; - actor.set_height(0); - Tweener.addTween(actor, - { opacity: 255, - height: naturalHeight, - time: FADE_ANIMATION_TIME, - transition: 'easeOutQuad', - onComplete: function() { - this.set_height(-1); - hold.release(); - }, - }); - - return hold; - } - - function fadeOutActor(actor) { - if (!actor.visible || actor.opacity == 0) { - actor.opacity = 0; - actor.hide(); - return null; - } -@@ -439,309 +433,30 @@ const ShellUserVerifier = new Lang.Class({ - this._retry(); - })); - } - } else { - if (!this.hasPendingMessages) { - this._cancelAndReset(); - } else { - let signalId = this.connect('no-more-messages', - Lang.bind(this, function() { - this.disconnect(signalId); - this._cancelAndReset(); - })); - } - } - - this.emit('verification-failed'); - }, - - _onConversationStopped: function(client, serviceName) { - // if the password service fails, then cancel everything. - // But if, e.g., fingerprint fails, still give - // password authentication a chance to succeed - if (serviceName == PASSWORD_SERVICE_NAME) { - this._verificationFailed(true); - } - - this.emit('hide-login-hint'); - }, - }); - Signals.addSignalMethods(ShellUserVerifier.prototype); -- --const AuthPrompt = new Lang.Class({ -- Name: 'AuthPrompt', -- -- _init: function() { -- this.actor = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', -- vertical: true }); -- this.actor.connect('key-press-event', -- Lang.bind(this, function(actor, event) { -- if (event.get_key_symbol() == Clutter.KEY_Escape) { -- this.emit('cancel'); -- } -- })); -- -- this._userWell = new St.Bin({ x_fill: true, -- x_align: St.Align.START }); -- this.actor.add(this._userWell, -- { x_align: St.Align.START, -- x_fill: true, -- y_fill: true, -- expand: true }); -- this._label = new St.Label({ style_class: 'login-dialog-prompt-label' }); -- -- this.actor.add(this._label, -- { expand: true, -- x_fill: true, -- y_fill: true, -- x_align: St.Align.START }); -- this._entry = new St.Entry({ style_class: 'login-dialog-prompt-entry', -- can_focus: true }); -- ShellEntry.addContextMenu(this._entry, { isPassword: true }); -- -- this.actor.add(this._entry, -- { expand: true, -- x_fill: true, -- y_fill: false, -- x_align: St.Align.START }); -- -- this._entry.grab_key_focus(); -- -- this._message = new St.Label({ opacity: 0 }); -- this.actor.add(this._message, { x_fill: true }); -- -- this._loginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' }); -- this.actor.add(this._loginHint); -- -- this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box', -- vertical: false }); -- this.actor.add(this._buttonBox, -- { expand: true, -- x_align: St.Align.MIDDLE, -- y_align: St.Align.END }); -- -- this._defaultButtonWell = new St.Widget(); -- this._defaultButtonWellActor = null; -- -- this._initButtons(); -- -- let spinnerIcon = global.datadir + '/theme/process-working.svg'; -- this._spinner = new Panel.AnimatedIcon(spinnerIcon, DEFAULT_BUTTON_WELL_ICON_SIZE); -- this._spinner.actor.opacity = 0; -- this._spinner.actor.show(); -- this._defaultButtonWell.add_child(this._spinner.actor); -- }, -- -- _initButtons: function() { -- this.cancelButton = new St.Button({ style_class: 'modal-dialog-button', -- button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, -- reactive: true, -- can_focus: true, -- label: _("Cancel") }); -- this.cancelButton.connect('clicked', -- Lang.bind(this, function() { -- this.emit('cancel'); -- })); -- this._buttonBox.add(this.cancelButton, -- { expand: false, -- x_fill: false, -- y_fill: false, -- x_align: St.Align.START, -- y_align: St.Align.END }); -- -- this._buttonBox.add(this._defaultButtonWell, -- { expand: true, -- x_fill: false, -- y_fill: false, -- x_align: St.Align.END, -- y_align: St.Align.MIDDLE }); -- this.nextButton = new St.Button({ style_class: 'modal-dialog-button', -- button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, -- reactive: true, -- can_focus: true, -- label: _("Next") }); -- this.nextButton.connect('clicked', -- Lang.bind(this, function() { -- this.emit('next'); -- })); -- this.nextButton.add_style_pseudo_class('default'); -- this._buttonBox.add(this.nextButton, -- { expand: false, -- x_fill: false, -- y_fill: false, -- x_align: St.Align.END, -- y_align: St.Align.END }); -- -- this._updateNextButtonSensitivity(this._entry.text.length > 0); -- -- this._entry.clutter_text.connect('text-changed', -- Lang.bind(this, function() { -- this._updateNextButtonSensitivity(this._entry.text.length > 0); -- })); -- this._entry.clutter_text.connect('activate', Lang.bind(this, function() { -- this.emit('next'); -- })); -- }, -- -- addActorToDefaultButtonWell: function(actor) { -- this._defaultButtonWell.add_child(actor); -- -- actor.add_constraint(new Clutter.AlignConstraint({ source: this._spinner.actor, -- align_axis: Clutter.AlignAxis.BOTH, -- factor: 0.5 })); -- }, -- -- setActorInDefaultButtonWell: function(actor, animate) { -- if (!this._defaultButtonWellActor && -- !actor) -- return; -- -- let oldActor = this._defaultButtonWellActor; -- -- if (oldActor) -- Tweener.removeTweens(oldActor); -- -- let isSpinner; -- if (actor == this._spinner.actor) -- isSpinner = true; -- else -- isSpinner = false; -- -- if (this._defaultButtonWellActor != actor && oldActor) { -- if (!animate) { -- oldActor.opacity = 0; -- } else { -- Tweener.addTween(oldActor, -- { opacity: 0, -- time: DEFAULT_BUTTON_WELL_ANIMATION_TIME, -- delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY, -- transition: 'linear', -- onCompleteScope: this, -- onComplete: function() { -- if (isSpinner) { -- if (this._spinner) -- this._spinner.stop(); -- } -- } -- }); -- } -- } -- -- if (actor) { -- if (isSpinner) -- this._spinner.play(); -- -- if (!animate) -- actor.opacity = 255; -- else -- Tweener.addTween(actor, -- { opacity: 255, -- time: DEFAULT_BUTTON_WELL_ANIMATION_TIME, -- delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY, -- transition: 'linear' }); -- } -- -- this._defaultButtonWellActor = actor; -- }, -- -- startSpinning: function() { -- this.setActorInDefaultButtonWell(this._spinner.actor, true); -- }, -- -- stopSpinning: function() { -- this.setActorInDefaultButtonWell(null, false); -- }, -- -- clear: function() { -- this._entry.text = ''; -- this.stopSpinning(); -- }, -- -- setPasswordChar: function(passwordChar) { -- this._entry.clutter_text.set_password_char(passwordChar); -- this._entry.menu.isPassword = passwordChar != ''; -- }, -- -- setQuestion: function(question) { -- this._label.set_text(question); -- -- this._label.show(); -- this._entry.show(); -- -- this._loginHint.opacity = 0; -- this._loginHint.show(); -- -- this._entry.grab_key_focus(); -- }, -- -- getAnswer: function() { -- let text = this._entry.get_text(); -- -- return text; -- }, -- -- setMessage: function(message, styleClass) { -- if (message) { -- this._message.text = message; -- this._message.styleClass = styleClass; -- this._message.opacity = 255; -- } else { -- this._message.opacity = 0; -- } -- }, -- -- _updateNextButtonSensitivity: function(sensitive) { -- this.nextButton.reactive = sensitive; -- this.nextButton.can_focus = sensitive; -- }, -- -- updateSensitivity: function(sensitive) { -- this._updateNextButtonSensitivity(sensitive); -- this._entry.reactive = sensitive; -- this._entry.clutter_text.editable = sensitive; -- }, -- -- hide: function() { -- this.setActorInDefaultButtonWell(null, true); -- this.actor.hide(); -- this._loginHint.opacity = 0; -- -- this.setUser(null); -- -- this.updateSensitivity(true); -- this._entry.set_text(''); -- }, -- -- setUser: function(user) { -- if (user) { -- let userWidget = new UserWidget.UserWidget(user); -- this._userWell.set_child(userWidget.actor); -- } else { -- this._userWell.set_child(null); -- } -- }, -- -- setHint: function(message) { -- if (message) { -- this._loginHint.set_text(message) -- this._loginHint.opacity = 255; -- } else { -- this._loginHint.opacity = 0; -- this._loginHint.set_text(''); -- } -- }, -- -- reset: function() { -- this._message.opacity = 0; -- this.setUser(null); -- this.stopSpinning(); -- }, -- -- addCharacter: function(unichar) { -- if (!this._entry.visible) -- return; -- -- this._entry.grab_key_focus(); -- this._entry.clutter_text.insert_unichar(unichar); -- } --}); --Signals.addSignalMethods(AuthPrompt.prototype); -diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js -index 4a36cd3..7fd5271 100644 ---- a/js/ui/unlockDialog.js -+++ b/js/ui/unlockDialog.js -@@ -1,96 +1,97 @@ - // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - - 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 GnomeDesktop = imports.gi.GnomeDesktop; - const Gtk = imports.gi.Gtk; - const Lang = imports.lang; - const Signals = imports.signals; - const Shell = imports.gi.Shell; - const St = imports.gi.St; - - const Layout = imports.ui.layout; - const Main = imports.ui.main; - const Panel = imports.ui.panel; - const Tweener = imports.ui.tweener; - const UserMenu = imports.ui.userMenu; - const UserWidget = imports.ui.userWidget; - -+const AuthPrompt = imports.gdm.authPrompt; - const Batch = imports.gdm.batch; - const GdmUtil = imports.gdm.util; - const LoginDialog = imports.gdm.loginDialog; - - // The timeout before going back automatically to the lock screen (in seconds) - const IDLE_TIMEOUT = 2 * 60; - - const UnlockDialog = new Lang.Class({ - Name: 'UnlockDialog', - - _init: function(parentActor) { - this.actor = new St.Widget({ accessible_role: Atk.Role.WINDOW, - style_class: 'login-dialog', - visible: false }); - - this.actor.add_constraint(new Layout.MonitorConstraint({ primary: true })); - parentActor.add_child(this.actor); - - this._userManager = AccountsService.UserManager.get_default(); - this._userName = GLib.get_user_name(); - this._user = this._userManager.get_user(this._userName); - - this._firstQuestion = true; - - this._greeterClient = new Gdm.Client(); - this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient, { reauthenticationOnly: true }); - this._userVerified = false; - - this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion)); - this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage)); - this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); - this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed)); - this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); - - this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint)); - this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint)); - - this._promptBox = new St.BoxLayout({ vertical: true }); - this.actor.add_child(this._promptBox); - this._promptBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - -- this._authPrompt = new GdmUtil.AuthPrompt(); -+ this._authPrompt = new AuthPrompt.AuthPrompt(); - this._authPrompt.setUser(this._user); - this._authPrompt.setPasswordChar('\u25cf'); - this._authPrompt.nextButton.label = _("Unlock"); - this._authPrompt.connect('cancel', Lang.bind(this, this._escape)); - this._authPrompt.connect('next', Lang.bind(this, this._doUnlock)); - - this._promptBox.add_child(this._authPrompt.actor); - - this.allowCancel = false; - - let screenSaverSettings = new Gio.Settings({ schema: 'org.gnome.desktop.screensaver' }); - if (screenSaverSettings.get_boolean('user-switch-enabled')) { - let otherUserLabel = new St.Label({ text: _("Log in as another user"), - style_class: 'login-dialog-not-listed-label' }); - this._otherUserButton = new St.Button({ style_class: 'login-dialog-not-listed-button', - can_focus: true, - child: otherUserLabel, - reactive: true, - x_align: St.Align.START, - x_fill: true }); - this._otherUserButton.connect('clicked', Lang.bind(this, this._otherUserClicked)); - this._promptBox.add_child(this._otherUserButton); - } else { - this._otherUserButton = null; - } - - this._updateSensitivity(true); - - let batch = new Batch.Hold(); - this._userVerifier.begin(this._userName, batch); --- -1.8.3.1 - - -From 849b77a62febc33bf2b7c8a524247cac77800b39 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Mon, 22 Jul 2013 11:07:35 -0400 -Subject: [PATCH 23/69] authPrompt: move unlock and login user verifier code - here - -There's quite a bit of duplicated code between the login dialog -and the unlock dialog dealing with the various signals from the -ShellUserVerifier. - -This commit moves that duplicated code into the AuthPrompt. - -https://bugzilla.gnome.org/show_bug.cgi?id=704707 ---- - js/gdm/authPrompt.js | 152 +++++++++++++++++++++++++++++++++++++- - js/gdm/loginDialog.js | 198 ++++++++++++-------------------------------------- - js/ui/unlockDialog.js | 121 +++--------------------------- - 3 files changed, 206 insertions(+), 265 deletions(-) - -diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index bb59d96..b0dcd0d 100644 ---- a/js/gdm/authPrompt.js -+++ b/js/gdm/authPrompt.js -@@ -1,161 +1,266 @@ - // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - - const Clutter = imports.gi.Clutter; - const Lang = imports.lang; - const Signals = imports.signals; - const St = imports.gi.St; - - const Panel = imports.ui.panel; -+const Batch = imports.gdm.batch; -+const GdmUtil = imports.gdm.util; -+const Params = imports.misc.params; - const ShellEntry = imports.ui.shellEntry; - const Tweener = imports.ui.tweener; - const UserWidget = imports.ui.userWidget; - - const DEFAULT_BUTTON_WELL_ICON_SIZE = 24; - const DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0; - const DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3; - -+const AuthPromptMode = { -+ UNLOCK_ONLY: 0, -+ UNLOCK_OR_LOG_IN: 1 -+}; -+ - const AuthPrompt = new Lang.Class({ - Name: 'AuthPrompt', - -- _init: function() { -+ _init: function(gdmClient, mode) { -+ this.verifyingUser = false; -+ -+ this._gdmClient = gdmClient; -+ this._mode = mode; -+ -+ let reauthenticationOnly; -+ if (this._mode == AuthPromptMode.UNLOCK_ONLY) -+ reauthenticationOnly = true; -+ else if (this._mode == AuthPromptMode.UNLOCK_OR_LOG_IN) -+ reauthenticationOnly = false; -+ -+ this._userVerifier = new GdmUtil.ShellUserVerifier(this._gdmClient, { reauthenticationOnly: reauthenticationOnly }); -+ -+ this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion)); -+ this._userVerifier.connect('show-message', Lang.bind(this, this._onShowMessage)); -+ this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed)); -+ this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); -+ this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); -+ this._userVerifier.connect('show-login-hint', Lang.bind(this, this._onShowLoginHint)); -+ this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._onHideLoginHint)); -+ -+ this.connect('next', Lang.bind(this, function() { -+ this.updateSensitivity(false); -+ this.startSpinning(); -+ if (this._queryingService) { -+ this._userVerifier.answerQuery(this._queryingService, this._entry.text); -+ } else { -+ this._preemptiveAnswer = this._entry.text; -+ } -+ })); -+ - this.actor = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', - vertical: true }); -+ this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); - this.actor.connect('key-press-event', - Lang.bind(this, function(actor, event) { - if (event.get_key_symbol() == Clutter.KEY_Escape) { -- this.emit('cancel'); -+ this.cancel(); - } - })); - - this._userWell = new St.Bin({ x_fill: true, - x_align: St.Align.START }); - this.actor.add(this._userWell, - { x_align: St.Align.START, - x_fill: true, - y_fill: true, - expand: true }); - this._label = new St.Label({ style_class: 'login-dialog-prompt-label' }); - - this.actor.add(this._label, - { expand: true, - x_fill: true, - y_fill: true, - x_align: St.Align.START }); - this._entry = new St.Entry({ style_class: 'login-dialog-prompt-entry', - can_focus: true }); - ShellEntry.addContextMenu(this._entry, { isPassword: true }); - - this.actor.add(this._entry, - { expand: true, - x_fill: true, - y_fill: false, - x_align: St.Align.START }); - - this._entry.grab_key_focus(); - - this._message = new St.Label({ opacity: 0 }); - this.actor.add(this._message, { x_fill: true }); - - this._loginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' }); - this.actor.add(this._loginHint); - - this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box', - vertical: false }); - this.actor.add(this._buttonBox, - { expand: true, - x_align: St.Align.MIDDLE, - y_align: St.Align.END }); - - this._defaultButtonWell = new St.Widget(); - this._defaultButtonWellActor = null; - - this._initButtons(); - - let spinnerIcon = global.datadir + '/theme/process-working.svg'; - this._spinner = new Panel.AnimatedIcon(spinnerIcon, DEFAULT_BUTTON_WELL_ICON_SIZE); - this._spinner.actor.opacity = 0; - this._spinner.actor.show(); - this._defaultButtonWell.add_child(this._spinner.actor); - }, - -+ _onDestroy: function() { -+ this._userVerifier.clear(); -+ }, -+ - _initButtons: function() { - this.cancelButton = new St.Button({ style_class: 'modal-dialog-button', - button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, - reactive: true, - can_focus: true, - label: _("Cancel") }); - this.cancelButton.connect('clicked', - Lang.bind(this, function() { -- this.emit('cancel'); -+ this.cancel(); - })); - this._buttonBox.add(this.cancelButton, - { expand: false, - x_fill: false, - y_fill: false, - x_align: St.Align.START, - y_align: St.Align.END }); - - this._buttonBox.add(this._defaultButtonWell, - { expand: true, - x_fill: false, - y_fill: false, - x_align: St.Align.END, - y_align: St.Align.MIDDLE }); - this.nextButton = new St.Button({ style_class: 'modal-dialog-button', - button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, - reactive: true, - can_focus: true, - label: _("Next") }); - this.nextButton.connect('clicked', - Lang.bind(this, function() { - this.emit('next'); - })); - this.nextButton.add_style_pseudo_class('default'); - this._buttonBox.add(this.nextButton, - { expand: false, - x_fill: false, - y_fill: false, - x_align: St.Align.END, - y_align: St.Align.END }); - - this._updateNextButtonSensitivity(this._entry.text.length > 0); - - this._entry.clutter_text.connect('text-changed', - Lang.bind(this, function() { - this._updateNextButtonSensitivity(this._entry.text.length > 0); - })); - this._entry.clutter_text.connect('activate', Lang.bind(this, function() { - this.emit('next'); - })); - }, - -+ _onAskQuestion: function(verifier, serviceName, question, passwordChar) { -+ if (this._preemptiveAnswer) { -+ this._userVerifier.answerQuery(this._queryingService, this._preemptiveAnswer); -+ this._preemptiveAnswer = null; -+ return; -+ } -+ -+ if (this._queryingService) -+ this.clear(); -+ -+ this._queryingService = serviceName; -+ this.setPasswordChar(passwordChar); -+ this.setQuestion(question); -+ -+ if (this.verifyingUser) -+ this.cancelButton.show(); -+ else -+ this.cancelButton.hide(); -+ -+ if (passwordChar) { -+ if (this._mode == AuthPromptMode.UNLOCK_ONLY) -+ this.nextButton.label = _("Unlock"); -+ else if (this._mode == AuthPromptMode.UNLOCK_OR_LOG_IN) -+ this.nextButton.label = C_("button", "Sign In"); -+ } else { -+ this.nextButton.label = _("Next"); -+ } -+ -+ this.updateSensitivity(true); -+ this.emit('prompted'); -+ }, -+ -+ _onShowMessage: function(userVerifier, message, styleClass) { -+ this.setMessage(message, styleClass); -+ }, -+ -+ _onVerificationFailed: function() { -+ this.clear(); -+ -+ this.updateSensitivity(true); -+ this.setActorInDefaultButtonWell(null); -+ this.userVerified = false; -+ }, -+ -+ _onVerificationComplete: function() { -+ this.userVerified = true; -+ }, -+ -+ _onReset: function() { -+ if (!this.userVerified) -+ this.reset(); -+ }, -+ -+ _onShowLoginHint: function(verifier, message) { -+ this.setHint(message); -+ }, -+ -+ _onHideLoginHint: function() { -+ this.setHint(null); -+ }, -+ - addActorToDefaultButtonWell: function(actor) { - this._defaultButtonWell.add_child(actor); - - actor.add_constraint(new Clutter.AlignConstraint({ source: this._spinner.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - }, - - setActorInDefaultButtonWell: function(actor, animate) { - if (!this._defaultButtonWellActor && - !actor) - return; - - let oldActor = this._defaultButtonWellActor; - - if (oldActor) - Tweener.removeTweens(oldActor); - - let isSpinner; - if (actor == this._spinner.actor) - isSpinner = true; - else - isSpinner = false; - - if (this._defaultButtonWellActor != actor && oldActor) { - if (!animate) { - oldActor.opacity = 0; - } else { - Tweener.addTween(oldActor, - { opacity: 0, -@@ -251,44 +356,85 @@ const AuthPrompt = new Lang.Class({ - this.setActorInDefaultButtonWell(null, true); - this.actor.hide(); - this._loginHint.opacity = 0; - - this.setUser(null); - - this.updateSensitivity(true); - this._entry.set_text(''); - }, - - setUser: function(user) { - if (user) { - let userWidget = new UserWidget.UserWidget(user); - this._userWell.set_child(userWidget.actor); - } else { - this._userWell.set_child(null); - } - }, - - setHint: function(message) { - if (message) { - this._loginHint.set_text(message) - this._loginHint.opacity = 255; - } else { - this._loginHint.opacity = 0; - this._loginHint.set_text(''); - } - }, - - reset: function() { -+ this.verifyingUser = false; -+ this.userVerified = false; -+ this._queryingService = null; -+ this.clear(); - this._message.opacity = 0; - this.setUser(null); - this.stopSpinning(); -+ this.setHint(null); -+ -+ this.emit('reset'); - }, - - addCharacter: function(unichar) { - if (!this._entry.visible) - return; - - this._entry.grab_key_focus(); - this._entry.clutter_text.insert_unichar(unichar); -+ }, -+ -+ begin: function(params) { -+ params = Params.parse(params, { userName: null, -+ hold: null }); -+ -+ this.updateSensitivity(false); -+ -+ let hold = params.hold; -+ if (!hold) -+ hold = new Batch.Hold(); -+ -+ this._userVerifier.begin(params.userName, hold); -+ this.verifyingUser = true; -+ }, -+ -+ finish: function(onComplete) { -+ if (!this._userVerifier.hasPendingMessages) { -+ onComplete(); -+ return; -+ } -+ -+ let signalId = this._userVerifier.connect('no-more-messages', -+ Lang.bind(this, function() { -+ this._userVerifier.disconnect(signalId); -+ onComplete(); -+ })); -+ }, -+ -+ cancel: function() { -+ if (this.verifyingUser) -+ this._userVerifier.cancel(); -+ -+ this.reset(); - } - }); - Signals.addSignalMethods(AuthPrompt.prototype); -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index d9e3898..fe594e4 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -375,123 +375,112 @@ const SessionMenuButton = new Lang.Class({ - - 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, - 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() -- this._greeterClient = new Gdm.Client(); -+ let gdmClient = new Gdm.Client(); - - if (GLib.getenv('GDM_GREETER_TEST') != '1') { -- this._greeter = this._greeterClient.get_greeter_sync(null); -+ 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._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient); -- this._userVerifier.connect('ask-question', Lang.bind(this, this._askQuestion)); -- this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage)); -- this._userVerifier.connect('verification-failed', Lang.bind(this, this._verificationFailed)); -- this._userVerifier.connect('reset', Lang.bind(this, this._reset)); -- this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint)); -- this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint)); -- this._verifyingUser = false; -- - 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', - vertical: true, - visible: false }); - this._userSelectionBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - this.actor.add_child(this._userSelectionBox); - - this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner', - text: '' }); - 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(); -+ this._authPrompt = new AuthPrompt.AuthPrompt(gdmClient, AuthPrompt.AuthPromptMode.UNLOCK_OR_LOGIN); -+ this._authPrompt.connect('prompted', Lang.bind(this, this._onPrompted)); -+ this._authPrompt.connect('reset', Lang.bind(this, this._reset)); - this._authPrompt.hide(); -- this._authPrompt.connect('cancel', -- Lang.bind(this, function() { -- this.cancel(); -- })); - - this._authPrompt.actor.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - - this.actor.add_child(this._authPrompt.actor); - this._userList.actor.add_constraint(new Clutter.BindConstraint({ source: this._authPrompt.actor, - coordinate: Clutter.BindCoordinate.WIDTH })); - - // 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._hideUserListAndLogIn)); - this._notListedButton.hide(); - - this._userSelectionBox.add(this._notListedButton, - { expand: false, - x_align: St.Align.START, - x_fill: true }); - -@@ -514,296 +503,213 @@ const LoginDialog = new Lang.Class({ - 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); - - }, - - _updateDisableUserList: function() { - let disableUserList = this._settings.get_boolean(GdmUtil.DISABLE_USER_LIST_KEY); - - if (disableUserList != this._disableUserList) { - this._disableUserList = disableUserList; - -- if (!this._verifyingUser) -+ if (!this._authPrompt.verifyingUser) - this._reset(); - } - }, - - _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(); - } - }, - - _updateLogoTexture: function(cache, uri) { - if (this._logoFileUri != uri) - return; - - let icon = null; - if (this._logoFileUri) - icon = this._textureCache.load_uri_async(this._logoFileUri, - -1, _LOGO_ICON_HEIGHT); - this._logoBin.set_child(icon); - }, - - _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._authPrompt.cancelButton.show(); -+ -+ this._showPrompt(); -+ }, -+ - _reset: function() { -- this._userVerifier.clear(); -+ if (this._authPrompt.verifyingUser) -+ return; - -- this._updateSensitivity(true); -- this._authPrompt.reset(); -+ this._sessionMenuButton.updateSensitivity(true); - - this._user = null; -- this._verifyingUser = false; - - if (this._disableUserList) - this._hideUserListAndLogIn(); - else - this._showUserList(); - }, - -- _verificationFailed: function() { -- this._authPrompt.clear(); -- -- this._updateSensitivity(true); -- this._authPrompt.setActorInDefaultButtonWell(null); -- }, -- - _onDefaultSessionChanged: function(client, sessionId) { - this._sessionMenuButton.setActiveSession(sessionId); - }, - -- _showMessage: function(userVerifier, message, styleClass) { -- this._authPrompt.setMessage(message, styleClass); -- }, -- -- _showLoginHint: function(verifier, message) { -- this._authPrompt.setHint(message); -- }, -- -- _hideLoginHint: function() { -- this._authPrompt.setHint(null); -- }, -- -- cancel: function() { -- if (this._verifyingUser) -- this._userVerifier.cancel(); -- else -- this._reset(); -- }, -- - _shouldShowSessionMenuButton: function() { -- if (this._verifyingUser) -+ if (this._authPrompt.verifyingUser) - return true; - - if (!this._user) - return false; - - if (this._user.is_logged_in) - return false; - - return true; - }, - -- _showPrompt: function(forSecret) { -+ _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' }); -- -- let hold = new Batch.Hold(); -- let tasks = [function() { -- this._preparePrompt(forSecret, hold); -- }, -- -- hold]; -- -- let batch = new Batch.ConcurrentBatch(this, tasks); -- -- return batch.run(); -- }, -- -- _preparePrompt: function(forSecret, hold) { -- if (!this._disableUserList || this._verifyingUser) { -- this._authPrompt.cancelButton.show(); -- } else { -- this._authPrompt.cancelButton.hide(); -- } -- -- if (forSecret) { -- this._authPrompt.nextButton.label = C_("button", "Sign In"); -- } else { -- this._authPrompt.nextButton.label = _("Next"); -- } -- -- let signalId = this._authPrompt.connect('next', Lang.bind(this, function() { -- this._authPrompt.disconnect(signalId); -- hold.release(); -- })); -- }, -- -- _updateSensitivity: function(sensitive) { -- this._sessionMenuButton.updateSensitivity(sensitive); -- this._authPrompt.updateSensitivity(sensitive); -- }, -- -- _askQuestion: function(verifier, serviceName, question, passwordChar) { -- this._authPrompt.setPasswordChar(passwordChar); -- this._authPrompt.setQuestion(question); -- -- this._updateSensitivity(true); -- -- if (this._shouldShowSessionMenuButton()) -- this._authPrompt.setActorInDefaultButtonWell(this._sessionMenuButton.actor); -- else -- this._authPrompt.setActorInDefaultButtonWell(null); -- -- let tasks = [function() { -- return this._showPrompt(!!passwordChar); -- }, -- -- function() { -- let text = this._authPrompt.getAnswer(); -- -- this._updateSensitivity(false); -- this._authPrompt.startSpinning(); -- this._userVerifier.answerQuery(serviceName, text); -- }]; -- -- let batch = new Batch.ConsecutiveBatch(this, tasks); -- return batch.run(); - }, - - _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._showLoginHint(null, _("(e.g., user or %s)").format(hint)); -+ this._authPrompt.setHint(_("(e.g., user or %s)").format(hint)); - }, - - _askForUsernameAndLogIn: function() { - this._authPrompt.setPasswordChar(''); - this._authPrompt.setQuestion(_("Username: ")); - - let realmManager = new Realmd.Manager(); -- let signalId = realmManager.connect('login-format-changed', -- Lang.bind(this, this._showRealmLoginHint)); -+ let realmSignalId = realmManager.connect('login-format-changed', -+ Lang.bind(this, this._showRealmLoginHint)); - this._showRealmLoginHint(realmManager.loginFormat); - -- let tasks = [this._showPrompt, -- -- function() { -- let userName = this._authPrompt.getAnswer(); -- this._authPrompt._entry.reactive = false; -- return this._beginVerificationForUser(userName); -- }, -- -- function() { -- realmManager.disconnect(signalId) -- realmManager.release(); -- }]; -+ let nextSignalId = this._authPrompt.connect('next', -+ Lang.bind(this, function() { -+ this._authPrompt.disconnect(nextSignalId); -+ this._authPrompt.updateSensitivity(false); -+ let answer = this._authPrompt.getAnswer(); -+ this._authPrompt.clear(); -+ this._authPrompt.startSpinning(); -+ this._authPrompt.begin({ userName: answer }); - -- let batch = new Batch.ConsecutiveBatch(this, tasks); -- return batch.run(); -+ realmManager.disconnect(realmSignalId) -+ realmManager.release(); -+ })); -+ this._authPrompt.cancelButton.hide(); -+ this._showPrompt(); - }, - - _startSession: function(serviceName) { - Tweener.addTween(this.actor, - { opacity: 0, - time: _FADE_ANIMATION_TIME, - transition: 'easeOutQuad', - onUpdate: function() { - let children = Main.layoutManager.uiGroup.get_children(); - - for (let i = 0; i < children.length; i++) { - if (children[i] != Main.layoutManager.screenShieldGroup) - children[i].opacity = this.actor.opacity; - } - }, - onUpdateScope: this, - onComplete: function() { - Mainloop.idle_add(Lang.bind(this, function() { - this._greeter.call_start_session_when_ready_sync(serviceName, true, null); - return false; - })); - }, - onCompleteScope: this }); - }, - - _onSessionOpened: function(client, serviceName) { -- if (!this._userVerifier.hasPendingMessages) { -+ this._authPrompt.finish(Lang.bind(this, function() { - this._startSession(serviceName); -- } else { -- let signalId = this._userVerifier.connect('no-more-messages', -- Lang.bind(this, function() { -- this._userVerifier.disconnect(signalId); -- this._startSession(serviceName); -- })); -- } -+ })); - }, - - _waitForItemForUser: function(userName) { - let item = this._userList.getItemFromUserName(userName); - - if (item) - return null; - - let hold = new Batch.Hold(); - let signalId = this._userList.connect('item-added', - Lang.bind(this, function() { - let item = this._userList.getItemFromUserName(userName); - - if (item) - hold.release(); - })); - - hold.connect('release', Lang.bind(this, function() { - this._userList.disconnect(signalId); - })); - - return hold; - }, - - _showTimedLoginAnimation: function() { - this._timedLoginItem.actor.grab_key_focus(); - return this._timedLoginItem.showTimedLoginIndicator(this._timedLoginAnimationTime); - }, - - _blockTimedLoginUntilIdle: function() { -@@ -896,77 +802,69 @@ const LoginDialog = new Lang.Class({ - } - } else if (event.type() == Clutter.EventType.KEY_RELEASE || - event.type() == Clutter.EventType.BUTTON_RELEASE) { - this._resetTimedLogin(); - } - - return false; - })); - }, - - _setUserListExpanded: function(expanded) { - this._userList.updateStyle(expanded); - this._userSelectionBox.visible = expanded; - }, - - _hideUserListAndLogIn: function() { - this._setUserListExpanded(false); - if (this._userSelectionBox.visible) - GdmUtil.cloneAndFadeOutActor(this._userSelectionBox); - this._askForUsernameAndLogIn(); - }, - - _showUserList: function() { - this._authPrompt.hide(); - this._sessionMenuButton.close(); - this._setUserListExpanded(true); - this._notListedButton.show(); - this._userList.actor.grab_key_focus(); - }, - -- _beginVerificationForUser: function(userName) { -- let hold = new Batch.Hold(); -- -- this._userVerifier.begin(userName, hold); -- this._verifyingUser = true; -- return hold; -- }, -- - _beginVerificationForItem: function(item) { - this._authPrompt.setUser(item.user); - -- let tasks = [function() { -- let userName = item.user.get_user_name(); -- return this._beginVerificationForUser(userName); -- }]; -- let batch = new Batch.ConsecutiveBatch(this, tasks); -- return batch.run(); -+ 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; - - let batch = new Batch.ConcurrentBatch(this, [new Batch.ConsecutiveBatch(this, tasks), - this._beginVerificationForItem(activatedItem)]); - batch.run(); - }, - - _onDestroy: function() { - if (this._userManagerLoadedId) { - this._userManager.disconnect(this._userManagerLoadedId); - this._userManagerLoadedId = 0; - } - }, - - _loadUserList: function() { - let users = this._userManager.list_users(); - - for (let i = 0; i < users.length; i++) { - this._userList.addUser(users[i]); - } -diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js -index 7fd5271..53ff9b6 100644 ---- a/js/ui/unlockDialog.js -+++ b/js/ui/unlockDialog.js -@@ -16,247 +16,144 @@ const St = imports.gi.St; - const Layout = imports.ui.layout; - const Main = imports.ui.main; - const Panel = imports.ui.panel; - const Tweener = imports.ui.tweener; - const UserMenu = imports.ui.userMenu; - const UserWidget = imports.ui.userWidget; - - const AuthPrompt = imports.gdm.authPrompt; - const Batch = imports.gdm.batch; - const GdmUtil = imports.gdm.util; - const LoginDialog = imports.gdm.loginDialog; - - // The timeout before going back automatically to the lock screen (in seconds) - const IDLE_TIMEOUT = 2 * 60; - - const UnlockDialog = new Lang.Class({ - Name: 'UnlockDialog', - - _init: function(parentActor) { - this.actor = new St.Widget({ accessible_role: Atk.Role.WINDOW, - style_class: 'login-dialog', - visible: false }); - - this.actor.add_constraint(new Layout.MonitorConstraint({ primary: true })); - parentActor.add_child(this.actor); - - this._userManager = AccountsService.UserManager.get_default(); - this._userName = GLib.get_user_name(); - this._user = this._userManager.get_user(this._userName); - -- this._firstQuestion = true; -- -- this._greeterClient = new Gdm.Client(); -- this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient, { reauthenticationOnly: true }); -- this._userVerified = false; -- -- this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion)); -- this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage)); -- this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); -- this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed)); -- this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); -- -- this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint)); -- this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint)); -- - this._promptBox = new St.BoxLayout({ vertical: true }); - this.actor.add_child(this._promptBox); - this._promptBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - -- this._authPrompt = new AuthPrompt.AuthPrompt(); -+ this._authPrompt = new AuthPrompt.AuthPrompt(new Gdm.Client(), AuthPrompt.AuthPromptMode.UNLOCK_ONLY); -+ this._authPrompt.connect('reset', Lang.bind(this, this._onReset)); - this._authPrompt.setUser(this._user); - this._authPrompt.setPasswordChar('\u25cf'); - this._authPrompt.nextButton.label = _("Unlock"); -- this._authPrompt.connect('cancel', Lang.bind(this, this._escape)); -- this._authPrompt.connect('next', Lang.bind(this, this._doUnlock)); - - this._promptBox.add_child(this._authPrompt.actor); - - this.allowCancel = false; - - let screenSaverSettings = new Gio.Settings({ schema: 'org.gnome.desktop.screensaver' }); - if (screenSaverSettings.get_boolean('user-switch-enabled')) { - let otherUserLabel = new St.Label({ text: _("Log in as another user"), - style_class: 'login-dialog-not-listed-label' }); - this._otherUserButton = new St.Button({ style_class: 'login-dialog-not-listed-button', - can_focus: true, - child: otherUserLabel, - reactive: true, - x_align: St.Align.START, - x_fill: true }); - this._otherUserButton.connect('clicked', Lang.bind(this, this._otherUserClicked)); - this._promptBox.add_child(this._otherUserButton); - } else { - this._otherUserButton = null; - } - -+ this._authPrompt.begin({ userName: this._userName }); - this._updateSensitivity(true); - -- let batch = new Batch.Hold(); -- this._userVerifier.begin(this._userName, batch); -- - Main.ctrlAltTabManager.addGroup(this.actor, _("Unlock Window"), 'dialog-password-symbolic'); - - this._idleMonitor = new GnomeDesktop.IdleMonitor(); - this._idleWatchId = this._idleMonitor.add_idle_watch(IDLE_TIMEOUT * 1000, Lang.bind(this, this._escape)); - }, - - _updateSensitivity: function(sensitive) { - this._authPrompt.updateSensitivity(sensitive); - - if (this._otherUserButton) { - this._otherUserButton.reactive = sensitive; - this._otherUserButton.can_focus = sensitive; - } - }, - -- _showMessage: function(userVerifier, message, styleClass) { -- this._authPrompt.setMessage(message, styleClass); -- }, -- -- _onAskQuestion: function(verifier, serviceName, question, passwordChar) { -- if (this._firstQuestion && this._firstQuestionAnswer) { -- this._userVerifier.answerQuery(serviceName, this._firstQuestionAnswer); -- this._firstQuestionAnswer = null; -- this._firstQuestion = false; -- return; -- } -- -- if (!this._firstQuestion) -- this._promptEntry.text = ''; -- else -- this._firstQuestion = false; -- -- this._authPrompt.setPasswordChar(passwordChar); -- this._authPrompt.setQuestion(question); -- -- this._currentQuery = serviceName; -- -- this._updateSensitivity(true); -- this._authPrompt.stopSpinning(); -- }, -- -- _showLoginHint: function(verifier, message) { -- this._authPrompt.setHint(message); -- }, -- -- _hideLoginHint: function() { -- this._authPrompt.setHint(null); -- }, -- -- _doUnlock: function() { -- if (this._firstQuestion) { -- // we haven't received a query yet, so stash the answer -- // and make ourself non-reactive -- // the actual reply to GDM will be sent as soon as asked -- this._firstQuestionAnswer = this._promptEntry.text; -- this._updateSensitivity(false); -- this._authPrompt.startSpinning(); -- return; -- } -- -- if (!this._currentQuery) -- return; -- -- let query = this._currentQuery; -- this._currentQuery = null; -- -- this._updateSensitivity(false); -- this._authPrompt.startSpinning(); -- -- this._userVerifier.answerQuery(query, this._authPrompt.getAnswer()); -- }, -- -- _onVerificationComplete: function() { -- this._userVerified = true; -- }, -- - _onReset: function() { -- if (!this._userVerified) { -- this._userVerifier.clear(); -- this.emit('failed'); -- } -- }, -- -- _onVerificationFailed: function() { -- this._currentQuery = null; -- this._firstQuestion = true; -- this._userVerified = false; -- -- this._authPrompt.clear(); -- -- this._updateSensitivity(false); -- this._authPrompt.stopSpinning(); -+ this.emit('failed'); - }, - - _escape: function() { - if (this.allowCancel) { -- this._userVerifier.cancel(); -+ this._authPrompt.cancel(); - this.emit('failed'); - } - }, - - _otherUserClicked: function(button, event) { - Gdm.goto_login_session_sync(null); - -- this._userVerifier.cancel(); -- this.emit('failed'); -+ this._authPrompt.cancel(); - }, - - destroy: function() { -- this._userVerifier.clear(); -+ this.popModal(); - this.actor.destroy(); - - if (this._idleWatchId) { - this._idleMonitor.remove_watch(this._idleWatchId); - this._idleWatchId = 0; - } - }, - - cancel: function() { -- this._userVerifier.cancel(null); -+ this._authPrompt.cancel(); - - this.destroy(); - }, - - addCharacter: function(unichar) { - this._authPrompt.addCharacter(unichar); - }, - - finish: function(onComplete) { -- if (!this._userVerifier.hasPendingMessages) { -- onComplete(); -- return; -- } -- -- let signalId = this._userVerifier.connect('no-more-messages', -- Lang.bind(this, function() { -- this._userVerifier.disconnect(signalId); -- onComplete(); -- })); -+ this._authPrompt.finish(onComplete); - }, - - open: function(timestamp) { - this.actor.show(); - - if (this._isModal) - return true; - - if (!Main.pushModal(this.actor, { timestamp: timestamp, - keybindingMode: Shell.KeyBindingMode.UNLOCK_SCREEN })) - return false; - - this._isModal = true; - - return true; - }, - - popModal: function(timestamp) { - if (this._isModal) { - Main.popModal(this.actor, timestamp); - this._isModal = false; - } - } - }); - Signals.addSignalMethods(UnlockDialog.prototype); --- -1.8.3.1 - - -From 03072fa74c2fdd3129c5329cca04a9789318cdbc Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 24 Jul 2013 11:25:02 -0400 -Subject: [PATCH 24/69] loginDialog: correct typo - -commit 7e7295f259febf34c89659a9bcb05f9924fa1976 introduced a typo -(LOGIN instead of LOG_IN). - -The follow up commit fixes that. ---- - js/gdm/loginDialog.js | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index fe594e4..8fecc28 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -423,61 +423,61 @@ const LoginDialog = new Lang.Class({ - 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', - vertical: true, - visible: false }); - this._userSelectionBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - this.actor.add_child(this._userSelectionBox); - - this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner', - text: '' }); - 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_LOGIN); -+ 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._reset)); - this._authPrompt.hide(); - - this._authPrompt.actor.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - - this.actor.add_child(this._authPrompt.actor); - this._userList.actor.add_constraint(new Clutter.BindConstraint({ source: this._authPrompt.actor, - coordinate: Clutter.BindCoordinate.WIDTH })); - - // 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._hideUserListAndLogIn)); - this._notListedButton.hide(); - - this._userSelectionBox.add(this._notListedButton, - { expand: false, --- -1.8.3.1 - - -From 1f9975a9098165d7e4649140aabafa8ed4d07058 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 24 Jul 2013 10:53:48 -0400 -Subject: [PATCH 25/69] authPrompt: fade out message if user starts to type - -If there are no messages in the queue and a user starts to -type then we can safely hide the message label since the -user has probably already read it. - -This fixes a weirdness where "Incorrect Password" messages stay -around, even as the user types in the new correct password. - -https://bugzilla.gnome.org/show_bug.cgi?id=704817 ---- - js/gdm/authPrompt.js | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index b0dcd0d..75cf392 100644 ---- a/js/gdm/authPrompt.js -+++ b/js/gdm/authPrompt.js -@@ -1,49 +1,51 @@ - // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - - const Clutter = imports.gi.Clutter; - const Lang = imports.lang; - const Signals = imports.signals; - const St = imports.gi.St; - - const Panel = imports.ui.panel; - const Batch = imports.gdm.batch; - const GdmUtil = imports.gdm.util; - const Params = imports.misc.params; - const ShellEntry = imports.ui.shellEntry; - const Tweener = imports.ui.tweener; - const UserWidget = imports.ui.userWidget; - - const DEFAULT_BUTTON_WELL_ICON_SIZE = 24; - const DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0; - const DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3; - -+const MESSAGE_FADE_OUT_ANIMATION_TIME = 0.5; -+ - const AuthPromptMode = { - UNLOCK_ONLY: 0, - UNLOCK_OR_LOG_IN: 1 - }; - - const AuthPrompt = new Lang.Class({ - Name: 'AuthPrompt', - - _init: function(gdmClient, mode) { - this.verifyingUser = false; - - this._gdmClient = gdmClient; - this._mode = mode; - - let reauthenticationOnly; - if (this._mode == AuthPromptMode.UNLOCK_ONLY) - reauthenticationOnly = true; - else if (this._mode == AuthPromptMode.UNLOCK_OR_LOG_IN) - reauthenticationOnly = false; - - this._userVerifier = new GdmUtil.ShellUserVerifier(this._gdmClient, { reauthenticationOnly: reauthenticationOnly }); - - this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion)); - this._userVerifier.connect('show-message', Lang.bind(this, this._onShowMessage)); - this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed)); - this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); - this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); - this._userVerifier.connect('show-login-hint', Lang.bind(this, this._onShowLoginHint)); - this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._onHideLoginHint)); - -@@ -139,60 +141,63 @@ const AuthPrompt = new Lang.Class({ - x_align: St.Align.START, - y_align: St.Align.END }); - - this._buttonBox.add(this._defaultButtonWell, - { expand: true, - x_fill: false, - y_fill: false, - x_align: St.Align.END, - y_align: St.Align.MIDDLE }); - this.nextButton = new St.Button({ style_class: 'modal-dialog-button', - button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, - reactive: true, - can_focus: true, - label: _("Next") }); - this.nextButton.connect('clicked', - Lang.bind(this, function() { - this.emit('next'); - })); - this.nextButton.add_style_pseudo_class('default'); - this._buttonBox.add(this.nextButton, - { expand: false, - x_fill: false, - y_fill: false, - x_align: St.Align.END, - y_align: St.Align.END }); - - this._updateNextButtonSensitivity(this._entry.text.length > 0); - - this._entry.clutter_text.connect('text-changed', - Lang.bind(this, function() { -+ if (!this._userVerifier.hasPendingMessages) -+ this._fadeOutMessage(); -+ - this._updateNextButtonSensitivity(this._entry.text.length > 0); - })); - this._entry.clutter_text.connect('activate', Lang.bind(this, function() { - this.emit('next'); - })); - }, - - _onAskQuestion: function(verifier, serviceName, question, passwordChar) { - if (this._preemptiveAnswer) { - this._userVerifier.answerQuery(this._queryingService, this._preemptiveAnswer); - this._preemptiveAnswer = null; - return; - } - - if (this._queryingService) - this.clear(); - - this._queryingService = serviceName; - this.setPasswordChar(passwordChar); - this.setQuestion(question); - - if (this.verifyingUser) - this.cancelButton.show(); - else - this.cancelButton.hide(); - - if (passwordChar) { - if (this._mode == AuthPromptMode.UNLOCK_ONLY) - this.nextButton.label = _("Unlock"); - else if (this._mode == AuthPromptMode.UNLOCK_OR_LOG_IN) -@@ -304,62 +309,74 @@ const AuthPrompt = new Lang.Class({ - }, - - clear: function() { - this._entry.text = ''; - this.stopSpinning(); - }, - - setPasswordChar: function(passwordChar) { - this._entry.clutter_text.set_password_char(passwordChar); - this._entry.menu.isPassword = passwordChar != ''; - }, - - setQuestion: function(question) { - this._label.set_text(question); - - this._label.show(); - this._entry.show(); - - this._loginHint.opacity = 0; - this._loginHint.show(); - - this._entry.grab_key_focus(); - }, - - getAnswer: function() { - let text = this._entry.get_text(); - - return text; - }, - -+ _fadeOutMessage: function() { -+ if (this._message.opacity == 0) -+ return; -+ Tweener.removeTweens(this._message); -+ Tweener.addTween(this._message, -+ { opacity: 0, -+ time: MESSAGE_FADE_OUT_ANIMATION_TIME, -+ transition: 'easeOutQuad' -+ }); -+ }, -+ - setMessage: function(message, styleClass) { - if (message) { -+ Tweener.removeTweens(this._message); - this._message.text = message; - this._message.styleClass = styleClass; - this._message.opacity = 255; - } else { - this._message.opacity = 0; - } - }, - - _updateNextButtonSensitivity: function(sensitive) { - this.nextButton.reactive = sensitive; - this.nextButton.can_focus = sensitive; - }, - - updateSensitivity: function(sensitive) { - this._updateNextButtonSensitivity(sensitive); - this._entry.reactive = sensitive; - this._entry.clutter_text.editable = sensitive; - }, - - hide: function() { - this.setActorInDefaultButtonWell(null, true); - this.actor.hide(); - this._loginHint.opacity = 0; - - this.setUser(null); - - this.updateSensitivity(true); - this._entry.set_text(''); - }, - --- -1.8.3.1 - - -From b242ad1649db947f5f002685a4834ba3d5bd8f42 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Sun, 28 Jul 2013 12:40:55 -0400 -Subject: [PATCH 26/69] authPrompt: let PAM message wrap if longer than entry - -Right now the whole authPrompt spreads out if a PAM message -comes in that longer than the entry. - -This commit changes it to wrap instead, by forcing the -auth prompt to be a fixed width (slightly bigger than -the entry width was sized to previously). - -https://bugzilla.gnome.org/show_bug.cgi?id=705037 ---- - data/theme/gnome-shell.css | 5 +---- - js/gdm/authPrompt.js | 1 + - 2 files changed, 2 insertions(+), 4 deletions(-) - -diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css -index c42c19e..e074554 100644 ---- a/data/theme/gnome-shell.css -+++ b/data/theme/gnome-shell.css -@@ -2320,71 +2320,68 @@ StScrollBar StButton#vhandle:active { - border-radius: 8px; - width: 64px; - height: 64px; - } - - .login-dialog-not-listed-label { - font-size: 10.5pt; - font-weight: bold; - color: #666666; - padding-top: 1em; - padding-left: 2px; - } - - .login-dialog-not-listed-button:focus .login-dialog-not-listed-label, - .login-dialog-not-listed-button:hover .login-dialog-not-listed-label { - color: #E8E8E8; - } - - .login-dialog-username { - font-size: 16pt; - font-weight: bold; - text-align: left; - padding-left: 15px; - text-shadow: black 0px 4px 3px 0px; - } - - .login-dialog-prompt-layout { - padding-top: 24px; - padding-bottom: 12px; - spacing: 8px; -+ width: 23em; - } - - .login-dialog-prompt-label { - color: #eeeeee; - font-size: 14px; - } - --.login-dialog-prompt-entry { -- width: 20em; --} -- - .login-dialog-session-list-button StIcon { - icon-size: 1.25em; - } - - .login-dialog-session-list-button { - color: #8b8b8b; - } - - .login-dialog-session-list-button:hover, - .login-dialog-session-list-button:active { - color: white; - } - - .login-dialog-logo-bin { - padding: 24px 0px; - } - - .login-dialog .modal-dialog-button-box { - spacing: 3px; - } - - .login-dialog .modal-dialog-button { - border-radius: 5px; - padding: 3px 18px; - } - - .login-dialog .modal-dialog-button:focus { - padding: 2px 17px; - } - -diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index 75cf392..49b98fa 100644 ---- a/js/gdm/authPrompt.js -+++ b/js/gdm/authPrompt.js -@@ -69,60 +69,61 @@ const AuthPrompt = new Lang.Class({ - } - })); - - this._userWell = new St.Bin({ x_fill: true, - x_align: St.Align.START }); - this.actor.add(this._userWell, - { x_align: St.Align.START, - x_fill: true, - y_fill: true, - expand: true }); - this._label = new St.Label({ style_class: 'login-dialog-prompt-label' }); - - this.actor.add(this._label, - { expand: true, - x_fill: true, - y_fill: true, - x_align: St.Align.START }); - this._entry = new St.Entry({ style_class: 'login-dialog-prompt-entry', - can_focus: true }); - ShellEntry.addContextMenu(this._entry, { isPassword: true }); - - this.actor.add(this._entry, - { expand: true, - x_fill: true, - y_fill: false, - x_align: St.Align.START }); - - this._entry.grab_key_focus(); - - this._message = new St.Label({ opacity: 0 }); -+ this._message.clutter_text.line_wrap = true; - this.actor.add(this._message, { x_fill: true }); - - this._loginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' }); - this.actor.add(this._loginHint); - - this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box', - vertical: false }); - this.actor.add(this._buttonBox, - { expand: true, - x_align: St.Align.MIDDLE, - y_align: St.Align.END }); - - this._defaultButtonWell = new St.Widget(); - this._defaultButtonWellActor = null; - - this._initButtons(); - - let spinnerIcon = global.datadir + '/theme/process-working.svg'; - this._spinner = new Panel.AnimatedIcon(spinnerIcon, DEFAULT_BUTTON_WELL_ICON_SIZE); - this._spinner.actor.opacity = 0; - this._spinner.actor.show(); - this._defaultButtonWell.add_child(this._spinner.actor); - }, - - _onDestroy: function() { - this._userVerifier.clear(); - }, - - _initButtons: function() { - this.cancelButton = new St.Button({ style_class: 'modal-dialog-button', --- -1.8.3.1 - - -From 542b0fae6238e108248e62fc1adc598b28bbe244 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Mon, 22 Jul 2013 10:59:57 -0400 -Subject: [PATCH 27/69] authPrompt: Call next button "Unlock" when user - switching - -When a ShellUserVerifier is asked to verify a user at the login -screen it will transparently first try to reauthenticate the user -against an existing session and then fall back to logging a user -into a new session. The former is used for user switching. -It's useful to know which type of verification is happening, so -the next button can be made to say "Unlock" instead of "Sign In" when -a user is already signed in. - -This commit exports a new "reauthenticating" property on the -ShellUserVerifier that the auth prompt checks when deciding which -label to use for its next button. - -https://bugzilla.gnome.org/show_bug.cgi?id=704795 ---- - js/gdm/authPrompt.js | 4 ++-- - js/gdm/util.js | 3 +++ - 2 files changed, 5 insertions(+), 2 deletions(-) - -diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index 49b98fa..706cbe0 100644 ---- a/js/gdm/authPrompt.js -+++ b/js/gdm/authPrompt.js -@@ -172,63 +172,63 @@ const AuthPrompt = new Lang.Class({ - if (!this._userVerifier.hasPendingMessages) - this._fadeOutMessage(); - - this._updateNextButtonSensitivity(this._entry.text.length > 0); - })); - this._entry.clutter_text.connect('activate', Lang.bind(this, function() { - this.emit('next'); - })); - }, - - _onAskQuestion: function(verifier, serviceName, question, passwordChar) { - if (this._preemptiveAnswer) { - this._userVerifier.answerQuery(this._queryingService, this._preemptiveAnswer); - this._preemptiveAnswer = null; - return; - } - - if (this._queryingService) - this.clear(); - - this._queryingService = serviceName; - this.setPasswordChar(passwordChar); - this.setQuestion(question); - - if (this.verifyingUser) - this.cancelButton.show(); - else - this.cancelButton.hide(); - - if (passwordChar) { -- if (this._mode == AuthPromptMode.UNLOCK_ONLY) -+ if (this._userVerifier.reauthenticating) - this.nextButton.label = _("Unlock"); -- else if (this._mode == AuthPromptMode.UNLOCK_OR_LOG_IN) -+ else - this.nextButton.label = C_("button", "Sign In"); - } else { - this.nextButton.label = _("Next"); - } - - this.updateSensitivity(true); - this.emit('prompted'); - }, - - _onShowMessage: function(userVerifier, message, styleClass) { - this.setMessage(message, styleClass); - }, - - _onVerificationFailed: function() { - this.clear(); - - this.updateSensitivity(true); - this.setActorInDefaultButtonWell(null); - this.userVerified = false; - }, - - _onVerificationComplete: function() { - this.userVerified = true; - }, - - _onReset: function() { - if (!this.userVerified) - this.reset(); - }, - -diff --git a/js/gdm/util.js b/js/gdm/util.js -index 20540b7..1facf98 100644 ---- a/js/gdm/util.js -+++ b/js/gdm/util.js -@@ -94,68 +94,70 @@ function cloneAndFadeOutActor(actor) { - clone.set_position(x, y); - - let hold = new Batch.Hold(); - Tweener.addTween(clone, - { opacity: 0, - time: CLONE_FADE_ANIMATION_TIME, - transition: 'easeOutQuad', - onComplete: function() { - clone.destroy(); - hold.release(); - } - }); - return hold; - } - - const ShellUserVerifier = new Lang.Class({ - Name: 'ShellUserVerifier', - - _init: function(client, params) { - params = Params.parse(params, { reauthenticationOnly: false }); - this._reauthOnly = params.reauthenticationOnly; - - this._client = client; - - this._settings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA }); - - this._fprintManager = new Fprint.FprintManager(); - this._messageQueue = []; - this._messageQueueTimeoutId = 0; - this.hasPendingMessages = false; -+ this.reauthenticating = false; - - this._failCounter = 0; - }, - - begin: function(userName, hold) { - this._cancellable = new Gio.Cancellable(); - this._hold = hold; - this._userName = userName; -+ this.reauthenticating = false; - - this._checkForFingerprintReader(); - - if (userName) { - // If possible, reauthenticate an already running session, - // so any session specific credentials get updated appropriately - this._client.open_reauthentication_channel(userName, this._cancellable, - Lang.bind(this, this._reauthenticationChannelOpened)); - } else { - this._client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot)); - } - }, - - cancel: function() { - if (this._cancellable) - this._cancellable.cancel(); - - if (this._userVerifier) - this._userVerifier.call_cancel_sync(null); - }, - - clear: function() { - if (this._cancellable) { - this._cancellable.cancel(); - this._cancellable = null; - } - - if (this._userVerifier) { - this._userVerifier.run_dispose(); - this._userVerifier = null; -@@ -240,60 +242,61 @@ const ShellUserVerifier = new Lang.Class({ - if (!error && device) - this._haveFingerprintReader = true; - })); - }, - - _reportInitError: function(where, error) { - logError(error, where); - this._hold.release(); - - this._queueMessage(_("Authentication error"), 'login-dialog-message-warning'); - this._verificationFailed(false); - }, - - _reauthenticationChannelOpened: function(client, result) { - try { - this._userVerifier = client.open_reauthentication_channel_finish(result); - } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - return; - } catch(e if e.matches(Gio.DBusError, Gio.DBusError.ACCESS_DENIED) && - !this._reauthOnly) { - // Gdm emits org.freedesktop.DBus.Error.AccessDenied when there is - // no session to reauthenticate. Fall back to performing verification - // from this login session - client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot)); - return; - } catch(e) { - this._reportInitError('Failed to open reauthentication channel', e); - return; - } - -+ this.reauthenticating = true; - this._connectSignals(); - this._beginVerification(); - this._hold.release(); - }, - - _userVerifierGot: function(client, result) { - try { - this._userVerifier = client.get_user_verifier_finish(result); - } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - return; - } catch(e) { - this._reportInitError('Failed to obtain user verifier', e); - return; - } - - this._connectSignals(); - this._beginVerification(); - this._hold.release(); - }, - - _connectSignals: function() { - this._userVerifier.connect('info', Lang.bind(this, this._onInfo)); - this._userVerifier.connect('problem', Lang.bind(this, this._onProblem)); - this._userVerifier.connect('info-query', Lang.bind(this, this._onInfoQuery)); - this._userVerifier.connect('secret-info-query', Lang.bind(this, this._onSecretInfoQuery)); - this._userVerifier.connect('conversation-stopped', Lang.bind(this, this._onConversationStopped)); - this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); - this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); - }, - --- -1.8.3.1 - - -From 2fc335431dc903b7353745e3670df8c63237e6b7 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Mon, 29 Jul 2013 13:24:36 -0400 -Subject: [PATCH 28/69] authPrompt: disassociate from userVerifier when - destroyed - -Otherwise, it won't get GC'd and we'll end up potentially calling -its signal handlers after destruction. - -https://bugzilla.gnome.org/show_bug.cgi?id=683437 ---- - js/gdm/authPrompt.js | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index 706cbe0..d50f0fb 100644 ---- a/js/gdm/authPrompt.js -+++ b/js/gdm/authPrompt.js -@@ -96,60 +96,62 @@ const AuthPrompt = new Lang.Class({ - this._entry.grab_key_focus(); - - this._message = new St.Label({ opacity: 0 }); - this._message.clutter_text.line_wrap = true; - this.actor.add(this._message, { x_fill: true }); - - this._loginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' }); - this.actor.add(this._loginHint); - - this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box', - vertical: false }); - this.actor.add(this._buttonBox, - { expand: true, - x_align: St.Align.MIDDLE, - y_align: St.Align.END }); - - this._defaultButtonWell = new St.Widget(); - this._defaultButtonWellActor = null; - - this._initButtons(); - - let spinnerIcon = global.datadir + '/theme/process-working.svg'; - this._spinner = new Panel.AnimatedIcon(spinnerIcon, DEFAULT_BUTTON_WELL_ICON_SIZE); - this._spinner.actor.opacity = 0; - this._spinner.actor.show(); - this._defaultButtonWell.add_child(this._spinner.actor); - }, - - _onDestroy: function() { - this._userVerifier.clear(); -+ this._userVerifier.disconnectAll(); -+ this._userVerifier = null; - }, - - _initButtons: function() { - this.cancelButton = new St.Button({ style_class: 'modal-dialog-button', - button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, - reactive: true, - can_focus: true, - label: _("Cancel") }); - this.cancelButton.connect('clicked', - Lang.bind(this, function() { - this.cancel(); - })); - this._buttonBox.add(this.cancelButton, - { expand: false, - x_fill: false, - y_fill: false, - x_align: St.Align.START, - y_align: St.Align.END }); - - this._buttonBox.add(this._defaultButtonWell, - { expand: true, - x_fill: false, - y_fill: false, - x_align: St.Align.END, - y_align: St.Align.MIDDLE }); - this.nextButton = new St.Button({ style_class: 'modal-dialog-button', - button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, - reactive: true, - can_focus: true, - label: _("Next") }); --- -1.8.3.1 - - -From 04cd7cae1f815fccc55cd85ae5d1f085a2fd9dc1 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Sun, 28 Jul 2013 15:55:09 -0400 -Subject: [PATCH 29/69] loginDialog: don't ever call _reset directly - -The only time we ever call _reset directly is when -detecting changes to disable-user-list. We can implicitly -trigger a reset for this case, just as easily by calling -this._authPrompt.reset() - -This commit makes that change for consistency and to make -it easier to adjust the authprompt workflow later. - -https://bugzilla.gnome.org/show_bug.cgi?id=683437 ---- - js/gdm/loginDialog.js | 9 +++------ - 1 file changed, 3 insertions(+), 6 deletions(-) - -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index 8fecc28..1ed68ba 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -425,61 +425,61 @@ const LoginDialog = new Lang.Class({ - 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', - vertical: true, - visible: false }); - this._userSelectionBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - this.actor.add_child(this._userSelectionBox); - - this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner', - text: '' }); - 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._reset)); -+ this._authPrompt.connect('reset', Lang.bind(this, this._onReset)); - this._authPrompt.hide(); - - this._authPrompt.actor.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - - this.actor.add_child(this._authPrompt.actor); - this._userList.actor.add_constraint(new Clutter.BindConstraint({ source: this._authPrompt.actor, - coordinate: Clutter.BindCoordinate.WIDTH })); - - // 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._hideUserListAndLogIn)); - this._notListedButton.hide(); - - this._userSelectionBox.add(this._notListedButton, - { expand: false, - x_align: St.Align.START, - x_fill: true }); -@@ -504,109 +504,106 @@ const LoginDialog = new Lang.Class({ - 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); - - }, - - _updateDisableUserList: function() { - let disableUserList = this._settings.get_boolean(GdmUtil.DISABLE_USER_LIST_KEY); - - if (disableUserList != this._disableUserList) { - this._disableUserList = disableUserList; - - if (!this._authPrompt.verifyingUser) -- this._reset(); -+ this._authPrompt.reset(); - } - }, - - _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(); - } - }, - - _updateLogoTexture: function(cache, uri) { - if (this._logoFileUri != uri) - return; - - let icon = null; - if (this._logoFileUri) - icon = this._textureCache.load_uri_async(this._logoFileUri, - -1, _LOGO_ICON_HEIGHT); - this._logoBin.set_child(icon); - }, - - _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._authPrompt.cancelButton.show(); - - this._showPrompt(); - }, - -- _reset: function() { -- if (this._authPrompt.verifyingUser) -- return; -- -+ _onReset: function() { - this._sessionMenuButton.updateSensitivity(true); - - this._user = null; - - if (this._disableUserList) - this._hideUserListAndLogIn(); - else - this._showUserList(); - }, - - _onDefaultSessionChanged: function(client, sessionId) { - this._sessionMenuButton.setActiveSession(sessionId); - }, - - _shouldShowSessionMenuButton: function() { - if (this._authPrompt.verifyingUser) - return true; - - if (!this._user) - return false; - - if (this._user.is_logged_in) - return false; - - return true; - }, - - _showPrompt: function() { - if (this._authPrompt.actor.visible) - return; --- -1.8.3.1 - - -From 25b4b72076d8fb8f5ec896574d8e9ef8dd3a2ccc Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Sun, 28 Jul 2013 16:24:31 -0400 -Subject: [PATCH 30/69] authPrompt: consolidate verifyingUser/userVerified - -Right now we have two booleans that specify when user verification -is happening and when it succeeded, respectively. - -This commit consolidates them into one AuthPromptStatus enumeration. - -This clean up will allow us to check for verification failure more -easily. - -https://bugzilla.gnome.org/show_bug.cgi?id=683437 ---- - js/gdm/authPrompt.js | 22 ++++++++++++++-------- - js/gdm/loginDialog.js | 2 +- - 2 files changed, 15 insertions(+), 9 deletions(-) - -diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index d50f0fb..f915bf9 100644 ---- a/js/gdm/authPrompt.js -+++ b/js/gdm/authPrompt.js -@@ -1,61 +1,68 @@ - // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - - const Clutter = imports.gi.Clutter; - const Lang = imports.lang; - const Signals = imports.signals; - const St = imports.gi.St; - - const Panel = imports.ui.panel; - const Batch = imports.gdm.batch; - const GdmUtil = imports.gdm.util; - const Params = imports.misc.params; - const ShellEntry = imports.ui.shellEntry; - const Tweener = imports.ui.tweener; - const UserWidget = imports.ui.userWidget; - - const DEFAULT_BUTTON_WELL_ICON_SIZE = 24; - const DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0; - const DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3; - - const MESSAGE_FADE_OUT_ANIMATION_TIME = 0.5; - - const AuthPromptMode = { - UNLOCK_ONLY: 0, - UNLOCK_OR_LOG_IN: 1 - }; - -+const AuthPromptStatus = { -+ NOT_VERIFYING: 0, -+ VERIFYING: 1, -+ VERIFICATION_FAILED: 2, -+ VERIFICATION_SUCCEEDED: 3 -+}; -+ - const AuthPrompt = new Lang.Class({ - Name: 'AuthPrompt', - - _init: function(gdmClient, mode) { -- this.verifyingUser = false; -+ this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; - - this._gdmClient = gdmClient; - this._mode = mode; - - let reauthenticationOnly; - if (this._mode == AuthPromptMode.UNLOCK_ONLY) - reauthenticationOnly = true; - else if (this._mode == AuthPromptMode.UNLOCK_OR_LOG_IN) - reauthenticationOnly = false; - - this._userVerifier = new GdmUtil.ShellUserVerifier(this._gdmClient, { reauthenticationOnly: reauthenticationOnly }); - - this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion)); - this._userVerifier.connect('show-message', Lang.bind(this, this._onShowMessage)); - this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed)); - this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); - this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); - this._userVerifier.connect('show-login-hint', Lang.bind(this, this._onShowLoginHint)); - this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._onHideLoginHint)); - - this.connect('next', Lang.bind(this, function() { - this.updateSensitivity(false); - this.startSpinning(); - if (this._queryingService) { - this._userVerifier.answerQuery(this._queryingService, this._entry.text); - } else { - this._preemptiveAnswer = this._entry.text; - } - })); - -@@ -195,69 +202,69 @@ const AuthPrompt = new Lang.Class({ - this.setPasswordChar(passwordChar); - this.setQuestion(question); - - if (this.verifyingUser) - this.cancelButton.show(); - else - this.cancelButton.hide(); - - if (passwordChar) { - if (this._userVerifier.reauthenticating) - this.nextButton.label = _("Unlock"); - else - this.nextButton.label = C_("button", "Sign In"); - } else { - this.nextButton.label = _("Next"); - } - - this.updateSensitivity(true); - this.emit('prompted'); - }, - - _onShowMessage: function(userVerifier, message, styleClass) { - this.setMessage(message, styleClass); - }, - - _onVerificationFailed: function() { - this.clear(); - - this.updateSensitivity(true); - this.setActorInDefaultButtonWell(null); -- this.userVerified = false; -+ this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED; - }, - - _onVerificationComplete: function() { -- this.userVerified = true; -+ this.verificationStatus = AuthPromptStatus.VERIFICATION_SUCCEEDED; - }, - - _onReset: function() { -- if (!this.userVerified) -+ if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) - this.reset(); - }, - - _onShowLoginHint: function(verifier, message) { - this.setHint(message); - }, - - _onHideLoginHint: function() { - this.setHint(null); - }, - - addActorToDefaultButtonWell: function(actor) { - this._defaultButtonWell.add_child(actor); - - actor.add_constraint(new Clutter.AlignConstraint({ source: this._spinner.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - }, - - setActorInDefaultButtonWell: function(actor, animate) { - if (!this._defaultButtonWellActor && - !actor) - return; - - let oldActor = this._defaultButtonWellActor; - - if (oldActor) - Tweener.removeTweens(oldActor); - - let isSpinner; -@@ -376,85 +383,84 @@ const AuthPrompt = new Lang.Class({ - this.setActorInDefaultButtonWell(null, true); - this.actor.hide(); - this._loginHint.opacity = 0; - - this.setUser(null); - - this.updateSensitivity(true); - this._entry.set_text(''); - }, - - setUser: function(user) { - if (user) { - let userWidget = new UserWidget.UserWidget(user); - this._userWell.set_child(userWidget.actor); - } else { - this._userWell.set_child(null); - } - }, - - setHint: function(message) { - if (message) { - this._loginHint.set_text(message) - this._loginHint.opacity = 255; - } else { - this._loginHint.opacity = 0; - this._loginHint.set_text(''); - } - }, - - reset: function() { -- this.verifyingUser = false; -- this.userVerified = false; -+ this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; - this._queryingService = null; - this.clear(); - this._message.opacity = 0; - this.setUser(null); - this.stopSpinning(); - this.setHint(null); - - this.emit('reset'); - }, - - addCharacter: function(unichar) { - if (!this._entry.visible) - return; - - this._entry.grab_key_focus(); - this._entry.clutter_text.insert_unichar(unichar); - }, - - begin: function(params) { - params = Params.parse(params, { userName: null, - hold: null }); - - this.updateSensitivity(false); - - let hold = params.hold; - if (!hold) - hold = new Batch.Hold(); - - this._userVerifier.begin(params.userName, hold); -- this.verifyingUser = true; -+ this.verificationStatus = AuthPromptStatus.VERIFYING; - }, - - finish: function(onComplete) { - if (!this._userVerifier.hasPendingMessages) { - onComplete(); - return; - } - - let signalId = this._userVerifier.connect('no-more-messages', - Lang.bind(this, function() { - this._userVerifier.disconnect(signalId); - onComplete(); - })); - }, - - cancel: function() { -- if (this.verifyingUser) -+ if (this.verificationStatus == AuthPromptStatus.VERIFYING) - this._userVerifier.cancel(); - - this.reset(); - } - }); - Signals.addSignalMethods(AuthPrompt.prototype); -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index 1ed68ba..c5c42f1 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -503,61 +503,61 @@ const LoginDialog = new Lang.Class({ - 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); - - }, - - _updateDisableUserList: function() { - let disableUserList = this._settings.get_boolean(GdmUtil.DISABLE_USER_LIST_KEY); - - if (disableUserList != this._disableUserList) { - this._disableUserList = disableUserList; - -- if (!this._authPrompt.verifyingUser) -+ if (this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING) - this._authPrompt.reset(); - } - }, - - _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(); - } - }, - - _updateLogoTexture: function(cache, uri) { - if (this._logoFileUri != uri) - return; - - let icon = null; - if (this._logoFileUri) - icon = this._textureCache.load_uri_async(this._logoFileUri, - -1, _LOGO_ICON_HEIGHT); - this._logoBin.set_child(icon); - }, - - _updateLogo: function() { - let path = this._settings.get_string(GdmUtil.LOGO_KEY); - --- -1.8.3.1 - - -From ce3e6485c61a7d95aefe473347527ea262d4ed9d Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Mon, 29 Jul 2013 10:52:02 -0400 -Subject: [PATCH 31/69] util: clear user verifier after cancelling it - -If we don't clear it, then the connection to gdm will remain open. - -https://bugzilla.gnome.org/show_bug.cgi?id=683437 ---- - js/gdm/util.js | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/js/gdm/util.js b/js/gdm/util.js -index 1facf98..9557c66 100644 ---- a/js/gdm/util.js -+++ b/js/gdm/util.js -@@ -121,62 +121,64 @@ const ShellUserVerifier = new Lang.Class({ - this._messageQueue = []; - this._messageQueueTimeoutId = 0; - this.hasPendingMessages = false; - this.reauthenticating = false; - - this._failCounter = 0; - }, - - begin: function(userName, hold) { - this._cancellable = new Gio.Cancellable(); - this._hold = hold; - this._userName = userName; - this.reauthenticating = false; - - this._checkForFingerprintReader(); - - if (userName) { - // If possible, reauthenticate an already running session, - // so any session specific credentials get updated appropriately - this._client.open_reauthentication_channel(userName, this._cancellable, - Lang.bind(this, this._reauthenticationChannelOpened)); - } else { - this._client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot)); - } - }, - - cancel: function() { - if (this._cancellable) - this._cancellable.cancel(); - -- if (this._userVerifier) -+ if (this._userVerifier) { - this._userVerifier.call_cancel_sync(null); -+ this.clear(); -+ } - }, - - clear: function() { - if (this._cancellable) { - this._cancellable.cancel(); - this._cancellable = null; - } - - if (this._userVerifier) { - this._userVerifier.run_dispose(); - this._userVerifier = null; - } - - this._clearMessageQueue(); - }, - - answerQuery: function(serviceName, answer) { - if (!this.hasPendingMessages) { - this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null); - } else { - let signalId = this.connect('no-more-messages', - Lang.bind(this, function() { - this.disconnect(signalId); - this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null); - })); - } - }, - - _getIntervalForMessage: function(message) { - // We probably could be smarter here --- -1.8.3.1 - - -From 810fc0f00ea35940b634a31602b34b7867256e33 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Mon, 29 Jul 2013 08:46:37 -0400 -Subject: [PATCH 32/69] authPrompt: cancel user verification if verifying when - reset - -authPrompt.reset() currently only leaves the authPrompt in a -sane state if the user isn't verifying. - -This commit makes sure to cancel verification if a reset happens -while verification is in process. - -https://bugzilla.gnome.org/show_bug.cgi?id=683437 ---- - js/gdm/authPrompt.js | 12 ++++++++---- - 1 file changed, 8 insertions(+), 4 deletions(-) - -diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index f915bf9..07549c8 100644 ---- a/js/gdm/authPrompt.js -+++ b/js/gdm/authPrompt.js -@@ -210,62 +210,64 @@ const AuthPrompt = new Lang.Class({ - if (passwordChar) { - if (this._userVerifier.reauthenticating) - this.nextButton.label = _("Unlock"); - else - this.nextButton.label = C_("button", "Sign In"); - } else { - this.nextButton.label = _("Next"); - } - - this.updateSensitivity(true); - this.emit('prompted'); - }, - - _onShowMessage: function(userVerifier, message, styleClass) { - this.setMessage(message, styleClass); - }, - - _onVerificationFailed: function() { - this.clear(); - - this.updateSensitivity(true); - this.setActorInDefaultButtonWell(null); - this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED; - }, - - _onVerificationComplete: function() { - this.verificationStatus = AuthPromptStatus.VERIFICATION_SUCCEEDED; - }, - - _onReset: function() { -- if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) -+ if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) { -+ this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; - this.reset(); -+ } - }, - - _onShowLoginHint: function(verifier, message) { - this.setHint(message); - }, - - _onHideLoginHint: function() { - this.setHint(null); - }, - - addActorToDefaultButtonWell: function(actor) { - this._defaultButtonWell.add_child(actor); - - actor.add_constraint(new Clutter.AlignConstraint({ source: this._spinner.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - }, - - setActorInDefaultButtonWell: function(actor, animate) { - if (!this._defaultButtonWellActor && - !actor) - return; - - let oldActor = this._defaultButtonWellActor; - - if (oldActor) - Tweener.removeTweens(oldActor); - - let isSpinner; - if (actor == this._spinner.actor) -@@ -383,84 +385,86 @@ const AuthPrompt = new Lang.Class({ - this.setActorInDefaultButtonWell(null, true); - this.actor.hide(); - this._loginHint.opacity = 0; - - this.setUser(null); - - this.updateSensitivity(true); - this._entry.set_text(''); - }, - - setUser: function(user) { - if (user) { - let userWidget = new UserWidget.UserWidget(user); - this._userWell.set_child(userWidget.actor); - } else { - this._userWell.set_child(null); - } - }, - - setHint: function(message) { - if (message) { - this._loginHint.set_text(message) - this._loginHint.opacity = 255; - } else { - this._loginHint.opacity = 0; - this._loginHint.set_text(''); - } - }, - - reset: function() { -+ let oldStatus = this.verificationStatus; - this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; -+ -+ if (oldStatus == AuthPromptStatus.VERIFYING) -+ this._userVerifier.cancel(); -+ - this._queryingService = null; - this.clear(); - this._message.opacity = 0; - this.setUser(null); - this.stopSpinning(); - this.setHint(null); - - this.emit('reset'); - }, - - addCharacter: function(unichar) { - if (!this._entry.visible) - return; - - this._entry.grab_key_focus(); - this._entry.clutter_text.insert_unichar(unichar); - }, - - begin: function(params) { - params = Params.parse(params, { userName: null, - hold: null }); - - this.updateSensitivity(false); - - let hold = params.hold; - if (!hold) - hold = new Batch.Hold(); - - this._userVerifier.begin(params.userName, hold); - this.verificationStatus = AuthPromptStatus.VERIFYING; - }, - - finish: function(onComplete) { - if (!this._userVerifier.hasPendingMessages) { - onComplete(); - return; - } - - let signalId = this._userVerifier.connect('no-more-messages', - Lang.bind(this, function() { - this._userVerifier.disconnect(signalId); - onComplete(); - })); - }, - - cancel: function() { -- if (this.verificationStatus == AuthPromptStatus.VERIFYING) -- this._userVerifier.cancel(); -- - this.reset(); - } - }); - Signals.addSignalMethods(AuthPrompt.prototype); --- -1.8.3.1 - - -From dc52d1d2ddaefb1fe2845e8b6efee0d9407c20d1 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Sun, 28 Jul 2013 16:06:04 -0400 -Subject: [PATCH 33/69] unlockDialog: only emit 'failed' on reset after - failure/cancel - -We currently emit "failed" any time the UserVerifier is reset, -and user verification didn't succeed prior. - -A more conceptually clear time to emit "failed" would be if -the UserVerifier is reset and user verification failed prior, -and to emit "failed" if the user cancels unlock. - -This commit restructures things to do that. Aside from being -more conceptually clear, it also lays the groundwork for us -to be able to reset the unlock screen without failing. - -https://bugzilla.gnome.org/show_bug.cgi?id=683437 ---- - js/gdm/authPrompt.js | 4 ++++ - js/ui/unlockDialog.js | 9 ++++----- - 2 files changed, 8 insertions(+), 5 deletions(-) - -diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index 07549c8..c10a178 100644 ---- a/js/gdm/authPrompt.js -+++ b/js/gdm/authPrompt.js -@@ -398,73 +398,77 @@ const AuthPrompt = new Lang.Class({ - this._userWell.set_child(userWidget.actor); - } else { - this._userWell.set_child(null); - } - }, - - setHint: function(message) { - if (message) { - this._loginHint.set_text(message) - this._loginHint.opacity = 255; - } else { - this._loginHint.opacity = 0; - this._loginHint.set_text(''); - } - }, - - reset: function() { - let oldStatus = this.verificationStatus; - this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; - - if (oldStatus == AuthPromptStatus.VERIFYING) - this._userVerifier.cancel(); - - this._queryingService = null; - this.clear(); - this._message.opacity = 0; - this.setUser(null); - this.stopSpinning(); - this.setHint(null); - -+ if (oldStatus == AuthPromptStatus.VERIFICATION_FAILED) -+ this.emit('failed'); -+ - this.emit('reset'); - }, - - addCharacter: function(unichar) { - if (!this._entry.visible) - return; - - this._entry.grab_key_focus(); - this._entry.clutter_text.insert_unichar(unichar); - }, - - begin: function(params) { - params = Params.parse(params, { userName: null, - hold: null }); - - this.updateSensitivity(false); - - let hold = params.hold; - if (!hold) - hold = new Batch.Hold(); - - this._userVerifier.begin(params.userName, hold); - this.verificationStatus = AuthPromptStatus.VERIFYING; - }, - - finish: function(onComplete) { - if (!this._userVerifier.hasPendingMessages) { - onComplete(); - return; - } - - let signalId = this._userVerifier.connect('no-more-messages', - Lang.bind(this, function() { - this._userVerifier.disconnect(signalId); - onComplete(); - })); - }, - - cancel: function() { - this.reset(); -+ this.emit('cancelled'); - } - }); - Signals.addSignalMethods(AuthPrompt.prototype); -diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js -index 53ff9b6..bfc97f3 100644 ---- a/js/ui/unlockDialog.js -+++ b/js/ui/unlockDialog.js -@@ -23,112 +23,111 @@ const UserWidget = imports.ui.userWidget; - const AuthPrompt = imports.gdm.authPrompt; - const Batch = imports.gdm.batch; - const GdmUtil = imports.gdm.util; - const LoginDialog = imports.gdm.loginDialog; - - // The timeout before going back automatically to the lock screen (in seconds) - const IDLE_TIMEOUT = 2 * 60; - - const UnlockDialog = new Lang.Class({ - Name: 'UnlockDialog', - - _init: function(parentActor) { - this.actor = new St.Widget({ accessible_role: Atk.Role.WINDOW, - style_class: 'login-dialog', - visible: false }); - - this.actor.add_constraint(new Layout.MonitorConstraint({ primary: true })); - parentActor.add_child(this.actor); - - this._userManager = AccountsService.UserManager.get_default(); - this._userName = GLib.get_user_name(); - this._user = this._userManager.get_user(this._userName); - - this._promptBox = new St.BoxLayout({ vertical: true }); - this.actor.add_child(this._promptBox); - this._promptBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - - this._authPrompt = new AuthPrompt.AuthPrompt(new Gdm.Client(), AuthPrompt.AuthPromptMode.UNLOCK_ONLY); -- this._authPrompt.connect('reset', Lang.bind(this, this._onReset)); -+ this._authPrompt.connect('failed', Lang.bind(this, this._fail)); -+ this._authPrompt.connect('cancelled', Lang.bind(this, this._fail)); - this._authPrompt.setUser(this._user); - this._authPrompt.setPasswordChar('\u25cf'); - this._authPrompt.nextButton.label = _("Unlock"); - - this._promptBox.add_child(this._authPrompt.actor); - - this.allowCancel = false; - - let screenSaverSettings = new Gio.Settings({ schema: 'org.gnome.desktop.screensaver' }); - if (screenSaverSettings.get_boolean('user-switch-enabled')) { - let otherUserLabel = new St.Label({ text: _("Log in as another user"), - style_class: 'login-dialog-not-listed-label' }); - this._otherUserButton = new St.Button({ style_class: 'login-dialog-not-listed-button', - can_focus: true, - child: otherUserLabel, - reactive: true, - x_align: St.Align.START, - x_fill: true }); - this._otherUserButton.connect('clicked', Lang.bind(this, this._otherUserClicked)); - this._promptBox.add_child(this._otherUserButton); - } else { - this._otherUserButton = null; - } - - this._authPrompt.begin({ userName: this._userName }); - this._updateSensitivity(true); - - Main.ctrlAltTabManager.addGroup(this.actor, _("Unlock Window"), 'dialog-password-symbolic'); - - this._idleMonitor = new GnomeDesktop.IdleMonitor(); - this._idleWatchId = this._idleMonitor.add_idle_watch(IDLE_TIMEOUT * 1000, Lang.bind(this, this._escape)); - }, - - _updateSensitivity: function(sensitive) { - this._authPrompt.updateSensitivity(sensitive); - - if (this._otherUserButton) { - this._otherUserButton.reactive = sensitive; - this._otherUserButton.can_focus = sensitive; - } - }, - -- _onReset: function() { -+ _fail: function() { - this.emit('failed'); - }, - - _escape: function() { -- if (this.allowCancel) { -+ if (this.allowCancel) - this._authPrompt.cancel(); -- this.emit('failed'); -- } - }, - - _otherUserClicked: function(button, event) { - Gdm.goto_login_session_sync(null); - - this._authPrompt.cancel(); - }, - - destroy: function() { - this.popModal(); - this.actor.destroy(); - - if (this._idleWatchId) { - this._idleMonitor.remove_watch(this._idleWatchId); - this._idleWatchId = 0; - } - }, - - cancel: function() { - this._authPrompt.cancel(); - - this.destroy(); - }, - - addCharacter: function(unichar) { - this._authPrompt.addCharacter(unichar); - }, - - finish: function(onComplete) { - this._authPrompt.finish(onComplete); --- -1.8.3.1 - - -From c89eee9198fbc22eda40d74c9c778b7ed82c51e4 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Fri, 16 Aug 2013 13:26:13 -0400 -Subject: [PATCH 34/69] loginDialog: fix session menu visibility - -The shouldShowSessionMenu function has a few bugs in it. -This fixes them. - -https://bugzilla.gnome.org/show_bug.cgi?id=706153 ---- - js/gdm/loginDialog.js | 7 ++----- - 1 file changed, 2 insertions(+), 5 deletions(-) - -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index c5c42f1..6808902 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -565,67 +565,64 @@ const LoginDialog = new Lang.Class({ - this._updateLogoTexture(this._textureCache, this._logoFileUri); - }, - - _onPrompted: function() { - this._sessionMenuButton.updateSensitivity(true); - - if (this._shouldShowSessionMenuButton()) - this._authPrompt.setActorInDefaultButtonWell(this._sessionMenuButton.actor); - - this._authPrompt.cancelButton.show(); - - this._showPrompt(); - }, - - _onReset: function() { - this._sessionMenuButton.updateSensitivity(true); - - this._user = null; - - if (this._disableUserList) - this._hideUserListAndLogIn(); - else - this._showUserList(); - }, - - _onDefaultSessionChanged: function(client, sessionId) { - this._sessionMenuButton.setActiveSession(sessionId); - }, - - _shouldShowSessionMenuButton: function() { -- if (this._authPrompt.verifyingUser) -- return true; -- -- if (!this._user) -+ if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFYING) - return false; - -- if (this._user.is_logged_in) -+ if (this._user && 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' }); - }, - - _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.setHint(_("(e.g., user or %s)").format(hint)); - }, - - _askForUsernameAndLogIn: function() { --- -1.8.3.1 - - -From eb341ad40b886d1556ea4c9549afe9bad606ab45 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Sun, 28 Jul 2013 17:49:50 -0400 -Subject: [PATCH 35/69] authPrompt: add support for auth without username - -This commit introduces a new BeginRequestType enum which gets -passed to the 'call-begin-when-ready' signal to specify whether -a username should be provided to the begin() method and changes -the loginDialog to comply. - -Currently, the signal only ever gets emitted with - -AuthPrompt.BeginRequestType.PROVIDE_USERNAME - -but that will change in the future when providing smartcard -support. - -https://bugzilla.gnome.org/show_bug.cgi?id=683437 ---- - js/gdm/authPrompt.js | 7 ++++++- - js/gdm/loginDialog.js | 32 ++++++++++++++++++++++++-------- - js/ui/unlockDialog.js | 16 ++++++++++++++-- - 3 files changed, 44 insertions(+), 11 deletions(-) - -diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index c10a178..e987d25 100644 ---- a/js/gdm/authPrompt.js -+++ b/js/gdm/authPrompt.js -@@ -4,60 +4,65 @@ const Clutter = imports.gi.Clutter; - const Lang = imports.lang; - const Signals = imports.signals; - const St = imports.gi.St; - - const Panel = imports.ui.panel; - const Batch = imports.gdm.batch; - const GdmUtil = imports.gdm.util; - const Params = imports.misc.params; - const ShellEntry = imports.ui.shellEntry; - const Tweener = imports.ui.tweener; - const UserWidget = imports.ui.userWidget; - - const DEFAULT_BUTTON_WELL_ICON_SIZE = 24; - const DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0; - const DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3; - - const MESSAGE_FADE_OUT_ANIMATION_TIME = 0.5; - - const AuthPromptMode = { - UNLOCK_ONLY: 0, - UNLOCK_OR_LOG_IN: 1 - }; - - const AuthPromptStatus = { - NOT_VERIFYING: 0, - VERIFYING: 1, - VERIFICATION_FAILED: 2, - VERIFICATION_SUCCEEDED: 3 - }; - -+const BeginRequestType = { -+ PROVIDE_USERNAME: 0, -+ DONT_PROVIDE_USERNAME: 1 -+}; -+ - const AuthPrompt = new Lang.Class({ - Name: 'AuthPrompt', - - _init: function(gdmClient, mode) { - this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; - - this._gdmClient = gdmClient; - this._mode = mode; - - let reauthenticationOnly; - if (this._mode == AuthPromptMode.UNLOCK_ONLY) - reauthenticationOnly = true; - else if (this._mode == AuthPromptMode.UNLOCK_OR_LOG_IN) - reauthenticationOnly = false; - - this._userVerifier = new GdmUtil.ShellUserVerifier(this._gdmClient, { reauthenticationOnly: reauthenticationOnly }); - - this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion)); - this._userVerifier.connect('show-message', Lang.bind(this, this._onShowMessage)); - this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed)); - this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); - this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); - this._userVerifier.connect('show-login-hint', Lang.bind(this, this._onShowLoginHint)); - this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._onHideLoginHint)); - - this.connect('next', Lang.bind(this, function() { - this.updateSensitivity(false); - this.startSpinning(); - if (this._queryingService) { - this._userVerifier.answerQuery(this._queryingService, this._entry.text); -@@ -401,61 +406,61 @@ const AuthPrompt = new Lang.Class({ - } - }, - - setHint: function(message) { - if (message) { - this._loginHint.set_text(message) - this._loginHint.opacity = 255; - } else { - this._loginHint.opacity = 0; - this._loginHint.set_text(''); - } - }, - - reset: function() { - let oldStatus = this.verificationStatus; - this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; - - if (oldStatus == AuthPromptStatus.VERIFYING) - this._userVerifier.cancel(); - - this._queryingService = null; - this.clear(); - this._message.opacity = 0; - this.setUser(null); - this.stopSpinning(); - this.setHint(null); - - if (oldStatus == AuthPromptStatus.VERIFICATION_FAILED) - this.emit('failed'); - -- this.emit('reset'); -+ this.emit('reset', BeginRequestType.PROVIDE_USERNAME); - }, - - addCharacter: function(unichar) { - if (!this._entry.visible) - return; - - this._entry.grab_key_focus(); - this._entry.clutter_text.insert_unichar(unichar); - }, - - begin: function(params) { - params = Params.parse(params, { userName: null, - hold: null }); - - this.updateSensitivity(false); - - let hold = params.hold; - if (!hold) - hold = new Batch.Hold(); - - this._userVerifier.begin(params.userName, hold); - this.verificationStatus = AuthPromptStatus.VERIFYING; - }, - - finish: function(onComplete) { - if (!this._userVerifier.hasPendingMessages) { - onComplete(); - return; - } - -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index 6808902..b40aa85 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -449,61 +449,66 @@ const LoginDialog = new Lang.Class({ - { 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.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - - this.actor.add_child(this._authPrompt.actor); - this._userList.actor.add_constraint(new Clutter.BindConstraint({ source: this._authPrompt.actor, - coordinate: Clutter.BindCoordinate.WIDTH })); - - // 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._hideUserListAndLogIn)); -+ this._notListedButton.connect('clicked', -+ Lang.bind(this, function() { -+ this._authPrompt.cancelButton.show(); -+ this._hideUserListAndLogIn(); -+ })); -+ - this._notListedButton.hide(); - - this._userSelectionBox.add(this._notListedButton, - { expand: false, - x_align: St.Align.START, - x_fill: true }); - - this._logoBin = new St.Bin({ style_class: 'login-dialog-logo-bin', y_expand: true }); - this._logoBin.set_y_align(Clutter.ActorAlign.END); - this._logoBin.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.X_AXIS, - factor: 0.5 })); - this._logoBin.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.Y_AXIS, - factor: 1.0 })); - this.actor.add_child(this._logoBin); - this._updateLogo(); - - 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(); - -@@ -549,110 +554,112 @@ const LoginDialog = new Lang.Class({ - - _updateLogoTexture: function(cache, uri) { - if (this._logoFileUri != uri) - return; - - let icon = null; - if (this._logoFileUri) - icon = this._textureCache.load_uri_async(this._logoFileUri, - -1, _LOGO_ICON_HEIGHT); - this._logoBin.set_child(icon); - }, - - _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._authPrompt.cancelButton.show(); - - this._showPrompt(); - }, - -- _onReset: function() { -+ _onReset: function(authPrompt, beginRequest) { - this._sessionMenuButton.updateSensitivity(true); - - this._user = null; - -- if (this._disableUserList) -+ if (this._disableUserList) { -+ this._authPrompt.cancelButton.hide(); - this._hideUserListAndLogIn(); -- else -- this._showUserList(); -+ } else { -+ this._showUserList(); -+ } - }, - - _onDefaultSessionChanged: function(client, sessionId) { - this._sessionMenuButton.setActiveSession(sessionId); - }, - - _shouldShowSessionMenuButton: function() { - if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFYING) - return false; - - if (this._user && 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' }); - }, - - _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.setHint(_("(e.g., user or %s)").format(hint)); - }, - -- _askForUsernameAndLogIn: function() { -+ _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._authPrompt.clear(); - this._authPrompt.startSpinning(); - this._authPrompt.begin({ userName: answer }); - - realmManager.disconnect(realmSignalId) - realmManager.release(); - })); - this._authPrompt.cancelButton.hide(); - this._showPrompt(); - }, - - _startSession: function(serviceName) { - Tweener.addTween(this.actor, - { opacity: 0, - time: _FADE_ANIMATION_TIME, - transition: 'easeOutQuad', - onUpdate: function() { -@@ -781,65 +788,74 @@ const LoginDialog = new Lang.Class({ - }, - - _onTimedLoginRequested: function(client, userName, seconds) { - this._startTimedLogin(userName, seconds); - - global.stage.connect('captured-event', - Lang.bind(this, function(actor, event) { - if (this._timedLoginDelay == undefined) - return false; - - if (event.type() == Clutter.EventType.KEY_PRESS || - event.type() == Clutter.EventType.BUTTON_PRESS) { - if (this._timedLoginBatch) { - this._timedLoginBatch.cancel(); - this._timedLoginBatch = null; - } - } else if (event.type() == Clutter.EventType.KEY_RELEASE || - event.type() == Clutter.EventType.BUTTON_RELEASE) { - this._resetTimedLogin(); - } - - return false; - })); - }, - - _setUserListExpanded: function(expanded) { - this._userList.updateStyle(expanded); - this._userSelectionBox.visible = expanded; - }, - -- _hideUserListAndLogIn: function() { -+ _hideUserList: function() { - this._setUserListExpanded(false); - if (this._userSelectionBox.visible) - GdmUtil.cloneAndFadeOutActor(this._userSelectionBox); -- this._askForUsernameAndLogIn(); -+ }, -+ -+ _hideUserListAskForUsernameAndBeginVerification: function() { -+ this._hideUserList(); -+ this._askForUsernameAndBeginVerification(); -+ }, -+ -+ _hideUserListAndBeginVerification: function() { -+ this._hideUserList(); -+ this._authPrompt.begin(); - }, - - _showUserList: function() { - this._authPrompt.hide(); - 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; -diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js -index bfc97f3..09024ba 100644 ---- a/js/ui/unlockDialog.js -+++ b/js/ui/unlockDialog.js -@@ -25,106 +25,118 @@ const Batch = imports.gdm.batch; - const GdmUtil = imports.gdm.util; - const LoginDialog = imports.gdm.loginDialog; - - // The timeout before going back automatically to the lock screen (in seconds) - const IDLE_TIMEOUT = 2 * 60; - - const UnlockDialog = new Lang.Class({ - Name: 'UnlockDialog', - - _init: function(parentActor) { - this.actor = new St.Widget({ accessible_role: Atk.Role.WINDOW, - style_class: 'login-dialog', - visible: false }); - - this.actor.add_constraint(new Layout.MonitorConstraint({ primary: true })); - parentActor.add_child(this.actor); - - this._userManager = AccountsService.UserManager.get_default(); - this._userName = GLib.get_user_name(); - this._user = this._userManager.get_user(this._userName); - - this._promptBox = new St.BoxLayout({ vertical: true }); - this.actor.add_child(this._promptBox); - this._promptBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - - this._authPrompt = new AuthPrompt.AuthPrompt(new Gdm.Client(), AuthPrompt.AuthPromptMode.UNLOCK_ONLY); - this._authPrompt.connect('failed', Lang.bind(this, this._fail)); - this._authPrompt.connect('cancelled', Lang.bind(this, this._fail)); -- this._authPrompt.setUser(this._user); -+ this._authPrompt.connect('reset', Lang.bind(this, this._onReset)); - this._authPrompt.setPasswordChar('\u25cf'); - this._authPrompt.nextButton.label = _("Unlock"); - - this._promptBox.add_child(this._authPrompt.actor); - - this.allowCancel = false; - - let screenSaverSettings = new Gio.Settings({ schema: 'org.gnome.desktop.screensaver' }); - if (screenSaverSettings.get_boolean('user-switch-enabled')) { - let otherUserLabel = new St.Label({ text: _("Log in as another user"), - style_class: 'login-dialog-not-listed-label' }); - this._otherUserButton = new St.Button({ style_class: 'login-dialog-not-listed-button', - can_focus: true, - child: otherUserLabel, - reactive: true, - x_align: St.Align.START, - x_fill: true }); - this._otherUserButton.connect('clicked', Lang.bind(this, this._otherUserClicked)); - this._promptBox.add_child(this._otherUserButton); - } else { - this._otherUserButton = null; - } - -- this._authPrompt.begin({ userName: this._userName }); -+ this._authPrompt.reset(); - this._updateSensitivity(true); - - Main.ctrlAltTabManager.addGroup(this.actor, _("Unlock Window"), 'dialog-password-symbolic'); - - this._idleMonitor = new GnomeDesktop.IdleMonitor(); - this._idleWatchId = this._idleMonitor.add_idle_watch(IDLE_TIMEOUT * 1000, Lang.bind(this, this._escape)); - }, - - _updateSensitivity: function(sensitive) { - this._authPrompt.updateSensitivity(sensitive); - - if (this._otherUserButton) { - this._otherUserButton.reactive = sensitive; - this._otherUserButton.can_focus = sensitive; - } - }, - - _fail: function() { - this.emit('failed'); - }, - -+ _onReset: function(authPrompt, beginRequest) { -+ let userName; -+ if (beginRequest == AuthPrompt.BeginRequestType.PROVIDE_USERNAME) { -+ this._authPrompt.setUser(this._user); -+ userName = this._userName; -+ } else { -+ userName = null; -+ } -+ -+ this._authPrompt.begin({ userName: userName }); -+ }, -+ - _escape: function() { - if (this.allowCancel) - this._authPrompt.cancel(); - }, - - _otherUserClicked: function(button, event) { - Gdm.goto_login_session_sync(null); - - this._authPrompt.cancel(); - }, - - destroy: function() { - this.popModal(); - this.actor.destroy(); - - if (this._idleWatchId) { - this._idleMonitor.remove_watch(this._idleWatchId); - this._idleWatchId = 0; - } - }, - - cancel: function() { - this._authPrompt.cancel(); - - this.destroy(); - }, - - addCharacter: function(unichar) { - this._authPrompt.addCharacter(unichar); - }, --- -1.8.3.1 - - -From d7c6ef5e0f8e9d6f036e5d61a6f458d7067b2998 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Sun, 28 Jul 2013 19:42:26 -0400 -Subject: [PATCH 36/69] util: abstract out main auth service in code - -Right now, the primary way a user logs in is with -a password. They can also swipe their finger, if their -fingerprint is enrolled, but it's expected the fingerprint -auth service won't ask questions the user has to respond to -by typing. As such, we ignore questions that comes from -anything but the main auth service: gdm-password. - -In the future, if a user inserts a smartcard, we'll want -to treat the gdm-smartcard service as the main auth service, -and let any questions from it get to the user. - -This commit tries to prepare for that eventuality by storing -the name of the main auth service away in a _mainService variable -when verification is first begun, and then later checking incoming -queries against that service instead of checking against -gdm-password directly. - -Of course, right now, _mainService is always gdm-password. - -https://bugzilla.gnome.org/show_bug.cgi?id=683437 ---- - js/gdm/util.js | 35 ++++++++++++++++++++++++----------- - 1 file changed, 24 insertions(+), 11 deletions(-) - -diff --git a/js/gdm/util.js b/js/gdm/util.js -index 9557c66..eba8b27 100644 ---- a/js/gdm/util.js -+++ b/js/gdm/util.js -@@ -89,60 +89,61 @@ function cloneAndFadeOutActor(actor) { - reactive: false }); - - Main.uiGroup.add_child(clone); - - let [x, y] = actor.get_transformed_position(); - clone.set_position(x, y); - - let hold = new Batch.Hold(); - Tweener.addTween(clone, - { opacity: 0, - time: CLONE_FADE_ANIMATION_TIME, - transition: 'easeOutQuad', - onComplete: function() { - clone.destroy(); - hold.release(); - } - }); - return hold; - } - - const ShellUserVerifier = new Lang.Class({ - Name: 'ShellUserVerifier', - - _init: function(client, params) { - params = Params.parse(params, { reauthenticationOnly: false }); - this._reauthOnly = params.reauthenticationOnly; - - this._client = client; - - this._settings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA }); -+ this._updateDefaultService(); - - this._fprintManager = new Fprint.FprintManager(); - this._messageQueue = []; - this._messageQueueTimeoutId = 0; - this.hasPendingMessages = false; - this.reauthenticating = false; - - this._failCounter = 0; - }, - - begin: function(userName, hold) { - this._cancellable = new Gio.Cancellable(); - this._hold = hold; - this._userName = userName; - this.reauthenticating = false; - - this._checkForFingerprintReader(); - - if (userName) { - // If possible, reauthenticate an already running session, - // so any session specific credentials get updated appropriately - this._client.open_reauthentication_channel(userName, this._cancellable, - Lang.bind(this, this._reauthenticationChannelOpened)); - } else { - this._client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot)); - } - }, - - cancel: function() { - if (this._cancellable) -@@ -275,193 +276,205 @@ const ShellUserVerifier = new Lang.Class({ - this._connectSignals(); - this._beginVerification(); - this._hold.release(); - }, - - _userVerifierGot: function(client, result) { - try { - this._userVerifier = client.get_user_verifier_finish(result); - } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - return; - } catch(e) { - this._reportInitError('Failed to obtain user verifier', e); - return; - } - - this._connectSignals(); - this._beginVerification(); - this._hold.release(); - }, - - _connectSignals: function() { - this._userVerifier.connect('info', Lang.bind(this, this._onInfo)); - this._userVerifier.connect('problem', Lang.bind(this, this._onProblem)); - this._userVerifier.connect('info-query', Lang.bind(this, this._onInfoQuery)); - this._userVerifier.connect('secret-info-query', Lang.bind(this, this._onSecretInfoQuery)); - this._userVerifier.connect('conversation-stopped', Lang.bind(this, this._onConversationStopped)); - this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); - this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); - }, - -+ _getForegroundService: function() { -+ // For now, the foreground service is always the default service -+ return this._defaultService; -+ }, -+ -+ serviceIsForeground: function(serviceName) { -+ return serviceName == this._getForegroundService(); -+ }, -+ -+ _updateDefaultService: function() { -+ // For now, the default service is always the password service -+ this._defaultService = PASSWORD_SERVICE_NAME; -+ }, -+ - _beginVerification: function() { - this._hold.acquire(); - - if (this._userName) { -- this._userVerifier.call_begin_verification_for_user(PASSWORD_SERVICE_NAME, -+ this._userVerifier.call_begin_verification_for_user(this._getForegroundService(), - this._userName, - this._cancellable, - Lang.bind(this, function(obj, result) { - try { - obj.call_begin_verification_for_user_finish(result); - } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - return; - } catch(e) { - this._reportInitError('Failed to start verification for user', e); - return; - } - - this._hold.release(); - })); - - if (this._haveFingerprintReader) { - this._hold.acquire(); - - this._userVerifier.call_begin_verification_for_user(FINGERPRINT_SERVICE_NAME, - this._userName, - this._cancellable, - Lang.bind(this, function(obj, result) { - try { - obj.call_begin_verification_for_user_finish(result); - } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - return; - } catch(e) { - this._reportInitError('Failed to start fingerprint verification for user', e); - return; - } - - this._hold.release(); - })); - } - } else { -- this._userVerifier.call_begin_verification(PASSWORD_SERVICE_NAME, -+ this._userVerifier.call_begin_verification(this._getForegroundService(), - this._cancellable, - Lang.bind(this, function(obj, result) { - try { - obj.call_begin_verification_finish(result); - } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - return; - } catch(e) { - this._reportInitError('Failed to start verification', e); - return; - } - - this._hold.release(); - })); - } - }, - - _onInfo: function(client, serviceName, info) { - // We don't display fingerprint messages, because they - // have words like UPEK in them. Instead we use the messages - // as a cue to display our own message. - if (serviceName == FINGERPRINT_SERVICE_NAME && - this._haveFingerprintReader) { - - // Translators: this message is shown below the password entry field - // to indicate the user can swipe their finger instead - this.emit('show-login-hint', _("(or swipe finger)")); -- } else if (serviceName == PASSWORD_SERVICE_NAME) { -+ } else if (this.serviceIsForeground(serviceName)) { - this._queueMessage(info, 'login-dialog-message-info'); - } - }, - - _onProblem: function(client, serviceName, problem) { -- // we don't want to show auth failed messages to -- // users who haven't enrolled their fingerprint. -- if (serviceName != PASSWORD_SERVICE_NAME) -+ if (!this.serviceIsForeground(serviceName)) - return; -+ - this._queueMessage(problem, 'login-dialog-message-warning'); - }, - - _onInfoQuery: function(client, serviceName, question) { -- // We only expect questions to come from the main auth service -- if (serviceName != PASSWORD_SERVICE_NAME) -+ if (!this.serviceIsForeground(serviceName)) - return; - - this.emit('ask-question', serviceName, question, ''); - }, - - _onSecretInfoQuery: function(client, serviceName, secretQuestion) { -- // We only expect secret requests to come from the main auth service -- if (serviceName != PASSWORD_SERVICE_NAME) -+ if (!this.serviceIsForeground(serviceName)) - return; - - this.emit('ask-question', serviceName, secretQuestion, '\u25cf'); - }, - - _onReset: function() { - // Clear previous attempts to authenticate - this._failCounter = 0; -+ this._updateDefaultService(); - - this.emit('reset'); - }, - - _onVerificationComplete: function() { - this.emit('verification-complete'); - }, - - _cancelAndReset: function() { - this.cancel(); - this._onReset(); - }, - - _retry: function() { - this.begin(this._userName, new Batch.Hold()); - }, - - _verificationFailed: function(retry) { - // For Not Listed / enterprise logins, immediately reset - // the dialog - // Otherwise, we allow ALLOWED_FAILURES attempts. After that, we - // go back to the welcome screen. - - this._failCounter++; - let canRetry = retry && this._userName && - this._failCounter < this._settings.get_int(ALLOWED_FAILURES_KEY); - - if (canRetry) { - if (!this.hasPendingMessages) { - this._retry(); - } else { - let signalId = this.connect('no-more-messages', - Lang.bind(this, function() { - this.disconnect(signalId); - this._retry(); - })); - } - } else { - if (!this.hasPendingMessages) { - this._cancelAndReset(); - } else { - let signalId = this.connect('no-more-messages', - Lang.bind(this, function() { - this.disconnect(signalId); - this._cancelAndReset(); - })); - } - } - - this.emit('verification-failed'); - }, - - _onConversationStopped: function(client, serviceName) { - // if the password service fails, then cancel everything. - // But if, e.g., fingerprint fails, still give - // password authentication a chance to succeed -- if (serviceName == PASSWORD_SERVICE_NAME) { -+ if (this.serviceIsForeground(serviceName)) { - this._verificationFailed(true); - } - - this.emit('hide-login-hint'); - }, - }); - Signals.addSignalMethods(ShellUserVerifier.prototype); --- -1.8.3.1 - - -From f3dd2a7bfd911de064555b4b69626b2262f25eec Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Mon, 29 Jul 2013 14:23:45 -0400 -Subject: [PATCH 37/69] gdmUtil: pave way for fingeprint to optionally be - default auth service - -Currently, fingerprint authentication is always a secondary thing. -If a user wants to swipe their finger when the computer is asking -for a password, so be it. - -This commit paves the way for making fingerprint auth optionally -be the main way to authenticate. Currently there's no way to enable -this, but in a future commit will honor - -enable-password-authentication=false - -in gsettings. - -https://bugzilla.gnome.org/show_bug.cgi?id=683437 ---- - js/gdm/util.js | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/js/gdm/util.js b/js/gdm/util.js -index eba8b27..f41b2b2 100644 ---- a/js/gdm/util.js -+++ b/js/gdm/util.js -@@ -348,71 +348,71 @@ const ShellUserVerifier = new Lang.Class({ - obj.call_begin_verification_for_user_finish(result); - } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - return; - } catch(e) { - this._reportInitError('Failed to start fingerprint verification for user', e); - return; - } - - this._hold.release(); - })); - } - } else { - this._userVerifier.call_begin_verification(this._getForegroundService(), - this._cancellable, - Lang.bind(this, function(obj, result) { - try { - obj.call_begin_verification_finish(result); - } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - return; - } catch(e) { - this._reportInitError('Failed to start verification', e); - return; - } - - this._hold.release(); - })); - } - }, - - _onInfo: function(client, serviceName, info) { -- // We don't display fingerprint messages, because they -- // have words like UPEK in them. Instead we use the messages -- // as a cue to display our own message. -- if (serviceName == FINGERPRINT_SERVICE_NAME && -+ if (this.serviceIsForeground(serviceName)) { -+ this._queueMessage(info, 'login-dialog-message-info'); -+ } else if (serviceName == FINGERPRINT_SERVICE_NAME && - this._haveFingerprintReader) { -+ // We don't show fingerprint messages directly since it's -+ // not the main auth service. Instead we use the messages -+ // as a cue to display our own message. - - // Translators: this message is shown below the password entry field - // to indicate the user can swipe their finger instead - this.emit('show-login-hint', _("(or swipe finger)")); -- } else if (this.serviceIsForeground(serviceName)) { -- this._queueMessage(info, 'login-dialog-message-info'); - } - }, - - _onProblem: function(client, serviceName, problem) { - if (!this.serviceIsForeground(serviceName)) - return; - - this._queueMessage(problem, 'login-dialog-message-warning'); - }, - - _onInfoQuery: function(client, serviceName, question) { - if (!this.serviceIsForeground(serviceName)) - return; - - this.emit('ask-question', serviceName, question, ''); - }, - - _onSecretInfoQuery: function(client, serviceName, secretQuestion) { - if (!this.serviceIsForeground(serviceName)) - return; - - this.emit('ask-question', serviceName, secretQuestion, '\u25cf'); - }, - - _onReset: function() { - // Clear previous attempts to authenticate - this._failCounter = 0; - this._updateDefaultService(); - - this.emit('reset'); --- -1.8.3.1 - - -From 01894a09e35086a8a9f887d56d873c98ee52edb9 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Mon, 29 Jul 2013 14:37:10 -0400 -Subject: [PATCH 38/69] authPrompt: emit prompted when given a message - -Some pam modules prompt without expecting the user to type -an answer back (e.g. "Please swipe finger"). We need to -emit prompted in this case too, so the the dialog will get shown. - -https://bugzilla.gnome.org/show_bug.cgi?id=683437 ---- - js/gdm/authPrompt.js | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index e987d25..3f5e4fe 100644 ---- a/js/gdm/authPrompt.js -+++ b/js/gdm/authPrompt.js -@@ -200,60 +200,61 @@ const AuthPrompt = new Lang.Class({ - return; - } - - if (this._queryingService) - this.clear(); - - this._queryingService = serviceName; - this.setPasswordChar(passwordChar); - this.setQuestion(question); - - if (this.verifyingUser) - this.cancelButton.show(); - else - this.cancelButton.hide(); - - if (passwordChar) { - if (this._userVerifier.reauthenticating) - this.nextButton.label = _("Unlock"); - else - this.nextButton.label = C_("button", "Sign In"); - } else { - this.nextButton.label = _("Next"); - } - - this.updateSensitivity(true); - this.emit('prompted'); - }, - - _onShowMessage: function(userVerifier, message, styleClass) { - this.setMessage(message, styleClass); -+ this.emit('prompted'); - }, - - _onVerificationFailed: function() { - this.clear(); - - this.updateSensitivity(true); - this.setActorInDefaultButtonWell(null); - this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED; - }, - - _onVerificationComplete: function() { - this.verificationStatus = AuthPromptStatus.VERIFICATION_SUCCEEDED; - }, - - _onReset: function() { - if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) { - this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; - this.reset(); - } - }, - - _onShowLoginHint: function(verifier, message) { - this.setHint(message); - }, - - _onHideLoginHint: function() { - this.setHint(null); - }, - - addActorToDefaultButtonWell: function(actor) { --- -1.8.3.1 - - -From 893a0a63e1b9fd911ef17c7f72ade6f92121cb2d Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Fri, 16 Aug 2013 10:29:26 -0400 -Subject: [PATCH 39/69] gdmUtil: factor out some duplicated code in - beginVerification - -The duplication makes the function look a lot more complicated -than it actually is. - -This commit moves the common code to a new _startService function. - -https://bugzilla.gnome.org/show_bug.cgi?id=683437 ---- - js/gdm/util.js | 73 +++++++++++++++++----------------------------------------- - 1 file changed, 21 insertions(+), 52 deletions(-) - -diff --git a/js/gdm/util.js b/js/gdm/util.js -index f41b2b2..acab471 100644 ---- a/js/gdm/util.js -+++ b/js/gdm/util.js -@@ -290,115 +290,84 @@ const ShellUserVerifier = new Lang.Class({ - - this._connectSignals(); - this._beginVerification(); - this._hold.release(); - }, - - _connectSignals: function() { - this._userVerifier.connect('info', Lang.bind(this, this._onInfo)); - this._userVerifier.connect('problem', Lang.bind(this, this._onProblem)); - this._userVerifier.connect('info-query', Lang.bind(this, this._onInfoQuery)); - this._userVerifier.connect('secret-info-query', Lang.bind(this, this._onSecretInfoQuery)); - this._userVerifier.connect('conversation-stopped', Lang.bind(this, this._onConversationStopped)); - this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); - this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); - }, - - _getForegroundService: function() { - // For now, the foreground service is always the default service - return this._defaultService; - }, - - serviceIsForeground: function(serviceName) { - return serviceName == this._getForegroundService(); - }, - - _updateDefaultService: function() { - // For now, the default service is always the password service - this._defaultService = PASSWORD_SERVICE_NAME; - }, - -- _beginVerification: function() { -+ _startService: function(serviceName) { - this._hold.acquire(); -+ this._userVerifier.call_begin_verification_for_user(serviceName, -+ this._userName, -+ this._cancellable, -+ Lang.bind(this, function(obj, result) { -+ try { -+ obj.call_begin_verification_for_user_finish(result); -+ } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { -+ return; -+ } catch(e) { -+ this._reportInitError('Failed to start verification for user', e); -+ return; -+ } - -- if (this._userName) { -- this._userVerifier.call_begin_verification_for_user(this._getForegroundService(), -- this._userName, -- this._cancellable, -- Lang.bind(this, function(obj, result) { -- try { -- obj.call_begin_verification_for_user_finish(result); -- } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { -- return; -- } catch(e) { -- this._reportInitError('Failed to start verification for user', e); -- return; -- } -- -- this._hold.release(); -- })); -+ this._hold.release(); -+ })); -+ }, - -- if (this._haveFingerprintReader) { -- this._hold.acquire(); -- -- this._userVerifier.call_begin_verification_for_user(FINGERPRINT_SERVICE_NAME, -- this._userName, -- this._cancellable, -- Lang.bind(this, function(obj, result) { -- try { -- obj.call_begin_verification_for_user_finish(result); -- } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { -- return; -- } catch(e) { -- this._reportInitError('Failed to start fingerprint verification for user', e); -- return; -- } -- -- this._hold.release(); -- })); -- } -- } else { -- this._userVerifier.call_begin_verification(this._getForegroundService(), -- this._cancellable, -- Lang.bind(this, function(obj, result) { -- try { -- obj.call_begin_verification_finish(result); -- } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { -- return; -- } catch(e) { -- this._reportInitError('Failed to start verification', e); -- return; -- } -- -- this._hold.release(); -- })); -- } -+ _beginVerification: function() { -+ this._startService(this._getForegroundService()); -+ -+ if (this._userName && this._haveFingerprintReader) -+ this._startService(FINGERPRINT_SERVICE_NAME); - }, - - _onInfo: function(client, serviceName, info) { - if (this.serviceIsForeground(serviceName)) { - this._queueMessage(info, 'login-dialog-message-info'); - } else if (serviceName == FINGERPRINT_SERVICE_NAME && - this._haveFingerprintReader) { - // We don't show fingerprint messages directly since it's - // not the main auth service. Instead we use the messages - // as a cue to display our own message. - - // Translators: this message is shown below the password entry field - // to indicate the user can swipe their finger instead - this.emit('show-login-hint', _("(or swipe finger)")); - } - }, - - _onProblem: function(client, serviceName, problem) { - if (!this.serviceIsForeground(serviceName)) - return; - - this._queueMessage(problem, 'login-dialog-message-warning'); - }, - - _onInfoQuery: function(client, serviceName, question) { - if (!this.serviceIsForeground(serviceName)) - return; - - this.emit('ask-question', serviceName, question, ''); - }, --- -1.8.3.1 - - -From 85dc68df12383429c03292684170c1419045ea9a Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Mon, 29 Jul 2013 14:18:30 -0400 -Subject: [PATCH 40/69] gdmUtil: support disabling password authentication - -This commit skips trying password authentication if it's -disallowed, favoring fingerprint login instead. - -https://bugzilla.gnome.org/show_bug.cgi?id=683437 ---- - js/gdm/util.js | 16 ++++++++++++---- - 1 file changed, 12 insertions(+), 4 deletions(-) - -diff --git a/js/gdm/util.js b/js/gdm/util.js -index acab471..a7b8b62 100644 ---- a/js/gdm/util.js -+++ b/js/gdm/util.js -@@ -1,53 +1,54 @@ - // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - - const Clutter = imports.gi.Clutter; - const Gio = imports.gi.Gio; - const GLib = imports.gi.GLib; - const Lang = imports.lang; - const Mainloop = imports.mainloop; - const Signals = imports.signals; - const St = imports.gi.St; - - const Batch = imports.gdm.batch; - const Fprint = imports.gdm.fingerprint; - const Main = imports.ui.main; - const Params = imports.misc.params; - const ShellEntry = imports.ui.shellEntry; - const Tweener = imports.ui.tweener; - - const PASSWORD_SERVICE_NAME = 'gdm-password'; - const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint'; - const FADE_ANIMATION_TIME = 0.16; - const CLONE_FADE_ANIMATION_TIME = 0.25; - - const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen'; -+const PASSWORD_AUTHENTICATION_KEY = 'enable-password-authentication'; - const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication'; - const BANNER_MESSAGE_KEY = 'banner-message-enable'; - const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text'; - const ALLOWED_FAILURES_KEY = 'allowed-failures'; - - const LOGO_KEY = 'logo'; - const DISABLE_USER_LIST_KEY = 'disable-user-list'; - - // Give user 16ms to read each character of a PAM message - const USER_READ_TIME = 16 - - function fadeInActor(actor) { - if (actor.opacity == 255 && actor.visible) - return null; - - let hold = new Batch.Hold(); - actor.show(); - let [minHeight, naturalHeight] = actor.get_preferred_height(-1); - - actor.opacity = 0; - actor.set_height(0); - Tweener.addTween(actor, - { opacity: 255, - height: naturalHeight, - time: FADE_ANIMATION_TIME, - transition: 'easeOutQuad', - onComplete: function() { - this.set_height(-1); - hold.release(); - }, -@@ -89,60 +90,62 @@ function cloneAndFadeOutActor(actor) { - reactive: false }); - - Main.uiGroup.add_child(clone); - - let [x, y] = actor.get_transformed_position(); - clone.set_position(x, y); - - let hold = new Batch.Hold(); - Tweener.addTween(clone, - { opacity: 0, - time: CLONE_FADE_ANIMATION_TIME, - transition: 'easeOutQuad', - onComplete: function() { - clone.destroy(); - hold.release(); - } - }); - return hold; - } - - const ShellUserVerifier = new Lang.Class({ - Name: 'ShellUserVerifier', - - _init: function(client, params) { - params = Params.parse(params, { reauthenticationOnly: false }); - this._reauthOnly = params.reauthenticationOnly; - - this._client = client; - - this._settings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA }); -+ this._settings.connect('changed', -+ Lang.bind(this, this._updateDefaultService)); - this._updateDefaultService(); - - this._fprintManager = new Fprint.FprintManager(); - this._messageQueue = []; - this._messageQueueTimeoutId = 0; - this.hasPendingMessages = false; - this.reauthenticating = false; - - this._failCounter = 0; - }, - - begin: function(userName, hold) { - this._cancellable = new Gio.Cancellable(); - this._hold = hold; - this._userName = userName; - this.reauthenticating = false; - - this._checkForFingerprintReader(); - - if (userName) { - // If possible, reauthenticate an already running session, - // so any session specific credentials get updated appropriately - this._client.open_reauthentication_channel(userName, this._cancellable, - Lang.bind(this, this._reauthenticationChannelOpened)); - } else { - this._client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot)); - } - }, - - cancel: function() { -@@ -210,67 +213,70 @@ const ShellUserVerifier = new Lang.Class({ - - this._messageQueueTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, - message.interval, - Lang.bind(this, function() { - this._messageQueueTimeoutId = 0; - this._queueMessageTimeout(); - })); - }, - - _queueMessage: function(message, iconName) { - let interval = this._getIntervalForMessage(message); - - this.hasPendingMessages = true; - this._messageQueue.push({ text: message, interval: interval, iconName: iconName }); - this._queueMessageTimeout(); - }, - - _clearMessageQueue: function() { - this.finishMessageQueue(); - - if (this._messageQueueTimeoutId != 0) { - GLib.source_remove(this._messageQueueTimeoutId); - this._messageQueueTimeoutId = 0; - } - this.emit('show-message', null, null); - }, - - _checkForFingerprintReader: function() { - this._haveFingerprintReader = false; - -- if (!this._settings.get_boolean(FINGERPRINT_AUTHENTICATION_KEY)) -+ if (!this._settings.get_boolean(FINGERPRINT_AUTHENTICATION_KEY)) { -+ this._updateDefaultService(); - return; -+ } - - this._fprintManager.GetDefaultDeviceRemote(Gio.DBusCallFlags.NONE, this._cancellable, Lang.bind(this, - function(device, error) { - if (!error && device) - this._haveFingerprintReader = true; -+ this._updateDefaultService(); - })); - }, - - _reportInitError: function(where, error) { - logError(error, where); - this._hold.release(); - - this._queueMessage(_("Authentication error"), 'login-dialog-message-warning'); - this._verificationFailed(false); - }, - - _reauthenticationChannelOpened: function(client, result) { - try { - this._userVerifier = client.open_reauthentication_channel_finish(result); - } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - return; - } catch(e if e.matches(Gio.DBusError, Gio.DBusError.ACCESS_DENIED) && - !this._reauthOnly) { - // Gdm emits org.freedesktop.DBus.Error.AccessDenied when there is - // no session to reauthenticate. Fall back to performing verification - // from this login session - client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot)); - return; - } catch(e) { - this._reportInitError('Failed to open reauthentication channel', e); - return; - } - - this.reauthenticating = true; - this._connectSignals(); -@@ -286,87 +292,89 @@ const ShellUserVerifier = new Lang.Class({ - } catch(e) { - this._reportInitError('Failed to obtain user verifier', e); - return; - } - - this._connectSignals(); - this._beginVerification(); - this._hold.release(); - }, - - _connectSignals: function() { - this._userVerifier.connect('info', Lang.bind(this, this._onInfo)); - this._userVerifier.connect('problem', Lang.bind(this, this._onProblem)); - this._userVerifier.connect('info-query', Lang.bind(this, this._onInfoQuery)); - this._userVerifier.connect('secret-info-query', Lang.bind(this, this._onSecretInfoQuery)); - this._userVerifier.connect('conversation-stopped', Lang.bind(this, this._onConversationStopped)); - this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); - this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); - }, - - _getForegroundService: function() { - // For now, the foreground service is always the default service - return this._defaultService; - }, - - serviceIsForeground: function(serviceName) { - return serviceName == this._getForegroundService(); - }, - - _updateDefaultService: function() { -- // For now, the default service is always the password service -- this._defaultService = PASSWORD_SERVICE_NAME; -+ if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY)) -+ this._defaultService = PASSWORD_SERVICE_NAME; -+ else if (this._haveFingerprintReader) -+ this._defaultService = FINGERPRINT_SERVICE_NAME; - }, - - _startService: function(serviceName) { - this._hold.acquire(); - this._userVerifier.call_begin_verification_for_user(serviceName, - this._userName, - this._cancellable, - Lang.bind(this, function(obj, result) { - try { - obj.call_begin_verification_for_user_finish(result); - } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - return; - } catch(e) { - this._reportInitError('Failed to start verification for user', e); - return; - } - - this._hold.release(); - })); - }, - - _beginVerification: function() { - this._startService(this._getForegroundService()); - -- if (this._userName && this._haveFingerprintReader) -+ if (this._userName && this._haveFingerprintReader && !this.serviceIsForeground(FINGERPRINT_SERVICE_NAME)) - this._startService(FINGERPRINT_SERVICE_NAME); - }, - - _onInfo: function(client, serviceName, info) { - if (this.serviceIsForeground(serviceName)) { - this._queueMessage(info, 'login-dialog-message-info'); - } else if (serviceName == FINGERPRINT_SERVICE_NAME && - this._haveFingerprintReader) { - // We don't show fingerprint messages directly since it's - // not the main auth service. Instead we use the messages - // as a cue to display our own message. - - // Translators: this message is shown below the password entry field - // to indicate the user can swipe their finger instead - this.emit('show-login-hint', _("(or swipe finger)")); - } - }, - - _onProblem: function(client, serviceName, problem) { - if (!this.serviceIsForeground(serviceName)) - return; - - this._queueMessage(problem, 'login-dialog-message-warning'); - }, - - _onInfoQuery: function(client, serviceName, question) { - if (!this.serviceIsForeground(serviceName)) - return; - - this.emit('ask-question', serviceName, question, ''); --- -1.8.3.1 - - -From ebb92fbc5adb2534c1a5d5604c76a515d8f73da7 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Thu, 30 May 2013 10:15:09 -0400 -Subject: [PATCH 41/69] misc: add objectManager class - -The D-Bus ObjectManager interface is fairly recent addition to the -D-Bus specification. Its purpose is to provide a standardized way -to track objects dynamically coming and going for a service, and -to track capabilities dynamically coming and going for those objects -(by means of interfaces). - -This commit adds the requisite code needed to make use of the -ObjectManager interface. - -It will ultimately be needed to implement smartcard support in the -login screen. - -https://bugzilla.gnome.org/show_bug.cgi?id=683437 ---- - js/Makefile.am | 1 + - js/misc/objectManager.js | 254 +++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 255 insertions(+) - create mode 100644 js/misc/objectManager.js - -diff --git a/js/Makefile.am b/js/Makefile.am -index 57f08e2..8740678 100644 ---- a/js/Makefile.am -+++ b/js/Makefile.am -@@ -7,60 +7,61 @@ misc/config.js: misc/config.js.in Makefile - [ -d $(@D) ] || $(mkdir_p) $(@D) ; \ - sed -e "s|[@]PACKAGE_NAME@|$(PACKAGE_NAME)|g" \ - -e "s|[@]PACKAGE_VERSION@|$(PACKAGE_VERSION)|g" \ - -e "s|[@]HAVE_BLUETOOTH@|$(HAVE_BLUETOOTH)|g" \ - -e "s|[@]GETTEXT_PACKAGE@|$(GETTEXT_PACKAGE)|g" \ - -e "s|[@]datadir@|$(datadir)|g" \ - -e "s|[@]libexecdir@|$(libexecdir)|g" \ - -e "s|[@]sysconfdir@|$(sysconfdir)|g" \ - $< > $@ - - jsdir = $(pkgdatadir)/js - - nobase_dist_js_DATA = \ - gdm/authPrompt.js \ - gdm/batch.js \ - gdm/fingerprint.js \ - gdm/loginDialog.js \ - gdm/powerMenu.js \ - gdm/realmd.js \ - gdm/util.js \ - extensionPrefs/main.js \ - misc/config.js \ - misc/extensionUtils.js \ - misc/fileUtils.js \ - misc/gnomeSession.js \ - misc/hash.js \ - misc/history.js \ - misc/jsParse.js \ - misc/loginManager.js \ - misc/modemManager.js \ -+ misc/objectManager.js \ - misc/params.js \ - misc/util.js \ - perf/core.js \ - ui/altTab.js \ - ui/appDisplay.js \ - ui/appFavorites.js \ - ui/backgroundMenu.js \ - ui/background.js \ - ui/boxpointer.js \ - ui/calendar.js \ - ui/checkBox.js \ - ui/ctrlAltTab.js \ - ui/dash.js \ - ui/dateMenu.js \ - ui/dnd.js \ - ui/endSessionDialog.js \ - ui/extensionSystem.js \ - ui/extensionDownloader.js \ - ui/environment.js \ - ui/ibusCandidatePopup.js\ - ui/grabHelper.js \ - ui/iconGrid.js \ - ui/keyboard.js \ - ui/layout.js \ - ui/lightbox.js \ - ui/lookingGlass.js \ - ui/magnifier.js \ - ui/magnifierDBus.js \ - ui/main.js \ - ui/messageTray.js \ -diff --git a/js/misc/objectManager.js b/js/misc/objectManager.js -new file mode 100644 -index 0000000..b954f1b ---- /dev/null -+++ b/js/misc/objectManager.js -@@ -0,0 +1,254 @@ -+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -+ -+const Gio = imports.gi.Gio; -+const GLib = imports.gi.GLib; -+const Lang = imports.lang; -+const Params = imports.misc.params; -+const Signals = imports.signals; -+ -+// Specified in the D-Bus specification here: -+// http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager -+const ObjectManagerIface = -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+const ObjectManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(ObjectManagerIface); -+ -+const ObjectManager = new Lang.Class({ -+ Name: 'ObjectManager', -+ _init: function(params) { -+ params = Params.parse(params, { connection: null, -+ name: null, -+ objectPath: null, -+ knownInterfaces: null, -+ cancellable: null, -+ onLoaded: null }); -+ -+ this._connection = params.connection; -+ this._serviceName = params.name; -+ this._managerPath = params.objectPath; -+ this._cancellable = params.cancellable; -+ -+ this._managerProxy = new Gio.DBusProxy({ g_connection: this._connection, -+ g_interface_name: ObjectManagerInfo.name, -+ g_interface_info: ObjectManagerInfo, -+ g_name: this._serviceName, -+ g_object_path: this._managerPath, -+ g_flags: Gio.DBusProxyFlags.NONE }); -+ -+ this._interfaceInfos = {}; -+ this._objects = {}; -+ this._interfaces = {}; -+ this._onLoaded = params.onLoaded; -+ -+ if (params.knownInterfaces) -+ this._registerInterfaces(params.knownInterfaces); -+ -+ // Start out inhibiting load until at least the proxy -+ // manager is loaded and the remote objects are fetched -+ this._numLoadInhibitors = 1; -+ this._managerProxy.init_async(GLib.PRIORITY_DEFAULT, -+ this._cancellable, -+ Lang.bind(this, this._onManagerProxyLoaded)); -+ }, -+ -+ _tryToCompleteLoad: function() { -+ this._numLoadInhibitors--; -+ if (this._numLoadInhibitors == 0) { -+ if (this._onLoaded) -+ this._onLoaded(); -+ } -+ }, -+ -+ _addInterface: function(objectPath, interfaceName, onFinished) { -+ let info = this._interfaceInfos[interfaceName]; -+ -+ if (!info) -+ return; -+ -+ let proxy = new Gio.DBusProxy({ g_connection: this._connection, -+ g_name: this._serviceName, -+ g_object_path: objectPath, -+ g_interface_name: interfaceName, -+ g_interface_info: info, -+ g_flags: Gio.DBusProxyFlags.NONE }); -+ -+ proxy.init_async(GLib.PRIORITY_DEFAULT, -+ this._cancellable, -+ Lang.bind(this, function(initable, result) { -+ let error = null; -+ try { -+ initable.init_finish(result); -+ } catch(e) { -+ logError(e, 'could not initialize proxy for interface ' + interfaceName); -+ -+ if (onFinished) -+ onFinished(); -+ return; -+ } -+ -+ let isNewObject; -+ if (!this._objects[objectPath]) { -+ this._objects[objectPath] = {}; -+ isNewObject = true; -+ } else { -+ isNewObject = false; -+ } -+ -+ this._objects[objectPath][interfaceName] = proxy; -+ -+ if (!this._interfaces[interfaceName]) -+ this._interfaces[interfaceName] = []; -+ -+ this._interfaces[interfaceName].push(proxy); -+ -+ if (isNewObject) -+ this.emit('object-added', objectPath); -+ -+ this.emit('interface-added', interfaceName, proxy); -+ -+ if (onFinished) -+ onFinished(); -+ })); -+ }, -+ -+ _removeInterface: function(objectPath, interfaceName) { -+ if (!this._objects[objectPath]) -+ return; -+ -+ let proxy = this._objects[objectPath][interfaceName]; -+ -+ if (this._interfaces[interfaceName]) { -+ let index = this._interfaces[interfaceName].indexOf(proxy); -+ -+ if (index >= 0) -+ this._interfaces[interfaceName].splice(index, 1); -+ -+ if (this._interfaces[interfaceName].length == 0) -+ delete this._interfaces[interfaceName]; -+ } -+ -+ this.emit('interface-removed', interfaceName, proxy); -+ -+ this._objects[objectPath][interfaceName] = null; -+ -+ if (Object.keys(this._objects[objectPath]).length == 0) { -+ delete this._objects[objectPath]; -+ this.emit('object-removed', objectPath); -+ } -+ }, -+ -+ _onManagerProxyLoaded: function(initable, result) { -+ let error = null; -+ try { -+ initable.init_finish(result); -+ } catch(e) { -+ logError(e, 'could not initialize object manager for object ' + params.name); -+ -+ this._tryToCompleteLoad(); -+ return; -+ } -+ -+ this._managerProxy.connectSignal('InterfacesAdded', -+ Lang.bind(this, function(objectManager, sender, [objectPath, interfaces]) { -+ let interfaceNames = Object.keys(interfaces); -+ for (let i = 0; i < interfaceNames.length; i++) -+ this._addInterface(objectPath, interfaceNames[i]); -+ })); -+ this._managerProxy.connectSignal('InterfacesRemoved', -+ Lang.bind(this, function(objectManager, sender, [objectPath, interfaceNames]) { -+ for (let i = 0; i < interfaceNames.length; i++) -+ this._removeInterface(objectPath, interfaceNames[i]); -+ })); -+ -+ if (Object.keys(this._interfaceInfos).length == 0) { -+ this._tryToCompleteLoad(); -+ return; -+ } -+ -+ this._managerProxy.GetManagedObjectsRemote(Lang.bind(this, function(result, error) { -+ if (!result) { -+ if (error) { -+ logError(error, 'could not get remote objects for service ' + this._serviceName + ' path ' + this._managerPath); -+ } -+ -+ this._tryToCompleteLoad(); -+ return; -+ } -+ -+ let [objects] = result; -+ -+ let objectPaths = Object.keys(objects); -+ for (let i = 0; i < objectPaths.length; i++) { -+ let objectPath = objectPaths[i]; -+ let object = objects[objectPath]; -+ -+ let interfaceNames = Object.getOwnPropertyNames(object); -+ for (let j = 0; j < interfaceNames.length; j++) { -+ let interfaceName = interfaceNames[j]; -+ -+ // Prevent load from completing until the interface is loaded -+ this._numLoadInhibitors++; -+ this._addInterface(objectPath, -+ interfaceName, -+ Lang.bind(this, this._tryToCompleteLoad)); -+ } -+ } -+ this._tryToCompleteLoad(); -+ })); -+ }, -+ -+ _registerInterfaces: function(interfaces) { -+ for (let i = 0; i < interfaces.length; i++) { -+ let info = Gio.DBusInterfaceInfo.new_for_xml(interfaces[i]); -+ this._interfaceInfos[info.name] = info; -+ } -+ }, -+ -+ getProxy: function(objectPath, interfaceName) { -+ let object = this._objects[objectPath]; -+ -+ if (!object) -+ return null; -+ -+ return object[interfaceName]; -+ }, -+ -+ getProxiesForInterface: function(interfaceName) { -+ let proxyList = this._interfaces[interfaceName]; -+ -+ if (!proxyList) -+ return []; -+ -+ return proxyList; -+ }, -+ -+ getAllProxies: function() { -+ let proxies = []; -+ -+ let objectPaths = Object.keys(this._objects); -+ for (let i = 0; i < objectPaths.length; i++) { -+ let object = this._objects[objectPaths]; -+ -+ let interfaceNames = Object.keys(object); -+ for (let j = 0; i < interfaceNames.length; i++) { -+ let interfaceName = interfaceNames[i]; -+ if (object[interfaceName]) -+ proxies.push(object(interfaceName)); -+ } -+ } -+ -+ return proxies; -+ } -+}); -+Signals.addSignalMethods(ObjectManager.prototype); --- -1.8.3.1 - - -From 71c033d5b31daa0b5bcef155d1c8aee9405d8b10 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Thu, 30 May 2013 10:18:51 -0400 -Subject: [PATCH 42/69] misc: add code to use settings-daemon smartcard service - -gnome-settings-daemon monitors smartcard insertion and removal -events on the system and then exports a model of the current -smartcard topology over the bus using the D-Bus ObjectManager interface. - -This commit adds the support code needed in gnome-shell to talk to -the gnome-settings-daemon service. - -A future commit will use this code to inform the login screen -when a user inserts a smartcard (so it can react appropriately) - -https://bugzilla.gnome.org/show_bug.cgi?id=683437 ---- - js/Makefile.am | 1 + - js/misc/smartcardManager.js | 117 ++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 118 insertions(+) - create mode 100644 js/misc/smartcardManager.js - -diff --git a/js/Makefile.am b/js/Makefile.am -index 8740678..425b6fb 100644 ---- a/js/Makefile.am -+++ b/js/Makefile.am -@@ -9,60 +9,61 @@ misc/config.js: misc/config.js.in Makefile - -e "s|[@]PACKAGE_VERSION@|$(PACKAGE_VERSION)|g" \ - -e "s|[@]HAVE_BLUETOOTH@|$(HAVE_BLUETOOTH)|g" \ - -e "s|[@]GETTEXT_PACKAGE@|$(GETTEXT_PACKAGE)|g" \ - -e "s|[@]datadir@|$(datadir)|g" \ - -e "s|[@]libexecdir@|$(libexecdir)|g" \ - -e "s|[@]sysconfdir@|$(sysconfdir)|g" \ - $< > $@ - - jsdir = $(pkgdatadir)/js - - nobase_dist_js_DATA = \ - gdm/authPrompt.js \ - gdm/batch.js \ - gdm/fingerprint.js \ - gdm/loginDialog.js \ - gdm/powerMenu.js \ - gdm/realmd.js \ - gdm/util.js \ - extensionPrefs/main.js \ - misc/config.js \ - misc/extensionUtils.js \ - misc/fileUtils.js \ - misc/gnomeSession.js \ - misc/hash.js \ - misc/history.js \ - misc/jsParse.js \ - misc/loginManager.js \ - misc/modemManager.js \ - misc/objectManager.js \ - misc/params.js \ -+ misc/smartcardManager.js \ - misc/util.js \ - perf/core.js \ - ui/altTab.js \ - ui/appDisplay.js \ - ui/appFavorites.js \ - ui/backgroundMenu.js \ - ui/background.js \ - ui/boxpointer.js \ - ui/calendar.js \ - ui/checkBox.js \ - ui/ctrlAltTab.js \ - ui/dash.js \ - ui/dateMenu.js \ - ui/dnd.js \ - ui/endSessionDialog.js \ - ui/extensionSystem.js \ - ui/extensionDownloader.js \ - ui/environment.js \ - ui/ibusCandidatePopup.js\ - ui/grabHelper.js \ - ui/iconGrid.js \ - ui/keyboard.js \ - ui/layout.js \ - ui/lightbox.js \ - ui/lookingGlass.js \ - ui/magnifier.js \ - ui/magnifierDBus.js \ - ui/main.js \ - ui/messageTray.js \ - ui/modalDialog.js \ -diff --git a/js/misc/smartcardManager.js b/js/misc/smartcardManager.js -new file mode 100644 -index 0000000..644b033 ---- /dev/null -+++ b/js/misc/smartcardManager.js -@@ -0,0 +1,117 @@ -+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -+ -+const Gio = imports.gi.Gio; -+const Lang = imports.lang; -+const Shell = imports.gi.Shell; -+const Signals = imports.signals; -+ -+const ObjectManager = imports.misc.objectManager; -+ -+const SmartcardTokenIface = -+ -+ -+ -+ -+; -+ -+let _smartcardManager = null; -+ -+function getSmartcardManager() { -+ if (_smartcardManager == null) -+ _smartcardManager = new SmartcardManager(); -+ -+ return _smartcardManager; -+} -+ -+const SmartcardManager = new Lang.Class({ -+ Name: 'SmartcardManager', -+ _init: function() { -+ this._objectManager = new ObjectManager.ObjectManager({ connection: Gio.DBus.session, -+ name: "org.gnome.SettingsDaemon.Smartcard", -+ objectPath: '/org/gnome/SettingsDaemon/Smartcard', -+ knownInterfaces: [ SmartcardTokenIface ], -+ onLoaded: Lang.bind(this, this._onLoaded) }); -+ this._insertedTokens = {}; -+ this._loginToken = null; -+ }, -+ -+ _onLoaded: function() { -+ let tokens = this._objectManager.getProxiesForInterface('org.gnome.SettingsDaemon.Smartcard.Token'); -+ -+ for (let i = 0; i < tokens.length; i++) -+ this._addToken(tokens[i]); -+ -+ this._objectManager.connect('interface-added', Lang.bind(this, function(objectManager, interfaceName, proxy) { -+ if (interfaceName == 'org.gnome.SettingsDaemon.Smartcard.Token') -+ this._addToken(proxy); -+ })); -+ -+ this._objectManager.connect('interface-removed', Lang.bind(this, function(objectManager, interfaceName, proxy) { -+ if (interfaceName == 'org.gnome.SettingsDaemon.Smartcard.Token') -+ this._removeToken(proxy); -+ })); -+ }, -+ -+ _updateToken: function(token) { -+ let objectPath = token.get_object_path(); -+ -+ delete this._insertedTokens[objectPath]; -+ -+ if (token.IsInserted) -+ this._insertedTokens[objectPath] = token; -+ -+ if (token.UsedToLogin) -+ this._loginToken = token; -+ }, -+ -+ _addToken: function(token) { -+ this._updateToken(token); -+ -+ token.connect('g-properties-changed', -+ Lang.bind(this, function(proxy, properties) { -+ if ('IsInserted' in properties.deep_unpack()) { -+ this._updateToken(token); -+ -+ if (token.IsInserted) { -+ this.emit('smartcard-inserted', token); -+ } else { -+ this.emit('smartcard-removed', token); -+ } -+ } -+ })); -+ -+ // Emit a smartcard-inserted at startup if it's already plugged in -+ if (token.IsInserted) -+ this.emit('smartcard-inserted', token); -+ }, -+ -+ _removeToken: function(token) { -+ let objectPath = token.get_object_path(); -+ -+ if (this._insertedTokens[objectPath] == token) { -+ delete this._insertedTokens[objectPath]; -+ this.emit('smartcard-removed', token); -+ } -+ -+ if (this._loginToken == token) -+ this._loginToken = null; -+ -+ token.disconnectAll(); -+ }, -+ -+ hasInsertedTokens: function() { -+ return Object.keys(this._insertedTokens).length > 0; -+ }, -+ -+ hasInsertedLoginToken: function() { -+ if (!this._loginToken) -+ return false; -+ -+ if (!this._loginToken.IsInserted) -+ return false; -+ -+ return true; -+ } -+ -+}); -+Signals.addSignalMethods(SmartcardManager.prototype); --- -1.8.3.1 - - -From cf8eee82c8603f331a3de0bd7046f352634c7200 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Thu, 27 Jun 2013 08:54:19 -0400 -Subject: [PATCH 43/69] authPrompt: support smartcard authentication - -This commit detects when a user inserts a smartcard, -and then initiates user verification using the gdm-smartcard -PAM service. - -Likewise, if a user removes their smartcard, password verification -(or the user list depending on auth mode and configuration) are initiated - -https://bugzilla.gnome.org/show_bug.cgi?id=683437 ---- - js/gdm/authPrompt.js | 39 ++++++++++++++++++++++++++++++++++++++- - js/gdm/util.js | 48 +++++++++++++++++++++++++++++++++++++++++++++++- - js/ui/screenShield.js | 8 ++++++++ - 3 files changed, 93 insertions(+), 2 deletions(-) - -diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index 3f5e4fe..cfdf052 100644 ---- a/js/gdm/authPrompt.js -+++ b/js/gdm/authPrompt.js -@@ -33,60 +33,62 @@ const AuthPromptStatus = { - - const BeginRequestType = { - PROVIDE_USERNAME: 0, - DONT_PROVIDE_USERNAME: 1 - }; - - const AuthPrompt = new Lang.Class({ - Name: 'AuthPrompt', - - _init: function(gdmClient, mode) { - this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; - - this._gdmClient = gdmClient; - this._mode = mode; - - let reauthenticationOnly; - if (this._mode == AuthPromptMode.UNLOCK_ONLY) - reauthenticationOnly = true; - else if (this._mode == AuthPromptMode.UNLOCK_OR_LOG_IN) - reauthenticationOnly = false; - - this._userVerifier = new GdmUtil.ShellUserVerifier(this._gdmClient, { reauthenticationOnly: reauthenticationOnly }); - - this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion)); - this._userVerifier.connect('show-message', Lang.bind(this, this._onShowMessage)); - this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed)); - this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); - this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); - this._userVerifier.connect('show-login-hint', Lang.bind(this, this._onShowLoginHint)); - this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._onHideLoginHint)); -+ this._userVerifier.connect('smartcard-status-changed', Lang.bind(this, this._onSmartcardStatusChanged)); -+ this.smartcardDetected = this._userVerifier.smartcardDetected; - - this.connect('next', Lang.bind(this, function() { - this.updateSensitivity(false); - this.startSpinning(); - if (this._queryingService) { - this._userVerifier.answerQuery(this._queryingService, this._entry.text); - } else { - this._preemptiveAnswer = this._entry.text; - } - })); - - this.actor = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', - vertical: true }); - this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); - this.actor.connect('key-press-event', - Lang.bind(this, function(actor, event) { - if (event.get_key_symbol() == Clutter.KEY_Escape) { - this.cancel(); - } - })); - - this._userWell = new St.Bin({ x_fill: true, - x_align: St.Align.START }); - this.actor.add(this._userWell, - { x_align: St.Align.START, - x_fill: true, - y_fill: true, - expand: true }); - this._label = new St.Label({ style_class: 'login-dialog-prompt-label' }); - -@@ -198,60 +200,79 @@ const AuthPrompt = new Lang.Class({ - this._userVerifier.answerQuery(this._queryingService, this._preemptiveAnswer); - this._preemptiveAnswer = null; - return; - } - - if (this._queryingService) - this.clear(); - - this._queryingService = serviceName; - this.setPasswordChar(passwordChar); - this.setQuestion(question); - - if (this.verifyingUser) - this.cancelButton.show(); - else - this.cancelButton.hide(); - - if (passwordChar) { - if (this._userVerifier.reauthenticating) - this.nextButton.label = _("Unlock"); - else - this.nextButton.label = C_("button", "Sign In"); - } else { - this.nextButton.label = _("Next"); - } - - this.updateSensitivity(true); - this.emit('prompted'); - }, - -+ _onSmartcardStatusChanged: function() { -+ this.smartcardDetected = this._userVerifier.smartcardDetected; -+ -+ // Most of the time we want to reset if the user inserts or removes -+ // a smartcard. Smartcard insertion "preempts" what the user was -+ // doing, and smartcard removal aborts the preemption. -+ // The exceptions are: 1) Don't reset on smartcard insertion if we're already verifying -+ // with a smartcard -+ // 2) Don't reset if we've already succeeded at verification and -+ // the user is getting logged in. -+ if (this._userVerifier.serviceIsDefault(GdmUtil.SMARTCARD_SERVICE_NAME) && -+ this.verificationStatus == AuthPromptStatus.VERIFYING && -+ this.smartcardDetected) -+ return; -+ -+ if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) -+ this.reset(); -+ }, -+ - _onShowMessage: function(userVerifier, message, styleClass) { - this.setMessage(message, styleClass); - this.emit('prompted'); - }, - - _onVerificationFailed: function() { - this.clear(); - - this.updateSensitivity(true); - this.setActorInDefaultButtonWell(null); - this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED; - }, - - _onVerificationComplete: function() { - this.verificationStatus = AuthPromptStatus.VERIFICATION_SUCCEEDED; - }, - - _onReset: function() { - if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) { - this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; - this.reset(); - } - }, - - _onShowLoginHint: function(verifier, message) { - this.setHint(message); - }, - - _onHideLoginHint: function() { - this.setHint(null); -@@ -407,61 +428,77 @@ const AuthPrompt = new Lang.Class({ - } - }, - - setHint: function(message) { - if (message) { - this._loginHint.set_text(message) - this._loginHint.opacity = 255; - } else { - this._loginHint.opacity = 0; - this._loginHint.set_text(''); - } - }, - - reset: function() { - let oldStatus = this.verificationStatus; - this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; - - if (oldStatus == AuthPromptStatus.VERIFYING) - this._userVerifier.cancel(); - - this._queryingService = null; - this.clear(); - this._message.opacity = 0; - this.setUser(null); - this.stopSpinning(); - this.setHint(null); - - if (oldStatus == AuthPromptStatus.VERIFICATION_FAILED) - this.emit('failed'); - -- this.emit('reset', BeginRequestType.PROVIDE_USERNAME); -+ let beginRequestType; -+ -+ if (this._mode == AuthPromptMode.UNLOCK_ONLY) { -+ // The user is constant at the unlock screen, so it will immediately -+ // respond to the request with the username -+ beginRequestType = BeginRequestType.PROVIDE_USERNAME; -+ } else if (this._userVerifier.serviceIsForeground(GdmUtil.SMARTCARD_SERVICE_NAME)) { -+ // We don't need to know the username if the user preempted the login screen -+ // with a smartcard. -+ beginRequestType = BeginRequestType.DONT_PROVIDE_USERNAME; -+ } else { -+ // In all other cases, we should get the username up front. -+ beginRequestType = BeginRequestType.PROVIDE_USERNAME; -+ } -+ -+ this.emit('reset', beginRequestType); -+ - }, - - addCharacter: function(unichar) { - if (!this._entry.visible) - return; - - this._entry.grab_key_focus(); - this._entry.clutter_text.insert_unichar(unichar); - }, - - begin: function(params) { - params = Params.parse(params, { userName: null, - hold: null }); - - this.updateSensitivity(false); - - let hold = params.hold; - if (!hold) - hold = new Batch.Hold(); - - this._userVerifier.begin(params.userName, hold); - this.verificationStatus = AuthPromptStatus.VERIFYING; - }, - - finish: function(onComplete) { - if (!this._userVerifier.hasPendingMessages) { - onComplete(); - return; - } - -diff --git a/js/gdm/util.js b/js/gdm/util.js -index a7b8b62..7ed5097 100644 ---- a/js/gdm/util.js -+++ b/js/gdm/util.js -@@ -1,55 +1,58 @@ - // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - - const Clutter = imports.gi.Clutter; - const Gio = imports.gi.Gio; - const GLib = imports.gi.GLib; - const Lang = imports.lang; - const Mainloop = imports.mainloop; - const Signals = imports.signals; - const St = imports.gi.St; - - const Batch = imports.gdm.batch; - const Fprint = imports.gdm.fingerprint; - const Main = imports.ui.main; - const Params = imports.misc.params; - const ShellEntry = imports.ui.shellEntry; -+const SmartcardManager = imports.misc.smartcardManager; - const Tweener = imports.ui.tweener; - - const PASSWORD_SERVICE_NAME = 'gdm-password'; - const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint'; -+const SMARTCARD_SERVICE_NAME = 'gdm-smartcard'; - const FADE_ANIMATION_TIME = 0.16; - const CLONE_FADE_ANIMATION_TIME = 0.25; - - const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen'; - const PASSWORD_AUTHENTICATION_KEY = 'enable-password-authentication'; - const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication'; -+const SMARTCARD_AUTHENTICATION_KEY = 'enable-smartcard-authentication'; - const BANNER_MESSAGE_KEY = 'banner-message-enable'; - const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text'; - const ALLOWED_FAILURES_KEY = 'allowed-failures'; - - const LOGO_KEY = 'logo'; - const DISABLE_USER_LIST_KEY = 'disable-user-list'; - - // Give user 16ms to read each character of a PAM message - const USER_READ_TIME = 16 - - function fadeInActor(actor) { - if (actor.opacity == 255 && actor.visible) - return null; - - let hold = new Batch.Hold(); - actor.show(); - let [minHeight, naturalHeight] = actor.get_preferred_height(-1); - - actor.opacity = 0; - actor.set_height(0); - Tweener.addTween(actor, - { opacity: 255, - height: naturalHeight, - time: FADE_ANIMATION_TIME, - transition: 'easeOutQuad', - onComplete: function() { - this.set_height(-1); - hold.release(); - }, - }); -@@ -95,60 +98,73 @@ function cloneAndFadeOutActor(actor) { - clone.set_position(x, y); - - let hold = new Batch.Hold(); - Tweener.addTween(clone, - { opacity: 0, - time: CLONE_FADE_ANIMATION_TIME, - transition: 'easeOutQuad', - onComplete: function() { - clone.destroy(); - hold.release(); - } - }); - return hold; - } - - const ShellUserVerifier = new Lang.Class({ - Name: 'ShellUserVerifier', - - _init: function(client, params) { - params = Params.parse(params, { reauthenticationOnly: false }); - this._reauthOnly = params.reauthenticationOnly; - - this._client = client; - - this._settings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA }); - this._settings.connect('changed', - Lang.bind(this, this._updateDefaultService)); - this._updateDefaultService(); - - this._fprintManager = new Fprint.FprintManager(); -+ this._smartcardManager = SmartcardManager.getSmartcardManager(); -+ -+ // We check for smartcards right away, since an inserted smartcard -+ // at startup should result in immediately initiating authentication. -+ // This is different than fingeprint readers, where we only check them -+ // after a user has been picked. -+ this._checkForSmartcard(); -+ -+ this._smartcardManager.connect('smartcard-inserted', -+ Lang.bind(this, this._checkForSmartcard)); -+ this._smartcardManager.connect('smartcard-removed', -+ Lang.bind(this, this._checkForSmartcard)); -+ - this._messageQueue = []; - this._messageQueueTimeoutId = 0; - this.hasPendingMessages = false; - this.reauthenticating = false; - - this._failCounter = 0; - }, - - begin: function(userName, hold) { - this._cancellable = new Gio.Cancellable(); - this._hold = hold; - this._userName = userName; - this.reauthenticating = false; - - this._checkForFingerprintReader(); - - if (userName) { - // If possible, reauthenticate an already running session, - // so any session specific credentials get updated appropriately - this._client.open_reauthentication_channel(userName, this._cancellable, - Lang.bind(this, this._reauthenticationChannelOpened)); - } else { - this._client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot)); - } - }, - - cancel: function() { - if (this._cancellable) - this._cancellable.cancel(); - -@@ -226,128 +242,158 @@ const ShellUserVerifier = new Lang.Class({ - this._messageQueue.push({ text: message, interval: interval, iconName: iconName }); - this._queueMessageTimeout(); - }, - - _clearMessageQueue: function() { - this.finishMessageQueue(); - - if (this._messageQueueTimeoutId != 0) { - GLib.source_remove(this._messageQueueTimeoutId); - this._messageQueueTimeoutId = 0; - } - this.emit('show-message', null, null); - }, - - _checkForFingerprintReader: function() { - this._haveFingerprintReader = false; - - if (!this._settings.get_boolean(FINGERPRINT_AUTHENTICATION_KEY)) { - this._updateDefaultService(); - return; - } - - this._fprintManager.GetDefaultDeviceRemote(Gio.DBusCallFlags.NONE, this._cancellable, Lang.bind(this, - function(device, error) { - if (!error && device) - this._haveFingerprintReader = true; - this._updateDefaultService(); - })); - }, - -+ _checkForSmartcard: function() { -+ let smartcardDetected; -+ -+ if (!this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY)) -+ smartcardDetected = false; -+ else if (this._reauthOnly) -+ smartcardDetected = this._smartcardManager.hasInsertedLoginToken(); -+ else -+ smartcardDetected = this._smartcardManager.hasInsertedTokens(); -+ -+ if (smartcardDetected != this.smartcardDetected) { -+ this.smartcardDetected = smartcardDetected; -+ -+ if (this.smartcardDetected) -+ this._preemptingService = SMARTCARD_SERVICE_NAME; -+ else if (this._preemptingService == SMARTCARD_SERVICE_NAME) -+ this._preemptingService = null; -+ -+ this.emit('smartcard-status-changed'); -+ } -+ }, -+ - _reportInitError: function(where, error) { - logError(error, where); - this._hold.release(); - - this._queueMessage(_("Authentication error"), 'login-dialog-message-warning'); - this._verificationFailed(false); - }, - - _reauthenticationChannelOpened: function(client, result) { - try { - this._userVerifier = client.open_reauthentication_channel_finish(result); - } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - return; - } catch(e if e.matches(Gio.DBusError, Gio.DBusError.ACCESS_DENIED) && - !this._reauthOnly) { - // Gdm emits org.freedesktop.DBus.Error.AccessDenied when there is - // no session to reauthenticate. Fall back to performing verification - // from this login session - client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot)); - return; - } catch(e) { - this._reportInitError('Failed to open reauthentication channel', e); - return; - } - - this.reauthenticating = true; - this._connectSignals(); - this._beginVerification(); - this._hold.release(); - }, - - _userVerifierGot: function(client, result) { - try { - this._userVerifier = client.get_user_verifier_finish(result); - } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - return; - } catch(e) { - this._reportInitError('Failed to obtain user verifier', e); - return; - } - - this._connectSignals(); - this._beginVerification(); - this._hold.release(); - }, - - _connectSignals: function() { - this._userVerifier.connect('info', Lang.bind(this, this._onInfo)); - this._userVerifier.connect('problem', Lang.bind(this, this._onProblem)); - this._userVerifier.connect('info-query', Lang.bind(this, this._onInfoQuery)); - this._userVerifier.connect('secret-info-query', Lang.bind(this, this._onSecretInfoQuery)); - this._userVerifier.connect('conversation-stopped', Lang.bind(this, this._onConversationStopped)); - this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); - this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); - }, - - _getForegroundService: function() { -- // For now, the foreground service is always the default service -+ if (this._preemptingService) -+ return this._preemptingService; -+ - return this._defaultService; - }, - - serviceIsForeground: function(serviceName) { - return serviceName == this._getForegroundService(); - }, - -+ serviceIsDefault: function(serviceName) { -+ return serviceName == this._defaultService; -+ }, -+ - _updateDefaultService: function() { - if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY)) - this._defaultService = PASSWORD_SERVICE_NAME; -+ else if (this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY)) -+ this._defaultService = SMARTCARD_SERVICE_NAME; - else if (this._haveFingerprintReader) - this._defaultService = FINGERPRINT_SERVICE_NAME; - }, - - _startService: function(serviceName) { - this._hold.acquire(); - this._userVerifier.call_begin_verification_for_user(serviceName, - this._userName, - this._cancellable, - Lang.bind(this, function(obj, result) { - try { - obj.call_begin_verification_for_user_finish(result); - } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - return; - } catch(e) { - this._reportInitError('Failed to start verification for user', e); - return; - } - - this._hold.release(); - })); - }, - - _beginVerification: function() { - this._startService(this._getForegroundService()); - - if (this._userName && this._haveFingerprintReader && !this.serviceIsForeground(FINGERPRINT_SERVICE_NAME)) - this._startService(FINGERPRINT_SERVICE_NAME); - }, - -diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js -index d9fe883..2c812f5 100644 ---- a/js/ui/screenShield.js -+++ b/js/ui/screenShield.js -@@ -1,55 +1,56 @@ - // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - - const Cairo = imports.cairo; - const Clutter = imports.gi.Clutter; - const Gio = imports.gi.Gio; - const GLib = imports.gi.GLib; - const GnomeDesktop = imports.gi.GnomeDesktop; - const Lang = imports.lang; - const Mainloop = imports.mainloop; - const Meta = imports.gi.Meta; - const Shell = imports.gi.Shell; - const Signals = imports.signals; - const St = imports.gi.St; - const TweenerEquations = imports.tweener.equations; - - const Background = imports.ui.background; - const GnomeSession = imports.misc.gnomeSession; - const Hash = imports.misc.hash; - const Layout = imports.ui.layout; - const LoginManager = imports.misc.loginManager; - const Lightbox = imports.ui.lightbox; - const Main = imports.ui.main; - const Overview = imports.ui.overview; - const MessageTray = imports.ui.messageTray; - const ShellDBus = imports.ui.shellDBus; -+const SmartcardManager = imports.misc.smartcardManager; - const Tweener = imports.ui.tweener; - const Util = imports.misc.util; - - const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver'; - const LOCK_ENABLED_KEY = 'lock-enabled'; - const LOCK_DELAY_KEY = 'lock-delay'; - - // fraction of screen height the arrow must reach before completing - // the slide up automatically - const ARROW_DRAG_THRESHOLD = 0.1; - - // Parameters for the arrow animation - const N_ARROWS = 3; - const ARROW_ANIMATION_TIME = 0.6; - const ARROW_ANIMATION_PEAK_OPACITY = 0.4; - const ARROW_IDLE_TIME = 30000; // ms - - const SUMMARY_ICON_SIZE = 48; - - // ScreenShield animation time - // - STANDARD_FADE_TIME is used when the session goes idle - // - MANUAL_FADE_TIME is used for lowering the shield when asked by the user, - // or when cancelling the dialog - // - BACKGROUND_FADE_TIME is used when the background changes to crossfade to new background - // - CURTAIN_SLIDE_TIME is used when raising the shield before unlocking - // - INITIAL_FADE_IN_TIME is used for the initial fade in at startup - const STANDARD_FADE_TIME = 10; - const MANUAL_FADE_TIME = 0.3; - const BACKGROUND_FADE_TIME = 1.0; - const CURTAIN_SLIDE_TIME = 0.3; -@@ -478,60 +479,67 @@ const ScreenShield = new Lang.Class({ - - this._lockDialogGroup = new St.Widget({ x_expand: true, - y_expand: true, - opacity: 0, - pivot_point: new Clutter.Point({ x: 0.5, y: 0.5 }), - name: 'lockDialogGroup' }); - - Tweener.addTween(this._lockDialogGroup, - { opacity: 255, - time: INITIAL_FADE_IN_TIME, - transition: 'easeInQuad', - }); - - this.actor.add_actor(this._lockDialogGroup); - this.actor.add_actor(this._lockScreenGroup); - - this._presence = new GnomeSession.Presence(Lang.bind(this, function(proxy, error) { - if (error) { - logError(error, 'Error while reading gnome-session presence'); - return; - } - - this._onStatusChanged(proxy.status); - })); - this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) { - this._onStatusChanged(status); - })); - - this._screenSaverDBus = new ShellDBus.ScreenSaverDBus(this); - -+ this._smartcardManager = SmartcardManager.getSmartcardManager(); -+ this._smartcardManager.connect('smartcard-inserted', -+ Lang.bind(this, function(manager, token) { -+ if (this._isLocked && token.UsedToLogin) -+ this._liftShield(true, 0); -+ })); -+ - this._inhibitor = null; - this._aboutToSuspend = false; - this._loginManager = LoginManager.getLoginManager(); - this._loginManager.connect('prepare-for-sleep', - Lang.bind(this, this._prepareForSleep)); - this._inhibitSuspend(); - - this._loginManager.getCurrentSessionProxy(Lang.bind(this, - function(sessionProxy) { - this._loginSession = sessionProxy; - this._loginSession.connectSignal('Lock', Lang.bind(this, function() { this.lock(false); })); - this._loginSession.connectSignal('Unlock', Lang.bind(this, function() { this.deactivate(false); })); - })); - - this._settings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA }); - - this._isModal = false; - this._hasLockScreen = false; - this._isGreeter = false; - this._isActive = false; - this._isLocked = false; - this._inUnlockAnimation = false; - this._activationTime = 0; - this._becameActiveId = 0; - this._lockTimeoutId = 0; - - this._lightbox = new Lightbox.Lightbox(Main.uiGroup, - { inhibitEvents: true, - fadeInTime: STANDARD_FADE_TIME, - fadeFactor: 1 }); --- -1.8.3.1 - - -From 8365ce925bf451718882e554ff89b6a7aa36ee07 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Sun, 28 Jul 2013 20:55:12 -0400 -Subject: [PATCH 44/69] loginDialog: fix up cancel button visibility - -This commit makes sure we hide when there's nothing to cancel -to and show it when there's something to cancel to. - -https://bugzilla.gnome.org/show_bug.cgi?id=683437 ---- - js/gdm/loginDialog.js | 21 +++++++++++++++++---- - 1 file changed, 17 insertions(+), 4 deletions(-) - -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index b40aa85..643c7d6 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -513,98 +513,108 @@ const LoginDialog = new Lang.Class({ - 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); - - }, - - _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(); - } - }, - - _updateLogoTexture: function(cache, uri) { - if (this._logoFileUri != uri) - return; - - let icon = null; - if (this._logoFileUri) - icon = this._textureCache.load_uri_async(this._logoFileUri, - -1, _LOGO_ICON_HEIGHT); - this._logoBin.set_child(icon); - }, - - _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._authPrompt.cancelButton.show(); -- - this._showPrompt(); - }, - - _onReset: function(authPrompt, beginRequest) { - this._sessionMenuButton.updateSensitivity(true); - - this._user = null; - - if (this._disableUserList) { - this._authPrompt.cancelButton.hide(); - this._hideUserListAndLogIn(); - } else { - this._showUserList(); - } - }, - - _onDefaultSessionChanged: function(client, sessionId) { - this._sessionMenuButton.setActiveSession(sessionId); - }, - - _shouldShowSessionMenuButton: function() { - if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFYING) - return false; - - if (this._user && this._user.is_logged_in()) - return false; - - return true; - }, - -@@ -622,65 +632,66 @@ const LoginDialog = new Lang.Class({ - _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.setHint(_("(e.g., user or %s)").format(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._authPrompt.clear(); - this._authPrompt.startSpinning(); - this._authPrompt.begin({ userName: answer }); -+ this._updateCancelButton(); - - realmManager.disconnect(realmSignalId) - realmManager.release(); - })); -- this._authPrompt.cancelButton.hide(); -+ this._updateCancelButton(); - this._showPrompt(); - }, - - _startSession: function(serviceName) { - Tweener.addTween(this.actor, - { opacity: 0, - time: _FADE_ANIMATION_TIME, - transition: 'easeOutQuad', - onUpdate: function() { - let children = Main.layoutManager.uiGroup.get_children(); - - for (let i = 0; i < children.length; i++) { - if (children[i] != Main.layoutManager.screenShieldGroup) - children[i].opacity = this.actor.opacity; - } - }, - onUpdateScope: this, - onComplete: function() { - Mainloop.idle_add(Lang.bind(this, function() { - this._greeter.call_start_session_when_ready_sync(serviceName, true, null); - return false; - })); - }, - onCompleteScope: this }); - }, - - _onSessionOpened: function(client, serviceName) { - this._authPrompt.finish(Lang.bind(this, function() { - this._startSession(serviceName); - })); -@@ -833,60 +844,62 @@ const LoginDialog = new Lang.Class({ - - _showUserList: function() { - this._authPrompt.hide(); - 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), - this._beginVerificationForItem(activatedItem)]); - batch.run(); - }, - - _onDestroy: function() { - if (this._userManagerLoadedId) { - this._userManager.disconnect(this._userManagerLoadedId); - this._userManagerLoadedId = 0; - } - }, - - _loadUserList: function() { - let users = this._userManager.list_users(); - - for (let i = 0; i < users.length; i++) { - this._userList.addUser(users[i]); - } - - this._updateDisableUserList(); - - this._userManager.connect('user-added', - Lang.bind(this, function(userManager, user) { - this._userList.addUser(user); - })); - - this._userManager.connect('user-removed', - Lang.bind(this, function(userManager, user) { - this._userList.removeUser(user); - })); --- -1.8.3.1 - - -From 9b3d0f302a216f70bb23685f08318afc6cfc21c4 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Sun, 28 Jul 2013 16:15:43 -0400 -Subject: [PATCH 45/69] authPrompt: don't muck with cancelButton in - onAskQuestion - -onAskQuestion has this code: - - if (this.verifyingUser) - this.cancelButton.show(); - else - this.cancelButton.hide(); - -but onAskQuestion can only be called when this.verifyingUser is true. -Also, cancelButton is public, and it only ever otherwise gets hidden -from callers. - -This commit drops mucking with cancelButton visibility, leaving it -entirely up to the callers to deal with. - -https://bugzilla.gnome.org/show_bug.cgi?id=683437 ---- - js/gdm/authPrompt.js | 5 ----- - 1 file changed, 5 deletions(-) - -diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index cfdf052..cbd2c46 100644 ---- a/js/gdm/authPrompt.js -+++ b/js/gdm/authPrompt.js -@@ -182,65 +182,60 @@ const AuthPrompt = new Lang.Class({ - y_align: St.Align.END }); - - this._updateNextButtonSensitivity(this._entry.text.length > 0); - - this._entry.clutter_text.connect('text-changed', - Lang.bind(this, function() { - if (!this._userVerifier.hasPendingMessages) - this._fadeOutMessage(); - - this._updateNextButtonSensitivity(this._entry.text.length > 0); - })); - this._entry.clutter_text.connect('activate', Lang.bind(this, function() { - this.emit('next'); - })); - }, - - _onAskQuestion: function(verifier, serviceName, question, passwordChar) { - if (this._preemptiveAnswer) { - this._userVerifier.answerQuery(this._queryingService, this._preemptiveAnswer); - this._preemptiveAnswer = null; - return; - } - - if (this._queryingService) - this.clear(); - - this._queryingService = serviceName; - this.setPasswordChar(passwordChar); - this.setQuestion(question); - -- if (this.verifyingUser) -- this.cancelButton.show(); -- else -- this.cancelButton.hide(); -- - if (passwordChar) { - if (this._userVerifier.reauthenticating) - this.nextButton.label = _("Unlock"); - else - this.nextButton.label = C_("button", "Sign In"); - } else { - this.nextButton.label = _("Next"); - } - - this.updateSensitivity(true); - this.emit('prompted'); - }, - - _onSmartcardStatusChanged: function() { - this.smartcardDetected = this._userVerifier.smartcardDetected; - - // Most of the time we want to reset if the user inserts or removes - // a smartcard. Smartcard insertion "preempts" what the user was - // doing, and smartcard removal aborts the preemption. - // The exceptions are: 1) Don't reset on smartcard insertion if we're already verifying - // with a smartcard - // 2) Don't reset if we've already succeeded at verification and - // the user is getting logged in. - if (this._userVerifier.serviceIsDefault(GdmUtil.SMARTCARD_SERVICE_NAME) && - this.verificationStatus == AuthPromptStatus.VERIFYING && - this.smartcardDetected) - return; - - if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) - this.reset(); --- -1.8.3.1 - - -From aa83e0e4c6a6d5963fb33f2a43d440431155a378 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Fri, 2 Aug 2013 14:10:16 -0400 -Subject: [PATCH 46/69] authPrompt: fix disable-user-list / Not Listed? - -If the first question asked to a user is from the -shell and not from the PAM service (i.e. Username: ), -then we'll save what the user types until PAM asks -a question and then try to send it to PAM. - -This commit makes sure the preemptive answer can be used -before the PAM conversation gets started, and makes sure -to discard the preemptive answer if we're not expecting it. - -https://bugzilla.gnome.org/show_bug.cgi?id=705370 ---- - js/gdm/authPrompt.js | 12 ++++++++++-- - 1 file changed, 10 insertions(+), 2 deletions(-) - -diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index cbd2c46..d09e5b6 100644 ---- a/js/gdm/authPrompt.js -+++ b/js/gdm/authPrompt.js -@@ -170,61 +170,62 @@ const AuthPrompt = new Lang.Class({ - can_focus: true, - label: _("Next") }); - this.nextButton.connect('clicked', - Lang.bind(this, function() { - this.emit('next'); - })); - this.nextButton.add_style_pseudo_class('default'); - this._buttonBox.add(this.nextButton, - { expand: false, - x_fill: false, - y_fill: false, - x_align: St.Align.END, - y_align: St.Align.END }); - - this._updateNextButtonSensitivity(this._entry.text.length > 0); - - this._entry.clutter_text.connect('text-changed', - Lang.bind(this, function() { - if (!this._userVerifier.hasPendingMessages) - this._fadeOutMessage(); - - this._updateNextButtonSensitivity(this._entry.text.length > 0); - })); - this._entry.clutter_text.connect('activate', Lang.bind(this, function() { - this.emit('next'); - })); - }, - - _onAskQuestion: function(verifier, serviceName, question, passwordChar) { - if (this._preemptiveAnswer) { -- this._userVerifier.answerQuery(this._queryingService, this._preemptiveAnswer); -+ if (this._queryingService) -+ this._userVerifier.answerQuery(this._queryingService, this._preemptiveAnswer); - this._preemptiveAnswer = null; - return; - } - - if (this._queryingService) - this.clear(); - - this._queryingService = serviceName; - this.setPasswordChar(passwordChar); - this.setQuestion(question); - - if (passwordChar) { - if (this._userVerifier.reauthenticating) - this.nextButton.label = _("Unlock"); - else - this.nextButton.label = C_("button", "Sign In"); - } else { - this.nextButton.label = _("Next"); - } - - this.updateSensitivity(true); - this.emit('prompted'); - }, - - _onSmartcardStatusChanged: function() { - this.smartcardDetected = this._userVerifier.smartcardDetected; - - // Most of the time we want to reset if the user inserts or removes - // a smartcard. Smartcard insertion "preempts" what the user was - // doing, and smartcard removal aborts the preemption. -@@ -338,61 +339,68 @@ const AuthPrompt = new Lang.Class({ - this.setActorInDefaultButtonWell(this._spinner.actor, true); - }, - - stopSpinning: function() { - this.setActorInDefaultButtonWell(null, false); - }, - - clear: function() { - this._entry.text = ''; - this.stopSpinning(); - }, - - setPasswordChar: function(passwordChar) { - this._entry.clutter_text.set_password_char(passwordChar); - this._entry.menu.isPassword = passwordChar != ''; - }, - - setQuestion: function(question) { - this._label.set_text(question); - - this._label.show(); - this._entry.show(); - - this._loginHint.opacity = 0; - this._loginHint.show(); - - this._entry.grab_key_focus(); - }, - - getAnswer: function() { -- let text = this._entry.get_text(); -+ let text; -+ -+ if (this._preemptiveAnswer) { -+ text = this._preemptiveAnswer; -+ this._preemptiveAnswer = null; -+ } else { -+ text = this._entry.get_text(); -+ } - - return text; - }, - - _fadeOutMessage: function() { - if (this._message.opacity == 0) - return; - Tweener.removeTweens(this._message); - Tweener.addTween(this._message, - { opacity: 0, - time: MESSAGE_FADE_OUT_ANIMATION_TIME, - transition: 'easeOutQuad' - }); - }, - - setMessage: function(message, styleClass) { - if (message) { - Tweener.removeTweens(this._message); - this._message.text = message; - this._message.styleClass = styleClass; - this._message.opacity = 255; - } else { - this._message.opacity = 0; - } - }, - - _updateNextButtonSensitivity: function(sensitive) { - this.nextButton.reactive = sensitive; - this.nextButton.can_focus = sensitive; - }, --- -1.8.3.1 - - -From 482a7e0c2e9a00b5393f871e848f356b2c0a600a Mon Sep 17 00:00:00 2001 -From: "Jasper St. Pierre" -Date: Tue, 6 Aug 2013 09:22:48 -0400 -Subject: [PATCH 47/69] screenShield: Don't crash when trying to deactivate the - shield - -If the user has a lock delay, or deactivate() has been called at -any other time, we need to check for the unlock dialog, as it may -not always exist. ---- - js/ui/screenShield.js | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js -index 2c812f5..bdce9e8 100644 ---- a/js/ui/screenShield.js -+++ b/js/ui/screenShield.js -@@ -1091,63 +1091,66 @@ const ScreenShield = new Lang.Class({ - - _clearLockScreen: function() { - this._clock.destroy(); - this._clock = null; - - if (this._notificationsBox) { - this._notificationsBox.destroy(); - this._notificationsBox = null; - } - - this._stopArrowAnimation(); - - this._lockScreenContentsBox.destroy(); - - this._hasLockScreen = false; - }, - - get locked() { - return this._isLocked; - }, - - get active() { - return this._isActive; - }, - - get activationTime() { - return this._activationTime; - }, - - deactivate: function(animate) { -- this._dialog.finish(Lang.bind(this, function() { -+ if (this._dialog) -+ this._dialog.finish(Lang.bind(this, function() { -+ this._finishDeactivate(animate); -+ })); -+ else - this._finishDeactivate(animate); -- })); - }, - - _finishDeactivate: function(animate) { - this._hideLockScreen(animate, 0); - - if (this._hasLockScreen) - this._clearLockScreen(); - - if (Main.sessionMode.currentMode == 'lock-screen') - Main.sessionMode.popMode('lock-screen'); - if (Main.sessionMode.currentMode == 'unlock-dialog') - Main.sessionMode.popMode('unlock-dialog'); - - Tweener.addTween(this._lockDialogGroup, { - scale_x: 0, - scale_y: 0, - time: animate ? Overview.ANIMATION_TIME : 0, - transition: 'easeOutQuad', - onComplete: Lang.bind(this, this._completeDeactivate), - onCompleteScope: this - }); - }, - - _completeDeactivate: function() { - if (this._dialog && !this._isGreeter) { - this._dialog.destroy(); - this._dialog = null; - } - - this._lightbox.hide(); --- -1.8.3.1 - - -From d5a1f4e4846b0fc4d9a695bd520289fefc508dfd Mon Sep 17 00:00:00 2001 -From: "Jasper St. Pierre" -Date: Tue, 6 Aug 2013 09:49:00 -0400 -Subject: [PATCH 48/69] screenShield: Remove confusing name - -We have both finishDeactivate and completeDeactivate. Don't. ---- - js/ui/screenShield.js | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js -index bdce9e8..2a8001e 100644 ---- a/js/ui/screenShield.js -+++ b/js/ui/screenShield.js -@@ -1093,67 +1093,67 @@ const ScreenShield = new Lang.Class({ - this._clock.destroy(); - this._clock = null; - - if (this._notificationsBox) { - this._notificationsBox.destroy(); - this._notificationsBox = null; - } - - this._stopArrowAnimation(); - - this._lockScreenContentsBox.destroy(); - - this._hasLockScreen = false; - }, - - get locked() { - return this._isLocked; - }, - - get active() { - return this._isActive; - }, - - get activationTime() { - return this._activationTime; - }, - - deactivate: function(animate) { - if (this._dialog) - this._dialog.finish(Lang.bind(this, function() { -- this._finishDeactivate(animate); -+ this._continueDeactivate(animate); - })); - else -- this._finishDeactivate(animate); -+ this._continueDeactivate(animate); - }, - -- _finishDeactivate: function(animate) { -+ _continueDeactivate: function(animate) { - this._hideLockScreen(animate, 0); - - if (this._hasLockScreen) - this._clearLockScreen(); - - if (Main.sessionMode.currentMode == 'lock-screen') - Main.sessionMode.popMode('lock-screen'); - if (Main.sessionMode.currentMode == 'unlock-dialog') - Main.sessionMode.popMode('unlock-dialog'); - - Tweener.addTween(this._lockDialogGroup, { - scale_x: 0, - scale_y: 0, - time: animate ? Overview.ANIMATION_TIME : 0, - transition: 'easeOutQuad', - onComplete: Lang.bind(this, this._completeDeactivate), - onCompleteScope: this - }); - }, - - _completeDeactivate: function() { - if (this._dialog && !this._isGreeter) { - this._dialog.destroy(); - this._dialog = null; - } - - this._lightbox.hide(); - - if (this._isModal) { - Main.popModal(this.actor); --- -1.8.3.1 - - -From 3d6f7008778f671a573888b0ea47b134b50691ef Mon Sep 17 00:00:00 2001 -From: Giovanni Campagna -Date: Mon, 3 Jun 2013 23:45:31 +0200 -Subject: [PATCH 49/69] ScreenShield: remove curtain animation when hiding - without animation - -If we don't remove the animation, we might leave a pending call -to _lockScreenShown() which would confuse our state tracking into -thinking we're active when we're not. - -https://bugzilla.gnome.org/show_bug.cgi?id=700901 ---- - js/ui/screenShield.js | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js -index 2a8001e..8fea66a 100644 ---- a/js/ui/screenShield.js -+++ b/js/ui/screenShield.js -@@ -850,73 +850,74 @@ const ScreenShield = new Lang.Class({ - if (!this._becomeModal()) { - // In the login screen, this is a hard error. Fail-whale - log('Could not acquire modal grab for the login screen. Aborting login process.'); - Meta.quit(Meta.ExitCode.ERROR); - } - - return false; - })); - - this.actor.show(); - this._isGreeter = Main.sessionMode.isGreeter; - this._isLocked = true; - this._ensureUnlockDialog(true, true); - this._hideLockScreen(false, 0); - }, - - _hideLockScreenComplete: function() { - if (Main.sessionMode.currentMode == 'lock-screen') - Main.sessionMode.popMode('lock-screen'); - - this._lockScreenState = MessageTray.State.HIDDEN; - this._lockScreenGroup.hide(); - }, - - _hideLockScreen: function(animate, velocity) { - if (this._lockScreenState == MessageTray.State.HIDDEN) - return; - - this._lockScreenState = MessageTray.State.HIDING; - -+ Tweener.removeTweens(this._lockScreenGroup); -+ - if (animate) { - // Tween the lock screen out of screen - // if velocity is not specified (i.e. we come here from pressing ESC), - // use the same speed regardless of original position - // if velocity is specified, it's in pixels per milliseconds - let h = global.stage.height; - let delta = (h + this._lockScreenGroup.y); - let min_velocity = global.stage.height / (CURTAIN_SLIDE_TIME * 1000); - - velocity = Math.max(min_velocity, velocity); - let time = (delta / velocity) / 1000; - -- Tweener.removeTweens(this._lockScreenGroup); - Tweener.addTween(this._lockScreenGroup, - { y: -h, - time: time, - transition: 'easeInQuad', - onComplete: Lang.bind(this, this._hideLockScreenComplete), - }); - } else { - this._hideLockScreenComplete(); - } - - global.stage.show_cursor(); - }, - - _ensureUnlockDialog: function(onPrimary, allowCancel) { - if (!this._dialog) { - let constructor = Main.sessionMode.unlockDialog; - if (!constructor) { - // This session mode has no locking capabilities - this.deactivate(true); - return; - } - - this._dialog = new constructor(this._lockDialogGroup); - - - let time = global.get_current_time(); - if (!this._dialog.open(time, onPrimary)) { - // This is kind of an impossible error: we're already modal - // by the time we reach this... - log('Could not open login dialog: failed to acquire grab'); --- -1.8.3.1 - - -From 0db93a2e049dc1ba1db7864754ac2004e5486d50 Mon Sep 17 00:00:00 2001 -From: Giovanni Campagna -Date: Thu, 6 Jun 2013 22:09:28 +0200 -Subject: [PATCH 50/69] ScreenShield: don't really deactivate when acting as a - greeter - -In greeter mode, we don't want to hide the login dialog, drop the -modal or send spurious signals to gnome-settings-daemon. - -https://bugzilla.gnome.org/show_bug.cgi?id=701761 ---- - js/ui/screenShield.js | 16 +++++++++++++++- - 1 file changed, 15 insertions(+), 1 deletion(-) - -diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js -index 8fea66a..862fd1e 100644 ---- a/js/ui/screenShield.js -+++ b/js/ui/screenShield.js -@@ -1111,72 +1111,86 @@ const ScreenShield = new Lang.Class({ - }, - - get active() { - return this._isActive; - }, - - get activationTime() { - return this._activationTime; - }, - - deactivate: function(animate) { - if (this._dialog) - this._dialog.finish(Lang.bind(this, function() { - this._continueDeactivate(animate); - })); - else - this._continueDeactivate(animate); - }, - - _continueDeactivate: function(animate) { - this._hideLockScreen(animate, 0); - - if (this._hasLockScreen) - this._clearLockScreen(); - - if (Main.sessionMode.currentMode == 'lock-screen') - Main.sessionMode.popMode('lock-screen'); - if (Main.sessionMode.currentMode == 'unlock-dialog') - Main.sessionMode.popMode('unlock-dialog'); - -+ if (this._isGreeter) { -+ // We don't want to "deactivate" any more than -+ // this. In particular, we don't want to drop -+ // the modal, hide ourselves or destroy the dialog -+ // But we do want to set isActive to false, so that -+ // gnome-session will reset the idle counter, and -+ // gnome-settings-daemon will stop blanking the screen -+ -+ this._activationTime = 0; -+ this._isActive = false; -+ this.emit('active-changed'); -+ return; -+ } -+ - Tweener.addTween(this._lockDialogGroup, { - scale_x: 0, - scale_y: 0, - time: animate ? Overview.ANIMATION_TIME : 0, - transition: 'easeOutQuad', - onComplete: Lang.bind(this, this._completeDeactivate), - onCompleteScope: this - }); - }, - - _completeDeactivate: function() { -- if (this._dialog && !this._isGreeter) { -+ if (this._dialog) { - this._dialog.destroy(); - this._dialog = null; - } - - this._lightbox.hide(); - - if (this._isModal) { - Main.popModal(this.actor); - this._isModal = false; - } - - this.actor.hide(); - - if (this._becameActiveId != 0) { - this.idleMonitor.remove_watch(this._becameActiveId); - this._becameActiveId = 0; - } - - if (this._lockTimeoutId != 0) { - Mainloop.source_remove(this._lockTimeoutId); - this._lockTimeoutId = 0; - } - - this._activationTime = 0; - this._isActive = false; - this._isLocked = false; - this.emit('active-changed'); - this.emit('locked-changed'); - }, - --- -1.8.3.1 - - -From c2deee5a4d58a8f873498751621c244c2ff2df1f Mon Sep 17 00:00:00 2001 -From: Giovanni Campagna -Date: Mon, 12 Aug 2013 15:14:37 +0200 -Subject: [PATCH 51/69] ScreenShield: don't allow events through the lock - dialog - -Make the lock dialog group reactive, to intercept any events -before they go to the actors below. -In the future, we may restructure our chrome to have a clear -layer system, but for now it fixes a security issue in the lock -screen (you can see the contents of the windows by dragging -if the screen was locked with the overview active) - -https://bugzilla.gnome.org/show_bug.cgi?id=705840 ---- - js/ui/screenShield.js | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js -index 862fd1e..1d296a2 100644 ---- a/js/ui/screenShield.js -+++ b/js/ui/screenShield.js -@@ -452,60 +452,61 @@ const ScreenShield = new Lang.Class({ - - this._updateBackgrounds(); - Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._updateBackgrounds)); - - this._arrowAnimationId = 0; - this._arrowWatchId = 0; - this._arrowActiveWatchId = 0; - this._arrowContainer = new St.BoxLayout({ style_class: 'screen-shield-arrows', - vertical: true, - x_align: Clutter.ActorAlign.CENTER, - y_align: Clutter.ActorAlign.END, - // HACK: without these, ClutterBinLayout - // ignores alignment properties on the actor - x_expand: true, - y_expand: true }); - - for (let i = 0; i < N_ARROWS; i++) { - let arrow = new Arrow({ opacity: 0 }); - this._arrowContainer.add_actor(arrow); - } - this._lockScreenContents.add_actor(this._arrowContainer); - - this._dragAction = new Clutter.GestureAction(); - this._dragAction.connect('gesture-begin', Lang.bind(this, this._onDragBegin)); - this._dragAction.connect('gesture-progress', Lang.bind(this, this._onDragMotion)); - this._dragAction.connect('gesture-end', Lang.bind(this, this._onDragEnd)); - this._lockScreenGroup.add_action(this._dragAction); - - this._lockDialogGroup = new St.Widget({ x_expand: true, - y_expand: true, -+ reactive: true, - opacity: 0, - pivot_point: new Clutter.Point({ x: 0.5, y: 0.5 }), - name: 'lockDialogGroup' }); - - Tweener.addTween(this._lockDialogGroup, - { opacity: 255, - time: INITIAL_FADE_IN_TIME, - transition: 'easeInQuad', - }); - - this.actor.add_actor(this._lockDialogGroup); - this.actor.add_actor(this._lockScreenGroup); - - this._presence = new GnomeSession.Presence(Lang.bind(this, function(proxy, error) { - if (error) { - logError(error, 'Error while reading gnome-session presence'); - return; - } - - this._onStatusChanged(proxy.status); - })); - this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) { - this._onStatusChanged(status); - })); - - this._screenSaverDBus = new ShellDBus.ScreenSaverDBus(this); - - this._smartcardManager = SmartcardManager.getSmartcardManager(); - this._smartcardManager.connect('smartcard-inserted', - Lang.bind(this, function(manager, token) { --- -1.8.3.1 - - -From 3618ce49f59f00eb08b040e33ff64aae592c30fd Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 21 Aug 2013 11:54:03 -0400 -Subject: [PATCH 52/69] loginDialog: add support for auth without username / - fix Not Listed? - -commit 93f072d1fcf578c4e7550bd755e84bd46abcd493 attempted to -add support for auth without a username to the login screen, but -do to a messed up rebase only partially added it. - -This commit fixes that. - -https://bugzilla.gnome.org/show_bug.cgi?id=706607 ---- - js/gdm/loginDialog.js | 17 ++++++----------- - 1 file changed, 6 insertions(+), 11 deletions(-) - -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index 643c7d6..887bedb 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -449,65 +449,61 @@ const LoginDialog = new Lang.Class({ - { 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.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - - this.actor.add_child(this._authPrompt.actor); - this._userList.actor.add_constraint(new Clutter.BindConstraint({ source: this._authPrompt.actor, - coordinate: Clutter.BindCoordinate.WIDTH })); - - // 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, function() { -- this._authPrompt.cancelButton.show(); -- this._hideUserListAndLogIn(); -- })); -+ 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.Bin({ style_class: 'login-dialog-logo-bin', y_expand: true }); - this._logoBin.set_y_align(Clutter.ActorAlign.END); - this._logoBin.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.X_AXIS, - factor: 0.5 })); - this._logoBin.add_constraint(new Clutter.AlignConstraint({ source: this.actor, - align_axis: Clutter.AlignAxis.Y_AXIS, - factor: 1.0 })); - this.actor.add_child(this._logoBin); - this._updateLogo(); - - 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(); -@@ -569,66 +565,65 @@ const LoginDialog = new Lang.Class({ - if (this._logoFileUri != uri) - return; - - let icon = null; - if (this._logoFileUri) - icon = this._textureCache.load_uri_async(this._logoFileUri, - -1, _LOGO_ICON_HEIGHT); - this._logoBin.set_child(icon); - }, - - _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; - -- if (this._disableUserList) { -- this._authPrompt.cancelButton.hide(); -- this._hideUserListAndLogIn(); -- } else { -- this._showUserList(); -- } -+ if (!this._disableUserList && -+ beginRequest == AuthPrompt.BeginRequestType.PROVIDE_USERNAME) -+ this._showUserList(); -+ else -+ this._hideUserListAndBeginVerification(); - }, - - _onDefaultSessionChanged: function(client, sessionId) { - this._sessionMenuButton.setActiveSession(sessionId); - }, - - _shouldShowSessionMenuButton: function() { - if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFYING) - return false; - - if (this._user && 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' }); - }, - - _showRealmLoginHint: function(realmManager, hint) { - if (!hint) - return; --- -1.8.3.1 - - -From 891a19f8c381772a4e235b014c2c106279bcd940 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Fri, 16 Aug 2013 08:48:35 -0400 -Subject: [PATCH 53/69] theme: minor user item tweaks - - too much padding between avatar and name - -https://cloud.gnome.org/public.php?service=files&t=2a4b3383b568a7986edfcb3501bdd020 - not enough vertical padding between avatar image -and "Password" - -https://cloud.gnome.org/public.php?service=files&t=16b6eaa8f607650bcd11a4d4236fe7be ---- - data/theme/gnome-shell.css | 7 ++----- - 1 file changed, 2 insertions(+), 5 deletions(-) - -diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css -index e074554..2885a6e 100644 ---- a/data/theme/gnome-shell.css -+++ b/data/theme/gnome-shell.css -@@ -2247,61 +2247,61 @@ StScrollBar StButton#vhandle:active { - } - - .login-dialog-prompt-login-hint-message { - font-size: 10.5pt; - } - - .login-dialog-user-list-view { - -st-vfade-offset: 1em; - } - - .login-dialog-user-list { - spacing: 12px; - padding: .2em; - } - - .login-dialog-user-list-item { - border-radius: 10px; - padding: .2em; - } - - .login-dialog-user-list-item:ltr { - padding-right: 1em; - } - - .login-dialog-user-list-item:rtl { - padding-left: 1em; - } - - .login-dialog-user-list-item .login-dialog-user-list-item-name { - font-size: 20pt; -- padding-left: 1em; -+ padding-left: 9px; - } - - .login-dialog-user-list:expanded .login-dialog-user-list-item { - color: #666666; - } - - .login-dialog-user-list-item, - .login-dialog-user-list-item:hover .login-dialog-user-list-item-name, - .login-dialog-user-list:expanded .login-dialog-user-list-item:focus .login-dialog-user-list-item-name, - .login-dialog-user-list:expanded .login-dialog-user-list-item:logged-in { - color: white; - text-shadow: black 0px 2px 2px; - } - - .login-dialog-user-list-item:hover { - background-color: rgba(255,255,255,0.1); - } - - .login-dialog-user-list:expanded .login-dialog-user-list-item:focus { - background-color: rgba(255,255,255,0.33); - } - - .login-dialog-user-list:expanded .login-dialog-user-list-item:logged-in { - background-image: url("logged-in-indicator.svg"); - background-size: contain; - } - - .login-dialog-user-list-item-text-box { - padding: 0 0.5em; - } -@@ -2326,60 +2326,61 @@ StScrollBar StButton#vhandle:active { - font-size: 10.5pt; - font-weight: bold; - color: #666666; - padding-top: 1em; - padding-left: 2px; - } - - .login-dialog-not-listed-button:focus .login-dialog-not-listed-label, - .login-dialog-not-listed-button:hover .login-dialog-not-listed-label { - color: #E8E8E8; - } - - .login-dialog-username { - font-size: 16pt; - font-weight: bold; - text-align: left; - padding-left: 15px; - text-shadow: black 0px 4px 3px 0px; - } - - .login-dialog-prompt-layout { - padding-top: 24px; - padding-bottom: 12px; - spacing: 8px; - width: 23em; - } - - .login-dialog-prompt-label { - color: #eeeeee; - font-size: 14px; -+ padding-top: 11px; - } - - .login-dialog-session-list-button StIcon { - icon-size: 1.25em; - } - - .login-dialog-session-list-button { - color: #8b8b8b; - } - - .login-dialog-session-list-button:hover, - .login-dialog-session-list-button:active { - color: white; - } - - .login-dialog-logo-bin { - padding: 24px 0px; - } - - .login-dialog .modal-dialog-button-box { - spacing: 3px; - } - - .login-dialog .modal-dialog-button { - border-radius: 5px; - padding: 3px 18px; - } - - .login-dialog .modal-dialog-button:focus { - padding: 2px 17px; -@@ -2391,64 +2392,60 @@ StScrollBar StButton#vhandle:active { - background-gradient-direction: vertical; - border-color: #16335d; - } - - .login-dialog .modal-dialog-button:default:focus { - border: 2px solid #377fe7; - } - - .login-dialog .modal-dialog-button:default:hover { - background-gradient-start: #74a0d0; - background-gradient-end: #436d9f; - } - - .login-dialog .modal-dialog-button:default:active, - .login-dialog .modal-dialog-button:default:pressed { - background-gradient-start: #436d9f; - background-gradient-end: #74a0d0; - } - - .login-dialog .modal-dialog-button:default:insensitive { - border-color: #666666; - color: #9f9f9f; - background-gradient-direction: none; - background-color: rgba(102, 102, 102, 0.15); - } - - .login-dialog-message-warning { - color: orange; - } - --.user-widget { -- spacing: .4em; --} -- - .user-widget-label { - font-size: 16pt; - font-weight: bold; - text-align: left; - padding-left: 15px; - text-shadow: black 0px 4px 3px 0px; - } - - /* Screen shield */ - - .screen-shield-background { - background: black; - } - - #lockDialogGroup { - background: #2e3436 url(noise-texture.png); - background-repeat: repeat; - } - - .screen-shield-arrows { - padding-bottom: 3em; - } - - .screen-shield-arrows Gjs_Arrow { - color: white; - width: 80px; - height: 48px; - -arrow-thickness: 12px; - -arrow-shadow: 0 1px 1px rgba(0,0,0,0.4); - } --- -1.8.3.1 - - -From 2700af5367c39b33a37f08b9c049074458db18a9 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Mon, 19 Aug 2013 12:00:33 -0400 -Subject: [PATCH 54/69] loginDialog: consolidate message label and login hint - label - -Right now the login hint is showing up just above the the cancel -button, instead of just below the text entry field. - -The mockup here: - -https://raw.github.com/gnome-design-team/gnome-mockups/master/system-lock-login-boot/login-dissect.png - -Says it should share a label with the PAM info/error messages. - -This commit consolidates the two labels. - -https://bugzilla.gnome.org/show_bug.cgi?id=706324 ---- - data/theme/gnome-shell.css | 16 ++++++++++---- - js/gdm/authPrompt.js | 55 +++++++++++++++++++--------------------------- - js/gdm/loginDialog.js | 2 +- - js/gdm/util.js | 26 +++++++++++++--------- - 4 files changed, 51 insertions(+), 48 deletions(-) - -diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css -index 2885a6e..d0578c2 100644 ---- a/data/theme/gnome-shell.css -+++ b/data/theme/gnome-shell.css -@@ -2219,64 +2219,60 @@ StScrollBar StButton#vhandle:active { - 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; - - padding-bottom: 80px; - padding-top: 80px; - - border-radius: 16px; - min-height: 150px; - max-height: 700px; - min-width: 350px; - } - - .login-dialog-button-box { - spacing: 5px; - } - --.login-dialog-prompt-login-hint-message { -- font-size: 10.5pt; --} -- - .login-dialog-user-list-view { - -st-vfade-offset: 1em; - } - - .login-dialog-user-list { - spacing: 12px; - padding: .2em; - } - - .login-dialog-user-list-item { - border-radius: 10px; - padding: .2em; - } - - .login-dialog-user-list-item:ltr { - padding-right: 1em; - } - - .login-dialog-user-list-item:rtl { - padding-left: 1em; - } - - .login-dialog-user-list-item .login-dialog-user-list-item-name { - font-size: 20pt; - padding-left: 9px; - } - - .login-dialog-user-list:expanded .login-dialog-user-list-item { - color: #666666; - } -@@ -2388,64 +2384,76 @@ StScrollBar StButton#vhandle:active { - - .login-dialog .modal-dialog-button:default { - background-gradient-start: #6793c4; - background-gradient-end: #335d8f; - background-gradient-direction: vertical; - border-color: #16335d; - } - - .login-dialog .modal-dialog-button:default:focus { - border: 2px solid #377fe7; - } - - .login-dialog .modal-dialog-button:default:hover { - background-gradient-start: #74a0d0; - background-gradient-end: #436d9f; - } - - .login-dialog .modal-dialog-button:default:active, - .login-dialog .modal-dialog-button:default:pressed { - background-gradient-start: #436d9f; - background-gradient-end: #74a0d0; - } - - .login-dialog .modal-dialog-button:default:insensitive { - border-color: #666666; - color: #9f9f9f; - background-gradient-direction: none; - background-color: rgba(102, 102, 102, 0.15); - } - -+.login-dialog-message-warning, -+.login-dialog-message-info { -+ padding-top: 4px; -+ padding-bottom: 16px; -+ min-height: 2em; -+} -+ - .login-dialog-message-warning { - color: orange; - } - -+.login-dialog-message-hint { -+ padding-bottom: 16px; -+ min-height: 2em; -+} -+ - .user-widget-label { - font-size: 16pt; - font-weight: bold; - text-align: left; - padding-left: 15px; - text-shadow: black 0px 4px 3px 0px; - } - - /* Screen shield */ - - .screen-shield-background { - background: black; - } - - #lockDialogGroup { - background: #2e3436 url(noise-texture.png); - background-repeat: repeat; - } - - .screen-shield-arrows { - padding-bottom: 3em; - } - - .screen-shield-arrows Gjs_Arrow { - color: white; - width: 80px; - height: 48px; - -arrow-thickness: 12px; - -arrow-shadow: 0 1px 1px rgba(0,0,0,0.4); - } -diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index d09e5b6..732ad1a 100644 ---- a/js/gdm/authPrompt.js -+++ b/js/gdm/authPrompt.js -@@ -9,139 +9,136 @@ const Panel = imports.ui.panel; - const Batch = imports.gdm.batch; - const GdmUtil = imports.gdm.util; - const Params = imports.misc.params; - const ShellEntry = imports.ui.shellEntry; - const Tweener = imports.ui.tweener; - const UserWidget = imports.ui.userWidget; - - const DEFAULT_BUTTON_WELL_ICON_SIZE = 24; - const DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0; - const DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3; - - const MESSAGE_FADE_OUT_ANIMATION_TIME = 0.5; - - const AuthPromptMode = { - UNLOCK_ONLY: 0, - UNLOCK_OR_LOG_IN: 1 - }; - - const AuthPromptStatus = { - NOT_VERIFYING: 0, - VERIFYING: 1, - VERIFICATION_FAILED: 2, - VERIFICATION_SUCCEEDED: 3 - }; - - const BeginRequestType = { - PROVIDE_USERNAME: 0, - DONT_PROVIDE_USERNAME: 1 - }; - -+let _messageStyleMap; -+ - const AuthPrompt = new Lang.Class({ - Name: 'AuthPrompt', - - _init: function(gdmClient, mode) { - this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; - - this._gdmClient = gdmClient; - this._mode = mode; - - let reauthenticationOnly; - if (this._mode == AuthPromptMode.UNLOCK_ONLY) - reauthenticationOnly = true; - else if (this._mode == AuthPromptMode.UNLOCK_OR_LOG_IN) - reauthenticationOnly = false; - - this._userVerifier = new GdmUtil.ShellUserVerifier(this._gdmClient, { reauthenticationOnly: reauthenticationOnly }); - - this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion)); - this._userVerifier.connect('show-message', Lang.bind(this, this._onShowMessage)); - this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed)); - this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); - this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); -- this._userVerifier.connect('show-login-hint', Lang.bind(this, this._onShowLoginHint)); -- this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._onHideLoginHint)); - this._userVerifier.connect('smartcard-status-changed', Lang.bind(this, this._onSmartcardStatusChanged)); - this.smartcardDetected = this._userVerifier.smartcardDetected; - - this.connect('next', Lang.bind(this, function() { - this.updateSensitivity(false); - this.startSpinning(); - if (this._queryingService) { - this._userVerifier.answerQuery(this._queryingService, this._entry.text); - } else { - this._preemptiveAnswer = this._entry.text; - } - })); - - this.actor = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', - vertical: true }); - this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); - this.actor.connect('key-press-event', - Lang.bind(this, function(actor, event) { - if (event.get_key_symbol() == Clutter.KEY_Escape) { - this.cancel(); - } - })); - - this._userWell = new St.Bin({ x_fill: true, - x_align: St.Align.START }); - this.actor.add(this._userWell, - { x_align: St.Align.START, - x_fill: true, - y_fill: true, - expand: true }); - this._label = new St.Label({ style_class: 'login-dialog-prompt-label' }); - - this.actor.add(this._label, - { expand: true, - x_fill: true, - y_fill: true, - x_align: St.Align.START }); - this._entry = new St.Entry({ style_class: 'login-dialog-prompt-entry', - can_focus: true }); - ShellEntry.addContextMenu(this._entry, { isPassword: true }); - - this.actor.add(this._entry, - { expand: true, - x_fill: true, - y_fill: false, - x_align: St.Align.START }); - - this._entry.grab_key_focus(); - - this._message = new St.Label({ opacity: 0 }); - this._message.clutter_text.line_wrap = true; -- this.actor.add(this._message, { x_fill: true }); -- -- this._loginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' }); -- this.actor.add(this._loginHint); -+ this.actor.add(this._message, { x_fill: true, y_align: St.Align.START }); - - this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box', - vertical: false }); - this.actor.add(this._buttonBox, - { expand: true, - x_align: St.Align.MIDDLE, - y_align: St.Align.END }); - - this._defaultButtonWell = new St.Widget(); - this._defaultButtonWellActor = null; - - this._initButtons(); - - let spinnerIcon = global.datadir + '/theme/process-working.svg'; - this._spinner = new Panel.AnimatedIcon(spinnerIcon, DEFAULT_BUTTON_WELL_ICON_SIZE); - this._spinner.actor.opacity = 0; - this._spinner.actor.show(); - this._defaultButtonWell.add_child(this._spinner.actor); - }, - - _onDestroy: function() { - this._userVerifier.clear(); - this._userVerifier.disconnectAll(); - this._userVerifier = null; - }, - - _initButtons: function() { - this.cancelButton = new St.Button({ style_class: 'modal-dialog-button', - button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, - reactive: true, -@@ -215,92 +212,84 @@ const AuthPrompt = new Lang.Class({ - this.nextButton.label = _("Unlock"); - else - this.nextButton.label = C_("button", "Sign In"); - } else { - this.nextButton.label = _("Next"); - } - - this.updateSensitivity(true); - this.emit('prompted'); - }, - - _onSmartcardStatusChanged: function() { - this.smartcardDetected = this._userVerifier.smartcardDetected; - - // Most of the time we want to reset if the user inserts or removes - // a smartcard. Smartcard insertion "preempts" what the user was - // doing, and smartcard removal aborts the preemption. - // The exceptions are: 1) Don't reset on smartcard insertion if we're already verifying - // with a smartcard - // 2) Don't reset if we've already succeeded at verification and - // the user is getting logged in. - if (this._userVerifier.serviceIsDefault(GdmUtil.SMARTCARD_SERVICE_NAME) && - this.verificationStatus == AuthPromptStatus.VERIFYING && - this.smartcardDetected) - return; - - if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) - this.reset(); - }, - -- _onShowMessage: function(userVerifier, message, styleClass) { -- this.setMessage(message, styleClass); -+ _onShowMessage: function(userVerifier, message, type) { -+ this.setMessage(message, type); - this.emit('prompted'); - }, - - _onVerificationFailed: function() { - this.clear(); - - this.updateSensitivity(true); - this.setActorInDefaultButtonWell(null); - this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED; - }, - - _onVerificationComplete: function() { - this.verificationStatus = AuthPromptStatus.VERIFICATION_SUCCEEDED; - }, - - _onReset: function() { - if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) { - this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; - this.reset(); - } - }, - -- _onShowLoginHint: function(verifier, message) { -- this.setHint(message); -- }, -- -- _onHideLoginHint: function() { -- this.setHint(null); -- }, -- - addActorToDefaultButtonWell: function(actor) { - this._defaultButtonWell.add_child(actor); - - actor.add_constraint(new Clutter.AlignConstraint({ source: this._spinner.actor, - align_axis: Clutter.AlignAxis.BOTH, - factor: 0.5 })); - }, - - setActorInDefaultButtonWell: function(actor, animate) { - if (!this._defaultButtonWellActor && - !actor) - return; - - let oldActor = this._defaultButtonWellActor; - - if (oldActor) - Tweener.removeTweens(oldActor); - - let isSpinner; - if (actor == this._spinner.actor) - isSpinner = true; - else - isSpinner = false; - - if (this._defaultButtonWellActor != actor && oldActor) { - if (!animate) { - oldActor.opacity = 0; - } else { - Tweener.addTween(oldActor, - { opacity: 0, -@@ -332,155 +321,155 @@ const AuthPrompt = new Lang.Class({ - transition: 'linear' }); - } - - this._defaultButtonWellActor = actor; - }, - - startSpinning: function() { - this.setActorInDefaultButtonWell(this._spinner.actor, true); - }, - - stopSpinning: function() { - this.setActorInDefaultButtonWell(null, false); - }, - - clear: function() { - this._entry.text = ''; - this.stopSpinning(); - }, - - setPasswordChar: function(passwordChar) { - this._entry.clutter_text.set_password_char(passwordChar); - this._entry.menu.isPassword = passwordChar != ''; - }, - - setQuestion: function(question) { - this._label.set_text(question); - - this._label.show(); - this._entry.show(); - -- this._loginHint.opacity = 0; -- this._loginHint.show(); -- - this._entry.grab_key_focus(); - }, - - getAnswer: function() { - let text; - - if (this._preemptiveAnswer) { - text = this._preemptiveAnswer; - this._preemptiveAnswer = null; - } else { - text = this._entry.get_text(); - } - - return text; - }, - - _fadeOutMessage: function() { - if (this._message.opacity == 0) - return; - Tweener.removeTweens(this._message); - Tweener.addTween(this._message, - { opacity: 0, - time: MESSAGE_FADE_OUT_ANIMATION_TIME, - transition: 'easeOutQuad' - }); - }, - -- setMessage: function(message, styleClass) { -+ _initMessageStyleMap: function() { -+ if (_messageStyleMap) -+ return; -+ -+ _messageStyleMap = {}; -+ _messageStyleMap[GdmUtil.MessageType.NONE] = ''; -+ _messageStyleMap[GdmUtil.MessageType.ERROR] = 'login-dialog-message-warning'; -+ _messageStyleMap[GdmUtil.MessageType.INFO] = 'login-dialog-message-info'; -+ _messageStyleMap[GdmUtil.MessageType.HINT] = 'login-dialog-message-hint'; -+ -+ }, -+ -+ setMessage: function(message, type) { -+ this._initMessageStyleMap(); - if (message) { - Tweener.removeTweens(this._message); - this._message.text = message; -- this._message.styleClass = styleClass; -+ this._message.styleClass = _messageStyleMap[type]; - this._message.opacity = 255; - } else { -+ this._message.styleClass = null; - this._message.opacity = 0; - } - }, - - _updateNextButtonSensitivity: function(sensitive) { - this.nextButton.reactive = sensitive; - this.nextButton.can_focus = sensitive; - }, - - updateSensitivity: function(sensitive) { - this._updateNextButtonSensitivity(sensitive); - this._entry.reactive = sensitive; - this._entry.clutter_text.editable = sensitive; - }, - - hide: function() { - this.setActorInDefaultButtonWell(null, true); - this.actor.hide(); -- this._loginHint.opacity = 0; -+ this._message.opacity = 0; - - this.setUser(null); - - this.updateSensitivity(true); - this._entry.set_text(''); - }, - - setUser: function(user) { - if (user) { - let userWidget = new UserWidget.UserWidget(user); - this._userWell.set_child(userWidget.actor); - } else { - this._userWell.set_child(null); - } - }, - -- setHint: function(message) { -- if (message) { -- this._loginHint.set_text(message) -- this._loginHint.opacity = 255; -- } else { -- this._loginHint.opacity = 0; -- this._loginHint.set_text(''); -- } -- }, -- - reset: function() { - let oldStatus = this.verificationStatus; - this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; - - if (oldStatus == AuthPromptStatus.VERIFYING) - this._userVerifier.cancel(); - - this._queryingService = null; - this.clear(); - this._message.opacity = 0; - this.setUser(null); - this.stopSpinning(); -- this.setHint(null); - - if (oldStatus == AuthPromptStatus.VERIFICATION_FAILED) - this.emit('failed'); - - let beginRequestType; - - if (this._mode == AuthPromptMode.UNLOCK_ONLY) { - // The user is constant at the unlock screen, so it will immediately - // respond to the request with the username - beginRequestType = BeginRequestType.PROVIDE_USERNAME; - } else if (this._userVerifier.serviceIsForeground(GdmUtil.SMARTCARD_SERVICE_NAME)) { - // We don't need to know the username if the user preempted the login screen - // with a smartcard. - beginRequestType = BeginRequestType.DONT_PROVIDE_USERNAME; - } else { - // In all other cases, we should get the username up front. - beginRequestType = BeginRequestType.PROVIDE_USERNAME; - } - - this.emit('reset', beginRequestType); - - }, - - addCharacter: function(unichar) { - if (!this._entry.visible) - return; - - this._entry.grab_key_focus(); - this._entry.clutter_text.insert_unichar(unichar); - }, -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index 887bedb..26028c8 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -607,61 +607,61 @@ const LoginDialog = new Lang.Class({ - if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFYING) - return false; - - if (this._user && 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' }); - }, - - _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.setHint(_("(e.g., user or %s)").format(hint)); -+ 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._authPrompt.clear(); - this._authPrompt.startSpinning(); - this._authPrompt.begin({ userName: answer }); - this._updateCancelButton(); - - realmManager.disconnect(realmSignalId) - realmManager.release(); - })); - this._updateCancelButton(); - this._showPrompt(); - }, - - _startSession: function(serviceName) { - Tweener.addTween(this.actor, -diff --git a/js/gdm/util.js b/js/gdm/util.js -index 7ed5097..bfbd1b3 100644 ---- a/js/gdm/util.js -+++ b/js/gdm/util.js -@@ -9,60 +9,67 @@ const Signals = imports.signals; - const St = imports.gi.St; - - const Batch = imports.gdm.batch; - const Fprint = imports.gdm.fingerprint; - const Main = imports.ui.main; - const Params = imports.misc.params; - const ShellEntry = imports.ui.shellEntry; - const SmartcardManager = imports.misc.smartcardManager; - const Tweener = imports.ui.tweener; - - const PASSWORD_SERVICE_NAME = 'gdm-password'; - const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint'; - const SMARTCARD_SERVICE_NAME = 'gdm-smartcard'; - const FADE_ANIMATION_TIME = 0.16; - const CLONE_FADE_ANIMATION_TIME = 0.25; - - const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen'; - const PASSWORD_AUTHENTICATION_KEY = 'enable-password-authentication'; - const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication'; - const SMARTCARD_AUTHENTICATION_KEY = 'enable-smartcard-authentication'; - const BANNER_MESSAGE_KEY = 'banner-message-enable'; - const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text'; - const ALLOWED_FAILURES_KEY = 'allowed-failures'; - - const LOGO_KEY = 'logo'; - const DISABLE_USER_LIST_KEY = 'disable-user-list'; - - // Give user 16ms to read each character of a PAM message - const USER_READ_TIME = 16 - -+const MessageType = { -+ NONE: 0, -+ ERROR: 1, -+ INFO: 2, -+ HINT: 3 -+}; -+ - function fadeInActor(actor) { - if (actor.opacity == 255 && actor.visible) - return null; - - let hold = new Batch.Hold(); - actor.show(); - let [minHeight, naturalHeight] = actor.get_preferred_height(-1); - - actor.opacity = 0; - actor.set_height(0); - Tweener.addTween(actor, - { opacity: 255, - height: naturalHeight, - time: FADE_ANIMATION_TIME, - transition: 'easeOutQuad', - onComplete: function() { - this.set_height(-1); - hold.release(); - }, - }); - - return hold; - } - - function fadeOutActor(actor) { - if (!actor.visible || actor.opacity == 0) { - actor.opacity = 0; - actor.hide(); - return null; - } -@@ -198,131 +205,132 @@ const ShellUserVerifier = new Lang.Class({ - this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null); - })); - } - }, - - _getIntervalForMessage: function(message) { - // We probably could be smarter here - return message.length * USER_READ_TIME; - }, - - finishMessageQueue: function() { - if (!this.hasPendingMessages) - return; - - this._messageQueue = []; - - this.hasPendingMessages = false; - this.emit('no-more-messages'); - }, - - _queueMessageTimeout: function() { - if (this._messageQueue.length == 0) { - this.finishMessageQueue(); - return; - } - - if (this._messageQueueTimeoutId != 0) - return; - - let message = this._messageQueue.shift(); -- this.emit('show-message', message.text, message.iconName); -+ -+ this.emit('show-message', message.text, message.type); - - this._messageQueueTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, - message.interval, - Lang.bind(this, function() { - this._messageQueueTimeoutId = 0; - this._queueMessageTimeout(); - })); - }, - -- _queueMessage: function(message, iconName) { -+ _queueMessage: function(message, messageType) { - let interval = this._getIntervalForMessage(message); - - this.hasPendingMessages = true; -- this._messageQueue.push({ text: message, interval: interval, iconName: iconName }); -+ this._messageQueue.push({ text: message, type: messageType, interval: interval }); - this._queueMessageTimeout(); - }, - - _clearMessageQueue: function() { - this.finishMessageQueue(); - - if (this._messageQueueTimeoutId != 0) { - GLib.source_remove(this._messageQueueTimeoutId); - this._messageQueueTimeoutId = 0; - } -- this.emit('show-message', null, null); -+ this.emit('show-message', null, MessageType.NONE); - }, - - _checkForFingerprintReader: function() { - this._haveFingerprintReader = false; - - if (!this._settings.get_boolean(FINGERPRINT_AUTHENTICATION_KEY)) { - this._updateDefaultService(); - return; - } - - this._fprintManager.GetDefaultDeviceRemote(Gio.DBusCallFlags.NONE, this._cancellable, Lang.bind(this, - function(device, error) { - if (!error && device) - this._haveFingerprintReader = true; - this._updateDefaultService(); - })); - }, - - _checkForSmartcard: function() { - let smartcardDetected; - - if (!this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY)) - smartcardDetected = false; - else if (this._reauthOnly) - smartcardDetected = this._smartcardManager.hasInsertedLoginToken(); - else - smartcardDetected = this._smartcardManager.hasInsertedTokens(); - - if (smartcardDetected != this.smartcardDetected) { - this.smartcardDetected = smartcardDetected; - - if (this.smartcardDetected) - this._preemptingService = SMARTCARD_SERVICE_NAME; - else if (this._preemptingService == SMARTCARD_SERVICE_NAME) - this._preemptingService = null; - - this.emit('smartcard-status-changed'); - } - }, - - _reportInitError: function(where, error) { - logError(error, where); - this._hold.release(); - -- this._queueMessage(_("Authentication error"), 'login-dialog-message-warning'); -+ this._queueMessage(_("Authentication error"), MessageType.ERROR); - this._verificationFailed(false); - }, - - _reauthenticationChannelOpened: function(client, result) { - try { - this._userVerifier = client.open_reauthentication_channel_finish(result); - } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - return; - } catch(e if e.matches(Gio.DBusError, Gio.DBusError.ACCESS_DENIED) && - !this._reauthOnly) { - // Gdm emits org.freedesktop.DBus.Error.AccessDenied when there is - // no session to reauthenticate. Fall back to performing verification - // from this login session - client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot)); - return; - } catch(e) { - this._reportInitError('Failed to open reauthentication channel', e); - return; - } - - this.reauthenticating = true; - this._connectSignals(); - this._beginVerification(); - this._hold.release(); - }, - - _userVerifierGot: function(client, result) { - try { - this._userVerifier = client.get_user_verifier_finish(result); - } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { -@@ -372,78 +380,78 @@ const ShellUserVerifier = new Lang.Class({ - }, - - _startService: function(serviceName) { - this._hold.acquire(); - this._userVerifier.call_begin_verification_for_user(serviceName, - this._userName, - this._cancellable, - Lang.bind(this, function(obj, result) { - try { - obj.call_begin_verification_for_user_finish(result); - } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - return; - } catch(e) { - this._reportInitError('Failed to start verification for user', e); - return; - } - - this._hold.release(); - })); - }, - - _beginVerification: function() { - this._startService(this._getForegroundService()); - - if (this._userName && this._haveFingerprintReader && !this.serviceIsForeground(FINGERPRINT_SERVICE_NAME)) - this._startService(FINGERPRINT_SERVICE_NAME); - }, - - _onInfo: function(client, serviceName, info) { - if (this.serviceIsForeground(serviceName)) { -- this._queueMessage(info, 'login-dialog-message-info'); -+ this._queueMessage(info, MessageType.INFO); - } else if (serviceName == FINGERPRINT_SERVICE_NAME && - this._haveFingerprintReader) { - // We don't show fingerprint messages directly since it's - // not the main auth service. Instead we use the messages - // as a cue to display our own message. - - // Translators: this message is shown below the password entry field - // to indicate the user can swipe their finger instead -- this.emit('show-login-hint', _("(or swipe finger)")); -+ this._queueMessage(_("(or swipe finger)"), MessageType.HINT); - } - }, - - _onProblem: function(client, serviceName, problem) { - if (!this.serviceIsForeground(serviceName)) - return; - -- this._queueMessage(problem, 'login-dialog-message-warning'); -+ this._queueMessage(problem, MessageType.ERROR); - }, - - _onInfoQuery: function(client, serviceName, question) { - if (!this.serviceIsForeground(serviceName)) - return; - - this.emit('ask-question', serviceName, question, ''); - }, - - _onSecretInfoQuery: function(client, serviceName, secretQuestion) { - if (!this.serviceIsForeground(serviceName)) - return; - - this.emit('ask-question', serviceName, secretQuestion, '\u25cf'); - }, - - _onReset: function() { - // Clear previous attempts to authenticate - this._failCounter = 0; - this._updateDefaultService(); - - this.emit('reset'); - }, - - _onVerificationComplete: function() { - this.emit('verification-complete'); - }, - - _cancelAndReset: function() { - this.cancel(); -@@ -469,35 +477,33 @@ const ShellUserVerifier = new Lang.Class({ - this._retry(); - } else { - let signalId = this.connect('no-more-messages', - Lang.bind(this, function() { - this.disconnect(signalId); - this._retry(); - })); - } - } else { - if (!this.hasPendingMessages) { - this._cancelAndReset(); - } else { - let signalId = this.connect('no-more-messages', - Lang.bind(this, function() { - this.disconnect(signalId); - this._cancelAndReset(); - })); - } - } - - this.emit('verification-failed'); - }, - - _onConversationStopped: function(client, serviceName) { - // if the password service fails, then cancel everything. - // But if, e.g., fingerprint fails, still give - // password authentication a chance to succeed - if (this.serviceIsForeground(serviceName)) { - this._verificationFailed(true); - } -- -- this.emit('hide-login-hint'); - }, - }); - Signals.addSignalMethods(ShellUserVerifier.prototype); --- -1.8.3.1 - - -From e0f9cbf201a2c41e8049a37bd97ae1b6e92cba71 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 21 Aug 2013 18:00:40 -0400 -Subject: [PATCH 55/69] objectManager: clear inhibitor on unregistered - interfaces - -A D-Bus service can export more supported interfaces than the -shell cares about. In those cases, we avoid creating proxies, -but neglect to finish things up so the object manager class -knows it can mark itself loaded. - -This commit makes sure we do the proper finishing, so the object -manager still loads in the face of unsupported interfaces. - -https://bugzilla.gnome.org/show_bug.cgi?id=706542 ---- - js/misc/objectManager.js | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/js/misc/objectManager.js b/js/misc/objectManager.js -index b954f1b..f7265fe 100644 ---- a/js/misc/objectManager.js -+++ b/js/misc/objectManager.js -@@ -46,62 +46,65 @@ const ObjectManager = new Lang.Class({ - g_object_path: this._managerPath, - g_flags: Gio.DBusProxyFlags.NONE }); - - this._interfaceInfos = {}; - this._objects = {}; - this._interfaces = {}; - this._onLoaded = params.onLoaded; - - if (params.knownInterfaces) - this._registerInterfaces(params.knownInterfaces); - - // Start out inhibiting load until at least the proxy - // manager is loaded and the remote objects are fetched - this._numLoadInhibitors = 1; - this._managerProxy.init_async(GLib.PRIORITY_DEFAULT, - this._cancellable, - Lang.bind(this, this._onManagerProxyLoaded)); - }, - - _tryToCompleteLoad: function() { - this._numLoadInhibitors--; - if (this._numLoadInhibitors == 0) { - if (this._onLoaded) - this._onLoaded(); - } - }, - - _addInterface: function(objectPath, interfaceName, onFinished) { - let info = this._interfaceInfos[interfaceName]; - -- if (!info) -+ if (!info) { -+ if (onFinished) -+ onFinished(); - return; -+ } - - let proxy = new Gio.DBusProxy({ g_connection: this._connection, - g_name: this._serviceName, - g_object_path: objectPath, - g_interface_name: interfaceName, - g_interface_info: info, - g_flags: Gio.DBusProxyFlags.NONE }); - - proxy.init_async(GLib.PRIORITY_DEFAULT, - this._cancellable, - Lang.bind(this, function(initable, result) { - let error = null; - try { - initable.init_finish(result); - } catch(e) { - logError(e, 'could not initialize proxy for interface ' + interfaceName); - - if (onFinished) - onFinished(); - return; - } - - let isNewObject; - if (!this._objects[objectPath]) { - this._objects[objectPath] = {}; - isNewObject = true; - } else { - isNewObject = false; - } - --- -1.8.3.1 - - -From 8fa149b7be4dd6d364a62d3329eed092f0678b52 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Thu, 22 Aug 2013 09:40:12 -0400 -Subject: [PATCH 56/69] objectManager: fix indentation - ---- - js/misc/objectManager.js | 34 +++++++++++++++++----------------- - 1 file changed, 17 insertions(+), 17 deletions(-) - -diff --git a/js/misc/objectManager.js b/js/misc/objectManager.js -index f7265fe..6998dd2 100644 ---- a/js/misc/objectManager.js -+++ b/js/misc/objectManager.js -@@ -44,78 +44,78 @@ const ObjectManager = new Lang.Class({ - g_interface_info: ObjectManagerInfo, - g_name: this._serviceName, - g_object_path: this._managerPath, - g_flags: Gio.DBusProxyFlags.NONE }); - - this._interfaceInfos = {}; - this._objects = {}; - this._interfaces = {}; - this._onLoaded = params.onLoaded; - - if (params.knownInterfaces) - this._registerInterfaces(params.knownInterfaces); - - // Start out inhibiting load until at least the proxy - // manager is loaded and the remote objects are fetched - this._numLoadInhibitors = 1; - this._managerProxy.init_async(GLib.PRIORITY_DEFAULT, - this._cancellable, - Lang.bind(this, this._onManagerProxyLoaded)); - }, - - _tryToCompleteLoad: function() { - this._numLoadInhibitors--; - if (this._numLoadInhibitors == 0) { - if (this._onLoaded) - this._onLoaded(); - } - }, - - _addInterface: function(objectPath, interfaceName, onFinished) { -- let info = this._interfaceInfos[interfaceName]; -+ let info = this._interfaceInfos[interfaceName]; - -- if (!info) { -- if (onFinished) -- onFinished(); -- return; -- } -- -- let proxy = new Gio.DBusProxy({ g_connection: this._connection, -- g_name: this._serviceName, -- g_object_path: objectPath, -- g_interface_name: interfaceName, -- g_interface_info: info, -- g_flags: Gio.DBusProxyFlags.NONE }); -- -- proxy.init_async(GLib.PRIORITY_DEFAULT, -- this._cancellable, -- Lang.bind(this, function(initable, result) { -+ if (!info) { -+ if (onFinished) -+ onFinished(); -+ return; -+ } -+ -+ let proxy = new Gio.DBusProxy({ g_connection: this._connection, -+ g_name: this._serviceName, -+ g_object_path: objectPath, -+ g_interface_name: interfaceName, -+ g_interface_info: info, -+ g_flags: Gio.DBusProxyFlags.NONE }); -+ -+ proxy.init_async(GLib.PRIORITY_DEFAULT, -+ this._cancellable, -+ Lang.bind(this, function(initable, result) { - let error = null; - try { - initable.init_finish(result); - } catch(e) { - logError(e, 'could not initialize proxy for interface ' + interfaceName); - - if (onFinished) - onFinished(); - return; - } - - let isNewObject; - if (!this._objects[objectPath]) { - this._objects[objectPath] = {}; - isNewObject = true; - } else { - isNewObject = false; - } - - this._objects[objectPath][interfaceName] = proxy; - - if (!this._interfaces[interfaceName]) - this._interfaces[interfaceName] = []; - - this._interfaces[interfaceName].push(proxy); - - if (isNewObject) - this.emit('object-added', objectPath); - - this.emit('interface-added', interfaceName, proxy); --- -1.8.3.1 - - -From c2b2051f772839bebb387e81c58156f9f20966bf Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 21 Aug 2013 18:05:55 -0400 -Subject: [PATCH 57/69] gdmUtil: make _startService support no username - -commit fd11ad95f61b904d6f7014f8d56c1c27d88af65c factored -out duplicated code, but unintentionally dropped support -for beginning verification without a username. - -This commit brings it back. - -https://bugzilla.gnome.org/show_bug.cgi?id=706542 ---- - js/gdm/util.js | 47 ++++++++++++++++++++++++++++++++--------------- - 1 file changed, 32 insertions(+), 15 deletions(-) - -diff --git a/js/gdm/util.js b/js/gdm/util.js -index bfbd1b3..f421902 100644 ---- a/js/gdm/util.js -+++ b/js/gdm/util.js -@@ -354,75 +354,92 @@ const ShellUserVerifier = new Lang.Class({ - this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); - this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); - }, - - _getForegroundService: function() { - if (this._preemptingService) - return this._preemptingService; - - return this._defaultService; - }, - - serviceIsForeground: function(serviceName) { - return serviceName == this._getForegroundService(); - }, - - serviceIsDefault: function(serviceName) { - return serviceName == this._defaultService; - }, - - _updateDefaultService: function() { - if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY)) - this._defaultService = PASSWORD_SERVICE_NAME; - else if (this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY)) - this._defaultService = SMARTCARD_SERVICE_NAME; - else if (this._haveFingerprintReader) - this._defaultService = FINGERPRINT_SERVICE_NAME; - }, - - _startService: function(serviceName) { - this._hold.acquire(); -- this._userVerifier.call_begin_verification_for_user(serviceName, -- this._userName, -- this._cancellable, -- Lang.bind(this, function(obj, result) { -- try { -- obj.call_begin_verification_for_user_finish(result); -- } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { -- return; -- } catch(e) { -- this._reportInitError('Failed to start verification for user', e); -- return; -- } -- -- this._hold.release(); -- })); -+ if (this._userName) { -+ this._userVerifier.call_begin_verification_for_user(serviceName, -+ this._userName, -+ this._cancellable, -+ Lang.bind(this, function(obj, result) { -+ try { -+ obj.call_begin_verification_for_user_finish(result); -+ } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { -+ return; -+ } catch(e) { -+ this._reportInitError('Failed to start verification for user', e); -+ return; -+ } -+ -+ this._hold.release(); -+ })); -+ } else { -+ this._userVerifier.call_begin_verification(serviceName, -+ this._cancellable, -+ Lang.bind(this, function(obj, result) { -+ try { -+ obj.call_begin_verification_finish(result); -+ } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { -+ return; -+ } catch(e) { -+ this._reportInitError('Failed to start verification', e); -+ return; -+ } -+ -+ this._hold.release(); -+ })); -+ } - }, - - _beginVerification: function() { - this._startService(this._getForegroundService()); - - if (this._userName && this._haveFingerprintReader && !this.serviceIsForeground(FINGERPRINT_SERVICE_NAME)) - this._startService(FINGERPRINT_SERVICE_NAME); - }, - - _onInfo: function(client, serviceName, info) { - if (this.serviceIsForeground(serviceName)) { - this._queueMessage(info, MessageType.INFO); - } else if (serviceName == FINGERPRINT_SERVICE_NAME && - this._haveFingerprintReader) { - // We don't show fingerprint messages directly since it's - // not the main auth service. Instead we use the messages - // as a cue to display our own message. - - // Translators: this message is shown below the password entry field - // to indicate the user can swipe their finger instead - this._queueMessage(_("(or swipe finger)"), MessageType.HINT); - } - }, - - _onProblem: function(client, serviceName, problem) { - if (!this.serviceIsForeground(serviceName)) - return; - - this._queueMessage(problem, MessageType.ERROR); - }, --- -1.8.3.1 - - -From 1292f8268952af0fb25f13f3d857d7b848ccf4d6 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Thu, 22 Aug 2013 16:18:20 -0400 -Subject: [PATCH 58/69] loginDialog: ask for username up front if - disable-user-list==TRUE - -Right now, we rely on PAM to ask for the username if disable-user-list -is TRUE. This is suboptimal because it means we can't check if we -should show a session menu. - -This commit changes disable-user-list==TRUE to ask for a username up -front, rather than have PAM do it. - -https://bugzilla.gnome.org/show_bug.cgi?id=706607 ---- - js/gdm/loginDialog.js | 14 +++++++++----- - 1 file changed, 9 insertions(+), 5 deletions(-) - -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index 26028c8..315a863 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -565,119 +565,123 @@ const LoginDialog = new Lang.Class({ - if (this._logoFileUri != uri) - return; - - let icon = null; - if (this._logoFileUri) - icon = this._textureCache.load_uri_async(this._logoFileUri, - -1, _LOGO_ICON_HEIGHT); - this._logoBin.set_child(icon); - }, - - _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; - -- if (!this._disableUserList && -- beginRequest == AuthPrompt.BeginRequestType.PROVIDE_USERNAME) -- this._showUserList(); -- else -+ 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) - return false; - -- if (this._user && this._user.is_logged_in()) -+ 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' }); - }, - - _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); - this._authPrompt.clear(); - this._authPrompt.startSpinning(); - this._authPrompt.begin({ userName: answer }); - this._updateCancelButton(); - - realmManager.disconnect(realmSignalId) - realmManager.release(); - })); - this._updateCancelButton(); - this._showPrompt(); - }, - - _startSession: function(serviceName) { - Tweener.addTween(this.actor, - { opacity: 0, - time: _FADE_ANIMATION_TIME, - transition: 'easeOutQuad', - onUpdate: function() { - let children = Main.layoutManager.uiGroup.get_children(); - - for (let i = 0; i < children.length; i++) { - if (children[i] != Main.layoutManager.screenShieldGroup) - children[i].opacity = this.actor.opacity; - } - }, - onUpdateScope: this, - onComplete: function() { - Mainloop.idle_add(Lang.bind(this, function() { - this._greeter.call_start_session_when_ready_sync(serviceName, true, null); - return false; --- -1.8.3.1 - - -From a00b1674fbb3278e3763e662c9176b394c17d2b4 Mon Sep 17 00:00:00 2001 -From: "Jasper St. Pierre" -Date: Mon, 26 Aug 2013 18:02:04 -0400 -Subject: [PATCH 59/69] loginDialog: Provide a finish method - -The screenShield expects to be able to call finish on the dialog. ---- - js/gdm/loginDialog.js | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index 315a863..0224bd2 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -895,32 +895,36 @@ const LoginDialog = new Lang.Class({ - - this._userManager.connect('user-added', - Lang.bind(this, function(userManager, user) { - this._userList.addUser(user); - })); - - this._userManager.connect('user-removed', - Lang.bind(this, function(userManager, user) { - this._userList.removeUser(user); - })); - }, - - open: function() { - Main.ctrlAltTabManager.addGroup(this.actor, - _("Login Window"), - 'dialog-password-symbolic', - { sortGroup: CtrlAltTab.SortGroup.MIDDLE }); - this._userList.actor.grab_key_focus(); - this.actor.show(); - - return true; - }, - - close: function() { - Main.ctrlAltTabManager.removeGroup(this.dialogLayout); - }, - - addCharacter: function(unichar) { - this._authPrompt.addCharacter(unichar); - }, -+ -+ finish: function(onComplete) { -+ this._authPrompt.finish(onComplete); -+ }, - }); - Signals.addSignalMethods(LoginDialog.prototype); --- -1.8.3.1 - - -From bfc9443c5ff4d4968b2944a009084959684171a1 Mon Sep 17 00:00:00 2001 -From: "Jasper St. Pierre" -Date: Mon, 26 Aug 2013 18:04:09 -0400 -Subject: [PATCH 60/69] loginDialog: Fade in the gdm auth prompt on login - ---- - js/gdm/loginDialog.js | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index 0224bd2..d99d79b 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -884,47 +884,53 @@ const LoginDialog = new Lang.Class({ - } - }, - - _loadUserList: function() { - let users = this._userManager.list_users(); - - for (let i = 0; i < users.length; i++) { - this._userList.addUser(users[i]); - } - - this._updateDisableUserList(); - - this._userManager.connect('user-added', - Lang.bind(this, function(userManager, user) { - this._userList.addUser(user); - })); - - this._userManager.connect('user-removed', - Lang.bind(this, function(userManager, user) { - this._userList.removeUser(user); - })); - }, - - open: function() { - Main.ctrlAltTabManager.addGroup(this.actor, - _("Login Window"), - 'dialog-password-symbolic', - { sortGroup: CtrlAltTab.SortGroup.MIDDLE }); - this._userList.actor.grab_key_focus(); - this.actor.show(); -+ this.actor.opacity = 0; -+ -+ Tweener.addTween(this.actor, -+ { opacity: 255, -+ time: 1, -+ transition: 'easeInQuad' }); - - return true; - }, - - close: function() { - Main.ctrlAltTabManager.removeGroup(this.dialogLayout); - }, - - addCharacter: function(unichar) { - this._authPrompt.addCharacter(unichar); - }, - - finish: function(onComplete) { - this._authPrompt.finish(onComplete); - }, - }); - Signals.addSignalMethods(LoginDialog.prototype); --- -1.8.3.1 - - -From 0534d84dbc65938fe5bea26dcd5749f2e438e428 Mon Sep 17 00:00:00 2001 -From: "Jasper St. Pierre" -Date: Mon, 26 Aug 2013 15:43:27 -0400 -Subject: [PATCH 61/69] unlockDialog: Remove clutter constraints from the code - -These cause annoying allocation cycle warnings, and it's simpler to -just express our desired layout in terms of nested containers. -Adapt the theme to match as well. - -https://bugzilla.gnome.org/show_bug.cgi?id=706843 ---- - data/theme/gnome-shell.css | 8 -------- - js/ui/unlockDialog.js | 10 ++++++---- - 2 files changed, 6 insertions(+), 12 deletions(-) - -diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css -index d0578c2..a0642f2 100644 ---- a/data/theme/gnome-shell.css -+++ b/data/theme/gnome-shell.css -@@ -2205,68 +2205,60 @@ StScrollBar StButton#vhandle:active { - - .candidate-page-button-next { - border-radius: 0px 4px 4px 0px; - } - - .candidate-page-button-icon { - icon-size: 1em; - } - - /* Login Dialog */ - - .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; -- -- padding-bottom: 80px; -- padding-top: 80px; -- -- border-radius: 16px; -- min-height: 150px; -- max-height: 700px; -- min-width: 350px; - } - - .login-dialog-button-box { - spacing: 5px; - } - - .login-dialog-user-list-view { - -st-vfade-offset: 1em; - } - - .login-dialog-user-list { - spacing: 12px; - padding: .2em; - } - - .login-dialog-user-list-item { - border-radius: 10px; - padding: .2em; - } - - .login-dialog-user-list-item:ltr { - padding-right: 1em; - } - - .login-dialog-user-list-item:rtl { - padding-left: 1em; - } - - .login-dialog-user-list-item .login-dialog-user-list-item-name { - font-size: 20pt; -diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js -index 09024ba..abbe8c4 100644 ---- a/js/ui/unlockDialog.js -+++ b/js/ui/unlockDialog.js -@@ -7,74 +7,76 @@ const Gdm = imports.gi.Gdm; - const Gio = imports.gi.Gio; - const GLib = imports.gi.GLib; - const GnomeDesktop = imports.gi.GnomeDesktop; - const Gtk = imports.gi.Gtk; - const Lang = imports.lang; - const Signals = imports.signals; - const Shell = imports.gi.Shell; - const St = imports.gi.St; - - const Layout = imports.ui.layout; - const Main = imports.ui.main; - const Panel = imports.ui.panel; - const Tweener = imports.ui.tweener; - const UserMenu = imports.ui.userMenu; - const UserWidget = imports.ui.userWidget; - - const AuthPrompt = imports.gdm.authPrompt; - const Batch = imports.gdm.batch; - const GdmUtil = imports.gdm.util; - const LoginDialog = imports.gdm.loginDialog; - - // The timeout before going back automatically to the lock screen (in seconds) - const IDLE_TIMEOUT = 2 * 60; - - const UnlockDialog = new Lang.Class({ - Name: 'UnlockDialog', - - _init: function(parentActor) { - this.actor = new St.Widget({ accessible_role: Atk.Role.WINDOW, - style_class: 'login-dialog', -+ layout_manager: new Clutter.BoxLayout(), - visible: false }); - - this.actor.add_constraint(new Layout.MonitorConstraint({ primary: true })); - parentActor.add_child(this.actor); - - this._userManager = AccountsService.UserManager.get_default(); - this._userName = GLib.get_user_name(); - this._user = this._userManager.get_user(this._userName); - -- this._promptBox = new St.BoxLayout({ vertical: true }); -+ this._promptBox = new St.BoxLayout({ vertical: true, -+ x_align: Clutter.ActorAlign.CENTER, -+ y_align: Clutter.ActorAlign.CENTER, -+ x_expand: true, -+ y_expand: true }); - this.actor.add_child(this._promptBox); -- this._promptBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, -- align_axis: Clutter.AlignAxis.BOTH, -- factor: 0.5 })); - - this._authPrompt = new AuthPrompt.AuthPrompt(new Gdm.Client(), AuthPrompt.AuthPromptMode.UNLOCK_ONLY); - this._authPrompt.connect('failed', Lang.bind(this, this._fail)); - this._authPrompt.connect('cancelled', Lang.bind(this, this._fail)); - this._authPrompt.connect('reset', Lang.bind(this, this._onReset)); - this._authPrompt.setPasswordChar('\u25cf'); - this._authPrompt.nextButton.label = _("Unlock"); - - this._promptBox.add_child(this._authPrompt.actor); - - this.allowCancel = false; - - let screenSaverSettings = new Gio.Settings({ schema: 'org.gnome.desktop.screensaver' }); - if (screenSaverSettings.get_boolean('user-switch-enabled')) { - let otherUserLabel = new St.Label({ text: _("Log in as another user"), - style_class: 'login-dialog-not-listed-label' }); - this._otherUserButton = new St.Button({ style_class: 'login-dialog-not-listed-button', - can_focus: true, - child: otherUserLabel, - reactive: true, - x_align: St.Align.START, - x_fill: true }); - this._otherUserButton.connect('clicked', Lang.bind(this, this._otherUserClicked)); - this._promptBox.add_child(this._otherUserButton); - } else { - this._otherUserButton = null; - } - - this._authPrompt.reset(); - this._updateSensitivity(true); --- -1.8.3.1 - - -From 7173c7501671002b986a70187d5b9c029a063b17 Mon Sep 17 00:00:00 2001 -From: "Jasper St. Pierre" -Date: Mon, 26 Aug 2013 15:47:52 -0400 -Subject: [PATCH 62/69] gdm: Remove constraints from authPrompt / loginDialog - as well - -https://bugzilla.gnome.org/show_bug.cgi?id=706843 ---- - data/theme/gnome-shell.css | 1 + - js/gdm/authPrompt.js | 6 +----- - js/gdm/loginDialog.js | 35 +++++++++++++---------------------- - 3 files changed, 15 insertions(+), 27 deletions(-) - -diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css -index a0642f2..9b7fe4a 100644 ---- a/data/theme/gnome-shell.css -+++ b/data/theme/gnome-shell.css -@@ -2218,60 +2218,61 @@ StScrollBar StButton#vhandle:active { - 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 { - border-radius: 10px; - padding: .2em; - } - - .login-dialog-user-list-item:ltr { - padding-right: 1em; - } - - .login-dialog-user-list-item:rtl { - padding-left: 1em; - } - - .login-dialog-user-list-item .login-dialog-user-list-item-name { - font-size: 20pt; - padding-left: 9px; - } - - .login-dialog-user-list:expanded .login-dialog-user-list-item { - color: #666666; - } - - .login-dialog-user-list-item, - .login-dialog-user-list-item:hover .login-dialog-user-list-item-name, - .login-dialog-user-list:expanded .login-dialog-user-list-item:focus .login-dialog-user-list-item-name, - .login-dialog-user-list:expanded .login-dialog-user-list-item:logged-in { - color: white; - text-shadow: black 0px 2px 2px; -diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index 732ad1a..674dd3a 100644 ---- a/js/gdm/authPrompt.js -+++ b/js/gdm/authPrompt.js -@@ -93,61 +93,61 @@ const AuthPrompt = new Lang.Class({ - this._label = new St.Label({ style_class: 'login-dialog-prompt-label' }); - - this.actor.add(this._label, - { expand: true, - x_fill: true, - y_fill: true, - x_align: St.Align.START }); - this._entry = new St.Entry({ style_class: 'login-dialog-prompt-entry', - can_focus: true }); - ShellEntry.addContextMenu(this._entry, { isPassword: true }); - - this.actor.add(this._entry, - { expand: true, - x_fill: true, - y_fill: false, - x_align: St.Align.START }); - - this._entry.grab_key_focus(); - - this._message = new St.Label({ opacity: 0 }); - this._message.clutter_text.line_wrap = true; - this.actor.add(this._message, { x_fill: true, y_align: St.Align.START }); - - this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box', - vertical: false }); - this.actor.add(this._buttonBox, - { expand: true, - x_align: St.Align.MIDDLE, - y_align: St.Align.END }); - -- this._defaultButtonWell = new St.Widget(); -+ this._defaultButtonWell = new St.Widget({ layout_manager: new Clutter.BinLayout() }); - this._defaultButtonWellActor = null; - - this._initButtons(); - - let spinnerIcon = global.datadir + '/theme/process-working.svg'; - this._spinner = new Panel.AnimatedIcon(spinnerIcon, DEFAULT_BUTTON_WELL_ICON_SIZE); - this._spinner.actor.opacity = 0; - this._spinner.actor.show(); - this._defaultButtonWell.add_child(this._spinner.actor); - }, - - _onDestroy: function() { - this._userVerifier.clear(); - this._userVerifier.disconnectAll(); - this._userVerifier = null; - }, - - _initButtons: function() { - this.cancelButton = new St.Button({ style_class: 'modal-dialog-button', - button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, - reactive: true, - can_focus: true, - label: _("Cancel") }); - this.cancelButton.connect('clicked', - Lang.bind(this, function() { - this.cancel(); - })); - this._buttonBox.add(this.cancelButton, - { expand: false, - x_fill: false, -@@ -238,64 +238,60 @@ const AuthPrompt = new Lang.Class({ - if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) - this.reset(); - }, - - _onShowMessage: function(userVerifier, message, type) { - this.setMessage(message, type); - this.emit('prompted'); - }, - - _onVerificationFailed: function() { - this.clear(); - - this.updateSensitivity(true); - this.setActorInDefaultButtonWell(null); - this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED; - }, - - _onVerificationComplete: function() { - this.verificationStatus = AuthPromptStatus.VERIFICATION_SUCCEEDED; - }, - - _onReset: function() { - if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) { - this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; - this.reset(); - } - }, - - addActorToDefaultButtonWell: function(actor) { - this._defaultButtonWell.add_child(actor); -- -- actor.add_constraint(new Clutter.AlignConstraint({ source: this._spinner.actor, -- align_axis: Clutter.AlignAxis.BOTH, -- factor: 0.5 })); - }, - - setActorInDefaultButtonWell: function(actor, animate) { - if (!this._defaultButtonWellActor && - !actor) - return; - - let oldActor = this._defaultButtonWellActor; - - if (oldActor) - Tweener.removeTweens(oldActor); - - let isSpinner; - if (actor == this._spinner.actor) - isSpinner = true; - else - isSpinner = false; - - if (this._defaultButtonWellActor != actor && oldActor) { - if (!animate) { - oldActor.opacity = 0; - } else { - Tweener.addTween(oldActor, - { opacity: 0, - time: DEFAULT_BUTTON_WELL_ANIMATION_TIME, - delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY, - transition: 'linear', - onCompleteScope: this, - onComplete: function() { - if (isSpinner) { -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index d99d79b..1649e4e 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -367,159 +367,151 @@ const SessionMenuButton = new Lang.Class({ - - 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.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._userSelectionBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, -- align_axis: Clutter.AlignAxis.BOTH, -- factor: 0.5 })); - this.actor.add_child(this._userSelectionBox); - - this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner', - text: '' }); - 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.add_constraint(new Clutter.AlignConstraint({ source: this.actor, -- align_axis: Clutter.AlignAxis.BOTH, -- factor: 0.5 })); -- - this.actor.add_child(this._authPrompt.actor); -- this._userList.actor.add_constraint(new Clutter.BindConstraint({ source: this._authPrompt.actor, -- coordinate: Clutter.BindCoordinate.WIDTH })); - - // 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.Bin({ style_class: 'login-dialog-logo-bin', y_expand: true }); -- this._logoBin.set_y_align(Clutter.ActorAlign.END); -- this._logoBin.add_constraint(new Clutter.AlignConstraint({ source: this.actor, -- align_axis: Clutter.AlignAxis.X_AXIS, -- factor: 0.5 })); -- this._logoBin.add_constraint(new Clutter.AlignConstraint({ source: this.actor, -- align_axis: Clutter.AlignAxis.Y_AXIS, -- factor: 1.0 })); -+ this._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 }); - 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); - -@@ -538,65 +530,64 @@ const LoginDialog = new Lang.Class({ - - _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(); - } - }, - - _updateLogoTexture: function(cache, uri) { - if (this._logoFileUri != uri) - return; - -- let icon = null; -+ this._logoBin.destroy_all_children(); - if (this._logoFileUri) -- icon = this._textureCache.load_uri_async(this._logoFileUri, -- -1, _LOGO_ICON_HEIGHT); -- this._logoBin.set_child(icon); -+ 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; - - if (beginRequest == AuthPrompt.BeginRequestType.PROVIDE_USERNAME) { - if (!this._disableUserList) - this._showUserList(); - else - this._hideUserListAskForUsernameAndBeginVerification(); - } else { - this._hideUserListAndBeginVerification(); - } --- -1.8.3.1 - - -From 0f101cb83ce429d209a55be8e8071be51ea1bdf6 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 27 Aug 2013 10:17:26 -0400 -Subject: [PATCH 63/69] authPrompt: give message label an initial style - -This commit consolidates the styles of the various -message types into one 'login-dialog-message' style -and then adds additional styles on top to cover the -differences. - -This allows us to give the message label an initial -style so that is padded properly before any messages -are displayed. - -https://bugzilla.gnome.org/show_bug.cgi?id=706670 ---- - data/theme/gnome-shell.css | 6 ++---- - js/gdm/authPrompt.js | 28 +++++++++++----------------- - 2 files changed, 13 insertions(+), 21 deletions(-) - -diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css -index 9b7fe4a..40b4835 100644 ---- a/data/theme/gnome-shell.css -+++ b/data/theme/gnome-shell.css -@@ -2377,74 +2377,72 @@ StScrollBar StButton#vhandle:active { - - .login-dialog .modal-dialog-button:default { - background-gradient-start: #6793c4; - background-gradient-end: #335d8f; - background-gradient-direction: vertical; - border-color: #16335d; - } - - .login-dialog .modal-dialog-button:default:focus { - border: 2px solid #377fe7; - } - - .login-dialog .modal-dialog-button:default:hover { - background-gradient-start: #74a0d0; - background-gradient-end: #436d9f; - } - - .login-dialog .modal-dialog-button:default:active, - .login-dialog .modal-dialog-button:default:pressed { - background-gradient-start: #436d9f; - background-gradient-end: #74a0d0; - } - - .login-dialog .modal-dialog-button:default:insensitive { - border-color: #666666; - color: #9f9f9f; - background-gradient-direction: none; - background-color: rgba(102, 102, 102, 0.15); - } - --.login-dialog-message-warning, --.login-dialog-message-info { -+.login-dialog-message { - padding-top: 4px; - padding-bottom: 16px; - min-height: 2em; - } - - .login-dialog-message-warning { - color: orange; - } - - .login-dialog-message-hint { -- padding-bottom: 16px; -- min-height: 2em; -+ padding-top: 0px; - } - - .user-widget-label { - font-size: 16pt; - font-weight: bold; - text-align: left; - padding-left: 15px; - text-shadow: black 0px 4px 3px 0px; - } - - /* Screen shield */ - - .screen-shield-background { - background: black; - } - - #lockDialogGroup { - background: #2e3436 url(noise-texture.png); - background-repeat: repeat; - } - - .screen-shield-arrows { - padding-bottom: 3em; - } - - .screen-shield-arrows Gjs_Arrow { - color: white; - width: 80px; - height: 48px; - -arrow-thickness: 12px; -diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js -index 674dd3a..2121f2e 100644 ---- a/js/gdm/authPrompt.js -+++ b/js/gdm/authPrompt.js -@@ -9,62 +9,60 @@ const Panel = imports.ui.panel; - const Batch = imports.gdm.batch; - const GdmUtil = imports.gdm.util; - const Params = imports.misc.params; - const ShellEntry = imports.ui.shellEntry; - const Tweener = imports.ui.tweener; - const UserWidget = imports.ui.userWidget; - - const DEFAULT_BUTTON_WELL_ICON_SIZE = 24; - const DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0; - const DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3; - - const MESSAGE_FADE_OUT_ANIMATION_TIME = 0.5; - - const AuthPromptMode = { - UNLOCK_ONLY: 0, - UNLOCK_OR_LOG_IN: 1 - }; - - const AuthPromptStatus = { - NOT_VERIFYING: 0, - VERIFYING: 1, - VERIFICATION_FAILED: 2, - VERIFICATION_SUCCEEDED: 3 - }; - - const BeginRequestType = { - PROVIDE_USERNAME: 0, - DONT_PROVIDE_USERNAME: 1 - }; - --let _messageStyleMap; -- - const AuthPrompt = new Lang.Class({ - Name: 'AuthPrompt', - - _init: function(gdmClient, mode) { - this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; - - this._gdmClient = gdmClient; - this._mode = mode; - - let reauthenticationOnly; - if (this._mode == AuthPromptMode.UNLOCK_ONLY) - reauthenticationOnly = true; - else if (this._mode == AuthPromptMode.UNLOCK_OR_LOG_IN) - reauthenticationOnly = false; - - this._userVerifier = new GdmUtil.ShellUserVerifier(this._gdmClient, { reauthenticationOnly: reauthenticationOnly }); - - this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion)); - this._userVerifier.connect('show-message', Lang.bind(this, this._onShowMessage)); - this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed)); - this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); - this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); - this._userVerifier.connect('smartcard-status-changed', Lang.bind(this, this._onSmartcardStatusChanged)); - this.smartcardDetected = this._userVerifier.smartcardDetected; - - this.connect('next', Lang.bind(this, function() { - this.updateSensitivity(false); - this.startSpinning(); - if (this._queryingService) { - this._userVerifier.answerQuery(this._queryingService, this._entry.text); -@@ -82,61 +80,62 @@ const AuthPrompt = new Lang.Class({ - this.cancel(); - } - })); - - this._userWell = new St.Bin({ x_fill: true, - x_align: St.Align.START }); - this.actor.add(this._userWell, - { x_align: St.Align.START, - x_fill: true, - y_fill: true, - expand: true }); - this._label = new St.Label({ style_class: 'login-dialog-prompt-label' }); - - this.actor.add(this._label, - { expand: true, - x_fill: true, - y_fill: true, - x_align: St.Align.START }); - this._entry = new St.Entry({ style_class: 'login-dialog-prompt-entry', - can_focus: true }); - ShellEntry.addContextMenu(this._entry, { isPassword: true }); - - this.actor.add(this._entry, - { expand: true, - x_fill: true, - y_fill: false, - x_align: St.Align.START }); - - this._entry.grab_key_focus(); - -- this._message = new St.Label({ opacity: 0 }); -+ this._message = new St.Label({ opacity: 0, -+ styleClass: 'login-dialog-message' }); - this._message.clutter_text.line_wrap = true; - this.actor.add(this._message, { x_fill: true, y_align: St.Align.START }); - - this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box', - vertical: false }); - this.actor.add(this._buttonBox, - { expand: true, - x_align: St.Align.MIDDLE, - y_align: St.Align.END }); - - this._defaultButtonWell = new St.Widget({ layout_manager: new Clutter.BinLayout() }); - this._defaultButtonWellActor = null; - - this._initButtons(); - - let spinnerIcon = global.datadir + '/theme/process-working.svg'; - this._spinner = new Panel.AnimatedIcon(spinnerIcon, DEFAULT_BUTTON_WELL_ICON_SIZE); - this._spinner.actor.opacity = 0; - this._spinner.actor.show(); - this._defaultButtonWell.add_child(this._spinner.actor); - }, - - _onDestroy: function() { - this._userVerifier.clear(); - this._userVerifier.disconnectAll(); - this._userVerifier = null; - }, - - _initButtons: function() { - this.cancelButton = new St.Button({ style_class: 'modal-dialog-button', -@@ -344,81 +343,76 @@ const AuthPrompt = new Lang.Class({ - this._label.show(); - this._entry.show(); - - this._entry.grab_key_focus(); - }, - - getAnswer: function() { - let text; - - if (this._preemptiveAnswer) { - text = this._preemptiveAnswer; - this._preemptiveAnswer = null; - } else { - text = this._entry.get_text(); - } - - return text; - }, - - _fadeOutMessage: function() { - if (this._message.opacity == 0) - return; - Tweener.removeTweens(this._message); - Tweener.addTween(this._message, - { opacity: 0, - time: MESSAGE_FADE_OUT_ANIMATION_TIME, - transition: 'easeOutQuad' - }); - }, - -- _initMessageStyleMap: function() { -- if (_messageStyleMap) -- return; -- -- _messageStyleMap = {}; -- _messageStyleMap[GdmUtil.MessageType.NONE] = ''; -- _messageStyleMap[GdmUtil.MessageType.ERROR] = 'login-dialog-message-warning'; -- _messageStyleMap[GdmUtil.MessageType.INFO] = 'login-dialog-message-info'; -- _messageStyleMap[GdmUtil.MessageType.HINT] = 'login-dialog-message-hint'; -+ setMessage: function(message, type) { -+ if (type == GdmUtil.MessageType.ERROR) -+ this._message.add_style_class_name('login-dialog-message-warning'); -+ else -+ this._message.remove_style_class_name('login-dialog-message-warning'); - -- }, -+ if (type == GdmUtil.MessageType.HINT) -+ this._message.add_style_class_name('login-dialog-message-hint'); -+ else -+ this._message.remove_style_class_name('login-dialog-message-hint'); - -- setMessage: function(message, type) { -- this._initMessageStyleMap(); - if (message) { - Tweener.removeTweens(this._message); - this._message.text = message; -- this._message.styleClass = _messageStyleMap[type]; - this._message.opacity = 255; - } else { -- this._message.styleClass = null; - this._message.opacity = 0; - } - }, - - _updateNextButtonSensitivity: function(sensitive) { - this.nextButton.reactive = sensitive; - this.nextButton.can_focus = sensitive; - }, - - updateSensitivity: function(sensitive) { - this._updateNextButtonSensitivity(sensitive); - this._entry.reactive = sensitive; - this._entry.clutter_text.editable = sensitive; - }, - - hide: function() { - this.setActorInDefaultButtonWell(null, true); - this.actor.hide(); - this._message.opacity = 0; - - this.setUser(null); - - this.updateSensitivity(true); - this._entry.set_text(''); - }, - - setUser: function(user) { - if (user) { - let userWidget = new UserWidget.UserWidget(user); - this._userWell.set_child(userWidget.actor); --- -1.8.3.1 - - -From 6f8fdc032baf8641759d0b03e1873660dbe9c4a5 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 27 Aug 2013 10:28:26 -0400 -Subject: [PATCH 64/69] theme: add bottom badding for login dialog hint - -Since we're getting rid of the top padding, we need to add what we -take away to the bottom padding to keep the size the same. - -https://bugzilla.gnome.org/show_bug.cgi?id=706670 ---- - data/theme/gnome-shell.css | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css -index 40b4835..fe33fe5 100644 ---- a/data/theme/gnome-shell.css -+++ b/data/theme/gnome-shell.css -@@ -2389,60 +2389,61 @@ StScrollBar StButton#vhandle:active { - .login-dialog .modal-dialog-button:default:hover { - background-gradient-start: #74a0d0; - background-gradient-end: #436d9f; - } - - .login-dialog .modal-dialog-button:default:active, - .login-dialog .modal-dialog-button:default:pressed { - background-gradient-start: #436d9f; - background-gradient-end: #74a0d0; - } - - .login-dialog .modal-dialog-button:default:insensitive { - border-color: #666666; - color: #9f9f9f; - background-gradient-direction: none; - background-color: rgba(102, 102, 102, 0.15); - } - - .login-dialog-message { - padding-top: 4px; - padding-bottom: 16px; - min-height: 2em; - } - - .login-dialog-message-warning { - color: orange; - } - - .login-dialog-message-hint { - padding-top: 0px; -+ padding-bottom: 20px; - } - - .user-widget-label { - font-size: 16pt; - font-weight: bold; - text-align: left; - padding-left: 15px; - text-shadow: black 0px 4px 3px 0px; - } - - /* Screen shield */ - - .screen-shield-background { - background: black; - } - - #lockDialogGroup { - background: #2e3436 url(noise-texture.png); - background-repeat: repeat; - } - - .screen-shield-arrows { - padding-bottom: 3em; - } - - .screen-shield-arrows Gjs_Arrow { - color: white; - width: 80px; - height: 48px; - -arrow-thickness: 12px; + _loadUserList: function() { -- -1.8.3.1 +2.5.0 -From 331987e35c3846939a232de758ef513f3e97174c Mon Sep 17 00:00:00 2001 +From 284fef5e484a76d919e9dade90cdc8ea99a304f9 Mon Sep 17 00:00:00 2001 From: Ray Strode -Date: Thu, 29 Aug 2013 11:46:56 -0400 -Subject: [PATCH 65/69] loginDialog: show session menu button when in auth - failed +Date: Tue, 30 Jun 2015 12:51:59 -0400 +Subject: [PATCH 11/19] gdm: fix cancel button when not listed is clicked -Right now we only show the session menu button when verifying, -but we should also show it when verification is failed or we -can end up in situation where the session menu disappears during -an authentication retry. +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. -https://bugzilla.gnome.org/show_bug.cgi?id=707064 +This commit makes cancel work at the "Not Listed?" username screen. --- - js/gdm/loginDialog.js | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) + js/gdm/authPrompt.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index 1649e4e..9d5e243 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -571,61 +571,62 @@ const LoginDialog = new Lang.Class({ - }, - - _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; - - 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) -+ 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' }); +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({ }, - _showRealmLoginHint: function(realmManager, hint) { - if (!hint) + cancel: function() { +- if (this.verificationStatus == AuthPromptStatus.NOT_VERIFYING || this.verificationStatus == AuthPromptStatus.VERIFICATION_SUCCEEDED) { ++ if (this.verificationStatus == AuthPromptStatus.VERIFICATION_SUCCEEDED) { 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); + } + this.reset(); -- -1.8.3.1 +2.5.0 -From 253f51209898c1b9a96d12319e15c97261a621c0 Mon Sep 17 00:00:00 2001 +From b1f7ee30ae333a288528215b0f120d7b342ad448 Mon Sep 17 00:00:00 2001 From: Ray Strode -Date: Thu, 7 Nov 2013 23:15:39 -0500 -Subject: [PATCH 66/69] loginDialog: display banner message when - disable-user-list=true +Date: Fri, 14 Nov 2014 15:57:16 -0500 +Subject: [PATCH 12/19] gdm: fix handling of removed smartcard at startup -The login screen supports showing a banner message which admins -can use to mention login rules or disclaimers. +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 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 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 -This commit moves the banner message to display when prompting to -the user instead of when showing the user list. -It also moves the banner to a more aesthetically pleasing location -on screen, and adds a scrollbar if the message is too long. +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. --- - data/theme/gnome-shell.css | 10 ++++--- - js/gdm/loginDialog.js | 66 +++++++++++++++++++++++++++++++++++++++------- - 2 files changed, 62 insertions(+), 14 deletions(-) + js/gdm/util.js | 5 +++++ + 1 file changed, 5 insertions(+) -diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css -index fe33fe5..4191817 100644 ---- a/data/theme/gnome-shell.css -+++ b/data/theme/gnome-shell.css -@@ -2185,67 +2185,69 @@ 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: 10pt; -- font-weight: bold; -- text-align: center; -+ font-size: 9pt; - color: #666666; -- padding-bottom: 1em; -+ 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 9d5e243..7b2b1d6 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', -@@ -366,155 +367,186 @@ 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: new Clutter.BinLayout(), -+ layout_manager: table, - 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.actor.add_child(this._authPrompt.actor); -+ 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 }); -- this.actor.add_child(this._logoBin); -+ -+ 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); -+ - 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); - - }, - - _updateDisableUserList: function() { -@@ -526,87 +558,101 @@ 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); +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; ++ } }, - _shouldShowSessionMenuButton: function() { - if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFYING && - this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFICATION_FAILED) - return false; + _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; - if (this._user && this._user.is_loaded && this._user.is_logged_in()) - return false; ++ 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; - return true; - }, +- if (oldStatus == AuthPromptStatus.VERIFYING) ++ if (this._userVerifier) + this._userVerifier.cancel(); - _showPrompt: function() { - if (this._authPrompt.actor.visible) + this._queryingService = null; -- -1.8.3.1 +2.5.0 -From e0f3dfb3a34b00898a436a2baffa65901ba6f6f1 Mon Sep 17 00:00:00 2001 +From 8b5dfd5db42a9f5688edb304fd31f09fcbde129b Mon Sep 17 00:00:00 2001 From: Ray Strode -Date: Thu, 9 Jan 2014 10:42:08 -0500 -Subject: [PATCH 67/69] loginDialog: defer loading user list until idle +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 + -In some cases we load the user list after going back -to main loop and in other cases we load the user list -right away (depending on if accounts service is ready). +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 -In the case we load the user list right away we cause a -traceback because loading the user list forces a reset, -which then tries to reset actors which aren't instantiated -yet. +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. -This commit ensures the user list is loaded after the constructor -finishes and the event loop runs irregardless of the accountsservice -state. +Unfortunately it fails to desensitize the next button +up front when the entry starts out empty. -https://bugzilla.gnome.org/show_bug.cgi?id=721868 +This commit addresses that bug. --- - js/gdm/loginDialog.js | 2 +- + js/gdm/authPrompt.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js -index 7b2b1d6..c8d3231 100644 ---- a/js/gdm/loginDialog.js -+++ b/js/gdm/loginDialog.js -@@ -503,61 +503,61 @@ const LoginDialog = new Lang.Class({ - 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); - - 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(); -+ GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, 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); - - }, - - _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(); - } +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({ }, - _updateCancelButton: function() { + updateSensitivity: function(sensitive) { +- this._updateNextButtonSensitivity(sensitive); ++ this._updateNextButtonSensitivity(sensitive && this._entry.text.length > 0); + this._entry.reactive = sensitive; + this._entry.clutter_text.editable = sensitive; + }, -- -1.8.3.1 +2.5.0 -From 06245cfa219edeac9c9a4f879b3a4bc9b64c209f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Tue, 26 Nov 2013 20:52:24 +0100 -Subject: [PATCH 68/69] loginDialog: Implement cancel() +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 -The screen shield expects a cancel() method on the unlockDialog -implementation, but LoginDialog does not provide it currently. +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. -https://bugzilla.gnome.org/show_bug.cgi?id=719378 +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 | 4 ++++ - 1 file changed, 4 insertions(+) + 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 c8d3231..ca2b060 100644 +index 66b8fff..a51ffd5 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js -@@ -936,39 +936,43 @@ const LoginDialog = new Lang.Class({ - this._userList.addUser(user); - })); - - this._userManager.connect('user-removed', - Lang.bind(this, function(userManager, user) { - this._userList.removeUser(user); - })); +@@ -870,7 +870,7 @@ const LoginDialog = new Lang.Class({ }, - open: function() { - Main.ctrlAltTabManager.addGroup(this.actor, - _("Login Window"), - 'dialog-password-symbolic', - { sortGroup: CtrlAltTab.SortGroup.MIDDLE }); - this._userList.actor.grab_key_focus(); - this.actor.show(); - this.actor.opacity = 0; + _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, - { opacity: 255, - time: 1, - transition: 'easeInQuad' }); - - return true; - }, - - close: function() { - Main.ctrlAltTabManager.removeGroup(this.dialogLayout); - }, - -+ cancel: function() { -+ this._authPrompt.cancel(); -+ }, -+ - addCharacter: function(unichar) { - this._authPrompt.addCharacter(unichar); - }, - - finish: function(onComplete) { - this._authPrompt.finish(onComplete); +@@ -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 }); }, - }); - Signals.addSignalMethods(LoginDialog.prototype); -- -1.8.3.1 +2.5.0 -From 7e0f3897195f5e64bca04dc5fab9e5d0553272d2 Mon Sep 17 00:00:00 2001 +From eb2381cff936e62f68d72730dbff2d485408059f Mon Sep 17 00:00:00 2001 From: Ray Strode -Date: Mon, 17 Feb 2014 14:20:31 -0500 -Subject: [PATCH 69/69] loginDialog: make banner message more prominent. +Date: Mon, 3 Aug 2015 14:07:17 -0400 +Subject: [PATCH 19/19] gdm: clear user verifier when finished with it -This commit moves the login banner to the top of the screen, and -ensures it gets shown right away at the Username prompt. +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 --- - data/theme/gnome-shell.css | 13 +++++-------- - js/gdm/loginDialog.js | 44 ++++++++++++++++++++++---------------------- - 2 files changed, 27 insertions(+), 30 deletions(-) + js/gdm/authPrompt.js | 2 ++ + 1 file changed, 2 insertions(+) -diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css -index 4191817..532c8a5 100644 ---- a/data/theme/gnome-shell.css -+++ b/data/theme/gnome-shell.css -@@ -2186,68 +2186,65 @@ 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: 10em; -- height: 10em; --} -- --.login-dialog-banner { -- font-size: 9pt; -- color: #666666; -- width: 30em; -+ padding-top: 96px; -+ padding-left: 1em; -+ height: 14em; -+ max-width: 42em; -+ min-width: 25em; - } - - .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 ca2b060..ee0199c 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); - - 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)); - - this._userList.connect('activate', - Lang.bind(this, function(userList, item) { - this._onUserListActivated(item); - })); - - - this._sessionMenuButton = new SessionMenuButton(); - this._sessionMenuButton.connect('session-activated', -@@ -589,107 +589,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; - }, +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({ - _updateLogoTexture: function(cache, uri) { - if (this._logoFileUri != uri) + finish: function(onComplete) { + if (!this._userVerifier.hasPendingMessages) { ++ this._userVerifier.clear(); + onComplete(); 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(); } +@@ -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(); + })); }, - - _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); -- -1.8.3.1 +2.5.0 diff --git a/SOURCES/pass-mode-parameter-with-accelerators.patch b/SOURCES/pass-mode-parameter-with-accelerators.patch new file mode 100644 index 0000000..66930c3 --- /dev/null +++ b/SOURCES/pass-mode-parameter-with-accelerators.patch @@ -0,0 +1,80 @@ +From 17df7d3b30dee931d1934a5b8783749837569818 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 12 Nov 2014 21:21:44 +0100 +Subject: [PATCH 1/2] shellDBus: Change AcceleratorActivated signature + +Adding new parameters to the signal currently will break keybindings +until gnome-settings-daemon is updated to the new API as well. +Put additional parameters into a dictionary instead to make future +extensions easier. + +https://bugzilla.gnome.org/show_bug.cgi?id=711682 +--- + js/ui/shellDBus.js | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js +index f8b05f4..871a387 100644 +--- a/js/ui/shellDBus.js ++++ b/js/ui/shellDBus.js +@@ -44,8 +44,7 @@ const GnomeShellIface = ' \ + \ + \ + \ +- \ +- \ ++ \ + \ + \ + \ +@@ -190,11 +189,13 @@ const GnomeShell = new Lang.Class({ + + let connection = this._dbusImpl.get_connection(); + let info = this._dbusImpl.get_info(); ++ let params = { 'device-id': GLib.Variant.new('u', deviceid), ++ 'timestamp': GLib.Variant.new('u', timestamp) }; + connection.emit_signal(destination, + this._dbusImpl.get_object_path(), + info ? info.name : null, + 'AcceleratorActivated', +- GLib.Variant.new('(uuu)', [action, deviceid, timestamp])); ++ GLib.Variant.new('(ua{sv})', [action, params])); + }, + + _grabAcceleratorForSender: function(accelerator, flags, sender) { +-- +2.3.6 + + +From 74a42c3f12fa23aa6cdb0f6f1fbe8464efd41640 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 12 Nov 2014 20:49:24 +0100 +Subject: [PATCH 2/2] shellDBus: Add mode parameter to AcceleratorActivated + signal + +This will allow g-s-d to handle actions differently based on the +current mode - namely, allow the power button when locked, but +make sure to never show any dialogs in that case. + +https://bugzilla.gnome.org/show_bug.cgi?id=711682 +--- + js/ui/shellDBus.js | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js +index 871a387..73fbb07 100644 +--- a/js/ui/shellDBus.js ++++ b/js/ui/shellDBus.js +@@ -190,7 +190,8 @@ const GnomeShell = new Lang.Class({ + let connection = this._dbusImpl.get_connection(); + let info = this._dbusImpl.get_info(); + let params = { 'device-id': GLib.Variant.new('u', deviceid), +- 'timestamp': GLib.Variant.new('u', timestamp) }; ++ 'timestamp': GLib.Variant.new('u', timestamp), ++ 'action-mode': GLib.Variant.new('u', Main.actionMode) }; + connection.emit_signal(destination, + this._dbusImpl.get_object_path(), + info ? info.name : null, +-- +2.3.6 + diff --git a/SOURCES/respect-disk-writes-lockdown-setting.patch b/SOURCES/respect-disk-writes-lockdown-setting.patch deleted file mode 100644 index 46f94c4..0000000 --- a/SOURCES/respect-disk-writes-lockdown-setting.patch +++ /dev/null @@ -1,126 +0,0 @@ -From 6625c06d5da50979ea4a350a168abfa5cc1e8498 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Fri, 3 Oct 2014 16:49:21 +0200 -Subject: [PATCH 1/3] screencast: Don't leak recorders on failure - -ShellRecorder.record() may fail, remove the recorder from the map -in that case. - -https://bugzilla.gnome.org/show_bug.cgi?id=737846 ---- - js/ui/screencast.js | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/js/ui/screencast.js b/js/ui/screencast.js -index 168f589..99f0366 100644 ---- a/js/ui/screencast.js -+++ b/js/ui/screencast.js -@@ -109,6 +109,8 @@ const ScreencastService = new Lang.Class({ - this._applyOptionalParameters(recorder, options); - let [success, fileName] = recorder.record(); - returnValue = [success, fileName ? fileName : '']; -+ if (!success) -+ this._stopRecordingForSender(sender); - } - - invocation.return_value(GLib.Variant.new('(bs)', returnValue)); -@@ -142,6 +144,8 @@ const ScreencastService = new Lang.Class({ - this._applyOptionalParameters(recorder, options); - let [success, fileName] = recorder.record(); - returnValue = [success, fileName ? fileName : '']; -+ if (!success) -+ this._stopRecordingForSender(sender); - } - - invocation.return_value(GLib.Variant.new('(bs)', returnValue)); --- -2.1.0 - - -From 6c6e8f04f466909ed16670bc1c1ae77e30deb95d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Fri, 3 Oct 2014 16:40:49 +0200 -Subject: [PATCH 2/3] screencast: Re-add lockdown support - -Commit 81bb7009ea120d3 removed support for the disable-disk-writes -lockdown feature for screencasts, add it back. - -https://bugzilla.gnome.org/show_bug.cgi?id=737846 ---- - js/ui/screencast.js | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - -diff --git a/js/ui/screencast.js b/js/ui/screencast.js -index 99f0366..63caecb 100644 ---- a/js/ui/screencast.js -+++ b/js/ui/screencast.js -@@ -41,6 +41,8 @@ const ScreencastService = new Lang.Class({ - - this._recorders = new Hash.Map(); - -+ this._lockdownSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.lockdown' }); -+ - Main.sessionMode.connect('updated', - Lang.bind(this, this._sessionModeChanged)); - }, -@@ -95,7 +97,8 @@ const ScreencastService = new Lang.Class({ - - ScreencastAsync: function(params, invocation) { - let returnValue = [false, '']; -- if (!Main.sessionMode.allowScreencast) { -+ if (!Main.sessionMode.allowScreencast || -+ this._lockdownSettings.get_boolean('disable-save-to-disk')) { - invocation.return_value(GLib.Variant.new('(bs)', returnValue)); - return; - } -@@ -118,7 +121,8 @@ const ScreencastService = new Lang.Class({ - - ScreencastAreaAsync: function(params, invocation) { - let returnValue = [false, '']; -- if (!Main.sessionMode.allowScreencast) { -+ if (!Main.sessionMode.allowScreencast || -+ this._lockdownSettings.get_boolean('disable-save-to-disk')) { - invocation.return_value(GLib.Variant.new('(bs)', returnValue)); - return; - } --- -2.1.0 - - -From 2cfc69f5ddfd126e2c2be5180e782e67c431631a Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Fri, 3 Oct 2014 16:33:37 +0200 -Subject: [PATCH 3/3] screenshot: Respect lockdown settings - -We allow users/admins to lock down disk writes, respect that when -taking screenshots. - -https://bugzilla.gnome.org/show_bug.cgi?id=737846 ---- - js/ui/screenshot.js | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/js/ui/screenshot.js b/js/ui/screenshot.js -index dd6448e..6e08fb5 100644 ---- a/js/ui/screenshot.js -+++ b/js/ui/screenshot.js -@@ -64,12 +64,15 @@ const ScreenshotService = new Lang.Class({ - - this._screenShooter = new Hash.Map(); - -+ this._lockdownSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.lockdown' }); -+ - Gio.DBus.session.own_name('org.gnome.Shell.Screenshot', Gio.BusNameOwnerFlags.REPLACE, null, null); - }, - - _createScreenshot: function(invocation) { - let sender = invocation.get_sender(); -- if (this._screenShooter.has(sender)) { -+ if (this._screenShooter.has(sender) || -+ this._lockdownSettings.get_boolean('disable-save-to-disk')) { - invocation.return_value(GLib.Variant.new('(bs)', [false, ''])); - return null; - } --- -2.1.0 - diff --git a/SOURCES/support-headless-mode.patch b/SOURCES/support-headless-mode.patch new file mode 100644 index 0000000..f800072 --- /dev/null +++ b/SOURCES/support-headless-mode.patch @@ -0,0 +1,305 @@ +From 261497c9581472621320072c4f243bcc33d75726 Mon Sep 17 00:00:00 2001 +From: Rui Matos +Date: Wed, 10 Jun 2015 16:05:41 +0200 +Subject: [PATCH 1/2] AllView: prevent accessing a NULL effect + +In some cases we might be allocated a size such that +this._grid.topPadding and this._grid.bottomPadding are both 0 which +means that the ScrollView fade effect gets removed. In that case don't +try to access the effect since it will be NULL. + +https://bugzilla.gnome.org/show_bug.cgi?id=750714 +--- + js/ui/appDisplay.js | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js +index ae40f3e..45e5c71 100644 +--- a/js/ui/appDisplay.js ++++ b/js/ui/appDisplay.js +@@ -738,7 +738,8 @@ const AllView = new Lang.Class({ + let fadeOffset = Math.min(this._grid.topPadding, + this._grid.bottomPadding); + this._scrollView.update_fade_effect(fadeOffset, 0); +- this._scrollView.get_effect('fade').fade_edges = true; ++ if (fadeOffset > 0) ++ this._scrollView.get_effect('fade').fade_edges = true; + + if (this._availWidth != availWidth || this._availHeight != availHeight || oldNPages != this._grid.nPages()) { + this._adjustment.value = 0; +-- +2.5.0 + + +From 2076a96ee5ad7669e050de035aa10c33af76d810 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 16 Jul 2015 15:15:41 +0200 +Subject: [PATCH 2/2] layout: Handle the no-monitor case + +--- + js/ui/layout.js | 66 ++++++++++++++++++++++++++++++++------------- + js/ui/lookingGlass.js | 4 +++ + js/ui/messageTray.js | 6 +++-- + js/ui/panel.js | 5 +++- + js/ui/workspaceThumbnail.js | 3 ++- + 5 files changed, 62 insertions(+), 22 deletions(-) + +diff --git a/js/ui/layout.js b/js/ui/layout.js +index e9aab13..d124705 100644 +--- a/js/ui/layout.js ++++ b/js/ui/layout.js +@@ -106,7 +106,10 @@ const MonitorConstraint = new Lang.Class({ + return; + + let monitor; +- if (this._primary) { ++ if (Main.layoutManager.monitors.length == 0) { ++ monitor = new Meta.Rectangle({ width: global.screen_width, ++ height: global.screen_height }); ++ } else if (this._primary) { + monitor = Main.layoutManager.primaryMonitor; + } else { + let index = Math.min(this._index, Main.layoutManager.monitors.length - 1); +@@ -297,7 +300,9 @@ const LayoutManager = new Lang.Class({ + for (let i = 0; i < nMonitors; i++) + this.monitors.push(new Monitor(i, screen.get_monitor_geometry(i))); + +- if (nMonitors == 1) { ++ if (nMonitors == 0) { ++ this.primaryIndex = this.bottomIndex = -1; ++ } else if (nMonitors == 1) { + this.primaryIndex = this.bottomIndex = 0; + } else { + // If there are monitors below the primary, then we need +@@ -311,8 +316,10 @@ const LayoutManager = new Lang.Class({ + } + } + } +- this.primaryMonitor = this.monitors[this.primaryIndex]; +- this.bottomMonitor = this.monitors[this.bottomIndex]; ++ this.primaryMonitor = this.primaryIndex > -1 ? this.monitors[this.primaryIndex] ++ : null; ++ this.bottomMonitor = this.bottomIndex > -1 ? this.monitors[this.bottomIndex] ++ : null; + }, + + _updateHotCorners: function() { +@@ -423,6 +430,10 @@ const LayoutManager = new Lang.Class({ + }, + + _updateKeyboardBox: function() { ++ this.keyboardBox.visible = this.keyboardMonitor != null; ++ if (!this.keyboardBox.visible) ++ return; ++ + this.keyboardBox.set_position(this.keyboardMonitor.x, + this.keyboardMonitor.y + this.keyboardMonitor.height); + this.keyboardBox.set_size(this.keyboardMonitor.width, -1); +@@ -432,17 +443,27 @@ const LayoutManager = new Lang.Class({ + this.screenShieldGroup.set_position(0, 0); + this.screenShieldGroup.set_size(global.screen_width, global.screen_height); + +- this.panelBox.set_position(this.primaryMonitor.x, this.primaryMonitor.y); +- this.panelBox.set_size(this.primaryMonitor.width, -1); ++ if (this.primaryMonitor != null) { ++ this.panelBox.set_position(this.primaryMonitor.x, this.primaryMonitor.y); ++ this.panelBox.set_size(this.primaryMonitor.width, -1); ++ } else { ++ this.panelBox.set_position(0, 0); ++ this.panelBox.set_size(global.screen_width, -1); ++ } + + if (this.keyboardIndex < 0) + this.keyboardIndex = this.primaryIndex; + else + this._updateKeyboardBox(); + +- this.trayBox.set_position(this.bottomMonitor.x, +- this.bottomMonitor.y + this.bottomMonitor.height); +- this.trayBox.set_size(this.bottomMonitor.width, -1); ++ if (this.bottomMonitor != null) { ++ this.trayBox.set_position(this.bottomMonitor.x, ++ this.bottomMonitor.y + this.bottomMonitor.height); ++ this.trayBox.set_size(this.bottomMonitor.width, -1); ++ } else { ++ this.trayBox.set_position(0, global.screen_height); ++ this.trayBox.set_size(global.screen_width, -1); ++ } + }, + + _panelBoxChanged: function() { +@@ -461,9 +482,8 @@ const LayoutManager = new Lang.Class({ + this._rightPanelBarrier = null; + } + +- if (this.panelBox.height) { +- let primary = this.primaryMonitor; +- ++ let primary = this.primaryMonitor; ++ if (this.panelBox.height && primary) { + this._rightPanelBarrier = new Meta.Barrier({ display: global.display, + x1: primary.x + primary.width, y1: primary.y, + x2: primary.x + primary.width, y2: primary.y + this.panelBox.height, +@@ -486,14 +506,16 @@ const LayoutManager = new Lang.Class({ + }, + + _updateTrayBarrier: function() { +- let monitor = this.bottomMonitor; +- + if (this._trayBarrier) { + this._trayPressure.removeBarrier(this._trayBarrier); + this._trayBarrier.destroy(); + this._trayBarrier = null; + } + ++ let monitor = this.bottomMonitor; ++ if (!monitor) ++ return; ++ + this._trayBarrier = new Meta.Barrier({ display: global.display, + x1: monitor.x, x2: monitor.x + monitor.width, + y1: monitor.y + monitor.height, y2: monitor.y + monitor.height, +@@ -544,7 +566,7 @@ const LayoutManager = new Lang.Class({ + }, + + get keyboardMonitor() { +- return this.monitors[this.keyboardIndex]; ++ return this.keyboardIndex > -1 ? this.monitors[this.keyboardIndex] : null; + }, + + get focusIndex() { +@@ -558,7 +580,7 @@ const LayoutManager = new Lang.Class({ + }, + + get focusMonitor() { +- return this.monitors[this.focusIndex]; ++ return this.focusIndex > -1 ? this.monitors[this.focusIndex] : null; + }, + + set keyboardIndex(v) { +@@ -613,7 +635,7 @@ const LayoutManager = new Lang.Class({ + reactive: true }); + this.addChrome(this._coverPane); + +- if (Meta.is_restart()) { ++ if (Meta.is_restart() || global.screen.get_n_monitors() == 0) { + // On restart, we don't do an animation + } else if (Main.sessionMode.isGreeter) { + this.panelBox.translation_y = -this.panelBox.height; +@@ -654,7 +676,7 @@ const LayoutManager = new Lang.Class({ + }, + + _startupAnimation: function() { +- if (Meta.is_restart()) ++ if (Meta.is_restart() || global.screen.get_n_monitors() == 0) + this._startupAnimationComplete(); + else if (Main.sessionMode.isGreeter) + this._startupAnimationGreeter(); +@@ -885,6 +907,9 @@ const LayoutManager = new Lang.Class({ + global.window_group.visible = windowsVisible; + global.top_window_group.visible = windowsVisible; + ++ if (global.screen.get_n_monitors() == 0) ++ return; ++ + for (let i = 0; i < this._trackedActors.length; i++) { + let actorData = this._trackedActors[i], visible; + if (!actorData.trackFullscreen) +@@ -901,6 +926,9 @@ const LayoutManager = new Lang.Class({ + }, + + getWorkAreaForMonitor: function(monitorIndex) { ++ if (monitorIndex < 0) ++ return new Meta.Rectangle(); ++ + // Assume that all workspaces will have the same + // struts and pick the first one. + let ws = global.screen.get_workspace_by_index(0); +@@ -1008,6 +1036,8 @@ const LayoutManager = new Lang.Class({ + // we don't create a strut for it at all. + let side; + let primary = this.primaryMonitor; ++ if (!primary) ++ continue; + if (x1 <= primary.x && x2 >= primary.x + primary.width) { + if (y1 <= primary.y) + side = Meta.Side.TOP; +diff --git a/js/ui/lookingGlass.js b/js/ui/lookingGlass.js +index eb837d8..d5e3353 100644 +--- a/js/ui/lookingGlass.js ++++ b/js/ui/lookingGlass.js +@@ -538,6 +538,8 @@ const Inspector = new Lang.Class({ + return; + + let primary = Main.layoutManager.primaryMonitor; ++ if (!primary) ++ return; + + let [minWidth, minHeight, natWidth, natHeight] = + this._eventHandler.get_preferred_size(); +@@ -1036,6 +1038,8 @@ const LookingGlass = new Lang.Class({ + + _resize: function() { + let primary = Main.layoutManager.primaryMonitor; ++ if (!primary) ++ return; + let myWidth = primary.width * 0.7; + let availableHeight = primary.height - Main.layoutManager.keyboardBox.height; + let myHeight = Math.min(primary.height * 0.7, availableHeight * 0.9); +diff --git a/js/ui/messageTray.js b/js/ui/messageTray.js +index f1ce7f2..0be69bc 100644 +--- a/js/ui/messageTray.js ++++ b/js/ui/messageTray.js +@@ -1995,7 +1995,8 @@ const MessageTray = new Lang.Class({ + + _checkTrayDwell: function(x, y) { + let monitor = Main.layoutManager.bottomMonitor; +- let shouldDwell = (x >= monitor.x && x <= monitor.x + monitor.width && ++ let shouldDwell = monitor && ++ (x >= monitor.x && x <= monitor.x + monitor.width && + y == monitor.y + monitor.height - 1); + if (shouldDwell) { + // We only set up dwell timeout when the user is not hovering over the tray +@@ -2434,7 +2435,8 @@ const MessageTray = new Lang.Class({ + let shouldShowNotification = (hasNotifications && this._trayState == State.HIDDEN && !this._traySummoned); + let nextNotification = this._notificationQueue[0] || null; + if (shouldShowNotification && nextNotification) { +- let limited = this._busy || Main.layoutManager.bottomMonitor.inFullscreen; ++ let bottomMonitor = Main.layoutManager.bottomMonitor; ++ let limited = this._busy || (bottomMonitor && bottomMonitor.inFullscreen); + let showNextNotification = (!limited || nextNotification.forFeedback || nextNotification.urgency == Urgency.CRITICAL); + if (showNextNotification) { + let len = this._notificationQueue.length; +diff --git a/js/ui/panel.js b/js/ui/panel.js +index dd04601..fedc7cc 100644 +--- a/js/ui/panel.js ++++ b/js/ui/panel.js +@@ -931,7 +931,10 @@ const Panel = new Lang.Class({ + + _getPreferredWidth: function(actor, forHeight, alloc) { + alloc.min_size = -1; +- alloc.natural_size = Main.layoutManager.primaryMonitor.width; ++ if (Main.layoutManager.primaryMonitor) ++ alloc.natural_size = Main.layoutManager.primaryMonitor.width; ++ else ++ alloc.natural_size = 0; + }, + + _getPreferredHeight: function(actor, forWidth, alloc) { +diff --git a/js/ui/workspaceThumbnail.js b/js/ui/workspaceThumbnail.js +index 3adc327..bb1c8fe 100644 +--- a/js/ui/workspaceThumbnail.js ++++ b/js/ui/workspaceThumbnail.js +@@ -264,7 +264,8 @@ const WorkspaceThumbnail = new Lang.Class({ + this._createBackground(); + + let monitor = Main.layoutManager.primaryMonitor; +- this.setPorthole(monitor.x, monitor.y, monitor.width, monitor.height); ++ if (monitor) ++ this.setPorthole(monitor.x, monitor.y, monitor.width, monitor.height); + + let windows = global.get_window_actors().filter(Lang.bind(this, function(actor) { + let win = actor.meta_window; +-- +2.5.0 + diff --git a/SOURCES/vertical-monitor-layouts.patch b/SOURCES/vertical-monitor-layouts.patch deleted file mode 100644 index 4caa571..0000000 --- a/SOURCES/vertical-monitor-layouts.patch +++ /dev/null @@ -1,131 +0,0 @@ -From b2f4c99a00e6d69db88b24e2d723f71b272443de Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Tue, 15 Apr 2014 17:24:07 +0200 -Subject: [PATCH 1/2] layout: Don't always extend struts to the screen edge - -NetWM struts are defined in terms of screen edges (rather than monitor -edges), which works poorly with vertical monitor layouts (as it renders -entire monitors unusable). Don't extend struts in those cases. - -https://bugzilla.gnome.org/show_bug.cgi?id=663690 ---- - js/ui/layout.js | 30 +++++++++++++++++++++++++----- - 1 file changed, 25 insertions(+), 5 deletions(-) - -diff --git a/js/ui/layout.js b/js/ui/layout.js -index 141eecc..3dcc858 100644 ---- a/js/ui/layout.js -+++ b/js/ui/layout.js -@@ -1006,19 +1006,39 @@ const LayoutManager = new Lang.Class({ - continue; - - // Ensure that the strut rects goes all the way to the screen edge, -- // as this really what mutter expects. -+ // as this really what mutter expects. However skip this step -+ // in cases where this would render an entire monitor unusable. - switch (side) { - case Meta.Side.TOP: -- y1 = 0; -+ let hasMonitorsAbove = this.monitors.some(Lang.bind(this, -+ function(mon) { -+ return this._isAboveOrBelowPrimary(mon) && -+ mon.y < primary.y; -+ })); -+ if (!hasMonitorsAbove) -+ y1 = 0; - break; - case Meta.Side.BOTTOM: -- y2 = global.screen_height; -+ if (this.primaryIndex == this.bottomIndex) -+ y2 = global.screen_height; - break; - case Meta.Side.LEFT: -- x1 = 0; -+ let hasMonitorsLeft = this.monitors.some(Lang.bind(this, -+ function(mon) { -+ return !this._isAboveOrBelowPrimary(mon) && -+ mon.x < primary.x; -+ })); -+ if (!hasMonitorsLeft) -+ x1 = 0; - break; - case Meta.Side.RIGHT: -- x2 = global.screen_width; -+ let hasMonitorsRight = this.monitors.some(Lang.bind(this, -+ function(mon) { -+ return !this._isAboveOrBelowPrimary(mon) && -+ mon.x > primary.x; -+ })); -+ if (!hasMonitorsRight) -+ x2 = global.screen_width; - break; - } - --- -2.1.0 - - -From ecdd65097513ff9b36afde817db8627b933da7e3 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Wed, 11 Jun 2014 02:16:43 +0200 -Subject: [PATCH 2/2] layout: Do not expand struts to screen edges - -set_builtin_struts() in mutter now handles this for us, so we can kill -off the extra code here. - -https://bugzilla.gnome.org/show_bug.cgi?id=730527 ---- - js/ui/layout.js | 37 ------------------------------------- - 1 file changed, 37 deletions(-) - -diff --git a/js/ui/layout.js b/js/ui/layout.js -index 3dcc858..2f0a5a5 100644 ---- a/js/ui/layout.js -+++ b/js/ui/layout.js -@@ -1005,43 +1005,6 @@ const LayoutManager = new Lang.Class({ - else - continue; - -- // Ensure that the strut rects goes all the way to the screen edge, -- // as this really what mutter expects. However skip this step -- // in cases where this would render an entire monitor unusable. -- switch (side) { -- case Meta.Side.TOP: -- let hasMonitorsAbove = this.monitors.some(Lang.bind(this, -- function(mon) { -- return this._isAboveOrBelowPrimary(mon) && -- mon.y < primary.y; -- })); -- if (!hasMonitorsAbove) -- y1 = 0; -- break; -- case Meta.Side.BOTTOM: -- if (this.primaryIndex == this.bottomIndex) -- y2 = global.screen_height; -- break; -- case Meta.Side.LEFT: -- let hasMonitorsLeft = this.monitors.some(Lang.bind(this, -- function(mon) { -- return !this._isAboveOrBelowPrimary(mon) && -- mon.x < primary.x; -- })); -- if (!hasMonitorsLeft) -- x1 = 0; -- break; -- case Meta.Side.RIGHT: -- let hasMonitorsRight = this.monitors.some(Lang.bind(this, -- function(mon) { -- return !this._isAboveOrBelowPrimary(mon) && -- mon.x > primary.x; -- })); -- if (!hasMonitorsRight) -- x2 = global.screen_width; -- break; -- } -- - let strutRect = new Meta.Rectangle({ x: x1, y: y1, width: x2 - x1, height: y2 - y1}); - let strut = new Meta.Strut({ rect: strutRect, side: side }); - struts.push(strut); --- -2.1.0 - diff --git a/SPECS/gnome-shell.spec b/SPECS/gnome-shell.spec index 4612499..e68e087 100644 --- a/SPECS/gnome-shell.spec +++ b/SPECS/gnome-shell.spec @@ -1,6 +1,6 @@ Name: gnome-shell -Version: 3.8.4 -Release: 45%{?dist} +Version: 3.14.4 +Release: 37%{?dist} Summary: Window management and application launching for GNOME Group: User Interface/Desktops @@ -8,69 +8,49 @@ License: GPLv2+ Provides: desktop-notification-daemon URL: http://live.gnome.org/GnomeShell #VCS: git:git://git.gnome.org/gnome-shell -Source0: http://download.gnome.org/sources/gnome-shell/3.8/%{name}-%{version}.tar.xz +Source0: http://download.gnome.org/sources/gnome-shell/3.14/%{name}-%{version}.tar.xz Source1: org.gnome.shell.gschema.override # Replace Epiphany with Firefox in the default favourite apps list Patch1: gnome-shell-favourite-apps-firefox.patch Patch2: gnome-shell-favourite-apps-yelp.patch Patch3: gnome-shell-favourite-apps-terminal.patch -Patch4: gnome-shell-favourite-apps-empathy.patch -Patch10: 0001-popupMenu-Fix-removing-the-active-menu-from-PopupMen.patch -Patch11: 0001-catch-more-errors-on-extensions-enable-and-disable.patch -Patch12: vertical-monitor-layouts.patch -Patch13: fix-thumbail-box-shrinking.patch -Patch14: 0001-dateMenu-Try-to-use-the-default-calendar-application.patch -Patch15: 0001-appSwitcher-Add-option-to-limit-to-the-current-works.patch - -Patch20: 0001-main-allow-session-mode-to-be-specified-in-the-envir.patch - -Patch30: 0001-network-Do-not-use-timestamp-to-identify-connections.patch -Patch31: 0001-network-Don-t-disable-switch-in-wifi-section-while-c.patch - -Patch40: fix-remote-search-provider-loading.patch +Patch10: support-headless-mode.patch +Patch11: fix-menu-ornament-oddities.patch Patch50: fix-background-leaks.patch -Patch60: 0001-main-Actually-respect-hasWorkspaces.patch -Patch61: 0001-main-Close-runDialog-as-necessary-on-session-mode-ch.patch -Patch62: 0001-keyring-Don-t-unregister-the-prompt-when-disabled.patch -Patch63: 0002-keyring-Cancel-active-prompts-on-disable.patch - -Patch70: 0001-screenshot-Extend-ScreenshotArea-parameter-validatio.patch -Patch71: 0002-screencast-Fix-disabling-screencasts-via-session-mod.patch -Patch72: 0003-screencast-Validate-parameters-of-ScreencastArea.patch -Patch73: 0001-screenshot-Also-validate-parameters-to-FlashArea.patch -Patch74: 0001-shell-screenshot-Only-allow-one-screenshot-request-a.patch -Patch75: respect-disk-writes-lockdown-setting.patch - +Patch60: drop-gsystem-dependency.patch +Patch61: 0001-messageTray-Emit-signal-when-notifications-are-enabl.patch +Patch62: pass-mode-parameter-with-accelerators.patch Patch80: 0001-shellDBus-Add-a-DBus-method-to-load-a-single-extensi.patch Patch81: 0002-extensions-Add-a-SESSION_MODE-extension-type.patch +Patch82: 0001-magnifier-don-t-spew-to-console-when-focus-moves-aro.patch +Patch83: 0001-extensionSystem-Notify-about-extension-issues-on-upd.patch Patch90: 0001-panel-add-an-icon-to-the-ActivitiesButton.patch +Patch91: 0001-app-Fall-back-to-window-title-instead-of-WM_CLASS.patch +Patch92: 0001-gdm-honor-timed-login-delay-even-if-animations-disab.patch Patch99: login-screen-backport.patch -Patch100: gdm-support-pre-authenticated-logins-from-oVirt.patch -Patch101: dont-load-user-list-when-disabled.patch -Patch102: disallow-cancel-after-success.patch -Patch103: fix-login-screen-focus.patch -Patch104: fix-cancel-sensitivity.patch -Patch105: login-banner-fixes.patch -Patch106: fix-session-activation.patch - -Patch110: 0001-Add-support-for-meta_restart-and-MetaDisplay-restart.patch - -%define clutter_version 1.13.4 -%define gnome_bluetooth_version 3.5.5 -%define gobject_introspection_version 0.10.1 -%define gjs_version 1.35.4 -%define mutter_version 3.8.4-12 +Patch100: 0001-screenShield-unblank-when-inserting-smartcard.patch +Patch101: enforce-smartcard-at-unlock.patch +Patch102: disable-unlock-entry-until-question.patch + +Patch110: 0001-shell_dbus_acquire_name-Don-t-leak-error.patch +Patch111: 0002-shell_dbus_acquire_name-Don-t-leak-the-result.patch +Patch112: 0003-Check-error-of-g_dbus_proxy_new_sync-call.patch + +%define clutter_version 1.15.90 +%define gnome_bluetooth_version 1:3.9.0 +%define gobject_introspection_version 1.41.0 +%define gjs_version 1.39.0 +%define mutter_version 3.14.1 %define eds_version 3.5.3 %define gnome_desktop_version 3.7.90 -%define gnome_menus_version 3.5.3 %define json_glib_version 0.13.2 -%define gsettings_desktop_schemas_version 3.7.4 +%define gsettings_desktop_schemas_version 3.11.4 %define caribou_version 0.4.8 %define libcroco_version 0.6.8 %define telepathy_logger_version 0.2.6 @@ -81,7 +61,6 @@ BuildRequires: automake >= 1.10 BuildRequires: gnome-common >= 2.2.0 BuildRequires: libtool >= 1.4.3 BuildRequires: caribou-devel >= %{caribou_version} -BuildRequires: chrpath BuildRequires: clutter-devel >= %{clutter_version} BuildRequires: dbus-glib-devel BuildRequires: desktop-file-utils @@ -89,7 +68,6 @@ BuildRequires: evolution-data-server-devel >= %{eds_version} BuildRequires: gcr-devel BuildRequires: gjs-devel >= %{gjs_version} BuildRequires: glib2-devel -BuildRequires: gnome-menus-devel >= %{gnome_menus_version} BuildRequires: gobject-introspection >= %{gobject_introspection_version} BuildRequires: json-glib-devel >= %{json_glib_version} BuildRequires: upower-devel @@ -122,8 +100,7 @@ BuildRequires: gtk-doc gnome-common %ifnarch s390 s390x Requires: gnome-bluetooth%{?_isa} >= %{gnome_bluetooth_version} %endif -Requires: gnome-desktop3 >= %{gnome_desktop_version} -Requires: gnome-menus%{?_isa} >= %{gnome_menus_version} +Requires: gnome-desktop3%{?_isa} >= %{gnome_desktop_version} # wrapper script uses to restart old GNOME session if run --replace # from the command line Requires: gobject-introspection%{?_isa} >= %{gobject_introspection_version} @@ -132,6 +109,8 @@ Requires: gjs%{?_isa} >= %{gjs_version} Requires: librsvg2%{?_isa} # needed as it is now split from Clutter Requires: json-glib%{?_isa} >= %{json_glib_version} +# For $libdir/mozilla/plugins +Requires: mozilla-filesystem%{?_isa} Requires: mutter%{?_isa} >= %{mutter_version} Requires: upower%{?_isa} Requires: polkit%{?_isa} >= 0.100 @@ -147,8 +126,9 @@ Requires: caribou%{?_isa} >= %{caribou_version} Requires: accountsservice-libs%{?_isa} Requires: gdm-libs%{?_isa} Requires: clutter%{?_isa} >= %{clutter_version} -# needed for screen recording -Requires: gstreamer1-plugins-good +# needed for settings items in menus +Requires: control-center + %description GNOME Shell provides core user interface functions for the GNOME 3 desktop, @@ -172,54 +152,35 @@ be used only by extensions.gnome.org. %patch1 -p1 -b .firefox %patch2 -p1 -b .yelp %patch3 -p1 -b .terminal -%patch4 -p1 -b .empathy - -%patch10 -p1 -b .fix-popup-menu-manager-exception -%patch11 -p1 -b .catch-extension-errors -%patch12 -p1 -b .improve-vertical-monitor-layouts -%patch13 -p1 -b .fix-shrinking-workspace-switcher -%patch14 -p1 -b .use-default-calendar-app -%patch15 -p1 -b .current-workspace-app-switcher-option - -%patch20 -p1 -b .main-allow-session-mode-to-be-specified-in-the-envir -%patch30 -p1 -b .fix-stuck-network-icon -%patch31 -p1 -b .keep-wifi-switch - -%patch40 -p1 -b .fix-remote-search-provider-loading +%patch10 -p1 -b .support-headless-start +%patch11 -p1 -b .fix-menu-ornament-oddities %patch50 -p1 -b .fix-background-leaks -%patch60 -p1 -b .support-has-workspaces -%patch61 -p1 -b .close-run-dialog-on-lock -%patch62 -p1 -b .prevent-fallback-keyring-dialog -%patch63 -p1 -b .cancel-keyring-dialog-on-lock - -%patch70 -p1 -b .validate-screenshot-params -%patch71 -p1 -b .fix-disable-screencasts -%patch72 -p1 -b .validate-screencast-params -%patch73 -p1 -b .validate-screenshot-params -%patch74 -p1 -b .disallow-consecutive-screenshots -%patch75 -p1 -b .respect-disk-writes-lockdown +%patch60 -p1 -b .drop-gsystem-dependency +%patch61 -p1 -b .fix-enable-notifications +%patch62 -p1 -b .pass-mode-parameter-with-accelerators %patch80 -p1 %patch81 -p1 +%patch82 -p1 -b .fix-magnifier-spew +%patch83 -p1 -b .extension-update-notification %patch90 -p1 -b .panel-add-an-icon-to-the-ActivitiesButton +%patch91 -p1 -b .change-fallback-app-name +%patch92 -p1 -b .honor-timed-login-delay-even-if-animations-disabled %patch99 -p1 -b .login-screen-backport -%patch100 -p1 -b .gdm-support-pre-authenticated-logins-from-oVirt -%patch101 -p1 -b .dont-load-user-list-when-disabled -%patch102 -p1 -b .disallow-cancel-after-success -%patch103 -p1 -b .fix-login-screen-focus -%patch104 -p1 -b .fix-cancel-sensitivity -%patch105 -p1 -b .login-banner-fixes -%patch106 -p1 -b .fix-session-activation +%patch100 -p1 -b .unblank-when-inserting-smartcard +%patch101 -p1 -b .enforce-smartcard-at-unlock-time +%patch102 -p1 -b .disable-unlock-entry-until-question -%patch110 -p1 -b .meta-restart +%patch110 -p1 -b .dont-leak +%patch111 -p1 -b .dont-leak-more +%patch112 -p1 -b .clean-exit %build -autoreconf -f (if ! test -x configure; then NOCONFIGURE=1 ./autogen.sh; fi; %configure --disable-static --disable-compile-warnings) make V=1 %{?_smp_mflags} @@ -232,19 +193,12 @@ rm -rf %{buildroot}/%{_libdir}/mozilla/plugins/*.la desktop-file-validate %{buildroot}%{_datadir}/applications/gnome-shell.desktop desktop-file-validate %{buildroot}%{_datadir}/applications/gnome-shell-extension-prefs.desktop desktop-file-validate %{buildroot}%{_datadir}/applications/evolution-calendar.desktop +rm -f %{buildroot}%{_datadir}/applications/gnome-shell-wayland.desktop cp %{SOURCE1} %{buildroot}/%{_datadir}/glib-2.0/schemas %find_lang %{name} -%ifnarch s390 s390x ppc ppc64 ppc64p7 -# The libdir rpath breaks nvidia binary only folks, so we remove it. -# See bug 716572 -# skip on s390(x), workarounds a chrpath issue -chrpath -r %{_libdir}/gnome-shell:%{_libdir}/gnome-bluetooth $RPM_BUILD_ROOT%{_bindir}/gnome-shell -chrpath -r %{_libdir}/gnome-bluetooth $RPM_BUILD_ROOT%{_libdir}/gnome-shell/libgnome-shell.so -%endif - %preun glib-compile-schemas --allow-any-name %{_datadir}/glib-2.0/schemas &> /dev/null ||: @@ -262,11 +216,12 @@ glib-compile-schemas --allow-any-name %{_datadir}/glib-2.0/schemas &> /dev/null %{_datadir}/applications/gnome-shell.desktop %{_datadir}/applications/gnome-shell-extension-prefs.desktop %{_datadir}/applications/evolution-calendar.desktop -%{_datadir}/gnome-control-center/keybindings/50-gnome-shell-screenshot.xml +%{_datadir}/applications/org.gnome.Shell.PortalHelper.desktop %{_datadir}/gnome-control-center/keybindings/50-gnome-shell-system.xml %{_datadir}/gnome-shell/ %{_datadir}/dbus-1/services/org.gnome.Shell.CalendarServer.service %{_datadir}/dbus-1/services/org.gnome.Shell.HotplugSniffer.service +%{_datadir}/dbus-1/services/org.gnome.Shell.PortalHelper.service %{_datadir}/dbus-1/interfaces/org.gnome.Shell.Screencast.xml %{_datadir}/dbus-1/interfaces/org.gnome.Shell.Screenshot.xml %{_datadir}/dbus-1/interfaces/org.gnome.ShellSearchProvider.xml @@ -275,6 +230,7 @@ glib-compile-schemas --allow-any-name %{_datadir}/glib-2.0/schemas &> /dev/null %{_libexecdir}/gnome-shell-calendar-server %{_libexecdir}/gnome-shell-perf-helper %{_libexecdir}/gnome-shell-hotplug-sniffer +%{_libexecdir}/gnome-shell-portal-helper # Co own these directories instead of pulling in GConf # after all, we are trying to get rid of GConf with these files %dir %{_datadir}/GConf @@ -288,6 +244,166 @@ glib-compile-schemas --allow-any-name %{_datadir}/glib-2.0/schemas &> /dev/null %{_libdir}/mozilla/plugins/*.so %changelog +* Tue Oct 13 2015 Ray Strode 3.14.4-37 +- Fix Username: entry when disable-user-list is on + Related: #1262999 + Resolves: 1270378 + +* Thu Oct 08 2015 Florian Müllner - 3.14.4-36 +- Improve connecting to a headless shell via VNC + Related: #1243856 + +* Mon Oct 05 2015 Ray Strode 3.14.4-35 +- Ensure the unlock password entry is desensitized when there's + no password being asked for (Such as when the message is just + "Please insert smartcard") + Resolves: #1262999 + +* Mon Sep 28 2015 Ray Strode 3.14.4-33 +- Enforce smartcard at unlock time, if it's used to login + Resolves: #1263759 + +* Thu Sep 24 2015 Matthias Clasen - 3.14.4-32 +- Avoid abrt reports when the session bus is going away early + Resolves: #1254986 + +* Mon Sep 21 2015 Florian Müllner - 3.14.4-31 +- Notify about outdated extensions on updates + Related: #1261552 + +* Fri Sep 18 2015 Ray Strode 3.14.4-30 +- Another timed login update. Makes the indicator work + when animations are disabled. + Related: #1252424 + +* Tue Sep 15 2015 Ray Strode 3.14.4-29 +- Fix spew when turning on magnifier + Resolves: #1260057 + +* Tue Sep 15 2015 Ray Strode 3.14.4-28 +- Drop gnome-session-xsession dependency + Resolves: #1251495 + +* Fri Sep 11 2015 Ray Strode 3.14.4-27 +- Actually apply patch to unblank when inserting smartcard + Related: #1201756 + +* Tue Aug 18 2015 Ray Strode 3.14.4-26 +- Fix timed login in virtual machines + Resolves: #1252424 + +* Wed Aug 05 2015 Ray Strode 3.14.4-25 +- Fix user switching, which broke in 3.14.4-17 + Related: #1220023 + +* Thu Jul 30 2015 Florian Müllner - 3.14.4-24 +- Fix some menu ornament oddities + Related: #1174373 + +* Fri Jul 24 2015 Florian Müllner - 3.14.4-23 +- Fix a couple more warnings when running headless + Related: #1243856 + +* Thu Jul 23 2015 Ray Strode 3.14.4-22 +- One more update to Next button handling + Resolves: 1240623 + Related: #1240615 + Related: #1174373 + +* Wed Jul 22 2015 Ray Strode 3.14.4-21 +- Make sure Next button starts out desensitized + Resolves: 1240623 + Related: #1240615 + Related: #1174373 + +* Fri Jul 17 2015 Ray Strode 3.14.4-20 +- set next button to next when asking for username + Resolves: 1240615 + Related: #1174373 + +* Fri Jul 17 2015 Florian Müllner - 3.14.4-19 +- Fix bottom tray handling when running headless + Related: #1243856 + +* Thu Jul 16 2015 Florian Müllner - 3.14.4-18 +- Support headless start + Resolves: #1243856 + +* Wed Jul 15 2015 Ray Strode 3.14.4-17 +- Fix wonkiness if user hits escape from Not Listed screen + after typing wrong password + Resolves: #1220023 + +* Fri Jul 10 2015 Florian Müllner - 3.14.4-16 +- Fix user list scrolling on login screen + Resolves: #1184802 + +* Wed Jul 08 2015 Milan Crha 3.14.4-15 +- Rebuild against updated libical and evolution-data-server + Related: #1209787 + +* Wed Jul 08 2015 Milan Crha 3.14.4-14 +- Rebuild against updated libical + Related: #1209787 + +* Fri Jul 03 2015 Ray Strode 3.14.4-13 +- Unblank screen when a smartcard is inserted + Resolves: #1201756 + +* Wed Jul 01 2015 Ray Strode 3.14.4-12 +- Ensure password authentication is used if no authentication scheme is configured +- Ensure smartcard authentication is used if smartcard authentication is configured + + Related: #1174373 1034968 + +* Tue Jun 30 2015 Ray Strode 3.14.4-11 +- Fix cancel button from Not Listed? screen + Resolves: #1182035 + +* Thu Jun 25 2015 Ray Strode 3.14.4-10 +- Make login banner overflow to book view at the right time + Resolves: #1217157 + +* Fri Jun 12 2015 Florian Müllner - 3.14.4-9 +- Make login banner message more prominent + Resolves: rhbz#1182223 + +* Thu May 21 2015 Florian Müllner - 3.14.4-8 +- Pass mode parameter with accelerators + Resolves: rhbz#1028451 + +* Wed May 20 2015 Florian Müllner - 3.14.4-7 +- Change fallback app name + Resolves: rhbz#1125788 + +* Wed May 20 2015 Ray Strode 3.14.4-6 +- More login screen backports + Related: rhbz#1174373 + +* Thu May 14 2015 Florian Müllner - 3.14.4-5 +- Fix enabling/disabling per-app notifications + Resolves: rhbz#1051132 + +* Fri May 08 2015 Florian Müllner - 3.14.4-4 +- Fix removal of libgsystem dependency + Related: rhbz#1174373 + +* Thu May 7 2015 Matthias Clasen - 3.14.4-3 +- Drop use of libgsystem + Related: rhbz#1174373 + +* Thu May 07 2015 Ray Strode 3.14.4-2 +- Drop chrpath weirdness +- Readd browser plugin +- Drop wayland desktop file + Related: rhbz#1174373 + +* Thu May 04 2015 Florian Müllner - 3.14.4-1 +- Update to latest stable 3.14 release + +* Mon May 04 2015 Florian Müllner - 3.8.4-46 +- Rebuild for eds so name bump + * Thu Nov 13 2014 Ray Strode 3.8.4-45 - Don't inform GDM about session changes that came from GDM Resolves: #1163474 @@ -361,7 +477,7 @@ glib-compile-schemas --allow-any-name %{_datadir}/glib-2.0/schemas &> /dev/null - Add a patch for quadbuffer stereo suppport Resolves: rhbz#1108893 -* Wed Apr 16 2014 Florian Müllner - 3.13.4-32 +* Wed Apr 16 2014 Florian Müllner - 3.8.4-32 - Improve vertical monitor layouts Resolves: rhbz#1075240