Back to index

unity  6.0.0
LauncherController.cpp
Go to the documentation of this file.
00001 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
00002 /*
00003  * Copyright (C) 2010, 2011 Canonical Ltd
00004  *
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 3 as
00007  * published by the Free Software Foundation.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016  *
00017  * Authored by: Jason Smith <jason.smith@canonical.com>
00018  *              Tim Penhey <tim.penhey@canonical.com>
00019  */
00020 
00021 #include <glib/gi18n-lib.h>
00022 #include <libbamf/libbamf.h>
00023 
00024 #include <Nux/Nux.h>
00025 #include <Nux/HLayout.h>
00026 #include <Nux/BaseWindow.h>
00027 #include <NuxCore/Logger.h>
00028 
00029 #include "LauncherOptions.h"
00030 #include "BamfLauncherIcon.h"
00031 #include "DesktopLauncherIcon.h"
00032 #include "DeviceLauncherIcon.h"
00033 #include "DeviceLauncherSection.h"
00034 #include "EdgeBarrierController.h"
00035 #include "FavoriteStore.h"
00036 #include "HudLauncherIcon.h"
00037 #include "Launcher.h"
00038 #include "LauncherController.h"
00039 #include "LauncherEntryRemote.h"
00040 #include "LauncherEntryRemoteModel.h"
00041 #include "AbstractLauncherIcon.h"
00042 #include "SoftwareCenterLauncherIcon.h"
00043 #include "LauncherModel.h"
00044 #include "unity-shared/WindowManager.h"
00045 #include "TrashLauncherIcon.h"
00046 #include "BFBLauncherIcon.h"
00047 #include "unity-shared/UScreen.h"
00048 #include "unity-shared/UBusWrapper.h"
00049 #include "unity-shared/UBusMessages.h"
00050 #include "unity-shared/TimeUtil.h"
00051 
00052 namespace unity
00053 {
00054 namespace launcher
00055 {
00056 namespace
00057 {
00058 nux::logging::Logger logger("unity.launcher");
00059 
00060 const std::string DBUS_NAME = "com.canonical.Unity.Launcher";
00061 const std::string DBUS_PATH = "/com/canonical/Unity/Launcher";
00062 const std::string DBUS_INTROSPECTION =
00063   "<node>"
00064   "  <interface name='com.canonical.Unity.Launcher'>"
00065   ""
00066   "    <method name='AddLauncherItemFromPosition'>"
00067   "      <arg type='s' name='title' direction='in'/>"
00068   "      <arg type='s' name='icon' direction='in'/>"
00069   "      <arg type='i' name='icon_x' direction='in'/>"
00070   "      <arg type='i' name='icon_y' direction='in'/>"
00071   "      <arg type='i' name='icon_size' direction='in'/>"
00072   "      <arg type='s' name='desktop_file' direction='in'/>"
00073   "      <arg type='s' name='aptdaemon_task' direction='in'/>"
00074   "    </method>"
00075   ""
00076   "  </interface>"
00077   "</node>";
00078 }
00079 
00080 namespace local
00081 {
00082 namespace
00083 {
00084   const int super_tap_duration = 250;
00085   const int launcher_minimum_show_duration = 1250;
00086   const int shortcuts_show_delay = 750;
00087   const int ignore_repeat_shortcut_duration = 250;
00088 
00089   const std::string KEYPRESS_TIMEOUT = "keypress-timeout";
00090   const std::string LABELS_TIMEOUT = "label-show-timeout";
00091   const std::string HIDE_TIMEOUT = "hide-timeout";
00092 }
00093 }
00094 
00095 class Controller::Impl
00096 {
00097 public:
00098   Impl(Display* display, Controller* parent);
00099   ~Impl();
00100 
00101   void UpdateNumWorkspaces(int workspaces);
00102 
00103   Launcher* CreateLauncher(int monitor);
00104 
00105   void Save();
00106   void SortAndUpdate();
00107 
00108   nux::ObjectPtr<Launcher> CurrentLauncher();
00109 
00110   void OnIconAdded(AbstractLauncherIcon::Ptr icon);
00111   void OnIconRemoved(AbstractLauncherIcon::Ptr icon);
00112 
00113   void OnLauncherAddRequest(char* path, AbstractLauncherIcon::Ptr before);
00114   void OnLauncherAddRequestSpecial(std::string const& path, std::string const& aptdaemon_trans_id,
00115                                    std::string const& icon_path, int icon_x, int icon_y, int icon_size);
00116   void OnLauncherRemoveRequest(AbstractLauncherIcon::Ptr icon);
00117   void OnSCIconAnimationComplete(AbstractLauncherIcon::Ptr icon);
00118 
00119   void OnLauncherEntryRemoteAdded(LauncherEntryRemote::Ptr const& entry);
00120   void OnLauncherEntryRemoteRemoved(LauncherEntryRemote::Ptr const& entry);
00121 
00122   void OnFavoriteStoreFavoriteAdded(std::string const& entry, std::string const& pos, bool before);
00123   void OnFavoriteStoreFavoriteRemoved(std::string const& entry);
00124   void OnFavoriteStoreReordered();
00125 
00126 
00127   void InsertExpoAction();
00128   void RemoveExpoAction();
00129 
00130   void InsertDesktopIcon();
00131   void RemoveDesktopIcon();
00132 
00133   void SendHomeActivationRequest();
00134 
00135   int MonitorWithMouse();
00136 
00137   void InsertTrash();
00138 
00139   void RegisterIcon(AbstractLauncherIcon::Ptr icon);
00140 
00141   AbstractLauncherIcon::Ptr CreateFavorite(const char* file_path);
00142 
00143   SoftwareCenterLauncherIcon::Ptr CreateSCLauncherIcon(std::string const& file_path, std::string const& aptdaemon_trans_id, std::string const& icon_path);
00144 
00145   void SetupBamf();
00146 
00147   void EnsureLaunchers(int primary, std::vector<nux::Geometry> const& monitors);
00148 
00149   void OnExpoActivated();
00150 
00151   void OnScreenChanged(int primary_monitor, std::vector<nux::Geometry>& monitors);
00152 
00153   void OnWindowFocusChanged (guint32 xid);
00154 
00155   void OnViewOpened(BamfMatcher* matcher, BamfView* view);
00156 
00157   void ReceiveMouseDownOutsideArea(int x, int y, unsigned long button_flags, unsigned long key_flags);
00158 
00159   void ReceiveLauncherKeyPress(unsigned long eventType,
00160                                unsigned long keysym,
00161                                unsigned long state,
00162                                const char* character,
00163                                unsigned short keyCount);
00164 
00165   static void OnBusAcquired(GDBusConnection* connection, const gchar* name, gpointer user_data);
00166   static void OnDBusMethodCall(GDBusConnection* connection, const gchar* sender, const gchar* object_path,
00167                                const gchar* interface_name, const gchar* method_name,
00168                                GVariant* parameters, GDBusMethodInvocation* invocation,
00169                                gpointer user_data);
00170 
00171   static GDBusInterfaceVTable interface_vtable;
00172 
00173   Controller* parent_;
00174   LauncherModel::Ptr model_;
00175   nux::ObjectPtr<Launcher> launcher_;
00176   nux::ObjectPtr<Launcher> keyboard_launcher_;
00177   int                    sort_priority_;
00178   DeviceLauncherSection  device_section_;
00179   LauncherEntryRemoteModel remote_model_;
00180   AbstractLauncherIcon::Ptr expo_icon_;
00181   AbstractLauncherIcon::Ptr desktop_icon_;
00182   int                    num_workspaces_;
00183   bool                   show_desktop_icon_;
00184   Display*               display_;
00185 
00186   bool                   launcher_open;
00187   bool                   launcher_keynav;
00188   bool                   launcher_grabbed;
00189   bool                   reactivate_keynav;
00190   int                    reactivate_index;
00191   bool                   keynav_restore_window_;
00192   int                    launcher_key_press_time_;
00193   unsigned int           dbus_owner_;
00194 
00195   ui::EdgeBarrierController::Ptr edge_barriers_;
00196 
00197   LauncherList launchers;
00198 
00199   glib::Object<BamfMatcher> matcher_;
00200   glib::Signal<void, BamfMatcher*, BamfView*> view_opened_signal_;
00201   glib::SourceManager sources_;
00202   UBusManager ubus;
00203 
00204   sigc::connection on_expoicon_activate_connection_;
00205   sigc::connection launcher_key_press_connection_;
00206   sigc::connection launcher_event_outside_connection_;
00207 };
00208 
00209 GDBusInterfaceVTable Controller::Impl::interface_vtable =
00210   { Controller::Impl::OnDBusMethodCall, NULL, NULL};
00211 
00212 Controller::Impl::Impl(Display* display, Controller* parent)
00213   : parent_(parent)
00214   , model_(new LauncherModel())
00215   , sort_priority_(0)
00216   , show_desktop_icon_(false)
00217   , display_(display)
00218   , edge_barriers_(new ui::EdgeBarrierController())
00219   , matcher_(bamf_matcher_get_default())
00220 {
00221   edge_barriers_->options = parent_->options();
00222 
00223   UScreen* uscreen = UScreen::GetDefault();
00224   auto monitors = uscreen->GetMonitors();
00225   int primary = uscreen->GetPrimaryMonitor();
00226 
00227   launcher_open = false;
00228   launcher_keynav = false;
00229   launcher_grabbed = false;
00230   reactivate_keynav = false;
00231   keynav_restore_window_ = true;
00232 
00233   EnsureLaunchers(primary, monitors);
00234 
00235   launcher_ = launchers[0];
00236   device_section_.IconAdded.connect(sigc::mem_fun(this, &Impl::OnIconAdded));
00237 
00238   num_workspaces_ = WindowManager::Default()->WorkspaceCount();
00239   if (num_workspaces_ > 1)
00240   {
00241     InsertExpoAction();
00242   }
00243 
00244   // Insert the "Show Desktop" launcher icon in the launcher...
00245   if (show_desktop_icon_)
00246     InsertDesktopIcon();
00247 
00248   InsertTrash();
00249 
00250   sources_.Add(std::make_shared<glib::Timeout>(500, [&]() { SetupBamf(); return false; }));
00251 
00252   remote_model_.entry_added.connect(sigc::mem_fun(this, &Impl::OnLauncherEntryRemoteAdded));
00253   remote_model_.entry_removed.connect(sigc::mem_fun(this, &Impl::OnLauncherEntryRemoteRemoved));
00254 
00255   FavoriteStore::Instance().favorite_added.connect(sigc::mem_fun(this, &Impl::OnFavoriteStoreFavoriteAdded));
00256   FavoriteStore::Instance().favorite_removed.connect(sigc::mem_fun(this, &Impl::OnFavoriteStoreFavoriteRemoved));
00257   FavoriteStore::Instance().reordered.connect(sigc::mem_fun(this, &Impl::OnFavoriteStoreReordered));
00258 
00259   LauncherHideMode hide_mode = parent_->options()->hide_mode;
00260   BFBLauncherIcon* bfb = new BFBLauncherIcon(hide_mode);
00261   RegisterIcon(AbstractLauncherIcon::Ptr(bfb));
00262 
00263   HudLauncherIcon* hud = new HudLauncherIcon(hide_mode);
00264   RegisterIcon(AbstractLauncherIcon::Ptr(hud));
00265 
00266   parent_->options()->hide_mode.changed.connect([bfb,hud](LauncherHideMode mode) {
00267     bfb->SetHideMode(mode);
00268     hud->SetHideMode(mode);
00269   });
00270 
00271   desktop_icon_ = AbstractLauncherIcon::Ptr(new DesktopLauncherIcon());
00272 
00273   uscreen->changed.connect(sigc::mem_fun(this, &Controller::Impl::OnScreenChanged));
00274 
00275   WindowManager& plugin_adapter = *(WindowManager::Default());
00276   plugin_adapter.window_focus_changed.connect (sigc::mem_fun (this, &Controller::Impl::OnWindowFocusChanged));
00277 
00278   launcher_key_press_time_ = 0;
00279 
00280   ubus.RegisterInterest(UBUS_QUICKLIST_END_KEY_NAV, [&](GVariant * args) {
00281     if (reactivate_keynav)
00282       parent_->KeyNavGrab();
00283       model_->SetSelection(reactivate_index);
00284   });
00285 
00286   parent_->AddChild(model_.get());
00287 
00288   uscreen->resuming.connect([&]() -> void {
00289     for (auto launcher : launchers)
00290       launcher->QueueDraw();
00291   });
00292 
00293   dbus_owner_ = g_bus_own_name(G_BUS_TYPE_SESSION, DBUS_NAME.c_str(), G_BUS_NAME_OWNER_FLAGS_NONE,
00294                                OnBusAcquired, nullptr, nullptr, this, nullptr);
00295 }
00296 
00297 Controller::Impl::~Impl()
00298 {
00299   // Since the launchers are in a window which adds a reference to the
00300   // launcher, we need to make sure the base windows are unreferenced
00301   // otherwise the launchers never die.
00302   for (auto launcher_ptr : launchers)
00303   {
00304     if (launcher_ptr.IsValid())
00305       launcher_ptr->GetParent()->UnReference();
00306   }
00307 
00308   g_bus_unown_name(dbus_owner_);
00309 }
00310 
00311 void Controller::Impl::EnsureLaunchers(int primary, std::vector<nux::Geometry> const& monitors)
00312 {
00313   unsigned int num_monitors = monitors.size();
00314   unsigned int num_launchers = parent_->multiple_launchers ? num_monitors : 1;
00315   unsigned int launchers_size = launchers.size();
00316   unsigned int last_monitor = 0;
00317 
00318   if (num_launchers == 1)
00319   {
00320     if (launchers_size == 0)
00321     {
00322       launchers.push_back(nux::ObjectPtr<Launcher>(CreateLauncher(primary)));
00323     }
00324     else if (!launchers[0].IsValid())
00325     {
00326       launchers[0] = nux::ObjectPtr<Launcher>(CreateLauncher(primary));
00327     }
00328 
00329     launchers[0]->monitor(primary);
00330     launchers[0]->Resize();
00331     last_monitor = 1;
00332   }
00333   else
00334   {
00335     for (unsigned int i = 0; i < num_monitors; i++, last_monitor++)
00336     {
00337       if (i >= launchers_size)
00338       {
00339         launchers.push_back(nux::ObjectPtr<Launcher>(CreateLauncher(i)));
00340       }
00341 
00342       launchers[i]->monitor(i);
00343       launchers[i]->Resize();
00344     }
00345   }
00346 
00347   for (unsigned int i = last_monitor; i < launchers_size; ++i)
00348   {
00349     auto launcher = launchers[i];
00350     if (launcher.IsValid())
00351     {
00352       parent_->RemoveChild(launcher.GetPointer());
00353       launcher->GetParent()->UnReference();
00354       edge_barriers_->Unsubscribe(launcher.GetPointer(), launcher->monitor);
00355     }
00356   }
00357 
00358   launchers.resize(num_launchers);
00359 
00360   for (size_t i = 0; i < launchers.size(); ++i)
00361   {
00362     edge_barriers_->Subscribe(launchers[i].GetPointer(), launchers[i]->monitor);
00363   }
00364 }
00365 
00366 void Controller::Impl::OnScreenChanged(int primary_monitor, std::vector<nux::Geometry>& monitors)
00367 {
00368   EnsureLaunchers(primary_monitor, monitors);
00369 }
00370 
00371 void Controller::Impl::OnWindowFocusChanged (guint32 xid)
00372 {
00373   static bool keynav_first_focus = false;
00374 
00375   if (parent_->IsOverlayOpen())
00376     keynav_first_focus = false;
00377 
00378   if (keynav_first_focus)
00379   {
00380     keynav_first_focus = false;
00381     keynav_restore_window_ = false;
00382     parent_->KeyNavTerminate(false);
00383   }
00384   else if (launcher_keynav)
00385   {
00386     keynav_first_focus = true;
00387   }
00388 }
00389 
00390 Launcher* Controller::Impl::CreateLauncher(int monitor)
00391 {
00392   nux::BaseWindow* launcher_window = new nux::BaseWindow(TEXT("LauncherWindow"));
00393 
00394   Launcher* launcher = new Launcher(launcher_window);
00395   launcher->display = display_;
00396   launcher->monitor = monitor;
00397   launcher->options = parent_->options();
00398   launcher->SetModel(model_);
00399 
00400   nux::HLayout* layout = new nux::HLayout(NUX_TRACKER_LOCATION);
00401   layout->AddView(launcher, 1);
00402   layout->SetContentDistribution(nux::eStackLeft);
00403   layout->SetVerticalExternalMargin(0);
00404   layout->SetHorizontalExternalMargin(0);
00405 
00406   launcher_window->SetLayout(layout);
00407   launcher_window->SetBackgroundColor(nux::color::Transparent);
00408   launcher_window->ShowWindow(true);
00409   launcher_window->EnableInputWindow(true, launcher::window_title, false, false);
00410   launcher_window->InputWindowEnableStruts(false);
00411   launcher_window->SetEnterFocusInputArea(launcher);
00412 
00413   launcher->launcher_addrequest.connect(sigc::mem_fun(this, &Impl::OnLauncherAddRequest));
00414   launcher->launcher_removerequest.connect(sigc::mem_fun(this, &Impl::OnLauncherRemoveRequest));
00415 
00416   launcher->icon_animation_complete.connect(sigc::mem_fun(this, &Impl::OnSCIconAnimationComplete));
00417 
00418   parent_->AddChild(launcher);
00419 
00420   return launcher;
00421 }
00422 
00423 void Controller::Impl::OnLauncherAddRequest(char* path, AbstractLauncherIcon::Ptr before)
00424 {
00425   for (auto it : model_->GetSublist<BamfLauncherIcon> ())
00426   {
00427     if (path && path == it->DesktopFile())
00428     {
00429       it->Stick();
00430       model_->ReorderBefore(it, before, false);
00431       Save();
00432       return;
00433     }
00434   }
00435 
00436   AbstractLauncherIcon::Ptr result = CreateFavorite(path);
00437   if (result)
00438   {
00439     RegisterIcon(result);
00440     if (before)
00441       model_->ReorderBefore(result, before, false);
00442   }
00443 
00444   Save();
00445 }
00446 
00447 void Controller::Impl::Save()
00448 {
00449   unity::FavoriteList desktop_paths;
00450 
00451   // Updates gsettings favorites.
00452   auto launchers = model_->GetSublist<BamfLauncherIcon> ();
00453   for (auto icon : launchers)
00454   {
00455     if (!icon->IsSticky())
00456       continue;
00457 
00458     std::string const& desktop_file = icon->DesktopFile();
00459 
00460     if (!desktop_file.empty())
00461       desktop_paths.push_back(desktop_file);
00462   }
00463 
00464   unity::FavoriteStore::Instance().SetFavorites(desktop_paths);
00465 }
00466 
00467 void
00468 Controller::Impl::OnLauncherAddRequestSpecial(std::string const& path,
00469                                               std::string const& aptdaemon_trans_id,
00470                                               std::string const& icon_path,
00471                                               int icon_x,
00472                                               int icon_y,
00473                                               int icon_size)
00474 {
00475   auto bamf_icons = model_->GetSublist<BamfLauncherIcon>();
00476   for (auto icon : bamf_icons)
00477   {
00478     if (icon->DesktopFile() == path)
00479       return;
00480   }
00481 
00482   SoftwareCenterLauncherIcon::Ptr result = CreateSCLauncherIcon(path, aptdaemon_trans_id, icon_path);
00483 
00484   CurrentLauncher()->ForceReveal(true);
00485 
00486   if (result)
00487   {
00488     result->SetQuirk(AbstractLauncherIcon::QUIRK_VISIBLE, false);
00489     result->Animate(CurrentLauncher(), icon_x, icon_y, icon_size);
00490     RegisterIcon(result);
00491     Save();
00492   }
00493 }
00494 
00495 void Controller::Impl::OnSCIconAnimationComplete(AbstractLauncherIcon::Ptr icon)
00496 {
00497   icon->SetQuirk(AbstractLauncherIcon::QUIRK_VISIBLE, true);
00498   launcher_->ForceReveal(false);
00499 }
00500 
00501 void Controller::Impl::SortAndUpdate()
00502 {
00503   gint   shortcut = 1;
00504 
00505   auto launchers = model_->GetSublist<BamfLauncherIcon> ();
00506   for (auto icon : launchers)
00507   {
00508     if (shortcut <= 10 && icon->IsVisible())
00509     {
00510       std::stringstream shortcut_string;
00511       shortcut_string << (shortcut % 10);
00512       icon->SetShortcut(shortcut_string.str()[0]);
00513       ++shortcut;
00514     }
00515     // reset shortcut
00516     else
00517     {
00518       icon->SetShortcut(0);
00519     }
00520   }
00521 }
00522 
00523 void Controller::Impl::OnIconAdded(AbstractLauncherIcon::Ptr icon)
00524 {
00525   this->RegisterIcon(icon);
00526 }
00527 
00528 void Controller::Impl::OnIconRemoved(AbstractLauncherIcon::Ptr icon)
00529 {
00530   SortAndUpdate();
00531 }
00532 
00533 void Controller::Impl::OnLauncherRemoveRequest(AbstractLauncherIcon::Ptr icon)
00534 {
00535   switch (icon->GetIconType())
00536   {
00537     case AbstractLauncherIcon::TYPE_APPLICATION:
00538     {
00539       BamfLauncherIcon* bamf_icon = dynamic_cast<BamfLauncherIcon*>(icon.GetPointer());
00540 
00541       if (bamf_icon)
00542       {
00543         bamf_icon->UnStick();
00544         bamf_icon->Quit();
00545       }
00546 
00547       break;
00548     }
00549     case AbstractLauncherIcon::TYPE_DEVICE:
00550     {
00551       DeviceLauncherIcon* device_icon = dynamic_cast<DeviceLauncherIcon*>(icon.GetPointer());
00552 
00553       if (device_icon && device_icon->CanEject())
00554         device_icon->Eject();
00555 
00556       break;
00557     }
00558     default:
00559       break;
00560   }
00561 }
00562 
00563 void Controller::Impl::OnLauncherEntryRemoteAdded(LauncherEntryRemote::Ptr const& entry)
00564 {
00565   for (auto icon : *model_)
00566   {
00567     if (!icon || icon->RemoteUri().empty())
00568       continue;
00569 
00570     if (entry->AppUri() == icon->RemoteUri())
00571     {
00572       icon->InsertEntryRemote(entry);
00573     }
00574   }
00575 }
00576 
00577 void Controller::Impl::OnLauncherEntryRemoteRemoved(LauncherEntryRemote::Ptr const& entry)
00578 {
00579   for (auto icon : *model_)
00580   {
00581     icon->RemoveEntryRemote(entry);
00582   }
00583 }
00584 
00585 void Controller::Impl::OnFavoriteStoreFavoriteAdded(std::string const& entry, std::string const& pos, bool before)
00586 {
00587   auto bamf_list = model_->GetSublist<BamfLauncherIcon>();
00588   AbstractLauncherIcon::Ptr other;
00589   if (bamf_list.size() > 0)
00590     other = *(bamf_list.begin());
00591 
00592   if (!pos.empty())
00593   {
00594     for (auto it : bamf_list)
00595     {
00596       if (it->GetQuirk(AbstractLauncherIcon::QUIRK_VISIBLE) && pos == it->DesktopFile())
00597         other = it;
00598     }
00599   }
00600 
00601   for (auto it : bamf_list)
00602   {
00603     if (entry == it->DesktopFile())
00604     {
00605       it->Stick(false);
00606       if (!before)
00607         model_->ReorderAfter(it, other);
00608       else
00609         model_->ReorderBefore(it, other, false);
00610       return;
00611     }
00612   }
00613 
00614   AbstractLauncherIcon::Ptr result = CreateFavorite(entry.c_str());
00615   if (result)
00616   {
00617     RegisterIcon(result);
00618     if (!before)
00619       model_->ReorderAfter(result, other);
00620     else
00621       model_->ReorderBefore(result, other, false);
00622   }
00623 
00624   SortAndUpdate();
00625 }
00626 
00627 void Controller::Impl::OnFavoriteStoreFavoriteRemoved(std::string const& entry)
00628 {
00629   for (auto it : model_->GetSublist<BamfLauncherIcon> ())
00630   {
00631     if (it->DesktopFile() == entry)
00632     {
00633       OnLauncherRemoveRequest(it);
00634       break;
00635      }
00636   }
00637 }
00638 
00639 void Controller::Impl::OnFavoriteStoreReordered()
00640 {
00641   FavoriteList const& favs = FavoriteStore::Instance().GetFavorites();
00642   auto bamf_list = model_->GetSublist<BamfLauncherIcon>();
00643 
00644   int i = 0;
00645   for (auto it : favs)
00646   {
00647     auto icon = std::find_if(bamf_list.begin(), bamf_list.end(),
00648     [&it](AbstractLauncherIcon::Ptr x) { return (x->DesktopFile() == it); });
00649 
00650     if (icon != bamf_list.end())
00651     {
00652       (*icon)->SetSortPriority(i++);
00653     }
00654   }
00655 
00656   for (auto it : bamf_list)
00657   {
00658     if (!it->IsSticky())
00659       it->SetSortPriority(i++);
00660   }
00661 
00662   model_->Sort();
00663 }
00664 
00665 void Controller::Impl::OnExpoActivated()
00666 {
00667   WindowManager::Default()->InitiateExpo();
00668 }
00669 
00670 void Controller::Impl::InsertTrash()
00671 {
00672   AbstractLauncherIcon::Ptr icon(new TrashLauncherIcon());
00673   RegisterIcon(icon);
00674 }
00675 
00676 void Controller::Impl::UpdateNumWorkspaces(int workspaces)
00677 {
00678   if ((num_workspaces_ == 0) && (workspaces > 0))
00679   {
00680     InsertExpoAction();
00681   }
00682   else if ((num_workspaces_ > 0) && (workspaces == 0))
00683   {
00684     RemoveExpoAction();
00685   }
00686 
00687   num_workspaces_ = workspaces;
00688 }
00689 
00690 void Controller::Impl::InsertExpoAction()
00691 {
00692   expo_icon_ = AbstractLauncherIcon::Ptr(new SimpleLauncherIcon());
00693 
00694   SimpleLauncherIcon* icon = static_cast<SimpleLauncherIcon*>(expo_icon_.GetPointer());
00695   icon->tooltip_text = _("Workspace Switcher");
00696   icon->icon_name = "workspace-switcher";
00697   icon->SetQuirk(AbstractLauncherIcon::QUIRK_VISIBLE, true);
00698   icon->SetQuirk(AbstractLauncherIcon::QUIRK_RUNNING, false);
00699   icon->SetIconType(AbstractLauncherIcon::TYPE_EXPO);
00700   icon->SetShortcut('s');
00701 
00702   on_expoicon_activate_connection_ = icon->activate.connect(sigc::mem_fun(this, &Impl::OnExpoActivated));
00703 
00704 
00705   RegisterIcon(expo_icon_);
00706 }
00707 
00708 void Controller::Impl::RemoveExpoAction()
00709 {
00710   if (on_expoicon_activate_connection_)
00711     on_expoicon_activate_connection_.disconnect();
00712   model_->RemoveIcon(expo_icon_);
00713 }
00714 
00715 void Controller::Impl::InsertDesktopIcon()
00716 {
00717   RegisterIcon(desktop_icon_);
00718 }
00719 
00720 void Controller::Impl::RemoveDesktopIcon()
00721 {
00722   model_->RemoveIcon(desktop_icon_);
00723 }
00724 
00725 void Controller::Impl::RegisterIcon(AbstractLauncherIcon::Ptr icon)
00726 {
00727   model_->AddIcon(icon);
00728   std::string const& path = icon->DesktopFile();
00729 
00730   if (!path.empty())
00731   {
00732     LauncherEntryRemote::Ptr const& entry = remote_model_.LookupByDesktopFile(path);
00733 
00734     if (entry)
00735       icon->InsertEntryRemote(entry);
00736   }
00737 }
00738 
00739 /* static private */
00740 void Controller::Impl::OnViewOpened(BamfMatcher* matcher, BamfView* view)
00741 {
00742   if (!BAMF_IS_APPLICATION(view))
00743     return;
00744 
00745   BamfApplication* app = BAMF_APPLICATION(view);
00746 
00747   if (bamf_view_is_sticky(view) ||
00748       g_object_get_qdata(G_OBJECT(app), g_quark_from_static_string("unity-seen")))
00749   {
00750     return;
00751   }
00752 
00753   AbstractLauncherIcon::Ptr icon(new BamfLauncherIcon(app));
00754   icon->visibility_changed.connect(sigc::mem_fun(this, &Impl::SortAndUpdate));
00755   icon->SetSortPriority(sort_priority_++);
00756   RegisterIcon(icon);
00757   SortAndUpdate();
00758 }
00759 
00760 AbstractLauncherIcon::Ptr Controller::Impl::CreateFavorite(const char* file_path)
00761 {
00762   BamfApplication* app;
00763   AbstractLauncherIcon::Ptr result;
00764 
00765   app = bamf_matcher_get_application_for_desktop_file(matcher_, file_path, true);
00766   if (!app)
00767     return result;
00768 
00769   if (g_object_get_qdata(G_OBJECT(app), g_quark_from_static_string("unity-seen")))
00770   {
00771     bamf_view_set_sticky(BAMF_VIEW(app), true);
00772     return result;
00773   }
00774 
00775   bamf_view_set_sticky(BAMF_VIEW(app), true);
00776   AbstractLauncherIcon::Ptr icon (new BamfLauncherIcon(app));
00777   icon->SetSortPriority(sort_priority_++);
00778   result = icon;
00779 
00780   return result;
00781 }
00782 
00783 SoftwareCenterLauncherIcon::Ptr Controller::Impl::CreateSCLauncherIcon(std::string const& file_path,
00784                                                                        std::string const& aptdaemon_trans_id,
00785                                                                        std::string const& icon_path)
00786 {
00787   BamfApplication* app;
00788   SoftwareCenterLauncherIcon::Ptr result;
00789 
00790   app = bamf_matcher_get_application_for_desktop_file(matcher_, file_path.c_str(), true);
00791   if (!BAMF_IS_APPLICATION(app))
00792     return result;
00793 
00794   if (g_object_get_qdata(G_OBJECT(app), g_quark_from_static_string("unity-seen")))
00795   {
00796     bamf_view_set_sticky(BAMF_VIEW(app), true);
00797     return result;
00798   }
00799 
00800   bamf_view_set_sticky(BAMF_VIEW(app), true);
00801   result = new SoftwareCenterLauncherIcon(app, aptdaemon_trans_id, icon_path);
00802   result->SetSortPriority(sort_priority_++);
00803 
00804   return result;
00805 }
00806 
00807 void Controller::Impl::SetupBamf()
00808 {
00809   GList* apps, *l;
00810   BamfApplication* app;
00811 
00812   // Sufficiently large number such that we ensure proper sorting
00813   // (avoids case where first item gets tacked onto end rather than start)
00814   int priority = 100;
00815 
00816   FavoriteList const& favs = FavoriteStore::Instance().GetFavorites();
00817 
00818   for (FavoriteList::const_iterator i = favs.begin(), end = favs.end();
00819        i != end; ++i)
00820   {
00821     AbstractLauncherIcon::Ptr fav = CreateFavorite(i->c_str());
00822 
00823     if (fav)
00824     {
00825       fav->SetSortPriority(priority);
00826       RegisterIcon(fav);
00827       priority++;
00828     }
00829   }
00830 
00831   apps = bamf_matcher_get_applications(matcher_);
00832   view_opened_signal_.Connect(matcher_, "view-opened", sigc::mem_fun(this, &Impl::OnViewOpened));
00833 
00834   for (l = apps; l; l = l->next)
00835   {
00836     app = BAMF_APPLICATION(l->data);
00837 
00838     if (g_object_get_qdata(G_OBJECT(app), g_quark_from_static_string("unity-seen")))
00839       continue;
00840 
00841     AbstractLauncherIcon::Ptr icon(new BamfLauncherIcon(app));
00842     icon->SetSortPriority(sort_priority_++);
00843     RegisterIcon(icon);
00844   }
00845   g_list_free(apps);
00846   SortAndUpdate();
00847 
00848   model_->order_changed.connect(sigc::mem_fun(this, &Impl::SortAndUpdate));
00849   model_->icon_removed.connect(sigc::mem_fun(this, &Impl::OnIconRemoved));
00850   model_->saved.connect(sigc::mem_fun(this, &Impl::Save));
00851 }
00852 
00853 void Controller::Impl::SendHomeActivationRequest()
00854 {
00855   ubus.SendMessage(UBUS_PLACE_ENTRY_ACTIVATE_REQUEST, g_variant_new("(sus)", "home.lens", dash::NOT_HANDLED, ""));
00856 }
00857 
00858 Controller::Controller(Display* display)
00859  : options(Options::Ptr(new Options()))
00860  , multiple_launchers(true)
00861  , pimpl(new Impl(display, this))
00862 {
00863   multiple_launchers.changed.connect([&](bool value) -> void {
00864     UScreen* uscreen = UScreen::GetDefault();
00865     auto monitors = uscreen->GetMonitors();
00866     int primary = uscreen->GetPrimaryMonitor();
00867     pimpl->EnsureLaunchers(primary, monitors);
00868     options()->show_for_all = !value;
00869   });
00870 }
00871 
00872 Controller::~Controller()
00873 {}
00874 
00875 void Controller::UpdateNumWorkspaces(int workspaces)
00876 {
00877   pimpl->UpdateNumWorkspaces(workspaces);
00878 }
00879 
00880 Launcher& Controller::launcher() const
00881 {
00882   return *(pimpl->launcher_);
00883 }
00884 
00885 Controller::LauncherList& Controller::launchers() const
00886 {
00887   return pimpl->launchers;
00888 }
00889 
00890 std::vector<char> Controller::GetAllShortcuts() const
00891 {
00892   std::vector<char> shortcuts;
00893   for (auto icon : *(pimpl->model_))
00894   {
00895     // TODO: find out why the icons use guint64 for shortcuts.
00896     char shortcut = icon->GetShortcut();
00897     if (shortcut)
00898       shortcuts.push_back(shortcut);
00899   }
00900   return shortcuts;
00901 }
00902 
00903 std::vector<AbstractLauncherIcon::Ptr> Controller::GetAltTabIcons(bool current) const
00904 {
00905   std::vector<AbstractLauncherIcon::Ptr> results;
00906 
00907   results.push_back(pimpl->desktop_icon_);
00908 
00909   for (auto icon : *(pimpl->model_))
00910   {
00911     if (icon->ShowInSwitcher(current))
00912     {
00913       //otherwise we get two desktop icons in the switcher.
00914       if (icon->GetIconType() != AbstractLauncherIcon::IconType::TYPE_DESKTOP)
00915       {
00916         results.push_back(icon);
00917       }
00918     }
00919   }
00920   return results;
00921 }
00922 
00923 Window Controller::LauncherWindowId(int launcher) const
00924 {
00925   if (launcher >= (int)pimpl->launchers.size())
00926     return 0;
00927   return pimpl->launchers[launcher]->GetParent()->GetInputWindowId();
00928 }
00929 
00930 Window Controller::KeyNavLauncherInputWindowId() const
00931 {
00932   if (KeyNavIsActive())
00933     return pimpl->keyboard_launcher_->GetParent()->GetInputWindowId();
00934   return 0;
00935 }
00936 
00937 void Controller::PushToFront()
00938 {
00939   pimpl->launcher_->GetParent()->PushToFront();
00940 }
00941 
00942 void Controller::SetShowDesktopIcon(bool show_desktop_icon)
00943 {
00944   if (pimpl->show_desktop_icon_ == show_desktop_icon)
00945     return;
00946 
00947   pimpl->show_desktop_icon_ = show_desktop_icon;
00948 
00949   if (pimpl->show_desktop_icon_)
00950     pimpl->InsertDesktopIcon();
00951   else
00952     pimpl->RemoveDesktopIcon();
00953 }
00954 
00955 int Controller::Impl::MonitorWithMouse()
00956 {
00957   UScreen* uscreen = UScreen::GetDefault();
00958   return uscreen->GetMonitorWithMouse();
00959 }
00960 
00961 nux::ObjectPtr<Launcher> Controller::Impl::CurrentLauncher()
00962 {
00963   nux::ObjectPtr<Launcher> result;
00964   int best = std::min<int> (launchers.size() - 1, MonitorWithMouse());
00965   if (best >= 0)
00966     result = launchers[best];
00967   return result;
00968 }
00969 
00970 void Controller::HandleLauncherKeyPress(int when)
00971 {
00972   pimpl->launcher_key_press_time_ = when;
00973 
00974   auto show_launcher = [&]()
00975   {
00976     if (pimpl->keyboard_launcher_.IsNull())
00977       pimpl->keyboard_launcher_ = pimpl->CurrentLauncher();
00978 
00979     pimpl->sources_.Remove(local::HIDE_TIMEOUT);
00980     pimpl->keyboard_launcher_->ForceReveal(true);
00981     pimpl->launcher_open = true;
00982 
00983     return false;
00984   };
00985   auto key_timeout = std::make_shared<glib::Timeout>(local::super_tap_duration, show_launcher);
00986   pimpl->sources_.Add(key_timeout, local::KEYPRESS_TIMEOUT);
00987 
00988   auto show_shortcuts = [&]()
00989   {
00990     if (!pimpl->launcher_keynav)
00991     {
00992       if (pimpl->keyboard_launcher_.IsNull())
00993         pimpl->keyboard_launcher_ = pimpl->CurrentLauncher();
00994 
00995       pimpl->keyboard_launcher_->ShowShortcuts(true);
00996       pimpl->launcher_open = true;
00997     }
00998 
00999     return false;
01000   };
01001   auto labels_timeout = std::make_shared<glib::Timeout>(local::shortcuts_show_delay, show_shortcuts);
01002   pimpl->sources_.Add(labels_timeout, local::LABELS_TIMEOUT);
01003 }
01004 
01005 bool Controller::AboutToShowDash(int was_tap, int when) const
01006 {
01007   if ((when - pimpl->launcher_key_press_time_) < local::super_tap_duration && was_tap)
01008     return true;
01009   return false;
01010 }
01011 
01012 void Controller::HandleLauncherKeyRelease(bool was_tap, int when)
01013 {
01014   int tap_duration = when - pimpl->launcher_key_press_time_;
01015   if (tap_duration < local::super_tap_duration && was_tap)
01016   {
01017     LOG_DEBUG(logger) << "Quick tap, sending activation request.";
01018     pimpl->SendHomeActivationRequest();
01019   }
01020   else
01021   {
01022     LOG_DEBUG(logger) << "Tap too long: " << tap_duration;
01023   }
01024 
01025   pimpl->sources_.Remove(local::LABELS_TIMEOUT);
01026   pimpl->sources_.Remove(local::KEYPRESS_TIMEOUT);
01027 
01028   if (pimpl->keyboard_launcher_.IsValid())
01029   {
01030     pimpl->keyboard_launcher_->ShowShortcuts(false);
01031 
01032     int ms_since_show = tap_duration;
01033     if (ms_since_show > local::launcher_minimum_show_duration)
01034     {
01035       pimpl->keyboard_launcher_->ForceReveal(false);
01036       pimpl->launcher_open = false;
01037 
01038       if (!pimpl->launcher_keynav)
01039         pimpl->keyboard_launcher_.Release();
01040     }
01041     else
01042     {
01043       int time_left = local::launcher_minimum_show_duration - ms_since_show;
01044 
01045       auto hide_launcher = [&]()
01046       {
01047         if (pimpl->keyboard_launcher_.IsValid())
01048         {
01049           pimpl->keyboard_launcher_->ForceReveal(false);
01050           pimpl->launcher_open = false;
01051 
01052           if (!pimpl->launcher_keynav)
01053             pimpl->keyboard_launcher_.Release();
01054         }
01055 
01056         return false;
01057       };
01058 
01059       auto hide_timeout = std::make_shared<glib::Timeout>(time_left, hide_launcher);
01060       pimpl->sources_.Add(hide_timeout, local::HIDE_TIMEOUT);
01061     }
01062   }
01063 }
01064 
01065 bool Controller::HandleLauncherKeyEvent(Display *display, unsigned int key_sym, unsigned long key_code, unsigned long key_state, char* key_string)
01066 {
01067   LauncherModel::iterator it;
01068 
01069   // Shortcut to start launcher icons. Only relies on Keycode, ignore modifier
01070   for (it = pimpl->model_->begin(); it != pimpl->model_->end(); it++)
01071   {
01072     if ((XKeysymToKeycode(display, (*it)->GetShortcut()) == key_code) ||
01073         ((gchar)((*it)->GetShortcut()) == key_string[0]))
01074     {
01075       struct timespec last_action_time = (*it)->GetQuirkTime(AbstractLauncherIcon::QUIRK_LAST_ACTION);
01076       struct timespec current;
01077       TimeUtil::SetTimeStruct(&current);
01078       if (TimeUtil::TimeDelta(&current, &last_action_time) > local::ignore_repeat_shortcut_duration)
01079       {
01080         if (g_ascii_isdigit((gchar)(*it)->GetShortcut()) && (key_state & ShiftMask))
01081           (*it)->OpenInstance(ActionArg(ActionArg::LAUNCHER, 0));
01082         else
01083           (*it)->Activate(ActionArg(ActionArg::LAUNCHER, 0));
01084       }
01085 
01086       // disable the "tap on super" check
01087       pimpl->launcher_key_press_time_ = 0;
01088       return true;
01089     }
01090   }
01091 
01092   return false;
01093 }
01094 
01095 void Controller::Impl::ReceiveMouseDownOutsideArea(int x, int y, unsigned long button_flags, unsigned long key_flags)
01096 {
01097   if (launcher_grabbed)
01098     parent_->KeyNavTerminate(false);
01099 }
01100 
01101 void Controller::KeyNavGrab()
01102 {
01103   pimpl->launcher_grabbed = true;
01104   KeyNavActivate();
01105   pimpl->keyboard_launcher_->GrabKeyboard();
01106 
01107   pimpl->launcher_key_press_connection_ =
01108     pimpl->keyboard_launcher_->key_down.connect(sigc::mem_fun(pimpl.get(), &Controller::Impl::ReceiveLauncherKeyPress));
01109   pimpl->launcher_event_outside_connection_ =
01110     pimpl->keyboard_launcher_->mouse_down_outside_pointer_grab_area.connect(sigc::mem_fun(pimpl.get(), &Controller::Impl::ReceiveMouseDownOutsideArea));
01111 }
01112 
01113 void Controller::KeyNavActivate()
01114 {
01115   if (pimpl->launcher_keynav)
01116     return;
01117 
01118   pimpl->reactivate_keynav = false;
01119   pimpl->launcher_keynav = true;
01120   pimpl->keynav_restore_window_ = true;
01121   pimpl->keyboard_launcher_ = pimpl->CurrentLauncher();
01122 
01123   pimpl->keyboard_launcher_->EnterKeyNavMode();
01124   pimpl->model_->SetSelection(0);
01125 
01126   if (pimpl->launcher_grabbed)
01127   {
01128     pimpl->ubus.SendMessage(UBUS_LAUNCHER_START_KEY_NAV,
01129                             g_variant_new_int32(pimpl->keyboard_launcher_->monitor));
01130   }
01131   else
01132   {
01133     pimpl->ubus.SendMessage(UBUS_LAUNCHER_START_KEY_SWTICHER,
01134                             g_variant_new_int32(pimpl->keyboard_launcher_->monitor));
01135   }
01136 
01137   AbstractLauncherIcon::Ptr const& selected = pimpl->model_->Selection();
01138 
01139   if (selected)
01140   {
01141     pimpl->ubus.SendMessage(UBUS_LAUNCHER_SELECTION_CHANGED,
01142                             g_variant_new_string(selected->tooltip_text().c_str()));
01143   }
01144 }
01145 
01146 void Controller::KeyNavNext()
01147 {
01148   pimpl->model_->SelectNext();
01149 
01150   AbstractLauncherIcon::Ptr const& selected = pimpl->model_->Selection();
01151 
01152   if (selected)
01153   {
01154     pimpl->ubus.SendMessage(UBUS_LAUNCHER_SELECTION_CHANGED,
01155                             g_variant_new_string(selected->tooltip_text().c_str()));
01156   }
01157 }
01158 
01159 void Controller::KeyNavPrevious()
01160 {
01161   pimpl->model_->SelectPrevious();
01162 
01163   AbstractLauncherIcon::Ptr const& selected = pimpl->model_->Selection();
01164 
01165   if (selected)
01166   {
01167     pimpl->ubus.SendMessage(UBUS_LAUNCHER_SELECTION_CHANGED,
01168                             g_variant_new_string(selected->tooltip_text().c_str()));
01169   }
01170 }
01171 
01172 void Controller::KeyNavTerminate(bool activate)
01173 {
01174   if (!pimpl->launcher_keynav)
01175     return;
01176 
01177   if (activate && pimpl->keynav_restore_window_)
01178   {
01179     /* If the selected icon is running, we must not restore the input to the old */
01180     AbstractLauncherIcon::Ptr const& icon = pimpl->model_->Selection();
01181     pimpl->keynav_restore_window_ = !icon->GetQuirk(AbstractLauncherIcon::QUIRK_RUNNING);
01182   }
01183 
01184   pimpl->keyboard_launcher_->ExitKeyNavMode();
01185 
01186   if (pimpl->launcher_grabbed)
01187   {
01188     pimpl->keyboard_launcher_->UnGrabKeyboard();
01189     pimpl->launcher_key_press_connection_.disconnect();
01190     pimpl->launcher_event_outside_connection_.disconnect();
01191     pimpl->launcher_grabbed = false;
01192     pimpl->ubus.SendMessage(UBUS_LAUNCHER_END_KEY_NAV,
01193                             g_variant_new_boolean(pimpl->keynav_restore_window_));
01194   }
01195   else
01196   {
01197     pimpl->ubus.SendMessage(UBUS_LAUNCHER_END_KEY_SWTICHER,
01198                             g_variant_new_boolean(pimpl->keynav_restore_window_));
01199   }
01200 
01201   if (activate)
01202   {
01203     pimpl->sources_.Add(std::make_shared<glib::Idle>([this] {
01204       pimpl->model_->Selection()->Activate(ActionArg(ActionArg::LAUNCHER, 0));
01205       return false;
01206     }));
01207   }
01208 
01209   pimpl->launcher_keynav = false;
01210   if (!pimpl->launcher_open)
01211     pimpl->keyboard_launcher_.Release();
01212 }
01213 
01214 bool Controller::KeyNavIsActive() const
01215 {
01216   return pimpl->launcher_keynav;
01217 }
01218 
01219 bool Controller::IsOverlayOpen() const
01220 {
01221   for (auto launcher_ptr : pimpl->launchers)
01222   {
01223     if (launcher_ptr->IsOverlayOpen())
01224       return true;
01225   }
01226   return false;
01227 }
01228 
01229 std::string
01230 Controller::GetName() const
01231 {
01232   return "LauncherController";
01233 }
01234 
01235 void
01236 Controller::AddProperties(GVariantBuilder* builder)
01237 {
01238   timespec current;
01239   clock_gettime(CLOCK_MONOTONIC, &current);
01240 
01241   unity::variant::BuilderWrapper(builder)
01242   .add("key_nav_is_active", KeyNavIsActive())
01243   .add("key_nav_launcher_monitor", pimpl->keyboard_launcher_.IsValid() ?  pimpl->keyboard_launcher_->monitor : -1)
01244   .add("key_nav_selection", pimpl->model_->SelectionIndex())
01245   .add("key_nav_is_grabbed", pimpl->launcher_grabbed)
01246   .add("keyboard_launcher", pimpl->CurrentLauncher()->monitor);
01247 }
01248 
01249 void Controller::Impl::ReceiveLauncherKeyPress(unsigned long eventType,
01250                                                unsigned long keysym,
01251                                                unsigned long state,
01252                                                const char* character,
01253                                                unsigned short keyCount)
01254 {
01255   /*
01256    * all key events below are related to keynavigation. Make an additional
01257    * check that we are in a keynav mode when we inadvertadly receive the focus
01258    */
01259   if (!launcher_grabbed)
01260     return;
01261 
01262   switch (keysym)
01263   {
01264       // up (move selection up or go to global-menu if at top-most icon)
01265     case NUX_VK_UP:
01266     case NUX_KP_UP:
01267       parent_->KeyNavPrevious();
01268       break;
01269 
01270       // down (move selection down and unfold launcher if needed)
01271     case NUX_VK_DOWN:
01272     case NUX_KP_DOWN:
01273       parent_->KeyNavNext();
01274       break;
01275 
01276       // super/control/esc/left (close quicklist or exit laucher key-focus)
01277     case NUX_VK_LWIN:
01278     case NUX_VK_RWIN:
01279     case NUX_VK_CONTROL:
01280     case NUX_VK_LEFT:
01281     case NUX_KP_LEFT:
01282     case NUX_VK_ESCAPE:
01283       // hide again
01284       parent_->KeyNavTerminate(false);
01285       break;
01286 
01287       // right/shift-f10 (open quicklist of currently selected icon)
01288     case XK_F10:
01289       if (!(state & nux::NUX_STATE_SHIFT))
01290         break;
01291     case NUX_VK_RIGHT:
01292     case NUX_KP_RIGHT:
01293     case XK_Menu:
01294       if (model_->Selection()->OpenQuicklist(true, keyboard_launcher_->monitor()))
01295       {
01296         reactivate_keynav = true;
01297         reactivate_index = model_->SelectionIndex();
01298         parent_->KeyNavTerminate(false);
01299       }
01300       break;
01301 
01302       // <SPACE> (open a new instance)
01303     case NUX_VK_SPACE:
01304       model_->Selection()->OpenInstance(ActionArg(ActionArg::LAUNCHER, 0));
01305       parent_->KeyNavTerminate(false);
01306       break;
01307 
01308       // <RETURN> (start/activate currently selected icon)
01309     case NUX_VK_ENTER:
01310     case NUX_KP_ENTER:
01311     parent_->KeyNavTerminate(true);
01312     break;
01313 
01314     default:
01315       // ALT + <Anykey>; treat it as a shortcut and exit keynav
01316       if (state & nux::NUX_STATE_ALT)
01317       {
01318         parent_->KeyNavTerminate(false);
01319       }
01320       break;
01321   }
01322 }
01323 
01324 void Controller::Impl::OnBusAcquired(GDBusConnection* connection, const gchar* name, gpointer user_data)
01325 {
01326   GDBusNodeInfo* introspection_data = g_dbus_node_info_new_for_xml(DBUS_INTROSPECTION.c_str(), nullptr);
01327   unsigned int reg_id;
01328 
01329   if (!introspection_data)
01330   {
01331     LOG_WARNING(logger) << "No introspection data loaded. Won't get dynamic launcher addition.";
01332     return;
01333   }
01334 
01335   reg_id = g_dbus_connection_register_object(connection, DBUS_PATH.c_str(),
01336                                              introspection_data->interfaces[0],
01337                                              &interface_vtable, user_data,
01338                                              nullptr, nullptr);
01339   if (!reg_id)
01340   {
01341     LOG_WARNING(logger) << "Object registration failed. Won't get dynamic launcher addition.";
01342   }
01343 
01344   g_dbus_node_info_unref(introspection_data);
01345 }
01346 
01347 void Controller::Impl::OnDBusMethodCall(GDBusConnection* connection, const gchar* sender,
01348                                         const gchar* object_path, const gchar* interface_name,
01349                                         const gchar* method_name, GVariant* parameters,
01350                                         GDBusMethodInvocation* invocation, gpointer user_data)
01351 {
01352   if (g_strcmp0(method_name, "AddLauncherItemFromPosition") == 0)
01353   {
01354     auto self = static_cast<Controller::Impl*>(user_data);
01355     glib::String icon, icon_title, desktop_file, aptdaemon_task;
01356     gint icon_x, icon_y, icon_size;
01357 
01358     g_variant_get(parameters, "(ssiiiss)", &icon_title, &icon, &icon_x, &icon_y,
01359                                            &icon_size, &desktop_file, &aptdaemon_task);
01360 
01361     self->OnLauncherAddRequestSpecial(desktop_file.Str(), aptdaemon_task.Str(),
01362                                       icon.Str(), icon_x, icon_y, icon_size);
01363 
01364     g_dbus_method_invocation_return_value(invocation, nullptr);
01365   }
01366 }
01367 
01368 } // namespace launcher
01369 } // namespace unity