Back to index

unity  6.0.0
DashController.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2010 Canonical Ltd
00003  *
00004  * This program is free software: you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License version 3 as
00006  * published by the Free Software Foundation.
00007  *
00008  * This program is distributed in the hope that it will be useful,
00009  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011  * GNU General Public License for more details.
00012  *
00013  * You should have received a copy of the GNU General Public License
00014  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00015  *
00016  * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
00017  */
00018 
00019 #include "DashController.h"
00020 
00021 #include <NuxCore/Logger.h>
00022 #include <Nux/HLayout.h>
00023 
00024 #include "unity-shared/UnitySettings.h"
00025 #include "unity-shared/PanelStyle.h"
00026 #include "unity-shared/PluginAdapter.h"
00027 #include "unity-shared/UBusMessages.h"
00028 #include "unity-shared/UScreen.h"
00029 
00030 namespace unity
00031 {
00032 namespace dash
00033 {
00034 
00035 const char window_title[] = "unity-dash";
00036 
00037 namespace
00038 {
00039 nux::logging::Logger logger("unity.dash.controller");
00040 const unsigned int PRELOAD_TIMEOUT_LENGTH = 40;
00041 }
00042 
00043 Controller::Controller()
00044   : launcher_width(64)
00045   , use_primary(false)
00046   , monitor_(0)
00047   , visible_(false)
00048   , need_show_(false)
00049   , view_(nullptr)
00050   , ensure_timeout_(PRELOAD_TIMEOUT_LENGTH)
00051   , timeline_animator_(90)
00052 {
00053   SetupRelayoutCallbacks();
00054   RegisterUBusInterests();
00055 
00056   ensure_timeout_.Run([&]() { EnsureDash(); return false; });
00057   timeline_animator_.animation_updated.connect(sigc::mem_fun(this, &Controller::OnViewShowHideFrame));
00058 
00059   SetupWindow();
00060 
00061   Settings::Instance().changed.connect([&]()
00062   {
00063     if (window_ && view_)
00064     {
00065       window_->PushToFront();
00066       window_->SetInputFocus();
00067       nux::GetWindowCompositor().SetKeyFocusArea(view_->default_focus());
00068     }
00069   });
00070 
00071   auto spread_cb = sigc::bind(sigc::mem_fun(this, &Controller::HideDash), true);
00072   PluginAdapter::Default()->initiate_spread.connect(spread_cb);
00073 }
00074 
00075 void Controller::SetupWindow()
00076 {
00077   window_ = new nux::BaseWindow(dash::window_title);
00078   window_->SetBackgroundColor(nux::Color(0.0f, 0.0f, 0.0f, 0.0f));
00079   window_->SetConfigureNotifyCallback(&Controller::OnWindowConfigure, this);
00080   window_->ShowWindow(false);
00081   window_->SetOpacity(0.0f);
00082   window_->mouse_down_outside_pointer_grab_area.connect(sigc::mem_fun(this, &Controller::OnMouseDownOutsideWindow));
00083 
00084   /* FIXME - first time we load our windows there is a race that causes the input window not to actually get input, this side steps that by causing an input window show and hide before we really need it. */
00085   auto plugin_adapter = PluginAdapter::Default();
00086   plugin_adapter->saveInputFocus ();
00087   window_->EnableInputWindow(true, dash::window_title, true, false);
00088   window_->EnableInputWindow(false, dash::window_title, true, false);
00089   plugin_adapter->restoreInputFocus ();
00090 }
00091 
00092 void Controller::SetupDashView()
00093 {
00094   view_ = new DashView();
00095   AddChild(view_);
00096 
00097   nux::HLayout* layout = new nux::HLayout(NUX_TRACKER_LOCATION);
00098   layout->AddView(view_, 1);
00099   layout->SetContentDistribution(nux::eStackLeft);
00100   layout->SetVerticalExternalMargin(0);
00101   layout->SetHorizontalExternalMargin(0);
00102 
00103   window_->SetLayout(layout);
00104   ubus_manager_.UnregisterInterest(UBUS_PLACE_ENTRY_ACTIVATE_REQUEST);
00105 }
00106 
00107 void Controller::SetupRelayoutCallbacks()
00108 {
00109   GdkScreen* screen = gdk_screen_get_default();
00110 
00111   sig_manager_.Add(new glib::Signal<void, GdkScreen*>(screen,
00112     "monitors-changed", sigc::mem_fun(this, &Controller::Relayout)));
00113   sig_manager_.Add(new glib::Signal<void, GdkScreen*>(screen,
00114     "size-changed", sigc::mem_fun(this, &Controller::Relayout)));
00115 }
00116 
00117 void Controller::RegisterUBusInterests()
00118 {
00119   ubus_manager_.RegisterInterest(UBUS_DASH_EXTERNAL_ACTIVATION,
00120                                  sigc::mem_fun(this, &Controller::OnExternalShowDash));
00121   ubus_manager_.RegisterInterest(UBUS_PLACE_VIEW_CLOSE_REQUEST,
00122                                  sigc::mem_fun(this, &Controller::OnExternalHideDash));
00123   ubus_manager_.RegisterInterest(UBUS_PLACE_ENTRY_ACTIVATE_REQUEST,
00124                                  sigc::mem_fun(this, &Controller::OnActivateRequest));
00125   ubus_manager_.RegisterInterest(UBUS_DASH_ABOUT_TO_SHOW,
00126                                  [&] (GVariant*) { EnsureDash(); });
00127   ubus_manager_.RegisterInterest(UBUS_OVERLAY_SHOWN, [&] (GVariant *data) {
00128     unity::glib::String overlay_identity;
00129     gboolean can_maximise = FALSE;
00130     gint32 overlay_monitor = 0;
00131     g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING, &overlay_identity, &can_maximise, &overlay_monitor);
00132 
00133     // hide if something else is coming up
00134     if (overlay_identity.Str() != "dash")
00135     {
00136       HideDash(true);
00137     }
00138   });
00139 }
00140 
00141 void Controller::EnsureDash()
00142 {
00143   LOG_DEBUG(logger) << "Initializing Dash";
00144   if (!window_)
00145     SetupWindow();
00146 
00147   if (!view_)
00148   {
00149     SetupDashView();
00150     Relayout();
00151     ensure_timeout_.Remove();
00152 
00153     on_realize.emit();
00154   }
00155 }
00156 
00157 nux::BaseWindow* Controller::window() const
00158 {
00159   return window_.GetPointer();
00160 }
00161 
00162 // We update the @geo that's sent in with our desired width and height
00163 void Controller::OnWindowConfigure(int window_width, int window_height,
00164                                        nux::Geometry& geo, void* data)
00165 {
00166   Controller* self = static_cast<Controller*>(data);
00167   geo = self->GetIdealWindowGeometry();
00168 }
00169 
00170 int Controller::GetIdealMonitor()
00171 {
00172   UScreen *uscreen = UScreen::GetDefault();
00173   int primary_monitor;
00174   if (use_primary)
00175     primary_monitor = uscreen->GetPrimaryMonitor();
00176   else
00177     primary_monitor = uscreen->GetMonitorWithMouse();
00178 
00179   return primary_monitor;
00180 }
00181 
00182 nux::Geometry Controller::GetIdealWindowGeometry()
00183 {
00184   UScreen *uscreen = UScreen::GetDefault();
00185   auto monitor_geo = uscreen->GetMonitorGeometry(GetIdealMonitor());
00186 
00187   // We want to cover as much of the screen as possible to grab any mouse events outside
00188   // of our window
00189   panel::Style &panel_style = panel::Style::Instance();
00190   return nux::Geometry (monitor_geo.x + launcher_width,
00191                         monitor_geo.y + panel_style.panel_height,
00192                         monitor_geo.width - launcher_width,
00193                         monitor_geo.height - panel_style.panel_height);
00194 }
00195 
00196 void Controller::Relayout(GdkScreen*screen)
00197 {
00198   EnsureDash();
00199 
00200   nux::Geometry geo = GetIdealWindowGeometry();
00201   window_->SetGeometry(geo);
00202   view_->Relayout();
00203   panel::Style &panel_style = panel::Style::Instance();
00204   view_->SetMonitorOffset(launcher_width, panel_style.panel_height);
00205 }
00206 
00207 void Controller::OnMouseDownOutsideWindow(int x, int y,
00208                                           unsigned long bflags, unsigned long kflags)
00209 {
00210   HideDash();
00211 }
00212 
00213 void Controller::OnScreenUngrabbed()
00214 {
00215   LOG_DEBUG(logger) << "On Screen Ungrabbed called";
00216   if (need_show_)
00217   {
00218     EnsureDash();
00219     ShowDash();
00220   }
00221 }
00222 
00223 void Controller::OnExternalShowDash(GVariant* variant)
00224 {
00225   EnsureDash();
00226   visible_ ? HideDash() : ShowDash();
00227 }
00228 
00229 void Controller::OnExternalHideDash(GVariant* variant)
00230 {
00231   EnsureDash();
00232 
00233   if (variant)
00234   {
00235     HideDash(g_variant_get_boolean(variant));
00236   }
00237   else
00238   {
00239     HideDash();
00240   }
00241 }
00242 
00243 void Controller::ShowDash()
00244 {
00245   EnsureDash();
00246   PluginAdapter* adaptor = PluginAdapter::Default();
00247   // Don't want to show at the wrong time
00248   if (visible_ || adaptor->IsExpoActive() || adaptor->IsScaleActive())
00249     return;
00250 
00251   // We often need to wait for the mouse/keyboard to be available while a plugin
00252   // is finishing it's animations/cleaning up. In these cases, we patiently wait
00253   // for the screen to be available again before honouring the request.
00254   if (adaptor->IsScreenGrabbed())
00255   {
00256     screen_ungrabbed_slot_.disconnect();
00257     screen_ungrabbed_slot_ = PluginAdapter::Default()->compiz_screen_ungrabbed.connect(sigc::mem_fun(this, &Controller::OnScreenUngrabbed));
00258     need_show_ = true;
00259     return;
00260   }
00261   view_->AboutToShow();
00262 
00263   window_->ShowWindow(true);
00264   window_->PushToFront();
00265   if (!Settings::Instance().is_standalone) // in standalone mode, we do not need an input window. we are one.
00266     window_->EnableInputWindow(true, dash::window_title, true, false);
00267   window_->SetInputFocus();
00268   window_->CaptureMouseDownAnyWhereElse(true);
00269   window_->QueueDraw();
00270 
00271   nux::GetWindowCompositor().SetKeyFocusArea(view_->default_focus());
00272 
00273   need_show_ = false;
00274   visible_ = true;
00275 
00276   StartShowHideTimeline();
00277 
00278   monitor_ = GetIdealMonitor();
00279   GVariant* info = g_variant_new(UBUS_OVERLAY_FORMAT_STRING, "dash", TRUE, monitor_);
00280   ubus_manager_.SendMessage(UBUS_OVERLAY_SHOWN, info);
00281 }
00282 
00283 void Controller::HideDash(bool restore)
00284 {
00285   if (!visible_)
00286    return;
00287 
00288   screen_ungrabbed_slot_.disconnect();
00289 
00290   EnsureDash();
00291 
00292   view_->AboutToHide();
00293 
00294   window_->CaptureMouseDownAnyWhereElse(false);
00295   window_->EnableInputWindow(false, dash::window_title, true, false);
00296   visible_ = false;
00297 
00298   nux::GetWindowCompositor().SetKeyFocusArea(NULL,nux::KEY_NAV_NONE);
00299 
00300   if (restore)
00301     PluginAdapter::Default ()->restoreInputFocus ();
00302 
00303   StartShowHideTimeline();
00304 
00305   GVariant* info = g_variant_new(UBUS_OVERLAY_FORMAT_STRING, "dash", TRUE, monitor_);
00306   ubus_manager_.SendMessage(UBUS_OVERLAY_HIDDEN, info);
00307 }
00308 
00309 void Controller::StartShowHideTimeline()
00310 {
00311   EnsureDash();
00312 
00313   double current_opacity = window_->GetOpacity();
00314   timeline_animator_.Stop();
00315   timeline_animator_.Start(visible_ ? current_opacity : 1.0f - current_opacity);
00316 }
00317 
00318 void Controller::OnViewShowHideFrame(double progress)
00319 {
00320   window_->SetOpacity(visible_ ? progress : 1.0f - progress);
00321 
00322   if (progress == 1.0f && !visible_)
00323   {
00324     window_->ShowWindow(false);
00325   }
00326 }
00327 
00328 void Controller::OnActivateRequest(GVariant* variant)
00329 {
00330   EnsureDash();
00331   view_->OnActivateRequest(variant);
00332 }
00333 
00334 gboolean Controller::CheckShortcutActivation(const char* key_string)
00335 {
00336   EnsureDash();
00337   std::string lens_id = view_->GetIdForShortcutActivation(std::string(key_string));
00338   if (lens_id != "")
00339   {
00340     if (PluginAdapter::Default()->IsScaleActive())
00341       PluginAdapter::Default()->TerminateScale();
00342 
00343     GVariant* args = g_variant_new("(sus)", lens_id.c_str(), dash::GOTO_DASH_URI, "");
00344     OnActivateRequest(args);
00345     g_variant_unref(args);
00346     return true;
00347   }
00348   return false;
00349 }
00350 
00351 std::vector<char> Controller::GetAllShortcuts()
00352 {
00353   EnsureDash();
00354   return view_->GetAllShortcuts();
00355 }
00356 
00357 // Introspectable
00358 std::string Controller::GetName() const
00359 {
00360   return "DashController";
00361 }
00362 
00363 void Controller::AddProperties(GVariantBuilder* builder)
00364 {
00365   variant::BuilderWrapper(builder).add("visible", visible_)
00366                                   .add("monitor", monitor_);
00367 }
00368 
00369 
00370 }
00371 }