=== modified file 'launcher/StandaloneSwitcher.cpp'
--- launcher/StandaloneSwitcher.cpp	2013-02-06 17:27:24 +0000
+++ launcher/StandaloneSwitcher.cpp	2013-08-09 17:51:48 +0000
@@ -131,7 +131,6 @@
   nux::VLayout* layout = new nux::VLayout(TEXT(""), NUX_TRACKER_LOCATION);
 
   controller = std::make_shared<Controller>();
-  controller->SetWorkspace(nux::Geometry(0, 0, 900, 600), 0);
 
   layout->SetContentDistribution(nux::MAJOR_POSITION_CENTER);
   layout->SetHorizontalExternalMargin (10);

=== modified file 'launcher/SwitcherController.cpp'
--- launcher/SwitcherController.cpp	2013-06-18 19:04:55 +0000
+++ launcher/SwitcherController.cpp	2013-08-09 17:51:48 +0000
@@ -23,6 +23,7 @@
 
 #include "unity-shared/UBusMessages.h"
 #include "unity-shared/WindowManager.h"
+#include "unity-shared/UScreen.h"
 
 #include "SwitcherController.h"
 #include "SwitcherControllerImpl.h"
@@ -41,6 +42,8 @@
 const std::string DETAIL_TIMEOUT = "detail-timeout";
 const std::string VIEW_CONSTRUCT_IDLE = "view-construct-idle";
 const unsigned FADE_DURATION = 80;
