[gnome-shell/wip/gdm-shell: 2/6] wip: add very rough initial cut at gdm mode (needs-split)



commit 1b5000e0ec175b62fe2d7511f29a08dadce1156e
Author: Ray Strode <rstrode redhat com>
Date:   Mon Jun 27 17:20:38 2011 -0400

    wip: add very rough initial cut at gdm mode (needs-split)
    
    This is just my in-progress code sketch pushed to a branch so
    it's backed up.

 data/Makefile.am              |    1 +
 data/theme/gnome-shell.css    |  100 ++++++++
 js/Makefile.am                |    2 +
 js/ui/calendar.js             |   20 +-
 js/ui/chrome.js               |   10 +-
 js/ui/dateMenu.js             |   76 ++++---
 js/ui/dialog.js               |  228 ++++++++++++++++++
 js/ui/loginDialog.js          |  533 +++++++++++++++++++++++++++++++++++++++++
 js/ui/main.js                 |  226 +++++++++++-------
 js/ui/messageTray.js          |   68 +++---
 js/ui/notificationDaemon.js   |    8 +-
 js/ui/panel.js                |  208 ++++++++++-------
 js/ui/status/accessibility.js |   14 +-
 js/ui/status/keyboard.js      |   22 +-
 js/ui/status/power.js         |   13 +-
 js/ui/status/volume.js        |   14 +-
 js/ui/windowManager.js        |   32 ++--
 17 files changed, 1276 insertions(+), 299 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index 69fb40d..b8c08d6 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -38,6 +38,7 @@ dist_theme_DATA =				\
 	theme/running-indicator.svg		\
 	theme/scroll-hhandle.svg		\
 	theme/scroll-vhandle.svg		\
