diff --git a/js/ui/altTab.js b/js/ui/altTab.js
index b493b7c..d7c9dd0 100644
--- a/js/ui/altTab.js
+++ b/js/ui/altTab.js
@@ -54,7 +54,7 @@ AltTabPopup.prototype = {
         // the switcher appears underneath the current pointer location
         this._disableHover();
 
-        global.stage.add_actor(this.actor);
+        Main.uiGroup.add_actor(this.actor);
     },
 
     _getPreferredWidth: function (actor, forHeight, alloc) {
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index 5397e18..a68feb3 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -616,7 +616,7 @@ AppIconMenu.prototype = {
         }));
         source.actor.connect('destroy', Lang.bind(this, function () { this.actor.destroy(); }));
 
-        global.stage.add_actor(this.actor);
+        Main.uiGroup.add_actor(this.actor);
     },
 
     _getPreferredWidth: function(actor, forHeight, alloc) {
diff --git a/js/ui/chrome.js b/js/ui/chrome.js
index 406fae1..7ec07ca 100644
--- a/js/ui/chrome.js
+++ b/js/ui/chrome.js
@@ -21,7 +21,7 @@ Chrome.prototype = {
     _init: function() {
         // The group itself has zero size so it doesn't interfere with DND
         this.actor = new Clutter.Group({ width: 0, height: 0 });
-        global.stage.add_actor(this.actor);
+        Main.uiGroup.add_actor(this.actor);
         this.nonOverviewActor = new Clutter.Group();
         this.actor.add_actor(this.nonOverviewActor);
 
diff --git a/js/ui/dnd.js b/js/ui/dnd.js
index 2132165..4a7c3eb 100644
--- a/js/ui/dnd.js
+++ b/js/ui/dnd.js
@@ -6,6 +6,7 @@ const St = imports.gi.St;
 const Lang = imports.lang;
 const Signals = imports.signals;
 const Tweener = imports.ui.tweener;
+const Main = imports.ui.main;
 
 const Params = imports.misc.params;
 
@@ -22,7 +23,7 @@ function _getEventHandlerActor() {
         eventHandlerActor = new Clutter.Rectangle();
         eventHandlerActor.width = 0;
         eventHandlerActor.height = 0;
-        global.stage.add_actor(eventHandlerActor);
+        Main.uiGroup.add_actor(eventHandlerActor);
         // We connect to 'event' rather than 'captured-event' because the capturing phase doesn't happen
         // when you've grabbed the pointer.
         eventHandlerActor.connect('event',
diff --git a/js/ui/lookingGlass.js b/js/ui/lookingGlass.js
index 5283850..e82dcf0 100644
--- a/js/ui/lookingGlass.js
+++ b/js/ui/lookingGlass.js
@@ -257,7 +257,7 @@ Inspector.prototype = {
         eventHandler.connect('notify::allocation', Lang.bind(this, function () {
             eventHandler.x = primary.x + Math.floor((primary.width - eventHandler.width) / 2);
         }));
-        global.stage.add_actor(eventHandler);
+        Main.uiGroup.add_actor(eventHandler);
         let displayText = new St.Label();
         eventHandler.add(displayText, { expand: true });
 
@@ -471,7 +471,7 @@ LookingGlass.prototype = {
                       Lang.bind(this, this._updateFont));
         this._updateFont();
 
-        global.stage.add_actor(this.actor);
+        Main.uiGroup.add_actor(this.actor);
 
         let toolbar = new St.BoxLayout({ name: "Toolbar" });
         this.actor.add_actor(toolbar);

diff --git a/js/ui/main.js b/js/ui/main.js
index be92604..af51612 100644
--- a/js/ui/main.js
+++ b/js/ui/main.js
@@ -45,6 +46,7 @@ let recorder = null;
 let shellDBusService = null;
 let modalCount = 0;
 let modalActorFocusStack = [];
+let uiGroup = null;
 let _errorLogStack = [];
 let _startDate;
 
@@ -105,6 +108,12 @@ function start() {
        getRunDialog().open();
     });
 
+    // Set up stage hierarchy to group all UI actors under one container.
+    uiGroup = new Clutter.Group();
+    global.window_group.reparent(uiGroup);
+    global.overlay_group.reparent(uiGroup);
+    global.stage.add_actor(uiGroup);
+
     placesManager = new PlaceDisplay.PlacesManager();
     overview = new Overview.Overview();
     chrome = new Chrome.Chrome();
 
diff --git a/js/ui/panel.js b/js/ui/panel.js
index 31007fb..052e81a 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -606,7 +606,7 @@ Panel.prototype = {
                                    transition: 'linear',
                                    onUpdate: function() { ripple.opacity = 255 * Math.sqrt(ripple._opacity); },
                                    onComplete: function() { ripple.destroy(); } });
-        global.stage.add_actor(ripple);
+        Main.uiGroup.add_actor(ripple);
     },
 
     _onHotCornerEntered : function() {
diff --git a/js/ui/runDialog.js b/js/ui/runDialog.js
index 1139dbc..a0a319c 100644
--- a/js/ui/runDialog.js
+++ b/js/ui/runDialog.js
@@ -213,7 +213,7 @@ RunDialog.prototype = {
         // hidden then show it in show()
         this._group = new Clutter.Group({ visible: false,
                                           x: 0, y: 0 });
-        global.stage.add_actor(this._group);
+        Main.uiGroup.add_actor(this._group);
 
         let lightbox = new Lightbox.Lightbox(this._group, true);
 
diff --git a/js/ui/workspaceSwitcherPopup.js b/js/ui/workspaceSwitcherPopup.js
index 274c7dd..cd41d83 100644
--- a/js/ui/workspaceSwitcherPopup.js
+++ b/js/ui/workspaceSwitcherPopup.js
@@ -5,6 +5,7 @@ const Lang = imports.lang;
 const Mainloop = imports.mainloop;
 const Shell = imports.gi.Shell;
 const St = imports.gi.St;
+const Main = imports.ui.main;
 
 const Tweener = imports.ui.tweener;
 
@@ -25,7 +26,7 @@ WorkspaceSwitcherPopup.prototype = {
                                          y: 0,
                                          width: global.screen_width,
                                          height: global.screen_height });
-        global.stage.add_actor(this.actor);
+        Main.uiGroup.add_actor(this.actor);
 
         this._scaleWidth = global.screen_width / global.screen_height;
 