+const int XY_OFFSET = 100;
+const int WH_OFFSET = -200;
 
 /**
  * Helper comparison functor for sorting application icons.
@@ -78,7 +81,6 @@
   , impl_(new Controller::Impl(this, 20, create_window))
 {}
 
-
 Controller::~Controller()
 {}
 
@@ -93,6 +95,9 @@
                       SortMode sort,
                       std::vector<AbstractLauncherIcon::Ptr> results)
 {
+  auto uscreen = UScreen::GetDefault();
+  monitor_     = uscreen->GetMonitorWithMouse();
+
   impl_->Show(show, sort, results);
 }
 
@@ -102,15 +107,6 @@
     impl_->model_->Select(index);
 }
 
-void Controller::SetWorkspace(nux::Geometry geo, int monitor)
-{
-  monitor_ = monitor;
-  impl_->workarea_ = geo;
-
-  if (impl_->view_)
-    impl_->view_->monitor = monitor_;
-}
-
 void Controller::Hide(bool accept_state)
 {
   if (Visible())
@@ -124,6 +120,14 @@
   return visible_;
 }
 
+nux::Geometry Controller::GetInputWindowGeometry() const
+{
+  if (impl_->view_window_)
+    return impl_->view_window_->GetGeometry();
+
+  return {0, 0, 0, 0};
+}
+
 bool Controller::StartDetailMode()
 {
   if (visible_)
@@ -333,6 +337,7 @@
   obj_->AddChild(model_.get());
   model_->selection_changed.connect(sigc::mem_fun(this, &Controller::Impl::OnModelSelectionChanged));
   model_->detail_selection.changed.connect([this] (bool) { sources_.Remove(DETAIL_TIMEOUT); });
+  model_->request_detail_hide.connect(sigc::mem_fun(this, &Controller::Impl::DetailHide));
   model_->only_detail_on_viewport = (show == ShowMode::CURRENT_VIEWPORT);
 
   SelectFirstItem();
@@ -350,17 +355,21 @@
     ShowView();
   }
 
-  if (obj_->detail_on_timeout)
-  {
-    auto cb_func = sigc::mem_fun(this, &Controller::Impl::OnDetailTimer);
-    sources_.AddTimeout(obj_->initial_detail_timeout_length, cb_func, DETAIL_TIMEOUT);
-  }
+  ResetDetailTimer(obj_->initial_detail_timeout_length);
 
   ubus_manager_.SendMessage(UBUS_OVERLAY_CLOSE_REQUEST);
   ubus_manager_.SendMessage(UBUS_SWITCHER_SHOWN,
                             g_variant_new("(bi)", true, obj_->monitor_));
 }
 
+void Controller::Impl::ResetDetailTimer(int timeout_length)
+{
+  if (obj_->detail_on_timeout)
+  {
+    auto cb_func = sigc::mem_fun(this, &Controller::Impl::OnDetailTimer);
+    sources_.AddTimeout(timeout_length, cb_func, DETAIL_TIMEOUT);
+  }
+}
 
 bool Controller::Impl::OnDetailTimer()
 {
@@ -375,11 +384,7 @@
 
 void Controller::Impl::OnModelSelectionChanged(AbstractLauncherIcon::Ptr const& icon)
 {
-  if (obj_->detail_on_timeout)
-  {
-    auto cb_func = sigc::mem_fun(this, &Controller::Impl::OnDetailTimer);
-    sources_.AddTimeout(obj_->detail_timeout_length, cb_func, DETAIL_TIMEOUT);
-  }
+  ResetDetailTimer(obj_->detail_timeout_length);
 
   if (icon)
   {
@@ -434,10 +439,21 @@
     view_window_->SetOpacity(0.0f);
     view_window_->SetLayout(main_layout_);
     view_window_->SetBackgroundColor(nux::color::Transparent);
-    view_window_->SetGeometry(workarea_);
   }
 }
 
+nux::Geometry GetSwitcherViewsGeometry()
+{
+  auto uscreen     = UScreen::GetDefault();
+  int monitor      = uscreen->GetMonitorWithMouse();
+  auto monitor_geo = uscreen->GetMonitorGeometry(monitor);
+
+  monitor_geo.OffsetPosition(XY_OFFSET, XY_OFFSET);
+  monitor_geo.OffsetSize(WH_OFFSET, WH_OFFSET);
+
+  return monitor_geo;
+}
+
 void Controller::Impl::ConstructView()
 {
   if (view_ || !model_)
@@ -451,10 +467,22 @@
   view_->background_color = bg_color_;
   view_->monitor = obj_->monitor_;
 
+  view_->hide_request.connect(sigc::mem_fun(this, &Controller::Impl::Hide));
+
+  view_->switcher_mouse_up.connect([this] (int icon_index, int button) {
+      if (button == 3)
+        InitiateDetail(true);
+  });
+
+  view_->switcher_mouse_move.connect([this] (int icon_index) {
+      if (icon_index >= 0)
+        ResetDetailTimer(obj_->detail_timeout_length);
+  });
+
   ConstructWindow();
   main_layout_->AddView(view_.GetPointer(), 1);
   view_window_->SetEnterFocusInputArea(view_.GetPointer());
-  view_window_->SetGeometry(workarea_);
+  view_window_->SetGeometry(GetSwitcherViewsGeometry());
 
   view_built.emit();
 }
@@ -491,6 +519,14 @@
   }
 }
 
+void Controller::Impl::DetailHide()
+{
+  // FIXME We need to refactor SwitcherModel so we can add/remove icons without causing
+  // a crash. If you remove the last application in the list it crashes.
+  model_->detail_selection = false;
+  Hide(false);
+}
+
 void Controller::Impl::HideWindow()
 {
   main_layout_->RemoveChildObject(view_.GetPointer());
@@ -579,7 +615,7 @@
     obj_->detail_mode_ = DetailMode::TAB_NEXT_WINDOW;
   }
   else
-  { 
+  {
     model_->detail_selection = false;
   }
 }

=== modified file 'launcher/SwitcherController.h'
--- launcher/SwitcherController.h	2013-06-18 18:48:31 +0000
+++ launcher/SwitcherController.h	2013-08-09 17:51:48 +0000
@@ -88,6 +88,7 @@
   bool CanShowSwitcher(const std::vector<launcher::AbstractLauncherIcon::Ptr>& resutls) const;
 
   bool Visible();
+  nux::Geometry GetInputWindowGeometry() const;
 
   bool StartDetailMode();
   bool StopDetailMode();
@@ -107,8 +108,6 @@
 
   void SelectFirstItem();
 
-  void SetWorkspace(nux::Geometry geo, int monitor);
-
   nux::ObjectPtr<SwitcherView> GetView() const;
 
   ui::LayoutWindow::Vector ExternalRenderTargets();

=== modified file 'launcher/SwitcherControllerImpl.h'
--- launcher/SwitcherControllerImpl.h	2013-06-14 00:23:34 +0000
+++ launcher/SwitcherControllerImpl.h	2013-08-09 17:51:48 +0000
@@ -48,6 +48,7 @@
 
   void Show(ShowMode show, SortMode sort, std::vector<launcher::AbstractLauncherIcon::Ptr> results);
   void Hide(bool accept_state);
+  void DetailHide();
 
   void Next();
   void Prev();
@@ -82,6 +83,7 @@
   void ShowView();
   void HideWindow();
 
+  void ResetDetailTimer(int timeout_length);
   bool OnDetailTimer();
   void OnModelSelectionChanged(launcher::AbstractLauncherIcon::Ptr const& icon);
   void OnBackgroundUpdate(GVariant* data);
@@ -94,7 +96,6 @@
   SwitcherView::Ptr view_;
 
   // @todo move these view data into the SwitcherView class
-  nux::Geometry workarea_;
   Controller::WindowCreator create_window_;
   MockableBaseWindow::Ptr view_window_;
   nux::HLayout* main_layout_;

=== modified file 'launcher/SwitcherModel.cpp'
--- launcher/SwitcherModel.cpp	2013-06-20 20:46:40 +0000
+++ launcher/SwitcherModel.cpp	2013-08-09 17:51:48 +0000
@@ -149,6 +149,12 @@
       results.push_back(xid);
   }
 
+  if (results.empty() && detail_selection)
+  {
+    request_detail_hide.emit();
+    return results;
+  }
+
   std::sort(results.begin(), results.end(), [&wm](Window first, Window second) {
       return wm.GetWindowActiveNumber(first) > wm.GetWindowActiveNumber(second);
   });

=== modified file 'launcher/SwitcherModel.h'
--- launcher/SwitcherModel.h	2013-06-17 23:56:23 +0000
+++ launcher/SwitcherModel.h	2013-08-09 17:51:48 +0000
@@ -101,6 +101,7 @@
   void Select(unsigned int index);
 
   sigc::signal<void, launcher::AbstractLauncherIcon::Ptr const&> selection_changed;
+  sigc::signal<void> request_detail_hide;
 
 protected:
   // Introspectable methods

=== modified file 'launcher/SwitcherView.cpp'
--- launcher/SwitcherView.cpp	2013-07-29 17:17:43 +0000
+++ launcher/SwitcherView.cpp	2013-08-09 17:51:48 +0000
@@ -21,6 +21,7 @@
 #include "SwitcherView.h"
 #include "unity-shared/IconRenderer.h"
 #include "unity-shared/TimeUtil.h"
+#include "unity-shared/UScreen.h"
 
 #include <Nux/Nux.h>
 #include <UnityCore/Variant.h>
@@ -36,6 +37,8 @@
 namespace
 {
   const unsigned int VERTICAL_PADDING = 45;
+  const unsigned int SPREAD_OFFSET = 100;
+  const unsigned int EXTRA_ICON_SPACE = 10;
 }
 
 NUX_IMPLEMENT_OBJECT_TYPE(SwitcherView);
@@ -55,6 +58,8 @@
   , spread_size(3.5f)
   , icon_renderer_(std::make_shared<IconRenderer>())
   , text_view_(new StaticCairoText(""))
+  , last_icon_selected_(-1)
+  , last_detail_icon_selected_(-1)
   , target_sizes_set_(false)
 {
   icon_renderer_->pip_style = OVER_TILE;
@@ -68,7 +73,13 @@
   icon_size.changed.connect (sigc::mem_fun (this, &SwitcherView::OnIconSizeChanged));
   tile_size.changed.connect (sigc::mem_fun (this, &SwitcherView::OnTileSizeChanged));
 
+  mouse_move.connect (sigc::mem_fun(this, &SwitcherView::RecvMouseMove));
+  mouse_down.connect (sigc::mem_fun(this, &SwitcherView::RecvMouseDown));
+  mouse_up.connect   (sigc::mem_fun(this, &SwitcherView::RecvMouseUp));
+  mouse_wheel.connect(sigc::mem_fun(this, &SwitcherView::RecvMouseWheel));
+
   CaptureMouseDownAnyWhereElse(true);
+  SetAcceptMouseWheelEvent(true);
   ResetTimer();
 
   animate.changed.connect([this] (bool enabled) {
@@ -103,9 +114,32 @@
   .add("animation-length", animation_length)
   .add("spread-size", (float)spread_size)
   .add("label", text_view_->GetText())
+  .add("spread_offset", SPREAD_OFFSET)
   .add("label_visible", text_view_->IsVisible());
 }
 
+debug::Introspectable::IntrospectableList SwitcherView::GetIntrospectableChildren()
+{
+  std::list<unity::debug::Introspectable*> introspection_results;
+
+  if (model_->detail_selection)
+  {
+    for (auto const& target : render_targets_)
+    {
+      introspection_results.push_back(target.get());
+    }
+  }
+  else if (!last_args_.empty())
+  {
+    for (auto& args : last_args_)
+    {
+      introspection_results.push_back(&args);
+    }
+  }
+
+  return introspection_results;
+}
+
 LayoutWindow::Vector SwitcherView::ExternalTargets ()
 {
   return render_targets_;
@@ -118,6 +152,8 @@
   model->detail_selection.changed.connect (sigc::mem_fun (this, &SwitcherView::OnDetailSelectionChanged));
   model->detail_selection_index.changed.connect (sigc::mem_fun (this, &SwitcherView::OnDetailSelectionIndexChanged));
 
+  last_icon_selected_ = -1;
+
   if (!model->Selection())
     return;
 
@@ -129,12 +165,12 @@
 
 void SwitcherView::OnIconSizeChanged (int size)
 {
-  icon_renderer_->SetTargetSize(tile_size, icon_size, 10);
+  icon_renderer_->SetTargetSize(tile_size, icon_size, minimum_spacing);
 }
 
 void SwitcherView::OnTileSizeChanged (int size)
 {
-  icon_renderer_->SetTargetSize(tile_size, icon_size, 10);
+  icon_renderer_->SetTargetSize(tile_size, icon_size, minimum_spacing);
   vertical_size = tile_size + VERTICAL_PADDING * 2;
 }
 
@@ -167,6 +203,8 @@
 {
   text_view_->SetVisible(!detail);
 
+  last_detail_icon_selected_ = -1;
+
   if (!detail)
   {
     text_view_->SetText(model_->Selection()->tooltip_text());
@@ -186,6 +224,181 @@
   QueueDraw();
 }
 
+nux::Point CalculateMouseMonitorOffset(int x, int y)
+{
+  int monitor = unity::UScreen::GetDefault()->GetMonitorWithMouse();
+  nux::Geometry const& geo = unity::UScreen::GetDefault()->GetMonitorGeometry(monitor);
+
+  return {geo.x + x, geo.y + y};
+}
+
+void SwitcherView::RecvMouseMove(int x, int y, int /*dx*/, int /*dy*/, unsigned long /*button_flags*/, unsigned long /*key_flags*/)
+{
+  if (model_->detail_selection)
+  {
+    HandleDetailMouseMove(x, y);
+  }
+  else
+  {
+    HandleMouseMove(x, y);
+  }
+}
+
+void SwitcherView::HandleDetailMouseMove(int x, int y)
+{
+  nux::Point const& mouse_pos = CalculateMouseMonitorOffset(x, y);
+  int detail_icon_index = DetailIconIdexAt(mouse_pos.x, mouse_pos.y);
+
+  if (detail_icon_index >= 0 && detail_icon_index != last_detail_icon_selected_)
+  {
+    model_->detail_selection_index = detail_icon_index;
+    last_detail_icon_selected_ = detail_icon_index;
+  }
+}
+
+void SwitcherView::HandleMouseMove(int x, int y)
+{
+  int icon_index = IconIndexAt(x, y);
+
+  if (icon_index >= 0)
+  {
+    if (icon_index != last_icon_selected_)
+    {
+      if (icon_index != model_->SelectionIndex())
+      {
+        model_->Select(icon_index);
+      }
+
+      last_icon_selected_ = icon_index;
+    }
+
+    switcher_mouse_move.emit(icon_index);
+  }
+}
+
+void SwitcherView::RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long /*key_flags*/)
+{
+  int button = nux::GetEventButton(button_flags);
+
+  if (!CheckMouseInsideBackground(x, y))
+    hide_request.emit(false);
+
+  if (model_->detail_selection)
+  {
+    HandleDetailMouseDown(x, y, button);
+  }
+  else
+  {
+    HandleMouseDown(x, y, button);
+  }
+}
+
+void SwitcherView::HandleDetailMouseDown(int x, int y, int button)
+{
+  nux::Point const& mouse_pos = CalculateMouseMonitorOffset(x, y);
+  int detail_icon_index = DetailIconIdexAt(mouse_pos.x, mouse_pos.y);
+
+  last_detail_icon_selected_ = detail_icon_index;
+
+  switcher_mouse_down.emit(detail_icon_index, button);
+}
+
+void SwitcherView::HandleMouseDown(int x, int y, int button)
+{
+  int icon_index = IconIndexAt(x,y);
+
+  last_icon_selected_ = icon_index;
+
+  switcher_mouse_down.emit(icon_index, button);
+}
+
+void SwitcherView::RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long /*key_flags*/)
+{
+  int button = nux::GetEventButton(button_flags);
+
+  if (model_->detail_selection)
+  {
+    HandleDetailMouseUp(x, y, button);
+  }
+  else
+  {
+    HandleMouseUp(x, y, button);
+  }
+}
+
+void SwitcherView::HandleDetailMouseUp(int x, int y, int button)
+{
+  nux::Point const& mouse_pos = CalculateMouseMonitorOffset(x, y);
+  int detail_icon_index = DetailIconIdexAt(mouse_pos.x, mouse_pos.y);
+
+  switcher_mouse_up.emit(detail_icon_index, button);
+
+  if (button == 1)
+  {
+    if (detail_icon_index >= 0 && detail_icon_index == last_detail_icon_selected_)
+    {
+      model_->detail_selection_index = detail_icon_index;
+      hide_request.emit(true);
+    }
+  }
+  else if (button == 3)
+  {
+    model_->detail_selection = false;
+  }
+}
+
+void SwitcherView::HandleMouseUp(int x, int y, int button)
+{
+  int icon_index = IconIndexAt(x,y);
+
+  switcher_mouse_up.emit(icon_index, button);
+
+  if (button == 1)
+  {
+    if (icon_index >= 0 && icon_index == last_icon_selected_)
+    {
+      model_->Select(icon_index);
+      hide_request.emit(true);
+    }
+  }
+}
+
+void SwitcherView::RecvMouseWheel(int /*x*/, int /*y*/, int wheel_delta, unsigned long /*button_flags*/, unsigned long /*key_flags*/)
+{
+  if (model_->detail_selection)
+  {
+    HandleDetailMouseWheel(wheel_delta);
+  }
+  else
+  {
+    HandleMouseWheel(wheel_delta);
+  }
+}
+
+void SwitcherView::HandleDetailMouseWheel(int wheel_delta)
+{
+  if (wheel_delta > 0)
+  {
+    model_->NextDetail();
+  }
+  else
+  {
+    model_->PrevDetail();
+  }
+}
+
+void SwitcherView::HandleMouseWheel(int wheel_delta)
+{
+  if (wheel_delta > 0)
+  {
+    model_->Next();
+  }
+  else
+  {
+    model_->Prev();
+  }
+}
+
 SwitcherModel::Ptr SwitcherView::GetModel()
 {
   return model_;
@@ -420,7 +633,7 @@
       nux::Geometry const& spread_bounds = UpdateRenderTargets(progress);
       ResizeRenderTargets(spread_bounds, progress);
       // remove extra space consumed by spread
-      spread_padded_width = spread_bounds.width + 100;
+      spread_padded_width = spread_bounds.width + SPREAD_OFFSET;
       max_width -= spread_padded_width - tile_size;
 
       int expansion = std::max(0, spread_bounds.height - icon_size);
@@ -551,7 +764,7 @@
 
   if (!target_sizes_set_)
   {
-    icon_renderer_->SetTargetSize(tile_size, icon_size, 10);
+    icon_renderer_->SetTargetSize(tile_size, icon_size, minimum_spacing);
     target_sizes_set_ = true;
   }
 
@@ -640,9 +853,9 @@
   }
 }
 
