diff options
| author | Marco Trevisan (Treviño) <mail@3v1n0.net> | 2013-03-07 17:43:06 +0100 |
|---|---|---|
| committer | Marco Trevisan (Treviño) <mail@3v1n0.net> | 2013-03-07 17:43:06 +0100 |
| commit | c5c588214074a38370c6c447ed1119dba7edc173 (patch) | |
| tree | 9182b44221e322015bd1d0731e4d48314f9742ef /launcher | |
| parent | 07391b49bd09666c23ab76629eb31968daffaf77 (diff) | |
| parent | 45048fbb79c09b01561b1aa8c5f51053c0d8c03e (diff) | |
Merging with trunk
(bzr r3144.3.31)
Diffstat (limited to 'launcher')
29 files changed, 520 insertions, 178 deletions
diff --git a/launcher/AbstractLauncherIcon.h b/launcher/AbstractLauncherIcon.h index db8f1492b..36d0eddaf 100644 --- a/launcher/AbstractLauncherIcon.h +++ b/launcher/AbstractLauncherIcon.h @@ -59,9 +59,10 @@ public: { } - ActionArg(Source source, int button, Window target = 0, int monitor = -1) + ActionArg(Source source, int button, Time timestamp = -1, Window target = 0, int monitor = -1) : source(source) , button(button) + , timestamp(timestamp) , target(target) , monitor(monitor) { @@ -69,6 +70,7 @@ public: Source source; int button; + Time timestamp; Window target; int monitor; }; @@ -131,7 +133,9 @@ public: nux::Property<std::string> tooltip_text; nux::Property<bool> tooltip_enabled; nux::Property<Position> position; + nux::Property<bool> removed; + virtual void ShowTooltip() = 0; virtual void HideTooltip() = 0; virtual void SetShortcut(guint64 shortcut) = 0; diff --git a/launcher/ApplicationLauncherIcon.cpp b/launcher/ApplicationLauncherIcon.cpp index 6ff39832c..ade59aacc 100644 --- a/launcher/ApplicationLauncherIcon.cpp +++ b/launcher/ApplicationLauncherIcon.cpp @@ -324,7 +324,7 @@ void ApplicationLauncherIcon::ActivateLauncherIcon(ActionArg arg) return; SetQuirk(Quirk::STARTING, true); - OpenInstanceLauncherIcon(); + OpenInstanceLauncherIcon(arg.timestamp); } else // app is running { @@ -468,12 +468,19 @@ void ApplicationLauncherIcon::UpdateDesktopFile() g_file_monitor_set_rate_limit(_desktop_file_monitor, 1000); auto sig = new glib::Signal<void, GFileMonitor*, GFile*, GFile*, GFileMonitorEvent>(_desktop_file_monitor, "changed", - [&] (GFileMonitor*, GFile*, GFile*, GFileMonitorEvent event_type) { + [&] (GFileMonitor*, GFile* f, GFile*, GFileMonitorEvent event_type) { switch (event_type) { case G_FILE_MONITOR_EVENT_DELETED: - UnStick(); + { + glib::Object<GFile> file(f, glib::AddRef()); + _source_manager.AddTimeoutSeconds(1, [this, file] { + if (!g_file_query_exists (file, nullptr)) + UnStick(); + return false; + }); break; + } case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: UpdateDesktopQuickList(); UpdateBackgroundColor(); @@ -510,7 +517,7 @@ void ApplicationLauncherIcon::AddProperties(GVariantBuilder* builder) .add("startup_notification_timestamp", _startup_notification_timestamp); } -void ApplicationLauncherIcon::OpenInstanceWithUris(std::set<std::string> const& uris) +void ApplicationLauncherIcon::OpenInstanceWithUris(std::set<std::string> const& uris, Time timestamp) { glib::Error error; glib::Object<GDesktopAppInfo> desktopInfo(g_desktop_app_info_new_from_filename(DesktopFile().c_str())); @@ -519,8 +526,9 @@ void ApplicationLauncherIcon::OpenInstanceWithUris(std::set<std::string> const& GdkDisplay* display = gdk_display_get_default(); glib::Object<GdkAppLaunchContext> app_launch_context(gdk_display_get_app_launch_context(display)); - _startup_notification_timestamp = nux::GetWindowThread()->GetGraphicsDisplay().GetCurrentEvent().x11_timestamp; - gdk_app_launch_context_set_timestamp(app_launch_context, _startup_notification_timestamp); + _startup_notification_timestamp = timestamp; + if (_startup_notification_timestamp >= 0) + gdk_app_launch_context_set_timestamp(app_launch_context, _startup_notification_timestamp); if (g_app_info_supports_uris(appInfo)) { @@ -558,10 +566,10 @@ void ApplicationLauncherIcon::OpenInstanceWithUris(std::set<std::string> const& UpdateQuirkTime(Quirk::STARTING); } -void ApplicationLauncherIcon::OpenInstanceLauncherIcon() +void ApplicationLauncherIcon::OpenInstanceLauncherIcon(Time timestamp) { std::set<std::string> empty; - OpenInstanceWithUris(empty); + OpenInstanceWithUris(empty, timestamp); } void ApplicationLauncherIcon::Focus(ActionArg arg) @@ -576,7 +584,7 @@ void ApplicationLauncherIcon::Focus(ActionArg arg) else if (app_->type() == "webapp") { // Webapps are again special. - OpenInstanceLauncherIcon(); + OpenInstanceLauncherIcon(arg.timestamp); return; } @@ -779,7 +787,10 @@ void ApplicationLauncherIcon::UnStick() if (!IsSticky()) return; + SetQuirk(Quirk::VISIBLE, app_->running()); + app_->sticky = false; + if (!app_->running()) Remove(); } @@ -1143,7 +1154,8 @@ nux::DndAction ApplicationLauncherIcon::OnQueryAcceptDrop(DndData const& dnd_dat void ApplicationLauncherIcon::OnAcceptDrop(DndData const& dnd_data) { - OpenInstanceWithUris(ValidateUrisForLaunch(dnd_data)); + auto timestamp = nux::GetWindowThread()->GetGraphicsDisplay().GetCurrentEvent().x11_timestamp; + OpenInstanceWithUris(ValidateUrisForLaunch(dnd_data), timestamp); } bool ApplicationLauncherIcon::ShowInSwitcher(bool current) diff --git a/launcher/ApplicationLauncherIcon.h b/launcher/ApplicationLauncherIcon.h index 7bee592c5..04594aa48 100644 --- a/launcher/ApplicationLauncherIcon.h +++ b/launcher/ApplicationLauncherIcon.h @@ -77,7 +77,7 @@ protected: void OnDndEnter(); void OnDndHovered(); void OnDndLeave(); - void OpenInstanceLauncherIcon(); + void OpenInstanceLauncherIcon(Time timestamp) override; void ToggleSticky(); bool OnShouldHighlightOnDrag(DndData const& dnd_data); @@ -114,7 +114,7 @@ private: void UpdateMenus(); void UpdateDesktopQuickList(); - void OpenInstanceWithUris(std::set<std::string> const& uris); + void OpenInstanceWithUris(std::set<std::string> const& uris, Time timestamp); void Focus(ActionArg arg); bool Spread(bool current_desktop, int state, bool force); diff --git a/launcher/BFBLauncherIcon.cpp b/launcher/BFBLauncherIcon.cpp index a84d71f7b..f7d701020 100644 --- a/launcher/BFBLauncherIcon.cpp +++ b/launcher/BFBLauncherIcon.cpp @@ -58,8 +58,9 @@ void BFBLauncherIcon::OnOverlayShown(GVariant *data, bool visible) unity::glib::String overlay_identity; gboolean can_maximise = FALSE; gint32 overlay_monitor = 0; + int width, height; g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING, - &overlay_identity, &can_maximise, &overlay_monitor); + &overlay_identity, &can_maximise, &overlay_monitor, &width, &height); if (overlay_identity.Str() == "dash" && IsVisibleOnMonitor(overlay_monitor)) { diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 3987c69cf..b32d93953 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -57,6 +57,7 @@ set (LAUNCHER_SOURCES SoftwareCenterLauncherIcon.cpp SpacerLauncherIcon.cpp Tooltip.cpp + TooltipManager.cpp TrashLauncherIcon.cpp VolumeImp.cpp VolumeLauncherIcon.cpp diff --git a/launcher/EdgeBarrierController.cpp b/launcher/EdgeBarrierController.cpp index c1d1ad8da..46514431d 100644 --- a/launcher/EdgeBarrierController.cpp +++ b/launcher/EdgeBarrierController.cpp @@ -24,8 +24,15 @@ #include "unity-shared/UScreen.h" #include "UnityCore/GLibSource.h" -namespace unity { -namespace ui { +namespace unity +{ +namespace ui +{ + +namespace +{ + int const Y_BREAK_BUFFER = 20; +} EdgeBarrierController::Impl::Impl(EdgeBarrierController *parent) @@ -119,7 +126,14 @@ void EdgeBarrierController::Impl::BarrierReset() void EdgeBarrierController::Impl::BarrierPush(PointerBarrierWrapper* owner, BarrierEvent::Ptr const& event) { - decaymulator_.value = decaymulator_.value + event->velocity; + if (EventIsInsideYBreakZone(event)) + { + decaymulator_.value = decaymulator_.value + event->velocity; + } + else + { + BarrierReset(); + } if (decaymulator_.value > edge_overcome_pressure_) { @@ -127,6 +141,22 @@ void EdgeBarrierController::Impl::BarrierPush(PointerBarrierWrapper* owner, Barr } } +bool EdgeBarrierController::Impl::EventIsInsideYBreakZone(BarrierEvent::Ptr const& event) +{ + static int y_break_zone = event->y; + + if (decaymulator_.value <= 0) + y_break_zone = event->y; + + if (event->y <= y_break_zone + Y_BREAK_BUFFER && + event->y >= y_break_zone - Y_BREAK_BUFFER) + { + return true; + } + + return false; +} + void EdgeBarrierController::Impl::OnPointerBarrierEvent(PointerBarrierWrapper* owner, BarrierEvent::Ptr const& event) { if (owner->released) diff --git a/launcher/EdgeBarrierControllerPrivate.h b/launcher/EdgeBarrierControllerPrivate.h index c7cef24b8..eb4199d19 100644 --- a/launcher/EdgeBarrierControllerPrivate.h +++ b/launcher/EdgeBarrierControllerPrivate.h @@ -42,6 +42,8 @@ struct EdgeBarrierController::Impl void BarrierRelease(PointerBarrierWrapper* owner, int event); void BarrierReset(); + bool EventIsInsideYBreakZone(BarrierEvent::Ptr const& event); + std::vector<PointerBarrierWrapper::Ptr> barriers_; std::vector<EdgeBarrierSubscriber*> subscribers_; Decaymulator decaymulator_; diff --git a/launcher/ExpoLauncherIcon.cpp b/launcher/ExpoLauncherIcon.cpp index 17c2d64d7..8e2adc3a8 100644 --- a/launcher/ExpoLauncherIcon.cpp +++ b/launcher/ExpoLauncherIcon.cpp @@ -66,6 +66,11 @@ void ExpoLauncherIcon::OnViewportLayoutChanged(int hsize, int vsize) } } +void ExpoLauncherIcon::AboutToRemove() +{ + WindowManager::Default().SetViewportSize(1, 1); +} + void ExpoLauncherIcon::UpdateIcon() { auto const& vp = WindowManager::Default().GetCurrentViewport(); diff --git a/launcher/ExpoLauncherIcon.h b/launcher/ExpoLauncherIcon.h index af1ba244e..f660cdcaa 100644 --- a/launcher/ExpoLauncherIcon.h +++ b/launcher/ExpoLauncherIcon.h @@ -32,6 +32,7 @@ class ExpoLauncherIcon : public SimpleLauncherIcon public: ExpoLauncherIcon(); void Stick(bool save); + void AboutToRemove(); protected: void ActivateLauncherIcon(ActionArg arg); diff --git a/launcher/HudLauncherIcon.cpp b/launcher/HudLauncherIcon.cpp index 7fea6c4f7..39fa01a0d 100644 --- a/launcher/HudLauncherIcon.cpp +++ b/launcher/HudLauncherIcon.cpp @@ -89,8 +89,9 @@ void HudLauncherIcon::OnOverlayShown(GVariant* data, bool visible) unity::glib::String overlay_identity; gboolean can_maximise = FALSE; gint32 overlay_monitor = 0; + int width, height; g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING, - &overlay_identity, &can_maximise, &overlay_monitor); + &overlay_identity, &can_maximise, &overlay_monitor, &width, &height); // If the hud is open, we show the HUD button if we have a locked launcher if (overlay_identity.Str() == "hud" && diff --git a/launcher/Launcher.cpp b/launcher/Launcher.cpp index 7565dd182..79c8f472f 100644 --- a/launcher/Launcher.cpp +++ b/launcher/Launcher.cpp @@ -101,7 +101,7 @@ NUX_IMPLEMENT_OBJECT_TYPE(Launcher); const int Launcher::Launcher::ANIM_DURATION_SHORT = 125; -Launcher::Launcher(nux::BaseWindow* parent, +Launcher::Launcher(MockableBaseWindow* parent, NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) #ifdef USE_X11 @@ -286,6 +286,21 @@ void Launcher::SetStateMouseOverLauncher(bool over_launcher) _hide_machine.SetQuirk(LauncherHideMachine::MOUSE_OVER_LAUNCHER, over_launcher); _hide_machine.SetQuirk(LauncherHideMachine::REVEAL_PRESSURE_PASS, false); _hover_machine.SetQuirk(LauncherHoverMachine::MOUSE_OVER_LAUNCHER, over_launcher); + tooltip_manager_.SetHover(over_launcher); +} + +void Launcher::SetIconUnderMouse(AbstractLauncherIcon::Ptr const& icon) +{ + if (_icon_under_mouse == icon) + return; + + if (_icon_under_mouse) + _icon_under_mouse->mouse_leave.emit(monitor); + if (icon) + icon->mouse_enter.emit(monitor); + + _icon_under_mouse = icon; + tooltip_manager_.SetIcon(icon); } bool Launcher::MouseBeyondDragThreshold() const @@ -1210,8 +1225,9 @@ void Launcher::OnOverlayShown(GVariant* data) unity::glib::String overlay_identity; gboolean can_maximise = FALSE; gint32 overlay_monitor = 0; + int width, height; g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING, - &overlay_identity, &can_maximise, &overlay_monitor); + &overlay_identity, &can_maximise, &overlay_monitor, &width, &height); std::string identity(overlay_identity.Str()); LOG_DEBUG(logger) << "Overlay shown: " << identity @@ -1251,8 +1267,9 @@ void Launcher::OnOverlayHidden(GVariant* data) unity::glib::String overlay_identity; gboolean can_maximise = FALSE; gint32 overlay_monitor = 0; + int width, height; g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING, - &overlay_identity, &can_maximise, &overlay_monitor); + &overlay_identity, &can_maximise, &overlay_monitor, &width, &height); std::string identity = overlay_identity.Str(); @@ -1316,7 +1333,8 @@ void Launcher::SetHidden(bool hide_launcher) TimeUtil::SetTimeStruct(&_times[TIME_AUTOHIDE], &_times[TIME_AUTOHIDE], ANIM_DURATION_SHORT); - _parent->EnableInputWindow(!hide_launcher, launcher::window_title, false, false); + if (nux::GetWindowThread()->IsEmbeddedWindow()) + _parent->EnableInputWindow(!hide_launcher, launcher::window_title, false, false); if (!hide_launcher && GetActionState() == ACTION_DRAG_EXTERNAL) DndReset(); @@ -1600,8 +1618,7 @@ void Launcher::OnIconRemoved(AbstractLauncherIcon::Ptr const& icon) if (icon->needs_redraw_connection.connected()) icon->needs_redraw_connection.disconnect(); - if (icon == _icon_under_mouse) - _icon_under_mouse = nullptr; + SetIconUnderMouse(AbstractLauncherIcon::Ptr()); if (icon == _icon_mouse_down) _icon_mouse_down = nullptr; if (icon == _drag_icon) @@ -1920,11 +1937,7 @@ bool Launcher::StartIconDragTimeout(int x, int y) // if we are still waiting… if (GetActionState() == ACTION_NONE) { - if (_icon_under_mouse) - { - _icon_under_mouse->mouse_leave.emit(monitor); - _icon_under_mouse = nullptr; - } + SetIconUnderMouse(AbstractLauncherIcon::Ptr()); _initial_drag_animation = true; StartIconDragRequest(x, y); } @@ -2163,11 +2176,7 @@ void Launcher::RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_ GetActionState() == ACTION_NONE) return; - if (_icon_under_mouse) - { - _icon_under_mouse->mouse_leave.emit(monitor); - _icon_under_mouse = nullptr; - } + SetIconUnderMouse(AbstractLauncherIcon::Ptr()); if (GetActionState() == ACTION_NONE) { @@ -2219,6 +2228,7 @@ void Launcher::RecvMouseLeave(int x, int y, unsigned long button_flags, unsigned void Launcher::RecvMouseMove(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags) { SetMousePosition(x, y); + tooltip_manager_.MouseMoved(); if (!_hidden) UpdateChangeInMousePosition(dx, dy); @@ -2297,7 +2307,9 @@ ui::EdgeBarrierSubscriber::Result Launcher::HandleBarrierEvent(ui::PointerBarrie if (!apply_to_reveal) return ui::EdgeBarrierSubscriber::Result::IGNORED; - _hide_machine.AddRevealPressure(event->velocity); + if (!owner->IsFirstEvent()) + _hide_machine.AddRevealPressure(event->velocity); + return ui::EdgeBarrierSubscriber::Result::HANDLED; } @@ -2365,18 +2377,7 @@ void Launcher::EventLogic() launcher_icon = MouseIconIntersection(_mouse_position.x, _mouse_position.y); } - - if (_icon_under_mouse && (_icon_under_mouse != launcher_icon)) - { - _icon_under_mouse->mouse_leave.emit(monitor); - _icon_under_mouse = nullptr; - } - - if (launcher_icon && (_icon_under_mouse != launcher_icon)) - { - launcher_icon->mouse_enter.emit(monitor); - _icon_under_mouse = launcher_icon; - } + SetIconUnderMouse(launcher_icon); } void Launcher::MouseDownLogic(int x, int y, unsigned long button_flags, unsigned long key_flags) @@ -2391,6 +2392,7 @@ void Launcher::MouseDownLogic(int x, int y, unsigned long button_flags, unsigned sources_.AddTimeout(START_DRAGICON_DURATION, cb_func, START_DRAGICON_TIMEOUT); launcher_icon->mouse_down.emit(nux::GetEventButton(button_flags), monitor, key_flags); + tooltip_manager_.IconClicked(); } } diff --git a/launcher/Launcher.h b/launcher/Launcher.h index 338fa1ab8..ac61275d6 100644 --- a/launcher/Launcher.h +++ b/launcher/Launcher.h @@ -39,8 +39,10 @@ #include "LauncherDragWindow.h" #include "LauncherHideMachine.h" #include "LauncherHoverMachine.h" +#include "unity-shared/MockableBaseWindow.h" #include "unity-shared/UBusWrapper.h" #include "SoftwareCenterLauncherIcon.h" +#include "TooltipManager.h" #ifdef USE_X11 # include "PointerBarrier.h" @@ -65,7 +67,7 @@ class Launcher : public unity::debug::Introspectable, NUX_DECLARE_OBJECT_TYPE(Launcher, nux::View); public: - Launcher(nux::BaseWindow* parent, NUX_FILE_LINE_PROTO); + Launcher(MockableBaseWindow* parent, NUX_FILE_LINE_PROTO); nux::Property<Display*> display; nux::Property<int> monitor; @@ -99,7 +101,7 @@ public: BacklightMode GetBacklightMode() const; bool IsBackLightModeToggles() const; - nux::BaseWindow* GetParent() const + MockableBaseWindow* GetParent() const { return _parent; }; @@ -222,6 +224,7 @@ private: bool OnScrollTimeout(); void SetMousePosition(int x, int y); + void SetIconUnderMouse(AbstractLauncherIcon::Ptr const& icon); void SetStateMouseOverLauncher(bool over_launcher); @@ -334,7 +337,7 @@ private: bool DndIsSpecialRequest(std::string const& uri) const; LauncherModel::Ptr _model; - nux::BaseWindow* _parent; + MockableBaseWindow* _parent; nux::ObjectPtr<nux::View> _active_tooltip; QuicklistView* _active_quicklist; @@ -388,6 +391,7 @@ private: nux::ObjectPtr<LauncherDragWindow> _drag_window; LauncherHideMachine _hide_machine; LauncherHoverMachine _hover_machine; + TooltipManager tooltip_manager_; unity::DndData _dnd_data; nux::DndAction _drag_action; diff --git a/launcher/LauncherController.cpp b/launcher/LauncherController.cpp index f62ecc2be..25da39a3a 100644 --- a/launcher/LauncherController.cpp +++ b/launcher/LauncherController.cpp @@ -24,7 +24,6 @@ #include <Nux/Nux.h> #include <Nux/HLayout.h> -#include <Nux/BaseWindow.h> #include <NuxCore/Logger.h> #include <UnityCore/DesktopUtilities.h> @@ -68,6 +67,11 @@ const std::string DBUS_INTROSPECTION = " <arg type='s' name='aptdaemon_task' direction='in'/>" " </method>" "" + " <method name='UpdateLauncherIconFavoriteState'>" + " <arg type='s' name='icon_uri' direction='in'/>" + " <arg type='b' name='is_sticky' direction='in'/>" + " </method>" + "" " </interface>" "</node>"; } @@ -89,11 +93,16 @@ namespace const std::string RUNNING_APPS_URI = FavoriteStore::URI_PREFIX_UNITY + "running-apps"; const std::string DEVICES_URI = FavoriteStore::URI_PREFIX_UNITY + "devices"; } -} -GDBusInterfaceVTable Controller::Impl::interface_vtable = - { Controller::Impl::OnDBusMethodCall, NULL, NULL}; +std::string CreateAppUriNameFromDesktopPath(const std::string &desktop_path) +{ + if (desktop_path.empty()) + return ""; + + return FavoriteStore::URI_PREFIX_APP + DesktopUtilities::GetDesktopID(desktop_path); +} +} Controller::Impl::Impl(Controller* parent, XdndManager::Ptr const& xdnd_manager) : parent_(parent) @@ -111,10 +120,7 @@ Controller::Impl::Impl(Controller* parent, XdndManager::Ptr const& xdnd_manager) , launcher_key_press_time_(0) , last_dnd_monitor_(-1) , super_tap_duration_(0) - , dbus_owner_(g_bus_own_name(G_BUS_TYPE_SESSION, DBUS_NAME.c_str(), G_BUS_NAME_OWNER_FLAGS_NONE, - OnBusAcquired, nullptr, nullptr, this, nullptr)) - , gdbus_connection_(nullptr) - , reg_id_(0) + , dbus_server_(DBUS_NAME) { #ifdef USE_X11 edge_barriers_.options = parent_->options(); @@ -179,6 +185,10 @@ Controller::Impl::Impl(Controller* parent, XdndManager::Ptr const& xdnd_manager) xdnd_manager_->dnd_started.connect(sigc::mem_fun(this, &Impl::OnDndStarted)); xdnd_manager_->dnd_finished.connect(sigc::mem_fun(this, &Impl::OnDndFinished)); xdnd_manager_->monitor_changed.connect(sigc::mem_fun(this, &Impl::OnDndMonitorChanged)); + + dbus_server_.AddObjects(DBUS_INTROSPECTION, DBUS_PATH); + for (auto const& obj : dbus_server_.GetObjects()) + obj->SetMethodsCallsHandler(sigc::mem_fun(this, &Impl::OnDBusMethodCall)); } Controller::Impl::~Impl() @@ -191,11 +201,6 @@ Controller::Impl::~Impl() if (launcher_ptr) launcher_ptr->GetParent()->UnReference(); } - - if (gdbus_connection_ && reg_id_) - g_dbus_connection_unregister_object(gdbus_connection_, reg_id_); - - g_bus_unown_name(dbus_owner_); } void Controller::Impl::EnsureLaunchers(int primary, std::vector<nux::Geometry> const& monitors) @@ -216,7 +221,7 @@ void Controller::Impl::EnsureLaunchers(int primary, std::vector<nux::Geometry> c launchers[i] = nux::ObjectPtr<Launcher>(CreateLauncher()); } - int monitor = (num_launchers == 1) ? primary : i; + int monitor = (num_launchers == 1 && num_monitors > 1) ? primary : i; if (launchers[i]->monitor() != monitor) { @@ -314,7 +319,7 @@ void Controller::Impl::OnDndMonitorChanged(int monitor) Launcher* Controller::Impl::CreateLauncher() { - nux::BaseWindow* launcher_window = new nux::BaseWindow(TEXT("LauncherWindow")); + auto* launcher_window = new MockableBaseWindow(TEXT("LauncherWindow")); Launcher* launcher = new Launcher(launcher_window); launcher->options = parent_->options(); @@ -329,7 +334,10 @@ Launcher* Controller::Impl::CreateLauncher() launcher_window->SetLayout(layout); launcher_window->SetBackgroundColor(nux::color::Transparent); launcher_window->ShowWindow(true); - launcher_window->EnableInputWindow(true, launcher::window_title, false, false); + + if (nux::GetWindowThread()->IsEmbeddedWindow()) + launcher_window->EnableInputWindow(true, launcher::window_title, false, false); + launcher_window->InputWindowEnableStruts(parent_->options()->hide_mode == LAUNCHER_HIDE_NEVER); launcher_window->SetEnterFocusInputArea(launcher); @@ -348,7 +356,7 @@ void Controller::Impl::OnLauncherAddRequest(std::string const& icon_uri, Abstrac if (icon_uri.find(FavoriteStore::URI_PREFIX_FILE) == 0) { auto const& desktop_path = icon_uri.substr(FavoriteStore::URI_PREFIX_FILE.length()); - app_uri = FavoriteStore::URI_PREFIX_APP + DesktopUtilities::GetDesktopID(desktop_path); + app_uri = local::CreateAppUriNameFromDesktopPath(desktop_path); } auto const& icon = GetIconByUri(app_uri.empty() ? icon_uri : app_uri); @@ -433,6 +441,62 @@ void Controller::Impl::SaveIconsOrder() } void +Controller::Impl::OnLauncherUpdateIconStickyState(std::string const& icon_uri, bool sticky) +{ + if (icon_uri.empty()) + return; + + std::string target_uri = icon_uri; + if (icon_uri.find(FavoriteStore::URI_PREFIX_FILE) == 0) + { + auto const& desktop_path = + icon_uri.substr(FavoriteStore::URI_PREFIX_FILE.length()); + + // app uri instead + target_uri = local::CreateAppUriNameFromDesktopPath(desktop_path); + } + auto const& existing_icon_entry = + GetIconByUri(target_uri); + + if (existing_icon_entry) + { + // use the backgroung mechanism of model updates & propagation + bool should_update = (existing_icon_entry->IsSticky() != sticky); + if (should_update) + { + if (sticky) + { + existing_icon_entry->Stick(true); + } + else + { + existing_icon_entry->UnStick(); + } + + SortAndUpdate(); + } + } + else + { + FavoriteStore& favorite_store = FavoriteStore::Instance(); + + bool should_update = (favorite_store.IsFavorite(target_uri) != sticky); + if (should_update) + { + if (sticky) + { + favorite_store.AddFavorite(target_uri, -1); + RegisterIcon(CreateFavoriteIcon(target_uri)); + } + else + { + favorite_store.RemoveFavorite(target_uri); + } + } + } +} + +void Controller::Impl::OnLauncherAddRequestSpecial(std::string const& path, std::string const& aptdaemon_trans_id, std::string const& icon_path, @@ -525,7 +589,7 @@ void Controller::Impl::OnLauncherEntryRemoteRemoved(LauncherEntryRemote::Ptr con void Controller::Impl::OnFavoriteStoreFavoriteAdded(std::string const& entry, std::string const& pos, bool before) { - if (entry == local::RUNNING_APPS_URI || entry == local::DEVICES_URI || entry == expo_icon_->RemoteUri()) + if (entry == local::RUNNING_APPS_URI || entry == local::DEVICES_URI) { // Since the running apps and the devices are always shown, when added to // the model, we only have to re-order them @@ -570,11 +634,12 @@ void Controller::Impl::OnFavoriteStoreFavoriteAdded(std::string const& entry, st void Controller::Impl::OnFavoriteStoreFavoriteRemoved(std::string const& entry) { - if (entry == local::RUNNING_APPS_URI || entry == local::DEVICES_URI || entry == expo_icon_->RemoteUri()) + if (entry == local::RUNNING_APPS_URI || entry == local::DEVICES_URI) { // Since the running apps and the devices are always shown, when added to // the model, we only have to re-order them ResetIconPriorities(); + SaveIconsOrder(); return; } @@ -595,7 +660,6 @@ void Controller::Impl::ResetIconPriorities() auto const& apps_icons = model_->GetSublist<ApplicationLauncherIcon>(); auto const& volumes_icons = model_->GetSublist<VolumeLauncherIcon>(); bool running_apps_found = false; - bool expo_icon_found = false; bool volumes_found = false; for (auto const& fav : favs) @@ -622,10 +686,6 @@ void Controller::Impl::ResetIconPriorities() volumes_found = true; continue; } - else if (fav == expo_icon_->RemoteUri()) - { - expo_icon_found = true; - } auto const& icon = GetIconByUri(fav); @@ -642,9 +702,6 @@ void Controller::Impl::ResetIconPriorities() } } - if (!expo_icon_found) - expo_icon_->SetSortPriority(++sort_priority_); - if (!volumes_found) { for (auto const& ico : volumes_icons) @@ -655,9 +712,6 @@ void Controller::Impl::ResetIconPriorities() } model_->Sort(); - - if (!expo_icon_found) - SaveIconsOrder(); } void Controller::Impl::UpdateNumWorkspaces(int workspaces) @@ -825,8 +879,6 @@ AbstractLauncherIcon::Ptr Controller::Impl::CreateFavoriteIcon(std::string const if (!app || app->seen()) return result; - // Sticky apps are those that are in the launcher when not running. - app->sticky = true; result = AbstractLauncherIcon::Ptr(new ApplicationLauncherIcon(app)); } else if (icon_uri.find(FavoriteStore::URI_PREFIX_DEVICE) == 0) @@ -923,12 +975,33 @@ void Controller::Impl::AddDevices() } } +void Controller::Impl::MigrateFavorites() +{ + // This migrates favorites to new format, ensuring that upgrades won't lose anything + auto& favorites = FavoriteStore::Instance(); + auto const& favs = favorites.GetFavorites(); + + auto fav_it = std::find_if(begin(favs), end(favs), [](std::string const& fav) { + return (fav.find(FavoriteStore::URI_PREFIX_UNITY) != std::string::npos); + }); + + if (fav_it == end(favs)) + { + favorites.AddFavorite(local::RUNNING_APPS_URI, -1); + favorites.AddFavorite(expo_icon_->RemoteUri(), -1); + favorites.AddFavorite(local::DEVICES_URI, -1); + } +} + void Controller::Impl::SetupIcons() { + MigrateFavorites(); + auto& favorite_store = FavoriteStore::Instance(); FavoriteList const& favs = favorite_store.GetFavorites(); bool running_apps_added = false; bool devices_added = false; + for (auto const& fav_uri : favs) { if (fav_uri == local::RUNNING_APPS_URI) @@ -956,23 +1029,15 @@ void Controller::Impl::SetupIcons() AddRunningApps(); } - if (model_->IconIndex(expo_icon_) < 0) - { - LOG_INFO(logger) << "Adding expo icon"; - RegisterIcon(CreateFavoriteIcon(expo_icon_->RemoteUri()), ++sort_priority_); - } - if (!devices_added) { LOG_INFO(logger) << "Adding devices"; AddDevices(); } - if (std::find(favs.begin(), favs.end(), expo_icon_->RemoteUri()) == favs.end()) - SaveIconsOrder(); - ApplicationManager::Default().application_started .connect(sigc::mem_fun(this, &Impl::OnApplicationStarted)); + device_section_.icon_added.connect(sigc::mem_fun(this, &Impl::OnDeviceIconAdded)); favorite_store.favorite_added.connect(sigc::mem_fun(this, &Impl::OnFavoriteStoreFavoriteAdded)); favorite_store.favorite_removed.connect(sigc::mem_fun(this, &Impl::OnFavoriteStoreFavoriteRemoved)); @@ -1181,7 +1246,7 @@ void Controller::HandleLauncherKeyRelease(bool was_tap, int when) } } -bool Controller::HandleLauncherKeyEvent(Display *display, unsigned int key_sym, unsigned long key_code, unsigned long key_state, char* key_string) +bool Controller::HandleLauncherKeyEvent(Display *display, unsigned int key_sym, unsigned long key_code, unsigned long key_state, char* key_string, Time timestamp) { LauncherModel::iterator it; @@ -1197,9 +1262,9 @@ bool Controller::HandleLauncherKeyEvent(Display *display, unsigned int key_sym, if (TimeUtil::TimeDelta(¤t, &last_action_time) > local::ignore_repeat_shortcut_duration) { if (g_ascii_isdigit((gchar)(*it)->GetShortcut()) && (key_state & ShiftMask)) - (*it)->OpenInstance(ActionArg(ActionArg::LAUNCHER, 0)); + (*it)->OpenInstance(ActionArg(ActionArg::LAUNCHER, 0, timestamp)); else - (*it)->Activate(ActionArg(ActionArg::LAUNCHER, 0)); + (*it)->Activate(ActionArg(ActionArg::LAUNCHER, 0, timestamp)); } // disable the "tap on super" check @@ -1319,8 +1384,10 @@ void Controller::KeyNavTerminate(bool activate) if (activate) { - pimpl->sources_.AddIdle([this] { - pimpl->model_->Selection()->Activate(ActionArg(ActionArg::LAUNCHER, 0)); + auto timestamp = nux::GetWindowThread()->GetGraphicsDisplay().GetCurrentEvent().x11_timestamp; + + pimpl->sources_.AddIdle([this, timestamp] { + pimpl->model_->Selection()->Activate(ActionArg(ActionArg::LAUNCHER, 0, timestamp)); return false; }); } @@ -1420,10 +1487,12 @@ void Controller::Impl::ReceiveLauncherKeyPress(unsigned long eventType, // <SPACE> (open a new instance) case NUX_VK_SPACE: - model_->Selection()->OpenInstance(ActionArg(ActionArg::LAUNCHER, 0)); + { + auto timestamp = nux::GetWindowThread()->GetGraphicsDisplay().GetCurrentEvent().x11_timestamp; + model_->Selection()->OpenInstance(ActionArg(ActionArg::LAUNCHER, 0, timestamp)); parent_->KeyNavTerminate(false); break; - + } // <RETURN> (start/activate currently selected icon) case NUX_VK_ENTER: case NUX_KP_ENTER: @@ -1450,50 +1519,29 @@ void Controller::Impl::OpenQuicklist() } } -void Controller::Impl::OnBusAcquired(GDBusConnection* connection, const gchar* name, gpointer user_data) -{ - GDBusNodeInfo* introspection_data = g_dbus_node_info_new_for_xml(DBUS_INTROSPECTION.c_str(), nullptr); - - if (!introspection_data) - { - LOG_WARNING(logger) << "No introspection data loaded. Won't get dynamic launcher addition."; - return; - } - - auto self = static_cast<Controller::Impl*>(user_data); - - self->gdbus_connection_ = connection; - self->reg_id_ = g_dbus_connection_register_object(connection, DBUS_PATH.c_str(), - introspection_data->interfaces[0], - &interface_vtable, user_data, - nullptr, nullptr); - if (!self->reg_id_) - { - LOG_WARNING(logger) << "Object registration failed. Won't get dynamic launcher addition."; - } - - g_dbus_node_info_unref(introspection_data); -} - -void Controller::Impl::OnDBusMethodCall(GDBusConnection* connection, const gchar* sender, - const gchar* object_path, const gchar* interface_name, - const gchar* method_name, GVariant* parameters, - GDBusMethodInvocation* invocation, gpointer user_data) +GVariant* Controller::Impl::OnDBusMethodCall(std::string const& method, GVariant *parameters) { - if (g_strcmp0(method_name, "AddLauncherItemFromPosition") == 0) + if (method == "AddLauncherItemFromPosition") { - auto self = static_cast<Controller::Impl*>(user_data); glib::String icon, icon_title, desktop_file, aptdaemon_task; gint icon_x, icon_y, icon_size; g_variant_get(parameters, "(ssiiiss)", &icon_title, &icon, &icon_x, &icon_y, &icon_size, &desktop_file, &aptdaemon_task); - self->OnLauncherAddRequestSpecial(desktop_file.Str(), aptdaemon_task.Str(), - icon.Str(), icon_x, icon_y, icon_size); + OnLauncherAddRequestSpecial(desktop_file.Str(), aptdaemon_task.Str(), + icon.Str(), icon_x, icon_y, icon_size); + } + else if (method == "UpdateLauncherIconFavoriteState") + { + gboolean is_sticky; + glib::String icon_uri; + g_variant_get(parameters, "(sb)", &icon_uri, &is_sticky); - g_dbus_method_invocation_return_value(invocation, nullptr); + OnLauncherUpdateIconStickyState(icon_uri.Str(), is_sticky); } + + return nullptr; } } // namespace launcher diff --git a/launcher/LauncherController.h b/launcher/LauncherController.h index 04504ebc8..d4c0c7744 100644 --- a/launcher/LauncherController.h +++ b/launcher/LauncherController.h @@ -70,7 +70,8 @@ public: unsigned int key_sym, unsigned long key_code, unsigned long key_state, - char* key_string); + char* key_string, + Time timestamp); void KeyNavActivate(); void KeyNavGrab(); diff --git a/launcher/LauncherControllerPrivate.h b/launcher/LauncherControllerPrivate.h index b275ae0de..af2ced337 100644 --- a/launcher/LauncherControllerPrivate.h +++ b/launcher/LauncherControllerPrivate.h @@ -24,6 +24,7 @@ #define LAUNCHER_CONTROLLER_PRIVATE_H #include <Nux/Nux.h> +#include <UnityCore/GLibDBusServer.h> #include "AbstractLauncherIcon.h" #include "DeviceLauncherSection.h" @@ -71,6 +72,7 @@ public: void OnLauncherAddRequest(std::string const& icon_uri, AbstractLauncherIcon::Ptr const& before); void OnLauncherAddRequestSpecial(std::string const& path, std::string const& aptdaemon_trans_id, std::string const& icon_path, int icon_x, int icon_y, int icon_size); + void OnLauncherUpdateIconStickyState(std::string const& desktop_file, bool sticky); void OnLauncherRemoveRequest(AbstractLauncherIcon::Ptr const& icon); void OnLauncherEntryRemoteAdded(LauncherEntryRemote::Ptr const& entry); @@ -91,6 +93,7 @@ public: SoftwareCenterLauncherIcon::Ptr CreateSCLauncherIcon(std::string const& file_path, std::string const& aptdaemon_trans_id, std::string const& icon_path); void SetupIcons(); + void MigrateFavorites(); void AddRunningApps(); void AddDevices(); @@ -115,14 +118,7 @@ public: void OnDndStarted(std::string const& data, int monitor); void OnDndFinished(); void OnDndMonitorChanged(int monitor); - - static void OnBusAcquired(GDBusConnection* connection, const gchar* name, gpointer user_data); - static void OnDBusMethodCall(GDBusConnection* connection, const gchar* sender, const gchar* object_path, - const gchar* interface_name, const gchar* method_name, - GVariant* parameters, GDBusMethodInvocation* invocation, - gpointer user_data); - - static GDBusInterfaceVTable interface_vtable; + GVariant* OnDBusMethodCall(std::string const& method, GVariant *parameters); Controller* parent_; LauncherModel::Ptr model_; @@ -151,10 +147,7 @@ public: int last_dnd_monitor_; int super_tap_duration_; - unsigned dbus_owner_; - GDBusConnection* gdbus_connection_; - unsigned reg_id_; - + glib::DBusServer dbus_server_; glib::SourceManager sources_; UBusManager ubus; diff --git a/launcher/LauncherIcon.cpp b/launcher/LauncherIcon.cpp index f34d7fd65..b0a9a9425 100644 --- a/launcher/LauncherIcon.cpp +++ b/launcher/LauncherIcon.cpp @@ -106,6 +106,7 @@ LauncherIcon::LauncherIcon(IconType type) tooltip_text = "blank"; position = Position::FLOATING; + removed = false; // FIXME: the abstraction is already broken, should be fixed for O // right now, hooking the dynamic quicklist the less ugly possible way @@ -230,7 +231,7 @@ LauncherIcon::OpenInstance(ActionArg arg) if (wm.IsScaleActive()) wm.TerminateScale(); - OpenInstanceLauncherIcon(); + OpenInstanceLauncherIcon(arg.timestamp); UpdateQuirkTime(Quirk::LAST_ACTION); } @@ -527,23 +528,12 @@ void LauncherIcon::RecvMouseEnter(int monitor) { _last_monitor = monitor; - if (QuicklistManager::Default()->Current()) - { - // A quicklist is active - return; - } - - ShowTooltip(); } void LauncherIcon::RecvMouseLeave(int monitor) { _last_monitor = -1; _allow_quicklist_to_show = true; - - if (_tooltip) - _tooltip->ShowWindow(false); - tooltip_visible.emit(nux::ObjectPtr<nux::View>(nullptr)); } bool LauncherIcon::OpenQuicklist(bool select_first_item, int monitor) @@ -661,7 +651,9 @@ void LauncherIcon::RecvMouseUp(int button, int monitor, unsigned long key_flags) void LauncherIcon::RecvMouseClick(int button, int monitor, unsigned long key_flags) { - ActionArg arg(ActionArg::LAUNCHER, button); + auto timestamp = nux::GetWindowThread()->GetGraphicsDisplay().GetCurrentEvent().x11_timestamp; + + ActionArg arg(ActionArg::LAUNCHER, button, timestamp); arg.monitor = monitor; bool shift_pressed = nux::GetKeyModifierState(key_flags, nux::NUX_STATE_SHIFT); diff --git a/launcher/LauncherIcon.h b/launcher/LauncherIcon.h index b6712796c..af3f0bed1 100644 --- a/launcher/LauncherIcon.h +++ b/launcher/LauncherIcon.h @@ -250,7 +250,7 @@ protected: virtual void ActivateLauncherIcon(ActionArg arg) {} - virtual void OpenInstanceLauncherIcon() {} + virtual void OpenInstanceLauncherIcon(Time timestamp) {} virtual bool HandlesSpread () { return false; } diff --git a/launcher/LauncherModel.cpp b/launcher/LauncherModel.cpp index 202235d9b..a9e694924 100644 --- a/launcher/LauncherModel.cpp +++ b/launcher/LauncherModel.cpp @@ -49,7 +49,8 @@ unity::debug::Introspectable::IntrospectableList LauncherModel::GetIntrospectabl introspection_results_.clear(); for (auto icon : _inner) - introspection_results_.push_back(icon.GetPointer()); + if (!icon->removed) + introspection_results_.push_back(icon.GetPointer()); return introspection_results_; } @@ -139,6 +140,8 @@ void LauncherModel::RemoveIcon(AbstractLauncherIcon::Ptr const& icon) void LauncherModel::OnIconRemove(AbstractLauncherIcon::Ptr const& icon) { + icon->removed = true; + timeouts_.AddTimeout(1000, [this, icon] { RemoveIcon(icon); return false; diff --git a/launcher/MockLauncherIcon.h b/launcher/MockLauncherIcon.h index 147b34564..b6d512aa7 100644 --- a/launcher/MockLauncherIcon.h +++ b/launcher/MockLauncherIcon.h @@ -68,6 +68,7 @@ public: , type_(type) , sort_priority_(DefaultPriority(type)) , remote_uri_("fake") + , is_tooltip_visible_(false) { tooltip_text = "Mock Icon"; position = Position::FLOATING; @@ -80,7 +81,9 @@ public: void AddProperties(GVariantBuilder* builder) {} - void HideTooltip() {} + void ShowTooltip() { is_tooltip_visible_ = true; } + void HideTooltip() { is_tooltip_visible_ = false; } + bool IsTooltipVisible() { return is_tooltip_visible_; } void SetShortcut(guint64 shortcut) {} @@ -366,6 +369,7 @@ private: timespec quirk_times_[unsigned(Quirk::LAST)]; std::map<int, nux::Point3> center_; std::string remote_uri_; + bool is_tooltip_visible_; }; } diff --git a/launcher/PointerBarrier.cpp b/launcher/PointerBarrier.cpp index 1e3876c16..5d513c5b3 100644 --- a/launcher/PointerBarrier.cpp +++ b/launcher/PointerBarrier.cpp @@ -43,6 +43,8 @@ PointerBarrierWrapper::PointerBarrierWrapper() , max_velocity_multiplier(1.0f) , direction(BOTH) , event_base_(0) + , last_event_(0) + , first_event_(false) , barrier(0) , smoothing_count_(0) , smoothing_accum_(0) @@ -114,12 +116,22 @@ void PointerBarrierWrapper::EmitCurrentData(int event_id, int x, int y) return; int velocity = std::min<int>(600 * max_velocity_multiplier, smoothing_accum_ / smoothing_count_); + SendBarrierEvent(x, y, velocity, event_id); + + smoothing_accum_ = 0; + smoothing_count_ = 0; +} + +void PointerBarrierWrapper::SendBarrierEvent(int x, int y, int velocity, int event_id) +{ auto event = std::make_shared<BarrierEvent>(x, y, velocity, event_id); barrier_event.emit(this, event); +} - smoothing_accum_ = 0; - smoothing_count_ = 0; +bool PointerBarrierWrapper::IsFirstEvent() const +{ + return first_event_; } bool PointerBarrierWrapper::HandleEvent(XEvent xevent) @@ -138,9 +150,9 @@ bool PointerBarrierWrapper::HandleEvent(XEvent xevent) /* If the barrier is released, just emit the current event without * waiting, so there won't be any delay on releasing the barrier. */ smoothing_timeout_.reset(); - auto event = std::make_shared<BarrierEvent>(notify_event->x, notify_event->y, - notify_event->velocity, notify_event->event_id); - barrier_event.emit(this, event); + + SendBarrierEvent(notify_event->x, notify_event->y, + notify_event->velocity, notify_event->event_id); } else if (!smoothing_timeout_) { @@ -148,15 +160,24 @@ bool PointerBarrierWrapper::HandleEvent(XEvent xevent) int y = notify_event->y; int event = notify_event->event_id; - auto smoothing_cb = [&, event, x, y] () + // If we are a new event, don't delay sending the first event + if (last_event_ != event) { + first_event_ = true; + last_event_ = event; + + SendBarrierEvent(notify_event->x, notify_event->y, + notify_event->velocity, notify_event->event_id); + + first_event_ = false; + } + + smoothing_timeout_.reset(new glib::Timeout(smoothing, [this, event, x, y] () { EmitCurrentData(event, x, y); smoothing_timeout_.reset(); return false; - }; - - smoothing_timeout_.reset(new glib::Timeout(smoothing, smoothing_cb)); + })); } } diff --git a/launcher/PointerBarrier.h b/launcher/PointerBarrier.h index 7a796950d..6576c090e 100644 --- a/launcher/PointerBarrier.h +++ b/launcher/PointerBarrier.h @@ -86,6 +86,8 @@ public: sigc::signal<void, PointerBarrierWrapper*, BarrierEvent::Ptr> barrier_event; + bool IsFirstEvent() const; + protected: void EmitCurrentData(int event_id, int x, int y); bool HandleEvent(XEvent event); @@ -93,7 +95,11 @@ protected: private: static bool HandleEventWrapper(XEvent event, void* data); + void SendBarrierEvent(int x, int y, int velocity, int event_id); + int event_base_; + int last_event_; + bool first_event_; PointerBarrier barrier; int smoothing_count_; diff --git a/launcher/StandaloneLauncher.cpp b/launcher/StandaloneLauncher.cpp index ccc5e11e4..777951f6f 100644 --- a/launcher/StandaloneLauncher.cpp +++ b/launcher/StandaloneLauncher.cpp @@ -64,7 +64,6 @@ private: { SetupBackground(); controller.reset(new launcher::Controller(std::make_shared<XdndManager>())); - controller->launcher().GetParent()->EnableInputWindow(false); UScreen* uscreen = UScreen::GetDefault(); std::vector<nux::Geometry> fake_monitor({nux::Geometry(0, 0, win_size.width, win_size.height)}); diff --git a/launcher/SwitcherController.cpp b/launcher/SwitcherController.cpp index 684918cef..89922e006 100644 --- a/launcher/SwitcherController.cpp +++ b/launcher/SwitcherController.cpp @@ -139,6 +139,11 @@ SwitcherView::Ptr Controller::GetView() const return impl_->GetView(); } +bool Controller::IsDetailViewShown() +{ + return impl_->IsDetailViewShown(); +} + void Controller::SetDetail(bool value, unsigned int min_windows) { impl_->SetDetail(value, min_windows); @@ -421,8 +426,9 @@ void Controller::Impl::Hide(bool accept_state) Selection selection = GetCurrentSelection(); if (selection.application_) { + Time timestamp = -1; selection.application_->Activate(ActionArg(ActionArg::SWITCHER, 0, - selection.window_)); + timestamp, selection.window_)); } } @@ -520,6 +526,11 @@ SwitcherView::Ptr Controller::Impl::GetView() const return view_; } +bool Controller::Impl::IsDetailViewShown() +{ + return model_ && model_->detail_selection(); +} + void Controller::Impl::SetDetail(bool value, unsigned int min_windows) { if (value && model_->DetailXids().size() >= min_windows) diff --git a/launcher/SwitcherController.h b/launcher/SwitcherController.h index 29c5b7e7c..f291b7182 100644 --- a/launcher/SwitcherController.h +++ b/launcher/SwitcherController.h @@ -98,6 +98,7 @@ public: void Select(int index); + bool IsDetailViewShown(); void SetDetail(bool detail, unsigned int min_windows = 1); diff --git a/launcher/SwitcherControllerImpl.h b/launcher/SwitcherControllerImpl.h index 5734f1b05..9a877e5d0 100644 --- a/launcher/SwitcherControllerImpl.h +++ b/launcher/SwitcherControllerImpl.h @@ -56,6 +56,7 @@ struct Controller::Impl void NextDetail(); void PrevDetail(); + bool IsDetailViewShown(); void SetDetail(bool detail, unsigned int min_windows = 1); void SelectFirstItem(); diff --git a/launcher/SwitcherModel.cpp b/launcher/SwitcherModel.cpp index afaec75fb..cb2d41a73 100644 --- a/launcher/SwitcherModel.cpp +++ b/launcher/SwitcherModel.cpp @@ -39,11 +39,18 @@ SwitcherModel::SwitcherModel(std::vector<AbstractLauncherIcon::Ptr> const& icons , index_(0) , last_index_(0) { + // When using Webapps, there are more than one active icon, so let's just pick + // up the first one found which is the web browser. + bool found = false; + for (auto const& application : applications_) { AddChild(application.GetPointer()); - if (application->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE)) + if (application->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE) && !found) + { last_active_application_ = application; + found = true; + } } } diff --git a/launcher/TooltipManager.cpp b/launcher/TooltipManager.cpp new file mode 100644 index 000000000..c34783233 --- /dev/null +++ b/launcher/TooltipManager.cpp @@ -0,0 +1,126 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2013 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 <http://www.gnu.org/licenses/>. + * + * Authored by: Jacob Edwards <j.johan.edwards@gmail.com> + */ + +#include "TooltipManager.h" + +namespace unity +{ +namespace launcher +{ + +namespace +{ +const unsigned int TOOLTIPS_SHOW_TIMEOUT_LENGTH = 1000; +} + +TooltipManager::TooltipManager() + : show_tooltips_(false) + , hovered_(false) + , timer_locked_(false) +{} + +void TooltipManager::SetIcon(AbstractLauncherIcon::Ptr const& newIcon) +{ + if (icon_ == newIcon) + return; + + // Unlock hover timer, in case the previous icon had no valid tooltip + timer_locked_ = false; + + if (show_tooltips_) + { + // Show new tooltip, get rid of the old olne + if (icon_) + icon_->HideTooltip(); + if (newIcon) + newIcon->ShowTooltip(); + } + else if (!newIcon) + { + // Stop the hover timer for null launcher space + StopTimer(); + } + else + { + AbstractLauncherIcon::IconType type = newIcon->GetIconType(); + if ((type == AbstractLauncherIcon::IconType::HOME || + type == AbstractLauncherIcon::IconType::HUD) && + newIcon->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE)) + { + // Lock the hover timer for no valid tooltip cases + timer_locked_ = true; + StopTimer(); + } + } + + icon_ = newIcon; +} + +void TooltipManager::SetHover(bool on_launcher) +{ + if (hovered_ == on_launcher) + return; + hovered_ = on_launcher; + + if (show_tooltips_ && !hovered_) + { + show_tooltips_ = false; + if (icon_) + icon_->HideTooltip(); + } +} + +void TooltipManager::MouseMoved() +{ + if (!icon_ || show_tooltips_) + return; + + ResetTimer(); +} + +void TooltipManager::IconClicked() +{ + StopTimer(); + if (show_tooltips_ && icon_) + icon_->HideTooltip(); + + show_tooltips_ = false; + timer_locked_ = true; +} + +void TooltipManager::ResetTimer() +{ + if (timer_locked_) + return; + + hover_timer_.reset(new glib::Timeout(TOOLTIPS_SHOW_TIMEOUT_LENGTH)); + hover_timer_->Run([&] () { + show_tooltips_ = true; + icon_->ShowTooltip(); + return false; + }); +} + +void TooltipManager::StopTimer() +{ + hover_timer_.reset(); +} + +} // namespace launcher +} // namespace unity diff --git a/launcher/TooltipManager.h b/launcher/TooltipManager.h new file mode 100644 index 000000000..f61fc199f --- /dev/null +++ b/launcher/TooltipManager.h @@ -0,0 +1,57 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2013 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 <http://www.gnu.org/licenses/>. + * + * Authored by: Jacob Edwards <j.johan.edwards@gmail.com> + */ + +#ifndef TOOLTIPMANAGER +#define TOOLTIPMANAGER + +#include <boost/noncopyable.hpp> +#include <UnityCore/GLibSource.h> + +#include "AbstractLauncherIcon.h" + +namespace unity +{ +namespace launcher +{ + +class TooltipManager : public boost::noncopyable +{ +public: + TooltipManager(); + + void SetHover(bool on_launcher); + void SetIcon(AbstractLauncherIcon::Ptr const& newIcon); + void MouseMoved(); + void IconClicked(); + +private: + void ResetTimer(); + void StopTimer(); + + bool show_tooltips_; + bool hovered_; + AbstractLauncherIcon::Ptr icon_; + glib::Source::UniquePtr hover_timer_; + bool timer_locked_; +}; + +} // namespace launcher +} // namespace unity + +#endif diff --git a/launcher/XdndCollectionWindowImp.cpp b/launcher/XdndCollectionWindowImp.cpp index e39f373a7..b98075187 100644 --- a/launcher/XdndCollectionWindowImp.cpp +++ b/launcher/XdndCollectionWindowImp.cpp @@ -40,9 +40,14 @@ public: ShowWindow(true); PushToBack(); - // Hack to create the X Window as soon as possible. - EnableInputWindow(true, "XdndCollectionWindowImp"); - EnableInputWindow(false, "XdndCollectionWindowImp"); + + if (nux::GetWindowThread()->IsEmbeddedWindow()) + { + // Hack to create the X Window as soon as possible. + EnableInputWindow(true, "XdndCollectionWindowImp"); + EnableInputWindow(false, "XdndCollectionWindowImp"); + } + SetDndEnabled(false, true); uscreen->changed.connect(sigc::mem_fun(this, &PrivateWindow::OnScreenChanged)); @@ -100,13 +105,17 @@ void XdndCollectionWindowImp::Collect() // the launcher window and the dash window. Don't forget to call PushToBack as // soon as possible. window_->PushToFront(); - window_->EnableInputWindow(true, "XdndCollectionWindowImp"); + + if (nux::GetWindowThread()->IsEmbeddedWindow()) + window_->EnableInputWindow(true, "XdndCollectionWindowImp"); } void XdndCollectionWindowImp::Deactivate() { window_->PushToBack(); - window_->EnableInputWindow(false, "XdndCollectionWindowImp"); + + if (nux::GetWindowThread()->IsEmbeddedWindow()) + window_->EnableInputWindow(false, "XdndCollectionWindowImp"); } } |
