diff options
| author | Sam Spilsbury <sam.spilsbury@canonical.com> | 2013-03-22 11:33:00 +0800 |
|---|---|---|
| committer | Sam Spilsbury <sam.spilsbury@canonical.com> | 2013-03-22 11:33:00 +0800 |
| commit | fee726045ee0fdfd265b657fab792bfcab5809cc (patch) | |
| tree | 676e82804f443eb1f6856a7117d3611e58c031f0 /launcher | |
| parent | 8f7ba0c05f948efdcf21c28bd19bb23e51fd9849 (diff) | |
| parent | e9e3a104f7fbe33c9d7fa15cca5707fec75ff07a (diff) | |
Merge lp:unity and use the old fbo api
(bzr r3139.1.11)
Diffstat (limited to 'launcher')
32 files changed, 707 insertions, 341 deletions
diff --git a/launcher/AbstractLauncherIcon.h b/launcher/AbstractLauncherIcon.h index be9f65589..859ab56ba 100644 --- a/launcher/AbstractLauncherIcon.h +++ b/launcher/AbstractLauncherIcon.h @@ -41,10 +41,9 @@ namespace unity namespace launcher { -class ActionArg +struct ActionArg { -public: - enum Source + enum class Source { LAUNCHER, SWITCHER, @@ -52,25 +51,24 @@ public: }; ActionArg() - : source(OTHER) + : source(Source::OTHER) , button(0) + , timestamp(0) , target(0) , monitor(-1) - { - } + {} - ActionArg(Source source, int button, Time timestamp = -1, Window target = 0, int monitor = -1) + ActionArg(Source source, int button, unsigned long timestamp = 0, Window target = 0, int monitor = -1) : source(source) , button(button) , timestamp(timestamp) , target(target) , monitor(monitor) - { - } + {} Source source; int button; - Time timestamp; + unsigned long timestamp; Window target; int monitor; }; @@ -128,6 +126,12 @@ public: END }; + enum class ScrollDirection + { + UP, + DOWN + }; + virtual ~AbstractLauncherIcon() {} nux::Property<std::string> tooltip_text; @@ -135,6 +139,7 @@ public: nux::Property<Position> position; nux::Property<bool> removed; + virtual void ShowTooltip() = 0; virtual void HideTooltip() = 0; virtual void SetShortcut(guint64 shortcut) = 0; @@ -226,6 +231,8 @@ public: return static_cast<int>(type) * 1000; } + virtual void PerformScroll(ScrollDirection direction, Time timestamp) = 0; + sigc::signal<void, int, int, unsigned long> mouse_down; sigc::signal<void, int, int, unsigned long> mouse_up; sigc::signal<void, int, int, unsigned long> mouse_click; diff --git a/launcher/ApplicationLauncherIcon.cpp b/launcher/ApplicationLauncherIcon.cpp index ade59aacc..2e0e70691 100644 --- a/launcher/ApplicationLauncherIcon.cpp +++ b/launcher/ApplicationLauncherIcon.cpp @@ -60,6 +60,9 @@ ApplicationLauncherIcon::ApplicationLauncherIcon(ApplicationPtr const& app) : SimpleLauncherIcon(IconType::APPLICATION) , app_(app) , _startup_notification_timestamp(0) + , _last_scroll_timestamp(0) + , _last_scroll_direction(ScrollDirection::DOWN) + , _progressive_scroll(0) , use_custom_bg_color_(false) , bg_color_(nux::color::White) { @@ -87,68 +90,68 @@ ApplicationLauncherIcon::ApplicationLauncherIcon(ApplicationPtr const& app) // Lambda functions should be fine here because when the application the icon // is only ever removed when the application is closed. app->window_opened.connect([this](ApplicationWindow const&) { - EnsureWindowState(); - UpdateMenus(); - UpdateIconGeometries(GetCenters()); - }); - app->window_closed.connect([this]() { EnsureWindowState(); }); - app->window_moved.connect([this](ApplicationWindow const&) { EnsureWindowState(); }); + EnsureWindowState(); + UpdateMenus(); + UpdateIconGeometries(GetCenters()); + }); + app->window_closed.connect(sigc::mem_fun(this, &ApplicationLauncherIcon::EnsureWindowState)); + app->window_moved.connect(sigc::hide(sigc::mem_fun(this, &ApplicationLauncherIcon::EnsureWindowState))); app->urgent.changed.connect([this](bool const& urgent) { - LOG_DEBUG(logger) << tooltip_text() << " urgent now " << (urgent ? "true" : "false"); - SetQuirk(Quirk::URGENT, urgent); - }); + LOG_DEBUG(logger) << tooltip_text() << " urgent now " << (urgent ? "true" : "false"); + SetQuirk(Quirk::URGENT, urgent); + }); app->active.changed.connect([this](bool const& active) { - LOG_DEBUG(logger) << tooltip_text() << " active now " << (active ? "true" : "false"); - SetQuirk(Quirk::ACTIVE, active); - }); + LOG_DEBUG(logger) << tooltip_text() << " active now " << (active ? "true" : "false"); + SetQuirk(Quirk::ACTIVE, active); + }); app->running.changed.connect([this](bool const& running) { - LOG_DEBUG(logger) << tooltip_text() << " running now " << (running ? "true" : "false"); - SetQuirk(Quirk::RUNNING, running); - - if (running) - { - _source_manager.Remove(ICON_REMOVE_TIMEOUT); - - /* It can happen that these values are not set - * during initialization if the view is closed - * very early, so we need to make sure that they - * are updated as soon as the view is re-opened. */ - if (tooltip_text().empty()) - tooltip_text = app_->title(); - - if (icon_name == DEFAULT_ICON) - { - std::string icon = app_->icon(); - icon_name = (icon.empty() ? DEFAULT_ICON : icon); - } - - EnsureWindowState(); - UpdateIconGeometries(GetCenters()); - } - }); + LOG_DEBUG(logger) << tooltip_text() << " running now " << (running ? "true" : "false"); + SetQuirk(Quirk::RUNNING, running); + + if (running) + { + _source_manager.Remove(ICON_REMOVE_TIMEOUT); + + /* It can happen that these values are not set + * during initialization if the view is closed + * very early, so we need to make sure that they + * are updated as soon as the view is re-opened. */ + if (tooltip_text().empty()) + tooltip_text = app_->title(); + + if (icon_name == DEFAULT_ICON) + { + std::string icon = app_->icon(); + icon_name = (icon.empty() ? DEFAULT_ICON : icon); + } + + EnsureWindowState(); + UpdateIconGeometries(GetCenters()); + } + }); app->visible.changed.connect([this](bool const& visible) { - if (!IsSticky()) - SetQuirk(Quirk::VISIBLE, visible); - }); + if (!IsSticky()) + SetQuirk(Quirk::VISIBLE, visible); + }); app->closed.connect([this]() { - if (!IsSticky()) - { - SetQuirk(Quirk::VISIBLE, false); - - /* Use a timeout to remove the icon, this avoids - * that we remove an application that is going - * to be reopened soon. So applications that - * have a splash screen won't be removed from - * the launcher while the splash is closed and - * a new window is opened. */ - _source_manager.AddTimeoutSeconds(1, [&] { - Remove(); - return false; - }, ICON_REMOVE_TIMEOUT); - } - }); + if (!IsSticky()) + { + SetQuirk(Quirk::VISIBLE, false); + + /* Use a timeout to remove the icon, this avoids + * that we remove an application that is going + * to be reopened soon. So applications that + * have a splash screen won't be removed from + * the launcher while the splash is closed and + * a new window is opened. */ + _source_manager.AddTimeoutSeconds(1, [this] { + Remove(); + return false; + }, ICON_REMOVE_TIMEOUT); + } + }); WindowManager& wm = WindowManager::Default(); wm.window_minimized.connect(sigc::mem_fun(this, &ApplicationLauncherIcon::OnWindowMinimized)); @@ -259,7 +262,7 @@ void ApplicationLauncherIcon::ActivateLauncherIcon(ActionArg arg) * an unmapped (!= minimized) window around and * if so force "Focus" behaviour */ - if (arg.source != ActionArg::SWITCHER) + if (arg.source != ActionArg::Source::SWITCHER) { user_visible = app_->visible(); @@ -336,7 +339,7 @@ void ApplicationLauncherIcon::ActivateLauncherIcon(ActionArg arg) } else // #2 above { - if (arg.source != ActionArg::SWITCHER) + if (arg.source != ActionArg::Source::SWITCHER) { Spread(true, 0, false); } @@ -347,7 +350,7 @@ void ApplicationLauncherIcon::ActivateLauncherIcon(ActionArg arg) if (scaleWasActive) // #4 above { Focus(arg); - if (arg.source != ActionArg::SWITCHER) + if (arg.source != ActionArg::Source::SWITCHER) Spread(true, 0, false); } else // #3 above @@ -440,7 +443,7 @@ void ApplicationLauncherIcon::OnWindowMoved(guint32 moved_win) if (!app_->OwnsWindow(moved_win)) return; - _source_manager.AddTimeout(250, [&] { + _source_manager.AddTimeout(250, [this] { EnsureWindowState(); UpdateIconGeometries(GetCenters()); @@ -465,31 +468,32 @@ void ApplicationLauncherIcon::UpdateDesktopFile() glib::Object<GFile> desktop_file(g_file_new_for_path(_desktop_file.c_str())); _desktop_file_monitor = g_file_monitor_file(desktop_file, G_FILE_MONITOR_NONE, nullptr, nullptr); - 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* f, GFile*, GFileMonitorEvent event_type) { - switch (event_type) - { - case G_FILE_MONITOR_EVENT_DELETED: - { - 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(); - break; - default: - break; - } - }); - _gsignals.Add(sig); + g_file_monitor_set_rate_limit(_desktop_file_monitor, 2000); + + _gsignals.Add<void, GFileMonitor*, GFile*, GFile*, GFileMonitorEvent>(_desktop_file_monitor, "changed", + [this] (GFileMonitor*, GFile* f, GFile*, GFileMonitorEvent event_type) { + switch (event_type) + { + case G_FILE_MONITOR_EVENT_DELETED: + { + 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(); + break; + } + default: + break; + } + }); } } @@ -527,7 +531,7 @@ void ApplicationLauncherIcon::OpenInstanceWithUris(std::set<std::string> const& glib::Object<GdkAppLaunchContext> app_launch_context(gdk_display_get_app_launch_context(display)); _startup_notification_timestamp = timestamp; - if (_startup_notification_timestamp >= 0) + if (_startup_notification_timestamp > 0) gdk_app_launch_context_set_timestamp(app_launch_context, _startup_notification_timestamp); if (g_app_info_supports_uris(appInfo)) @@ -588,7 +592,7 @@ void ApplicationLauncherIcon::Focus(ActionArg arg) return; } - bool show_only_visible = arg.source == ActionArg::SWITCHER; + bool show_only_visible = arg.source == ActionArg::Source::SWITCHER; app_->Focus(show_only_visible, arg.monitor); } @@ -642,7 +646,7 @@ void ApplicationLauncherIcon::UpdateDesktopQuickList() { for (GList *l = dbusmenu_menuitem_get_children(_menu_desktop_shortcuts); l; l = l->next) { - _gsignals.Disconnect(l->data, "item-activated"); + _gsignals.Disconnect(l->data, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED); } } @@ -669,15 +673,12 @@ void ApplicationLauncherIcon::UpdateDesktopQuickList() dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, name); dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE); dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); - dbusmenu_menuitem_property_set(item, "shortcut-nick", nicks[index]); + std::string nick(nicks[index]); - auto sig = new glib::Signal<void, DbusmenuMenuitem*, gint>(item, "item-activated", - [&] (DbusmenuMenuitem* item, gint) { - const gchar *nick; - nick = dbusmenu_menuitem_property_get(item, "shortcut-nick"); - indicator_desktop_shortcuts_nick_exec(_desktop_shortcuts, nick); - }); - _gsignals.Add(sig); + _gsignals.Add<void, DbusmenuMenuitem*, gint>(item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + [this, nick] (DbusmenuMenuitem* item, unsigned) { + indicator_desktop_shortcuts_nick_exec(_desktop_shortcuts, nick.c_str()); + }); dbusmenu_menuitem_child_append(_menu_desktop_shortcuts, item); index++; @@ -726,8 +727,8 @@ void ApplicationLauncherIcon::EnsureMenuItemsWindowsReady() dbusmenu_menuitem_property_set_int(menu_item, QuicklistMenuItem::MAXIMUM_LABEL_WIDTH_PROPERTY, MAXIMUM_QUICKLIST_WIDTH); Window xid = w->window_id(); - _gsignals.Add<void, DbusmenuMenuitem*, int>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - [xid] (DbusmenuMenuitem*, int) { + _gsignals.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + [xid] (DbusmenuMenuitem*, unsigned) { WindowManager& wm = WindowManager::Default(); wm.Activate(xid); wm.Raise(xid); @@ -818,8 +819,8 @@ void ApplicationLauncherIcon::EnsureMenuItemsReady() dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); - _gsignals.Add<void, DbusmenuMenuitem*, int>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - [&] (DbusmenuMenuitem*, int) { + _gsignals.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + [this] (DbusmenuMenuitem*, unsigned) { ToggleSticky(); }); @@ -839,8 +840,8 @@ void ApplicationLauncherIcon::EnsureMenuItemsReady() dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); - _gsignals.Add<void, DbusmenuMenuitem*, int>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - [&] (DbusmenuMenuitem*, int) { + _gsignals.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + [this] (DbusmenuMenuitem*, unsigned) { Quit(); }); @@ -933,24 +934,19 @@ AbstractLauncherIcon::MenuItemsVector ApplicationLauncherIcon::GetMenus() else { glib::String app_name(g_markup_escape_text(app_->title().c_str(), -1)); - std::ostringstream bold_app_name; - bold_app_name << "<b>" << app_name << "</b>"; + std::string bold_app_name("<b>"+app_name.Str()+"</b>"); item = dbusmenu_menuitem_new(); dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, - bold_app_name.str().c_str()); - dbusmenu_menuitem_property_set_bool(item, - DBUSMENU_MENUITEM_PROP_ENABLED, - true); - dbusmenu_menuitem_property_set_bool(item, - QuicklistMenuItem::MARKUP_ENABLED_PROPERTY, - true); - - _gsignals.Add<void, DbusmenuMenuitem*, int>(item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - [&] (DbusmenuMenuitem*, int) { - _source_manager.AddIdle([&] { - ActivateLauncherIcon(ActionArg()); + bold_app_name.c_str()); + dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE); + dbusmenu_menuitem_property_set_bool(item, QuicklistMenuItem::MARKUP_ENABLED_PROPERTY, TRUE); + + _gsignals.Add<void, DbusmenuMenuitem*, unsigned>(item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + [this] (DbusmenuMenuitem*, unsigned timestamp) { + _source_manager.AddIdle([this, timestamp] { + ActivateLauncherIcon(ActionArg(ActionArg::Source::LAUNCHER, 0, timestamp)); return false; }); }); @@ -1104,7 +1100,7 @@ void ApplicationLauncherIcon::OnDndHovered() void ApplicationLauncherIcon::OnDndEnter() { /* Disabled, since the DND code is currently disabled as well. - _source_manager.AddTimeout(1000, [&] { + _source_manager.AddTimeout(1000, [this] { OnDndHovered(); return false; }, ICON_DND_OVER_TIMEOUT); @@ -1154,7 +1150,7 @@ nux::DndAction ApplicationLauncherIcon::OnQueryAcceptDrop(DndData const& dnd_dat void ApplicationLauncherIcon::OnAcceptDrop(DndData const& dnd_data) { - auto timestamp = nux::GetWindowThread()->GetGraphicsDisplay().GetCurrentEvent().x11_timestamp; + auto timestamp = nux::GetGraphicsDisplay()->GetCurrentEvent().x11_timestamp; OpenInstanceWithUris(ValidateUrisForLaunch(dnd_data), timestamp); } @@ -1171,7 +1167,7 @@ bool ApplicationLauncherIcon::ShowInSwitcher(bool current) } else { - for (int i = 0; i < max_num_monitors; i++) + for (int i = 0; i < max_num_monitors; ++i) { if (WindowVisibleOnMonitor(i)) { @@ -1222,6 +1218,94 @@ const std::set<std::string> ApplicationLauncherIcon::GetSupportedTypes() return supported_types; } +void PerformScrollUp(WindowList const& windows, unsigned int progressive_scroll) +{ + if (!progressive_scroll) + { + windows.at(1)->Focus(); + return; + } + else if (progressive_scroll == 1) + { + windows.back()->Focus(); + return; + } + + WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.at(windows.size() - progressive_scroll + 1)->window_id()); + windows.at(windows.size() - progressive_scroll + 1)->Focus(); +} + +void PerformScrollDown(WindowList const& windows, unsigned int progressive_scroll) +{ + if (!progressive_scroll) + { + WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.back()->window_id()); + windows.at(1)->Focus(); + return; + } + + WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.at(progressive_scroll)->window_id()); + windows.at(progressive_scroll)->Focus(); +} + +void ApplicationLauncherIcon::PerformScroll(ScrollDirection direction, Time timestamp) +{ + if (timestamp - _last_scroll_timestamp < 150) + return; + else if (timestamp - _last_scroll_timestamp > 1500 || direction != _last_scroll_direction) + _progressive_scroll = 0; + + _last_scroll_timestamp = timestamp; + _last_scroll_direction = direction; + + auto const& windows = GetWindowsOnCurrentDesktopInStackingOrder(); + if (windows.empty()) + return; + + if (!IsActive()) + { + windows.at(0)->Focus(); + return; + } + + if (windows.size() <= 1) + return; + + ++_progressive_scroll; + _progressive_scroll %= windows.size(); + + switch(direction) + { + case ScrollDirection::UP: + PerformScrollUp(windows, _progressive_scroll); + break; + case ScrollDirection::DOWN: + PerformScrollDown(windows, _progressive_scroll); + break; + } +} + +WindowList ApplicationLauncherIcon::GetWindowsOnCurrentDesktopInStackingOrder() +{ + auto windows = GetWindows(WindowFilter::ON_CURRENT_DESKTOP | WindowFilter::ON_ALL_MONITORS); + auto sorted_windows = WindowManager::Default().GetWindowsInStackingOrder(); + + // Order the windows + std::sort(windows.begin(), windows.end(), [&sorted_windows] (ApplicationWindowPtr const& win1, ApplicationWindowPtr const& win2) { + for (auto const& window : sorted_windows) + { + if (window == win1->window_id()) + return false; + else if (window == win2->window_id()) + return true; + } + + return true; + }); + + return windows; +} + std::string ApplicationLauncherIcon::GetName() const { return "ApplicationLauncherIcon"; diff --git a/launcher/ApplicationLauncherIcon.h b/launcher/ApplicationLauncherIcon.h index 04594aa48..8a604a6f7 100644 --- a/launcher/ApplicationLauncherIcon.h +++ b/launcher/ApplicationLauncherIcon.h @@ -68,6 +68,8 @@ public: std::vector<Window> WindowsOnViewport(); std::vector<Window> WindowsForMonitor(int monitor); + void PerformScroll(ScrollDirection direction, Time timestamp) override; + protected: void Remove(); void UpdateIconGeometries(std::vector<nux::Point3> center); @@ -124,9 +126,13 @@ private: WindowList GetWindows(WindowFilterMask filter = 0, int monitor = -1); const std::set<std::string> GetSupportedTypes(); std::string GetDesktopID(); + WindowList GetWindowsOnCurrentDesktopInStackingOrder(); std::string _remote_uri; Time _startup_notification_timestamp; + Time _last_scroll_timestamp; + ScrollDirection _last_scroll_direction; + unsigned int _progressive_scroll; std::set<std::string> _supported_types; std::map<std::string, glib::Object<DbusmenuClient>> _menu_clients; std::map<std::string, glib::Object<DbusmenuMenuitem>> _menu_items; 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/DeviceLauncherSection.cpp b/launcher/DeviceLauncherSection.cpp index b46e34f7c..41443eca7 100644 --- a/launcher/DeviceLauncherSection.cpp +++ b/launcher/DeviceLauncherSection.cpp @@ -32,8 +32,8 @@ DeviceLauncherSection::DeviceLauncherSection(AbstractVolumeMonitorWrapper::Ptr v DevicesSettings::Ptr devices_settings) : monitor_(volume_monitor) , devices_settings_(devices_settings) - , file_manager_opener_(new FileManagerOpenerImp) - , device_notification_display_(new DeviceNotificationDisplayImp) + , file_manager_opener_(std::make_shared<FileManagerOpenerImp>()) + , device_notification_display_(std::make_shared<DeviceNotificationDisplayImp>()) { monitor_->volume_added.connect(sigc::mem_fun(this, &DeviceLauncherSection::OnVolumeAdded)); monitor_->volume_removed.connect(sigc::mem_fun(this, &DeviceLauncherSection::OnVolumeRemoved)); diff --git a/launcher/FileManagerOpener.h b/launcher/FileManagerOpener.h index a318930bc..b96d495fd 100644 --- a/launcher/FileManagerOpener.h +++ b/launcher/FileManagerOpener.h @@ -20,7 +20,6 @@ #ifndef UNITYSHELL_FILEMANAGER_OPENER_H #define UNITYSHELL_FILEMANAGER_OPENER_H -#include <boost/noncopyable.hpp> #include <memory> #include <string> @@ -29,14 +28,18 @@ namespace unity namespace launcher { -class FileManagerOpener : private boost::noncopyable +class FileManagerOpener { public: typedef std::shared_ptr<FileManagerOpener> Ptr; + FileManagerOpener() = default; virtual ~FileManagerOpener() {} + virtual void Open(std::string const& uri, unsigned long long timestamp = 0) = 0; - virtual void Open(std::string const& uri) = 0; +private: + FileManagerOpener(FileManagerOpener const&) = delete; + FileManagerOpener& operator=(FileManagerOpener const&) = delete; }; } diff --git a/launcher/FileManagerOpenerImp.cpp b/launcher/FileManagerOpenerImp.cpp index 8fb2cd964..4d5068c26 100644 --- a/launcher/FileManagerOpenerImp.cpp +++ b/launcher/FileManagerOpenerImp.cpp @@ -1,6 +1,6 @@ // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* - * Copyright (C) 2012 Canonical Ltd + * Copyright (C) 2012-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 @@ -15,20 +15,43 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + * Marco Trevisan <marco.trevisan@canonical.com> */ -#include <gio/gio.h> - #include "FileManagerOpenerImp.h" +#include <NuxCore/Logger.h> +#include <UnityCore/GLibWrapper.h> +#include <gdk/gdk.h> namespace unity { namespace launcher { -void FileManagerOpenerImp::Open(std::string const& uri) +DECLARE_LOGGER(logger, "unity.launcher.filemanager.opener.imp"); + +void FileManagerOpenerImp::Open(std::string const& uri, unsigned long long timestamp) { - g_app_info_launch_default_for_uri(uri. c_str(), nullptr, nullptr); + if (uri.empty()) + { + LOG_ERROR(logger) << "Impossible to open an empty location"; + return; + } + + glib::Error error; + GdkDisplay* display = gdk_display_get_default(); + glib::Object<GdkAppLaunchContext> context(gdk_display_get_app_launch_context(display)); + + if (timestamp > 0) + gdk_app_launch_context_set_timestamp(context, timestamp); + + auto const& gcontext = glib::object_cast<GAppLaunchContext>(context); + g_app_info_launch_default_for_uri(uri.c_str(), gcontext, &error); + + if (error) + { + LOG_ERROR(logger) << "Impossible to open the location: " << error.Message(); + } } } diff --git a/launcher/FileManagerOpenerImp.h b/launcher/FileManagerOpenerImp.h index 6a4d62562..09785ed5b 100644 --- a/launcher/FileManagerOpenerImp.h +++ b/launcher/FileManagerOpenerImp.h @@ -30,7 +30,7 @@ namespace launcher class FileManagerOpenerImp : public FileManagerOpener { public: - virtual void Open(std::string const& uri); + virtual void Open(std::string const& uri, unsigned long long timestamp); }; } 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 81eedd501..49e694f22 100644 --- a/launcher/Launcher.cpp +++ b/launcher/Launcher.cpp @@ -91,6 +91,9 @@ const int START_DRAGICON_DURATION = 250; const int MOUSE_DEADZONE = 15; const float DRAG_OUT_PIXELS = 300.0f; +const int SCROLL_AREA_HEIGHT = 24; +const int SCROLL_FPS = 30; + const std::string START_DRAGICON_TIMEOUT = "start-dragicon-timeout"; const std::string SCROLL_TIMEOUT = "scroll-timeout"; const std::string ANIMATION_IDLE = "animation-idle"; @@ -101,7 +104,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 +289,20 @@ 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; } bool Launcher::MouseBeyondDragThreshold() const @@ -1210,8 +1227,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 +1269,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 +1335,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(); @@ -1485,27 +1505,18 @@ void Launcher::SetHover(bool hovered) bool Launcher::MouseOverTopScrollArea() { - return _mouse_position.y < panel::Style::Instance().panel_height; -} - -bool Launcher::MouseOverTopScrollExtrema() -{ - return _mouse_position.y == 0; + return _mouse_position.y < SCROLL_AREA_HEIGHT; } bool Launcher::MouseOverBottomScrollArea() { - return _mouse_position.y > GetGeometry().height - panel::Style::Instance().panel_height; -} - -bool Launcher::MouseOverBottomScrollExtrema() -{ - return _mouse_position.y == GetGeometry().height - 1; + return _mouse_position.y >= GetGeometry().height - SCROLL_AREA_HEIGHT; } bool Launcher::OnScrollTimeout() { bool continue_animation = true; + int speed = 0; if (IsInKeyNavMode() || !_hovered || GetActionState() == ACTION_DRAG_LAUNCHER) @@ -1516,19 +1527,21 @@ bool Launcher::OnScrollTimeout() { if (_launcher_drag_delta >= _launcher_drag_delta_max) continue_animation = false; - else if (MouseOverTopScrollExtrema()) - _launcher_drag_delta += 6; else - _launcher_drag_delta += 3; + { + speed = (SCROLL_AREA_HEIGHT - _mouse_position.y) / SCROLL_AREA_HEIGHT * SCROLL_FPS; + _launcher_drag_delta += speed; + } } else if (MouseOverBottomScrollArea()) { if (_launcher_drag_delta <= _launcher_drag_delta_min) continue_animation = false; - else if (MouseOverBottomScrollExtrema()) - _launcher_drag_delta -= 6; else - _launcher_drag_delta -= 3; + { + speed = ((_mouse_position.y + 1) - (GetGeometry().height - SCROLL_AREA_HEIGHT)) / SCROLL_AREA_HEIGHT * SCROLL_FPS; + _launcher_drag_delta -= speed; + } } else { @@ -1600,8 +1613,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 +1932,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 +2171,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 +2223,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(_icon_under_mouse); if (!_hidden) UpdateChangeInMousePosition(dx, dy); @@ -2233,9 +2238,16 @@ void Launcher::RecvMouseWheel(int /*x*/, int /*y*/, int wheel_delta, unsigned lo return; bool alt_pressed = nux::GetKeyModifierState(key_flags, nux::NUX_STATE_ALT); - if (alt_pressed) + { ScrollLauncher(wheel_delta); + } + else if (_icon_under_mouse) + { + auto timestamp = nux::GetGraphicsDisplay()->GetCurrentEvent().x11_timestamp; + auto scroll_direction = (wheel_delta < 0) ? AbstractLauncherIcon::ScrollDirection::DOWN : AbstractLauncherIcon::ScrollDirection::UP; + _icon_under_mouse->PerformScroll(scroll_direction, timestamp); + } } void Launcher::ScrollLauncher(int wheel_delta) @@ -2367,18 +2379,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) @@ -2393,6 +2394,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(); } } @@ -2734,7 +2736,7 @@ void Launcher::ProcessDndDrop(int x, int y) else if (_dnd_hovered_icon && _drag_action != nux::DNDACTION_NONE) { if (IsOverlayOpen()) - ubus_.SendMessage(UBUS_PLACE_VIEW_CLOSE_REQUEST); + ubus_.SendMessage(UBUS_OVERLAY_CLOSE_REQUEST); _dnd_hovered_icon->AcceptDrop(_dnd_data); } diff --git a/launcher/Launcher.h b/launcher/Launcher.h index 338fa1ab8..d04f0ca9c 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); @@ -240,10 +243,8 @@ private: void EnsureScrollTimer(); bool MouseOverTopScrollArea(); - bool MouseOverTopScrollExtrema(); bool MouseOverBottomScrollArea(); - bool MouseOverBottomScrollExtrema(); float DnDStartProgress(struct timespec const& current) const; float DnDExitProgress(struct timespec const& current) const; @@ -334,7 +335,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 +389,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 a9cd3fba8..eef602458 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) @@ -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, @@ -1198,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, timestamp)); + (*it)->OpenInstance(ActionArg(ActionArg::Source::LAUNCHER, 0, timestamp)); else - (*it)->Activate(ActionArg(ActionArg::LAUNCHER, 0, timestamp)); + (*it)->Activate(ActionArg(ActionArg::Source::LAUNCHER, 0, timestamp)); } // disable the "tap on super" check @@ -1320,10 +1384,10 @@ void Controller::KeyNavTerminate(bool activate) if (activate) { - auto timestamp = nux::GetWindowThread()->GetGraphicsDisplay().GetCurrentEvent().x11_timestamp; + auto timestamp = nux::GetGraphicsDisplay()->GetCurrentEvent().x11_timestamp; pimpl->sources_.AddIdle([this, timestamp] { - pimpl->model_->Selection()->Activate(ActionArg(ActionArg::LAUNCHER, 0, timestamp)); + pimpl->model_->Selection()->Activate(ActionArg(ActionArg::Source::LAUNCHER, 0, timestamp)); return false; }); } @@ -1424,8 +1488,8 @@ void Controller::Impl::ReceiveLauncherKeyPress(unsigned long eventType, // <SPACE> (open a new instance) case NUX_VK_SPACE: { - auto timestamp = nux::GetWindowThread()->GetGraphicsDisplay().GetCurrentEvent().x11_timestamp; - model_->Selection()->OpenInstance(ActionArg(ActionArg::LAUNCHER, 0, timestamp)); + auto timestamp = nux::GetGraphicsDisplay()->GetCurrentEvent().x11_timestamp; + model_->Selection()->OpenInstance(ActionArg(ActionArg::Source::LAUNCHER, 0, timestamp)); parent_->KeyNavTerminate(false); break; } @@ -1455,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/LauncherControllerPrivate.h b/launcher/LauncherControllerPrivate.h index 8b9449505..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); @@ -116,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_; @@ -152,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 895612f70..7efe4b458 100644 --- a/launcher/LauncherIcon.cpp +++ b/launcher/LauncherIcon.cpp @@ -62,6 +62,8 @@ const std::string UNITY_THEME_NAME = "unity-icon-theme"; const std::string CENTER_STABILIZE_TIMEOUT = "center-stabilize-timeout"; const std::string PRESENT_TIMEOUT = "present-timeout"; const std::string QUIRK_DELAY_TIMEOUT = "quirk-delay-timeout"; + +const unsigned TOOLTIP_FADE_DURATION = 80; } NUX_IMPLEMENT_OBJECT_TYPE(LauncherIcon); @@ -86,6 +88,7 @@ LauncherIcon::LauncherIcon(IconType type) , _parent_geo(max_num_monitors) , _saved_center(max_num_monitors) , _allow_quicklist_to_show(true) + , _tooltip_fade_animator(TOOLTIP_FADE_DURATION) { for (unsigned i = 0; i < unsigned(Quirk::LAST); ++i) { @@ -115,6 +118,19 @@ LauncherIcon::LauncherIcon(IconType type) mouse_down.connect(sigc::mem_fun(this, &LauncherIcon::RecvMouseDown)); mouse_up.connect(sigc::mem_fun(this, &LauncherIcon::RecvMouseUp)); mouse_click.connect(sigc::mem_fun(this, &LauncherIcon::RecvMouseClick)); + + _tooltip_fade_animator.updated.connect([this] (double opacity) { + if (_tooltip) + { + _tooltip->SetOpacity(opacity); + + if (opacity == 0.0f && _tooltip_fade_animator.GetStartValue() > _tooltip_fade_animator.GetFinishValue()) + { + _tooltip->ShowWindow(false); + _tooltip->SetOpacity(0.0f); + } + } + }); } LauncherIcon::~LauncherIcon() @@ -143,6 +159,7 @@ LauncherIcon::~LauncherIcon() void LauncherIcon::LoadTooltip() { _tooltip = new Tooltip(); + _tooltip->SetOpacity(0.0f); AddChild(_tooltip.GetPointer()); _tooltip->text = tooltip_text(); @@ -522,29 +539,23 @@ LauncherIcon::ShowTooltip() _tooltip->ShowTooltipWithTipAt(tip_x, tip_y); _tooltip->ShowWindow(!tooltip_text().empty()); tooltip_visible.emit(_tooltip); + + if (_tooltip_fade_animator.CurrentState() == nux::animation::Animation::State::Running) + _tooltip_fade_animator.Reverse(); + else + _tooltip_fade_animator.SetStartValue(0.0f).SetFinishValue(1.0f).Start(); } 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) @@ -662,9 +673,9 @@ void LauncherIcon::RecvMouseUp(int button, int monitor, unsigned long key_flags) void LauncherIcon::RecvMouseClick(int button, int monitor, unsigned long key_flags) { - auto timestamp = nux::GetWindowThread()->GetGraphicsDisplay().GetCurrentEvent().x11_timestamp; + auto timestamp = nux::GetGraphicsDisplay()->GetCurrentEvent().x11_timestamp; - ActionArg arg(ActionArg::LAUNCHER, button, timestamp); + ActionArg arg(ActionArg::Source::LAUNCHER, button, timestamp); arg.monitor = monitor; bool shift_pressed = nux::GetKeyModifierState(key_flags, nux::NUX_STATE_SHIFT); @@ -680,7 +691,13 @@ void LauncherIcon::RecvMouseClick(int button, int monitor, unsigned long key_fla void LauncherIcon::HideTooltip() { if (_tooltip) - _tooltip->ShowWindow(false); + { + if (_tooltip_fade_animator.CurrentState() == nux::animation::Animation::State::Running) + _tooltip_fade_animator.Reverse(); + else + _tooltip_fade_animator.SetStartValue(1.0f).SetFinishValue(0.0f).Start(); + } + tooltip_visible.emit(nux::ObjectPtr<nux::View>(nullptr)); } @@ -1217,6 +1234,9 @@ void LauncherIcon::UnStick() SetQuirk(Quirk::VISIBLE, false); } +void LauncherIcon::PerformScroll(ScrollDirection direction, Time timestamp) +{} + } // namespace launcher } // namespace unity diff --git a/launcher/LauncherIcon.h b/launcher/LauncherIcon.h index af3f0bed1..68a783b60 100644 --- a/launcher/LauncherIcon.h +++ b/launcher/LauncherIcon.h @@ -21,12 +21,9 @@ #ifndef LAUNCHERICON_H #define LAUNCHERICON_H -#include <set> -#include <boost/unordered_map.hpp> - #include <Nux/Nux.h> #include <Nux/BaseWindow.h> -#include <NuxCore/Math/MathInc.h> +#include <NuxCore/Animation.h> #include <gtk/gtk.h> #include <libdbusmenu-glib/client.h> @@ -196,6 +193,8 @@ public: virtual void UnStick(); + void PerformScroll(ScrollDirection direction, Time timestamp) override; + protected: std::vector<nux::Point3> GetCenters(); @@ -336,6 +335,8 @@ private: std::list<LauncherEntryRemote::Ptr> _entry_list; + nux::animation::AnimateValue<double> _tooltip_fade_animator; + protected: glib::SourceManager _source_manager; }; diff --git a/launcher/MockLauncherIcon.h b/launcher/MockLauncherIcon.h index 147b34564..e1057515c 100644 --- a/launcher/MockLauncherIcon.h +++ b/launcher/MockLauncherIcon.h @@ -22,7 +22,6 @@ #define MOCKLAUNCHERICON_H #include <Nux/Nux.h> -#include <NuxCore/Math/MathInc.h> #include <Nux/BaseWindow.h> #include <Nux/View.h> @@ -68,6 +67,7 @@ public: , type_(type) , sort_priority_(DefaultPriority(type)) , remote_uri_("fake") + , is_tooltip_visible_(false) { tooltip_text = "Mock Icon"; position = Position::FLOATING; @@ -80,7 +80,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) {} @@ -311,6 +313,8 @@ public: void UnStick() {} + void PerformScroll(ScrollDirection /*direction*/, Time /*timestamp*/) override {} + private: nux::BaseTexture* TextureFromGtkTheme(const char* icon_name, int size) { @@ -366,6 +370,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/QuicklistMenuItem.cpp b/launcher/QuicklistMenuItem.cpp index f24cf0fab..9d3d9bac0 100644 --- a/launcher/QuicklistMenuItem.cpp +++ b/launcher/QuicklistMenuItem.cpp @@ -134,12 +134,13 @@ void QuicklistMenuItem::Activate() const if (!_menu_item || !GetSelectable()) return; - dbusmenu_menuitem_handle_event(_menu_item, "clicked", nullptr, 0); + auto event_time = nux::GetGraphicsDisplay()->GetCurrentEvent().x11_timestamp; + dbusmenu_menuitem_handle_event(_menu_item, "clicked", nullptr, event_time); if (!IsOverlayQuicklist()) { UBusManager manager; - manager.SendMessage(UBUS_PLACE_VIEW_CLOSE_REQUEST); + manager.SendMessage(UBUS_OVERLAY_CLOSE_REQUEST); } } diff --git a/launcher/SimpleLauncherIcon.cpp b/launcher/SimpleLauncherIcon.cpp index 7138a0bf7..8cf1d97b0 100644 --- a/launcher/SimpleLauncherIcon.cpp +++ b/launcher/SimpleLauncherIcon.cpp @@ -88,7 +88,7 @@ void SimpleLauncherIcon::OnMouseLeave(int monitor) void SimpleLauncherIcon::ActivateLauncherIcon(ActionArg arg) { activate.emit(); - UBusManager::SendMessage(UBUS_PLACE_VIEW_CLOSE_REQUEST, + UBusManager::SendMessage(UBUS_OVERLAY_CLOSE_REQUEST, g_variant_new_boolean(FALSE)); } diff --git a/launcher/StandaloneLauncher.cpp b/launcher/StandaloneLauncher.cpp index ccc5e11e4..cec0cd82d 100644 --- a/launcher/StandaloneLauncher.cpp +++ b/launcher/StandaloneLauncher.cpp @@ -18,7 +18,9 @@ * */ -#include "Nux/Nux.h" +#include <Nux/Nux.h> +#include <Nux/NuxTimerTickSource.h> +#include <NuxCore/AnimationController.h> #include <gtk/gtk.h> #include "unity-shared/BackgroundEffectHelper.h" @@ -43,6 +45,7 @@ struct LauncherWindow { LauncherWindow() : wt(nux::CreateGUIThread("Unity Launcher", win_size.width, win_size.height, 0, &LauncherWindow::ThreadWidgetInit, this)) + , animation_controller(tick_source) {} void Show() @@ -64,7 +67,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)}); @@ -86,6 +88,8 @@ private: unity::Settings settings; panel::Style panel_style; std::shared_ptr<nux::WindowThread> wt; + nux::NuxTimerTickSource tick_source; + nux::animation::AnimationController animation_controller; launcher::Controller::Ptr controller; }; diff --git a/launcher/SwitcherController.cpp b/launcher/SwitcherController.cpp index 28bbc0c4f..58b3850b9 100644 --- a/launcher/SwitcherController.cpp +++ b/launcher/SwitcherController.cpp @@ -316,7 +316,7 @@ void Controller::Impl::Show(ShowMode show, SortMode sort, std::vector<AbstractLa sources_.AddTimeout(obj_->initial_detail_timeout_length, cb_func, DETAIL_TIMEOUT); } - ubus_manager_.SendMessage(UBUS_PLACE_VIEW_CLOSE_REQUEST); + ubus_manager_.SendMessage(UBUS_OVERLAY_CLOSE_REQUEST); ubus_manager_.SendMessage(UBUS_SWITCHER_SHOWN, g_variant_new("(bi)", true, obj_->monitor_)); } @@ -365,6 +365,7 @@ void Controller::Impl::ShowView() if (view_window_) { + view_->live_background = true; view_window_->ShowWindow(true); view_window_->PushToFront(); @@ -409,7 +410,6 @@ void Controller::Impl::ConstructView() view_->SetModel(model_); view_->background_color = bg_color_; view_->monitor = obj_->monitor_; - view_->SetupBackground(); ConstructWindow(); main_layout_->AddView(view_.GetPointer(), 1); @@ -426,8 +426,8 @@ void Controller::Impl::Hide(bool accept_state) Selection selection = GetCurrentSelection(); if (selection.application_) { - Time timestamp = -1; - selection.application_->Activate(ActionArg(ActionArg::SWITCHER, 0, + Time timestamp = 0; + selection.application_->Activate(ActionArg(ActionArg::Source::SWITCHER, 0, timestamp, selection.window_)); } } @@ -458,7 +458,6 @@ void Controller::Impl::HideWindow() view_window_->SetOpacity(0.0f); view_window_->ShowWindow(false); view_window_->PushToBack(); - view_window_->EnableInputWindow(false); model_.reset(); view_.Release(); diff --git a/launcher/SwitcherView.cpp b/launcher/SwitcherView.cpp index 2453b786f..b75063899 100644 --- a/launcher/SwitcherView.cpp +++ b/launcher/SwitcherView.cpp @@ -564,12 +564,14 @@ nux::Geometry SwitcherView::GetBackgroundGeometry() return last_background_; } -void SwitcherView::DrawOverlay(nux::GraphicsEngine& GfxContext, bool force_draw, nux::Geometry internal_clip) +void SwitcherView::DrawOverlay(nux::GraphicsEngine& GfxContext, bool force_draw, nux::Geometry const& clip) { - nux::Geometry base = GetGeometry(); + nux::Geometry const& base = GetGeometry(); + nux::Geometry internal_clip = clip; GfxContext.GetRenderStates().SetPremultipliedBlend(nux::SRC_OVER); + for (auto const& arg : last_args_) { if (text_view_->IsVisible() && model_->Selection() == arg.icon) diff --git a/launcher/SwitcherView.h b/launcher/SwitcherView.h index 85d3e1336..a690d9b73 100644 --- a/launcher/SwitcherView.h +++ b/launcher/SwitcherView.h @@ -79,7 +79,7 @@ protected: void AddProperties(GVariantBuilder* builder); void PreDraw(nux::GraphicsEngine& GfxContext, bool force_draw); - void DrawOverlay(nux::GraphicsEngine& GfxContext, bool force_draw, nux::Geometry clip); + void DrawOverlay(nux::GraphicsEngine& GfxContext, bool force_draw, nux::Geometry const& clip); nux::Geometry GetBackgroundGeometry(); ui::RenderArg InterpolateRenderArgs(ui::RenderArg const& start, ui::RenderArg const& end, float progress); diff --git a/launcher/TooltipManager.cpp b/launcher/TooltipManager.cpp new file mode 100644 index 000000000..dee8a5103 --- /dev/null +++ b/launcher/TooltipManager.cpp @@ -0,0 +1,92 @@ +// -*- 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> + * Andrea Azzarone <andrea.azzarone@canonical.com> + */ + +#include "TooltipManager.h" + +namespace unity +{ +namespace launcher +{ +namespace +{ +const unsigned int TOOLTIPS_SHOW_TIMEOUT_LENGTH = 500; +} + +TooltipManager::TooltipManager() + : skip_timeout_(false) +{} + +void TooltipManager::MouseMoved(AbstractLauncherIcon::Ptr const& icon_under_mouse) +{ + if (icon_ == icon_under_mouse) + return; + + StopTimer(); + if (icon_) + icon_->HideTooltip(); + + icon_ = icon_under_mouse; + + if (icon_ && !skip_timeout_) + ResetTimer(icon_); + else if (icon_ && skip_timeout_) + icon_->ShowTooltip(); +} + +void TooltipManager::IconClicked() +{ + if (icon_) + icon_->HideTooltip(); +} + +void TooltipManager::SetHover(bool hovered) +{ + if (!hovered) + Reset(); +} + +void TooltipManager::Reset() +{ + StopTimer(); + + if (icon_) + icon_->HideTooltip(); + + icon_ = AbstractLauncherIcon::Ptr(); + skip_timeout_ = false; +} + +void TooltipManager::ResetTimer(AbstractLauncherIcon::Ptr const& icon_under_mouse) +{ + hover_timer_.reset(new glib::Timeout(TOOLTIPS_SHOW_TIMEOUT_LENGTH)); + hover_timer_->Run([&] () { + skip_timeout_ = true; + icon_under_mouse->ShowTooltip(); + return false; + }); + } + +void TooltipManager::StopTimer() +{ + hover_timer_.reset(); +} + +} +} diff --git a/launcher/TooltipManager.h b/launcher/TooltipManager.h new file mode 100644 index 000000000..817239d26 --- /dev/null +++ b/launcher/TooltipManager.h @@ -0,0 +1,56 @@ +// -*- 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> + * Andrea Azzarone <andrea.azzarone@canonical.com> + */ + +#ifndef LAUNCHER_TOOLTIP_MANAGER_H +#define LAUNCHER_TOOLTIP_MANAGER_H + +#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 hovered); + void MouseMoved(AbstractLauncherIcon::Ptr const& icon_under_mouse); + void IconClicked(); + +private: + void Reset(); + void ResetTimer(AbstractLauncherIcon::Ptr const& icon_under_mouse); + void StopTimer(); + + bool skip_timeout_; + AbstractLauncherIcon::Ptr icon_; + glib::Source::UniquePtr hover_timer_; +}; + +} +} + +#endif diff --git a/launcher/TrashLauncherIcon.cpp b/launcher/TrashLauncherIcon.cpp index 2ec4563dd..f16c6f8b1 100644 --- a/launcher/TrashLauncherIcon.cpp +++ b/launcher/TrashLauncherIcon.cpp @@ -1,6 +1,6 @@ // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* - * Copyright (C) 2010 Canonical Ltd + * Copyright (C) 2010-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 @@ -16,6 +16,7 @@ * * Authored by: Jason Smith <jason.smith@canonical.com> * Andrea Azzarone <azzaronea@gmail.com> + * Marco Trevisan <marco.trevisan@canonical.com> */ #include "TrashLauncherIcon.h" @@ -24,11 +25,13 @@ #include <glib/gi18n-lib.h> #include <Nux/WindowCompositor.h> #include <NuxCore/Logger.h> +#include <UnityCore/GLibDBusProxy.h> #include <zeitgeist.h> #include "Launcher.h" #include "QuicklistManager.h" #include "QuicklistMenuItemLabel.h" +#include "FileManagerOpenerImp.h" namespace unity { @@ -38,11 +41,12 @@ DECLARE_LOGGER(logger, "unity.launcher.icon"); namespace { const std::string ZEITGEIST_UNITY_ACTOR = "application://compiz.desktop"; + const std::string TRASH_URI = "trash:///"; } -TrashLauncherIcon::TrashLauncherIcon() +TrashLauncherIcon::TrashLauncherIcon(FileManagerOpener::Ptr const& fmo) : SimpleLauncherIcon(IconType::TRASH) - , proxy_("org.gnome.Nautilus", "/org/gnome/Nautilus", "org.gnome.Nautilus.FileOperations") + , file_manager_(fmo ? fmo : std::make_shared<FileManagerOpenerImp>()) , cancellable_(g_cancellable_new()) { tooltip_text = _("Trash"); @@ -52,10 +56,11 @@ TrashLauncherIcon::TrashLauncherIcon() SetQuirk(Quirk::RUNNING, false); SetShortcut('t'); - glib::Object<GFile> location(g_file_new_for_uri("trash:///")); + glib::Object<GFile> location(g_file_new_for_uri(TRASH_URI.c_str())); glib::Error err; trash_monitor_ = g_file_monitor_directory(location, G_FILE_MONITOR_NONE, nullptr, &err); + g_file_monitor_set_rate_limit(trash_monitor_, 1000); if (err) { @@ -83,12 +88,16 @@ AbstractLauncherIcon::MenuItemsVector TrashLauncherIcon::GetMenus() /* Empty Trash */ glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new()); - dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Empty Trash...")); + dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Empty Trash…")); dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, !empty_); dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); empty_activated_signal_.Connect(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - [this] (DbusmenuMenuitem*, int) { - proxy_.Call("EmptyTrash"); + [this] (DbusmenuMenuitem*, unsigned) { + auto proxy = std::make_shared<glib::DBusProxy>("org.gnome.Nautilus", "/org/gnome/Nautilus", + "org.gnome.Nautilus.FileOperations"); + + // Passing the proxy to the lambda we ensure that it will be destroyed when needed + proxy->CallBegin("EmptyTrash", nullptr, [proxy] (GVariant*, glib::Error const&) {}); }); result.push_back(menu_item); @@ -100,13 +109,12 @@ void TrashLauncherIcon::ActivateLauncherIcon(ActionArg arg) { SimpleLauncherIcon::ActivateLauncherIcon(arg); - glib::Error error; - g_spawn_command_line_async("xdg-open trash://", &error); + file_manager_->Open(TRASH_URI.c_str(), arg.timestamp); } void TrashLauncherIcon::UpdateTrashIcon() { - glib::Object<GFile> location(g_file_new_for_uri("trash:///")); + glib::Object<GFile> location(g_file_new_for_uri(TRASH_URI.c_str())); g_file_query_info_async(location, G_FILE_ATTRIBUTE_STANDARD_ICON, @@ -117,14 +125,12 @@ void TrashLauncherIcon::UpdateTrashIcon() this); } -void TrashLauncherIcon::UpdateTrashIconCb(GObject* source, - GAsyncResult* res, - gpointer data) +void TrashLauncherIcon::UpdateTrashIconCb(GObject* source, GAsyncResult* res, gpointer data) { - TrashLauncherIcon* self = (TrashLauncherIcon*) data; + auto self = static_cast<TrashLauncherIcon*>(data); // FIXME: should use the generic LoadIcon function (not taking from the unity theme) - glib::Object<GFileInfo> info(g_file_query_info_finish(G_FILE(source), res, NULL)); + glib::Object<GFileInfo> info(g_file_query_info_finish(G_FILE(source), res, nullptr)); if (info) { @@ -132,7 +138,6 @@ void TrashLauncherIcon::UpdateTrashIconCb(GObject* source, glib::String icon_string(g_icon_to_string(icon)); self->icon_name = icon_string.Str(); - self->empty_ = (self->icon_name == "user-trash"); } } @@ -152,23 +157,22 @@ bool TrashLauncherIcon::OnShouldHighlightOnDrag(DndData const& dnd_data) return true; } - void TrashLauncherIcon::OnAcceptDrop(DndData const& dnd_data) { - for (auto it : dnd_data.Uris()) + for (auto const& uri : dnd_data.Uris()) { - glib::Object<GFile> file(g_file_new_for_uri(it.c_str())); + glib::Object<GFile> file(g_file_new_for_uri(uri.c_str())); /* Log ZG event when moving file to trash; this is requred by File Lens. See https://bugs.launchpad.net/unity/+bug/870150 */ if (g_file_trash(file, NULL, NULL)) { // based on nautilus zg event logging code - glib::String origin(g_path_get_dirname(it.c_str())); + glib::String origin(g_path_get_dirname(uri.c_str())); glib::String parse_name(g_file_get_parse_name(file)); glib::String display_name(g_path_get_basename(parse_name)); - ZeitgeistSubject *subject = zeitgeist_subject_new_full(it.c_str(), + ZeitgeistSubject *subject = zeitgeist_subject_new_full(uri.c_str(), NULL, // subject interpretation NULL, // suject manifestation NULL, // mime-type diff --git a/launcher/TrashLauncherIcon.h b/launcher/TrashLauncherIcon.h index 8f9df0966..640886bf0 100644 --- a/launcher/TrashLauncherIcon.h +++ b/launcher/TrashLauncherIcon.h @@ -21,12 +21,12 @@ #define TRASHLAUNCHERICON_H #include <gio/gio.h> -#include <UnityCore/GLibDBusProxy.h> #include <UnityCore/GLibWrapper.h> #include <UnityCore/GLibSignal.h> #include "DndData.h" #include "SimpleLauncherIcon.h" +#include "FileManagerOpener.h" namespace unity { @@ -37,7 +37,7 @@ class TrashLauncherIcon : public SimpleLauncherIcon { public: - TrashLauncherIcon(); + TrashLauncherIcon(FileManagerOpener::Ptr const& = nullptr); ~TrashLauncherIcon(); protected: @@ -55,12 +55,12 @@ private: static void UpdateTrashIconCb(GObject* source, GAsyncResult* res, gpointer data); - gboolean empty_; - glib::DBusProxy proxy_; + bool empty_; + FileManagerOpener::Ptr file_manager_; glib::Object<GCancellable> cancellable_; glib::Object<GFileMonitor> trash_monitor_; glib::Signal<void, GFileMonitor*, GFile*, GFile*, GFileMonitorEvent> trash_changed_signal_; - glib::Signal<void, DbusmenuMenuitem*, int> empty_activated_signal_; + glib::Signal<void, DbusmenuMenuitem*, unsigned> empty_activated_signal_; }; } diff --git a/launcher/Volume.h b/launcher/Volume.h index 0675a14f7..1248027c9 100644 --- a/launcher/Volume.h +++ b/launcher/Volume.h @@ -20,7 +20,6 @@ #ifndef UNITYSHELL_VOLUME_H #define UNITYSHELL_VOLUME_H -#include <boost/noncopyable.hpp> #include <memory> #include <sigc++/signal.h> #include <sigc++/trackable.h> @@ -31,12 +30,13 @@ namespace unity namespace launcher { -class Volume : private boost::noncopyable, public sigc::trackable +class Volume : public sigc::trackable { public: typedef std::shared_ptr<Volume> Ptr; - virtual ~Volume() {} + Volume() = default; + virtual ~Volume() = default; virtual bool CanBeEjected() const = 0; virtual bool CanBeRemoved() const = 0; @@ -48,12 +48,16 @@ public: virtual bool IsMounted() const = 0; virtual void EjectAndShowNotification() = 0; - virtual void MountAndOpenInFileManager() = 0; + virtual void MountAndOpenInFileManager(unsigned long long timestamp = 0) = 0; virtual void StopDrive() = 0; virtual void Unmount() = 0; sigc::signal<void> changed; sigc::signal<void> removed; + +private: + Volume(Volume const&) = delete; + Volume& operator=(Volume const&) = delete; }; } diff --git a/launcher/VolumeImp.cpp b/launcher/VolumeImp.cpp index c63d4d1a0..b00ccd965 100644 --- a/launcher/VolumeImp.cpp +++ b/launcher/VolumeImp.cpp @@ -40,6 +40,7 @@ public: DeviceNotificationDisplay::Ptr const& device_notification_display, VolumeImp* parent) : parent_(parent) + , open_timestamp_(0) , cancellable_(g_cancellable_new()) , volume_(volume) , file_manager_opener_(file_manager_opener) @@ -140,8 +141,10 @@ public: } } - void MountAndOpenInFileManager() + void MountAndOpenInFileManager(unsigned long long timestamp) { + open_timestamp_ = timestamp; + if (!IsMounted()) MountAndOnFinishOpenInFileManager(); else @@ -170,7 +173,7 @@ public: void OpenInFileManager() { - file_manager_opener_->Open(GetUri()); + file_manager_opener_->Open(GetUri(), open_timestamp_); } std::string GetUri() @@ -216,6 +219,7 @@ public: } VolumeImp* parent_; + unsigned long long open_timestamp_; glib::Object<GCancellable> cancellable_; glib::Object<GVolume> volume_; FileManagerOpener::Ptr file_manager_opener_; @@ -278,9 +282,9 @@ bool VolumeImp::IsMounted() const return pimpl->IsMounted(); } -void VolumeImp::MountAndOpenInFileManager() +void VolumeImp::MountAndOpenInFileManager(unsigned long long timestamp) { - pimpl->MountAndOpenInFileManager(); + pimpl->MountAndOpenInFileManager(timestamp); } void VolumeImp::EjectAndShowNotification() diff --git a/launcher/VolumeImp.h b/launcher/VolumeImp.h index 0d8cc2112..cea1768de 100644 --- a/launcher/VolumeImp.h +++ b/launcher/VolumeImp.h @@ -53,7 +53,7 @@ public: virtual bool IsMounted() const; virtual void EjectAndShowNotification(); - virtual void MountAndOpenInFileManager(); + virtual void MountAndOpenInFileManager(unsigned long long timestamp); virtual void StopDrive(); virtual void Unmount(); diff --git a/launcher/VolumeLauncherIcon.cpp b/launcher/VolumeLauncherIcon.cpp index 4f1342435..471f98631 100644 --- a/launcher/VolumeLauncherIcon.cpp +++ b/launcher/VolumeLauncherIcon.cpp @@ -46,7 +46,7 @@ const unsigned int volume_changed_timeout = 500; class VolumeLauncherIcon::Impl { public: - typedef glib::Signal<void, DbusmenuMenuitem*, int> ItemSignal; + typedef glib::Signal<void, DbusmenuMenuitem*, unsigned> ItemSignal; Impl(Volume::Ptr const& volume, DevicesSettings::Ptr const& devices_settings, @@ -136,7 +136,7 @@ public: void ActivateLauncherIcon(ActionArg arg) { parent_->SimpleLauncherIcon::ActivateLauncherIcon(arg); - volume_->MountAndOpenInFileManager(); + volume_->MountAndOpenInFileManager(arg.timestamp); } MenuItemsVector GetMenus() @@ -194,8 +194,8 @@ public: dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); dbusmenu_menuitem_property_set_bool(menu_item, QuicklistMenuItem::MARKUP_ENABLED_PROPERTY, true); - gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) { - volume_->MountAndOpenInFileManager(); + gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned timestamp) { + volume_->MountAndOpenInFileManager(timestamp); })); menu.push_back(menu_item); @@ -209,8 +209,8 @@ public: dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); - gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) { - volume_->MountAndOpenInFileManager(); + gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned timestamp) { + volume_->MountAndOpenInFileManager(timestamp); })); menu.push_back(menu_item); diff --git a/launcher/XdndCollectionWindowImp.cpp b/launcher/XdndCollectionWindowImp.cpp index 102580be9..1976db13c 100644 --- a/launcher/XdndCollectionWindowImp.cpp +++ b/launcher/XdndCollectionWindowImp.cpp @@ -41,9 +41,14 @@ public: // We are not calling ShowWindow () as this window // isn't really visible 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)); @@ -101,13 +106,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"); } } |