-int SwitcherView::IconIndexAt(int x, int y)
+int SwitcherView::IconIndexAt(int x, int y) const
 {
-  int half_size = icon_size.Get() / 2;
+  int half_size = icon_size.Get() / 2 + EXTRA_ICON_SPACE;
   int icon_index = -1;
 
   // Taking icon rotation into consideration will make selection more
@@ -673,5 +886,27 @@
   return icon_index;
 }
 
+int SwitcherView::DetailIconIdexAt(int x, int y) const
+{
+  int index = -1;
+
+  for (unsigned int i = 0; i < render_targets_.size(); ++i)
+  {
+    if (render_targets_[i]->result.IsPointInside(x + SPREAD_OFFSET, y + SPREAD_OFFSET))
+      return i;
+  }
+
+  return index;
+}
+
+bool SwitcherView::CheckMouseInsideBackground(int x, int y) const
+{
+  nux::Point p(x,y);
+  if (last_background_.IsInside(p))
+    return true;
+
+  return false;
+}
+
 }
 }

=== modified file 'launcher/SwitcherView.h'
--- launcher/SwitcherView.h	2013-02-13 01:45:00 +0000
+++ launcher/SwitcherView.h	2013-08-09 17:51:48 +0000
@@ -25,6 +25,7 @@
 #include "unity-shared/StaticCairoText.h"
 #include "unity-shared/LayoutSystem.h"
 #include "unity-shared/BackgroundEffectHelper.h"
