Back to index

unity  6.0.0
LauncherHideMachine.cpp
Go to the documentation of this file.
00001 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
00002 /*
00003  * Copyright (C) 2011 Canonical Ltd
00004  *
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 3 as
00007  * published by the Free Software Foundation.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016  *
00017  * Authored by: Jason Smith <jason.smith@canonical.com>
00018  */
00019 
00020 #include "LauncherHideMachine.h"
00021 
00022 #include <boost/lexical_cast.hpp>
00023 #include <NuxCore/Logger.h>
00024 
00025 namespace unity
00026 {
00027 namespace launcher
00028 {
00029 
00030 namespace
00031 {
00032 nux::logging::Logger logger("unity.launcher");
00033 const unsigned int HIDE_DELAY_TIMEOUT_LENGTH = 750;
00034 }
00035 
00036 LauncherHideMachine::LauncherHideMachine()
00037   : reveal_progress(0)
00038   , decaymulator_(new ui::Decaymulator())
00039   , _mode(HIDE_NEVER)
00040   , _quirks(DEFAULT)
00041   , _should_hide(false)
00042   , _latest_emit_should_hide(false)
00043 {
00044   decaymulator_->value.changed.connect([&](int value) { reveal_progress = value / static_cast<float>(reveal_pressure); });
00045   edge_decay_rate.changed.connect(sigc::mem_fun (this, &LauncherHideMachine::OnDecayRateChanged));
00046 }
00047 
00048 void LauncherHideMachine::OnDecayRateChanged(int value)
00049 {
00050   decaymulator_->rate_of_decay = value;  
00051 }
00052 
00053 void LauncherHideMachine::AddRevealPressure(int pressure)
00054 {
00055   decaymulator_->value = decaymulator_->value + pressure;
00056 
00057   if (decaymulator_->value > reveal_pressure)
00058   {
00059     SetQuirk(REVEAL_PRESSURE_PASS, true);
00060     SetQuirk(MOUSE_MOVE_POST_REVEAL, true);
00061     decaymulator_->value = 0;
00062   }
00063 }
00064 
00065 void LauncherHideMachine::SetShouldHide(bool value, bool skip_delay)
00066 {
00067   if (_should_hide == value)
00068     return;
00069 
00070   if (value && !skip_delay)
00071   {
00072     _hide_delay_timeout.reset(new glib::Timeout(HIDE_DELAY_TIMEOUT_LENGTH));
00073     _hide_delay_timeout->Run([&] () {
00074       EnsureHideState(true);
00075       return false;
00076     });
00077   }
00078   else
00079   {
00080     _should_hide = value;
00081 
00082     _hide_changed_emit_idle.reset(new glib::Idle(glib::Source::Priority::DEFAULT));
00083     _hide_changed_emit_idle->Run(sigc::mem_fun(this, &LauncherHideMachine::EmitShouldHideChanged));
00084   }
00085 }
00086 
00087 /* == Quick Quirk Reference : please keep up to date ==
00088     LAUNCHER_HIDDEN        = 1 << 0, 1
00089     MOUSE_OVER_LAUNCHER    = 1 << 1, 2
00090     QUICKLIST_OPEN         = 1 << 4, 16  #VISIBLE_REQUIRED
00091     EXTERNAL_DND_ACTIVE    = 1 << 5, 32  #VISIBLE_REQUIRED
00092     INTERNAL_DND_ACTIVE    = 1 << 6, 64  #VISIBLE_REQUIRED
00093     TRIGGER_BUTTON_SHOW    = 1 << 7, 128 #VISIBLE_REQUIRED
00094     DND_PUSHED_OFF         = 1 << 10, 1024
00095     MOUSE_MOVE_POST_REVEAL = 1 << 11, 2k
00096     VERTICAL_SLIDE_ACTIVE  = 1 << 12, 4k  #VISIBLE_REQUIRED
00097     KEY_NAV_ACTIVE         = 1 << 13, 8k  #VISIBLE_REQUIRED
00098     PLACES_VISIBLE         = 1 << 14, 16k #VISIBLE_REQUIRED
00099     LAST_ACTION_ACTIVATE   = 1 << 15, 32k
00100     SCALE_ACTIVE           = 1 << 16, 64k  #VISIBLE_REQUIRED
00101     EXPO_ACTIVE            = 1 << 17, 128k #VISIBLE_REQUIRED
00102     MT_DRAG_OUT            = 1 << 18, 256k #VISIBLE_REQUIRED
00103     LAUNCHER_PULSE         = 1 << 20, 1M   #VISIBLE_REQUIRED
00104     LOCK_HIDE              = 1 << 21, 2M
00105 */
00106 
00107 #define VISIBLE_REQUIRED (QUICKLIST_OPEN | EXTERNAL_DND_ACTIVE | \
00108 INTERNAL_DND_ACTIVE | TRIGGER_BUTTON_SHOW | VERTICAL_SLIDE_ACTIVE |\
00109 KEY_NAV_ACTIVE | PLACES_VISIBLE | SCALE_ACTIVE | EXPO_ACTIVE |\
00110 MT_DRAG_OUT | LAUNCHER_PULSE)
00111 
00112 void LauncherHideMachine::EnsureHideState(bool skip_delay)
00113 {
00114   bool should_hide;
00115 
00116   if (_mode == HIDE_NEVER)
00117   {
00118     SetShouldHide(false, skip_delay);
00119     return;
00120   }
00121   
00122   // early check to see if we are locking to hidden - but only if we are in non HIDE_NEVER
00123   if (GetQuirk(LOCK_HIDE))
00124   {
00125     SetShouldHide(true, true);
00126     return;
00127   }
00128 
00129   do
00130   {
00131     // first we check the condition where external DND is active and the push off has happened
00132     if (GetQuirk((HideQuirk)(EXTERNAL_DND_ACTIVE | DND_PUSHED_OFF), false))
00133     {
00134       should_hide = true;
00135       break;
00136     }
00137 
00138     // figure out if we are going to hide because of a window
00139     bool hide_for_window = false;
00140     if (_mode == AUTOHIDE)
00141       hide_for_window = true;
00142 
00143     // if we activated AND we would hide because of a window, go ahead and do it
00144     if (!_should_hide && GetQuirk(LAST_ACTION_ACTIVATE) && hide_for_window)
00145     {
00146       should_hide = true;
00147       break;
00148     }
00149 
00150     // Is there anything holding us open?
00151     HideQuirk _should_show_quirk;
00152     if (GetQuirk(LAUNCHER_HIDDEN))
00153     {
00154       _should_show_quirk = (HideQuirk) ((VISIBLE_REQUIRED) | REVEAL_PRESSURE_PASS);
00155     }
00156     else
00157     {
00158       _should_show_quirk = (HideQuirk)(VISIBLE_REQUIRED);
00159       // mouse position over launcher is only taken into account if we move it after the revealing state
00160       if (GetQuirk(MOUSE_MOVE_POST_REVEAL))
00161         _should_show_quirk = (HideQuirk)(_should_show_quirk | MOUSE_OVER_LAUNCHER);
00162     }
00163 
00164     if (GetQuirk(_should_show_quirk))
00165     {
00166       should_hide = false;
00167       break;
00168     }
00169 
00170     // nothing holding us open, any reason to hide?
00171     should_hide = hide_for_window;
00172 
00173   }
00174   while (false);
00175 
00176   SetShouldHide(should_hide, skip_delay);
00177 }
00178 
00179 void LauncherHideMachine::SetMode(LauncherHideMachine::HideMode mode)
00180 {
00181   if (_mode == mode)
00182     return;
00183 
00184   _mode = mode;
00185   EnsureHideState(true);
00186 }
00187 
00188 LauncherHideMachine::HideMode
00189 LauncherHideMachine::GetMode() const
00190 {
00191   return _mode;
00192 }
00193 
00194 #define SKIP_DELAY_QUIRK (EXTERNAL_DND_ACTIVE | DND_PUSHED_OFF | EXPO_ACTIVE | SCALE_ACTIVE | MT_DRAG_OUT | TRIGGER_BUTTON_SHOW)
00195 
00196 void LauncherHideMachine::SetQuirk(LauncherHideMachine::HideQuirk quirk, bool active)
00197 {
00198   if (GetQuirk(quirk) == active)
00199     return;
00200 
00201   if (active)
00202     _quirks = (HideQuirk)(_quirks | quirk);
00203   else
00204     _quirks = (HideQuirk)(_quirks & ~quirk);
00205 
00206   // no skipping when last action was activate on general case
00207   bool skip = quirk & SKIP_DELAY_QUIRK && !GetQuirk(LAST_ACTION_ACTIVATE);
00208 
00209   // but skip on last action if we were out of the launcher/bfb
00210   if (GetQuirk(LAST_ACTION_ACTIVATE) && !active && (quirk & (MOUSE_OVER_LAUNCHER)))
00211     skip = true;
00212 
00213   EnsureHideState(skip);
00214 }
00215 
00216 bool LauncherHideMachine::GetQuirk(LauncherHideMachine::HideQuirk quirk, bool allow_partial) const
00217 {
00218   if (allow_partial)
00219     return _quirks & quirk;
00220   return (_quirks & quirk) == quirk;
00221 }
00222 
00223 bool LauncherHideMachine::ShouldHide() const
00224 {
00225   return _should_hide;
00226 }
00227 
00228 bool LauncherHideMachine::EmitShouldHideChanged()
00229 {
00230   if (_should_hide == _latest_emit_should_hide)
00231     return false;
00232 
00233   _latest_emit_should_hide = _should_hide;
00234   should_hide_changed.emit(_should_hide);
00235 
00236   return false;
00237 }
00238 
00239 std::string LauncherHideMachine::DebugHideQuirks() const
00240 {
00241   // Although I do wonder why we are returning a string representation
00242   // of the enum value as an integer anyway.
00243   return boost::lexical_cast<std::string>(_quirks);
00244 }
00245 
00246 } // namespace launcher
00247 } // namespace unity