+	theme/selected-user.svg			\
 	theme/source-button-border.svg		\
 	theme/toggle-off-us.svg			\
 	theme/toggle-off-intl.svg		\
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index 7e7e786..c63c362 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -1661,3 +1661,103 @@ StTooltip StLabel {
 .magnifier-zoom-region.full-screen {
     border-width: 0px;
 }
+/* Copyright 2011, Red Hat, Inc.
+ *
+ * Portions adapted from Mx's data/style/default.css
+ *   Copyright 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+.login-dialog-title {
+    font-size: 14pt;
+    font-weight: bold;
+    color: #666666;
+    padding-bottom: 2em;
+}
+
+.login-dialog {
+    border-radius: 16px;
+    min-height: 150px;
+    max-height: 700px;
+    min-width: 350px;
+}
+
+.login-dialog-user-list {
+    spacing: 12px;
+}
+
+.login-dialog-user-list:rtl {
+}
+
+.login-dialog-user-list-item {
+    color: #cccccc;
+}
+
+.login-dialog-user-list-item:ltr {
+    padding-right: 1em;
+}
+
+.login-dialog-user-list-item:rtl {
+    padding-left: 1em;
+}
+
+.login-dialog-user-list-item:hover {
+    color: white;
+    text-shadow: black 2px 2px 4px 4px;
+}
+
+.login-dialog-user-list-item:active {
+    color: white;
+    text-shadow: black 1px 1px 4px 4px;
+}
+
+.login-dialog-user-list-item-icon {
+    border: 2px solid #8b8b8b;
+    border-radius: 8px;
+    width: 64px;
+    height: 64px;
+}
+
+.login-dialog-user-list-item-name {
+    font-size: 20pt;
+    padding-left: 1em;
+}
+
+.login-dialog-not-listed-button {
+    padding-top: 2em;
+}
+.login-dialog-not-listed-label {
+    font-size: 14pt;
+    font-weight: bold;
+    color: #666666;
+}
+
+.login-dialog-prompt-layout {
+    padding-bottom: 64px;
+}
+.login-dialog-prompt-label {
+    color: white;
+    font-size: 20pt;
+}
+
+.login-dialog-prompt-entry {
+    padding: 4px;
+    border-radius: 4px;
+    border: 2px solid #5656cc;
+    color: black;
+    background-color: white;
+    caret-color: black;
+    caret-size: 1px;
+}
diff --git a/js/Makefile.am b/js/Makefile.am
index a085bfc..5cd0267 100644
--- a/js/Makefile.am
+++ b/js/Makefile.am
@@ -21,6 +21,7 @@ nobase_dist_js_DATA = 	\
 	ui/ctrlAltTab.js	\
 	ui/dash.js		\
 	ui/dateMenu.js		\
+	ui/dialog.js		\
 	ui/dnd.js		\
 	ui/docDisplay.js	\
 	ui/endSessionDialog.js	\
@@ -29,6 +30,7 @@ nobase_dist_js_DATA = 	\
 	ui/iconGrid.js		\
 	ui/lightbox.js		\
 	ui/link.js		\
+	ui/loginDialog.js	\
 	ui/lookingGlass.js	\
 	ui/magnifier.js		\
 	ui/magnifierDBus.js	\
diff --git a/js/ui/calendar.js b/js/ui/calendar.js
index 0f87305..0220f50 100644
--- a/js/ui/calendar.js
+++ b/js/ui/calendar.js
@@ -351,12 +351,14 @@ function Calendar(eventSource) {
 
 Calendar.prototype = {
     _init: function(eventSource) {
-        this._eventSource = eventSource;
+        if (eventSource) {
+            this._eventSource = eventSource;
 
-        this._eventSource.connect('changed', Lang.bind(this,
-                                                       function() {
-                                                           this._update(false);
-                                                       }));
+            this._eventSource.connect('changed', Lang.bind(this,
+                                                           function() {
+                                                               this._update(false);
+                                                           }));
+        }
 
         // FIXME: This is actually the fallback method for GTK+ for the week start;
         // GTK+ by preference uses nl_langinfo (NL_TIME_FIRST_WEEKDAY). We probably
@@ -573,7 +575,7 @@ Calendar.prototype = {
                 this.setDate(newlySelectedDate, false);
             }));
 
-            let hasEvents = this._eventSource.hasEvents(iter);
+            let hasEvents = this._eventSource && this._eventSource.hasEvents(iter);
             let styleClass = 'calendar-day-base calendar-day';
             if (_isWorkDay(iter))
                 styleClass += ' calendar-work-day'
@@ -620,7 +622,8 @@ Calendar.prototype = {
         }
         // Signal to the event source that we are interested in events
         // only from this date range
-        this._eventSource.requestRange(beginDate, iter, forceReload);
+        if (this._eventSource)
+            this._eventSource.requestRange(beginDate, iter, forceReload);
     }
 };
 
@@ -667,6 +670,9 @@ EventsList.prototype = {
     },
 
     _addPeriod: function(header, begin, end, includeDayName, showNothingScheduled) {
+        if (!this._eventSource)
+            return;
+
         let events = this._eventSource.getEvents(begin, end);
 
         let clockFormat = this._desktopSettings.get_string(CLOCK_FORMAT_KEY);;
diff --git a/js/ui/chrome.js b/js/ui/chrome.js
index 474deb9..9b018c2 100644
--- a/js/ui/chrome.js
+++ b/js/ui/chrome.js
@@ -44,10 +44,12 @@ Chrome.prototype = {
         global.screen.connect('notify::n-workspaces',
                               Lang.bind(this, this._queueUpdateRegions));
 
-        Main.overview.connect('showing',
-                             Lang.bind(this, this._overviewShowing));
-        Main.overview.connect('hidden',
-                             Lang.bind(this, this._overviewHidden));
+        if (Main.overview) {
+            Main.overview.connect('showing',
+                                 Lang.bind(this, this._overviewShowing));
+            Main.overview.connect('hidden',
+                                 Lang.bind(this, this._overviewHidden));
+        }
 
         this._updateMonitors();
         this._updateFullscreen();
diff --git a/js/ui/dateMenu.js b/js/ui/dateMenu.js
index a6a5196..708ed77 100644
--- a/js/ui/dateMenu.js
+++ b/js/ui/dateMenu.js
@@ -50,7 +50,9 @@ DateMenuButton.prototype = {
         let hbox;
         let vbox;
 
-        this._eventSource = new Calendar.DBusEventSource();
+        if (global.session_type == Shell.SessionType.USER) {
+            this._eventSource = new Calendar.DBusEventSource();
+        }
 
         let menuAlignment = 0.25;
         if (St.Widget.get_default_direction() == St.TextDirection.RTL)
@@ -73,43 +75,51 @@ DateMenuButton.prototype = {
         this._date.style_class = 'datemenu-date-label';
         vbox.add(this._date);
 
-        this._eventList = new Calendar.EventsList(this._eventSource);
+        if (this._eventSource) {
+            this._eventList = new Calendar.EventsList(this._eventSource);
+        }
 
         // Calendar
         this._calendar = new Calendar.Calendar(this._eventSource);
-        this._calendar.connect('selected-date-changed',
-                               Lang.bind(this, function(calendar, date) {
-                                   this._eventList.setDate(date);
-                               }));
+        if (this._eventList) {
+            this._calendar.connect('selected-date-changed',
+                                   Lang.bind(this, function(calendar, date) {
+                                       this._eventList.setDate(date);
+                                   }));
+        }
         vbox.add(this._calendar.actor);
 
-        item = new PopupMenu.PopupSeparatorMenuItem();
-        item.setColumnWidths(1);
-        vbox.add(item.actor, {y_align: St.Align.END, expand: true, y_fill: false});
-        item = new PopupMenu.PopupMenuItem(_("Date and Time Settings"));
-        item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
-        item.actor.can_focus = false;
-        vbox.add(item.actor);
+        if (global.session_type == Shell.SessionType.USER) {
+            item = new PopupMenu.PopupSeparatorMenuItem();
+            item.setColumnWidths(1);
+            vbox.add(item.actor, {y_align: St.Align.END, expand: true, y_fill: false});
+            item = new PopupMenu.PopupMenuItem(_("Date and Time Settings"));
+            item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
+            item.actor.can_focus = false;
+            vbox.add(item.actor);
 
-        // Add vertical separator
+            // Add vertical separator
 
-        item = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
-                                    pseudo_class: 'highlighted' });
-        item.connect('repaint', Lang.bind(this, _onVertSepRepaint));
-        hbox.add(item);
+            item = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
+                                        pseudo_class: 'highlighted' });
+            item.connect('repaint', Lang.bind(this, _onVertSepRepaint));
+            hbox.add(item);
 
-        // Fill up the second column
+            // Fill up the second column
 
-        vbox = new St.BoxLayout({vertical: true});
-        hbox.add(vbox, { expand: true });
+            vbox = new St.BoxLayout({vertical: true});
+            hbox.add(vbox, { expand: true });
 
-        // Event list
-        vbox.add(this._eventList.actor, { expand: true });
+            // Event list
+            if (this._eventList) {
+                vbox.add(this._eventList.actor, { expand: true });
+            }
 
-        item = new PopupMenu.PopupMenuItem(_("Open Calendar"));
-        item.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
-        item.actor.can_focus = false;
-        vbox.add(item.actor, {y_align: St.Align.END, expand: true, y_fill: false});
+            item = new PopupMenu.PopupMenuItem(_("Open Calendar"));
+            item.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
+            item.actor.can_focus = false;
+            vbox.add(item.actor, {y_align: St.Align.END, expand: true, y_fill: false});
+        }
 
         // Whenever the menu is opened, select today
         this.menu.connect('open-state-changed', Lang.bind(this, function(menu, isOpen) {
diff --git a/js/ui/dialog.js b/js/ui/dialog.js
new file mode 100644
index 0000000..c3df6f2
--- /dev/null
+++ b/js/ui/dialog.js
@@ -0,0 +1,228 @@
+/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
+
+const Clutter = imports.gi.Clutter;
+const Gdk = imports.gi.Gdk;
+const Gio = imports.gi.Gio;
+const GLib = imports.gi.GLib;
+const Lang = imports.lang;
+const Meta = imports.gi.Meta;
+const Pango = imports.gi.Pango;
+const St = imports.gi.St;
+const Shell = imports.gi.Shell;
+const Signals = imports.signals;
+const Gettext = imports.gettext.domain('gnome-shell');
+const _ = Gettext.gettext;
+
+const Params = imports.misc.params;
+
+const CtrlAltTab = imports.ui.ctrlAltTab;
+const Lightbox = imports.ui.lightbox;
+const Main = imports.ui.main;
+const Tweener = imports.ui.tweener;
+
+const OPEN_AND_CLOSE_TIME = 0.1;
+const FADE_OUT_DIALOG_TIME = 1.0;
+
+const State = {
+    OPENED: 0,
+    CLOSED: 1,
+    OPENING: 2,
+    CLOSING: 3,
+    FADED_OUT: 4
+};
+
+function Dialog() {
+    this._init();
+}
+
+Dialog.prototype = {
+    _init: function(params) {
+        params = Params.parse(params, { styleClass: null });
+
+        this.state = State.CLOSED;
+
+        this._group = new St.Group({ visible: false,
+                                     x: 0,
+                                     y: 0 });
+        Main.uiGroup.add_actor(this._group);
+
+        let constraint = new Clutter.BindConstraint({ source: global.stage,
+                                                      coordinate: Clutter.BindCoordinate.POSITION | Clutter.BindCoordinate.SIZE });
+        this._group.add_constraint(constraint);
+
+        this._group.connect('destroy', Lang.bind(this, this._onGroupDestroy));
+
+        this._actionKeys = {};
+        this._group.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
+
+        this._backgroundBin = new St.Bin();
+        this._group.add_actor(this._backgroundBin);
+
+        this._dialogLayout = new St.BoxLayout({ style_class: 'modal-dialog',
+                                                reactive:     true,
+                                                can_focus:    true,
+                                                vertical:     true });
+        if (params.styleClass != null) {
+            this._dialogLayout.add_style_class_name(params.styleClass);
+        }
+
+        this._backgroundBin.add_actor(this._dialogLayout);
+
+        this.contentLayout = new St.BoxLayout({ vertical: true });
+        this._dialogLayout.add(this.contentLayout,
+                               { x_fill:  true,
+                                 y_fill:  true,
+                                 x_align: St.Align.MIDDLE,
+                                 y_align: St.Align.START });
+
+        this._buttonLayout = new St.BoxLayout({ style_class: 'modal-dialog-button-box',
+                                                opacity:     220,
+                                                vertical:    false });
+        this._dialogLayout.add(this._buttonLayout,
+                               { expand:  true,
+                                 x_align: St.Align.MIDDLE,
+                                 y_align: St.Align.END });
+
+        global.focus_manager.add_group(this._dialogLayout);
+        this._initialKeyFocus = this._dialogLayout;
+        this._savedKeyFocus = null;
+    },
+
+    setButtons: function(buttons) {
+        this._actionKeys = {};
+
+        let hadChildren = this._buttonLayout.get_children() > 0;
+
+        this._buttonLayout.destroy_children();
+
+        let i = 0;
+        for (let index in buttons) {
+            let buttonInfo = buttons[index];
+            let label = buttonInfo['label'];
+            let action = buttonInfo['action'];
+            let key = buttonInfo['key'];
+
+            let button = new St.Button({ style_class: 'modal-dialog-button',
+                                         reactive:    true,
+                                         can_focus:   true,
+                                         label:       label });
+
+            let x_alignment;
+            if (buttons.length == 1)
+                x_alignment = St.Align.END;
+            else if (i == 0)
+                x_alignment = St.Align.START;
+            else if (i == buttons.length - 1)
+                x_alignment = St.Align.END;
+            else
+                x_alignment = St.Align.MIDDLE;
+
+            this._initialKeyFocus = button;
+            this._buttonLayout.add(button,
+                                   { expand: true,
+                                     x_fill: false,
+                                     y_fill: false,
+                                     x_align: x_alignment,
+                                     y_align: St.Align.MIDDLE });
+
+            if (!hadChildren) {
+                this._buttonLayout.opacity = 0;
+                Tweener.addTween(this._buttonLayout,
+                                 { opacity: 255,
+                                   time: 0.33,
+                                   transition: 'easeOutQuad',
+                                   onComplete: Lang.bind(this, function() {
+                                   })
+                                 });
+            }
+
+            button.connect('clicked', action);
+
+            if (key)
+                this._actionKeys[key] = action;
+            i++;
+        }
+    },
+
+    _onKeyPressEvent: function(object, keyPressEvent) {
+        let symbol = keyPressEvent.get_key_symbol();
+        let action = this._actionKeys[symbol];
+
+        if (action)
+            action();
+    },
+
+    _onGroupDestroy: function() {
+        this.emit('destroy');
+    },
+
+    _fadeOpen: function() {
+        let monitor = global.get_focus_monitor();
+
+        this._backgroundBin.set_position(monitor.x, monitor.y);
+        this._backgroundBin.set_size(monitor.width, monitor.height);
+
+        this.state = State.OPENING;
+
+        this._initialKeyFocus.grab_key_focus();
+
+        this._dialogLayout.opacity = 255;
+        this._group.opacity = 0;
+        this._group.show();
+        Tweener.addTween(this._group,
+                         { opacity: 255,
+                           time: OPEN_AND_CLOSE_TIME,
+                           transition: 'easeOutQuad',
+                           onComplete: Lang.bind(this,
+                               function() {
+                                   this.state = State.OPENED;
+                                   this.emit('opened');
+                               })
+                         });
+    },
+
+    setInitialKeyFocus: function(actor) {
+        if (actor)
+            this._initialKeyFocus = actor;
+    },
+
+    open: function() {
+        if (this.state == State.OPENED || this.state == State.OPENING)
+            return true;
+
+        Main.ctrlAltTabManager.addGroup(this._group,
+                                        _("Login Window"),
+                                        'dialog-password',
+                                        { sortGroup: CtrlAltTab.SortGroup.MIDDLE });
+
+        Main.pushModal(this._dialogLayout);
+
+        this._fadeOpen();
+        return true;
+    },
+
+    close: function() {
+        if (this.state == State.CLOSED || this.state == State.CLOSING)
+            return;
+
+        this.state = State.CLOSING;
+        this._savedKeyFocus = null;
+
+        Main.popModal(this._dialogLayout);
+
+        Main.ctrlAltTabManager.removeGroup(this._group);
+
+        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();
+                               })
+                         });
+    },
+
+};
+Signals.addSignalMethods(Dialog.prototype);
diff --git a/js/ui/loginDialog.js b/js/ui/loginDialog.js
new file mode 100644
index 0000000..b521048
--- /dev/null
+++ b/js/ui/loginDialog.js
@@ -0,0 +1,533 @@
+/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*-
+ *
+ * Copyright 2010 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 Lang = imports.lang;
+const Signals = imports.signals;
+
+const Gettext = imports.gettext.domain('gnome-shell');
+const _ = Gettext.gettext;
+
+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 Mainloop = imports.mainloop;
+const Pango = imports.gi.Pango;
+const St = imports.gi.St;
+const Shell = imports.gi.Shell;
+const GdmGreeter = imports.gi.GdmGreeter;
+const AccountsService = imports.gi.AccountsService;
+
+const Dialog = imports.ui.dialog;
+const Lightbox = imports.ui.lightbox;
+const Main = imports.ui.main;
+const ModalDialog = imports.ui.modalDialog;
+const Tweener = imports.ui.tweener;
+
+const _DIALOG_ICON_SIZE = 64;
+
+let _loginDialog = null;
+
+function ListItem(user, reason) {
+    this._init(user, reason);
+}
+
+ListItem.prototype = {
+    _init: function(user) {
+        this.user = user;
+
+        let layout = new St.BoxLayout({ vertical: false });
+
+        this.actor = new St.Button({ style_class: 'login-dialog-user-list-item',
+                                     can_focus:   true,
+                                     child:       layout,
+                                     reactive:    true,
+                                     x_align:     St.Align.START,
+                                     x_fill:      true });
+        this._userChangedId = this.user.connect('changed',
+                                                 Lang.bind(this, this._onUserChanged));
+        this._iconBin = new St.Bin();
+        layout.add(this._iconBin);
+        let textLayout = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-text-box',
+                                            vertical:    true });
+        layout.add(textLayout,
+                   { y_fill: false,
+                     y_align: St.Align.MIDDLE,
+                     expand: true });
+
+        this._nameLabel = new St.Label({ text:        this.user.get_real_name(),
+                                         style_class: 'login-dialog-user-list-item-name' });
+        textLayout.add(this._nameLabel);
+
+        this._updateIcon();
+
+        this.actor.connect('clicked', Lang.bind(this, this._onClicked));
+    },
+
+    _onUserChanged: function() {
+        this._nameLabel.set_text(this.user.get_real_name());
+        this._updateIcon();
+    },
+
+    _setIconFromFile: function(iconFile, styleClass) {
+        if (styleClass)
+            this._iconBin.set_style_class_name(styleClass);
+        this._iconBin.set_style(null);
+
+        this._iconBin.child = null;
+        if (iconFile) {
+            this._iconBin.show();
+            this._iconBin.set_style('background-image: url("' + iconFile + '");');
+        } else {
+            this._iconBin.hide();
+        }
+    },
+
+    _setIconFromName: function(iconName, styleClass) {
+        if (styleClass)
+            this._iconBin.set_style_class_name(styleClass);
+        this._iconBin.set_style(null);
+
+        if (iconName != null) {
+            let gicon = new Gio.ThemedIcon({ name: iconName });
+            let icon = new St.Icon();
+            icon.set_gicon(gicon);
+
+            this._iconBin.child = icon;
+            this._iconBin.show();
+        } else {
+            this._iconBin.child = null;
+            this._iconBin.hide();
+        }
+    },
+
+    _updateIcon: function() {
+        let iconFileName = this.user.get_icon_file();
+        let gicon = null;
+
+        if (GLib.file_test(iconFileName, GLib.FileTest.EXISTS)) {
+            this._setIconFromFile(iconFileName, 'login-dialog-user-list-item-icon');
+        } else {
+            this._setIconFromName('avatar-default', 'login-dialog-user-list-item-icon');
+        }
+    },
+
+    _onClicked: function() {
+        this.emit('activate');
+    }
+
+};
+Signals.addSignalMethods(ListItem.prototype);
+
+function UserList() {
+    this._init.apply(this, arguments);
+}
+
+UserList.prototype = {
+    _init: function() {
+        this.actor = new St.ScrollView({ style_class: 'login-dialog-user-list'});
+        this.actor.set_policy(Gtk.PolicyType.NEVER,
+                              Gtk.PolicyType.AUTOMATIC);
+
+        this._layout = new St.BoxLayout({ vertical:    true,
+                                          style_class: 'login-dialog-user-list' });
+
+        this.actor.add_actor(this._layout,
+                             { x_fill:  true,
+                               y_fill:  true,
+                               x_align: St.Align.START,
+                               y_align: St.Align.MIDDLE });
+        this._items = {};
+    },
+
+    _hideItem: function(item) {
+        item.actor.hide();
+    },
+
+    _showItem: function(item) {
+        item.actor.show();
+        item._nameLabel.show();
+    },
+
+    _shrinkItem: function(item) {
+        item._nameLabel.hide();
+    },
+
+    _growItem: function(item) {
+        item._nameLabel.show();
+    },
+
+    _onItemActivated: function(activatedItem) {
+        this.actor.set_policy(Gtk.PolicyType.NEVER,
+                              Gtk.PolicyType.NEVER);
+
+        for (userName in this._items) {
+            let item = this._items[userName];
+            if (item != activatedItem) {
+                this._hideItem(item);
+            } else {
+                this._shrinkItem(item);
+            }
+        }
+
+        this.emit('activate', activatedItem);
+    },
+
+    hideAllUsers: function() {
+        this.actor.set_policy(Gtk.PolicyType.NEVER,
+                              Gtk.PolicyType.NEVER);
+
+        for (userName in this._items) {
+            let item = this._items[userName];
+            this._hideItem(item);
+        }
+    },
+
+    showAllUsers: function() {
+        for (userName in this._items) {
+            let item = this._items[userName];
+            this._showItem(item);
+        }
+
+        this.actor.set_policy(Gtk.PolicyType.NEVER,
+                              Gtk.PolicyType.AUTOMATIC);
+    },
+
+    addUser: function(user) {
+        if (!user.is_loaded)
+            return null;
+
+        let userName = user.get_user_name();
+
+        if (!userName)
+            return null;
+
+        this.removeUser(user);
+
+        let item = new ListItem(user);
+        this._layout.add(item.actor, { x_fill: true });
+
+        this._items[userName] = item;
+
+        item.connect('activate',
+                     Lang.bind(this, this._onItemActivated));
+
+        return item;
+    },
+
+    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);
+
+function LoginDialog() {
+    if (_loginDialog == null) {
+        this._init();
+        _loginDialog = this;
+    }
+
+    return _loginDialog;
+}
+
+LoginDialog.prototype = {
+    __proto__: Dialog.Dialog.prototype,
+
+    _init: function() {
+        Dialog.Dialog.prototype._init.call(this, { styleClass: 'login-dialog' });
+
+        this.connect('destroy',
+                     Lang.bind(this, this._onDestroy));
+        this.connect('opened',
+                     Lang.bind(this, this._onOpened));
+
+        this._userManager = AccountsService.UserManager.get_default()
+        this._greeterClient = new GdmGreeter.Client();
+
+        this._greeterClient.open_connection();
+
+        this._greeterClient.call_start_conversation('gdm-password');
+
+        this._greeterClient.connect('ready',
+                                    Lang.bind(this, this._onReady));
+        this._greeterClient.connect('reset',
+                                    Lang.bind(this, this._onReset));
+        this._greeterClient.connect('info',
+                                    Lang.bind(this, this._onInfo));
+        this._greeterClient.connect('problem',
+                                    Lang.bind(this, this._onProblem));
+        this._greeterClient.connect('info-query',
+                                    Lang.bind(this, this._onInfoQuery));
+        this._greeterClient.connect('secret-info-query',
+                                    Lang.bind(this, this._onSecretInfoQuery));
+        this._greeterClient.connect('session-opened',
+                                    Lang.bind(this, this._onSessionOpened));
+        this._greeterClient.connect('timed-login-requested',
+                                    Lang.bind(this, this._onTimedLoginRequested));
+        this._greeterClient.connect('authentication-failed',
+                                    Lang.bind(this, this._onAuthenticationFailed));
+        this._greeterClient.connect('conversation-stopped',
+                                    Lang.bind(this, this._onConversationStopped));
+
+        this._titleLabel = new St.Label({ style_class: 'login-dialog-title',
+                                          text: _("Sign In") });
+
+        this.contentLayout.add(this._titleLabel,
+                              { y_fill:  false,
+                                y_align: St.Align.START });
+
+        let mainContentLayout = new St.BoxLayout({ vertical: false });
+        this.contentLayout.add(mainContentLayout,
+                               { x_fill: true,
+                                 y_fill: false });
+
+        this._userList = new UserList();
+        mainContentLayout.add(this._userList.actor,
+                              { x_fill: true,
+                                y_fill: true });
+
+        this._promptLayout = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout',
+                                                vertical:    true });
+        mainContentLayout.add(this._promptLayout,
+                              { expand: true,
+                                x_fill: true,
+                                y_fill: true,
+                                x_align: St.Align.START });
+        this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' });
+        this._promptLayout.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' });
+        this._promptLayout.add(this._promptEntry,
+                              { expand: true,
+                                x_fill: true,
+                                y_fill: false,
+                                x_align: St.Align.START});
+        this._promptLayout.hide();
+
+        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',
+                                                can_focus:   true,
+                                                child:       notListedLabel,
+                                                reactive:    true,
+                                                x_align:     St.Align.START,
+                                                x_fill:      true });
+
+        this._notListedButton.connect('clicked', Lang.bind(this, this._onNotListedClicked));
+
+        this.contentLayout.add(this._notListedButton,
+                               { expand: false,
+                                 x_align: St.Align.START,
+                                 x_fill: true });
+
+        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, user) {
+                                   this._onUserListActivated(user);
+                               }));
+
+    },
+
+    _onReady: function(client, serviceName) {
+    },
+
+    _onReset: function(client, serviceName) {
+        this._greeterClient.call_start_conversation('gdm-password');
+
+        this._promptEntry.set_text('');
+
+        if (this._promptEntryActivateCallbackId) {
+            this._promptEntry.clutter_text.disconnect(this._promptEntryActivateCallbackId);
+            this._promptEntryActivateCallbackId = null;
+        }
+
+        this.setButtons([]);
+
+        this._promptLabel.hide();
+        this._promptLayout.hide();
+
+        this._userList.showAllUsers();
+        this._userList.actor.grab_key_focus();
+
+        this._notListedButton.show();
+        this._titleLabel.show();
+    },
+
+    _onInfo: function(client, serviceName, info) {
+        Main.notifyError(info);
+    },
+
+    _onProblem: function(client, serviceName, problem) {
+        Main.notifyError(problem);
+    },
+
+    _onCancel: function(client) {
+        this._greeterClient.call_cancel();
+    },
+
+    _onSignIn: function(serviceName) {
+        let _text = this._promptEntry.get_text();
+        this._promptEntry.set_text('');
+
+        this._greeterClient.call_answer_query(serviceName, _text);
+    },
+
+    _showPrompt: function(callback) {
+        let buttons = [{ action: Lang.bind(this, this._onCancel),
+                         label:  _("Cancel"),
+                         key:    Clutter.Escape },
+                       { action: callback,
+                         label:  _("Sign In") }];
+
+        if (!this._promptLayout.visible) {
+            this._promptLayout.show();
+            this._promptLabel.show();
+            this._promptEntry.show();
+            this._promptEntry.grab_key_focus();
+        }
+
+        this._promptEntryActivateCallbackId = this._promptEntry.clutter_text.connect('activate',
+                                                              Lang.bind(this, function() {
+                                                                  callback();
+                                                                  this._promptEntry.clutter_text.disconnect(this._promptEntryActivateCallbackId);
+                                                                  this._promptEntryActivateCallbackId = null;
+                                                              }));
+
+        this.setButtons(buttons);
+    },
+
+    _onInfoQuery: function(client, serviceName, question) {
+        this._promptEntry.set_text('');
+        this._promptEntry.clutter_text.set_password_char('');
+        this._promptLabel.set_text(question);
+        this._showPrompt(Lang.bind(this, function() {
+                             this._onSignIn(serviceName);
+                         }));
+
+    },
+
+    _onSecretInfoQuery: function(client, serviceName, secretQuestion) {
+        this._promptEntry.set_text('');
+        this._promptEntry.clutter_text.set_password_char('\u25cf');
+        this._promptLabel.set_text(secretQuestion);
+
+        this._showPrompt(Lang.bind(this, function() {
+                             this._onSignIn(serviceName);
+                         }));
+    },
+
+    _onSessionOpened: function(client, serviceName) {
+        this._greeterClient.call_start_session_when_ready(serviceName, true);
+    },
+
+    _onTimedLoginRequested: function(client, serviceName, seconds) {
+    },
+
+    _onAuthenticationFailed: function(client) {
+        this._greeterClient.call_cancel();
+    },
+
+    _onConversationStopped: function(client, serviceName) {
+        this._greeterClient.call_cancel();
+    },
+
+    _onNotListedClicked: function(user) {
+        this._titleLabel.hide();
+        this._notListedButton.hide();
+        this._userList.hideAllUsers();
+        this._greeterClient.call_begin_verification('gdm-password');
+    },
+
+    _onUserListActivated: function(item) {
+        this._titleLabel.hide();
+        this._notListedButton.hide();
+        this._greeterClient.call_begin_verification_for_user('gdm-password',
+                                                             item.user.get_user_name());
+    },
+
+    _onDestroy: function() {
+        if (this._userManagerLoadedId) {
+            this._userManager.disconnect(this._userManagerLoadedId);
+            this._userManagerLoadedId = 0;
+        }
+    },
+
+    _loadUserList: function() {
+        let users = this._userManager.list_users();
+        let item = null;
+
+        for (let i = 0; i < users.length; i++) {
+            if (!item)
+                item = this._userList.addUser(users[i]);
+            else
+                this._userList.addUser(users[i]);
+        }
+
+        this._userManager.connect('user-added',
+                                  Lang.bind(this, function(userManager, user) {
+                                      if (!user.is_system_account())
+                                          this._userList.addUser(user);
+                                  }));
+
+        this._userManager.connect('user-removed',
+                                  Lang.bind(this, function(userManager, user) {
+                                      this._userList.removeUser(user);
+                                  }));
+
+        Mainloop.idle_add(Lang.bind(this, function() {
+            this.emit('loaded');
+        }));
+    },
+
+    _onOpened: function() {
+        this._userList.actor.grab_key_focus();
+    },
+};
diff --git a/js/ui/main.js b/js/ui/main.js
index 43fcfa5..025d0e7 100644
--- a/js/ui/main.js
+++ b/js/ui/main.js
@@ -1,8 +1,11 @@
 /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 
+imports.gi.versions.Clutter = '1.0';
+
 const Clutter = imports.gi.Clutter;
 const DBus = imports.dbus;
 const Gdk = imports.gi.Gdk;
+const GdmGreeter = imports.gi.GdmGreeter;
 const Gio = imports.gi.Gio;
 const GLib = imports.gi.GLib;
 const GConf = imports.gi.GConf;
@@ -18,6 +21,7 @@ const EndSessionDialog = imports.ui.endSessionDialog;
 const PolkitAuthenticationAgent = imports.ui.polkitAuthenticationAgent;
 const Environment = imports.ui.environment;
 const ExtensionSystem = imports.ui.extensionSystem;
+const LoginDialog = imports.ui.loginDialog;
 const MessageTray = imports.ui.messageTray;
 const Overview = imports.ui.overview;
 const Panel = imports.ui.panel;
@@ -39,10 +43,12 @@ const DEFAULT_BACKGROUND_COLOR = new Clutter.Color();
 DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
 
 let chrome = null;
+let greeterClient = null;
 let panel = null;
 let hotCorners = [];
 let placesManager = null;
 let overview = null;
+let loginDialog = null;
 let runDialog = null;
 let lookingGlass = null;
 let wm = null;
@@ -109,15 +115,17 @@ function start() {
     _defaultCssStylesheet = global.datadir + '/theme/gnome-shell.css';
     loadTheme();
 
-    let shellwm = global.window_manager;
-    shellwm.takeover_keybinding('panel_main_menu');
-    shellwm.connect('keybinding::panel_main_menu', function () {
-        overview.toggle();
-    });
-    shellwm.takeover_keybinding('panel_run_dialog');
-    shellwm.connect('keybinding::panel_run_dialog', function () {
-       getRunDialog().open();
-    });
+    if (global.session_type == Shell.SessionType.USER) {
+        let shellwm = global.window_manager;
+        shellwm.takeover_keybinding('panel_main_menu');
+        shellwm.connect('keybinding::panel_main_menu', function () {
+            overview.toggle();
+        });
+        shellwm.takeover_keybinding('panel_run_dialog');
+        shellwm.connect('keybinding::panel_run_dialog', function () {
+           getRunDialog().open();
+        });
+    }
 
     // Set up stage hierarchy to group all UI actors under one container.
     uiGroup = new Clutter.Group();
@@ -126,10 +134,14 @@ function start() {
     global.overlay_group.reparent(uiGroup);
     global.stage.add_actor(uiGroup);
 
-    placesManager = new PlaceDisplay.PlacesManager();
+    if (global.session_type == Shell.SessionType.USER) {
+        placesManager = new PlaceDisplay.PlacesManager();
+    }
     xdndHandler = new XdndHandler.XdndHandler();
     ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
-    overview = new Overview.Overview();
+    if (global.session_type == Shell.SessionType.USER) {
+        overview = new Overview.Overview();
+    }
     chrome = new Chrome.Chrome();
     magnifier = new Magnifier.Magnifier();
     statusIconDispatcher = new StatusIconDispatcher.StatusIconDispatcher();
@@ -138,43 +150,61 @@ function start() {
     messageTray = new MessageTray.MessageTray();
     notificationDaemon = new NotificationDaemon.NotificationDaemon();
     windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
-    telepathyClient = new TelepathyClient.Client();
 
-    overview.init();
+    if (global.session_type == Shell.SessionType.USER) {
+        telepathyClient = new TelepathyClient.Client();
+    }
+
+    if (global.session_type == Shell.SessionType.USER) {
+        overview.init();
+    }
     statusIconDispatcher.start(messageTray.actor);
 
     _startDate = new Date();
 
-    let recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' });
+    if (global.session_type == Shell.SessionType.USER) {
+        let recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' });
 
-    global.screen.connect('toggle-recording', function() {
-        if (recorder == null) {
-            recorder = new Shell.Recorder({ stage: global.stage });
-        }
+        global.screen.connect('toggle-recording', function() {
+            if (recorder == null) {
+                recorder = new Shell.Recorder({ stage: global.stage });
+            }
 
-        if (recorder.is_recording()) {
-            recorder.pause();
-        } else {
-            // read the parameters from GSettings always in case they have changed
-            recorder.set_framerate(recorderSettings.get_int('framerate'));
-            recorder.set_filename('shell-%d%u-%c.' + recorderSettings.get_string('file-extension'));
-            let pipeline = recorderSettings.get_string('pipeline');
+            if (recorder.is_recording()) {
+                recorder.pause();
+            } else {
+                // read the parameters from GSettings always in case they have changed
+                recorder.set_framerate(recorderSettings.get_int('framerate'));
+                recorder.set_filename('shell-%d%u-%c.' + recorderSettings.get_string('file-extension'));
+                let pipeline = recorderSettings.get_string('pipeline');
 
-            if (!pipeline.match(/^\s*$/))
-                recorder.set_pipeline(pipeline);
-            else
-                recorder.set_pipeline(null);
+                if (!pipeline.match(/^\s*$/))
+                    recorder.set_pipeline(pipeline);
+                else
+                    recorder.set_pipeline(null);
 
-            recorder.record();
-        }
-    });
+                recorder.record();
+            }
+        });
+    }
 
-    global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT, false, -1, 1);
+    if (global.session_type == Shell.SessionType.LOGIN) {
+        global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT, false, 1, 1);
+    } else {
+        global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT, false, -1, 1);
+    }
 
     // Provide the bus object for gnome-session to
     // initiate logouts.
     EndSessionDialog.init();
 
+    if (global.session_type == Shell.SessionType.LOGIN) {
+        loginDialog = new LoginDialog.LoginDialog();
+        loginDialog.connect('loaded', function() {
+                                loginDialog.open();
+                            });
+    }
+
     // Attempt to become a PolicyKit authentication agent
     PolkitAuthenticationAgent.init()
 
@@ -189,8 +219,10 @@ function start() {
     panel.startStatusArea();
     panel.startupAnimation();
 
-    let display = global.screen.get_display();
-    display.connect('overlay-key', Lang.bind(overview, overview.toggle));
+    if (global.session_type == Shell.SessionType.USER) {
+        let display = global.screen.get_display();
+        display.connect('overlay-key', Lang.bind(overview, overview.toggle));
+    }
 
     global.stage.connect('captured-event', _globalKeyPressHandler);
 
@@ -488,73 +520,77 @@ function _relayout() {
         hotCorners[i].destroy();
     hotCorners = [];
 
+    if (global.session_type == Shell.SessionType.USER) {
+        let primary = global.get_primary_monitor();
+        for (let i = 0; i < monitors.length; i++) {
+            let monitor = monitors[i];
+            let isPrimary = (monitor.x == primary.x &&
+                             monitor.y == primary.y &&
+                             monitor.width == primary.width &&
+                             monitor.height == primary.height);
 
-    let primary = global.get_primary_monitor();
-    for (let i = 0; i < monitors.length; i++) {
-        let monitor = monitors[i];
-        let isPrimary = (monitor.x == primary.x &&
-                         monitor.y == primary.y &&
-                         monitor.width == primary.width &&
-                         monitor.height == primary.height);
-
-        let cornerX = monitor.x;
-        let cornerY = monitor.y;
-        if (St.Widget.get_default_direction() == St.TextDirection.RTL)
-            cornerX += monitor.width;
+            let cornerX = monitor.x;
+            let cornerY = monitor.y;
+            if (St.Widget.get_default_direction() == St.TextDirection.RTL)
+                cornerX += monitor.width;
 
 
-        let haveTopLeftCorner = true;
+            let haveTopLeftCorner = true;
 
-        /* Check if we have a top left (right for RTL) corner.
-         * I.e. if there is no monitor directly above or to the left(right) */
-        let besideX;
-        if (St.Widget.get_default_direction() == St.TextDirection.RTL)
-            besideX = monitor.x + 1;
-        else
-            besideX = cornerX - 1;
-        let besideY = cornerY;
-        let aboveX = cornerX;
-        let aboveY = cornerY - 1;
-
-        for (let j = 0; j < monitors.length; j++) {
-            if (i == j)
-                continue;
-            let otherMonitor = monitors[j];
-            if (besideX >= otherMonitor.x &&
-                besideX < otherMonitor.x + otherMonitor.width &&
-                besideY >= otherMonitor.y &&
-                besideY < otherMonitor.y + otherMonitor.height) {
-                haveTopLeftCorner = false;
-                break;
-            }
-            if (aboveX >= otherMonitor.x &&
-                aboveX < otherMonitor.x + otherMonitor.width &&
-                aboveY >= otherMonitor.y &&
-                aboveY < otherMonitor.y + otherMonitor.height) {
-                haveTopLeftCorner = false;
-                break;
+            /* Check if we have a top left (right for RTL) corner.
+             * I.e. if there is no monitor directly above or to the left(right) */
+            let besideX;
+            if (St.Widget.get_default_direction() == St.TextDirection.RTL)
+                besideX = monitor.x + 1;
+            else
+                besideX = cornerX - 1;
+            let besideY = cornerY;
+            let aboveX = cornerX;
+            let aboveY = cornerY - 1;
+
+            for (let j = 0; j < monitors.length; j++) {
+                if (i == j)
+                    continue;
+                let otherMonitor = monitors[j];
+                if (besideX >= otherMonitor.x &&
+                    besideX < otherMonitor.x + otherMonitor.width &&
+                    besideY >= otherMonitor.y &&
+                    besideY < otherMonitor.y + otherMonitor.height) {
+                    haveTopLeftCorner = false;
+                    break;
+                }
+                if (aboveX >= otherMonitor.x &&
+                    aboveX < otherMonitor.x + otherMonitor.width &&
+                    aboveY >= otherMonitor.y &&
+                    aboveY < otherMonitor.y + otherMonitor.height) {
+                    haveTopLeftCorner = false;
+                    break;
+                }
             }
-        }
 
-        /* We only want hot corners where there is a natural top-left
-         * corner, and on the primary monitor */
-        if (!isPrimary && !haveTopLeftCorner)
-            continue;
+            /* We only want hot corners where there is a natural top-left
+             * corner, and on the primary monitor */
+            if (!isPrimary && !haveTopLeftCorner)
+                continue;
 
-        let corner = new Panel.HotCorner(isPrimary ? panel.button : null);
-        hotCorners.push(corner);
-        corner.actor.set_position(cornerX, cornerY);
-        if (isPrimary)
-            panel.setHotCorner(corner);
+            let corner = new Panel.HotCorner(isPrimary ? panel.button : null);
+            hotCorners.push(corner);
+            corner.actor.set_position(cornerX, cornerY);
+            if (isPrimary)
+                panel.setHotCorner(corner);
+        }
     }
 
     panel.relayout();