+#include "unity-shared/Introspectable.h"
 #include "unity-shared/UnityWindowView.h"
 
 #include <Nux/View.h>
@@ -70,13 +71,24 @@
 
   // Returns the index of the icon at the given position, in window coordinates.
   // If there's no icon there, -1 is returned.
-  int IconIndexAt(int x, int y);
-
+  int IconIndexAt(int x, int y) const;
+  int DetailIconIdexAt(int x, int y) const;
+
+  /* void; int icon_index, int button*/
+  sigc::signal<void, int, int>  switcher_mouse_down;
+  sigc::signal<void, int, int>  switcher_mouse_up;
+
+  /* void; int icon_index */
+  sigc::signal<void, int>  switcher_mouse_move;
+
+  /* void; bool visible */
+  sigc::signal<void, bool> hide_request;
 
 protected:
   // Introspectable methods
   std::string GetName() const;
   void AddProperties(GVariantBuilder* builder);
+  IntrospectableList GetIntrospectableChildren();
 
   void PreDraw(nux::GraphicsEngine& GfxContext, bool force_draw);
   void DrawOverlay(nux::GraphicsEngine& GfxContext, bool force_draw, nux::Geometry const& clip);
@@ -88,7 +100,24 @@
   std::list<ui::RenderArg> RenderArgsFlat(nux::Geometry& background_geo, int selection, float progress);
 
   ui::RenderArg CreateBaseArgForIcon(launcher::AbstractLauncherIcon::Ptr const& icon);
