// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright (C) 2011 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Jason Smith */ #include "LauncherHideMachine.h" namespace unity { namespace launcher { namespace { const unsigned int HIDE_DELAY_TIMEOUT_LENGTH = 400; } LauncherHideMachine::LauncherHideMachine() : reveal_progress(0) , _mode(HIDE_NEVER) , _quirks(DEFAULT) , _should_hide(false) , _latest_emit_should_hide(false) { decaymulator_.value.changed.connect([this](int value) { reveal_progress = value / static_cast(reveal_pressure); }); edge_decay_rate.changed.connect(sigc::mem_fun (this, &LauncherHideMachine::OnDecayRateChanged)); } void LauncherHideMachine::OnDecayRateChanged(int value) { decaymulator_.rate_of_decay = value; } void LauncherHideMachine::AddRevealPressure(int pressure) { decaymulator_.value = decaymulator_.value + pressure; if (decaymulator_.value > reveal_pressure) { SetQuirk(REVEAL_PRESSURE_PASS, true); SetQuirk(MOUSE_MOVE_POST_REVEAL, true); decaymulator_.value = 0; } } void LauncherHideMachine::SetShouldHide(bool value, bool skip_delay) { if (_should_hide == value) return; if (value && !skip_delay) { _hide_delay_timeout.reset(new glib::Timeout(HIDE_DELAY_TIMEOUT_LENGTH)); _hide_delay_timeout->Run([this] () { EnsureHideState(true); return false; }); } else { _should_hide = value; _hide_changed_emit_idle.reset(new glib::Idle(glib::Source::Priority::DEFAULT)); _hide_changed_emit_idle->Run(sigc::mem_fun(this, &LauncherHideMachine::EmitShouldHideChanged)); } } /* == Quick Quirk Reference : please keep up to date == LAUNCHER_HIDDEN = 1 << 0, 1 MOUSE_OVER_LAUNCHER = 1 << 1, 2 QUICKLIST_OPEN = 1 << 2, 4 #VISIBLE_REQUIRED EXTERNAL_DND_ACTIVE = 1 << 3, 8 #VISIBLE_REQUIRED INTERNAL_DND_ACTIVE = 1 << 4, 16 #VISIBLE_REQUIRED TRIGGER_BUTTON_SHOW = 1 << 5, 32 #VISIBLE_REQUIRED DND_PUSHED_OFF = 1 << 6, 64 MOUSE_MOVE_POST_REVEAL = 1 << 7, 128 VERTICAL_SLIDE_ACTIVE = 1 << 8, 256 #VISIBLE_REQUIRED KEY_NAV_ACTIVE = 1 << 9, 512 #VISIBLE_REQUIRED PLACES_VISIBLE = 1 << 10, 1024 #VISIBLE_REQUIRED SCALE_ACTIVE = 1 << 11, 2048 #VISIBLE_REQUIRED EXPO_ACTIVE = 1 << 12, 4096 #VISIBLE_REQUIRED MT_DRAG_OUT = 1 << 13, 8192 #VISIBLE_REQUIRED REVEAL_PRESSURE_PASS = 1 << 14, 16384 LAUNCHER_PULSE = 1 << 15, 32768 #VISIBLE_REQUIRED LOCK_HIDE = 1 << 16, 65536 SHORTCUT_KEYS_VISIBLE = 1 << 17, 131072 #VISIBLE REQUIRED */ #define VISIBLE_REQUIRED (QUICKLIST_OPEN | EXTERNAL_DND_ACTIVE | \ INTERNAL_DND_ACTIVE | TRIGGER_BUTTON_SHOW | VERTICAL_SLIDE_ACTIVE |\ KEY_NAV_ACTIVE | PLACES_VISIBLE | SCALE_ACTIVE | EXPO_ACTIVE |\ MT_DRAG_OUT | LAUNCHER_PULSE | SHORTCUT_KEYS_VISIBLE) void LauncherHideMachine::EnsureHideState(bool skip_delay) { bool should_hide; if (_mode == HIDE_NEVER) { SetShouldHide(false, skip_delay); return; } // early check to see if we are locking to hidden - but only if we are in non HIDE_NEVER if (GetQuirk(LOCK_HIDE)) { SetShouldHide(true, true); return; } do { // first we check the condition where external DND is active and the push off has happened if (GetQuirk((HideQuirk)(EXTERNAL_DND_ACTIVE | DND_PUSHED_OFF), false)) { should_hide = true; break; } // figure out if we are going to hide because of a window bool hide_for_window = false; if (_mode == AUTOHIDE) hide_for_window = true; // Is there anything holding us open? HideQuirk _should_show_quirk; if (GetQuirk(LAUNCHER_HIDDEN)) { _should_show_quirk = (HideQuirk) ((VISIBLE_REQUIRED) | REVEAL_PRESSURE_PASS); } else { _should_show_quirk = (HideQuirk)(VISIBLE_REQUIRED); // mouse position over launcher is only taken into account if we move it after the revealing state if (GetQuirk(MOUSE_MOVE_POST_REVEAL)) _should_show_quirk = (HideQuirk)(_should_show_quirk | MOUSE_OVER_LAUNCHER); } if (GetQuirk(_should_show_quirk)) { should_hide = false; break; } // nothing holding us open, any reason to hide? should_hide = hide_for_window; } while (false); SetShouldHide(should_hide, skip_delay); } void LauncherHideMachine::SetMode(LauncherHideMachine::HideMode mode) { if (_mode == mode) return; _mode = mode; EnsureHideState(true); } LauncherHideMachine::HideMode LauncherHideMachine::GetMode() const { return _mode; } #define SKIP_DELAY_QUIRK (EXTERNAL_DND_ACTIVE | DND_PUSHED_OFF | EXPO_ACTIVE | SCALE_ACTIVE | MT_DRAG_OUT | TRIGGER_BUTTON_SHOW) void LauncherHideMachine::SetQuirk(LauncherHideMachine::HideQuirk quirk, bool active) { if (GetQuirk(quirk) == active) return; if (active) _quirks = (HideQuirk)(_quirks | quirk); else _quirks = (HideQuirk)(_quirks & ~quirk); bool skip = quirk & SKIP_DELAY_QUIRK; EnsureHideState(skip); } bool LauncherHideMachine::GetQuirk(LauncherHideMachine::HideQuirk quirk, bool allow_partial) const { if (allow_partial) return _quirks & quirk; return (_quirks & quirk) == quirk; } bool LauncherHideMachine::ShouldHide() const { return _should_hide; } bool LauncherHideMachine::EmitShouldHideChanged() { if (_should_hide == _latest_emit_should_hide) return false; _latest_emit_should_hide = _should_hide; should_hide_changed.emit(_should_hide); return false; } std::string LauncherHideMachine::DebugHideQuirks() const { // Although I do wonder why we are returning a string representation // of the enum value as an integer anyway. return std::to_string(_quirks); } } // namespace launcher } // namespace unity