Back to index

unity  6.0.0
Launcher.cpp
Go to the documentation of this file.
00001 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
00002 /*
00003  * Copyright (C) 2010 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  * Authored by: Jay Taoko <jay.taoko@canonical.com>
00019  */
00020 
00021 #include "config.h"
00022 #include <math.h>
00023 
00024 #include <Nux/Nux.h>
00025 #include <Nux/VScrollBar.h>
00026 #include <Nux/HLayout.h>
00027 #include <Nux/VLayout.h>
00028 #include <Nux/MenuPage.h>
00029 #include <NuxCore/Logger.h>
00030 
00031 #include <NuxGraphics/NuxGraphics.h>
00032 #include <NuxGraphics/GpuDevice.h>
00033 #include <NuxGraphics/GLTextureResourceManager.h>
00034 
00035 #include <Nux/BaseWindow.h>
00036 #include <Nux/WindowCompositor.h>
00037 
00038 #include "Launcher.h"
00039 #include "AbstractLauncherIcon.h"
00040 #include "unity-shared/PanelStyle.h"
00041 #include "SpacerLauncherIcon.h"
00042 #include "LauncherModel.h"
00043 #include "QuicklistManager.h"
00044 #include "QuicklistView.h"
00045 #include "unity-shared/IconRenderer.h"
00046 #include "unity-shared/TimeUtil.h"
00047 #include "unity-shared/TextureCache.h"
00048 #include "unity-shared/IconLoader.h"
00049 #include "unity-shared/WindowManager.h"
00050 #include "unity-shared/UScreen.h"
00051 #include "unity-shared/UBusMessages.h"
00052 
00053 #include <UnityCore/GLibWrapper.h>
00054 #include <UnityCore/Variant.h>
00055 
00056 #include <type_traits>
00057 #include <sigc++/sigc++.h>
00058 
00059 namespace unity
00060 {
00061 using ui::RenderArg;
00062 using ui::Decaymulator;
00063 
00064 namespace launcher
00065 {
00066 
00067 const char window_title[] = "unity-launcher";
00068 
00069 namespace
00070 {
00071 
00072 nux::logging::Logger logger("unity.launcher");
00073 
00074 const int URGENT_BLINKS = 3;
00075 const int WIGGLE_CYCLES = 6;
00076 
00077 const int MAX_STARTING_BLINKS = 5;
00078 const int STARTING_BLINK_LAMBDA = 3;
00079 
00080 const int PULSE_BLINK_LAMBDA = 2;
00081 
00082 const float BACKLIGHT_STRENGTH = 0.9f;
00083 const int ICON_PADDING = 6;
00084 const int RIGHT_LINE_WIDTH = 1;
00085 
00086 const int ANIM_DURATION_SHORT_SHORT = 100;
00087 const int ANIM_DURATION = 200;
00088 const int ANIM_DURATION_LONG = 350;
00089 const int START_DRAGICON_DURATION = 250;
00090 
00091 const int MOUSE_DEADZONE = 15;
00092 const float DRAG_OUT_PIXELS = 300.0f;
00093 
00094 const std::string DND_CHECK_TIMEOUT = "dnd-check-timeout";
00095 const std::string STRUT_HACK_TIMEOUT = "strut-hack-timeout";
00096 const std::string START_DRAGICON_TIMEOUT = "start-dragicon-timeout";
00097 const std::string SCROLL_TIMEOUT = "scroll-timeout";
00098 const std::string ANIMATION_IDLE = "animation-idle";
00099 }
00100 
00101 
00102 NUX_IMPLEMENT_OBJECT_TYPE(Launcher);
00103 
00104 const int Launcher::Launcher::ANIM_DURATION_SHORT = 125;
00105 
00106 Launcher::Launcher(nux::BaseWindow* parent,
00107                    NUX_FILE_LINE_DECL)
00108   : View(NUX_FILE_LINE_PARAM)
00109   , monitor(0)
00110   , _parent(parent)
00111   , _active_quicklist(nullptr)
00112   , _hovered(false)
00113   , _hidden(false)
00114   , _scroll_limit_reached(false)
00115   , _render_drag_window(false)
00116   , _shortcuts_shown(false)
00117   , _data_checked(false)
00118   , _steal_drag(false)
00119   , _drag_edge_touching(false)
00120   , _dash_is_open(false)
00121   , _hud_is_open(false)
00122   , _folded_angle(1.0f)
00123   , _neg_folded_angle(-1.0f)
00124   , _folded_z_distance(10.0f)
00125   , _last_delta_y(0.0f)
00126   , _edge_overcome_pressure(0.0f)
00127   , _launcher_action_state(ACTION_NONE)
00128   , _space_between_icons(5)
00129   , _icon_image_size(48)
00130   , _icon_image_size_delta(6)
00131   , _icon_glow_size(62)
00132   , _icon_size(_icon_image_size + _icon_image_size_delta)
00133   , _dnd_delta_y(0)
00134   , _dnd_delta_x(0)
00135   , _postreveal_mousemove_delta_x(0)
00136   , _postreveal_mousemove_delta_y(0)
00137   , _launcher_drag_delta(0)
00138   , _enter_y(0)
00139   , _last_button_press(0)
00140   , _drag_out_id(0)
00141   , _drag_out_delta_x(0.0f)
00142   , _last_reveal_progress(0.0f)
00143   , _selection_atom(0)
00144   , _background_color(nux::color::DimGray)
00145 {
00146   m_Layout = new nux::HLayout(NUX_TRACKER_LOCATION);
00147 
00148   _collection_window = new unity::DNDCollectionWindow();
00149   _collection_window->collected.connect(sigc::mem_fun(this, &Launcher::OnDNDDataCollected));
00150 
00151   _offscreen_drag_texture = nux::GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(2, 2, 1, nux::BITFMT_R8G8B8A8);
00152 
00153   bg_effect_helper_.owner = this;
00154   bg_effect_helper_.enabled = false;
00155 
00156   SetCompositionLayout(m_Layout);
00157   CaptureMouseDownAnyWhereElse(true);
00158   SetAcceptKeyNavFocusOnMouseDown(false);
00159   SetAcceptMouseWheelEvent(true);
00160   SetDndEnabled(false, true);
00161 
00162   _hide_machine.should_hide_changed.connect(sigc::mem_fun(this, &Launcher::SetHidden));
00163   _hide_machine.reveal_progress.changed.connect([&](float value) { EnsureAnimation(); });
00164   _hover_machine.should_hover_changed.connect(sigc::mem_fun(this, &Launcher::SetHover));
00165 
00166   mouse_down.connect(sigc::mem_fun(this, &Launcher::RecvMouseDown));
00167   mouse_up.connect(sigc::mem_fun(this, &Launcher::RecvMouseUp));
00168   mouse_drag.connect(sigc::mem_fun(this, &Launcher::RecvMouseDrag));
00169   mouse_enter.connect(sigc::mem_fun(this, &Launcher::RecvMouseEnter));
00170   mouse_leave.connect(sigc::mem_fun(this, &Launcher::RecvMouseLeave));
00171   mouse_move.connect(sigc::mem_fun(this, &Launcher::RecvMouseMove));
00172   mouse_wheel.connect(sigc::mem_fun(this, &Launcher::RecvMouseWheel));
00173   //OnEndFocus.connect   (sigc::mem_fun (this, &Launcher::exitKeyNavMode));
00174 
00175   QuicklistManager& ql_manager = *(QuicklistManager::Default());
00176   ql_manager.quicklist_opened.connect(sigc::mem_fun(this, &Launcher::RecvQuicklistOpened));
00177   ql_manager.quicklist_closed.connect(sigc::mem_fun(this, &Launcher::RecvQuicklistClosed));
00178 
00179   WindowManager& plugin_adapter = *(WindowManager::Default());
00180   plugin_adapter.window_mapped.connect(sigc::mem_fun(this, &Launcher::OnWindowMapped));
00181   plugin_adapter.window_unmapped.connect(sigc::mem_fun(this, &Launcher::OnWindowUnmapped));
00182 
00183   plugin_adapter.initiate_spread.connect(sigc::mem_fun(this, &Launcher::OnPluginStateChanged));
00184   plugin_adapter.initiate_expo.connect(sigc::mem_fun(this, &Launcher::OnPluginStateChanged));
00185   plugin_adapter.terminate_spread.connect(sigc::mem_fun(this, &Launcher::OnPluginStateChanged));
00186   plugin_adapter.terminate_expo.connect(sigc::mem_fun(this, &Launcher::OnPluginStateChanged));
00187   plugin_adapter.compiz_screen_viewport_switch_ended.connect(sigc::mem_fun(this, &Launcher::EnsureAnimation));
00188 
00189   GeisAdapter& adapter = GeisAdapter::Instance();
00190   adapter.drag_start.connect(sigc::mem_fun(this, &Launcher::OnDragStart));
00191   adapter.drag_update.connect(sigc::mem_fun(this, &Launcher::OnDragUpdate));
00192   adapter.drag_finish.connect(sigc::mem_fun(this, &Launcher::OnDragFinish));
00193 
00194   display.changed.connect(sigc::mem_fun(this, &Launcher::OnDisplayChanged));
00195 
00196   // 0 out timers to avoid wonky startups
00197   for (int i = 0; i < TIME_LAST; ++i)
00198   {
00199     _times[i].tv_sec = 0;
00200     _times[i].tv_nsec = 0;
00201   }
00202 
00203   ubus_.RegisterInterest(UBUS_OVERLAY_SHOWN, sigc::mem_fun(this, &Launcher::OnOverlayShown));
00204   ubus_.RegisterInterest(UBUS_OVERLAY_HIDDEN, sigc::mem_fun(this, &Launcher::OnOverlayHidden));
00205   ubus_.RegisterInterest(UBUS_LAUNCHER_ACTION_DONE, sigc::mem_fun(this, &Launcher::OnActionDone));
00206   ubus_.RegisterInterest(UBUS_BACKGROUND_COLOR_CHANGED, sigc::mem_fun(this, &Launcher::OnBGColorChanged));
00207   ubus_.RegisterInterest(UBUS_LAUNCHER_LOCK_HIDE, sigc::mem_fun(this, &Launcher::OnLockHideChanged));
00208 
00209   // request the latest colour from bghash
00210   ubus_.SendMessage(UBUS_BACKGROUND_REQUEST_COLOUR_EMIT);
00211 
00212   icon_renderer = ui::AbstractIconRenderer::Ptr(new ui::IconRenderer());
00213   icon_renderer->SetTargetSize(_icon_size, _icon_image_size, _space_between_icons);
00214 
00215   TextureCache& cache = TextureCache::GetDefault();
00216   TextureCache::CreateTextureCallback cb = [&](std::string const& name, int width, int height) -> nux::BaseTexture* {
00217     return nux::CreateTexture2DFromFile((PKGDATADIR"/" + name + ".png").c_str(), -1, true);
00218   };
00219 
00220   launcher_sheen_ = cache.FindTexture("dash_sheen", 0, 0, cb);
00221   launcher_pressure_effect_ = cache.FindTexture("launcher_pressure_effect", 0, 0, cb);
00222 
00223   options.changed.connect(sigc::mem_fun (this, &Launcher::OnOptionsChanged));
00224 }
00225 
00226 /* Introspection */
00227 std::string Launcher::GetName() const
00228 {
00229   return "Launcher";
00230 }
00231 
00232 void Launcher::OnDisplayChanged(Display* display)
00233 {
00234   _collection_window->display = display;
00235 }
00236 
00237 void Launcher::OnDragStart(GeisAdapter::GeisDragData* data)
00238 {
00239   if (_drag_out_id && _drag_out_id == data->id)
00240     return;
00241 
00242   if (data->touches == 4)
00243   {
00244     _drag_out_id = data->id;
00245     if (_hidden)
00246     {
00247       _drag_out_delta_x = 0.0f;
00248     }
00249     else
00250     {
00251       _drag_out_delta_x = DRAG_OUT_PIXELS;
00252       _hide_machine.SetQuirk(LauncherHideMachine::MT_DRAG_OUT, false);
00253     }
00254   }
00255 }
00256 
00257 void Launcher::OnDragUpdate(GeisAdapter::GeisDragData* data)
00258 {
00259   if (data->id == _drag_out_id)
00260   {
00261     _drag_out_delta_x = CLAMP(_drag_out_delta_x + data->delta_x, 0.0f, DRAG_OUT_PIXELS);
00262     EnsureAnimation();
00263   }
00264 }
00265 
00266 void Launcher::OnDragFinish(GeisAdapter::GeisDragData* data)
00267 {
00268   if (data->id == _drag_out_id)
00269   {
00270     if (_drag_out_delta_x >= DRAG_OUT_PIXELS - 90.0f)
00271       _hide_machine.SetQuirk(LauncherHideMachine::MT_DRAG_OUT, true);
00272     TimeUtil::SetTimeStruct(&_times[TIME_DRAG_OUT], &_times[TIME_DRAG_OUT], ANIM_DURATION_SHORT);
00273     _drag_out_id = 0;
00274     EnsureAnimation();
00275   }
00276 }
00277 
00278 void Launcher::AddProperties(GVariantBuilder* builder)
00279 {
00280   timespec current;
00281   clock_gettime(CLOCK_MONOTONIC, &current);
00282 
00283   unity::variant::BuilderWrapper(builder)
00284   .add(GetAbsoluteGeometry())
00285   .add("hover-progress", GetHoverProgress(current))
00286   .add("dnd-exit-progress", DnDExitProgress(current))
00287   .add("autohide-progress", AutohideProgress(current))
00288   .add("dnd-delta", _dnd_delta_y)
00289   .add("hovered", _hovered)
00290   .add("hidemode", options()->hide_mode)
00291   .add("hidden", _hidden)
00292   .add("is_showing", ! _hidden)
00293   .add("monitor", monitor())
00294   .add("quicklist-open", _hide_machine.GetQuirk(LauncherHideMachine::QUICKLIST_OPEN))
00295   .add("hide-quirks", _hide_machine.DebugHideQuirks())
00296   .add("hover-quirks", _hover_machine.DebugHoverQuirks())
00297   .add("icon-size", _icon_size)
00298   .add("shortcuts_shown", _shortcuts_shown);
00299 }
00300 
00301 void Launcher::SetMousePosition(int x, int y)
00302 {
00303   bool beyond_drag_threshold = MouseBeyondDragThreshold();
00304   _mouse_position = nux::Point2(x, y);
00305 
00306   if (beyond_drag_threshold != MouseBeyondDragThreshold())
00307     TimeUtil::SetTimeStruct(&_times[TIME_DRAG_THRESHOLD], &_times[TIME_DRAG_THRESHOLD], ANIM_DURATION_SHORT);
00308 
00309   EnsureScrollTimer();
00310 }
00311 
00312 void Launcher::SetStateMouseOverLauncher(bool over_launcher)
00313 {
00314   _hide_machine.SetQuirk(LauncherHideMachine::MOUSE_OVER_LAUNCHER, over_launcher);
00315   _hide_machine.SetQuirk(LauncherHideMachine::REVEAL_PRESSURE_PASS, false);
00316   _hover_machine.SetQuirk(LauncherHoverMachine::MOUSE_OVER_LAUNCHER, over_launcher);
00317 }
00318 
00319 bool Launcher::MouseBeyondDragThreshold() const
00320 {
00321   if (GetActionState() == ACTION_DRAG_ICON)
00322     return _mouse_position.x > GetGeometry().width + _icon_size / 2;
00323   return false;
00324 }
00325 
00326 /* Render Layout Logic */
00327 float Launcher::GetHoverProgress(struct timespec const& current) const
00328 {
00329   if (_hovered)
00330     return CLAMP((float)(unity::TimeUtil::TimeDelta(&current, &_times[TIME_ENTER])) / (float) ANIM_DURATION, 0.0f, 1.0f);
00331   else
00332     return 1.0f - CLAMP((float)(unity::TimeUtil::TimeDelta(&current, &_times[TIME_LEAVE])) / (float) ANIM_DURATION, 0.0f, 1.0f);
00333 }
00334 
00335 float Launcher::DnDExitProgress(struct timespec const& current) const
00336 {
00337   return pow(1.0f - CLAMP((float)(unity::TimeUtil::TimeDelta(&current, &_times[TIME_DRAG_END])) / (float) ANIM_DURATION_LONG, 0.0f, 1.0f), 2);
00338 }
00339 
00340 float Launcher::DragOutProgress(struct timespec const& current) const
00341 {
00342   float timeout = CLAMP((float)(unity::TimeUtil::TimeDelta(&current, &_times[TIME_DRAG_OUT])) / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f);
00343   float progress = CLAMP(_drag_out_delta_x / DRAG_OUT_PIXELS, 0.0f, 1.0f);
00344 
00345   if (_drag_out_id || _hide_machine.GetQuirk(LauncherHideMachine::MT_DRAG_OUT))
00346     return progress;
00347   return progress * (1.0f - timeout);
00348 }
00349 
00350 float Launcher::AutohideProgress(struct timespec const& current) const
00351 {
00352   // time-based progress (full scale or finish the TRIGGER_AUTOHIDE_MIN -> 0.00f on bfb)
00353   float animation_progress;
00354   animation_progress = CLAMP((float)(unity::TimeUtil::TimeDelta(&current, &_times[TIME_AUTOHIDE])) / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f);
00355   if (_hidden)
00356     return animation_progress;
00357   else
00358     return 1.0f - animation_progress;
00359 }
00360 
00361 float Launcher::DragHideProgress(struct timespec const& current) const
00362 {
00363   if (_drag_edge_touching)
00364     return CLAMP((float)(unity::TimeUtil::TimeDelta(&current, &_times[TIME_DRAG_EDGE_TOUCH])) / (float)(ANIM_DURATION * 3), 0.0f, 1.0f);
00365   else
00366     return 1.0f - CLAMP((float)(unity::TimeUtil::TimeDelta(&current, &_times[TIME_DRAG_EDGE_TOUCH])) / (float)(ANIM_DURATION * 3), 0.0f, 1.0f);
00367 }
00368 
00369 float Launcher::DragThresholdProgress(struct timespec const& current) const
00370 {
00371   if (MouseBeyondDragThreshold())
00372     return 1.0f - CLAMP((float)(unity::TimeUtil::TimeDelta(&current, &_times[TIME_DRAG_THRESHOLD])) / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f);
00373   else
00374     return CLAMP((float)(unity::TimeUtil::TimeDelta(&current, &_times[TIME_DRAG_THRESHOLD])) / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f);
00375 }
00376 
00377 void Launcher::EnsureAnimation()
00378 {
00379   QueueDraw();
00380 }
00381 
00382 bool Launcher::IconNeedsAnimation(AbstractLauncherIcon::Ptr icon, struct timespec const& current) const
00383 {
00384   struct timespec time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_VISIBLE);
00385   if (unity::TimeUtil::TimeDelta(&current, &time) < ANIM_DURATION_SHORT)
00386     return true;
00387 
00388   time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_RUNNING);
00389   if (unity::TimeUtil::TimeDelta(&current, &time) < ANIM_DURATION_SHORT)
00390     return true;
00391 
00392   time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_STARTING);
00393   if (unity::TimeUtil::TimeDelta(&current, &time) < (ANIM_DURATION_LONG * MAX_STARTING_BLINKS * STARTING_BLINK_LAMBDA * 2))
00394     return true;
00395 
00396   time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_URGENT);
00397   if (unity::TimeUtil::TimeDelta(&current, &time) < (ANIM_DURATION_LONG * URGENT_BLINKS * 2))
00398     return true;
00399 
00400   time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_PULSE_ONCE);
00401   if (unity::TimeUtil::TimeDelta(&current, &time) < (ANIM_DURATION_LONG * PULSE_BLINK_LAMBDA * 2))
00402     return true;
00403 
00404   time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_PRESENTED);
00405   if (unity::TimeUtil::TimeDelta(&current, &time) < ANIM_DURATION)
00406     return true;
00407 
00408   time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_SHIMMER);
00409   if (unity::TimeUtil::TimeDelta(&current, &time) < ANIM_DURATION_LONG)
00410     return true;
00411 
00412   time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_CENTER_SAVED);
00413   if (unity::TimeUtil::TimeDelta(&current, &time) < ANIM_DURATION)
00414     return true;
00415 
00416   time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_PROGRESS);
00417   if (unity::TimeUtil::TimeDelta(&current, &time) < ANIM_DURATION)
00418     return true;
00419 
00420   time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_DROP_DIM);
00421   if (unity::TimeUtil::TimeDelta(&current, &time) < ANIM_DURATION)
00422     return true;
00423 
00424   time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_DESAT);
00425   if (unity::TimeUtil::TimeDelta(&current, &time) < ANIM_DURATION_SHORT_SHORT)
00426     return true;
00427 
00428   time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_DROP_PRELIGHT);
00429   if (unity::TimeUtil::TimeDelta(&current, &time) < ANIM_DURATION)
00430     return true;
00431 
00432   return false;
00433 }
00434 
00435 bool Launcher::AnimationInProgress() const
00436 {
00437   // performance here can be improved by caching the longer remaining animation found and short circuiting to that each time
00438   // this way extra checks may be avoided
00439 
00440   if (_last_reveal_progress != _hide_machine.reveal_progress)
00441     return true;
00442 
00443   // short circuit to avoid unneeded calculations
00444   struct timespec current;
00445   clock_gettime(CLOCK_MONOTONIC, &current);
00446 
00447   // hover in animation
00448   if (unity::TimeUtil::TimeDelta(&current, &_times[TIME_ENTER]) < ANIM_DURATION)
00449     return true;
00450 
00451   // hover out animation
00452   if (unity::TimeUtil::TimeDelta(&current, &_times[TIME_LEAVE]) < ANIM_DURATION)
00453     return true;
00454 
00455   // drag end animation
00456   if (unity::TimeUtil::TimeDelta(&current, &_times[TIME_DRAG_END]) < ANIM_DURATION_LONG)
00457     return true;
00458 
00459   // hide animation (time only), position is trigger manually on the bfb
00460   if (unity::TimeUtil::TimeDelta(&current, &_times[TIME_AUTOHIDE]) < ANIM_DURATION_SHORT)
00461     return true;
00462 
00463   // collapse animation on DND out of launcher space
00464   if (unity::TimeUtil::TimeDelta(&current, &_times[TIME_DRAG_THRESHOLD]) < ANIM_DURATION_SHORT)
00465     return true;
00466 
00467   // hide animation for dnd
00468   if (unity::TimeUtil::TimeDelta(&current, &_times[TIME_DRAG_EDGE_TOUCH]) < ANIM_DURATION * 6)
00469     return true;
00470 
00471   // restore from drag_out animation
00472   if (unity::TimeUtil::TimeDelta(&current, &_times[TIME_DRAG_OUT]) < ANIM_DURATION_SHORT)
00473     return true;
00474 
00475   // animations happening on specific icons
00476   LauncherModel::iterator it;
00477   for (it = _model->begin(); it != _model->end(); it++)
00478     if (IconNeedsAnimation(*it, current))
00479       return true;
00480 
00481   return false;
00482 }
00483 
00484 /* Min is when you are on the trigger */
00485 float Launcher::GetAutohidePositionMin() const
00486 {
00487   if (options()->auto_hide_animation() == SLIDE_ONLY || options()->auto_hide_animation() == FADE_AND_SLIDE)
00488     return 0.35f;
00489   else
00490     return 0.25f;
00491 }
00492 /* Max is the initial state over the bfb */
00493 float Launcher::GetAutohidePositionMax() const
00494 {
00495   if (options()->auto_hide_animation() == SLIDE_ONLY || options()->auto_hide_animation() == FADE_AND_SLIDE)
00496     return 1.00f;
00497   else
00498     return 0.75f;
00499 }
00500 
00501 
00502 float Launcher::IconVisibleProgress(AbstractLauncherIcon::Ptr icon, struct timespec const& current) const
00503 {
00504   if (!icon->IsVisibleOnMonitor(monitor))
00505     return 0.0f;
00506 
00507   if (icon->GetIconType() == AbstractLauncherIcon::TYPE_HUD)
00508   {
00509     return (icon->GetQuirk(AbstractLauncherIcon::QUIRK_VISIBLE)) ? 1.0f : 0.0f;
00510   }
00511 
00512   if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_VISIBLE))
00513   {
00514     struct timespec icon_visible_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_VISIBLE);
00515     int enter_ms = unity::TimeUtil::TimeDelta(&current, &icon_visible_time);
00516     return CLAMP((float) enter_ms / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f);
00517   }
00518   else
00519   {
00520     struct timespec icon_hide_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_VISIBLE);
00521     int hide_ms = unity::TimeUtil::TimeDelta(&current, &icon_hide_time);
00522     return 1.0f - CLAMP((float) hide_ms / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f);
00523   }
00524 }
00525 
00526 void Launcher::SetDndDelta(float x, float y, nux::Geometry const& geo, timespec const& current)
00527 {
00528   AbstractLauncherIcon::Ptr anchor;
00529   anchor = MouseIconIntersection(x, _enter_y);
00530 
00531   if (anchor)
00532   {
00533     float position = y;
00534     for (AbstractLauncherIcon::Ptr model_icon : *_model)
00535     {
00536       if (model_icon == anchor)
00537       {
00538         position += _icon_size / 2;
00539         _launcher_drag_delta = _enter_y - position;
00540 
00541         if (position + _icon_size / 2 + _launcher_drag_delta > geo.height)
00542           _launcher_drag_delta -= (position + _icon_size / 2 + _launcher_drag_delta) - geo.height;
00543 
00544         break;
00545       }
00546       position += (_icon_size + _space_between_icons) * IconVisibleProgress(model_icon, current);
00547     }
00548   }
00549 }
00550 
00551 float Launcher::IconPresentProgress(AbstractLauncherIcon::Ptr icon, struct timespec const& current) const
00552 {
00553   struct timespec icon_present_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_PRESENTED);
00554   int ms = unity::TimeUtil::TimeDelta(&current, &icon_present_time);
00555   float result = CLAMP((float) ms / (float) ANIM_DURATION, 0.0f, 1.0f);
00556 
00557   if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_PRESENTED))
00558     return result;
00559   else
00560     return 1.0f - result;
00561 }
00562 
00563 float Launcher::IconUrgentProgress(AbstractLauncherIcon::Ptr icon, struct timespec const& current) const
00564 {
00565   struct timespec urgent_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_URGENT);
00566   int urgent_ms = unity::TimeUtil::TimeDelta(&current, &urgent_time);
00567   float result;
00568 
00569   if (options()->urgent_animation() == URGENT_ANIMATION_WIGGLE)
00570     result = CLAMP((float) urgent_ms / (float)(ANIM_DURATION_SHORT * WIGGLE_CYCLES), 0.0f, 1.0f);
00571   else
00572     result = CLAMP((float) urgent_ms / (float)(ANIM_DURATION_LONG * URGENT_BLINKS * 2), 0.0f, 1.0f);
00573 
00574   if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_URGENT))
00575     return result;
00576   else
00577     return 1.0f - result;
00578 }
00579 
00580 float Launcher::IconDropDimValue(AbstractLauncherIcon::Ptr icon, struct timespec const& current) const
00581 {
00582   struct timespec dim_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_DROP_DIM);
00583   int dim_ms = unity::TimeUtil::TimeDelta(&current, &dim_time);
00584   float result = CLAMP((float) dim_ms / (float) ANIM_DURATION, 0.0f, 1.0f);
00585 
00586   if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_DROP_DIM))
00587     return 1.0f - result;
00588   else
00589     return result;
00590 }
00591 
00592 float Launcher::IconDesatValue(AbstractLauncherIcon::Ptr icon, struct timespec const& current) const
00593 {
00594   if (!IsOverlayOpen())
00595     return 1.0f;
00596 
00597   struct timespec dim_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_DESAT);
00598   int ms = unity::TimeUtil::TimeDelta(&current, &dim_time);
00599   float result = CLAMP((float) ms / (float) ANIM_DURATION_SHORT_SHORT, 0.0f, 1.0f);
00600 
00601   if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_DESAT))
00602     return 1.0f - result;
00603   else
00604     return result;
00605 }
00606 
00607 float Launcher::IconShimmerProgress(AbstractLauncherIcon::Ptr icon, struct timespec const& current) const
00608 {
00609   struct timespec shimmer_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_SHIMMER);
00610   int shimmer_ms = unity::TimeUtil::TimeDelta(&current, &shimmer_time);
00611   return CLAMP((float) shimmer_ms / (float) ANIM_DURATION_LONG, 0.0f, 1.0f);
00612 }
00613 
00614 float Launcher::IconCenterTransitionProgress(AbstractLauncherIcon::Ptr icon, struct timespec const& current) const
00615 {
00616   struct timespec save_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_CENTER_SAVED);
00617   int save_ms = unity::TimeUtil::TimeDelta(&current, &save_time);
00618   return CLAMP((float) save_ms / (float) ANIM_DURATION, 0.0f, 1.0f);
00619 }
00620 
00621 float Launcher::IconUrgentPulseValue(AbstractLauncherIcon::Ptr icon, struct timespec const& current) const
00622 {
00623   if (!icon->GetQuirk(AbstractLauncherIcon::QUIRK_URGENT))
00624     return 1.0f; // we are full on in a normal condition
00625 
00626   double urgent_progress = (double) IconUrgentProgress(icon, current);
00627   return 0.5f + (float)(std::cos(M_PI * (float)(URGENT_BLINKS * 2) * urgent_progress)) * 0.5f;
00628 }
00629 
00630 float Launcher::IconPulseOnceValue(AbstractLauncherIcon::Ptr icon, struct timespec const &current) const
00631 {
00632   struct timespec pulse_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_PULSE_ONCE);
00633   int pulse_ms = unity::TimeUtil::TimeDelta(&current, &pulse_time);
00634   double pulse_progress = (double) CLAMP((float) pulse_ms / (ANIM_DURATION_LONG * PULSE_BLINK_LAMBDA * 2), 0.0f, 1.0f);
00635 
00636   if (pulse_progress == 1.0f)
00637     icon->SetQuirk(AbstractLauncherIcon::QUIRK_PULSE_ONCE, false);
00638 
00639   return 0.5f + (float) (std::cos(M_PI * 2.0 * pulse_progress)) * 0.5f;
00640 }
00641 
00642 float Launcher::IconUrgentWiggleValue(AbstractLauncherIcon::Ptr icon, struct timespec const& current) const
00643 {
00644   if (!icon->GetQuirk(AbstractLauncherIcon::QUIRK_URGENT))
00645     return 0.0f; // we are full on in a normal condition
00646 
00647   double urgent_progress = (double) IconUrgentProgress(icon, current);
00648   return 0.3f * (float)(std::sin(M_PI * (float)(WIGGLE_CYCLES * 2) * urgent_progress)) * 0.5f;
00649 }
00650 
00651 float Launcher::IconStartingBlinkValue(AbstractLauncherIcon::Ptr icon, struct timespec const& current) const
00652 {
00653   struct timespec starting_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_STARTING);
00654   int starting_ms = unity::TimeUtil::TimeDelta(&current, &starting_time);
00655   double starting_progress = (double) CLAMP((float) starting_ms / (float)(ANIM_DURATION_LONG * STARTING_BLINK_LAMBDA), 0.0f, 1.0f);
00656   double val = IsBackLightModeToggles() ? 3.0f : 4.0f;
00657   return 0.5f + (float)(std::cos(M_PI * val * starting_progress)) * 0.5f;
00658 }
00659 
00660 float Launcher::IconStartingPulseValue(AbstractLauncherIcon::Ptr icon, struct timespec const& current) const
00661 {
00662   struct timespec starting_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_STARTING);
00663   int starting_ms = unity::TimeUtil::TimeDelta(&current, &starting_time);
00664   double starting_progress = (double) CLAMP((float) starting_ms / (float)(ANIM_DURATION_LONG * MAX_STARTING_BLINKS * STARTING_BLINK_LAMBDA * 2), 0.0f, 1.0f);
00665 
00666   if (starting_progress == 1.0f && !icon->GetQuirk(AbstractLauncherIcon::QUIRK_RUNNING))
00667   {
00668     icon->SetQuirk(AbstractLauncherIcon::QUIRK_STARTING, false);
00669     icon->ResetQuirkTime(AbstractLauncherIcon::QUIRK_STARTING);
00670   }
00671 
00672   return 0.5f + (float)(std::cos(M_PI * (float)(MAX_STARTING_BLINKS * 2) * starting_progress)) * 0.5f;
00673 }
00674 
00675 float Launcher::IconBackgroundIntensity(AbstractLauncherIcon::Ptr icon, struct timespec const& current) const
00676 {
00677   float result = 0.0f;
00678 
00679   struct timespec running_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_RUNNING);
00680   int running_ms = unity::TimeUtil::TimeDelta(&current, &running_time);
00681   float running_progress = CLAMP((float) running_ms / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f);
00682 
00683   if (!icon->GetQuirk(AbstractLauncherIcon::QUIRK_RUNNING))
00684     running_progress = 1.0f - running_progress;
00685 
00686   // After we finish a fade in from running, we can reset the quirk
00687   if (running_progress == 1.0f && icon->GetQuirk(AbstractLauncherIcon::QUIRK_RUNNING))
00688     icon->SetQuirk(AbstractLauncherIcon::QUIRK_STARTING, false);
00689 
00690   float backlight_strength;
00691   if (options()->backlight_mode() == BACKLIGHT_ALWAYS_ON)
00692     backlight_strength = BACKLIGHT_STRENGTH;
00693   else if (IsBackLightModeToggles())
00694     backlight_strength = BACKLIGHT_STRENGTH * running_progress;
00695   else
00696     backlight_strength = 0.0f;
00697 
00698   switch (options()->launch_animation())
00699   {
00700     case LAUNCH_ANIMATION_NONE:
00701       result = backlight_strength;
00702       break;
00703     case LAUNCH_ANIMATION_BLINK:
00704       if (options()->backlight_mode() == BACKLIGHT_ALWAYS_ON)
00705         result = IconStartingBlinkValue(icon, current);
00706       else if (options()->backlight_mode() == BACKLIGHT_ALWAYS_OFF)
00707         result = 1.0f - IconStartingBlinkValue(icon, current);
00708       else
00709         result = backlight_strength; // The blink concept is a failure in this case (it just doesn't work right)
00710       break;
00711     case LAUNCH_ANIMATION_PULSE:
00712       if (running_progress == 1.0f && icon->GetQuirk(AbstractLauncherIcon::QUIRK_RUNNING))
00713         icon->ResetQuirkTime(AbstractLauncherIcon::QUIRK_STARTING);
00714 
00715       result = backlight_strength;
00716       if (options()->backlight_mode() == BACKLIGHT_ALWAYS_ON)
00717         result *= CLAMP(running_progress + IconStartingPulseValue(icon, current), 0.0f, 1.0f);
00718       else if (IsBackLightModeToggles())
00719         result += (BACKLIGHT_STRENGTH - result) * (1.0f - IconStartingPulseValue(icon, current));
00720       else
00721         result = 1.0f - CLAMP(running_progress + IconStartingPulseValue(icon, current), 0.0f, 1.0f);
00722       break;
00723   }
00724 
00725   if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_PULSE_ONCE))
00726   {
00727     if (options()->backlight_mode() == BACKLIGHT_ALWAYS_ON)
00728       result *= CLAMP(running_progress + IconPulseOnceValue(icon, current), 0.0f, 1.0f);
00729     else if (options()->backlight_mode() == BACKLIGHT_NORMAL)
00730       result += (BACKLIGHT_STRENGTH - result) * (1.0f - IconPulseOnceValue(icon, current));
00731     else
00732       result = 1.0f - CLAMP(running_progress + IconPulseOnceValue(icon, current), 0.0f, 1.0f);
00733   }
00734 
00735   // urgent serves to bring the total down only
00736   if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_URGENT) && options()->urgent_animation() == URGENT_ANIMATION_PULSE)
00737     result *= 0.2f + 0.8f * IconUrgentPulseValue(icon, current);
00738 
00739   return result;
00740 }
00741 
00742 float Launcher::IconProgressBias(AbstractLauncherIcon::Ptr icon, struct timespec const& current) const
00743 {
00744   struct timespec icon_progress_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_PROGRESS);
00745   int ms = unity::TimeUtil::TimeDelta(&current, &icon_progress_time);
00746   float result = CLAMP((float) ms / (float) ANIM_DURATION, 0.0f, 1.0f);
00747 
00748   if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_PROGRESS))
00749     return -1.0f + result;
00750   else
00751     return result;
00752 }
00753 
00754 bool Launcher::IconDrawEdgeOnly(AbstractLauncherIcon::Ptr icon) const
00755 {
00756   if (options()->backlight_mode() == BACKLIGHT_EDGE_TOGGLE)
00757     return true;
00758 
00759   if (options()->backlight_mode() == BACKLIGHT_NORMAL_EDGE_TOGGLE && !icon->WindowVisibleOnMonitor(monitor))
00760     return true;
00761 
00762   return false;
00763 }
00764 
00765 void Launcher::SetupRenderArg(AbstractLauncherIcon::Ptr icon, struct timespec const& current, RenderArg& arg)
00766 {
00767   float desat_value = IconDesatValue(icon, current);
00768   arg.icon                = icon.GetPointer();
00769   arg.alpha               = 0.2f + 0.8f * desat_value;
00770   arg.saturation          = desat_value;
00771   arg.colorify            = nux::color::White;
00772   arg.running_arrow       = icon->GetQuirk(AbstractLauncherIcon::QUIRK_RUNNING);
00773   arg.running_colored     = icon->GetQuirk(AbstractLauncherIcon::QUIRK_URGENT);
00774   arg.draw_edge_only      = IconDrawEdgeOnly(icon);
00775   arg.active_colored      = false;
00776   arg.x_rotation          = 0.0f;
00777   arg.y_rotation          = 0.0f;
00778   arg.z_rotation          = 0.0f;
00779   arg.skip                = false;
00780   arg.stick_thingy        = false;
00781   arg.keyboard_nav_hl     = false;
00782   arg.progress_bias       = IconProgressBias(icon, current);
00783   arg.progress            = CLAMP(icon->GetProgress(), 0.0f, 1.0f);
00784   arg.draw_shortcut       = _shortcuts_shown && !_hide_machine.GetQuirk(LauncherHideMachine::PLACES_VISIBLE);
00785   arg.system_item         = icon->GetIconType() == AbstractLauncherIcon::TYPE_HOME    ||
00786                             icon->GetIconType() == AbstractLauncherIcon::TYPE_HUD;
00787   arg.colorify_background = icon->GetIconType() == AbstractLauncherIcon::TYPE_HOME    ||
00788                             icon->GetIconType() == AbstractLauncherIcon::TYPE_HUD     ||
00789                             icon->GetIconType() == AbstractLauncherIcon::TYPE_TRASH   ||
00790                             icon->GetIconType() == AbstractLauncherIcon::TYPE_DESKTOP ||
00791                             icon->GetIconType() == AbstractLauncherIcon::TYPE_DEVICE  ||
00792                             icon->GetIconType() == AbstractLauncherIcon::TYPE_EXPO;
00793 
00794   // trying to protect against flickering when icon is dragged from dash LP: #863230
00795   if (arg.alpha < 0.2)
00796   {
00797     arg.alpha = 0.2;
00798     arg.saturation = 0.0;
00799   }
00800 
00801   arg.active_arrow = icon->GetQuirk(AbstractLauncherIcon::QUIRK_ACTIVE);
00802 
00803   /* BFB or HUD icons don't need the active arrow if the overaly is opened
00804    * in another monitor */
00805   if (arg.active_arrow && !IsOverlayOpen() &&
00806       (icon->GetIconType() == AbstractLauncherIcon::TYPE_HOME ||
00807        icon->GetIconType() == AbstractLauncherIcon::TYPE_HUD))
00808   {
00809     arg.active_arrow = false;
00810   }
00811 
00812   if (options()->show_for_all)
00813     arg.running_on_viewport = icon->WindowVisibleOnViewport();
00814   else
00815     arg.running_on_viewport = icon->WindowVisibleOnMonitor(monitor);
00816 
00817   guint64 shortcut = icon->GetShortcut();
00818   if (shortcut > 32)
00819     arg.shortcut_label = (char) shortcut;
00820   else
00821     arg.shortcut_label = 0;
00822 
00823   // we dont need to show strays
00824   if (!icon->GetQuirk(AbstractLauncherIcon::QUIRK_RUNNING))
00825   {
00826     if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_URGENT))
00827     {
00828       arg.running_arrow = true;
00829       arg.window_indicators = 1;
00830     }
00831     else
00832       arg.window_indicators = 0;
00833   }
00834   else
00835   {
00836     if (options()->show_for_all)
00837       arg.window_indicators = std::max<int> (icon->WindowsOnViewport().size(), 1);
00838     else
00839       arg.window_indicators = std::max<int> (icon->WindowsForMonitor(monitor).size(), 1);
00840   }
00841 
00842   arg.backlight_intensity = IconBackgroundIntensity(icon, current);
00843   arg.shimmer_progress = IconShimmerProgress(icon, current);
00844 
00845   float urgent_progress = IconUrgentProgress(icon, current);
00846 
00847   if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_URGENT))
00848     urgent_progress = CLAMP(urgent_progress * 3.0f, 0.0f, 1.0f);  // we want to go 3x faster than the urgent normal cycle
00849   else
00850     urgent_progress = CLAMP(urgent_progress * 3.0f - 2.0f, 0.0f, 1.0f);  // we want to go 3x faster than the urgent normal cycle
00851   arg.glow_intensity = urgent_progress;
00852 
00853   if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_URGENT) && options()->urgent_animation() == URGENT_ANIMATION_WIGGLE)
00854   {
00855     arg.z_rotation = IconUrgentWiggleValue(icon, current);
00856   }
00857 
00858   if (IsInKeyNavMode())
00859   {
00860     if (icon == _model->Selection())
00861       arg.keyboard_nav_hl = true;
00862   }
00863 }
00864 
00865 void Launcher::FillRenderArg(AbstractLauncherIcon::Ptr icon,
00866                              RenderArg& arg,
00867                              nux::Point3& center,
00868                              nux::Geometry const& parent_abs_geo,
00869                              float folding_threshold,
00870                              float folded_size,
00871                              float folded_spacing,
00872                              float autohide_offset,
00873                              float folded_z_distance,
00874                              float animation_neg_rads,
00875                              struct timespec const& current)
00876 {
00877   SetupRenderArg(icon, current, arg);
00878 
00879   // reset z
00880   center.z = 0;
00881 
00882   float size_modifier = IconVisibleProgress(icon, current);
00883   if (size_modifier < 1.0f)
00884   {
00885     arg.alpha *= size_modifier;
00886     center.z = 300.0f * (1.0f - size_modifier);
00887   }
00888 
00889   float drop_dim_value = 0.2f + 0.8f * IconDropDimValue(icon, current);
00890 
00891   if (drop_dim_value < 1.0f)
00892     arg.alpha *= drop_dim_value;
00893 
00894   // trying to protect against flickering when icon is dragged from dash LP: #863230
00895   if (arg.alpha < 0.2)
00896   {
00897     arg.alpha = 0.2;
00898     arg.saturation = 0.0;
00899   }
00900 
00901   if (icon == _drag_icon)
00902   {
00903     if (MouseBeyondDragThreshold())
00904       arg.stick_thingy = true;
00905 
00906     if (GetActionState() == ACTION_DRAG_ICON ||
00907         (_drag_window && _drag_window->Animating()) ||
00908         icon->IsSpacer())
00909       arg.skip = true;
00910     size_modifier *= DragThresholdProgress(current);
00911   }
00912 
00913   if (size_modifier <= 0.0f)
00914     arg.skip = true;
00915 
00916   // goes for 0.0f when fully unfolded, to 1.0f folded
00917   float folding_progress = CLAMP((center.y + _icon_size - folding_threshold) / (float) _icon_size, 0.0f, 1.0f);
00918   float present_progress = IconPresentProgress(icon, current);
00919 
00920   folding_progress *= 1.0f - present_progress;
00921 
00922   float half_size = (folded_size / 2.0f) + (_icon_size / 2.0f - folded_size / 2.0f) * (1.0f - folding_progress);
00923   float icon_hide_offset = autohide_offset;
00924 
00925   icon_hide_offset *= 1.0f - (present_progress * icon->PresentUrgency());
00926 
00927   // icon is crossing threshold, start folding
00928   center.z += folded_z_distance * folding_progress;
00929   arg.x_rotation = animation_neg_rads * folding_progress;
00930 
00931   float spacing_overlap = CLAMP((float)(center.y + (2.0f * half_size * size_modifier) + (_space_between_icons * size_modifier) - folding_threshold) / (float) _icon_size, 0.0f, 1.0f);
00932   float spacing = (_space_between_icons * (1.0f - spacing_overlap) + folded_spacing * spacing_overlap) * size_modifier;
00933 
00934   nux::Point3 centerOffset;
00935   float center_transit_progress = IconCenterTransitionProgress(icon, current);
00936   if (center_transit_progress <= 1.0f)
00937   {
00938     int saved_center = icon->GetSavedCenter(monitor).y - parent_abs_geo.y;
00939     centerOffset.y = (saved_center - (center.y + (half_size * size_modifier))) * (1.0f - center_transit_progress);
00940   }
00941 
00942   center.y += half_size * size_modifier;   // move to center
00943 
00944   arg.render_center = nux::Point3(roundf(center.x + icon_hide_offset), roundf(center.y + centerOffset.y), roundf(center.z));
00945   arg.logical_center = nux::Point3(roundf(center.x + icon_hide_offset), roundf(center.y), roundf(center.z));
00946 
00947   icon->SetCenter(nux::Point3(roundf(center.x), roundf(center.y), roundf(center.z)), monitor, parent_abs_geo);
00948 
00949   // FIXME: this is a hack, we should have a look why SetAnimationTarget is necessary in SetAnimationTarget
00950   // we should ideally just need it at start to set the target
00951   if (!_initial_drag_animation && icon == _drag_icon && _drag_window && _drag_window->Animating())
00952     _drag_window->SetAnimationTarget(static_cast<int>(_drag_icon->GetCenter(monitor).x),
00953                                      static_cast<int>(_drag_icon->GetCenter(monitor).y));
00954 
00955   center.y += (half_size * size_modifier) + spacing;   // move to end
00956 }
00957 
00958 float Launcher::DragLimiter(float x)
00959 {
00960   float result = (1 - std::pow(159.0 / 160,  std::abs(x))) * 160;
00961 
00962   if (x >= 0.0f)
00963     return result;
00964   return -result;
00965 }
00966 
00967 nux::Color FullySaturateColor (nux::Color color)
00968 {
00969   float max = std::max<float>(color.red, std::max<float>(color.green, color.blue));
00970   color = color * (1.0f / max);
00971   return color;
00972 }
00973 
00974 void Launcher::RenderArgs(std::list<RenderArg> &launcher_args,
00975                           nux::Geometry& box_geo, float* launcher_alpha, nux::Geometry const& parent_abs_geo)
00976 {
00977   nux::Geometry const& geo = GetGeometry();
00978   LauncherModel::iterator it;
00979   nux::Point3 center;
00980   struct timespec current;
00981   clock_gettime(CLOCK_MONOTONIC, &current);
00982 
00983   nux::Color colorify = FullySaturateColor(_background_color);
00984 
00985   float hover_progress = GetHoverProgress(current);
00986   float folded_z_distance = _folded_z_distance * (1.0f - hover_progress);
00987   float animation_neg_rads = _neg_folded_angle * (1.0f - hover_progress);
00988 
00989   float folding_constant = 0.25f;
00990   float folding_not_constant = folding_constant + ((1.0f - folding_constant) * hover_progress);
00991 
00992   float folded_size = _icon_size * folding_not_constant;
00993   float folded_spacing = _space_between_icons * folding_not_constant;
00994 
00995   center.x = geo.width / 2;
00996   center.y = _space_between_icons;
00997   center.z = 0;
00998 
00999   int launcher_height = geo.height;
01000 
01001   // compute required height of launcher AND folding threshold
01002   float sum = 0.0f + center.y;
01003   float folding_threshold = launcher_height - _icon_size / 2.5f;
01004   for (it = _model->begin(); it != _model->end(); it++)
01005   {
01006     float height = (_icon_size + _space_between_icons) * IconVisibleProgress(*it, current);
01007     sum += height;
01008 
01009     // magic constant must some day be explained, for now suffice to say this constant prevents the bottom from "marching";
01010     float magic_constant = 1.3f;
01011 
01012     float present_progress = IconPresentProgress(*it, current);
01013     folding_threshold -= CLAMP(sum - launcher_height, 0.0f, height * magic_constant) * (folding_constant + (1.0f - folding_constant) * present_progress);
01014   }
01015 
01016   if (sum - _space_between_icons <= launcher_height)
01017     folding_threshold = launcher_height;
01018 
01019   float autohide_offset = 0.0f;
01020   *launcher_alpha = 1.0f;
01021   if (options()->hide_mode != LAUNCHER_HIDE_NEVER || _hide_machine.GetQuirk(LauncherHideMachine::LOCK_HIDE))
01022   {
01023 
01024     float autohide_progress = AutohideProgress(current) * (1.0f - DragOutProgress(current));
01025     if (options()->auto_hide_animation() == FADE_ONLY)
01026     {
01027       *launcher_alpha = 1.0f - autohide_progress;
01028     }
01029     else
01030     {
01031       if (autohide_progress > 0.0f)
01032       {
01033         autohide_offset -= geo.width * autohide_progress;
01034         if (options()->auto_hide_animation() == FADE_AND_SLIDE)
01035           *launcher_alpha = 1.0f - 0.5f * autohide_progress;
01036       }
01037     }
01038   }
01039 
01040   float drag_hide_progress = DragHideProgress(current);
01041   if (options()->hide_mode != LAUNCHER_HIDE_NEVER && drag_hide_progress > 0.0f)
01042   {
01043     autohide_offset -= geo.width * 0.25f * drag_hide_progress;
01044 
01045     if (drag_hide_progress >= 1.0f)
01046       _hide_machine.SetQuirk(LauncherHideMachine::DND_PUSHED_OFF, true);
01047   }
01048 
01049   // Inform the painter where to paint the box
01050   box_geo = geo;
01051 
01052   if (options()->hide_mode != LAUNCHER_HIDE_NEVER || _hide_machine.GetQuirk(LauncherHideMachine::LOCK_HIDE))
01053     box_geo.x += autohide_offset;
01054 
01055   /* Why we need last_geo? It stores the last box_geo (note: as it is a static variable,
01056    * it is initialized only first time). Infact we call SetDndDelta that calls MouseIconIntersection
01057    * that uses values (HitArea) that are computed in UpdateIconXForm.
01058    * The problem is that in DrawContent we calls first RenderArgs, then UpdateIconXForm. Just
01059    * use last_geo to hack this problem.
01060    */
01061   static nux::Geometry last_geo = box_geo;
01062 
01063   // this happens on hover, basically its a flag and a value in one, we translate this into a dnd offset
01064   if (_enter_y != 0 && _enter_y + _icon_size / 2 > folding_threshold)
01065     SetDndDelta(last_geo.x + last_geo.width / 2, center.y, geo, current);
01066 
01067   // Update the last_geo value.
01068   last_geo = box_geo;
01069   _enter_y = 0;
01070 
01071   if (hover_progress > 0.0f && _launcher_drag_delta != 0)
01072   {
01073     float delta_y = _launcher_drag_delta;
01074 
01075     // logically dnd exit only restores to the clamped ranges
01076     // hover_progress restores to 0
01077     float max = 0.0f;
01078     float min = MIN(0.0f, launcher_height - sum);
01079 
01080     if (_launcher_drag_delta > max)
01081       delta_y = max + DragLimiter(delta_y - max);
01082     else if (_launcher_drag_delta < min)
01083       delta_y = min + DragLimiter(delta_y - min);
01084 
01085     if (GetActionState() != ACTION_DRAG_LAUNCHER)
01086     {
01087       float dnd_progress = DnDExitProgress(current);
01088 
01089       if (_launcher_drag_delta > max)
01090         delta_y = max + (delta_y - max) * dnd_progress;
01091       else if (_launcher_drag_delta < min)
01092         delta_y = min + (delta_y - min) * dnd_progress;
01093 
01094       if (dnd_progress == 0.0f)
01095         _launcher_drag_delta = (int) delta_y;
01096     }
01097 
01098     delta_y *= hover_progress;
01099     center.y += delta_y;
01100     folding_threshold += delta_y;
01101 
01102     _scroll_limit_reached = (delta_y == _last_delta_y);
01103     _last_delta_y = delta_y;
01104   }
01105   else
01106   {
01107     _launcher_drag_delta = 0;
01108   }
01109 
01110   // The functional position we wish to represent for these icons is not smooth. Rather than introducing
01111   // special casing to represent this, we use MIN/MAX functions. This helps ensure that even though our
01112   // function is not smooth it is continuous, which is more important for our visual representation (icons
01113   // wont start jumping around).  As a general rule ANY if () statements that modify center.y should be seen
01114   // as bugs.
01115   int index = 1;
01116   for (it = _model->main_begin(); it != _model->main_end(); it++)
01117   {
01118     RenderArg arg;
01119     AbstractLauncherIcon::Ptr icon = *it;
01120 
01121     FillRenderArg(icon, arg, center, parent_abs_geo, folding_threshold, folded_size, folded_spacing,
01122                   autohide_offset, folded_z_distance, animation_neg_rads, current);
01123     arg.colorify = colorify;
01124     launcher_args.push_back(arg);
01125     index++;
01126   }
01127 
01128   // compute maximum height of shelf
01129   float shelf_sum = 0.0f;
01130   for (it = _model->shelf_begin(); it != _model->shelf_end(); it++)
01131   {
01132     float height = (_icon_size + _space_between_icons) * IconVisibleProgress(*it, current);
01133     shelf_sum += height;
01134   }
01135 
01136   // add bottom padding
01137   if (shelf_sum > 0.0f)
01138     shelf_sum += _space_between_icons;
01139 
01140   float shelf_delta = MAX(((launcher_height - shelf_sum) + _space_between_icons) - center.y, 0.0f);
01141   folding_threshold += shelf_delta;
01142   center.y += shelf_delta;
01143 
01144   for (it = _model->shelf_begin(); it != _model->shelf_end(); it++)
01145   {
01146     RenderArg arg;
01147     AbstractLauncherIcon::Ptr icon = *it;
01148 
01149     FillRenderArg(icon, arg, center, parent_abs_geo, folding_threshold, folded_size, folded_spacing,
01150                   autohide_offset, folded_z_distance, animation_neg_rads, current);
01151     arg.colorify = colorify;
01152     launcher_args.push_back(arg);
01153   }
01154 }
01155 
01156 /* End Render Layout Logic */
01157 
01158 void Launcher::ForceReveal(bool force_reveal)
01159 {
01160   _hide_machine.SetQuirk(LauncherHideMachine::TRIGGER_BUTTON_SHOW, force_reveal);
01161 }
01162 
01163 void Launcher::ShowShortcuts(bool show)
01164 {
01165   _shortcuts_shown = show;
01166   _hover_machine.SetQuirk(LauncherHoverMachine::SHORTCUT_KEYS_VISIBLE, show);
01167   EnsureAnimation();
01168 }
01169 
01170 void Launcher::OnBGColorChanged(GVariant *data)
01171 {
01172   double red = 0.0f, green = 0.0f, blue = 0.0f, alpha = 0.0f;
01173 
01174   g_variant_get(data, "(dddd)", &red, &green, &blue, &alpha);
01175   _background_color = nux::Color(red, green, blue, alpha);
01176   QueueDraw();
01177 }
01178 
01179 void Launcher::OnLockHideChanged(GVariant *data)
01180 {
01181   gboolean enable_lock = FALSE;
01182   g_variant_get(data, "(b)", &enable_lock);
01183 
01184   if (enable_lock)
01185   {
01186     _hide_machine.SetQuirk(LauncherHideMachine::LOCK_HIDE, true);
01187   }
01188   else
01189   {
01190     _hide_machine.SetQuirk(LauncherHideMachine::LOCK_HIDE, false);
01191   }
01192 }
01193 
01194 void Launcher::DesaturateIcons()
01195 {
01196   for (auto icon : *_model)
01197   {
01198     if (icon->GetIconType () != AbstractLauncherIcon::TYPE_HOME &&
01199         icon->GetIconType () != AbstractLauncherIcon::TYPE_HUD)
01200     {
01201       icon->SetQuirk(AbstractLauncherIcon::QUIRK_DESAT, true);
01202     }
01203 
01204     icon->HideTooltip();
01205   }
01206 }
01207 
01208 void Launcher::SaturateIcons()
01209 {
01210   for (auto icon : *_model)
01211   {
01212     icon->SetQuirk(AbstractLauncherIcon::QUIRK_DESAT, false);
01213   }
01214 }
01215 
01216 void Launcher::OnOverlayShown(GVariant* data)
01217 {
01218   // check the type of overlay
01219   unity::glib::String overlay_identity;
01220   gboolean can_maximise = FALSE;
01221   gint32 overlay_monitor = 0;
01222   g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING,
01223                 &overlay_identity, &can_maximise, &overlay_monitor);
01224   std::string identity(overlay_identity.Str());
01225 
01226   LOG_DEBUG(logger) << "Overlay shown: " << identity
01227                     << ", " << (can_maximise ? "can maximise" : "can't maximise")
01228                     << ", on monitor " << overlay_monitor
01229                     << " (for monitor " << monitor() << ")";
01230 
01231   if (overlay_monitor == monitor())
01232   {
01233     if (identity == "dash")
01234     {
01235       _dash_is_open = true;
01236       _hide_machine.SetQuirk(LauncherHideMachine::PLACES_VISIBLE, true);
01237       _hover_machine.SetQuirk(LauncherHoverMachine::PLACES_VISIBLE, true);
01238     }
01239     if (identity == "hud")
01240     {
01241       _hud_is_open = true;
01242     }
01243     bg_effect_helper_.enabled = true;
01244     // Don't desaturate icons if the mouse is over the launcher:
01245     if (!_hovered)
01246     {
01247       LOG_DEBUG(logger) << "Desaturate on monitor " << monitor();
01248       DesaturateIcons();
01249     }
01250 
01251     if (_icon_under_mouse)
01252       _icon_under_mouse->HideTooltip();
01253   }
01254   EnsureAnimation();
01255 }
01256 
01257 void Launcher::OnOverlayHidden(GVariant* data)
01258 {
01259   // check the type of overlay
01260   unity::glib::String overlay_identity;
01261   gboolean can_maximise = FALSE;
01262   gint32 overlay_monitor = 0;
01263   g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING,
01264                 &overlay_identity, &can_maximise, &overlay_monitor);
01265 
01266   std::string identity = overlay_identity.Str();
01267 
01268   LOG_DEBUG(logger) << "Overlay hidden: " << identity
01269                     << ", " << (can_maximise ? "can maximise" : "can't maximise")
01270                     << ", on monitor " << overlay_monitor
01271                     << " (for monitor" << monitor() << ")";
01272 
01273   if (overlay_monitor == monitor())
01274   {
01275     if (identity == "dash")
01276     {
01277       _hide_machine.SetQuirk(LauncherHideMachine::PLACES_VISIBLE, false);
01278       _hover_machine.SetQuirk(LauncherHoverMachine::PLACES_VISIBLE, false);
01279       _dash_is_open = false;
01280     }
01281     else if (identity == "hud")
01282     {
01283       _hud_is_open = false;
01284     }
01285 
01286     // If they are both now shut, then disable the effect helper and saturate the icons.
01287     if (!IsOverlayOpen())
01288     {
01289       bg_effect_helper_.enabled = false;
01290       LOG_DEBUG(logger) << "Saturate on monitor " << monitor();
01291       SaturateIcons();
01292     }
01293   }
01294   EnsureAnimation();
01295 
01296   // as the leave event is no more received when the place is opened
01297   // FIXME: remove when we change the mouse grab strategy in nux
01298   nux::Point pt = nux::GetWindowCompositor().GetMousePosition();
01299   SetStateMouseOverLauncher(GetAbsoluteGeometry().IsInside(pt));
01300 }
01301 
01302 bool Launcher::IsOverlayOpen() const
01303 {
01304   return _dash_is_open || _hud_is_open;
01305 }
01306 
01307 void Launcher::OnActionDone(GVariant* data)
01308 {
01309   _hide_machine.SetQuirk(LauncherHideMachine::LAST_ACTION_ACTIVATE, true);
01310 }
01311 
01312 void Launcher::SetHidden(bool hidden)
01313 {
01314   if (hidden == _hidden)
01315     return;
01316 
01317   _hidden = hidden;
01318   _hide_machine.SetQuirk(LauncherHideMachine::LAUNCHER_HIDDEN, hidden);
01319   _hover_machine.SetQuirk(LauncherHoverMachine::LAUNCHER_HIDDEN, hidden);
01320 
01321   _hide_machine.SetQuirk(LauncherHideMachine::LAST_ACTION_ACTIVATE, false);
01322 
01323   if (hidden)
01324   {
01325     _hide_machine.SetQuirk(LauncherHideMachine::MOUSE_MOVE_POST_REVEAL, false);
01326     _hide_machine.SetQuirk(LauncherHideMachine::MT_DRAG_OUT, false);
01327     SetStateMouseOverLauncher(false);
01328   }
01329 
01330   _postreveal_mousemove_delta_x = 0;
01331   _postreveal_mousemove_delta_y = 0;
01332 
01333   TimeUtil::SetTimeStruct(&_times[TIME_AUTOHIDE], &_times[TIME_AUTOHIDE], ANIM_DURATION_SHORT);
01334 
01335   _parent->EnableInputWindow(!hidden, launcher::window_title, false, false);
01336 
01337   if (!hidden && GetActionState() == ACTION_DRAG_EXTERNAL)
01338     DndReset();
01339 
01340   EnsureAnimation();
01341 
01342   hidden_changed.emit();
01343 }
01344 
01345 int Launcher::GetMouseX() const
01346 {
01347   return _mouse_position.x;
01348 }
01349 
01350 int Launcher::GetMouseY() const
01351 {
01352   return _mouse_position.y;
01353 }
01354 
01355 bool Launcher::OnUpdateDragManagerTimeout()
01356 {
01357   if (display() == 0)
01358     return false;
01359 
01360   if (!_selection_atom)
01361     _selection_atom = XInternAtom(display(), "XdndSelection", false);
01362 
01363   Window drag_owner = XGetSelectionOwner(display(), _selection_atom);
01364 
01365   // evil hack because Qt does not release the seelction owner on drag finished
01366   Window root_r, child_r;
01367   int root_x_r, root_y_r, win_x_r, win_y_r;
01368   unsigned int mask;
01369   XQueryPointer(display(), DefaultRootWindow(display()), &root_r, &child_r, &root_x_r, &root_y_r, &win_x_r, &win_y_r, &mask);
01370 
01371   if (drag_owner && (mask & (Button1Mask | Button2Mask | Button3Mask)))
01372   {
01373     if (_data_checked == false)
01374     {
01375       _data_checked = true;
01376       _collection_window->Collect();
01377     }
01378 
01379     return true;
01380   }
01381 
01382   _data_checked = false;
01383   _collection_window->PushToBack();
01384   _collection_window->EnableInputWindow(false, "DNDCollectionWindow");
01385 
01386   if (IsOverlayOpen() && !_hovered)
01387     DesaturateIcons();
01388 
01389   DndReset();
01390   _hide_machine.SetQuirk(LauncherHideMachine::EXTERNAL_DND_ACTIVE, false);
01391   _hide_machine.SetQuirk(LauncherHideMachine::DND_PUSHED_OFF, false);
01392 
01393   return false;
01394 }
01395 
01396 void Launcher::DndTimeoutSetup()
01397 {
01398   if (sources_.GetSource(DND_CHECK_TIMEOUT))
01399     return;
01400 
01401   auto timeout = std::make_shared<glib::Timeout>(200);
01402   sources_.Add(timeout, DND_CHECK_TIMEOUT);
01403   timeout->Run(sigc::mem_fun(this, &Launcher::OnUpdateDragManagerTimeout));
01404 }
01405 
01406 void Launcher::OnWindowMapped(guint32 xid)
01407 {
01408   //CompWindow* window = _screen->findWindow(xid);
01409   //if (window && window->type() | CompWindowTypeDndMask)
01410   //{
01411     DndTimeoutSetup();
01412   //}
01413 
01414   if (GetActionState() != ACTION_NONE)
01415     ResetMouseDragState();
01416 }
01417 
01418 void Launcher::OnWindowUnmapped(guint32 xid)
01419 {
01420   //CompWindow* window = _screen->findWindow(xid);
01421   //if (window && window->type() | CompWindowTypeDndMask)
01422   //{
01423     DndTimeoutSetup();
01424   //}
01425 }
01426 
01427 void Launcher::OnPluginStateChanged()
01428 {
01429   _hide_machine.SetQuirk (LauncherHideMachine::EXPO_ACTIVE, WindowManager::Default ()->IsExpoActive ());
01430   _hide_machine.SetQuirk (LauncherHideMachine::SCALE_ACTIVE, WindowManager::Default ()->IsScaleActive ());
01431 }
01432 
01433 LauncherHideMode Launcher::GetHideMode() const
01434 {
01435   return options()->hide_mode;
01436 }
01437 
01438 /* End Launcher Show/Hide logic */
01439 
01440 // Hacks around compiz failing to see the struts because the window was just mapped.
01441 bool Launcher::StrutHack()
01442 {
01443   _parent->InputWindowEnableStruts(false);
01444 
01445   if (options()->hide_mode == LAUNCHER_HIDE_NEVER)
01446     _parent->InputWindowEnableStruts(true);
01447 
01448   return false;
01449 }
01450 
01451 void Launcher::OnOptionsChanged(Options::Ptr options)
01452 {
01453    UpdateOptions(options);
01454 
01455    options->option_changed.connect(sigc::mem_fun(this, &Launcher::OnOptionChanged));
01456 }
01457 
01458 void Launcher::OnOptionChanged()
01459 {
01460   UpdateOptions(options());
01461 }
01462 
01463 void Launcher::UpdateOptions(Options::Ptr options)
01464 {
01465   SetHideMode(options->hide_mode);
01466   SetIconSize(options->tile_size, options->icon_size);
01467 
01468   ConfigureBarrier();
01469   EnsureAnimation();
01470 }
01471 
01472 void Launcher::ConfigureBarrier()
01473 {
01474   nux::Geometry geo = GetAbsoluteGeometry();
01475 
01476   float decay_responsiveness_mult = ((options()->edge_responsiveness() - 1) * .3f) + 1;
01477   float reveal_responsiveness_mult = ((options()->edge_responsiveness() - 1) * .025f) + 1;
01478 
01479   _hide_machine.reveal_pressure = options()->edge_reveal_pressure() * reveal_responsiveness_mult;
01480   _hide_machine.edge_decay_rate = options()->edge_decay_rate() * decay_responsiveness_mult;
01481 }
01482 
01483 void Launcher::SetHideMode(LauncherHideMode hidemode)
01484 {
01485   if (hidemode != LAUNCHER_HIDE_NEVER)
01486   {
01487     _parent->InputWindowEnableStruts(false);
01488   }
01489   else
01490   {
01491     _parent->EnableInputWindow(true, launcher::window_title, false, false);
01492 
01493     if (!sources_.GetSource(STRUT_HACK_TIMEOUT))
01494     {
01495       auto timeout = std::make_shared<glib::Timeout>(1000, sigc::mem_fun(this, &Launcher::StrutHack));
01496       sources_.Add(timeout, STRUT_HACK_TIMEOUT);
01497     }
01498 
01499     _parent->InputWindowEnableStruts(true);
01500   }
01501 
01502   _hide_machine.SetMode((LauncherHideMachine::HideMode) hidemode);
01503   EnsureAnimation();
01504 }
01505 
01506 BacklightMode Launcher::GetBacklightMode() const
01507 {
01508   return options()->backlight_mode();
01509 }
01510 
01511 bool Launcher::IsBackLightModeToggles() const
01512 {
01513   switch (options()->backlight_mode()) {
01514     case BACKLIGHT_NORMAL:
01515     case BACKLIGHT_EDGE_TOGGLE:
01516     case BACKLIGHT_NORMAL_EDGE_TOGGLE:
01517       return true;
01518     default:
01519       return false;
01520   }
01521 }
01522 
01523 nux::ObjectPtr<nux::View> Launcher::GetActiveTooltip() const
01524 {
01525   return _active_tooltip;
01526 }
01527 
01528 void Launcher::SetActionState(LauncherActionState actionstate)
01529 {
01530   if (_launcher_action_state == actionstate)
01531     return;
01532 
01533   _launcher_action_state = actionstate;
01534 
01535   _hover_machine.SetQuirk(LauncherHoverMachine::LAUNCHER_IN_ACTION, (actionstate != ACTION_NONE));
01536 }
01537 
01538 Launcher::LauncherActionState
01539 Launcher::GetActionState() const
01540 {
01541   return _launcher_action_state;
01542 }
01543 
01544 void Launcher::SetHover(bool hovered)
01545 {
01546 
01547   if (hovered == _hovered)
01548     return;
01549 
01550   _hovered = hovered;
01551 
01552   if (_hovered)
01553   {
01554     _enter_y = (int) _mouse_position.y;
01555     TimeUtil::SetTimeStruct(&_times[TIME_ENTER], &_times[TIME_LEAVE], ANIM_DURATION);
01556   }
01557   else
01558   {
01559     TimeUtil::SetTimeStruct(&_times[TIME_LEAVE], &_times[TIME_ENTER], ANIM_DURATION);
01560   }
01561 
01562   if (IsOverlayOpen() && !_hide_machine.GetQuirk(LauncherHideMachine::EXTERNAL_DND_ACTIVE))
01563   {
01564     if (hovered && !_hover_machine.GetQuirk(LauncherHoverMachine::SHORTCUT_KEYS_VISIBLE))
01565       SaturateIcons();
01566     else
01567       DesaturateIcons();
01568   }
01569 
01570   EnsureAnimation();
01571 }
01572 
01573 bool Launcher::MouseOverTopScrollArea()
01574 {
01575   return _mouse_position.y < panel::Style::Instance().panel_height;
01576 }
01577 
01578 bool Launcher::MouseOverTopScrollExtrema()
01579 {
01580   return _mouse_position.y == 0;
01581 }
01582 
01583 bool Launcher::MouseOverBottomScrollArea()
01584 {
01585   return _mouse_position.y > GetGeometry().height - panel::Style::Instance().panel_height;
01586 }
01587 
01588 bool Launcher::MouseOverBottomScrollExtrema()
01589 {
01590   return _mouse_position.y == GetGeometry().height - 1;
01591 }
01592 
01593 bool Launcher::OnScrollTimeout()
01594 {
01595   bool continue_animation = true;
01596 
01597   //
01598   // Always check _scroll_limit_reached to ensure we don't keep spinning
01599   // this timer if the mouse happens to be left idle over one of the autoscroll
01600   // hotspots on the launcher.
01601   //
01602   if (IsInKeyNavMode() || !_hovered || _scroll_limit_reached ||
01603       GetActionState() == ACTION_DRAG_LAUNCHER)
01604   {
01605     continue_animation = false;
01606   }
01607   else if (MouseOverTopScrollArea())
01608   {
01609     if (MouseOverTopScrollExtrema())
01610       _launcher_drag_delta += 6;
01611     else
01612       _launcher_drag_delta += 3;
01613   }
01614   else if (MouseOverBottomScrollArea())
01615   {
01616     if (MouseOverBottomScrollExtrema())
01617       _launcher_drag_delta -= 6;
01618     else
01619       _launcher_drag_delta -= 3;
01620   }
01621   else
01622   {
01623     continue_animation = false;
01624   }
01625 
01626   if (continue_animation)
01627   {
01628     EnsureAnimation();
01629   }
01630   else
01631   {
01632     _scroll_limit_reached = false;
01633   }
01634 
01635   return continue_animation;
01636 }
01637 
01638 void Launcher::EnsureScrollTimer()
01639 {
01640   bool needed = MouseOverTopScrollArea() || MouseOverBottomScrollArea();
01641 
01642   if (needed && !sources_.GetSource(SCROLL_TIMEOUT))
01643   {
01644     auto timeout = std::make_shared<glib::Timeout>(20, sigc::mem_fun(this, &Launcher::OnScrollTimeout));
01645     sources_.Add(timeout, SCROLL_TIMEOUT);
01646   }
01647   else if (!needed)
01648   {
01649     sources_.Remove(SCROLL_TIMEOUT);
01650   }
01651 }
01652 
01653 void Launcher::SetIconSize(int tile_size, int icon_size)
01654 {
01655   _icon_size = tile_size;
01656   _icon_image_size = icon_size;
01657   _icon_image_size_delta = tile_size - icon_size;
01658   _icon_glow_size = icon_size + 14;
01659 
01660   icon_renderer->SetTargetSize(_icon_size, _icon_image_size, _space_between_icons);
01661 
01662   Resize();
01663 }
01664 
01665 int Launcher::GetIconSize() const
01666 {
01667     return _icon_size;
01668 }
01669 
01670 void Launcher::Resize()
01671 {
01672   UScreen* uscreen = UScreen::GetDefault();
01673   auto geo = uscreen->GetMonitorGeometry(monitor());
01674   unity::panel::Style &panel_style = panel::Style::Instance();
01675   int width = _icon_size + ICON_PADDING*2 + RIGHT_LINE_WIDTH - 2;
01676   nux::Geometry new_geometry(geo.x, geo.y + panel_style.panel_height, width, geo.height - panel_style.panel_height);
01677   SetMaximumHeight(new_geometry.height);
01678   _parent->SetGeometry(new_geometry);
01679   SetGeometry(nux::Geometry(0, 0, new_geometry.width, new_geometry.height));
01680 
01681   ConfigureBarrier();
01682 }
01683 
01684 void Launcher::OnIconAdded(AbstractLauncherIcon::Ptr icon)
01685 {
01686   EnsureAnimation();
01687 
01688   icon->needs_redraw.connect(sigc::mem_fun(this, &Launcher::OnIconNeedsRedraw));
01689   icon->tooltip_visible.connect(sigc::mem_fun(this, &Launcher::OnTooltipVisible));
01690 }
01691 
01692 void Launcher::OnIconRemoved(AbstractLauncherIcon::Ptr icon)
01693 {
01694   if (icon->needs_redraw_connection.connected())
01695     icon->needs_redraw_connection.disconnect();
01696 
01697   if (icon == _icon_under_mouse)
01698     _icon_under_mouse = nullptr;
01699   if (icon == _icon_mouse_down)
01700     _icon_mouse_down = nullptr;
01701   if (icon == _drag_icon)
01702     _drag_icon = nullptr;
01703 
01704   EnsureAnimation();
01705 }
01706 
01707 void Launcher::OnOrderChanged()
01708 {
01709   EnsureAnimation();
01710 }
01711 
01712 void Launcher::SetModel(LauncherModel::Ptr model)
01713 {
01714   _model = model;
01715 
01716   for (auto icon : *_model)
01717     icon->needs_redraw.connect(sigc::mem_fun(this, &Launcher::OnIconNeedsRedraw));
01718 
01719   _model->icon_added.connect(sigc::mem_fun(this, &Launcher::OnIconAdded));
01720   _model->icon_removed.connect(sigc::mem_fun(this, &Launcher::OnIconRemoved));
01721   _model->order_changed.connect(sigc::mem_fun(this, &Launcher::OnOrderChanged));
01722   _model->selection_changed.connect(sigc::mem_fun(this, &Launcher::OnSelectionChanged));
01723 }
01724 
01725 LauncherModel::Ptr Launcher::GetModel() const
01726 {
01727   return _model;
01728 }
01729 
01730 void Launcher::EnsureIconOnScreen(AbstractLauncherIcon::Ptr selection)
01731 {
01732   nux::Geometry const& geo = GetGeometry();
01733 
01734   int natural_y = 0;
01735   for (auto icon : *_model)
01736   {
01737     if (!icon->GetQuirk(AbstractLauncherIcon::QUIRK_VISIBLE) || !icon->IsVisibleOnMonitor(monitor))
01738       continue;
01739 
01740     if (icon == selection)
01741       break;
01742 
01743     natural_y += _icon_size + _space_between_icons;
01744   }
01745 
01746   int max_drag_delta = geo.height - (natural_y + _icon_size + (2 * _space_between_icons));
01747   int min_drag_delta = -natural_y;
01748 
01749   _launcher_drag_delta = std::max<int>(min_drag_delta, std::min<int>(max_drag_delta, _launcher_drag_delta));
01750 }
01751 
01752 void Launcher::OnSelectionChanged(AbstractLauncherIcon::Ptr selection)
01753 {
01754   if (IsInKeyNavMode())
01755   {
01756     EnsureIconOnScreen(selection);
01757     EnsureAnimation();
01758   }
01759 }
01760 
01761 void Launcher::OnIconNeedsRedraw(AbstractLauncherIcon::Ptr icon)
01762 {
01763   EnsureAnimation();
01764 }
01765 
01766 void Launcher::OnTooltipVisible(nux::ObjectPtr<nux::View> view)
01767 {
01768   _active_tooltip = view;
01769 }
01770 
01771 void Launcher::Draw(nux::GraphicsEngine& GfxContext, bool force_draw)
01772 {
01773 
01774 }
01775 
01776 void Launcher::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw)
01777 {
01778   icon_renderer->monitor = monitor();
01779 
01780   nux::Geometry const& base = GetGeometry();
01781   nux::Geometry bkg_box;
01782   std::list<RenderArg> args;
01783   std::list<RenderArg>::reverse_iterator rev_it;
01784   float launcher_alpha = 1.0f;
01785 
01786   // rely on the compiz event loop to come back to us in a nice throttling
01787   if (AnimationInProgress())
01788   {
01789     auto idle = std::make_shared<glib::Idle>(glib::Source::Priority::DEFAULT);
01790     sources_.Add(idle, ANIMATION_IDLE);
01791     idle->Run([&]() {
01792       EnsureAnimation();
01793       return false;
01794     });
01795   }
01796 
01797   nux::ROPConfig ROP;
01798   ROP.Blend = false;
01799   ROP.SrcBlend = GL_ONE;
01800   ROP.DstBlend = GL_ONE_MINUS_SRC_ALPHA;
01801 
01802   nux::Geometry const& geo_absolute = GetAbsoluteGeometry();
01803   RenderArgs(args, bkg_box, &launcher_alpha, geo_absolute);
01804   bkg_box.width -= RIGHT_LINE_WIDTH;
01805 
01806   if (_drag_icon && _render_drag_window)
01807   {
01808     RenderIconToTexture(GfxContext, _drag_icon, _offscreen_drag_texture);
01809     _drag_window->ShowWindow(true);
01810 
01811     _render_drag_window = false;
01812   }
01813 
01814   // clear region
01815   GfxContext.PushClippingRectangle(base);
01816   gPainter.PushDrawColorLayer(GfxContext, base, nux::Color(0x00000000), true, ROP);
01817 
01818   GfxContext.GetRenderStates().SetBlend(true);
01819   GfxContext.GetRenderStates().SetPremultipliedBlend(nux::SRC_OVER);
01820   GfxContext.GetRenderStates().SetColorMask(true, true, true, true);
01821 
01822   int push_count = 1;
01823 
01824   // clip vertically but not horizontally
01825   GfxContext.PushClippingRectangle(nux::Geometry(base.x, bkg_box.y, base.width, bkg_box.height));
01826 
01827   float reveal_progress = _hide_machine.reveal_progress;
01828   if ((reveal_progress > 0 || _last_reveal_progress > 0) && launcher_pressure_effect_.IsValid())
01829   {
01830     if (std::abs(_last_reveal_progress - reveal_progress) <= .1f)
01831     {
01832       _last_reveal_progress = reveal_progress;
01833     }
01834     else
01835     {
01836       if (_last_reveal_progress > reveal_progress)
01837         _last_reveal_progress -= .1f;
01838       else
01839         _last_reveal_progress += .1f;
01840     }
01841     nux::Color pressure_color = nux::color::White * _last_reveal_progress;
01842     nux::TexCoordXForm texxform_pressure;
01843     GfxContext.QRP_1Tex(base.x, base.y, launcher_pressure_effect_->GetWidth(), base.height,
01844                         launcher_pressure_effect_->GetDeviceTexture(),
01845                         texxform_pressure,
01846                         pressure_color);
01847   }
01848 
01849   if (IsOverlayOpen())
01850   {
01851     nux::Geometry blur_geo(geo_absolute.x, geo_absolute.y, base.width, base.height);
01852     nux::ObjectPtr<nux::IOpenGLBaseTexture> blur_texture;
01853 
01854     if (BackgroundEffectHelper::blur_type != unity::BLUR_NONE && (bkg_box.x + bkg_box.width > 0))
01855     {
01856       blur_texture = bg_effect_helper_.GetBlurRegion(blur_geo);
01857     }
01858     else
01859     {
01860       blur_texture = bg_effect_helper_.GetRegion(blur_geo);
01861     }
01862 
01863     if (blur_texture.IsValid())
01864     {
01865       nux::TexCoordXForm texxform_blur_bg;
01866       texxform_blur_bg.flip_v_coord = true;
01867       texxform_blur_bg.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD);
01868       texxform_blur_bg.uoffset = ((float) base.x) / geo_absolute.width;
01869       texxform_blur_bg.voffset = ((float) base.y) / geo_absolute.height;
01870 
01871       GfxContext.PushClippingRectangle(bkg_box);
01872 
01873 #ifndef NUX_OPENGLES_20
01874       if (GfxContext.UsingGLSLCodePath())
01875         gPainter.PushDrawCompositionLayer(GfxContext, base,
01876                                           blur_texture,
01877                                           texxform_blur_bg,
01878                                           nux::color::White,
01879                                           _background_color, nux::LAYER_BLEND_MODE_OVERLAY,
01880                                           true, ROP);
01881       else
01882         gPainter.PushDrawTextureLayer(GfxContext, base,
01883                                       blur_texture,
01884                                       texxform_blur_bg,
01885                                       nux::color::White,
01886                                       true,
01887                                       ROP);
01888 #else
01889         gPainter.PushDrawCompositionLayer(GfxContext, base,
01890                                           blur_texture,
01891                                           texxform_blur_bg,
01892                                           nux::color::White,
01893                                           _background_color, nux::LAYER_BLEND_MODE_OVERLAY,
01894                                           true, ROP);
01895 #endif
01896       GfxContext.PopClippingRectangle();
01897 
01898       push_count++;
01899     }
01900 
01901     unsigned int alpha = 0, src = 0, dest = 0;
01902     GfxContext.GetRenderStates().GetBlend(alpha, src, dest);
01903 
01904     // apply the darkening
01905     GfxContext.GetRenderStates().SetBlend(true, GL_ZERO, GL_SRC_COLOR);
01906     gPainter.Paint2DQuadColor(GfxContext, bkg_box, nux::Color(0.9f, 0.9f, 0.9f, 1.0f));
01907     GfxContext.GetRenderStates().SetBlend (alpha, src, dest);
01908 
01909     // apply the bg colour
01910 #ifndef NUX_OPENGLES_20
01911     if (GfxContext.UsingGLSLCodePath() == false)
01912       gPainter.Paint2DQuadColor(GfxContext, bkg_box, _background_color);
01913 #endif
01914 
01915     // apply the shine
01916     GfxContext.GetRenderStates().SetBlend(true, GL_DST_COLOR, GL_ONE);
01917     nux::TexCoordXForm texxform;
01918     texxform.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD);
01919     texxform.SetWrap(nux::TEXWRAP_CLAMP, nux::TEXWRAP_CLAMP);
01920     texxform.uoffset = (1.0f / launcher_sheen_->GetWidth()); // TODO (gord) don't use absolute values here
01921     texxform.voffset = (1.0f / launcher_sheen_->GetHeight()) * panel::Style::Instance().panel_height;
01922     GfxContext.QRP_1Tex(base.x, base.y, base.width, base.height,
01923                         launcher_sheen_->GetDeviceTexture(),
01924                         texxform,
01925                         nux::color::White);
01926 
01927     //reset the blend state
01928     GfxContext.GetRenderStates().SetBlend (alpha, src, dest);
01929   }
01930   else
01931   {
01932     nux::Color color = _background_color;
01933     color.alpha = options()->background_alpha;
01934     gPainter.Paint2DQuadColor(GfxContext, bkg_box, color);
01935   }
01936 
01937   GfxContext.GetRenderStates().SetPremultipliedBlend(nux::SRC_OVER);
01938 
01939   icon_renderer->PreprocessIcons(args, base);
01940   EventLogic();
01941 
01942   /* draw launcher */
01943   for (rev_it = args.rbegin(); rev_it != args.rend(); rev_it++)
01944   {
01945     if ((*rev_it).stick_thingy)
01946       gPainter.Paint2DQuadColor(GfxContext,
01947                                 nux::Geometry(bkg_box.x, (*rev_it).render_center.y - 3, bkg_box.width, 2),
01948                                 nux::Color(0xAAAAAAAA));
01949 
01950     if ((*rev_it).skip)
01951       continue;
01952 
01953     icon_renderer->RenderIcon(GfxContext, *rev_it, bkg_box, base);
01954   }
01955 
01956   if (!IsOverlayOpen())
01957   {
01958     const double right_line_opacity = 0.15f * launcher_alpha;
01959 
01960     gPainter.Paint2DQuadColor(GfxContext,
01961                               nux::Geometry(bkg_box.x + bkg_box.width,
01962                                             bkg_box.y,
01963                                             RIGHT_LINE_WIDTH,
01964                                             bkg_box.height),
01965                               nux::color::White * right_line_opacity);
01966 
01967     gPainter.Paint2DQuadColor(GfxContext,
01968                               nux::Geometry(bkg_box.x,
01969                                             bkg_box.y,
01970                                             bkg_box.width,
01971                                             8),
01972                               nux::Color(0x70000000),
01973                               nux::Color(0x00000000),
01974                               nux::Color(0x00000000),
01975                               nux::Color(0x70000000));
01976   }
01977 
01978   // FIXME: can be removed for a bgk_box->SetAlpha once implemented
01979   GfxContext.GetRenderStates().SetPremultipliedBlend(nux::DST_IN);
01980   nux::Color alpha_mask = nux::Color(0xFFAAAAAA) * launcher_alpha;
01981   gPainter.Paint2DQuadColor(GfxContext, bkg_box, alpha_mask);
01982 
01983   GfxContext.GetRenderStates().SetColorMask(true, true, true, true);
01984   GfxContext.GetRenderStates().SetPremultipliedBlend(nux::SRC_OVER);
01985 
01986   gPainter.PopBackground(push_count);
01987   GfxContext.PopClippingRectangle();
01988   GfxContext.PopClippingRectangle();
01989 }
01990 
01991 void Launcher::PostDraw(nux::GraphicsEngine& GfxContext, bool force_draw)
01992 {
01993 }
01994 
01995 long Launcher::PostLayoutManagement(long LayoutResult)
01996 {
01997   View::PostLayoutManagement(LayoutResult);
01998 
01999   SetMousePosition(0, 0);
02000 
02001   return nux::eCompliantHeight | nux::eCompliantWidth;
02002 }
02003 
02004 void Launcher::OnDragWindowAnimCompleted()
02005 {
02006   if (_drag_window)
02007     _drag_window->ShowWindow(false);
02008 
02009   EnsureAnimation();
02010 }
02011 
02012 bool Launcher::StartIconDragTimeout()
02013 {
02014   // if we are still waiting…
02015   if (GetActionState() == ACTION_NONE)
02016   {
02017     if (_icon_under_mouse)
02018     {
02019       _icon_under_mouse->mouse_leave.emit(monitor);
02020       _icon_under_mouse = nullptr;
02021     }
02022     _initial_drag_animation = true;
02023     StartIconDragRequest(GetMouseX(), GetMouseY());
02024   }
02025 
02026   return false;
02027 }
02028 
02029 void Launcher::StartIconDragRequest(int x, int y)
02030 {
02031   nux::Geometry geo = GetAbsoluteGeometry();
02032   AbstractLauncherIcon::Ptr drag_icon = MouseIconIntersection((int)(GetGeometry().width / 2.0f), y);
02033 
02034   x += geo.x;
02035   y += geo.y;
02036 
02037 
02038   // FIXME: nux doesn't give nux::GetEventButton (button_flags) there, relying
02039   // on an internal Launcher property then
02040   if (drag_icon && (_last_button_press == 1) && _model->IconHasSister(drag_icon))
02041   {
02042     SetActionState(ACTION_DRAG_ICON);
02043     StartIconDrag(drag_icon);
02044     UpdateDragWindowPosition(drag_icon->GetCenter(monitor).x, drag_icon->GetCenter(monitor).y);
02045     if (_initial_drag_animation)
02046     {
02047       _drag_window->SetAnimationTarget(x, y);
02048       _drag_window->StartAnimation();
02049     }
02050     EnsureAnimation();
02051   }
02052   else
02053   {
02054     _drag_icon = NULL;
02055     if (_drag_window)
02056     {
02057       _drag_window->ShowWindow(false);
02058       _drag_window = nullptr;
02059     }
02060   }
02061 }
02062 
02063 void Launcher::StartIconDrag(AbstractLauncherIcon::Ptr icon)
02064 {
02065   if (!icon)
02066     return;
02067 
02068   _hide_machine.SetQuirk(LauncherHideMachine::INTERNAL_DND_ACTIVE, true);
02069   _drag_icon = icon;
02070 
02071   if (_drag_window)
02072   {
02073     _drag_window->ShowWindow(false);
02074   }
02075 
02076   _offscreen_drag_texture = nux::GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(_icon_size, _icon_size, 1, nux::BITFMT_R8G8B8A8);
02077   _drag_window = new LauncherDragWindow(_offscreen_drag_texture);
02078 
02079   _render_drag_window = true;
02080 
02081   ubus_.SendMessage(UBUS_LAUNCHER_ICON_START_DND);
02082 }
02083 
02084 void Launcher::EndIconDrag()
02085 {
02086   if (_drag_window)
02087   {
02088     AbstractLauncherIcon::Ptr hovered_icon = MouseIconIntersection(_mouse_position.x, _mouse_position.y);
02089 
02090     if (hovered_icon && hovered_icon->GetIconType() == AbstractLauncherIcon::TYPE_TRASH)
02091     {
02092       hovered_icon->SetQuirk(AbstractLauncherIcon::QUIRK_PULSE_ONCE, true);
02093 
02094       launcher_removerequest.emit(_drag_icon);
02095 
02096       _drag_window->ShowWindow(false);
02097       EnsureAnimation();
02098     }
02099     else
02100     {
02101       _model->Save();
02102 
02103       _drag_window->SetAnimationTarget((int)(_drag_icon->GetCenter(monitor).x),
02104                                        (int)(_drag_icon->GetCenter(monitor).y));
02105       _drag_window->StartAnimation();
02106 
02107       if (_drag_window->on_anim_completed.connected())
02108         _drag_window->on_anim_completed.disconnect();
02109       _drag_window->on_anim_completed = _drag_window->anim_completed.connect(sigc::mem_fun(this, &Launcher::OnDragWindowAnimCompleted));
02110     }
02111   }
02112 
02113   if (MouseBeyondDragThreshold())
02114     TimeUtil::SetTimeStruct(&_times[TIME_DRAG_THRESHOLD], &_times[TIME_DRAG_THRESHOLD], ANIM_DURATION_SHORT);
02115 
02116   _render_drag_window = false;
02117 
02118   _hide_machine.SetQuirk(LauncherHideMachine::INTERNAL_DND_ACTIVE, false);
02119   ubus_.SendMessage(UBUS_LAUNCHER_ICON_END_DND);
02120 }
02121 
02122 void Launcher::UpdateDragWindowPosition(int x, int y)
02123 {
02124   if (_drag_window)
02125   {
02126     nux::Geometry const& geo = _drag_window->GetGeometry();
02127     _drag_window->SetBaseXY(x - geo.width / 2, y - geo.height / 2);
02128 
02129     AbstractLauncherIcon::Ptr hovered_icon = MouseIconIntersection((int)((GetGeometry().x + GetGeometry().width) / 2.0f), y - GetAbsoluteGeometry().y);
02130 
02131     struct timespec current;
02132     clock_gettime(CLOCK_MONOTONIC, &current);
02133     if (_drag_icon && hovered_icon && _drag_icon != hovered_icon)
02134     {
02135       float progress = DragThresholdProgress(current);
02136 
02137       if (progress >= 1.0f)
02138         _model->ReorderSmart(_drag_icon, hovered_icon, true);
02139       else if (progress == 0.0f) {
02140         if (_drag_icon->GetIconType() == hovered_icon->GetIconType()) {
02141           _model->ReorderBefore(_drag_icon, hovered_icon, false);
02142         } else {
02143           // LauncherModel::ReorderBefore does not work on different icon types
02144           // so if hovered_icon is of a different type than _drag_icon
02145           // try to use LauncherModel::ReorderAfter with the icon that is before hovered_icon
02146           AbstractLauncherIcon::Ptr iconBeforeHover;
02147           LauncherModel::iterator it;
02148           LauncherModel::iterator prevIt = _model->end();
02149           for (it = _model->begin(); it != _model->end(); it++)
02150           {
02151             if (!(*it)->GetQuirk(AbstractLauncherIcon::QUIRK_VISIBLE) || !(*it)->IsVisibleOnMonitor(monitor))
02152               continue;
02153 
02154             if ((*it) == hovered_icon) {
02155               if (prevIt != _model->end()) {
02156                 iconBeforeHover = *prevIt;
02157               }
02158               break;
02159             }
02160 
02161             prevIt = it;
02162           }
02163 
02164           if (iconBeforeHover && _drag_icon != iconBeforeHover) {
02165             _model->ReorderAfter(_drag_icon, iconBeforeHover);
02166           }
02167         }
02168       }
02169     }
02170   }
02171 }
02172 
02173 void Launcher::ResetMouseDragState()
02174 {
02175   if (GetActionState() == ACTION_DRAG_ICON)
02176     EndIconDrag();
02177 
02178   if (GetActionState() == ACTION_DRAG_LAUNCHER)
02179     _hide_machine.SetQuirk(LauncherHideMachine::VERTICAL_SLIDE_ACTIVE, false);
02180 
02181   SetActionState(ACTION_NONE);
02182   _dnd_delta_x = 0;
02183   _dnd_delta_y = 0;
02184   _last_button_press = 0;
02185   EnsureAnimation();
02186 }
02187 
02188 void Launcher::RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags)
02189 {
02190   _last_button_press = nux::GetEventButton(button_flags);
02191   SetMousePosition(x, y);
02192 
02193   MouseDownLogic(x, y, button_flags, key_flags);
02194   EnsureAnimation();
02195 }
02196 
02197 void Launcher::RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags)
02198 {
02199   SetMousePosition(x, y);
02200 
02201   MouseUpLogic(x, y, button_flags, key_flags);
02202   ResetMouseDragState();
02203 }
02204 
02205 void Launcher::RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags)
02206 {
02207   /* FIXME: nux doesn't give nux::GetEventButton (button_flags) there, relying
02208    * on an internal Launcher property then
02209    */
02210 
02211   if (_last_button_press != 1)
02212     return;
02213 
02214   SetMousePosition(x, y);
02215 
02216   // FIXME: hack (see SetupRenderArg)
02217   _initial_drag_animation = false;
02218 
02219   _dnd_delta_y += dy;
02220   _dnd_delta_x += dx;
02221 
02222   if (nux::Abs(_dnd_delta_y) < MOUSE_DEADZONE &&
02223       nux::Abs(_dnd_delta_x) < MOUSE_DEADZONE &&
02224       GetActionState() == ACTION_NONE)
02225     return;
02226 
02227   if (_icon_under_mouse)
02228   {
02229     _icon_under_mouse->mouse_leave.emit(monitor);
02230     _icon_under_mouse = nullptr;
02231   }
02232 
02233   if (GetActionState() == ACTION_NONE)
02234   {
02235     if (nux::Abs(_dnd_delta_y) >= nux::Abs(_dnd_delta_x))
02236     {
02237       _launcher_drag_delta += _dnd_delta_y;
02238       SetActionState(ACTION_DRAG_LAUNCHER);
02239       _hide_machine.SetQuirk(LauncherHideMachine::VERTICAL_SLIDE_ACTIVE, true);
02240     }
02241     else
02242     {
02243       StartIconDragRequest(x, y);
02244     }
02245   }
02246   else if (GetActionState() == ACTION_DRAG_LAUNCHER)
02247   {
02248     _launcher_drag_delta += dy;
02249     ubus_.SendMessage(UBUS_LAUNCHER_END_DND);
02250   }
02251   else if (GetActionState() == ACTION_DRAG_ICON)
02252   {
02253     nux::Geometry geo = GetAbsoluteGeometry();
02254     UpdateDragWindowPosition(geo.x + x, geo.y + y);
02255   }
02256 
02257   EnsureAnimation();
02258 }
02259 
02260 void Launcher::RecvMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags)
02261 {
02262   SetMousePosition(x, y);
02263   SetStateMouseOverLauncher(true);
02264 
02265   EventLogic();
02266   EnsureAnimation();
02267 }
02268 
02269 void Launcher::RecvMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags)
02270 {
02271   SetMousePosition(x, y);
02272   SetStateMouseOverLauncher(false);
02273   //AbstractLauncherIcon::SetSkipTooltipDelay(false);
02274 
02275   EventLogic();
02276   EnsureAnimation();
02277 }
02278 
02279 void Launcher::RecvMouseMove(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags)
02280 {
02281   SetMousePosition(x, y);
02282 
02283   if (!_hidden)
02284   {
02285     _postreveal_mousemove_delta_x += dx;
02286     _postreveal_mousemove_delta_y += dy;
02287 
02288     // check the state before changing it to avoid uneeded hide calls
02289     if (!_hide_machine.GetQuirk(LauncherHideMachine::MOUSE_MOVE_POST_REVEAL) &&
02290         (nux::Abs(_postreveal_mousemove_delta_x) > MOUSE_DEADZONE ||
02291          nux::Abs(_postreveal_mousemove_delta_y) > MOUSE_DEADZONE))
02292       _hide_machine.SetQuirk(LauncherHideMachine::MOUSE_MOVE_POST_REVEAL, true);
02293   }
02294 
02295 
02296 
02297   // Every time the mouse moves, we check if it is inside an icon...
02298   EventLogic();
02299 }
02300 
02301 void Launcher::RecvMouseWheel(int x, int y, int wheel_delta, unsigned long button_flags, unsigned long key_flags)
02302 {
02303   if (!_hovered)
02304     return;
02305 
02306   if (wheel_delta < 0)
02307   {
02308     // scroll up
02309     _launcher_drag_delta -= 10;
02310   }
02311   else
02312   {
02313     // scroll down
02314     _launcher_drag_delta += 10;
02315   }
02316 
02317   EnsureAnimation();
02318 }
02319 
02320 bool Launcher::HandleBarrierEvent(ui::PointerBarrierWrapper* owner, ui::BarrierEvent::Ptr event)
02321 {
02322   nux::Geometry abs_geo = GetAbsoluteGeometry();
02323 
02324   bool apply_to_reveal = false;
02325   if (_hidden && event->x >= abs_geo.x && event->x <= abs_geo.x + abs_geo.width)
02326   {
02327     if (options()->reveal_trigger == RevealTrigger::EDGE)
02328     {
02329       if (event->y >= abs_geo.y)
02330         apply_to_reveal = true;
02331     }
02332     else if (options()->reveal_trigger == RevealTrigger::CORNER)
02333     {
02334       if (event->y < abs_geo.y)
02335         apply_to_reveal = true;
02336     }
02337   }
02338 
02339   if (apply_to_reveal)
02340   {
02341     int root_x_return, root_y_return, win_x_return, win_y_return;
02342     unsigned int mask_return;
02343     Window root_return, child_return;
02344     Display *dpy = nux::GetGraphicsDisplay()->GetX11Display();
02345 
02346     if (XQueryPointer (dpy, DefaultRootWindow(dpy), &root_return, &child_return, &root_x_return,
02347                        &root_y_return, &win_x_return, &win_y_return, &mask_return))
02348     {
02349       if (mask_return & (Button1Mask | Button3Mask))
02350         apply_to_reveal = false;
02351     }
02352   }
02353 
02354   if (!apply_to_reveal)
02355     return false;
02356 
02357   _hide_machine.AddRevealPressure(event->velocity);
02358   return true;
02359 }
02360 
02361 bool Launcher::IsInKeyNavMode() const
02362 {
02363   return _hide_machine.GetQuirk(LauncherHideMachine::KEY_NAV_ACTIVE);
02364 }
02365 
02366 void Launcher::EnterKeyNavMode()
02367 {
02368   _hide_machine.SetQuirk(LauncherHideMachine::KEY_NAV_ACTIVE, true);
02369   _hover_machine.SetQuirk(LauncherHoverMachine::KEY_NAV_ACTIVE, true);
02370   SaturateIcons();
02371 }
02372 
02373 void Launcher::ExitKeyNavMode()
02374 {
02375   _hide_machine.SetQuirk(LauncherHideMachine::KEY_NAV_ACTIVE, false);
02376   _hover_machine.SetQuirk(LauncherHoverMachine::KEY_NAV_ACTIVE, false);
02377 }
02378 
02379 void Launcher::RecvQuicklistOpened(QuicklistView* quicklist)
02380 {
02381   UScreen* uscreen = UScreen::GetDefault();
02382   if (uscreen->GetMonitorGeometry(monitor).IsInside(nux::Point(quicklist->GetGeometry().x, quicklist->GetGeometry().y)))
02383   {
02384     _hide_machine.SetQuirk(LauncherHideMachine::QUICKLIST_OPEN, true);
02385     _hover_machine.SetQuirk(LauncherHoverMachine::QUICKLIST_OPEN, true);
02386     EventLogic();
02387     EnsureAnimation();
02388   }
02389 }
02390 
02391 void Launcher::RecvQuicklistClosed(QuicklistView* quicklist)
02392 {
02393   nux::Point pt = nux::GetWindowCompositor().GetMousePosition();
02394   if (!GetAbsoluteGeometry().IsInside(pt))
02395   {
02396     // The Quicklist just closed and the mouse is outside the launcher.
02397     SetHover(false);
02398     SetStateMouseOverLauncher(false);
02399   }
02400   // Cancel any prior state that was set before the Quicklist appeared.
02401   SetActionState(ACTION_NONE);
02402 
02403   _hide_machine.SetQuirk(LauncherHideMachine::QUICKLIST_OPEN, false);
02404   _hover_machine.SetQuirk(LauncherHoverMachine::QUICKLIST_OPEN, false);
02405 
02406   EventLogic();
02407   EnsureAnimation();
02408 }
02409 
02410 void Launcher::EventLogic()
02411 {
02412   if (GetActionState() == ACTION_DRAG_ICON ||
02413       GetActionState() == ACTION_DRAG_LAUNCHER)
02414     return;
02415 
02416   AbstractLauncherIcon::Ptr launcher_icon;
02417 
02418   if (!_hidden && !IsInKeyNavMode() && _hovered)
02419   {
02420     launcher_icon = MouseIconIntersection(_mouse_position.x, _mouse_position.y);
02421   }
02422 
02423 
02424   if (_icon_under_mouse && (_icon_under_mouse != launcher_icon))
02425   {
02426     _icon_under_mouse->mouse_leave.emit(monitor);
02427     _icon_under_mouse = nullptr;
02428   }
02429 
02430   if (launcher_icon && (_icon_under_mouse != launcher_icon))
02431   {
02432     launcher_icon->mouse_enter.emit(monitor);
02433     _icon_under_mouse = launcher_icon;
02434 
02435     _hide_machine.SetQuirk(LauncherHideMachine::LAST_ACTION_ACTIVATE, false);
02436   }
02437 }
02438 
02439 void Launcher::MouseDownLogic(int x, int y, unsigned long button_flags, unsigned long key_flags)
02440 {
02441   AbstractLauncherIcon::Ptr launcher_icon;
02442   launcher_icon = MouseIconIntersection(_mouse_position.x, _mouse_position.y);
02443 
02444   _hide_machine.SetQuirk(LauncherHideMachine::LAST_ACTION_ACTIVATE, false);
02445 
02446   if (launcher_icon)
02447   {
02448     _icon_mouse_down = launcher_icon;
02449     // if MouseUp after the time ended -> it's an icon drag, otherwise, it's starting an app
02450     auto timeout = std::make_shared<glib::Timeout>(START_DRAGICON_DURATION);
02451     sources_.Add(timeout, START_DRAGICON_TIMEOUT);
02452     timeout->Run(sigc::mem_fun(this, &Launcher::StartIconDragTimeout));
02453 
02454     launcher_icon->mouse_down.emit(nux::GetEventButton(button_flags), monitor, key_flags);
02455   }
02456 }
02457 
02458 void Launcher::MouseUpLogic(int x, int y, unsigned long button_flags, unsigned long key_flags)
02459 {
02460   AbstractLauncherIcon::Ptr launcher_icon;
02461 
02462   launcher_icon = MouseIconIntersection(_mouse_position.x, _mouse_position.y);
02463 
02464   sources_.Remove(START_DRAGICON_TIMEOUT);
02465 
02466   if (_icon_mouse_down && (_icon_mouse_down == launcher_icon))
02467   {
02468     _icon_mouse_down->mouse_up.emit(nux::GetEventButton(button_flags), monitor, key_flags);
02469 
02470     if (GetActionState() == ACTION_NONE)
02471     {
02472       _icon_mouse_down->mouse_click.emit(nux::GetEventButton(button_flags), monitor, key_flags);
02473     }
02474   }
02475 
02476   if (launcher_icon && (_icon_mouse_down != launcher_icon))
02477   {
02478     launcher_icon->mouse_up.emit(nux::GetEventButton(button_flags), monitor, key_flags);
02479   }
02480 
02481   if (GetActionState() == ACTION_DRAG_LAUNCHER)
02482   {
02483     TimeUtil::SetTimeStruct(&_times[TIME_DRAG_END]);
02484   }
02485 
02486   _icon_mouse_down = nullptr;
02487 }
02488 
02489 AbstractLauncherIcon::Ptr Launcher::MouseIconIntersection(int x, int y)
02490 {
02491   LauncherModel::iterator it;
02492   // We are looking for the icon at screen coordinates x, y;
02493   nux::Point2 mouse_position(x, y);
02494   int inside = 0;
02495 
02496   for (it = _model->begin(); it != _model->end(); it++)
02497   {
02498     if (!(*it)->GetQuirk(AbstractLauncherIcon::QUIRK_VISIBLE) || !(*it)->IsVisibleOnMonitor(monitor))
02499       continue;
02500 
02501     nux::Point2 screen_coord [4];
02502     for (int i = 0; i < 4; ++i)
02503     {
02504       auto hit_transform = (*it)->GetTransform(AbstractLauncherIcon::TRANSFORM_HIT_AREA, monitor);
02505       screen_coord [i].x = hit_transform [i].x;
02506       screen_coord [i].y = hit_transform [i].y;
02507     }
02508     inside = PointInside2DPolygon(screen_coord, 4, mouse_position, 1);
02509     if (inside)
02510       return (*it);
02511   }
02512 
02513   return AbstractLauncherIcon::Ptr();
02514 }
02515 
02516 void Launcher::RenderIconToTexture(nux::GraphicsEngine& GfxContext, AbstractLauncherIcon::Ptr icon, nux::ObjectPtr<nux::IOpenGLBaseTexture> texture)
02517 {
02518   RenderArg arg;
02519   struct timespec current;
02520   clock_gettime(CLOCK_MONOTONIC, &current);
02521 
02522   SetupRenderArg(icon, current, arg);
02523   arg.render_center = nux::Point3(roundf(_icon_size / 2.0f), roundf(_icon_size / 2.0f), 0.0f);
02524   arg.logical_center = arg.render_center;
02525   arg.x_rotation = 0.0f;
02526   arg.running_arrow = false;
02527   arg.active_arrow = false;
02528   arg.skip = false;
02529   arg.window_indicators = 0;
02530   arg.alpha = 1.0f;
02531 
02532   std::list<RenderArg> drag_args;
02533   drag_args.push_front(arg);
02534 
02535   SetOffscreenRenderTarget(texture);
02536   icon_renderer->PreprocessIcons(drag_args, nux::Geometry(0, 0, _icon_size, _icon_size));
02537   icon_renderer->RenderIcon(nux::GetWindowThread()->GetGraphicsEngine(), arg, nux::Geometry(0, 0, _icon_size, _icon_size), nux::Geometry(0, 0, _icon_size, _icon_size));
02538   RestoreSystemRenderTarget();
02539 }
02540 
02541 void Launcher::SetOffscreenRenderTarget(nux::ObjectPtr<nux::IOpenGLBaseTexture> texture)
02542 {
02543   int width = texture->GetWidth();
02544   int height = texture->GetHeight();
02545 
02546   auto graphics_display = nux::GetGraphicsDisplay();
02547   auto gpu_device = graphics_display->GetGpuDevice();
02548   gpu_device->FormatFrameBufferObject(width, height, nux::BITFMT_R8G8B8A8);
02549   gpu_device->SetColorRenderTargetSurface(0, texture->GetSurfaceLevel(0));
02550   gpu_device->ActivateFrameBuffer();
02551 
02552   auto graphics_engine = graphics_display->GetGraphicsEngine();
02553   graphics_engine->SetContext(0, 0, width, height);
02554   graphics_engine->SetViewport(0, 0, width, height);
02555   graphics_engine->Push2DWindow(width, height);
02556   graphics_engine->EmptyClippingRegion();
02557 }
02558 
02559 void Launcher::RestoreSystemRenderTarget()
02560 {
02561   nux::GetWindowCompositor().RestoreRenderingSurface();
02562 }
02563 
02564 void Launcher::OnDNDDataCollected(const std::list<char*>& mimes)
02565 {
02566   _dnd_data.Reset();
02567 
02568   unity::glib::String uri_list_const(g_strdup("text/uri-list"));
02569 
02570   for (auto it : mimes)
02571   {
02572     if (!g_str_equal(it, uri_list_const.Value()))
02573       continue;
02574 
02575     _dnd_data.Fill(nux::GetWindowThread()->GetGraphicsDisplay().GetDndData(uri_list_const.Value()));
02576     break;
02577   }
02578 
02579   _hide_machine.SetQuirk(LauncherHideMachine::EXTERNAL_DND_ACTIVE, true);
02580 
02581   for (auto it : _dnd_data.Uris())
02582   {
02583     if (g_str_has_suffix(it.c_str(), ".desktop"))
02584     {
02585       _steal_drag = true;
02586       break;
02587     }
02588   }
02589 
02590   if (!_steal_drag)
02591   {
02592     for (auto it : *_model)
02593     {
02594       if (it->ShouldHighlightOnDrag(_dnd_data))
02595       {
02596         it->SetQuirk(AbstractLauncherIcon::QUIRK_DESAT, false);
02597         it->SetQuirk(AbstractLauncherIcon::QUIRK_DROP_PRELIGHT, true);
02598       }
02599       else
02600       {
02601         it->SetQuirk(AbstractLauncherIcon::QUIRK_DROP_DIM, true);
02602       }
02603     }
02604   }
02605   else
02606   {
02607     if (IsOverlayOpen())
02608       SaturateIcons();
02609   }
02610 }
02611 
02612 void Launcher::ProcessDndEnter()
02613 {
02614   SetStateMouseOverLauncher(true);
02615 
02616   _dnd_data.Reset();
02617   _drag_action = nux::DNDACTION_NONE;
02618   _steal_drag = false;
02619   _data_checked = false;
02620   _drag_edge_touching = false;
02621   _dnd_hovered_icon = nullptr;
02622 }
02623 
02624 void Launcher::DndReset()
02625 {
02626   _dnd_data.Reset();
02627 
02628   for (auto it : *_model)
02629   {
02630     it->SetQuirk(AbstractLauncherIcon::QUIRK_DROP_PRELIGHT, false);
02631     it->SetQuirk(AbstractLauncherIcon::QUIRK_DROP_DIM, false);
02632   }
02633 
02634   DndHoveredIconReset();
02635 }
02636 
02637 void Launcher::DndHoveredIconReset()
02638 {
02639   _drag_edge_touching = false;
02640   SetActionState(ACTION_NONE);
02641 
02642   if (_steal_drag && _dnd_hovered_icon)
02643   {
02644     _dnd_hovered_icon->SetQuirk(AbstractLauncherIcon::QUIRK_VISIBLE, false);
02645     _dnd_hovered_icon->remove.emit(_dnd_hovered_icon);
02646   }
02647 
02648   if (!_steal_drag && _dnd_hovered_icon)
02649     _dnd_hovered_icon->SendDndLeave();
02650 
02651   _steal_drag = false;
02652   _dnd_hovered_icon = nullptr;
02653 }
02654 
02655 void Launcher::ProcessDndLeave()
02656 {
02657   SetStateMouseOverLauncher(false);
02658 
02659   DndHoveredIconReset();
02660 }
02661 
02662 void Launcher::ProcessDndMove(int x, int y, std::list<char*> mimes)
02663 {
02664   nux::Area* parent = GetToplevel();
02665   unity::glib::String uri_list_const(g_strdup("text/uri-list"));
02666 
02667   if (!_data_checked)
02668   {
02669     _data_checked = true;
02670     _dnd_data.Reset();
02671 
02672     // get the data
02673     for (auto it : mimes)
02674     {
02675       if (!g_str_equal(it, uri_list_const.Value()))
02676         continue;
02677 
02678       _dnd_data.Fill(nux::GetWindowThread()->GetGraphicsDisplay().GetDndData(uri_list_const.Value()));
02679       break;
02680     }
02681 
02682     // see if the launcher wants this one
02683     for (auto it : _dnd_data.Uris())
02684     {
02685       if (g_str_has_suffix(it.c_str(), ".desktop"))
02686       {
02687         _steal_drag = true;
02688         break;
02689       }
02690     }
02691 
02692     // only set hover once we know our first x/y
02693     SetActionState(ACTION_DRAG_EXTERNAL);
02694     SetStateMouseOverLauncher(true);
02695 
02696     if (!_steal_drag)
02697     {
02698       for (auto it : *_model)
02699       {
02700         if (it->QueryAcceptDrop(_dnd_data) != nux::DNDACTION_NONE)
02701           it->SetQuirk(AbstractLauncherIcon::QUIRK_DROP_PRELIGHT, true);
02702         else
02703           it->SetQuirk(AbstractLauncherIcon::QUIRK_DROP_DIM, true);
02704       }
02705     }
02706   }
02707 
02708   SetMousePosition(x - parent->GetGeometry().x, y - parent->GetGeometry().y);
02709 
02710   if (!IsOverlayOpen() && _mouse_position.x == 0 && _mouse_position.y <= (_parent->GetGeometry().height - _icon_size - 2 * _space_between_icons) && !_drag_edge_touching)
02711   {
02712     if (_dnd_hovered_icon)
02713         _dnd_hovered_icon->SendDndLeave();
02714 
02715     _drag_edge_touching = true;
02716     TimeUtil::SetTimeStruct(&_times[TIME_DRAG_EDGE_TOUCH], &_times[TIME_DRAG_EDGE_TOUCH], ANIM_DURATION * 3);
02717     EnsureAnimation();
02718   }
02719   else if (_mouse_position.x != 0 && _drag_edge_touching)
02720   {
02721     _drag_edge_touching = false;
02722     TimeUtil::SetTimeStruct(&_times[TIME_DRAG_EDGE_TOUCH], &_times[TIME_DRAG_EDGE_TOUCH], ANIM_DURATION * 3);
02723     EnsureAnimation();
02724   }
02725 
02726   EventLogic();
02727   AbstractLauncherIcon::Ptr hovered_icon = MouseIconIntersection(_mouse_position.x, _mouse_position.y);
02728 
02729   bool hovered_icon_is_appropriate = false;
02730   if (hovered_icon)
02731   {
02732     if (hovered_icon->GetIconType() == AbstractLauncherIcon::TYPE_TRASH)
02733       _steal_drag = false;
02734 
02735     if (hovered_icon->GetIconType() == AbstractLauncherIcon::TYPE_APPLICATION || hovered_icon->GetIconType() == AbstractLauncherIcon::TYPE_EXPO)
02736       hovered_icon_is_appropriate = true;
02737   }
02738 
02739   if (_steal_drag)
02740   {
02741     _drag_action = nux::DNDACTION_COPY;
02742     if (!_dnd_hovered_icon && hovered_icon_is_appropriate)
02743     {
02744       _dnd_hovered_icon = new SpacerLauncherIcon(monitor());
02745       _dnd_hovered_icon->SetSortPriority(G_MAXINT);
02746       _model->AddIcon(_dnd_hovered_icon);
02747       _model->ReorderBefore(_dnd_hovered_icon, hovered_icon, true);
02748     }
02749     else if (_dnd_hovered_icon)
02750     {
02751       if (hovered_icon)
02752       {
02753         if (hovered_icon_is_appropriate)
02754         {
02755           _model->ReorderSmart(_dnd_hovered_icon, hovered_icon, true);
02756         }
02757         else
02758         {
02759           _dnd_hovered_icon->SetQuirk(AbstractLauncherIcon::QUIRK_VISIBLE, false);
02760           _dnd_hovered_icon->remove.emit(_dnd_hovered_icon);
02761           _dnd_hovered_icon = nullptr;
02762         }
02763       }
02764     }
02765   }
02766   else
02767   {
02768     if (!_drag_edge_touching && hovered_icon != _dnd_hovered_icon)
02769     {
02770       if (hovered_icon)
02771       {
02772         hovered_icon->SendDndEnter();
02773         _drag_action = hovered_icon->QueryAcceptDrop(_dnd_data);
02774       }
02775       else
02776       {
02777         _drag_action = nux::DNDACTION_NONE;
02778       }
02779 
02780       if (_dnd_hovered_icon)
02781         _dnd_hovered_icon->SendDndLeave();
02782 
02783       _dnd_hovered_icon = hovered_icon;
02784     }
02785   }
02786 
02787   bool accept;
02788   if (_drag_action != nux::DNDACTION_NONE)
02789     accept = true;
02790   else
02791     accept = false;
02792 
02793   SendDndStatus(accept, _drag_action, nux::Geometry(x, y, 1, 1));
02794 }
02795 
02796 void Launcher::ProcessDndDrop(int x, int y)
02797 {
02798   if (_steal_drag)
02799   {
02800     for (auto it : _dnd_data.Uris())
02801     {
02802       if (g_str_has_suffix(it.c_str(), ".desktop"))
02803       {
02804         char* path = nullptr;
02805 
02806         if (g_str_has_prefix(it.c_str(), "application://"))
02807         {
02808           const char* tmp = it.c_str() + strlen("application://");
02809           unity::glib::String tmp2(g_strdup_printf("file:///usr/share/applications/%s", tmp));
02810           path = g_filename_from_uri(tmp2.Value(), NULL, NULL);
02811         }
02812         else if (g_str_has_prefix(it.c_str(), "file://"))
02813         {
02814           path = g_filename_from_uri(it.c_str(), NULL, NULL);
02815         }
02816 
02817         if (path)
02818         {
02819           launcher_addrequest.emit(path, _dnd_hovered_icon);
02820           g_free(path);
02821         }
02822       }
02823     }
02824   }
02825   else if (_dnd_hovered_icon && _drag_action != nux::DNDACTION_NONE)
02826   {
02827      if (IsOverlayOpen())
02828        ubus_.SendMessage(UBUS_PLACE_VIEW_CLOSE_REQUEST);
02829 
02830     _dnd_hovered_icon->AcceptDrop(_dnd_data);
02831   }
02832 
02833   if (_drag_action != nux::DNDACTION_NONE)
02834     SendDndFinished(true, _drag_action);
02835   else
02836     SendDndFinished(false, _drag_action);
02837 
02838   // reset our shiz
02839   DndReset();
02840 }
02841 
02842 /*
02843  * Returns the current selected icon if it is in keynavmode
02844  * It will return NULL if it is not on keynavmode
02845  */
02846 AbstractLauncherIcon::Ptr Launcher::GetSelectedMenuIcon() const
02847 {
02848   if (!IsInKeyNavMode())
02849     return AbstractLauncherIcon::Ptr();
02850   return _model->Selection();
02851 }
02852 
02853 //
02854 // Key navigation
02855 //
02856 bool Launcher::InspectKeyEvent(unsigned int eventType,
02857                           unsigned int keysym,
02858                           const char* character)
02859 {
02860   // The Launcher accepts all key inputs.
02861   return true;
02862 }
02863 
02864 } // namespace launcher
02865 } // namespace unity