+
 private:
+  void RecvMouseMove(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags);
+  void HandleDetailMouseMove(int x, int y);
+  void HandleMouseMove(int x, int y);
+
+  void RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags);
+  void HandleDetailMouseDown(int x, int y, int button);
+  void HandleMouseDown(int x, int y, int button);
+
+  void RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags);
+  void HandleDetailMouseUp(int x, int y, int button);
+  void HandleMouseUp(int x, int y, int button);
+
+  void RecvMouseWheel(int x, int y, int wheel_delta, unsigned long button_flags, unsigned long key_flags);
+  void HandleDetailMouseWheel(int wheel_delta);
+  void HandleMouseWheel(int wheel_delta);
+
   void OnSelectionChanged(launcher::AbstractLauncherIcon::Ptr const& selection);
   void OnDetailSelectionChanged (bool detail);
   void OnDetailSelectionIndexChanged (unsigned int index);
@@ -111,14 +140,17 @@
   void ResetTimer();
   void SaveLast();
 
+  bool CheckMouseInsideBackground(int x, int y) const;
+
   SwitcherModel::Ptr model_;
   ui::LayoutSystem layout_system_;
   ui::AbstractIconRenderer::Ptr icon_renderer_;
   nux::ObjectPtr<StaticCairoText> text_view_;
 
+  int last_icon_selected_;
+  int last_detail_icon_selected_;
   bool target_sizes_set_;
 
-
   std::list<ui::RenderArg> last_args_;
   std::list<ui::RenderArg> saved_args_;
 

=== modified file 'plugins/unityshell/src/unityshell.cpp'
--- plugins/unityshell/src/unityshell.cpp	2013-08-07 13:27:56 +0000
+++ plugins/unityshell/src/unityshell.cpp	2013-08-09 17:51:48 +0000
@@ -971,6 +971,19 @@
   return false;
 }
 
+LayoutWindow::Ptr UnityScreen::GetSwitcherDetailLayoutWindow(Window window) const
+{
+  LayoutWindow::Vector const& targets = switcher_controller_->ExternalRenderTargets();
+
+  for (LayoutWindow::Ptr const& target : targets)
+  {
+    if (target->xid == window)
+      return target;
+  }
+
+  return nullptr;
+}
+
 void UnityWindow::enterShowDesktop ()
 {
   if (!mShowdesktopHandler)
@@ -1169,7 +1182,8 @@
         handled = true;
       }
       else if (event->xbutton.button == Button2 &&
-               GetScaledGeometry().IsPointInside(event->xbutton.x_root, event->xbutton.y_root))
+              (GetScaledGeometry().IsPointInside(event->xbutton.x_root, event->xbutton.y_root) ||
+               GetLayoutWindowGeometry().IsPointInside(event->xbutton.x_root, event->xbutton.y_root)))
       {
         middle_clicked_ = true;
         handled = true;
@@ -1190,7 +1204,9 @@
         if (was_pressed)
         {
           if (close_button_geo_.IsPointInside(event->xbutton.x_root, event->xbutton.y_root))
+          {
             window->close(0);
+          }
 
           handled = true;
         }
@@ -1198,7 +1214,8 @@
         if (middle_clicked_)
         {
           if (event->xbutton.button == Button2 &&
-              GetScaledGeometry().IsPointInside(event->xbutton.x_root, event->xbutton.y_root))
+             (GetScaledGeometry().IsPointInside(event->xbutton.x_root, event->xbutton.y_root) ||
+              GetLayoutWindowGeometry().IsPointInside(event->xbutton.x_root, event->xbutton.y_root)))
           {
             window->close(0);
           }
@@ -1492,6 +1509,14 @@
         if (CompWindow *w = screen->findWindow(ss->getSelectedWindow()))
           skip_other_plugins = UnityWindow::get(w)->handleEvent(event);
       }
