summaryrefslogtreecommitdiff
diff options
-rw-r--r--UnityCore/DesktopUtilities.cpp34
-rw-r--r--UnityCore/DesktopUtilities.h1
-rw-r--r--UnityCore/GLibDBusProxy.cpp4
-rw-r--r--com.canonical.Unity.gschema.xml6
-rw-r--r--dash/DashController.cpp47
-rw-r--r--dash/DashController.h9
-rw-r--r--dash/DashView.cpp21
-rw-r--r--dash/DashView.h2
-rw-r--r--dash/previews/Track.cpp6
-rw-r--r--hud/HudAbstractView.h4
-rw-r--r--hud/HudController.cpp53
-rw-r--r--hud/HudController.h10
-rw-r--r--hud/HudView.cpp125
-rw-r--r--hud/HudView.h9
-rw-r--r--hud/StandaloneHud.cpp5
-rw-r--r--launcher/AbstractLauncherIcon.h18
-rw-r--r--launcher/BFBLauncherIcon.cpp1
-rw-r--r--launcher/BamfLauncherIcon.cpp77
-rw-r--r--launcher/BamfLauncherIcon.h1
-rw-r--r--launcher/CMakeLists.txt1
-rw-r--r--launcher/DesktopLauncherIcon.cpp25
-rw-r--r--launcher/DesktopLauncherIcon.h14
-rw-r--r--launcher/DeviceLauncherSection.cpp21
-rw-r--r--launcher/DeviceLauncherSection.h8
-rw-r--r--launcher/DndData.cpp10
-rw-r--r--launcher/DndData.h2
-rw-r--r--launcher/ExpoLauncherIcon.cpp64
-rw-r--r--launcher/ExpoLauncherIcon.h45
-rw-r--r--launcher/FavoriteStore.cpp97
-rw-r--r--launcher/FavoriteStore.h29
-rw-r--r--launcher/FavoriteStoreGSettings.cpp133
-rw-r--r--launcher/FavoriteStoreGSettings.h11
-rw-r--r--launcher/FavoriteStorePrivate.cpp14
-rw-r--r--launcher/FavoriteStorePrivate.h4
-rw-r--r--launcher/HudLauncherIcon.cpp3
-rw-r--r--launcher/Launcher.cpp194
-rw-r--r--launcher/Launcher.h13
-rw-r--r--launcher/LauncherController.cpp749
-rw-r--r--launcher/LauncherController.h4
-rw-r--r--launcher/LauncherControllerPrivate.h67
-rw-r--r--launcher/LauncherDragWindow.cpp25
-rw-r--r--launcher/LauncherDragWindow.h7
-rw-r--r--launcher/LauncherIcon.cpp35
-rw-r--r--launcher/LauncherIcon.h14
-rw-r--r--launcher/LauncherModel.cpp62
-rw-r--r--launcher/MockLauncherIcon.h26
-rw-r--r--launcher/SoftwareCenterLauncherIcon.cpp67
-rw-r--r--launcher/SoftwareCenterLauncherIcon.h2
-rw-r--r--launcher/SpacerLauncherIcon.cpp2
-rw-r--r--launcher/SpacerLauncherIcon.h4
-rw-r--r--launcher/StandaloneLauncher.cpp2
-rw-r--r--launcher/TrashLauncherIcon.cpp1
-rw-r--r--launcher/VolumeLauncherIcon.cpp38
-rw-r--r--launcher/VolumeLauncherIcon.h3
-rw-r--r--manual-tests/Launcher.txt15
-rw-r--r--panel/PanelMenuView.h1
-rw-r--r--panel/WindowButtons.cpp13
-rw-r--r--panel/WindowButtons.h3
-rw-r--r--plugins/unityshell/src/unityshell.cpp64
-rw-r--r--plugins/unityshell/src/unityshell.h5
-rw-r--r--plugins/unityshell/unityshell.xml.in6
-rw-r--r--tests/CMakeLists.txt31
-rw-r--r--tests/autopilot/unity/emulators/dash.py4
-rw-r--r--tests/autopilot/unity/tests/test_dash.py33
-rw-r--r--tests/autopilot/unity/tests/test_hud.py32
-rw-r--r--tests/data/applications/bzr-handle-patch.desktop (renamed from tests/data/bzr-handle-patch.desktop)0
-rw-r--r--tests/data/applications/no-icon.desktop (renamed from tests/data/no-icon.desktop)0
-rw-r--r--tests/data/applications/ubuntu-software-center.desktop (renamed from tests/data/ubuntu-software-center.desktop)0
-rw-r--r--tests/data/applications/ubuntuone-installer.desktop (renamed from tests/data/ubuntuone-installer.desktop)0
-rw-r--r--tests/data/applications/update-manager.desktop (renamed from tests/data/update-manager.desktop)0
-rw-r--r--tests/gmockvolume.c5
-rw-r--r--tests/test_bamf_launcher_icon.cpp (renamed from tests/test_bamflaunchericon.cpp)72
-rw-r--r--tests/test_bfb_launcher_icon.cpp17
-rw-r--r--tests/test_desktop_launcher_icon.cpp80
-rw-r--r--tests/test_desktop_utilities.cpp68
-rw-r--r--tests/test_device_launcher_section.cpp69
-rw-r--r--tests/test_expo_launcher_icon.cpp58
-rw-r--r--tests/test_favorite_store.cpp111
-rw-r--r--tests/test_favorite_store_gsettings.cpp73
-rw-r--r--tests/test_hud_controller.cpp3
-rw-r--r--tests/test_hud_launcher_icon.cpp53
-rw-r--r--tests/test_launcher.cpp237
-rw-r--r--tests/test_launcher_controller.cpp1276
-rw-r--r--tests/test_launcher_icon.cpp113
-rw-r--r--tests/test_launcher_model.cpp178
-rw-r--r--tests/test_main.cpp1
-rw-r--r--tests/test_main_xless.cpp2
-rw-r--r--tests/test_mock_devices.h93
-rw-r--r--tests/test_software_center_launcher_icon.cpp74
-rw-r--r--tests/test_trash_launcher_icon.cpp39
-rw-r--r--tests/test_unity_settings.cpp110
-rw-r--r--tests/test_volume_launcher_icon.cpp111
-rwxr-xr-xtools/unity.cmake8
-rwxr-xr-xunity-shared/DashStyle.cpp8
-rw-r--r--unity-shared/IconLoader.cpp4
-rw-r--r--unity-shared/OverlayRenderer.cpp6
-rw-r--r--unity-shared/PanelStyle.cpp6
-rw-r--r--unity-shared/PluginAdapter.h2
-rw-r--r--unity-shared/PluginAdapterCompiz.cpp5
-rw-r--r--unity-shared/PluginAdapterStandalone.cpp22
-rw-r--r--unity-shared/ResizingBaseWindow.h53
-rw-r--r--unity-shared/UnitySettings.cpp125
-rw-r--r--unity-shared/UnitySettings.h20
-rw-r--r--unity-shared/WindowManager.cpp5
-rw-r--r--unity-shared/WindowManager.h1
-rw-r--r--unity-standalone/StandaloneUnity.cpp6
106 files changed, 4326 insertions, 1224 deletions
diff --git a/UnityCore/DesktopUtilities.cpp b/UnityCore/DesktopUtilities.cpp
index 46f5b0165..a627c191b 100644
--- a/UnityCore/DesktopUtilities.cpp
+++ b/UnityCore/DesktopUtilities.cpp
@@ -19,8 +19,10 @@
*/
#include <algorithm>
+#include <memory>
#include <glib.h>
+#include <gio/gdesktopappinfo.h>
#include "DesktopUtilities.h"
#include "GLibWrapper.h"
@@ -119,23 +121,41 @@ std::string DesktopUtilities::GetDesktopID(std::string const& desktop_path)
return GetDesktopID(data_dirs, desktop_path);
}
+std::string DesktopUtilities::GetDesktopPathById(std::string const& desktop_id)
+{
+ if (desktop_id.empty())
+ return "";
+
+ glib::Object<GDesktopAppInfo> info;
+
+ if (desktop_id.find(G_DIR_SEPARATOR_S) != std::string::npos)
+ info = g_desktop_app_info_new_from_filename(desktop_id.c_str());
+ else
+ info = g_desktop_app_info_new(desktop_id.c_str());
+
+ if (info)
+ {
+ const char* filename = g_desktop_app_info_get_filename(info);
+
+ if (filename)
+ return filename;
+ }
+
+ return "";
+}
std::string DesktopUtilities::GetBackgroundColor(std::string const& desktop_path)
{
- GKeyFile* key_file = g_key_file_new();
+ std::shared_ptr<GKeyFile> key_file(g_key_file_new(), g_key_file_free);
glib::Error error;
- g_key_file_load_from_file(key_file, desktop_path.c_str(), static_cast<GKeyFileFlags>(0), &error);
+ g_key_file_load_from_file(key_file.get(), desktop_path.c_str(), static_cast<GKeyFileFlags>(0), &error);
if (error)
- {
- g_key_file_free(key_file);
return "";
- }
- glib::String value(g_key_file_get_string(key_file, "Desktop Entry", "X-Unity-IconBackgroundColor", &error));
+ glib::String value(g_key_file_get_string(key_file.get(), "Desktop Entry", "X-Unity-IconBackgroundColor", &error));
- g_key_file_free(key_file);
return value.Str();
}
diff --git a/UnityCore/DesktopUtilities.h b/UnityCore/DesktopUtilities.h
index 7a6b38402..072b40c80 100644
--- a/UnityCore/DesktopUtilities.h
+++ b/UnityCore/DesktopUtilities.h
@@ -36,6 +36,7 @@ public:
static std::string GetDesktopID(std::string const& desktop_path);
static std::string GetDesktopID(std::vector<std::string> const& default_paths,
std::string const& desktop_path);
+ static std::string GetDesktopPathById(std::string const& desktop_id);
static std::string GetBackgroundColor(std::string const& desktop_path);
};
diff --git a/UnityCore/GLibDBusProxy.cpp b/UnityCore/GLibDBusProxy.cpp
index da0ac00fd..bd086574b 100644
--- a/UnityCore/GLibDBusProxy.cpp
+++ b/UnityCore/GLibDBusProxy.cpp
@@ -90,7 +90,6 @@ public:
glib::Object<GDBusProxy> proxy_;
glib::Object<GCancellable> cancellable_;
- guint watcher_id_;
bool connected_;
glib::Signal<void, GDBusProxy*, char*, char*, GVariant*> g_signal_connection_;
@@ -113,7 +112,6 @@ DBusProxy::Impl::Impl(DBusProxy* owner,
, bus_type_(bus_type)
, flags_(flags)
, cancellable_(g_cancellable_new())
- , watcher_id_(0)
, connected_(false)
{
StartReconnectionTimeout();
@@ -122,8 +120,6 @@ DBusProxy::Impl::Impl(DBusProxy* owner,
DBusProxy::Impl::~Impl()
{
g_cancellable_cancel(cancellable_);
- if (watcher_id_)
- g_bus_unwatch_name(watcher_id_);
}
void DBusProxy::Impl::StartReconnectionTimeout()
diff --git a/com.canonical.Unity.gschema.xml b/com.canonical.Unity.gschema.xml
index 7656110a5..66d4563a6 100644
--- a/com.canonical.Unity.gschema.xml
+++ b/com.canonical.Unity.gschema.xml
@@ -44,9 +44,9 @@
</schema>
<schema path="/com/canonical/unity/launcher/" id="com.canonical.Unity.Launcher" gettext-domain="unity">
<key type="as" name="favorites">
- <default>[ 'ubiquity-gtkui.desktop', 'nautilus-home.desktop', 'firefox.desktop', 'libreoffice-writer.desktop', 'libreoffice-calc.desktop', 'libreoffice-impress.desktop', 'ubuntu-software-center.desktop', 'ubuntuone-installer.desktop', 'gnome-control-center.desktop' ]</default>
- <summary>List of desktop file ids for favorites on the launcher.</summary>
- <description>These applications are shown in the Launcher by default.</description>
+ <default>[ 'application://ubiquity-gtkui.desktop', 'application://nautilus-home.desktop', 'application://firefox.desktop', 'application://libreoffice-writer.desktop', 'application://libreoffice-calc.desktop', 'application://libreoffice-impress.desktop', 'application://ubuntu-software-center.desktop', 'application://ubuntuone-installer.desktop', 'application://gnome-control-center.desktop', 'unity://running-apps', 'unity://expo-icon', 'unity://devices' ]</default>
+ <summary>List of items that should be shown by default in the launcher</summary>
+ <description>These items can be application://desktop-id.desktop, device://uiid and unity://special-id (including unity://running-apps that specifies the position of the ran applications, unity://devices the position of the attached devices, unity://expo-icon the position of the workspace switcher and unity://show-desktop-icon the position of the show-desktop icon); the order of this list determines the launcher items position.</description>
</key>
<key type="s" name="favorite-migration">
<default>''</default>
diff --git a/dash/DashController.cpp b/dash/DashController.cpp
index 7cba3e165..e5e8f6233 100644
--- a/dash/DashController.cpp
+++ b/dash/DashController.cpp
@@ -66,17 +66,17 @@ Controller::Controller()
, timeline_animator_(90)
, dbus_connect_cancellable_(g_cancellable_new())
{
- SetupRelayoutCallbacks();
RegisterUBusInterests();
ensure_timeout_.Run([&]() { EnsureDash(); return false; });
timeline_animator_.animation_updated.connect(sigc::mem_fun(this, &Controller::OnViewShowHideFrame));
SetupWindow();
+ UScreen::GetDefault()->changed.connect([&] (int, std::vector<nux::Geometry>&) { Relayout(true); });
- Settings::Instance().changed.connect([&]()
+ Settings::Instance().form_factor.changed.connect([this](FormFactor)
{
- if (window_ && view_)
+ if (window_ && view_ && visible_)
{
window_->PushToFront();
window_->SetInputFocus();
@@ -97,7 +97,12 @@ Controller::~Controller()
void Controller::SetupWindow()
{
- window_ = new nux::BaseWindow(dash::window_title);
+ window_ = new ResizingBaseWindow(dash::window_title, [this](nux::Geometry const& geo)
+ {
+ if (view_)
+ return GetInputWindowGeometry();
+ return geo;
+ });
window_->SetBackgroundColor(nux::Color(0.0f, 0.0f, 0.0f, 0.0f));
window_->SetConfigureNotifyCallback(&Controller::OnWindowConfigure, this);
window_->ShowWindow(false);
@@ -122,17 +127,11 @@ void Controller::SetupDashView()
layout->SetContentDistribution(nux::eStackLeft);
layout->SetVerticalExternalMargin(0);
layout->SetHorizontalExternalMargin(0);
-
window_->SetLayout(layout);
- ubus_manager_.UnregisterInterest(UBUS_PLACE_ENTRY_ACTIVATE_REQUEST);
-}
-void Controller::SetupRelayoutCallbacks()
-{
- GdkScreen* screen = gdk_screen_get_default();
- auto relayout_cb = sigc::mem_fun(this, &Controller::Relayout);
- sig_manager_.Add<void, GdkScreen*>(screen, "monitors-changed", relayout_cb);
- sig_manager_.Add<void, GdkScreen*>(screen, "size-changed", relayout_cb);
+ window_->UpdateInputWindowGeometry();
+
+ ubus_manager_.UnregisterInterest(UBUS_PLACE_ENTRY_ACTIVATE_REQUEST);
}
void Controller::RegisterUBusInterests()
@@ -218,13 +217,19 @@ nux::Geometry Controller::GetIdealWindowGeometry()
monitor_geo.height - panel_style.panel_height);
}
-void Controller::Relayout(GdkScreen*screen)
+void Controller::Relayout(bool check_monitor)
{
EnsureDash();
+ if (check_monitor)
+ {
+ monitor_ = CLAMP(GetIdealMonitor(), 0, static_cast<int>(UScreen::GetDefault()->GetMonitors().size()-1));
+ printf("relayout on monitor:%d, monitor count:%d\n", monitor_, static_cast<int>(UScreen::GetDefault()->GetMonitors().size()));
+ }
+
nux::Geometry geo = GetIdealWindowGeometry();
- window_->SetGeometry(geo);
view_->Relayout();
+ window_->SetGeometry(geo);
panel::Style &panel_style = panel::Style::Instance();
view_->SetMonitorOffset(launcher_width, panel_style.panel_height);
}
@@ -291,7 +296,11 @@ void Controller::ShowDash()
window_->ShowWindow(true);
window_->PushToFront();
if (!Settings::Instance().is_standalone) // in standalone mode, we do not need an input window. we are one.
+ {
window_->EnableInputWindow(true, dash::window_title, true, false);
+ // update the input window geometry. This causes the input window to match the actual size of the dash.
+ window_->UpdateInputWindowGeometry();
+ }
window_->SetInputFocus();
window_->CaptureMouseDownAnyWhereElse(true);
window_->QueueDraw();
@@ -445,6 +454,14 @@ void Controller::OnDBusMethodCall(GDBusConnection* connection, const gchar* send
}
}
+nux::Geometry Controller::GetInputWindowGeometry()
+{
+ EnsureDash();
+ nux::Geometry const& window_geo(window_->GetGeometry());
+ nux::Geometry const& view_content_geo(view_->GetContentGeometry());
+ return nux::Geometry(window_geo.x, window_geo.y, view_content_geo.width, view_content_geo.height);
+}
+
}
}
diff --git a/dash/DashController.h b/dash/DashController.h
index d6854d5f8..821b8b96c 100644
--- a/dash/DashController.h
+++ b/dash/DashController.h
@@ -27,12 +27,12 @@
#include <NuxCore/Property.h>
#include <NuxGraphics/GraphicsEngine.h>
#include <Nux/Nux.h>
-#include <Nux/BaseWindow.h>
#include "DashView.h"
#include "unity-shared/Animator.h"
#include "unity-shared/Introspectable.h"
#include "unity-shared/UBusWrapper.h"
+#include "unity-shared/ResizingBaseWindow.h"
namespace unity
{
@@ -60,6 +60,7 @@ public:
void HideDash(bool restore_focus = true);
bool IsVisible() const;
+ nux::Geometry GetInputWindowGeometry();
protected:
std::string GetName() const;
@@ -69,12 +70,11 @@ private:
void EnsureDash();
void SetupWindow();
void SetupDashView();
- void SetupRelayoutCallbacks();
void RegisterUBusInterests();
nux::Geometry GetIdealWindowGeometry();
int GetIdealMonitor();
- void Relayout(GdkScreen*screen=NULL);
+ void Relayout(bool check_monitor =false);
void OnMouseDownOutsideWindow(int x, int y, unsigned long bflags, unsigned long kflags);
void OnScreenUngrabbed();
@@ -96,7 +96,7 @@ private:
static void OnWindowConfigure(int width, int height, nux::Geometry& geo, void* data);
private:
- nux::ObjectPtr<nux::BaseWindow> window_;
+ nux::ObjectPtr<ResizingBaseWindow> window_;
int monitor_;
bool visible_;
@@ -104,7 +104,6 @@ private:
DashView* view_;
sigc::connection screen_ungrabbed_slot_;
- glib::SignalManager sig_manager_;
glib::TimeoutSeconds ensure_timeout_;
Animator timeline_animator_;
UBusManager ubus_manager_;
diff --git a/dash/DashView.cpp b/dash/DashView.cpp
index 79385b1da..b0713b7be 100644
--- a/dash/DashView.cpp
+++ b/dash/DashView.cpp
@@ -107,7 +107,10 @@ DashView::DashView()
SetupViews();
SetupUBusConnections();
- Settings::Instance().changed.connect(sigc::mem_fun(this, &DashView::Relayout));
+ Settings::Instance().form_factor.changed.connect([this](FormFactor) {
+ Relayout();
+ });
+
lenses_.lens_added.connect(sigc::mem_fun(this, &DashView::OnLensAdded));
mouse_down.connect(sigc::mem_fun(this, &DashView::OnMouseButtonDown));
preview_state_machine_.PreviewActivated.connect(sigc::mem_fun(this, &DashView::BuildPreview));
@@ -434,7 +437,6 @@ void DashView::Relayout()
content_geo_ = geo;
}
-
// kinda hacky, but it makes sure the content isn't so big that it throws
// the bottom of the dash off the screen
// not hugely happy with this, so FIXME
@@ -760,7 +762,7 @@ void DashView::OnMouseButtonDown(int x, int y, unsigned long button, unsigned lo
dash::Style& style = dash::Style::Instance();
nux::Geometry geo(content_geo_);
- if (Settings::Instance().GetFormFactor() == FormFactor::DESKTOP)
+ if (Settings::Instance().form_factor() == FormFactor::DESKTOP)
{
geo.width += style.GetDashRightTileWidth();
geo.height += style.GetDashBottomTileHeight();
@@ -1057,7 +1059,7 @@ bool DashView::DoFallbackActivation(std::string const& fake_uri)
return LaunchApp(appname);
}
else
- return gtk_show_uri(NULL, uri.c_str(), time(NULL), NULL);
+ return gtk_show_uri(NULL, uri.c_str(), CurrentTime, NULL);
return false;
}
@@ -1192,11 +1194,11 @@ void DashView::AddProperties(GVariantBuilder* builder)
std::string form_factor("unknown");
- if (Settings::Instance().GetFormFactor() == FormFactor::NETBOOK)
+ if (Settings::Instance().form_factor() == FormFactor::NETBOOK)
form_factor = "netbook";
- else if (Settings::Instance().GetFormFactor() == FormFactor::DESKTOP)
+ else if (Settings::Instance().form_factor() == FormFactor::DESKTOP)
form_factor = "desktop";
- else if (Settings::Instance().GetFormFactor() == FormFactor::TV)
+ else if (Settings::Instance().form_factor() == FormFactor::TV)
form_factor = "tv";
unity::variant::BuilderWrapper wrapper(builder);
@@ -1416,5 +1418,10 @@ nux::Area* DashView::FindAreaUnderMouse(const nux::Point& mouse_position, nux::N
return (view == nullptr) ? this : view;
}
+nux::Geometry const& DashView::GetContentGeometry() const
+{
+ return content_geo_;
+}
+
}
}
diff --git a/dash/DashView.h b/dash/DashView.h
index 4bd202fe6..de3b487ab 100644
--- a/dash/DashView.h
+++ b/dash/DashView.h
@@ -74,6 +74,8 @@ public:
nux::View* default_focus() const;
+ nux::Geometry const& GetContentGeometry() const;
+
protected:
void ProcessDndEnter();
diff --git a/dash/previews/Track.cpp b/dash/previews/Track.cpp
index 3f8efffdd..a7f281a85 100644
--- a/dash/previews/Track.cpp
+++ b/dash/previews/Track.cpp
@@ -349,9 +349,9 @@ void Track::DrawContent(nux::GraphicsEngine& gfx_engine, bool force_draw)
nux::Area* Track::FindAreaUnderMouse(const nux::Point& mouse_position, nux::NuxEventType event_type)
{
- bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type);
- if (mouse_inside == false)
- return NULL;
+ bool mouse_inside = TestMousePointerInclusion(mouse_position, event_type);
+ if (mouse_inside == false)
+ return NULL;
return this;
}
diff --git a/hud/HudAbstractView.h b/hud/HudAbstractView.h
index e4755180e..56f20e2be 100644
--- a/hud/HudAbstractView.h
+++ b/hud/HudAbstractView.h
@@ -48,8 +48,9 @@ public:
virtual void SearchFinished() = 0;
virtual void SetIcon(std::string const& icon_name, unsigned int tile_size, unsigned int size, unsigned int padding) = 0;
virtual void SetQueries(Hud::Queries queries) = 0;
- virtual void SetWindowGeometry(nux::Geometry const& absolute_geo, nux::Geometry const& geo) = 0;
+ virtual void SetMonitorOffset(int x, int y) = 0;
virtual void ShowEmbeddedIcon(bool show) = 0;
+ virtual nux::Geometry GetContentGeometry() = 0;
virtual nux::View* default_focus() const = 0;
@@ -58,6 +59,7 @@ public:
sigc::signal<void, std::string> search_activated;
sigc::signal<void, Query::Ptr> query_activated;
sigc::signal<void, Query::Ptr> query_selected;
+ sigc::signal<void> layout_changed;
};
} // namespace hud
diff --git a/hud/HudController.cpp b/hud/HudController.cpp
index a28d65819..0ae81222a 100644
--- a/hud/HudController.cpp
+++ b/hud/HudController.cpp
@@ -54,7 +54,7 @@ Controller::Controller(std::function<AbstractView*(void)> const& function)
{
LOG_DEBUG(logger) << "hud startup";
SetupWindow();
- UScreen::GetDefault()->changed.connect([&] (int, std::vector<nux::Geometry>&) { Relayout(); });
+ UScreen::GetDefault()->changed.connect([&] (int, std::vector<nux::Geometry>&) { Relayout(true); });
ubus.RegisterInterest(UBUS_HUD_CLOSE_REQUEST, sigc::mem_fun(this, &Controller::OnExternalHideHud));
@@ -90,7 +90,12 @@ void Controller::SetupWindow()
// Since BaseWindow is a View it is initially unowned. This means that the first
// reference that is taken grabs ownership of the pointer. Since the smart pointer
// references it, it becomes the owner, so no need to adopt the pointer here.
- window_ = new nux::BaseWindow("Hud");
+ window_ = new ResizingBaseWindow("Hud", [this](nux::Geometry const& geo)
+ {
+ if (view_)
+ return GetInputWindowGeometry();
+ return geo;
+ });
window_->SetBackgroundColor(nux::Color(0.0f, 0.0f, 0.0f, 0.0f));
window_->SetConfigureNotifyCallback(&Controller::OnWindowConfigure, this);
window_->ShowWindow(false);
@@ -117,6 +122,8 @@ void Controller::SetupHudView()
layout_->AddView(view_, 1, nux::MINOR_POSITION_TOP);
window_->SetLayout(layout_);
+ window_->UpdateInputWindowGeometry();
+
view_->mouse_down_outside_pointer_grab_area.connect(sigc::mem_fun(this, &Controller::OnMouseDownOutsideWindow));
LOG_DEBUG(logger) << "connecting to signals";
@@ -124,6 +131,7 @@ void Controller::SetupHudView()
view_->search_activated.connect(sigc::mem_fun(this, &Controller::OnSearchActivated));
view_->query_activated.connect(sigc::mem_fun(this, &Controller::OnQueryActivated));
view_->query_selected.connect(sigc::mem_fun(this, &Controller::OnQuerySelected));
+ view_->layout_changed.connect(sigc::bind(sigc::mem_fun(this, &Controller::Relayout), nullptr));
// Add to the debug introspection.
AddChild(view_);
}
@@ -155,13 +163,15 @@ bool Controller::IsLockedToLauncher(int monitor)
void Controller::EnsureHud()
{
- LOG_DEBUG(logger) << "Initializing Hud";
-
if (!window_)
+ {
+ LOG_DEBUG(logger) << "Initializing Hud Window";
SetupWindow();
+ }
if (!view_)
{
+ LOG_DEBUG(logger) << "Initializing Hud View";
SetupHudView();
Relayout();
}
@@ -212,16 +222,20 @@ nux::Geometry Controller::GetIdealWindowGeometry()
return geo;
}
-void Controller::Relayout()
+void Controller::Relayout(bool check_monitor)
{
EnsureHud();
- nux::Geometry const& content_geo = view_->GetGeometry();
+
+ if (check_monitor)
+ {
+ monitor_index_ = CLAMP(GetIdealMonitor(), 0, static_cast<int>(UScreen::GetDefault()->GetMonitors().size()-1));
+ }
nux::Geometry const& geo = GetIdealWindowGeometry();
- window_->SetGeometry(geo);
- layout_->SetMinMaxSize(content_geo.width, content_geo.height);
- view_->SetWindowGeometry(window_->GetAbsoluteGeometry(), window_->GetGeometry());
view_->Relayout();
+ window_->SetGeometry(geo);
+ panel::Style &panel_style = panel::Style::Instance();
+ view_->SetMonitorOffset(launcher_width, panel_style.panel_height);
}
void Controller::OnMouseDownOutsideWindow(int x, int y,
@@ -255,7 +269,15 @@ void Controller::OnExternalHideHud(GVariant* variant)
{
LOG_DEBUG(logger) << "External Hiding the hud";
EnsureHud();
- HideHud();
+
+ if (variant)
+ {
+ HideHud(g_variant_get_boolean(variant));
+ }
+ else
+ {
+ HideHud();
+ }
}
void Controller::ShowHideHud()
@@ -353,6 +375,7 @@ void Controller::ShowHud()
window_->ShowWindow(true);
window_->PushToFront();
window_->EnableInputWindow(true, "Hud", true, false);
+ window_->UpdateInputWindowGeometry();
window_->SetInputFocus();
window_->CaptureMouseDownAnyWhereElse(true);
view_->CaptureMouseDownAnyWhereElse(true);
@@ -363,7 +386,6 @@ void Controller::ShowHud()
visible_ = true;
StartShowHideTimeline();
- view_->SetWindowGeometry(window_->GetAbsoluteGeometry(), window_->GetGeometry());
// hide the launcher
GVariant* message_data = g_variant_new("(b)", TRUE);
@@ -504,6 +526,15 @@ void Controller::AddProperties(GVariantBuilder* builder)
.add("locked_to_launcher", IsLockedToLauncher(monitor_index_));
}
+nux::Geometry Controller::GetInputWindowGeometry()
+{
+ EnsureHud();
+ nux::Geometry const& window_geo(window_->GetGeometry());
+ nux::Geometry const& view_content_geo(view_->GetContentGeometry());
+ return nux::Geometry(window_geo.x, window_geo.y, view_content_geo.width, view_content_geo.height);
+}
+
+
}
}
diff --git a/hud/HudController.h b/hud/HudController.h
index 6ca3aa35a..eb60312ba 100644
--- a/hud/HudController.h
+++ b/hud/HudController.h
@@ -24,14 +24,15 @@
#include <gdk/gdk.h>
#include <UnityCore/Hud.h>
+#include <UnityCore/GLibSignal.h>
#include <NuxCore/Property.h>
#include <NuxGraphics/GraphicsEngine.h>
#include <Nux/Nux.h>
-#include <Nux/BaseWindow.h>
#include "unity-shared/Animator.h"
#include "unity-shared/UBusWrapper.h"
+#include "unity-shared/ResizingBaseWindow.h"
#include "HudView.h"
namespace unity
@@ -59,6 +60,8 @@ public:
void HideHud(bool restore_focus = true);
bool IsVisible();
+ nux::Geometry GetInputWindowGeometry();
+
protected:
// Introspectable
std::string GetName() const;
@@ -75,7 +78,7 @@ private:
bool IsLockedToLauncher(int monitor);
nux::Geometry GetIdealWindowGeometry();
- void Relayout();
+ void Relayout(bool check_monitor =false);
void OnMouseDownOutsideWindow(int x, int y, unsigned long bflags, unsigned long kflags);
void OnScreenUngrabbed();
@@ -96,8 +99,9 @@ private:
void OnQueriesFinished(Hud::Queries queries);
private:
- nux::ObjectPtr<nux::BaseWindow> window_;
+ nux::ObjectPtr<ResizingBaseWindow> window_;
UBusManager ubus;
+ glib::SignalManager sig_manager_;
Hud hud_service_;
bool visible_;
bool need_show_;
diff --git a/hud/HudView.cpp b/hud/HudView.cpp
index 4bf76d6b6..aabee909c 100644
--- a/hud/HudView.cpp
+++ b/hud/HudView.cpp
@@ -61,10 +61,10 @@ View::View()
: AbstractView()
, button_views_(nullptr)
, visible_(false)
+ , timeline_animating_(false)
, start_time_(0)
, last_known_height_(0)
, current_height_(0)
- , timeline_need_more_draw_(false)
, selected_button_(0)
, show_embedded_icon_(true)
, keyboard_stole_focus_(false)
@@ -122,6 +122,12 @@ View::~View()
{
}
+void View::SetMonitorOffset(int x, int y)
+{
+ renderer_.x_offset = x;
+ renderer_.y_offset = y;
+}
+
void View::ProcessGrowShrink()
{
float diff = g_get_monotonic_time() - start_time_;
@@ -129,24 +135,25 @@ void View::ProcessGrowShrink()
// only animate if we are after our defined pause time
if (diff > pause_before_grow_length)
{
- float progress = (diff - pause_before_grow_length) / grow_anim_length;
- int last_height = last_known_height_;
- int new_height = 0;
-
- if (last_height < target_height)
- {
- // grow
- new_height = last_height + ((target_height - last_height) * progress);
- }
- else
- {
- //shrink
- new_height = last_height - ((last_height - target_height) * progress);
- }
-
- LOG_DEBUG(logger) << "resizing to " << target_height << " (" << new_height << ")"
+ float progress = (diff - pause_before_grow_length) / grow_anim_length;
+ int last_height = last_known_height_;
+ int new_height = 0;
+
+ if (last_height < target_height)
+ {
+ // grow
+ new_height = last_height + ((target_height - last_height) * progress);
+ }
+ else
+ {
+ //shrink
+ new_height = last_height - ((last_height - target_height) * progress);
+ }
+
+
+ LOG_DEBUG(logger) << "resizing to " << target_height << " (" << new_height << ")"
<< "View height: " << GetGeometry().height;
- current_height_ = new_height;
+ current_height_ = new_height;
}
for (auto button : buttons_)
@@ -154,14 +161,23 @@ void View::ProcessGrowShrink()
button->SetSkipDraw((button->GetAbsoluteY() + button->GetBaseHeight()) > (GetAbsoluteY() + current_height_));
}
- QueueDraw();
-
if (diff > grow_anim_length + pause_before_grow_length)
{
// ensure we are at our final location and update last known height
current_height_ = target_height;
last_known_height_ = target_height;
- timeline_need_more_draw_ = false;
+
+ layout_changed.emit();
+ timeline_idle_.reset();
+ timeline_animating_ = false;
+ }
+ else
+ {
+ timeline_idle_.reset(new glib::Timeout(0, [this]
+ {
+ QueueDraw();
+ return false;
+ }));
}
}
@@ -187,27 +203,6 @@ void View::Relayout()
QueueDraw();
}
-long View::PostLayoutManagement(long LayoutResult)
-{
- Relayout();
- if (GetGeometry().height != last_known_height_)
- {
- // Start the timeline of drawing the dash resize
- if (timeline_need_more_draw_)
- {
- // already started, just reset the last known height
- last_known_height_ = current_height_;
- }
-
- timeline_need_more_draw_ = true;
- start_time_ = g_get_monotonic_time();
- QueueDraw();
- }
-
- return LayoutResult;
-}
-
-
nux::View* View::default_focus() const
{
return search_bar_->text_entry();
@@ -361,14 +356,6 @@ void View::AboutToHide()
renderer_.AboutToHide();
}
-void View::SetWindowGeometry(nux::Geometry const& absolute_geo, nux::Geometry const& geo)
-{
- window_geometry_ = geo;
- window_geometry_.x = 0;
- window_geometry_.y = 0;
- absolute_window_geometry_ = absolute_geo;
-}
-
void View::SetupViews()
{
dash::Style& style = dash::Style::Instance();
@@ -405,6 +392,17 @@ void View::SetupViews()
content_layout_->AddLayout(button_views_.GetPointer(), 1, nux::MINOR_POSITION_LEFT);
}
+ content_layout_->geometry_changed.connect([&](nux::Area*, nux::Geometry& geo)
+ {
+ if (!timeline_animating_)
+ {
+ timeline_animating_ = true;
+ start_time_ = g_get_monotonic_time();
+ QueueDraw();
+ }
+ });
+
+
layout_->AddLayout(content_layout_.GetPointer(), 1, nux::MINOR_POSITION_TOP);
}
@@ -450,14 +448,12 @@ void View::OnMouseButtonDown(int x, int y, unsigned long button, unsigned long k
void View::Draw(nux::GraphicsEngine& gfx_context, bool force_draw)
{
- if (timeline_need_more_draw_)
- {
+ if (timeline_animating_)
ProcessGrowShrink();
- }
nux::Geometry draw_content_geo(layout_->GetGeometry());
draw_content_geo.height = current_height_;
- renderer_.DrawFull(gfx_context, draw_content_geo, absolute_window_geometry_, window_geometry_, true);
+ renderer_.DrawFull(gfx_context, draw_content_geo, GetAbsoluteGeometry(), GetGeometry(), true);
}
void View::DrawContent(nux::GraphicsEngine& gfx_context, bool force_draw)
@@ -465,7 +461,7 @@ void View::DrawContent(nux::GraphicsEngine& gfx_context, bool force_draw)
nux::Geometry draw_content_geo(layout_->GetGeometry());
draw_content_geo.height = current_height_;
- renderer_.DrawInner(gfx_context, draw_content_geo, absolute_window_geometry_, window_geometry_);
+ renderer_.DrawInner(gfx_context, draw_content_geo, GetAbsoluteGeometry(), GetGeometry());
gfx_context.PushClippingRectangle(draw_content_geo);
@@ -492,16 +488,7 @@ void View::DrawContent(nux::GraphicsEngine& gfx_context, bool force_draw)
}
gfx_context.PopClippingRectangle();
- renderer_.DrawInnerCleanup(gfx_context, draw_content_geo, absolute_window_geometry_, window_geometry_);
-
- if (timeline_need_more_draw_ && !timeline_idle_)
- {
- timeline_idle_.reset(new glib::Idle([&] () {
- QueueDraw();
- timeline_idle_.reset();
- return false;
- }));
- }
+ renderer_.DrawInnerCleanup(gfx_context, draw_content_geo, GetAbsoluteGeometry(), GetGeometry());
}
void View::MouseStealsHudButtonFocus()
@@ -769,6 +756,14 @@ nux::Area* View::FindKeyFocusArea(unsigned int event_type,
return search_bar_->text_entry();
}
+nux::Geometry View::GetContentGeometry()
+{
+ nux::Geometry geo(content_geo_);
+ geo.height = current_height_;
+ return geo;
+}
+
+
}
}
diff --git a/hud/HudView.h b/hud/HudView.h
index 982bafe24..ea654d386 100644
--- a/hud/HudView.h
+++ b/hud/HudView.h
@@ -60,7 +60,9 @@ public:
void AboutToShow();
void AboutToHide();
- void SetWindowGeometry(nux::Geometry const& absolute_geo, nux::Geometry const& geo);
+ void SetMonitorOffset(int x, int y);
+
+ nux::Geometry GetContentGeometry();
protected:
virtual Area* FindKeyFocusArea(unsigned int event_type,
@@ -69,7 +71,6 @@ protected:
void SetupViews();
void OnSearchChanged(std::string const& search_string);
- virtual long PostLayoutManagement(long LayoutResult);
private:
void OnMouseButtonDown(int x, int y, unsigned long button, unsigned long key);
@@ -110,14 +111,12 @@ private:
Hud::Queries queries_;
nux::Geometry content_geo_;
OverlayRenderer renderer_;
- nux::Geometry window_geometry_;
- nux::Geometry absolute_window_geometry_;
glib::Source::UniquePtr timeline_idle_;
+ bool timeline_animating_;
guint64 start_time_;
int last_known_height_;
int current_height_;
- bool timeline_need_more_draw_;
int selected_button_;
bool show_embedded_icon_;
bool activated_signal_sent_;
diff --git a/hud/StandaloneHud.cpp b/hud/StandaloneHud.cpp
index 74d9b7b3f..72e9fefbe 100644
--- a/hud/StandaloneHud.cpp
+++ b/hud/StandaloneHud.cpp
@@ -69,7 +69,7 @@ void TestRunner::Init ()
hud_view_ = new unity::hud::View();
- layout->AddView (hud_view_, 0, nux::MINOR_POSITION_TOP);
+ layout->AddView (hud_view_, 1, nux::MINOR_POSITION_TOP);
nux::GetWindowCompositor().SetKeyFocusArea(hud_view_->default_focus());
nux::GetWindowThread()->SetLayout (layout);
@@ -109,9 +109,6 @@ void TestRunner::Init ()
});
hud_service_.RequestQuery("");
-
- hud_view_->SetWindowGeometry(layout->GetAbsoluteGeometry(), layout->GetGeometry());
-
}
void TestRunner::InitWindowThread(nux::NThread* thread, void* InitData)
diff --git a/launcher/AbstractLauncherIcon.h b/launcher/AbstractLauncherIcon.h
index 178796b2e..78252c90e 100644
--- a/launcher/AbstractLauncherIcon.h
+++ b/launcher/AbstractLauncherIcon.h
@@ -93,6 +93,7 @@ public:
DESKTOP,
PLACE,
DEVICE,
+ SPACER,
TRASH,
END
};
@@ -117,10 +118,18 @@ public:
LAST
};
+ enum class Position
+ {
+ BEGIN,
+ FLOATING,
+ END
+ };
+
virtual ~AbstractLauncherIcon() {}
nux::Property<std::string> tooltip_text;
nux::Property<bool> tooltip_enabled;
+ nux::Property<Position> position;
virtual void HideTooltip() = 0;
@@ -158,8 +167,6 @@ public:
virtual const bool WindowVisibleOnViewport() = 0;
- virtual bool IsSpacer() = 0;
-
virtual float PresentUrgency() = 0;
virtual float GetProgress() = 0;
@@ -211,6 +218,11 @@ public:
virtual void UnStick() = 0;
+ static int DefaultPriority(IconType type)
+ {
+ return static_cast<int>(type) * 1000;
+ }
+
sigc::signal<void, int, int, unsigned long> mouse_down;
sigc::signal<void, int, int, unsigned long> mouse_up;
sigc::signal<void, int, int, unsigned long> mouse_click;
@@ -221,6 +233,8 @@ public:
sigc::signal<void, AbstractLauncherIcon::Ptr> remove;
sigc::signal<void, nux::ObjectPtr<nux::View>> tooltip_visible;
sigc::signal<void> visibility_changed;
+ sigc::signal<void> position_saved;
+ sigc::signal<void> position_forgot;
sigc::connection needs_redraw_connection;
sigc::connection on_icon_added_connection;
diff --git a/launcher/BFBLauncherIcon.cpp b/launcher/BFBLauncherIcon.cpp
index 54c05b5ed..d512fbad4 100644
--- a/launcher/BFBLauncherIcon.cpp
+++ b/launcher/BFBLauncherIcon.cpp
@@ -36,6 +36,7 @@ BFBLauncherIcon::BFBLauncherIcon(LauncherHideMode hide_mode)
{
tooltip_text = _("Dash Home");
icon_name = PKGDATADIR"/launcher_bfb.png";
+ position = Position::BEGIN;
SetQuirk(Quirk::VISIBLE, true);
SetQuirk(Quirk::RUNNING, false);
diff --git a/launcher/BamfLauncherIcon.cpp b/launcher/BamfLauncherIcon.cpp
index f088b99d5..f24529f30 100644
--- a/launcher/BamfLauncherIcon.cpp
+++ b/launcher/BamfLauncherIcon.cpp
@@ -74,11 +74,7 @@ BamfLauncherIcon::BamfLauncherIcon(BamfApplication* app)
tooltip_text = BamfName();
icon_name = (icon ? icon.Str() : DEFAULT_ICON);
- if (IsSticky())
- SetQuirk(Quirk::VISIBLE, true);
- else
- SetQuirk(Quirk::VISIBLE, bamf_view_user_visible(bamf_view));
-
+ SetQuirk(Quirk::VISIBLE, bamf_view_user_visible(bamf_view));
SetQuirk(Quirk::ACTIVE, bamf_view_is_active(bamf_view));
SetQuirk(Quirk::RUNNING, bamf_view_is_running(bamf_view));
@@ -95,7 +91,7 @@ BamfLauncherIcon::BamfLauncherIcon(BamfApplication* app)
sig = new glib::Signal<void, BamfView*, BamfView*>(bamf_view, "child-removed",
[&] (BamfView*, BamfView*) { EnsureWindowState(); });
_gsignals.Add(sig);
-
+
sig = new glib::Signal<void, BamfView*, BamfView*>(bamf_view, "child-moved",
[&] (BamfView *, BamfView *) {
EnsureWindowState();
@@ -173,9 +169,12 @@ BamfLauncherIcon::BamfLauncherIcon(BamfApplication* app)
BamfLauncherIcon::~BamfLauncherIcon()
{
- if (_bamf_app)
+ if (_bamf_app.IsType(BAMF_TYPE_APPLICATION))
+ {
+ bamf_view_set_sticky(BAMF_VIEW(_bamf_app.RawPtr()), FALSE);
g_object_set_qdata(G_OBJECT(_bamf_app.RawPtr()),
g_quark_from_static_string("unity-seen"), nullptr);
+ }
}
void BamfLauncherIcon::Remove()
@@ -201,11 +200,6 @@ bool BamfLauncherIcon::IsSticky() const
return bamf_view_is_sticky(BAMF_VIEW(_bamf_app.RawPtr()));
}
-bool BamfLauncherIcon::IsVisible() const
-{
- return GetQuirk(Quirk::VISIBLE);
-}
-
bool BamfLauncherIcon::IsActive() const
{
return GetQuirk(Quirk::ACTIVE);
@@ -235,7 +229,6 @@ void BamfLauncherIcon::ActivateLauncherIcon(ActionArg arg)
wm->Activate(arg.target);
return;
}
-
/* We should check each child to see if there is
* an unmapped (!= minimized) window around and
@@ -638,22 +631,22 @@ std::vector<Window> BamfLauncherIcon::GetFocusableWindows(ActionArg arg, bool &a
GList* children;
BamfView *focusable_child = BAMF_VIEW (bamf_application_get_focusable_child (_bamf_app.RawPtr()));
-
+
if (focusable_child != NULL)
{
Window xid;
-
+
if (BAMF_IS_WINDOW (focusable_child))
xid = bamf_window_get_xid (BAMF_WINDOW(focusable_child));
else if (BAMF_IS_TAB (focusable_child))
{
BamfTab *focusable_tab = BAMF_TAB (focusable_child);
-
+
xid = bamf_tab_get_xid (focusable_tab);
-
+
bamf_tab_raise (focusable_tab);
}
-
+
windows.push_back(xid);
return windows;
}
@@ -662,7 +655,7 @@ std::vector<Window> BamfLauncherIcon::GetFocusableWindows(ActionArg arg, bool &a
if (g_strcmp0 (bamf_application_get_application_type (_bamf_app.RawPtr()), "webapp") == 0)
{
OpenInstanceLauncherIcon(arg);
-
+
return windows;
}
}
@@ -762,13 +755,13 @@ void BamfLauncherIcon::EnsureWindowState()
{
/* BamfTab does not support the monitor interface...so a bit of a nasty hack here. */
xid = bamf_tab_get_xid (static_cast<BamfTab*>(l->data));
-
+
if (WindowManager::Default()->IsWindowOnCurrentDesktop(xid) == false)
continue;
-
+
for (int j = 0; j < max_num_monitors; j++)
monitors[j] = true;
-
+
continue;
}
@@ -939,30 +932,28 @@ void BamfLauncherIcon::Quit()
void BamfLauncherIcon::Stick(bool save)
{
+ SimpleLauncherIcon::Stick(save);
+
if (IsSticky())
return;
- std::string const& desktop_file = DesktopFile();
bamf_view_set_sticky(BAMF_VIEW(_bamf_app.RawPtr()), true);
-
- if (save && !desktop_file.empty())
- FavoriteStore::Instance().AddFavorite(desktop_file, -1);
}
void BamfLauncherIcon::UnStick()
{
+ SimpleLauncherIcon::UnStick();
+
if (!IsSticky())
return;
- std::string const& desktop_file = DesktopFile();
BamfView* view = BAMF_VIEW(_bamf_app.RawPtr());
bamf_view_set_sticky(view, false);
- if (bamf_view_is_closed(view) || !bamf_view_user_visible(view))
- Remove();
+ SetQuirk(Quirk::VISIBLE, bamf_view_user_visible(view));
- if (!desktop_file.empty())
- FavoriteStore::Instance().RemoveFavorite(desktop_file);
+ if (bamf_view_is_closed(view))
+ Remove();
}
void BamfLauncherIcon::ToggleSticky()
@@ -1227,12 +1218,11 @@ std::string BamfLauncherIcon::GetRemoteUri()
{
if (_remote_uri.empty())
{
- const std::string prefix = "application://";
std::string const& desktop_id = GetDesktopID();
if (!desktop_id.empty())
{
- _remote_uri = prefix + desktop_id;
+ _remote_uri = FavoriteStore::URI_PREFIX_APP + desktop_id;
}
}
@@ -1384,32 +1374,25 @@ void BamfLauncherIcon::FillSupportedTypes()
if (desktop_file.empty())
return;
- GKeyFile* key_file = g_key_file_new();
+ std::shared_ptr<GKeyFile> key_file(g_key_file_new(), g_key_file_free);
glib::Error error;
- g_key_file_load_from_file(key_file, desktop_file.c_str(), (GKeyFileFlags) 0, &error);
+ g_key_file_load_from_file(key_file.get(), desktop_file.c_str(), (GKeyFileFlags) 0, &error);
if (error)
- {
- g_key_file_free(key_file);
return;
- }
- char** mimes = g_key_file_get_string_list(key_file, "Desktop Entry", "MimeType", nullptr, nullptr);
+ std::shared_ptr<char*> mimes(g_key_file_get_string_list(key_file.get(), "Desktop Entry", "MimeType", nullptr, nullptr),
+ g_strfreev);
+
if (!mimes)
- {
- g_key_file_free(key_file);
return;
- }
- for (int i = 0; mimes[i]; i++)
+ for (int i = 0; mimes.get()[i]; i++)
{
- unity::glib::String super_type(g_content_type_from_mime_type(mimes[i]));
+ unity::glib::String super_type(g_content_type_from_mime_type(mimes.get()[i]));
_supported_types.insert(super_type.Str());
}
-
- g_key_file_free(key_file);
- g_strfreev(mimes);
}
}
diff --git a/launcher/BamfLauncherIcon.h b/launcher/BamfLauncherIcon.h
index b18a10a38..4ee7bb3f7 100644
--- a/launcher/BamfLauncherIcon.h
+++ b/launcher/BamfLauncherIcon.h
@@ -48,7 +48,6 @@ public:
std::string DesktopFile();
bool IsSticky() const;
- bool IsVisible() const;
bool IsActive() const;
bool IsRunning() const;
bool IsUrgent() const;
diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt
index 28bb87dde..1107e19bc 100644
--- a/launcher/CMakeLists.txt
+++ b/launcher/CMakeLists.txt
@@ -42,6 +42,7 @@ set (LAUNCHER_SOURCES
DevicesSettingsImp.cpp
DndData.cpp
EdgeBarrierController.cpp
+ ExpoLauncherIcon.cpp
FavoriteStore.cpp
FavoriteStoreGSettings.cpp
FavoriteStorePrivate.cpp
diff --git a/launcher/DesktopLauncherIcon.cpp b/launcher/DesktopLauncherIcon.cpp
index 712763060..50ec49624 100644
--- a/launcher/DesktopLauncherIcon.cpp
+++ b/launcher/DesktopLauncherIcon.cpp
@@ -19,6 +19,7 @@
#include "DesktopLauncherIcon.h"
#include "unity-shared/WindowManager.h"
+#include "FavoriteStore.h"
#include <glib/gi18n-lib.h>
@@ -28,17 +29,14 @@ namespace launcher
{
DesktopLauncherIcon::DesktopLauncherIcon()
- : SimpleLauncherIcon(IconType::DESKTOP)
- , show_in_switcher_(true)
+ : SimpleLauncherIcon(IconType::DESKTOP)
+ , show_in_switcher_(true)
{
tooltip_text = _("Show Desktop");
icon_name = "desktop";
SetQuirk(Quirk::VISIBLE, true);
SetQuirk(Quirk::RUNNING, false);
-}
-
-DesktopLauncherIcon::~DesktopLauncherIcon()
-{
+ SetShortcut('d');
}
void
@@ -53,5 +51,20 @@ std::string DesktopLauncherIcon::GetName() const
return "DesktopLauncherIcon";
}
+std::string DesktopLauncherIcon::GetRemoteUri()
+{
+ return FavoriteStore::URI_PREFIX_UNITY + "desktop-icon";
+}
+
+void DesktopLauncherIcon::SetShowInSwitcher(bool show_in_switcher)
+{
+ show_in_switcher_ = show_in_switcher;
+}
+
+bool DesktopLauncherIcon::ShowInSwitcher(bool current)
+{
+ return show_in_switcher_;
+}
+
} // namespace launcher
} // namespace unity
diff --git a/launcher/DesktopLauncherIcon.h b/launcher/DesktopLauncherIcon.h
index de1ee83a8..987ca3df9 100644
--- a/launcher/DesktopLauncherIcon.h
+++ b/launcher/DesktopLauncherIcon.h
@@ -29,24 +29,16 @@ namespace launcher
class DesktopLauncherIcon : public SimpleLauncherIcon
{
-
public:
DesktopLauncherIcon();
- ~DesktopLauncherIcon();
-
- void SetShowInSwitcher(bool show_in_switcher)
- {
- show_in_switcher_ = show_in_switcher;
- }
- bool ShowInSwitcher(bool current)
- {
- return show_in_switcher_;
- }
+ void SetShowInSwitcher(bool show_in_switcher);
+ bool ShowInSwitcher(bool current);
protected:
void ActivateLauncherIcon(ActionArg arg);
std::string GetName() const;
+ std::string GetRemoteUri();
private:
bool show_in_switcher_;
diff --git a/launcher/DeviceLauncherSection.cpp b/launcher/DeviceLauncherSection.cpp
index b618f0cb9..b46e34f7c 100644
--- a/launcher/DeviceLauncherSection.cpp
+++ b/launcher/DeviceLauncherSection.cpp
@@ -38,10 +38,7 @@ DeviceLauncherSection::DeviceLauncherSection(AbstractVolumeMonitorWrapper::Ptr v
monitor_->volume_added.connect(sigc::mem_fun(this, &DeviceLauncherSection::OnVolumeAdded));
monitor_->volume_removed.connect(sigc::mem_fun(this, &DeviceLauncherSection::OnVolumeRemoved));
- device_populate_idle_.Run([this] () {
- PopulateEntries();
- return false;
- });
+ PopulateEntries();
}
void DeviceLauncherSection::PopulateEntries()
@@ -60,11 +57,11 @@ void DeviceLauncherSection::TryToCreateAndAddIcon(glib::Object<GVolume> volume)
if (map_.find(volume) != map_.end())
return;
- VolumeLauncherIcon::Ptr icon(new VolumeLauncherIcon(std::make_shared<VolumeImp>(volume, file_manager_opener_, device_notification_display_),
- devices_settings_));
+ auto vol = std::make_shared<VolumeImp>(volume, file_manager_opener_, device_notification_display_);
+ VolumeLauncherIcon::Ptr icon(new VolumeLauncherIcon(vol, devices_settings_));
map_[volume] = icon;
- IconAdded.emit(icon);
+ icon_added.emit(icon);
}
void DeviceLauncherSection::OnVolumeRemoved(glib::Object<GVolume> const& volume)
@@ -76,5 +73,15 @@ void DeviceLauncherSection::OnVolumeRemoved(glib::Object<GVolume> const& volume)
map_.erase(volume_it);
}
+std::vector<VolumeLauncherIcon::Ptr> DeviceLauncherSection::GetIcons() const
+{
+ std::vector<VolumeLauncherIcon::Ptr> icons;
+
+ for (auto const& it : map_)
+ icons.push_back(it.second);
+
+ return icons;
+}
+
}
}
diff --git a/launcher/DeviceLauncherSection.h b/launcher/DeviceLauncherSection.h
index 551fa4a2a..9df9148e5 100644
--- a/launcher/DeviceLauncherSection.h
+++ b/launcher/DeviceLauncherSection.h
@@ -23,8 +23,6 @@
#include <map>
#include <memory>
-#include <UnityCore/GLibSource.h>
-
#include "AbstractVolumeMonitorWrapper.h"
#include "DevicesSettings.h"
#include "DeviceNotificationDisplay.h"
@@ -42,7 +40,9 @@ public:
DeviceLauncherSection(AbstractVolumeMonitorWrapper::Ptr volume_monitor,
DevicesSettings::Ptr devices_settings);
- sigc::signal<void, AbstractLauncherIcon::Ptr> IconAdded;
+ std::vector<VolumeLauncherIcon::Ptr> GetIcons() const;
+
+ sigc::signal<void, AbstractLauncherIcon::Ptr> icon_added;
private:
void PopulateEntries();
@@ -55,8 +55,6 @@ private:
DevicesSettings::Ptr devices_settings_;
FileManagerOpener::Ptr file_manager_opener_;
DeviceNotificationDisplay::Ptr device_notification_display_;
-
- glib::Idle device_populate_idle_;
};
}
diff --git a/launcher/DndData.cpp b/launcher/DndData.cpp
index 63cfd485e..9482e45f5 100644
--- a/launcher/DndData.cpp
+++ b/launcher/DndData.cpp
@@ -27,12 +27,12 @@
#include <UnityCore/GLibWrapper.h>
namespace unity {
-
-void DndData::Fill(char* uris)
-{
+
+void DndData::Fill(const char* uris)
+{
Reset();
-
- char* pch = strtok (uris, "\r\n");
+
+ const char* pch = strtok (const_cast<char*>(uris), "\r\n");
while (pch)
{
glib::String content_type(g_content_type_guess(pch,
diff --git a/launcher/DndData.h b/launcher/DndData.h
index e714d8bcf..48c5014bc 100644
--- a/launcher/DndData.h
+++ b/launcher/DndData.h
@@ -32,7 +32,7 @@ public:
/**
* Fills the object given a list of uris.
**/
- void Fill(char* uris);
+ void Fill(const char* uris);
/**
* Resets the object. Call this function when no longer need data
diff --git a/launcher/ExpoLauncherIcon.cpp b/launcher/ExpoLauncherIcon.cpp
new file mode 100644
index 000000000..6c15ca1e0
--- /dev/null
+++ b/launcher/ExpoLauncherIcon.cpp
@@ -0,0 +1,64 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+ * Copyright (C) 2012 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 "ExpoLauncherIcon.h"
+#include "unity-shared/WindowManager.h"
+#include "FavoriteStore.h"
+
+#include <glib/gi18n-lib.h>
+
+namespace unity
+{
+namespace launcher
+{
+
+ExpoLauncherIcon::ExpoLauncherIcon()
+ : SimpleLauncherIcon(IconType::EXPO)
+{
+ tooltip_text = _("Workspace Switcher");
+ icon_name = "workspace-switcher";
+ SetQuirk(Quirk::VISIBLE, false);
+ SetQuirk(Quirk::RUNNING, false);
+ SetShortcut('s');
+}
+
+void ExpoLauncherIcon::ActivateLauncherIcon(ActionArg arg)
+{
+ SimpleLauncherIcon::ActivateLauncherIcon(arg);
+ WindowManager::Default()->InitiateExpo();
+}
+
+void ExpoLauncherIcon::Stick(bool save)
+{
+ SimpleLauncherIcon::Stick(save);
+ SetQuirk(Quirk::VISIBLE, (WindowManager::Default()->WorkspaceCount() > 1));
+}
+
+std::string ExpoLauncherIcon::GetName() const
+{
+ return "ExpoLauncherIcon";
+}
+
+std::string ExpoLauncherIcon::GetRemoteUri()
+{
+ return FavoriteStore::URI_PREFIX_UNITY + "expo-icon";
+}
+
+} // namespace launcher
+} // namespace unity
diff --git a/launcher/ExpoLauncherIcon.h b/launcher/ExpoLauncherIcon.h
new file mode 100644
index 000000000..b4a335675
--- /dev/null
+++ b/launcher/ExpoLauncherIcon.h
@@ -0,0 +1,45 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+ * Copyright (C) 2012 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 EXPO_LAUNCHER_ICON_H
+#define EXPO_LAUNCHER_ICON_H
+
+#include "SimpleLauncherIcon.h"
+
+namespace unity
+{
+namespace launcher
+{
+
+class ExpoLauncherIcon : public SimpleLauncherIcon
+{
+public:
+ ExpoLauncherIcon();
+ void Stick(bool save);
+
+protected:
+ void ActivateLauncherIcon(ActionArg arg);
+ std::string GetName() const;
+ std::string GetRemoteUri();
+};
+
+}
+}
+
+#endif // EXPO_LAUNCHER_ICON_H
diff --git a/launcher/FavoriteStore.cpp b/launcher/FavoriteStore.cpp
index aca71f8e3..8977da5ac 100644
--- a/launcher/FavoriteStore.cpp
+++ b/launcher/FavoriteStore.cpp
@@ -1,6 +1,6 @@
// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
/*
-* Copyright (C) 2010 Canonical Ltd
+* Copyright (C) 2010-2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
@@ -15,19 +15,29 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
+* Marco Trevisan <marco.trevisan@canonical.com>
*/
#include <NuxCore/Logger.h>
-#include "FavoriteStoreGSettings.h"
+#include <glib.h>
+
+#include "FavoriteStore.h"
+#include "FavoriteStorePrivate.h"
namespace unity
{
namespace
{
- nux::logging::Logger logger("unity.favouritestore");
- FavoriteStore* favoritestore_instance = nullptr;
+nux::logging::Logger logger("unity.favorite.store");
+FavoriteStore* favoritestore_instance = nullptr;
+const std::string PREFIX_SEPARATOR = "://";
}
+const std::string FavoriteStore::URI_PREFIX_APP = "application://";
+const std::string FavoriteStore::URI_PREFIX_FILE = "file://";
+const std::string FavoriteStore::URI_PREFIX_DEVICE = "device://";
+const std::string FavoriteStore::URI_PREFIX_UNITY = "unity://";
+
FavoriteStore::FavoriteStore()
{
if (favoritestore_instance)
@@ -56,4 +66,83 @@ FavoriteStore& FavoriteStore::Instance()
return *favoritestore_instance;
}
+bool FavoriteStore::IsValidFavoriteUri(std::string const& uri)
+{
+ if (uri.empty())
+ return false;
+
+ if (uri.find(URI_PREFIX_APP) == 0 || uri.find(URI_PREFIX_FILE) == 0)
+ {
+ return internal::impl::IsDesktopFilePath(uri);
+ }
+ else if (uri.find(URI_PREFIX_DEVICE) == 0)
+ {
+ return uri.length() > URI_PREFIX_DEVICE.length();
+ }
+ else if (uri.find(URI_PREFIX_UNITY) == 0)
+ {
+ return uri.length() > URI_PREFIX_UNITY.length();
+ }
+
+ return false;
+}
+
+std::string FavoriteStore::ParseFavoriteFromUri(std::string const& uri) const
+{
+ if (uri.empty())
+ return "";
+
+ std::string fav = uri;
+ auto prefix_pos = fav.find(PREFIX_SEPARATOR);
+
+ if (prefix_pos == std::string::npos)
+ {
+ // We assume that favorites with no prefix, but with a .desktop suffix are applications
+ if (internal::impl::IsDesktopFilePath(uri))
+ {
+ fav = URI_PREFIX_APP + fav;
+ prefix_pos = URI_PREFIX_APP.length();
+ }
+ }
+ else
+ {
+ prefix_pos += PREFIX_SEPARATOR.length();
+ }
+
+ // Matches application://desktop-id.desktop or application:///path/to/file.desktop
+ if (fav.find(URI_PREFIX_APP) == 0 || fav.find(URI_PREFIX_FILE) == 0)
+ {
+ std::string const& fav_value = fav.substr(prefix_pos);
+
+ if (fav_value.empty())
+ {
+ LOG_WARNING(logger) << "Unable to load Favorite for uri '" << fav << "'";
+ return "";
+ }
+
+ if (fav_value[0] == '/' || fav.find(URI_PREFIX_FILE) == 0)
+ {
+ if (g_file_test(fav_value.c_str(), G_FILE_TEST_EXISTS))
+ {
+ return fav;
+ }
+ else
+ {
+ LOG_WARNING(logger) << "Unable to load desktop file: " << fav_value;
+ }
+ }
+ else
+ {
+ return URI_PREFIX_APP + fav_value;
+ }
+ }
+ else if (IsValidFavoriteUri(fav))
+ {
+ return fav;
+ }
+
+ LOG_WARNING(logger) << "Unable to load Favorite for uri '" << fav << "'";
+ return "";
+}
+
}
diff --git a/launcher/FavoriteStore.h b/launcher/FavoriteStore.h
index 95675b29e..b31c989ad 100644
--- a/launcher/FavoriteStore.h
+++ b/launcher/FavoriteStore.h
@@ -1,6 +1,6 @@
// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
/*
-* Copyright (C) 2010 Canonical Ltd
+* Copyright (C) 2010-2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
@@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
+* Marco Trevisan <marco.trevisan@canonical.com>
*/
#ifndef UNITY_FAVORITE_STORE_H
@@ -42,26 +43,38 @@ public:
static FavoriteStore& Instance();
- virtual FavoriteList const& GetFavorites() = 0;
+ virtual FavoriteList const& GetFavorites() const = 0;
// These will NOT emit the relevant signals, so bare that in mind
// i.e. don't hope that you can add stuff and hook the view up to
// favorite_added events to update the view. The signals only emit if
// there has been a change on the GSettings object from an external
// source
- virtual void AddFavorite(std::string const& desktop_path, int position) = 0;
- virtual void RemoveFavorite(std::string const& desktop_path) = 0;
- virtual void MoveFavorite(std::string const& desktop_path, int position) = 0;
- virtual void SetFavorites(FavoriteList const& desktop_paths) = 0;
+ virtual void AddFavorite(std::string const& icon_uri, int position) = 0;
+ virtual void RemoveFavorite(std::string const& icon_uri) = 0;
+ virtual void MoveFavorite(std::string const& icon_uri, int position) = 0;
+ virtual bool IsFavorite(std::string const& icon_uri) const = 0;
+ virtual int FavoritePosition(std::string const& icon_uri) const = 0;
+ virtual void SetFavorites(FavoriteList const& icon_uris) = 0;
// Signals
// These only emit if something has changed the GSettings object externally
- //desktop_path, position, before/after
+ //icon_uri, position, before/after
sigc::signal<void, std::string const&, std::string const&, bool> favorite_added;
- //desktop_path
+ //icon_uri
sigc::signal<void, std::string const&> favorite_removed;
sigc::signal<void> reordered;
+
+ static const std::string URI_PREFIX_APP;
+ static const std::string URI_PREFIX_FILE;
+ static const std::string URI_PREFIX_DEVICE;
+ static const std::string URI_PREFIX_UNITY;
+
+ static bool IsValidFavoriteUri(std::string const& uri);
+
+protected:
+ std::string ParseFavoriteFromUri(std::string const& uri) const;
};
}
diff --git a/launcher/FavoriteStoreGSettings.cpp b/launcher/FavoriteStoreGSettings.cpp
index 087e9bcea..102ba2ff2 100644
--- a/launcher/FavoriteStoreGSettings.cpp
+++ b/launcher/FavoriteStoreGSettings.cpp
@@ -1,6 +1,6 @@
// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
/*
-* Copyright (C) 2010 Canonical Ltd
+* Copyright (C) 2010-2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
@@ -15,9 +15,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
+* Marco Trevisan <marco.trevisan@canonical.com>
*/
-#include <gio/gdesktopappinfo.h>
#include <NuxCore/Logger.h>
#include <UnityCore/DesktopUtilities.h>
@@ -40,7 +40,7 @@ namespace internal
namespace
{
-nux::logging::Logger logger("unity.favorites");
+nux::logging::Logger logger("unity.favorite.store.gsettings");
const std::string SETTINGS_NAME = "com.canonical.Unity.Launcher";
const std::string SETTINGS_KEY = "favorites";
}
@@ -59,117 +59,89 @@ FavoriteStoreGSettings::FavoriteStoreGSettings()
void FavoriteStoreGSettings::Refresh()
{
- FillList(favorites_);
+ FillList();
}
-void FavoriteStoreGSettings::FillList(FavoriteList& list)
+void FavoriteStoreGSettings::FillList()
{
- list.clear();
+ favorites_.clear();
+ std::shared_ptr<gchar*> favs(g_settings_get_strv(settings_, SETTINGS_KEY.c_str()));
- gchar** favs = g_settings_get_strv(settings_, SETTINGS_KEY.c_str());
-
- for (int i = 0; favs[i] != NULL; ++i)
+ for (int i = 0; favs.get()[i]; ++i)
{
- // We will be storing either full /path/to/desktop/files or foo.desktop id's
- if (favs[i][0] == '/')
- {
- if (g_file_test(favs[i], G_FILE_TEST_EXISTS))
- {
- list.push_back(favs[i]);
- }
- else
- {
- LOG_WARNING(logger) << "Unable to load desktop file: "
- << favs[i];
- }
- }
- else
- {
- glib::Object<GDesktopAppInfo> info(g_desktop_app_info_new(favs[i]));
- const char* filename = 0;
- if (info)
- filename = g_desktop_app_info_get_filename(info);
-
- if (filename)
- {
- list.push_back(filename);
- }
- else
- {
- LOG_WARNING(logger) << "Unable to load GDesktopAppInfo for '" << favs[i] << "'";
- }
- }
- }
+ std::string const& fav = ParseFavoriteFromUri(favs.get()[i]);
- g_strfreev(favs);
+ if (!fav.empty())
+ favorites_.push_back(fav);
+ }
}
-FavoriteList const& FavoriteStoreGSettings::GetFavorites()
+FavoriteList const& FavoriteStoreGSettings::GetFavorites() const
{
return favorites_;
}
-void FavoriteStoreGSettings::AddFavorite(std::string const& desktop_path, int position)
+void FavoriteStoreGSettings::AddFavorite(std::string const& icon_uri, int position)
{
- int size = favorites_.size();
- if (desktop_path.empty() || position > size)
+ std::string const& fav = ParseFavoriteFromUri(icon_uri);
+
+ if (fav.empty() || position > static_cast<int>(favorites_.size()))
return;
if (position < 0)
{
// It goes on the end.
- favorites_.push_back(desktop_path);
+ favorites_.push_back(fav);
}
else
{
FavoriteList::iterator pos = favorites_.begin();
std::advance(pos, position);
- favorites_.insert(pos, desktop_path);
+ favorites_.insert(pos, fav);
}
SaveFavorites(favorites_);
Refresh();
}
-void FavoriteStoreGSettings::RemoveFavorite(std::string const& desktop_path)
+void FavoriteStoreGSettings::RemoveFavorite(std::string const& icon_uri)
{
- if (desktop_path.empty() || desktop_path[0] != '/')
+ std::string const& fav = ParseFavoriteFromUri(icon_uri);
+
+ if (fav.empty())
return;
- FavoriteList::iterator pos = std::find(favorites_.begin(), favorites_.end(), desktop_path);
+ FavoriteList::iterator pos = std::find(favorites_.begin(), favorites_.end(), fav);
if (pos == favorites_.end())
- {
return;
- }
favorites_.erase(pos);
SaveFavorites(favorites_);
Refresh();
}
-void FavoriteStoreGSettings::MoveFavorite(std::string const& desktop_path, int position)
+void FavoriteStoreGSettings::MoveFavorite(std::string const& icon_uri, int position)
{
- int size = favorites_.size();
- if (desktop_path.empty() || position > size)
+ std::string const& fav = ParseFavoriteFromUri(icon_uri);
+
+ if (fav.empty() || position > static_cast<int>(favorites_.size()))
return;
- FavoriteList::iterator pos = std::find(favorites_.begin(), favorites_.end(), desktop_path);
+ FavoriteList::iterator pos = std::find(favorites_.begin(), favorites_.end(), fav);
if (pos == favorites_.end())
- {
return;
- }
favorites_.erase(pos);
if (position < 0)
{
// It goes on the end.
- favorites_.push_back(desktop_path);
+ favorites_.push_back(fav);
}
else
{
FavoriteList::iterator insert_pos = favorites_.begin();
std::advance(insert_pos, position);
- favorites_.insert(insert_pos, desktop_path);
+ favorites_.insert(insert_pos, fav);
}
SaveFavorites(favorites_);
@@ -186,26 +158,34 @@ void FavoriteStoreGSettings::SaveFavorites(FavoriteList const& favorites, bool i
{
const int size = favorites.size();
const char* favs[size + 1];
- favs[size] = NULL;
- int index = 0;
// Since we don't always save the full path, we store the values we are
// actually going to save in a different list.
- auto system_dirs = DesktopUtilities::GetDataDirectories();
FavoriteList values;
- for (FavoriteList::const_iterator i = favorites.begin(), end = favorites.end();
- i != end; ++i, ++index)
+ int index = 0;
+
+ for (auto const& fav_uri : favorites)
{
+ std::string const& fav = ParseFavoriteFromUri(fav_uri);
+ if (fav.empty())
+ {
+ LOG_WARNING(logger) << "Impossible to add favorite '" << fav_uri << "' to store";
+ continue;
+ }
+
// By using insert we get the iterator to the newly inserted string value.
// That way we can use the c_str() method to access the const char* for
// the string that we are going to save. This way we know that the pointer
// is valid for the lifetime of the favs array usage in the method call to
// set the settings, and that we aren't referencing a temporary.
- std::string const& desktop_id = DesktopUtilities::GetDesktopID(system_dirs, *i);
- FavoriteList::iterator iter = values.insert(values.end(), desktop_id);
+ FavoriteList::iterator iter = values.insert(values.end(), fav);
favs[index] = iter->c_str();
+ ++index;
}
+ for (int i = index; i <= size; ++i)
+ favs[i] = nullptr;
+
ignore_signals_ = ignore;
if (!g_settings_set_strv(settings_, SETTINGS_KEY.c_str(), favs))
{
@@ -220,7 +200,7 @@ void FavoriteStoreGSettings::Changed()
return;
FavoriteList old(favorites_);
- FillList(favorites_);
+ FillList();
auto newbies = impl::GetNewbies(old, favorites_);
@@ -243,7 +223,26 @@ void FavoriteStoreGSettings::Changed()
if (impl::NeedToBeReordered(old, favorites_))
reordered.emit();
+}
+
+bool FavoriteStoreGSettings::IsFavorite(std::string const& icon_uri) const
+{
+ return std::find(favorites_.begin(), favorites_.end(), icon_uri) != favorites_.end();
+}
+
+int FavoriteStoreGSettings::FavoritePosition(std::string const& icon_uri) const
+{
+ int index = 0;
+
+ for (auto const& fav : favorites_)
+ {
+ if (fav == icon_uri)
+ return index;
+
+ ++index;
+ }
+ return -1;
}
} // namespace internal
diff --git a/launcher/FavoriteStoreGSettings.h b/launcher/FavoriteStoreGSettings.h
index 5fd084b90..2250fef82 100644
--- a/launcher/FavoriteStoreGSettings.h
+++ b/launcher/FavoriteStoreGSettings.h
@@ -1,6 +1,6 @@
// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
/*
-* Copyright (C) 2010 Canonical Ltd
+* Copyright (C) 2010-2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
@@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
+* Marco Trevisan <marco.trevisan@canonical.com>
*/
#ifndef FAVORITE_STORE_GSETTINGS_H
@@ -38,17 +39,19 @@ class FavoriteStoreGSettings : public FavoriteStore
public:
FavoriteStoreGSettings();
- virtual FavoriteList const& GetFavorites();
+ virtual FavoriteList const& GetFavorites() const;
virtual void AddFavorite(std::string const& desktop_path, int position);
virtual void RemoveFavorite(std::string const& desktop_path);
virtual void MoveFavorite(std::string const& desktop_path, int position);
- void SaveFavorites(FavoriteList const& favorites, bool ignore = true);
+ virtual bool IsFavorite(std::string const& icon_uri) const;
+ virtual int FavoritePosition(std::string const& icon_uri) const;
virtual void SetFavorites(FavoriteList const& desktop_paths);
+ void SaveFavorites(FavoriteList const& favorites, bool ignore = true);
private:
void Refresh();
void Changed();
- void FillList(FavoriteList& list);
+ void FillList();
FavoriteList favorites_;
bool ignore_signals_;
diff --git a/launcher/FavoriteStorePrivate.cpp b/launcher/FavoriteStorePrivate.cpp
index 5478fa0d5..b4d1d94f4 100644
--- a/launcher/FavoriteStorePrivate.cpp
+++ b/launcher/FavoriteStorePrivate.cpp
@@ -124,6 +124,20 @@ bool NeedToBeReordered(std::list<std::string> const& old, std::list<std::string>
return false;
}
+bool IsDesktopFilePath(std::string const& path)
+{
+ static const std::string desktop_ext = ".desktop";
+ auto path_len = path.length();
+ auto desktop_length = desktop_ext.length();
+
+ if (path_len > desktop_length)
+ {
+ return path.compare(path_len - desktop_length, desktop_length, desktop_ext) == 0;
+ }
+
+ return false;
+}
+
} // namespace impl
} // namespace internal
diff --git a/launcher/FavoriteStorePrivate.h b/launcher/FavoriteStorePrivate.h
index 196751452..3edad2357 100644
--- a/launcher/FavoriteStorePrivate.h
+++ b/launcher/FavoriteStorePrivate.h
@@ -32,13 +32,15 @@ namespace impl
std::vector<std::string> GetNewbies(std::list<std::string> const& old, std::list<std::string> const& fresh);
-void GetSignalAddedInfo(std::list<std::string> const& favs, std::vector<std::string> const& newbies,
+void GetSignalAddedInfo(std::list<std::string> const& favs, std::vector<std::string> const& newbies,
std::string const& path, std::string& position, bool& before);
std::vector<std::string> GetRemoved(std::list<std::string> const& old, std::list<std::string> const& fresh);
bool NeedToBeReordered(std::list<std::string> const& old, std::list<std::string> const& fresh);
+bool IsDesktopFilePath(std::string const& path);
+
} // namespace impl
} // namespace internal
diff --git a/launcher/HudLauncherIcon.cpp b/launcher/HudLauncherIcon.cpp
index 2c24957a0..9f617d475 100644
--- a/launcher/HudLauncherIcon.cpp
+++ b/launcher/HudLauncherIcon.cpp
@@ -45,6 +45,7 @@ HudLauncherIcon::HudLauncherIcon(LauncherHideMode hide_mode)
{
tooltip_text = _("HUD");
icon_name = PKGDATADIR"/launcher_bfb.png";
+ position = Position::BEGIN;
SetQuirk(Quirk::VISIBLE, false);
SetQuirk(Quirk::RUNNING, false);
SetQuirk(Quirk::ACTIVE, true);
@@ -121,7 +122,7 @@ nux::Color HudLauncherIcon::GlowColor()
void HudLauncherIcon::ActivateLauncherIcon(ActionArg arg)
{
- if (GetQuirk(Quirk::VISIBLE))
+ if (IsVisible())
{
ubus_manager_.SendMessage(UBUS_HUD_CLOSE_REQUEST);
}
diff --git a/launcher/Launcher.cpp b/launcher/Launcher.cpp
index 742759240..fed7da3b1 100644
--- a/launcher/Launcher.cpp
+++ b/launcher/Launcher.cpp
@@ -54,6 +54,7 @@
#include <UnityCore/GLibWrapper.h>
#include <UnityCore/Variant.h>
+#include <boost/algorithm/string.hpp>
#include <sigc++/sigc++.h>
namespace unity
@@ -106,6 +107,7 @@ Launcher::Launcher(nux::BaseWindow* parent,
nux::ObjectPtr<DNDCollectionWindow> const& collection_window,
NUX_FILE_LINE_DECL)
: View(NUX_FILE_LINE_PARAM)
+ , display(nux::GetGraphicsDisplay()->GetX11Display())
, monitor(0)
, _parent(parent)
, _active_quicklist(nullptr)
@@ -463,9 +465,8 @@ bool Launcher::AnimationInProgress() const
return true;
// animations happening on specific icons
- LauncherModel::iterator it;
- for (it = _model->begin(); it != _model->end(); ++it)
- if (IconNeedsAnimation(*it, current))
+ for (auto const &icon : *_model)
+ if (IconNeedsAnimation(icon, current))
return true;
return false;
@@ -496,10 +497,10 @@ float Launcher::IconVisibleProgress(AbstractLauncherIcon::Ptr icon, struct times
if (icon->GetIconType() == AbstractLauncherIcon::IconType::HUD)
{
- return (icon->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE)) ? 1.0f : 0.0f;
+ return icon->IsVisible() ? 1.0f : 0.0f;
}
- if (icon->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE))
+ if (icon->IsVisible())
{
struct timespec icon_visible_time = icon->GetQuirkTime(AbstractLauncherIcon::Quirk::VISIBLE);
int enter_ms = unity::TimeUtil::TimeDelta(&current, &icon_visible_time);
@@ -892,8 +893,11 @@ void Launcher::FillRenderArg(AbstractLauncherIcon::Ptr icon,
if (GetActionState() == ACTION_DRAG_ICON ||
(_drag_window && _drag_window->Animating()) ||
- icon->IsSpacer())
+ icon->GetIconType() == AbstractLauncherIcon::IconType::SPACER)
+ {
arg.skip = true;
+ }
+
size_modifier *= DragThresholdProgress(current);
}
@@ -933,11 +937,12 @@ void Launcher::FillRenderArg(AbstractLauncherIcon::Ptr icon,
icon->SetCenter(nux::Point3(roundf(center.x), roundf(center.y), roundf(center.z)), monitor, parent_abs_geo);
- // FIXME: this is a hack, we should have a look why SetAnimationTarget is necessary in SetAnimationTarget
- // we should ideally just need it at start to set the target
+ // FIXME: this is a hack, to avoid that we set the target to the end of the icon
if (!_initial_drag_animation && icon == _drag_icon && _drag_window && _drag_window->Animating())
- _drag_window->SetAnimationTarget(static_cast<int>(_drag_icon->GetCenter(monitor).x),
- static_cast<int>(_drag_icon->GetCenter(monitor).y));
+ {
+ auto const& icon_center = _drag_icon->GetCenter(monitor);
+ _drag_window->SetAnimationTarget(icon_center.x, icon_center.y);
+ }
center.y += (half_size * size_modifier) + spacing; // move to end
}
@@ -954,10 +959,10 @@ float Launcher::DragLimiter(float x)
nux::Color FullySaturateColor (nux::Color color)
{
float max = std::max<float>(color.red, std::max<float>(color.green, color.blue));
+
if (max > 0.0f)
- {
color = color * (1.0f / max);
- }
+
return color;
}
@@ -1397,8 +1402,8 @@ void Launcher::DndTimeoutSetup()
void Launcher::OnPluginStateChanged()
{
- _hide_machine.SetQuirk (LauncherHideMachine::EXPO_ACTIVE, WindowManager::Default ()->IsExpoActive ());
- _hide_machine.SetQuirk (LauncherHideMachine::SCALE_ACTIVE, WindowManager::Default ()->IsScaleActive ());
+ _hide_machine.SetQuirk(LauncherHideMachine::EXPO_ACTIVE, WindowManager::Default()->IsExpoActive());
+ _hide_machine.SetQuirk(LauncherHideMachine::SCALE_ACTIVE, WindowManager::Default()->IsScaleActive());
}
LauncherHideMode Launcher::GetHideMode() const
@@ -1670,11 +1675,6 @@ LauncherModel::Ptr Launcher::GetModel() const
return _model;
}
-void Launcher::SetDevicesSettings(DevicesSettings::Ptr devices_settings)
-{
- devices_settings_ = devices_settings;
-}
-
void Launcher::EnsureIconOnScreen(AbstractLauncherIcon::Ptr selection)
{
nux::Geometry const& geo = GetGeometry();
@@ -1682,7 +1682,7 @@ void Launcher::EnsureIconOnScreen(AbstractLauncherIcon::Ptr selection)
int natural_y = 0;
for (auto icon : *_model)
{
- if (!icon->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE) || !icon->IsVisibleOnMonitor(monitor))
+ if (!icon->IsVisible() || !icon->IsVisibleOnMonitor(monitor))
continue;
if (icon == selection)
@@ -1954,7 +1954,7 @@ void Launcher::OnDragWindowAnimCompleted()
EnsureAnimation();
}
-bool Launcher::StartIconDragTimeout()
+bool Launcher::StartIconDragTimeout(int x, int y)
{
// if we are still waiting…
if (GetActionState() == ACTION_NONE)
@@ -1965,7 +1965,7 @@ bool Launcher::StartIconDragTimeout()
_icon_under_mouse = nullptr;
}
_initial_drag_animation = true;
- StartIconDragRequest(GetMouseX(), GetMouseY());
+ StartIconDragRequest(x, y);
}
return false;
@@ -1973,26 +1973,27 @@ bool Launcher::StartIconDragTimeout()
void Launcher::StartIconDragRequest(int x, int y)
{
- nux::Geometry geo = GetAbsoluteGeometry();
- AbstractLauncherIcon::Ptr drag_icon = MouseIconIntersection((int)(GetGeometry().width / 2.0f), y);
-
- x += geo.x;
- y += geo.y;
-
+ nux::Geometry const& abs_geo = GetAbsoluteGeometry();
+ AbstractLauncherIcon::Ptr drag_icon = MouseIconIntersection(abs_geo.width / 2.0f, y);
// FIXME: nux doesn't give nux::GetEventButton (button_flags) there, relying
// on an internal Launcher property then
- bool can_drag = (_model->IconHasSister(drag_icon) || drag_icon->GetIconType() == AbstractLauncherIcon::IconType::DEVICE);
- if (drag_icon && _last_button_press == 1 && can_drag)
+ if (drag_icon && _last_button_press == 1 && drag_icon->position() == AbstractLauncherIcon::Position::FLOATING)
{
+ auto const& icon_center = drag_icon->GetCenter(monitor);
+ x += abs_geo.x;
+ y += abs_geo.y;
+
SetActionState(ACTION_DRAG_ICON);
StartIconDrag(drag_icon);
- UpdateDragWindowPosition(drag_icon->GetCenter(monitor).x, drag_icon->GetCenter(monitor).y);
+ UpdateDragWindowPosition(icon_center.x, icon_center.y);
+
if (_initial_drag_animation)
{
_drag_window->SetAnimationTarget(x, y);
- _drag_window->StartAnimation();
+ _drag_window->StartQuickAnimation();
}
+
EnsureAnimation();
}
else
@@ -2009,6 +2010,7 @@ void Launcher::StartIconDrag(AbstractLauncherIcon::Ptr icon)
_hide_machine.SetQuirk(LauncherHideMachine::INTERNAL_DND_ACTIVE, true);
_drag_icon = icon;
+ _drag_icon_position = _model->IconIndex(icon);
HideDragWindow();
_offscreen_drag_texture = nux::GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(_icon_size, _icon_size, 1, nux::BITFMT_R8G8B8A8);
@@ -2032,15 +2034,20 @@ void Launcher::EndIconDrag()
{
hovered_icon->SetQuirk(AbstractLauncherIcon::Quirk::PULSE_ONCE, true);
- launcher_removerequest.emit(_drag_icon);
+ remove_request.emit(_drag_icon);
HideDragWindow();
EnsureAnimation();
}
else
{
- if (!_drag_window->Cancelled())
+ if (!_drag_window->Cancelled() && _model->IconIndex(_drag_icon) != _drag_icon_position)
+ {
+ if (_drag_icon->GetIconType() == AbstractLauncherIcon::IconType::DEVICE)
+ _drag_icon->Stick(false);
+
_model->Save();
+ }
if (_drag_window->on_anim_completed.connected())
_drag_window->on_anim_completed.disconnect();
@@ -2048,7 +2055,7 @@ void Launcher::EndIconDrag()
auto const& icon_center = _drag_icon->GetCenter(monitor);
_drag_window->SetAnimationTarget(icon_center.x, icon_center.y),
- _drag_window->StartAnimation();
+ _drag_window->StartQuickAnimation();
}
}
@@ -2104,15 +2111,11 @@ void Launcher::UpdateDragWindowPosition(int x, int y)
return;
auto const& launcher_geo = GetGeometry();
- auto hovered_icon = MouseIconIntersection((launcher_geo.x + launcher_geo.width) / 2.0, y - GetAbsoluteY());
+ auto const& hovered_icon = MouseIconIntersection((launcher_geo.x + launcher_geo.width) / 2.0, y - GetAbsoluteY());
struct timespec current;
clock_gettime(CLOCK_MONOTONIC, &current);
float progress = DragThresholdProgress(current);
- // Icons of different types can't be mixed, so let's avoid this.
- if (hovered_icon && hovered_icon->GetIconType() != _drag_icon->GetIconType())
- hovered_icon = nullptr;
-
if (hovered_icon && _drag_icon != hovered_icon)
{
if (progress >= 1.0f)
@@ -2131,12 +2134,8 @@ void Launcher::UpdateDragWindowPosition(int x, int y)
{
auto const& icon = *it;
- if (!icon->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE) ||
- !icon->IsVisibleOnMonitor(monitor) ||
- icon->GetIconType() != _drag_icon->GetIconType())
- {
+ if (!icon->IsVisible() || !icon->IsVisibleOnMonitor(monitor))
continue;
- }
if (y >= icon->GetCenter(monitor).y)
{
@@ -2217,7 +2216,9 @@ void Launcher::RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_
}
else
{
- StartIconDragRequest(x, y);
+ // We we can safely start the icon drag, from the original mouse-down position
+ sources_.Remove(START_DRAGICON_DURATION);
+ StartIconDragRequest(x - _dnd_delta_x, y - _dnd_delta_y);
}
}
else if (GetActionState() == ACTION_DRAG_LAUNCHER)
@@ -2227,7 +2228,7 @@ void Launcher::RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_
}
else if (GetActionState() == ACTION_DRAG_ICON)
{
- nux::Geometry geo = GetAbsoluteGeometry();
+ nux::Geometry const& geo = GetAbsoluteGeometry();
UpdateDragWindowPosition(geo.x + x, geo.y + y);
}
@@ -2406,7 +2407,7 @@ void Launcher::MouseDownLogic(int x, int y, unsigned long button_flags, unsigned
{
_icon_mouse_down = launcher_icon;
// if MouseUp after the time ended -> it's an icon drag, otherwise, it's starting an app
- auto cb_func = sigc::mem_fun(this, &Launcher::StartIconDragTimeout);
+ auto cb_func = sigc::bind(sigc::mem_fun(this, &Launcher::StartIconDragTimeout), x, y);
sources_.AddTimeout(START_DRAGICON_DURATION, cb_func, START_DRAGICON_TIMEOUT);
launcher_icon->mouse_down.emit(nux::GetEventButton(button_flags), monitor, key_flags);
@@ -2453,7 +2454,7 @@ AbstractLauncherIcon::Ptr Launcher::MouseIconIntersection(int x, int y)
for (it = _model->begin(); it != _model->end(); ++it)
{
- if (!(*it)->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE) || !(*it)->IsVisibleOnMonitor(monitor))
+ if (!(*it)->IsVisible() || !(*it)->IsVisibleOnMonitor(monitor))
continue;
nux::Point2 screen_coord [4];
@@ -2538,35 +2539,41 @@ void Launcher::RestoreSystemRenderTarget()
nux::GetWindowCompositor().RestoreRenderingSurface();
}
+bool Launcher::DndIsSpecialRequest(std::string const& uri) const
+{
+ return (boost::algorithm::ends_with(uri, ".desktop") || uri.find("device://") == 0);
+}
+
void Launcher::OnDNDDataCollected(const std::list<char*>& mimes)
{
_dnd_data.Reset();
- unity::glib::String uri_list_const(g_strdup("text/uri-list"));
+ const std::string uri_list = "text/uri-list";
+ auto& display = nux::GetWindowThread()->GetGraphicsDisplay();
- for (auto it : mimes)
+ for (auto const& mime : mimes)
{
- if (!g_str_equal(it, uri_list_const.Value()))
+ if (mime != uri_list)
continue;
- _dnd_data.Fill(nux::GetWindowThread()->GetGraphicsDisplay().GetDndData(uri_list_const.Value()));
+ _dnd_data.Fill(display.GetDndData(const_cast<char*>(uri_list.c_str())));
break;
}
_hide_machine.SetQuirk(LauncherHideMachine::EXTERNAL_DND_ACTIVE, true);
- for (auto it : _dnd_data.Uris())
+ auto const& uris = _dnd_data.Uris();
+ if (std::find_if(uris.begin(), uris.end(), [this] (std::string const& uri)
+ {return DndIsSpecialRequest(uri);}) != uris.end())
{
- if (g_str_has_suffix(it.c_str(), ".desktop") || g_str_has_prefix(it.c_str(), "device://"))
- {
- _steal_drag = true;
- break;
- }
- }
+ _steal_drag = true;
- if (!_steal_drag)
+ if (IsOverlayOpen())
+ SaturateIcons();
+ }
+ else
{
- for (auto it : *_model)
+ for (auto const& it : *_model)
{
if (it->ShouldHighlightOnDrag(_dnd_data))
{
@@ -2580,11 +2587,6 @@ void Launcher::OnDNDDataCollected(const std::list<char*>& mimes)
}
}
}
- else
- {
- if (IsOverlayOpen())
- SaturateIcons();
- }
}
void Launcher::ProcessDndEnter()
@@ -2652,32 +2654,29 @@ void Launcher::ProcessDndLeave()
void Launcher::ProcessDndMove(int x, int y, std::list<char*> mimes)
{
- nux::Area* parent = GetToplevel();
- unity::glib::String uri_list_const(g_strdup("text/uri-list"));
-
if (!_data_checked)
{
+ const std::string uri_list = "text/uri-list";
_data_checked = true;
_dnd_data.Reset();
+ auto& display = nux::GetWindowThread()->GetGraphicsDisplay();
// get the data
- for (auto it : mimes)
+ for (auto const& mime : mimes)
{
- if (!g_str_equal(it, uri_list_const.Value()))
+ if (mime != uri_list)
continue;
- _dnd_data.Fill(nux::GetWindowThread()->GetGraphicsDisplay().GetDndData(uri_list_const.Value()));
+ _dnd_data.Fill(display.GetDndData(const_cast<char*>(uri_list.c_str())));
break;
}
// see if the launcher wants this one
- for (auto it : _dnd_data.Uris())
+ auto const& uris = _dnd_data.Uris();
+ if (std::find_if(uris.begin(), uris.end(), [this] (std::string const& uri)
+ {return DndIsSpecialRequest(uri);}) != uris.end())
{
- if (g_str_has_suffix(it.c_str(), ".desktop") || g_str_has_prefix(it.c_str(), "device://"))
- {
- _steal_drag = true;
- break;
- }
+ _steal_drag = true;
}
// only set hover once we know our first x/y
@@ -2686,7 +2685,7 @@ void Launcher::ProcessDndMove(int x, int y, std::list<char*> mimes)
if (!_steal_drag)
{
- for (auto it : *_model)
+ for (auto const& it : *_model)
{
if (it->ShouldHighlightOnDrag(_dnd_data))
it->SetQuirk(AbstractLauncherIcon::Quirk::DESAT, false);
@@ -2696,7 +2695,7 @@ void Launcher::ProcessDndMove(int x, int y, std::list<char*> mimes)
}
}
- SetMousePosition(x - parent->GetGeometry().x, y - parent->GetGeometry().y);
+ SetMousePosition(x - _parent->GetGeometry().x, y - _parent->GetGeometry().y);
if (!IsOverlayOpen() && _mouse_position.x == 0 && _mouse_position.y <= (_parent->GetGeometry().height - _icon_size - 2 * _space_between_icons) && !_drag_edge_touching)
{
@@ -2723,7 +2722,7 @@ void Launcher::ProcessDndMove(int x, int y, std::list<char*> mimes)
if (hovered_icon->GetIconType() == AbstractLauncherIcon::IconType::TRASH)
_steal_drag = false;
- if (hovered_icon->GetIconType() == AbstractLauncherIcon::IconType::APPLICATION || hovered_icon->GetIconType() == AbstractLauncherIcon::IconType::EXPO)
+ if (hovered_icon->position() == AbstractLauncherIcon::Position::FLOATING)
hovered_icon_is_appropriate = true;
}
@@ -2733,7 +2732,6 @@ void Launcher::ProcessDndMove(int x, int y, std::list<char*> mimes)
if (!_dnd_hovered_icon && hovered_icon_is_appropriate)
{
_dnd_hovered_icon = new SpacerLauncherIcon(monitor());
- _dnd_hovered_icon->SetSortPriority(G_MAXINT);
_model->AddIcon(_dnd_hovered_icon);
_model->ReorderBefore(_dnd_hovered_icon, hovered_icon, true);
}
@@ -2788,34 +2786,10 @@ void Launcher::ProcessDndDrop(int x, int y)
{
if (_steal_drag)
{
- for (auto it : _dnd_data.Uris())
+ for (auto const& uri : _dnd_data.Uris())
{
- if (g_str_has_suffix(it.c_str(), ".desktop"))
- {
- char* path = nullptr;
-
- if (g_str_has_prefix(it.c_str(), "application://"))
- {
- const char* tmp = it.c_str() + strlen("application://");
- unity::glib::String tmp2(g_strdup_printf("file:///usr/share/applications/%s", tmp));
- path = g_filename_from_uri(tmp2.Value(), NULL, NULL);
- }
- else if (g_str_has_prefix(it.c_str(), "file://"))
- {
- path = g_filename_from_uri(it.c_str(), NULL, NULL);
- }
-
- if (path)
- {
- launcher_addrequest.emit(path, _dnd_hovered_icon);
- g_free(path);
- }
- }
- else if (devices_settings_ && g_str_has_prefix(it.c_str(), "device://"))
- {
- const gchar* uuid = it.c_str() + 9;
- devices_settings_->TryToUnblacklist(uuid);
- }
+ if (DndIsSpecialRequest(uri))
+ add_request.emit(uri, _dnd_hovered_icon);
}
}
else if (_dnd_hovered_icon && _drag_action != nux::DNDACTION_NONE)
diff --git a/launcher/Launcher.h b/launcher/Launcher.h
index c23489c4d..d9759ba78 100644
--- a/launcher/Launcher.h
+++ b/launcher/Launcher.h
@@ -83,8 +83,6 @@ public:
void SetModel(LauncherModel::Ptr model);
LauncherModel::Ptr GetModel() const;
- void SetDevicesSettings(DevicesSettings::Ptr devices_settings);
-
void StartKeyShowLauncher();
void EndKeyShowLauncher();
@@ -121,9 +119,8 @@ public:
int GetDragDelta() const;
void SetHover(bool hovered);
- sigc::signal<void, char*, AbstractLauncherIcon::Ptr> launcher_addrequest;
- sigc::signal<void, AbstractLauncherIcon::Ptr> launcher_removerequest;
- sigc::signal<void, AbstractLauncherIcon::Ptr> icon_animation_complete;
+ sigc::signal<void, std::string const&, AbstractLauncherIcon::Ptr> add_request;
+ sigc::signal<void, AbstractLauncherIcon::Ptr> remove_request;
sigc::signal<void> selection_change;
sigc::signal<void> hidden_changed;
sigc::signal<void> sc_launcher_icon_animation;
@@ -199,7 +196,7 @@ private:
void OnSelectionChanged(AbstractLauncherIcon::Ptr selection);
bool StrutHack();
- bool StartIconDragTimeout();
+ bool StartIconDragTimeout(int x, int y);
bool OnScrollTimeout();
bool OnUpdateDragManagerTimeout();
@@ -319,6 +316,7 @@ private:
void DndReset();
void DndHoveredIconReset();
void DndTimeoutSetup();
+ bool DndIsSpecialRequest(std::string const& uri) const;
LauncherModel::Ptr _model;
nux::BaseWindow* _parent;
@@ -365,6 +363,7 @@ private:
int _launcher_drag_delta_min;
int _enter_y;
int _last_button_press;
+ int _drag_icon_position;
float _drag_out_delta_x;
bool _drag_gesture_ongoing;
float _last_reveal_progress;
@@ -389,8 +388,6 @@ private:
ui::AbstractIconRenderer::Ptr icon_renderer;
BackgroundEffectHelper bg_effect_helper_;
- DevicesSettings::Ptr devices_settings_;
-
UBusManager ubus_;
glib::SourceManager sources_;
diff --git a/launcher/LauncherController.cpp b/launcher/LauncherController.cpp
index bcc59bdca..c365dd96f 100644
--- a/launcher/LauncherController.cpp
+++ b/launcher/LauncherController.cpp
@@ -1,6 +1,6 @@
// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
/*
- * Copyright (C) 2010, 2011 Canonical Ltd
+ * Copyright (C) 2010-2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
@@ -16,6 +16,7 @@
*
* Authored by: Jason Smith <jason.smith@canonical.com>
* Tim Penhey <tim.penhey@canonical.com>
+ * Marco Trevisan <marco.trevisan@canonical.com>
*/
#include <glib/gi18n-lib.h>
@@ -25,6 +26,7 @@
#include <Nux/HLayout.h>
#include <Nux/BaseWindow.h>
#include <NuxCore/Logger.h>
+#include <UnityCore/DesktopUtilities.h>
#include "LauncherOptions.h"
#include "BamfLauncherIcon.h"
@@ -35,6 +37,7 @@
#include "LauncherController.h"
#include "LauncherControllerPrivate.h"
#include "SoftwareCenterLauncherIcon.h"
+#include "ExpoLauncherIcon.h"
#include "unity-shared/WindowManager.h"
#include "TrashLauncherIcon.h"
#include "BFBLauncherIcon.h"
@@ -82,63 +85,45 @@ namespace
const std::string KEYPRESS_TIMEOUT = "keypress-timeout";
const std::string LABELS_TIMEOUT = "label-show-timeout";
const std::string HIDE_TIMEOUT = "hide-timeout";
-}
-}
+ const std::string SOFTWARE_CENTER_AGENT = "software-center-agent";
+ const std::string RUNNING_APPS_URI = FavoriteStore::URI_PREFIX_UNITY + "running-apps";
+ const std::string DEVICES_URI = FavoriteStore::URI_PREFIX_UNITY + "devices";
+}
+}
GDBusInterfaceVTable Controller::Impl::interface_vtable =
{ Controller::Impl::OnDBusMethodCall, NULL, NULL};
-Controller::Impl::Impl(Display* display, Controller* parent)
+
+Controller::Impl::Impl(Controller* parent)
: parent_(parent)
- , model_(new LauncherModel())
- , sort_priority_(0)
- , volume_monitor_(new VolumeMonitorWrapper)
- , devices_settings_(new DevicesSettingsImp)
- , device_section_(volume_monitor_, devices_settings_)
- , show_desktop_icon_(false)
- , display_(display)
+ , model_(std::make_shared<LauncherModel>())
, matcher_(bamf_matcher_get_default())
+ , device_section_(std::make_shared<VolumeMonitorWrapper>(), std::make_shared<DevicesSettingsImp>())
+ , expo_icon_(new ExpoLauncherIcon())
+ , desktop_icon_(new DesktopLauncherIcon())
+ , sort_priority_(AbstractLauncherIcon::DefaultPriority(AbstractLauncherIcon::IconType::APPLICATION))
+ , launcher_open(false)
+ , launcher_keynav(false)
+ , launcher_grabbed(false)
+ , reactivate_keynav(false)
+ , keynav_restore_window_(true)
+ , launcher_key_press_time_(0)
+ , dbus_owner_(g_bus_own_name(G_BUS_TYPE_SESSION, DBUS_NAME.c_str(), G_BUS_NAME_OWNER_FLAGS_NONE,
+ OnBusAcquired, nullptr, nullptr, this, nullptr))
{
edge_barriers_.options = parent_->options();
UScreen* uscreen = UScreen::GetDefault();
- auto monitors = uscreen->GetMonitors();
- int primary = uscreen->GetPrimaryMonitor();
+ EnsureLaunchers(uscreen->GetPrimaryMonitor(), uscreen->GetMonitors());
- launcher_open = false;
- launcher_keynav = false;
- launcher_grabbed = false;
- reactivate_keynav = false;
- keynav_restore_window_ = true;
-
- EnsureLaunchers(primary, monitors);
-
- launcher_ = launchers[0];
- device_section_.IconAdded.connect(sigc::mem_fun(this, &Impl::OnIconAdded));
-
- num_workspaces_ = WindowManager::Default()->WorkspaceCount();
- if (num_workspaces_ > 1)
- {
- InsertExpoAction();
- }
-
- // Insert the "Show Desktop" launcher icon in the launcher...
- if (show_desktop_icon_)
- InsertDesktopIcon();
-
- InsertTrash();
-
- sources_.AddTimeout(500, [&] { SetupBamf(); return false; });
+ SetupIcons();
remote_model_.entry_added.connect(sigc::mem_fun(this, &Impl::OnLauncherEntryRemoteAdded));
remote_model_.entry_removed.connect(sigc::mem_fun(this, &Impl::OnLauncherEntryRemoteRemoved));
- FavoriteStore::Instance().favorite_added.connect(sigc::mem_fun(this, &Impl::OnFavoriteStoreFavoriteAdded));
- FavoriteStore::Instance().favorite_removed.connect(sigc::mem_fun(this, &Impl::OnFavoriteStoreFavoriteRemoved));
- FavoriteStore::Instance().reordered.connect(sigc::mem_fun(this, &Impl::OnFavoriteStoreReordered));
-
LauncherHideMode hide_mode = parent_->options()->hide_mode;
BFBLauncherIcon* bfb = new BFBLauncherIcon(hide_mode);
RegisterIcon(AbstractLauncherIcon::Ptr(bfb));
@@ -146,35 +131,27 @@ Controller::Impl::Impl(Display* display, Controller* parent)
HudLauncherIcon* hud = new HudLauncherIcon(hide_mode);
RegisterIcon(AbstractLauncherIcon::Ptr(hud));
- parent_->options()->hide_mode.changed.connect([bfb,hud](LauncherHideMode mode) {
+ TrashLauncherIcon* trash = new TrashLauncherIcon();
+ RegisterIcon(AbstractLauncherIcon::Ptr(trash));
+
+ parent_->options()->hide_mode.changed.connect([bfb, hud](LauncherHideMode mode) {
bfb->SetHideMode(mode);
hud->SetHideMode(mode);
});
- desktop_icon_ = AbstractLauncherIcon::Ptr(new DesktopLauncherIcon());
-
uscreen->changed.connect(sigc::mem_fun(this, &Controller::Impl::OnScreenChanged));
WindowManager& plugin_adapter = *(WindowManager::Default());
- plugin_adapter.window_focus_changed.connect (sigc::mem_fun (this, &Controller::Impl::OnWindowFocusChanged));
-
- launcher_key_press_time_ = 0;
+ plugin_adapter.window_focus_changed.connect(sigc::mem_fun(this, &Controller::Impl::OnWindowFocusChanged));
ubus.RegisterInterest(UBUS_QUICKLIST_END_KEY_NAV, [&](GVariant * args) {
if (reactivate_keynav)
parent_->KeyNavGrab();
- model_->SetSelection(reactivate_index);
- });
- parent_->AddChild(model_.get());
-
- uscreen->resuming.connect([&]() -> void {
- for (auto launcher : launchers)
- launcher->QueueDraw();
+ model_->SetSelection(reactivate_index);
});
- dbus_owner_ = g_bus_own_name(G_BUS_TYPE_SESSION, DBUS_NAME.c_str(), G_BUS_NAME_OWNER_FLAGS_NONE,
- OnBusAcquired, nullptr, nullptr, this, nullptr);
+ parent_->AddChild(model_.get());
}
Controller::Impl::~Impl()
@@ -182,9 +159,9 @@ Controller::Impl::~Impl()
// Since the launchers are in a window which adds a reference to the
// launcher, we need to make sure the base windows are unreferenced
// otherwise the launchers never die.
- for (auto launcher_ptr : launchers)
+ for (auto const& launcher_ptr : launchers)
{
- if (launcher_ptr.IsValid())
+ if (launcher_ptr)
launcher_ptr->GetParent()->UnReference();
}
@@ -198,7 +175,7 @@ void Controller::Impl::EnsureLaunchers(int primary, std::vector<nux::Geometry> c
unsigned int launchers_size = launchers.size();
unsigned int last_launcher = 0;
- for (unsigned int i = 0; i < num_launchers; i++, last_launcher++)
+ for (unsigned int i = 0; i < num_launchers; ++i, ++last_launcher)
{
if (i >= launchers_size)
{
@@ -232,6 +209,7 @@ void Controller::Impl::EnsureLaunchers(int primary, std::vector<nux::Geometry> c
}
}
+ launcher_ = launchers[0];
launchers.resize(num_launchers);
}
@@ -240,7 +218,7 @@ void Controller::Impl::OnScreenChanged(int primary_monitor, std::vector<nux::Geo
EnsureLaunchers(primary_monitor, monitors);
}
-void Controller::Impl::OnWindowFocusChanged (guint32 xid)
+void Controller::Impl::OnWindowFocusChanged(guint32 xid)
{
static bool keynav_first_focus = false;
@@ -264,11 +242,9 @@ Launcher* Controller::Impl::CreateLauncher(int monitor)
nux::BaseWindow* launcher_window = new nux::BaseWindow(TEXT("LauncherWindow"));
Launcher* launcher = new Launcher(launcher_window, nux::ObjectPtr<DNDCollectionWindow>(new DNDCollectionWindow));
- launcher->display = display_;
launcher->monitor = monitor;
launcher->options = parent_->options();
launcher->SetModel(model_);
- launcher->SetDevicesSettings(devices_settings_);
nux::HLayout* layout = new nux::HLayout(NUX_TRACKER_LOCATION);
layout->AddView(launcher, 1);
@@ -283,58 +259,103 @@ Launcher* Controller::Impl::CreateLauncher(int monitor)
launcher_window->InputWindowEnableStruts(parent_->options()->hide_mode == LAUNCHER_HIDE_NEVER);
launcher_window->SetEnterFocusInputArea(launcher);
- launcher->launcher_addrequest.connect(sigc::mem_fun(this, &Impl::OnLauncherAddRequest));
- launcher->launcher_removerequest.connect(sigc::mem_fun(this, &Impl::OnLauncherRemoveRequest));
-
- launcher->icon_animation_complete.connect(sigc::mem_fun(this, &Impl::OnSCIconAnimationComplete));
+ launcher->add_request.connect(sigc::mem_fun(this, &Impl::OnLauncherAddRequest));
+ launcher->remove_request.connect(sigc::mem_fun(this, &Impl::OnLauncherRemoveRequest));
parent_->AddChild(launcher);
return launcher;
}
-void Controller::Impl::OnLauncherAddRequest(char* path, AbstractLauncherIcon::Ptr before)
+void Controller::Impl::OnLauncherAddRequest(std::string const& icon_uri, AbstractLauncherIcon::Ptr icon_before)
{
- for (auto it : model_->GetSublist<BamfLauncherIcon> ())
+ std::string app_uri;
+
+ if (icon_uri.find(FavoriteStore::URI_PREFIX_FILE) == 0)
{
- if (path && path == it->DesktopFile())
- {
- it->Stick();
- model_->ReorderBefore(it, before, false);
- Save();
- return;
- }
+ auto const& desktop_path = icon_uri.substr(FavoriteStore::URI_PREFIX_FILE.length());
+ app_uri = FavoriteStore::URI_PREFIX_APP + DesktopUtilities::GetDesktopID(desktop_path);
}
- AbstractLauncherIcon::Ptr result = CreateFavorite(path);
- if (result)
+ auto const& icon = GetIconByUri(app_uri.empty() ? icon_uri : app_uri);
+
+ if (icon)
{
- RegisterIcon(result);
- if (before)
- model_->ReorderBefore(result, before, false);
+ icon->Stick(false);
+ model_->ReorderAfter(icon, icon_before);
+ }
+ else
+ {
+ if (icon_before)
+ RegisterIcon(CreateFavoriteIcon(icon_uri), icon_before->SortPriority());
+ else
+ RegisterIcon(CreateFavoriteIcon(icon_uri));
}
- Save();
+ SaveIconsOrder();
}
-void Controller::Impl::Save()
+void Controller::Impl::AddFavoriteKeepingOldPosition(FavoriteList& icons, std::string const& icon_uri) const
{
- unity::FavoriteList desktop_paths;
+ auto const& favorites = FavoriteStore::Instance().GetFavorites();
+ auto it = std::find(favorites.rbegin(), favorites.rend(), icon_uri);
+
+ FavoriteList::reverse_iterator icons_it = icons.rbegin();
- // Updates gsettings favorites.
- auto launchers = model_->GetSublist<BamfLauncherIcon> ();
- for (auto icon : launchers)
+ while (it != favorites.rend())
+ {
+ icons_it = std::find(icons.rbegin(), icons.rend(), *it);
+
+ if (icons_it != icons.rend())
+ break;
+
+ ++it;
+ }
+
+ icons.insert(icons_it.base(), icon_uri);
+}
+
+void Controller::Impl::SaveIconsOrder()
+{
+ FavoriteList icons;
+ bool found_first_running_app = false;
+ bool found_first_device = false;
+
+ for (auto const& icon : *model_)
{
if (!icon->IsSticky())
+ {
+ if (!icon->IsVisible())
+ continue;
+
+ if (!found_first_running_app && icon->GetIconType() == AbstractLauncherIcon::IconType::APPLICATION)
+ {
+ found_first_running_app = true;
+ icons.push_back(local::RUNNING_APPS_URI);
+ }
+
+ if (!found_first_device && icon->GetIconType() == AbstractLauncherIcon::IconType::DEVICE)
+ {
+ found_first_device = true;
+ icons.push_back(local::DEVICES_URI);
+ }
+
continue;
+ }
- std::string const& desktop_file = icon->DesktopFile();
+ std::string const& remote_uri = icon->RemoteUri();
- if (!desktop_file.empty())
- desktop_paths.push_back(desktop_file);
+ if (!remote_uri.empty())
+ icons.push_back(remote_uri);
}
- unity::FavoriteStore::Instance().SetFavorites(desktop_paths);
+ if (!found_first_running_app)
+ AddFavoriteKeepingOldPosition(icons, local::RUNNING_APPS_URI);
+
+ if (!found_first_device)
+ AddFavoriteKeepingOldPosition(icons, local::DEVICES_URI);
+
+ FavoriteStore::Instance().SetFavorites(icons);
}
void
@@ -345,64 +366,53 @@ Controller::Impl::OnLauncherAddRequestSpecial(std::string const& path,
int icon_y,
int icon_size)
{
- auto bamf_icons = model_->GetSublist<BamfLauncherIcon>();
- for (auto icon : bamf_icons)
- {
- if (icon->DesktopFile() == path)
- return;
- }
-
// Check if desktop file was supplied, or if it's set to SC's agent
// See https://bugs.launchpad.net/unity/+bug/1002440
- if (path.empty() || path == "software-center-agent")
+ if (path.empty() || path == local::SOFTWARE_CENTER_AGENT)
return;
- SoftwareCenterLauncherIcon::Ptr result = CreateSCLauncherIcon(path, aptdaemon_trans_id, icon_path);
+ auto const& icon = std::find_if(model_->begin(), model_->end(),
+ [&path](AbstractLauncherIcon::Ptr const& i) { return (i->DesktopFile() == path); });
- CurrentLauncher()->ForceReveal(true);
+ if (icon != model_->end())
+ return;
+
+ auto const& result = CreateSCLauncherIcon(path, aptdaemon_trans_id, icon_path);
if (result)
{
- result->SetQuirk(AbstractLauncherIcon::Quirk::VISIBLE, false);
- result->Animate(CurrentLauncher(), icon_x, icon_y, icon_size);
- RegisterIcon(result);
- Save();
+ // Setting the icon position and adding it to the model, makes the launcher
+ // to compute its center
+ RegisterIcon(result, GetLastIconPriority<BamfLauncherIcon>("", true));
+
+ // This will ensure that the center of the new icon is set, so that
+ // the animation could be done properly.
+ sources_.AddIdle([this, icon_x, icon_y, result] {
+ result->Animate(CurrentLauncher(), icon_x, icon_y);
+ return false;
+ });
}
}
-void Controller::Impl::OnSCIconAnimationComplete(AbstractLauncherIcon::Ptr icon)
-{
- icon->SetQuirk(AbstractLauncherIcon::Quirk::VISIBLE, true);
- launcher_->ForceReveal(false);
-}
-
void Controller::Impl::SortAndUpdate()
{
- gint shortcut = 1;
+ unsigned shortcut = 1;
- auto launchers = model_->GetSublist<BamfLauncherIcon> ();
- for (auto icon : launchers)
+ for (auto const& icon : model_->GetSublist<BamfLauncherIcon>())
{
if (shortcut <= 10 && icon->IsVisible())
{
- std::stringstream shortcut_string;
- shortcut_string << (shortcut % 10);
- icon->SetShortcut(shortcut_string.str()[0]);
+ icon->SetShortcut(std::to_string(shortcut % 10)[0]);
++shortcut;
}
- // reset shortcut
else
{
+ // reset shortcut
icon->SetShortcut(0);
}
}
}
-void Controller::Impl::OnIconAdded(AbstractLauncherIcon::Ptr icon)
-{
- this->RegisterIcon(icon);
-}
-
void Controller::Impl::OnIconRemoved(AbstractLauncherIcon::Ptr icon)
{
SortAndUpdate();
@@ -428,10 +438,13 @@ void Controller::Impl::OnLauncherRemoveRequest(AbstractLauncherIcon::Ptr icon)
{
auto device_icon = dynamic_cast<VolumeLauncherIcon*>(icon.GetPointer());
- if (device_icon && device_icon->CanEject())
- device_icon->EjectAndShowNotification();
- else if (device_icon && device_icon->CanStop())
- device_icon->StopDrive();
+ if (device_icon)
+ {
+ if (device_icon->CanEject())
+ device_icon->EjectAndShowNotification();
+ else if (device_icon->CanStop())
+ device_icon->StopDrive();
+ }
break;
}
@@ -442,63 +455,63 @@ void Controller::Impl::OnLauncherRemoveRequest(AbstractLauncherIcon::Ptr icon)
void Controller::Impl::OnLauncherEntryRemoteAdded(LauncherEntryRemote::Ptr const& entry)
{
- for (auto icon : *model_)
- {
- if (!icon || icon->RemoteUri().empty())
- continue;
+ if (entry->AppUri().empty())
+ return;
- if (entry->AppUri() == icon->RemoteUri())
- {
- icon->InsertEntryRemote(entry);
- }
- }
+ auto const& apps_icons = model_->GetSublist<BamfLauncherIcon>();
+ auto const& icon = std::find_if(apps_icons.begin(), apps_icons.end(),
+ [&entry](AbstractLauncherIcon::Ptr const& i) { return (i->RemoteUri() == entry->AppUri()); });
+
+ if (icon != apps_icons.end())
+ (*icon)->InsertEntryRemote(entry);
}
void Controller::Impl::OnLauncherEntryRemoteRemoved(LauncherEntryRemote::Ptr const& entry)
{
- for (auto icon : *model_)
- {
+ for (auto const& icon : *model_)
icon->RemoveEntryRemote(entry);
- }
}
void Controller::Impl::OnFavoriteStoreFavoriteAdded(std::string const& entry, std::string const& pos, bool before)
{
- auto bamf_list = model_->GetSublist<BamfLauncherIcon>();
- AbstractLauncherIcon::Ptr other;
- if (bamf_list.size() > 0)
- other = *(bamf_list.begin());
+ if (entry == local::RUNNING_APPS_URI || entry == local::DEVICES_URI)
+ {
+ // Since the running apps and the devices are always shown, when added to
+ // the model, we only have to re-order them
+ ResetIconPriorities();
+ return;
+ }
+
+ AbstractLauncherIcon::Ptr other = *(model_->begin());
if (!pos.empty())
{
- for (auto it : bamf_list)
+ for (auto const& it : *model_)
{
- if (it->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE) && pos == it->DesktopFile())
+ if (it->IsVisible() && pos == it->RemoteUri())
other = it;
}
}
- for (auto it : bamf_list)
+ AbstractLauncherIcon::Ptr const& fav = GetIconByUri(entry);
+ if (fav)
{
- if (entry == it->DesktopFile())
- {
- it->Stick(false);
- if (!before)
- model_->ReorderAfter(it, other);
- else
- model_->ReorderBefore(it, other, false);
- return;
- }
- }
+ fav->Stick(false);
- AbstractLauncherIcon::Ptr result = CreateFavorite(entry.c_str());
- if (result)
+ if (before)
+ model_->ReorderBefore(fav, other, false);
+ else
+ model_->ReorderAfter(fav, other);
+ }
+ else
{
+ AbstractLauncherIcon::Ptr const& result = CreateFavoriteIcon(entry);
RegisterIcon(result);
- if (!before)
- model_->ReorderAfter(result, other);
- else
+
+ if (before)
model_->ReorderBefore(result, other, false);
+ else
+ model_->ReorderAfter(result, other);
}
SortAndUpdate();
@@ -506,104 +519,132 @@ void Controller::Impl::OnFavoriteStoreFavoriteAdded(std::string const& entry, st
void Controller::Impl::OnFavoriteStoreFavoriteRemoved(std::string const& entry)
{
- for (auto icon : model_->GetSublist<BamfLauncherIcon> ())
+ if (entry == local::RUNNING_APPS_URI || entry == local::DEVICES_URI)
{
- if (icon->DesktopFile() == entry)
- {
- icon->UnStick();
- break;
- }
+ // Since the running apps and the devices are always shown, when added to
+ // the model, we only have to re-order them
+ ResetIconPriorities();
+ return;
+ }
+
+ auto const& icon = GetIconByUri(entry);
+ if (icon)
+ {
+ icon->UnStick();
+
+ // When devices are removed from favorites, they should be re-ordered (not removed)
+ if (icon->GetIconType() == AbstractLauncherIcon::IconType::DEVICE)
+ ResetIconPriorities();
}
}
-void Controller::Impl::OnFavoriteStoreReordered()
+void Controller::Impl::ResetIconPriorities()
{
FavoriteList const& favs = FavoriteStore::Instance().GetFavorites();
- auto bamf_list = model_->GetSublist<BamfLauncherIcon>();
+ auto const& apps_icons = model_->GetSublist<BamfLauncherIcon>();
+ auto const& volumes_icons = model_->GetSublist<VolumeLauncherIcon>();
+ bool running_apps_found = false;
+ bool volumes_found = false;
- int i = 0;
- for (auto it : favs)
+ for (auto const& fav : favs)
{
- auto icon = std::find_if(bamf_list.begin(), bamf_list.end(),
- [&it](AbstractLauncherIcon::Ptr x) { return (x->DesktopFile() == it); });
+ if (fav == local::RUNNING_APPS_URI)
+ {
+ for (auto const& ico : apps_icons)
+ {
+ if (!ico->IsSticky())
+ ico->SetSortPriority(++sort_priority_);
+ }
- if (icon != bamf_list.end())
+ running_apps_found = true;
+ continue;
+ }
+ else if (fav == local::DEVICES_URI)
{
- (*icon)->SetSortPriority(i++);
+ for (auto const& ico : volumes_icons)
+ {
+ if (!ico->IsSticky())
+ ico->SetSortPriority(++sort_priority_);
+ }
+
+ volumes_found = true;
+ continue;
}
+
+ auto const& icon = GetIconByUri(fav);
+
+ if (icon)
+ icon->SetSortPriority(++sort_priority_);
}
- for (auto it : bamf_list)
+ if (!running_apps_found)
{
- if (!it->IsSticky())
- it->SetSortPriority(i++);
+ for (auto const& ico : apps_icons)
+ {
+ if (!ico->IsSticky())
+ ico->SetSortPriority(++sort_priority_);
+ }
}
- model_->Sort();
-}
-
-void Controller::Impl::OnExpoActivated()
-{
- WindowManager::Default()->InitiateExpo();
-}
+ if (!volumes_found)
+ {
+ for (auto const& ico : volumes_icons)
+ {
+ if (!ico->IsSticky())
+ ico->SetSortPriority(++sort_priority_);
+ }
+ }
-void Controller::Impl::InsertTrash()
-{
- AbstractLauncherIcon::Ptr icon(new TrashLauncherIcon());
- RegisterIcon(icon);
+ model_->Sort();
}
void Controller::Impl::UpdateNumWorkspaces(int workspaces)
{
- if ((num_workspaces_ == 0) && (workspaces > 0))
+ bool visible = expo_icon_->IsVisible();
+ bool wp_enabled = (workspaces > 1);
+
+ if (wp_enabled && !visible)
{
- InsertExpoAction();
+ if (FavoriteStore::Instance().IsFavorite(expo_icon_->RemoteUri()))
+ {
+ expo_icon_->SetQuirk(AbstractLauncherIcon::Quirk::VISIBLE, true);
+ }
}
- else if ((num_workspaces_ > 0) && (workspaces == 0))
+ else if (!wp_enabled && visible)
{
- RemoveExpoAction();
+ expo_icon_->SetQuirk(AbstractLauncherIcon::Quirk::VISIBLE, false);
}
-
- num_workspaces_ = workspaces;
}
-void Controller::Impl::InsertExpoAction()
+void Controller::Impl::RegisterIcon(AbstractLauncherIcon::Ptr icon, int priority)
{
- expo_icon_ = AbstractLauncherIcon::Ptr(new SimpleLauncherIcon(AbstractLauncherIcon::IconType::EXPO));
-
- SimpleLauncherIcon* icon = static_cast<SimpleLauncherIcon*>(expo_icon_.GetPointer());
- icon->tooltip_text = _("Workspace Switcher");
- icon->icon_name = "workspace-switcher";
- icon->SetQuirk(AbstractLauncherIcon::Quirk::VISIBLE, true);
- icon->SetQuirk(AbstractLauncherIcon::Quirk::RUNNING, false);
- icon->SetShortcut('s');
-
- on_expoicon_activate_connection_ = icon->activate.connect(sigc::mem_fun(this, &Impl::OnExpoActivated));
-
+ if (!icon || model_->IconIndex(icon) >= 0)
+ return;
- RegisterIcon(expo_icon_);
-}
+ if (priority != std::numeric_limits<int>::min())
+ icon->SetSortPriority(priority);
-void Controller::Impl::RemoveExpoAction()
-{
- if (on_expoicon_activate_connection_)
- on_expoicon_activate_connection_.disconnect();
- model_->RemoveIcon(expo_icon_);
-}
+ icon->position_saved.connect([this] {
+ // These calls must be done in order: first we save the new sticky icons
+ // then we re-order the model so that there won't be two icons with the same
+ // priority
+ SaveIconsOrder();
+ ResetIconPriorities();
+ });
-void Controller::Impl::InsertDesktopIcon()
-{
- RegisterIcon(desktop_icon_);
-}
+ std::string const& icon_uri = icon->RemoteUri();
+ icon->position_forgot.connect([this, icon_uri] {
+ FavoriteStore::Instance().RemoveFavorite(icon_uri);
+ });
-void Controller::Impl::RemoveDesktopIcon()
-{
- model_->RemoveIcon(desktop_icon_);
-}
+ if (icon->GetIconType() == AbstractLauncherIcon::IconType::APPLICATION)
+ {
+ icon->visibility_changed.connect(sigc::mem_fun(this, &Impl::SortAndUpdate));
+ SortAndUpdate();
+ }
-void Controller::Impl::RegisterIcon(AbstractLauncherIcon::Ptr icon)
-{
model_->AddIcon(icon);
+
std::string const& path = icon->DesktopFile();
if (!path.empty())
@@ -615,7 +656,59 @@ void Controller::Impl::RegisterIcon(AbstractLauncherIcon::Ptr icon)
}
}
-/* static private */
+template<typename IconType>
+int Controller::Impl::GetLastIconPriority(std::string const& favorite_uri, bool sticky)
+{
+ auto const& icons = model_->GetSublist<IconType>();
+ int icon_prio = std::numeric_limits<int>::min();
+
+ AbstractLauncherIcon::Ptr last_icon;
+
+ // Get the last (non)-sticky icon position (if available)
+ for (auto it = icons.rbegin(); it != icons.rend(); ++it)
+ {
+ auto const& icon = *it;
+ bool update_last_icon = ((!last_icon && !sticky) || sticky);
+
+ if (update_last_icon || icon->IsSticky() == sticky)
+ {
+ last_icon = icon;
+
+ if (icon->IsSticky() == sticky)
+ break;
+ }
+ }
+
+ if (last_icon)
+ {
+ icon_prio = last_icon->SortPriority();
+
+ if (sticky && last_icon->IsSticky() != sticky)
+ icon_prio -= 1;
+ }
+ else if (!favorite_uri.empty())
+ {
+ // If we have no applications opened, we must guess it position by favorites
+ for (auto const& fav : FavoriteStore::Instance().GetFavorites())
+ {
+ if (fav == favorite_uri)
+ {
+ if (icon_prio == std::numeric_limits<int>::min())
+ icon_prio = (*model_->begin())->SortPriority() - 1;
+
+ break;
+ }
+
+ auto const& icon = GetIconByUri(fav);
+
+ if (icon)
+ icon_prio = icon->SortPriority();
+ }
+ }
+
+ return icon_prio;
+}
+
void Controller::Impl::OnViewOpened(BamfMatcher* matcher, BamfView* view)
{
if (!BAMF_IS_APPLICATION(view))
@@ -630,35 +723,111 @@ void Controller::Impl::OnViewOpened(BamfMatcher* matcher, BamfView* view)
}
AbstractLauncherIcon::Ptr icon(new BamfLauncherIcon(app));
- icon->visibility_changed.connect(sigc::mem_fun(this, &Impl::SortAndUpdate));
- icon->SetSortPriority(sort_priority_++);
- RegisterIcon(icon);
- SortAndUpdate();
+ RegisterIcon(icon, GetLastIconPriority<BamfLauncherIcon>(local::RUNNING_APPS_URI));
}
-AbstractLauncherIcon::Ptr Controller::Impl::CreateFavorite(const char* file_path)
+void Controller::Impl::OnDeviceIconAdded(AbstractLauncherIcon::Ptr icon)
+{
+ RegisterIcon(icon, GetLastIconPriority<VolumeLauncherIcon>(local::DEVICES_URI));
+}
+
+AbstractLauncherIcon::Ptr Controller::Impl::CreateFavoriteIcon(std::string const& icon_uri)
{
- BamfApplication* app;
AbstractLauncherIcon::Ptr result;
- app = bamf_matcher_get_application_for_desktop_file(matcher_, file_path, true);
- if (!app)
+ if (!FavoriteStore::IsValidFavoriteUri(icon_uri))
+ {
+ LOG_WARNING(logger) << "Ignoring favorite '" << icon_uri << "'.";
return result;
+ }
- if (g_object_get_qdata(G_OBJECT(app), g_quark_from_static_string("unity-seen")))
+ std::string desktop_id;
+
+ if (icon_uri.find(FavoriteStore::URI_PREFIX_APP) == 0)
{
- bamf_view_set_sticky(BAMF_VIEW(app), true);
- return result;
+ desktop_id = icon_uri.substr(FavoriteStore::URI_PREFIX_APP.size());
+ }
+ else if (icon_uri.find(FavoriteStore::URI_PREFIX_FILE) == 0)
+ {
+ desktop_id = icon_uri.substr(FavoriteStore::URI_PREFIX_FILE.size());
}
- bamf_view_set_sticky(BAMF_VIEW(app), true);
- AbstractLauncherIcon::Ptr icon (new BamfLauncherIcon(app));
- icon->SetSortPriority(sort_priority_++);
- result = icon;
+ if (!desktop_id.empty())
+ {
+ BamfApplication* app;
+ std::string const& desktop_path = DesktopUtilities::GetDesktopPathById(desktop_id);
+
+ app = bamf_matcher_get_application_for_desktop_file(matcher_, desktop_path.c_str(), true);
+
+ if (!app)
+ return result;
+
+ if (g_object_get_qdata(G_OBJECT(app), g_quark_from_static_string("unity-seen")))
+ {
+ bamf_view_set_sticky(BAMF_VIEW(app), true);
+ return result;
+ }
+
+ result = AbstractLauncherIcon::Ptr(new BamfLauncherIcon(app));
+ }
+ else if (icon_uri.find(FavoriteStore::URI_PREFIX_DEVICE) == 0)
+ {
+ 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); });
+
+ if (icon == devices.end())
+ {
+ // Using an idle to remove the favorite, not to erase while iterating
+ sources_.AddIdle([this, icon_uri] {
+ FavoriteStore::Instance().RemoveFavorite(icon_uri);
+ return false;
+ });
+
+ return result;
+ }
+
+ result = *icon;
+ }
+ else if (desktop_icon_->RemoteUri() == icon_uri)
+ {
+ result = desktop_icon_;
+ }
+ else if (expo_icon_->RemoteUri() == icon_uri)
+ {
+ result = expo_icon_;
+ }
+
+ if (result)
+ {
+ if (!result->IsSticky())
+ result->Stick(false);
+ else
+ {
+ LOG_ERROR(logger) << "Ignoring favorite '" << icon_uri << "': it's already on the launcher!";
+ result = nullptr;
+ }
+ }
return result;
}
+AbstractLauncherIcon::Ptr Controller::Impl::GetIconByUri(std::string const& icon_uri)
+{
+ if (icon_uri.empty())
+ return AbstractLauncherIcon::Ptr();
+
+ auto const& icon = std::find_if(model_->begin(), model_->end(),
+ [&icon_uri](AbstractLauncherIcon::Ptr const& i) { return (i->RemoteUri() == icon_uri); });
+
+ if (icon != model_->end())
+ {
+ return *icon;
+ }
+
+ return AbstractLauncherIcon::Ptr();
+}
+
SoftwareCenterLauncherIcon::Ptr Controller::Impl::CreateSCLauncherIcon(std::string const& file_path,
std::string const& aptdaemon_trans_id,
std::string const& icon_path)
@@ -678,50 +847,79 @@ SoftwareCenterLauncherIcon::Ptr Controller::Impl::CreateSCLauncherIcon(std::stri
bamf_view_set_sticky(BAMF_VIEW(app), true);
result = new SoftwareCenterLauncherIcon(app, aptdaemon_trans_id, icon_path);
- result->SetSortPriority(sort_priority_++);
return result;
}
-void Controller::Impl::SetupBamf()
+void Controller::Impl::AddRunningApps()
{
- GList* apps, *l;
- BamfApplication* app;
-
- FavoriteList const& favs = FavoriteStore::Instance().GetFavorites();
+ std::shared_ptr<GList> apps(bamf_matcher_get_applications(matcher_), g_list_free);
- for (FavoriteList::const_iterator i = favs.begin(), end = favs.end();
- i != end; ++i)
+ for (GList *l = apps.get(); l; l = l->next)
{
- AbstractLauncherIcon::Ptr fav = CreateFavorite(i->c_str());
+ if (!BAMF_IS_APPLICATION(l->data))
+ continue;
- if (fav)
- {
- fav->SetSortPriority(sort_priority_++);
- RegisterIcon(fav);
- }
- }
+ BamfApplication* app = BAMF_APPLICATION(l->data);
- apps = bamf_matcher_get_applications(matcher_);
- view_opened_signal_.Connect(matcher_, "view-opened", sigc::mem_fun(this, &Impl::OnViewOpened));
+ if (g_object_get_qdata(G_OBJECT(app), g_quark_from_static_string("unity-seen")))
+ continue;
- for (l = apps; l; l = l->next)
+ AbstractLauncherIcon::Ptr icon(new BamfLauncherIcon(app));
+ RegisterIcon(icon, ++sort_priority_);
+ }
+}
+
+void Controller::Impl::AddDevices()
+{
+ auto& fav_store = FavoriteStore::Instance();
+ for (auto const& icon : device_section_.GetIcons())
{
- app = BAMF_APPLICATION(l->data);
+ if (!icon->IsSticky() && !fav_store.IsFavorite(icon->RemoteUri()))
+ RegisterIcon(icon, ++sort_priority_);
+ }
+}
- if (g_object_get_qdata(G_OBJECT(app), g_quark_from_static_string("unity-seen")))
+void Controller::Impl::SetupIcons()
+{
+ auto& favorite_store = FavoriteStore::Instance();
+ FavoriteList const& favs = favorite_store.GetFavorites();
+ bool running_apps_added = false;
+ bool devices_added = false;
+
+ for (auto const& fav_uri : favs)
+ {
+ if (fav_uri == local::RUNNING_APPS_URI)
+ {
+ AddRunningApps();
+ running_apps_added = true;
continue;
+ }
+ else if (fav_uri == local::DEVICES_URI)
+ {
+ AddDevices();
+ devices_added = true;
+ continue;
+ }
- AbstractLauncherIcon::Ptr icon(new BamfLauncherIcon(app));
- icon->SetSortPriority(sort_priority_++);
- RegisterIcon(icon);
+ RegisterIcon(CreateFavoriteIcon(fav_uri), ++sort_priority_);
}
- g_list_free(apps);
- SortAndUpdate();
+
+ if (!running_apps_added)
+ AddRunningApps();
+
+ if (!devices_added)
+ AddDevices();
+
+ view_opened_signal_.Connect(matcher_, "view-opened", sigc::mem_fun(this, &Impl::OnViewOpened));
+ 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));
model_->order_changed.connect(sigc::mem_fun(this, &Impl::SortAndUpdate));
model_->icon_removed.connect(sigc::mem_fun(this, &Impl::OnIconRemoved));
- model_->saved.connect(sigc::mem_fun(this, &Impl::Save));
+ model_->saved.connect(sigc::mem_fun(this, &Impl::SaveIconsOrder));
}
void Controller::Impl::SendHomeActivationRequest()
@@ -729,10 +927,10 @@ void Controller::Impl::SendHomeActivationRequest()
ubus.SendMessage(UBUS_PLACE_ENTRY_ACTIVATE_REQUEST, g_variant_new("(sus)", "home.lens", dash::NOT_HANDLED, ""));
}
-Controller::Controller(Display* display)
+Controller::Controller()
: options(Options::Ptr(new Options()))
, multiple_launchers(true)
- , pimpl(new Impl(display, this))
+ , pimpl(new Impl(this))
{
multiple_launchers.changed.connect([&](bool value) -> void {
UScreen* uscreen = UScreen::GetDefault();
@@ -814,19 +1012,6 @@ void Controller::PushToFront()
pimpl->launcher_->GetParent()->PushToFront();
}
-void Controller::SetShowDesktopIcon(bool show_desktop_icon)
-{
- if (pimpl->show_desktop_icon_ == show_desktop_icon)
- return;
-
- pimpl->show_desktop_icon_ = show_desktop_icon;
-
- if (pimpl->show_desktop_icon_)
- pimpl->InsertDesktopIcon();
- else
- pimpl->RemoveDesktopIcon();
-}
-
int Controller::Impl::MonitorWithMouse()
{
UScreen* uscreen = UScreen::GetDefault();
@@ -1110,7 +1295,7 @@ Controller::AddProperties(GVariantBuilder* builder)
timespec current;
clock_gettime(CLOCK_MONOTONIC, &current);
- unity::variant::BuilderWrapper(builder)
+ variant::BuilderWrapper(builder)
.add("key_nav_is_active", KeyNavIsActive())
.add("key_nav_launcher_monitor", pimpl->keyboard_launcher_.IsValid() ? pimpl->keyboard_launcher_->monitor : -1)
.add("key_nav_selection", pimpl->model_->SelectionIndex())
diff --git a/launcher/LauncherController.h b/launcher/LauncherController.h
index e18f2cae2..ec203ec8f 100644
--- a/launcher/LauncherController.h
+++ b/launcher/LauncherController.h
@@ -47,7 +47,7 @@ public:
nux::Property<Options::Ptr> options;
nux::Property<bool> multiple_launchers;
- Controller(Display* display);
+ Controller();
~Controller();
Launcher& launcher() const;
@@ -61,8 +61,6 @@ public:
void PushToFront();
- void SetShowDesktopIcon(bool show_desktop_icon);
-
bool AboutToShowDash(int was_tap, int when) const;
void HandleLauncherKeyPress(int when);
diff --git a/launcher/LauncherControllerPrivate.h b/launcher/LauncherControllerPrivate.h
index cd730a37e..9cb22c856 100644
--- a/launcher/LauncherControllerPrivate.h
+++ b/launcher/LauncherControllerPrivate.h
@@ -46,59 +46,53 @@ namespace launcher
class Controller::Impl
{
public:
- Impl(Display* display, Controller* parent);
+ Impl(Controller* parent);
~Impl();
void UpdateNumWorkspaces(int workspaces);
Launcher* CreateLauncher(int monitor);
- void Save();
+ void SaveIconsOrder();
void SortAndUpdate();
nux::ObjectPtr<Launcher> CurrentLauncher();
- void OnIconAdded(AbstractLauncherIcon::Ptr icon);
+ template<typename IconType>
+ int GetLastIconPriority(std::string const& favorite_uri = "", bool sticky = false);
+ void AddFavoriteKeepingOldPosition(FavoriteList& icons, std::string const& icon_uri) const;
+
void OnIconRemoved(AbstractLauncherIcon::Ptr icon);
+ void OnDeviceIconAdded(AbstractLauncherIcon::Ptr icon);
- void OnLauncherAddRequest(char* path, AbstractLauncherIcon::Ptr before);
+ void OnLauncherAddRequest(std::string const& icon_uri, AbstractLauncherIcon::Ptr before);
void OnLauncherAddRequestSpecial(std::string const& path, std::string const& aptdaemon_trans_id,
std::string const& icon_path, int icon_x, int icon_y, int icon_size);
void OnLauncherRemoveRequest(AbstractLauncherIcon::Ptr icon);
- void OnSCIconAnimationComplete(AbstractLauncherIcon::Ptr icon);
void OnLauncherEntryRemoteAdded(LauncherEntryRemote::Ptr const& entry);
void OnLauncherEntryRemoteRemoved(LauncherEntryRemote::Ptr const& entry);
void OnFavoriteStoreFavoriteAdded(std::string const& entry, std::string const& pos, bool before);
void OnFavoriteStoreFavoriteRemoved(std::string const& entry);
- void OnFavoriteStoreReordered();
-
-
- void InsertExpoAction();
- void RemoveExpoAction();
-
- void InsertDesktopIcon();
- void RemoveDesktopIcon();
+ void ResetIconPriorities();
void SendHomeActivationRequest();
int MonitorWithMouse();
- void InsertTrash();
-
- void RegisterIcon(AbstractLauncherIcon::Ptr icon);
-
- AbstractLauncherIcon::Ptr CreateFavorite(const char* file_path);
+ void RegisterIcon(AbstractLauncherIcon::Ptr icon, int priority = std::numeric_limits<int>::min());
+ AbstractLauncherIcon::Ptr CreateFavoriteIcon(std::string const& icon_uri);
+ 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);
- void SetupBamf();
+ void SetupIcons();
+ void AddRunningApps();
+ void AddDevices();
void EnsureLaunchers(int primary, std::vector<nux::Geometry> const& monitors);
- void OnExpoActivated();
-
void OnScreenChanged(int primary_monitor, std::vector<nux::Geometry>& monitors);
void OnWindowFocusChanged (guint32 xid);
@@ -123,38 +117,31 @@ public:
Controller* parent_;
LauncherModel::Ptr model_;
+ glib::Object<BamfMatcher> matcher_;
nux::ObjectPtr<Launcher> launcher_;
nux::ObjectPtr<Launcher> keyboard_launcher_;
- int sort_priority_;
- AbstractVolumeMonitorWrapper::Ptr volume_monitor_;
- DevicesSettingsImp::Ptr devices_settings_;
DeviceLauncherSection device_section_;
LauncherEntryRemoteModel remote_model_;
AbstractLauncherIcon::Ptr expo_icon_;
AbstractLauncherIcon::Ptr desktop_icon_;
- int num_workspaces_;
- bool show_desktop_icon_;
- Display* display_;
-
- bool launcher_open;
- bool launcher_keynav;
- bool launcher_grabbed;
- bool reactivate_keynav;
- int reactivate_index;
- bool keynav_restore_window_;
- int launcher_key_press_time_;
- unsigned int dbus_owner_;
-
ui::EdgeBarrierController edge_barriers_;
-
LauncherList launchers;
- glib::Object<BamfMatcher> matcher_;
+ unsigned sort_priority_;
+ bool launcher_open;
+ bool launcher_keynav;
+ bool launcher_grabbed;
+ bool reactivate_keynav;
+ int reactivate_index;
+ bool keynav_restore_window_;
+ int launcher_key_press_time_;
+ unsigned dbus_owner_;
+
+
glib::Signal<void, BamfMatcher*, BamfView*> view_opened_signal_;
glib::SourceManager sources_;
UBusManager ubus;
- sigc::connection on_expoicon_activate_connection_;
sigc::connection launcher_key_press_connection_;
sigc::connection launcher_event_outside_connection_;
};
diff --git a/launcher/LauncherDragWindow.cpp b/launcher/LauncherDragWindow.cpp
index 53334ab89..8fcc92ed6 100644
--- a/launcher/LauncherDragWindow.cpp
+++ b/launcher/LauncherDragWindow.cpp
@@ -31,10 +31,17 @@ namespace unity
namespace launcher
{
+namespace
+{
+ const float QUICK_ANIMATION_SPEED = 0.3f;
+ const float SLOW_ANIMATION_SPEED = 0.05f;
+}
+
NUX_IMPLEMENT_OBJECT_TYPE(LauncherDragWindow);
LauncherDragWindow::LauncherDragWindow(nux::ObjectPtr<nux::IOpenGLBaseTexture> icon)
: nux::BaseWindow("")
+ , animation_speed_(QUICK_ANIMATION_SPEED)
, _cancelled(false)
, _icon(icon)
{
@@ -79,6 +86,18 @@ void LauncherDragWindow::SetAnimationTarget(int x, int y)
_animation_target = nux::Point2(x, y);
}
+void LauncherDragWindow::StartQuickAnimation()
+{
+ animation_speed_ = QUICK_ANIMATION_SPEED;
+ StartAnimation();
+}
+
+void LauncherDragWindow::StartSlowAnimation()
+{
+ animation_speed_ = SLOW_ANIMATION_SPEED;
+ StartAnimation();
+}
+
void LauncherDragWindow::StartAnimation()
{
if (animation_timer_)
@@ -89,7 +108,7 @@ void LauncherDragWindow::StartAnimation()
}
bool LauncherDragWindow::OnAnimationTimeout()
-{
+{
nux::Geometry const& geo = GetGeometry();
int half_size = geo.width / 2;
@@ -97,11 +116,11 @@ bool LauncherDragWindow::OnAnimationTimeout()
int target_x = static_cast<int>(_animation_target.x) - half_size;
int target_y = static_cast<int>(_animation_target.y) - half_size;
- int x_delta = static_cast<int>(static_cast<float>(target_x - geo.x) * .3f);
+ int x_delta = static_cast<int>(static_cast<float>(target_x - geo.x) * animation_speed_);
if (std::abs(x_delta) < 5)
x_delta = (x_delta >= 0) ? std::min(5, target_x - geo.x) : std::max(-5, target_x - geo.x);
- int y_delta = static_cast<int>(static_cast<float>(target_y - geo.y) * .3f);
+ int y_delta = static_cast<int>(static_cast<float>(target_y - geo.y) * animation_speed_);
if (std::abs(y_delta) < 5)
y_delta = (y_delta >= 0) ? std::min(5, target_y - geo.y) : std::max(-5, target_y - geo.y);
diff --git a/launcher/LauncherDragWindow.h b/launcher/LauncherDragWindow.h
index cda37d342..10f17ab8c 100644
--- a/launcher/LauncherDragWindow.h
+++ b/launcher/LauncherDragWindow.h
@@ -42,7 +42,8 @@ public:
void DrawContent(nux::GraphicsEngine& gfxContext, bool forceDraw);
void SetAnimationTarget(int x, int y);
- void StartAnimation();
+ void StartQuickAnimation();
+ void StartSlowAnimation();
bool Animating() const;
bool Cancelled() const;
@@ -56,9 +57,11 @@ protected:
bool AcceptKeyNavFocus();
private:
+ void StartAnimation();
bool OnAnimationTimeout();
void CancelDrag();
-
+
+ float animation_speed_;
bool _cancelled;
nux::ObjectPtr<nux::IOpenGLBaseTexture> _icon;
nux::Point2 _animation_target;
diff --git a/launcher/LauncherIcon.cpp b/launcher/LauncherIcon.cpp
index e216358b4..5ddd5494f 100644
--- a/launcher/LauncherIcon.cpp
+++ b/launcher/LauncherIcon.cpp
@@ -74,10 +74,11 @@ glib::Object<GtkIconTheme> LauncherIcon::_unity_theme;
LauncherIcon::LauncherIcon(IconType type)
: _icon_type(type)
+ , _sticky(false)
, _remote_urgent(false)
, _present_urgency(0)
, _progress(0)
- , _sort_priority(0)
+ , _sort_priority(DefaultPriority(type))
, _last_monitor(0)
, _background_color(nux::color::White)
, _glow_color(nux::color::White)
@@ -89,7 +90,7 @@ LauncherIcon::LauncherIcon(IconType type)
, _saved_center(max_num_monitors)
, _allow_quicklist_to_show(true)
{
- for (unsigned i = 0; i < unsigned(Quirk::LAST); i++)
+ for (unsigned i = 0; i < unsigned(Quirk::LAST); ++i)
{
_quirks[i] = false;
_quirk_times[i].tv_sec = 0;
@@ -107,10 +108,10 @@ LauncherIcon::LauncherIcon(IconType type)
tooltip_text.SetSetterFunction(sigc::mem_fun(this, &LauncherIcon::SetTooltipText));
tooltip_text = "blank";
+ position = Position::FLOATING;
+
// FIXME: the abstraction is already broken, should be fixed for O
// right now, hooking the dynamic quicklist the less ugly possible way
-
-
mouse_enter.connect(sigc::mem_fun(this, &LauncherIcon::RecvMouseEnter));
mouse_leave.connect(sigc::mem_fun(this, &LauncherIcon::RecvMouseLeave));
mouse_down.connect(sigc::mem_fun(this, &LauncherIcon::RecvMouseDown));
@@ -517,6 +518,7 @@ LauncherIcon::ShowTooltip()
if (!_tooltip)
LoadTooltip();
+ _tooltip->SetText(tooltip_text());
_tooltip->ShowTooltipWithTipAt(tip_x, tip_y);
_tooltip->ShowWindow(!tooltip_text().empty());
tooltip_visible.emit(_tooltip);
@@ -1179,6 +1181,31 @@ void LauncherIcon::EmitRemove()
remove.emit(AbstractLauncherIcon::Ptr(this));
}
+void LauncherIcon::Stick(bool save)
+{
+ if (_sticky)
+ return;
+
+ _sticky = true;
+
+ if (save)
+ position_saved.emit();
+
+ SetQuirk(Quirk::VISIBLE, true);
+}
+
+void LauncherIcon::UnStick()
+{
+ if (!_sticky)
+ return;
+
+ _sticky = false;
+
+ position_forgot.emit();
+
+ SetQuirk(Quirk::VISIBLE, false);
+}
+
} // namespace launcher
} // namespace unity
diff --git a/launcher/LauncherIcon.h b/launcher/LauncherIcon.h
index 34bdb077e..c1b79a517 100644
--- a/launcher/LauncherIcon.h
+++ b/launcher/LauncherIcon.h
@@ -108,11 +108,6 @@ public:
const bool WindowVisibleOnViewport();
- virtual bool IsSpacer()
- {
- return false;
- };
-
float PresentUrgency();
float GetProgress();
@@ -188,9 +183,9 @@ public:
virtual std::string DesktopFile() { return std::string(""); }
- virtual bool IsSticky() const { return false; }
+ virtual bool IsSticky() const { return _sticky; }
- virtual bool IsVisible() const { return false; }
+ virtual bool IsVisible() const { return GetQuirk(Quirk::VISIBLE); }
virtual bool IsVisibleOnMonitor(int monitor) const;
@@ -198,9 +193,9 @@ public:
virtual void AboutToRemove() {}
- virtual void Stick(bool save = true) {}
+ virtual void Stick(bool save = true);
- virtual void UnStick() {}
+ virtual void UnStick();
protected:
std::vector<nux::Point3> GetCenters();
@@ -313,6 +308,7 @@ private:
void OnTooltipEnabledChanged(bool value);
+ bool _sticky;
bool _remote_urgent;
float _present_urgency;
float _progress;
diff --git a/launcher/LauncherModel.cpp b/launcher/LauncherModel.cpp
index 8e01465dd..6efefa106 100644
--- a/launcher/LauncherModel.cpp
+++ b/launcher/LauncherModel.cpp
@@ -56,14 +56,14 @@ unity::debug::Introspectable::IntrospectableList LauncherModel::GetIntrospectabl
bool LauncherModel::IconShouldShelf(AbstractLauncherIcon::Ptr const& icon) const
{
- return icon->GetIconType() == AbstractLauncherIcon::IconType::TRASH;
+ return icon->position() == AbstractLauncherIcon::Position::END;
}
bool LauncherModel::CompareIcons(AbstractLauncherIcon::Ptr const& first, AbstractLauncherIcon::Ptr const& second)
{
- if (first->GetIconType() < second->GetIconType())
+ if (first->position() < second->position())
return true;
- else if (first->GetIconType() > second->GetIconType())
+ else if (first->position() > second->position())
return false;
return first->SortPriority() < second->SortPriority();
@@ -163,25 +163,11 @@ bool LauncherModel::IconHasSister(AbstractLauncherIcon::Ptr const& icon) const
if (!icon)
return false;
- const_iterator it;
- const_iterator end;
+ auto const& container = IconShouldShelf(icon) ? _inner_shelf : _inner_main;
- if (IconShouldShelf(icon))
+ for (auto const& icon_it : container)
{
- it = _inner_shelf.begin();
- end = _inner_shelf.end();
- }
- else
- {
- it = _inner_main.begin();
- end = _inner_main.end();
- }
-
- for (; it != end; ++it)
- {
- AbstractLauncherIcon::Ptr const& iter_icon = *it;
-
- if (iter_icon != icon && iter_icon->GetIconType() == icon->GetIconType())
+ if (icon_it != icon && icon_it->GetIconType() == icon->GetIconType())
return true;
}
@@ -193,16 +179,20 @@ void LauncherModel::ReorderAfter(AbstractLauncherIcon::Ptr const& icon, Abstract
if (icon == other || icon.IsNull() || other.IsNull())
return;
- if (icon->GetIconType() != other->GetIconType())
+ if (icon->position() != other->position())
return;
icon->SetSortPriority(other->SortPriority() + 1);
for (auto it = std::next(std::find(begin(), end(), other)); it != end(); ++it)
{
- // Increasing the priority of the icons next to the other one
auto const& icon_it = *it;
- int new_priority = icon_it->SortPriority() + 1;
+
+ if (icon_it == icon)
+ continue;
+
+ // Increasing the priority of the icons next to the other one
+ int new_priority = icon_it->SortPriority() + 2;
icon_it->SetSortPriority(new_priority);
}
@@ -214,7 +204,7 @@ void LauncherModel::ReorderBefore(AbstractLauncherIcon::Ptr const& icon, Abstrac
if (icon == other || icon.IsNull() || other.IsNull())
return;
- if (icon->GetIconType() != other->GetIconType())
+ if (icon->position() != other->position())
return;
bool found_target = false;
@@ -228,7 +218,13 @@ void LauncherModel::ReorderBefore(AbstractLauncherIcon::Ptr const& icon, Abstrac
continue;
}
- int new_priority = icon_it->SortPriority() + (found_target ? 1 : -1);
+ int old_priority = icon_it->SortPriority();
+ int new_priority = old_priority + (found_target ? 1 : -1);
+
+ // We need to reduce the priority of all the icons previous to 'other'
+ if (icon_it != other && !found_target && other->SortPriority() == old_priority)
+ new_priority -= 1;
+
icon_it->SetSortPriority(new_priority);
if (icon_it == other)
@@ -237,7 +233,7 @@ void LauncherModel::ReorderBefore(AbstractLauncherIcon::Ptr const& icon, Abstrac
icon_it->SaveCenter();
center = !center;
- new_priority = new_priority - 1;
+ new_priority += -1;
icon->SetSortPriority(new_priority);
if (animate && center)
@@ -260,7 +256,7 @@ void LauncherModel::ReorderSmart(AbstractLauncherIcon::Ptr const& icon, Abstract
if (icon == other || icon.IsNull() || other.IsNull())
return;
- if (icon->GetIconType() != other->GetIconType())
+ if (icon->position() != other->position())
return;
bool found_icon = false;
@@ -276,7 +272,13 @@ void LauncherModel::ReorderSmart(AbstractLauncherIcon::Ptr const& icon, Abstract
continue;
}
- int new_priority = icon_it->SortPriority() + (found_target ? 1 : -1);
+ int old_priority = icon_it->SortPriority();
+ int new_priority = old_priority + (found_target ? 1 : -1);
+
+ // We need to reduce the priority of all the icons previous to 'other'
+ if (icon_it != other && !found_target && other->SortPriority() == old_priority)
+ new_priority -= 1;
+
icon_it->SetSortPriority(new_priority);
if (icon_it == other)
@@ -285,7 +287,7 @@ void LauncherModel::ReorderSmart(AbstractLauncherIcon::Ptr const& icon, Abstract
icon_it->SaveCenter();
center = !center;
- new_priority = new_priority + (found_icon ? 1 : -1);
+ new_priority += found_icon ? 1 : -1;
icon->SetSortPriority(new_priority);
if (animate && center)
@@ -377,7 +379,7 @@ AbstractLauncherIcon::Ptr LauncherModel::GetClosestIcon(AbstractLauncherIcon::Pt
for (auto const& current : _inner)
{
- if (current->GetIconType() != icon->GetIconType())
+ if (current->position() != icon->position())
continue;
if (!found_target)
diff --git a/launcher/MockLauncherIcon.h b/launcher/MockLauncherIcon.h
index b52cb272b..a5c95457a 100644
--- a/launcher/MockLauncherIcon.h
+++ b/launcher/MockLauncherIcon.h
@@ -45,20 +45,20 @@ class MockLauncherIcon : public AbstractLauncherIcon
NUX_DECLARE_OBJECT_TYPE(MockLauncherIcon, AbstractLauncherIcon);
public:
MockLauncherIcon(IconType type = IconType::APPLICATION)
- : type_(type)
- , sort_priority_(0)
- , icon_(0)
+ : icon_(0)
+ , type_(type)
+ , sort_priority_(DefaultPriority(type))
+ , remote_uri_("fake")
{
tooltip_text = "Mock Icon";
+ position = Position::FLOATING;
for (unsigned i = 0; i < unsigned(Quirk::LAST); ++i)
- {
quirks_[i] = false;
- }
}
std::string GetName() const { return "MockLauncherIcon"; }
-
+
void AddProperties(GVariantBuilder* builder) {}
void HideTooltip() {}
@@ -180,11 +180,6 @@ public:
return true;
}
- bool IsSpacer()
- {
- return false;
- }
-
float PresentUrgency()
{
return 0.0f;
@@ -244,7 +239,7 @@ public:
std::string RemoteUri()
{
- return "fake";
+ return remote_uri_;
}
nux::BaseTexture* TextureForSize(int size)
@@ -293,9 +288,9 @@ public:
bool IsVisible() const { return false; }
void AboutToRemove() {}
-
+
void Stick(bool save = true) {}
-
+
void UnStick() {}
private:
@@ -346,12 +341,13 @@ private:
return result;
}
+ nux::BaseTexture* icon_;
IconType type_;
int sort_priority_;
- nux::BaseTexture* icon_;
bool quirks_[unsigned(Quirk::LAST)];
timespec quirk_times_[unsigned(Quirk::LAST)];
std::map<int, nux::Point3> center_;
+ std::string remote_uri_;
};
}
diff --git a/launcher/SoftwareCenterLauncherIcon.cpp b/launcher/SoftwareCenterLauncherIcon.cpp
index 93227a2a8..df29e37f7 100644
--- a/launcher/SoftwareCenterLauncherIcon.cpp
+++ b/launcher/SoftwareCenterLauncherIcon.cpp
@@ -45,23 +45,19 @@ SoftwareCenterLauncherIcon::SoftwareCenterLauncherIcon(BamfApplication* app,
, needs_urgent_(false)
, aptdaemon_trans_id_(aptdaemon_trans_id)
{
-
+ SetQuirk(Quirk::VISIBLE, false);
aptdaemon_trans_.Connect("PropertyChanged", sigc::mem_fun(this, &SoftwareCenterLauncherIcon::OnPropertyChanged));
aptdaemon_trans_.Connect("Finished", sigc::mem_fun(this, &SoftwareCenterLauncherIcon::OnFinished));
- icon_name = icon_path;
+ if (!icon_path.empty())
+ icon_name = icon_path;
+
if (!aptdaemon_trans_id_.empty()) // Application is being installed, or hasn't been installed yet
tooltip_text = _("Waiting to install");
}
-void SoftwareCenterLauncherIcon::Animate(nux::ObjectPtr<Launcher> launcher,
- int icon_x,
- int icon_y,
- int icon_size)
+void SoftwareCenterLauncherIcon::Animate(nux::ObjectPtr<Launcher> const& launcher, int start_x, int start_y)
{
- int target_x = 0;
- int target_y = 0;
-
launcher_ = launcher;
icon_texture_ = nux::GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(
@@ -72,54 +68,45 @@ void SoftwareCenterLauncherIcon::Animate(nux::ObjectPtr<Launcher> launcher,
drag_window_ = new LauncherDragWindow(icon_texture_);
+ launcher->ForceReveal(true);
launcher->RenderIconToTexture(nux::GetWindowThread()->GetGraphicsEngine(),
AbstractLauncherIcon::Ptr(this),
icon_texture_);
- drag_window_->SetBaseXY(icon_x, icon_y);
+ auto const& icon_center = GetCenter(launcher->monitor());
+ drag_window_->SetBaseXY(start_x, start_y);
drag_window_->ShowWindow(true);
-
- // Find out the center of last BamfLauncherIcon with non-zero co-ordinates
- auto bamf_icons = launcher->GetModel()->GetSublist<BamfLauncherIcon>();
- //TODO: don't iterate through them and pick the last one, just use back() to get the last one.
- for (auto current_bamf_icon : bamf_icons)
- {
- auto icon_center = current_bamf_icon->GetCenter(launcher->monitor);
-
- if (icon_center.x != 0 && icon_center.y != 0)
- {
- target_x = icon_center.x;
- target_y = icon_center.y;
- }
- }
-
- target_y = target_y + (launcher->GetIconSize() / 2);
- drag_window_->SetAnimationTarget(target_x, target_y);
-
+ drag_window_->SetAnimationTarget(icon_center.x, icon_center.y + (launcher->GetIconSize() / 2));
drag_window_->on_anim_completed = drag_window_->anim_completed.connect(sigc::mem_fun(this, &SoftwareCenterLauncherIcon::OnDragAnimationFinished));
- drag_window_->StartAnimation();
+ drag_window_->StartSlowAnimation();
}
void SoftwareCenterLauncherIcon::OnDragAnimationFinished()
{
drag_window_->ShowWindow(false);
- launcher_->icon_animation_complete.emit(AbstractLauncherIcon::Ptr(this));
drag_window_ = nullptr;
+ launcher_->ForceReveal(false);
+ launcher_ = nullptr;
+ icon_texture_ = nullptr;
+ SetQuirk(Quirk::VISIBLE, true);
}
void SoftwareCenterLauncherIcon::ActivateLauncherIcon(ActionArg arg)
{
if (finished_)
{
- if (needs_urgent_)
- {
- SetQuirk(Quirk::URGENT, false);
- needs_urgent_ = false;
- }
- BamfLauncherIcon::ActivateLauncherIcon(arg);
+ if (needs_urgent_)
+ {
+ SetQuirk(Quirk::URGENT, false);
+ needs_urgent_ = false;
+ }
+
+ BamfLauncherIcon::ActivateLauncherIcon(arg);
}
else
- SetQuirk(Quirk::STARTING, false);
+ {
+ SetQuirk(Quirk::STARTING, false);
+ }
}
void SoftwareCenterLauncherIcon::OnFinished(GVariant *params)
@@ -135,7 +122,9 @@ void SoftwareCenterLauncherIcon::OnFinished(GVariant *params)
SetProgress(0.0f);
finished_ = true;
needs_urgent_ = true;
- } else {
+ }
+ else
+ {
// failure condition, remove icon again
UnStick();
}
@@ -167,7 +156,7 @@ void SoftwareCenterLauncherIcon::OnPropertyChanged(GVariant* params)
std::string SoftwareCenterLauncherIcon::GetName() const
{
- return "SoftwareCenterLauncherIcon";
+ return "SoftwareCenterLauncherIcon";
}
}
diff --git a/launcher/SoftwareCenterLauncherIcon.h b/launcher/SoftwareCenterLauncherIcon.h
index 70794437a..a25d5babb 100644
--- a/launcher/SoftwareCenterLauncherIcon.h
+++ b/launcher/SoftwareCenterLauncherIcon.h
@@ -42,7 +42,7 @@ public:
std::string const& aptdaemon_trans_id,
std::string const& icon_path);
- void Animate(nux::ObjectPtr<Launcher> launcher, int icon_x, int icon_y, int icon_size);
+ void Animate(nux::ObjectPtr<Launcher> const& launcher, int start_x, int start_y);
std::string GetName() const;
diff --git a/launcher/SpacerLauncherIcon.cpp b/launcher/SpacerLauncherIcon.cpp
index db4803b7a..3839e4a77 100644
--- a/launcher/SpacerLauncherIcon.cpp
+++ b/launcher/SpacerLauncherIcon.cpp
@@ -28,7 +28,7 @@ namespace launcher
{
SpacerLauncherIcon::SpacerLauncherIcon(int monitor)
- : SingleMonitorLauncherIcon(IconType::APPLICATION, monitor)
+ : SingleMonitorLauncherIcon(IconType::SPACER, monitor)
{
SetQuirk(Quirk::VISIBLE, true);
SetQuirk(Quirk::RUNNING, false);
diff --git a/launcher/SpacerLauncherIcon.h b/launcher/SpacerLauncherIcon.h
index 584d25253..f31303f0c 100644
--- a/launcher/SpacerLauncherIcon.h
+++ b/launcher/SpacerLauncherIcon.h
@@ -32,10 +32,6 @@ class SpacerLauncherIcon : public SingleMonitorLauncherIcon
public:
SpacerLauncherIcon(int monitor);
- bool IsSpacer()
- {
- return true;
- }
protected:
std::string GetName() const;
};
diff --git a/launcher/StandaloneLauncher.cpp b/launcher/StandaloneLauncher.cpp
index 43eb597f0..cef9f0c9f 100644
--- a/launcher/StandaloneLauncher.cpp
+++ b/launcher/StandaloneLauncher.cpp
@@ -46,7 +46,7 @@ static launcher::Controller::Ptr controller;
void ThreadWidgetInit(nux::NThread* thread, void* InitData)
{
// launcherWindow->SetGeometry (nux::Geometry(0, 0, 300, 800));
- controller.reset(new launcher::Controller(0));
+ controller.reset(new launcher::Controller());
}
int main(int argc, char** argv)
diff --git a/launcher/TrashLauncherIcon.cpp b/launcher/TrashLauncherIcon.cpp
index d9cd579a7..865d3edfe 100644
--- a/launcher/TrashLauncherIcon.cpp
+++ b/launcher/TrashLauncherIcon.cpp
@@ -46,6 +46,7 @@ TrashLauncherIcon::TrashLauncherIcon()
{
tooltip_text = _("Trash");
icon_name = "user-trash";
+ position = Position::END;
SetQuirk(Quirk::VISIBLE, true);
SetQuirk(Quirk::RUNNING, false);
SetShortcut('t');
diff --git a/launcher/VolumeLauncherIcon.cpp b/launcher/VolumeLauncherIcon.cpp
index bba622e9b..cbe9fcff2 100644
--- a/launcher/VolumeLauncherIcon.cpp
+++ b/launcher/VolumeLauncherIcon.cpp
@@ -26,6 +26,7 @@
#include "DevicesSettings.h"
#include "Volume.h"
#include "VolumeLauncherIcon.h"
+#include "FavoriteStore.h"
namespace unity
{
@@ -36,7 +37,7 @@ namespace
nux::logging::Logger logger("unity.launcher");
-const unsigned int volume_changed_timeout = 500;
+const unsigned int volume_changed_timeout = 500;
}
@@ -61,7 +62,7 @@ public:
}
~Impl()
- {
+ {
volume_changed_conn_.disconnect();
volume_removed_conn_.disconnect();
settings_changed_conn_.disconnect();
@@ -83,7 +84,7 @@ public:
void UpdateKeepInLauncher()
{
- auto identifier = volume_->GetIdentifier();
+ auto const& identifier = volume_->GetIdentifier();
keep_in_launcher_ = !devices_settings_->IsABlacklistedDevice(identifier);
}
@@ -104,6 +105,7 @@ public:
if (devices_settings_->IsABlacklistedDevice(volume_->GetIdentifier()))
devices_settings_->TryToUnblacklist(volume_->GetIdentifier());
+ parent_->UnStick();
parent_->Remove();
}
@@ -163,7 +165,8 @@ public:
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 identifier = volume_->GetIdentifier();
+ auto const& identifier = volume_->GetIdentifier();
+ parent_->UnStick();
devices_settings_->TryToBlacklist(identifier);
}));
@@ -239,6 +242,16 @@ public:
menu.push_back(menu_item);
}
+ std::string GetRemoteUri()
+ {
+ auto const& identifier = volume_->GetIdentifier();
+
+ if (identifier.empty())
+ return "";
+
+ return FavoriteStore::URI_PREFIX_DEVICE + identifier;
+ }
+
VolumeLauncherIcon* parent_;
bool keep_in_launcher_;
Volume::Ptr volume_;
@@ -293,6 +306,23 @@ AbstractLauncherIcon::MenuItemsVector VolumeLauncherIcon::GetMenus()
return pimpl_->GetMenus();
}
+std::string VolumeLauncherIcon::GetRemoteUri()
+{
+ return pimpl_->GetRemoteUri();
+}
+
+void VolumeLauncherIcon::Stick(bool save)
+{
+ SimpleLauncherIcon::Stick(save);
+ pimpl_->devices_settings_->TryToUnblacklist(pimpl_->volume_->GetIdentifier());
+}
+
+void VolumeLauncherIcon::UnStick()
+{
+ SimpleLauncherIcon::UnStick();
+ SetQuirk(Quirk::VISIBLE, true);
+}
+
//
// Introspection
//
diff --git a/launcher/VolumeLauncherIcon.h b/launcher/VolumeLauncherIcon.h
index 48e3e975f..a8bfb1ec1 100644
--- a/launcher/VolumeLauncherIcon.h
+++ b/launcher/VolumeLauncherIcon.h
@@ -43,7 +43,10 @@ public:
void EjectAndShowNotification(); // TODO: rename to private virtual void DoDropToTrash();
bool CanStop() const;
void StopDrive();
+ void Stick(bool save = true);
+ void UnStick();
MenuItemsVector GetMenus();
+ std::string GetRemoteUri();
protected:
virtual void ActivateLauncherIcon(ActionArg arg);
diff --git a/manual-tests/Launcher.txt b/manual-tests/Launcher.txt
index f31610116..fa5e5268b 100644
--- a/manual-tests/Launcher.txt
+++ b/manual-tests/Launcher.txt
@@ -191,6 +191,21 @@ Expected Result:
it, and the any pips for running apps show again.
+Dragging fixed icons does not reorder an icon above or below
+------------------------------------------------------------
+This test is about not reordering when dragging fixed icons.
+
+#. Move the mouse so it is over the BFB launcher icon
+#. Press and hold the mouse button
+#. Try to drag the icon to the right of the launcher.
+#. Move the mouse down at least to the height of the second launcher icon
+ keeping the mouse pressed.
+#. Release
+
+Outcome:
+ * No icon should be dragged.
+
+
Dragged launcher icons out of the launcher are properly drawn
-------------------------------------------------------------
This test ensures that the launcher icons out of the launcher are properly drawn
diff --git a/panel/PanelMenuView.h b/panel/PanelMenuView.h
index 6fc954a6c..be7e452c3 100644
--- a/panel/PanelMenuView.h
+++ b/panel/PanelMenuView.h
@@ -136,7 +136,6 @@ private:
glib::Object<BamfMatcher> _matcher;
nux::TextureLayer* _title_layer;
- nux::HLayout* _menu_layout;
nux::ObjectPtr<WindowButtons> _window_buttons;
nux::ObjectPtr<PanelTitlebarGrabArea> _titlebar_grab_area;
nux::ObjectPtr<nux::BaseTexture> _title_texture;
diff --git a/panel/WindowButtons.cpp b/panel/WindowButtons.cpp
index 2f2c149dd..6d8e7d15b 100644
--- a/panel/WindowButtons.cpp
+++ b/panel/WindowButtons.cpp
@@ -395,7 +395,7 @@ WindowButtons::WindowButtons()
ubus_manager_.RegisterInterest(UBUS_OVERLAY_SHOWN, sigc::mem_fun(this, &WindowButtons::OnOverlayShown));
ubus_manager_.RegisterInterest(UBUS_OVERLAY_HIDDEN, sigc::mem_fun(this, &WindowButtons::OnOverlayHidden));
- Settings::Instance().changed.connect(sigc::mem_fun(this, &WindowButtons::OnDashSettingsUpdated));
+ Settings::Instance().form_factor.changed.connect(sigc::mem_fun(this, &WindowButtons::OnDashSettingsUpdated));
}
nux::Area* WindowButtons::FindAreaUnderMouse(const nux::Point& mouse, nux::NuxEventType event_type)
@@ -470,7 +470,7 @@ void WindowButtons::OnRestoreClicked(nux::Button *button)
if (win_button->IsOverlayOpen())
{
- Settings::Instance().SetFormFactor(FormFactor::DESKTOP);
+ Settings::Instance().form_factor = FormFactor::DESKTOP;
}
else
{
@@ -494,7 +494,7 @@ void WindowButtons::OnMaximizeClicked(nux::Button *button)
if (win_button->IsOverlayOpen())
{
- Settings::Instance().SetFormFactor(FormFactor::NETBOOK);
+ Settings::Instance().form_factor = FormFactor::NETBOOK;
}
maximize_clicked.emit();
@@ -550,7 +550,7 @@ void WindowButtons::OnOverlayShown(GVariant* data)
if (restore_button && maximize_button)
{
Settings &dash_settings = Settings::Instance();
- bool maximizable = (dash_settings.GetFormFactor() == FormFactor::DESKTOP);
+ bool maximizable = (dash_settings.form_factor() == FormFactor::DESKTOP);
restore_button->SetEnabled(can_maximise);
maximize_button->SetEnabled(can_maximise);
@@ -645,7 +645,7 @@ void WindowButtons::OnOverlayHidden(GVariant* data)
}
}
-void WindowButtons::OnDashSettingsUpdated()
+void WindowButtons::OnDashSettingsUpdated(FormFactor form_factor)
{
WindowButton* maximize_button = nullptr;
WindowButton* restore_button = nullptr;
@@ -672,8 +672,7 @@ void WindowButtons::OnDashSettingsUpdated()
if (restore_button && restore_button->IsOverlayOpen() && maximize_button)
{
- Settings &dash_settings = Settings::Instance();
- bool maximizable = (dash_settings.GetFormFactor() == FormFactor::DESKTOP);
+ bool maximizable = (form_factor == FormFactor::DESKTOP);
if (maximizable != maximize_button->IsVisible())
{
diff --git a/panel/WindowButtons.h b/panel/WindowButtons.h
index b798d7b57..41e708bfe 100644
--- a/panel/WindowButtons.h
+++ b/panel/WindowButtons.h
@@ -26,6 +26,7 @@
#include "unity-shared/UBusWrapper.h"
#include "unity-shared/Introspectable.h"
+#include "unity-shared/UnitySettings.h"
namespace unity
{
@@ -70,7 +71,7 @@ private:
void OnMaximizeClicked(nux::Button *button);
void OnOverlayShown(GVariant* data);
void OnOverlayHidden(GVariant* data);
- void OnDashSettingsUpdated();
+ void OnDashSettingsUpdated(FormFactor form_factor);
int monitor_;
double opacity_;
diff --git a/plugins/unityshell/src/unityshell.cpp b/plugins/unityshell/src/unityshell.cpp
index f1c59d49f..45cd3c00e 100644
--- a/plugins/unityshell/src/unityshell.cpp
+++ b/plugins/unityshell/src/unityshell.cpp
@@ -276,7 +276,6 @@ UnityScreen::UnityScreen(CompScreen* screen)
optionSetAutohideAnimationNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
optionSetDashBlurExperimentalNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
optionSetShortcutOverlayNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
- optionSetShowDesktopIconNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
optionSetShowLauncherInitiate(boost::bind(&UnityScreen::showLauncherKeyInitiate, this, _1, _2, _3));
optionSetShowLauncherTerminate(boost::bind(&UnityScreen::showLauncherKeyTerminate, this, _1, _2, _3));
optionSetKeyboardFocusInitiate(boost::bind(&UnityScreen::setKeyboardFocusKeyInitiate, this, _1, _2, _3));
@@ -923,6 +922,33 @@ void UnityScreen::leaveShowDesktopMode (CompWindow *w)
}
}
+bool UnityScreen::DoesPointIntersectUnityGeos(nux::Point const& pt)
+{
+ auto launchers = launcher_controller_->launchers();
+ for (auto launcher : launchers)
+ {
+ nux::Geometry hud_geo = launcher->GetAbsoluteGeometry();
+
+ if (launcher->Hidden())
+ continue;
+
+ if (hud_geo.IsInside(pt))
+ {
+ return true;
+ }
+ }
+
+ for (nux::Geometry &panel_geo : panel_controller_->GetGeometries ())
+ {
+ if (panel_geo.IsInside(pt))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void UnityWindow::enterShowDesktop ()
{
if (!mShowdesktopHandler)
@@ -1441,12 +1467,26 @@ void UnityScreen::handleEvent(XEvent* event)
if (CompWindow *w = screen->findWindow(ss->getSelectedWindow()))
skip_other_plugins = UnityWindow::get(w)->handleEvent(event);
}
- if (launcher_controller_->IsOverlayOpen())
+
+
+ if (dash_controller_->IsVisible())
{
- int monitor_with_mouse = UScreen::GetDefault()->GetMonitorWithMouse();
- if (overlay_monitor_ != monitor_with_mouse)
+ nux::Point pt(event->xbutton.x_root, event->xbutton.y_root);
+ nux::Geometry dash_geo = dash_controller_->GetInputWindowGeometry();
+
+ if (!dash_geo.IsInside(pt) && !DoesPointIntersectUnityGeos(pt))
{
dash_controller_->HideDash(false);
+ }
+ }
+
+ if (hud_controller_->IsVisible())
+ {
+ nux::Point pt(event->xbutton.x_root, event->xbutton.y_root);
+ nux::Geometry hud_geo = hud_controller_->GetInputWindowGeometry();
+
+ if (!hud_geo.IsInside(pt) && !DoesPointIntersectUnityGeos(pt))
+ {
hud_controller_->HideHud(false);
}
}
@@ -2690,6 +2730,7 @@ CompPoint UnityWindow::tryNotIntersectUI(CompPoint& pos)
return pos;
}
+
bool UnityWindow::place(CompPoint& pos)
{
bool was_maximized = PluginAdapter::Default ()->MaximizeIfBigEnough(window);
@@ -2853,9 +2894,6 @@ void UnityScreen::optionChanged(CompOption* opt, UnityshellOptions::Options num)
enable_shortcut_overlay_ = optionGetShortcutOverlay();
shortcut_controller_->SetEnabled(enable_shortcut_overlay_);
break;
- case UnityshellOptions::ShowDesktopIcon:
- launcher_controller_->SetShowDesktopIcon(optionGetShowDesktopIcon());
- break;
case UnityshellOptions::DecayRate:
launcher_options->edge_decay_rate = optionGetDecayRate() * 100;
break;
@@ -2928,11 +2966,13 @@ bool UnityScreen::setOptionForPlugin(const char* plugin, const char* name,
CompOption::Value& v)
{
bool status = screen->setOptionForPlugin(plugin, name, v);
+
if (status)
{
- if (strcmp(plugin, "core") == 0 && strcmp(name, "hsize") == 0)
+ if (strcmp(plugin, "core") == 0)
{
- launcher_controller_->UpdateNumWorkspaces(screen->vpSize().width() * screen->vpSize().height());
+ if (strcmp(name, "hsize") == 0 || strcmp(name, "vsize") == 0)
+ launcher_controller_->UpdateNumWorkspaces(screen->vpSize().width() * screen->vpSize().height());
}
}
return status;
@@ -2963,7 +3003,7 @@ void UnityScreen::OnDashRealized ()
void UnityScreen::initLauncher()
{
Timer timer;
- launcher_controller_ = std::make_shared<launcher::Controller>(screen->dpy());
+ launcher_controller_ = std::make_shared<launcher::Controller>();
AddChild(launcher_controller_.get());
switcher_controller_ = std::make_shared<switcher::Controller>();
@@ -3692,7 +3732,7 @@ void UnityWindow::scalePaintDecoration(GLWindowPaintAttrib const& attrib,
void UnityWindow::OnInitiateSpreed()
{
- auto const windows = screen->windows();
+ auto const& windows = screen->windows();
if (std::find(windows.begin(), windows.end(), window) == windows.end())
return;
@@ -3708,7 +3748,7 @@ void UnityWindow::OnInitiateSpreed()
void UnityWindow::OnTerminateSpreed()
{
- auto const windows = screen->windows();
+ auto const& windows = screen->windows();
if (std::find(windows.begin(), windows.end(), window) == windows.end())
return;
diff --git a/plugins/unityshell/src/unityshell.h b/plugins/unityshell/src/unityshell.h
index 1c3091497..dabc386fe 100644
--- a/plugins/unityshell/src/unityshell.h
+++ b/plugins/unityshell/src/unityshell.h
@@ -190,6 +190,8 @@ public:
switcher::Controller::Ptr switcher_controller();
launcher::Controller::Ptr launcher_controller();
+ bool DoesPointIntersectUnityGeos(nux::Point const& pt);
+
protected:
std::string GetName() const;
void AddProperties(GVariantBuilder* builder);
@@ -344,7 +346,8 @@ class UnityWindow :
public compiz::WindowInputRemoverLockAcquireInterface,
public WrapableHandler<ScaleWindowInterface, 4>,
public BaseSwitchWindow,
- public PluginClassHandler <UnityWindow, CompWindow>
+ public PluginClassHandler <UnityWindow, CompWindow>,
+ public sigc::trackable
{
public:
UnityWindow(CompWindow*);
diff --git a/plugins/unityshell/unityshell.xml.in b/plugins/unityshell/unityshell.xml.in
index 98571394a..abaa07cba 100644
--- a/plugins/unityshell/unityshell.xml.in
+++ b/plugins/unityshell/unityshell.xml.in
@@ -400,12 +400,6 @@
<default>true</default>
</option>
- <option name="show_desktop_icon" type="bool">
- <_short>Show "Desktop Icon" in the launcher</_short>
- <_long>Enable/Disable "Show Desktop Icon" in the launcher.</_long>
- <default>false</default>
- </option>
-
<option name="menus_fadein" type="int">
<_short>Menus Fade-in duration</_short>
<_long>Duration (in milliseconds) of the menus fade-in animation, used when the mouse goes over the top-panel.</_long>
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 402d1cad8..3b868e16f 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -3,16 +3,16 @@ set(UNITY_SRC ../plugins/unityshell/src)
#
# Data
#
-configure_file (${CMAKE_CURRENT_SOURCE_DIR}/data/ubuntuone-installer.desktop
- ${CMAKE_BINARY_DIR}/tests/data/ubuntuone-installer.desktop)
-configure_file (${CMAKE_CURRENT_SOURCE_DIR}/data/ubuntu-software-center.desktop
- ${CMAKE_BINARY_DIR}/tests/data/ubuntu-software-center.desktop)
-configure_file (${CMAKE_CURRENT_SOURCE_DIR}/data/update-manager.desktop
- ${CMAKE_BINARY_DIR}/tests/data/update-manager.desktop)
-configure_file (${CMAKE_CURRENT_SOURCE_DIR}/data/bzr-handle-patch.desktop
- ${CMAKE_BINARY_DIR}/tests/data/bzr-handle-patch.desktop)
-configure_file (${CMAKE_CURRENT_SOURCE_DIR}/data/no-icon.desktop
- ${CMAKE_BINARY_DIR}/tests/data/no-icon.desktop)
+configure_file (${CMAKE_CURRENT_SOURCE_DIR}/data/applications/ubuntuone-installer.desktop
+ ${CMAKE_BINARY_DIR}/tests/data/applications/ubuntuone-installer.desktop)
+configure_file (${CMAKE_CURRENT_SOURCE_DIR}/data/applications/ubuntu-software-center.desktop
+ ${CMAKE_BINARY_DIR}/tests/data/applications/ubuntu-software-center.desktop)
+configure_file (${CMAKE_CURRENT_SOURCE_DIR}/data/applications/update-manager.desktop
+ ${CMAKE_BINARY_DIR}/tests/data/applications/update-manager.desktop)
+configure_file (${CMAKE_CURRENT_SOURCE_DIR}/data/applications/bzr-handle-patch.desktop
+ ${CMAKE_BINARY_DIR}/tests/data/applications/bzr-handle-patch.desktop)
+configure_file (${CMAKE_CURRENT_SOURCE_DIR}/data/applications/no-icon.desktop
+ ${CMAKE_BINARY_DIR}/tests/data/applications/no-icon.desktop)
#
# Unit tests
#
@@ -136,6 +136,7 @@ if (GTEST_SRC_DIR AND
test_indicator_entry.cpp
test_indicators.cpp
test_introspection.cpp
+ test_favorite_store.cpp
test_favorite_store_gsettings.cpp
test_favorite_store_private.cpp
test_home_lens.cpp
@@ -200,20 +201,23 @@ if (GTEST_SRC_DIR AND
# Tests that require X
add_executable(test-gtest
test_main.cpp
- test_bamflaunchericon.cpp
+ test_bamf_launcher_icon.cpp
test_bfb_launcher_icon.cpp
test_dashview_impl.cpp
+ test_desktop_launcher_icon.cpp
test_edge_barrier_controller.cpp
test_launcher.cpp
test_device_launcher_section.cpp
test_lensview_impl.cpp
test_hud_button.cpp
test_hud_controller.cpp
+ test_hud_launcher_icon.cpp
test_hud_view.cpp
test_icon_loader.cpp
test_im_text_entry.cpp
test_launcher_controller.cpp
test_launcher_drag_window.cpp
+ test_launcher_icon.cpp
test_keyboard_util.cpp
test_panel_style.cpp
test_previews_application.cpp
@@ -226,11 +230,15 @@ if (GTEST_SRC_DIR AND
test_resultviewgrid.cpp
test_shortcut_controller.cpp
test_single_monitor_launcher_icon.cpp
+ test_software_center_launcher_icon.cpp
+ test_expo_launcher_icon.cpp
test_switcher_controller.cpp
test_switcher_model.cpp
test_texture_cache.cpp
test_thumbnail_generator.cpp
+ test_trash_launcher_icon.cpp
test_launcher_minimize_speed.cpp
+ test_unity_settings.cpp
test_volume_imp.cpp
test_volume_launcher_icon.cpp
gmockmount.c
@@ -273,6 +281,7 @@ if (GTEST_SRC_DIR AND
${CMAKE_SOURCE_DIR}/launcher/DevicesSettingsImp.cpp
${CMAKE_SOURCE_DIR}/launcher/DndData.cpp
${CMAKE_SOURCE_DIR}/launcher/EdgeBarrierController.cpp
+ ${CMAKE_SOURCE_DIR}/launcher/ExpoLauncherIcon.cpp
${CMAKE_SOURCE_DIR}/launcher/FavoriteStore.cpp
${CMAKE_SOURCE_DIR}/launcher/FavoriteStoreGSettings.cpp
${CMAKE_SOURCE_DIR}/launcher/FavoriteStorePrivate.cpp
diff --git a/tests/autopilot/unity/emulators/dash.py b/tests/autopilot/unity/emulators/dash.py
index 0d38591e8..b23ddaa3a 100644
--- a/tests/autopilot/unity/emulators/dash.py
+++ b/tests/autopilot/unity/emulators/dash.py
@@ -155,6 +155,10 @@ class Dash(KeybindingsHelper):
active_lens_name = self.view.get_lensbar().active_lens
return self.view.get_lensview_by_name(active_lens_name)
+ @property
+ def geometry(self):
+ return (self.view.x, self.view.y, self.view.width, self.view.height)
+
class DashController(UnityIntrospectionObject):
"""The main dash controller object."""
diff --git a/tests/autopilot/unity/tests/test_dash.py b/tests/autopilot/unity/tests/test_dash.py
index 335e9491e..2c872c2c4 100644
--- a/tests/autopilot/unity/tests/test_dash.py
+++ b/tests/autopilot/unity/tests/test_dash.py
@@ -107,6 +107,39 @@ class DashRevealTests(DashTestCase):
self.dash.reveal_application_lens()
self.assertThat(self.dash.active_lens, Eventually(Equals('applications.lens')))
+ def test_closes_mouse_down_outside(self):
+ """Test that a mouse down outside of the dash closes the dash."""
+
+ self.dash.ensure_visible()
+ current_monitor = self.dash.monitor
+
+ (x,y,w,h) = self.dash.geometry
+ (screen_x,screen_y,screen_w,screen_h) = self.screen_geo.get_monitor_geometry(current_monitor)
+
+ self.mouse.move(x + w + (screen_w-((screen_x-x)+w))/2, y + h + (screen_h-((screen_y-y)+h))/2)
+ self.mouse.click()
+
+ self.assertThat(self.dash.visible, Eventually(Equals(False)))
+
+ def test_closes_then_focuses_window_on_mouse_down(self):
+ """If 2 windows are open with 1 maximized and the non-maxmized
+ focused. Then from the Dash clicking on the maximized window
+ must focus that window and close the dash.
+ """
+ char_win = self.start_app("Character Map")
+ self.keybinding("window/maximize")
+ self.start_app("Calculator")
+
+ self.dash.ensure_visible()
+
+ #Click bottom right of the screen
+ w = self.screen_geo.get_screen_width()
+ h = self.screen_geo.get_screen_height()
+ self.mouse.move(w,h)
+ self.mouse.click()
+
+ self.assertProperty(char_win, is_active=True)
+
class DashSearchInputTests(DashTestCase):
"""Test features involving input to the dash search"""
diff --git a/tests/autopilot/unity/tests/test_hud.py b/tests/autopilot/unity/tests/test_hud.py
index 2472ef2db..6cd171d43 100644
--- a/tests/autopilot/unity/tests/test_hud.py
+++ b/tests/autopilot/unity/tests/test_hud.py
@@ -409,6 +409,38 @@ class HudBehaviorTests(HudTestsBase):
self.keyboard.type("HasFocus")
self.assertThat(self.hud.search_string, Eventually(Equals("HasFocus")))
+ def test_closes_mouse_down_outside(self):
+ """Test that a mouse down outside of the hud closes the hud."""
+
+ self.hud.ensure_visible()
+ current_monitor = self.hud.monitor
+
+ (x,y,w,h) = self.hud.geometry
+ (screen_x,screen_y,screen_w,screen_h) = self.screen_geo.get_monitor_geometry(current_monitor)
+
+ self.mouse.move(x + w + (screen_w-((screen_x-x)+w))/2, y + h + (screen_h-((screen_y-y)+h))/2)
+ self.mouse.click()
+
+ self.assertThat(self.hud.visible, Eventually(Equals(False)))
+
+ def test_closes_then_focuses_window_on_mouse_down(self):
+ """If 2 windows are open with 1 maximized and the non-maxmized
+ focused. Then from the Hud clicking on the maximized window
+ must focus that window and close the hud.
+ """
+ char_win = self.start_app("Character Map")
+ self.keybinding("window/maximize")
+ self.start_app("Calculator")
+
+ self.hud.ensure_visible()
+
+ #Click bottom right of the screen
+ w = self.screen_geo.get_screen_width()
+ h = self.screen_geo.get_screen_height()
+ self.mouse.move(w,h)
+ self.mouse.click()
+
+ self.assertProperty(char_win, is_active=True)
class HudLauncherInteractionsTests(HudTestsBase):
diff --git a/tests/data/bzr-handle-patch.desktop b/tests/data/applications/bzr-handle-patch.desktop
index 900e34d8d..900e34d8d 100644
--- a/tests/data/bzr-handle-patch.desktop
+++ b/tests/data/applications/bzr-handle-patch.desktop
diff --git a/tests/data/no-icon.desktop b/tests/data/applications/no-icon.desktop
index 4f2902fe2..4f2902fe2 100644
--- a/tests/data/no-icon.desktop
+++ b/tests/data/applications/no-icon.desktop
diff --git a/tests/data/ubuntu-software-center.desktop b/tests/data/applications/ubuntu-software-center.desktop
index e8f860e07..e8f860e07 100644
--- a/tests/data/ubuntu-software-center.desktop
+++ b/tests/data/applications/ubuntu-software-center.desktop
diff --git a/tests/data/ubuntuone-installer.desktop b/tests/data/applications/ubuntuone-installer.desktop
index 99c6a47b7..99c6a47b7 100644
--- a/tests/data/ubuntuone-installer.desktop
+++ b/tests/data/applications/ubuntuone-installer.desktop
diff --git a/tests/data/update-manager.desktop b/tests/data/applications/update-manager.desktop
index 5f9f3a64f..5f9f3a64f 100644
--- a/tests/data/update-manager.desktop
+++ b/tests/data/applications/update-manager.desktop
diff --git a/tests/gmockvolume.c b/tests/gmockvolume.c
index be667f2b8..a46aee298 100644
--- a/tests/gmockvolume.c
+++ b/tests/gmockvolume.c
@@ -83,9 +83,10 @@ g_mock_volume_class_init (GMockVolumeClass *klass)
static void
g_mock_volume_init (GMockVolume *mock_volume)
{
- mock_volume->name = g_strdup("");
+ guint32 uuid = g_random_int();
+ mock_volume->name = g_strdup_printf("MockVolume %u", uuid);
mock_volume->icon = g_icon_new_for_string("", NULL);
- mock_volume->uuid = g_strdup("");
+ mock_volume->uuid = g_strdup_printf("%u", uuid);
mock_volume->mount = NULL;
}
diff --git a/tests/test_bamflaunchericon.cpp b/tests/test_bamf_launcher_icon.cpp
index 874407b75..b33d20620 100644
--- a/tests/test_bamflaunchericon.cpp
+++ b/tests/test_bamf_launcher_icon.cpp
@@ -23,16 +23,19 @@
#include <gmock/gmock.h>
#include <UnityCore/GLibWrapper.h>
+#include <UnityCore/DesktopUtilities.h>
#include "BamfLauncherIcon.h"
+#include "FavoriteStore.h"
using namespace unity;
+using namespace unity::launcher;
namespace
{
-const std::string USC_DESKTOP = BUILDDIR"/tests/data/ubuntu-software-center.desktop";
-const std::string NO_ICON_DESKTOP = BUILDDIR"/tests/data/no-icon.desktop";
+const std::string USC_DESKTOP = BUILDDIR"/tests/data/applications/ubuntu-software-center.desktop";
+const std::string NO_ICON_DESKTOP = BUILDDIR"/tests/data/applications/no-icon.desktop";
class TestBamfLauncherIcon : public testing::Test
{
@@ -61,6 +64,11 @@ public:
nux::ObjectPtr<launcher::BamfLauncherIcon> empty_app;
};
+TEST_F(TestBamfLauncherIcon, Position)
+{
+ EXPECT_EQ(usc_icon->position(), AbstractLauncherIcon::Position::FLOATING);
+}
+
TEST_F(TestBamfLauncherIcon, TestCustomBackgroundColor)
{
nux::Color const& color = usc_icon->BackgroundColor();
@@ -78,4 +86,64 @@ TEST_F(TestBamfLauncherIcon, TestDefaultIcon)
EXPECT_EQ(empty_app->icon_name.Get(), "application-default-icon");
}
+TEST_F(TestBamfLauncherIcon, Stick)
+{
+ BamfView* bamf_app = BAMF_VIEW(bamf_matcher_get_application_for_desktop_file(bamf_matcher, USC_DESKTOP.c_str(), FALSE));
+ ASSERT_FALSE(bamf_view_is_sticky(bamf_app));
+
+ bool saved = false;
+ usc_icon->position_saved.connect([&saved] {saved = true;});
+
+ usc_icon->Stick(false);
+ EXPECT_TRUE(bamf_view_is_sticky(bamf_app));
+ EXPECT_TRUE(usc_icon->IsSticky());
+ EXPECT_TRUE(usc_icon->IsVisible());
+ EXPECT_FALSE(saved);
+
+ usc_icon->Stick(true);
+ EXPECT_FALSE(saved);
+ bamf_view_set_sticky(bamf_app, FALSE);
+}
+
+TEST_F(TestBamfLauncherIcon, StickAndSave)
+{
+ BamfView* bamf_app = BAMF_VIEW(bamf_matcher_get_application_for_desktop_file(bamf_matcher, USC_DESKTOP.c_str(), FALSE));
+ ASSERT_FALSE(bamf_view_is_sticky(bamf_app));
+
+ bool saved = false;
+ usc_icon->position_saved.connect([&saved] {saved = true;});
+
+ usc_icon->Stick(true);
+ EXPECT_TRUE(bamf_view_is_sticky(bamf_app));
+ EXPECT_TRUE(usc_icon->IsSticky());
+ EXPECT_TRUE(usc_icon->IsVisible());
+ EXPECT_TRUE(saved);
+ bamf_view_set_sticky(bamf_app, FALSE);
+}
+
+TEST_F(TestBamfLauncherIcon, Unstick)
+{
+ BamfView* bamf_app = BAMF_VIEW(bamf_matcher_get_application_for_desktop_file(bamf_matcher, USC_DESKTOP.c_str(), FALSE));
+ ASSERT_FALSE(bamf_view_is_sticky(bamf_app));
+
+ bool forgot = false;
+ usc_icon->position_forgot.connect([&forgot] {forgot = true;});
+
+ usc_icon->Stick(false);
+ ASSERT_TRUE(bamf_view_is_sticky(bamf_app));
+ ASSERT_TRUE(usc_icon->IsSticky());
+
+ usc_icon->UnStick();
+ EXPECT_FALSE(bamf_view_is_sticky(bamf_app));
+ EXPECT_FALSE(usc_icon->IsSticky());
+ EXPECT_FALSE(usc_icon->IsVisible());
+ EXPECT_TRUE(forgot);
+}
+
+TEST_F(TestBamfLauncherIcon, RemoteUri)
+{
+ EXPECT_EQ(usc_icon->RemoteUri(), FavoriteStore::URI_PREFIX_APP + DesktopUtilities::GetDesktopID(USC_DESKTOP));
+ EXPECT_TRUE(empty_app->RemoteUri().empty());
+}
+
}
diff --git a/tests/test_bfb_launcher_icon.cpp b/tests/test_bfb_launcher_icon.cpp
index bcc6c5f54..e4e0cb3f7 100644
--- a/tests/test_bfb_launcher_icon.cpp
+++ b/tests/test_bfb_launcher_icon.cpp
@@ -33,18 +33,21 @@ public:
MockBFBLauncherIcon()
: BFBLauncherIcon(LauncherHideMode::LAUNCHER_HIDE_NEVER)
{}
-
- AbstractLauncherIcon::MenuItemsVector GetMenus()
- {
- return BFBLauncherIcon::GetMenus();
- }
};
-TEST(TestBFBLauncherIcon, OverlayMenus)
+struct TestBFBLauncherIcon : testing::Test
{
MockBFBLauncherIcon bfb;
+};
- for (auto menu_item : bfb.GetMenus())
+TEST_F(TestBFBLauncherIcon, Position)
+{
+ EXPECT_EQ(bfb.position, AbstractLauncherIcon::Position::BEGIN);
+}
+
+TEST_F(TestBFBLauncherIcon, OverlayMenus)
+{
+ for (auto menu_item : bfb.Menus())
{
bool overlay_item = dbusmenu_menuitem_property_get_bool(menu_item, QuicklistMenuItem::OVERLAY_MENU_ITEM_PROPERTY);
ASSERT_TRUE(overlay_item);
diff --git a/tests/test_desktop_launcher_icon.cpp b/tests/test_desktop_launcher_icon.cpp
new file mode 100644
index 000000000..2a4828e11
--- /dev/null
+++ b/tests/test_desktop_launcher_icon.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2012 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 warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY 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
+ * version 3 along with this program. If not, see
+ * <http://www.gnu.org/licenses/>
+ *
+ * Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com>
+ */
+
+#include <gmock/gmock.h>
+
+#include "PluginAdapter.h"
+#include "DesktopLauncherIcon.h"
+
+using namespace unity;
+using namespace unity::launcher;
+
+namespace
+{
+
+struct TestDesktopLauncherIcon : testing::Test
+{
+ DesktopLauncherIcon icon;
+};
+
+TEST_F(TestDesktopLauncherIcon, Type)
+{
+ EXPECT_EQ(icon.GetIconType(), AbstractLauncherIcon::IconType::DESKTOP);
+}
+
+TEST_F(TestDesktopLauncherIcon, Shortcut)
+{
+ EXPECT_EQ(icon.GetShortcut(), 'd');
+}
+
+TEST_F(TestDesktopLauncherIcon, Position)
+{
+ EXPECT_EQ(icon.position(), AbstractLauncherIcon::Position::FLOATING);
+}
+
+TEST_F(TestDesktopLauncherIcon, ActivateToggleShowDesktop)
+{
+ auto plugin_adapter = PluginAdapter::Default();
+
+ ASSERT_FALSE(plugin_adapter->InShowDesktop());
+
+ icon.Activate(ActionArg());
+ ASSERT_TRUE(plugin_adapter->InShowDesktop());
+
+ icon.Activate(ActionArg());
+ EXPECT_FALSE(plugin_adapter->InShowDesktop());
+}
+
+TEST_F(TestDesktopLauncherIcon, ShowInSwitcher)
+{
+ EXPECT_TRUE(icon.ShowInSwitcher(false));
+ EXPECT_TRUE(icon.ShowInSwitcher(true));
+
+ icon.SetShowInSwitcher(false);
+
+ EXPECT_FALSE(icon.ShowInSwitcher(false));
+ EXPECT_FALSE(icon.ShowInSwitcher(true));
+}
+
+TEST_F(TestDesktopLauncherIcon, RemoteUri)
+{
+ EXPECT_EQ(icon.RemoteUri(), "unity://desktop-icon");
+}
+
+}
diff --git a/tests/test_desktop_utilities.cpp b/tests/test_desktop_utilities.cpp
index dd362a3ee..4cf258767 100644
--- a/tests/test_desktop_utilities.cpp
+++ b/tests/test_desktop_utilities.cpp
@@ -30,7 +30,9 @@ using namespace unity;
using testing::Eq;
namespace {
-
+
+const std::string LOCAL_DATA_DIR = BUILDDIR"/tests/data";
+
TEST(TestDesktopUtilitiesDesktopID, TestEmptyValues)
{
std::vector<std::string> empty_list;
@@ -88,71 +90,99 @@ TEST(TestDesktopUtilitiesDesktopID, TestSubdirectory)
Eq("subdir-to.desktop"));
EXPECT_THAT(DesktopUtilities::GetDesktopID(dirs, "/this/path/applications/subdir1/subdir2/to.desktop"),
Eq("subdir1-subdir2-to.desktop"));
+ EXPECT_THAT(DesktopUtilities::GetDesktopID(dirs, "/this/path/applications/subdir1/subdir2-to.desktop"),
+ Eq("subdir1-subdir2-to.desktop"));
}
TEST(TestDesktopUtilitiesDataDirectories, TestGetUserDataDirectory)
{
- const gchar* old_home = g_getenv("XDG_DATA_HOME");
+ const gchar* env = g_getenv("XDG_DATA_HOME");
+ std::string old_home = env ? env : "";
+
g_setenv("XDG_DATA_HOME", "UnityUserConfig", TRUE);
std::string const& user_data_dir = DesktopUtilities::GetUserDataDirectory();
- g_setenv("XDG_DATA_HOME", old_home, TRUE);
+ g_setenv("XDG_DATA_HOME", old_home.c_str(), TRUE);
EXPECT_THAT(user_data_dir, Eq("UnityUserConfig"));
}
TEST(TestDesktopUtilitiesDataDirectories, TestGetSystemDataDirectory)
{
- const gchar* old_dirs = g_getenv("XDG_DATA_DIRS");
- g_setenv("XDG_DATA_DIRS", "dir1:dir2::dir3:dir4", TRUE);
+ const gchar* env = g_getenv("XDG_DATA_DIRS");
+ std::string old_dirs = env ? env : "";
+ g_setenv("XDG_DATA_DIRS", ("dir1:dir2::dir3:dir4:"+LOCAL_DATA_DIR).c_str(), TRUE);
std::vector<std::string> const& system_dirs = DesktopUtilities::GetSystemDataDirectories();
- g_setenv("XDG_DATA_DIRS", old_dirs, TRUE);
+ g_setenv("XDG_DATA_DIRS", old_dirs.c_str(), TRUE);
- ASSERT_THAT(system_dirs.size(), Eq(4));
+ ASSERT_THAT(system_dirs.size(), Eq(5));
EXPECT_THAT(system_dirs[0], Eq("dir1"));
EXPECT_THAT(system_dirs[1], Eq("dir2"));
EXPECT_THAT(system_dirs[2], Eq("dir3"));
EXPECT_THAT(system_dirs[3], Eq("dir4"));
+ EXPECT_THAT(system_dirs[4], Eq(LOCAL_DATA_DIR));
}
TEST(TestDesktopUtilitiesDataDirectories, TestGetDataDirectory)
{
- const gchar* old_dirs = g_getenv("XDG_DATA_DIRS");
- g_setenv("XDG_DATA_DIRS", "dir1:dir2::dir3:dir4", TRUE);
- const gchar* old_home = g_getenv("XDG_DATA_HOME");
+ const gchar* env = g_getenv("XDG_DATA_DIRS");
+ std::string old_dirs = env ? env : "";
+ env = g_getenv("XDG_DATA_HOME");
+ std::string old_home = env ? env : "";
+
+ g_setenv("XDG_DATA_DIRS", ("dir1:dir2::dir3:dir4:"+LOCAL_DATA_DIR).c_str(), TRUE);
g_setenv("XDG_DATA_HOME", "UnityUserConfig", TRUE);
std::vector<std::string> const& data_dirs = DesktopUtilities::GetDataDirectories();
- g_setenv("XDG_DATA_DIRS", old_dirs, TRUE);
- g_setenv("XDG_DATA_HOME", old_home, TRUE);
+ g_setenv("XDG_DATA_DIRS", old_dirs.c_str(), TRUE);
+ g_setenv("XDG_DATA_HOME", old_home.c_str(), TRUE);
- ASSERT_THAT(data_dirs.size(), Eq(5));
+ ASSERT_THAT(data_dirs.size(), Eq(6));
EXPECT_THAT(data_dirs[0], Eq("dir1"));
EXPECT_THAT(data_dirs[1], Eq("dir2"));
EXPECT_THAT(data_dirs[2], Eq("dir3"));
EXPECT_THAT(data_dirs[3], Eq("dir4"));
- EXPECT_THAT(data_dirs[4], Eq("UnityUserConfig"));
+ EXPECT_THAT(data_dirs[4], Eq(LOCAL_DATA_DIR));
+ EXPECT_THAT(data_dirs[5], Eq("UnityUserConfig"));
+}
+
+TEST(TestDesktopUtilities, TestGetDesktopPathById)
+{
+ const gchar* env = g_getenv("XDG_DATA_DIRS");
+ std::string old_dirs = env ? env : "";
+ env = g_getenv("XDG_DATA_HOME");
+ std::string old_home = env ? env : "";
+
+ g_setenv("XDG_DATA_DIRS", LOCAL_DATA_DIR.c_str(), TRUE);
+ g_setenv("XDG_DATA_HOME", "UnityUserConfig", TRUE);
+
+ std::string const& file = DesktopUtilities::GetDesktopPathById("ubuntu-software-center.desktop");
+
+ g_setenv("XDG_DATA_DIRS", old_dirs.c_str(), TRUE);
+ g_setenv("XDG_DATA_HOME", old_dirs.c_str(), TRUE);
+
+ EXPECT_EQ(file, LOCAL_DATA_DIR + "/applications/ubuntu-software-center.desktop");
}
-TEST(TestDesktopUtilitiesDataDirectories, TestGetBackgroundColor)
+TEST(TestDesktopUtilities, TestGetBackgroundColor)
{
- std::string const& color = DesktopUtilities::GetBackgroundColor(BUILDDIR"/tests/data/ubuntu-software-center.desktop");
+ std::string const& color = DesktopUtilities::GetBackgroundColor(LOCAL_DATA_DIR+"/applications/ubuntu-software-center.desktop");
EXPECT_EQ(color, "#aabbcc");
}
-TEST(TestDesktopUtilitiesDataDirectories, TestGetBackgroundColorNoKey)
+TEST(TestDesktopUtilities, TestGetBackgroundColorNoKey)
{
- std::string const& color = DesktopUtilities::GetBackgroundColor(BUILDDIR"/tests/data/update-manager.desktop");
+ std::string const& color = DesktopUtilities::GetBackgroundColor(LOCAL_DATA_DIR+"/applications/update-manager.desktop");
EXPECT_TRUE(color.empty());
}
-TEST(TestDesktopUtilitiesDataDirectories, TestGetBackgroundColorNoFile)
+TEST(TestDesktopUtilities, TestGetBackgroundColorNoFile)
{
std::string const& color = DesktopUtilities::GetBackgroundColor("hello-world.desktop");
diff --git a/tests/test_device_launcher_section.cpp b/tests/test_device_launcher_section.cpp
index 055a1156e..e436fa72d 100644
--- a/tests/test_device_launcher_section.cpp
+++ b/tests/test_device_launcher_section.cpp
@@ -21,17 +21,16 @@
*/
#include <gmock/gmock.h>
-using namespace testing;
-#include "DeviceLauncherSection.h"
#include "DevicesSettings.h"
-#include "AbstractVolumeMonitorWrapper.h"
-using namespace unity;
-using namespace unity::launcher;
-
-#include "gmockvolume.h"
+#include "test_mock_devices.h"
#include "test_utils.h"
+using namespace testing;
+using namespace unity::launcher;
+
+namespace unity
+{
namespace
{
@@ -50,72 +49,38 @@ public:
bool icon_added;
};
-class MockVolumeMonitorWrapper : public AbstractVolumeMonitorWrapper
-{
-public:
- typedef std::shared_ptr<MockVolumeMonitorWrapper> Ptr;
-
- MockVolumeMonitorWrapper()
- : volume1(G_VOLUME(g_mock_volume_new()))
- , volume2(G_VOLUME(g_mock_volume_new()))
- {
- }
-
- VolumeList GetVolumes()
- {
- VolumeList ret;
-
- ret.push_back(volume1);
- ret.push_back(volume2);
-
- return ret;
- }
-
- glib::Object<GVolume> volume1;
- glib::Object<GVolume> volume2;
-};
-
-class MockDevicesSettings : public DevicesSettings
+struct TestDeviceLauncherSection : Test
{
- MOCK_CONST_METHOD1(IsABlacklistedDevice, bool(std::string const& uuid));
- MOCK_METHOD1(TryToBlacklist, void(std::string const& uuid));
- MOCK_METHOD1(TryToUnblacklist, void(std::string const& uuid));
-};
-
-class TestDeviceLauncherSection : public Test
-{
-public:
TestDeviceLauncherSection()
: monitor_(new MockVolumeMonitorWrapper)
, devices_settings_(new MockDevicesSettings)
, section_(monitor_, devices_settings_)
{}
- void SetUp()
- {
- // Make sure PopulateEntries is called.
- Utils::WaitForTimeoutMSec(1500);
- }
-
MockVolumeMonitorWrapper::Ptr monitor_;
DevicesSettings::Ptr devices_settings_;
DeviceLauncherSection section_;
};
-
-TEST_F(TestDeviceLauncherSection, TestNoDuplicates)
+TEST_F(TestDeviceLauncherSection, NoDuplicates)
{
std::shared_ptr<EventListener> listener(new EventListener);
- section_.IconAdded.connect(sigc::mem_fun(*listener, &EventListener::OnIconAdded));
+ section_.icon_added.connect(sigc::mem_fun(*listener, &EventListener::OnIconAdded));
// Emit the signal volume_added for each volume.
- monitor_->volume_added.emit(monitor_->volume1);
- monitor_->volume_added.emit(monitor_->volume2);
+ monitor_->volume_added.emit(*(std::next(monitor_->volumes_.begin(), 0)));
+ monitor_->volume_added.emit(*(std::next(monitor_->volumes_.begin(), 1)));
Utils::WaitForTimeoutMSec(500);
EXPECT_EQ(listener->icon_added, false);
}
+TEST_F(TestDeviceLauncherSection, GetIcons)
+{
+ EXPECT_EQ(section_.GetIcons().size(), 2);
+}
+
+}
}
diff --git a/tests/test_expo_launcher_icon.cpp b/tests/test_expo_launcher_icon.cpp
new file mode 100644
index 000000000..e1550fc43
--- /dev/null
+++ b/tests/test_expo_launcher_icon.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2012 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 warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY 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
+ * version 3 along with this program. If not, see
+ * <http://www.gnu.org/licenses/>
+ *
+ * Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com>
+ */
+
+#include <gmock/gmock.h>
+
+#include "ExpoLauncherIcon.h"
+#include "PluginAdapter.h"
+
+using namespace unity;
+using namespace unity::launcher;
+
+namespace
+{
+struct TestExpoLauncherIcon : testing::Test
+{
+ ExpoLauncherIcon icon;
+};
+
+TEST_F(TestExpoLauncherIcon, ActivateToggleExpo)
+{
+ auto plugin_adapter = PluginAdapter::Default();
+
+ ASSERT_FALSE(plugin_adapter->IsExpoActive());
+
+ icon.Activate(ActionArg());
+ ASSERT_TRUE(plugin_adapter->IsExpoActive());
+
+ icon.Activate(ActionArg());
+ EXPECT_FALSE(plugin_adapter->IsExpoActive());
+}
+
+TEST_F(TestExpoLauncherIcon, Position)
+{
+ EXPECT_EQ(icon.position(), AbstractLauncherIcon::Position::FLOATING);
+}
+
+TEST_F(TestExpoLauncherIcon, RemoteUri)
+{
+ EXPECT_EQ(icon.RemoteUri(), "unity://expo-icon");
+}
+
+}
diff --git a/tests/test_favorite_store.cpp b/tests/test_favorite_store.cpp
new file mode 100644
index 000000000..3fd0d1bd3
--- /dev/null
+++ b/tests/test_favorite_store.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2012 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 warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY 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
+ * version 3 along with this program. If not, see
+ * <http://www.gnu.org/licenses/>
+ *
+ * Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com>
+ */
+
+#include <gmock/gmock.h>
+#include <config.h>
+
+#include "FavoriteStore.h"
+
+using namespace unity;
+
+namespace
+{
+class MockFavoriteStore : public FavoriteStore
+{
+public:
+ FavoriteList const& GetFavorites() const { return fav_list_; }
+ void AddFavorite(std::string const& icon_uri, int position) {}
+ void RemoveFavorite(std::string const& icon_uri) {}
+ void MoveFavorite(std::string const& icon_uri, int position) {}
+ bool IsFavorite(std::string const& icon_uri) const { return false; }
+ int FavoritePosition(std::string const& icon_uri) const { return -1; }
+ void SetFavorites(FavoriteList const& icon_uris) {}
+
+ std::string ParseFavoriteFromUri(std::string const& uri) const
+ {
+ return FavoriteStore::ParseFavoriteFromUri(uri);
+ }
+
+private:
+ FavoriteList fav_list_;
+};
+
+struct TestFavoriteStore : public testing::Test
+{
+ MockFavoriteStore favorite_store;
+};
+
+TEST_F(TestFavoriteStore, Construction)
+{
+ FavoriteStore& instance = FavoriteStore::Instance();
+ EXPECT_EQ(&instance, &favorite_store);
+}
+
+TEST_F(TestFavoriteStore, UriPrefixes)
+{
+ EXPECT_EQ(FavoriteStore::URI_PREFIX_APP, "application://");
+ EXPECT_EQ(FavoriteStore::URI_PREFIX_FILE, "file://");
+ EXPECT_EQ(FavoriteStore::URI_PREFIX_DEVICE, "device://");
+ EXPECT_EQ(FavoriteStore::URI_PREFIX_UNITY, "unity://");
+}
+
+TEST_F(TestFavoriteStore, IsValidFavoriteUri)
+{
+ EXPECT_FALSE(FavoriteStore::IsValidFavoriteUri(""));
+ EXPECT_FALSE(FavoriteStore::IsValidFavoriteUri("invalid-favorite"));
+ EXPECT_FALSE(FavoriteStore::IsValidFavoriteUri("/path/to/desktop_file"));
+ EXPECT_FALSE(FavoriteStore::IsValidFavoriteUri("desktop_file"));
+ EXPECT_FALSE(FavoriteStore::IsValidFavoriteUri("file:///path/to/desktop_file"));
+ EXPECT_FALSE(FavoriteStore::IsValidFavoriteUri("application://desktop_file"));
+ EXPECT_FALSE(FavoriteStore::IsValidFavoriteUri("application://"));
+ EXPECT_FALSE(FavoriteStore::IsValidFavoriteUri("device://"));
+ EXPECT_FALSE(FavoriteStore::IsValidFavoriteUri("unity://"));
+
+ EXPECT_TRUE(FavoriteStore::IsValidFavoriteUri("device://uuid"));
+ EXPECT_TRUE(FavoriteStore::IsValidFavoriteUri("file:///path/to/desktop_file.desktop"));
+ EXPECT_TRUE(FavoriteStore::IsValidFavoriteUri("application://desktop_file.desktop"));
+ EXPECT_TRUE(FavoriteStore::IsValidFavoriteUri("device://a"));
+ EXPECT_TRUE(FavoriteStore::IsValidFavoriteUri("unity://b"));
+ EXPECT_TRUE(FavoriteStore::IsValidFavoriteUri("application://c.desktop"));
+}
+
+TEST_F(TestFavoriteStore, ParseFavoriteFromUri)
+{
+ const std::string VALID_DESKTOP_PATH = BUILDDIR"/tests/data/applications/ubuntu-software-center.desktop";
+ EXPECT_EQ(favorite_store.ParseFavoriteFromUri("file.desktop"), "application://file.desktop");
+ EXPECT_EQ(favorite_store.ParseFavoriteFromUri(VALID_DESKTOP_PATH), "application://"+VALID_DESKTOP_PATH);
+
+ EXPECT_EQ(favorite_store.ParseFavoriteFromUri("application://file.desktop"), "application://file.desktop");
+ EXPECT_EQ(favorite_store.ParseFavoriteFromUri("application://"+VALID_DESKTOP_PATH), "application://"+VALID_DESKTOP_PATH);
+ EXPECT_EQ(favorite_store.ParseFavoriteFromUri("file://"+VALID_DESKTOP_PATH), "file://"+VALID_DESKTOP_PATH);
+
+ EXPECT_EQ(favorite_store.ParseFavoriteFromUri("unity://uri"), "unity://uri");
+ EXPECT_EQ(favorite_store.ParseFavoriteFromUri("device://uuid"), "device://uuid");
+
+ EXPECT_TRUE(favorite_store.ParseFavoriteFromUri("file").empty());
+ EXPECT_TRUE(favorite_store.ParseFavoriteFromUri("/path/to/file").empty());
+ EXPECT_TRUE(favorite_store.ParseFavoriteFromUri("/path/to/file.desktop").empty());
+ EXPECT_TRUE(favorite_store.ParseFavoriteFromUri("application:///path/to/file.desktop").empty());
+ EXPECT_TRUE(favorite_store.ParseFavoriteFromUri("file:///path/to/file.desktop").empty());
+ EXPECT_TRUE(favorite_store.ParseFavoriteFromUri("file://file.desktop").empty());
+ EXPECT_TRUE(favorite_store.ParseFavoriteFromUri("unity://").empty());
+ EXPECT_TRUE(favorite_store.ParseFavoriteFromUri("device://").empty());
+}
+
+}
diff --git a/tests/test_favorite_store_gsettings.cpp b/tests/test_favorite_store_gsettings.cpp
index 245fcd001..3ed90f709 100644
--- a/tests/test_favorite_store_gsettings.cpp
+++ b/tests/test_favorite_store_gsettings.cpp
@@ -21,18 +21,12 @@
#include <config.h>
-#include <algorithm>
-#include <memory>
-#include <string>
-
-#define G_SETTINGS_ENABLE_BACKEND
-#include <gio/gsettingsbackend.h>
#include <gmock/gmock.h>
#include <glib.h>
#include "FavoriteStore.h"
#include "FavoriteStoreGSettings.h"
-#include "FavoriteStorePrivate.h"
+
#include <UnityCore/GLibWrapper.h>
using namespace unity;
@@ -45,14 +39,16 @@ const gchar* SETTINGS_NAME = "com.canonical.Unity.Launcher";
const gchar* SETTINGS_KEY = "favorites";
const gchar* SCHEMA_DIRECTORY = BUILDDIR"/settings";
-const char* base_store_favs[] = { BUILDDIR"/tests/data/ubuntuone-installer.desktop",
- BUILDDIR"/tests/data/ubuntu-software-center.desktop",
- BUILDDIR"/tests/data/update-manager.desktop",
+const char* base_store_favs[] = { BUILDDIR"/tests/data/applications/ubuntuone-installer.desktop",
+ "file://" BUILDDIR "/tests/data/applications/ubuntu-software-center.desktop",
+ "application://" BUILDDIR "/tests/data/applications/update-manager.desktop",
+ "unity://test-icon",
+ "device://uuid",
NULL
};
const int n_base_store_favs = G_N_ELEMENTS(base_store_favs) - 1; /* NULL */
-const std::string other_desktop = BUILDDIR"/tests/data/bzr-handle-patch.desktop";
+const std::string other_desktop = "application://" BUILDDIR "/tests/data/applications/bzr-handle-patch.desktop";
// Utilities
std::string const& at(FavoriteList const& favs, int index)
@@ -110,9 +106,9 @@ TEST_F(TestFavoriteStoreGSettings, TestGetFavorites)
FavoriteList const& favs = settings.GetFavorites();
ASSERT_EQ(favs.size(), n_base_store_favs);
- EXPECT_TRUE(ends_with(at(favs, 0), base_store_favs[0]));
+ EXPECT_TRUE(ends_with(at(favs, 0), FavoriteStore::URI_PREFIX_APP+base_store_favs[0]));
EXPECT_TRUE(ends_with(at(favs, 1), base_store_favs[1]));
- EXPECT_TRUE(at(favs, 2) == base_store_favs[2]);
+ EXPECT_EQ(at(favs, 2), base_store_favs[2]);
}
TEST_F(TestFavoriteStoreGSettings, TestAddFavorite)
@@ -122,7 +118,7 @@ TEST_F(TestFavoriteStoreGSettings, TestAddFavorite)
settings.AddFavorite(other_desktop, 0);
FavoriteList const& favs = settings.GetFavorites();
ASSERT_EQ(favs.size(), n_base_store_favs + 1);
- EXPECT_TRUE(other_desktop == at(favs, 0));
+ EXPECT_EQ(other_desktop, at(favs, 0));
}
TEST_F(TestFavoriteStoreGSettings, TestAddFavoritePosition)
@@ -132,7 +128,7 @@ TEST_F(TestFavoriteStoreGSettings, TestAddFavoritePosition)
settings.AddFavorite(other_desktop, 2);
FavoriteList const& favs = settings.GetFavorites();
ASSERT_EQ(favs.size(), n_base_store_favs + 1);
- EXPECT_TRUE(other_desktop == at(favs, 2));
+ EXPECT_EQ(other_desktop, at(favs, 2));
}
TEST_F(TestFavoriteStoreGSettings,TestAddFavoriteLast)
@@ -142,7 +138,7 @@ TEST_F(TestFavoriteStoreGSettings,TestAddFavoriteLast)
settings.AddFavorite(other_desktop, -1);
FavoriteList const& favs = settings.GetFavorites();
ASSERT_EQ(favs.size(), n_base_store_favs + 1);
- EXPECT_TRUE(other_desktop == favs.back());
+ EXPECT_EQ(other_desktop, favs.back());
}
TEST_F(TestFavoriteStoreGSettings,TestAddFavoriteOutOfRange)
@@ -178,13 +174,13 @@ TEST_F(TestFavoriteStoreGSettings, TestRemoveFavoriteBad)
FavoriteStore &settings = FavoriteStore::Instance();
FavoriteList const& favs = settings.GetFavorites();
- settings.RemoveFavorite("");
+ settings.RemoveFavorite(" ");
EXPECT_EQ(favs.size(), n_base_store_favs);
- settings.RemoveFavorite("foo.desktop");
+ settings.RemoveFavorite("application://foo.desktop");
EXPECT_EQ(favs.size(), n_base_store_favs);
- settings.RemoveFavorite("/this/desktop/doesnt/exist/hopefully.desktop");
+ settings.RemoveFavorite("application:///this/desktop/doesnt/exist/hopefully.desktop");
EXPECT_EQ(favs.size(), n_base_store_favs);
}
@@ -198,7 +194,7 @@ TEST_F(TestFavoriteStoreGSettings, TestMoveFavorite)
ASSERT_EQ(favs.size(), n_base_store_favs);
EXPECT_EQ(at(favs, 0), base_store_favs[2]);
- EXPECT_TRUE(ends_with(at(favs, 1), base_store_favs[0]));
+ EXPECT_TRUE(ends_with(at(favs, 1), FavoriteStore::URI_PREFIX_APP+base_store_favs[0]));
EXPECT_TRUE(ends_with(at(favs, 2), base_store_favs[1]));
}
@@ -212,7 +208,7 @@ TEST_F(TestFavoriteStoreGSettings, TestMoveFavoriteBad)
settings.MoveFavorite(at(favs, 0), 100);
ASSERT_EQ(favs.size(), n_base_store_favs);
- EXPECT_TRUE(ends_with(at(favs, 0), base_store_favs[0]));
+ EXPECT_TRUE(ends_with(at(favs, 0), FavoriteStore::URI_PREFIX_APP+base_store_favs[0]));
EXPECT_TRUE(ends_with(at(favs, 1), base_store_favs[1]));
EXPECT_EQ(at(favs, 2), base_store_favs[2]);
}
@@ -239,7 +235,7 @@ TEST_F(TestFavoriteStoreGSettings, TestFavoriteAddedSignalFirst)
favorite_store->SaveFavorites(favs, false);
ASSERT_TRUE(signal_received);
- EXPECT_EQ(position, base_store_favs[0]);
+ EXPECT_EQ(position, FavoriteStore::URI_PREFIX_APP+base_store_favs[0]);
EXPECT_TRUE(before);
}
@@ -322,12 +318,12 @@ TEST_F(TestFavoriteStoreGSettings, TestFavoriteRemoved)
{
FavoriteStore &settings = FavoriteStore::Instance();
bool signal_received = false;
- std::string path_removed;
+ std::vector<std::string> paths_removed;
settings.favorite_removed.connect([&](std::string const& path)
{
signal_received = true;
- path_removed = path;
+ paths_removed.push_back(path);
});
FavoriteList favs;
@@ -336,7 +332,10 @@ TEST_F(TestFavoriteStoreGSettings, TestFavoriteRemoved)
favorite_store->SaveFavorites(favs, false);
ASSERT_TRUE(signal_received);
- EXPECT_EQ(path_removed, base_store_favs[1]);
+ ASSERT_EQ(paths_removed.size(), 3);
+ EXPECT_EQ(paths_removed[0], base_store_favs[4]);
+ EXPECT_EQ(paths_removed[1], base_store_favs[1]);
+ EXPECT_EQ(paths_removed[2], base_store_favs[3]);
}
TEST_F(TestFavoriteStoreGSettings, TestFavoriteReordered)
@@ -464,4 +463,28 @@ TEST_F(TestFavoriteStoreGSettings, TestFavoriteSignalsMixed3)
EXPECT_TRUE(reordered_received);
}
+TEST_F(TestFavoriteStoreGSettings, TestIsFavorite)
+{
+ EXPECT_TRUE(favorite_store->IsFavorite(FavoriteStore::URI_PREFIX_APP+base_store_favs[0]));
+
+ for (int i = 1; i < n_base_store_favs; i++)
+ {
+ ASSERT_TRUE(favorite_store->IsFavorite(base_store_favs[i]));
+ }
+
+ EXPECT_FALSE(favorite_store->IsFavorite("unity://invalid-favorite"));
+}
+
+TEST_F(TestFavoriteStoreGSettings, TestFavoritePosition)
+{
+ EXPECT_EQ(favorite_store->FavoritePosition(FavoriteStore::URI_PREFIX_APP+base_store_favs[0]), 0);
+
+ for (int i = 1; i < n_base_store_favs; i++)
+ {
+ ASSERT_EQ(favorite_store->FavoritePosition(base_store_favs[i]), i);
+ }
+
+ EXPECT_EQ(favorite_store->FavoritePosition("unity://invalid-favorite"), -1);
+}
+
} // anonymous namespace
diff --git a/tests/test_hud_controller.cpp b/tests/test_hud_controller.cpp
index 6bd379fe2..018900bdd 100644
--- a/tests/test_hud_controller.cpp
+++ b/tests/test_hud_controller.cpp
@@ -44,12 +44,13 @@ public:
MOCK_METHOD0(SearchFinished, void());
MOCK_METHOD4(SetIcon, void(std::string const&, unsigned int tile_size, unsigned int size, unsigned int padding));
MOCK_METHOD1(SetQueries, void(hud::Hud::Queries queries));
- MOCK_METHOD2(SetWindowGeometry, void(nux::Geometry const& absolute_geo, nux::Geometry const& geo));
+ MOCK_METHOD2(SetMonitorOffset, void(int x, int y));
MOCK_METHOD1(ShowEmbeddedIcon, void(bool show));
MOCK_CONST_METHOD0(default_focus, nux::View*());
MOCK_CONST_METHOD0(GetName, std::string());
MOCK_METHOD1(AddProperties, void(GVariantBuilder*));
MOCK_METHOD2(Draw, void(nux::GraphicsEngine&, bool));
+ MOCK_METHOD0(GetContentGeometry, nux::Geometry());
};
diff --git a/tests/test_hud_launcher_icon.cpp b/tests/test_hud_launcher_icon.cpp
new file mode 100644
index 000000000..20dbe30ee
--- /dev/null
+++ b/tests/test_hud_launcher_icon.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2012 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 warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY 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
+ * version 3 along with this program. If not, see
+ * <http://www.gnu.org/licenses/>
+ *
+ * Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com>
+ */
+
+#include <gmock/gmock.h>
+
+#include "HudLauncherIcon.h"
+
+using namespace unity;
+using namespace unity::launcher;
+
+namespace
+{
+
+class MockHudLauncherIcon : public HudLauncherIcon
+{
+public:
+ MockHudLauncherIcon()
+ : HudLauncherIcon(LauncherHideMode::LAUNCHER_HIDE_NEVER)
+ {}
+};
+
+struct TestHudLauncherIcon : testing::Test
+{
+ MockHudLauncherIcon hud;
+};
+
+TEST_F(TestHudLauncherIcon, Type)
+{
+ EXPECT_EQ(hud.GetIconType(), AbstractLauncherIcon::IconType::HUD);
+}
+
+TEST_F(TestHudLauncherIcon, Position)
+{
+ EXPECT_EQ(hud.position(), AbstractLauncherIcon::Position::BEGIN);
+}
+
+}
diff --git a/tests/test_launcher.cpp b/tests/test_launcher.cpp
index ae8f7bb4e..2e83f4f17 100644
--- a/tests/test_launcher.cpp
+++ b/tests/test_launcher.cpp
@@ -48,8 +48,12 @@ class MockMockLauncherIcon : public launcher::MockLauncherIcon
{
public:
typedef nux::ObjectPtr<MockMockLauncherIcon> Ptr;
+ MockMockLauncherIcon(IconType type = IconType::APPLICATION)
+ : MockLauncherIcon(type)
+ {}
MOCK_METHOD1(ShouldHighlightOnDrag, bool(DndData const&));
+ MOCK_METHOD1(Stick, void(bool));
};
}
@@ -57,7 +61,7 @@ public:
class TestLauncher : public Test
{
public:
- class MockLauncher : public launcher::Launcher
+ class MockLauncher : public Launcher
{
public:
MockLauncher(nux::BaseWindow* parent, nux::ObjectPtr<DNDCollectionWindow> const& collection_window)
@@ -92,6 +96,11 @@ public:
Launcher::ShowDragWindow();
}
+ void EndIconDrag()
+ {
+ Launcher::EndIconDrag();
+ }
+
void UpdateDragWindowPosition(int x, int y)
{
Launcher::UpdateDragWindowPosition(x, y);
@@ -106,6 +115,55 @@ public:
{
Launcher::ResetMouseDragState();
}
+
+ bool DndIsSpecialRequest(std::string const& uri) const
+ {
+ return Launcher::DndIsSpecialRequest(uri);
+ }
+
+ int GetDragIconPosition() const
+ {
+ return _drag_icon_position;
+ }
+
+ void ProcessDndEnter()
+ {
+ Launcher::ProcessDndEnter();
+ }
+
+ void ProcessDndLeave()
+ {
+ Launcher::ProcessDndLeave();
+ }
+
+ void ProcessDndMove(int x, int y, std::list<char*> mimes)
+ {
+ Launcher::ProcessDndMove(x, y, mimes);
+ }
+
+ void FakeProcessDndMove(int x, int y, std::list<std::string> uris)
+ {
+ _dnd_data.Reset();
+
+ std::string data_uri;
+ for (std::string const& uri : uris)
+ data_uri += uri+"\r\n";
+
+ _dnd_data.Fill(data_uri.c_str());
+
+ if (std::find_if(_dnd_data.Uris().begin(), _dnd_data.Uris().end(), [this] (std::string const& uri)
+ {return DndIsSpecialRequest(uri);}) != _dnd_data.Uris().end())
+ {
+ _steal_drag = true;
+ }
+
+ _dnd_hovered_icon = MouseIconIntersection(x, y);
+ }
+
+ void ProcessDndDrop(int x, int y)
+ {
+ Launcher::ProcessDndDrop(x, y);
+ }
};
TestLauncher()
@@ -119,6 +177,29 @@ public:
launcher_->SetModel(model_);
}
+ std::vector<MockMockLauncherIcon::Ptr> AddMockIcons(unsigned number)
+ {
+ std::vector<MockMockLauncherIcon::Ptr> icons;
+ int icon_size = launcher_->GetIconSize();
+ int monitor = launcher_->monitor();
+ auto const& launcher_geo = launcher_->GetGeometry();
+ int model_pre_size = model_->Size();
+
+ for (unsigned i = 0; i < number; ++i)
+ {
+ MockMockLauncherIcon::Ptr icon(new MockMockLauncherIcon);
+ icon->SetCenter(nux::Point3(icon_size/2.0f, icon_size/2.0f * (i+1) + 1, 0), monitor, launcher_geo);
+
+ icons.push_back(icon);
+ model_->AddIcon(icon);
+ }
+
+ EXPECT_EQ(icons.size(), number);
+ EXPECT_EQ(model_pre_size + number, number);
+
+ return icons;
+ }
+
MockUScreen uscreen;
nux::BaseWindow* parent_window_;
nux::ObjectPtr<DNDCollectionWindow> dnd_collection_window_;
@@ -206,19 +287,11 @@ TEST_F(TestLauncher, TestIconBackgroundIntensity)
TEST_F(TestLauncher, DragLauncherIconCancelRestoresIconOrder)
{
- MockMockLauncherIcon::Ptr icon1(new MockMockLauncherIcon);
- MockMockLauncherIcon::Ptr icon2(new MockMockLauncherIcon);
- MockMockLauncherIcon::Ptr icon3(new MockMockLauncherIcon);
+ auto const& icons = AddMockIcons(3);
- model_->AddIcon(icon1);
- model_->AddIcon(icon2);
- model_->AddIcon(icon3);
-
- // Set the icon centers
- int icon_size = launcher_->GetIconSize();
- icon1->SetCenter(nux::Point3(icon_size/2.0f, icon_size/2.0f * 1 + 1, 0), launcher_->monitor(), launcher_->GetGeometry());
- icon2->SetCenter(nux::Point3(icon_size/2.0f, icon_size/2.0f * 2 + 1, 0), launcher_->monitor(), launcher_->GetGeometry());
- icon3->SetCenter(nux::Point3(icon_size/2.0f, icon_size/2.0f * 3 + 1, 0), launcher_->monitor(), launcher_->GetGeometry());
+ auto const& icon1 = icons[0];
+ auto const& icon2 = icons[1];
+ auto const& icon3 = icons[2];
// Start dragging icon2
launcher_->StartIconDrag(icon2);
@@ -257,8 +330,146 @@ TEST_F(TestLauncher, DragLauncherIconCancelRestoresIconOrder)
EXPECT_FALSE(model_saved);
launcher_->HideDragWindow();
+
+ // Let's wait the drag icon animation to be completed
+ Utils::WaitForTimeout(1);
+ EXPECT_EQ(launcher_->GetDraggedIcon(), nullptr);
+}
+
+TEST_F(TestLauncher, DragLauncherIconSavesIconOrderIfPositionHasChanged)
+{
+ auto const& icons = AddMockIcons(3);
+
+ auto const& icon1 = icons[0];
+ auto const& icon2 = icons[1];
+ auto const& icon3 = icons[2];
+
+ // Start dragging icon2
+ launcher_->StartIconDrag(icon2);
+ launcher_->ShowDragWindow();
+ ASSERT_EQ(launcher_->GetDragIconPosition(), model_->IconIndex(icon2));
+
+ // Moving icon2 at the end
+ auto const& center3 = icon3->GetCenter(launcher_->monitor());
+ launcher_->UpdateDragWindowPosition(center3.x, center3.y);
+
+ bool model_saved = false;
+ model_->saved.connect([&model_saved] { model_saved = true; });
+
+ ASSERT_NE(launcher_->GetDragIconPosition(), model_->IconIndex(icon2));
+ launcher_->EndIconDrag();
+
+ // The icon order should be reset
+ auto it = model_->begin();
+ ASSERT_EQ(*it, icon1); it++;
+ ASSERT_EQ(*it, icon3); it++;
+ ASSERT_EQ(*it, icon2);
+
+ EXPECT_TRUE(model_saved);
+
+ // Let's wait the drag icon animation to be completed
+ Utils::WaitForTimeout(1);
+ EXPECT_EQ(launcher_->GetDraggedIcon(), nullptr);
}
+TEST_F(TestLauncher, DragLauncherIconSavesIconOrderIfPositionHasNotChanged)
+{
+ auto const& icons = AddMockIcons(3);
+
+ auto const& icon1 = icons[0];
+ auto const& icon2 = icons[1];
+ auto const& icon3 = icons[2];
+
+ // Start dragging icon2
+ launcher_->StartIconDrag(icon2);
+ launcher_->ShowDragWindow();
+ ASSERT_EQ(launcher_->GetDragIconPosition(), model_->IconIndex(icon2));
+
+ // Moving icon2 at the end
+ auto center3 = icon3->GetCenter(launcher_->monitor());
+ launcher_->UpdateDragWindowPosition(center3.x, center3.y);
+
+ // Swapping the centers
+ icon3->SetCenter(icon2->GetCenter(launcher_->monitor()), launcher_->monitor(), launcher_->GetGeometry());
+ icon2->SetCenter(center3, launcher_->monitor(), launcher_->GetGeometry());
+
+ // Moving icon2 back to the middle
+ center3 = icon3->GetCenter(launcher_->monitor());
+ launcher_->UpdateDragWindowPosition(center3.x, center3.y);
+
+ bool model_saved = false;
+ model_->saved.connect([&model_saved] { model_saved = true; });
+
+ ASSERT_EQ(launcher_->GetDragIconPosition(), model_->IconIndex(icon2));
+ launcher_->EndIconDrag();
+
+ // The icon order should be reset
+ auto it = model_->begin();
+ ASSERT_EQ(*it, icon1); it++;
+ ASSERT_EQ(*it, icon2); it++;
+ ASSERT_EQ(*it, icon3);
+
+ EXPECT_FALSE(model_saved);
+
+ // Let's wait the drag icon animation to be completed
+ Utils::WaitForTimeout(1);
+ EXPECT_EQ(launcher_->GetDraggedIcon(), nullptr);
+}
+
+TEST_F(TestLauncher, DragLauncherIconSticksDeviceIcon)
+{
+ auto const& icons = AddMockIcons(1);
+
+ MockMockLauncherIcon::Ptr device(new MockMockLauncherIcon(AbstractLauncherIcon::IconType::DEVICE));
+ model_->AddIcon(device);
+
+ // Start dragging device icon
+ launcher_->StartIconDrag(device);
+ launcher_->ShowDragWindow();
+
+ // Moving device icon to the beginning
+ auto const& center = icons[0]->GetCenter(launcher_->monitor());
+ launcher_->UpdateDragWindowPosition(center.x, center.y);
+
+ EXPECT_CALL(*device, Stick(false));
+ launcher_->EndIconDrag();
+}
+
+TEST_F(TestLauncher, DndIsSpecialRequest)
+{
+ EXPECT_TRUE(launcher_->DndIsSpecialRequest("MyFile.desktop"));
+ EXPECT_TRUE(launcher_->DndIsSpecialRequest("/full/path/to/MyFile.desktop"));
+ EXPECT_TRUE(launcher_->DndIsSpecialRequest("application://MyFile.desktop"));
+ EXPECT_TRUE(launcher_->DndIsSpecialRequest("file://MyFile.desktop"));
+ EXPECT_TRUE(launcher_->DndIsSpecialRequest("file://full/path/to/MyFile.desktop"));
+ EXPECT_TRUE(launcher_->DndIsSpecialRequest("device://uuuid"));
+
+ EXPECT_FALSE(launcher_->DndIsSpecialRequest("MyFile.txt"));
+ EXPECT_FALSE(launcher_->DndIsSpecialRequest("/full/path/to/MyFile.txt"));
+ EXPECT_FALSE(launcher_->DndIsSpecialRequest("file://full/path/to/MyFile.txt"));
+}
+
+TEST_F(TestLauncher, AddRequestSignal)
+{
+ auto const& icons = AddMockIcons(1);
+ auto const& center = icons[0]->GetCenter(launcher_->monitor());
+ launcher_->ProcessDndEnter();
+ launcher_->FakeProcessDndMove(center.x, center.y, {"application://MyFile.desktop"});
+
+ bool add_request = false;
+ launcher_->add_request.connect([&] (std::string const& uri, AbstractLauncherIcon::Ptr const& drop_icon) {
+ EXPECT_EQ(drop_icon, icons[0]);
+ EXPECT_EQ(uri, "application://MyFile.desktop");
+ add_request = true;
+ });
+
+ launcher_->ProcessDndDrop(center.x, center.y);
+ launcher_->ProcessDndLeave();
+
+ EXPECT_TRUE(add_request);
+}
+
+
}
}
diff --git a/tests/test_launcher_controller.cpp b/tests/test_launcher_controller.cpp
index a4d5fc660..79b036b81 100644
--- a/tests/test_launcher_controller.cpp
+++ b/tests/test_launcher_controller.cpp
@@ -23,8 +23,18 @@
#include "FavoriteStore.h"
#include "LauncherController.h"
#include "LauncherControllerPrivate.h"
+#include "ExpoLauncherIcon.h"
+#include "DesktopLauncherIcon.h"
+#include "MockLauncherIcon.h"
+#include "BFBLauncherIcon.h"
+#include "HudLauncherIcon.h"
+#include "TrashLauncherIcon.h"
+#include "VolumeLauncherIcon.h"
+#include "SoftwareCenterLauncherIcon.h"
#include "PanelStyle.h"
#include "UnitySettings.h"
+#include "test_utils.h"
+#include "test_mock_devices.h"
using namespace unity::launcher;
using namespace testing;
@@ -32,63 +42,221 @@ using namespace testing;
namespace unity
{
-class MockFavoriteStore : public FavoriteStore
+namespace
{
-public:
- FavoriteList const& GetFavorites()
+namespace places
+{
+const std::string APPS_URI = "unity://running-apps";
+const std::string DEVICES_URI = "unity://devices";
+}
+
+namespace app
+{
+ const std::string UBUNTU_ONE = BUILDDIR "/tests/data/applications/ubuntuone-installer.desktop";
+ const std::string SW_CENTER = BUILDDIR "/tests/data/applications/ubuntu-software-center.desktop";
+ const std::string UPDATE_MANAGER = BUILDDIR "/tests/data/applications/update-manager.desktop";
+ const std::string BZR_HANDLE_PATCH = BUILDDIR "/tests/data/applications/bzr-handle-patch.desktop";
+ const std::string NO_ICON = BUILDDIR "/tests/data/applications/no-icon.desktop";
+}
+}
+
+struct MockFavoriteStore : FavoriteStore
+{
+ MockFavoriteStore()
+ {
+ fav_list_ = { FavoriteStore::URI_PREFIX_APP + app::UBUNTU_ONE,
+ FavoriteStore::URI_PREFIX_APP + app::SW_CENTER,
+ FavoriteStore::URI_PREFIX_APP + app::UPDATE_MANAGER };
+ }
+
+ FavoriteList const& GetFavorites() const
{
return fav_list_;
- };
+ }
+
+ void AddFavorite(std::string const& icon_uri, int position)
+ {
+ if (!IsValidFavoriteUri(icon_uri))
+ return;
+
+ if (position < 0)
+ fav_list_.push_back(icon_uri);
+ else
+ fav_list_.insert(std::next(fav_list_.begin(), position), icon_uri);
+ }
+
+ void RemoveFavorite(std::string const& icon_uri)
+ {
+ fav_list_.remove(icon_uri);
+ }
+
+ void MoveFavorite(std::string const& icon_uri, int position)
+ {
+ RemoveFavorite(icon_uri);
+ AddFavorite(icon_uri, position);
+ }
+
+ bool IsFavorite(std::string const& icon_uri) const
+ {
+ return std::find(fav_list_.begin(), fav_list_.end(), icon_uri) != fav_list_.end();
+ }
+
+ int FavoritePosition(std::string const& icon_uri) const
+ {
+ auto it = std::find(fav_list_.begin(), fav_list_.end(), icon_uri);
+
+ if (it != fav_list_.end())
+ return std::distance(fav_list_.begin(), it);
- void AddFavorite(std::string const& desktop_path, int position) {};
- void RemoveFavorite(std::string const& desktop_path) {};
- void MoveFavorite(std::string const& desktop_path, int position) {};
- void SetFavorites(FavoriteList const& desktop_paths) {};
+ return -1;
+ }
+
+ void SetFavorites(FavoriteList const& icon_uris)
+ {
+ fav_list_ = icon_uris;
+ }
+
+ void ClearFavorites()
+ {
+ fav_list_.clear();
+ }
private:
FavoriteList fav_list_;
};
-class MockBamfLauncherIcon : public BamfLauncherIcon
+struct MockBamfLauncherIcon : public BamfLauncherIcon
{
-public:
- MockBamfLauncherIcon(BamfApplication* app)
- : BamfLauncherIcon(app) {}
+ typedef nux::ObjectPtr<MockBamfLauncherIcon> Ptr;
+ typedef bool Fake;
+ MockBamfLauncherIcon(Fake = true, std::string const& remote_uri = "")
+ : BamfLauncherIcon(static_cast<BamfApplication*>(g_object_new(BAMF_TYPE_APPLICATION, nullptr)))
+ , remote_uri_(remote_uri)
+ {
+ InitMock();
+ SetQuirk(Quirk::VISIBLE, true);
+ }
+
+ explicit MockBamfLauncherIcon(BamfApplication* app)
+ : BamfLauncherIcon(app)
+ {
+ InitMock();
+ }
+
+ MockBamfLauncherIcon(std::string const& desktop_file)
+ : BamfLauncherIcon(bamf_matcher_get_application_for_desktop_file(bamf_matcher_get_default(), desktop_file.c_str(), TRUE))
+ {
+ InitMock();
+ }
+
+ void InitMock()
+ {
+ ON_CALL(*this, Stick(_)).WillByDefault(Invoke(this, &MockBamfLauncherIcon::ReallyStick));
+ }
+
+ std::string GetRemoteUri()
+ {
+ if (remote_uri_.empty())
+ return BamfLauncherIcon::GetRemoteUri();
+ else
+ return FavoriteStore::URI_PREFIX_APP + remote_uri_;
+ }
+
+ bool IsSticky() const
+ {
+ if (remote_uri_.empty())
+ return BamfLauncherIcon::IsSticky();
+ else
+ return SimpleLauncherIcon::IsSticky();
+ }
+
+ void ReallyStick(bool save) { BamfLauncherIcon::Stick(save); }
+
+ MOCK_METHOD1(Stick, void(bool));
MOCK_METHOD0(UnStick, void());
MOCK_METHOD0(Quit, void());
+
+ std::string remote_uri_;
+};
+
+struct MockVolumeLauncherIcon : public VolumeLauncherIcon
+{
+ typedef nux::ObjectPtr<MockVolumeLauncherIcon> Ptr;
+
+ MockVolumeLauncherIcon()
+ : VolumeLauncherIcon(Volume::Ptr(volume_ = new MockVolume()),
+ std::make_shared<MockDevicesSettings>())
+ , uuid_(std::to_string(g_random_int()))
+ {
+ ON_CALL(*volume_, GetIdentifier()).WillByDefault(Return(uuid_));
+ ON_CALL(*this, Stick(_)).WillByDefault(Invoke(this, &MockVolumeLauncherIcon::ReallyStick));
+ }
+
+ void ReallyStick(bool save) { VolumeLauncherIcon::Stick(save); }
+
+ MOCK_METHOD1(Stick, void(bool));
+ MOCK_METHOD0(UnStick, void());
+
+ MockVolume* volume_;
+ std::string uuid_;
};
namespace launcher
{
-class TestLauncherController : public testing::Test
+struct TestLauncherController : public testing::Test
{
-public:
- TestLauncherController()
- : lc(nux::GetGraphicsDisplay()->GetX11Display())
- {}
-
virtual void SetUp()
{
lc.multiple_launchers = true;
}
protected:
- ui::EdgeBarrierController &GetBarrierController()
+ struct MockLauncherController : Controller
{
- return lc.pimpl->edge_barriers_;
- }
+ Controller::Impl* Impl() const { return pimpl.get(); }
- LauncherModel::Ptr GetLauncherModel()
- {
- return lc.pimpl->model_;
- }
+ AbstractLauncherIcon::Ptr GetIconByDesktop(std::string const& path) const
+ {
+ auto const& model = Impl()->model_;
+ auto icon = std::find_if(model->begin(), model->end(),
+ [&path](AbstractLauncherIcon::Ptr const& i) { return ( i->DesktopFile() == path); });
+
+ if (icon != model->end())
+ return *icon;
+
+ return AbstractLauncherIcon::Ptr();
+ }
+
+ void ClearModel()
+ {
+ auto const& model = Impl()->model_;
+ std::vector<AbstractLauncherIcon::Ptr> icons;
+
+ for (auto const& icon : *model)
+ icons.push_back(icon);
+
+ for (auto const& icon : icons)
+ model->RemoveIcon(icon);
+
+ ASSERT_EQ(model->Size(), 0);
+ }
+
+ void DisconnectSignals()
+ {
+ Impl()->view_opened_signal_.Disconnect();
+ Impl()->device_section_.icon_added.clear();
+ Impl()->model_->icon_removed.clear();
+ Impl()->model_->saved.clear();
+ Impl()->model_->order_changed.clear();
+ }
+ };
MockUScreen uscreen;
Settings settings;
panel::Style panel_style;
MockFavoriteStore favorite_store;
- Controller lc;
+ MockLauncherController lc;
};
}
@@ -98,6 +266,29 @@ TEST_F(TestLauncherController, Construction)
EXPECT_TRUE(lc.multiple_launchers());
ASSERT_EQ(lc.launchers().size(), 1);
EXPECT_EQ(lc.launcher().monitor(), 0);
+ ASSERT_EQ(lc.Impl()->parent_, &lc);
+ ASSERT_TRUE(lc.Impl()->matcher_.IsType(BAMF_TYPE_MATCHER));
+ ASSERT_NE(lc.Impl()->model_, nullptr);
+ EXPECT_EQ(lc.Impl()->expo_icon_->GetIconType(), AbstractLauncherIcon::IconType::EXPO);
+ EXPECT_EQ(lc.Impl()->desktop_icon_->GetIconType(), AbstractLauncherIcon::IconType::DESKTOP);
+ EXPECT_GE(lc.Impl()->sort_priority_, AbstractLauncherIcon::DefaultPriority(AbstractLauncherIcon::IconType::APPLICATION));
+ EXPECT_EQ(lc.Impl()->model_->GetSublist<BFBLauncherIcon>().size(), 1);
+ EXPECT_EQ(lc.Impl()->model_->GetSublist<HudLauncherIcon>().size(), 1);
+ EXPECT_EQ(lc.Impl()->model_->GetSublist<TrashLauncherIcon>().size(), 1);
+ EXPECT_FALSE(lc.Impl()->launcher_open);
+ EXPECT_FALSE(lc.Impl()->launcher_keynav);
+ EXPECT_FALSE(lc.Impl()->launcher_grabbed);
+ EXPECT_FALSE(lc.Impl()->reactivate_keynav);
+ EXPECT_TRUE(lc.Impl()->keynav_restore_window_);
+ EXPECT_EQ(lc.Impl()->launcher_key_press_time_, 0);
+
+ for (auto const& fav_uri : favorite_store.GetFavorites())
+ {
+ auto const& model_icon_it = std::find_if(lc.Impl()->model_->begin(), lc.Impl()->model_->end(),
+ [&fav_uri](AbstractLauncherIcon::Ptr const& i) { return (i->RemoteUri() == fav_uri); });
+
+ ASSERT_TRUE((*model_icon_it).IsValid());
+ }
}
TEST_F(TestLauncherController, MultimonitorMultipleLaunchers)
@@ -188,7 +379,7 @@ TEST_F(TestLauncherController, MultiMonitorEdgeBarrierSubscriptions)
uscreen.SetupFakeMultiMonitor();
for (int i = 0; i < max_num_monitors; ++i)
- ASSERT_EQ(GetBarrierController().GetSubscriber(i), lc.launchers()[i].GetPointer());
+ ASSERT_EQ(lc.Impl()->edge_barriers_.GetSubscriber(i), lc.launchers()[i].GetPointer());
}
TEST_F(TestLauncherController, SingleMonitorEdgeBarrierSubscriptionsUpdates)
@@ -204,11 +395,11 @@ TEST_F(TestLauncherController, SingleMonitorEdgeBarrierSubscriptionsUpdates)
{
if (j == i)
{
- ASSERT_EQ(GetBarrierController().GetSubscriber(j), &lc.launcher());
+ ASSERT_EQ(lc.Impl()->edge_barriers_.GetSubscriber(j), &lc.launcher());
}
else
{
- ASSERT_EQ(GetBarrierController().GetSubscriber(j), nullptr);
+ ASSERT_EQ(lc.Impl()->edge_barriers_.GetSubscriber(j), nullptr);
}
}
}
@@ -216,18 +407,14 @@ TEST_F(TestLauncherController, SingleMonitorEdgeBarrierSubscriptionsUpdates)
TEST_F(TestLauncherController, OnlyUnstickIconOnFavoriteRemoval)
{
- const std::string USC_DESKTOP = BUILDDIR"/tests/data/ubuntu-software-center.desktop";
-
- glib::Object<BamfMatcher> matcher(bamf_matcher_get_default());
-
- auto bamf_app = bamf_matcher_get_application_for_desktop_file(matcher, USC_DESKTOP.c_str(), TRUE);
- MockBamfLauncherIcon *bamf_icon = new MockBamfLauncherIcon(bamf_app);
- GetLauncherModel()->AddIcon(AbstractLauncherIcon::Ptr(bamf_icon));
+ const std::string desktop = app::BZR_HANDLE_PATCH;
+ MockBamfLauncherIcon::Ptr bamf_icon(new MockBamfLauncherIcon(desktop));
+ lc.Impl()->model_->AddIcon(bamf_icon);
EXPECT_CALL(*bamf_icon, UnStick());
EXPECT_CALL(*bamf_icon, Quit()).Times(0);
- favorite_store.favorite_removed.emit(USC_DESKTOP);
+ favorite_store.favorite_removed.emit(FavoriteStore::URI_PREFIX_APP + desktop);
}
TEST_F(TestLauncherController, EnabledStrutsByDefault)
@@ -290,5 +477,1020 @@ TEST_F(TestLauncherController, DisabledStrutsAddingNewLaunchersOnNeverHide)
ASSERT_FALSE(lc.launchers()[i]->GetParent()->InputWindowStrutsEnabled());
}
+TEST_F(TestLauncherController, CreateFavoriteInvalid)
+{
+ auto const& fav = lc.Impl()->CreateFavoriteIcon("InvalidUri");
+
+ EXPECT_FALSE(fav.IsValid());
+}
+
+TEST_F(TestLauncherController, CreateFavoriteDesktopFile)
+{
+ std::string desktop_file = app::BZR_HANDLE_PATCH;
+ std::string icon_uri = FavoriteStore::URI_PREFIX_APP + desktop_file;
+ auto const& fav = lc.Impl()->CreateFavoriteIcon(icon_uri);
+
+ ASSERT_TRUE(fav.IsValid());
+ EXPECT_EQ(fav->GetIconType(), AbstractLauncherIcon::IconType::APPLICATION);
+ EXPECT_EQ(fav->DesktopFile(), desktop_file);
+ EXPECT_EQ(fav->RemoteUri(), icon_uri);
+ EXPECT_TRUE(fav->IsSticky());
+ EXPECT_NE(dynamic_cast<BamfLauncherIcon*>(fav.GetPointer()), nullptr);
+}
+
+TEST_F(TestLauncherController, CreateFavoriteInvalidDesktopFile)
+{
+ // This desktop file has already been added as favorite, so it is invalid
+ std::string desktop_file = *(favorite_store.GetFavorites().begin());
+ std::string icon_uri = FavoriteStore::URI_PREFIX_APP + desktop_file;
+ auto const& fav = lc.Impl()->CreateFavoriteIcon(icon_uri);
+
+ EXPECT_FALSE(fav.IsValid());
+}
+
+TEST_F(TestLauncherController, CreateFavoriteDevice)
+{
+ lc.Impl()->device_section_ = MockDeviceLauncherSection();
+ auto const& icons = lc.Impl()->device_section_.GetIcons();
+ auto const& device_icon = *(icons.begin());
+
+ ASSERT_TRUE(device_icon.IsValid());
+ ASSERT_FALSE(device_icon->IsSticky());
+
+ auto const& fav = lc.Impl()->CreateFavoriteIcon(device_icon->RemoteUri());
+
+ ASSERT_TRUE(fav.IsValid());
+ EXPECT_EQ(fav, device_icon);
+ EXPECT_EQ(fav->GetIconType(), AbstractLauncherIcon::IconType::DEVICE);
+ EXPECT_EQ(fav->RemoteUri(), device_icon->RemoteUri());
+ EXPECT_TRUE(fav->IsSticky());
+ EXPECT_NE(dynamic_cast<VolumeLauncherIcon*>(fav.GetPointer()), nullptr);
+}
+
+TEST_F(TestLauncherController, CreateFavoriteInvalidDevice)
+{
+ auto const& fav = lc.Impl()->CreateFavoriteIcon(FavoriteStore::URI_PREFIX_APP + "invalid-uuid");
+
+ EXPECT_FALSE(fav.IsValid());
+}
+
+TEST_F(TestLauncherController, CreateFavoriteExpoIcon)
+{
+ lc.Impl()->expo_icon_->UnStick();
+ std::string icon_uri = FavoriteStore::URI_PREFIX_UNITY + "expo-icon";
+ auto const& fav = lc.Impl()->CreateFavoriteIcon(icon_uri);
+
+ ASSERT_TRUE(fav.IsValid());
+ EXPECT_EQ(fav, lc.Impl()->expo_icon_);
+ EXPECT_EQ(fav->GetIconType(), AbstractLauncherIcon::IconType::EXPO);
+ EXPECT_EQ(fav->RemoteUri(), icon_uri);
+ EXPECT_TRUE(fav->IsSticky());
+ EXPECT_NE(dynamic_cast<ExpoLauncherIcon*>(fav.GetPointer()), nullptr);
+}
+
+TEST_F(TestLauncherController, CreateFavoriteDesktopIcon)
+{
+ lc.Impl()->desktop_icon_->UnStick();
+ std::string icon_uri = FavoriteStore::URI_PREFIX_UNITY + "desktop-icon";
+ auto const& fav = lc.Impl()->CreateFavoriteIcon(icon_uri);
+
+ ASSERT_TRUE(fav.IsValid());
+ EXPECT_EQ(fav, lc.Impl()->desktop_icon_);
+ EXPECT_EQ(fav->GetIconType(), AbstractLauncherIcon::IconType::DESKTOP);
+ EXPECT_EQ(fav->RemoteUri(), icon_uri);
+ EXPECT_TRUE(fav->IsSticky());
+ EXPECT_NE(dynamic_cast<DesktopLauncherIcon*>(fav.GetPointer()), nullptr);
+}
+
+TEST_F(TestLauncherController, CreateFavoriteInvalidUnity)
+{
+ std::string icon_uri = FavoriteStore::URI_PREFIX_UNITY + "foooooo";
+ auto const& fav = lc.Impl()->CreateFavoriteIcon(icon_uri);
+
+ EXPECT_FALSE(fav.IsValid());
+}
+
+TEST_F(TestLauncherController, RegisterIconApplication)
+{
+ AbstractLauncherIcon::Ptr icon(new MockLauncherIcon());
+ int pre_priority = icon->SortPriority();
+
+ ASSERT_TRUE(icon->position_saved.empty());
+ ASSERT_TRUE(icon->position_forgot.empty());
+ ASSERT_TRUE(icon->visibility_changed.empty());
+ ASSERT_EQ(lc.Impl()->model_->IconIndex(icon), -1);
+
+ lc.Impl()->RegisterIcon(icon);
+
+ EXPECT_EQ(pre_priority, icon->SortPriority());
+ EXPECT_FALSE(icon->position_saved.empty());
+ EXPECT_FALSE(icon->position_forgot.empty());
+ EXPECT_FALSE(icon->visibility_changed.empty());
+ EXPECT_NE(lc.Impl()->model_->IconIndex(icon), -1);
+}
+
+TEST_F(TestLauncherController, RegisterIconApplicationWithPriority)
+{
+ AbstractLauncherIcon::Ptr icon(new MockLauncherIcon());
+ lc.Impl()->RegisterIcon(icon, std::numeric_limits<int>::max());
+ EXPECT_EQ(icon->SortPriority(), std::numeric_limits<int>::max());
+}
+
+TEST_F(TestLauncherController, RegisterIconApplicationWithDefaultPriority)
+{
+ AbstractLauncherIcon::Ptr icon(new MockLauncherIcon());
+ int pre_priority = icon->SortPriority();
+ lc.Impl()->RegisterIcon(icon, std::numeric_limits<int>::min());
+ EXPECT_EQ(icon->SortPriority(), pre_priority);
+}
+
+TEST_F(TestLauncherController, RegisterIconTwoTimesDoesNotWork)
+{
+ AbstractLauncherIcon::Ptr icon(new MockLauncherIcon());
+ lc.Impl()->RegisterIcon(icon, std::numeric_limits<int>::min());
+ int pre_registrations = icon->visibility_changed.size();
+
+ lc.Impl()->RegisterIcon(icon, std::numeric_limits<int>::min());
+ EXPECT_EQ(icon->visibility_changed.size(), pre_registrations);
+}
+
+TEST_F(TestLauncherController, RegisterIconDevice)
+{
+ AbstractLauncherIcon::Ptr icon(new MockLauncherIcon(AbstractLauncherIcon::IconType::DEVICE));
+ int pre_priority = icon->SortPriority();
+
+ lc.Impl()->RegisterIcon(icon);
+
+ EXPECT_EQ(pre_priority, icon->SortPriority());
+ EXPECT_FALSE(icon->position_saved.empty());
+ EXPECT_FALSE(icon->position_forgot.empty());
+ EXPECT_TRUE(icon->visibility_changed.empty());
+ EXPECT_NE(lc.Impl()->model_->IconIndex(icon), -1);
+}
+
+TEST_F(TestLauncherController, RegisteredIconSavesPosition)
+{
+ MockBamfLauncherIcon::Ptr app_icon(new MockBamfLauncherIcon(true, "normal-icon.desktop"));
+ lc.Impl()->RegisterIcon(app_icon);
+ ASSERT_FALSE(favorite_store.IsFavorite(app_icon->RemoteUri()));
+
+ app_icon->Stick(true);
+ ASSERT_TRUE(app_icon->IsSticky());
+ EXPECT_TRUE(favorite_store.IsFavorite(app_icon->RemoteUri()));
+}
+
+TEST_F(TestLauncherController, RegisteredIconForgetsPosition)
+{
+ auto const& fav = lc.Impl()->GetIconByUri(*(favorite_store.GetFavorites().begin()));
+ ASSERT_TRUE(favorite_store.IsFavorite(fav->RemoteUri()));
+
+ fav->UnStick();
+ EXPECT_FALSE(favorite_store.IsFavorite(fav->RemoteUri()));
+}
+
+TEST_F(TestLauncherController, GetIconByUriDesktop)
+{
+ lc.Impl()->RegisterIcon(lc.Impl()->desktop_icon_);
+ std::string icon_uri = FavoriteStore::URI_PREFIX_UNITY + "desktop-icon";
+ auto const& fav = lc.Impl()->GetIconByUri(icon_uri);
+
+ EXPECT_EQ(fav, lc.Impl()->desktop_icon_);
+}
+
+TEST_F(TestLauncherController, GetIconByUriExpo)
+{
+ lc.Impl()->RegisterIcon(lc.Impl()->expo_icon_);
+ std::string icon_uri = FavoriteStore::URI_PREFIX_UNITY + "expo-icon";
+ auto const& fav = lc.Impl()->GetIconByUri(icon_uri);
+
+ EXPECT_EQ(fav, lc.Impl()->expo_icon_);
+}
+
+TEST_F(TestLauncherController, GetIconByUriApplications)
+{
+ for (auto const& fav_uri : favorite_store.GetFavorites())
+ {
+ auto const& model_icon_it = std::find_if(lc.Impl()->model_->begin(), lc.Impl()->model_->end(),
+ [&fav_uri](AbstractLauncherIcon::Ptr const& i) { return (i->RemoteUri() == fav_uri); });
+ ASSERT_NE(model_icon_it, lc.Impl()->model_->end());
+
+ auto const& fav = lc.Impl()->GetIconByUri(fav_uri);
+ ASSERT_EQ(fav, *model_icon_it);
+ }
+
+ std::string desktop = app::BZR_HANDLE_PATCH;
+ std::string icon_uri = FavoriteStore::URI_PREFIX_APP + desktop;
+ auto const& fav = lc.Impl()->CreateFavoriteIcon(icon_uri);
+ lc.Impl()->RegisterIcon(fav);
+ EXPECT_EQ(fav, lc.Impl()->GetIconByUri(icon_uri));
+}
+
+TEST_F(TestLauncherController, AddRunningApps)
+{
+ lc.ClearModel();
+ lc.DisconnectSignals();
+ lc.Impl()->AddRunningApps();
+
+ std::shared_ptr<GList> apps(bamf_matcher_get_applications(lc.Impl()->matcher_), g_list_free);
+
+ for (GList *l = apps.get(); l; l = l->next)
+ {
+ if (!BAMF_IS_APPLICATION(l->data))
+ continue;
+
+ BamfApplication* app = BAMF_APPLICATION(l->data);
+
+ ASSERT_NE(g_object_get_qdata(G_OBJECT(app), g_quark_from_static_string("unity-seen")), nullptr);
+
+ auto desktop = bamf_application_get_desktop_file(app);
+ std::string path(desktop ? desktop : "");
+
+ if (path.empty())
+ continue;
+
+ ASSERT_TRUE(lc.GetIconByDesktop(path).IsValid());
+ }
+}
+
+TEST_F(TestLauncherController, AddDevices)
+{
+ lc.ClearModel();
+ lc.DisconnectSignals();
+ lc.Impl()->device_section_ = MockDeviceLauncherSection();
+ auto const& icons = lc.Impl()->device_section_.GetIcons();
+ auto const& device_icon1 = *(icons.begin());
+ auto const& device_icon2 = *(std::next(icons.begin()));
+
+ device_icon1->Stick(false);
+
+ lc.Impl()->AddDevices();
+
+ EXPECT_FALSE(lc.Impl()->GetIconByUri(device_icon1->RemoteUri()).IsValid());
+ EXPECT_TRUE(lc.Impl()->GetIconByUri(device_icon2->RemoteUri()).IsValid());
+}
+
+TEST_F(TestLauncherController, SetupIcons)
+{
+ lc.ClearModel();
+ lc.Impl()->device_section_ = MockDeviceLauncherSection();
+ auto const& model = lc.Impl()->model_;
+ int icon_index = 0;
+
+ favorite_store.SetFavorites({ FavoriteStore::URI_PREFIX_APP + app::UBUNTU_ONE,
+ FavoriteStore::URI_PREFIX_APP + app::SW_CENTER,
+ places::DEVICES_URI,
+ FavoriteStore::URI_PREFIX_APP + app::UPDATE_MANAGER });
+ std::shared_ptr<GList> apps(bamf_matcher_get_applications(lc.Impl()->matcher_), g_list_free);
+ lc.Impl()->SetupIcons();
+ lc.DisconnectSignals();
+
+ auto fav = lc.Impl()->GetIconByUri(FavoriteStore::URI_PREFIX_APP + app::UBUNTU_ONE);
+ EXPECT_EQ(model->IconIndex(fav), icon_index);
+
+ 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())
+ ASSERT_EQ(model->IconIndex(device), ++icon_index);
+
+ fav = lc.Impl()->GetIconByUri(FavoriteStore::URI_PREFIX_APP + app::UPDATE_MANAGER);
+ EXPECT_EQ(model->IconIndex(fav), ++icon_index);
+
+
+ for (GList *l = apps.get(); l; l = l->next)
+ {
+ if (!BAMF_IS_APPLICATION(l->data))
+ continue;
+
+ auto desktop = bamf_application_get_desktop_file(BAMF_APPLICATION(l->data));
+ std::string path(desktop ? desktop : "");
+ ++icon_index;
+
+ if (path.empty())
+ continue;
+
+ auto const& icon = lc.GetIconByDesktop(path);
+
+ ASSERT_TRUE(icon.IsValid());
+ ASSERT_EQ(model->IconIndex(icon), icon_index);
+ }
+}
+
+TEST_F(TestLauncherController, ResetIconPriorities)
+{
+ lc.ClearModel();
+ lc.Impl()->device_section_ = MockDeviceLauncherSection();
+ auto const& model = lc.Impl()->model_;
+
+ favorite_store.AddFavorite(places::APPS_URI, -1);
+ favorite_store.AddFavorite(places::DEVICES_URI, -1);
+ std::shared_ptr<GList> apps(bamf_matcher_get_applications(lc.Impl()->matcher_), g_list_free);
+ lc.Impl()->SetupIcons();
+ lc.DisconnectSignals();
+
+ favorite_store.SetFavorites({ places::DEVICES_URI,
+ FavoriteStore::URI_PREFIX_APP + app::SW_CENTER,
+ places::APPS_URI,
+ FavoriteStore::URI_PREFIX_APP + app::UBUNTU_ONE,
+ FavoriteStore::URI_PREFIX_APP + app::UPDATE_MANAGER });
+ lc.Impl()->ResetIconPriorities();
+
+ int icon_index = -1;
+
+ 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);
+ EXPECT_EQ(model->IconIndex(fav), ++icon_index);
+
+ for (GList *l = apps.get(); l; l = l->next)
+ {
+ if (!BAMF_IS_APPLICATION(l->data))
+ continue;
+
+ auto desktop = bamf_application_get_desktop_file(BAMF_APPLICATION(l->data));
+ std::string path(desktop ? desktop : "");
+ ++icon_index;
+
+ if (path.empty())
+ continue;
+
+ auto const& icon = lc.GetIconByDesktop(path);
+
+ ASSERT_TRUE(icon.IsValid());
+ ASSERT_EQ(model->IconIndex(icon), icon_index);
+ }
+
+ fav = lc.Impl()->GetIconByUri(FavoriteStore::URI_PREFIX_APP + app::UBUNTU_ONE);
+ EXPECT_EQ(model->IconIndex(fav), ++icon_index);
+
+ fav = lc.Impl()->GetIconByUri(FavoriteStore::URI_PREFIX_APP + app::UPDATE_MANAGER);
+ EXPECT_EQ(model->IconIndex(fav), ++icon_index);
+}
+
+TEST_F(TestLauncherController, GetLastIconPriorityUnSticky)
+{
+ lc.ClearModel();
+ lc.Impl()->device_section_ = MockDeviceLauncherSection(3);
+ auto const& device_icons = lc.Impl()->device_section_.GetIcons();
+ auto const& last_device = *(device_icons.rbegin());
+
+ favorite_store.SetFavorites({ places::DEVICES_URI,
+ FavoriteStore::URI_PREFIX_APP + app::SW_CENTER });
+
+ lc.Impl()->SetupIcons();
+ lc.DisconnectSignals();
+
+ int last_priority = lc.Impl()->GetLastIconPriority<VolumeLauncherIcon>();
+ EXPECT_EQ(last_priority, last_device->SortPriority());
+}
+
+TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithAllStickyIcons)
+{
+ lc.ClearModel();
+ lc.Impl()->device_section_ = MockDeviceLauncherSection(3);
+ auto const& device_icons = lc.Impl()->device_section_.GetIcons();
+ auto const& last_device = *(device_icons.rbegin());
+
+ favorite_store.SetFavorites({ places::DEVICES_URI,
+ FavoriteStore::URI_PREFIX_APP + app::SW_CENTER });
+
+ lc.Impl()->SetupIcons();
+ lc.DisconnectSignals();
+
+ for (auto const& device : device_icons)
+ device->Stick(false);
+
+ int last_priority = lc.Impl()->GetLastIconPriority<VolumeLauncherIcon>();
+ EXPECT_EQ(last_priority, last_device->SortPriority());
+}
+
+TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithSomeStickyIcons)
+{
+ lc.ClearModel();
+ lc.Impl()->device_section_ = 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.rbegin());
+
+ favorite_store.SetFavorites({ places::DEVICES_URI,
+ FavoriteStore::URI_PREFIX_APP + app::SW_CENTER });
+
+ lc.Impl()->SetupIcons();
+ lc.DisconnectSignals();
+
+ last_device->Stick(false);
+
+ int last_priority = lc.Impl()->GetLastIconPriority<VolumeLauncherIcon>();
+ EXPECT_EQ(last_priority, first_device->SortPriority());
+}
+
+TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithNoIcons)
+{
+ lc.ClearModel();
+ lc.Impl()->device_section_ = MockDeviceLauncherSection(0);
+ lc.Impl()->SetupIcons();
+ lc.DisconnectSignals();
+
+ int last_priority = lc.Impl()->GetLastIconPriority<VolumeLauncherIcon>();
+ EXPECT_EQ(last_priority, std::numeric_limits<int>::min());
+}
+
+TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithNoIconsAndUri)
+{
+ lc.ClearModel();
+ lc.Impl()->device_section_ = MockDeviceLauncherSection(0);
+
+ favorite_store.SetFavorites({ places::DEVICES_URI,
+ FavoriteStore::URI_PREFIX_APP + app::SW_CENTER });
+ lc.Impl()->SetupIcons();
+
+ auto first_icon = lc.Impl()->GetIconByUri(FavoriteStore::URI_PREFIX_APP + app::SW_CENTER);
+
+ int last_priority = lc.Impl()->GetLastIconPriority<VolumeLauncherIcon>(places::DEVICES_URI);
+ EXPECT_EQ(last_priority, first_icon->SortPriority() - 1);
+
+ favorite_store.SetFavorites({ FavoriteStore::URI_PREFIX_APP + app::SW_CENTER,
+ places::DEVICES_URI });
+ favorite_store.reordered.emit();
+
+ first_icon = lc.Impl()->GetIconByUri(FavoriteStore::URI_PREFIX_APP + app::SW_CENTER);
+
+ last_priority = lc.Impl()->GetLastIconPriority<VolumeLauncherIcon>(places::DEVICES_URI);
+ EXPECT_EQ(last_priority, first_icon->SortPriority());
+}
+
+TEST_F(TestLauncherController, GetLastIconPrioritySticky)
+{
+ lc.ClearModel();
+ lc.Impl()->device_section_ = MockDeviceLauncherSection(3);
+ lc.Impl()->SetupIcons();
+ lc.DisconnectSignals();
+
+ auto const& device_icons = lc.Impl()->device_section_.GetIcons();
+ auto const& first_device = *(device_icons.begin());
+
+ int last_priority = lc.Impl()->GetLastIconPriority<VolumeLauncherIcon>("", true);
+ EXPECT_EQ(last_priority, first_device->SortPriority() - 1);
+}
+
+TEST_F(TestLauncherController, GetLastIconPriorityStickyWithAllStickyIcons)
+{
+ lc.ClearModel();
+ lc.Impl()->device_section_ = MockDeviceLauncherSection(3);
+ auto const& device_icons = lc.Impl()->device_section_.GetIcons();
+ auto const& last_device = *(device_icons.rbegin());
+
+ favorite_store.SetFavorites({ places::DEVICES_URI,
+ FavoriteStore::URI_PREFIX_APP + app::SW_CENTER });
+
+ lc.Impl()->SetupIcons();
+ lc.DisconnectSignals();
+
+ for (auto const& device : device_icons)
+ device->Stick(false);
+
+ int last_priority = lc.Impl()->GetLastIconPriority<VolumeLauncherIcon>("", true);
+ EXPECT_EQ(last_priority, last_device->SortPriority());
+}
+
+TEST_F(TestLauncherController, GetLastIconPriorityStickyWithSomeStickyIcons)
+{
+ lc.ClearModel();
+ lc.Impl()->device_section_ = 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,
+ FavoriteStore::URI_PREFIX_APP + app::SW_CENTER });
+
+ lc.Impl()->SetupIcons();
+ lc.DisconnectSignals();
+
+ first_device->Stick(false);
+
+ int last_priority = lc.Impl()->GetLastIconPriority<VolumeLauncherIcon>("", true);
+ EXPECT_EQ(last_priority, first_device->SortPriority());
+}
+
+TEST_F(TestLauncherController, GetLastIconPriorityStickyWithNoIcons)
+{
+ lc.ClearModel();
+ lc.Impl()->device_section_ = MockDeviceLauncherSection(0);
+ lc.Impl()->SetupIcons();
+ lc.DisconnectSignals();
+
+ int last_priority = lc.Impl()->GetLastIconPriority<VolumeLauncherIcon>();
+ EXPECT_EQ(last_priority, std::numeric_limits<int>::min());
}
+TEST_F(TestLauncherController, LauncherAddRequestApplicationAdd)
+{
+ auto const& model = lc.Impl()->model_;
+ std::string desktop = app::BZR_HANDLE_PATCH;
+ std::string icon_uri = FavoriteStore::URI_PREFIX_APP + desktop;
+ ASSERT_FALSE(lc.Impl()->GetIconByUri(icon_uri).IsValid());
+
+ auto app_icons = model->GetSublist<BamfLauncherIcon>();
+ auto const& second_app = *(std::next(app_icons.begin()));
+
+ lc.launcher().add_request.emit(icon_uri, second_app);
+
+ auto const& new_icon = lc.Impl()->GetIconByUri(icon_uri);
+ ASSERT_TRUE(new_icon.IsValid());
+ EXPECT_EQ(model->IconIndex(new_icon), model->IconIndex(second_app) + 1);
+}
+
+TEST_F(TestLauncherController, LauncherAddRequestApplicationStick)
+{
+ auto const& model = lc.Impl()->model_;
+ std::string desktop = app::BZR_HANDLE_PATCH;
+ std::string icon_uri = FavoriteStore::URI_PREFIX_FILE + desktop;
+
+ MockBamfLauncherIcon::Ptr bamf_icon(new MockBamfLauncherIcon(desktop));
+ lc.Impl()->RegisterIcon(bamf_icon, std::numeric_limits<int>::max());
+
+ auto app_icons = model->GetSublist<BamfLauncherIcon>();
+ auto const& first_app = *(app_icons.begin());
+ ASSERT_LT(model->IconIndex(first_app), model->IconIndex(bamf_icon));
+
+ EXPECT_CALL(*bamf_icon, Stick(false));
+ lc.launcher().add_request.emit(icon_uri, first_app);
+
+ EXPECT_EQ(model->IconIndex(bamf_icon), model->IconIndex(first_app) + 1);
+}
+
+TEST_F(TestLauncherController, LauncherAddRequestDeviceAdd)
+{
+ auto const& model = lc.Impl()->model_;
+ lc.Impl()->device_section_ = MockDeviceLauncherSection();
+ auto const& icons = lc.Impl()->device_section_.GetIcons();
+ auto const& device_icon = *(icons.begin());
+ auto const& icon_uri = device_icon->RemoteUri();
+
+ ASSERT_FALSE(lc.Impl()->GetIconByUri(icon_uri).IsValid());
+
+ auto app_icons = model->GetSublist<BamfLauncherIcon>();
+ auto const& first_app = *(app_icons.begin());
+
+ lc.launcher().add_request.emit(icon_uri, first_app);
+
+ auto const& new_icon = lc.Impl()->GetIconByUri(icon_uri);
+ ASSERT_TRUE(new_icon.IsValid());
+ EXPECT_EQ(new_icon, device_icon);
+ EXPECT_EQ(model->IconIndex(new_icon), model->IconIndex(first_app) + 1);
+}
+
+TEST_F(TestLauncherController, LauncherAddRequestDeviceStick)
+{
+ auto const& model = lc.Impl()->model_;
+ MockVolumeLauncherIcon::Ptr device_icon(new MockVolumeLauncherIcon());
+ lc.Impl()->RegisterIcon(device_icon, std::numeric_limits<int>::max());
+
+ auto app_icons = model->GetSublist<BamfLauncherIcon>();
+ auto const& second_app = *(std::next(app_icons.begin()));
+ ASSERT_LT(model->IconIndex(second_app), model->IconIndex(device_icon));
+
+ EXPECT_CALL(*device_icon, Stick(false));
+ lc.launcher().add_request.emit(device_icon->RemoteUri(), second_app);
+
+ EXPECT_EQ(model->IconIndex(device_icon), model->IconIndex(second_app) + 1);
+}
+
+TEST_F(TestLauncherController, LauncherRemoveRequestApplicationUnStickAndQuit)
+{
+ MockBamfLauncherIcon::Ptr bamf_icon(new MockBamfLauncherIcon());
+
+ EXPECT_CALL(*bamf_icon, UnStick());
+ EXPECT_CALL(*bamf_icon, Quit());
+ lc.launcher().remove_request.emit(bamf_icon);
+}
+
+TEST_F(TestLauncherController, LauncherRemoveRequestDeviceEjects)
+{
+ MockVolumeLauncherIcon::Ptr device_icon(new MockVolumeLauncherIcon());
+
+ EXPECT_CALL(*(device_icon->volume_), CanBeEjected())
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(*(device_icon->volume_), CanBeStopped())
+ .WillRepeatedly(Return(true));
+
+ EXPECT_CALL(*(device_icon->volume_), EjectAndShowNotification());
+ EXPECT_CALL(*(device_icon->volume_), StopDrive()).Times(0);
+
+ lc.launcher().remove_request.emit(device_icon);
+}
+
+TEST_F(TestLauncherController, LauncherRemoveRequestDeviceStops)
+{
+ MockVolumeLauncherIcon::Ptr device_icon(new MockVolumeLauncherIcon());
+
+ EXPECT_CALL(*(device_icon->volume_), CanBeEjected())
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(*(device_icon->volume_), CanBeStopped())
+ .WillRepeatedly(Return(true));
+
+ EXPECT_CALL(*(device_icon->volume_), StopDrive());
+ EXPECT_CALL(*(device_icon->volume_), EjectAndShowNotification()).Times(0);
+
+ lc.launcher().remove_request.emit(device_icon);
+}
+
+TEST_F(TestLauncherController, LauncherAddRequestSpecial)
+{
+ std::string desktop = app::BZR_HANDLE_PATCH;
+ std::string icon_uri = FavoriteStore::URI_PREFIX_APP + desktop;
+ ASSERT_FALSE(lc.Impl()->GetIconByUri(icon_uri).IsValid());
+
+ lc.Impl()->OnLauncherAddRequestSpecial(desktop, "", "", 0, 0, 32);
+
+ auto const& sw_center_icon = lc.Impl()->GetIconByUri(icon_uri);
+ ASSERT_TRUE(sw_center_icon.IsValid());
+ EXPECT_NE(dynamic_cast<SoftwareCenterLauncherIcon*>(sw_center_icon.GetPointer()), nullptr);
+}
+
+TEST_F(TestLauncherController, LauncherAddRequestSpecialIgnored)
+{
+ std::string desktop = app::BZR_HANDLE_PATCH;
+ std::string icon_uri = FavoriteStore::URI_PREFIX_APP + desktop;
+
+ MockBamfLauncherIcon::Ptr bamf_icon(new MockBamfLauncherIcon(desktop));
+ lc.Impl()->RegisterIcon(bamf_icon, std::numeric_limits<int>::max());
+ ASSERT_TRUE(lc.Impl()->GetIconByUri(icon_uri).IsValid());
+
+ EXPECT_CALL(*bamf_icon, Stick(false)).Times(0);
+
+ int previous_model_size = lc.Impl()->model_->Size();
+ lc.Impl()->OnLauncherAddRequestSpecial(desktop, "", "", 0, 0, 32);
+
+ EXPECT_EQ(previous_model_size, lc.Impl()->model_->Size());
+}
+
+TEST_F(TestLauncherController, SaveIconsOrder)
+{
+ favorite_store.ClearFavorites();
+ lc.ClearModel();
+ lc.DisconnectSignals();
+ int priority = 0;
+
+ MockBamfLauncherIcon::Ptr sticky_app(new MockBamfLauncherIcon(true, "sticky-app"));
+ sticky_app->Stick(false);
+ lc.Impl()->RegisterIcon(sticky_app, ++priority);
+
+ MockBamfLauncherIcon::Ptr invisible_app(new MockBamfLauncherIcon(true, "invisible-app"));
+ invisible_app->SetQuirk(AbstractLauncherIcon::Quirk::VISIBLE, false);
+ lc.Impl()->RegisterIcon(invisible_app, ++priority);
+
+ MockVolumeLauncherIcon::Ptr sticky_device(new MockVolumeLauncherIcon());
+ sticky_device->Stick(false);
+ lc.Impl()->RegisterIcon(sticky_device, ++priority);
+
+ MockVolumeLauncherIcon::Ptr device(new MockVolumeLauncherIcon());
+ lc.Impl()->RegisterIcon(device, ++priority);
+
+ MockBamfLauncherIcon::Ptr running_app(new MockBamfLauncherIcon(true, "running-app"));
+ lc.Impl()->RegisterIcon(running_app, ++priority);
+
+ lc.Impl()->SaveIconsOrder();
+
+ auto it = favorite_store.GetFavorites().begin();
+
+ ASSERT_EQ(*it, sticky_app->RemoteUri()); ++it;
+ ASSERT_EQ(*it, sticky_device->RemoteUri()); ++it;
+ ASSERT_EQ(*it, places::DEVICES_URI); ++it;
+ ASSERT_EQ(*it, places::APPS_URI); ++it;
+ ASSERT_EQ(it, favorite_store.GetFavorites().end());
+}
+
+TEST_F(TestLauncherController, SaveIconsOrderWithOnlyStickyIcons)
+{
+ favorite_store.ClearFavorites();
+ lc.ClearModel();
+ int priority = 0;
+
+ MockBamfLauncherIcon::Ptr sticky_app(new MockBamfLauncherIcon(true, "sticky-app"));
+ sticky_app->Stick(false);
+ lc.Impl()->RegisterIcon(sticky_app, ++priority);
+
+ MockVolumeLauncherIcon::Ptr sticky_device(new MockVolumeLauncherIcon());
+ sticky_device->Stick(false);
+ lc.Impl()->RegisterIcon(sticky_device, ++priority);
+
+ lc.Impl()->SaveIconsOrder();
+
+ auto it = favorite_store.GetFavorites().begin();
+
+ ASSERT_EQ(*it, sticky_app->RemoteUri()); ++it;
+ ASSERT_EQ(*it, sticky_device->RemoteUri()); ++it;
+ ASSERT_EQ(*it, places::APPS_URI); ++it;
+ ASSERT_EQ(*it, places::DEVICES_URI); ++it;
+ ASSERT_EQ(it, favorite_store.GetFavorites().end());
+}
+
+TEST_F(TestLauncherController, SaveIconsOrderTriesToKeepIconProvidersOrder)
+{
+ favorite_store.ClearFavorites();
+ lc.ClearModel();
+ int priority = 0;
+
+ favorite_store.SetFavorites({FavoriteStore::URI_PREFIX_APP + "foo.desktop", places::DEVICES_URI,
+ FavoriteStore::URI_PREFIX_APP + "bar.desktop", places::APPS_URI,
+ FavoriteStore::URI_PREFIX_APP + "foobar.desktop"});
+
+ MockBamfLauncherIcon::Ptr sticky_app(new MockBamfLauncherIcon(true, "sticky-app"));
+ sticky_app->Stick(false);
+ lc.Impl()->RegisterIcon(sticky_app, ++priority);
+
+ MockVolumeLauncherIcon::Ptr sticky_device(new MockVolumeLauncherIcon());
+ sticky_device->Stick(false);
+ lc.Impl()->RegisterIcon(sticky_device, ++priority);
+
+ lc.Impl()->SaveIconsOrder();
+
+ auto it = favorite_store.GetFavorites().begin();
+
+ ASSERT_EQ(*it, places::DEVICES_URI); ++it;
+ ASSERT_EQ(*it, places::APPS_URI); ++it;
+ ASSERT_EQ(*it, sticky_app->RemoteUri()); ++it;
+ ASSERT_EQ(*it, sticky_device->RemoteUri()); ++it;
+ ASSERT_EQ(it, favorite_store.GetFavorites().end());
+}
+
+TEST_F(TestLauncherController, SaveIconsOrderTriesToKeepIconProvidersOrder2)
+{
+ favorite_store.ClearFavorites();
+ lc.ClearModel();
+ int priority = 0;
+
+ MockBamfLauncherIcon::Ptr sticky_app(new MockBamfLauncherIcon(true, "sticky-app"));
+ sticky_app->Stick(false);
+ lc.Impl()->RegisterIcon(sticky_app, ++priority);
+
+ MockVolumeLauncherIcon::Ptr sticky_device(new MockVolumeLauncherIcon());
+ sticky_device->Stick(false);
+ lc.Impl()->RegisterIcon(sticky_device, ++priority);
+
+ favorite_store.SetFavorites({places::DEVICES_URI, sticky_app->RemoteUri(), places::APPS_URI});
+ lc.Impl()->SaveIconsOrder();
+
+ auto it = favorite_store.GetFavorites().begin();
+
+ ASSERT_EQ(*it, places::DEVICES_URI); ++it;
+ ASSERT_EQ(*it, sticky_app->RemoteUri()); ++it;
+ ASSERT_EQ(*it, places::APPS_URI); ++it;
+ ASSERT_EQ(*it, sticky_device->RemoteUri()); ++it;
+ ASSERT_EQ(it, favorite_store.GetFavorites().end());
+}
+
+TEST_F(TestLauncherController, SortAndUpdate)
+{
+ lc.ClearModel();
+
+ MockVolumeLauncherIcon::Ptr device(new MockVolumeLauncherIcon());
+ lc.Impl()->RegisterIcon(device, 0);
+
+ for (int i = 0; i < 15; ++i)
+ {
+ MockBamfLauncherIcon::Ptr app(new MockBamfLauncherIcon());
+ app->SetQuirk(AbstractLauncherIcon::Quirk::VISIBLE, (i % 5) != 0);
+ lc.Impl()->RegisterIcon(app, 0);
+ }
+
+ int expected_shortcut = 1;
+
+ for (auto const& icon : *(lc.Impl()->model_))
+ {
+ if (icon->IsVisible() && icon->GetIconType() == AbstractLauncherIcon::IconType::APPLICATION && expected_shortcut <= 10)
+ {
+ ASSERT_EQ(icon->GetShortcut(), std::to_string(expected_shortcut % 10)[0]);
+ ++expected_shortcut;
+ }
+ else
+ {
+ ASSERT_EQ(icon->GetShortcut(), 0);
+ }
+ }
+}
+
+TEST_F(TestLauncherController, OnFavoriteStoreFavoriteAddedNew)
+{
+ std::string icon_uri = FavoriteStore::URI_PREFIX_APP + app::BZR_HANDLE_PATCH;
+
+ favorite_store.favorite_added.emit(icon_uri, "", true);
+
+ auto const& new_icon = lc.Impl()->GetIconByUri(icon_uri);
+ ASSERT_TRUE(new_icon.IsValid());
+ EXPECT_TRUE(new_icon->IsSticky());
+}
+
+TEST_F(TestLauncherController, OnFavoriteStoreFavoriteAddedNewBeforeIcon)
+{
+ std::string icon_uri = FavoriteStore::URI_PREFIX_APP + app::BZR_HANDLE_PATCH;
+ auto const& model = lc.Impl()->model_;
+
+ auto app_icons = model->GetSublist<BamfLauncherIcon>();
+ auto const& first_app = *(app_icons.begin());
+ favorite_store.favorite_added.emit(icon_uri, first_app->RemoteUri(), true);
+
+ auto const& new_icon = lc.Impl()->GetIconByUri(icon_uri);
+
+ ASSERT_TRUE(new_icon.IsValid());
+ EXPECT_TRUE(new_icon->IsSticky());
+ EXPECT_EQ(model->IconIndex(new_icon), model->IconIndex(first_app) - 1);
+}
+
+TEST_F(TestLauncherController, OnFavoriteStoreFavoriteAddedNewAfterIcon)
+{
+ std::string icon_uri = FavoriteStore::URI_PREFIX_APP + app::BZR_HANDLE_PATCH;
+ auto const& model = lc.Impl()->model_;
+
+ auto app_icons = model->GetSublist<BamfLauncherIcon>();
+ auto const& first_app = *(app_icons.begin());
+ favorite_store.favorite_added.emit(icon_uri, first_app->RemoteUri(), false);
+
+ auto const& new_icon = lc.Impl()->GetIconByUri(icon_uri);
+
+ ASSERT_TRUE(new_icon.IsValid());
+ EXPECT_TRUE(new_icon->IsSticky());
+ EXPECT_EQ(model->IconIndex(new_icon), model->IconIndex(first_app) + 1);
+}
+
+TEST_F(TestLauncherController, OnFavoriteStoreFavoriteAddedStick)
+{
+ std::string desktop = app::BZR_HANDLE_PATCH;
+ std::string icon_uri = FavoriteStore::URI_PREFIX_APP + desktop;
+
+ MockBamfLauncherIcon::Ptr app_icon(new MockBamfLauncherIcon(desktop));
+ lc.Impl()->RegisterIcon(app_icon, std::numeric_limits<int>::max());
+
+ EXPECT_CALL(*app_icon, Stick(false));
+ favorite_store.favorite_added.emit(icon_uri, "", false);
+ EXPECT_TRUE(app_icon->IsSticky());
+}
+
+TEST_F(TestLauncherController, OnFavoriteStoreFavoriteAddedStickBefore)
+{
+ auto const& model = lc.Impl()->model_;
+ std::string desktop = app::BZR_HANDLE_PATCH;
+ std::string icon_uri = FavoriteStore::URI_PREFIX_APP + desktop;
+
+ MockBamfLauncherIcon::Ptr app_icon(new MockBamfLauncherIcon(desktop));
+ lc.Impl()->RegisterIcon(app_icon, std::numeric_limits<int>::max());
+
+ auto app_icons = model->GetSublist<BamfLauncherIcon>();
+ auto const& first_app = *(app_icons.begin());
+ ASSERT_LT(model->IconIndex(first_app), model->IconIndex(app_icon));
+
+ EXPECT_CALL(*app_icon, Stick(false));
+
+ favorite_store.favorite_added.emit(icon_uri, first_app->RemoteUri(), false);
+ EXPECT_TRUE(app_icon->IsSticky());
+ EXPECT_EQ(model->IconIndex(app_icon), model->IconIndex(first_app) + 1);
+}
+
+TEST_F(TestLauncherController, OnFavoriteStoreFavoriteAddedStickAfter)
+{
+ auto const& model = lc.Impl()->model_;
+ std::string desktop = app::BZR_HANDLE_PATCH;
+ std::string icon_uri = FavoriteStore::URI_PREFIX_APP + desktop;
+
+ MockBamfLauncherIcon::Ptr app_icon(new MockBamfLauncherIcon(desktop));
+ lc.Impl()->RegisterIcon(app_icon, std::numeric_limits<int>::max());
+
+ auto const& app_icons = model->GetSublist<BamfLauncherIcon>();
+ auto const& first_app = *(app_icons.begin());
+ ASSERT_LT(model->IconIndex(first_app), model->IconIndex(app_icon));
+
+ EXPECT_CALL(*app_icon, Stick(false));
+
+ favorite_store.favorite_added.emit(icon_uri, first_app->RemoteUri(), true);
+ EXPECT_TRUE(app_icon->IsSticky());
+ EXPECT_EQ(model->IconIndex(app_icon), model->IconIndex(first_app) - 1);
+}
+
+TEST_F(TestLauncherController, OnFavoriteStoreFavoriteAddedDeviceSection)
+{
+ lc.ClearModel();
+ lc.Impl()->device_section_ = MockDeviceLauncherSection();
+ auto const& model = lc.Impl()->model_;
+ auto const& icons = lc.Impl()->device_section_.GetIcons();
+ auto const& device_icon1(*(icons.begin()));
+ auto const& device_icon2(*(std::next(icons.begin())));
+
+ favorite_store.SetFavorites({ FavoriteStore::URI_PREFIX_APP + app::UBUNTU_ONE });
+ lc.Impl()->SetupIcons();
+ lc.DisconnectSignals();
+
+ auto const& app_icons = lc.Impl()->model_->GetSublist<BamfLauncherIcon>();
+ auto const& last_app = *(app_icons.rbegin());
+
+ ASSERT_EQ(model->IconIndex(device_icon1), model->IconIndex(last_app) + 1);
+ ASSERT_EQ(model->IconIndex(device_icon2), model->IconIndex(last_app) + 2);
+
+ favorite_store.AddFavorite(places::DEVICES_URI, 0);
+ favorite_store.favorite_added.emit(places::DEVICES_URI, "", false);
+
+ EXPECT_EQ(model->IconIndex(device_icon1), 0);
+ EXPECT_EQ(model->IconIndex(device_icon2), 1);
+}
+
+TEST_F(TestLauncherController, OnFavoriteStoreFavoriteRemovedApplication)
+{
+ MockBamfLauncherIcon::Ptr app_icon(new MockBamfLauncherIcon(true, "sticky-icon"));
+ lc.Impl()->RegisterIcon(app_icon);
+ app_icon->Stick(false);
+
+ EXPECT_CALL(*app_icon, UnStick());
+ favorite_store.favorite_removed.emit(app_icon->RemoteUri());
+}
+
+TEST_F(TestLauncherController, OnFavoriteStoreFavoriteRemovedDevice)
+{
+ lc.ClearModel();
+ lc.Impl()->device_section_ = MockDeviceLauncherSection();
+ auto const& model = lc.Impl()->model_;
+
+ auto const& icons = lc.Impl()->device_section_.GetIcons();
+ auto const& device_icon(*(icons.begin()));
+
+ favorite_store.SetFavorites({ FavoriteStore::URI_PREFIX_APP + app::UBUNTU_ONE,
+ device_icon->RemoteUri(),
+ FavoriteStore::URI_PREFIX_APP + app::UPDATE_MANAGER });
+ lc.Impl()->SetupIcons();
+ lc.DisconnectSignals();
+
+ ASSERT_EQ(model->IconIndex(device_icon), 1);
+
+ favorite_store.RemoveFavorite(device_icon->RemoteUri());
+ favorite_store.favorite_removed.emit(device_icon->RemoteUri());
+
+ auto const& app_icons = lc.Impl()->model_->GetSublist<BamfLauncherIcon>();
+ auto const& last_app = *(app_icons.rbegin());
+ EXPECT_EQ(model->IconIndex(device_icon), model->IconIndex(last_app) + 1);
+}
+
+TEST_F(TestLauncherController, OnFavoriteStoreFavoriteRemovedDeviceSection)
+{
+ lc.ClearModel();
+ lc.Impl()->device_section_ = MockDeviceLauncherSection();
+ auto const& model = lc.Impl()->model_;
+
+ auto const& icons = lc.Impl()->device_section_.GetIcons();
+ auto const& device_icon1(*(icons.begin()));
+ auto const& device_icon2(*(std::next(icons.begin())));
+
+ favorite_store.SetFavorites({ places::DEVICES_URI,
+ FavoriteStore::URI_PREFIX_APP + app::UBUNTU_ONE });
+ lc.Impl()->SetupIcons();
+ lc.DisconnectSignals();
+
+ ASSERT_EQ(model->IconIndex(device_icon1), 0);
+ ASSERT_EQ(model->IconIndex(device_icon2), 1);
+
+ favorite_store.RemoveFavorite(places::DEVICES_URI);
+ favorite_store.favorite_removed.emit(places::DEVICES_URI);
+
+ auto const& app_icons = lc.Impl()->model_->GetSublist<BamfLauncherIcon>();
+ auto const& last_app = *(app_icons.rbegin());
+ EXPECT_EQ(model->IconIndex(device_icon1), model->IconIndex(last_app) + 1);
+ EXPECT_EQ(model->IconIndex(device_icon2), model->IconIndex(last_app) + 2);
+}
+
+TEST_F(TestLauncherController, OnViewOpened)
+{
+ auto const& app_icons = lc.Impl()->model_->GetSublist<BamfLauncherIcon>();
+ auto const& last_app = *(app_icons.rbegin());
+
+ auto app = bamf_matcher_get_application_for_desktop_file(lc.Impl()->matcher_, app::BZR_HANDLE_PATCH.c_str(), TRUE);
+ g_signal_emit_by_name(lc.Impl()->matcher_, "view-opened", app);
+ lc.DisconnectSignals();
+
+ auto const& icon = lc.GetIconByDesktop(app::BZR_HANDLE_PATCH);
+ ASSERT_TRUE(icon.IsValid());
+
+ ASSERT_EQ(lc.Impl()->model_->IconIndex(icon), lc.Impl()->model_->IconIndex(last_app) + 1);
+}
+
+TEST_F(TestLauncherController, UpdateNumWorkspacesDisable)
+{
+ favorite_store.AddFavorite(lc.Impl()->expo_icon_->RemoteUri(), -1);
+ auto const& fav = lc.Impl()->CreateFavoriteIcon(lc.Impl()->expo_icon_->RemoteUri());
+ lc.Impl()->RegisterIcon(fav);
+ ASSERT_TRUE(lc.Impl()->expo_icon_->IsVisible());
+
+ lc.UpdateNumWorkspaces(1);
+ EXPECT_FALSE(lc.Impl()->expo_icon_->IsVisible());
+}
+
+TEST_F(TestLauncherController, UpdateNumWorkspacesEnable)
+{
+ favorite_store.AddFavorite(lc.Impl()->expo_icon_->RemoteUri(), -1);
+ auto const& fav = lc.Impl()->CreateFavoriteIcon(lc.Impl()->expo_icon_->RemoteUri());
+ lc.Impl()->RegisterIcon(fav);
+ lc.Impl()->expo_icon_->SetQuirk(AbstractLauncherIcon::Quirk::VISIBLE, false);
+
+ lc.UpdateNumWorkspaces(2);
+ EXPECT_TRUE(lc.Impl()->expo_icon_->IsVisible());
+}
+
+}
diff --git a/tests/test_launcher_icon.cpp b/tests/test_launcher_icon.cpp
new file mode 100644
index 000000000..f94618adb
--- /dev/null
+++ b/tests/test_launcher_icon.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2012 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 warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY 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
+ * version 3 along with this program. If not, see
+ * <http://www.gnu.org/licenses/>
+ *
+ * Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com>
+ */
+
+#include <gmock/gmock.h>
+
+#include "LauncherIcon.h"
+
+using namespace unity;
+using namespace unity::launcher;
+
+namespace
+{
+struct MockLauncherIcon : LauncherIcon
+{
+ MockLauncherIcon(IconType type)
+ : LauncherIcon(type)
+ {}
+
+ virtual nux::BaseTexture* GetTextureForSize(int size) { return nullptr; }
+};
+
+struct TestLauncherIcon : testing::Test
+{
+ TestLauncherIcon()
+ : icon(AbstractLauncherIcon::IconType::APPLICATION)
+ {}
+
+ MockLauncherIcon icon;
+};
+
+TEST_F(TestLauncherIcon, Construction)
+{
+ EXPECT_EQ(icon.GetIconType(), AbstractLauncherIcon::IconType::APPLICATION);
+ EXPECT_EQ(icon.position(), AbstractLauncherIcon::Position::FLOATING);
+ EXPECT_EQ(icon.SortPriority(), AbstractLauncherIcon::DefaultPriority(AbstractLauncherIcon::IconType::APPLICATION));
+ EXPECT_FALSE(icon.IsSticky());
+ EXPECT_FALSE(icon.IsVisible());
+
+ for (unsigned i = 0; i < unsigned(AbstractLauncherIcon::Quirk::LAST); ++i)
+ ASSERT_FALSE(icon.GetQuirk(static_cast<AbstractLauncherIcon::Quirk>(i)));
+}
+
+TEST_F(TestLauncherIcon, Visibility)
+{
+ ASSERT_FALSE(icon.GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
+ ASSERT_FALSE(icon.IsVisible());
+
+ icon.SetQuirk(AbstractLauncherIcon::Quirk::VISIBLE, true);
+ ASSERT_TRUE(icon.GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
+ EXPECT_TRUE(icon.IsVisible());
+
+ icon.SetQuirk(AbstractLauncherIcon::Quirk::VISIBLE, false);
+ ASSERT_FALSE(icon.GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
+ EXPECT_FALSE(icon.IsVisible());
+}
+
+TEST_F(TestLauncherIcon, Stick)
+{
+ bool saved = false;
+ icon.position_saved.connect([&saved] {saved = true;});
+
+ icon.Stick(false);
+ EXPECT_TRUE(icon.IsSticky());
+ EXPECT_TRUE(icon.IsVisible());
+ EXPECT_FALSE(saved);
+
+ icon.Stick(true);
+ EXPECT_FALSE(saved);
+}
+
+TEST_F(TestLauncherIcon, StickAndSave)
+{
+ bool saved = false;
+ icon.position_saved.connect([&saved] {saved = true;});
+
+ icon.Stick(true);
+ EXPECT_TRUE(icon.IsSticky());
+ EXPECT_TRUE(icon.IsVisible());
+ EXPECT_TRUE(saved);
+}
+
+TEST_F(TestLauncherIcon, Unstick)
+{
+ bool forgot = false;
+ icon.position_forgot.connect([&forgot] {forgot = true;});
+
+ icon.Stick(false);
+ ASSERT_TRUE(icon.IsSticky());
+ ASSERT_TRUE(icon.IsVisible());
+
+ icon.UnStick();
+ EXPECT_FALSE(icon.IsSticky());
+ EXPECT_FALSE(icon.IsVisible());
+ EXPECT_TRUE(forgot);
+}
+
+}
diff --git a/tests/test_launcher_model.cpp b/tests/test_launcher_model.cpp
index a56c929cf..30a698362 100644
--- a/tests/test_launcher_model.cpp
+++ b/tests/test_launcher_model.cpp
@@ -158,6 +158,27 @@ TEST_F(TestLauncherModel, ModelKeepsPriorityDeltas)
TEST_F(TestLauncherModel, ReorderBefore)
{
+ model.AddIcon(icon1);
+ model.AddIcon(icon2);
+ model.AddIcon(icon3);
+ model.AddIcon(icon4);
+
+ model.ReorderBefore(icon3, icon2, false);
+
+ LauncherModel::iterator it;
+ it = model.begin();
+
+ EXPECT_EQ(icon1, *it);
+ it++;
+ EXPECT_EQ(icon3, *it);
+ it++;
+ EXPECT_EQ(icon2, *it);
+ it++;
+ EXPECT_EQ(icon4, *it);
+}
+
+TEST_F(TestLauncherModel, ReorderBeforeWithPriority)
+{
icon1->SetSortPriority(0);
icon2->SetSortPriority(1);
icon3->SetSortPriority(2);
@@ -182,28 +203,70 @@ TEST_F(TestLauncherModel, ReorderBefore)
EXPECT_EQ(icon4, *it);
}
-TEST_F(TestLauncherModel, ReorderAfter)
+TEST_F(TestLauncherModel, ReorderAfterNext)
{
model.AddIcon(icon1);
+ model.AddIcon(icon2);
model.AddIcon(icon3);
+ model.AddIcon(icon4);
+
+ model.ReorderAfter(icon2, icon3);
+
+ LauncherModel::iterator it;
+ it = model.begin();
+
+ EXPECT_EQ(icon1, *it);
+ it++;
+ EXPECT_EQ(icon3, *it);
+ it++;
+ EXPECT_EQ(icon2, *it);
+ it++;
+ EXPECT_EQ(icon4, *it);
+}
+
+TEST_F(TestLauncherModel, ReorderAfterPrevious)
+{
+ model.AddIcon(icon1);
model.AddIcon(icon2);
+ model.AddIcon(icon3);
model.AddIcon(icon4);
- model.ReorderAfter(icon3, icon2);
+ model.ReorderAfter(icon4, icon1);
LauncherModel::iterator it;
it = model.begin();
EXPECT_EQ(icon1, *it);
it++;
+ EXPECT_EQ(icon4, *it);
+ it++;
EXPECT_EQ(icon2, *it);
it++;
EXPECT_EQ(icon3, *it);
+}
+
+TEST_F(TestLauncherModel, ReorderSmart)
+{
+ model.AddIcon(icon1);
+ model.AddIcon(icon2);
+ model.AddIcon(icon3);
+ model.AddIcon(icon4);
+
+ model.ReorderSmart(icon3, icon2, false);
+
+ LauncherModel::iterator it;
+ it = model.begin();
+
+ EXPECT_EQ(icon1, *it);
+ it++;
+ EXPECT_EQ(icon3, *it);
+ it++;
+ EXPECT_EQ(icon2, *it);
it++;
EXPECT_EQ(icon4, *it);
}
-TEST_F(TestLauncherModel, ReorderSmart)
+TEST_F(TestLauncherModel, ReorderSmartWithDifferentPriority)
{
icon1->SetSortPriority(0);
icon2->SetSortPriority(1);
@@ -229,50 +292,129 @@ TEST_F(TestLauncherModel, ReorderSmart)
EXPECT_EQ(icon4, *it);
}
-TEST_F(TestLauncherModel, OrderByType)
+TEST_F(TestLauncherModel, ReorderSmartWithSimilarPriority)
{
- AbstractLauncherIcon::Ptr icon1(new MockLauncherIcon(AbstractLauncherIcon::IconType::HOME));
- AbstractLauncherIcon::Ptr icon2(new MockLauncherIcon(AbstractLauncherIcon::IconType::APPLICATION));
- AbstractLauncherIcon::Ptr icon3(new MockLauncherIcon(AbstractLauncherIcon::IconType::EXPO));
- AbstractLauncherIcon::Ptr icon4(new MockLauncherIcon(AbstractLauncherIcon::IconType::DEVICE));
- AbstractLauncherIcon::Ptr icon5(new MockLauncherIcon(AbstractLauncherIcon::IconType::TRASH));
+ icon1->SetSortPriority(0);
+ icon2->SetSortPriority(0);
+ icon3->SetSortPriority(1);
+ icon4->SetSortPriority(1);
+ model.AddIcon(icon1);
+ model.AddIcon(icon2);
model.AddIcon(icon3);
model.AddIcon(icon4);
- model.AddIcon(icon2);
+
+ model.ReorderSmart(icon4, icon3, false);
+
+ LauncherModel::iterator it;
+ it = model.begin();
+
+ EXPECT_EQ(icon1, *it);
+ it++;
+ EXPECT_EQ(icon2, *it);
+ it++;
+ EXPECT_EQ(icon4, *it);
+ it++;
+ EXPECT_EQ(icon3, *it);
+}
+
+TEST_F(TestLauncherModel, ReorderSmartManyIconsWithSimilarPriority)
+{
+ AbstractLauncherIcon::Ptr icon5(new MockLauncherIcon);
+ AbstractLauncherIcon::Ptr icon6(new MockLauncherIcon);
+ icon1->SetSortPriority(0);
+ icon2->SetSortPriority(0);
+ icon3->SetSortPriority(1);
+ icon4->SetSortPriority(1);
+ icon5->SetSortPriority(1);
+ icon6->SetSortPriority(2);
+
model.AddIcon(icon1);
+ model.AddIcon(icon2);
+ model.AddIcon(icon3);
+ model.AddIcon(icon4);
model.AddIcon(icon5);
+ model.AddIcon(icon6);
+
+ model.ReorderSmart(icon6, icon4, false);
+
+ LauncherModel::iterator it;
+ it = model.begin();
+
+ EXPECT_EQ(icon1, *it); it++;
+ EXPECT_EQ(icon2, *it); it++;
+ EXPECT_EQ(icon3, *it); it++;
+ EXPECT_EQ(icon6, *it); it++;
+ EXPECT_EQ(icon4, *it); it++;
+ EXPECT_EQ(icon5, *it);
+}
+
+TEST_F(TestLauncherModel, OrderByPosition)
+{
+ icon1->position = AbstractLauncherIcon::Position::BEGIN;
+ icon2->position = AbstractLauncherIcon::Position::FLOATING;
+ icon3->position = AbstractLauncherIcon::Position::FLOATING;
+ icon4->position = AbstractLauncherIcon::Position::END;
+
+ model.AddIcon(icon3);
+ model.AddIcon(icon4);
+ model.AddIcon(icon2);
+ model.AddIcon(icon1);
auto it = model.begin();
EXPECT_EQ(icon1, *it);
it++;
- EXPECT_EQ(icon2, *it);
- it++;
EXPECT_EQ(icon3, *it);
it++;
- EXPECT_EQ(icon4, *it);
+ EXPECT_EQ(icon2, *it);
it++;
- EXPECT_EQ(icon5, *it);
+ EXPECT_EQ(icon4, *it);
it++;
EXPECT_EQ(it, model.end());
auto it_main = model.main_begin();
EXPECT_EQ(icon1, *it_main);
it_main++;
- EXPECT_EQ(icon2, *it_main);
- it_main++;
EXPECT_EQ(icon3, *it_main);
it_main++;
- EXPECT_EQ(icon4, *it_main);
+ EXPECT_EQ(icon2, *it_main);
it_main++;
EXPECT_EQ(it_main, model.main_end());
auto it_shelf = model.shelf_begin();
- EXPECT_EQ(icon5, *it_shelf);
+ EXPECT_EQ(icon4, *it_shelf);
it_shelf++;
EXPECT_EQ(it_shelf, model.shelf_end());
}
+TEST_F(TestLauncherModel, OrderByType)
+{
+ AbstractLauncherIcon::Ptr icon1(new MockLauncherIcon(AbstractLauncherIcon::IconType::HOME));
+ AbstractLauncherIcon::Ptr icon2(new MockLauncherIcon(AbstractLauncherIcon::IconType::APPLICATION));
+ AbstractLauncherIcon::Ptr icon3(new MockLauncherIcon(AbstractLauncherIcon::IconType::EXPO));
+ AbstractLauncherIcon::Ptr icon4(new MockLauncherIcon(AbstractLauncherIcon::IconType::DEVICE));
+ AbstractLauncherIcon::Ptr icon5(new MockLauncherIcon(AbstractLauncherIcon::IconType::TRASH));
+
+ model.AddIcon(icon3);
+ model.AddIcon(icon4);
+ model.AddIcon(icon2);
+ model.AddIcon(icon1);
+ model.AddIcon(icon5);
+
+ auto it = model.begin();
+ EXPECT_EQ(icon1, *it);
+ it++;
+ EXPECT_EQ(icon2, *it);
+ it++;
+ EXPECT_EQ(icon3, *it);
+ it++;
+ EXPECT_EQ(icon4, *it);
+ it++;
+ EXPECT_EQ(icon5, *it);
+ it++;
+ EXPECT_EQ(it, model.end());
+}
+
TEST_F(TestLauncherModel, GetClosestIcon)
{
model.AddIcon(icon1);
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index a92978dab..ce210ddec 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -11,6 +11,7 @@ int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
gtk_init(&argc, &argv);
+ setlocale(LC_ALL, "C");
nux::NuxInitialize(0);
std::unique_ptr<nux::WindowThread> win_thread(nux::CreateNuxWindow("Tests",
diff --git a/tests/test_main_xless.cpp b/tests/test_main_xless.cpp
index da7862703..41577d15d 100644
--- a/tests/test_main_xless.cpp
+++ b/tests/test_main_xless.cpp
@@ -7,7 +7,7 @@ int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
g_type_init();
-
+ setlocale(LC_ALL, "C");
// Slightly higher as we're more likely to test things we know will fail
nux::logging::configure_logging("<root>=error");
diff --git a/tests/test_mock_devices.h b/tests/test_mock_devices.h
new file mode 100644
index 000000000..427608bbc
--- /dev/null
+++ b/tests/test_mock_devices.h
@@ -0,0 +1,93 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser 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 warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the applicable version of the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of both the GNU Lesser General Public
+ * License version 3 along with this program. If not, see
+ * <http://www.gnu.org/licenses/>
+ *
+ * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
+ *
+ */
+
+#ifndef TEST_MOCK_DEVICES_H
+#define TEST_MOCK_DEVICES_H
+
+#include "DeviceLauncherSection.h"
+#include "AbstractVolumeMonitorWrapper.h"
+#include "Volume.h"
+#include "gmockvolume.h"
+
+using namespace unity::launcher;
+
+namespace unity
+{
+
+struct MockVolumeMonitorWrapper : public AbstractVolumeMonitorWrapper
+{
+ typedef std::shared_ptr<MockVolumeMonitorWrapper> Ptr;
+
+ MockVolumeMonitorWrapper(unsigned size = 2)
+ {
+ for (unsigned i = 0; i < size; ++i)
+ {
+ glib::Object<GVolume> volume(G_VOLUME(g_mock_volume_new()));
+ volumes_.push_back(volume);
+ }
+ }
+
+ VolumeList GetVolumes() { return volumes_; }
+
+ VolumeList volumes_;
+};
+
+struct MockDevicesSettings : DevicesSettings
+{
+ typedef std::shared_ptr<MockDevicesSettings> Ptr;
+
+ MOCK_CONST_METHOD1(IsABlacklistedDevice, bool(std::string const& uuid));
+ MOCK_METHOD1(TryToBlacklist, void(std::string const& uuid));
+ MOCK_METHOD1(TryToUnblacklist, void(std::string const& uuid));
+};
+
+struct MockDeviceLauncherSection : DeviceLauncherSection
+{
+ MockDeviceLauncherSection(unsigned size = 2)
+ : DeviceLauncherSection(MockVolumeMonitorWrapper::Ptr(new MockVolumeMonitorWrapper(size)),
+ DevicesSettings::Ptr(new MockDevicesSettings))
+ {}
+};
+
+class MockVolume : public Volume
+{
+public:
+ typedef std::shared_ptr<MockVolume> Ptr;
+
+ MOCK_CONST_METHOD0(CanBeRemoved, bool(void));
+ MOCK_CONST_METHOD0(CanBeStopped, bool(void));
+ MOCK_CONST_METHOD0(GetName, std::string(void));
+ MOCK_CONST_METHOD0(GetIconName, std::string(void));
+ MOCK_CONST_METHOD0(GetIdentifier, std::string(void));
+ MOCK_CONST_METHOD0(HasSiblings, bool(void));
+ MOCK_CONST_METHOD0(CanBeEjected, bool(void));
+ MOCK_CONST_METHOD0(IsMounted, bool(void));
+
+ MOCK_METHOD0(EjectAndShowNotification, void(void));
+ MOCK_METHOD0(MountAndOpenInFileManager, void(void));
+ MOCK_METHOD0(StopDrive, void(void));
+ MOCK_METHOD0(Unmount, void(void));
+};
+
+}
+
+#endif
diff --git a/tests/test_software_center_launcher_icon.cpp b/tests/test_software_center_launcher_icon.cpp
new file mode 100644
index 000000000..1ca700e67
--- /dev/null
+++ b/tests/test_software_center_launcher_icon.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2012 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 warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY 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
+ * version 3 along with this program. If not, see
+ * <http://www.gnu.org/licenses/>
+ *
+ * Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com>
+ */
+
+#include <config.h>
+#include <gmock/gmock.h>
+
+#include "SoftwareCenterLauncherIcon.h"
+#include "Launcher.h"
+#include "PanelStyle.h"
+#include "UnitySettings.h"
+#include "test_utils.h"
+
+using namespace unity;
+using namespace unity::launcher;
+
+namespace
+{
+const std::string USC_DESKTOP = BUILDDIR"/tests/data/applications/ubuntu-software-center.desktop";
+
+struct TestSoftwareCenterLauncherIcon : testing::Test
+{
+ TestSoftwareCenterLauncherIcon()
+ : bamf_matcher(bamf_matcher_get_default())
+ , usc(bamf_matcher_get_application_for_desktop_file(bamf_matcher, USC_DESKTOP.c_str(), TRUE), glib::AddRef())
+ , icon(usc, "", "")
+ {}
+
+ glib::Object<BamfMatcher> bamf_matcher;
+ glib::Object<BamfApplication> usc;
+ SoftwareCenterLauncherIcon icon;
+};
+
+TEST_F(TestSoftwareCenterLauncherIcon, Construction)
+{
+ EXPECT_FALSE(icon.IsVisible());
+ EXPECT_EQ(icon.position(), AbstractLauncherIcon::Position::FLOATING);
+ EXPECT_EQ(icon.tooltip_text(), bamf_view_get_name(glib::object_cast<BamfView>(usc)));
+}
+
+TEST_F(TestSoftwareCenterLauncherIcon, Animate)
+{
+ ASSERT_FALSE(icon.IsVisible());
+
+ Settings settings;
+ panel::Style panel;
+ nux::ObjectPtr<nux::BaseWindow> win(new nux::BaseWindow(""));
+ nux::ObjectPtr<DNDCollectionWindow> cwin(new DNDCollectionWindow);
+ nux::ObjectPtr<Launcher> launcher(new Launcher(win.GetPointer(), cwin));
+ launcher->options = Options::Ptr(new Options);
+ launcher->SetModel(LauncherModel::Ptr(new LauncherModel));
+
+ icon.Animate(launcher, 1, 2);
+ Utils::WaitForTimeoutMSec(500);
+
+ EXPECT_TRUE(icon.IsVisible());
+}
+
+}
diff --git a/tests/test_trash_launcher_icon.cpp b/tests/test_trash_launcher_icon.cpp
new file mode 100644
index 000000000..dc91ee489
--- /dev/null
+++ b/tests/test_trash_launcher_icon.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2012 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 warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY 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
+ * version 3 along with this program. If not, see
+ * <http://www.gnu.org/licenses/>
+ *
+ * Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com>
+ */
+
+#include <gmock/gmock.h>
+
+#include "TrashLauncherIcon.h"
+
+using namespace unity;
+using namespace unity::launcher;
+
+namespace
+{
+struct TestTrashLauncherIcon : testing::Test
+{
+ TrashLauncherIcon icon;
+};
+
+TEST_F(TestTrashLauncherIcon, Position)
+{
+ EXPECT_EQ(icon.position(), AbstractLauncherIcon::Position::END);
+}
+
+}
diff --git a/tests/test_unity_settings.cpp b/tests/test_unity_settings.cpp
new file mode 100644
index 000000000..0ffb472c1
--- /dev/null
+++ b/tests/test_unity_settings.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2012 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 warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY 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
+ * version 3 along with this program. If not, see
+ * <http://www.gnu.org/licenses/>
+ *
+ * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
+ *
+ */
+
+#include <gio/gio.h>
+#include <gtest/gtest.h>
+
+#include "test_utils.h"
+#include "unity-shared/UnitySettings.h"
+
+#include <UnityCore/GLibWrapper.h>
+
+namespace
+{
+
+class TestUnitySettings : public testing::Test
+{
+public:
+ unity::glib::Object<GSettings> gsettings;
+ std::unique_ptr<unity::Settings> unity_settings;
+
+ void SetUp()
+ {
+ g_setenv("GSETTINGS_BACKEND", "memory", TRUE);
+
+ gsettings = g_settings_new("com.canonical.Unity");
+ g_settings_set_enum(gsettings, "form-factor", static_cast<int>(unity::FormFactor::DESKTOP));
+
+ unity_settings.reset(new unity::Settings);
+ }
+
+ void TearDown()
+ {
+ g_setenv("GSETTINGS_BACKEND", "", TRUE);
+ }
+};
+
+TEST_F(TestUnitySettings, SetFormFactor)
+{
+ unity_settings->form_factor = unity::FormFactor::NETBOOK;
+
+ int raw_form_factor = g_settings_get_enum(gsettings, "form-factor");
+ EXPECT_EQ(raw_form_factor, static_cast<int>(unity::FormFactor::NETBOOK));
+}
+
+TEST_F(TestUnitySettings, GetFormFactor)
+{
+ EXPECT_EQ(unity_settings->form_factor(), unity::FormFactor::DESKTOP);
+
+ g_settings_set_enum(gsettings, "form-factor", static_cast<int>(unity::FormFactor::NETBOOK));
+ EXPECT_EQ(unity_settings->form_factor(), unity::FormFactor::NETBOOK);
+}
+
+TEST_F(TestUnitySettings, FormFactorChangedSignal_Extern)
+{
+ bool signal_received = false;
+ unity::FormFactor new_form_factor;
+ unity_settings->form_factor.changed.connect([&](unity::FormFactor form_factor) {
+ signal_received = true;
+ new_form_factor = form_factor;
+ });
+
+ g_settings_set_enum(gsettings, "form-factor", static_cast<int>(unity::FormFactor::NETBOOK));
+ Utils::WaitUntil(signal_received);
+ EXPECT_EQ(new_form_factor, unity::FormFactor::NETBOOK);
+}
+
+TEST_F(TestUnitySettings, FormFactorChangedSignal_Extern_OtherKeys)
+{
+ bool signal_received = false;
+ unity_settings->form_factor.changed.connect([&](unity::FormFactor form_factor) {
+ signal_received = true;
+ });
+
+ g_settings_set_int(gsettings, "minimize-count", 0);
+ Utils::WaitForTimeout(1);
+ EXPECT_FALSE(signal_received);
+}
+
+TEST_F(TestUnitySettings, FormFactorChangedSignal_Inter)
+{
+ bool signal_received = false;
+ unity::FormFactor new_form_factor;
+ unity_settings->form_factor.changed.connect([&](unity::FormFactor form_factor) {
+ signal_received = true;
+ new_form_factor = form_factor;
+ });
+
+ unity_settings->form_factor = unity::FormFactor::NETBOOK;
+ Utils::WaitUntil(signal_received);
+ EXPECT_EQ(new_form_factor, unity::FormFactor::NETBOOK);
+}
+
+}
diff --git a/tests/test_volume_launcher_icon.cpp b/tests/test_volume_launcher_icon.cpp
index 287a9558c..46905144b 100644
--- a/tests/test_volume_launcher_icon.cpp
+++ b/tests/test_volume_launcher_icon.cpp
@@ -20,50 +20,19 @@
#include <gmock/gmock.h>
using namespace testing;
-#include "launcher/DevicesSettings.h"
-#include "launcher/Volume.h"
-#include "launcher/VolumeLauncherIcon.h"
+#include "DevicesSettings.h"
+#include "VolumeLauncherIcon.h"
+#include "FavoriteStore.h"
#include "test_utils.h"
+#include "test_mock_devices.h"
using namespace unity;
using namespace unity::launcher;
namespace
{
-class MockVolume : public Volume
+struct TestVolumeLauncherIcon : public Test
{
-public:
- typedef std::shared_ptr<MockVolume> Ptr;
-
- MOCK_CONST_METHOD0(CanBeRemoved, bool(void));
- MOCK_CONST_METHOD0(CanBeStopped, bool(void));
- MOCK_CONST_METHOD0(GetName, std::string(void));
- MOCK_CONST_METHOD0(GetIconName, std::string(void));
- MOCK_CONST_METHOD0(GetIdentifier, std::string(void));
- MOCK_CONST_METHOD0(HasSiblings, bool(void));
- MOCK_CONST_METHOD0(CanBeEjected, bool(void));
- MOCK_CONST_METHOD0(IsMounted, bool(void));
-
- MOCK_METHOD0(EjectAndShowNotification, void(void));
- MOCK_METHOD0(MountAndOpenInFileManager, void(void));
- MOCK_METHOD0(StopDrive, void(void));
- MOCK_METHOD0(Unmount, void(void));
-};
-
-class MockDevicesSettings : public DevicesSettings
-{
-public:
- typedef std::shared_ptr<MockDevicesSettings> Ptr;
-
- MOCK_CONST_METHOD1(IsABlacklistedDevice, bool(std::string const& uuid));
- MOCK_METHOD1(TryToBlacklist, void(std::string const& uuid));
- MOCK_METHOD1(TryToUnblacklist, void(std::string const& uuid));
-};
-
-
-class TestVolumeLauncherIcon : public Test
-{
-public:
virtual void SetUp()
{
volume_.reset(new MockVolume);
@@ -118,11 +87,12 @@ public:
std::advance(menuitem, index);
return *menuitem;
- }
+ }
MockVolume::Ptr volume_;
MockDevicesSettings::Ptr settings_;
VolumeLauncherIcon::Ptr icon_;
+ std::string old_lang_;
};
TEST_F(TestVolumeLauncherIcon, TestIconType)
@@ -138,6 +108,13 @@ TEST_F(TestVolumeLauncherIcon, TestQuirks)
EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::RUNNING));
}
+TEST_F(TestVolumeLauncherIcon, TestPosition)
+{
+ CreateIcon();
+
+ EXPECT_EQ(icon_->position(), AbstractLauncherIcon::Position::FLOATING);
+}
+
TEST_F(TestVolumeLauncherIcon, TestTooltipText)
{
CreateIcon();
@@ -159,6 +136,12 @@ TEST_F(TestVolumeLauncherIcon, TestVisibility_InitiallyMountedVolume)
EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
}
+TEST_F(TestVolumeLauncherIcon, RemoteUri)
+{
+ CreateIcon();
+ EXPECT_EQ(icon_->GetRemoteUri(), FavoriteStore::URI_PREFIX_DEVICE + volume_->GetIdentifier());
+}
+
TEST_F(TestVolumeLauncherIcon, TestVisibility_InitiallyMountedBlacklistedVolume)
{
EXPECT_CALL(*settings_, IsABlacklistedDevice(_))
@@ -216,7 +199,6 @@ TEST_F(TestVolumeLauncherIcon, TestVisibilityAfterUnmount)
.Times(0);
volume_->changed.emit();
- Utils::WaitForTimeout(1);
EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
}
@@ -235,7 +217,6 @@ TEST_F(TestVolumeLauncherIcon, TestVisibilityAfterUnmount_BlacklistedVolume)
.Times(0);
volume_->changed.emit();
- Utils::WaitForTimeout(1);
EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
}
@@ -269,7 +250,6 @@ TEST_F(TestVolumeLauncherIcon, TestUnlockFromLauncherMenuItem_Success)
dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0);
settings_->changed.emit(); // TryToBlacklist() works if DevicesSettings emits a changed signal.
- Utils::WaitForTimeout(1);
ASSERT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
}
@@ -288,7 +268,6 @@ TEST_F(TestVolumeLauncherIcon, TestUnlockFromLauncherMenuItem_Failure)
.Times(1);
dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0);
- Utils::WaitForTimeout(1);
ASSERT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
}
@@ -307,7 +286,6 @@ TEST_F(TestVolumeLauncherIcon, TestOpenMenuItem)
.Times(1);
dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0);
- Utils::WaitForTimeout(1);
}
TEST_F(TestVolumeLauncherIcon, TestEjectMenuItem_NotEjectableVolume)
@@ -335,7 +313,6 @@ TEST_F(TestVolumeLauncherIcon, TestEjectMenuItem)
EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_ENABLED));
dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0);
- Utils::WaitForTimeout(1);
}
TEST_F(TestVolumeLauncherIcon, TestEjectMenuItem_NotStoppableVolume)
@@ -363,7 +340,6 @@ TEST_F(TestVolumeLauncherIcon, TestSafelyRemoveMenuItem)
EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_ENABLED));
dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0);
- Utils::WaitForTimeout(1);
}
TEST_F(TestVolumeLauncherIcon, TestUnmountMenuItem_UnmountedVolume)
@@ -423,7 +399,6 @@ TEST_F(TestVolumeLauncherIcon, TestUnmountMenuItem)
EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_ENABLED));
dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0);
- Utils::WaitForTimeout(1);
}
TEST_F(TestVolumeLauncherIcon, TestCanBeEject)
@@ -495,4 +470,50 @@ TEST_F(TestVolumeLauncherIcon, OnRemoved_RemovableAndBlacklistedVolume)
volume_->removed.emit();
}
+TEST_F(TestVolumeLauncherIcon, Stick)
+{
+ CreateIcon();
+
+ bool saved = false;
+ icon_->position_saved.connect([&saved] {saved = true;});
+
+ EXPECT_CALL(*settings_, TryToUnblacklist(volume_->GetIdentifier()));
+ icon_->Stick(false);
+ EXPECT_TRUE(icon_->IsSticky());
+ EXPECT_TRUE(icon_->IsVisible());
+ EXPECT_FALSE(saved);
+}
+
+TEST_F(TestVolumeLauncherIcon, StickAndSave)
+{
+ CreateIcon();
+
+ bool saved = false;
+ icon_->position_saved.connect([&saved] {saved = true;});
+
+ EXPECT_CALL(*settings_, TryToUnblacklist(volume_->GetIdentifier()));
+ icon_->Stick(true);
+ EXPECT_TRUE(icon_->IsSticky());
+ EXPECT_TRUE(icon_->IsVisible());
+ EXPECT_TRUE(saved);
+}
+
+TEST_F(TestVolumeLauncherIcon, Unstick)
+{
+ CreateIcon();
+
+ bool forgot = false;
+ icon_->position_forgot.connect([&forgot] {forgot = true;});
+
+ EXPECT_CALL(*settings_, TryToUnblacklist(_));
+ icon_->Stick(false);
+ ASSERT_TRUE(icon_->IsSticky());
+ ASSERT_TRUE(icon_->IsVisible());
+
+ icon_->UnStick();
+ EXPECT_FALSE(icon_->IsSticky());
+ EXPECT_TRUE(icon_->IsVisible());
+ EXPECT_TRUE(forgot);
+}
+
}
diff --git a/tools/unity.cmake b/tools/unity.cmake
index 69bf4c1e5..c214fc322 100755
--- a/tools/unity.cmake
+++ b/tools/unity.cmake
@@ -161,6 +161,8 @@ if __name__ == '__main__':
help="Store log under filename.")
parser.add_option("--replace", action="store_true",
help="Run unity /!\ This is for compatibility with other desktop interfaces and acts the same as running unity without --replace")
+ parser.add_option("--reset", action="store_true",
+ help="Reset is not supported anymore. Deprecated option")
parser.add_option("--reset-icons", action="store_true",
help="Reset the default launcher icon.")
parser.add_option("-v", "--verbose", action="store_true",
@@ -171,7 +173,11 @@ if __name__ == '__main__':
if options.distro:
sys.exit(reset_to_distro())
-
+
+ if options.reset:
+ print ("ERROR: the reset option is now deprecated")
+ sys.exit(1)
+
if options.reset_icons:
reset_launcher_icons ()
diff --git a/unity-shared/DashStyle.cpp b/unity-shared/DashStyle.cpp
index 2efc26bee..4c7d16f5b 100755
--- a/unity-shared/DashStyle.cpp
+++ b/unity-shared/DashStyle.cpp
@@ -427,14 +427,14 @@ Style::Style()
style_instance = this;
}
- auto formfactor_lambda = [this] ()
+ auto formfactor_lambda = [this] (FormFactor)
{
- FormFactor formfactor = Settings::Instance().GetFormFactor();
+ FormFactor formfactor = Settings::Instance().form_factor();
always_maximised = (formfactor == FormFactor::NETBOOK || formfactor == FormFactor::TV);
};
- Settings::Instance().changed.connect(formfactor_lambda);
- formfactor_lambda();
+ Settings::Instance().form_factor.changed.connect(formfactor_lambda);
+ formfactor_lambda(FormFactor());
}
Style::~Style ()
diff --git a/unity-shared/IconLoader.cpp b/unity-shared/IconLoader.cpp
index 7812b6b25..b26d464e9 100644
--- a/unity-shared/IconLoader.cpp
+++ b/unity-shared/IconLoader.cpp
@@ -533,6 +533,10 @@ private:
unsigned cat_size = max_font_height * 9 / 8;
switch (category)
{
+ case UNITY_PROTOCOL_CATEGORY_TYPE_APPLICATION:
+ helper_handle =
+ impl->LoadFromFilename(PKGDATADIR"/emblem_apps.svg", -1, cat_size, helper_slot);
+ break;
case UNITY_PROTOCOL_CATEGORY_TYPE_BOOK:
helper_handle =
impl->LoadFromFilename(PKGDATADIR"/emblem_books.svg", -1, cat_size, helper_slot);
diff --git a/unity-shared/OverlayRenderer.cpp b/unity-shared/OverlayRenderer.cpp
index 24978e04e..9f2a6697c 100644
--- a/unity-shared/OverlayRenderer.cpp
+++ b/unity-shared/OverlayRenderer.cpp
@@ -438,7 +438,7 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c
bool paint_blur = BackgroundEffectHelper::blur_type != BLUR_NONE;
nux::Geometry geo(content_geo);
- int excess_border = (Settings::Instance().GetFormFactor() != FormFactor::NETBOOK || force_edges) ? EXCESS_BORDER : 0;
+ int excess_border = (Settings::Instance().form_factor() != FormFactor::NETBOOK || force_edges) ? EXCESS_BORDER : 0;
nux::Geometry larger_content_geo = content_geo;
larger_content_geo.OffsetSize(excess_border, excess_border);
@@ -578,7 +578,7 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c
}
- if (Settings::Instance().GetFormFactor() != FormFactor::NETBOOK || force_edges)
+ if (Settings::Instance().form_factor() != FormFactor::NETBOOK || force_edges)
{
// Paint the edges
{
@@ -835,7 +835,7 @@ void OverlayRendererImpl::DrawContent(nux::GraphicsEngine& gfx_context, nux::Geo
nux::Geometry geo = geometry;
bgs = 0;
- int excess_border = (Settings::Instance().GetFormFactor() != FormFactor::NETBOOK) ? EXCESS_BORDER : 0;
+ int excess_border = (Settings::Instance().form_factor() != FormFactor::NETBOOK) ? EXCESS_BORDER : 0;
nux::Geometry larger_content_geo = content_geo;
larger_content_geo.OffsetSize(excess_border, excess_border);
diff --git a/unity-shared/PanelStyle.cpp b/unity-shared/PanelStyle.cpp
index 2d64af4f0..885500567 100644
--- a/unity-shared/PanelStyle.cpp
+++ b/unity-shared/PanelStyle.cpp
@@ -73,12 +73,12 @@ Style::Style()
style_instance = this;
}
- if (Settings::Instance().GetFormFactor() == FormFactor::TV)
+ if (Settings::Instance().form_factor() == FormFactor::TV)
panel_height = 0;
- Settings::Instance().changed.connect([this]()
+ Settings::Instance().form_factor.changed.connect([this](FormFactor form_factor)
{
- if (Settings::Instance().GetFormFactor() == FormFactor::TV)
+ if (form_factor == FormFactor::TV)
panel_height = 0;
});
diff --git a/unity-shared/PluginAdapter.h b/unity-shared/PluginAdapter.h
index a6fda2bcf..36e454873 100644
--- a/unity-shared/PluginAdapter.h
+++ b/unity-shared/PluginAdapter.h
@@ -135,7 +135,9 @@ public:
void Activate(guint32 xid);
void Raise(guint32 xid);
void Lower(guint32 xid);
+
void ShowDesktop();
+ bool InShowDesktop() const;
void SetWindowIconGeometry(Window window, nux::Geometry const& geo);
diff --git a/unity-shared/PluginAdapterCompiz.cpp b/unity-shared/PluginAdapterCompiz.cpp
index fe1c978cc..5ddcd68ad 100644
--- a/unity-shared/PluginAdapterCompiz.cpp
+++ b/unity-shared/PluginAdapterCompiz.cpp
@@ -862,6 +862,11 @@ PluginAdapter::ShowDesktop()
}
}
+bool PluginAdapter::InShowDesktop() const
+{
+ return _in_show_desktop;
+}
+
void
PluginAdapter::OnShowDesktop()
{
diff --git a/unity-shared/PluginAdapterStandalone.cpp b/unity-shared/PluginAdapterStandalone.cpp
index 9e31f2a1b..83982a12a 100644
--- a/unity-shared/PluginAdapterStandalone.cpp
+++ b/unity-shared/PluginAdapterStandalone.cpp
@@ -50,12 +50,13 @@ PluginAdapter::Initialize(CompScreen* screen)
_default = new PluginAdapter(screen);
}
-PluginAdapter::PluginAdapter(CompScreen* screen) :
- m_Screen(screen),
- m_ExpoActionList(0),
- m_ScaleActionList(0),
- _in_show_desktop (false),
- _last_focused_window(nullptr)
+PluginAdapter::PluginAdapter(CompScreen* screen)
+ : m_Screen(screen)
+ , m_ExpoActionList(0)
+ , m_ScaleActionList(0)
+ , _expo_state(false)
+ , _in_show_desktop(false)
+ , _last_focused_window(nullptr)
{
}
@@ -171,12 +172,13 @@ PluginAdapter::IsScaleActiveForGroup() const
bool
PluginAdapter::IsExpoActive() const
{
- return false;
+ return _expo_state;
}
void
PluginAdapter::InitiateExpo()
{
+ _expo_state = !_expo_state;
}
bool
@@ -306,6 +308,12 @@ PluginAdapter::SetWindowIconGeometry(Window window, nux::Geometry const& geo)
void
PluginAdapter::ShowDesktop()
{
+ _in_show_desktop = !_in_show_desktop;
+}
+
+bool PluginAdapter::InShowDesktop() const
+{
+ return _in_show_desktop;
}
void
diff --git a/unity-shared/ResizingBaseWindow.h b/unity-shared/ResizingBaseWindow.h
new file mode 100644
index 000000000..ff400c1c2
--- /dev/null
+++ b/unity-shared/ResizingBaseWindow.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2012 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: Nick Dedekind <nick.dedekind@canonical.com>
+ */
+
+#ifndef RESIZEDINPUTWINDOW_BASEWINDOW_H
+#define RESIZEDINPUTWINDOW_BASEWINDOW_H
+
+#include <Nux/BaseWindow.h>
+
+namespace unity
+{
+
+class ResizingBaseWindow : public nux::BaseWindow
+{
+public:
+ ResizingBaseWindow(const char *WindowName, std::function<nux::Geometry (nux::Geometry const&)> geo_func)
+ : BaseWindow(WindowName, NUX_TRACKER_LOCATION)
+ {
+ geo_func_ = geo_func;
+ }
+
+ void UpdateInputWindowGeometry()
+ {
+ if (m_input_window && m_input_window_enabled)
+ m_input_window->SetGeometry(geo_func_(GetGeometry()));
+ }
+
+ virtual void SetGeometry(const nux::Geometry &geo)
+ {
+ Area::SetGeometry(geo);
+ UpdateInputWindowGeometry();
+ }
+
+private:
+ std::function<nux::Geometry (nux::Geometry const&)> geo_func_;
+};
+
+}
+#endif // RESIZEDINPUTWINDOW_BASEWINDOW_H
diff --git a/unity-shared/UnitySettings.cpp b/unity-shared/UnitySettings.cpp
index 8e628ed7d..a7518bf11 100644
--- a/unity-shared/UnitySettings.cpp
+++ b/unity-shared/UnitySettings.cpp
@@ -1,6 +1,6 @@
// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
/*
-* Copyright (C) 2010, 2011 Canonical Ltd
+* Copyright (C) 2010, 2011, 2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
@@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
+* Andrea Azzarone <andrea.azzarone@canonical.com>
*/
#include <gdk/gdk.h>
@@ -32,81 +33,69 @@ namespace
nux::logging::Logger logger("unity");
Settings* settings_instance = nullptr;
-const char* const FORM_FACTOR = "form-factor";
+
+const std::string SETTINGS_NAME = "com.canonical.Unity";
+const std::string FORM_FACTOR = "form-factor";
}
+//
+// Start private implementation
+//
class Settings::Impl
{
public:
- Impl(Settings* owner);
- ~Impl();
-
- FormFactor GetFormFactor() const;
- void SetFormFactor(FormFactor factor);
-
-private:
- void Refresh();
- static void Changed(GSettings* settings, gchar* key, Impl* self);
-
-private:
- Settings* owner_;
- GSettings* settings_;
- FormFactor form_factor_;
-};
-
-
-Settings::Impl::Impl(Settings* owner)
- : owner_(owner)
- , settings_(nullptr)
- , form_factor_(FormFactor::DESKTOP)
-{
- settings_ = g_settings_new("com.canonical.Unity");
- g_signal_connect(settings_, "changed",
- (GCallback)(Impl::Changed), this);
- Refresh();
-}
-
-Settings::Impl::~Impl()
-{
- g_object_unref(settings_);
-}
+ Impl(Settings* owner)
+ : parent_(owner)
+ , gsettings_(g_settings_new(SETTINGS_NAME.c_str()))
+ , cached_form_factor_(FormFactor::DESKTOP)
+ {
+ CacheFormFactor();
-void Settings::Impl::Refresh()
-{
- int raw_from_factor = g_settings_get_enum(settings_, FORM_FACTOR);
+ form_factor_changed_.Connect(gsettings_, "changed::" + FORM_FACTOR, [this] (GSettings*, gchar*) {
+ CacheFormFactor();
+ parent_->form_factor.changed.emit(cached_form_factor_);
+ });
+ }
- if (raw_from_factor == 0) //Automatic
+ void CacheFormFactor()
{
- UScreen *uscreen = UScreen::GetDefault();
- int primary_monitor = uscreen->GetMonitorWithMouse();
- auto geo = uscreen->GetMonitorGeometry(primary_monitor);
-
- form_factor_ = geo.height > 799 ? FormFactor::DESKTOP : FormFactor::NETBOOK;
+ int raw_from_factor = g_settings_get_enum(gsettings_, FORM_FACTOR.c_str());
+
+ if (raw_from_factor == 0) //Automatic
+ {
+ auto uscreen = UScreen::GetDefault();
+ int primary_monitor = uscreen->GetMonitorWithMouse();
+ auto const& geo = uscreen->GetMonitorGeometry(primary_monitor);
+
+ cached_form_factor_ = geo.height > 799 ? FormFactor::DESKTOP : FormFactor::NETBOOK;
+ }
+ else
+ {
+ cached_form_factor_ = static_cast<FormFactor>(raw_from_factor);
+ }
}
- else
+
+ FormFactor GetFormFactor() const
{
- form_factor_ = static_cast<FormFactor>(raw_from_factor);
+ return cached_form_factor_;
}
- owner_->changed.emit();
-}
+ bool SetFormFactor(FormFactor factor)
+ {
+ g_settings_set_enum(gsettings_, FORM_FACTOR.c_str(), static_cast<int>(factor));
+ return true;
+ }
-void Settings::Impl::Changed(GSettings* settings, char* key, Impl* self)
-{
- self->Refresh();
-}
+ Settings* parent_;
+ glib::Object<GSettings> gsettings_;
+ FormFactor cached_form_factor_;
-FormFactor Settings::Impl::GetFormFactor() const
-{
- return form_factor_;
-}
+ glib::Signal<void, GSettings*, gchar* > form_factor_changed_;
+};
-void Settings::Impl::SetFormFactor(FormFactor factor)
-{
- form_factor_ = factor;
- g_settings_set_enum(settings_, FORM_FACTOR, static_cast<int>(factor));
- owner_->changed.emit();
-}
+//
+// End private implementation
+//
Settings::Settings()
: is_standalone(false)
@@ -118,13 +107,15 @@ Settings::Settings()
}
else
{
+ form_factor.SetGetterFunction(sigc::mem_fun(*pimpl, &Impl::GetFormFactor));
+ form_factor.SetSetterFunction(sigc::mem_fun(*pimpl, &Impl::SetFormFactor));
+
settings_instance = this;
}
}
Settings::~Settings()
{
- delete pimpl;
if (settings_instance == this)
settings_instance = nullptr;
}
@@ -139,15 +130,5 @@ Settings& Settings::Instance()
return *settings_instance;
}
-FormFactor Settings::GetFormFactor() const
-{
- return pimpl->GetFormFactor();
-}
-
-void Settings::SetFormFactor(FormFactor factor)
-{
- pimpl->SetFormFactor(factor);
-}
-
} // namespace unity
diff --git a/unity-shared/UnitySettings.h b/unity-shared/UnitySettings.h
index 46f75d40b..182cc82bf 100644
--- a/unity-shared/UnitySettings.h
+++ b/unity-shared/UnitySettings.h
@@ -1,6 +1,6 @@
// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
/*
-* Copyright (C) 2010, 2011 Canonical Ltd
+* Copyright (C) 2010, 2011, 2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
@@ -15,11 +15,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
+* Andrea Azzarone <andrea.azzarone@canonical.com>
*/
-#ifndef UNITY_SETTINGS_H
-#define UNITY_SETTINGS_H
+#ifndef UNITYSHELL_SETTINGS_H
+#define UNITYSHELL_SETTINGS_H
+#include <memory>
#include <sigc++/signal.h>
#include <Nux/Nux.h>
@@ -29,7 +31,7 @@ namespace unity
enum class FormFactor
{
DESKTOP = 1,
- NETBOOK = 2,
+ NETBOOK,
TV
};
@@ -41,18 +43,14 @@ public:
static Settings& Instance();
- // NOTE: could potentially refactor this into a nux::Property
- FormFactor GetFormFactor() const;
- void SetFormFactor(FormFactor factor);
-
+ nux::RWProperty<FormFactor> form_factor;
nux::Property<bool> is_standalone;
- sigc::signal<void> changed;
private:
class Impl;
- Impl* pimpl;
+ std::unique_ptr<Impl> pimpl;
};
}
-#endif // UNITY_SETTINGS_H
+#endif
diff --git a/unity-shared/WindowManager.cpp b/unity-shared/WindowManager.cpp
index df983217c..5359d1a08 100644
--- a/unity-shared/WindowManager.cpp
+++ b/unity-shared/WindowManager.cpp
@@ -48,6 +48,11 @@ class WindowManagerDummy : public WindowManager
g_debug("%s", G_STRFUNC);
}
+ bool InShowDesktop() const
+ {
+ return false;
+ }
+
bool IsWindowMaximized(guint32 xid) const
{
return false;
diff --git a/unity-shared/WindowManager.h b/unity-shared/WindowManager.h
index 204c9439c..0600f5552 100644
--- a/unity-shared/WindowManager.h
+++ b/unity-shared/WindowManager.h
@@ -63,6 +63,7 @@ public:
virtual bool IsWindowMaximizable(guint32 xid) const = 0;
virtual void ShowDesktop() = 0;
+ virtual bool InShowDesktop() const = 0;
virtual void Restore(guint32 xid) = 0;
virtual void RestoreAt(guint32 xid, int x, int y) = 0;
diff --git a/unity-standalone/StandaloneUnity.cpp b/unity-standalone/StandaloneUnity.cpp
index a5dba677c..50069c989 100644
--- a/unity-standalone/StandaloneUnity.cpp
+++ b/unity-standalone/StandaloneUnity.cpp
@@ -86,7 +86,7 @@ UnityStandalone::~UnityStandalone ()
void UnityStandalone::Init ()
{
- launcher_controller.reset(new launcher::Controller(0));
+ launcher_controller.reset(new launcher::Controller());
panel_controller.reset(new panel::Controller());
dash_controller.reset(new dash::Controller());
@@ -119,7 +119,7 @@ UnityStandaloneTV::~UnityStandaloneTV() {};
void UnityStandaloneTV::Init()
{
- launcher_controller.reset(new launcher::Controller(0));
+ launcher_controller.reset(new launcher::Controller());
dash_controller.reset(new dash::Controller());
dash_controller->launcher_width = launcher_controller->launcher().GetAbsoluteWidth() - 1;
@@ -160,7 +160,7 @@ int main(int argc, char **argv)
// The instances for the pseudo-singletons.
Settings settings;
settings.is_standalone = true;
- if (force_tv) Settings::Instance().SetFormFactor(FormFactor::TV);
+ if (force_tv) Settings::Instance().form_factor(FormFactor::TV);
PluginAdapter::Initialize(NULL);
dash::Style dash_style;