-    overview.relayout();
 
-    // To avoid updating the position and size of the workspaces
-    // in the overview, we just hide the overview. The positions
-    // will be updated when it is next shown.
-    overview.hide();
+    if (global.session_type == Shell.SessionType.USER) {
+        overview.relayout();
+
+        // To avoid updating the position and size of the workspaces
+        // in the overview, we just hide the overview. The positions
+        // will be updated when it is next shown.
+        overview.hide();
+    }
 }
 
 function isWindowActorDisplayedOnWorkspace(win, workspaceIndex) {
@@ -597,6 +633,10 @@ function _globalKeyPressHandler(actor, event) {
         return true;
     }
 
+    if (global.session_type != Shell.SessionType.USER) {
+        return false;
+    }
+
     // Other bindings are only available when the overview is up and
     // no modal dialog is present.
     if (!overview.visible || modalCount > 1)
@@ -796,7 +836,9 @@ function activateWindow(window, time, workspaceNum) {
         window.activate(time);
     }
 
-    overview.hide();
+    if (global.session_type == Shell.SessionType.USER) {
+        overview.hide();
+    }
 }
 
 // TODO - replace this timeout with some system to guess when the user might
diff --git a/js/ui/messageTray.js b/js/ui/messageTray.js
index 1ae3fd7..1df6a54 100644
--- a/js/ui/messageTray.js
+++ b/js/ui/messageTray.js
@@ -213,14 +213,16 @@ FocusGrabber.prototype = {
         this._capturedEventId = 0;
         this._togglingFocusGrabMode = false;
 
-        Main.overview.connect('showing', Lang.bind(this,
-            function() {
-                this._toggleFocusGrabMode();
-            }));
-        Main.overview.connect('hidden', Lang.bind(this,
-            function() {
-                this._toggleFocusGrabMode();
-            }));
+        if (Main.overview) {
+            Main.overview.connect('showing', Lang.bind(this,
+                function() {
+                    this._toggleFocusGrabMode();
+                }));
+            Main.overview.connect('hidden', Lang.bind(this,
+                function() {
+                    this._toggleFocusGrabMode();
+                }));
+        }
     },
 
     grabFocus: function(actor) {
@@ -234,7 +236,7 @@ FocusGrabber.prototype = {
         this._prevFocusedWindow = metaDisplay.focus_window;
         this._prevKeyFocusActor = global.stage.get_key_focus();
 
-        if (!Main.overview.visible)
+        if (!Main.overview || !Main.overview.visible)
             global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
 
         // Use captured-event to notice clicks outside the focused actor
@@ -1247,7 +1249,11 @@ MessageTray.prototype = {
         this._notificationExpandedId = 0;
         this._summaryBoxPointerState = State.HIDDEN;
         this._summaryBoxPointerTimeoutId = 0;
-        this._overviewVisible = Main.overview.visible;
+        if (Main.overview && Main.overview.visible) {
+            this._overviewVisible = true;
+        } else {
+            this._overviewVisible = false;
+        }
         this._notificationRemoved = false;
         this._reNotifyAfterHideNotification = null;
 
@@ -1260,26 +1266,28 @@ MessageTray.prototype = {
 
         this._setSizePosition();
 
-        Main.overview.connect('showing', Lang.bind(this,
-            function() {
-                this._overviewVisible = true;
-                if (this._locked) {
-                    this._unsetClickedSummaryItem();
-                    this._unlock();
-                } else {
-                    this._updateState();
-                }
-            }));
-        Main.overview.connect('hiding', Lang.bind(this,
-            function() {
-                this._overviewVisible = false;
-                if (this._locked) {
-                    this._unsetClickedSummaryItem();
-                    this._unlock();
-                } else {
-                    this._updateState();
-                }
-            }));
+        if (Main.overview) {
+            Main.overview.connect('showing', Lang.bind(this,
+                function() {
+                    this._overviewVisible = true;
+                    if (this._locked) {
+                        this._unsetClickedSummaryItem();
+                        this._unlock();
+                    } else {
+                        this._updateState();
+                    }
+                }));
+            Main.overview.connect('hiding', Lang.bind(this,
+                function() {
+                    this._overviewVisible = false;
+                    if (this._locked) {
+                        this._unsetClickedSummaryItem();
+                        this._unlock();
+                    } else {
+                        this._updateState();
+                    }
+                }));
+        }
 
         this._summaryItems = [];
         // We keep a list of new summary items that were added to the summary since the last
diff --git a/js/ui/notificationDaemon.js b/js/ui/notificationDaemon.js
index 35eb581..a33870a 100644
--- a/js/ui/notificationDaemon.js
+++ b/js/ui/notificationDaemon.js
@@ -102,8 +102,10 @@ NotificationDaemon.prototype = {
 
         Shell.WindowTracker.get_default().connect('notify::focus-app',
             Lang.bind(this, this._onFocusAppChanged));
-        Main.overview.connect('hidden',
-            Lang.bind(this, this._onFocusAppChanged));
+        if (Main.overview) {
+            Main.overview.connect('hidden',
+                Lang.bind(this, this._onFocusAppChanged));
+        }
     },
 
     _iconForNotificationData: function(icon, hints, size) {
@@ -476,7 +478,7 @@ Source.prototype = {
             this.notifications.length > 0)
             return false;
 
-        if (Main.overview.visible) {
+        if (Main.overview && Main.overview.visible) {
             // We can't just connect to Main.overview's 'hidden' signal,
             // because it's emitted *before* it calls popModal()...
             let id = global.connect('notify::stage-input-mode', Lang.bind(this,
diff --git a/js/ui/panel.js b/js/ui/panel.js
index 7569f39..cbdf4d9 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -48,6 +48,14 @@ try {
     log('NMApplet is not supported. It is possible that your NetworkManager version is too old');
 }
 
+const LOGIN_TRAY_ICON_ORDER = ['a11y', 'display', 'keyboard', 'volume', 'battery'];
+const LOGIN_TRAY_ICON_SHELL_IMPLEMENTATION = {
+    'a11y': imports.ui.status.accessibility.ATIndicator,
+    'volume': imports.ui.status.volume.Indicator,
+    'battery': imports.ui.status.power.Indicator,
+    'keyboard': imports.ui.status.keyboard.XKBIndicator
+};
+
 // To make sure the panel corners blend nicely with the panel,
 // we draw background and borders the same way, e.g. drawing
 // them as filled shapes from the outside inwards instead of
@@ -56,6 +64,8 @@ try {
 // to blend border and background color together.
 // For that purpose we use the following helper methods, taken
 // from st-theme-node-drawing.c
+
+
 function _norm(x) {
     return Math.round(x / 255);
 }
@@ -65,6 +75,7 @@ function _over(srcColor, dstColor) {
     let dst = _premultiply(dstColor);
     let result = new Clutter.Color();
 
+
     result.alpha = src.alpha + _norm((255 - src.alpha) * dst.alpha);
     result.red = src.red + _norm((255 - src.alpha) * dst.red);
     result.green = src.green + _norm((255 - src.alpha) * dst.green);
@@ -270,15 +281,17 @@ AppMenuButton.prototype = {
         this.menu.addMenuItem(this._quitMenu);
         this._quitMenu.connect('activate', Lang.bind(this, this._onQuit));
 
-        this._visible = !Main.overview.visible;
-        if (!this._visible)
-            this.actor.hide();
-        Main.overview.connect('hiding', Lang.bind(this, function () {
-            this.show();
-        }));
-        Main.overview.connect('showing', Lang.bind(this, function () {
-            this.hide();
-        }));
+        if (Main.overview) {
+            this._visible = !Main.overview.visible;
+            if (!this._visible)
+                this.actor.hide();
+            Main.overview.connect('hiding', Lang.bind(this, function () {
+                this.show();
+            }));
+            Main.overview.connect('showing', Lang.bind(this, function () {
+                this.hide();
+            }));
+        }
 
         this._stop = true;
 
@@ -819,12 +832,22 @@ Panel.prototype = {
 
         this._statusArea = {};
 
-        Main.overview.connect('shown', Lang.bind(this, function () {
-            this.actor.add_style_class_name('in-overview');
-        }));
-        Main.overview.connect('hiding', Lang.bind(this, function () {
-            this.actor.remove_style_class_name('in-overview');
-        }));
+        if (Main.overview) {
+            Main.overview.connect('shown', Lang.bind(this, function () {
+                this.actor.add_style_class_name('in-overview');
+            }));
+            Main.overview.connect('hiding', Lang.bind(this, function () {
+                this.actor.remove_style_class_name('in-overview');
+            }));
+        }
+
+        if (global.session_type == Shell.SessionType.LOGIN) {
+            this._tray_icon_order = LOGIN_TRAY_ICON_ORDER;
+            this._tray_icon_shell_implementation = LOGIN_TRAY_ICON_SHELL_IMPLEMENTATION;
+        } else {
+            this._tray_icon_order = STANDARD_TRAY_ICON_ORDER;
+            this._tray_icon_shell_implementation = STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION;
+        }
 
         this._leftPointerBarrier = 0;
         this._rightPointerBarrier = 0;
@@ -908,39 +931,41 @@ Panel.prototype = {
             this._rightBox.allocate(childBox, flags);
         }));
 
-        /* Button on the left side of the panel. */
-        /* Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview". */
-        let label = new St.Label({ text: _("Activities") });
-        this.button = new St.Button({ name: 'panelActivities',
-                                      style_class: 'panel-button',
-                                      reactive: true,
-                                      can_focus: true });
-        this._activities = this.button;
-        this.button.set_child(label);
-        this.button._delegate = this.button;
-        this.button._xdndTimeOut = 0;
-        this.button.handleDragOver = Lang.bind(this,
-            function(source, actor, x, y, time) {
-                 if (source == Main.xdndHandler) {
-                    if (this.button._xdndTimeOut != 0)
-                        Mainloop.source_remove(this.button._xdndTimeOut);
-                    this.button._xdndTimeOut = Mainloop.timeout_add(BUTTON_DND_ACTIVATION_TIMEOUT,
-                                                                    Lang.bind(this,
-                                                                                function() {
-                                                                                    this._xdndShowOverview(actor);
-                                                                                }));
-                 }
-            });
-        this._leftBox.add(this.button);
-
-        // Synchronize the buttons pseudo classes with its corner
-        this.button.connect('style-changed', Lang.bind(this,
-            function(actor) {
-                let rtl = actor.get_direction() == St.TextDirection.RTL;
-                let corner = rtl ? this._rightCorner : this._leftCorner;
-                let pseudoClass = actor.get_style_pseudo_class();
-                corner.actor.set_style_pseudo_class(pseudoClass);
-            }));
+        if (global.session_type == Shell.SessionType.USER) {
+            /* Button on the left side of the panel. */
+            /* Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview". */
+            let label = new St.Label({ text: _("Activities") });
+            this.button = new St.Button({ name: 'panelActivities',
+                                          style_class: 'panel-button',
+                                          reactive: true,
+                                          can_focus: true });
+            this._activities = this.button;
+            this.button.set_child(label);
+            this.button._delegate = this.button;
+            this.button._xdndTimeOut = 0;
+            this.button.handleDragOver = Lang.bind(this,
+                function(source, actor, x, y, time) {
+                     if (source == Main.xdndHandler) {
+                        if (this.button._xdndTimeOut != 0)
+                            Mainloop.source_remove(this.button._xdndTimeOut);
+                        this.button._xdndTimeOut = Mainloop.timeout_add(BUTTON_DND_ACTIVATION_TIMEOUT,
+                                                                        Lang.bind(this,
+                                                                                    function() {
+                                                                                        this._xdndShowOverview(actor);
+                                                                                    }));
+                     }
+                });
+            this._leftBox.add(this.button);
+
+            // Synchronize the buttons pseudo classes with its corner
+            this.button.connect('style-changed', Lang.bind(this,
+                function(actor) {
+                    let rtl = actor.get_direction() == St.TextDirection.RTL;
+                    let corner = rtl ? this._rightCorner : this._leftCorner;
+                    let pseudoClass = actor.get_style_pseudo_class();
+                    corner.actor.set_style_pseudo_class(pseudoClass);
+                }));
+        }
 
         this._hotCorner = null;
 
@@ -966,43 +991,50 @@ Panel.prototype = {
         this._rightBox.add(this._trayBox);
         this._rightBox.add(this._statusBox);
 
-        this._userMenu = new StatusMenu.StatusMenuButton();
-        this._userMenu.actor.name = 'panelStatus';
-        this._rightBox.add(this._userMenu.actor);
-
-        // Synchronize the buttons pseudo classes with its corner
-        this._userMenu.actor.connect('style-changed', Lang.bind(this,
-            function(actor) {
-                let rtl = actor.get_direction() == St.TextDirection.RTL;
-                let corner = rtl ? this._leftCorner : this._rightCorner;
-                let pseudoClass = actor.get_style_pseudo_class();
-                corner.actor.set_style_pseudo_class(pseudoClass);
-            }));
+        if (global.session_type == Shell.SessionType.USER) {
+            this._userMenu = new StatusMenu.StatusMenuButton();
+            this._userMenu.actor.name = 'panelStatus';
+            this._rightBox.add(this._userMenu.actor);
+
+            // Synchronize the buttons pseudo classes with its corner
+            this._userMenu.actor.connect('style-changed', Lang.bind(this,
+                function(actor) {
+                    let rtl = actor.get_direction() == St.TextDirection.RTL;
+                    let corner = rtl ? this._leftCorner : this._rightCorner;
+                    let pseudoClass = actor.get_style_pseudo_class();
+                    corner.actor.set_style_pseudo_class(pseudoClass);
+                }));
+        }
 
         Main.statusIconDispatcher.connect('status-icon-added', Lang.bind(this, this._onTrayIconAdded));
         Main.statusIconDispatcher.connect('status-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
 
-        // TODO: decide what to do with the rest of the panel in the Overview mode (make it fade-out, become non-reactive, etc.)
-        // We get into the Overview mode on button-press-event as opposed to button-release-event because eventually we'll probably
-        // have the Overview act like a menu that allows the user to release the mouse on the activity the user wants
-        // to switch to.
-        this.button.connect('clicked', Lang.bind(this, function(b) {
-            if (!Main.overview.animationInProgress) {
-                this._hotCorner.maybeToggleOverviewOnClick();
-                return true;
-            } else {
-                return false;
-            }
-        }));
-        // In addition to pressing the button, the Overview can be entered and exited by other means, such as
-        // pressing the System key, Alt+F1 or Esc. We want the button to be pressed in when the Overview is entered
-        // and to be released when it is exited regardless of how it was triggered.
-        Main.overview.connect('showing', Lang.bind(this, function() {
-            this.button.checked = true;
-        }));
-        Main.overview.connect('hiding', Lang.bind(this, function() {
-            this.button.checked = false;
-        }));
+        if (global.session_type == Shell.SessionType.USER) {
+            // TODO: decide what to do with the rest of the panel in the Overview mode (make it fade-out, become non-reactive, etc.)
+            // We get into the Overview mode on button-press-event as opposed to button-release-event because eventually we'll probably
+            // have the Overview act like a menu that allows the user to release the mouse on the activity the user wants
+            // to switch to.
+            this.button.connect('clicked', Lang.bind(this, function(b) {
+                if (!Main.overview.animationInProgress) {
+                    this._hotCorner.maybeToggleOverviewOnClick();
+                    return true;
+                } else {
+                    return false;
+                }
+            }));
+        }
+
+        if (global.session_type == Shell.SessionType.USER) {
+            // In addition to pressing the button, the Overview can be entered and exited by other means, such as
+            // pressing the System key, Alt+F1 or Esc. We want the button to be pressed in when the Overview is entered
+            // and to be released when it is exited regardless of how it was triggered.
+            Main.overview.connect('showing', Lang.bind(this, function() {
+                this.button.checked = true;
+            }));
+            Main.overview.connect('hiding', Lang.bind(this, function() {
+                this.button.checked = false;
+            }));
+        }
 
         Main.chrome.addActor(this.actor);
         Main.chrome.addActor(this._leftCorner.actor, { affectsStruts: false,
@@ -1042,9 +1074,9 @@ Panel.prototype = {
     },
 
     startStatusArea: function() {
-        for (let i = 0; i < STANDARD_TRAY_ICON_ORDER.length; i++) {
-            let role = STANDARD_TRAY_ICON_ORDER[i];
-            let constructor = STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION[role];
+        for (let i = 0; i < this._tray_icon_order.length; i++) {
+            let role = this._tray_icon_order[i];
+            let constructor = this._tray_icon_shell_implementation[role];
             if (!constructor) {
                 // This icon is not implemented (this is a bug)
                 continue;
@@ -1058,7 +1090,9 @@ Panel.prototype = {
 
         // PopupMenuManager depends on menus being added in order for
         // keyboard navigation
-        this._menus.addMenu(this._userMenu.menu);
+        if (this._userMenu) {
+            this._menus.addMenu(this._userMenu.menu);
+        }
     },
 
     startupAnimation: function() {
@@ -1112,13 +1146,13 @@ Panel.prototype = {
     _onTrayIconAdded: function(o, icon, role) {
         icon.height = PANEL_ICON_SIZE;
 
-        if (STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION[role]) {
+        if (this._tray_icon_shell_implementation[role]) {
             // This icon is legacy, and replaced by a Shell version
             // Hide it
             return;
         }
         // Figure out the index in our well-known order for this icon
-        let position = STANDARD_TRAY_ICON_ORDER.indexOf(role);
+        let position = this._tray_icon_order.indexOf(role);
         icon._rolePosition = position;
         let children = this._trayBox.get_children();
         let i;
diff --git a/js/ui/status/accessibility.js b/js/ui/status/accessibility.js
index 560042c..f1ffbf9 100644
--- a/js/ui/status/accessibility.js
+++ b/js/ui/status/accessibility.js
@@ -87,12 +87,14 @@ ATIndicator.prototype = {
         let mouseKeys = this._buildItem(_("Mouse Keys"), A11Y_SCHEMA, KEY_MOUSE_KEYS_ENABLED);
         this.menu.addMenuItem(mouseKeys);
 
-        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
-        this.menu.addAction(_("Universal Access Settings"), function() {
-            Main.overview.hide();
-            let app = Shell.AppSystem.get_default().get_app('gnome-universal-access-panel.desktop');
-            app.activate(-1);
-        });
+        if (global.session_type == Shell.SessionType.USER) {
+            this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
+            this.menu.addAction(_("Universal Access Settings"), function() {
+                Main.overview.hide();
+                let app = Shell.AppSystem.get_default().get_app('gnome-universal-access-panel.desktop');
+                app.activate(-1);
+            });
+        }
     },
 
     _buildItemExtended: function(string, initial_value, writable, on_set) {
diff --git a/js/ui/status/keyboard.js b/js/ui/status/keyboard.js
index 3048da0..37af3a8 100644
--- a/js/ui/status/keyboard.js
+++ b/js/ui/status/keyboard.js
@@ -67,16 +67,18 @@ XKBIndicator.prototype = {
 
         this._sync_config();
 
-        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
-        this.menu.addAction(_("Show Keyboard Layout..."), Lang.bind(this, function() {
-            Main.overview.hide();
-            Util.spawn(['gkbd-keyboard-display', '-g', String(this._config.get_current_group() + 1)]);
-        }));
-        this.menu.addAction(_("Localization Settings"), function() {
-            Main.overview.hide();
-            let app = Shell.AppSystem.get_default().get_app('gnome-region-panel.desktop');
-            app.activate(-1);
-        });
+        if (global.session_type == Shell.SessionType.USER) {
+            this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
+            this.menu.addAction(_("Show Keyboard Layout..."), Lang.bind(this, function() {
+                Main.overview.hide();
+                Util.spawn(['gkbd-keyboard-display', '-g', String(this._config.get_current_group() + 1)]);
+            }));
+            this.menu.addAction(_("Localization Settings"), function() {
+                Main.overview.hide();
+                let app = Shell.AppSystem.get_default().get_app('gnome-region-panel.desktop');
+                app.activate(-1);
+            });
+        }
     },
 
     _sync_config: function() {
diff --git a/js/ui/status/power.js b/js/ui/status/power.js
index 1961702..222c699 100644
--- a/js/ui/status/power.js
+++ b/js/ui/status/power.js
@@ -78,13 +78,14 @@ Indicator.prototype = {
         this._deviceSep = new PopupMenu.PopupSeparatorMenuItem();
         this.menu.addMenuItem(this._deviceSep);
         this._otherDevicePosition = 2;
-        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
 
-        this.menu.addAction(_("Power Settings"),function() {
-            Main.overview.hide();
-            let app = Shell.AppSystem.get_default().get_app('gnome-power-panel.desktop');
-            app.activate(-1);
-        });
+        if (global.session_type == Shell.SessionType.USER) {
+            this.menu.addAction(_("Power Settings"),function() {
+                Main.overview.hide();
+                let app = Shell.AppSystem.get_default().get_app('gnome-power-panel.desktop');
+                app.activate(-1);
+            });
+        }
 
         this._proxy.connect('Changed', Lang.bind(this, this._devicesChanged));
         this._devicesChanged();
diff --git a/js/ui/status/volume.js b/js/ui/status/volume.js
index bd74cd9..bd669fe 100644
--- a/js/ui/status/volume.js
+++ b/js/ui/status/volume.js
@@ -60,12 +60,14 @@ Indicator.prototype = {
         this.menu.addMenuItem(this._inputTitle);
         this.menu.addMenuItem(this._inputSlider);
 
-        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
-        this.menu.addAction(_("Sound Settings"), function() {
-            Main.overview.hide();
-            let app = Shell.AppSystem.get_default().get_app('gnome-sound-panel.desktop');
-            app.activate(-1);
-        });
+        if (global.session_type == Shell.SessionType.USER) {
+            this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
+            this.menu.addAction(_("Sound Settings"), function() {
+                Main.overview.hide();
+                let app = Shell.AppSystem.get_default().get_app('gnome-sound-panel.desktop');
+                app.activate(-1);
+            });
+        }
 
         this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
         this._control.open();
diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js
index a3e2918..aa1f24d 100644
--- a/js/ui/windowManager.js
+++ b/js/ui/windowManager.js
@@ -121,14 +121,16 @@ WindowManager.prototype = {
         this.setKeybindingHandler('switch_group', Lang.bind(this, this._startAppSwitcher));
         this.setKeybindingHandler('switch_panels', Lang.bind(this, this._startA11ySwitcher));
 
-        Main.overview.connect('showing', Lang.bind(this, function() {
-            for (let i = 0; i < this._dimmedWindows.length; i++)
-                this._undimWindow(this._dimmedWindows[i], true);
-        }));
-        Main.overview.connect('hiding', Lang.bind(this, function() {
-            for (let i = 0; i < this._dimmedWindows.length; i++)
-                this._dimWindow(this._dimmedWindows[i], true);
-        }));
+        if (Main.overview) {
+            Main.overview.connect('showing', Lang.bind(this, function() {
+                for (let i = 0; i < this._dimmedWindows.length; i++)
+                    this._undimWindow(this._dimmedWindows[i], true);
+            }));
+            Main.overview.connect('hiding', Lang.bind(this, function() {
+                for (let i = 0; i < this._dimmedWindows.length; i++)
+                    this._dimWindow(this._dimmedWindows[i], true);
+            }));
+        }
     },
 
     setKeybindingHandler: function(keybinding, handler){
@@ -150,7 +152,7 @@ WindowManager.prototype = {
     },
 
     _shouldAnimate : function(actor) {
-        if (Main.overview.visible || this._animationsBlocked > 0)
+        if ((Main.overview && Main.overview.visible) || this._animationsBlocked > 0)
             return false;
         if (actor && (actor.meta_window.get_window_type() != Meta.WindowType.NORMAL))
             return false;
@@ -250,14 +252,14 @@ WindowManager.prototype = {
         if (shouldDim && !window._dimmed) {
             window._dimmed = true;
             this._dimmedWindows.push(window);
-            if (!Main.overview.visible)
+            if (!Main.overview || !Main.overview.visible)
                 this._dimWindow(window, true);
         } else if (!shouldDim && window._dimmed) {
             window._dimmed = false;
             this._dimmedWindows = this._dimmedWindows.filter(function(win) {
                                                                  return win != window;
                                                              });
-            if (!Main.overview.visible)
+            if (!Main.overview || !Main.overview.visible)
                 this._undimWindow(window, true);
         }
     },
@@ -573,7 +575,7 @@ WindowManager.prototype = {
         if (indexToActivate != activeWorkspaceIndex)
             global.screen.get_workspace_by_index(indexToActivate).activate(global.get_current_time());
 
-        if (!Main.overview.visible)
+        if (!Main.overview || !Main.overview.visible)
             this._workspaceSwitcherPopup.display(WorkspaceSwitcherPopup.UP, indexToActivate);
     },
 
@@ -589,7 +591,7 @@ WindowManager.prototype = {
         if (indexToActivate != activeWorkspaceIndex)
             global.screen.get_workspace_by_index(indexToActivate).activate(global.get_current_time());
 
-        if (!Main.overview.visible)
+        if (!Main.overview || !Main.overview.visible)
             this._workspaceSwitcherPopup.display(WorkspaceSwitcherPopup.DOWN, indexToActivate);
     },
 
@@ -602,7 +604,7 @@ WindowManager.prototype = {
         if (indexToActivate != activeWorkspaceIndex)
             global.screen.get_workspace_by_index(indexToActivate).activate(global.get_current_time());
 
-        if (!Main.overview.visible)
+        if (!Main.overview || !Main.overview.visible)
             this._workspaceSwitcherPopup.display(WorkspaceSwitcherPopup.UP, indexToActivate);
     },
 
@@ -615,7 +617,7 @@ WindowManager.prototype = {
         if (indexToActivate != activeWorkspaceIndex)
             global.screen.get_workspace_by_index(indexToActivate).activate(global.get_current_time());
 
-        if (!Main.overview.visible)
+        if (!Main.overview || !Main.overview.visible)
             this._workspaceSwitcherPopup.display(WorkspaceSwitcherPopup.DOWN, indexToActivate);
     }
 };



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]