+      else if (switcher_controller_->IsDetailViewShown())
+      {
+        Window win = switcher_controller_->GetCurrentSelection().window_;
+        CompWindow* w = screen->findWindow(win);
+
+        if (w)
+          skip_other_plugins = UnityWindow::get(w)->handleEvent(event);
+      }
       break;
     case ButtonPress:
       if (super_keypressed_)
@@ -1505,6 +1530,14 @@
         if (CompWindow *w = screen->findWindow(ss->getSelectedWindow()))
           skip_other_plugins = UnityWindow::get(w)->handleEvent(event);
       }
+      else if (switcher_controller_->IsDetailViewShown())
+      {
+        Window win = switcher_controller_->GetCurrentSelection().window_;
+        CompWindow* w = screen->findWindow(win);
+
+        if (w)
+          skip_other_plugins = UnityWindow::get(w)->handleEvent(event);
+      }
 
       if (dash_controller_->IsVisible())
       {
@@ -1532,8 +1565,7 @@
           }
         }
       }
-
-      if (hud_controller_->IsVisible())
+      else if (hud_controller_->IsVisible())
       {
         nux::Point pt(event->xbutton.x_root, event->xbutton.y_root);
         nux::Geometry const& hud_geo = hud_controller_->GetInputWindowGeometry();
@@ -1547,24 +1579,26 @@
           hud_controller_->HideHud(false);
         }
       }
+      else if (switcher_controller_->Visible())
+      {
+        nux::Point pt(event->xbutton.x_root, event->xbutton.y_root);
+        nux::Geometry const& switcher_geo = switcher_controller_->GetInputWindowGeometry();
+
+        if (!switcher_geo.IsInside(pt))
+        {
+          switcher_controller_->Hide(false);
+        }
+      }
       break;
     case ButtonRelease:
-      if (switcher_controller_ && switcher_controller_->Visible())
+
+      if (switcher_controller_->IsDetailViewShown())
       {
-        XButtonEvent *bev = reinterpret_cast<XButtonEvent*>(event);
-        if (bev->time - last_scroll_event_ > 150)
-        {
-          if (bev->button == Button4 || bev->button == local::SCROLL_UP_BUTTON)
-          {
-            switcher_controller_->Prev();
-            last_scroll_event_ = bev->time;
-          }
-          else if (bev->button == Button5 || bev->button == local::SCROLL_DOWN_BUTTON)
-          {
-            switcher_controller_->Next();
-            last_scroll_event_ = bev->time;
-          }
-        }
+        Window win = switcher_controller_->GetCurrentSelection().window_;
+        CompWindow* w = screen->findWindow(win);
+
+        if (w)
+          skip_other_plugins = UnityWindow::get(w)->handleEvent(event);
       }
       else if (wm.IsScaleActive())
       {
@@ -1686,7 +1720,7 @@
   }
 
   if (!skip_other_plugins &&
-      screen->otherGrabExist("deco", "move", "switcher", "resize", "unity-switcher", nullptr))
+      screen->otherGrabExist("deco", "move", "switcher", "resize", nullptr))
   {
     wt->ProcessForeignEvent(event, nullptr);
   }
