diff options
49 files changed, 1995 insertions, 1169 deletions
diff --git a/UnityCore/DesktopUtilities.cpp b/UnityCore/DesktopUtilities.cpp index a9a41c5e7..5b841cd0d 100644 --- a/UnityCore/DesktopUtilities.cpp +++ b/UnityCore/DesktopUtilities.cpp @@ -90,6 +90,11 @@ std::string DesktopUtilities::GetUserRuntimeDirectory() return ""; } +std::string DesktopUtilities::GetUserTrashDirectory() +{ + return GetUserDataDirectory().append(G_DIR_SEPARATOR_S "Trash" G_DIR_SEPARATOR_S "files" G_DIR_SEPARATOR_S); +} + std::vector<std::string> DesktopUtilities::GetSystemDataDirectories() { const char* const* system_dirs = g_get_system_data_dirs(); diff --git a/UnityCore/DesktopUtilities.h b/UnityCore/DesktopUtilities.h index 203603ea1..5c0488eaf 100644 --- a/UnityCore/DesktopUtilities.h +++ b/UnityCore/DesktopUtilities.h @@ -33,6 +33,7 @@ public: static std::string GetUserCacheDirectory(); static std::string GetUserRuntimeDirectory(); static std::string GetUserConfigDirectory(); + static std::string GetUserTrashDirectory(); static std::vector<std::string> GetSystemDataDirectories(); static std::vector<std::string> GetDataDirectories(); diff --git a/UnityCore/GLibDBusProxy.cpp b/UnityCore/GLibDBusProxy.cpp index 1cd6f4d3d..7e89f6ddf 100644 --- a/UnityCore/GLibDBusProxy.cpp +++ b/UnityCore/GLibDBusProxy.cpp @@ -301,7 +301,7 @@ void DBusProxy::Impl::OnPropertyChanged(GDBusProxy* proxy, GVariant* changed_pro } } - g_variant_iter_free (iter); + g_variant_iter_free(iter); } for (const gchar *property_name = *invalidated; property_name; property_name = *(++invalidated)) @@ -624,7 +624,7 @@ void DBusProxy::GetProperty(std::string const& name, ReplyCallback const& callba [] (GObject *source, GAsyncResult *res, gpointer user_data) { glib::Error err; std::unique_ptr<ReplyCallback> callback(static_cast<ReplyCallback*>(user_data)); - Variant result(g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &err)); + Variant result(g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &err), StealRef()); if (err) { @@ -660,7 +660,7 @@ void DBusProxy::SetProperty(std::string const& name, GVariant* value) nullptr, G_DBUS_CALL_FLAGS_NONE, -1, pimpl->cancellable_, [] (GObject *source, GAsyncResult *res, gpointer user_data) { glib::Error err; - Variant result(g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &err)); + Variant result(g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &err), StealRef()); if (err) { LOG_ERROR(logger) << "Impossible to set property: " << err; diff --git a/debian/control b/debian/control index 69db232f8..7c30e36b2 100644 --- a/debian/control +++ b/debian/control @@ -83,6 +83,7 @@ Depends: ${shlibs:Depends}, Provides: indicator-renderer Recommends: unity-control-center, ${unity-default-masterscopes} + nautilus, indicator-appmenu (>= 15.02.0), indicator-application, indicator-sound, diff --git a/launcher/AbstractLauncherIcon.h b/launcher/AbstractLauncherIcon.h index 926736be1..ed40c8f71 100644 --- a/launcher/AbstractLauncherIcon.h +++ b/launcher/AbstractLauncherIcon.h @@ -174,13 +174,17 @@ public: virtual WindowList Windows() = 0; - virtual std::vector<Window> WindowsForMonitor(int monitor) = 0; + virtual WindowList WindowsForMonitor(int monitor) = 0; - virtual std::vector<Window> WindowsOnViewport() = 0; + virtual WindowList WindowsOnViewport() = 0; - virtual const bool WindowVisibleOnMonitor(int monitor) = 0; + virtual bool WindowVisibleOnMonitor(int monitor) const = 0; - virtual const bool WindowVisibleOnViewport() = 0; + virtual bool WindowVisibleOnViewport() const = 0; + + virtual size_t WindowsVisibleOnMonitor(int monitor) const = 0; + + virtual size_t WindowsVisibleOnViewport() const = 0; virtual float PresentUrgency() = 0; diff --git a/launcher/ApplicationLauncherIcon.cpp b/launcher/ApplicationLauncherIcon.cpp index 3e6889825..91ea82107 100644 --- a/launcher/ApplicationLauncherIcon.cpp +++ b/launcher/ApplicationLauncherIcon.cpp @@ -1,6 +1,6 @@ // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* - * Copyright (C) 2010-2012 Canonical Ltd + * Copyright (C) 2010-2015 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 @@ -19,10 +19,8 @@ */ #include "config.h" -#include <boost/algorithm/string.hpp> #include <Nux/Nux.h> -#include <Nux/BaseWindow.h> #include <NuxCore/Logger.h> #include <UnityCore/GLibWrapper.h> @@ -30,12 +28,7 @@ #include "ApplicationLauncherIcon.h" #include "FavoriteStore.h" -#include "MultiMonitor.h" #include "unity-shared/DesktopApplicationManager.h" -#include "unity-shared/GnomeFileManager.h" -#include "unity-shared/UBusWrapper.h" -#include "unity-shared/UBusMessages.h" -#include "unity-shared/UScreen.h" #include <glib/gi18n-lib.h> #include <gio/gdesktopappinfo.h> @@ -44,15 +37,13 @@ namespace unity { namespace launcher { -DECLARE_LOGGER(logger, "unity.launcher.icon.application"); namespace { -// We use the "bamf-" prefix since the manager is protected, to avoid name clash -const std::string ICON_REMOVE_TIMEOUT = "bamf-icon-remove"; -const std::string ICON_DND_OVER_TIMEOUT = "bamf-icon-dnd-over"; +DECLARE_LOGGER(logger, "unity.launcher.icon.application"); + +// We use the "application-" prefix since the manager is protected, to avoid name clash +const std::string ICON_REMOVE_TIMEOUT = "application-icon-remove"; const std::string DEFAULT_ICON = "application-default-icon"; -const int MAXIMUM_QUICKLIST_WIDTH = 300; -const int COMPIZ_SCALE_DND_SPREAD = 1 << 7; enum MenuItemType { @@ -67,10 +58,8 @@ enum MenuItemType NUX_IMPLEMENT_OBJECT_TYPE(ApplicationLauncherIcon); ApplicationLauncherIcon::ApplicationLauncherIcon(ApplicationPtr const& app) - : SimpleLauncherIcon(IconType::APPLICATION) - , _startup_notification_timestamp(0) - , _last_scroll_timestamp(0) - , _progressive_scroll(0) + : WindowedLauncherIcon(IconType::APPLICATION) + , startup_notification_timestamp_(0) , use_custom_bg_color_(false) , bg_color_(nux::color::White) { @@ -83,13 +72,6 @@ ApplicationLauncherIcon::ApplicationLauncherIcon(ApplicationPtr const& app) << ", running: " << (app->running() ? "yes" : "no"); SetApplication(app); - - WindowManager& wm = WindowManager::Default(); - wm.window_minimized.connect(sigc::mem_fun(this, &ApplicationLauncherIcon::OnWindowMinimized)); - wm.screen_viewport_switch_ended.connect(sigc::mem_fun(this, &ApplicationLauncherIcon::EnsureWindowState)); - wm.terminate_expo.connect(sigc::mem_fun(this, &ApplicationLauncherIcon::EnsureWindowState)); - UScreen::GetDefault()->changed.connect(sigc::hide(sigc::hide(sigc::mem_fun(this, &ApplicationLauncherIcon::EnsureWindowsLocation)))); - EnsureWindowsLocation(); } @@ -157,23 +139,19 @@ void ApplicationLauncherIcon::SetupApplicationSignalsConnections() signals_conn_.Add(app_->window_opened.connect([this](ApplicationWindowPtr const& win) { signals_conn_.Add(win->monitor.changed.connect([this] (int) { EnsureWindowsLocation(); })); EnsureWindowsLocation(); - - if (WindowManager::Default().IsScaleActiveForGroup() && IsActive()) - Spread(true, 0, false); })); - auto ensure_win_location_cb = sigc::hide(sigc::mem_fun(this, &ApplicationLauncherIcon::EnsureWindowsLocation)); - signals_conn_.Add(app_->window_closed.connect(ensure_win_location_cb)); + signals_conn_.Add(app_->window_closed.connect([this] (ApplicationWindowPtr const&) { EnsureWindowsLocation(); })); for (auto& win : app_->GetWindows()) - signals_conn_.Add(win->monitor.changed.connect(ensure_win_location_cb)); + signals_conn_.Add(win->monitor.changed.connect([this] (int) { EnsureWindowsLocation(); })); - signals_conn_.Add(app_->urgent.changed.connect([this](bool const& urgent) { + signals_conn_.Add(app_->urgent.changed.connect([this](bool urgent) { LOG_DEBUG(logger) << tooltip_text() << " urgent now " << (urgent ? "true" : "false"); SetQuirk(Quirk::URGENT, urgent); })); - signals_conn_.Add(app_->active.changed.connect([this](bool const& active) { + signals_conn_.Add(app_->active.changed.connect([this](bool active) { LOG_DEBUG(logger) << tooltip_text() << " active now " << (active ? "true" : "false"); SetQuirk(Quirk::ACTIVE, active); })); @@ -185,8 +163,8 @@ void ApplicationLauncherIcon::SetupApplicationSignalsConnections() signals_conn_.Add(app_->title.changed.connect([this](std::string const& name) { LOG_DEBUG(logger) << tooltip_text() << " name now " << name; - if (_menu_items.size() == MenuItemType::SIZE) - _menu_items[MenuItemType::APP_NAME] = nullptr; + if (menu_items_.size() == MenuItemType::SIZE) + menu_items_[MenuItemType::APP_NAME] = nullptr; tooltip_text = name; })); @@ -195,7 +173,7 @@ void ApplicationLauncherIcon::SetupApplicationSignalsConnections() icon_name = (icon.empty() ? DEFAULT_ICON : icon); })); - signals_conn_.Add(app_->running.changed.connect([this](bool const& running) { + signals_conn_.Add(app_->running.changed.connect([this](bool running) { LOG_DEBUG(logger) << tooltip_text() << " running now " << (running ? "true" : "false"); SetQuirk(Quirk::RUNNING, running); @@ -208,35 +186,47 @@ void ApplicationLauncherIcon::SetupApplicationSignalsConnections() } })); - signals_conn_.Add(app_->visible.changed.connect([this](bool const& visible) { + signals_conn_.Add(app_->visible.changed.connect([this](bool visible) { SetQuirk(Quirk::VISIBLE, IsSticky() ? true : visible); })); - signals_conn_.Add(app_->closed.connect([this]() { - if (!IsSticky()) - { - SetQuirk(Quirk::VISIBLE, false); - HideTooltip(); - - /* 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); - } + signals_conn_.Add(app_->closed.connect([this] { + LOG_DEBUG(logger) << tooltip_text() << " closed"; + OnApplicationClosed(); })); } +WindowList ApplicationLauncherIcon::GetManagedWindows() const +{ + return app_ ? app_->GetWindows() : WindowList(); +} + +void ApplicationLauncherIcon::OnApplicationClosed() +{ + if (IsSticky()) + return; + + SetQuirk(Quirk::VISIBLE, false); + HideTooltip(); + + /* 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); +} + +// Move to WindowedLauncherIcon?! bool ApplicationLauncherIcon::GetQuirk(AbstractLauncherIcon::Quirk quirk, int monitor) const { if (quirk == Quirk::ACTIVE) { - if (!SimpleLauncherIcon::GetQuirk(Quirk::ACTIVE, monitor)) + if (!WindowedLauncherIcon::GetQuirk(Quirk::ACTIVE, monitor)) return false; if (app_->type() == AppType::WEBAPP) @@ -248,304 +238,35 @@ bool ApplicationLauncherIcon::GetQuirk(AbstractLauncherIcon::Quirk quirk, int mo return app_->OwnsWindow(WindowManager::Default().GetActiveWindow()); } - return SimpleLauncherIcon::GetQuirk(quirk, monitor); + return WindowedLauncherIcon::GetQuirk(quirk, monitor); } void ApplicationLauncherIcon::Remove() { LogUnityEvent(ApplicationEventType::LEAVE); UnsetApplication(); - SimpleLauncherIcon::Remove(); + WindowedLauncherIcon::Remove(); } bool ApplicationLauncherIcon::IsSticky() const { if (app_) - return app_->sticky() && SimpleLauncherIcon::IsSticky(); + return app_->sticky() && WindowedLauncherIcon::IsSticky(); return false; } -bool ApplicationLauncherIcon::IsActive() const -{ - return GetQuirk(Quirk::ACTIVE); -} - -bool ApplicationLauncherIcon::IsRunning() const -{ - return GetQuirk(Quirk::RUNNING); -} - -bool ApplicationLauncherIcon::IsUrgent() const -{ - return GetQuirk(Quirk::URGENT); -} - -void ApplicationLauncherIcon::ActivateLauncherIcon(ActionArg arg) -{ - SimpleLauncherIcon::ActivateLauncherIcon(arg); - WindowManager& wm = WindowManager::Default(); - - // This is a little awkward as the target is only set from the switcher. - if (arg.target) - { - // thumper: should we Raise too? should the WM raise? - wm.Activate(arg.target); - return; - } - - bool scale_was_active = wm.IsScaleActive(); - bool active = IsActive(); - bool user_visible = IsRunning(); - /* We should check each child to see if there is - * an unmapped (!= minimized) window around and - * if so force "Focus" behaviour */ - - if (arg.source != ActionArg::Source::SWITCHER) - { - user_visible = app_->visible(); - - if (active) - { - bool any_visible = false; - bool any_mapped = false; - bool any_on_top = false; - bool any_on_monitor = (arg.monitor < 0); - int active_monitor = arg.monitor; - - for (auto const& window : app_->GetWindows()) - { - Window xid = window->window_id(); - - if (!any_visible && wm.IsWindowOnCurrentDesktop(xid)) - { - any_visible = true; - } - - if (!any_mapped && wm.IsWindowMapped(xid)) - { - any_mapped = true; - } - - if (!any_on_top && wm.IsWindowOnTop(xid)) - { - any_on_top = true; - } - - if (!any_on_monitor && window->monitor() == arg.monitor && - wm.IsWindowMapped(xid) && wm.IsWindowVisible(xid)) - { - any_on_monitor = true; - } - - if (window->active()) - { - active_monitor = window->monitor(); - } - } - - if (!any_visible || !any_mapped || !any_on_top) - active = false; - - if (any_on_monitor && arg.monitor >= 0 && active_monitor != arg.monitor) - active = false; - } - - if (user_visible && IsSticky() && IsFileManager()) - { - // See bug #753938 - unsigned minimum_windows = 0; - auto const& file_manager = GnomeFileManager::Get(); - - if (file_manager->IsTrashOpened()) - ++minimum_windows; - - if (file_manager->IsDeviceOpened()) - ++minimum_windows; - - if (minimum_windows > 0) - { - if (file_manager->OpenedLocations().size() == minimum_windows && - GetWindows(WindowFilter::USER_VISIBLE|WindowFilter::MAPPED).size() == minimum_windows) - { - user_visible = false; - } - } - } - } - - /* Behaviour: - * 1) Nothing running, or nothing visible -> launch application - * 2) Running and active -> spread application - * 3) Running and not active -> focus application - * 4) Spread is active and different icon pressed -> change spread - * 5) Spread is active -> Spread de-activated, and fall through - */ - - if (!IsRunning() || (IsRunning() && !user_visible)) // #1 above - { - if (GetQuirk(Quirk::STARTING, arg.monitor)) - return; - - wm.TerminateScale(); - SetQuirk(Quirk::STARTING, true, arg.monitor); - OpenInstanceLauncherIcon(arg.timestamp); - } - else // app is running - { - if (active) - { - if (scale_was_active) // #5 above - { - wm.TerminateScale(); - - if (minimize_window_on_click()) - { - for (auto const& win : GetWindows(WindowFilter::ON_CURRENT_DESKTOP)) - wm.Minimize(win->window_id()); - } - else - { - Focus(arg); - } - } - else // #2 above - { - if (arg.source != ActionArg::Source::SWITCHER) - { - bool minimized = false; - - if (minimize_window_on_click()) - { - WindowList const& windows = GetWindows(WindowFilter::ON_CURRENT_DESKTOP); - - if (windows.size() == 1) - { - wm.Minimize(windows[0]->window_id()); - minimized = true; - } - } - - if (!minimized) - { - Spread(true, 0, false); - } - } - } - } - else - { - if (scale_was_active) // #4 above - { - if (GetWindows(WindowFilter::ON_CURRENT_DESKTOP).size() <= 1) - wm.TerminateScale(); - - Focus(arg); - - if (arg.source != ActionArg::Source::SWITCHER) - Spread(true, 0, false); - } - else // #3 above - { - Focus(arg); - } - } - } -} - -WindowList ApplicationLauncherIcon::GetWindows(WindowFilterMask filter, int monitor) -{ - WindowManager& wm = WindowManager::Default(); - WindowList results; - - monitor = (filter & WindowFilter::ON_ALL_MONITORS) ? -1 : monitor; - bool mapped = (filter & WindowFilter::MAPPED); - bool user_visible = (filter & WindowFilter::USER_VISIBLE); - bool current_desktop = (filter & WindowFilter::ON_CURRENT_DESKTOP); - - for (auto& window : app_->GetWindows()) - { - if ((monitor >= 0 && window->monitor() == monitor) || monitor < 0) - { - if ((user_visible && window->visible()) || !user_visible) - { - Window xid = window->window_id(); - - if ((mapped && wm.IsWindowMapped(xid)) || !mapped) - { - if ((current_desktop && wm.IsWindowOnCurrentDesktop(xid)) || !current_desktop) - { - results.push_back(window); - } - } - } - } - } - - return results; -} - -WindowList ApplicationLauncherIcon::Windows() +bool ApplicationLauncherIcon::IsUserVisible() const { - return GetWindows(WindowFilter::MAPPED|WindowFilter::ON_ALL_MONITORS); -} - -std::vector<Window> ApplicationLauncherIcon::WindowsOnViewport() -{ - WindowFilterMask filter = 0; - filter |= WindowFilter::MAPPED; - filter |= WindowFilter::USER_VISIBLE; - filter |= WindowFilter::ON_CURRENT_DESKTOP; - filter |= WindowFilter::ON_ALL_MONITORS; - - std::vector<Window> windows; - for (auto& window : GetWindows(filter)) - { - windows.push_back(window->window_id()); - } - return windows; -} - -std::vector<Window> ApplicationLauncherIcon::WindowsForMonitor(int monitor) -{ - WindowFilterMask filter = 0; - filter |= WindowFilter::MAPPED; - filter |= WindowFilter::USER_VISIBLE; - filter |= WindowFilter::ON_CURRENT_DESKTOP; - - std::vector<Window> windows; - for (auto& window : GetWindows(filter, monitor)) - { - windows.push_back(window->window_id()); - } - return windows; -} - -void ApplicationLauncherIcon::OnWindowMinimized(guint32 xid) -{ - for (auto const& window: app_->GetWindows()) - { - if (xid == window->window_id()) - { - int monitor = GetCenterForMonitor(window->monitor()).first; - - if (monitor >= 0) - { - Present(0.5f, 600, monitor); - FullyAnimateQuirkDelayed(300, Quirk::SHIMMER, monitor); - } - - break; - } - } + return app_ ? app_->visible() : false; } void ApplicationLauncherIcon::UpdateDesktopFile() { std::string const& filename = app_->desktop_file(); - if (_desktop_file_monitor) - _gsignals.Disconnect(_desktop_file_monitor, "changed"); + if (desktop_file_monitor_) + glib_signals_.Disconnect(desktop_file_monitor_, "changed"); auto old_uri = RemoteUri(); UpdateRemoteUri(); @@ -559,11 +280,11 @@ void ApplicationLauncherIcon::UpdateDesktopFile() // we can remove ourself from the launcher and when it's changed // we can update the quicklist. glib::Object<GFile> desktop_file(g_file_new_for_path(filename.c_str())); - _desktop_file_monitor = g_file_monitor_file(desktop_file, G_FILE_MONITOR_NONE, + desktop_file_monitor_ = g_file_monitor_file(desktop_file, G_FILE_MONITOR_NONE, nullptr, nullptr); - g_file_monitor_set_rate_limit(_desktop_file_monitor, 2000); + g_file_monitor_set_rate_limit(desktop_file_monitor_, 2000); - _gsignals.Add<void, GFileMonitor*, GFile*, GFile*, GFileMonitorEvent>(_desktop_file_monitor, "changed", + glib_signals_.Add<void, GFileMonitor*, GFile*, GFile*, GFileMonitorEvent>(desktop_file_monitor_, "changed", [this, desktop_file] (GFileMonitor*, GFile*, GFile*, GFileMonitorEvent event_type) { switch (event_type) { @@ -600,7 +321,7 @@ void ApplicationLauncherIcon::UpdateDesktopFile() bool update_saved_uri = (!filename.empty() && app_->sticky()); if (update_saved_uri) - SimpleLauncherIcon::UnStick(); + WindowedLauncherIcon::UnStick(); uri_changed.emit(new_uri); @@ -614,22 +335,6 @@ std::string ApplicationLauncherIcon::DesktopFile() const return app_->desktop_file(); } -void ApplicationLauncherIcon::AddProperties(debug::IntrospectionData& introspection) -{ - SimpleLauncherIcon::AddProperties(introspection); - - std::vector<Window> xids; - for (auto const& window : GetWindows()) - xids.push_back(window->window_id()); - - introspection - .add("desktop_file", DesktopFile()) - .add("desktop_id", app_->desktop_id()) - .add("xids", glib::Variant::FromVector(xids)) - .add("sticky", IsSticky()) - .add("startup_notification_timestamp", _startup_notification_timestamp); -} - void ApplicationLauncherIcon::OpenInstanceWithUris(std::set<std::string> const& uris, Time timestamp) { glib::Error error; @@ -639,9 +344,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 = timestamp; - if (_startup_notification_timestamp > 0) - 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)) { @@ -705,83 +410,40 @@ void ApplicationLauncherIcon::Focus(ActionArg arg) app_->Focus(show_only_visible, arg.monitor); } -bool ApplicationLauncherIcon::Spread(bool current_desktop, int state, bool force) -{ - std::vector<Window> windows; - for (auto& window : GetWindows(current_desktop ? WindowFilter::ON_CURRENT_DESKTOP : 0)) - windows.push_back(window->window_id()); - - return WindowManager::Default().ScaleWindowGroup(windows, state, force); -} - -void ApplicationLauncherIcon::EnsureWindowState() -{ - std::vector<int> number_of_windows_on_monitor(monitors::MAX); - - for (auto& window: app_->GetWindows()) - { - int monitor = window->monitor(); - Window window_id = window->window_id(); - - if (WindowManager::Default().IsWindowOnCurrentDesktop(window_id)) - { - // If monitor is -1 (or negative), show on all monitors. - if (monitor < 0) - { - for (unsigned j; j < monitors::MAX; ++j) - ++number_of_windows_on_monitor[j]; - } - else - { - ++number_of_windows_on_monitor[monitor]; - } - } - } - - for (unsigned i = 0; i < monitors::MAX; ++i) - SetNumberOfWindowsVisibleOnMonitor(number_of_windows_on_monitor[i], i); -} - -void ApplicationLauncherIcon::EnsureWindowsLocation() -{ - EnsureWindowState(); - UpdateIconGeometries(GetCenters()); -} - void ApplicationLauncherIcon::UpdateDesktopQuickList() { std::string const& desktop_file = DesktopFile(); - if (_menu_desktop_shortcuts) + if (menu_desktop_shortcuts_) { - for (GList *l = dbusmenu_menuitem_get_children(_menu_desktop_shortcuts); l; l = l->next) + for (GList *l = dbusmenu_menuitem_get_children(menu_desktop_shortcuts_); l; l = l->next) { - _gsignals.Disconnect(l->data, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED); + glib_signals_.Disconnect(l->data, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED); } - _menu_desktop_shortcuts = nullptr; + menu_desktop_shortcuts_ = nullptr; } if (desktop_file.empty()) return; - _menu_desktop_shortcuts = dbusmenu_menuitem_new(); - dbusmenu_menuitem_set_root(_menu_desktop_shortcuts, TRUE); + menu_desktop_shortcuts_ = dbusmenu_menuitem_new(); + dbusmenu_menuitem_set_root(menu_desktop_shortcuts_, TRUE); // Build a desktop shortcuts object and tell it that our // environment is Unity to handle the filtering - _desktop_shortcuts = indicator_desktop_shortcuts_new(desktop_file.c_str(), "Unity"); + desktop_shortcuts_ = indicator_desktop_shortcuts_new(desktop_file.c_str(), "Unity"); // This will get us a list of the nicks available, it should // always be at least one entry of NULL if there either aren't // any or they're filtered for the environment we're in - const gchar** nicks = indicator_desktop_shortcuts_get_nicks(_desktop_shortcuts); + const gchar** nicks = indicator_desktop_shortcuts_get_nicks(desktop_shortcuts_); for (int index = 0; nicks[index]; ++index) { // Build a dbusmenu item for each nick that is the desktop // file that is built from it's name and includes a callback // to the desktop shortcuts object to execute the nick - glib::String name(indicator_desktop_shortcuts_nick_get_name(_desktop_shortcuts, + glib::String name(indicator_desktop_shortcuts_nick_get_name(desktop_shortcuts_, nicks[index])); glib::Object<DbusmenuMenuitem> item(dbusmenu_menuitem_new()); dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, name); @@ -789,16 +451,16 @@ void ApplicationLauncherIcon::UpdateDesktopQuickList() dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); auto nick = glib::gchar_to_string(nicks[index]); - _gsignals.Add<void, DbusmenuMenuitem*, gint>(item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + glib_signals_.Add<void, DbusmenuMenuitem*, gint>(item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this, nick] (DbusmenuMenuitem* item, unsigned timestamp) { GdkDisplay* display = gdk_display_get_default(); glib::Object<GdkAppLaunchContext> context(gdk_display_get_app_launch_context(display)); gdk_app_launch_context_set_timestamp(context, timestamp); auto gcontext = glib::object_cast<GAppLaunchContext>(context); - indicator_desktop_shortcuts_nick_exec_with_context(_desktop_shortcuts, nick.c_str(), gcontext); + indicator_desktop_shortcuts_nick_exec_with_context(desktop_shortcuts_, nick.c_str(), gcontext); }); - dbusmenu_menuitem_child_append(_menu_desktop_shortcuts, item); + dbusmenu_menuitem_child_append(menu_desktop_shortcuts_, item); } } @@ -821,60 +483,16 @@ void ApplicationLauncherIcon::UpdateBackgroundColor() } } -void ApplicationLauncherIcon::EnsureMenuItemsWindowsReady() -{ - // delete all menu items for windows - _menu_items_windows.clear(); - - auto const& windows = Windows(); - - // We only add quicklist menu-items for windows if we have more than one window - if (windows.size() < 2) - return; - - // add menu items for all open windows - for (auto const& w : windows) - { - auto const& title = w->title(); - - if (title.empty()) - continue; - - glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new()); - dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, title.c_str()); - dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); - dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); - dbusmenu_menuitem_property_set_bool(menu_item, QuicklistMenuItem::MARKUP_ACCEL_DISABLED_PROPERTY, true); - dbusmenu_menuitem_property_set_int(menu_item, QuicklistMenuItem::MAXIMUM_LABEL_WIDTH_PROPERTY, MAXIMUM_QUICKLIST_WIDTH); - - Window xid = w->window_id(); - _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); - }); - - if (w->active()) - { - dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, DBUSMENU_MENUITEM_TOGGLE_RADIO); - dbusmenu_menuitem_property_set_int(menu_item, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED); - } - - _menu_items_windows.push_back(menu_item); - } -} - void ApplicationLauncherIcon::EnsureMenuItemsStaticQuicklist() { // make a client for desktop file actions - if (!_menu_desktop_shortcuts.IsType(DBUSMENU_TYPE_MENUITEM)) + if (!menu_desktop_shortcuts_.IsType(DBUSMENU_TYPE_MENUITEM)) { UpdateDesktopQuickList(); } } -void ApplicationLauncherIcon::Quit() +void ApplicationLauncherIcon::Quit() const { app_->Quit(); } @@ -899,7 +517,7 @@ void ApplicationLauncherIcon::Stick(bool save) } else { - SimpleLauncherIcon::Stick(save); + WindowedLauncherIcon::Stick(save); if (save) LogUnityEvent(ApplicationEventType::ACCESS); @@ -912,11 +530,11 @@ void ApplicationLauncherIcon::UnStick() return; LogUnityEvent(ApplicationEventType::ACCESS); - SimpleLauncherIcon::UnStick(); + WindowedLauncherIcon::UnStick(); SetQuirk(Quirk::VISIBLE, app_->visible()); app_->sticky = false; - if (!app_->running()) + if (!IsRunning()) Remove(); } @@ -956,10 +574,10 @@ ApplicationSubjectPtr ApplicationLauncherIcon::GetSubject() void ApplicationLauncherIcon::EnsureMenuItemsDefaultReady() { - if (_menu_items.size() == MenuItemType::SIZE) + if (menu_items_.size() == MenuItemType::SIZE) return; - _menu_items.resize(MenuItemType::SIZE); + menu_items_.resize(MenuItemType::SIZE); /* (Un)Stick to Launcher */ glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new()); @@ -968,12 +586,12 @@ void ApplicationLauncherIcon::EnsureMenuItemsDefaultReady() 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*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + glib_signals_.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned) { ToggleSticky(); }); - _menu_items[MenuItemType::STICK] = menu_item; + menu_items_[MenuItemType::STICK] = menu_item; /* Quit */ menu_item = dbusmenu_menuitem_new(); @@ -981,17 +599,17 @@ void ApplicationLauncherIcon::EnsureMenuItemsDefaultReady() 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*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + glib_signals_.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned) { Quit(); }); - _menu_items[MenuItemType::QUIT] = menu_item; + menu_items_[MenuItemType::QUIT] = menu_item; /* Separator */ menu_item = dbusmenu_menuitem_new(); dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); - _menu_items[MenuItemType::SEPARATOR] = menu_item; + menu_items_[MenuItemType::SEPARATOR] = menu_item; } AbstractLauncherIcon::MenuItemsVector ApplicationLauncherIcon::GetMenus() @@ -1003,7 +621,7 @@ AbstractLauncherIcon::MenuItemsVector ApplicationLauncherIcon::GetMenus() EnsureMenuItemsDefaultReady(); EnsureMenuItemsStaticQuicklist(); - for (auto const& menus : {GetRemoteMenus(), _menu_desktop_shortcuts}) + for (auto const& menus : {GetRemoteMenus(), menu_desktop_shortcuts_}) { if (!menus.IsType(DBUSMENU_TYPE_MENUITEM)) continue; @@ -1049,11 +667,11 @@ AbstractLauncherIcon::MenuItemsVector ApplicationLauncherIcon::GetMenus() if (separator_needed) { - result.push_back(_menu_items[MenuItemType::SEPARATOR]); + result.push_back(menu_items_[MenuItemType::SEPARATOR]); separator_needed = false; } - if (!_menu_items[MenuItemType::APP_NAME]) + if (!menu_items_[MenuItemType::APP_NAME]) { glib::String app_name(g_markup_escape_text(app_->title().c_str(), -1)); std::string bold_app_name("<b>"+app_name.Str()+"</b>"); @@ -1064,7 +682,7 @@ AbstractLauncherIcon::MenuItemsVector ApplicationLauncherIcon::GetMenus() 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, + glib_signals_.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)); @@ -1072,25 +690,23 @@ AbstractLauncherIcon::MenuItemsVector ApplicationLauncherIcon::GetMenus() }); }); - _menu_items[MenuItemType::APP_NAME] = item; + menu_items_[MenuItemType::APP_NAME] = item; } - result.push_back(_menu_items[MenuItemType::APP_NAME]); - result.push_back(_menu_items[MenuItemType::SEPARATOR]); + result.push_back(menu_items_[MenuItemType::APP_NAME]); + result.push_back(menu_items_[MenuItemType::SEPARATOR]); - EnsureMenuItemsWindowsReady(); + auto const& windows_menu_items = GetWindowsMenuItems(); - if (!_menu_items_windows.empty()) + if (!windows_menu_items.empty()) { - for (auto const& it : _menu_items_windows) - result.push_back(it); - - result.push_back(_menu_items[MenuItemType::SEPARATOR]); + result.insert(end(result), begin(windows_menu_items), end(windows_menu_items)); + result.push_back(menu_items_[MenuItemType::SEPARATOR]); } const char* label = !IsSticky() ? _("Lock to Launcher") : _("Unlock from Launcher"); - dbusmenu_menuitem_property_set(_menu_items[MenuItemType::STICK], DBUSMENU_MENUITEM_PROP_LABEL, label); - result.push_back(_menu_items[MenuItemType::STICK]); + dbusmenu_menuitem_property_set(menu_items_[MenuItemType::STICK], DBUSMENU_MENUITEM_PROP_LABEL, label); + result.push_back(menu_items_[MenuItemType::STICK]); if (IsRunning()) { @@ -1102,7 +718,7 @@ AbstractLauncherIcon::MenuItemsVector ApplicationLauncherIcon::GetMenus() 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*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + glib_signals_.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned) { app_->CreateLocalDesktopFile(); }); @@ -1111,7 +727,7 @@ AbstractLauncherIcon::MenuItemsVector ApplicationLauncherIcon::GetMenus() } if (!quit_item) - quit_item = _menu_items[MenuItemType::QUIT]; + quit_item = menu_items_[MenuItemType::QUIT]; dbusmenu_menuitem_property_set(quit_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Quit")); result.push_back(quit_item); @@ -1125,28 +741,7 @@ void ApplicationLauncherIcon::UpdateIconGeometries(std::vector<nux::Point3> cons if (app_->type() == AppType::WEBAPP) return; - nux::Geometry geo(0, 0, icon_size, icon_size); - - for (auto& window : app_->GetWindows()) - { - Window xid = window->window_id(); - int monitor = GetCenterForMonitor(window->monitor()).first; - - if (monitor < 0) - { - WindowManager::Default().SetWindowIconGeometry(xid, nux::Geometry()); - continue; - } - - geo.x = centers[monitor].x - icon_size / 2; - geo.y = centers[monitor].y - icon_size / 2; - WindowManager::Default().SetWindowIconGeometry(xid, geo); - } -} - -void ApplicationLauncherIcon::OnCenterStabilized(std::vector<nux::Point3> const& centers) -{ - UpdateIconGeometries(centers); + return WindowedLauncherIcon::UpdateIconGeometries(centers); } void ApplicationLauncherIcon::UpdateRemoteUri() @@ -1155,69 +750,21 @@ void ApplicationLauncherIcon::UpdateRemoteUri() if (!desktop_id.empty()) { - _remote_uri = FavoriteStore::URI_PREFIX_APP + desktop_id; + remote_uri_ = FavoriteStore::URI_PREFIX_APP + desktop_id; } else { - _remote_uri.clear(); + remote_uri_.clear(); } } std::string ApplicationLauncherIcon::GetRemoteUri() const { - return _remote_uri; -} - -void ApplicationLauncherIcon::OnDndEnter() -{ - auto timestamp = nux::GetGraphicsDisplay()->GetCurrentEvent().x11_timestamp; - - _source_manager.AddTimeout(1000, [this, timestamp] { - bool to_spread = GetWindows(WindowFilter::ON_CURRENT_DESKTOP).size() > 1; - - if (!to_spread) - WindowManager::Default().TerminateScale(); - - if (!IsRunning()) - return false; - - UBusManager::SendMessage(UBUS_OVERLAY_CLOSE_REQUEST); - Focus(ActionArg(ActionArg::Source::LAUNCHER, 1, timestamp)); - - if (to_spread) - Spread(true, COMPIZ_SCALE_DND_SPREAD, false); - - return false; - }, ICON_DND_OVER_TIMEOUT); -} - -void ApplicationLauncherIcon::OnDndLeave() -{ - _source_manager.Remove(ICON_DND_OVER_TIMEOUT); -} - -bool ApplicationLauncherIcon::IsFileManager() -{ - auto const& desktop_file = DesktopFile(); - - return boost::algorithm::ends_with(desktop_file, "org.gnome.Nautilus.desktop") || - boost::algorithm::ends_with(desktop_file, "nautilus.desktop") || - boost::algorithm::ends_with(desktop_file, "nautilus-folder-handler.desktop") || - boost::algorithm::ends_with(desktop_file, "nautilus-home.desktop"); + return remote_uri_; } bool ApplicationLauncherIcon::OnShouldHighlightOnDrag(DndData const& dnd_data) { - if (IsFileManager()) - { - for (auto const& uri : dnd_data.Uris()) - { - if (boost::algorithm::starts_with(uri, "file://")) - return true; - } - return false; - } - for (auto type : dnd_data.Types()) { for (auto supported_type : GetSupportedTypes()) @@ -1248,28 +795,6 @@ void ApplicationLauncherIcon::OnAcceptDrop(DndData const& dnd_data) OpenInstanceWithUris(dnd_data.Uris(), timestamp); } -bool ApplicationLauncherIcon::ShowInSwitcher(bool current) -{ - if (!removed() && IsRunning() && IsVisible()) - { - // If current is true, we only want to show the current workspace. - if (!current) - { - return true; - } - else - { - for (unsigned i = 0; i < monitors::MAX; ++i) - { - if (WindowVisibleOnMonitor(i)) - return true; - } - } - } - - return false; -} - bool ApplicationLauncherIcon::AllowDetailViewInSwitcher() const { return app_->type() != AppType::WEBAPP; @@ -1277,18 +802,11 @@ bool ApplicationLauncherIcon::AllowDetailViewInSwitcher() const uint64_t ApplicationLauncherIcon::SwitcherPriority() { - uint64_t result = 0; // Webapps always go at the back. if (app_->type() == AppType::WEBAPP) - return result; + return 0; - for (auto& window : app_->GetWindows()) - { - Window xid = window->window_id(); - result = std::max(result, WindowManager::Default().GetWindowActiveNumber(xid)); - } - - return result; + return WindowedLauncherIcon::SwitcherPriority(); } nux::Color ApplicationLauncherIcon::BackgroundColor() const @@ -1296,7 +814,7 @@ nux::Color ApplicationLauncherIcon::BackgroundColor() const if (use_custom_bg_color_) return bg_color_; - return SimpleLauncherIcon::BackgroundColor(); + return WindowedLauncherIcon::BackgroundColor(); } const std::set<std::string> ApplicationLauncherIcon::GetSupportedTypes() @@ -1312,102 +830,17 @@ const std::set<std::string> ApplicationLauncherIcon::GetSupportedTypes() return supported_types; } -void PerformScrollUp(WindowList const& windows, unsigned int progressive_scroll) -{ - if (progressive_scroll == windows.size() - 1) - { - //RestackAbove to preserve Global Stacking Order - WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.at(1)->window_id()); - WindowManager::Default().RestackBelow(windows.at(1)->window_id(), windows.at(0)->window_id()); - windows.back()->Focus(); - return; - } - - WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.at(progressive_scroll + 1)->window_id()); - windows.at(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) +std::string ApplicationLauncherIcon::GetName() const { - if (timestamp - _last_scroll_timestamp < 150) - return; - else if (timestamp - _last_scroll_timestamp > 1500) - _progressive_scroll = 0; - - _last_scroll_timestamp = timestamp; - - auto const& windows = GetWindowsOnCurrentDesktopInStackingOrder(); - - if (windows.empty()) - return; - - if (scroll_inactive_icons && !IsActive()) - { - windows.at(0)->Focus(); - return; - } - - if (!scroll_inactive_icons && !IsActive()) - return; - - if (windows.size() <= 1) - return; - - if (direction == ScrollDirection::DOWN) - ++_progressive_scroll; - else - //--_progressive_scroll; but roll to the top of windows - _progressive_scroll += windows.size() - 1; - _progressive_scroll %= windows.size(); - - switch(direction) - { - case ScrollDirection::UP: - PerformScrollUp(windows, _progressive_scroll); - break; - case ScrollDirection::DOWN: - PerformScrollDown(windows, _progressive_scroll); - break; - } + return "ApplicationLauncherIcon"; } -WindowList ApplicationLauncherIcon::GetWindowsOnCurrentDesktopInStackingOrder() +void ApplicationLauncherIcon::AddProperties(debug::IntrospectionData& introspection) { - 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; - } + WindowedLauncherIcon::AddProperties(introspection); - return true; - }); - - return windows; -} - -std::string ApplicationLauncherIcon::GetName() const -{ - return "ApplicationLauncherIcon"; + introspection.add("desktop_file", DesktopFile()) + .add("desktop_id", app_->desktop_id()); } } // namespace launcher diff --git a/launcher/ApplicationLauncherIcon.h b/launcher/ApplicationLauncherIcon.h index 2ea48c184..afdf0118e 100644 --- a/launcher/ApplicationLauncherIcon.h +++ b/launcher/ApplicationLauncherIcon.h @@ -1,6 +1,6 @@ // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* - * Copyright (C) 2010-2012 Canonical Ltd + * Copyright (C) 2010-2015 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 @@ -18,17 +18,15 @@ * Marco Trevisan (Treviño) <3v1n0@ubuntu.com> */ -#ifndef APPLICATIONLAUNCHERICON_H -#define APPLICATIONLAUNCHERICON_H +#ifndef APPLICATION_LAUNCHER_ICON_H +#define APPLICATION_LAUNCHER_ICON_H -#include <UnityCore/GLibSignal.h> -#include <UnityCore/GLibWrapper.h> #include <UnityCore/ConnectionManager.h> #include <UnityCore/Variant.h> #include <libindicator/indicator-desktop-shortcuts.h> -#include "SimpleLauncherIcon.h" +#include "WindowedLauncherIcon.h" namespace unity { @@ -37,115 +35,74 @@ namespace launcher class Launcher; -class ApplicationLauncherIcon : public SimpleLauncherIcon +class ApplicationLauncherIcon : public virtual WindowedLauncherIcon { - NUX_DECLARE_OBJECT_TYPE(ApplicationLauncherIcon, SimpleLauncherIcon); + NUX_DECLARE_OBJECT_TYPE(ApplicationLauncherIcon, WindowedLauncherIcon); public: - ApplicationLauncherIcon(ApplicationPtr const& app); + ApplicationLauncherIcon(ApplicationPtr const&); virtual ~ApplicationLauncherIcon(); - virtual void ActivateLauncherIcon(ActionArg arg); - std::string DesktopFile() const; - bool IsSticky() const; - bool IsActive() const; - bool IsRunning() const; - bool IsUrgent() const; - - virtual bool GetQuirk(Quirk quirk, int monitor = 0) const override; - - virtual void Quit(); - virtual void AboutToRemove(); - - virtual void Stick(bool save = true); - virtual void UnStick(); - - virtual bool ShowInSwitcher(bool current); - virtual bool AllowDetailViewInSwitcher() const override; - virtual uint64_t SwitcherPriority(); - - virtual nux::Color BackgroundColor() const; + bool IsSticky() const override; + bool IsUserVisible() const override; + bool GetQuirk(Quirk quirk, int monitor = 0) const override; - WindowList Windows(); - std::vector<Window> WindowsOnViewport(); - std::vector<Window> WindowsForMonitor(int monitor); + void Quit() const override; - void PerformScroll(ScrollDirection direction, Time timestamp) override; + void Stick(bool save = true) override; + void UnStick() override; protected: void SetApplication(ApplicationPtr const& app); ApplicationPtr GetApplication() const; - void Remove(); - void UpdateIconGeometries(std::vector<nux::Point3> const& centers); - void OnCenterStabilized(std::vector<nux::Point3> const& centers); - void AddProperties(debug::IntrospectionData&); - void OnAcceptDrop(DndData const& dnd_data); - void OnDndEnter(); - void OnDndLeave(); - void OpenInstanceLauncherIcon(Time timestamp) override; - void ToggleSticky(); - void LogUnityEvent(ApplicationEventType); - bool IsFileManager(); + WindowList GetManagedWindows() const override; - bool OnShouldHighlightOnDrag(DndData const& dnd_data); - nux::DndAction OnQueryAcceptDrop(DndData const& dnd_data); + void LogUnityEvent(ApplicationEventType); + void Remove(); - MenuItemsVector GetMenus(); + void AboutToRemove() override; + bool AllowDetailViewInSwitcher() const override; + uint64_t SwitcherPriority() override; + void UpdateIconGeometries(std::vector<nux::Point3> const& centers) override; + nux::Color BackgroundColor() const override; + MenuItemsVector GetMenus() override; + std::string GetRemoteUri() const override; - std::string GetRemoteUri() const; + void OpenInstanceLauncherIcon(Time timestamp) override; + void OpenInstanceWithUris(std::set<std::string> const& uris, Time timestamp); + void Focus(ActionArg arg) override; - bool HandlesSpread() { return true; } - std::string GetName() const; + void OnAcceptDrop(DndData const&) override; + bool OnShouldHighlightOnDrag(DndData const&) override; + nux::DndAction OnQueryAcceptDrop(DndData const&) override; - void UpdateDesktopFile(); - void UpdateRemoteUri(); - std::string _desktop_file; - -private: - typedef unsigned long int WindowFilterMask; - enum WindowFilter - { - MAPPED = (1 << 0), - USER_VISIBLE = (1 << 1), - ON_CURRENT_DESKTOP = (1 << 2), - ON_ALL_MONITORS = (1 << 3), - }; + std::string GetName() const override; + void AddProperties(debug::IntrospectionData&) override; void UnsetApplication(); void SetupApplicationSignalsConnections(); - void EnsureWindowState(); - void EnsureWindowsLocation(); - void EnsureMenuItemsWindowsReady(); void EnsureMenuItemsDefaultReady(); void EnsureMenuItemsStaticQuicklist(); void UpdateBackgroundColor(); void UpdateDesktopQuickList(); + void UpdateDesktopFile(); + void UpdateRemoteUri(); + void ToggleSticky(); + void OnApplicationClosed(); - void OpenInstanceWithUris(std::set<std::string> const& uris, Time timestamp); - void Focus(ActionArg arg); - bool Spread(bool current_desktop, int state, bool force); - - void OnWindowMinimized(guint32 xid); - - WindowList GetWindows(WindowFilterMask filter = 0, int monitor = -1); const std::set<std::string> GetSupportedTypes(); - WindowList GetWindowsOnCurrentDesktopInStackingOrder(); ApplicationSubjectPtr GetSubject(); ApplicationPtr app_; - std::string _remote_uri; - Time _startup_notification_timestamp; - Time _last_scroll_timestamp; - unsigned int _progressive_scroll; - std::set<std::string> _supported_types; - std::vector<glib::Object<DbusmenuMenuitem>> _menu_items; - std::vector<glib::Object<DbusmenuMenuitem>> _menu_items_windows; - glib::Object<IndicatorDesktopShortcuts> _desktop_shortcuts; - glib::Object<DbusmenuMenuitem> _menu_desktop_shortcuts; - glib::Object<GFileMonitor> _desktop_file_monitor; - glib::SignalManager _gsignals; + std::string remote_uri_; + Time startup_notification_timestamp_; + std::set<std::string> supported_types_; + MenuItemsVector menu_items_; + glib::Object<IndicatorDesktopShortcuts> desktop_shortcuts_; + glib::Object<DbusmenuMenuitem> menu_desktop_shortcuts_; + glib::Object<GFileMonitor> desktop_file_monitor_; bool use_custom_bg_color_; nux::Color bg_color_; @@ -153,7 +110,7 @@ private: connection::Manager signals_conn_; }; -} -} +} // namespace launcher +} // namespace unity -#endif // BAMFLAUNCHERICON_H +#endif // APPLICATION_LAUNCHER_ICON_H diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index f832a23e9..229d981c9 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -32,6 +32,7 @@ set (LAUNCHER_SOURCES FavoriteStore.cpp FavoriteStoreGSettings.cpp FavoriteStorePrivate.cpp + FileManagerLauncherIcon.cpp HudLauncherIcon.cpp Launcher.cpp LauncherController.cpp @@ -55,12 +56,14 @@ set (LAUNCHER_SOURCES SingleMonitorLauncherIcon.cpp SoftwareCenterLauncherIcon.cpp SpacerLauncherIcon.cpp + StorageLauncherIcon.cpp Tooltip.cpp TooltipManager.cpp TrashLauncherIcon.cpp VolumeImp.cpp VolumeLauncherIcon.cpp VolumeMonitorWrapper.cpp + WindowedLauncherIcon.cpp XdndCollectionWindowImp.cpp XdndManagerImp.cpp XdndStartStopNotifier.cpp diff --git a/launcher/DesktopLauncherIcon.cpp b/launcher/DesktopLauncherIcon.cpp index cec293077..df9a982aa 100644 --- a/launcher/DesktopLauncherIcon.cpp +++ b/launcher/DesktopLauncherIcon.cpp @@ -77,5 +77,10 @@ bool DesktopLauncherIcon::ShowInSwitcher(bool current) return show_in_switcher_; } +uint64_t DesktopLauncherIcon::SwitcherPriority() +{ + return std::numeric_limits<uint64_t>::max(); +} + } // namespace launcher } // namespace unity diff --git a/launcher/DesktopLauncherIcon.h b/launcher/DesktopLauncherIcon.h index 6778b59a6..c17099165 100644 --- a/launcher/DesktopLauncherIcon.h +++ b/launcher/DesktopLauncherIcon.h @@ -37,6 +37,7 @@ public: protected: void ActivateLauncherIcon(ActionArg arg); + uint64_t SwitcherPriority() override; std::string GetName() const; std::string GetRemoteUri() const; diff --git a/launcher/DeviceLauncherSection.h b/launcher/DeviceLauncherSection.h index 358b405c4..7824cca79 100644 --- a/launcher/DeviceLauncherSection.h +++ b/launcher/DeviceLauncherSection.h @@ -37,10 +37,14 @@ namespace launcher class DeviceLauncherSection : public sigc::trackable { public: + typedef std::shared_ptr<DeviceLauncherSection> Ptr; + DeviceLauncherSection(AbstractVolumeMonitorWrapper::Ptr const& volume_monitor = nullptr, DevicesSettings::Ptr const& devices_settings = nullptr, DeviceNotificationDisplay::Ptr const& notifications = nullptr); + virtual ~DeviceLauncherSection() = default; + std::vector<VolumeLauncherIcon::Ptr> GetIcons() const; sigc::signal<void, AbstractLauncherIcon::Ptr const&> icon_added; diff --git a/launcher/FileManagerLauncherIcon.cpp b/launcher/FileManagerLauncherIcon.cpp new file mode 100644 index 000000000..d5895ad0f --- /dev/null +++ b/launcher/FileManagerLauncherIcon.cpp @@ -0,0 +1,128 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2015 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: Marco Trevisan <marco.trevisan@canonical.com> + */ + +#include "FileManagerLauncherIcon.h" + +#include <boost/algorithm/string.hpp> +#include <NuxCore/Logger.h> +#include <UnityCore/DesktopUtilities.h> + +#include "unity-shared/GnomeFileManager.h" + +namespace unity +{ +namespace launcher +{ +namespace +{ +DECLARE_LOGGER(logger, "unity.launcher.icon.filemanager"); +const std::string TRASH_URI = "trash:"; +const std::string TRASH_PATH = "file://" + DesktopUtilities::GetUserTrashDirectory(); +const std::string DEFAULT_ICON = "system-file-manager"; +} + +FileManagerLauncherIcon::FileManagerLauncherIcon(ApplicationPtr const& app, DeviceLauncherSection::Ptr const& dev, FileManager::Ptr const& fm) + : WindowedLauncherIcon(IconType::APPLICATION) + , ApplicationLauncherIcon(app) + , StorageLauncherIcon(GetIconType(), fm ? fm : GnomeFileManager::Get()) + , devices_(dev) +{ + // We disconnect from ApplicationLauncherIcon app signals, as we manage them manually + signals_conn_.Clear(); + + signals_conn_.Add(app_->desktop_file.changed.connect([this](std::string const& desktop_file) { + LOG_DEBUG(logger) << tooltip_text() << " desktop_file now " << desktop_file; + UpdateDesktopFile(); + })); + + signals_conn_.Add(app_->closed.connect([this] { + LOG_DEBUG(logger) << tooltip_text() << " closed"; + OnApplicationClosed(); + })); + + signals_conn_.Add(app_->title.changed.connect([this](std::string const& name) { + LOG_DEBUG(logger) << tooltip_text() << " name now " << name; + menu_items_.clear(); + tooltip_text = name; + })); + + signals_conn_.Add(app_->icon.changed.connect([this](std::string const& icon) { + LOG_DEBUG(logger) << tooltip_text() << " icon now " << icon; + icon_name = (icon.empty() ? DEFAULT_ICON : icon); + })); + + UpdateStorageWindows(); +} + +void FileManagerLauncherIcon::Focus(ActionArg arg) +{ + WindowedLauncherIcon::Focus(arg); +} + +void FileManagerLauncherIcon::Quit() const +{ + WindowedLauncherIcon::Quit(); +} + +bool FileManagerLauncherIcon::IsLocationManaged(std::string const& location) const +{ + if (location.empty()) + return true; + + if (boost::algorithm::starts_with(location, TRASH_URI)) + return false; + + if (boost::algorithm::starts_with(location, TRASH_PATH)) + return false; + + for (auto const& volume_icon : devices_->GetIcons()) + { + auto const& volume_uri = volume_icon->GetVolumeUri(); + if (!volume_uri.empty() && boost::algorithm::starts_with(location, volume_uri)) + return false; + } + + return true; +} + +WindowList FileManagerLauncherIcon::GetManagedWindows() const +{ + return StorageLauncherIcon::GetManagedWindows(); +} + +WindowList FileManagerLauncherIcon::GetStorageWindows() const +{ + WindowList fm_windows; + + for (auto const& app_win : ApplicationLauncherIcon::GetManagedWindows()) + { + if (IsLocationManaged(file_manager_->LocationForWindow(app_win))) + fm_windows.push_back(app_win); + } + + return fm_windows; +} + +bool FileManagerLauncherIcon::OnShouldHighlightOnDrag(DndData const& dnd_data) +{ + return StorageLauncherIcon::OnShouldHighlightOnDrag(dnd_data); +} + +} // namespace launcher +} // namespace unity diff --git a/launcher/FileManagerLauncherIcon.h b/launcher/FileManagerLauncherIcon.h new file mode 100644 index 000000000..1996747a3 --- /dev/null +++ b/launcher/FileManagerLauncherIcon.h @@ -0,0 +1,52 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2015 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: Marco Trevisan <marco.trevisan@canonical.com> + */ + +#ifndef FILEMANAGER_LAUNCHER_ICON_H +#define FILEMANAGER_LAUNCHER_ICON_H + +#include "ApplicationLauncherIcon.h" +#include "StorageLauncherIcon.h" +#include "DeviceLauncherSection.h" + +namespace unity +{ +namespace launcher +{ + +class FileManagerLauncherIcon : public ApplicationLauncherIcon, public StorageLauncherIcon +{ +public: + FileManagerLauncherIcon(ApplicationPtr const&, DeviceLauncherSection::Ptr const&, FileManager::Ptr const& = nullptr); + +private: + WindowList GetManagedWindows() const override; + WindowList GetStorageWindows() const override; + void Focus(ActionArg arg) override; + void Quit() const override; + bool OnShouldHighlightOnDrag(DndData const& dnd_data) override; + + bool IsLocationManaged(std::string const&) const; + + DeviceLauncherSection::Ptr devices_; +}; + +} // namespace launcher +} // namespace unity + +#endif // FILEMANAGER_LAUNCHER_ICON_H diff --git a/launcher/Launcher.cpp b/launcher/Launcher.cpp index dc6b725ca..62fa5fb1b 100644 --- a/launcher/Launcher.cpp +++ b/launcher/Launcher.cpp @@ -578,16 +578,9 @@ void Launcher::SetupRenderArg(AbstractLauncherIcon::Ptr const& icon, RenderArg& else { if (options()->show_for_all) - arg.window_indicators = std::max<int> (icon->WindowsOnViewport().size(), 1); + arg.window_indicators = std::max<int>(icon->WindowsVisibleOnViewport(), 1); else - arg.window_indicators = std::max<int> (icon->WindowsForMonitor(monitor).size(), 1); - - if (icon->GetIconType() == AbstractLauncherIcon::IconType::TRASH || - icon->GetIconType() == AbstractLauncherIcon::IconType::DEVICE) - { - // TODO: also these icons should respect the actual windows they have - arg.window_indicators = 0; - } + arg.window_indicators = std::max<int>(icon->WindowsVisibleOnMonitor(monitor), 1); } arg.backlight_intensity = IconBackgroundIntensity(icon); diff --git a/launcher/LauncherController.cpp b/launcher/LauncherController.cpp index 778a0637c..be9516fa9 100644 --- a/launcher/LauncherController.cpp +++ b/launcher/LauncherController.cpp @@ -21,6 +21,7 @@ #include "config.h" #include <glib/gi18n-lib.h> +#include <boost/algorithm/string.hpp> #include <Nux/Nux.h> #include <Nux/HLayout.h> @@ -32,6 +33,7 @@ #include "DesktopLauncherIcon.h" #include "VolumeLauncherIcon.h" #include "FavoriteStore.h" +#include "FileManagerLauncherIcon.h" #include "HudLauncherIcon.h" #include "LauncherController.h" #include "LauncherControllerPrivate.h" @@ -102,13 +104,13 @@ std::string CreateAppUriNameFromDesktopPath(const std::string &desktop_path) return FavoriteStore::URI_PREFIX_APP + DesktopUtilities::GetDesktopID(desktop_path); } - } Controller::Impl::Impl(Controller* parent, XdndManager::Ptr const& xdnd_manager, ui::EdgeBarrierController::Ptr const& edge_barriers) : parent_(parent) , model_(std::make_shared<LauncherModel>()) , xdnd_manager_(xdnd_manager) + , device_section_(std::make_shared<DeviceLauncherSection>()) , expo_icon_(new ExpoLauncherIcon()) , desktop_icon_(new DesktopLauncherIcon()) , edge_barriers_(edge_barriers) @@ -342,6 +344,21 @@ Launcher* Controller::Impl::CreateLauncher() return launcher; } +ApplicationLauncherIcon* Controller::Impl::CreateAppLauncherIcon(ApplicationPtr const& app) +{ + auto const& desktop_file = app->desktop_file(); + + if (boost::algorithm::ends_with(desktop_file, "org.gnome.Nautilus.desktop") || + boost::algorithm::ends_with(desktop_file, "nautilus.desktop") || + boost::algorithm::ends_with(desktop_file, "nautilus-folder-handler.desktop") || + boost::algorithm::ends_with(desktop_file, "nautilus-home.desktop")) + { + return new FileManagerLauncherIcon(app, device_section_); + } + + return new ApplicationLauncherIcon(app); +} + void Controller::Impl::OnLauncherAddRequest(std::string const& icon_uri, AbstractLauncherIcon::Ptr const& icon_before) { std::string app_uri; @@ -838,7 +855,7 @@ void Controller::Impl::OnApplicationStarted(ApplicationPtr const& app) if (app->sticky() || app->seen()) return; - AbstractLauncherIcon::Ptr icon(new ApplicationLauncherIcon(app)); + AbstractLauncherIcon::Ptr icon(CreateAppLauncherIcon(app)); RegisterIcon(icon, GetLastIconPriority<ApplicationLauncherIcon>(local::RUNNING_APPS_URI)); } @@ -875,11 +892,11 @@ AbstractLauncherIcon::Ptr Controller::Impl::CreateFavoriteIcon(std::string const if (!app || app->seen()) return result; - result = AbstractLauncherIcon::Ptr(new ApplicationLauncherIcon(app)); + result = AbstractLauncherIcon::Ptr(CreateAppLauncherIcon(app)); } else if (icon_uri.find(FavoriteStore::URI_PREFIX_DEVICE) == 0) { - auto const& devices = device_section_.GetIcons(); + auto const& devices = device_section_->GetIcons(); auto const& icon = std::find_if(devices.begin(), devices.end(), [&icon_uri](AbstractLauncherIcon::Ptr const& i) { return (i->RemoteUri() == icon_uri); }); @@ -954,7 +971,7 @@ void Controller::Impl::AddRunningApps() << (app->seen() ? "yes" : "no"); if (!app->seen()) { - AbstractLauncherIcon::Ptr icon(new ApplicationLauncherIcon(app)); + AbstractLauncherIcon::Ptr icon(CreateAppLauncherIcon(app)); icon->SkipQuirkAnimation(AbstractLauncherIcon::Quirk::VISIBLE); RegisterIcon(icon, ++sort_priority_); } @@ -964,7 +981,7 @@ void Controller::Impl::AddRunningApps() void Controller::Impl::AddDevices() { auto& fav_store = FavoriteStore::Instance(); - for (auto const& icon : device_section_.GetIcons()) + for (auto const& icon : device_section_->GetIcons()) { if (!icon->IsSticky() && !fav_store.IsFavorite(icon->RemoteUri())) { @@ -1044,7 +1061,7 @@ void Controller::Impl::SetupIcons() ApplicationManager::Default().application_started .connect(sigc::mem_fun(this, &Impl::OnApplicationStarted)); - device_section_.icon_added.connect(sigc::mem_fun(this, &Impl::OnDeviceIconAdded)); + 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)); favorite_store.reordered.connect(sigc::mem_fun(this, &Impl::ResetIconPriorities)); diff --git a/launcher/LauncherControllerPrivate.h b/launcher/LauncherControllerPrivate.h index 30a0886b9..914e6877b 100644 --- a/launcher/LauncherControllerPrivate.h +++ b/launcher/LauncherControllerPrivate.h @@ -87,6 +87,7 @@ public: void RegisterIcon(AbstractLauncherIcon::Ptr const& icon, int priority = std::numeric_limits<int>::min()); + ApplicationLauncherIcon* CreateAppLauncherIcon(ApplicationPtr const&); AbstractLauncherIcon::Ptr CreateFavoriteIcon(std::string const& icon_uri, bool emit_signal = false); AbstractLauncherIcon::Ptr GetIconByUri(std::string const& icon_uri); SoftwareCenterLauncherIcon::Ptr CreateSCLauncherIcon(std::string const& file_path, std::string const& aptdaemon_trans_id, std::string const& icon_path); @@ -122,7 +123,7 @@ public: nux::ObjectPtr<Launcher> launcher_; nux::ObjectPtr<Launcher> keyboard_launcher_; XdndManager::Ptr xdnd_manager_; - DeviceLauncherSection device_section_; + DeviceLauncherSection::Ptr device_section_; LauncherEntryRemoteModel remote_model_; AbstractLauncherIcon::Ptr expo_icon_; AbstractLauncherIcon::Ptr desktop_icon_; diff --git a/launcher/LauncherIcon.cpp b/launcher/LauncherIcon.cpp index 5da35d1ce..1825ac60a 100644 --- a/launcher/LauncherIcon.cpp +++ b/launcher/LauncherIcon.cpp @@ -150,16 +150,26 @@ void LauncherIcon::LoadQuicklist() QuicklistManager::Default()->RegisterQuicklist(_quicklist); } -const bool LauncherIcon::WindowVisibleOnMonitor(int monitor) +bool LauncherIcon::WindowVisibleOnMonitor(int monitor) const { return _has_visible_window[monitor]; } -const bool LauncherIcon::WindowVisibleOnViewport() +bool LauncherIcon::WindowVisibleOnViewport() const { return _has_visible_window.any(); } +size_t LauncherIcon::WindowsVisibleOnMonitor(int monitor) const +{ + return _number_of_visible_windows[monitor]; +} + +size_t LauncherIcon::WindowsVisibleOnViewport() const +{ + return std::accumulate(begin(_number_of_visible_windows), end(_number_of_visible_windows), 0); +} + std::string LauncherIcon::GetName() const { diff --git a/launcher/LauncherIcon.h b/launcher/LauncherIcon.h index 65af7e08f..d42668ed5 100644 --- a/launcher/LauncherIcon.h +++ b/launcher/LauncherIcon.h @@ -82,7 +82,7 @@ public: nux::Point3 GetCenter(int monitor); - virtual void Activate(ActionArg arg); + void Activate(ActionArg arg); void OpenInstance(ActionArg arg); @@ -94,15 +94,19 @@ public: void SetOrder(int order); - virtual WindowList Windows() { return WindowList(); } + WindowList Windows() { return WindowList(); } - virtual std::vector<Window> WindowsOnViewport() { return std::vector<Window> (); } + WindowList WindowsOnViewport() { return WindowList(); } - virtual std::vector<Window> WindowsForMonitor(int monitor) { return std::vector<Window> (); } + WindowList WindowsForMonitor(int monitor) { return WindowList(); } - const bool WindowVisibleOnMonitor(int monitor); + bool WindowVisibleOnMonitor(int monitor) const; - const bool WindowVisibleOnViewport(); + bool WindowVisibleOnViewport() const; + + size_t WindowsVisibleOnMonitor(int monitor) const; + + size_t WindowsVisibleOnViewport() const; float PresentUrgency(); diff --git a/launcher/MockLauncherIcon.h b/launcher/MockLauncherIcon.h index 335f1e64b..1dae29cd8 100644 --- a/launcher/MockLauncherIcon.h +++ b/launcher/MockLauncherIcon.h @@ -112,34 +112,34 @@ public: return result; } - std::vector<Window> WindowsOnViewport () + WindowList WindowsOnViewport() { - std::vector<Window> result; + WindowList result; - result.push_back ((100 << 16) + 200); - result.push_back ((500 << 16) + 200); - result.push_back ((300 << 16) + 200); - result.push_back ((200 << 16) + 200); - result.push_back ((300 << 16) + 200); - result.push_back ((100 << 16) + 200); - result.push_back ((300 << 16) + 200); - result.push_back ((600 << 16) + 200); + result.push_back(std::make_shared<MockApplicationWindow>((100 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((500 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((300 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((200 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((300 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((100 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((300 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((600 << 16) + 200)); return result; } - std::vector<Window> WindowsForMonitor (int monitor) + WindowList WindowsForMonitor(int monitor) { - std::vector<Window> result; + WindowList result; - result.push_back ((100 << 16) + 200); - result.push_back ((500 << 16) + 200); - result.push_back ((300 << 16) + 200); - result.push_back ((200 << 16) + 200); - result.push_back ((300 << 16) + 200); - result.push_back ((100 << 16) + 200); - result.push_back ((300 << 16) + 200); - result.push_back ((600 << 16) + 200); + result.push_back(std::make_shared<MockApplicationWindow>((100 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((500 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((300 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((200 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((300 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((100 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((300 << 16) + 200)); + result.push_back(std::make_shared<MockApplicationWindow>((600 << 16) + 200)); return result; } @@ -194,16 +194,26 @@ public: return 7; } - const bool WindowVisibleOnViewport() + bool WindowVisibleOnViewport() const { return false; } - const bool WindowVisibleOnMonitor(int monitor) + bool WindowVisibleOnMonitor(int monitor) const { return false; } + size_t WindowsVisibleOnMonitor(int monitor) const + { + return 0; + } + + size_t WindowsVisibleOnViewport() const + { + return 0; + } + void SetVisibleOnMonitor(int monitor, bool visible) {} bool IsVisibleOnMonitor(int monitor) const diff --git a/launcher/SoftwareCenterLauncherIcon.cpp b/launcher/SoftwareCenterLauncherIcon.cpp index abd6abedf..fc842e9cb 100644 --- a/launcher/SoftwareCenterLauncherIcon.cpp +++ b/launcher/SoftwareCenterLauncherIcon.cpp @@ -46,7 +46,8 @@ NUX_IMPLEMENT_OBJECT_TYPE(SoftwareCenterLauncherIcon); SoftwareCenterLauncherIcon::SoftwareCenterLauncherIcon(ApplicationPtr const& app, std::string const& aptdaemon_trans_id, std::string const& icon_path) - : ApplicationLauncherIcon(app) + : WindowedLauncherIcon(IconType::APPLICATION) + , ApplicationLauncherIcon(app) , aptdaemon_trans_(std::make_shared<glib::DBusProxy>("org.debian.apt", aptdaemon_trans_id, "org.debian.apt.transaction", diff --git a/launcher/StorageLauncherIcon.cpp b/launcher/StorageLauncherIcon.cpp new file mode 100644 index 000000000..fcc367b72 --- /dev/null +++ b/launcher/StorageLauncherIcon.cpp @@ -0,0 +1,119 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2015 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: Marco Trevisan <marco.trevisan@canonical.com> + */ + +#include "StorageLauncherIcon.h" + +namespace unity +{ +namespace launcher +{ + +StorageLauncherIcon::StorageLauncherIcon(AbstractLauncherIcon::IconType icon_type, FileManager::Ptr const& fm) + : WindowedLauncherIcon(icon_type) + , file_manager_(fm) +{ + file_manager_->locations_changed.connect(sigc::mem_fun(this, &StorageLauncherIcon::UpdateStorageWindows)); +} + +void StorageLauncherIcon::UpdateStorageWindows() +{ + bool active = false; + bool urgent = false; + bool check_visibility = (GetIconType() == IconType::APPLICATION); + bool visible = IsSticky(); + + managed_windows_ = GetStorageWindows(); + windows_connections_.Clear(); + + for (auto const& win : managed_windows_) + { + windows_connections_.Add(win->monitor.changed.connect([this] (int) { EnsureWindowsLocation(); })); + windows_connections_.Add(win->urgent.changed.connect([this] (bool) { OnWindowStateChanged(); })); + windows_connections_.Add(win->active.changed.connect([this] (bool) { OnWindowStateChanged(); })); + windows_connections_.Add(win->closed.connect([this] { UpdateStorageWindows(); })); + + if (!active && win->active()) + active = true; + + if (!urgent && win->urgent()) + urgent = true; + + if (check_visibility) + { + windows_connections_.Add(win->visible.changed.connect([this] (bool) { OnWindowStateChanged(); })); + + if (!visible && win->visible()) + visible = true; + } + } + + SetQuirk(Quirk::RUNNING, !managed_windows_.empty()); + SetQuirk(Quirk::ACTIVE, active); + SetQuirk(Quirk::URGENT, urgent); + + if (check_visibility) + SetQuirk(Quirk::VISIBLE, visible); + + EnsureWindowsLocation(); +} + +WindowList StorageLauncherIcon::GetManagedWindows() const +{ + return managed_windows_; +} + +void StorageLauncherIcon::OnWindowStateChanged() +{ + bool active = false; + bool urgent = false; + bool check_visibility = (GetIconType() == IconType::APPLICATION); + bool visible = IsSticky(); + + for (auto const& win : managed_windows_) + { + if (!active && win->active()) + active = true; + + if (!urgent && win->urgent()) + urgent = true; + + if (check_visibility && !visible && win->visible()) + visible = true; + } + + SetQuirk(Quirk::ACTIVE, active); + SetQuirk(Quirk::URGENT, urgent); + + if (check_visibility) + SetQuirk(Quirk::VISIBLE, visible); +} + +bool StorageLauncherIcon::OnShouldHighlightOnDrag(DndData const& dnd_data) +{ + for (auto const& uri : dnd_data.Uris()) + { + if (uri.find("file://") == 0) + return true; + } + + return false; +} + +} // namespace launcher +} // namespace unity diff --git a/launcher/StorageLauncherIcon.h b/launcher/StorageLauncherIcon.h new file mode 100644 index 000000000..a552f88d5 --- /dev/null +++ b/launcher/StorageLauncherIcon.h @@ -0,0 +1,55 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2015 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: Marco Trevisan <marco.trevisan@canonical.com> + */ + +#ifndef STORAGE_LAUNCHER_ICON_H +#define STORAGE_LAUNCHER_ICON_H + +#include "WindowedLauncherIcon.h" +#include "unity-shared/FileManager.h" + +namespace unity +{ +namespace launcher +{ + +class StorageLauncherIcon : public virtual WindowedLauncherIcon +{ +public: + StorageLauncherIcon(AbstractLauncherIcon::IconType, FileManager::Ptr const&); + +protected: + void UpdateStorageWindows(); + WindowList GetManagedWindows() const override; + virtual WindowList GetStorageWindows() const = 0; + + bool OnShouldHighlightOnDrag(DndData const& dnd_data) override; + +private: + void OnWindowStateChanged(); + +protected: + FileManager::Ptr file_manager_; + WindowList managed_windows_; + connection::Manager windows_connections_; +}; + +} // namespace launcher +} // namespace unity + +#endif // STORAGE_LAUNCHER_ICON_H diff --git a/launcher/SwitcherController.cpp b/launcher/SwitcherController.cpp index 9b9711218..5f9c6e3f0 100644 --- a/launcher/SwitcherController.cpp +++ b/launcher/SwitcherController.cpp @@ -325,11 +325,18 @@ void Controller::Impl::Show(ShowMode show_mode, SortMode sort_mode, std::vector< model_->selection_changed.connect(sigc::mem_fun(this, &Controller::Impl::OnModelSelectionChanged)); model_->detail_selection.changed.connect([this] (bool) { sources_.Remove(DETAIL_TIMEOUT); }); model_->updated.connect([this] { if (!model_->Size()) Hide(false); }); - obj_->AddChild(model_.get()); + + if (!model_->Size()) + { + model_.reset(); + return; + } SelectFirstItem(); + obj_->AddChild(model_.get()); obj_->visible_ = true; + int real_wait = obj_->timeout_length() - fade_animator_.Duration(); if (real_wait > 0) @@ -442,7 +449,6 @@ void Controller::Impl::ConstructView() sources_.Remove(VIEW_CONSTRUCT_IDLE); view_ = SwitcherView::Ptr(new SwitcherView(icon_renderer_)); - obj_->AddChild(view_.GetPointer()); view_->SetModel(model_); view_->background_color = WindowManager::Default().average_color(); view_->monitor = obj_->monitor_; @@ -462,6 +468,7 @@ void Controller::Impl::ConstructView() view_->switcher_start_detail.connect(sigc::mem_fun(this, &Impl::StartDetailMode)); view_->switcher_stop_detail.connect(sigc::mem_fun(this, &Impl::StopDetailMode)); view_->switcher_close_current.connect(sigc::mem_fun(this, &Impl::CloseSelection)); + obj_->AddChild(view_.GetPointer()); ConstructWindow(); main_layout_->AddView(view_.GetPointer(), 1); @@ -507,6 +514,9 @@ void Controller::Impl::HideWindow() view_window_->ShowWindow(false); view_window_->PushToBack(); + obj_->RemoveChild(model_.get()); + obj_->RemoveChild(view_.GetPointer()); + model_.reset(); view_.Release(); } @@ -720,14 +730,11 @@ void Controller::Impl::SelectFirstItem() uint64_t second_first = 0; // second icons first highest active WindowManager& wm = WindowManager::Default(); - for (auto& window : first->Windows()) - { - Window xid = window->window_id(); - - if (model_->only_apps_on_viewport && !wm.IsWindowOnCurrentDesktop(xid)) - continue; + auto const& windows = (model_->only_apps_on_viewport) ? first->WindowsOnViewport() : first->Windows(); - uint64_t num = wm.GetWindowActiveNumber(xid); + for (auto& window : windows) + { + uint64_t num = wm.GetWindowActiveNumber(window->window_id()); if (num > first_highest) { diff --git a/launcher/SwitcherModel.cpp b/launcher/SwitcherModel.cpp index df3264328..4d8889435 100644 --- a/launcher/SwitcherModel.cpp +++ b/launcher/SwitcherModel.cpp @@ -37,16 +37,7 @@ namespace bool CompareSwitcherItemsPriority(AbstractLauncherIcon::Ptr const& first, AbstractLauncherIcon::Ptr const& second) { - if (first->GetIconType() == second->GetIconType()) - return first->SwitcherPriority() > second->SwitcherPriority(); - - if (first->GetIconType() == AbstractLauncherIcon::IconType::DESKTOP) - return true; - - if (second->GetIconType() == AbstractLauncherIcon::IconType::DESKTOP) - return false; - - return first->GetIconType() < second->GetIconType(); + return first->SwitcherPriority() > second->SwitcherPriority(); } } @@ -174,7 +165,7 @@ void SwitcherModel::ConnectToIconSignals(launcher::AbstractLauncherIcon::Ptr con void SwitcherModel::AddIcon(AbstractLauncherIcon::Ptr const& icon) { - if (!icon || icon->GetIconType() != AbstractLauncherIcon::IconType::APPLICATION) + if (!icon) return; if (icon->ShowInSwitcher(only_apps_on_viewport)) @@ -318,7 +309,7 @@ size_t SwitcherModel::Size() const AbstractLauncherIcon::Ptr SwitcherModel::Selection() const { - return applications_.at(index_); + return index_ < applications_.size() ? applications_.at(index_) : AbstractLauncherIcon::Ptr(); } int SwitcherModel::SelectionIndex() const @@ -328,7 +319,8 @@ int SwitcherModel::SelectionIndex() const bool SwitcherModel::SelectionIsActive() const { - return Selection()->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE); + auto const& selection = Selection(); + return selection ? selection->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE) : false; } AbstractLauncherIcon::Ptr SwitcherModel::LastSelection() const @@ -353,8 +345,12 @@ std::vector<Window> SwitcherModel::SelectionWindows() const WindowManager& wm = WindowManager::Default(); std::vector<Window> results; + auto const& selection = Selection(); + + if (!selection) + return results; - for (auto& window : Selection()->Windows()) + for (auto& window : selection->Windows()) { Window xid = window->window_id(); @@ -369,7 +365,7 @@ std::vector<Window> SwitcherModel::SelectionWindows() const return wm.GetWindowActiveNumber(first) > wm.GetWindowActiveNumber(second); }); - if (Selection() == last_active_application_) + if (selection == last_active_application_) { results.push_back(results.front()); results.erase(results.begin()); @@ -406,6 +402,9 @@ void SwitcherModel::UnsetDetailSelection() void SwitcherModel::NextIndex() { + if (applications_.empty()) + return; + last_index_ = index_; ++index_ %= applications_.size(); } @@ -419,6 +418,9 @@ void SwitcherModel::Next() void SwitcherModel::PrevIndex() { + if (applications_.empty()) + return; + last_index_ = index_; index_ = ((index_ > 0 && index_ < applications_.size()) ? index_ : applications_.size()) - 1; } @@ -432,7 +434,7 @@ void SwitcherModel::Prev() void SwitcherModel::NextDetail() { - if (!detail_selection()) + if (!detail_selection() || detail_xids_.empty()) return; detail_selection_index = (detail_selection_index + 1) % detail_xids_.size(); @@ -441,7 +443,7 @@ void SwitcherModel::NextDetail() void SwitcherModel::PrevDetail() { - if (!detail_selection()) + if (!detail_selection() || detail_xids_.empty()) return; detail_selection_index = ((detail_selection_index() > 0) ? detail_selection_index : detail_xids_.size()) - 1; diff --git a/launcher/SwitcherView.cpp b/launcher/SwitcherView.cpp index b81eeef5d..302901ba4 100644 --- a/launcher/SwitcherView.cpp +++ b/launcher/SwitcherView.cpp @@ -538,7 +538,7 @@ RenderArg SwitcherView::CreateBaseArgForIcon(AbstractLauncherIcon::Ptr const& ic // tells the renderer to render arrows by number arg.running_on_viewport = true; - arg.window_indicators = icon->WindowsForMonitor(monitor).size(); + arg.window_indicators = icon->WindowsVisibleOnMonitor(monitor); if (arg.window_indicators > 1) arg.running_arrow = true; else diff --git a/launcher/TrashLauncherIcon.cpp b/launcher/TrashLauncherIcon.cpp index fdc540e43..b8239aabd 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-2013 Canonical Ltd + * Copyright (C) 2010-2015 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 @@ -24,6 +24,7 @@ #include "config.h" #include <glib/gi18n-lib.h> #include <NuxCore/Logger.h> +#include <UnityCore/DesktopUtilities.h> #include <zeitgeist.h> #include "QuicklistMenuItemLabel.h" @@ -39,20 +40,19 @@ namespace DECLARE_LOGGER(logger, "unity.launcher.icon.trash"); const std::string ZEITGEIST_UNITY_ACTOR = "application://compiz.desktop"; const std::string TRASH_URI = "trash:"; + const std::string TRASH_PATH = "file://" + DesktopUtilities::GetUserTrashDirectory(); } -TrashLauncherIcon::TrashLauncherIcon(FileManager::Ptr const& fmo) - : SimpleLauncherIcon(IconType::TRASH) +TrashLauncherIcon::TrashLauncherIcon(FileManager::Ptr const& fm) + : WindowedLauncherIcon(IconType::TRASH) + , StorageLauncherIcon(GetIconType(), fm ? fm : GnomeFileManager::Get()) , empty_(true) - , file_manager_(fmo ? fmo : GnomeFileManager::Get()) { tooltip_text = _("Trash"); icon_name = "user-trash"; position = Position::END; SetQuirk(Quirk::VISIBLE, true); SkipQuirkAnimation(Quirk::VISIBLE); - - SetQuirk(Quirk::RUNNING, file_manager_->IsTrashOpened()); SetShortcut('t'); glib::Object<GFile> location(g_file_new_for_uri(TRASH_URI.c_str())); @@ -67,20 +67,27 @@ TrashLauncherIcon::TrashLauncherIcon(FileManager::Ptr const& fmo) } else { - trash_changed_signal_.Connect(trash_monitor_, "changed", + glib_signals_.Add<void, GFileMonitor*, GFile*, GFile*, GFileMonitorEvent>(trash_monitor_, "changed", [this] (GFileMonitor*, GFile*, GFile*, GFileMonitorEvent) { UpdateTrashIcon(); }); } - file_manager_->locations_changed.connect(sigc::mem_fun(this, &TrashLauncherIcon::OnOpenedLocationsChanged)); - UpdateTrashIcon(); + UpdateStorageWindows(); +} + +WindowList TrashLauncherIcon::GetStorageWindows() const +{ + auto windows = file_manager_->WindowsForLocation(TRASH_URI); + auto const& path_wins = file_manager_->WindowsForLocation(TRASH_PATH); + windows.insert(end(windows), begin(path_wins), end(path_wins)); + return windows; } -void TrashLauncherIcon::OnOpenedLocationsChanged() +void TrashLauncherIcon::OpenInstanceLauncherIcon(Time timestamp) { - SetQuirk(Quirk::RUNNING, file_manager_->IsTrashOpened()); + file_manager_->OpenTrash(timestamp); } AbstractLauncherIcon::MenuItemsVector TrashLauncherIcon::GetMenus() @@ -92,20 +99,41 @@ AbstractLauncherIcon::MenuItemsVector TrashLauncherIcon::GetMenus() 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, + glib_signals_.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned timestamp) { file_manager_->EmptyTrash(timestamp); }); result.push_back(menu_item); - return result; -} + if (IsRunning()) + { + auto const& windows_items = GetWindowsMenuItems(); + if (!windows_items.empty()) + { + menu_item = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); + result.push_back(menu_item); -void TrashLauncherIcon::ActivateLauncherIcon(ActionArg arg) -{ - SimpleLauncherIcon::ActivateLauncherIcon(arg); - file_manager_->OpenTrash(arg.timestamp); + result.insert(end(result), begin(windows_items), end(windows_items)); + } + + menu_item = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); + result.push_back(menu_item); + + menu_item = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Quit")); + dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); + dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); + result.push_back(menu_item); + + glib_signals_.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) { + Quit(); + }); + } + + return result; } void TrashLauncherIcon::UpdateTrashIcon() diff --git a/launcher/TrashLauncherIcon.h b/launcher/TrashLauncherIcon.h index 24a2622e3..3b32cd572 100644 --- a/launcher/TrashLauncherIcon.h +++ b/launcher/TrashLauncherIcon.h @@ -23,9 +23,10 @@ #include <gio/gio.h> #include <UnityCore/GLibWrapper.h> #include <UnityCore/GLibSignal.h> +#include <UnityCore/ConnectionManager.h> #include "DndData.h" -#include "SimpleLauncherIcon.h" +#include "StorageLauncherIcon.h" #include "unity-shared/FileManager.h" namespace unity @@ -33,7 +34,7 @@ namespace unity namespace launcher { -class TrashLauncherIcon : public SimpleLauncherIcon +class TrashLauncherIcon : public StorageLauncherIcon { public: TrashLauncherIcon(FileManager::Ptr const& = nullptr); @@ -45,21 +46,18 @@ protected: bool OnShouldHighlightOnDrag(DndData const& dnd_data); void OnAcceptDrop(DndData const& dnd_data); + WindowList GetStorageWindows() const override; std::string GetName() const; private: - void ActivateLauncherIcon(ActionArg arg); - void OnOpenedLocationsChanged(); + void OpenInstanceLauncherIcon(Time timestamp) override; MenuItemsVector GetMenus(); static void UpdateTrashIconCb(GObject* source, GAsyncResult* res, gpointer data); bool empty_; - FileManager::Ptr file_manager_; glib::Cancellable cancellable_; glib::Object<GFileMonitor> trash_monitor_; - glib::Signal<void, GFileMonitor*, GFile*, GFile*, GFileMonitorEvent> trash_changed_signal_; - glib::Signal<void, DbusmenuMenuitem*, unsigned> empty_activated_signal_; }; } diff --git a/launcher/VolumeLauncherIcon.cpp b/launcher/VolumeLauncherIcon.cpp index 8f09be7c7..85eee27fc 100644 --- a/launcher/VolumeLauncherIcon.cpp +++ b/launcher/VolumeLauncherIcon.cpp @@ -49,7 +49,7 @@ public: , volume_(volume) , devices_settings_(devices_settings) , notification_(notification) - , file_manager_(fm) + , file_manager_(parent_->file_manager_) { UpdateIcon(); UpdateVisibility(); @@ -60,48 +60,41 @@ public: { parent_->tooltip_text = volume_->GetName(); parent_->icon_name = volume_->GetIconName(); - parent_->SetQuirk(Quirk::RUNNING, file_manager_->IsPrefixOpened(volume_->GetUri())); } void UpdateVisibility() { - UpdateKeepInLauncher(); - parent_->SetQuirk(Quirk::VISIBLE, keep_in_launcher_); + parent_->SetQuirk(Quirk::VISIBLE, IsVisible()); } - void UpdateKeepInLauncher() + bool IsBlackListed() { - auto const& identifier = volume_->GetIdentifier(); - keep_in_launcher_ = !devices_settings_->IsABlacklistedDevice(identifier); + return devices_settings_->IsABlacklistedDevice(volume_->GetIdentifier()); } - void ConnectSignals() + bool IsVisible() { - connections_.Add(volume_->changed.connect(sigc::mem_fun(this, &Impl::OnVolumeChanged))); - connections_.Add(volume_->removed.connect(sigc::mem_fun(this, &Impl::OnVolumeRemoved))); - connections_.Add(devices_settings_->changed.connect(sigc::mem_fun(this, &Impl::OnSettingsChanged))); - connections_.Add(file_manager_->locations_changed.connect(sigc::mem_fun(this, &Impl::UpdateIcon))); + if (IsBlackListed() && parent_->GetManagedWindows().empty()) + return false; + + return true; } - void OnVolumeChanged() + void ConnectSignals() { - UpdateIcon(); + connections_.Add(volume_->changed.connect([this] { UpdateIcon(); })); + connections_.Add(volume_->removed.connect(sigc::mem_fun(this, &Impl::OnVolumeRemoved))); + connections_.Add(devices_settings_->changed.connect([this] { UpdateVisibility(); })); + connections_.Add(parent_->windows_changed.connect([this] (int) { UpdateVisibility(); })); } void OnVolumeRemoved() { - if (devices_settings_->IsABlacklistedDevice(volume_->GetIdentifier())) - devices_settings_->TryToUnblacklist(volume_->GetIdentifier()); - + devices_settings_->TryToUnblacklist(volume_->GetIdentifier()); parent_->UnStick(); parent_->Remove(); } - void OnSettingsChanged() - { - UpdateVisibility(); - } - bool CanEject() const { return volume_->CanBeEjected(); @@ -152,7 +145,7 @@ public: void OpenInFileManager(uint64_t timestamp) { DoActionWhenMounted([this, timestamp] { - file_manager_->OpenActiveChild(volume_->GetUri(), timestamp); + file_manager_->Open(volume_->GetUri(), timestamp); }); } @@ -171,29 +164,38 @@ public: AppendSeparatorItem(result); AppendNameItem(result); AppendSeparatorItem(result); - AppendUnlockFromLauncherItem(result); + AppendWindowsItems(result); + AppendToggleLockFromLauncherItem(result); AppendEjectItem(result); AppendSafelyRemoveItem(result); AppendUnmountItem(result); + AppendQuitItem(result); return result; } - void AppendUnlockFromLauncherItem(MenuItemsVector& menu) + void AppendToggleLockFromLauncherItem(MenuItemsVector& menu) { if (volume_->GetIdentifier().empty()) return; glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new()); - dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Unlock from Launcher")); + const char* label = IsBlackListed() ? _("Lock to Launcher") : _("Unlock from Launcher"); + dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, label); 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) { - auto const& identifier = volume_->GetIdentifier(); - parent_->UnStick(); - devices_settings_->TryToBlacklist(identifier); + parent_->glib_signals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) { + if (!IsBlackListed()) + { + parent_->UnStick(); + devices_settings_->TryToBlacklist(volume_->GetIdentifier()); + } + else + { + devices_settings_->TryToUnblacklist(volume_->GetIdentifier()); + } })); menu.push_back(menu_item); @@ -220,13 +222,26 @@ public: dbusmenu_menuitem_property_set_bool(menu_item, QuicklistMenuItem::MARKUP_ENABLED_PROPERTY, true); dbusmenu_menuitem_property_set_bool(menu_item, QuicklistMenuItem::MARKUP_ACCEL_DISABLED_PROPERTY, true); - gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned timestamp) { + parent_->glib_signals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned timestamp) { OpenInFileManager(timestamp); })); menu.push_back(menu_item); } + void AppendWindowsItems(MenuItemsVector& menu) + { + if (!parent_->IsRunning()) + return; + + auto const& windows_items = parent_->GetWindowsMenuItems(); + if (!windows_items.empty()) + { + menu.insert(end(menu), begin(windows_items), end(windows_items)); + AppendSeparatorItem(menu); + } + } + void AppendOpenItem(MenuItemsVector& menu) { glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new()); @@ -235,7 +250,7 @@ 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*, unsigned timestamp) { + parent_->glib_signals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned timestamp) { OpenInFileManager(timestamp); })); @@ -253,7 +268,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) { + parent_->glib_signals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) { + parent_->Quit(); EjectAndShowNotification(); })); @@ -271,8 +287,9 @@ 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_->StopDrive(); + parent_->glib_signals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) { + parent_->Quit(); + volume_->StopDrive(); })); menu.push_back(menu_item); @@ -289,8 +306,29 @@ 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_->Unmount(); + parent_->glib_signals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) { + volume_->Unmount(); + })); + + menu.push_back(menu_item); + } + + void AppendQuitItem(MenuItemsVector& menu) + { + if (!parent_->IsRunning()) + return; + + if (!menu.empty()) + AppendSeparatorItem(menu); + + glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new()); + + dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Quit")); + dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); + dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); + + parent_->glib_signals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) { + parent_->Quit(); })); menu.push_back(menu_item); @@ -307,13 +345,10 @@ public: } VolumeLauncherIcon* parent_; - bool keep_in_launcher_; Volume::Ptr volume_; DevicesSettings::Ptr devices_settings_; DeviceNotificationDisplay::Ptr notification_; FileManager::Ptr file_manager_; - - glib::SignalManager gsignals_; connection::Manager connections_; }; @@ -325,15 +360,20 @@ VolumeLauncherIcon::VolumeLauncherIcon(Volume::Ptr const& volume, DevicesSettings::Ptr const& devices_settings, DeviceNotificationDisplay::Ptr const& notification, FileManager::Ptr const& fm) - : SimpleLauncherIcon(IconType::DEVICE) + : WindowedLauncherIcon(IconType::DEVICE) + , StorageLauncherIcon(GetIconType(), fm) , pimpl_(new Impl(volume, devices_settings, notification, fm, this)) -{} +{ + UpdateStorageWindows(); +} VolumeLauncherIcon::~VolumeLauncherIcon() {} void VolumeLauncherIcon::AboutToRemove() { + StorageLauncherIcon::AboutToRemove(); + if (CanEject()) EjectAndShowNotification(); else if (CanStop()) @@ -360,12 +400,6 @@ void VolumeLauncherIcon::StopDrive() return pimpl_->StopDrive(); } -void VolumeLauncherIcon::ActivateLauncherIcon(ActionArg arg) -{ - SimpleLauncherIcon::ActivateLauncherIcon(arg); - pimpl_->OpenInFileManager(arg.timestamp); -} - AbstractLauncherIcon::MenuItemsVector VolumeLauncherIcon::GetMenus() { return pimpl_->GetMenus(); @@ -388,17 +422,6 @@ void VolumeLauncherIcon::UnStick() SetQuirk(Quirk::VISIBLE, true); } -bool VolumeLauncherIcon::OnShouldHighlightOnDrag(DndData const& dnd_data) -{ - for (auto const& uri : dnd_data.Uris()) - { - if (uri.find("file://") == 0) - return true; - } - - return false; -} - nux::DndAction VolumeLauncherIcon::OnQueryAcceptDrop(DndData const& dnd_data) { return dnd_data.Uris().empty() ? nux::DNDACTION_NONE : nux::DNDACTION_COPY; @@ -412,6 +435,21 @@ void VolumeLauncherIcon::OnAcceptDrop(DndData const& dnd_data) FullyAnimateQuirkDelayed(100, LauncherIcon::Quirk::SHIMMER); } +std::string VolumeLauncherIcon::GetVolumeUri() const +{ + return pimpl_->volume_->GetUri(); +} + +WindowList VolumeLauncherIcon::GetStorageWindows() const +{ + return file_manager_->WindowsForLocation(GetVolumeUri()); +} + +void VolumeLauncherIcon::OpenInstanceLauncherIcon(Time timestamp) +{ + pimpl_->OpenInFileManager(timestamp); +} + // // Introspection // diff --git a/launcher/VolumeLauncherIcon.h b/launcher/VolumeLauncherIcon.h index a78e2199c..3322db26c 100644 --- a/launcher/VolumeLauncherIcon.h +++ b/launcher/VolumeLauncherIcon.h @@ -24,7 +24,7 @@ #include "Volume.h" #include "DevicesSettings.h" #include "DeviceNotificationDisplay.h" -#include "SimpleLauncherIcon.h" +#include "StorageLauncherIcon.h" #include "unity-shared/FileManager.h" namespace unity @@ -32,7 +32,7 @@ namespace unity namespace launcher { -class VolumeLauncherIcon : public SimpleLauncherIcon +class VolumeLauncherIcon : public StorageLauncherIcon { public: typedef nux::ObjectPtr<VolumeLauncherIcon> Ptr; @@ -41,7 +41,7 @@ public: DeviceNotificationDisplay::Ptr const&, FileManager::Ptr const&); virtual ~VolumeLauncherIcon(); - virtual void AboutToRemove(); + void AboutToRemove() override; bool CanEject() const; // TODO: rename to public virtual bool IsTrashable(); void EjectAndShowNotification(); // TODO: rename to private virtual void DoDropToTrash(); @@ -49,14 +49,16 @@ public: void StopDrive(); void Stick(bool save = true); void UnStick(); + MenuItemsVector GetMenus(); std::string GetRemoteUri() const; + std::string GetVolumeUri() const; protected: - void ActivateLauncherIcon(ActionArg arg); - bool OnShouldHighlightOnDrag(DndData const&); void OnAcceptDrop(DndData const&); nux::DndAction OnQueryAcceptDrop(DndData const&); + WindowList GetStorageWindows() const override; + void OpenInstanceLauncherIcon(Time timestamp) override; // Introspection virtual std::string GetName() const; diff --git a/launcher/WindowedLauncherIcon.cpp b/launcher/WindowedLauncherIcon.cpp new file mode 100644 index 000000000..efffb81ac --- /dev/null +++ b/launcher/WindowedLauncherIcon.cpp @@ -0,0 +1,618 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2015 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: Marco Trevisan <marco.trevisan@canonical.com> + */ + +#include <Nux/Nux.h> + +#include "WindowedLauncherIcon.h" +#include "MultiMonitor.h" +#include "unity-shared/UBusWrapper.h" +#include "unity-shared/UBusMessages.h" +#include "unity-shared/UScreen.h" + +namespace unity +{ +namespace launcher +{ +namespace +{ +const std::string ICON_DND_OVER_TIMEOUT = "windowed-icon-dnd-over"; +const int COMPIZ_SCALE_DND_SPREAD = 1 << 7; +const int MAXIMUM_QUICKLIST_WIDTH = 300; +} + +NUX_IMPLEMENT_OBJECT_TYPE(WindowedLauncherIcon); + +WindowedLauncherIcon::WindowedLauncherIcon(AbstractLauncherIcon::IconType icon_type) + : SimpleLauncherIcon(icon_type) + , last_scroll_timestamp_(0) + , progressive_scroll_(0) +{ + WindowManager& wm = WindowManager::Default(); + wm.window_minimized.connect(sigc::mem_fun(this, &WindowedLauncherIcon::OnWindowMinimized)); + wm.screen_viewport_switch_ended.connect(sigc::mem_fun(this, &WindowedLauncherIcon::EnsureWindowState)); + wm.terminate_expo.connect(sigc::mem_fun(this, &WindowedLauncherIcon::EnsureWindowState)); + UScreen::GetDefault()->changed.connect(sigc::hide(sigc::hide(sigc::mem_fun(this, &WindowedLauncherIcon::EnsureWindowsLocation)))); + + windows_changed.connect([this] (int) { + if (WindowManager::Default().IsScaleActiveForGroup() && IsActive()) + Spread(true, 0, false); + }); +} + +bool WindowedLauncherIcon::IsActive() const +{ + return GetQuirk(Quirk::ACTIVE); +} + +bool WindowedLauncherIcon::IsRunning() const +{ + return GetQuirk(Quirk::RUNNING); +} + +bool WindowedLauncherIcon::IsUrgent() const +{ + return GetQuirk(Quirk::URGENT); +} + +bool WindowedLauncherIcon::IsUserVisible() const +{ + return IsRunning(); +} + +void WindowedLauncherIcon::ActivateLauncherIcon(ActionArg arg) +{ + SimpleLauncherIcon::ActivateLauncherIcon(arg); + WindowManager& wm = WindowManager::Default(); + + // This is a little awkward as the target is only set from the switcher. + if (arg.target) + { + // thumper: should we Raise too? should the WM raise? + wm.Activate(arg.target); + return; + } + + bool scale_was_active = wm.IsScaleActive(); + bool active = IsActive(); + bool user_visible = IsRunning(); + /* We should check each child to see if there is + * an unmapped (!= minimized) window around and + * if so force "Focus" behaviour */ + + if (arg.source != ActionArg::Source::SWITCHER) + { + user_visible = IsUserVisible(); + + if (active) + { + bool any_visible = false; + bool any_mapped = false; + bool any_on_top = false; + bool any_on_monitor = (arg.monitor < 0); + int active_monitor = arg.monitor; + + for (auto const& window : GetManagedWindows()) + { + Window xid = window->window_id(); + + if (!any_visible && wm.IsWindowOnCurrentDesktop(xid)) + { + any_visible = true; + } + + if (!any_mapped && wm.IsWindowMapped(xid)) + { + any_mapped = true; + } + + if (!any_on_top && wm.IsWindowOnTop(xid)) + { + any_on_top = true; + } + + if (!any_on_monitor && window->monitor() == arg.monitor && + wm.IsWindowMapped(xid) && wm.IsWindowVisible(xid)) + { + any_on_monitor = true; + } + + if (window->active()) + { + active_monitor = window->monitor(); + } + } + + if (!any_visible || !any_mapped || !any_on_top) + active = false; + + if (any_on_monitor && arg.monitor >= 0 && active_monitor != arg.monitor) + active = false; + } + } + + /* Behaviour: + * 1) Nothing running, or nothing visible -> launch application + * 2) Running and active -> spread application + * 3) Running and not active -> focus application + * 4) Spread is active and different icon pressed -> change spread + * 5) Spread is active -> Spread de-activated, and fall through + */ + + if (!IsRunning() || (IsRunning() && !user_visible)) // #1 above + { + if (GetQuirk(Quirk::STARTING, arg.monitor)) + return; + + wm.TerminateScale(); + SetQuirk(Quirk::STARTING, true, arg.monitor); + OpenInstanceLauncherIcon(arg.timestamp); + } + else // container is running + { + if (active) + { + if (scale_was_active) // #5 above + { + wm.TerminateScale(); + + if (minimize_window_on_click()) + { + for (auto const& win : GetWindows(WindowFilter::ON_CURRENT_DESKTOP)) + wm.Minimize(win->window_id()); + } + else + { + Focus(arg); + } + } + else // #2 above + { + if (arg.source != ActionArg::Source::SWITCHER) + { + bool minimized = false; + + if (minimize_window_on_click()) + { + WindowList const& windows = GetWindows(WindowFilter::ON_CURRENT_DESKTOP); + + if (windows.size() == 1) + { + wm.Minimize(windows[0]->window_id()); + minimized = true; + } + } + + if (!minimized) + { + Spread(true, 0, false); + } + } + } + } + else + { + if (scale_was_active) // #4 above + { + if (GetWindows(WindowFilter::ON_CURRENT_DESKTOP).size() <= 1) + wm.TerminateScale(); + + Focus(arg); + + if (arg.source != ActionArg::Source::SWITCHER) + Spread(true, 0, false); + } + else // #3 above + { + Focus(arg); + } + } + } +} + +WindowList WindowedLauncherIcon::GetWindows(WindowFilterMask filter, int monitor) +{ + if ((!filter && monitor < 0) || (filter == WindowFilter::ON_ALL_MONITORS)) + return GetManagedWindows(); + + WindowManager& wm = WindowManager::Default(); + WindowList results; + + monitor = (filter & WindowFilter::ON_ALL_MONITORS) ? -1 : monitor; + bool mapped = (filter & WindowFilter::MAPPED); + bool user_visible = (filter & WindowFilter::USER_VISIBLE); + bool current_desktop = (filter & WindowFilter::ON_CURRENT_DESKTOP); + + for (auto& window : GetManagedWindows()) + { + if ((monitor >= 0 && window->monitor() == monitor) || monitor < 0) + { + if ((user_visible && window->visible()) || !user_visible) + { + Window xid = window->window_id(); + + if ((mapped && wm.IsWindowMapped(xid)) || !mapped) + { + if ((current_desktop && wm.IsWindowOnCurrentDesktop(xid)) || !current_desktop) + { + results.push_back(window); + } + } + } + } + } + + return results; +} + +WindowList WindowedLauncherIcon::Windows() +{ + return GetWindows(WindowFilter::MAPPED|WindowFilter::ON_ALL_MONITORS); +} + +WindowList WindowedLauncherIcon::WindowsOnViewport() +{ + WindowFilterMask filter = 0; + filter |= WindowFilter::MAPPED; + filter |= WindowFilter::USER_VISIBLE; + filter |= WindowFilter::ON_CURRENT_DESKTOP; + filter |= WindowFilter::ON_ALL_MONITORS; + + return GetWindows(filter); +} + +WindowList WindowedLauncherIcon::WindowsForMonitor(int monitor) +{ + WindowFilterMask filter = 0; + filter |= WindowFilter::MAPPED; + filter |= WindowFilter::USER_VISIBLE; + filter |= WindowFilter::ON_CURRENT_DESKTOP; + + return GetWindows(filter, monitor); +} + +void WindowedLauncherIcon::OnWindowMinimized(Window xid) +{ + for (auto const& window : GetManagedWindows()) + { + if (xid == window->window_id()) + { + int monitor = GetCenterForMonitor(window->monitor()).first; + + if (monitor >= 0) + { + Present(0.5f, 600, monitor); + FullyAnimateQuirkDelayed(300, Quirk::SHIMMER, monitor); + } + + break; + } + } +} + +void WindowedLauncherIcon::Focus(ActionArg arg) +{ + bool show_only_visible = (arg.source == ActionArg::Source::SWITCHER); + ApplicationManager::Default().FocusWindowGroup(GetManagedWindows(), show_only_visible, arg.monitor); +} + +bool WindowedLauncherIcon::Spread(bool current_desktop, int state, bool force) +{ + std::vector<Window> windows; + for (auto& window : GetWindows(current_desktop ? WindowFilter::ON_CURRENT_DESKTOP : 0)) + windows.push_back(window->window_id()); + + return WindowManager::Default().ScaleWindowGroup(windows, state, force); +} + +void WindowedLauncherIcon::EnsureWindowState() +{ + std::vector<int> number_of_windows_on_monitor(monitors::MAX); + + for (auto const& window : WindowsOnViewport()) + { + int monitor = window->monitor(); + + // If monitor is -1 (or negative), show on all monitors. + if (monitor < 0) + { + for (unsigned j; j < monitors::MAX; ++j) + ++number_of_windows_on_monitor[j]; + } + else + { + ++number_of_windows_on_monitor[monitor]; + } + } + + for (unsigned i = 0; i < monitors::MAX; ++i) + SetNumberOfWindowsVisibleOnMonitor(number_of_windows_on_monitor[i], i); +} + +void WindowedLauncherIcon::EnsureWindowsLocation() +{ + EnsureWindowState(); + UpdateIconGeometries(GetCenters()); +} + +void WindowedLauncherIcon::UpdateIconGeometries(std::vector<nux::Point3> const& centers) +{ + nux::Geometry geo(0, 0, icon_size, icon_size); + + for (auto& window : GetManagedWindows()) + { + Window xid = window->window_id(); + int monitor = GetCenterForMonitor(window->monitor()).first; + + if (monitor < 0) + { + WindowManager::Default().SetWindowIconGeometry(xid, nux::Geometry()); + continue; + } + + geo.x = centers[monitor].x - icon_size / 2; + geo.y = centers[monitor].y - icon_size / 2; + WindowManager::Default().SetWindowIconGeometry(xid, geo); + } +} + +void WindowedLauncherIcon::OnCenterStabilized(std::vector<nux::Point3> const& centers) +{ + UpdateIconGeometries(centers); +} + +void WindowedLauncherIcon::OnDndEnter() +{ + auto timestamp = nux::GetGraphicsDisplay()->GetCurrentEvent().x11_timestamp; + + _source_manager.AddTimeout(1000, [this, timestamp] { + bool to_spread = GetWindows(WindowFilter::ON_CURRENT_DESKTOP).size() > 1; + + if (!to_spread) + WindowManager::Default().TerminateScale(); + + if (!IsRunning()) + return false; + + UBusManager::SendMessage(UBUS_OVERLAY_CLOSE_REQUEST); + Focus(ActionArg(ActionArg::Source::LAUNCHER, 1, timestamp)); + + if (to_spread) + Spread(true, COMPIZ_SCALE_DND_SPREAD, false); + + return false; + }, ICON_DND_OVER_TIMEOUT); +} + +void WindowedLauncherIcon::OnDndLeave() +{ + _source_manager.Remove(ICON_DND_OVER_TIMEOUT); +} + +bool WindowedLauncherIcon::HandlesSpread() +{ + return true; +} + +bool WindowedLauncherIcon::ShowInSwitcher(bool current) +{ + if (!removed() && IsRunning() && IsVisible()) + { + // If current is true, we only want to show the current workspace. + if (!current) + { + return true; + } + else + { + for (unsigned i = 0; i < monitors::MAX; ++i) + { + if (WindowVisibleOnMonitor(i)) + return true; + } + } + } + + return false; +} + +bool WindowedLauncherIcon::AllowDetailViewInSwitcher() const +{ + return true; +} + +uint64_t WindowedLauncherIcon::SwitcherPriority() +{ + uint64_t result = 0; + + for (auto& window : GetManagedWindows()) + { + Window xid = window->window_id(); + result = std::max(result, WindowManager::Default().GetWindowActiveNumber(xid)); + } + + return result; +} + +void PerformScrollUp(WindowList const& windows, unsigned int progressive_scroll) +{ + if (progressive_scroll == windows.size() - 1) + { + //RestackAbove to preserve Global Stacking Order + WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.at(1)->window_id()); + WindowManager::Default().RestackBelow(windows.at(1)->window_id(), windows.at(0)->window_id()); + windows.back()->Focus(); + return; + } + + WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.at(progressive_scroll + 1)->window_id()); + windows.at(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 WindowedLauncherIcon::PerformScroll(ScrollDirection direction, Time timestamp) +{ + if (timestamp - last_scroll_timestamp_ < 150) + return; + else if (timestamp - last_scroll_timestamp_ > 1500) + progressive_scroll_ = 0; + + last_scroll_timestamp_ = timestamp; + + auto const& windows = GetWindowsOnCurrentDesktopInStackingOrder(); + + if (windows.empty()) + return; + + if (scroll_inactive_icons && !IsActive()) + { + windows.at(0)->Focus(); + return; + } + + if (!scroll_inactive_icons && !IsActive()) + return; + + if (windows.size() <= 1) + return; + + if (direction == ScrollDirection::DOWN) + ++progressive_scroll_; + else + //--progressive_scroll_; but roll to the top of windows + progressive_scroll_ += windows.size() - 1; + progressive_scroll_ %= windows.size(); + + switch(direction) + { + case ScrollDirection::UP: + PerformScrollUp(windows, progressive_scroll_); + break; + case ScrollDirection::DOWN: + PerformScrollDown(windows, progressive_scroll_); + break; + } +} + +WindowList WindowedLauncherIcon::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; +} + +void WindowedLauncherIcon::Quit() const +{ + for (auto& window : GetManagedWindows()) + window->Quit(); +} + +void WindowedLauncherIcon::AboutToRemove() +{ + Quit(); +} + +AbstractLauncherIcon::MenuItemsVector WindowedLauncherIcon::GetWindowsMenuItems() +{ + auto const& windows = Windows(); + MenuItemsVector menu_items; + + // We only add quicklist menu-items for windows if we have more than one window + if (windows.size() < 2) + return menu_items; + + // add menu items for all open windows + for (auto const& w : windows) + { + auto const& title = w->title(); + + if (title.empty()) + continue; + + glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new()); + dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, title.c_str()); + dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); + dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); + dbusmenu_menuitem_property_set_bool(menu_item, QuicklistMenuItem::MARKUP_ACCEL_DISABLED_PROPERTY, true); + dbusmenu_menuitem_property_set_int(menu_item, QuicklistMenuItem::MAXIMUM_LABEL_WIDTH_PROPERTY, MAXIMUM_QUICKLIST_WIDTH); + + Window xid = w->window_id(); + glib_signals_.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + [xid] (DbusmenuMenuitem*, unsigned) { + WindowManager& wm = WindowManager::Default(); + wm.Activate(xid); + wm.Raise(xid); + }); + + if (w->active()) + { + dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, DBUSMENU_MENUITEM_TOGGLE_RADIO); + dbusmenu_menuitem_property_set_int(menu_item, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED); + } + + menu_items.push_back(menu_item); + } + + return menu_items; +} + +std::string WindowedLauncherIcon::GetName() const +{ + return "WindowedLauncherIcon"; +} + +void WindowedLauncherIcon::AddProperties(debug::IntrospectionData& introspection) +{ + SimpleLauncherIcon::AddProperties(introspection); + + std::vector<Window> xids; + for (auto const& window : GetManagedWindows()) + xids.push_back(window->window_id()); + + introspection.add("xids", glib::Variant::FromVector(xids)) + .add("sticky", IsSticky()); +} + +} // namespace launcher +} // namespace unity diff --git a/launcher/WindowedLauncherIcon.h b/launcher/WindowedLauncherIcon.h new file mode 100644 index 000000000..83ecbdb78 --- /dev/null +++ b/launcher/WindowedLauncherIcon.h @@ -0,0 +1,100 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2015 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: Marco Trevisan <marco.trevisan@canonical.com> + */ + +#ifndef WINDOWED_LAUNCHER_ICON_H +#define WINDOWED_LAUNCHER_ICON_H + +#include <UnityCore/GLibSignal.h> + +#include "SimpleLauncherIcon.h" + +namespace unity +{ +namespace launcher +{ + +class WindowedLauncherIcon : public SimpleLauncherIcon +{ + NUX_DECLARE_OBJECT_TYPE(WindowedLauncherIcon, SimpleLauncherIcon); +public: + WindowedLauncherIcon(AbstractLauncherIcon::IconType); + + WindowList Windows() override; + WindowList WindowsOnViewport() override; + WindowList WindowsForMonitor(int monitor) override; + + virtual bool IsActive() const; + virtual bool IsRunning() const; + virtual bool IsUrgent() const; + virtual bool IsUserVisible() const; + + virtual void Quit() const; + +protected: + virtual WindowList GetManagedWindows() const = 0; + void EnsureWindowState(); + void EnsureWindowsLocation(); + + virtual void UpdateIconGeometries(std::vector<nux::Point3> const& centers); + + std::string GetName() const override; + void AddProperties(debug::IntrospectionData&) override; + + bool HandlesSpread() override; + bool ShowInSwitcher(bool current) override; + bool AllowDetailViewInSwitcher() const override; + uint64_t SwitcherPriority() override; + void AboutToRemove() override; + + void ActivateLauncherIcon(ActionArg arg) override; + void PerformScroll(ScrollDirection direction, Time timestamp) override; + virtual void Focus(ActionArg arg); + virtual bool Spread(bool current_desktop, int state, bool force); + + typedef unsigned long int WindowFilterMask; + enum WindowFilter + { + MAPPED = (1 << 0), + USER_VISIBLE = (1 << 1), + ON_CURRENT_DESKTOP = (1 << 2), + ON_ALL_MONITORS = (1 << 3), + }; + + WindowList GetWindows(WindowFilterMask filter = 0, int monitor = -1); + WindowList GetWindowsOnCurrentDesktopInStackingOrder(); + + MenuItemsVector GetWindowsMenuItems(); + +private: + void OnCenterStabilized(std::vector<nux::Point3> const& centers) override; + void OnWindowMinimized(Window); + void OnDndEnter(); + void OnDndLeave(); + + Time last_scroll_timestamp_; + unsigned int progressive_scroll_; + +protected: + glib::SignalManager glib_signals_; +}; + +} // namespace launcher +} // namespace unity + +#endif // WINDOWED_LAUNCHER_ICON_H diff --git a/plugins/unityshell/src/inputremover.cpp b/plugins/unityshell/src/inputremover.cpp index b28e7a1e2..ec09f9eeb 100644 --- a/plugins/unityshell/src/inputremover.cpp +++ b/plugins/unityshell/src/inputremover.cpp @@ -19,12 +19,12 @@ * Sam Spilsbury <sam.spilsbury@canonical.com> */ -#include <cstdlib> -#include <boost/scoped_array.hpp> #include "inputremover.h" +#include <cstdlib> #include <X11/Xregion.h> #include <cstdio> #include <cstring> +#include <vector> namespace { @@ -347,8 +347,7 @@ compiz::WindowInputRemover::writeProperty (XRectangle *input, */ const size_t dataSize = headerSize + (nInput * 4); - boost::scoped_array<unsigned long> data(new unsigned long[dataSize]); - + std::vector<unsigned long> data(dataSize); data[0] = propVersion; data[1] = nInput; data[2] = inputOrdering; @@ -370,7 +369,7 @@ compiz::WindowInputRemover::writeProperty (XRectangle *input, type, fmt, PropModeReplace, - reinterpret_cast<unsigned char*>(data.get()), + reinterpret_cast<unsigned char*>(data.data()), dataSize); return true; diff --git a/services/panel-indicator-entry-accessible.c b/services/panel-indicator-entry-accessible.c index 459812dff..55f45d297 100644 --- a/services/panel-indicator-entry-accessible.c +++ b/services/panel-indicator-entry-accessible.c @@ -293,7 +293,7 @@ panel_indicator_entry_accessible_ref_child (AtkObject *accessible, gint i) g_return_val_if_fail (PANEL_IS_INDICATOR_ENTRY_ACCESSIBLE (accessible), NULL); piea = PANEL_INDICATOR_ENTRY_ACCESSIBLE (accessible); - if (piea->priv->entry->parent_object && GTK_IS_MENU (piea->priv->entry->menu)) + if (piea->priv->entry && piea->priv->entry->parent_object && GTK_IS_MENU (piea->priv->entry->menu)) { child = gtk_widget_get_accessible (GTK_WIDGET (piea->priv->entry->menu)); atk_object_set_parent (child, accessible); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9bcf0a582..17ea9b758 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -80,6 +80,7 @@ if (GMOCK_LIB AND set (GTEST_SLOW_SOURCES test_main.cpp logger_helper.cpp + mock-application.cpp test_switcher_controller_slow.cpp test_switcher_controller_class.cpp test_tooltip_manager.cpp diff --git a/tests/mock-application.h b/tests/mock-application.h index 312168854..0ee200f9d 100644 --- a/tests/mock-application.h +++ b/tests/mock-application.h @@ -91,7 +91,7 @@ struct MockApplicationWindow : unity::ApplicationWindow return; title_ = new_title; - title.changed(title_); + title.changed.emit(title_); } void SetIcon(std::string const& new_icon) @@ -100,7 +100,16 @@ struct MockApplicationWindow : unity::ApplicationWindow return; icon_ = new_icon; - icon.changed(icon_); + icon.changed.emit(icon_); + } + + void SetMonitor(int new_monitor) + { + if (monitor_ == new_monitor) + return; + + monitor_ = new_monitor; + monitor.changed.emit(monitor_); } }; @@ -329,6 +338,7 @@ struct MockApplicationManager : public unity::ApplicationManager MOCK_CONST_METHOD0(GetActiveApplication, unity::ApplicationPtr()); MOCK_CONST_METHOD1(GetWindowsForMonitor, unity::WindowList(int)); MOCK_CONST_METHOD1(GetWindowForId, unity::ApplicationWindowPtr(Window)); + MOCK_CONST_METHOD3(FocusWindowGroup, void(unity::WindowList const&, bool, int)); unity::ApplicationPtr LocalGetApplicationForDesktopFile(std::string const& desktop_file) { diff --git a/tests/test_application_launcher_icon.cpp b/tests/test_application_launcher_icon.cpp index 41688d36d..c34c39b6c 100644 --- a/tests/test_application_launcher_icon.cpp +++ b/tests/test_application_launcher_icon.cpp @@ -50,7 +50,8 @@ struct MockApplicationLauncherIcon : ApplicationLauncherIcon typedef nux::ObjectPtr<MockApplicationLauncherIcon> Ptr; MockApplicationLauncherIcon(ApplicationPtr const& app) - : ApplicationLauncherIcon(app) + : WindowedLauncherIcon(IconType::APPLICATION) + , ApplicationLauncherIcon(app) { ON_CALL(*this, Stick(_)).WillByDefault(Invoke([this] (bool save) { ApplicationLauncherIcon::Stick(save); })); ON_CALL(*this, Stick()).WillByDefault(Invoke([this] { ApplicationLauncherIcon::Stick(); })); @@ -67,11 +68,14 @@ struct MockApplicationLauncherIcon : ApplicationLauncherIcon bool LauncherIconIsSticky() const { return LauncherIcon::IsSticky(); } void LocalActivate(ActionArg a) { ApplicationLauncherIcon::ActivateLauncherIcon(a); } - using ApplicationLauncherIcon::IsFileManager; using ApplicationLauncherIcon::LogUnityEvent; using ApplicationLauncherIcon::Remove; using ApplicationLauncherIcon::SetApplication; using ApplicationLauncherIcon::GetApplication; + using ApplicationLauncherIcon::PerformScroll; + using LauncherIcon::BackgroundColor; + using LauncherIcon::GetRemoteUri; + using LauncherIcon::AllowDetailViewInSwitcher; }; MATCHER_P(AreArgsEqual, a, "") @@ -90,15 +94,15 @@ struct TestApplicationLauncherIcon : testmocks::TestUnityAppBase virtual void SetUp() override { usc_app = std::make_shared<MockApplication::Nice>(USC_DESKTOP, "softwarecenter"); - usc_icon = new NiceMock<MockApplicationLauncherIcon>(usc_app); + usc_icon = new MockApplicationLauncherIcon(usc_app); ASSERT_EQ(usc_icon->DesktopFile(), USC_DESKTOP); empty_app = std::make_shared<MockApplication::Nice>(NO_ICON_DESKTOP); - empty_icon = new NiceMock<MockApplicationLauncherIcon>(empty_app); + empty_icon = new MockApplicationLauncherIcon(empty_app); ASSERT_EQ(empty_icon->DesktopFile(), NO_ICON_DESKTOP); mock_app = std::make_shared<MockApplication::Nice>(); - mock_icon = new NiceMock<MockApplicationLauncherIcon>(mock_app); + mock_icon = new MockApplicationLauncherIcon(mock_app); ASSERT_TRUE(mock_icon->DesktopFile().empty()); } @@ -173,7 +177,7 @@ TEST_F(TestApplicationLauncherIcon, ApplicationSignalDisconnection) { std::shared_ptr<MockApplication> app = std::make_shared<MockApplication::Nice>(USC_DESKTOP); { - MockApplicationLauncherIcon::Ptr icon(new NiceMock<MockApplicationLauncherIcon>(app)); + MockApplicationLauncherIcon::Ptr icon(new MockApplicationLauncherIcon(app)); EXPECT_FALSE(app->closed.empty()); } @@ -266,7 +270,7 @@ TEST_F(TestApplicationLauncherIcon, StickStickedDesktopApp) auto app = std::make_shared<MockApplication::Nice>(USC_DESKTOP); app->sticky = true; app->desktop_file_ = UM_DESKTOP; - MockApplicationLauncherIcon::Ptr icon(new NiceMock<MockApplicationLauncherIcon>(app)); + MockApplicationLauncherIcon::Ptr icon(new MockApplicationLauncherIcon(app)); ASSERT_TRUE(icon->IsSticky()); EXPECT_TRUE(icon->LauncherIconIsSticky()); } @@ -275,7 +279,7 @@ TEST_F(TestApplicationLauncherIcon, StickStickedDesktopLessApp) { auto app = std::make_shared<MockApplication::Nice>(); app->sticky = true; - MockApplicationLauncherIcon::Ptr icon(new NiceMock<MockApplicationLauncherIcon>(app)); + MockApplicationLauncherIcon::Ptr icon(new MockApplicationLauncherIcon(app)); ASSERT_FALSE(icon->IsSticky()); EXPECT_FALSE(icon->LauncherIconIsSticky()); } @@ -291,7 +295,7 @@ TEST_F(TestApplicationLauncherIcon, StickAndSaveDesktopAppDontCreateNewDesktop) TEST_F(TestApplicationLauncherIcon, StickAndSaveDesktopLessAppCreatesNewDesktop) { auto app = std::make_shared<MockApplication::Nice>(); - MockApplicationLauncherIcon::Ptr icon(new NiceMock<MockApplicationLauncherIcon>(app)); + MockApplicationLauncherIcon::Ptr icon(new MockApplicationLauncherIcon(app)); EXPECT_CALL(*app, CreateLocalDesktopFile()); icon->Stick(true); @@ -354,7 +358,7 @@ TEST_F(TestApplicationLauncherIcon, UnstickDesktopAppLogEvents) TEST_F(TestApplicationLauncherIcon, UnstickDesktopLessAppLogEvent) { auto app = std::make_shared<MockApplication::Nice>(); - MockApplicationLauncherIcon::Ptr icon(new NiceMock<MockApplicationLauncherIcon>(app)); + MockApplicationLauncherIcon::Ptr icon(new MockApplicationLauncherIcon(app)); EXPECT_CALL(*unity_app_, LogEvent(ApplicationEventType::ACCESS, _)).Times(0); icon->UnStick(); @@ -1103,25 +1107,6 @@ TEST_F(TestApplicationLauncherIcon, QuicklistMenuItemRemoteOverridesQuitByProper dbusmenu_menuitem_handle_event(item, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0); } -TEST_F(TestApplicationLauncherIcon, IsFileManager) -{ - EXPECT_FALSE(usc_icon->IsFileManager()); - EXPECT_FALSE(empty_icon->IsFileManager()); - EXPECT_FALSE(mock_icon->IsFileManager()); - - auto app = std::make_shared<MockApplication::Nice>("/any/path/org.gnome.Nautilus.desktop", "Nautilus"); - MockApplicationLauncherIcon::Ptr icon(new NiceMock<MockApplicationLauncherIcon>(app)); - EXPECT_TRUE(icon->IsFileManager()); - - app = std::make_shared<MockApplication::Nice>("/any/path/nautilus-folder-handler.desktop", "Nautilus"); - icon = new NiceMock<MockApplicationLauncherIcon>(app); - EXPECT_TRUE(icon->IsFileManager()); - - app = std::make_shared<MockApplication::Nice>("/any/path/nautilus-home.desktop", "Nautilus"); - icon = new NiceMock<MockApplicationLauncherIcon>(app); - EXPECT_TRUE(icon->IsFileManager()); -} - TEST_F(TestApplicationLauncherIcon, AllowDetailViewInSwitcher) { mock_app->type_ = AppType::NORMAL; @@ -1232,7 +1217,7 @@ TEST_F(TestApplicationLauncherIcon, DestructionDontUnsetsAppSeenIfReplaced) mock_icon->Remove(); ASSERT_FALSE(mock_app->seen); - MockApplicationLauncherIcon::Ptr new_icon(new NiceMock<MockApplicationLauncherIcon>(mock_app)); + MockApplicationLauncherIcon::Ptr new_icon(new MockApplicationLauncherIcon(mock_app)); mock_icon = nullptr; EXPECT_TRUE(mock_app->seen); diff --git a/tests/test_launcher_controller.cpp b/tests/test_launcher_controller.cpp index fefc6d15e..7758b1830 100644 --- a/tests/test_launcher_controller.cpp +++ b/tests/test_launcher_controller.cpp @@ -136,8 +136,10 @@ private: struct MockApplicationLauncherIcon : ApplicationLauncherIcon { - typedef NiceMock<MockApplicationLauncherIcon> Nice; - typedef nux::ObjectPtr<MockApplicationLauncherIcon::Nice> Ptr; + // NiceMock doesn't work well with Virtual Inheritance, so we need to disable it + //typedef NiceMock<MockApplicationLauncherIcon> Nice; + typedef MockApplicationLauncherIcon Nice; + typedef nux::ObjectPtr<MockApplicationLauncherIcon> Ptr; typedef bool Fake; MockApplicationLauncherIcon(Fake = true, std::string const& remote_uri = "") @@ -154,7 +156,8 @@ struct MockApplicationLauncherIcon : ApplicationLauncherIcon } explicit MockApplicationLauncherIcon(ApplicationPtr const& app) - : ApplicationLauncherIcon(app) + : WindowedLauncherIcon(IconType::APPLICATION) + , ApplicationLauncherIcon(app) { ON_CALL(*this, Stick(_)).WillByDefault(Invoke([this] (bool save) { ApplicationLauncherIcon::Stick(save); })); ON_CALL(*this, UnStick()).WillByDefault(Invoke([this] { ApplicationLauncherIcon::UnStick(); })); @@ -170,15 +173,18 @@ struct MockApplicationLauncherIcon : ApplicationLauncherIcon MOCK_CONST_METHOD0(GetRemoteUri, std::string()); MOCK_METHOD1(Stick, void(bool)); MOCK_METHOD0(UnStick, void()); - MOCK_METHOD0(Quit, void()); + MOCK_CONST_METHOD0(Quit, void()); }; struct MockVolumeLauncherIcon : public VolumeLauncherIcon { typedef nux::ObjectPtr<MockVolumeLauncherIcon> Ptr; + // typedef NiceMock<MockVolumeLauncherIcon> Nice; + typedef MockVolumeLauncherIcon Nice; MockVolumeLauncherIcon() - : VolumeLauncherIcon(Volume::Ptr(volume_ = new NiceMock<MockVolume>()), + : WindowedLauncherIcon(IconType::DEVICE) + , VolumeLauncherIcon(Volume::Ptr(volume_ = new NiceMock<MockVolume>()), std::make_shared<MockDevicesSettings::Nice>(), std::make_shared<MockDeviceNotificationDisplay::Nice>(), std::make_shared<MockFileManager::Nice>()) @@ -269,7 +275,7 @@ protected: void DisconnectSignals() { ApplicationManager::Default().application_started.clear(); - Impl()->device_section_.icon_added.clear(); + Impl()->device_section_->icon_added.clear(); Impl()->model_->icon_removed.clear(); Impl()->model_->saved.clear(); Impl()->model_->order_changed.clear(); @@ -640,8 +646,8 @@ TEST_F(TestLauncherController, CreateFavoriteInvalidDesktopFile) TEST_F(TestLauncherController, CreateFavoriteDevice) { - lc.Impl()->device_section_ = MockDeviceLauncherSection(); - auto const& icons = lc.Impl()->device_section_.GetIcons(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(); + auto const& icons = lc.Impl()->device_section_->GetIcons(); auto const& device_icon = icons.front(); ASSERT_TRUE(device_icon.IsValid()); @@ -903,8 +909,8 @@ TEST_F(TestLauncherController, AddDevices) { lc.ClearModel(); lc.DisconnectSignals(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(); - auto const& icons = lc.Impl()->device_section_.GetIcons(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(); + auto const& icons = lc.Impl()->device_section_->GetIcons(); auto const& device_icon1 = icons.front(); auto const& device_icon2 = *(std::next(icons.begin())); @@ -949,7 +955,7 @@ TEST_F(TestLauncherController, MigrateFavoritesUnneeded) TEST_F(TestLauncherController, SetupIcons) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(); lc.Impl()->expo_icon_->UnStick(); lc.Impl()->desktop_icon_->UnStick(); auto const& model = lc.Impl()->model_; @@ -970,7 +976,7 @@ TEST_F(TestLauncherController, SetupIcons) fav = lc.Impl()->GetIconByUri(FavoriteStore::URI_PREFIX_APP + app::SW_CENTER); EXPECT_EQ(model->IconIndex(fav), ++icon_index); - for (auto const& device : lc.Impl()->device_section_.GetIcons()) + for (auto const& device : lc.Impl()->device_section_->GetIcons()) ASSERT_EQ(model->IconIndex(device), ++icon_index); fav = lc.Impl()->GetIconByUri(FavoriteStore::URI_PREFIX_APP + app::UPDATE_MANAGER); @@ -995,7 +1001,7 @@ TEST_F(TestLauncherController, SetupIcons) TEST_F(TestLauncherController, ResetIconPriorities) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(); auto const& model = lc.Impl()->model_; favorite_store.AddFavorite(places::APPS_URI, -1); @@ -1012,7 +1018,7 @@ TEST_F(TestLauncherController, ResetIconPriorities) int icon_index = -1; - for (auto const& device : lc.Impl()->device_section_.GetIcons()) + for (auto const& device : lc.Impl()->device_section_->GetIcons()) ASSERT_EQ(model->IconIndex(device), ++icon_index); auto fav = lc.Impl()->GetIconByUri(FavoriteStore::URI_PREFIX_APP + app::SW_CENTER); @@ -1043,8 +1049,8 @@ TEST_F(TestLauncherController, ResetIconPriorities) TEST_F(TestLauncherController, GetLastIconPriorityUnSticky) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(3); - auto const& device_icons = lc.Impl()->device_section_.GetIcons(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(3); + auto const& device_icons = lc.Impl()->device_section_->GetIcons(); auto const& last_device = device_icons.back(); favorite_store.SetFavorites({ places::DEVICES_URI, @@ -1060,8 +1066,8 @@ TEST_F(TestLauncherController, GetLastIconPriorityUnSticky) TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithAllStickyIcons) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(3); - auto const& device_icons = lc.Impl()->device_section_.GetIcons(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(3); + auto const& device_icons = lc.Impl()->device_section_->GetIcons(); auto const& last_device = device_icons.back(); favorite_store.SetFavorites({ places::DEVICES_URI, @@ -1080,8 +1086,8 @@ TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithAllStickyIcons) TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithSomeStickyIcons) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(3); - auto const& device_icons = lc.Impl()->device_section_.GetIcons(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(3); + auto const& device_icons = lc.Impl()->device_section_->GetIcons(); auto const& first_device = *(std::next(device_icons.rbegin())); auto const& last_device = device_icons.back(); @@ -1100,7 +1106,7 @@ TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithSomeStickyIcons) TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithNoIcons) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(0); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(0); lc.Impl()->SetupIcons(); lc.DisconnectSignals(); @@ -1111,7 +1117,7 @@ TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithNoIcons) TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithNoIconsAndUri) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(0); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(0); favorite_store.SetFavorites({ places::DEVICES_URI, FavoriteStore::URI_PREFIX_APP + app::SW_CENTER }); @@ -1136,11 +1142,11 @@ TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithNoIconsAndUri) TEST_F(TestLauncherController, GetLastIconPrioritySticky) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(3); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(3); lc.Impl()->SetupIcons(); lc.DisconnectSignals(); - auto const& device_icons = lc.Impl()->device_section_.GetIcons(); + auto const& device_icons = lc.Impl()->device_section_->GetIcons(); auto const& first_device = device_icons.front(); int last_priority = lc.Impl()->GetLastIconPriority<VolumeLauncherIcon>("", true); @@ -1150,8 +1156,8 @@ TEST_F(TestLauncherController, GetLastIconPrioritySticky) TEST_F(TestLauncherController, GetLastIconPriorityStickyWithAllStickyIcons) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(3); - auto const& device_icons = lc.Impl()->device_section_.GetIcons(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(3); + auto const& device_icons = lc.Impl()->device_section_->GetIcons(); auto const& last_device = device_icons.back(); favorite_store.SetFavorites({ places::DEVICES_URI, @@ -1170,8 +1176,8 @@ TEST_F(TestLauncherController, GetLastIconPriorityStickyWithAllStickyIcons) TEST_F(TestLauncherController, GetLastIconPriorityStickyWithSomeStickyIcons) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(3); - auto const& device_icons = lc.Impl()->device_section_.GetIcons(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(3); + auto const& device_icons = lc.Impl()->device_section_->GetIcons(); auto const& first_device = *(std::next(device_icons.rbegin())); favorite_store.SetFavorites({ places::DEVICES_URI, @@ -1189,7 +1195,7 @@ TEST_F(TestLauncherController, GetLastIconPriorityStickyWithSomeStickyIcons) TEST_F(TestLauncherController, GetLastIconPriorityStickyWithNoIcons) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(0); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(0); lc.Impl()->SetupIcons(); lc.DisconnectSignals(); @@ -1240,8 +1246,8 @@ TEST_F(TestLauncherController, LauncherAddRequestApplicationStick) TEST_F(TestLauncherController, LauncherAddRequestDeviceAdd) { auto const& model = lc.Impl()->model_; - lc.Impl()->device_section_ = MockDeviceLauncherSection(); - auto const& icons = lc.Impl()->device_section_.GetIcons(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(); + auto const& icons = lc.Impl()->device_section_->GetIcons(); auto const& device_icon = icons.front(); auto const& icon_uri = device_icon->RemoteUri(); @@ -1262,7 +1268,7 @@ TEST_F(TestLauncherController, LauncherAddRequestDeviceAdd) TEST_F(TestLauncherController, LauncherAddRequestDeviceStick) { auto const& model = lc.Impl()->model_; - MockVolumeLauncherIcon::Ptr device_icon(new NiceMock<MockVolumeLauncherIcon>()); + MockVolumeLauncherIcon::Ptr device_icon(new MockVolumeLauncherIcon::Nice()); lc.Impl()->RegisterIcon(device_icon, std::numeric_limits<int>::max()); auto app_icons = model->GetSublist<ApplicationLauncherIcon>(); @@ -1287,7 +1293,7 @@ TEST_F(TestLauncherController, LauncherRemoveRequestApplicationUnStickAndQuit) TEST_F(TestLauncherController, LauncherRemoveRequestDeviceEjects) { - MockVolumeLauncherIcon::Ptr device_icon(new NiceMock<MockVolumeLauncherIcon>()); + MockVolumeLauncherIcon::Ptr device_icon(new MockVolumeLauncherIcon::Nice()); EXPECT_CALL(*(device_icon->volume_), CanBeEjected()) .WillRepeatedly(Return(true)); @@ -1302,7 +1308,7 @@ TEST_F(TestLauncherController, LauncherRemoveRequestDeviceEjects) TEST_F(TestLauncherController, LauncherRemoveRequestDeviceStops) { - MockVolumeLauncherIcon::Ptr device_icon(new NiceMock<MockVolumeLauncherIcon>()); + MockVolumeLauncherIcon::Ptr device_icon(new MockVolumeLauncherIcon::Nice()); EXPECT_CALL(*(device_icon->volume_), CanBeEjected()) .WillRepeatedly(Return(false)); @@ -1362,7 +1368,7 @@ TEST_F(TestLauncherController, SaveIconsOrder) invisible_app->SetQuirk(AbstractLauncherIcon::Quirk::VISIBLE, false); lc.Impl()->RegisterIcon(invisible_app, ++priority); - MockVolumeLauncherIcon::Ptr sticky_device(new NiceMock<MockVolumeLauncherIcon>()); + MockVolumeLauncherIcon::Ptr sticky_device(new MockVolumeLauncherIcon::Nice()); sticky_device->Stick(false); lc.Impl()->RegisterIcon(sticky_device, ++priority); @@ -1393,7 +1399,7 @@ TEST_F(TestLauncherController, SaveIconsOrderWithOnlyStickyIcons) sticky_app->Stick(false); lc.Impl()->RegisterIcon(sticky_app, ++priority); - MockVolumeLauncherIcon::Ptr sticky_device(new NiceMock<MockVolumeLauncherIcon>()); + MockVolumeLauncherIcon::Ptr sticky_device(new MockVolumeLauncherIcon::Nice()); sticky_device->Stick(false); lc.Impl()->RegisterIcon(sticky_device, ++priority); @@ -1422,7 +1428,7 @@ TEST_F(TestLauncherController, SaveIconsOrderTriesToKeepIconProvidersOrder) sticky_app->Stick(false); lc.Impl()->RegisterIcon(sticky_app, ++priority); - MockVolumeLauncherIcon::Ptr sticky_device(new NiceMock<MockVolumeLauncherIcon>()); + MockVolumeLauncherIcon::Ptr sticky_device(new MockVolumeLauncherIcon::Nice()); sticky_device->Stick(false); lc.Impl()->RegisterIcon(sticky_device, ++priority); @@ -1447,7 +1453,7 @@ TEST_F(TestLauncherController, SaveIconsOrderTriesToKeepIconProvidersOrder2) sticky_app->Stick(false); lc.Impl()->RegisterIcon(sticky_app, ++priority); - MockVolumeLauncherIcon::Ptr sticky_device(new NiceMock<MockVolumeLauncherIcon>()); + MockVolumeLauncherIcon::Ptr sticky_device(new MockVolumeLauncherIcon::Nice()); sticky_device->Stick(false); lc.Impl()->RegisterIcon(sticky_device, ++priority); @@ -1597,9 +1603,9 @@ TEST_F(TestLauncherController, OnFavoriteStoreFavoriteAddedStickAfter) TEST_F(TestLauncherController, OnFavoriteStoreFavoriteAddedDeviceSection) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(); auto const& model = lc.Impl()->model_; - auto const& icons = lc.Impl()->device_section_.GetIcons(); + auto const& icons = lc.Impl()->device_section_->GetIcons(); auto const& device_icon1(icons.front()); auto const& device_icon2(*(std::next(icons.begin()))); @@ -1634,10 +1640,10 @@ TEST_F(TestLauncherController, OnFavoriteStoreFavoriteRemovedApplication) TEST_F(TestLauncherController, OnFavoriteStoreFavoriteRemovedDevice) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(); auto const& model = lc.Impl()->model_; - auto const& icons = lc.Impl()->device_section_.GetIcons(); + auto const& icons = lc.Impl()->device_section_->GetIcons(); auto const& device_icon(icons.front()); favorite_store.SetFavorites({ lc.Impl()->expo_icon_->RemoteUri(), @@ -1660,10 +1666,10 @@ TEST_F(TestLauncherController, OnFavoriteStoreFavoriteRemovedDevice) TEST_F(TestLauncherController, OnFavoriteStoreFavoriteRemovedDeviceSection) { lc.ClearModel(); - lc.Impl()->device_section_ = MockDeviceLauncherSection(); + lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(); auto const& model = lc.Impl()->model_; - auto const& icons = lc.Impl()->device_section_.GetIcons(); + auto const& icons = lc.Impl()->device_section_->GetIcons(); auto const& device_icon1(icons.front()); auto const& device_icon2(*(std::next(icons.begin()))); @@ -1958,10 +1964,9 @@ TEST_F(TestLauncherController, IconShowsOnQuickApplicationReopen) unity::glib::Object<BamfMockApplication> bamf_mock_application(bamf_mock_application_new()); ApplicationPtr app(new unity::bamf::Application(mock_manager, unity::glib::object_cast<BamfApplication>(bamf_mock_application))); - MockApplicationLauncherIcon::Ptr our_icon; - + AbstractLauncherIcon::Ptr our_icon; mock_manager.Default().application_started.emit(app); - + app->title.changed.emit("Hello"); auto app_icons = lc.Impl()->model_->GetSublist<ApplicationLauncherIcon>(); @@ -1971,7 +1976,7 @@ TEST_F(TestLauncherController, IconShowsOnQuickApplicationReopen) { our_icon = icon; break; - } + } } ASSERT_TRUE(our_icon); EXPECT_FALSE(our_icon->removed); diff --git a/tests/test_mock_filemanager.h b/tests/test_mock_filemanager.h index 231c0074e..1e541ebfd 100644 --- a/tests/test_mock_filemanager.h +++ b/tests/test_mock_filemanager.h @@ -32,15 +32,18 @@ struct MockFileManager : FileManager typedef testing::NiceMock<MockFileManager> Nice; MOCK_METHOD2(Open, void(std::string const& uri, uint64_t time)); - MOCK_METHOD2(OpenActiveChild, void(std::string const& uri, uint64_t time)); MOCK_METHOD1(OpenTrash, void(uint64_t time)); MOCK_METHOD1(TrashFile, bool(std::string const& uri)); MOCK_METHOD1(EmptyTrash, void(uint64_t time)); MOCK_METHOD3(CopyFiles, void(std::set<std::string> const& files, std::string const& dest, uint64_t time)); - MOCK_CONST_METHOD0(OpenedLocations, std::vector<std::string>()); - MOCK_CONST_METHOD1(IsPrefixOpened, bool(std::string const& uri)); - MOCK_CONST_METHOD0(IsTrashOpened, bool()); - MOCK_CONST_METHOD0(IsDeviceOpened, bool()); + MOCK_CONST_METHOD1(WindowsForLocation, WindowList(std::string const&)); + MOCK_CONST_METHOD1(LocationForWindow, std::string(ApplicationWindowPtr const&)); + + MockFileManager() + { + using namespace testing; + ON_CALL(*this, WindowsForLocation(_)).WillByDefault(Return(WindowList())); + } }; } diff --git a/tests/test_software_center_launcher_icon.cpp b/tests/test_software_center_launcher_icon.cpp index abf65d09f..6ee4d8d12 100644 --- a/tests/test_software_center_launcher_icon.cpp +++ b/tests/test_software_center_launcher_icon.cpp @@ -62,16 +62,17 @@ struct TestSoftwareCenterLauncherIcon : testmocks::TestUnityAppBase MockSoftwareCenterLauncherIcon(ApplicationPtr const& app, std::string const& aptdaemon_trans_id, std::string const& icon_path) - : SoftwareCenterLauncherIcon(app, aptdaemon_trans_id, icon_path) + : WindowedLauncherIcon(IconType::APPLICATION) + , SoftwareCenterLauncherIcon(app, aptdaemon_trans_id, icon_path) {} void LauncherIconUnstick() { LauncherIcon::UnStick(); } using SoftwareCenterLauncherIcon::GetActualDesktopFileAfterInstall; - using SoftwareCenterLauncherIcon::GetRemoteUri; using SoftwareCenterLauncherIcon::OnFinished; using SoftwareCenterLauncherIcon::OnPropertyChanged; using SoftwareCenterLauncherIcon::drag_window_; + using LauncherIcon::GetRemoteUri; }; nux::ObjectPtr<Launcher> CreateLauncher() diff --git a/tests/test_switcher_controller.h b/tests/test_switcher_controller.h index bc0118df4..5e35b2e59 100644 --- a/tests/test_switcher_controller.h +++ b/tests/test_switcher_controller.h @@ -27,10 +27,11 @@ #include "test_utils.h" #include "DesktopLauncherIcon.h" -#include "SimpleLauncherIcon.h" +#include "WindowedLauncherIcon.h" #include "SwitcherController.h" #include "SwitcherView.h" #include "TimeUtil.h" +#include "mock-application.h" #include "mock-base-window.h" #include "test_standalone_wm.h" @@ -48,35 +49,24 @@ const unsigned TICK_DURATION = 10 * 1000; /** * A fake ApplicationWindow for verifying selection of the switcher. */ -class FakeApplicationWindow : public unity::ApplicationWindow +struct FakeApplicationWindow : public ::testmocks::MockApplicationWindow::Nice { -public: + typedef NiceMock<FakeApplicationWindow> Nice; FakeApplicationWindow(Window xid, uint64_t active_number = 0); ~FakeApplicationWindow(); - - virtual WindowType type() const; - - virtual Window window_id() const; - virtual int monitor() const; - virtual unity::ApplicationPtr application() const; - virtual bool Focus() const; - virtual void Quit() const; - -private: - Window xid_; }; /** * A fake LauncherIcon for verifying selection operations of the switcher. */ -struct FakeLauncherIcon : unity::launcher::SimpleLauncherIcon +struct FakeLauncherIcon : unity::launcher::WindowedLauncherIcon { FakeLauncherIcon(std::string const& app_name, bool allow_detail_view, uint64_t priority); - unity::WindowList Windows() override; bool AllowDetailViewInSwitcher() const override; bool ShowInSwitcher(bool) override; uint64_t SwitcherPriority() override; + WindowList GetManagedWindows() const override; bool allow_detail_view_; uint64_t priority_; diff --git a/tests/test_switcher_controller_class.cpp b/tests/test_switcher_controller_class.cpp index 749359f54..807a239bc 100644 --- a/tests/test_switcher_controller_class.cpp +++ b/tests/test_switcher_controller_class.cpp @@ -26,14 +26,13 @@ using namespace unity::switcher; using namespace std::chrono; FakeApplicationWindow::FakeApplicationWindow(Window xid, uint64_t active_number) - : xid_(xid) + : MockApplicationWindow::Nice(xid) { - auto standalone_window = std::make_shared<StandaloneWindow>(xid_); + SetMonitor(-1); + auto standalone_window = std::make_shared<StandaloneWindow>(window_id()); standalone_window->active_number = active_number; testwrapper::StandaloneWM::Get()->AddStandaloneWindow(standalone_window); - - title.SetGetterFunction([this] { return "FakeApplicationWindow"; }); - icon.SetGetterFunction([this] { return ""; }); + ON_CALL(*this, Quit()).WillByDefault(Invoke([this] { WindowManager::Default().Close(window_id()); })); } FakeApplicationWindow::~FakeApplicationWindow() @@ -41,25 +40,17 @@ FakeApplicationWindow::~FakeApplicationWindow() testwrapper::StandaloneWM::Get()->Close(xid_); } -WindowType FakeApplicationWindow::type() const { return WindowType::MOCK; } - -Window FakeApplicationWindow::window_id() const { return xid_; } -int FakeApplicationWindow::monitor() const { return -1; } -ApplicationPtr FakeApplicationWindow::application() const { return ApplicationPtr(); } -bool FakeApplicationWindow::Focus() const { return false; } -void FakeApplicationWindow::Quit() const { WindowManager::Default().Close(xid_); } - FakeLauncherIcon::FakeLauncherIcon(std::string const& app_name, bool allow_detail_view, uint64_t priority) - : launcher::SimpleLauncherIcon(IconType::APPLICATION) + : launcher::WindowedLauncherIcon(IconType::APPLICATION) , allow_detail_view_(allow_detail_view) , priority_(priority) - , window_list{ std::make_shared<FakeApplicationWindow>(priority_ | 0x0001, SwitcherPriority()), - std::make_shared<FakeApplicationWindow>(priority_ | 0x0002, priority_) } + , window_list{ std::make_shared<FakeApplicationWindow::Nice>(priority_ | 0x0001, SwitcherPriority()), + std::make_shared<FakeApplicationWindow::Nice>(priority_ | 0x0002, priority_) } { tooltip_text = app_name; } -WindowList FakeLauncherIcon::Windows() +WindowList FakeLauncherIcon::GetManagedWindows() const { return window_list; } @@ -85,7 +76,7 @@ uint64_t FakeLauncherIcon::SwitcherPriority() //class TestSwitcherController : public testing::Test TestSwitcherController::TestSwitcherController() : animation_controller_(tick_source_) - , mock_window_(new NiceMock<testmocks::MockBaseWindow>()) + , mock_window_(new NiceMock<unity::testmocks::MockBaseWindow>()) , controller_(std::make_shared<Controller>([this] { return mock_window_; })) { controller_->timeout_length = 0; diff --git a/tests/test_trash_launcher_icon.cpp b/tests/test_trash_launcher_icon.cpp index 839c70ff4..d8a5b6162 100644 --- a/tests/test_trash_launcher_icon.cpp +++ b/tests/test_trash_launcher_icon.cpp @@ -27,9 +27,11 @@ using namespace unity; using namespace unity::launcher; using namespace testing; +using namespace testmocks; namespace { +const std::string TRASH_URI = "trash:"; struct TestTrashLauncherIcon : testmocks::TestUnityAppBase { @@ -42,6 +44,12 @@ struct TestTrashLauncherIcon : testmocks::TestUnityAppBase TrashLauncherIcon icon; }; +TEST_F(TestTrashLauncherIcon, InitState) +{ + EXPECT_FALSE(icon.GetQuirk(AbstractLauncherIcon::Quirk::RUNNING)); + EXPECT_FALSE(icon.GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE)); +} + TEST_F(TestTrashLauncherIcon, Position) { EXPECT_EQ(icon.position(), AbstractLauncherIcon::Position::END); @@ -74,15 +82,77 @@ TEST_F(TestTrashLauncherIcon, QuicklistEmptyTrash) TEST_F(TestTrashLauncherIcon, RunningState) { - EXPECT_CALL(*fm_, IsTrashOpened()).WillRepeatedly(Return(true)); + auto win1 = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + auto win2 = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + + ON_CALL(*fm_, WindowsForLocation(TRASH_URI)).WillByDefault(Return(WindowList({win1, win2}))); fm_->locations_changed.emit(); EXPECT_TRUE(icon.GetQuirk(AbstractLauncherIcon::Quirk::RUNNING)); - EXPECT_CALL(*fm_, IsTrashOpened()).WillRepeatedly(Return(false)); + ON_CALL(*fm_, WindowsForLocation(TRASH_URI)).WillByDefault(Return(WindowList())); fm_->locations_changed.emit(); EXPECT_FALSE(icon.GetQuirk(AbstractLauncherIcon::Quirk::RUNNING)); } +TEST_F(TestTrashLauncherIcon, ActiveState) +{ + auto win1 = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + auto win2 = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + + ON_CALL(*fm_, WindowsForLocation(TRASH_URI)).WillByDefault(Return(WindowList({win1, win2}))); + fm_->locations_changed.emit(); + ASSERT_FALSE(icon.GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE)); + + win2->LocalFocus(); + EXPECT_TRUE(icon.GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE)); + + ON_CALL(*fm_, WindowsForLocation(TRASH_URI)).WillByDefault(Return(WindowList())); + fm_->locations_changed.emit(); + EXPECT_FALSE(icon.GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE)); +} + +TEST_F(TestTrashLauncherIcon, WindowsCount) +{ + WindowList windows((g_random_int() % 10) + 5); + for (unsigned i = 0; i < windows.capacity(); ++i) + windows[i] = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + + ON_CALL(*fm_, WindowsForLocation(TRASH_URI)).WillByDefault(Return(windows)); + fm_->locations_changed.emit(); + EXPECT_EQ(icon.Windows().size(), windows.size()); +} + +TEST_F(TestTrashLauncherIcon, WindowsPerMonitor) +{ + WindowList windows((g_random_int() % 10) + 5); + for (unsigned i = 0; i < windows.capacity(); ++i) + { + auto win = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + win->monitor_ = i % 2; + windows[i] = win; + } + + ON_CALL(*fm_, WindowsForLocation(TRASH_URI)).WillByDefault(Return(windows)); + fm_->locations_changed.emit(); + + EXPECT_EQ(icon.WindowsVisibleOnMonitor(0), (windows.size() / 2) + (windows.size() % 2)); + EXPECT_EQ(icon.WindowsVisibleOnMonitor(1), windows.size() / 2); +} + +TEST_F(TestTrashLauncherIcon, WindowsOnMonitorChanges) +{ + auto win = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + ON_CALL(*fm_, WindowsForLocation(TRASH_URI)).WillByDefault(Return(WindowList({win}))); + fm_->locations_changed.emit(); + + EXPECT_EQ(icon.WindowsVisibleOnMonitor(0), 1); + EXPECT_EQ(icon.WindowsVisibleOnMonitor(1), 0); + + win->SetMonitor(1); + EXPECT_EQ(icon.WindowsVisibleOnMonitor(0), 0); + EXPECT_EQ(icon.WindowsVisibleOnMonitor(1), 1); +} + TEST_F(TestTrashLauncherIcon, FilemanagerSignalDisconnection) { auto file_manager = std::make_shared<NiceMock<MockFileManager>>(); diff --git a/tests/test_volume_launcher_icon.cpp b/tests/test_volume_launcher_icon.cpp index 8d6bc48c2..41b794bae 100644 --- a/tests/test_volume_launcher_icon.cpp +++ b/tests/test_volume_launcher_icon.cpp @@ -27,8 +27,11 @@ using namespace testing; #include "test_utils.h" #include "test_mock_devices.h" #include "test_mock_filemanager.h" +#include "mock-application.h" + using namespace unity; using namespace unity::launcher; +using namespace testmocks; namespace { @@ -43,7 +46,7 @@ struct TestVolumeLauncherIcon : public Test { SetupVolumeDefaultBehavior(); SetupSettingsDefaultBehavior(); - icon_ = new NiceMock<VolumeLauncherIcon>(volume_, settings_, notifications_, file_manager_); + icon_ = new VolumeLauncherIcon(volume_, settings_, notifications_, file_manager_); } void SetupSettingsDefaultBehavior() @@ -94,7 +97,7 @@ struct TestVolumeLauncherIconDelayedConstruction : TestVolumeLauncherIcon void CreateIcon() { - icon_ = new NiceMock<VolumeLauncherIcon>(volume_, settings_, notifications_, file_manager_); + icon_ = new VolumeLauncherIcon(volume_, settings_, notifications_, file_manager_); } }; @@ -105,7 +108,7 @@ TEST_F(TestVolumeLauncherIcon, TestIconType) TEST_F(TestVolumeLauncherIconDelayedConstruction, TestRunningOnClosed) { - ON_CALL(*file_manager_, IsPrefixOpened(volume_->GetUri())).WillByDefault(Return(false)); + ON_CALL(*file_manager_, WindowsForLocation(_)).WillByDefault(Return(WindowList())); CreateIcon(); EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::RUNNING)); @@ -113,7 +116,8 @@ TEST_F(TestVolumeLauncherIconDelayedConstruction, TestRunningOnClosed) TEST_F(TestVolumeLauncherIconDelayedConstruction, TestRunningOnOpened) { - ON_CALL(*file_manager_, IsPrefixOpened(volume_->GetUri())).WillByDefault(Return(true)); + auto win = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList({win}))); CreateIcon(); EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::RUNNING)); @@ -128,16 +132,91 @@ TEST_F(TestVolumeLauncherIcon, FilemanagerSignalDisconnection) TEST_F(TestVolumeLauncherIcon, TestRunningStateOnLocationChangedClosed) { - ON_CALL(*file_manager_, IsPrefixOpened(volume_->GetUri())).WillByDefault(Return(false)); + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList())); file_manager_->locations_changed.emit(); EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::RUNNING)); } TEST_F(TestVolumeLauncherIcon, TestRunningStateOnLocationChangedOpened) { - ON_CALL(*file_manager_, IsPrefixOpened(volume_->GetUri())).WillByDefault(Return(true)); + auto win1 = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + auto win2 = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList({win1, win2}))); + file_manager_->locations_changed.emit(); + EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::RUNNING)); +} + +TEST_F(TestVolumeLauncherIcon, RunningState) +{ + auto win1 = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + auto win2 = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList({win1, win2}))); file_manager_->locations_changed.emit(); EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::RUNNING)); + + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList())); + file_manager_->locations_changed.emit(); + EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::RUNNING)); +} + +TEST_F(TestVolumeLauncherIcon, ActiveState) +{ + auto win1 = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + auto win2 = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList({win1, win2}))); + file_manager_->locations_changed.emit(); + ASSERT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE)); + + win2->LocalFocus(); + EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE)); + + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList())); + file_manager_->locations_changed.emit(); + EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE)); +} + +TEST_F(TestVolumeLauncherIcon, WindowsCount) +{ + WindowList windows((g_random_int() % 10) + 5); + for (unsigned i = 0; i < windows.capacity(); ++i) + windows[i] = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(windows)); + file_manager_->locations_changed.emit(); + EXPECT_EQ(icon_->Windows().size(), windows.size()); +} + +TEST_F(TestVolumeLauncherIcon, WindowsPerMonitor) +{ + WindowList windows((g_random_int() % 10) + 5); + for (unsigned i = 0; i < windows.capacity(); ++i) + { + auto win = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + win->monitor_ = i % 2; + windows[i] = win; + } + + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(windows)); + file_manager_->locations_changed.emit(); + + EXPECT_EQ(icon_->WindowsVisibleOnMonitor(0), (windows.size() / 2) + (windows.size() % 2)); + EXPECT_EQ(icon_->WindowsVisibleOnMonitor(1), windows.size() / 2); +} + +TEST_F(TestVolumeLauncherIcon, WindowsOnMonitorChanges) +{ + auto win = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList({win}))); + file_manager_->locations_changed.emit(); + + EXPECT_EQ(icon_->WindowsVisibleOnMonitor(0), 1); + EXPECT_EQ(icon_->WindowsVisibleOnMonitor(1), 0); + + win->SetMonitor(1); + EXPECT_EQ(icon_->WindowsVisibleOnMonitor(0), 0); + EXPECT_EQ(icon_->WindowsVisibleOnMonitor(1), 1); } TEST_F(TestVolumeLauncherIcon, TestPosition) @@ -240,6 +319,32 @@ TEST_F(TestVolumeLauncherIconDelayedConstruction, TestVisibilityAfterUnmount_Bla EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); } +TEST_F(TestVolumeLauncherIcon, TestVisibilityWithWindows) +{ + ON_CALL(*settings_, IsABlacklistedDevice(volume_->GetIdentifier())).WillByDefault(Return(false)); + settings_->changed.emit(); + ASSERT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); + + auto win = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList({win}))); + file_manager_->locations_changed.emit(); + + EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); +} + +TEST_F(TestVolumeLauncherIcon, TestVisibilityWithWindows_Blacklisted) +{ + ON_CALL(*settings_, IsABlacklistedDevice(volume_->GetIdentifier())).WillByDefault(Return(true)); + settings_->changed.emit(); + ASSERT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); + + auto win = std::make_shared<MockApplicationWindow::Nice>(g_random_int()); + ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList({win}))); + file_manager_->locations_changed.emit(); + + EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); +} + TEST_F(TestVolumeLauncherIcon, TestUnlockFromLauncherMenuItem_VolumeWithoutIdentifier) { EXPECT_CALL(*volume_, GetIdentifier()) @@ -251,22 +356,22 @@ TEST_F(TestVolumeLauncherIcon, TestUnlockFromLauncherMenuItem_VolumeWithoutIdent TEST_F(TestVolumeLauncherIcon, TestUnlockFromLauncherMenuItem_Success) { + ON_CALL(*settings_, IsABlacklistedDevice(volume_->GetIdentifier())).WillByDefault(Return(false)); + settings_->changed.emit(); + ASSERT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); auto menuitem = GetMenuItemAtIndex(4); ASSERT_STREQ(dbusmenu_menuitem_property_get(menuitem, DBUSMENU_MENUITEM_PROP_LABEL), "Unlock from Launcher"); EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE)); EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_ENABLED)); - EXPECT_CALL(*settings_, TryToBlacklist(_)) - .Times(1); - - EXPECT_CALL(*settings_, IsABlacklistedDevice(_)) - .WillRepeatedly(Return(true)); - + EXPECT_CALL(*settings_, TryToBlacklist(volume_->GetIdentifier())).Times(1); dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0); + + EXPECT_CALL(*settings_, IsABlacklistedDevice(volume_->GetIdentifier())).WillRepeatedly(Return(true)); settings_->changed.emit(); // TryToBlacklist() works if DevicesSettings emits a changed signal. - ASSERT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); + EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); } TEST_F(TestVolumeLauncherIcon, TestUnlockFromLauncherMenuItem_Failure) @@ -277,12 +382,49 @@ TEST_F(TestVolumeLauncherIcon, TestUnlockFromLauncherMenuItem_Failure) EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE)); EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_ENABLED)); - EXPECT_CALL(*settings_, TryToBlacklist(_)) - .Times(1); + EXPECT_CALL(*settings_, TryToBlacklist(volume_->GetIdentifier())).Times(1); + dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0); + + EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); +} + +TEST_F(TestVolumeLauncherIcon, TestLockToLauncherMenuItem_Success) +{ + ON_CALL(*settings_, IsABlacklistedDevice(volume_->GetIdentifier())).WillByDefault(Return(true)); + settings_->changed.emit(); + ASSERT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); + + auto menuitem = GetMenuItemAtIndex(4); + ASSERT_STREQ(dbusmenu_menuitem_property_get(menuitem, DBUSMENU_MENUITEM_PROP_LABEL), "Lock to Launcher"); + EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE)); + EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_ENABLED)); + + EXPECT_CALL(*settings_, TryToUnblacklist(volume_->GetIdentifier())).Times(1); dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0); - ASSERT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); + EXPECT_CALL(*settings_, IsABlacklistedDevice(_)).WillRepeatedly(Return(false)); + settings_->changed.emit(); // TryToBlacklist() works if DevicesSettings emits a changed signal. + + EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); +} + +TEST_F(TestVolumeLauncherIcon, TestLockToLauncherMenuItem_Failure) +{ + ON_CALL(*settings_, IsABlacklistedDevice(volume_->GetIdentifier())).WillByDefault(Return(true)); + settings_->changed.emit(); + ASSERT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); + + auto menuitem = GetMenuItemAtIndex(4); + + ASSERT_STREQ(dbusmenu_menuitem_property_get(menuitem, DBUSMENU_MENUITEM_PROP_LABEL), "Lock to Launcher"); + EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE)); + EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_ENABLED)); + + EXPECT_CALL(*settings_, TryToUnblacklist(volume_->GetIdentifier())).Times(1); + dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0); + + EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)); } TEST_F(TestVolumeLauncherIcon, TestOpenMenuItem) @@ -298,7 +440,7 @@ TEST_F(TestVolumeLauncherIcon, TestOpenMenuItem) InSequence seq; EXPECT_CALL(*volume_, Mount()); - EXPECT_CALL(*file_manager_, OpenActiveChild(volume_->GetUri(), time)); + EXPECT_CALL(*file_manager_, Open(volume_->GetUri(), time)); dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, time); } @@ -318,7 +460,7 @@ TEST_F(TestVolumeLauncherIcon, TestNameMenuItem) InSequence seq; EXPECT_CALL(*volume_, Mount()); - EXPECT_CALL(*file_manager_, OpenActiveChild(volume_->GetUri(), time)); + EXPECT_CALL(*file_manager_, Open(volume_->GetUri(), time)); dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, time); } @@ -438,7 +580,7 @@ TEST_F(TestVolumeLauncherIcon, OnRemoved) EXPECT_CALL(*settings_, TryToBlacklist(_)) .Times(0); EXPECT_CALL(*settings_, TryToUnblacklist(_)) - .Times(0); + .Times(1); volume_->removed.emit(); } @@ -451,7 +593,7 @@ TEST_F(TestVolumeLauncherIcon, OnRemoved_RemovabledVolume) EXPECT_CALL(*settings_, TryToBlacklist(_)) .Times(0); EXPECT_CALL(*settings_, TryToUnblacklist(_)) - .Times(0); + .Times(1); volume_->removed.emit(); } @@ -516,7 +658,7 @@ TEST_F(TestVolumeLauncherIcon, ActivateMounted) uint64_t time = g_random_int(); InSequence seq; EXPECT_CALL(*volume_, Mount()).Times(0); - EXPECT_CALL(*file_manager_, OpenActiveChild(volume_->GetUri(), time)); + EXPECT_CALL(*file_manager_, Open(volume_->GetUri(), time)); icon_->Activate(ActionArg(ActionArg::Source::LAUNCHER, 0, time)); } @@ -526,7 +668,7 @@ TEST_F(TestVolumeLauncherIcon, ActivateUnmounted) ON_CALL(*volume_, IsMounted()).WillByDefault(Return(false)); InSequence seq; EXPECT_CALL(*volume_, Mount()); - EXPECT_CALL(*file_manager_, OpenActiveChild(volume_->GetUri(), time)); + EXPECT_CALL(*file_manager_, Open(volume_->GetUri(), time)); icon_->Activate(ActionArg(ActionArg::Source::LAUNCHER, 0, time)); } diff --git a/unity-shared/ApplicationManager.h b/unity-shared/ApplicationManager.h index c0f681a5e..8a5e6270d 100644 --- a/unity-shared/ApplicationManager.h +++ b/unity-shared/ApplicationManager.h @@ -109,6 +109,8 @@ public: nux::ROProperty<bool> active; nux::ROProperty<bool> urgent; nux::ROProperty<bool> maximized; + + sigc::signal<void> closed; }; @@ -219,6 +221,7 @@ public: virtual WindowList GetWindowsForMonitor(int monitor = -1) const = 0; virtual ApplicationPtr GetApplicationForWindow(Window xid) const = 0; virtual ApplicationWindowPtr GetWindowForId(Window xid) const = 0; + virtual void FocusWindowGroup(WindowList const&, bool show_on_visible, int monitor) const = 0; sigc::signal<void, ApplicationPtr const&> application_started; sigc::signal<void, ApplicationPtr const&> application_stopped; diff --git a/unity-shared/BamfApplicationManager.cpp b/unity-shared/BamfApplicationManager.cpp index 9a76d2a08..8225ccc05 100644 --- a/unity-shared/BamfApplicationManager.cpp +++ b/unity-shared/BamfApplicationManager.cpp @@ -147,6 +147,7 @@ WindowBase::WindowBase(ApplicationManager const& manager, }); signals_.Add<void, BamfView*>(bamf_view_, "closed", [this] (BamfView* view) { + this->closed.emit(); pool::wins_.erase(view); }); } @@ -473,7 +474,7 @@ ApplicationWindowPtr Application::GetFocusableWindow() const return pool::EnsureWindow(manager_, bamf_application_get_focusable_child(bamf_app_)); } -void Application::Focus(bool show_only_visible, int monitor) const +void Manager::FocusWindowGroup(WindowList const& wins, bool show_only_visible, int monitor) const { WindowManager& wm = WindowManager::Default(); std::vector<Window> urgent_windows; @@ -481,7 +482,7 @@ void Application::Focus(bool show_only_visible, int monitor) const std::vector<Window> non_visible_windows; bool any_visible = false; - for (auto& window : GetWindows()) + for (auto& window : wins) { Window window_id = window->window_id(); if (window->urgent()) @@ -526,12 +527,15 @@ void Application::Focus(bool show_only_visible, int monitor) const } } +void Application::Focus(bool show_only_visible, int monitor) const +{ + manager_.FocusWindowGroup(GetWindows(), show_only_visible, monitor); +} + void Application::Quit() const { for (auto& window : GetWindows()) - { window->Quit(); - } } bool Application::CreateLocalDesktopFile() const diff --git a/unity-shared/BamfApplicationManager.h b/unity-shared/BamfApplicationManager.h index 74503a9aa..30859025a 100644 --- a/unity-shared/BamfApplicationManager.h +++ b/unity-shared/BamfApplicationManager.h @@ -64,7 +64,7 @@ public: bool operator==(unity::ApplicationWindow const& other) const override { - return static_cast<WindowBase const*>(this)->bamf_view_ == static_cast<WindowBase const&>(other).bamf_view_; + return static_cast<WindowBase const*>(this)->bamf_view_ == static_cast<WindowBase const&>(other).bamf_view_; } bool operator!=(unity::ApplicationWindow const& other) const override { return !(operator==(other)); } }; @@ -175,6 +175,8 @@ public: ApplicationPtr EnsureApplication(BamfView*) const; ApplicationWindowPtr EnsureWindow(BamfView*) const; + void FocusWindowGroup(WindowList const&, bool show_on_visible, int monitor) const; + private: void OnViewOpened(BamfMatcher* matcher, BamfView* view); void OnViewClosed(BamfMatcher* matcher, BamfView* view); diff --git a/unity-shared/FileManager.h b/unity-shared/FileManager.h index 55647d2c0..15dc1d966 100644 --- a/unity-shared/FileManager.h +++ b/unity-shared/FileManager.h @@ -27,6 +27,8 @@ #include <vector> #include <set> #include <sigc++/sigc++.h> +#include "ApplicationManager.h" + namespace unity { @@ -40,15 +42,12 @@ public: virtual ~FileManager() = default; virtual void Open(std::string const& uri, uint64_t timestamp = 0) = 0; - virtual void OpenActiveChild(std::string const& uri, uint64_t timestamp = 0) = 0; virtual void OpenTrash(uint64_t timestamp) = 0; - virtual std::vector<std::string> OpenedLocations() const = 0; - virtual bool IsPrefixOpened(std::string const& uri) const = 0; - virtual bool IsTrashOpened() const = 0; - virtual bool IsDeviceOpened() const = 0; virtual void CopyFiles(std::set<std::string> const& uris, std::string const& dest, uint64_t timestamp = 0) = 0; virtual bool TrashFile(std::string const& uri) = 0; virtual void EmptyTrash(uint64_t timestamp = 0) = 0; + virtual WindowList WindowsForLocation(std::string const& location) const = 0; + virtual std::string LocationForWindow(ApplicationWindowPtr const&) const = 0; sigc::signal<void> locations_changed; @@ -57,6 +56,6 @@ private: FileManager& operator=(FileManager const&) = delete; }; -} +} // namespace unity #endif diff --git a/unity-shared/GnomeFileManager.cpp b/unity-shared/GnomeFileManager.cpp index 2f142f836..e273ffd70 100644 --- a/unity-shared/GnomeFileManager.cpp +++ b/unity-shared/GnomeFileManager.cpp @@ -21,8 +21,9 @@ #include "GnomeFileManager.h" #include <NuxCore/Logger.h> #include <UnityCore/DesktopUtilities.h> -#include <UnityCore/GLibWrapper.h> +#include <UnityCore/GLibSource.h> #include <UnityCore/GLibDBusProxy.h> +#include <UnityCore/GLibWrapper.h> #include <gdk/gdk.h> #include <gio/gio.h> @@ -33,10 +34,8 @@ namespace { DECLARE_LOGGER(logger, "unity.filemanager.gnome"); -const std::string TRASH_URI = "trash:"; +const std::string TRASH_URI = "trash:///"; const std::string FILE_SCHEMA = "file://"; -const std::string TRASH_PATH = FILE_SCHEMA + DesktopUtilities::GetUserDataDirectory() + "/Trash/files"; -const std::string DEVICES_PREFIX = FILE_SCHEMA + "/media/" + std::string(g_get_user_name()); const std::string NAUTILUS_NAME = "org.gnome.Nautilus"; const std::string NAUTILUS_PATH = "/org/gnome/Nautilus"; @@ -48,64 +47,83 @@ struct GnomeFileManager::Impl : parent_(parent) , filemanager_proxy_("org.freedesktop.FileManager1", "/org/freedesktop/FileManager1", "org.freedesktop.FileManager1") { - auto callback = sigc::mem_fun(this, &Impl::OnOpenLocationsUpdated); - filemanager_proxy_.GetProperty("OpenLocations", callback); - filemanager_proxy_.ConnectProperty("OpenLocations", callback); + auto callback = sigc::mem_fun(this, &Impl::OnOpenLocationsXidsUpdated); + filemanager_proxy_.GetProperty("XUbuntuOpenLocationsXids", callback); + filemanager_proxy_.ConnectProperty("XUbuntuOpenLocationsXids", callback); } - void OnOpenLocationsUpdated(GVariant* value) + glib::DBusProxy::Ptr NautilusOperationsProxy() const { - if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING_ARRAY)) + return std::make_shared<glib::DBusProxy>(NAUTILUS_NAME, NAUTILUS_PATH, + "org.gnome.Nautilus.FileOperations"); + } + + void OnOpenLocationsXidsUpdated(GVariant* value) + { + opened_location_for_xid_.clear(); + + if (!value) { - LOG_ERROR(logger) << "Locations value type is not matching the expected one!"; + LOG_WARN(logger) << "Locations have been invalidated, maybe there's no filemanager around..."; + parent_->locations_changed.emit(); return; } - opened_locations_.clear(); + if (!g_variant_is_of_type(value, G_VARIANT_TYPE("a{uas}"))) + { + LOG_ERROR(logger) << "Locations value type is not matching the expected one!"; + parent_->locations_changed.emit(); + return; + } GVariantIter iter; - const char *str; + GVariantIter *str_iter; + const char *loc; + guint32 xid; g_variant_iter_init(&iter, value); - while (g_variant_iter_loop(&iter, "s", &str)) + while (g_variant_iter_loop(&iter, "{uas}", &xid, &str_iter)) { - LOG_DEBUG(logger) << "Opened location " << str; - opened_locations_.push_back(str); + while (g_variant_iter_loop(str_iter, "s", &loc)) + { + /* We only care about the first mentioned location as per our "standard" + * it's the active one */ + LOG_DEBUG(logger) << xid << ": Opened location " << loc; + opened_location_for_xid_[xid] = loc; + break; + } } - parent_->locations_changed.emit(); - } - - std::string GetOpenedPrefix(std::string const& uri, bool allow_equal = true) - { - glib::Object<GFile> uri_file(g_file_new_for_uri(uri.c_str())); - - for (auto const& loc : opened_locations_) + // We must ensure that we emit the locations_changed signal only when all + // the parent windows have been registered on the app-manager + auto app_manager_not_synced = [this] { - bool equal = false; + auto& app_manager = ApplicationManager::Default(); + bool synced = true; - glib::Object<GFile> loc_file(g_file_new_for_uri(loc.c_str())); + for (auto const& pair : opened_location_for_xid_) + { + synced = (app_manager.GetWindowForId(pair.first) != nullptr); - if (allow_equal && g_file_equal(loc_file, uri_file)) - equal = true; + if (!synced) + break; + } - if (equal || g_file_has_prefix(loc_file, uri_file)) - return loc; - } + if (synced) + parent_->locations_changed.emit(); - return ""; - } + return !synced; + }; - glib::DBusProxy::Ptr NautilusOperationsProxy() const - { - return std::make_shared<glib::DBusProxy>(NAUTILUS_NAME, NAUTILUS_PATH, - "org.gnome.Nautilus.FileOperations"); + if (app_manager_not_synced()) + idle_.reset(new glib::Idle(app_manager_not_synced)); } GnomeFileManager* parent_; glib::DBusProxy filemanager_proxy_; - std::vector<std::string> opened_locations_; + glib::Source::UniquePtr idle_; + std::map<Window, std::string> opened_location_for_xid_; }; @@ -146,23 +164,9 @@ void GnomeFileManager::Open(std::string const& uri, uint64_t timestamp) } } -void GnomeFileManager::OpenActiveChild(std::string const& uri, uint64_t timestamp) -{ - auto const& opened = impl_->GetOpenedPrefix(uri); - - Open(opened.empty() ? uri : opened, timestamp); -} - void GnomeFileManager::OpenTrash(uint64_t timestamp) { - if (IsPrefixOpened(TRASH_PATH)) - { - OpenActiveChild(TRASH_PATH, timestamp); - } - else - { - OpenActiveChild(TRASH_URI, timestamp); - } + Open(TRASH_URI, timestamp); } void GnomeFileManager::Activate(uint64_t timestamp) @@ -252,25 +256,48 @@ void GnomeFileManager::CopyFiles(std::set<std::string> const& uris, std::string } } -std::vector<std::string> GnomeFileManager::OpenedLocations() const +WindowList GnomeFileManager::WindowsForLocation(std::string const& location) const { - return impl_->opened_locations_; -} + std::vector<ApplicationWindowPtr> windows; + auto& app_manager = ApplicationManager::Default(); -bool GnomeFileManager::IsPrefixOpened(std::string const& uri) const -{ - return !impl_->GetOpenedPrefix(uri).empty(); -} + glib::Object<GFile> location_file(g_file_new_for_uri(location.c_str())); -bool GnomeFileManager::IsTrashOpened() const -{ - return (IsPrefixOpened(TRASH_URI) || IsPrefixOpened(TRASH_PATH)); + for (auto const& pair : impl_->opened_location_for_xid_) + { + auto const& loc = pair.second; + bool matches = (loc == location); + + if (!matches) + { + glib::Object<GFile> loc_file(g_file_new_for_uri(loc.c_str())); + glib::String relative(g_file_get_relative_path(location_file, loc_file)); + matches = static_cast<bool>(relative); + } + + if (matches) + { + auto const& win = app_manager.GetWindowForId(pair.first); + + if (win && std::find(windows.rbegin(), windows.rend(), win) == windows.rend()) + windows.push_back(win); + } + } + + return windows; } -bool GnomeFileManager::IsDeviceOpened() const +std::string GnomeFileManager::LocationForWindow(ApplicationWindowPtr const& win) const { - return !impl_->GetOpenedPrefix(DEVICES_PREFIX, false).empty(); -} + if (win) + { + auto it = impl_->opened_location_for_xid_.find(win->window_id()); + if (it != end(impl_->opened_location_for_xid_)) + return it->second; + } + return std::string(); } + +} // namespace unity diff --git a/unity-shared/GnomeFileManager.h b/unity-shared/GnomeFileManager.h index 5b9ac1203..b017ce0ea 100644 --- a/unity-shared/GnomeFileManager.h +++ b/unity-shared/GnomeFileManager.h @@ -33,17 +33,14 @@ public: ~GnomeFileManager(); void Open(std::string const& uri, uint64_t timestamp); - void OpenActiveChild(std::string const& uri, uint64_t timestamp); void OpenTrash(uint64_t timestamp); void CopyFiles(std::set<std::string> const& uris, std::string const& dest, uint64_t timestamp); bool TrashFile(std::string const& uri); void EmptyTrash(uint64_t timestamp); - std::vector<std::string> OpenedLocations() const; - bool IsPrefixOpened(std::string const& uri) const; - bool IsTrashOpened() const; - bool IsDeviceOpened() const; + WindowList WindowsForLocation(std::string const& location) const; + std::string LocationForWindow(ApplicationWindowPtr const&) const; private: GnomeFileManager(); |