@@ -1890,7 +1924,7 @@
 bool UnityScreen::altTabInitiateCommon(CompAction* action, switcher::ShowMode show_mode)
 {
   if (!grab_index_)
-    grab_index_ = screen->pushGrab (screen->invisibleCursor(), "unity-switcher");
+    grab_index_ = screen->pushGrab (screen->normalCursor(), "unity-switcher");
 
   screen->addAction(&optionGetAltTabRight());
   screen->addAction(&optionGetAltTabDetailStart());
@@ -1921,18 +1955,6 @@
 
 void UnityScreen::SetUpAndShowSwitcher(switcher::ShowMode show_mode)
 {
-  // maybe check launcher position/hide state?
-
-  auto uscreen = UScreen::GetDefault();
-  int monitor = uscreen->GetMonitorWithMouse();
-  auto monitor_geo = uscreen->GetMonitorGeometry(monitor);
-
-  monitor_geo.x += 100;
-  monitor_geo.y += 100;
-  monitor_geo.width -= 200;
-  monitor_geo.height -= 200;
-  switcher_controller_->SetWorkspace(monitor_geo, monitor);
-
   RaiseInputWindows();
 
   auto results = launcher_controller_->GetAltTabIcons(show_mode == switcher::ShowMode::CURRENT_VIEWPORT,
@@ -3819,15 +3841,31 @@
   if (state != ScaleScreen::Wait && state != ScaleScreen::Out)
     return;
 
-  auto const& scaled_geo = GetScaledGeometry();
+  nux::Geometry const& scale_geo = GetScaledGeometry();
+
   auto const& pos = scale_win->getCurrentPosition();
 
   bool highlighted = (ss->getSelectedWindow() == window->id());
-  paintFakeDecoration(scaled_geo, attrib, transform, mask, highlighted, pos.scale);
+  paintFakeDecoration(scale_geo, attrib, transform, mask, highlighted, pos.scale);
+}
+
+nux::Geometry UnityWindow::GetLayoutWindowGeometry()
+{
+  auto const& layout_window = UnityScreen::get(screen)->GetSwitcherDetailLayoutWindow(window->id());
+
+  if (layout_window)
+    return layout_window->result;
+
+  return nux::Geometry();
 }
 
 nux::Geometry UnityWindow::GetScaledGeometry()
 {
+  WindowManager& wm = WindowManager::Default();
+
+  if (!wm.IsScaleActive())
+    return nux::Geometry();
+
   ScaleWindow* scale_win = ScaleWindow::get(window);
 
   ScalePosition const& pos = scale_win->getCurrentPosition();

=== modified file 'plugins/unityshell/src/unityshell.h'
--- plugins/unityshell/src/unityshell.h	2013-08-07 13:27:56 +0000
+++ plugins/unityshell/src/unityshell.h	2013-08-09 17:51:48 +0000
@@ -193,6 +193,8 @@
 
   bool DoesPointIntersectUnityGeos(nux::Point const& pt);
 
+  ui::LayoutWindow::Ptr GetSwitcherDetailLayoutWindow(Window window) const;
+
 protected:
   std::string GetName() const;
   void AddProperties(GVariantBuilder* builder);
@@ -392,6 +394,7 @@
   bool place(CompPoint& pos);
   CompPoint tryNotIntersectUI(CompPoint& pos);
   nux::Geometry GetScaledGeometry();
+  nux::Geometry GetLayoutWindowGeometry();
 
   void paintThumbnail(nux::Geometry const& bounding, float parent_alpha, float alpha, float scale_ratio, unsigned deco_height, bool selected);
 

=== modified file 'tests/autopilot/unity/emulators/switcher.py'
--- tests/autopilot/unity/emulators/switcher.py	2013-05-10 05:16:07 +0000
+++ tests/autopilot/unity/emulators/switcher.py	2013-08-09 17:51:48 +0000
@@ -234,6 +234,20 @@
 class SwitcherView(UnityIntrospectionObject):
     """An emulator class for interacting with with SwitcherView."""
 
+    @property
+    def icon_args(self):
+        return self.get_children_by_type(RenderArgs);
+
+    @property
+    def detail_icons(self):
+        return self.get_children_by_type(LayoutWindow);
+
+
+class RenderArgs(UnityIntrospectionObject):
+  """An emulator class for interacting with the RenderArgs class."""
+
+class LayoutWindow(UnityIntrospectionObject):
+  """An emulator class for interacting with the LayoutWindows class."""
 
 class SwitcherModel(UnityIntrospectionObject):
     """An emulator class for interacting with the SwitcherModel."""

=== modified file 'tests/autopilot/unity/tests/test_switcher.py'
--- tests/autopilot/unity/tests/test_switcher.py	2013-06-15 02:24:01 +0000
+++ tests/autopilot/unity/tests/test_switcher.py	2013-08-09 17:51:48 +0000
@@ -512,3 +512,102 @@
         self.addCleanup(self.unity.switcher.terminate)
 
         self.assertThat(self.unity.switcher.visible, Eventually(Equals(False)))
+
+class SwitcherDetailsMouseTests(SwitcherTestCase):
+    """ Test the interactions with the mouse and the switcher. """
+
+    def setUp(self):
+        super(SwitcherDetailsMouseTests, self).setUp()
+        self.set_timeout_setting(False)
+
+    def test_mouse_highlights_switcher_icons(self):
+        """ Tests that the mouse can hightlight all the switcher icons. """
+
+        self.process_manager.start_app("Character Map")
+
+        self.unity.switcher.initiate()
+        self.addCleanup(self.unity.switcher.terminate)
+
+        icon_args = self.unity.switcher.view.icon_args
+        offset = self.unity.switcher.view.spread_offset
+        icon_cords = []
+
+        # Must collect the cords before moving mouse
+        for args in icon_args:
+            x = args.logical_center_x + offset
+            y = args.logical_center_y + offset
+            icon_cords.append((x,y))
+
+        index = 0;
+        for cords in icon_cords:
+            self.mouse.move(cords[0], cords[1])
+            self.assertThat(index, Equals(self.unity.switcher.selection_index))
+            index += 1
+
+    def test_mouse_clicks_activate_icon(self):
+        """
+        Opens 2 different applications, CharMap being opened before TextEditor.
+        Then we get the index of the CharMap, and click on it, asserting CharMap is focused.
+        """
+
+        char_win1, char_win2 = self.start_applications("Character Map", "Text Editor")
+        self.assertVisibleWindowStack([char_win2, char_win1])
+        self.assertProperty(char_win1, is_focused=False)
+
+        self.unity.switcher.initiate()
+        self.addCleanup(self.unity.switcher.terminate)
+
+        index = self.unity.switcher.selection_index
+        offset = self.unity.switcher.view.spread_offset
+
+        icon_arg = self.unity.switcher.view.icon_args[index]
+        x = icon_arg.logical_center_x + offset
+        y = icon_arg.logical_center_y + offset
+        self.mouse.move(x, y)
+        self.mouse.click()
+
+        self.assertProperty(char_win1, is_focused=True)
+
+    def test_mouse_highlights_switcher_deatil_icons_motion(self):
+        """
+        Gather the cords of all the detail icons, move the mouse through each
+        asserting the index of each icon we move through.
+        """
+
+        self.start_applications("Character Map", "Character Map", "Character Map")
+
+        self.unity.switcher.initiate(SwitcherMode.DETAIL)
+        self.addCleanup(self.unity.switcher.terminate)
+
+        offset = self.unity.switcher.view.spread_offset
+        cords = []
+
+        for icon in self.unity.switcher.view.detail_icons:
+            cords.append((icon.x + offset, icon.y + offset))
+
+        index = 0;
+        for cord in cords:
+          self.mouse.move(cord[0], cord[1])
+          self.assertThat(index, Equals(self.unity.switcher.detail_selection_index))
+          index += 1
+
+    def test_mouse_click_will_activate_detail_icon(self):
+        """
+        Start 2 application of the same type, then click on index 0 in detail mode. This
+        will cause the focus from char_win2 to move to char_win1, showing clicking wokrs.
+        """
+
+        char_win1, char_win2 = self.start_applications("Character Map", "Character Map")
+        self.assertVisibleWindowStack([char_win2, char_win1])
+
+        self.unity.switcher.initiate(SwitcherMode.DETAIL)
+        self.addCleanup(self.unity.switcher.terminate)
+
+        offset = self.unity.switcher.view.spread_offset
+        x = self.unity.switcher.view.detail_icons[0].x + offset
+        y = self.unity.switcher.view.detail_icons[0].y + offset
+
+        self.mouse.move(x,y)
+        self.mouse.click()
+
+        self.assertProperty(char_win1, is_focused=True)

=== modified file 'tests/test_switcher_controller.cpp'
--- tests/test_switcher_controller.cpp	2013-06-21 18:58:17 +0000
+++ tests/test_switcher_controller.cpp	2013-08-09 17:51:48 +0000
@@ -272,3 +272,31 @@
   EXPECT_EQ(mock_window_->GetOpacity(), 0.0f);
   Mock::VerifyAndClearExpectations(mock_window_.GetPointer());
 }
+
+TEST_F(TestSwitcherController, TestRightClickedReceived)
+{
+  controller_->Show(ShowMode::ALL, SortMode::LAUNCHER_ORDER, icons_);
+
+  auto const& view = controller_->GetView();
+  auto const& model = view->GetModel();
+
+  ASSERT_FALSE(model->detail_selection());
+
+  view->switcher_mouse_up.emit(-1, 3);
+  view->switcher_mouse_down.emit(-1, 3);
+
+  ASSERT_TRUE(model->detail_selection());
+}
+
+TEST_F(TestSwitcherController, TestHideRequest)
+{
+  controller_->Show(ShowMode::ALL, SortMode::LAUNCHER_ORDER, icons_);
+
+  auto const& view = controller_->GetView();
+
+  ASSERT_TRUE(controller_->Visible());
+
+  view->hide_request.emit(false);
+
+  ASSERT_FALSE(controller_->Visible());
+}

=== modified file 'unity-shared/AbstractIconRenderer.h'
--- unity-shared/AbstractIconRenderer.h	2013-04-12 23:33:52 +0000
+++ unity-shared/AbstractIconRenderer.h	2013-08-09 17:51:48 +0000
@@ -22,8 +22,11 @@
 
 #include <Nux/Nux.h>
 
+#include "Introspectable.h"
 #include "IconTextureSource.h"
 
+#include <UnityCore/Variant.h>
+
 namespace unity
 {
 namespace ui
@@ -35,7 +38,7 @@
   OVER_TILE,
 };
 
-class RenderArg
+class RenderArg : public debug::Introspectable
 {
 public:
   RenderArg()
@@ -91,6 +94,17 @@
   bool          colorify_background;
   int           window_indicators;
   char          shortcut_label;
+
+protected:
+  // Introspectable methods
+  std::string GetName() const { return "RenderArgs"; }
+  void AddProperties(GVariantBuilder* builder)
+  {
+    unity::variant::BuilderWrapper(builder)
+        .add("logical_center_x", logical_center.x)
+        .add("logical_center_y", logical_center.y)
+        .add("logical_center_z", logical_center.z);
+  }
 };
 
 class AbstractIconRenderer

=== modified file 'unity-shared/LayoutSystem.cpp'
--- unity-shared/LayoutSystem.cpp	2013-06-17 23:56:23 +0000
+++ unity-shared/LayoutSystem.cpp	2013-08-09 17:51:48 +0000
@@ -19,6 +19,8 @@
 
 #include "LayoutSystem.h"
 
+#include <UnityCore/Variant.h>
+
 namespace unity {
 namespace ui {
 
@@ -290,5 +292,17 @@
   }
 }
 
+// Introspectable methods
+std::string LayoutWindow::GetName() const
+{
+  return "LayoutWindow";
+}
+
+void LayoutWindow::AddProperties(GVariantBuilder* builder)
+{
+  unity::variant::BuilderWrapper(builder)
+    .add(result);
+}
+
 }
 }

=== modified file 'unity-shared/LayoutSystem.h'
--- unity-shared/LayoutSystem.h	2013-06-14 00:23:34 +0000
+++ unity-shared/LayoutSystem.h	2013-08-09 17:51:48 +0000
@@ -24,13 +24,15 @@
 #include <sigc++/sigc++.h>
 #include <Nux/Nux.h>
 
+#include "unity-shared/Introspectable.h"
 #include "unity-shared/WindowManager.h"
 
 namespace unity {
 namespace ui {
 
-struct LayoutWindow
+class LayoutWindow : public debug::Introspectable
 {
+public:
   typedef std::shared_ptr<LayoutWindow> Ptr;
   typedef std::vector<LayoutWindow::Ptr> Vector;
 
@@ -45,6 +47,11 @@
   bool selected;
   float aspect_ratio;
   float alpha;
+
+protected:
+  // Introspectable methods
+  std::string GetName() const;
+  void AddProperties(GVariantBuilder* builder);
 };
 
 class LayoutSystem

