summaryrefslogtreecommitdiff
diff options
-rw-r--r--CMakeLists.txt4
-rw-r--r--HACKING7
-rw-r--r--README1
-rw-r--r--UnityCore/CMakeLists.txt2
-rw-r--r--UnityCore/Categories.cpp8
-rw-r--r--UnityCore/Categories.h1
-rw-r--r--UnityCore/Filters.cpp8
-rw-r--r--UnityCore/Filters.h1
-rw-r--r--UnityCore/GLibDBusProxy.cpp11
-rw-r--r--UnityCore/GLibDBusProxy.h1
-rw-r--r--UnityCore/GLibWrapper.cpp5
-rw-r--r--UnityCore/GLibWrapper.h1
-rw-r--r--UnityCore/HomeLens.cpp957
-rw-r--r--UnityCore/HomeLens.h79
-rw-r--r--UnityCore/Lens.cpp179
-rw-r--r--UnityCore/Lens.h23
-rw-r--r--UnityCore/Model-inl.h56
-rw-r--r--UnityCore/Model.h11
-rw-r--r--UnityCore/Results.cpp8
-rw-r--r--UnityCore/Results.h1
-rw-r--r--com.canonical.Unity.gschema.xml13
-rw-r--r--manual-tests/AutoMaximize.txt19
-rw-r--r--manual-tests/Dash.txt15
-rw-r--r--manual-tests/Launcher.txt40
-rw-r--r--manual-tests/SuperTab.txt55
-rw-r--r--plugins/unity-mt-grab-handles/src/unity-mt-grab-handles.cpp31
-rw-r--r--plugins/unity-mt-grab-handles/src/unity-mt-grab-handles.h4
-rw-r--r--plugins/unitydialog/src/unitydialog.cpp98
-rw-r--r--plugins/unitydialog/src/unitydialog.h24
-rw-r--r--plugins/unityshell/resources/dash-widgets.json4
-rw-r--r--plugins/unityshell/src/BamfLauncherIcon.cpp99
-rw-r--r--plugins/unityshell/src/BamfLauncherIcon.h8
-rw-r--r--plugins/unityshell/src/DashSearchBar.cpp12
-rw-r--r--plugins/unityshell/src/DashView.cpp50
-rw-r--r--plugins/unityshell/src/DashView.h6
-rw-r--r--plugins/unityshell/src/FavoriteStore.h10
-rw-r--r--plugins/unityshell/src/FavoriteStoreGSettings.cpp53
-rw-r--r--plugins/unityshell/src/FavoriteStoreGSettings.h3
-rw-r--r--plugins/unityshell/src/FavoriteStorePrivate.cpp130
-rw-r--r--plugins/unityshell/src/FavoriteStorePrivate.h47
-rw-r--r--plugins/unityshell/src/FilterBar.cpp32
-rw-r--r--plugins/unityshell/src/FilterBasicButton.cpp13
-rw-r--r--plugins/unityshell/src/FilterExpanderLabel.cpp53
-rw-r--r--plugins/unityshell/src/FilterExpanderLabel.h6
-rw-r--r--plugins/unityshell/src/FilterGenreWidget.cpp12
-rw-r--r--plugins/unityshell/src/FilterMultiRangeWidget.cpp10
-rw-r--r--plugins/unityshell/src/FilterRatingsWidget.cpp2
-rw-r--r--plugins/unityshell/src/HomeView.cpp252
-rw-r--r--plugins/unityshell/src/HomeView.h93
-rw-r--r--plugins/unityshell/src/IMTextEntry.cpp68
-rw-r--r--plugins/unityshell/src/IMTextEntry.h9
-rw-r--r--plugins/unityshell/src/IconLoader.cpp205
-rw-r--r--plugins/unityshell/src/IconRenderer.cpp33
-rw-r--r--plugins/unityshell/src/Introspectable.cpp2
-rw-r--r--plugins/unityshell/src/Introspectable.h6
-rw-r--r--plugins/unityshell/src/Launcher.cpp49
-rw-r--r--plugins/unityshell/src/Launcher.h2
-rw-r--r--plugins/unityshell/src/LauncherController.cpp141
-rw-r--r--plugins/unityshell/src/LauncherController.h2
-rw-r--r--plugins/unityshell/src/LauncherModel.cpp82
-rw-r--r--plugins/unityshell/src/LauncherModel.h1
-rw-r--r--plugins/unityshell/src/LensBar.cpp14
-rw-r--r--plugins/unityshell/src/LensView.cpp13
-rw-r--r--plugins/unityshell/src/PanelController.cpp32
-rw-r--r--plugins/unityshell/src/PanelController.h6
-rw-r--r--plugins/unityshell/src/PanelIndicatorsView.cpp5
-rw-r--r--plugins/unityshell/src/PanelIndicatorsView.h1
-rw-r--r--plugins/unityshell/src/PanelView.cpp5
-rw-r--r--plugins/unityshell/src/PanelView.h1
-rw-r--r--plugins/unityshell/src/PlacesGroup.cpp11
-rw-r--r--plugins/unityshell/src/PlacesHomeView.cpp378
-rw-r--r--plugins/unityshell/src/PlacesHomeView.h72
-rw-r--r--plugins/unityshell/src/PlacesSimpleTile.cpp6
-rw-r--r--plugins/unityshell/src/PlacesSimpleTile.h1
-rw-r--r--plugins/unityshell/src/PluginAdapter.cpp12
-rw-r--r--plugins/unityshell/src/ResultViewGrid.cpp15
-rw-r--r--plugins/unityshell/src/ScreenEffectFramebufferObject.cpp6
-rw-r--r--plugins/unityshell/src/ScreenEffectFramebufferObject.h2
-rw-r--r--plugins/unityshell/src/ShortcutController.cpp86
-rw-r--r--plugins/unityshell/src/ShortcutController.h15
-rw-r--r--plugins/unityshell/src/SoftwareCenterLauncherIcon.cpp102
-rw-r--r--plugins/unityshell/src/SoftwareCenterLauncherIcon.h60
-rw-r--r--plugins/unityshell/src/compizminimizedwindowhandler.h54
-rw-r--r--plugins/unityshell/src/unityshell.cpp366
-rw-r--r--plugins/unityshell/src/unityshell.h39
-rw-r--r--po/POTFILES.in1
-rw-r--r--services/panel-service.c7
-rw-r--r--standalone-clients/CMakeLists.txt4
-rw-r--r--standalone-clients/TestScreenEffectFramebufferObject.cpp198
-rw-r--r--standalone-clients/TestShortcut.cpp2
-rw-r--r--standalone-clients/standalone_dash.cpp16
-rw-r--r--tests/CMakeLists.txt21
-rw-r--r--tests/test_favorite_store_gsettings.cpp270
-rw-r--r--tests/test_favorite_store_private.cpp417
-rw-r--r--tests/test_home_lens.cpp362
-rw-r--r--tests/test_icon_loader.cpp191
-rw-r--r--tests/test_utils.h27
-rwxr-xr-xtools/unity-introspection-visualiser.py87
-rwxr-xr-xtools/unity.cmake4
99 files changed, 4566 insertions, 1501 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 359efd68e..66c47f12e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -17,6 +17,9 @@ set (CMAKE_CXX_FLAGS "-DGNOME_DESKTOP_USE_UNSTABLE_API -std=c++0x -fno-permissiv
set (CMAKE_CXX_FLAGS_DEBUG "-g3")
set (CMAKE_CXX_FLAGS_RELEASE "")
+if (BUILD_GLES)
+ SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNUX_OPENGLES_20 -DUSE_GLES")
+endif (BUILD_GLES)
#
# Niceties
@@ -136,6 +139,7 @@ add_subdirectory(UnityCore)
add_subdirectory(guides)
add_subdirectory(standalone-clients EXCLUDE_FROM_ALL)
+
#
# GSettings Schema
#
diff --git a/HACKING b/HACKING
index 4ed9de6c9..0248d7a73 100644
--- a/HACKING
+++ b/HACKING
@@ -39,5 +39,12 @@ or if you have a specific client you care about you can build that client explic
Testing is handled through GTest, googles test system, we currently have three test targets; test-gtest, test-gtest-xless, test-gtest-dbus. tests that require Nux should be in test-gtest as they require X, tests that can run headless should be in test-gtest-xless and tests that require dbus should be run with test-gtest-dbus, which tests run with our test service.
+To enable debug logging you must set the environment variable UNITY_LOG_SEVERITY to the log domain you
+want to watch and the log level for that domain. For example:
+
+ UNITY_LOG_SEVERITY="unity.dash.lens=DEBUG" standalone-clients/dash
+
+
+
for more information see the README file
diff --git a/README b/README
index 801461a13..e3ee6222c 100644
--- a/README
+++ b/README
@@ -18,4 +18,3 @@
Makes the panel run the unity-panel-service directly instead of through
D-Bus activation. This is used for testing how the panel reacts when it
starts before the service does.
-
diff --git a/UnityCore/CMakeLists.txt b/UnityCore/CMakeLists.txt
index ff1312f74..3b0d5140b 100644
--- a/UnityCore/CMakeLists.txt
+++ b/UnityCore/CMakeLists.txt
@@ -21,6 +21,7 @@ set (CORE_HEADERS
GLibSignal-inl.h
GLibWrapper.h
GLibWrapper-inl.h
+ HomeLens.h
IndicatorEntry.h
Indicator.h
Indicators.h
@@ -53,6 +54,7 @@ set (CORE_SOURCES
GLibDBusProxy.cpp
GLibSignal.cpp
GLibWrapper.cpp
+ HomeLens.cpp
Indicator.cpp
IndicatorEntry.cpp
Indicators.cpp
diff --git a/UnityCore/Categories.cpp b/UnityCore/Categories.cpp
index 247e513e1..ffb9a4910 100644
--- a/UnityCore/Categories.cpp
+++ b/UnityCore/Categories.cpp
@@ -31,6 +31,14 @@ Categories::Categories()
row_removed.connect(sigc::mem_fun(this, &Categories::OnRowRemoved));
}
+Categories::Categories(ModelType model_type)
+ : Model<Category>::Model(model_type)
+{
+ row_added.connect(sigc::mem_fun(this, &Categories::OnRowAdded));
+ row_changed.connect(sigc::mem_fun(this, &Categories::OnRowChanged));
+ row_removed.connect(sigc::mem_fun(this, &Categories::OnRowRemoved));
+}
+
void Categories::OnRowAdded(Category& category)
{
category_added.emit(category);
diff --git a/UnityCore/Categories.h b/UnityCore/Categories.h
index df26dbb37..562b0389e 100644
--- a/UnityCore/Categories.h
+++ b/UnityCore/Categories.h
@@ -36,6 +36,7 @@ public:
typedef std::shared_ptr<Categories> Ptr;
Categories();
+ Categories(ModelType model_type);
sigc::signal<void, Category const&> category_added;
sigc::signal<void, Category const&> category_changed;
diff --git a/UnityCore/Filters.cpp b/UnityCore/Filters.cpp
index a56ab88cf..3eaeba59d 100644
--- a/UnityCore/Filters.cpp
+++ b/UnityCore/Filters.cpp
@@ -56,6 +56,14 @@ Filters::Filters()
row_removed.connect(sigc::mem_fun(this, &Filters::OnRowRemoved));
}
+Filters::Filters(ModelType model_type)
+ : Model<FilterAdaptor>::Model(model_type)
+{
+ row_added.connect(sigc::mem_fun(this, &Filters::OnRowAdded));
+ row_changed.connect(sigc::mem_fun(this, &Filters::OnRowChanged));
+ row_removed.connect(sigc::mem_fun(this, &Filters::OnRowRemoved));
+}
+
Filters::~Filters()
{}
diff --git a/UnityCore/Filters.h b/UnityCore/Filters.h
index d0412385b..7b2e2b68a 100644
--- a/UnityCore/Filters.h
+++ b/UnityCore/Filters.h
@@ -51,6 +51,7 @@ public:
typedef std::map<DeeModelIter*, Filter::Ptr> FilterMap;
Filters();
+ Filters(ModelType model_type);
~Filters();
Filter::Ptr FilterAtIndex(std::size_t index);
diff --git a/UnityCore/GLibDBusProxy.cpp b/UnityCore/GLibDBusProxy.cpp
index b71333d5a..1cafe872c 100644
--- a/UnityCore/GLibDBusProxy.cpp
+++ b/UnityCore/GLibDBusProxy.cpp
@@ -72,6 +72,7 @@ public:
int timeout_msec);
void Connect(string const& signal_name, ReplyCallback callback);
+ bool IsConnected();
static void OnNameAppeared(GDBusConnection* connection, const char* name,
const char* name_owner, gpointer impl);
@@ -192,6 +193,11 @@ void DBusProxy::Impl::Connect()
this);
}
+bool DBusProxy::Impl::IsConnected()
+{
+ return connected_;
+}
+
void DBusProxy::Impl::OnProxyConnectCallback(GObject* source,
GAsyncResult* res,
gpointer impl)
@@ -320,5 +326,10 @@ void DBusProxy::Connect(std::string const& signal_name, ReplyCallback callback)
pimpl->Connect(signal_name, callback);
}
+bool DBusProxy::IsConnected()
+{
+ return pimpl->IsConnected();
+}
+
}
}
diff --git a/UnityCore/GLibDBusProxy.h b/UnityCore/GLibDBusProxy.h
index cb70da243..de363fe5b 100644
--- a/UnityCore/GLibDBusProxy.h
+++ b/UnityCore/GLibDBusProxy.h
@@ -54,6 +54,7 @@ public:
int timeout_msec = -1);
void Connect(std::string const& signal_name, ReplyCallback callback);
+ bool IsConnected();
sigc::signal<void> connected;
sigc::signal<void> disconnected;
diff --git a/UnityCore/GLibWrapper.cpp b/UnityCore/GLibWrapper.cpp
index 4ed398a94..05f5f4f7b 100644
--- a/UnityCore/GLibWrapper.cpp
+++ b/UnityCore/GLibWrapper.cpp
@@ -104,6 +104,11 @@ String::operator char*()
return string_;
}
+String::operator std::string()
+{
+ return Str();
+}
+
String::operator bool() const
{
return bool(string_);
diff --git a/UnityCore/GLibWrapper.h b/UnityCore/GLibWrapper.h
index 2710d2880..9eb33c538 100644
--- a/UnityCore/GLibWrapper.h
+++ b/UnityCore/GLibWrapper.h
@@ -115,6 +115,7 @@ public:
operator bool() const;
operator char*();
+ operator std::string();
gchar* Value();
std::string Str() const;
diff --git a/UnityCore/HomeLens.cpp b/UnityCore/HomeLens.cpp
new file mode 100644
index 000000000..b14f29b33
--- /dev/null
+++ b/UnityCore/HomeLens.cpp
@@ -0,0 +1,957 @@
+// -*- 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: Mikkel Kamstrup Erlandsen <mikkel.kamstrup@canonical.com>
+ */
+
+#include <glib.h>
+#include <string>
+#include <stdexcept>
+#include <map>
+
+#include "GLibSignal.h"
+#include "HomeLens.h"
+#include "Lens.h"
+#include "Model.h"
+
+#include "config.h"
+
+namespace unity
+{
+namespace dash
+{
+
+namespace
+{
+
+nux::logging::Logger logger("unity.dash.homelens");
+
+}
+
+/*
+ * Helper class that maps category offsets between the merged lens and
+ * source lenses. We also use it to merge categories from different lenses
+ * with the same display name into the same category.
+ *
+ * NOTE: The model pointers passed in are expected to be pointers to the
+ * result source models - and not the category source models!
+ */
+class HomeLens::CategoryRegistry
+{
+public:
+ CategoryRegistry(HomeLens* owner)
+ : is_dirty_(false)
+ , owner_(owner) {}
+
+ int FindCategoryOffset(DeeModel* model, unsigned int source_cat_offset)
+ {
+ glib::String c_id(g_strdup_printf("%u+%p", source_cat_offset, model));
+ std::map<std::string,unsigned int>::iterator i = reg_by_id_.find(c_id);
+
+ if (i != reg_by_id_.end())
+ return i->second;
+
+ return -1;
+ }
+
+ int FindCategoryOffset(const gchar* display_name)
+ {
+ std::map<std::string,unsigned int>::iterator i =
+ reg_by_display_name_.find(display_name);
+ if (i != reg_by_display_name_.end())
+ return i->second;
+
+ return -1;
+ }
+
+ /* Register a new category */
+ void RegisterCategoryOffset(DeeModel* model,
+ unsigned int source_cat_offset,
+ const gchar* display_name,
+ unsigned int target_cat_offset)
+ {
+ glib::String c_id(g_strdup_printf("%u+%p", source_cat_offset, model));
+
+ std::map<std::string,unsigned int>::iterator i = reg_by_id_.find(c_id);
+ if (i != reg_by_id_.end())
+ {
+ LOG_ERROR(logger) << "Category '" << c_id << "' already registered!";
+ return;
+ }
+
+ if (display_name != NULL)
+ {
+ i = reg_by_display_name_.find(display_name);
+ if (i != reg_by_display_name_.end())
+ {
+ LOG_ERROR(logger) << "Category '" << display_name << "' already registered!";
+ return;
+ }
+ }
+
+ /* Any existing categories with offsets >= target_cat_offset must be
+ * pushed up. Update both maps by id and display name */
+ std::map<std::string,unsigned int>::iterator end = reg_by_id_.end();
+ for (i = reg_by_id_.begin(); i != end; i++)
+ {
+ if (i->second >= target_cat_offset)
+ {
+ i->second = i->second + 1;
+ is_dirty_ = true;
+ }
+ }
+
+ for (i = reg_by_display_name_.begin(), end = reg_by_display_name_.end(); i != end; i++)
+ {
+ if (i->second >= target_cat_offset)
+ {
+ i->second = i->second + 1;
+ is_dirty_ = true;
+ }
+ }
+
+ reg_by_id_[c_id] = target_cat_offset;
+
+ /* Callers pass a NULL display_name when they already have a category
+ * with the right display registered */
+ if (display_name != NULL)
+ {
+ reg_by_display_name_[display_name] = target_cat_offset;
+ LOG_DEBUG(logger) << "Registered category '" << display_name
+ << "' with source offset " << source_cat_offset
+ << " and target offset " << target_cat_offset
+ << ". Id " << c_id;
+ }
+ else
+ {
+ LOG_DEBUG(logger) << "Registered category with source offset "
+ << source_cat_offset << " and target offset "
+ << target_cat_offset << ". Id " << c_id;
+ }
+ }
+
+ /* Associate a source results model and category offset with an existing
+ * target category offset */
+ void AssociateCategoryOffset(DeeModel* model,
+ unsigned int source_cat_offset,
+ unsigned int target_cat_offset)
+ {
+ glib::String c_id(g_strdup_printf("%u+%p", source_cat_offset, model));
+
+ std::map<std::string,unsigned int>::iterator i = reg_by_id_.find(c_id);
+ if (i != reg_by_id_.end())
+ {
+ LOG_ERROR(logger) << "Category '" << c_id << "' already registered!";
+ return;
+ }
+
+ reg_by_id_[c_id] = target_cat_offset;
+ }
+
+ /**
+ * Returns true and resets the dirty state if the registry was dirty.
+ * When you've checked a dirty registry you must either clear the
+ * merged results model or recalibrate all category offset in it
+ * (and Unity probably wont support the latter?).
+ */
+ bool CheckDirty()
+ {
+ return is_dirty_ ? (is_dirty_ = false, true) : false;
+ }
+
+private:
+ std::map<std::string,unsigned int> reg_by_id_;
+ std::map<std::string,unsigned int> reg_by_display_name_;
+ bool is_dirty_;
+ HomeLens* owner_;
+};
+
+/*
+ * Helper class that merges a set of DeeModels into one super model
+ */
+class HomeLens::ModelMerger : public sigc::trackable
+{
+public:
+ ModelMerger(glib::Object<DeeModel> target);
+ virtual ~ModelMerger();
+
+ void AddSource(glib::Object<DeeModel> source);
+
+protected:
+ virtual void OnSourceRowAdded(DeeModel *model, DeeModelIter *iter);
+ virtual void OnSourceRowRemoved(DeeModel* model, DeeModelIter* iter);
+ virtual void OnSourceRowChanged(DeeModel* model, DeeModelIter* iter);
+ void EnsureRowBuf(DeeModel *source);
+
+ /* The merge tag lives on the source models, pointing to the mapped
+ * row in the target model */
+ DeeModelTag* FindSourceToTargetTag(DeeModel *model);
+
+protected:
+ glib::SignalManager sig_manager_;
+ GVariant** row_buf_;
+ unsigned int n_cols_;
+ glib::Object<DeeModel> target_;
+ std::map<DeeModel*,DeeModelTag*> source_to_target_tags_;
+};
+
+/*
+ * Specialized ModelMerger that takes care merging results models.
+ * We need special handling here because rows in each lens' results model
+ * specifies an offset into the lens' categories model where the display
+ * name of the category is defined.
+ *
+ * This class converts the offset of the source lens' categories into
+ * offsets into the merged category model.
+ *
+ * Each row added to the target is tagged with a pointer to the Lens instance
+ * from which it came
+ */
+class HomeLens::ResultsMerger : public ModelMerger
+{
+public:
+ ResultsMerger(glib::Object<DeeModel> target,
+ HomeLens::CategoryRegistry* cat_registry);
+
+protected:
+ void OnSourceRowAdded(DeeModel *model, DeeModelIter *iter);
+ void OnSourceRowRemoved(DeeModel *model, DeeModelIter *iter);
+ void OnSourceRowChanged(DeeModel *model, DeeModelIter *iter);
+ void CheckCategoryRegistryDirty();
+
+private:
+ HomeLens::CategoryRegistry* cat_registry_;
+};
+
+/*
+ * Specialized ModelMerger that takes care merging category models.
+ * We need special handling here because rows in each lens' results model
+ * specifies an offset into the lens' categories model where the display
+ * name of the category is defined.
+ *
+ * This class records a map of the offsets from the original source category
+ * models to the offsets in the combined categories model.
+ */
+class HomeLens::CategoryMerger : public ModelMerger
+{
+public:
+ CategoryMerger(glib::Object<DeeModel> target,
+ HomeLens::CategoryRegistry* cat_registry);
+
+ void OnSourceRowAdded(DeeModel *model, DeeModelIter *iter);
+ void OnSourceRowRemoved(DeeModel *model, DeeModelIter *iter);
+
+private:
+ HomeLens::CategoryRegistry* cat_registry_;
+ DeeModelTag* priority_tag_;
+};
+
+/*
+ * Pimpl for HomeLens
+ */
+class HomeLens::Impl : public sigc::trackable
+{
+public:
+ Impl(HomeLens* owner);
+ ~Impl();
+
+ void OnLensAdded(Lens::Ptr& lens);
+ gsize FindLensPriority (Lens::Ptr& lens);
+ void EnsureCategoryAnnotation(Lens::Ptr& lens, DeeModel* results, DeeModel* categories);
+ Lens::Ptr FindLensForUri(std::string const& uri);
+
+ HomeLens* owner_;
+ Lenses::LensList lenses_;
+ HomeLens::CategoryRegistry cat_registry_;
+ HomeLens::ResultsMerger results_merger_;
+ HomeLens::CategoryMerger categories_merger_;
+ HomeLens::ModelMerger filters_merger_;
+ int running_searches_;
+ glib::Object<GSettings> settings_;
+};
+
+/*
+ * IMPLEMENTATION
+ */
+
+HomeLens::ModelMerger::ModelMerger(glib::Object<DeeModel> target)
+ : row_buf_(NULL)
+ , n_cols_(0)
+ , target_(target)
+{}
+
+HomeLens::ResultsMerger::ResultsMerger(glib::Object<DeeModel> target,
+ CategoryRegistry *cat_registry)
+ : HomeLens::ModelMerger::ModelMerger(target)
+ , cat_registry_(cat_registry)
+{}
+
+HomeLens::CategoryMerger::CategoryMerger(glib::Object<DeeModel> target,
+ CategoryRegistry *cat_registry)
+ : HomeLens::ModelMerger::ModelMerger(target)
+ , cat_registry_(cat_registry)
+ , priority_tag_(dee_model_register_tag(target, NULL))
+{}
+
+HomeLens::ModelMerger::~ModelMerger()
+{
+ if (row_buf_)
+ delete row_buf_;
+}
+
+void HomeLens::ModelMerger::AddSource(glib::Object<DeeModel> source)
+{
+ typedef glib::Signal<void, DeeModel*, DeeModelIter*> RowSignalType;
+
+ if (!source)
+ {
+ LOG_ERROR(logger) << "Trying to add NULL source to ModelMerger";
+ return;
+ }
+
+ DeeModelTag* merger_tag = dee_model_register_tag(source, NULL);
+ source_to_target_tags_[source.RawPtr()] = merger_tag;
+
+ sig_manager_.Add(new RowSignalType(source.RawPtr(),
+ "row-added",
+ sigc::mem_fun(this, &HomeLens::ModelMerger::OnSourceRowAdded)));
+
+ sig_manager_.Add(new RowSignalType(source.RawPtr(),
+ "row-removed",
+ sigc::mem_fun(this, &HomeLens::ModelMerger::OnSourceRowRemoved)));
+
+ sig_manager_.Add(new RowSignalType(source.RawPtr(),
+ "row-changed",
+ sigc::mem_fun(this, &HomeLens::ModelMerger::OnSourceRowChanged)));
+}
+
+void HomeLens::ModelMerger::OnSourceRowAdded(DeeModel *model, DeeModelIter *iter)
+{
+ // Default impl. does nothing.
+ // Note that the filters_merger_ relies on this behavior. Supporting
+ // filters on the home screen is possible, but *quite* tricky.
+ // So...
+ // Discard ALL the rows!
+}
+
+void HomeLens::ResultsMerger::OnSourceRowAdded(DeeModel *model, DeeModelIter *iter)
+{
+ DeeModelIter* target_iter;
+ DeeModelTag* target_tag;
+ int target_cat_offset, source_cat_offset;
+ const unsigned int CATEGORY_COLUMN = 2;
+
+ EnsureRowBuf(model);
+ CheckCategoryRegistryDirty();
+
+ dee_model_get_row (model, iter, row_buf_);
+ target_tag = FindSourceToTargetTag(model);
+
+ /* Update the row with the corrected category offset */
+ source_cat_offset = dee_model_get_uint32(model, iter, CATEGORY_COLUMN);
+ target_cat_offset = cat_registry_->FindCategoryOffset(model, source_cat_offset);
+
+ if (target_cat_offset >= 0)
+ {
+ g_variant_unref (row_buf_[CATEGORY_COLUMN]);
+ row_buf_[CATEGORY_COLUMN] = g_variant_new_uint32(target_cat_offset);
+
+ /* Sink the ref on the new row member. By Dee API contract they must all
+ * be strong refs, not floating */
+ g_variant_ref_sink(row_buf_[CATEGORY_COLUMN]);
+
+ target_iter = dee_model_append_row (target_, row_buf_);
+ dee_model_set_tag(model, iter, target_tag, target_iter);
+
+ LOG_DEBUG(logger) << "Found " << dee_model_get_string(model, iter, 0)
+ << " (source cat " << source_cat_offset << ", target cat "
+ << target_cat_offset << ")";
+ }
+ else
+ {
+ LOG_ERROR(logger) << "No category registered for model "
+ << model << ", source offset " << source_cat_offset
+ << ": " << dee_model_get_string(model, iter, 0);
+ }
+
+ for (unsigned int i = 0; i < n_cols_; i++) g_variant_unref(row_buf_[i]);
+}
+
+void HomeLens::CategoryMerger::OnSourceRowAdded(DeeModel *model, DeeModelIter *iter)
+{
+ DeeModel* results_model;
+ DeeModelIter* target_iter;
+ DeeModelIter* target_end;
+ DeeModelTag* target_tag;
+ int target_cat_offset, source_cat_offset;
+ const gchar* display_name;
+ const unsigned int DISPLAY_NAME_COLUMN = 0;
+ gsize lens_priority, prio;
+
+ EnsureRowBuf(model);
+
+ results_model = static_cast<DeeModel*>(g_object_get_data(
+ G_OBJECT(model), "unity-homelens-results-model"));
+ if (results_model == NULL)
+ {
+ LOG_DEBUG(logger) << "Category model " << model
+ << " does not have a results model yet";
+ return;
+ }
+
+ dee_model_get_row (model, iter, row_buf_);
+ target_tag = FindSourceToTargetTag(model);
+ source_cat_offset = dee_model_get_position(model, iter);
+
+ /* If we already have a category registered with the same display name
+ * then we just use that. Otherwise register a new category for it */
+ display_name = dee_model_get_string(model, iter, DISPLAY_NAME_COLUMN);
+ target_cat_offset = cat_registry_->FindCategoryOffset(display_name);
+ if (target_cat_offset >= 0)
+ {
+ cat_registry_->AssociateCategoryOffset(results_model, source_cat_offset,
+ target_cat_offset);
+ goto cleanup;
+ }
+
+ /*
+ * Below we can assume that we have a genuinely new category.
+ *
+ * Our goal is to insert the category at a position suitable for its
+ * priority. We insert it as the last item in the set of items which
+ * have equal priority.
+ *
+ * We allow our selves to do linear inserts as we wont expect a lot
+ * of categories.
+ */
+
+ lens_priority = GPOINTER_TO_SIZE(g_object_get_data(
+ G_OBJECT(model), "unity-homelens-priority"));
+
+ /* Seek correct position in the merged category model */
+ target_iter = dee_model_get_first_iter(target_);
+ target_end = dee_model_get_last_iter(target_);
+ while (target_iter != target_end)
+ {
+ prio = GPOINTER_TO_SIZE(dee_model_get_tag(target_, target_iter, priority_tag_));
+ if (lens_priority > prio)
+ break;
+ target_iter = dee_model_next(target_, target_iter);
+ }
+
+ /* Add the row to the merged categories model and store required metadata */
+ target_iter = dee_model_insert_row_before(target_, target_iter, row_buf_);
+ dee_model_set_tag(model, iter, target_tag, target_iter);
+ dee_model_set_tag(target_, target_iter, priority_tag_, GSIZE_TO_POINTER(lens_priority));
+ target_cat_offset = dee_model_get_position(target_, target_iter);
+ cat_registry_->RegisterCategoryOffset(results_model, source_cat_offset,
+ display_name, target_cat_offset);
+
+ cleanup:
+ for (unsigned int i = 0; i < n_cols_; i++) g_variant_unref(row_buf_[i]);
+}
+
+void HomeLens::CategoryMerger::OnSourceRowRemoved(DeeModel *model, DeeModelIter *iter)
+{
+ /* We don't support removals of categories.
+ * You can check out any time you like, but you can never leave
+ *
+ * The category registry code is spaghettified enough already.
+ * No more please.
+ */
+ LOG_DEBUG(logger) << "Removal of categories not supported.";
+}
+
+void HomeLens::ModelMerger::OnSourceRowRemoved(DeeModel *model, DeeModelIter *iter)
+{
+ DeeModelIter* target_iter;
+ DeeModelTag* target_tag;
+
+ EnsureRowBuf(model);
+
+ target_tag = FindSourceToTargetTag(model);
+ target_iter = static_cast<DeeModelIter*>(dee_model_get_tag(model,
+ iter,
+ target_tag));
+
+ /* We might not have registered a target iter for the row.
+ * This fx. happens if we re-used a category based on display_name */
+ if (target_iter != NULL)
+ dee_model_remove(target_, target_iter);
+}
+
+void HomeLens::ResultsMerger::OnSourceRowRemoved(DeeModel *model, DeeModelIter *iter)
+{
+ CheckCategoryRegistryDirty();
+ ModelMerger::OnSourceRowRemoved(model, iter);
+}
+
+void HomeLens::ModelMerger::OnSourceRowChanged(DeeModel *model, DeeModelIter *iter)
+{
+ DeeModelIter* target_iter;
+ DeeModelTag* target_tag;
+
+ EnsureRowBuf(model);
+
+ dee_model_get_row (model, iter, row_buf_);
+ target_tag = FindSourceToTargetTag(model);
+ target_iter = static_cast<DeeModelIter*>(dee_model_get_tag(model,
+ iter,
+ target_tag));
+
+ dee_model_set_row (target_, target_iter, row_buf_);
+
+ for (unsigned int i = 0; i < n_cols_; i++) g_variant_unref(row_buf_[i]);
+}
+
+void HomeLens::ResultsMerger::OnSourceRowChanged(DeeModel *model, DeeModelIter *iter)
+{
+ // FIXME: We can support this, but we need to re-calculate the category offset
+ LOG_WARN(logger) << "In-line changing of results not supported in the home lens. Sorry.";
+}
+
+void HomeLens::ModelMerger::EnsureRowBuf(DeeModel *model)
+{
+ if (G_UNLIKELY (n_cols_ == 0))
+ {
+ /* We have two things to accomplish here.
+ * 1) Allocate the row_buf_, and
+ * 2) Make sure that the target model has the correct schema set.
+ *
+ * INVARIANT: n_cols_ == 0 iff row_buf_ == NULL.
+ */
+
+ n_cols_ = dee_model_get_n_columns(model);
+
+ if (n_cols_ == 0)
+ {
+ LOG_ERROR(logger) << "Source model has not provided a schema for the model merger!";
+ return;
+ }
+
+ /* Lazily adopt schema from source if we don't have one.
+ * If we do have a schema let's validate that they match the source */
+ if (dee_model_get_n_columns(target_) == 0)
+ {
+ dee_model_set_schema_full(target_,
+ dee_model_get_schema(model, NULL),
+ n_cols_);
+ }
+ else
+ {
+ unsigned int n_cols1;
+ const gchar* const *schema1 = dee_model_get_schema(target_, &n_cols1);
+ const gchar* const *schema2 = dee_model_get_schema(model, NULL);
+
+ /* At the very least we should have an equal number of rows */
+ if (n_cols_ != n_cols1)
+ {
+ LOG_ERROR(logger) << "Schema mismatch between source and target model. Expected "
+ << n_cols1 << " columns, but found "
+ << n_cols_ << ".";
+ n_cols_ = 0;
+ return;
+ }
+
+ /* Compare schemas */
+ for (unsigned int i = 0; i < n_cols_; i++)
+ {
+ if (g_strcmp0(schema1[i], schema2[i]) != 0)
+ {
+ LOG_ERROR(logger) << "Schema mismatch between source and target model. Expected column "
+ << i << " to be '" << schema1[i] << "', but found '"
+ << schema2[i] << "'.";
+ n_cols_ = 0;
+ return;
+ }
+ }
+ }
+
+ row_buf_ = g_new0 (GVariant*, n_cols_);
+ }
+}
+
+DeeModelTag* HomeLens::ModelMerger::FindSourceToTargetTag(DeeModel *model)
+{
+ return source_to_target_tags_[model];
+}
+
+void HomeLens::ResultsMerger::CheckCategoryRegistryDirty()
+{
+ DeeModel* source;
+ DeeModelTag* target_tag;
+ const unsigned int CATEGORY_COLUMN = 2;
+ std::map<DeeModel*,DeeModelTag*>::iterator i, end;
+
+ if (G_LIKELY(!cat_registry_->CheckDirty()))
+ return;
+
+ LOG_DEBUG(logger) << "Category registry marked dirty. Fixing category offsets.";
+
+ /*
+ * Iterate over all results in each source model and re-calculate the
+ * the category offset in the corresponding rows in the target model
+ */
+ for (i = source_to_target_tags_.begin(), end = source_to_target_tags_.end();
+ i != end; i++)
+ {
+ source = i->first;
+ target_tag = i->second;
+
+ DeeModelIter* source_iter = dee_model_get_first_iter(source);
+ DeeModelIter* source_end = dee_model_get_last_iter(source);
+
+ for (source_iter = dee_model_get_first_iter(source), source_end = dee_model_get_last_iter(source);
+ source_iter != source_end;
+ source_iter = dee_model_next(source, source_iter))
+ {
+ DeeModelIter* target_iter = static_cast<DeeModelIter*>(dee_model_get_tag(source, source_iter, target_tag));
+
+ /* No guarantee that rows in the source are mapped to the target */
+ if (target_iter == NULL)
+ continue;
+
+ unsigned int source_cat_offset = dee_model_get_uint32(source, source_iter, CATEGORY_COLUMN);
+ int cat_offset = cat_registry_->FindCategoryOffset(source, source_cat_offset);
+
+ if (G_LIKELY(cat_offset >= 0))
+ {
+ dee_model_set_value(target_, target_iter, CATEGORY_COLUMN,
+ g_variant_new_uint32(cat_offset));
+ }
+ else
+ {
+ LOG_ERROR(logger) << "No registered category id for category "
+ << source_cat_offset << " on result source model "
+ << source << ".";
+ /* We can't really recover from this :-( */
+ }
+ }
+ }
+}
+
+HomeLens::Impl::Impl(HomeLens *owner)
+ : owner_(owner)
+ , cat_registry_(owner)
+ , results_merger_(owner->results()->model(), &cat_registry_)
+ , categories_merger_(owner->categories()->model(), &cat_registry_)
+ , filters_merger_(owner->filters()->model())
+ , running_searches_(0)
+ , settings_(g_settings_new("com.canonical.Unity.Dash"))
+{
+ DeeModel* results = owner->results()->model();
+ if (dee_model_get_n_columns(results) == 0)
+ {
+ dee_model_set_schema(results, "s", "s", "u", "s", "s", "s", "s", NULL);
+ }
+
+ DeeModel* categories = owner->categories()->model();
+ if (dee_model_get_n_columns(categories) == 0)
+ {
+ dee_model_set_schema(categories, "s", "s", "s", "a{sv}", NULL);
+ }
+
+ DeeModel* filters = owner->filters()->model();
+ if (dee_model_get_n_columns(filters) == 0)
+ {
+ dee_model_set_schema(filters, "s", "s", "s", "s", "a{sv}", "b", "b", "b", NULL);
+ }
+}
+
+HomeLens::Impl::~Impl()
+{
+
+}
+
+/*void HomeLens::Impl::CheckCategories()
+{
+
+}*/
+
+gsize HomeLens::Impl::FindLensPriority (Lens::Ptr& lens)
+{
+ gchar** lenses = g_settings_get_strv(settings_, "home-lens-ordering");
+ gsize pos = 0, len = g_strv_length(lenses);
+
+ for (pos = 0; pos < len; pos++)
+ {
+ if (g_strcmp0(lenses[pos], lens->id().c_str()) == 0)
+ break;
+ }
+
+ g_strfreev(lenses);
+
+ return len - pos;
+}
+
+void HomeLens::Impl::EnsureCategoryAnnotation (Lens::Ptr& lens,
+ DeeModel* categories,
+ DeeModel* results)
+{
+ if (categories && results)
+ {
+ if (!(DEE_IS_MODEL(results) && DEE_IS_MODEL(categories)))
+ {
+ LOG_ERROR(logger) << "The "
+ << std::string(DEE_IS_MODEL(results) ? "categories" : "results")
+ << " model is not a valid DeeModel. ("
+ << lens->id() << ")";
+ return;
+ }
+
+ g_object_set_data(G_OBJECT(categories),
+ "unity-homelens-results-model",
+ results);
+
+ gsize lens_priority = FindLensPriority(lens);
+ g_object_set_data(G_OBJECT(categories),
+ "unity-homelens-priority",
+ GSIZE_TO_POINTER(lens_priority));
+
+ LOG_DEBUG(logger) << "Registering results model " << results
+ << " and lens priority " << lens_priority
+ << " on category model " << categories << ". ("
+ << lens->id() << ")";
+ }
+}
+
+Lens::Ptr HomeLens::Impl::FindLensForUri(std::string const& uri)
+{
+ /* We iterate over all lenses looking for the given uri in their
+ * global results. This might seem like a sucky approach, but it
+ * saves us from a ship load of book keeping */
+
+ for (auto lens : lenses_)
+ {
+ DeeModel* results = lens->global_results()->model();
+ DeeModelIter* iter = dee_model_get_first_iter(results);
+ DeeModelIter* end = dee_model_get_last_iter(results);
+ const int URI_COLUMN = 0;
+
+ while (iter != end)
+ {
+ if (g_strcmp0(uri.c_str(), dee_model_get_string(results, iter, URI_COLUMN)) == 0)
+ {
+ return lens;
+ }
+ iter = dee_model_next(results, iter);
+ }
+ }
+
+ return Lens::Ptr();
+}
+
+// FIXME: Coordinated sorting between the lens bar and home screen categories. Make void FilesystemLenses::Impl::DecrementAndCheckChildrenWaiting() use the gsettings key
+// FIXME: on no results https://bugs.launchpad.net/unity/+bug/711199
+
+void HomeLens::Impl::OnLensAdded (Lens::Ptr& lens)
+{
+ lenses_.push_back (lens);
+ owner_->lens_added.emit(lens);
+
+ /* When we dispatch a search we inc the search count and when we finish
+ * one we decrease it. When we reach 0 we'll emit search_finished. */
+ lens->global_search_finished.connect([&] (Hints const& hints) {
+ running_searches_--;
+
+ if (running_searches_ <= 0)
+ {
+ owner_->search_finished.emit(Hints());
+ LOG_DEBUG(logger) << "Search finished";
+ }
+ });
+
+ nux::ROProperty<glib::Object<DeeModel>>& results_prop = lens->global_results()->model;
+ nux::ROProperty<glib::Object<DeeModel>>& categories_prop = lens->categories()->model;
+ nux::ROProperty<glib::Object<DeeModel>>& filters_prop = lens->filters()->model;
+
+ /*
+ * Important: We must ensure that the categories model is annotated
+ * with the results model in the "unity-homelens-results-model"
+ * data slot. We need it later to compute the transfermed offsets
+ * of the categories in the merged category model.
+ */
+
+ /* Most lenses add models lazily, but we can't know that;
+ * so try to see if we can add them up front */
+ if (results_prop().RawPtr())
+ {
+ EnsureCategoryAnnotation(lens, categories_prop(), results_prop());
+ results_merger_.AddSource(results_prop());
+ }
+
+ if (categories_prop().RawPtr())
+ {
+ EnsureCategoryAnnotation(lens, categories_prop(), results_prop());
+ categories_merger_.AddSource(categories_prop());
+ }
+
+ if (filters_prop().RawPtr())
+ filters_merger_.AddSource(filters_prop());
+
+ /*
+ * Pick it up when the lens set models lazily.
+ */
+ results_prop.changed.connect([&] (glib::Object<DeeModel> model)
+ {
+ EnsureCategoryAnnotation(lens, lens->categories()->model(), model);
+ results_merger_.AddSource(model);
+ });
+
+ categories_prop.changed.connect([&] (glib::Object<DeeModel> model)
+ {
+ EnsureCategoryAnnotation(lens, model, lens->global_results()->model());
+ categories_merger_.AddSource(model);
+ });
+
+ filters_prop.changed.connect([&] (glib::Object<DeeModel> model)
+ {
+ filters_merger_.AddSource(model);
+ });
+
+ /*
+ * Register pre-existing categories up front
+ * FIXME: Do the same for results?
+ */
+ DeeModel* cats = categories_prop();
+ DeeModelIter* cats_iter;
+ DeeModelIter* cats_end;
+ for (cats_iter = dee_model_get_first_iter(cats), cats_end = dee_model_get_last_iter(cats);
+ cats_iter != cats_end;
+ cats_iter = dee_model_next(cats, cats_iter))
+ {
+ categories_merger_.OnSourceRowAdded(cats, cats_iter);
+ }
+}
+
+HomeLens::HomeLens(std::string const& name, std::string const& description, std::string const& search_hint)
+ : Lens("home.lens", "", "", name, PKGDATADIR"/lens-nav-home.svg",
+ description, search_hint, true, "",
+ ModelType::LOCAL)
+ , pimpl(new Impl(this))
+{
+ count.SetGetterFunction(sigc::mem_fun(&pimpl->lenses_, &Lenses::LensList::size));
+ search_in_global = false;
+}
+
+HomeLens::~HomeLens()
+{
+ delete pimpl;
+}
+
+void HomeLens::AddLenses(Lenses& lenses)
+{
+ for (auto lens : lenses.GetLenses())
+ {
+ pimpl->OnLensAdded(lens);
+ }
+
+ lenses.lens_added.connect(sigc::mem_fun(pimpl, &HomeLens::Impl::OnLensAdded));
+}
+
+Lenses::LensList HomeLens::GetLenses() const
+{
+ return pimpl->lenses_;
+}
+
+Lens::Ptr HomeLens::GetLens(std::string const& lens_id) const
+{
+ for (auto lens: pimpl->lenses_)
+ {
+ if (lens->id == lens_id)
+ {
+ return lens;
+ }
+ }
+
+ return Lens::Ptr();
+}
+
+Lens::Ptr HomeLens::GetLensAtIndex(std::size_t index) const
+{
+ try
+ {
+ return pimpl->lenses_.at(index);
+ }
+ catch (std::out_of_range& error)
+ {
+ LOG_WARN(logger) << error.what();
+ }
+
+ return Lens::Ptr();
+}
+
+void HomeLens::GlobalSearch(std::string const& search_string)
+{
+ LOG_WARN(logger) << "Global search not enabled for HomeLens class."
+ << " Ignoring query '" << search_string << "'";
+}
+
+void HomeLens::Search(std::string const& search_string)
+{
+ LOG_DEBUG(logger) << "Search '" << search_string << "'";
+
+ /* Reset running search counter */
+ pimpl->running_searches_ = 0;
+
+ for (auto lens: pimpl->lenses_)
+ {
+ if (lens->search_in_global())
+ {
+ LOG_DEBUG(logger) << " - Global search on '" << lens->id() << "' for '"
+ << search_string << "'";
+ lens->view_type = ViewType::HOME_VIEW;
+ lens->GlobalSearch(search_string);
+ pimpl->running_searches_++;
+ }
+ }
+}
+
+void HomeLens::Activate(std::string const& uri)
+{
+ LOG_DEBUG(logger) << "Activate '" << uri << "'";
+
+ Lens::Ptr lens = pimpl->FindLensForUri(uri);
+
+ /* Fall back to default handling of URIs if no lens is found.
+ * - Although, this shouldn't really happen */
+ if (lens)
+ {
+ LOG_DEBUG(logger) << "Activation request passed to '" << lens->id() << "'";
+ lens->Activate(uri);
+ }
+ else
+ {
+ LOG_WARN(logger) << "Unable to find a lens for activating '" << uri
+ << "'. Using fallback activation.";
+ activated.emit(uri, HandledType::NOT_HANDLED, Hints());
+ }
+}
+
+void HomeLens::Preview(std::string const& uri)
+{
+ LOG_DEBUG(logger) << "Preview '" << uri << "'";
+
+ Lens::Ptr lens = pimpl->FindLensForUri(uri);
+
+ if (lens)
+ lens->Preview(uri);
+ else
+ LOG_WARN(logger) << "Unable to find a lens for previewing '" << uri << "'";
+}
+
+}
+}
diff --git a/UnityCore/HomeLens.h b/UnityCore/HomeLens.h
new file mode 100644
index 000000000..258318875
--- /dev/null
+++ b/UnityCore/HomeLens.h
@@ -0,0 +1,79 @@
+// -*- 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: Mikkel Kamstrup Erlandsen <mikkel.kamstrup@canonical.com>
+ */
+
+#ifndef UNITY_HOME_LENS_H
+#define UNITY_HOME_LENS_H
+
+#include <vector>
+#include <memory>
+#include <sigc++/signal.h>
+#include <sigc++/trackable.h>
+
+#include "Lenses.h"
+#include "Lens.h"
+
+namespace unity
+{
+namespace dash
+{
+
+/**
+ * A special Lens implementation that merges together a set of source Lens
+ * instances.
+ *
+ * NOTE: Changes in the filter models are currently not propagated back to the
+ * the source lenses. If we want to support filters on the dash home
+ * screen this needs to be addressed.
+ */
+class HomeLens : public Lens, public Lenses
+{
+public:
+ typedef std::shared_ptr<HomeLens> Ptr;
+
+ /**
+ * Should be constructed with i18n arguments:
+ * _("Home"), _("Home screen"), _("Search")
+ */
+ HomeLens(std::string const& name, std::string const& description, std::string const& search_hint);
+ virtual ~HomeLens();
+
+ void AddLenses(Lenses& lenses);
+
+ Lenses::LensList GetLenses() const;
+ Lens::Ptr GetLens(std::string const& lens_id) const;
+ Lens::Ptr GetLensAtIndex(std::size_t index) const;
+
+ void GlobalSearch(std::string const& search_string);
+ void Search(std::string const& search_string);
+ void Activate(std::string const& uri);
+ void Preview(std::string const& uri);
+
+private:
+ class Impl;
+ class ModelMerger;
+ class ResultsMerger;
+ class CategoryMerger;
+ class CategoryRegistry;
+ Impl* pimpl;
+};
+
+}
+}
+
+#endif
diff --git a/UnityCore/Lens.cpp b/UnityCore/Lens.cpp
index c3d75459a..b55f16ab4 100644
--- a/UnityCore/Lens.cpp
+++ b/UnityCore/Lens.cpp
@@ -51,11 +51,12 @@ public:
string const& description,
string const& search_hint,
bool visible,
- string const& shortcut);
+ string const& shortcut,
+ ModelType model_type);
~Impl();
- void OnProxyConnected();
+ void OnProxyConnectionChanged();
void OnProxyDisconnected();
void ResultsModelUpdated(unsigned long long begin_seqnum,
@@ -94,6 +95,7 @@ public:
string const& search_hint() const;
bool visible() const;
bool search_in_global() const;
+ bool set_search_in_global(bool val);
string const& shortcut() const;
Results::Ptr const& results() const;
Results::Ptr const& global_results() const;
@@ -121,7 +123,7 @@ public:
string private_connection_name_;
- glib::DBusProxy proxy_;
+ glib::DBusProxy* proxy_;
glib::Object<GCancellable> search_cancellable_;
glib::Object<GCancellable> global_search_cancellable_;
@@ -138,7 +140,8 @@ Lens::Impl::Impl(Lens* owner,
string const& description,
string const& search_hint,
bool visible,
- string const& shortcut)
+ string const& shortcut,
+ ModelType model_type)
: owner_(owner)
, id_(id)
, dbus_name_(dbus_name)
@@ -150,20 +153,46 @@ Lens::Impl::Impl(Lens* owner,
, visible_(visible)
, search_in_global_(false)
, shortcut_(shortcut)
- , results_(new Results())
- , global_results_(new Results())
- , categories_(new Categories())
- , filters_(new Filters())
+ , results_(new Results(model_type))
+ , global_results_(new Results(model_type))
+ , categories_(new Categories(model_type))
+ , filters_(new Filters(model_type))
, connected_(false)
- , proxy_(dbus_name, dbus_path, "com.canonical.Unity.Lens")
+ , proxy_(NULL)
, results_variant_(NULL)
, global_results_variant_(NULL)
{
- proxy_.connected.connect(sigc::mem_fun(this, &Lens::Impl::OnProxyConnected));
- proxy_.disconnected.connect(sigc::mem_fun(this, &Lens::Impl::OnProxyDisconnected));
- proxy_.Connect("Changed", sigc::mem_fun(this, &Lens::Impl::OnChanged));
+ if (model_type == ModelType::REMOTE)
+ {
+ proxy_ = new glib::DBusProxy(dbus_name, dbus_path, "com.canonical.Unity.Lens");
+ proxy_->connected.connect(sigc::mem_fun(this, &Lens::Impl::OnProxyConnectionChanged));
+ proxy_->disconnected.connect(sigc::mem_fun(this, &Lens::Impl::OnProxyDisconnected));
+ proxy_->Connect("Changed", sigc::mem_fun(this, &Lens::Impl::OnChanged));
+ }
+
+ /* Technically these signals will only be fired by remote models, but we
+ * connect them no matter the ModelType. Dee may grow support in the future.
+ */
results_->end_transaction.connect(sigc::mem_fun(this, &Lens::Impl::ResultsModelUpdated));
global_results_->end_transaction.connect(sigc::mem_fun(this, &Lens::Impl::GlobalResultsModelUpdated));
+
+ owner_->id.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::id));
+ owner_->dbus_name.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::dbus_name));
+ owner_->dbus_path.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::dbus_path));
+ owner_->name.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::name));
+ owner_->icon_hint.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::icon_hint));
+ owner_->description.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::description));
+ owner_->search_hint.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::search_hint));
+ owner_->visible.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::visible));
+ owner_->search_in_global.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::search_in_global));
+ owner_->search_in_global.SetSetterFunction(sigc::mem_fun(this, &Lens::Impl::set_search_in_global));
+ owner_->shortcut.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::shortcut));
+ owner_->results.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::results));
+ owner_->global_results.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::global_results));
+ owner_->categories.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::categories));
+ owner_->filters.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::filters));
+ owner_->connected.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::connected));
+ owner_->view_type.changed.connect(sigc::mem_fun(this, &Lens::Impl::OnViewTypeChanged));
}
Lens::Impl::~Impl()
@@ -176,13 +205,19 @@ Lens::Impl::~Impl()
{
g_cancellable_cancel (global_search_cancellable_);
}
+
+ if (proxy_)
+ delete proxy_;
}
-void Lens::Impl::OnProxyConnected()
+void Lens::Impl::OnProxyConnectionChanged()
{
- proxy_.Call("InfoRequest");
- ViewType current_view_type = owner_->view_type;
- proxy_.Call("SetViewType", g_variant_new("(u)", current_view_type));
+ if (proxy_->IsConnected())
+ {
+ proxy_->Call("InfoRequest");
+ ViewType current_view_type = owner_->view_type;
+ proxy_->Call("SetViewType", g_variant_new("(u)", current_view_type));
+ }
}
void Lens::Impl::OnProxyDisconnected()
@@ -387,12 +422,13 @@ void Lens::Impl::UpdateProperties(bool search_in_global,
void Lens::Impl::OnViewTypeChanged(ViewType view_type)
{
- proxy_.Call("SetViewType", g_variant_new("(u)", view_type));
+ if (proxy_ && proxy_->IsConnected())
+ proxy_->Call("SetViewType", g_variant_new("(u)", view_type));
}
void Lens::Impl::GlobalSearch(std::string const& search_string)
{
- LOG_DEBUG(logger) << "Global Searching " << id_ << " for " << search_string;
+ LOG_DEBUG(logger) << "Global Searching '" << id_ << "' for '" << search_string << "'";
GVariantBuilder b;
g_variant_builder_init(&b, G_VARIANT_TYPE("a{sv}"));
@@ -407,7 +443,7 @@ void Lens::Impl::GlobalSearch(std::string const& search_string)
global_results_variant_ = NULL;
}
- proxy_.Call("GlobalSearch",
+ proxy_->Call("GlobalSearch",
g_variant_new("(sa{sv})",
search_string.c_str(),
&b),
@@ -418,7 +454,13 @@ void Lens::Impl::GlobalSearch(std::string const& search_string)
void Lens::Impl::Search(std::string const& search_string)
{
- LOG_DEBUG(logger) << "Searching " << id_ << " for " << search_string;
+ LOG_DEBUG(logger) << "Searching '" << id_ << "' for '" << search_string << "'";
+
+ if (!proxy_->IsConnected())
+ {
+ LOG_DEBUG(logger) << "Skipping search. Proxy not connected. ('" << id_ << "')";
+ return;
+ }
GVariantBuilder b;
g_variant_builder_init(&b, G_VARIANT_TYPE("a{sv}"));
@@ -432,23 +474,29 @@ void Lens::Impl::Search(std::string const& search_string)
results_variant_ = NULL;
}
- proxy_.Call("Search",
- g_variant_new("(sa{sv})",
- search_string.c_str(),
- &b),
- sigc::mem_fun(this, &Lens::Impl::OnSearchFinished),
- search_cancellable_);
+ proxy_->Call("Search",
+ g_variant_new("(sa{sv})",
+ search_string.c_str(),
+ &b),
+ sigc::mem_fun(this, &Lens::Impl::OnSearchFinished),
+ search_cancellable_);
g_variant_builder_clear(&b);
}
void Lens::Impl::Activate(std::string const& uri)
{
- LOG_DEBUG(logger) << "Activating " << uri << " on " << id_;
+ LOG_DEBUG(logger) << "Activating '" << uri << "' on '" << id_ << "'";
+
+ if (!proxy_->IsConnected())
+ {
+ LOG_DEBUG(logger) << "Skipping activation. Proxy not connected. ('" << id_ << "')";
+ return;
+ }
- proxy_.Call("Activate",
- g_variant_new("(su)", uri.c_str(), 0),
- sigc::mem_fun(this, &Lens::Impl::ActivationReply));
+ proxy_->Call("Activate",
+ g_variant_new("(su)", uri.c_str(), 0),
+ sigc::mem_fun(this, &Lens::Impl::ActivationReply));
}
void Lens::Impl::ActivationReply(GVariant* parameters)
@@ -468,11 +516,17 @@ void Lens::Impl::ActivationReply(GVariant* parameters)
void Lens::Impl::Preview(std::string const& uri)
{
- LOG_DEBUG(logger) << "Previewing " << uri << " on " << id_;
+ LOG_DEBUG(logger) << "Previewing '" << uri << "' on '" << id_ << "'";
+
+ if (!proxy_->IsConnected())
+ {
+ LOG_DEBUG(logger) << "Skipping preview. Proxy not connected. ('" << id_ << "')";
+ return;
+ }
- proxy_.Call("Preview",
- g_variant_new("(s)", uri.c_str()),
- sigc::mem_fun(this, &Lens::Impl::PreviewReply));
+ proxy_->Call("Preview",
+ g_variant_new("(s)", uri.c_str()),
+ sigc::mem_fun(this, &Lens::Impl::PreviewReply));
}
void Lens::Impl::PreviewReply(GVariant* parameters)
@@ -535,6 +589,17 @@ bool Lens::Impl::search_in_global() const
return search_in_global_;
}
+bool Lens::Impl::set_search_in_global(bool val)
+{
+ if (search_in_global_ != val)
+ {
+ search_in_global_ = val;
+ owner_->search_in_global.EmitChanged(val);
+ }
+
+ return search_in_global_;
+}
+
string const& Lens::Impl::shortcut() const
{
return shortcut_;
@@ -584,25 +649,33 @@ Lens::Lens(string const& id_,
description_,
search_hint_,
visible_,
- shortcut_))
-{
- id.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::id));
- dbus_name.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::dbus_name));
- dbus_path.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::dbus_path));
- name.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::name));
- icon_hint.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::icon_hint));
- description.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::description));
- search_hint.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::search_hint));
- visible.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::visible));
- search_in_global.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::search_in_global));
- shortcut.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::shortcut));
- results.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::results));
- global_results.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::global_results));
- categories.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::categories));
- filters.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::filters));
- connected.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::connected));
- view_type.changed.connect(sigc::mem_fun(pimpl, &Lens::Impl::OnViewTypeChanged));
-}
+ shortcut_,
+ ModelType::REMOTE))
+{}
+
+Lens::Lens(string const& id_,
+ string const& dbus_name_,
+ string const& dbus_path_,
+ string const& name_,
+ string const& icon_hint_,
+ string const& description_,
+ string const& search_hint_,
+ bool visible_,
+ string const& shortcut_,
+ ModelType model_type)
+
+ : pimpl(new Impl(this,
+ id_,
+ dbus_name_,
+ dbus_path_,
+ name_,
+ icon_hint_,
+ description_,
+ search_hint_,
+ visible_,
+ shortcut_,
+ model_type))
+{}
Lens::~Lens()
{
diff --git a/UnityCore/Lens.h b/UnityCore/Lens.h
index cc145f7d9..886665211 100644
--- a/UnityCore/Lens.h
+++ b/UnityCore/Lens.h
@@ -67,12 +67,23 @@ public:
bool visible = true,
std::string const& shortcut = "");
- ~Lens();
-
- void GlobalSearch(std::string const& search_string);
- void Search(std::string const& search_string);
- void Activate(std::string const& uri);
- void Preview(std::string const& uri);
+ Lens(std::string const& id,
+ std::string const& dbus_name,
+ std::string const& dbus_path,
+ std::string const& name,
+ std::string const& icon,
+ std::string const& description,
+ std::string const& search_hint,
+ bool visible,
+ std::string const& shortcut,
+ ModelType model_type);
+
+ virtual ~Lens();
+
+ virtual void GlobalSearch(std::string const& search_string);
+ virtual void Search(std::string const& search_string);
+ virtual void Activate(std::string const& uri);
+ virtual void Preview(std::string const& uri);
nux::RWProperty<std::string> id;
nux::RWProperty<std::string> dbus_name;
diff --git a/UnityCore/Model-inl.h b/UnityCore/Model-inl.h
index 7991c477d..ee5b93895 100644
--- a/UnityCore/Model-inl.h
+++ b/UnityCore/Model-inl.h
@@ -34,10 +34,28 @@ nux::logging::Logger _model_inl_logger("unity.dash.model");
template<class RowAdaptor>
Model<RowAdaptor>::Model()
+ : model_type_(ModelType::REMOTE)
+{
+ Init();
+}
+
+template<class RowAdaptor>
+Model<RowAdaptor>::Model (ModelType model_type)
+ : model_type_(model_type)
+{
+ Init();
+
+ if (model_type == ModelType::LOCAL)
+ swarm_name = ":local";
+}
+
+template<class RowAdaptor>
+void Model<RowAdaptor>::Init ()
{
swarm_name.changed.connect(sigc::mem_fun(this, &Model<RowAdaptor>::OnSwarmNameChanged));
count.SetGetterFunction(sigc::mem_fun(this, &Model<RowAdaptor>::get_count));
seqnum.SetGetterFunction(sigc::mem_fun(this, &Model<RowAdaptor>::get_seqnum));
+ model.SetGetterFunction(sigc::mem_fun(this, &Model<RowAdaptor>::get_model));
}
template<class RowAdaptor>
@@ -52,7 +70,29 @@ void Model<RowAdaptor>::OnSwarmNameChanged(std::string const& swarm_name)
if (model_)
dee_model_clear(model_);
- model_ = dee_shared_model_new(swarm_name.c_str());
+ switch(model_type_)
+ {
+ case ModelType::LOCAL:
+ model_ = dee_sequence_model_new();
+ break;
+ case ModelType::REMOTE:
+ model_ = dee_shared_model_new(swarm_name.c_str());
+ sig_manager_.Add(new TransactionSignalType(model_,
+ "begin-transaction",
+ sigc::mem_fun(this, &Model<RowAdaptor>::OnTransactionBegin)));
+
+ sig_manager_.Add(new TransactionSignalType(model_,
+ "end-transaction",
+ sigc::mem_fun(this, &Model<RowAdaptor>::OnTransactionEnd)));
+ break;
+ default:
+ LOG_ERROR(_model_inl_logger) << "Unexpected ModelType " << model_type_;
+ break;
+ }
+
+ model.EmitChanged(model_);
+
+
renderer_tag_ = dee_model_register_tag(model_, NULL);
sig_manager_.Add(new RowSignalType(model_,
@@ -66,14 +106,6 @@ void Model<RowAdaptor>::OnSwarmNameChanged(std::string const& swarm_name)
sig_manager_.Add(new RowSignalType(model_,
"row-removed",
sigc::mem_fun(this, &Model<RowAdaptor>::OnRowRemoved)));
-
- sig_manager_.Add(new TransactionSignalType(model_,
- "begin-transaction",
- sigc::mem_fun(this, &Model<RowAdaptor>::OnTransactionBegin)));
-
- sig_manager_.Add(new TransactionSignalType(model_,
- "end-transaction",
- sigc::mem_fun(this, &Model<RowAdaptor>::OnTransactionEnd)));
}
template<class RowAdaptor>
@@ -148,6 +180,12 @@ unsigned long long Model<RowAdaptor>::get_seqnum()
return 0;
}
+template<class RowAdaptor>
+glib::Object<DeeModel> Model<RowAdaptor>::get_model()
+{
+ return model_;
+}
+
}
}
diff --git a/UnityCore/Model.h b/UnityCore/Model.h
index f7f436094..8eb4d14b2 100644
--- a/UnityCore/Model.h
+++ b/UnityCore/Model.h
@@ -35,6 +35,12 @@ namespace unity
namespace dash
{
+enum ModelType
+{
+ REMOTE,
+ LOCAL
+};
+
/* This template class encapsulates the basics of talking to a DeeSharedModel,
* however it is a template as you can choose your own RowAdaptor (see
* ResultsRowAdaptor.h for an example) which then presents the data in the rows
@@ -47,6 +53,7 @@ public:
typedef std::shared_ptr<Model> Ptr;
Model();
+ Model (ModelType model_type);
virtual ~Model();
const RowAdaptor RowAtIndex(std::size_t index);
@@ -54,6 +61,7 @@ public:
nux::Property<std::string> swarm_name;
nux::ROProperty<std::size_t> count;
nux::ROProperty<unsigned long long> seqnum;
+ nux::ROProperty<glib::Object<DeeModel>> model;
sigc::signal<void, RowAdaptor&> row_added;
sigc::signal<void, RowAdaptor&> row_changed;
@@ -63,6 +71,7 @@ public:
sigc::signal<void, unsigned long long, unsigned long long> end_transaction;
private:
+ void Init();
void OnRowAdded(DeeModel* model, DeeModelIter* iter);
void OnRowChanged(DeeModel* model, DeeModelIter* iter);
void OnRowRemoved(DeeModel* model, DeeModelIter* iter);
@@ -71,11 +80,13 @@ private:
void OnSwarmNameChanged(std::string const& swarm_name);
std::size_t get_count();
unsigned long long get_seqnum();
+ glib::Object<DeeModel> get_model();
private:
glib::Object<DeeModel> model_;
glib::SignalManager sig_manager_;
DeeModelTag* renderer_tag_;
+ ModelType model_type_;
};
}
diff --git a/UnityCore/Results.cpp b/UnityCore/Results.cpp
index d59302c4e..b38c8e77e 100644
--- a/UnityCore/Results.cpp
+++ b/UnityCore/Results.cpp
@@ -31,6 +31,14 @@ Results::Results()
row_removed.connect(sigc::mem_fun(this, &Results::OnRowRemoved));
}
+Results::Results(ModelType model_type)
+ : Model<Result>::Model(model_type)
+{
+ row_added.connect(sigc::mem_fun(this, &Results::OnRowAdded));
+ row_changed.connect(sigc::mem_fun(this, &Results::OnRowChanged));
+ row_removed.connect(sigc::mem_fun(this, &Results::OnRowRemoved));
+}
+
void Results::OnRowAdded(Result& result)
{
result_added.emit(result);
diff --git a/UnityCore/Results.h b/UnityCore/Results.h
index a6d48e4a8..ca98b9b95 100644
--- a/UnityCore/Results.h
+++ b/UnityCore/Results.h
@@ -36,6 +36,7 @@ public:
typedef std::shared_ptr<Results> Ptr;
Results();
+ Results(ModelType model_type);
sigc::signal<void, Result const&> result_added;
sigc::signal<void, Result const&> result_changed;
diff --git a/com.canonical.Unity.gschema.xml b/com.canonical.Unity.gschema.xml
index 6aa7f3058..bb783b7d6 100644
--- a/com.canonical.Unity.gschema.xml
+++ b/com.canonical.Unity.gschema.xml
@@ -21,7 +21,7 @@
<description>Whether the home screen should be expanded.</description>
</key>
</schema>
- <schema path="/desktop/unity/launcher/" id="com.canonical.Unity.Launcher" gettext-domain="unity">
+ <schema path="/desktop/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>
@@ -33,7 +33,7 @@
<description>This is a detection key for the favorite migration script to know whether the needed migration is done or not.</description>
</key>
</schema>
- <schema path="/desktop/unity/panel/" id="com.canonical.Unity.Panel" gettext-domain="unity">
+ <schema path="/desktop/unity/panel/" id="com.canonical.Unity.Panel" gettext-domain="unity">
<key type="as" name="systray-whitelist">
<default>[ 'JavaEmbeddedFrame', 'Wine', 'scp-dbus-service', 'Update-notifier' ]</default>
<summary>List of client names, resource classes or wm classes to allow in the Panel's systray implementation.</summary>
@@ -46,5 +46,12 @@
<summary>List of device uuid for favorites on the launcher.</summary>
<description>These devices are shown in the Launcher by default.</description>
</key>
- </schema>
+ </schema>
+ <schema path="/desktop/unity/dash/" id="com.canonical.Unity.Dash" gettext-domain="unity">
+ <key type="as" name="home-lens-ordering">
+ <default>[ 'applications.lens', 'files.lens', 'music.lens' ]</default>
+ <summary>List of lens ids specifying how lenses should be ordered in the Dash home screen.</summary>
+ <description>The categories listed on the Dash home screen will be ordered according to this list. Lenses not appearing in this list will not have any particular ordering and will always sort after lenses specified in this list.</description>
+ </key>
+ </schema>
</schemalist>
diff --git a/manual-tests/AutoMaximize.txt b/manual-tests/AutoMaximize.txt
new file mode 100644
index 000000000..dc375888c
--- /dev/null
+++ b/manual-tests/AutoMaximize.txt
@@ -0,0 +1,19 @@
+auto-maximize window
+=======================
+Thit test make sure that the auto-maximize window feature is disabled for
+resolution above the 1024x600.
+
+- Open the display panel
+- Set a resolution greater then 1024x600 (e.g 1366x768)
+- Open a window, that usually doesn't start maximized
+
+Outcome
+The window should not be in the maximized state.
+
+- Open the display panel
+- Set a resolution lower or equal to 1024x600.
+- Open the ccsm and change the automaximize-threshold option to 20 (experimental-tab of unity-plugin).
+- Open nautilus, that usually doesn't start maximized
+
+Outcome
+The window should be in the maximized state.
diff --git a/manual-tests/Dash.txt b/manual-tests/Dash.txt
index 7869d8d3c..116defd76 100644
--- a/manual-tests/Dash.txt
+++ b/manual-tests/Dash.txt
@@ -36,3 +36,18 @@ Outcome
The dropped icon should not have the keyboard focus and should not remain
enlightened.
+Dash SearchBar middle-click
+---------------------------
+This test shows how the middle click over the dash search bar should work
+(see lp:842462)
+
+#. Open a text editor, and write some dummy text
+#. Select some text part of the written dummy text with mouse
+#. Press Super or Alt+F2 to open the Dash
+#. Move the mouse over the dash search bar
+#. Press middle click to paste the content of your primary clipboard
+
+Outcome
+ The text previously selected is pasted on the search bar at mouse pointer
+ position, if the operation is repeated the text is inserted where
+ the mouse pointer is.
diff --git a/manual-tests/Launcher.txt b/manual-tests/Launcher.txt
new file mode 100644
index 000000000..bfafa408b
--- /dev/null
+++ b/manual-tests/Launcher.txt
@@ -0,0 +1,40 @@
+Test Launcher Icon with Windows in multiple workspaces
+------------------------------------------------------
+This test shows how the launcher should draw when there are application windows
+in multiple workspaces.
+
+#. Start on a fresh login
+#. Run an application
+#. Run another instance of this application and keep it on the initial workspace
+#. Run another instance of this application and move it no another workspaces
+#. Go back to the initial workspace
+
+Outcome
+ The Launcher icon "pips" should reflect the number of windows in the current
+ workspace, so when showing the "initial" workspace the launcher icon should
+ have 2 "pips", when moving to the second workspace (where there's only 1 window)
+ the launcher application icon should show 1 pip.
+ When moving to a workspace where there are no windows, the launcher icon should
+ use an empty arrow as left indicator.
+
+
+Test Launcher Spread with Windows in multiple workspaces
+--------------------------------------------------------
+This test shows how the launcher should spread the windows when they are in
+multiple workspaces.
+
+#. Start on a fresh login
+#. Run an application
+#. Run another instance of this application and keep it on the initial workspace
+#. Run another instance of this application and move it no another workspaces
+#. Go back to the initial workspace and focus the application windows
+
+Outcome
+ When in the current workspace there are multiple windows of the same
+ application and one of them is focused, clicking on the launcher should spread
+ only the windows that are in the current workspace.
+ If in the current workspace there is just one window, clicking on the launcher
+ icon should only focus it and nothing else (also with multiple clicks).
+ When moving to a workspace where there are no window o the given application,
+ clicking on its launcher icon should bring to focus the last focused window
+ in the last used workspace.
diff --git a/manual-tests/SuperTab.txt b/manual-tests/SuperTab.txt
index 5ab409083..95d512194 100644
--- a/manual-tests/SuperTab.txt
+++ b/manual-tests/SuperTab.txt
@@ -20,3 +20,58 @@ Outcome:
If in the launcher there are many icons and they are shown as collapsed,
when the Super+Tab is activated and the icons should be expanded when
neeeded.
+
+Super Tab switcher interaction with Shortcut Hint
+-------------------------------------------------
+This test shows the interaction between the shortcut hint overlay and the
+Super+Tab switcher.
+
+#. Start with a clean screen
+#. Press Super to make the shortcuts-overlay to show
+#. Then press Tab to initiate the Super+Tab launcher switcher
+
+Outcome:
+ The Super+Tab switcher is initialized, and the shortcut hint overlay is still
+ showing. Pressing also Shift to reverse the switcher direction doesn't hide
+ the overlay, that will be hidden once Super is released.
+
+#. Start with a clean screen
+#. Press Super+Tab quickly to make the launcher switcher to initialize without
+ making the shortcut overlay to show.
+
+Outcome:
+ Super+Tab switcher is initialized and the shortcut hint overlay is not shown
+ even keeping only super pressed until releasing it and pressing it again.
+
+Super Tab switcher cycling over launcher applications
+-----------------------------------------------------
+This test shows how the Super+Tab switcher should use a circular selection.
+
+#. Start with a clean screen
+#. Press Super+Tab multiple times to make the selection to reach the bottom
+ launcher icon
+#. Press Tab again
+
+Outcome:
+ The selection should go from the last launcher icon, to the first one.
+ The launcher view should be expanded/moved if needed to show the highlighted item.
+
+#. Start with a clean screen
+#. Press Super+Tab once to make the first launcher icon to highlight
+#. Press Shift+Tab while keeping Super pressed
+
+Outcome:
+ The selection should go from the first launcher icon to the last one.
+ The launcher view should be expanded/moved if needed to show the highlighted item.
+
+Escaping from Super Tab switcher
+--------------------------------
+This test shows how to escape from the Super+Tab switcher.
+
+#. Start with a clean screen
+#. Press Super+Tab one or more times to make the launcher switcher to initialize
+#. Press the Escape key when still pressing Super
+
+Outcome:
+ The Super Tab launcher switcher should terminate without performing any action
+ The previously selected launcher item should be deselected.
diff --git a/plugins/unity-mt-grab-handles/src/unity-mt-grab-handles.cpp b/plugins/unity-mt-grab-handles/src/unity-mt-grab-handles.cpp
index ce5792da1..c17ad2d0f 100644
--- a/plugins/unity-mt-grab-handles/src/unity-mt-grab-handles.cpp
+++ b/plugins/unity-mt-grab-handles/src/unity-mt-grab-handles.cpp
@@ -438,13 +438,21 @@ UnityMTGrabHandlesWindow::getOutputExtents(CompWindowExtents& output)
bool
UnityMTGrabHandlesWindow::glDraw(const GLMatrix& transform,
+#ifdef USE_GLES
+ const GLWindowPaintAttrib& attrib,
+#else
GLFragment::Attrib& fragment,
+#endif
const CompRegion& region,
unsigned int mask)
{
/* Draw the window on the bottom, we will be drawing the
* handles on top */
+#ifdef USE_GLES
+ bool status = gWindow->glDraw(transform, attrib, region, mask);
+#else
bool status = gWindow->glDraw(transform, fragment, region, mask);
+#endif
if (mHandles && mHandles->visible())
{
@@ -464,10 +472,17 @@ UnityMTGrabHandlesWindow::glDraw(const GLMatrix& transform,
GLTexture::MatrixList matl;
GLTexture::Matrix mat = tex->matrix();
CompRegion paintRegion(region);
+#ifdef USE_GLES
+ GLWindowPaintAttrib wAttrib(attrib);
+#endif
/* We can reset the window geometry since it will be
* re-added later */
+#ifdef USE_GLES
+ gWindow->vertexBuffer()->begin();
+#else
gWindow->geometry().reset();
+#endif
/* Not sure what this does, but it is necessary
* (adjusts for scale?) */
@@ -483,23 +498,35 @@ UnityMTGrabHandlesWindow::glDraw(const GLMatrix& transform,
* dim (so we get a nice render for things like
* wobbly etc etc */
gWindow->glAddGeometry(matl, reg, paintRegion);
-
+#ifdef USE_GLES
+ gWindow->vertexBuffer()->end();
+ wAttrib.opacity = mHandles->opacity();
+#else
/* Did it succeed? */
if (gWindow->geometry().vertices)
{
fragment.setOpacity(mHandles->opacity());
/* Texture rendering set-up */
us->gScreen->setTexEnvMode(GL_MODULATE);
+#endif
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
/* Draw the dim texture with all of it's modified
* geometry glory */
- gWindow->glDrawTexture(tex, fragment, mask | PAINT_WINDOW_BLEND_MASK
+ gWindow->glDrawTexture(tex,
+#ifdef USE_GLES
+ transform, wAttrib,
+#else
+ fragment,
+#endif
+ mask | PAINT_WINDOW_BLEND_MASK
| PAINT_WINDOW_TRANSLUCENT_MASK |
PAINT_WINDOW_TRANSFORMED_MASK);
/* Texture rendering tear-down */
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+#ifndef USE_GLES
us->gScreen->setTexEnvMode(GL_REPLACE);
}
+#endif
}
handle++;
diff --git a/plugins/unity-mt-grab-handles/src/unity-mt-grab-handles.h b/plugins/unity-mt-grab-handles/src/unity-mt-grab-handles.h
index e10568ce0..a5a4e362e 100644
--- a/plugins/unity-mt-grab-handles/src/unity-mt-grab-handles.h
+++ b/plugins/unity-mt-grab-handles/src/unity-mt-grab-handles.h
@@ -229,7 +229,11 @@ public:
void moveNotify(int dx, int dy, bool immediate);
bool glDraw(const GLMatrix&,
+#ifdef USE_GLES
+ const GLWindowPaintAttrib&,
+#else
GLFragment::Attrib&,
+#endif
const CompRegion&,
unsigned int);
diff --git a/plugins/unitydialog/src/unitydialog.cpp b/plugins/unitydialog/src/unitydialog.cpp
index f2423fe90..300b8e19f 100644
--- a/plugins/unitydialog/src/unitydialog.cpp
+++ b/plugins/unitydialog/src/unitydialog.cpp
@@ -420,7 +420,12 @@ UnityDialogWindow::glAddGeometry(const GLTexture::MatrixList& matrices,
/* Collect textures */
void
UnityDialogWindow::glDrawTexture(GLTexture* texture,
+#ifdef USE_GLES
+ const GLMatrix &transform,
+ const GLWindowPaintAttrib &attrib,
+#else
GLFragment::Attrib& fa,
+#endif
unsigned int mask)
{
unity::PaintInfoCollector::Active ()->processTexture (texture);
@@ -448,7 +453,11 @@ unity::GeometryCollection::addGeometryForWindow (CompWindow *w, const CompRegion
{
/* We can reset the window geometry since it will be
* re-added later */
+#ifdef USE_GLES
+ GLWindow::get (w)->vertexBuffer()->begin();
+#else
GLWindow::get (w)->geometry().reset();
+#endif
for (unsigned int i = 0; i < collectedMatrixLists.size (); i++)
{
@@ -462,6 +471,10 @@ unity::GeometryCollection::addGeometryForWindow (CompWindow *w, const CompRegion
* wobbly etc etc */
GLWindow::get (w)->glAddGeometry(matl, reg, paintRegion, min, max);
}
+
+#ifdef USE_GLES
+ GLWindow::get (w)->vertexBuffer()->end();
+#endif
}
void
@@ -497,7 +510,11 @@ unity::TexGeometryCollection::setTexture (GLTexture *tex)
}
void
-unity::TexGeometryCollection::addGeometriesAndDrawTextureForWindow(CompWindow *w, unsigned int mask)
+unity::TexGeometryCollection::addGeometriesAndDrawTextureForWindow(CompWindow *w,
+#ifdef USE_GLES
+ const GLMatrix &transform,
+#endif
+ unsigned int mask)
{
if (mTexture && mGeometries.status ())
{
@@ -509,6 +526,25 @@ unity::TexGeometryCollection::addGeometriesAndDrawTextureForWindow(CompWindow *w
mGeometries.addGeometryForWindow (w, paintRegion);
+#ifdef USE_GLES
+ UnityDialogScreen *uds = UnityDialogScreen::get (screen);
+ GLWindowPaintAttrib attrib (gWindow->lastPaintAttrib());
+ unsigned int glDrawTextureIndex = gWindow->glDrawTextureGetCurrentIndex();
+ /* Texture rendering set-up */
+// uds->gScreen->setTexEnvMode(GL_MODULATE);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ /* Draw the dim texture with all of it's modified
+ * geometry glory */
+ gWindow->glDrawTextureSetCurrentIndex(MAXSHORT);
+ gWindow->glDrawTexture(mTexture, transform, attrib, mask
+ | PAINT_WINDOW_BLEND_MASK
+ | PAINT_WINDOW_TRANSLUCENT_MASK
+ | PAINT_WINDOW_TRANSFORMED_MASK);
+ gWindow->glDrawTextureSetCurrentIndex(glDrawTextureIndex);
+ /* Texture rendering tear-down */
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ uds->gScreen->setTexEnvMode(GL_REPLACE);
+#else
if (gWindow->geometry().vertices)
{
UnityDialogScreen *uds = UnityDialogScreen::get (screen);
@@ -528,6 +564,7 @@ unity::TexGeometryCollection::addGeometriesAndDrawTextureForWindow(CompWindow *w
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
uds->gScreen->setTexEnvMode(GL_REPLACE);
}
+#endif
}
}
@@ -581,10 +618,18 @@ unity::PaintInfoCollector::processTexture (GLTexture *tex)
}
void
-unity::PaintInfoCollector::drawGeometriesForWindow(CompWindow *w, unsigned int pm)
+unity::PaintInfoCollector::drawGeometriesForWindow(CompWindow *w,
+#ifdef USE_GLES
+ const GLMatrix &transform,
+#endif
+ unsigned int pm)
{
for (unity::TexGeometryCollection &tcg : mCollection)
+#if USE_GLES
+ tcg.addGeometriesAndDrawTextureForWindow (w, transform, pm);
+#else
tcg.addGeometriesAndDrawTextureForWindow (w, pm);
+#endif
}
unity::PaintInfoCollector * unity::PaintInfoCollector::active_collector = NULL;
@@ -599,7 +644,11 @@ unity::PaintInfoCollector::Active ()
bool
UnityDialogWindow::glDraw(const GLMatrix& transform,
+#ifdef USE_GLES
+ const GLWindowPaintAttrib& attrib,
+#else
GLFragment::Attrib& fragment,
+#endif
const CompRegion& region,
unsigned int mask)
{
@@ -610,7 +659,13 @@ UnityDialogWindow::glDraw(const GLMatrix& transform,
/* Draw the window on the bottom, we will be drawing the
* dim render on top */
- bool status = gWindow->glDraw(transform, fragment, region, mask);
+ bool status = gWindow->glDraw(transform,
+#ifdef USE_GLES
+ attrib,
+#else
+ fragment,
+#endif
+ region, mask);
UNITY_DIALOG_SCREEN(screen);
@@ -618,10 +673,17 @@ UnityDialogWindow::glDraw(const GLMatrix& transform,
{
GLTexture::MatrixList matl;
GLTexture::Matrix mat = tex->matrix();
+#ifdef USE_GLES
+ GLWindowPaintAttrib wAttrib(attrib);
+#endif
/* We can reset the window geometry since it will be
* re-added later */
+#ifdef USE_GLES
+ gWindow->vertexBuffer()->begin();
+#else
gWindow->geometry().reset();
+#endif
/* Scale the dim render by the ratio of dim size
* to window size */
@@ -642,7 +704,28 @@ UnityDialogWindow::glDraw(const GLMatrix& transform,
* dim (so we get a nice render for things like
* wobbly etc etc */
gWindow->glAddGeometry(matl, reg, paintRegion);
-
+#ifdef USE_GLES
+ gWindow->vertexBuffer()->end();
+#endif
+
+#ifdef USE_GLES
+ unsigned int glDrawTextureIndex = gWindow->glDrawTextureGetCurrentIndex();
+ wAttrib.opacity = mShadeProgress;
+ /* Texture rendering set-up */
+// uds->gScreen->setTexEnvMode(GL_MODULATE);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ /* Draw the dim texture with all of it's modified
+ * geometry glory */
+ gWindow->glDrawTextureSetCurrentIndex(MAXSHORT);
+ gWindow->glDrawTexture(tex, transform, attrib, mask
+ | PAINT_WINDOW_BLEND_MASK
+ | PAINT_WINDOW_TRANSLUCENT_MASK
+ | PAINT_WINDOW_TRANSFORMED_MASK);
+ gWindow->glDrawTextureSetCurrentIndex(glDrawTextureIndex);
+ /* Texture rendering tear-down */
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ uds->gScreen->setTexEnvMode(GL_REPLACE);
+#else
/* Did it succeed? */
if (gWindow->geometry().vertices)
{
@@ -662,6 +745,7 @@ UnityDialogWindow::glDraw(const GLMatrix& transform,
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
uds->gScreen->setTexEnvMode(GL_REPLACE);
}
+#endif
}
for (CompWindow* w : mTransients)
@@ -674,7 +758,11 @@ UnityDialogWindow::glDraw(const GLMatrix& transform,
unity::PaintInfoCollector pc (w);
pc.collect();
- pc.drawGeometriesForWindow (window, mask);
+ pc.drawGeometriesForWindow (window,
+#ifdef USE_GLES
+ transform,
+#endif
+ mask);
}
}
diff --git a/plugins/unitydialog/src/unitydialog.h b/plugins/unitydialog/src/unitydialog.h
index c57a99b5c..be3d785ac 100644
--- a/plugins/unitydialog/src/unitydialog.h
+++ b/plugins/unitydialog/src/unitydialog.h
@@ -64,7 +64,13 @@ namespace unity
int max);
void setTexture (GLTexture *);
+#ifdef USE_GLES
+ void addGeometriesAndDrawTextureForWindow (CompWindow *w,
+ const GLMatrix &transform,
+ unsigned int mask);
+#else
void addGeometriesAndDrawTextureForWindow (CompWindow *, unsigned int pm);
+#endif
private:
GLTexture* mTexture;
@@ -78,7 +84,13 @@ namespace unity
PaintInfoCollector (CompWindow *w);
void collect ();
+#ifdef USE_GLES
+ void drawGeometriesForWindow (CompWindow *w,
+ const GLMatrix &transform,
+ unsigned int pm);
+#else
void drawGeometriesForWindow (CompWindow *w, unsigned int pm);
+#endif
void processGeometry (const GLTexture::MatrixList &ml,
const CompRegion &r,
@@ -242,7 +254,12 @@ public:
public:
bool
- glDraw(const GLMatrix&, GLFragment::Attrib&,
+ glDraw(const GLMatrix&,
+#ifdef USE_GLES
+ const GLWindowPaintAttrib&,
+#else
+ GLFragment::Attrib&,
+#endif
const CompRegion&, unsigned int);
bool
@@ -258,7 +275,12 @@ public:
void
glDrawTexture(GLTexture* texture,
+#ifdef USE_GLES
+ const GLMatrix& transform,
+ const GLWindowPaintAttrib& attrib,
+#else
GLFragment::Attrib& attrib,
+#endif
unsigned int mask);
diff --git a/plugins/unityshell/resources/dash-widgets.json b/plugins/unityshell/resources/dash-widgets.json
index 86f60fdf0..11da04b10 100644
--- a/plugins/unityshell/resources/dash-widgets.json
+++ b/plugins/unityshell/resources/dash-widgets.json
@@ -40,14 +40,14 @@
"icon-gap" : 40},
"button-label": {
- "border-opacity" : [ 1.0, 0.15, 0.15, 0.15, 0.15],
+ "border-opacity" : [ 0.8, 0.13, 0.13, 0.13, 0.13],
"border-color" : ["#ffffff", "#FFFFFF", "#FFFFFF", "#FFFFFF", "#FFFFFF"],
"border-size" : [ 2.0, 1.0, 1.0, 0.5, 0.5],
"text-size" : 1.0,
"text-color" : ["#ffffff", "#ffffff", "#ffffff", "#ffffff", "#ffffff"],
"text-opacity" : [ 1.0, 1.0, 1.0, 1.0, 1.0],
"fill-color" : ["#FFFFFF", "#000000", "#000000", "#000000", "#000000"],
- "fill-opacity" : [ 0.15, 0.0, 0.0, 0.0, 0.0],
+ "fill-opacity" : [ 0.13, 0.0, 0.0, 0.0, 0.0],
"overlay-opacity": [ 0.1, 0.1, 0.1, 0.0, 0.0],
"overlay-mode" : [ "normal", "normal", "normal", "normal", "normal"],
"blur-size" : [ 1, 1, 1, 0, 0]},
diff --git a/plugins/unityshell/src/BamfLauncherIcon.cpp b/plugins/unityshell/src/BamfLauncherIcon.cpp
index 8620de8b3..fa4f007fb 100644
--- a/plugins/unityshell/src/BamfLauncherIcon.cpp
+++ b/plugins/unityshell/src/BamfLauncherIcon.cpp
@@ -142,7 +142,7 @@ void BamfLauncherIcon::ActivateLauncherIcon(ActionArg arg)
{
if (arg.source != ActionArg::SWITCHER)
{
- Spread(0, false);
+ Spread(true, 0, false);
}
}
}
@@ -153,7 +153,7 @@ void BamfLauncherIcon::ActivateLauncherIcon(ActionArg arg)
WindowManager::Default()->TerminateScale();
Focus(arg);
if (arg.source != ActionArg::SWITCHER)
- Spread(0, false);
+ Spread(true, 0, false);
}
else // #3 above
{
@@ -213,8 +213,8 @@ BamfLauncherIcon::BamfLauncherIcon(Launcher* IconManager, BamfApplication* app)
WindowManager::Default()->window_minimized.connect(sigc::mem_fun(this, &BamfLauncherIcon::OnWindowMinimized));
WindowManager::Default()->window_moved.connect(sigc::mem_fun(this, &BamfLauncherIcon::OnWindowMoved));
- WindowManager::Default()->compiz_screen_viewport_switch_ended.connect(sigc::mem_fun(this, &BamfLauncherIcon::OnViewPortSwitchEnded));
- WindowManager::Default()->terminate_expo.connect(sigc::mem_fun(this, &BamfLauncherIcon::OnViewPortSwitchEnded));
+ WindowManager::Default()->compiz_screen_viewport_switch_ended.connect(sigc::mem_fun(this, &BamfLauncherIcon::EnsureWindowState));
+ WindowManager::Default()->terminate_expo.connect(sigc::mem_fun(this, &BamfLauncherIcon::EnsureWindowState));
IconManager->hidden_changed.connect(sigc::mem_fun(this, &BamfLauncherIcon::OnLauncherHiddenChanged));
// hack
@@ -323,9 +323,7 @@ std::string BamfLauncherIcon::NameForWindow (Window window)
view = static_cast <BamfView*> (l->data);
if (BAMF_IS_WINDOW(view) && (Window) bamf_window_get_xid(BAMF_WINDOW(view)) == window)
{
- gchar *name = bamf_view_get_name (view);
- result = name;
- g_free (name);
+ result = glib::String(bamf_view_get_name(view)).Str();
break;
}
}
@@ -348,40 +346,6 @@ void BamfLauncherIcon::OnWindowMinimized(guint32 xid)
UpdateQuirkTimeDelayed(300, QUIRK_SHIMMER);
}
-gboolean BamfLauncherIcon::OnWindowMovedTimeout(gpointer data)
-{
- BamfLauncherIcon *self = static_cast <BamfLauncherIcon *> (data);
- GList *children = bamf_view_get_children(BAMF_VIEW(self->m_App));
-
- bool any_on_current = false;
- bool found_moved = (self->_window_moved_xid != 0 ? false : true);
-
- for (GList *l = children; l; l = l->next)
- {
- BamfView *view = BAMF_VIEW(l->data);
-
- if (BAMF_IS_WINDOW(view))
- {
- Window xid = bamf_window_get_xid(BAMF_WINDOW(view));
-
- if (self->_window_moved_xid == xid)
- found_moved = true;
-
- if (WindowManager::Default()->IsWindowOnCurrentDesktop(xid))
- any_on_current = true;
-
- if (found_moved && any_on_current)
- break;
- }
- }
-
- self->SetHasWindowOnViewport(any_on_current);
- self->_window_moved_id = 0;
- g_list_free(children);
-
- return FALSE;
-}
-
void BamfLauncherIcon::OnWindowMoved(guint32 moved_win)
{
if (_window_moved_id != 0)
@@ -389,20 +353,13 @@ void BamfLauncherIcon::OnWindowMoved(guint32 moved_win)
_window_moved_xid = moved_win;
- if (_window_moved_xid == 0)
+ _window_moved_id = g_timeout_add(250, [] (gpointer data) -> gboolean
{
- OnWindowMovedTimeout(this);
- }
- else
- {
- _window_moved_id = g_timeout_add(250,
- (GSourceFunc)BamfLauncherIcon::OnWindowMovedTimeout, this);
- }
-}
-
-void BamfLauncherIcon::OnViewPortSwitchEnded()
-{
- OnWindowMoved(0);
+ BamfLauncherIcon* self = static_cast<BamfLauncherIcon*>(data);
+ self->EnsureWindowState();
+ self->_window_moved_id = 0;
+ return FALSE;
+ }, this);
}
bool BamfLauncherIcon::IsSticky()
@@ -652,11 +609,12 @@ void BamfLauncherIcon::Focus(ActionArg arg)
}
}
-bool BamfLauncherIcon::Spread(int state, bool force)
+bool BamfLauncherIcon::Spread(bool current_desktop, int state, bool force)
{
BamfView* view;
GList* children, *l;
children = bamf_view_get_children(BAMF_VIEW(m_App));
+ WindowManager* wm = WindowManager::Default();
std::vector<Window> windowList;
for (l = children; l; l = l->next)
@@ -666,7 +624,11 @@ bool BamfLauncherIcon::Spread(int state, bool force)
if (BAMF_IS_WINDOW(view))
{
guint32 xid = bamf_window_get_xid(BAMF_WINDOW(view));
- windowList.push_back((Window) xid);
+
+ if (!current_desktop || (current_desktop && wm->IsWindowOnCurrentDesktop(xid)))
+ {
+ windowList.push_back((Window) xid);
+ }
}
}
@@ -719,9 +681,9 @@ void BamfLauncherIcon::OnUrgentChanged(BamfView* view, gboolean urgent, gpointer
void BamfLauncherIcon::EnsureWindowState()
{
GList* children, *l;
- unsigned int children_count = 0;
+ bool has_win_on_current_vp = false;
unsigned int user_visible_count = 0;
- bool has_visible = false;
+ unsigned int children_count = 0;
children = bamf_view_get_children(BAMF_VIEW(m_App));
for (l = children; l; l = l->next)
@@ -729,16 +691,15 @@ void BamfLauncherIcon::EnsureWindowState()
if (!BAMF_IS_WINDOW(l->data))
continue;
- if (!has_visible)
+ Window xid = bamf_window_get_xid(BAMF_WINDOW(l->data));
+ if (WindowManager::Default()->IsWindowOnCurrentDesktop(xid))
{
- Window xid = bamf_window_get_xid(BAMF_WINDOW(l->data));
- if (WindowManager::Default()->IsWindowOnCurrentDesktop(xid))
- has_visible = true;
- }
+ has_win_on_current_vp = true;
- if (bamf_view_user_visible (BAMF_VIEW (l->data)))
- {
- user_visible_count++;
+ if (bamf_view_user_visible (BAMF_VIEW (l->data)))
+ {
+ user_visible_count++;
+ }
}
children_count++;
@@ -753,7 +714,7 @@ void BamfLauncherIcon::EnsureWindowState()
SetRelatedWindows(1);
}
- SetHasWindowOnViewport(has_visible);
+ SetHasWindowOnViewport(has_win_on_current_vp);
g_list_free(children);
}
@@ -910,7 +871,7 @@ void BamfLauncherIcon::Quit()
g_list_free(children);
}
-void BamfLauncherIcon::Stick()
+void BamfLauncherIcon::Stick(bool save)
{
BamfView* view = BAMF_VIEW(m_App);
@@ -920,7 +881,7 @@ void BamfLauncherIcon::Stick()
const gchar* desktop_file = DesktopFile();
bamf_view_set_sticky(view, true);
- if (desktop_file && strlen(desktop_file) > 0)
+ if (save && desktop_file && strlen(desktop_file) > 0)
FavoriteStore::GetDefault().AddFavorite(desktop_file, -1);
}
diff --git a/plugins/unityshell/src/BamfLauncherIcon.h b/plugins/unityshell/src/BamfLauncherIcon.h
index 52437c698..24c1e053a 100644
--- a/plugins/unityshell/src/BamfLauncherIcon.h
+++ b/plugins/unityshell/src/BamfLauncherIcon.h
@@ -46,9 +46,9 @@ public:
const char* DesktopFile();
bool IsSticky();
- void Quit();
- void Stick();
+ void Stick(bool save = true);
void UnStick();
+ void Quit();
void ActivateLauncherIcon(ActionArg arg);
@@ -116,13 +116,12 @@ private:
void OpenInstanceWithUris(std::set<std::string> uris);
void Focus(ActionArg arg);
- bool Spread(int state, bool force);
+ bool Spread(bool current_desktop, int state, bool force);
void EnsureMenuItemsReady();
void OnWindowMinimized(guint32 xid);
void OnWindowMoved(guint32 xid);
- void OnViewPortSwitchEnded();
bool OwnsWindow(Window w);
const std::set<std::string>& GetSupportedTypes();
@@ -147,7 +146,6 @@ private:
static gboolean OnDndHoveredTimeout(gpointer data);
static gboolean FillSupportedTypes(gpointer data);
- static gboolean OnWindowMovedTimeout(gpointer data);
};
}
diff --git a/plugins/unityshell/src/DashSearchBar.cpp b/plugins/unityshell/src/DashSearchBar.cpp
index d9493cad7..3088fad5a 100644
--- a/plugins/unityshell/src/DashSearchBar.cpp
+++ b/plugins/unityshell/src/DashSearchBar.cpp
@@ -45,7 +45,10 @@
#define LIVE_SEARCH_TIMEOUT 40
#define SPINNER_TIMEOUT 100
-static const float kExpandDefaultIconOpacity = 1.0f;
+namespace
+{
+const float kExpandDefaultIconOpacity = 1.0f;
+}
namespace unity
{
@@ -99,9 +102,10 @@ SearchBar::SearchBar(NUX_FILE_LINE_DECL)
layered_layout_->SetMaximumWidth(search_bar_width_);
layout_->AddView(layered_layout_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FIX);
- std::string filter_str = _("<b>Filter results</b>");
+ std::string filter_str = _("<small><b>Filter results</b></small>");
show_filters_ = new nux::StaticCairoText(filter_str.c_str());
show_filters_->SetVisible(false);
+ show_filters_->SetFont("Ubuntu 10");
show_filters_->SetTextColor(nux::Color(1.0f, 1.0f, 1.0f, 1.0f));
show_filters_->SetTextAlignment(nux::StaticCairoText::NUX_ALIGN_LEFT);
show_filters_->mouse_click.connect([&] (int x, int y, unsigned long b, unsigned long k) { showing_filters = !showing_filters; });
@@ -469,5 +473,5 @@ void SearchBar::AddProperties(GVariantBuilder* builder)
g_variant_builder_add (builder, "{sv}", "search_string", g_variant_new_string (pango_entry_->GetText().c_str()) );
}
-}
-}
+} // namespace dash
+} // namespace unity \ No newline at end of file
diff --git a/plugins/unityshell/src/DashView.cpp b/plugins/unityshell/src/DashView.cpp
index bc75f735c..bf998c647 100644
--- a/plugins/unityshell/src/DashView.cpp
+++ b/plugins/unityshell/src/DashView.cpp
@@ -47,6 +47,7 @@ NUX_IMPLEMENT_OBJECT_TYPE(DashView);
DashView::DashView()
: nux::View(NUX_TRACKER_LOCATION)
+ , home_lens_(new HomeLens(_("Home"), _("Home screen"), _("Search")))
, active_lens_view_(0)
, last_activated_uri_("")
, searching_timeout_id_(0)
@@ -67,6 +68,8 @@ DashView::DashView()
mouse_down.connect(sigc::mem_fun(this, &DashView::OnMouseButtonDown));
Relayout();
+
+ home_lens_->AddLenses(lenses_);
lens_bar_->Activate("home.lens");
}
@@ -81,6 +84,23 @@ void DashView::AboutToShow()
ubus_manager_.SendMessage(UBUS_BACKGROUND_REQUEST_COLOUR_EMIT);
visible_ = true;
search_bar_->text_entry()->SelectAll();
+
+ /* Give the lenses a chance to prep data before we map them */
+ lens_bar_->Activate(active_lens_view_->lens()->id());
+ if (active_lens_view_->lens()->id() == "home.lens")
+ {
+ for (auto lens : lenses_.GetLenses())
+ {
+ lens->view_type = ViewType::HOME_VIEW;
+ LOG_DEBUG(logger) << "Setting ViewType " << ViewType::HOME_VIEW
+ << " on '" << lens->id() << "'";
+ }
+
+ home_lens_->view_type = ViewType::LENS_VIEW;
+ LOG_DEBUG(logger) << "Setting ViewType " << ViewType::LENS_VIEW
+ << " on '" << home_lens_->id() << "'";
+ }
+
renderer_.AboutToShow();
}
@@ -88,6 +108,17 @@ void DashView::AboutToHide()
{
visible_ = false;
renderer_.AboutToHide();
+
+ for (auto lens : lenses_.GetLenses())
+ {
+ lens->view_type = ViewType::HIDDEN;
+ LOG_DEBUG(logger) << "Setting ViewType " << ViewType::HIDDEN
+ << " on '" << lens->id() << "'";
+ }
+
+ home_lens_->view_type = ViewType::HIDDEN;
+ LOG_DEBUG(logger) << "Setting ViewType " << ViewType::HIDDEN
+ << " on '" << home_lens_->id() << "'";
}
void DashView::SetupViews()
@@ -111,9 +142,9 @@ void DashView::SetupViews()
lenses_layout_ = new nux::VLayout();
content_layout_->AddView(lenses_layout_, 1, nux::MINOR_POSITION_LEFT);
- home_view_ = new HomeView();
+ home_view_ = new LensView(home_lens_);
active_lens_view_ = home_view_;
- lens_views_["home.lens"] = home_view_;
+ lens_views_[home_lens_->id] = home_view_;
lenses_layout_->AddView(home_view_);
lens_bar_ = new LensBar();
@@ -240,7 +271,6 @@ void DashView::OnActivateRequest(GVariant* args)
std::string id = AnalyseLensURI(uri.Str());
- home_view_->search_string = "";
lens_bar_->Activate(id);
if ((id == "home.lens" && handled_type != GOTO_DASH_URI ) || !visible_)
@@ -337,7 +367,6 @@ void DashView::OnLensAdded(Lens::Ptr& lens)
{
std::string id = lens->id;
lens_bar_->AddLens(lens);
- home_view_->AddLens(lens);
LensView* view = new LensView(lens);
view->SetVisible(false);
@@ -363,15 +392,17 @@ void DashView::OnLensBarActivated(std::string const& id)
for (auto it: lens_views_)
{
bool id_matches = it.first == id;
+ ViewType view_type = id_matches ? LENS_VIEW : (view == home_view_ ? HOME_VIEW : HIDDEN);
it.second->SetVisible(id_matches);
- it.second->view_type = id_matches ? LENS_VIEW : (view == home_view_ ? HOME_VIEW : HIDDEN);
+ it.second->view_type = view_type;
+
+ LOG_DEBUG(logger) << "Setting ViewType " << view_type
+ << " on '" << it.first << "'";
}
search_bar_->search_string = view->search_string;
- if (view != home_view_)
- search_bar_->search_hint = view->lens()->search_hint;
- else
- search_bar_->search_hint = _("Search");
+ search_bar_->search_hint = view->lens()->search_hint;
+
bool expanded = view->filters_expanded;
search_bar_->showing_filters = expanded;
@@ -554,6 +585,7 @@ bool DashView::InspectKeyEvent(unsigned int eventType,
ubus_manager_.SendMessage(UBUS_PLACE_VIEW_CLOSE_REQUEST);
else
search_bar_->search_string = "";
+
return true;
}
return false;
diff --git a/plugins/unityshell/src/DashView.h b/plugins/unityshell/src/DashView.h
index 492a982f0..9c881289d 100644
--- a/plugins/unityshell/src/DashView.h
+++ b/plugins/unityshell/src/DashView.h
@@ -27,10 +27,10 @@
#include <Nux/View.h>
#include <Nux/VLayout.h>
#include <UnityCore/FilesystemLenses.h>
+#include <UnityCore/HomeLens.h>
#include "BackgroundEffectHelper.h"
#include "DashSearchBar.h"
-#include "HomeView.h"
#include "Introspectable.h"
#include "LensBar.h"
#include "LensView.h"
@@ -95,6 +95,7 @@ private:
std::string AnalyseLensURI(std::string const& uri);
void UpdateLensFilter(std::string lens, std::string filter, std::string value);
void UpdateLensFilterValue(Filter::Ptr filter, std::string value);
+ void EnsureLensesInitialized();
bool AcceptKeyNavFocus();
bool InspectKeyEvent(unsigned int eventType, unsigned int key_sym, const char* character);
@@ -108,6 +109,7 @@ private:
private:
UBusManager ubus_manager_;
FilesystemLenses lenses_;
+ HomeLens::Ptr home_lens_;
LensViews lens_views_;
@@ -118,7 +120,7 @@ private:
nux::VLayout* lenses_layout_;
LensBar* lens_bar_;
- HomeView* home_view_;
+ LensView* home_view_;
LensView* active_lens_view_;
// Drawing related
diff --git a/plugins/unityshell/src/FavoriteStore.h b/plugins/unityshell/src/FavoriteStore.h
index 237e13582..ec6aa605e 100644
--- a/plugins/unityshell/src/FavoriteStore.h
+++ b/plugins/unityshell/src/FavoriteStore.h
@@ -34,7 +34,7 @@ namespace unity
// Use GetDefault () to get the correct store for the session
typedef std::list<std::string> FavoriteList;
-class FavoriteStore : boost::noncopyable
+class FavoriteStore : public sigc::trackable, boost::noncopyable
{
public:
virtual ~FavoriteStore();
@@ -54,12 +54,12 @@ public:
virtual void SetFavorites(FavoriteList const& desktop_paths) = 0;
// Signals
- // Therse only emit if something has changed the GSettings object externally
+ // These only emit if something has changed the GSettings object externally
- //desktop_path, position
- sigc::signal<void, std::string, int> favorite_added;
+ //desktop_path, position, before/after
+ sigc::signal<void, std::string const&, std::string const&, bool> favorite_added;
//desktop_path
- sigc::signal<void, std::string> favorite_removed;
+ sigc::signal<void, std::string const&> favorite_removed;
sigc::signal<void> reordered;
};
diff --git a/plugins/unityshell/src/FavoriteStoreGSettings.cpp b/plugins/unityshell/src/FavoriteStoreGSettings.cpp
index 8de351a39..239ea07a9 100644
--- a/plugins/unityshell/src/FavoriteStoreGSettings.cpp
+++ b/plugins/unityshell/src/FavoriteStoreGSettings.cpp
@@ -17,15 +17,14 @@
* Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
*/
-#include "FavoriteStoreGSettings.h"
-
#include <algorithm>
-#include <iostream>
#include <gio/gdesktopappinfo.h>
-
#include <NuxCore/Logger.h>
+#include "FavoriteStoreGSettings.h"
+#include "FavoriteStorePrivate.h"
+
#include "config.h"
/**
@@ -103,7 +102,12 @@ void FavoriteStoreGSettings::Init()
void FavoriteStoreGSettings::Refresh()
{
- favorites_.clear();
+ FillList(favorites_);
+}
+
+void FavoriteStoreGSettings::FillList(FavoriteList& list)
+{
+ list.clear();
gchar** favs = g_settings_get_strv(settings_, "favorites");
@@ -114,7 +118,7 @@ void FavoriteStoreGSettings::Refresh()
{
if (g_file_test(favs[i], G_FILE_TEST_EXISTS))
{
- favorites_.push_back(favs[i]);
+ list.push_back(favs[i]);
}
else
{
@@ -131,12 +135,11 @@ void FavoriteStoreGSettings::Refresh()
if (filename)
{
- favorites_.push_back(filename);
+ list.push_back(filename);
}
else
{
- LOG_WARNING(logger) << "Unable to load GDesktopAppInfo for '"
- << favs[i] << "'";
+ LOG_WARNING(logger) << "Unable to load GDesktopAppInfo for '" << favs[i] << "'";
}
}
}
@@ -222,7 +225,7 @@ void FavoriteStoreGSettings::SetFavorites(FavoriteList const& favorites)
Refresh();
}
-void FavoriteStoreGSettings::SaveFavorites(FavoriteList const& favorites)
+void FavoriteStoreGSettings::SaveFavorites(FavoriteList const& favorites, bool ignore)
{
const int size = favorites.size();
const char* favs[size + 1];
@@ -244,7 +247,7 @@ void FavoriteStoreGSettings::SaveFavorites(FavoriteList const& favorites)
favs[index] = iter->c_str();
}
- ignore_signals_ = true;
+ ignore_signals_ = ignore;
if (!g_settings_set_strv(settings_, "favorites", favs))
{
LOG_WARNING(logger) << "Saving favorites failed.";
@@ -254,10 +257,34 @@ void FavoriteStoreGSettings::SaveFavorites(FavoriteList const& favorites)
void FavoriteStoreGSettings::Changed(std::string const& key)
{
- if (ignore_signals_)
+ if (ignore_signals_ or key != "favorites")
return;
+
+ FavoriteList old(favorites_);
+ FillList(favorites_);
+
+ auto newbies = impl::GetNewbies(old, favorites_);
- LOG_DEBUG(logger) << "Changed: " << key;
+ for (auto it : favorites_)
+ {
+ if (std::find(newbies.begin(), newbies.end(), it) == newbies.end())
+ continue;
+
+ std::string pos;
+ bool before;
+
+ impl::GetSignalAddedInfo(favorites_, newbies , it, pos, before);
+ favorite_added.emit(it, pos, before);
+ }
+
+ for (auto it : impl::GetRemoved(old, favorites_))
+ {
+ favorite_removed.emit(it);
+ }
+
+ if (impl::NeedToBeReordered(old, favorites_))
+ reordered.emit();
+
}
namespace
diff --git a/plugins/unityshell/src/FavoriteStoreGSettings.h b/plugins/unityshell/src/FavoriteStoreGSettings.h
index d4e573806..600b6162c 100644
--- a/plugins/unityshell/src/FavoriteStoreGSettings.h
+++ b/plugins/unityshell/src/FavoriteStoreGSettings.h
@@ -42,6 +42,7 @@ public:
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 void SetFavorites(FavoriteList const& desktop_paths);
//Methods
@@ -50,7 +51,7 @@ public:
private:
void Init();
void Refresh();
- void SaveFavorites(FavoriteList const& favorites);
+ void FillList(FavoriteList& list);
FavoriteList favorites_;
glib::Object<GSettings> settings_;
diff --git a/plugins/unityshell/src/FavoriteStorePrivate.cpp b/plugins/unityshell/src/FavoriteStorePrivate.cpp
new file mode 100644
index 000000000..5478fa0d5
--- /dev/null
+++ b/plugins/unityshell/src/FavoriteStorePrivate.cpp
@@ -0,0 +1,130 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+* Copyright (C) 2011 Canonical Ltd
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 3 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* Authored by: Andrea Azzaronea <azzaronea@gmail.com>
+*/
+
+#include <algorithm>
+#include <boost/utility.hpp>
+
+#include "FavoriteStorePrivate.h"
+
+namespace unity
+{
+namespace internal
+{
+namespace impl
+{
+
+std::vector<std::string> GetNewbies(std::list<std::string> const& old, std::list<std::string> const& fresh)
+{
+ auto sorted_old(old);
+ auto sorted_fresh(fresh);
+
+ sorted_old.sort();
+ sorted_fresh.sort();
+
+ std::vector<std::string> result;
+ std::set_difference(sorted_fresh.begin(), sorted_fresh.end(), sorted_old.begin(), sorted_old.end(),
+ std::inserter(result, result.end()));
+
+ return result;
+}
+
+void GetSignalAddedInfo(std::list<std::string> const& favs, std::vector<std::string> const& newbies,
+ std::string const& path, std::string& position, bool& before)
+{
+ auto it = std::find(favs.begin(), favs.end(), path);
+ before = (it == favs.begin());
+ position = "";
+
+ if (before and favs.size() > 1)
+ {
+ while (it != favs.end() && std::find(newbies.begin(), newbies.end(), *it) != newbies.end())
+ ++it;
+
+ if (it != favs.end())
+ position = *it;
+ }
+ else if (!before)
+ {
+ position = *(boost::prior(it));
+ }
+
+}
+
+std::vector<std::string> GetRemoved(std::list<std::string> const& old, std::list<std::string> const& fresh)
+{
+ auto sorted_old(old);
+ auto sorted_fresh(fresh);
+
+ sorted_old.sort();
+ sorted_fresh.sort();
+
+ std::vector<std::string> result;
+ std::set_difference(sorted_old.begin(), sorted_old.end(), sorted_fresh.begin(), sorted_fresh.end(),
+ std::inserter(result, result.end()));
+
+ return result;
+}
+
+
+bool NeedToBeReordered(std::list<std::string> const& old, std::list<std::string> const& fresh)
+{
+ auto sorted_old(old);
+ auto sorted_fresh(fresh);
+
+ sorted_old.sort();
+ sorted_fresh.sort();
+
+ std::vector<std::string> ignore_old, ignore_fresh;
+
+ std::set_difference(sorted_old.begin(), sorted_old.end(), sorted_fresh.begin(), sorted_fresh.end(),
+ std::inserter(ignore_old, ignore_old.end()));
+ std::set_difference(sorted_fresh.begin(), sorted_fresh.end(), sorted_old.begin(), sorted_old.end(),
+ std::inserter(ignore_fresh, ignore_fresh.end()));
+
+ auto it_old = old.begin();
+ auto it_fresh = fresh.begin();
+
+ while (it_old != old.end() && it_fresh != fresh.end())
+ {
+
+ while (it_old != old.end() && std::find(ignore_old.begin(), ignore_old.end(), *it_old) != ignore_old.end())
+ ++it_old;
+
+ while (it_fresh != fresh.end() && std::find(ignore_fresh.begin(), ignore_fresh.end(), *it_fresh) != ignore_fresh.end())
+ ++it_fresh;
+
+ if (it_old == old.end() || it_fresh == fresh.end())
+ break;
+
+ if (*it_old != *it_fresh)
+ {
+ return true;
+ }
+
+ ++it_old;
+ ++it_fresh;
+ }
+
+ return false;
+}
+
+
+} // namespace impl
+} // namespace internal
+} // namespace unity
diff --git a/plugins/unityshell/src/FavoriteStorePrivate.h b/plugins/unityshell/src/FavoriteStorePrivate.h
new file mode 100644
index 000000000..4b27e0c03
--- /dev/null
+++ b/plugins/unityshell/src/FavoriteStorePrivate.h
@@ -0,0 +1,47 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+* Copyright (C) 2011 Canonical Ltd
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 3 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* Authored by: Andrea Azzaronea <azzaronea@gmail.com>
+*/
+
+#ifndef UNITYSHELL_FAVORITESTOREPRIVATE_H
+#define UNITYSHELL_FAVORITESTOREPRIVATE_H
+
+#include <list>
+#include <string>
+
+namespace unity
+{
+namespace internal
+{
+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,
+ 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);
+
+} // namespace impl
+} // namespace internal
+} // namespace unity
+
+#endif
+
diff --git a/plugins/unityshell/src/FilterBar.cpp b/plugins/unityshell/src/FilterBar.cpp
index c33316a26..4b80369ad 100644
--- a/plugins/unityshell/src/FilterBar.cpp
+++ b/plugins/unityshell/src/FilterBar.cpp
@@ -56,7 +56,7 @@ FilterBar::~FilterBar()
void FilterBar::Init()
{
nux::LinearLayout* layout = new nux::VLayout(NUX_TRACKER_LOCATION);
- layout->SetSpaceBetweenChildren(12);
+ layout->SetSpaceBetweenChildren(10);
SetLayout(layout);
}
@@ -105,10 +105,38 @@ void FilterBar::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw)
{
GfxContext.PushClippingRectangle(GetGeometry());
GetLayout()->ProcessDraw(GfxContext, force_draw);
+
+ nux::Color col(0.13f, 0.13f, 0.13f, 0.13f);
+
+ std::list<Area *>& layout_list = GetLayout()->GetChildren();
+ std::list<Area*>::iterator iter;
+ int i = 0;
+ int num_separators = layout_list.size() - 1;
+
+ for (iter = layout_list.begin(); iter != layout_list.end(); iter++)
+ {
+ if (i != num_separators)
+ {
+ nux::Area* filter_view = (*iter);
+ nux::Geometry const& geom = filter_view->GetGeometry();
+
+ unsigned int alpha = 0, src = 0, dest = 0;
+ GfxContext.GetRenderStates().GetBlend(alpha, src, dest);
+
+ GfxContext.GetRenderStates().SetBlend(true, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ GfxContext.GetRenderStates().SetColorMask(true, true, true, false);
+ nux::GetPainter().Draw2DLine(GfxContext,
+ geom.x , geom.y + geom.height - 1,
+ geom.x + geom.width, geom.y + geom.height - 1,
+ col);
+ GfxContext.GetRenderStates().SetBlend(alpha, src, dest);
+ }
+ i++;
+ }
+
GfxContext.PopClippingRectangle();
}
-
} // namespace dash
} // namespace unity
diff --git a/plugins/unityshell/src/FilterBasicButton.cpp b/plugins/unityshell/src/FilterBasicButton.cpp
index e7699e7a7..a4257f212 100644
--- a/plugins/unityshell/src/FilterBasicButton.cpp
+++ b/plugins/unityshell/src/FilterBasicButton.cpp
@@ -22,6 +22,12 @@
#include "DashStyle.h"
#include "FilterBasicButton.h"
+namespace
+{
+const int kMinButtonHeight = 30;
+const int kMinButtonWidth = 48;
+}
+
namespace unity
{
namespace dash
@@ -68,7 +74,8 @@ void FilterBasicButton::InitTheme()
normal_.reset(new nux::CairoWrapper(geo, sigc::bind(sigc::mem_fun(this, &FilterBasicButton::RedrawTheme), nux::ButtonVisualState::VISUAL_STATE_NORMAL)));
}
- // SetMinimumHeight(32);
+ SetMinimumHeight(kMinButtonHeight);
+ SetMinimumWidth(kMinButtonWidth);
}
void FilterBasicButton::RedrawTheme(nux::Geometry const& geom, cairo_t* cr, nux::ButtonVisualState faked_state)
@@ -79,6 +86,7 @@ void FilterBasicButton::RedrawTheme(nux::Geometry const& geom, cairo_t* cr, nux:
long FilterBasicButton::ComputeContentSize()
{
long ret = nux::Button::ComputeContentSize();
+
nux::Geometry const& geo = GetGeometry();
if (cached_geometry_ != geo)
@@ -136,5 +144,4 @@ void FilterBasicButton::Draw(nux::GraphicsEngine& GfxContext, bool force_draw)
}
} // namespace dash
-} // namespace unity
-
+} // namespace unity \ No newline at end of file
diff --git a/plugins/unityshell/src/FilterExpanderLabel.cpp b/plugins/unityshell/src/FilterExpanderLabel.cpp
index 302de673e..e5e4b3691 100644
--- a/plugins/unityshell/src/FilterExpanderLabel.cpp
+++ b/plugins/unityshell/src/FilterExpanderLabel.cpp
@@ -24,11 +24,18 @@
#include "FilterBasicButton.h"
#include "FilterExpanderLabel.h"
+namespace
+{
+const float kExpandDefaultIconOpacity = 1.0f;
+}
+
namespace unity
{
namespace dash
{
+
+
NUX_IMPLEMENT_OBJECT_TYPE(FilterExpanderLabel);
FilterExpanderLabel::FilterExpanderLabel(std::string const& label, NUX_FILE_LINE_DECL)
@@ -37,10 +44,9 @@ FilterExpanderLabel::FilterExpanderLabel(std::string const& label, NUX_FILE_LINE
, layout_(nullptr)
, top_bar_layout_(nullptr)
, right_hand_contents_(nullptr)
- , expander_graphic_(nullptr)
, cairo_label_(nullptr)
, raw_label_(label)
- , label_("<span size='larger' weight='bold'>" + label + "</span>" + " â–¾")
+ , label_("<span size='larger' weight='bold'>" + label + "</span>")
{
expanded.changed.connect(sigc::mem_fun(this, &FilterExpanderLabel::DoExpandChange));
BuildLayout();
@@ -57,7 +63,6 @@ void FilterExpanderLabel::SetLabel(std::string const& label)
label_ = "<span size='larger' weight='bold'>";
label_ += raw_label_;
label_ += "</span>";
- label_ += expanded ? " â–¾" : " â–¸";
cairo_label_->SetText(label_.c_str());
}
@@ -66,7 +71,7 @@ void FilterExpanderLabel::SetRightHandView(nux::View* view)
view->SetMaximumHeight(30);
right_hand_contents_ = view;
- top_bar_layout_->AddView(right_hand_contents_, 0, nux::MINOR_POSITION_LEFT, nux::MINOR_SIZE_FULL);
+ top_bar_layout_->AddView(right_hand_contents_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL);
}
void FilterExpanderLabel::SetContents(nux::Layout* contents)
@@ -83,6 +88,7 @@ void FilterExpanderLabel::BuildLayout()
{
layout_ = new nux::VLayout(NUX_TRACKER_LOCATION);
top_bar_layout_ = new nux::HLayout(NUX_TRACKER_LOCATION);
+ top_bar_layout_->SetHorizontalInternalMargin(8);
cairo_label_ = new nux::StaticText(label_.c_str(), NUX_TRACKER_LOCATION);
cairo_label_->SetFontName("Ubuntu 10");
@@ -93,10 +99,31 @@ void FilterExpanderLabel::BuildLayout()
expanded = !expanded;
});
- top_bar_layout_->AddView(cairo_label_, 1, nux::MINOR_POSITION_LEFT, nux::MINOR_SIZE_FULL);
+ nux::BaseTexture* arrow;
+ arrow = dash::Style::Instance().GetGroupUnexpandIcon();
+ expand_icon_ = new IconTexture(arrow,
+ arrow->GetWidth(),
+ arrow->GetHeight());
+ expand_icon_->SetOpacity(kExpandDefaultIconOpacity);
+ expand_icon_->SetMinimumSize(arrow->GetWidth(), arrow->GetHeight());
+ expand_icon_->SetVisible(true);
+ expand_icon_->mouse_click.connect(
+ [&] (int x, int y, unsigned long b, unsigned long k)
+ {
+ expanded = !expanded;
+ });
+ arrow_layout_ = new nux::VLayout();
+ arrow_top_space_ = new nux::SpaceLayout(2, 2, 11, 11);
+ arrow_bottom_space_ = new nux::SpaceLayout(2, 2, 9, 9);
+ arrow_layout_->AddView(arrow_top_space_, 0, nux::MINOR_POSITION_CENTER);
+ arrow_layout_->AddView(expand_icon_, 0, nux::MINOR_POSITION_CENTER);
+ arrow_layout_->AddView(arrow_bottom_space_, 0, nux::MINOR_POSITION_CENTER);
+
+ top_bar_layout_->AddView(cairo_label_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL);
+ top_bar_layout_->AddView(arrow_layout_, 0, nux::MINOR_POSITION_CENTER);
top_bar_layout_->AddSpace(1, 1);
- top_bar_layout_->SetMaximumWidth((Style::Instance().GetTileWidth() - 12) * 2 + 10);
+ top_bar_layout_->SetMaximumWidth((Style::Instance().GetTileWidth() - 12) * 2 + 20);
layout_->AddLayout(top_bar_layout_, 0, nux::MINOR_POSITION_LEFT);
layout_->SetVerticalInternalMargin(0);
@@ -109,13 +136,11 @@ void FilterExpanderLabel::BuildLayout()
void FilterExpanderLabel::DoExpandChange(bool change)
{
- label_ = "<span size='larger' weight='bold'>";
- label_ += raw_label_;
- label_ += "</span>";
- label_ += expanded ? " â–¾" : " â–¸";
-
- if (cairo_label_)
- cairo_label_->SetText(label_);
+ dash::Style& style = dash::Style::Instance();
+ if (expanded)
+ expand_icon_->SetTexture(style.GetGroupUnexpandIcon());
+ else
+ expand_icon_->SetTexture(style.GetGroupExpandIcon());
if (change and contents_ and !contents_->IsChildOf(layout_))
{
@@ -149,4 +174,4 @@ void FilterExpanderLabel::DrawContent(nux::GraphicsEngine& GfxContext, bool forc
}
} // namespace dash
-} // namespace unity
+} // namespace unity \ No newline at end of file
diff --git a/plugins/unityshell/src/FilterExpanderLabel.h b/plugins/unityshell/src/FilterExpanderLabel.h
index ca1b96181..ed409241b 100644
--- a/plugins/unityshell/src/FilterExpanderLabel.h
+++ b/plugins/unityshell/src/FilterExpanderLabel.h
@@ -30,6 +30,7 @@
#include <Nux/StaticText.h>
#include "FilterWidget.h"
+#include "IconTexture.h"
namespace unity
{
@@ -60,10 +61,13 @@ private:
nux::LinearLayout* layout_;
nux::LinearLayout* top_bar_layout_;
nux::View* right_hand_contents_;
- nux::View* expander_graphic_;
nux::StaticText* cairo_label_;
std::string raw_label_;
std::string label_;
+ nux::VLayout* arrow_layout_;
+ nux::SpaceLayout* arrow_top_space_;
+ nux::SpaceLayout* arrow_bottom_space_;
+ IconTexture* expand_icon_;
nux::ObjectPtr<nux::Layout> contents_;
};
diff --git a/plugins/unityshell/src/FilterGenreWidget.cpp b/plugins/unityshell/src/FilterGenreWidget.cpp
index a12558f41..9ab2277eb 100644
--- a/plugins/unityshell/src/FilterGenreWidget.cpp
+++ b/plugins/unityshell/src/FilterGenreWidget.cpp
@@ -47,7 +47,7 @@ FilterGenre::FilterGenre(int columns, NUX_FILE_LINE_DECL)
genre_layout_->ForceChildrenSize(true);
genre_layout_->MatchContentSize(true);
genre_layout_->SetSpaceBetweenChildren (9, 9);
- genre_layout_->SetTopAndBottomPadding(12);
+ genre_layout_->SetTopAndBottomPadding(9, 12);
genre_layout_->EnablePartialVisibility(false);
if (columns == 3)
{
@@ -55,7 +55,7 @@ FilterGenre::FilterGenre(int columns, NUX_FILE_LINE_DECL)
}
else
{
- genre_layout_->SetChildrenSize(Style::Instance().GetTileWidth() - 12, 33);
+ genre_layout_->SetChildrenSize(Style::Instance().GetTileWidth() - 7, 33);
}
SetRightHandView(all_button_);
@@ -122,17 +122,9 @@ void FilterGenre::InitTheme()
void FilterGenre::Draw(nux::GraphicsEngine& GfxContext, bool force_draw)
{
nux::Geometry const& geo = GetGeometry();
- nux::Color col(0.2f, 0.2f, 0.2f, 0.2f);
GfxContext.PushClippingRectangle(geo);
nux::GetPainter().PaintBackground(GfxContext, geo);
-
- nux::GetPainter().Draw2DLine(GfxContext,
- geo.x, geo.y + geo.height - 1,
- geo.x + geo.width, geo.y + geo.height - 1,
- col,
- col);
-
GfxContext.PopClippingRectangle();
}
diff --git a/plugins/unityshell/src/FilterMultiRangeWidget.cpp b/plugins/unityshell/src/FilterMultiRangeWidget.cpp
index a09a3aad2..ef552d2ce 100644
--- a/plugins/unityshell/src/FilterMultiRangeWidget.cpp
+++ b/plugins/unityshell/src/FilterMultiRangeWidget.cpp
@@ -44,7 +44,7 @@ FilterMultiRange::FilterMultiRange(NUX_FILE_LINE_DECL)
all_button_ = new FilterAllButton(NUX_TRACKER_LOCATION);
layout_ = new nux::HLayout(NUX_TRACKER_LOCATION);
- layout_->SetVerticalExternalMargin(12);
+ layout_->SetTopAndBottomPadding(9, 12);
SetRightHandView(all_button_);
SetContents(layout_);
@@ -158,17 +158,9 @@ void FilterMultiRange::InitTheme()
void FilterMultiRange::Draw(nux::GraphicsEngine& GfxContext, bool force_draw)
{
nux::Geometry const& geo = GetGeometry();
- nux::Color col(0.2f, 0.2f, 0.2f, 0.2f);
GfxContext.PushClippingRectangle(geo);
nux::GetPainter().PaintBackground(GfxContext, geo);
-
- nux::GetPainter().Draw2DLine(GfxContext,
- geo.x, geo.y + geo.height - 1,
- geo.x + geo.width, geo.y + geo.height - 1,
- col,
- col);
-
GfxContext.PopClippingRectangle();
}
diff --git a/plugins/unityshell/src/FilterRatingsWidget.cpp b/plugins/unityshell/src/FilterRatingsWidget.cpp
index b650d1d7d..0b9129cc1 100644
--- a/plugins/unityshell/src/FilterRatingsWidget.cpp
+++ b/plugins/unityshell/src/FilterRatingsWidget.cpp
@@ -43,7 +43,7 @@ FilterRatingsWidget::FilterRatingsWidget(NUX_FILE_LINE_DECL)
all_button_ = new FilterAllButton(NUX_TRACKER_LOCATION);
nux::VLayout* layout = new nux::VLayout(NUX_TRACKER_LOCATION);
- layout->SetTopAndBottomPadding(10, 0);
+ layout->SetTopAndBottomPadding(11, 12);
ratings_ = new FilterRatingsButton(NUX_TRACKER_LOCATION);
layout->AddView(ratings_);
diff --git a/plugins/unityshell/src/HomeView.cpp b/plugins/unityshell/src/HomeView.cpp
deleted file mode 100644
index a8c40d7ec..000000000
--- a/plugins/unityshell/src/HomeView.cpp
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright (C) 2010 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: Neil Jagdish Patel <neil.patel@canonical.com>
- */
-
-#include "HomeView.h"
-
-#include <boost/lexical_cast.hpp>
-
-#include <NuxCore/Logger.h>
-
-#include "DashStyle.h"
-#include "ResultRendererTile.h"
-#include "UBusMessages.h"
-
-namespace unity
-{
-namespace dash
-{
-
-namespace
-{
-nux::logging::Logger logger("unity.dash.homeview");
-}
-
-// This is so we can override the scroll bar for the view.
-class HomeScrollView: public nux::ScrollView
-{
-public:
- HomeScrollView(nux::VScrollBar* scroll_bar, NUX_FILE_LINE_DECL)
- : nux::ScrollView(NUX_FILE_LINE_PARAM)
- {
- SetVScrollBar(scroll_bar);
- }
-};
-
-
-
-NUX_IMPLEMENT_OBJECT_TYPE(HomeView);
-
-HomeView::HomeView()
- : fix_renderering_id_(0)
-{
- SetupViews();
-
- search_string.changed.connect([&](std::string const& search)
- {
- for (auto lens : lenses_)
- lens->GlobalSearch(search);
-
- for (auto group: categories_)
- {
- group->SetVisible(search != "" && counts_[group]);
- }
- home_view_->SetVisible(search == "");
- scroll_view_->SetVisible(search != "");
-
- QueueDraw();
- });
-}
-
-HomeView::~HomeView()
-{
- if (fix_renderering_id_)
- g_source_remove(fix_renderering_id_);
-}
-
-void HomeView::SetupViews()
-{
- layout_ = new nux::HLayout(NUX_TRACKER_LOCATION);
- layout_->SetHorizontalExternalMargin(7);
-
- scroll_view_ = new HomeScrollView(new PlacesVScrollBar(NUX_TRACKER_LOCATION),
- NUX_TRACKER_LOCATION);
- scroll_view_->EnableVerticalScrollBar(true);
- scroll_view_->EnableHorizontalScrollBar(false);
- scroll_view_->SetVisible(false);
- layout_->AddView(scroll_view_);
-
- scroll_layout_ = new nux::VLayout();
- scroll_view_->SetLayout(scroll_layout_);
-
- home_view_ = new PlacesHomeView();
- layout_->AddView(home_view_);
-
- SetLayout(layout_);
-}
-
-void HomeView::AddLens(Lens::Ptr lens)
-{
- lenses_.push_back(lens);
-
- std::string name = lens->name;
- std::string icon_hint = lens->icon_hint;
-
- LOG_DEBUG(logger) << "Lens added " << name;
-
- PlacesGroup* group = new PlacesGroup();
- group->SetName(name.c_str());
- group->SetIcon(icon_hint.c_str());
- group->SetExpanded(false);
- group->SetVisible(false);
- group->expanded.connect(sigc::mem_fun(this, &HomeView::OnGroupExpanded));
- categories_.push_back(group);
- counts_[group] = 0;
-
- ResultViewGrid* grid = new ResultViewGrid(NUX_TRACKER_LOCATION);
- grid->expanded = false;
- grid->SetModelRenderer(new ResultRendererTile(NUX_TRACKER_LOCATION));
- grid->UriActivated.connect([&, lens] (std::string const& uri) { uri_activated.emit(uri); lens->Activate(uri); });
- group->SetChildView(grid);
-
- Results::Ptr results = lens->global_results;
- results->result_added.connect([&, group, grid] (Result const& result)
- {
- grid->AddResult(const_cast<Result&>(result));
- counts_[group]++;
- UpdateCounts(group);
- });
-
- results->result_removed.connect([&, group, grid] (Result const& result)
- {
- grid->RemoveResult(const_cast<Result&>(result));
- counts_[group]--;
- UpdateCounts(group);
- });
-
-
- scroll_layout_->AddView(group, 0);
-}
-
-void HomeView::UpdateCounts(PlacesGroup* group)
-{
- group->SetCounts(dash::Style::Instance().GetDefaultNColumns(), counts_[group]);
- group->SetVisible(counts_[group]);
-
- QueueFixRenderering();
-}
-
-void HomeView::OnGroupExpanded(PlacesGroup* group)
-{
- ResultViewGrid* grid = static_cast<ResultViewGrid*>(group->GetChildView());
- grid->expanded = group->GetExpanded();
- ubus_manager_.SendMessage(UBUS_PLACE_VIEW_QUEUE_DRAW);
-}
-
-void HomeView::OnColumnsChanged()
-{
- unsigned int columns = dash::Style::Instance().GetDefaultNColumns();
-
- for (auto group: categories_)
- {
- group->SetCounts(columns, counts_[group]);
- }
-}
-
-void HomeView::QueueFixRenderering()
-{
- if (fix_renderering_id_)
- return;
-
- fix_renderering_id_ = g_idle_add_full (G_PRIORITY_DEFAULT, (GSourceFunc)FixRenderering, this, NULL);
-}
-
-gboolean HomeView::FixRenderering(HomeView* self)
-{
- std::list<Area*> children = self->scroll_layout_->GetChildren();
- std::list<Area*>::reverse_iterator rit;
- bool found_one = false;
-
- for (rit = children.rbegin(); rit != children.rend(); ++rit)
- {
- PlacesGroup* group = static_cast<PlacesGroup*>(*rit);
-
- if (group->IsVisible())
- group->SetDrawSeparator(found_one);
-
- found_one = group->IsVisible();
- }
-
- self->fix_renderering_id_ = 0;
- return FALSE;
-}
-
-void HomeView::Draw(nux::GraphicsEngine& gfx_context, bool force_draw)
-{
- nux::Geometry geo = GetGeometry();
-
- gfx_context.PushClippingRectangle(geo);
- nux::GetPainter().PaintBackground(gfx_context, geo);
- gfx_context.PopClippingRectangle();
-}
-
-void HomeView::DrawContent(nux::GraphicsEngine& gfx_context, bool force_draw)
-{
- gfx_context.PushClippingRectangle(GetGeometry());
-
- layout_->ProcessDraw(gfx_context, force_draw);
-
- gfx_context.PopClippingRectangle();
-}
-
-void HomeView::ActivateFirst()
-{
- for (auto lens: lenses_)
- {
- Results::Ptr results = lens->global_results;
- if (results->count())
- {
- Result result = results->RowAtIndex(0);
- if (result.uri != "")
- {
- uri_activated(result.uri);
- lens->Activate(result.uri);
- return;
- }
- }
- }
-}
-
-
-// Keyboard navigation
-bool HomeView::AcceptKeyNavFocus()
-{
- return false;
-}
-
-// Introspectable
-std::string HomeView::GetName() const
-{
- return "HomeView";
-}
-
-void HomeView::AddProperties(GVariantBuilder* builder)
-{}
-
-
-}
-}
diff --git a/plugins/unityshell/src/HomeView.h b/plugins/unityshell/src/HomeView.h
deleted file mode 100644
index 700779c6f..000000000
--- a/plugins/unityshell/src/HomeView.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2010 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: Neil Jagdish Patel <neil.patel@canonical.com>
- */
-
-#ifndef UNITY_HOME_VIEW_H_
-#define UNITY_HOME_VIEW_H_
-
-#include <string>
-
-#include <NuxGraphics/GraphicsEngine.h>
-#include <Nux/Nux.h>
-#include <Nux/HLayout.h>
-#include <Nux/View.h>
-#include <Nux/VLayout.h>
-#include <UnityCore/Lens.h>
-
-#include "LensView.h"
-#include "PlacesGroup.h"
-#include "PlacesHomeView.h"
-#include "ResultViewGrid.h"
-#include "UBusWrapper.h"
-
-namespace unity
-{
-namespace dash
-{
-
-class HomeView : public LensView
-{
- NUX_DECLARE_OBJECT_TYPE(HomeView, LensView);
- typedef std::vector<PlacesGroup*> CategoryGroups;
- typedef std::map<PlacesGroup*, unsigned int> ResultCounts;
- typedef std::vector<Lens::Ptr> Lenses;
-
-public:
- HomeView();
- ~HomeView();
-
- void AddLens(Lens::Ptr lens);
- void ActivateFirst();
-
-private:
- void SetupViews();
-
- void OnResultAdded(Result const& result);
- void OnResultRemoved(Result const& result);
- void UpdateCounts(PlacesGroup* group);
- void OnGroupExpanded(PlacesGroup* group);
- void OnColumnsChanged();
- void QueueFixRenderering();
-
- static gboolean FixRenderering(HomeView* self);
-
- void Draw(nux::GraphicsEngine& gfx_context, bool force_draw);
- void DrawContent(nux::GraphicsEngine& gfx_context, bool force_draw);
-
- bool AcceptKeyNavFocus();
- std::string GetName() const;
- void AddProperties(GVariantBuilder* builder);
-
-private:
- UBusManager ubus_manager_;
- CategoryGroups categories_;
- ResultCounts counts_;
- Lenses lenses_;
-
- nux::HLayout* layout_;
- nux::ScrollView* scroll_view_;
- nux::VLayout* scroll_layout_;
-
- PlacesHomeView* home_view_;
-
- guint fix_renderering_id_;
-};
-
-
-}
-}
-#endif
diff --git a/plugins/unityshell/src/IMTextEntry.cpp b/plugins/unityshell/src/IMTextEntry.cpp
index 6732c0a7d..1704a5561 100644
--- a/plugins/unityshell/src/IMTextEntry.cpp
+++ b/plugins/unityshell/src/IMTextEntry.cpp
@@ -42,8 +42,6 @@ IMTextEntry::IMTextEntry()
, preedit_string("")
, im_enabled(false)
, im_active(false)
- , im_context_(0)
- , client_window_(0)
, focused_(false)
{
g_setenv("IBUS_ENABLE_SYNC_MODE", "1", TRUE);
@@ -53,14 +51,6 @@ IMTextEntry::IMTextEntry()
mouse_up.connect(sigc::mem_fun(this, &IMTextEntry::OnMouseButtonUp));
}
-IMTextEntry::~IMTextEntry()
-{
- if (im_context_)
- g_object_unref(im_context_);
- if (client_window_)
- g_object_unref(client_window_);
-}
-
void IMTextEntry::CheckIMEnabled()
{
const char* module = g_getenv("GTK_IM_MODULE");
@@ -76,7 +66,7 @@ void IMTextEntry::CheckIMEnabled()
void IMTextEntry::SetupSimpleIM()
{
im_context_ = gtk_im_context_simple_new();
-
+
sig_manager_.Add(new Signal<void, GtkIMContext*, char*>(im_context_, "commit", sigc::mem_fun(this, &IMTextEntry::OnCommit)));
sig_manager_.Add(new Signal<void, GtkIMContext*>(im_context_, "preedit-changed", sigc::mem_fun(this, &IMTextEntry::OnPreeditChanged)));
sig_manager_.Add(new Signal<void, GtkIMContext*>(im_context_, "preedit-start", sigc::mem_fun(this, &IMTextEntry::OnPreeditStart)));
@@ -86,7 +76,7 @@ void IMTextEntry::SetupSimpleIM()
void IMTextEntry::SetupMultiIM()
{
im_context_ = gtk_im_multicontext_new();
-
+
sig_manager_.Add(new Signal<void, GtkIMContext*, char*>(im_context_, "commit", sigc::mem_fun(this, &IMTextEntry::OnCommit)));
sig_manager_.Add(new Signal<void, GtkIMContext*>(im_context_, "preedit-changed", sigc::mem_fun(this, &IMTextEntry::OnPreeditChanged)));
sig_manager_.Add(new Signal<void, GtkIMContext*>(im_context_, "preedit-start", sigc::mem_fun(this, &IMTextEntry::OnPreeditStart)));
@@ -100,7 +90,7 @@ bool IMTextEntry::InspectKeyEvent(unsigned int event_type,
bool propagate_event = !(TryHandleEvent(event_type, keysym, character));
LOG_DEBUG(logger) << "Input method "
- << (im_enabled ? gtk_im_multicontext_get_context_id(GTK_IM_MULTICONTEXT(im_context_)) : "simple")
+ << (im_enabled ? gtk_im_multicontext_get_context_id(glib::object_cast<GtkIMMulticontext>(im_context_)) : "simple")
<< " "
<< (propagate_event ? "did not handle " : "handled ")
<< "event ("
@@ -224,19 +214,37 @@ void IMTextEntry::Copy()
}
}
-void IMTextEntry::Paste()
+void IMTextEntry::Paste(bool primary)
{
- GtkClipboard* clip = gtk_clipboard_get_for_display(gdk_display_get_default(),
- GDK_SELECTION_CLIPBOARD);
+ GdkAtom origin = primary ? GDK_SELECTION_PRIMARY : GDK_SELECTION_CLIPBOARD;
+ glib::Object<GtkClipboard> clip(gtk_clipboard_get_for_display(gdk_display_get_default(),
+ origin));
auto callback = [](GtkClipboard* clip, const char* text, gpointer user_data)
{
IMTextEntry* self = static_cast<IMTextEntry*>(user_data);
- self->OnCommit (self->im_context_, const_cast<char*>(text));
+ if (text)
+ self->InsertTextAt(self->cursor_, std::string(text));
};
gtk_clipboard_request_text(clip, callback, this);
}
+void IMTextEntry::InsertTextAt(unsigned int position, std::string const& text)
+{
+ DeleteSelection();
+
+ if (!text.empty())
+ {
+ std::string new_text(GetText());
+ new_text.insert(position, text);
+
+ int cursor = position;
+ SetText(new_text.c_str());
+ SetCursor(cursor + text.length());
+ UpdateCursorLocation();
+ }
+}
+
void IMTextEntry::OnCommit(GtkIMContext* context, char* str)
{
LOG_DEBUG(logger) << "Commit: " << str;
@@ -244,13 +252,7 @@ void IMTextEntry::OnCommit(GtkIMContext* context, char* str)
if (str)
{
- std::string new_text = GetText();
- new_text.insert(cursor_, str);
-
- int cursor = cursor_;
- SetText(new_text.c_str());
- SetCursor(cursor + strlen(str));
- UpdateCursorLocation();
+ InsertTextAt(cursor_, std::string(str));
}
}
@@ -265,7 +267,7 @@ void IMTextEntry::OnPreeditChanged(GtkIMContext* context)
preedit_ = preedit.Str();
- if (strlen(preedit.Str().c_str())) {
+ if (!preedit.Str().empty()) {
preedit_cursor_ = preedit.Str().length();
QueueRefresh(true, true);
sigTextChanged.emit(this);
@@ -311,20 +313,28 @@ void IMTextEntry::UpdateCursorLocation()
nux::Rect strong, weak;
GetCursorRects(&strong, &weak);
nux::Geometry geo = GetGeometry();
-
+
GdkRectangle area = { strong.x + geo.x, strong.y + geo.y, strong.width, strong.height };
gtk_im_context_set_cursor_location(im_context_, &area);
}
void IMTextEntry::OnMouseButtonUp(int x, int y, unsigned long bflags, unsigned long kflags)
{
- if (nux::GetEventButton(bflags) == 3 && im_enabled)
+ int button = nux::GetEventButton(bflags);
+
+ if (im_enabled && button == 3)
{
GtkWidget* menu = gtk_menu_new();
- gtk_im_multicontext_append_menuitems(GTK_IM_MULTICONTEXT(im_context_),
- GTK_MENU_SHELL(menu));
+ gtk_im_multicontext_append_menuitems(glib::object_cast<GtkIMMulticontext>(im_context_),
+ GTK_MENU_SHELL(menu));
gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, GDK_CURRENT_TIME);
}
+ else if (button == 2)
+ {
+ SetCursor(XYToTextIndex(x, y));
+ UpdateCursorLocation();
+ Paste(true);
+ }
}
}
diff --git a/plugins/unityshell/src/IMTextEntry.h b/plugins/unityshell/src/IMTextEntry.h
index d36d5b68d..9209c84f5 100644
--- a/plugins/unityshell/src/IMTextEntry.h
+++ b/plugins/unityshell/src/IMTextEntry.h
@@ -26,6 +26,7 @@
#include <Nux/Nux.h>
#include <Nux/TextEntry.h>
#include <UnityCore/GLibSignal.h>
+#include <UnityCore/GLibWrapper.h>
namespace unity
{
@@ -40,7 +41,6 @@ class IMTextEntry : public nux::TextEntry
NUX_DECLARE_OBJECT_TYPE(IMTextEntry, nux::TextEntry);
public:
IMTextEntry();
- ~IMTextEntry();
nux::Property<std::string> preedit_string;
nux::Property<bool> im_enabled;
@@ -56,9 +56,10 @@ private:
void KeyEventToGdkEventKey(Event& event, GdkEventKey& gdk_event);
inline void CheckValidClientWindow(Window window);
bool TryHandleSpecial(unsigned int eventType, unsigned int keysym, const char* character);
+ void InsertTextAt(unsigned int position, std::string const& text);
void Cut();
void Copy();
- void Paste();
+ void Paste(bool primary = false);
void OnCommit(GtkIMContext* context, char* str);
void OnPreeditChanged(GtkIMContext* context);
@@ -73,8 +74,8 @@ private:
private:
glib::SignalManager sig_manager_;
- GtkIMContext* im_context_;
- GdkWindow* client_window_;
+ glib::Object<GtkIMContext> im_context_;
+ glib::Object<GdkWindow> client_window_;
bool focused_;
};
diff --git a/plugins/unityshell/src/IconLoader.cpp b/plugins/unityshell/src/IconLoader.cpp
index 52a4f9956..423a3d6bd 100644
--- a/plugins/unityshell/src/IconLoader.cpp
+++ b/plugins/unityshell/src/IconLoader.cpp
@@ -85,6 +85,9 @@ private:
IconLoaderCallback slot;
Handle handle;
Impl* self;
+ GtkIconInfo* icon_info;
+ GdkPixbuf* result;
+ glib::Error error;
IconLoaderTask(IconLoaderRequestType type_,
std::string const& data_,
@@ -95,6 +98,7 @@ private:
Impl* self_)
: type(type_), data(data_), size(size_), key(key_)
, slot(slot_), handle(handle_), self(self_)
+ , icon_info(NULL), result(NULL)
{}
};
@@ -116,17 +120,20 @@ private:
unsigned size,
IconLoaderCallback slot);
+ // these methods might run asynchronously
bool ProcessTask(IconLoaderTask* task);
bool ProcessIconNameTask(IconLoaderTask* task);
bool ProcessGIconTask(IconLoaderTask* task);
-
- // URI processing is async.
bool ProcessURITask(IconLoaderTask* task);
- void ProcessURITaskReady(IconLoaderTask* task, char* contents, gsize length);
- static void LoadContentsReady(GObject* object, GAsyncResult* res, IconLoaderTask* task);
+
+ // Loading/rendering of pixbufs is done in a separate thread
+ static gboolean LoaderJobFunc(GIOSchedulerJob* job, GCancellable *canc,
+ IconLoaderTask *task);
+ static gboolean LoadIconComplete(IconLoaderTask* task);
+ static gboolean CoalesceTasksCb(IconLoader::Impl* self);
// Loop calls the iteration function.
- static bool Loop(Impl* self);
+ static gboolean Loop(Impl* self);
bool Iteration();
private:
@@ -136,8 +143,11 @@ private:
TaskQueue tasks_;
typedef std::map<Handle, IconLoaderTask*> TaskMap;
TaskMap task_map_;
+ typedef std::vector<IconLoaderTask*> TaskArray;
+ TaskArray finished_tasks_;
guint idle_id_;
+ guint coalesce_id_;
bool no_load_;
GtkIconTheme* theme_; // Not owned.
Handle handle_counter_;
@@ -146,7 +156,8 @@ private:
IconLoader::Impl::Impl()
: idle_id_(0)
- // Option to disable loading, if your testing performance of other things
+ , coalesce_id_(0)
+ // Option to disable loading, if you're testing performance of other things
, no_load_(::getenv("UNITY_ICON_LOADER_DISABLE"))
, theme_(::gtk_icon_theme_get_default())
, handle_counter_(0)
@@ -312,26 +323,17 @@ bool IconLoader::Impl::ProcessTask(IconLoaderTask* task)
bool IconLoader::Impl::ProcessIconNameTask(IconLoaderTask* task)
{
- GdkPixbuf* pixbuf = nullptr;
GtkIconInfo* info = gtk_icon_theme_lookup_icon(theme_,
task->data.c_str(),
task->size,
(GtkIconLookupFlags)0);
if (info)
{
- glib::Error error;
+ task->icon_info = info;
+ g_io_scheduler_push_job ((GIOSchedulerJobFunc) LoaderJobFunc,
+ task, NULL, G_PRIORITY_HIGH_IDLE, NULL);
- pixbuf = gtk_icon_info_load_icon(info, &error);
- if (GDK_IS_PIXBUF(pixbuf))
- {
- cache_[task->key] = pixbuf;
- }
- else
- {
- LOG_WARNING(logger) << "Unable to load icon " << task->data
- << " at size " << task->size << ": " << error;
- }
- gtk_icon_info_free(info);
+ return false;
}
else
{
@@ -339,14 +341,12 @@ bool IconLoader::Impl::ProcessIconNameTask(IconLoaderTask* task)
<< " at size " << task->size;
}
- task->slot(task->data, task->size, pixbuf);
+ task->slot(task->data, task->size, nullptr);
return true;
}
bool IconLoader::Impl::ProcessGIconTask(IconLoaderTask* task)
{
- GdkPixbuf* pixbuf = NULL;
-
glib::Error error;
glib::Object<GIcon> icon(::g_icon_new_for_string(task->data.c_str(), &error));
@@ -368,18 +368,11 @@ bool IconLoader::Impl::ProcessGIconTask(IconLoaderTask* task)
(GtkIconLookupFlags)0);
if (info)
{
- pixbuf = gtk_icon_info_load_icon(info, &error);
+ task->icon_info = info;
+ g_io_scheduler_push_job ((GIOSchedulerJobFunc) LoaderJobFunc,
+ task, NULL, G_PRIORITY_HIGH_IDLE, NULL);
- if (GDK_IS_PIXBUF(pixbuf))
- {
- cache_[task->key] = pixbuf;
- }
- else
- {
- LOG_WARNING(logger) << "Unable to load icon " << task->data
- << " at size " << task->size << ": " << error;
- }
- gtk_icon_info_free(info);
+ return false;
}
else
{
@@ -409,58 +402,119 @@ bool IconLoader::Impl::ProcessGIconTask(IconLoaderTask* task)
<< " at size " << task->size << ": " << error;
}
- task->slot(task->data, task->size, pixbuf);
+ task->slot(task->data, task->size, nullptr);
return true;
}
bool IconLoader::Impl::ProcessURITask(IconLoaderTask* task)
{
- glib::Object<GFile> file(g_file_new_for_uri(task->data.c_str()));
-
- g_file_load_contents_async(file,
- NULL,
- (GAsyncReadyCallback)LoadContentsReady,
- task);
+ g_io_scheduler_push_job ((GIOSchedulerJobFunc) LoaderJobFunc,
+ task, NULL, G_PRIORITY_HIGH_IDLE, NULL);
return false;
}
-void IconLoader::Impl::ProcessURITaskReady(IconLoaderTask* task,
- char* contents,
- gsize length)
+gboolean IconLoader::Impl::LoaderJobFunc(GIOSchedulerJob* job,
+ GCancellable *canc,
+ IconLoaderTask *task)
{
- GInputStream* stream = g_memory_input_stream_new_from_data(contents, length, NULL);
+ // careful here this is running in non-main thread
+ if (task->icon_info)
+ {
+ task->result = gtk_icon_info_load_icon(task->icon_info, &task->error);
- glib::Error error;
- glib::Object<GdkPixbuf> pixbuf(gdk_pixbuf_new_from_stream_at_scale(stream,
- -1,
- task->size,
- true,
- NULL,
- &error));
- if (error)
+ gtk_icon_info_free (task->icon_info);
+ task->icon_info = NULL;
+ }
+ else if (task->type == REQUEST_TYPE_URI)
{
- LOG_WARNING(logger) << "Unable to create pixbuf from input stream for "
- << task->data << " at size " << task->size << ": " << error;
+ glib::Object<GFile> file(g_file_new_for_uri(task->data.c_str()));
+ glib::String contents;
+ gsize length = 0;
+
+ if (g_file_load_contents(file, canc, &contents, &length,
+ NULL, &task->error))
+ {
+ glib::Object<GInputStream> stream(
+ g_memory_input_stream_new_from_data(contents.Value(), length, NULL));
+
+ task->result = gdk_pixbuf_new_from_stream_at_scale(stream,
+ -1,
+ task->size,
+ TRUE,
+ canc,
+ &task->error);
+ g_input_stream_close(stream, canc, NULL);
+ }
}
- else
+
+ g_io_scheduler_job_send_to_mainloop_async (job,
+ (GSourceFunc) LoadIconComplete,
+ task,
+ NULL);
+
+ return FALSE;
+}
+
+// this will be invoked back in the thread from which push_job was called
+gboolean IconLoader::Impl::LoadIconComplete(IconLoaderTask* task)
+{
+ if (task->self->coalesce_id_ == 0)
{
- cache_[task->key] = pixbuf;
+ // we're using lower priority than the GIOSchedulerJob uses to deliver
+ // results to the mainloop
+ task->self->coalesce_id_ =
+ g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE + 10,
+ 40,
+ (GSourceFunc) IconLoader::Impl::CoalesceTasksCb,
+ task->self,
+ NULL);
+ }
+
+ task->self->finished_tasks_.push_back (task);
+
+ return FALSE;
+}
+
+gboolean IconLoader::Impl::CoalesceTasksCb(IconLoader::Impl* self)
+{
+ for (auto task : self->finished_tasks_)
+ {
+ // FIXME: we could update the cache sooner, but there are ref-counting
+ // issues on the pixbuf (and inside the slot callbacks) that prevent us
+ // from doing that.
+ if (GDK_IS_PIXBUF(task->result))
+ {
+ task->self->cache_[task->key] = task->result;
+ }
+ else
+ {
+ LOG_WARNING(logger) << "Unable to load icon " << task->data
+ << " at size " << task->size << ": " << task->error;
+ }
+
+ task->slot(task->data, task->size, task->result);
+
+ // this was all async, we need to erase the task from the task_map
+ self->task_map_.erase(task->handle);
+ delete task;
}
- task->slot(task->data, task->size, pixbuf);
- g_input_stream_close(stream, NULL, NULL);
+ self->finished_tasks_.clear ();
+ self->coalesce_id_ = 0;
+
+ return FALSE;
}
bool IconLoader::Impl::Iteration()
{
- static const int MAX_MICRO_SECS = 10000;
+ static const int MAX_MICRO_SECS = 1000;
util::Timer timer;
bool queue_empty = tasks_.empty();
- while (!queue_empty &&
- (timer.ElapsedMicroSeconds() < MAX_MICRO_SECS))
+ // always do at least one iteration if the queue isn't empty
+ while (!queue_empty)
{
IconLoaderTask* task = tasks_.front();
@@ -472,6 +526,8 @@ bool IconLoader::Impl::Iteration()
tasks_.pop();
queue_empty = tasks_.empty();
+
+ if (timer.ElapsedMicroSeconds() >= MAX_MICRO_SECS) break;
}
LOG_DEBUG(logger) << "Iteration done, queue size now at " << tasks_.size();
@@ -487,34 +543,11 @@ bool IconLoader::Impl::Iteration()
}
-bool IconLoader::Impl::Loop(IconLoader::Impl* self)
+gboolean IconLoader::Impl::Loop(IconLoader::Impl* self)
{
- return self->Iteration();
+ return self->Iteration() ? TRUE : FALSE;
}
-void IconLoader::Impl::LoadContentsReady(GObject* obj,
- GAsyncResult* res,
- IconLoaderTask* task)
-{
- glib::String contents;
- glib::Error error;
- gsize length = 0;
-
- if (g_file_load_contents_finish(G_FILE(obj), res, &contents, &length, NULL, &error))
- {
- task->self->ProcessURITaskReady(task, contents.Value(), length);
- }
- else
- {
- LOG_WARNING(logger) << "Unable to load contents of "
- << task->data << ": " << error;
- task->slot(task->data, task->size, nullptr);
- }
- task->self->task_map_.erase(task->handle);
- delete task;
-}
-
-
IconLoader::IconLoader()
: pimpl(new Impl())
{
diff --git a/plugins/unityshell/src/IconRenderer.cpp b/plugins/unityshell/src/IconRenderer.cpp
index f461b4045..2c6cb41e4 100644
--- a/plugins/unityshell/src/IconRenderer.cpp
+++ b/plugins/unityshell/src/IconRenderer.cpp
@@ -39,6 +39,14 @@ namespace unity
namespace ui
{
+#ifdef USE_GLES
+ #define VertexShaderHeader "#version 100\n"
+ #define FragmentShaderHeader "#version 100\n precision mediump float;\n"
+#else
+ #define VertexShaderHeader "#version 120\n"
+ #define FragmentShaderHeader "#version 110\n"
+#endif
+
/*
Use this shader to pass vertices in screen coordinates in the C++ code and compute use
the fragment shader to perform the texture perspective correct division.
@@ -60,9 +68,9 @@ namespace ui
#define LUMIN_BLUE "0.055"
nux::NString gPerspectiveCorrectShader = TEXT(
-"[Vertex Shader] \n\
-#version 120 \n\
-uniform mat4 ViewProjectionMatrix; \n\
+"[Vertex Shader] \n"
+VertexShaderHeader
+"uniform mat4 ViewProjectionMatrix; \n\
\n\
attribute vec4 iTexCoord0; \n\
attribute vec4 iVertex; \n\
@@ -75,9 +83,9 @@ void main() \n\
gl_Position = ViewProjectionMatrix * iVertex; \n\
} \n\
\n\
-[Fragment Shader] \n\
-#version 110 \n\
- \n\
+[Fragment Shader] \n"
+FragmentShaderHeader
+" \n\
varying vec4 varyTexCoord0; \n\
\n\
uniform sampler2D TextureObject0; \n\
@@ -649,8 +657,13 @@ void IconRenderer::RenderElement(nux::GraphicsEngine& GfxContext,
// Perspective correct
v0.x, v0.y, 0.0f, 1.0f, s0 / v0.w, t0 / v0.w, 0.0f, 1.0f / v0.w,
v1.x, v1.y, 0.0f, 1.0f, s1 / v1.w, t1 / v1.w, 0.0f, 1.0f / v1.w,
+#ifdef USE_GLES
+ v3.x, v3.y, 0.0f, 1.0f, s3 / v3.w, t3 / v3.w, 0.0f, 1.0f / v3.w,
+ v2.x, v2.y, 0.0f, 1.0f, s2 / v2.w, t2 / v2.w, 0.0f, 1.0f / v2.w,
+#else
v2.x, v2.y, 0.0f, 1.0f, s2 / v2.w, t2 / v2.w, 0.0f, 1.0f / v2.w,
v3.x, v3.y, 0.0f, 1.0f, s3 / v3.w, t3 / v3.w, 0.0f, 1.0f / v3.w,
+#endif
};
CHECKGL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
@@ -681,6 +694,7 @@ void IconRenderer::RenderElement(nux::GraphicsEngine& GfxContext,
local::shader_program_uv_persp_correction->SetUniformLocMatrix4fv((GLint)VPMatrixLocation, 1, false, (GLfloat*) & (_stored_projection_matrix.m));
}
}
+#ifndef USE_GLES
else
{
local::asm_shader->Begin();
@@ -698,6 +712,7 @@ void IconRenderer::RenderElement(nux::GraphicsEngine& GfxContext,
CHECKGL(glMatrixMode(GL_PROJECTION));
CHECKGL(glLoadMatrixf((float*) GfxContext.GetOpenGLProjectionMatrix().m));
}
+#endif
CHECKGL(glEnableVertexAttribArrayARB(VertexLocation));
CHECKGL(glVertexAttribPointerARB((GLuint)VertexLocation, 4, GL_FLOAT, GL_FALSE, 32, VtxBuffer));
@@ -716,8 +731,13 @@ void IconRenderer::RenderElement(nux::GraphicsEngine& GfxContext,
CHECKGL(glUniform4fARB(DesatFactor, arg.saturation, arg.saturation, arg.saturation, arg.saturation));
nux::GetWindowThread()->GetGraphicsEngine().SetTexture(GL_TEXTURE0, icon);
+#ifdef USE_GLES
+ CHECKGL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
+#else
CHECKGL(glDrawArrays(GL_QUADS, 0, 4));
+#endif
}
+#ifndef USE_GLES
else
{
CHECKGL(glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, bg_color.red, bg_color.green, bg_color.blue, bg_color.alpha));
@@ -726,6 +746,7 @@ void IconRenderer::RenderElement(nux::GraphicsEngine& GfxContext,
nux::GetWindowThread()->GetGraphicsEngine().SetTexture(GL_TEXTURE0, icon);
CHECKGL(glDrawArrays(GL_QUADS, 0, 4));
}
+#endif
if (VertexLocation != -1)
CHECKGL(glDisableVertexAttribArrayARB(VertexLocation));
diff --git a/plugins/unityshell/src/Introspectable.cpp b/plugins/unityshell/src/Introspectable.cpp
index c4b154a75..889dcf58e 100644
--- a/plugins/unityshell/src/Introspectable.cpp
+++ b/plugins/unityshell/src/Introspectable.cpp
@@ -32,6 +32,8 @@ Introspectable::~Introspectable()
{
for (auto parent : _parents)
parent->_children.remove(this);
+ for (auto child : _children)
+ child->_parents.remove(this);
}
GVariant*
diff --git a/plugins/unityshell/src/Introspectable.h b/plugins/unityshell/src/Introspectable.h
index 4d8f083a9..baa40fde9 100644
--- a/plugins/unityshell/src/Introspectable.h
+++ b/plugins/unityshell/src/Introspectable.h
@@ -41,10 +41,12 @@ public:
void RemoveChild(Introspectable* child);
IntrospectableList const& GetIntrospectableChildren() { return _children; };
virtual void AddProperties(GVariantBuilder* builder) = 0;
-
+
protected:
+ /// Please don't override this unless you really need to. The only valid reason
+ /// is if you have a property that simply *must* be called 'Children'.
virtual std::string GetChildsName() const;
-
+
/*
* AddProperties should be implemented as such ...
diff --git a/plugins/unityshell/src/Launcher.cpp b/plugins/unityshell/src/Launcher.cpp
index c2888803a..7fbbf011b 100644
--- a/plugins/unityshell/src/Launcher.cpp
+++ b/plugins/unityshell/src/Launcher.cpp
@@ -112,8 +112,8 @@ const gchar Launcher::introspection_xml[] =
" <interface name='com.canonical.Unity.Launcher'>"
""
" <method name='AddLauncherItemFromPosition'>"
- " <arg type='s' name='icon' direction='in'/>"
" <arg type='s' name='title' direction='in'/>"
+ " <arg type='s' name='icon' direction='in'/>"
" <arg type='i' name='icon_x' direction='in'/>"
" <arg type='i' name='icon_y' direction='in'/>"
" <arg type='i' name='icon_size' direction='in'/>"
@@ -2607,9 +2607,17 @@ void Launcher::SelectPreviousIcon()
{
_current_icon_index = temp_current_icon_index;
- if ((*it)->GetCenter().y + - _icon_size/ 2 < GetGeometry().y)
+ if ((*it)->GetCenter().y - _icon_size / 2 < GetGeometry().y)
+ {
_launcher_drag_delta += (_icon_size + _space_between_icons);
+ }
+ else if ((*it)->GetCenter().y + _icon_size / 2 > GetGeometry().height)
+ {
+ _launcher_drag_delta -= (*it)->GetCenter().y + _icon_size/2 +
+ _space_between_icons - GetGeometry().height;
+ }
}
+
EnsureAnimation();
selection_change.emit();
}
@@ -2635,7 +2643,13 @@ void Launcher::SelectNextIcon()
_current_icon_index = temp_current_icon_index;
if ((*it)->GetCenter().y + _icon_size / 2 > GetGeometry().height)
+ {
_launcher_drag_delta -= (_icon_size + _space_between_icons);
+ }
+ else if ((*it)->GetCenter().y - _icon_size / 2 < GetGeometry().y)
+ {
+ _launcher_drag_delta += GetGeometry().y - ((*it)->GetCenter().y - _icon_size);
+ }
}
EnsureAnimation();
@@ -2685,6 +2699,15 @@ void Launcher::KeySwitcherTerminate()
selection_change.emit();
}
+void Launcher::KeySwitcherCancel()
+{
+ if (!_key_switcher_activated)
+ return;
+
+ _current_icon_index = -1;
+ KeySwitcherTerminate();
+}
+
bool Launcher::KeySwitcherIsActive()
{
return _key_switcher_activated;
@@ -2695,6 +2718,11 @@ void Launcher::KeySwitcherNext()
if (!_key_switcher_activated)
return;
+ if (_current_icon_index == _model->Size() - 1)
+ {
+ _current_icon_index = -1;
+ }
+
SelectNextIcon();
}
@@ -2703,6 +2731,11 @@ void Launcher::KeySwitcherPrevious()
if (!_key_switcher_activated)
return;
+ if (_current_icon_index == 0)
+ {
+ _current_icon_index = _model->Size();
+ }
+
SelectPreviousIcon();
}
@@ -2862,13 +2895,9 @@ void Launcher::MouseDownLogic(int x, int y, unsigned long button_flags, unsigned
_start_dragicon_handle = g_timeout_add(START_DRAGICON_DURATION, &Launcher::StartIconDragTimeout, this);
launcher_icon->mouse_down.emit(nux::GetEventButton(button_flags));
-
- if (_key_switcher_activated)
- {
- _current_icon_index = -1;
- KeySwitcherTerminate();
- }
}
+
+ KeySwitcherCancel();
}
void Launcher::MouseUpLogic(int x, int y, unsigned long button_flags, unsigned long key_flags)
@@ -3301,10 +3330,10 @@ Launcher::handle_dbus_method_call(GDBusConnection* connection,
gchar* desktop_file;
gchar* aptdaemon_task;
- g_variant_get(parameters, "(ssiiiss)", &icon, &title, &icon_x, &icon_y, &icon_size, &desktop_file, &aptdaemon_task, NULL);
+ g_variant_get(parameters, "(ssiiiss)", &title, &icon, &icon_x, &icon_y, &icon_size, &desktop_file, &aptdaemon_task, NULL);
Launcher* self = (Launcher*)user_data;
- self->launcher_addrequest.emit(desktop_file, NULL);
+ self->launcher_addrequest_special.emit(desktop_file, NULL, aptdaemon_task, icon);
g_dbus_method_invocation_return_value(invocation, NULL);
g_free(icon);
diff --git a/plugins/unityshell/src/Launcher.h b/plugins/unityshell/src/Launcher.h
index 2b7b3bb76..6cec077ef 100644
--- a/plugins/unityshell/src/Launcher.h
+++ b/plugins/unityshell/src/Launcher.h
@@ -196,6 +196,7 @@ public:
void EnableCheckWindowOverLauncher(gboolean enabled);
sigc::signal<void, char*, LauncherIcon*> launcher_addrequest;
+ sigc::signal<void, char*, LauncherIcon*, char*, char*> launcher_addrequest_special;
sigc::signal<void, LauncherIcon*> launcher_removerequest;
sigc::signal<void> selection_change;
sigc::signal<void> hidden_changed;
@@ -210,6 +211,7 @@ public:
void KeySwitcherActivate();
void KeySwitcherTerminate();
+ void KeySwitcherCancel();
bool KeySwitcherIsActive();
void KeySwitcherNext();
void KeySwitcherPrevious();
diff --git a/plugins/unityshell/src/LauncherController.cpp b/plugins/unityshell/src/LauncherController.cpp
index 458dbff60..a06ab3042 100644
--- a/plugins/unityshell/src/LauncherController.cpp
+++ b/plugins/unityshell/src/LauncherController.cpp
@@ -38,12 +38,12 @@
#include "LauncherEntryRemote.h"
#include "LauncherEntryRemoteModel.h"
#include "LauncherIcon.h"
+#include "SoftwareCenterLauncherIcon.h"
#include "LauncherModel.h"
#include "WindowManager.h"
#include "TrashLauncherIcon.h"
#include "BFBLauncherIcon.h"
-
namespace unity
{
namespace launcher
@@ -68,10 +68,16 @@ public:
void OnIconRemoved(LauncherIcon* icon);
void OnLauncherAddRequest(char* path, LauncherIcon* before);
+ void OnLauncherAddRequestSpecial(char* path, LauncherIcon* before, char* aptdaemon_trans_id, char* icon_path);
void OnLauncherRemoveRequest(LauncherIcon* icon);
void OnLauncherEntryRemoteAdded(LauncherEntryRemote* entry);
void OnLauncherEntryRemoteRemoved(LauncherEntryRemote* 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();
@@ -85,6 +91,8 @@ public:
LauncherIcon* CreateFavorite(const char* file_path);
+ SoftwareCenterLauncherIcon* CreateSCLauncherIcon(const char* file_path, const char* aptdaemon_trans_id, char* icon_path);
+
void SetupBamf();
void OnExpoActivated();
@@ -148,6 +156,7 @@ Controller::Impl::Impl(Display* display)
launcher_->SetModel(model_.get());
launcher_->launcher_addrequest.connect(sigc::mem_fun(this, &Impl::OnLauncherAddRequest));
+ launcher_->launcher_addrequest_special.connect(sigc::mem_fun(this, &Impl::OnLauncherAddRequestSpecial));
launcher_->launcher_removerequest.connect(sigc::mem_fun(this, &Impl::OnLauncherRemoveRequest));
device_section_ = new DeviceLauncherSection(raw_launcher);
@@ -175,6 +184,10 @@ Controller::Impl::Impl(Display* display)
remote_model_.entry_added.connect(sigc::mem_fun(this, &Impl::OnLauncherEntryRemoteAdded));
remote_model_.entry_removed.connect(sigc::mem_fun(this, &Impl::OnLauncherEntryRemoteRemoved));
+
+ FavoriteStore::GetDefault().favorite_added.connect(sigc::mem_fun(this, &Impl::OnFavoriteStoreFavoriteAdded));
+ FavoriteStore::GetDefault().favorite_removed.connect(sigc::mem_fun(this, &Impl::OnFavoriteStoreFavoriteRemoved));
+ FavoriteStore::GetDefault().reordered.connect(sigc::mem_fun(this, &Impl::OnFavoriteStoreReordered));
RegisterIcon(new BFBLauncherIcon(raw_launcher));
desktop_icon_ = new DesktopLauncherIcon(raw_launcher);
@@ -236,6 +249,30 @@ void Controller::Impl::Save()
unity::FavoriteStore::GetDefault().SetFavorites(desktop_paths);
}
+void
+Controller::Impl::OnLauncherAddRequestSpecial(char* path, LauncherIcon* before, char* aptdaemon_trans_id, char* icon_path)
+{
+ std::list<BamfLauncherIcon*> launchers;
+ std::list<BamfLauncherIcon*>::iterator it;
+
+ launchers = model_->GetSublist<BamfLauncherIcon> ();
+ for (it = launchers.begin(); it != launchers.end(); it++)
+ {
+ if (g_strcmp0(path, (*it)->DesktopFile()) == 0)
+ return;
+ }
+
+ SoftwareCenterLauncherIcon* result = CreateSCLauncherIcon(path, aptdaemon_trans_id, icon_path);
+ if (result)
+ {
+ RegisterIcon(result);
+
+ if (before)
+ model_->ReorderBefore(result, before, false);
+ }
+ Save();
+}
+
void Controller::Impl::SortAndUpdate()
{
gint shortcut = 1;
@@ -321,6 +358,82 @@ void Controller::Impl::OnLauncherEntryRemoteRemoved(LauncherEntryRemote* entry)
}
}
+void Controller::Impl::OnFavoriteStoreFavoriteAdded(std::string const& entry, std::string const& pos, bool before)
+{
+ auto bamf_list = model_->GetSublist<BamfLauncherIcon>();
+ LauncherIcon* other = (bamf_list.size() > 0) ? *(bamf_list.begin()) : nullptr;
+
+ if (!pos.empty())
+ {
+ for (auto it : bamf_list)
+ {
+ if (it->GetQuirk(LauncherIcon::QUIRK_VISIBLE) && pos == it->DesktopFile())
+ other = it;
+ }
+ }
+
+ for (auto it : bamf_list)
+ {
+ if (entry == it->DesktopFile())
+ {
+ it->Stick(false);
+ if (!before)
+ model_->ReorderAfter(it, other);
+ else
+ model_->ReorderBefore(it, other, false);
+ return;
+ }
+ }
+
+ LauncherIcon* result = CreateFavorite(entry.c_str());
+ if (result)
+ {
+ RegisterIcon(result);
+ if (!before)
+ model_->ReorderAfter(result, other);
+ else
+ model_->ReorderBefore(result, other, false);
+ }
+}
+
+void Controller::Impl::OnFavoriteStoreFavoriteRemoved(std::string const& entry)
+{
+ for (auto it : model_->GetSublist<BamfLauncherIcon> ())
+ {
+ if (it->DesktopFile() == entry)
+ {
+ OnLauncherRemoveRequest(it);
+ break;
+ }
+ }
+}
+
+void Controller::Impl::OnFavoriteStoreReordered()
+{
+ FavoriteList const& favs = FavoriteStore::GetDefault().GetFavorites();
+ auto bamf_list = model_->GetSublist<BamfLauncherIcon>();
+
+ int i = 0;
+ for (auto it : favs)
+ {
+ auto icon = std::find_if(bamf_list.begin(), bamf_list.end(),
+ [&it](BamfLauncherIcon* x) { return (x->DesktopFile() == it); });
+
+ if (icon != bamf_list.end())
+ {
+ (*icon)->SetSortPriority(i++);
+ }
+ }
+
+ for (auto it : bamf_list)
+ {
+ if (!it->IsSticky())
+ it->SetSortPriority(i++);
+ }
+
+ model_->Sort();
+}
+
void Controller::Impl::OnExpoActivated()
{
WindowManager::Default()->InitiateExpo();
@@ -450,6 +563,32 @@ LauncherIcon* Controller::Impl::CreateFavorite(const char* file_path)
return icon;
}
+SoftwareCenterLauncherIcon*
+Controller::Impl::CreateSCLauncherIcon(const char* file_path, const char* aptdaemon_trans_id, char* icon_path)
+{
+ BamfApplication* app;
+ SoftwareCenterLauncherIcon* icon;
+
+ app = bamf_matcher_get_application_for_desktop_file(matcher_, file_path, true);
+ if (!BAMF_IS_APPLICATION(app))
+ return NULL;
+
+ if (g_object_get_qdata(G_OBJECT(app), g_quark_from_static_string("unity-seen")))
+ {
+ bamf_view_set_sticky(BAMF_VIEW(app), true);
+ return 0;
+ }
+
+ g_object_set_qdata(G_OBJECT(app), g_quark_from_static_string("unity-seen"), GINT_TO_POINTER(1));
+
+ bamf_view_set_sticky(BAMF_VIEW(app), true);
+ icon = new SoftwareCenterLauncherIcon(launcher_.GetPointer(), app, (char*)aptdaemon_trans_id, icon_path);
+ icon->SetIconType(LauncherIcon::TYPE_APPLICATION);
+ icon->SetSortPriority(sort_priority_++);
+
+ return icon;
+}
+
void Controller::Impl::SetupBamf()
{
GList* apps, *l;
diff --git a/plugins/unityshell/src/LauncherController.h b/plugins/unityshell/src/LauncherController.h
index 5da5d1378..d8492a2ad 100644
--- a/plugins/unityshell/src/LauncherController.h
+++ b/plugins/unityshell/src/LauncherController.h
@@ -26,6 +26,8 @@
#include <sigc++/sigc++.h>
#include <core/core.h>
+#include "SoftwareCenterLauncherIcon.h"
+
namespace unity
{
namespace launcher
diff --git a/plugins/unityshell/src/LauncherModel.cpp b/plugins/unityshell/src/LauncherModel.cpp
index dc862b76a..ea9769bc6 100644
--- a/plugins/unityshell/src/LauncherModel.cpp
+++ b/plugins/unityshell/src/LauncherModel.cpp
@@ -66,19 +66,17 @@ LauncherModel::Populate()
_inner.clear();
- iterator it, it2;
-
int i = 0;
- for (it = main_begin(); it != main_end(); it++)
+ for (auto icon : _inner_main)
{
- _inner.push_back(*it);
- (*it)->SetSortPriority(i++);
+ _inner.push_back(icon);
+ icon->SetSortPriority(i++);
}
- for (it = shelf_begin(); it != shelf_end(); it++)
+ for (auto icon : _inner_shelf)
{
- _inner.push_back(*it);
- (*it)->SetSortPriority(i++);
+ _inner.push_back(icon);
+ icon->SetSortPriority(i++);
}
return !std::equal(begin(), end(), copy.begin());
@@ -190,40 +188,68 @@ LauncherModel::IconHasSister(LauncherIcon* icon)
}
void
-LauncherModel::ReorderBefore(LauncherIcon* icon, LauncherIcon* other, bool save)
+LauncherModel::ReorderAfter(LauncherIcon* icon, LauncherIcon* other)
{
if (icon == other)
return;
- LauncherModel::iterator it;
+ int i = 0;
+ for (LauncherModel::iterator it = begin(); it != end(); ++it)
+ {
+ if ((*it) == icon)
+ continue;
+
+ if ((*it) == other)
+ {
+ (*it)->SetSortPriority(i);
+ ++i;
+
+ icon->SetSortPriority(i);
+ ++i;
+ }
+ else
+ {
+ (*it)->SetSortPriority(i);
+ ++i;
+ }
+ }
+
+ Sort();
+}
+
+void
+LauncherModel::ReorderBefore(LauncherIcon* icon, LauncherIcon* other, bool save)
+{
+ if (icon == other)
+ return;
int i = 0;
int j = 0;
- for (it = begin(); it != end(); it++)
+ for (auto icon_it : _inner)
{
- if ((*it) == icon)
+ if (icon_it == icon)
{
j++;
continue;
}
- if ((*it) == other)
+ if (icon_it == other)
{
icon->SetSortPriority(i);
if (i != j && save)
- (*it)->SaveCenter();
+ icon_it->SaveCenter();
i++;
- (*it)->SetSortPriority(i);
+ icon_it->SetSortPriority(i);
if (i != j && save)
- (*it)->SaveCenter();
+ icon_it->SaveCenter();
i++;
}
else
{
- (*it)->SetSortPriority(i);
+ icon_it->SetSortPriority(i);
if (i != j && save)
- (*it)->SaveCenter();
+ icon_it->SaveCenter();
i++;
}
j++;
@@ -238,48 +264,46 @@ LauncherModel::ReorderSmart(LauncherIcon* icon, LauncherIcon* other, bool save)
if (icon == other)
return;
- LauncherModel::iterator it;
-
int i = 0;
int j = 0;
bool skipped = false;
- for (it = begin(); it != end(); it++)
+ for (auto icon_it : _inner)
{
- if ((*it) == icon)
+ if (icon_it == icon)
{
skipped = true;
j++;
continue;
}
- if ((*it) == other)
+ if (icon_it == other)
{
if (!skipped)
{
icon->SetSortPriority(i);
if (i != j && save)
- (*it)->SaveCenter();
+ icon_it->SaveCenter();
i++;
}
- (*it)->SetSortPriority(i);
+ icon_it->SetSortPriority(i);
if (i != j && save)
- (*it)->SaveCenter();
+ icon_it->SaveCenter();
i++;
if (skipped)
{
icon->SetSortPriority(i);
if (i != j && save)
- (*it)->SaveCenter();
+ icon_it->SaveCenter();
i++;
}
}
else
{
- (*it)->SetSortPriority(i);
+ icon_it->SetSortPriority(i);
if (i != j && save)
- (*it)->SaveCenter();
+ icon_it->SaveCenter();
i++;
}
j++;
diff --git a/plugins/unityshell/src/LauncherModel.h b/plugins/unityshell/src/LauncherModel.h
index fa27fb011..e2113f3ea 100644
--- a/plugins/unityshell/src/LauncherModel.h
+++ b/plugins/unityshell/src/LauncherModel.h
@@ -51,6 +51,7 @@ public:
bool IconHasSister(LauncherIcon* icon);
+ void ReorderAfter(LauncherIcon* icon, LauncherIcon* other);
void ReorderBefore(LauncherIcon* icon, LauncherIcon* other, bool save);
void ReorderSmart(LauncherIcon* icon, LauncherIcon* other, bool save);
diff --git a/plugins/unityshell/src/LensBar.cpp b/plugins/unityshell/src/LensBar.cpp
index 65627990d..d28d0d0e0 100644
--- a/plugins/unityshell/src/LensBar.cpp
+++ b/plugins/unityshell/src/LensBar.cpp
@@ -148,10 +148,20 @@ void LensBar::DrawContent(nux::GraphicsEngine& gfx_context, bool force_draw)
void LensBar::SetActive(LensBarIcon* activated)
{
+ bool state_changed = false;
+
for (auto icon: icons_)
- icon->active = icon == activated;
+ {
+ bool state = icon == activated;
+
+ if (icon->active != state)
+ state_changed = true;
+
+ icon->active = state;
+ }
- lens_activated.emit(activated->id);
+ if (state_changed)
+ lens_activated.emit(activated->id);
}
void LensBar::ActivateNext()
diff --git a/plugins/unityshell/src/LensView.cpp b/plugins/unityshell/src/LensView.cpp
index d7d35920c..b3ddda08d 100644
--- a/plugins/unityshell/src/LensView.cpp
+++ b/plugins/unityshell/src/LensView.cpp
@@ -219,7 +219,12 @@ void LensView::OnCategoryAdded(Category const& category)
group->SetExpanded(false);
group->SetVisible(false);
group->expanded.connect(sigc::mem_fun(this, &LensView::OnGroupExpanded));
- categories_.push_back(group);
+
+
+ /* Add the group at the correct offset into the categories vector */
+ categories_.insert(categories_.begin() + index, group);
+
+ /* Reset result count */
counts_[group] = 0;
ResultViewGrid* grid = new ResultViewGrid(NUX_TRACKER_LOCATION);
@@ -232,7 +237,11 @@ void LensView::OnCategoryAdded(Category const& category)
grid->UriActivated.connect([&] (std::string const& uri) { uri_activated.emit(uri); lens_->Activate(uri); });
group->SetChildView(grid);
- scroll_layout_->AddView(group, 0);
+ /* We need the full range of method args so we can specify the offset
+ * of the group into the layout */
+ scroll_layout_->AddView(group, 0, nux::MinorDimensionPosition::eAbove,
+ nux::MinorDimensionSize::eFull, 100.0f,
+ (nux::LayoutPosition)index);
}
void LensView::OnResultAdded(Result const& result)
diff --git a/plugins/unityshell/src/PanelController.cpp b/plugins/unityshell/src/PanelController.cpp
index 54c7c22ee..af40a0155 100644
--- a/plugins/unityshell/src/PanelController.cpp
+++ b/plugins/unityshell/src/PanelController.cpp
@@ -36,7 +36,7 @@ namespace
nux::logging::Logger logger("unity.panel");
}
-class Controller::Impl : public sigc::trackable
+class Controller::Impl
{
public:
Impl();
@@ -58,14 +58,15 @@ public:
void SetMenuShowTimings(int fadein, int fadeout, int discovery,
int discovery_fadein, int discovery_fadeout);
+ void OnScreenChanged(int primary_monitor, std::vector<nux::Geometry>& monitors, Introspectable *iobj);
private:
unity::PanelView* ViewForWindow(nux::BaseWindow* window);
- void OnScreenChanged(int primary_monitor, std::vector<nux::Geometry>& monitors);
static void WindowConfigureCallback(int window_width,
int window_height,
nux::Geometry& geo,
void* user_data);
+
private:
std::vector<nux::BaseWindow*> windows_;
float opacity_;
@@ -89,9 +90,6 @@ Controller::Impl::Impl()
, menus_discovery_fadein_(0)
, menus_discovery_fadeout_(0)
{
- UScreen* screen = UScreen::GetDefault();
- screen->changed.connect(sigc::mem_fun(this, &Impl::OnScreenChanged));
- OnScreenChanged(screen->GetPrimaryMonitor(), screen->GetMonitors());
}
Controller::Impl::~Impl()
@@ -200,7 +198,8 @@ PanelView* Controller::Impl::ViewForWindow(nux::BaseWindow* window)
// We need to put a panel on every monitor, and try and re-use the panels we already have
void Controller::Impl::OnScreenChanged(int primary_monitor,
- std::vector<nux::Geometry>& monitors)
+ std::vector<nux::Geometry>& monitors,
+ Introspectable *iobj)
{
std::vector<nux::BaseWindow*>::iterator it, eit = windows_.end();
int n_monitors = monitors.size();
@@ -270,6 +269,9 @@ void Controller::Impl::OnScreenChanged(int primary_monitor,
windows_.push_back(window);
+ // add to introspectable tree:
+ iobj->AddChild(view);
+
LOG_DEBUG(logger) << "Added Panel for Monitor " << i;
}
}
@@ -301,10 +303,12 @@ float Controller::Impl::opacity() const
return opacity_;
}
-
Controller::Controller()
: pimpl(new Impl())
{
+ UScreen* screen = UScreen::GetDefault();
+ screen->changed.connect(sigc::mem_fun(this, &Controller::OnScreenChanged));
+ OnScreenChanged(screen->GetPrimaryMonitor(), screen->GetMonitors());
}
Controller::~Controller()
@@ -358,6 +362,20 @@ float Controller::opacity() const
return pimpl->opacity();
}
+std::string Controller::GetName() const
+{
+ return "PanelController";
+}
+
+void Controller::AddProperties(GVariantBuilder* builder)
+{
+ g_variant_builder_add(builder, "{sv}", "opacity", g_variant_new_double(pimpl->opacity()));
+}
+
+void Controller::OnScreenChanged(int primary_monitor, std::vector<nux::Geometry>& monitors)
+{
+ pimpl->OnScreenChanged(primary_monitor, monitors, this);
+}
} // namespace panel
} // namespace unity
diff --git a/plugins/unityshell/src/PanelController.h b/plugins/unityshell/src/PanelController.h
index e41dab9b4..0b76f2fe0 100644
--- a/plugins/unityshell/src/PanelController.h
+++ b/plugins/unityshell/src/PanelController.h
@@ -25,12 +25,13 @@
#include <Nux/Nux.h>
+#include "Introspectable.h"
namespace unity
{
namespace panel
{
-class Controller
+class Controller : public sigc::trackable, public unity::debug::Introspectable
{
public:
typedef std::shared_ptr<Controller> Ptr;
@@ -52,7 +53,10 @@ public:
float opacity() const;
+ std::string GetName() const;
+ void AddProperties(GVariantBuilder* builder);
private:
+ void OnScreenChanged(int primary_monitor, std::vector<nux::Geometry>& monitors);
class Impl;
Impl* pimpl;
};
diff --git a/plugins/unityshell/src/PanelIndicatorsView.cpp b/plugins/unityshell/src/PanelIndicatorsView.cpp
index ca7f533f3..f328b09fa 100644
--- a/plugins/unityshell/src/PanelIndicatorsView.cpp
+++ b/plugins/unityshell/src/PanelIndicatorsView.cpp
@@ -340,11 +340,6 @@ std::string PanelIndicatorsView::GetName() const
return "IndicatorsView";
}
-std::string PanelIndicatorsView::GetChildsName() const
-{
- return "entries";
-}
-
void
PanelIndicatorsView::AddProperties(GVariantBuilder* builder)
{
diff --git a/plugins/unityshell/src/PanelIndicatorsView.h b/plugins/unityshell/src/PanelIndicatorsView.h
index 284fca95d..9f7383a0d 100644
--- a/plugins/unityshell/src/PanelIndicatorsView.h
+++ b/plugins/unityshell/src/PanelIndicatorsView.h
@@ -83,7 +83,6 @@ protected:
Entries entries_;
std::string GetName() const;
- std::string GetChildsName() const;
void AddProperties(GVariantBuilder* builder);
private:
diff --git a/plugins/unityshell/src/PanelView.cpp b/plugins/unityshell/src/PanelView.cpp
index dccb4ad5e..29a502dff 100644
--- a/plugins/unityshell/src/PanelView.cpp
+++ b/plugins/unityshell/src/PanelView.cpp
@@ -205,11 +205,6 @@ std::string PanelView::GetName() const
return "UnityPanel";
}
-std::string PanelView::GetChildsName() const
-{
- return "indicators";
-}
-
void PanelView::AddProperties(GVariantBuilder* builder)
{
variant::BuilderWrapper(builder)
diff --git a/plugins/unityshell/src/PanelView.h b/plugins/unityshell/src/PanelView.h
index 8880e2a86..66804b116 100644
--- a/plugins/unityshell/src/PanelView.h
+++ b/plugins/unityshell/src/PanelView.h
@@ -81,7 +81,6 @@ public:
protected:
// Introspectable methods
std::string GetName() const;
- std::string GetChildsName() const;
void AddProperties(GVariantBuilder* builder);
private:
diff --git a/plugins/unityshell/src/PlacesGroup.cpp b/plugins/unityshell/src/PlacesGroup.cpp
index 83f7d9b43..5da93b3ce 100644
--- a/plugins/unityshell/src/PlacesGroup.cpp
+++ b/plugins/unityshell/src/PlacesGroup.cpp
@@ -44,10 +44,13 @@
#include "DashStyle.h"
-static const nux::Color kExpandDefaultTextColor(1.0f, 1.0f, 1.0f, 0.5f);
-static const nux::Color kExpandHoverTextColor(1.0f, 1.0f, 1.0f, 1.0f);
-static const float kExpandDefaultIconOpacity = 0.5f;
-static const float kExpandHoverIconOpacity = 1.0f;
+namespace
+{
+const nux::Color kExpandDefaultTextColor(1.0f, 1.0f, 1.0f, 0.5f);
+const nux::Color kExpandHoverTextColor(1.0f, 1.0f, 1.0f, 1.0f);
+const float kExpandDefaultIconOpacity = 0.5f;
+const float kExpandHoverIconOpacity = 1.0f;
+}
namespace unity
{
diff --git a/plugins/unityshell/src/PlacesHomeView.cpp b/plugins/unityshell/src/PlacesHomeView.cpp
deleted file mode 100644
index 073d1bff5..000000000
--- a/plugins/unityshell/src/PlacesHomeView.cpp
+++ /dev/null
@@ -1,378 +0,0 @@
-// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
-/*
- * Copyright (C) 2010 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: Neil Jagdish Patel <neil.patel@canonical.com>
- */
-
-#include "config.h"
-
-#include <Nux/Nux.h>
-#include <Nux/BaseWindow.h>
-#include <Nux/HLayout.h>
-#include <Nux/Layout.h>
-#include <Nux/WindowCompositor.h>
-
-#include <NuxImage/CairoGraphics.h>
-#include <NuxImage/ImageSurface.h>
-
-#include <NuxGraphics/GLThread.h>
-#include <NuxGraphics/RenderingPipe.h>
-
-#include <glib.h>
-#include <glib/gi18n-lib.h>
-#include <gio/gdesktopappinfo.h>
-#include "ubus-server.h"
-#include "UBusMessages.h"
-
-#include "PlacesHomeView.h"
-#include "PlacesSimpleTile.h"
-
-#include "DashStyle.h"
-#include <UnityCore/GLibWrapper.h>
-#include <UnityCore/Variant.h>
-
-#include <string>
-#include <vector>
-
-#define DELTA_DOUBLE_REQUEST 500000000
-
-namespace unity
-{
-
-enum
-{
- TYPE_PLACE = 0,
- TYPE_EXEC
-};
-
-class Shortcut : public PlacesSimpleTile
-{
-public:
- Shortcut(const char* icon, const char* name, int size)
- : PlacesSimpleTile(icon, name, size),
- _id(0),
- _place_id(NULL),
- _place_section(0),
- _exec(NULL)
- {
- SetDndEnabled(false, false);
- }
-
- ~Shortcut()
- {
- g_free(_place_id);
- g_free(_exec);
- }
-
- int _id;
- gchar* _place_id;
- guint32 _place_section;
- char* _exec;
-};
-
-PlacesHomeView::PlacesHomeView()
- : _ubus_handle(0)
-{
- dash::Style& style = dash::Style::Instance();
-
- SetName(_("Shortcuts"));
- SetIcon(PKGDATADIR"/shortcuts_group_icon.png");
- SetDrawSeparator(false);
-
- _layout = new nux::GridHLayout(NUX_TRACKER_LOCATION);
- _layout->SetReconfigureParentLayoutOnGeometryChange(true);
- SetChildLayout(_layout);
-
- _layout->ForceChildrenSize(true);
- _layout->SetChildrenSize(style.GetHomeTileWidth(), style.GetHomeTileHeight());
- _layout->EnablePartialVisibility(false);
- _layout->MatchContentSize(true);
- _layout->SetLeftAndRightPadding(32);
- _layout->SetSpaceBetweenChildren(32, 32);
- _layout->SetMinMaxSize((style.GetHomeTileWidth() * 4) + (32 * 5),
- (style.GetHomeTileHeight() * 2) + 32);
-
- _ubus_handle = ubus_server_register_interest(ubus_server_get_default(),
- UBUS_PLACE_VIEW_SHOWN,
- (UBusCallback) &PlacesHomeView::DashVisible,
- this);
-
- //In case the GConf key is invalid (e.g. when an app was uninstalled), we
- //rely on a fallback "whitelist" mechanism instead of showing nothing at all
- _browser_alternatives.push_back("firefox");
- _browser_alternatives.push_back("chromium-browser");
- _browser_alternatives.push_back("epiphany-browser");
- _browser_alternatives.push_back("midori");
-
- _photo_alternatives.push_back("shotwell");
- _photo_alternatives.push_back("f-spot");
- _photo_alternatives.push_back("gthumb");
- _photo_alternatives.push_back("gwenview");
- _photo_alternatives.push_back("eog");
-
- _email_alternatives.push_back("evolution");
- _email_alternatives.push_back("thunderbird");
- _email_alternatives.push_back("claws-mail");
- _email_alternatives.push_back("kmail");
-
- _music_alternatives.push_back("banshee-1");
- _music_alternatives.push_back("rhythmbox");
- _music_alternatives.push_back("totem");
- _music_alternatives.push_back("vlc");
-
- expanded.connect(sigc::mem_fun(this, &PlacesHomeView::Refresh));
-
- Refresh();
-}
-
-PlacesHomeView::~PlacesHomeView()
-{
- if (_ubus_handle != 0)
- ubus_server_unregister_interest(ubus_server_get_default(), _ubus_handle);
-}
-
-void
-PlacesHomeView::DashVisible(GVariant* data, void* val)
-{
- PlacesHomeView* self = (PlacesHomeView*)val;
- self->Refresh();
-}
-
-void
-PlacesHomeView::Refresh(PlacesGroup*foo)
-{
- Shortcut* shortcut = NULL;
- gchar* markup = NULL;
- const char* temp = "<big>%s</big>";
- int icon_size = dash::Style::Instance().GetHomeTileIconSize();
-
- _layout->Clear();
-
- // Media Apps
- markup = g_strdup_printf(temp, _("Media Apps"));
- shortcut = new Shortcut(PKGDATADIR"/find_media_apps.png",
- markup,
- icon_size);
- shortcut->_id = TYPE_PLACE;
- shortcut->_place_id = g_strdup("applications.lens?filter_type=media");
- shortcut->_place_section = 9;
- _layout->AddView(shortcut, 1, nux::eLeft, nux::eFull);
- shortcut->sigClick.connect(sigc::mem_fun(this, &PlacesHomeView::OnShortcutClicked));
- g_free(markup);
-
- // Internet Apps
- markup = g_strdup_printf(temp, _("Internet Apps"));
- shortcut = new Shortcut(PKGDATADIR"/find_internet_apps.png",
- markup,
- icon_size);
- shortcut->_id = TYPE_PLACE;
- shortcut->_place_id = g_strdup("applications.lens?filter_type=internet");
- shortcut->_place_section = 8;
- _layout->AddView(shortcut, 1, nux::eLeft, nux::eFull);
- shortcut->sigClick.connect(sigc::mem_fun(this, &PlacesHomeView::OnShortcutClicked));
- g_free(markup);
-
- // More Apps
- markup = g_strdup_printf(temp, _("More Apps"));
- shortcut = new Shortcut(PKGDATADIR"/find_more_apps.png",
- markup,
- icon_size);
- shortcut->_id = TYPE_PLACE;
- shortcut->_place_id = g_strdup("applications.lens");
- shortcut->_place_section = 0;
- _layout->AddView(shortcut, 1, nux::eLeft, nux::eFull);
- shortcut->sigClick.connect(sigc::mem_fun(this, &PlacesHomeView::OnShortcutClicked));
- g_free(markup);
-
- // Find Files
- markup = g_strdup_printf(temp, _("Find Files"));
- shortcut = new Shortcut(PKGDATADIR"/find_files.png",
- markup,
- icon_size);
- shortcut->_id = TYPE_PLACE;
- shortcut->_place_id = g_strdup("files.lens");
- shortcut->_place_section = 0;
- _layout->AddView(shortcut, 1, nux::eLeft, nux::eFull);
- shortcut->sigClick.connect(sigc::mem_fun(this, &PlacesHomeView::OnShortcutClicked));
- g_free(markup);
-
- // Browser
- CreateShortcutFromMime("x-scheme-handler/http", _("Browse the Web"), _browser_alternatives);
-
- // Photos
- // FIXME: Need to figure out the default
- CreateShortcutFromExec("shotwell", _("View Photos"), _photo_alternatives);
-
- CreateShortcutFromMime("x-scheme-handler/mailto", _("Check Email"), _email_alternatives);
-
- CreateShortcutFromMime("audio/x-vorbis+ogg", _("Listen to Music"), _music_alternatives);
-
- SetExpanded(true);
- SetCounts(8, 8);
-
- QueueDraw();
- _layout->QueueDraw();
- QueueRelayout();
-}
-
-void
-PlacesHomeView::CreateShortcutFromExec(const char* exec,
- const char* name,
- std::vector<std::string>& alternatives)
-{
- dash::Style& style = dash::Style::Instance();
- Shortcut* shortcut = NULL;
- gchar* id;
- gchar* markup;
- gchar* icon;
- gchar* real_exec;
- GDesktopAppInfo* info;
-
- markup = g_strdup_printf("<big>%s</big>", name);
-
- // We're going to try and create a desktop id from a exec string. Now, this is hairy at the
- // best of times but the following is the closest best-guess without having to do D-Bus
- // roundtrips to BAMF.
- if (exec)
- {
- char* basename;
-
- if (exec[0] == '/')
- basename = g_path_get_basename(exec);
- else
- basename = g_strdup(exec);
-
- id = g_strdup_printf("%s.desktop", basename);
-
- g_free(basename);
- }
- else
- {
- id = g_strdup_printf("%s.desktop", alternatives[0].c_str());
- }
-
- info = g_desktop_app_info_new(id);
- std::vector<std::string>::iterator iter = alternatives.begin();
- while (iter != alternatives.end())
- {
- if (!G_IS_DESKTOP_APP_INFO(info))
- {
- id = g_strdup_printf("%s.desktop", (*iter).c_str());
- info = g_desktop_app_info_new(id);
- iter++;
- }
-
- if (G_IS_DESKTOP_APP_INFO(info))
- {
- icon = g_icon_to_string(g_app_info_get_icon(G_APP_INFO(info)));
- real_exec = g_strdup(g_app_info_get_executable(G_APP_INFO(info)));
-
- shortcut = new Shortcut(icon, markup, style.GetHomeTileIconSize());
- shortcut->_id = TYPE_EXEC;
- shortcut->_exec = real_exec;
- _layout->AddView(shortcut, 1, nux::eLeft, nux::eFull);
- shortcut->sigClick.connect(sigc::mem_fun(this, &PlacesHomeView::OnShortcutClicked));
-
- g_free(icon);
-
- break;
- }
- }
-
- g_free(id);
- g_free(markup);
-}
-
-void PlacesHomeView::CreateShortcutFromMime(const char* mime,
- const char* name,
- std::vector<std::string>& alternatives)
-{
- dash::Style& style = dash::Style::Instance();
- GAppInfo* info = g_app_info_get_default_for_type(mime, FALSE);
-
- // If it was invalid check alternatives for backup
- if (!G_IS_DESKTOP_APP_INFO(info))
- {
- for (auto alt: alternatives)
- {
- std::string id = alt + ".desktop";
- info = G_APP_INFO(g_desktop_app_info_new(id.c_str()));
-
- if (G_IS_DESKTOP_APP_INFO(info))
- break;
- }
- }
-
- if (G_IS_DESKTOP_APP_INFO(info))
- {
- glib::String icon(g_icon_to_string(g_app_info_get_icon(G_APP_INFO(info))));
- glib::String markup(g_strdup_printf("<big>%s</big>", name));
-
- Shortcut* shortcut = new Shortcut(icon.Value(), markup.Value(), style.GetHomeTileIconSize());
- shortcut->_id = TYPE_EXEC;
- shortcut->_exec = g_strdup (g_app_info_get_executable(G_APP_INFO(info)));;
- shortcut->sigClick.connect(sigc::mem_fun(this, &PlacesHomeView::OnShortcutClicked));
- _layout->AddView(shortcut, 1, nux::eLeft, nux::eFull);
-
- g_object_unref(info);
- }
-}
-
-void
-PlacesHomeView::OnShortcutClicked(PlacesTile* tile)
-{
- Shortcut* shortcut = static_cast<Shortcut*>(tile);
- int id = shortcut->_id;
-
- if (id == TYPE_PLACE)
- {
- ubus_server_send_message(ubus_server_get_default(),
- UBUS_PLACE_ENTRY_ACTIVATE_REQUEST,
- g_variant_new("(sus)",
- shortcut->_place_id,
- shortcut->_place_section,
- ""));
- }
- else if (id == TYPE_EXEC)
- {
- GError* error = NULL;
-
- if (!g_spawn_command_line_async(shortcut->_exec, &error))
- {
- g_warning("%s: Unable to launch %s: %s",
- G_STRFUNC,
- shortcut->_exec,
- error->message);
- g_error_free(error);
- }
-
- ubus_server_send_message(ubus_server_get_default(),
- UBUS_PLACE_VIEW_CLOSE_REQUEST,
- NULL);
- }
-}
-
-std::string PlacesHomeView::GetName() const
-{
- return "PlacesHomeView";
-}
-
-void PlacesHomeView::AddProperties(GVariantBuilder* builder)
-{
- unity::variant::BuilderWrapper(builder).add(GetGeometry());
-}
-
-} // namespace unity
diff --git a/plugins/unityshell/src/PlacesHomeView.h b/plugins/unityshell/src/PlacesHomeView.h
deleted file mode 100644
index ead5aedc1..000000000
--- a/plugins/unityshell/src/PlacesHomeView.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
-/*
- * Copyright (C) 2010 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: Neil Jagdish Patel <neil.patel@canonical.com>
- */
-
-#ifndef PLACES_HOME_VIEW_H
-#define PLACES_HOME_VIEW_H
-
-#include <Nux/View.h>
-#include <Nux/Layout.h>
-#include <Nux/TextureArea.h>
-#include <NuxGraphics/GraphicsEngine.h>
-
-#include "Introspectable.h"
-
-#include <Nux/GridHLayout.h>
-
-#include "PlacesTile.h"
-#include "PlacesGroup.h"
-
-namespace unity
-{
-
-class PlacesHomeView : public unity::debug::Introspectable, public PlacesGroup
-{
-public:
- PlacesHomeView();
- ~PlacesHomeView();
-
- void Refresh(PlacesGroup* foo =NULL);
-
-protected:
- // Introspectable methods
- std::string GetName() const;
- void AddProperties(GVariantBuilder* builder);
-
-private:
- static void DashVisible(GVariant* data, void* val);
- void OnShortcutClicked(PlacesTile* _tile);
- void CreateShortcutFromExec(const char* exec,
- const char* name,
- std::vector<std::string>& alternatives);
- void CreateShortcutFromMime(const char* mime,
- const char* name,
- std::vector<std::string>& alternatives);
-
-private:
- nux::GridHLayout* _layout;
- std::vector<std::string> _browser_alternatives;
- std::vector<std::string> _photo_alternatives;
- std::vector<std::string> _email_alternatives;
- std::vector<std::string> _music_alternatives;
-
- guint _ubus_handle;
-};
-
-}
-#endif
diff --git a/plugins/unityshell/src/PlacesSimpleTile.cpp b/plugins/unityshell/src/PlacesSimpleTile.cpp
index 7ee262538..f6545a491 100644
--- a/plugins/unityshell/src/PlacesSimpleTile.cpp
+++ b/plugins/unityshell/src/PlacesSimpleTile.cpp
@@ -238,12 +238,6 @@ PlacesSimpleTile::GetName() const
return "PlacesTile";
}
-std::string
-PlacesSimpleTile::GetChildsName() const
-{
- return "PlacesTileContents";
-}
-
void
PlacesSimpleTile::AddProperties(GVariantBuilder* builder)
{
diff --git a/plugins/unityshell/src/PlacesSimpleTile.h b/plugins/unityshell/src/PlacesSimpleTile.h
index 36ecec887..561cc3b6a 100644
--- a/plugins/unityshell/src/PlacesSimpleTile.h
+++ b/plugins/unityshell/src/PlacesSimpleTile.h
@@ -49,7 +49,6 @@ protected:
nux::Geometry GetHighlightGeometry();
std::string GetName() const;
- std::string GetChildsName() const;
void AddProperties(GVariantBuilder* builder);
virtual bool DndSourceDragBegin();
diff --git a/plugins/unityshell/src/PluginAdapter.cpp b/plugins/unityshell/src/PluginAdapter.cpp
index 5b2f5e63e..dbc300053 100644
--- a/plugins/unityshell/src/PluginAdapter.cpp
+++ b/plugins/unityshell/src/PluginAdapter.cpp
@@ -28,6 +28,9 @@ namespace
nux::logging::Logger logger("unity.plugin");
+const int THRESHOLD_HEIGHT = 600;
+const int THRESHOLD_WIDTH = 1024;
+
}
PluginAdapter* PluginAdapter::_default = 0;
@@ -624,7 +627,7 @@ PluginAdapter::FocusWindowGroup(std::vector<Window> window_ids, FocusVisibility
* or scale, so unconditionally unminimize those
* windows when the launcher icon is activated */
if ((focus_visibility == WindowManager::FocusVisibility::ForceUnminimizeOnCurrentDesktop &&
- WindowManager::Default ()->IsWindowOnCurrentDesktop(win->id ())) ||
+ target_vp == m_Screen->vp()) ||
(focus_visibility == WindowManager::FocusVisibility::ForceUnminimizeInvisible &&
win->mapNum () == 0))
{
@@ -640,8 +643,7 @@ PluginAdapter::FocusWindowGroup(std::vector<Window> window_ids, FocusVisibility
}
else if ((any_mapped && !win->minimized()) || !any_mapped)
{
- if (!forced_unminimize ||
- WindowManager::Default ()->IsWindowOnCurrentDesktop (win->id ()))
+ if (!forced_unminimize || target_vp == m_Screen->vp())
{
win->raise();
top_win = win;
@@ -924,6 +926,10 @@ bool PluginAdapter::MaximizeIfBigEnough(CompWindow* window)
screen_height = o.workArea().height();
screen_width = o.workArea().width();
+
+ // See bug https://bugs.launchpad.net/unity/+bug/797808
+ if (screen_height * screen_width > THRESHOLD_HEIGHT * THRESHOLD_WIDTH)
+ return false;
// use server<parameter> because the window won't show the real parameter as
// not mapped yet
diff --git a/plugins/unityshell/src/ResultViewGrid.cpp b/plugins/unityshell/src/ResultViewGrid.cpp
index ef2773420..0511b8f53 100644
--- a/plugins/unityshell/src/ResultViewGrid.cpp
+++ b/plugins/unityshell/src/ResultViewGrid.cpp
@@ -626,8 +626,19 @@ void ResultViewGrid::Draw(nux::GraphicsEngine& GfxContext, bool force_draw)
int half_width = recorded_dash_width_ / 2;
int half_height = recorded_dash_height_;
- int offset_x = MAX(MIN((x_position - half_width) / (half_width / 10), 5), -5);
- int offset_y = MAX(MIN(((y_position + absolute_y) - half_height) / (half_height / 10), 5), -5);
+ int offset_x, offset_y;
+
+ /* Guard against divide-by-zero. SIGFPEs are not mythological
+ * contrary to popular belief */
+ if (half_width >= 10)
+ offset_x = MAX(MIN((x_position - half_width) / (half_width / 10), 5), -5);
+ else
+ offset_x = 0;
+
+ if (half_height >= 10)
+ offset_y = MAX(MIN(((y_position + absolute_y) - half_height) / (half_height / 10), 5), -5);
+ else
+ offset_y = 0;
if (recorded_dash_width_ < 1 || recorded_dash_height_ < 1)
{
diff --git a/plugins/unityshell/src/ScreenEffectFramebufferObject.cpp b/plugins/unityshell/src/ScreenEffectFramebufferObject.cpp
index 6b0011f38..1aa318f6a 100644
--- a/plugins/unityshell/src/ScreenEffectFramebufferObject.cpp
+++ b/plugins/unityshell/src/ScreenEffectFramebufferObject.cpp
@@ -17,6 +17,7 @@
* Authored By: Sam Spilsbury <sam.spilsbury@canonical.com>
*/
+#ifndef USE_GLES
#include "ScreenEffectFramebufferObject.h"
#include "BackgroundEffectHelper.h"
#include <NuxCore/Logger.h>
@@ -32,7 +33,7 @@ void unity::ScreenEffectFramebufferObject::paint (const nux::Geometry &output)
/* Draw the bit of the relevant framebuffer for each output */
glPushAttrib (GL_VIEWPORT_BIT);
- glViewport (0, mScreenSize.height - (output.y + output.height), mScreenSize.width, mScreenSize.height);
+ glViewport (0, 0, mScreenSize.width, mScreenSize.height);
if (mFBTexture)
{
@@ -232,3 +233,6 @@ unity::ScreenEffectFramebufferObject::~ScreenEffectFramebufferObject ()
if (mFBTexture)
glDeleteTextures (1, &mFBTexture);
}
+
+#endif // USE_GLES
+
diff --git a/plugins/unityshell/src/ScreenEffectFramebufferObject.h b/plugins/unityshell/src/ScreenEffectFramebufferObject.h
index 1dbecca0e..2481136f1 100644
--- a/plugins/unityshell/src/ScreenEffectFramebufferObject.h
+++ b/plugins/unityshell/src/ScreenEffectFramebufferObject.h
@@ -20,6 +20,7 @@
#ifndef UNITY_SCREENEFFECT_FRAMEBUFFER_H
#define UNITY_SCREENEFFECT_FRAMEBUFFER_H
+#ifndef USE_GLES
#include <Nux/Nux.h>
namespace unity
@@ -84,4 +85,5 @@ private:
};
} // namespace unity
+#endif // USE_GLES
#endif
diff --git a/plugins/unityshell/src/ShortcutController.cpp b/plugins/unityshell/src/ShortcutController.cpp
index 8a9288b3f..56b9e54b4 100644
--- a/plugins/unityshell/src/ShortcutController.cpp
+++ b/plugins/unityshell/src/ShortcutController.cpp
@@ -19,7 +19,6 @@
#include "ShortcutController.h"
#include "UBusMessages.h"
-#include "ubus-server.h"
#include "WindowManager.h"
namespace unity
@@ -34,39 +33,43 @@ const unsigned int SUPER_TAP_DURATION = 650;
Controller::Controller(std::list<AbstractHint*>& hints)
: view_window_(0)
, visible_(false)
+ , enabled_(true)
, show_timer_(0)
- , fade_in_animator_(new Animator(100))
- , fade_out_animator_(new Animator(100))
-
+ , fade_in_animator_(100)
+ , fade_out_animator_(100)
{
bg_color_ = nux::Color(0.0, 0.0, 0.0, 0.5);
- UBusServer *ubus = ubus_server_get_default();
- bg_update_handle_ = ubus_server_register_interest(ubus, UBUS_BACKGROUND_COLOR_CHANGED,
- (UBusCallback)&Controller::OnBackgroundUpdate,
- this);
+ ubus_manager_.RegisterInterest(UBUS_BACKGROUND_COLOR_CHANGED,
+ sigc::mem_fun(this, &Controller::OnBackgroundUpdate));
+
+ ubus_manager_.RegisterInterest(UBUS_LAUNCHER_START_KEY_SWTICHER, [&] (GVariant*) {
+ enabled_ = false;
+ });
+
+ ubus_manager_.RegisterInterest(UBUS_LAUNCHER_END_KEY_SWTICHER, [&] (GVariant*) {
+ enabled_ = true;
+ });
+
+ ubus_manager_.RegisterInterest(UBUS_PLACE_VIEW_SHOWN, [&] (GVariant*) {
+ Hide();
+ });
+
+ ubus_manager_.SendMessage(UBUS_BACKGROUND_REQUEST_COLOUR_EMIT);
model_.reset(new Model(hints));
-
+
model_->Fill();
ConstructView();
- fade_in_animator_->animation_updated.connect(sigc::mem_fun(this, &Controller::OnFadeInUpdated));
- fade_in_animator_->animation_ended.connect(sigc::mem_fun(this, &Controller::OnFadeInEnded));
- fade_out_animator_->animation_updated.connect(sigc::mem_fun(this, &Controller::OnFadeOutUpdated));
- fade_out_animator_->animation_ended.connect(sigc::mem_fun(this, &Controller::OnFadeOutEnded));
+ fade_in_animator_.animation_updated.connect(sigc::mem_fun(this, &Controller::OnFadeInUpdated));
+ fade_in_animator_.animation_ended.connect(sigc::mem_fun(this, &Controller::OnFadeInEnded));
+ fade_out_animator_.animation_updated.connect(sigc::mem_fun(this, &Controller::OnFadeOutUpdated));
+ fade_out_animator_.animation_ended.connect(sigc::mem_fun(this, &Controller::OnFadeOutEnded));
}
Controller::~Controller()
{
- ubus_server_unregister_interest(ubus_server_get_default(), bg_update_handle_);
-
- if (fade_in_animator_)
- delete fade_in_animator_;
-
- if (fade_out_animator_)
- delete fade_out_animator_;
-
if (view_window_)
view_window_->UnReference();
@@ -96,21 +99,23 @@ void Controller::OnFadeOutEnded()
}
-void Controller::OnBackgroundUpdate(GVariant* data, Controller* self)
+void Controller::OnBackgroundUpdate(GVariant* data)
{
gdouble red, green, blue, alpha;
g_variant_get(data, "(dddd)", &red, &green, &blue, &alpha);
- self->bg_color_ = nux::Color(red, green, blue, alpha);
+ bg_color_ = nux::Color(red, green, blue, alpha);
- if (self->view_)
- self->view_->background_color = self->bg_color_;
+ if (view_)
+ view_->background_color = bg_color_;
}
void Controller::Show()
{
if (show_timer_)
g_source_remove (show_timer_);
- show_timer_ = g_timeout_add(SUPER_TAP_DURATION, &Controller::OnShowTimer, this);
+
+ if (enabled_)
+ show_timer_ = g_timeout_add(SUPER_TAP_DURATION, &Controller::OnShowTimer, this);
model_->Fill();
visible_ = true;
@@ -119,16 +124,19 @@ void Controller::Show()
gboolean Controller::OnShowTimer(gpointer data)
{
Controller* self = static_cast<Controller*>(data);
-
- ubus_server_send_message(ubus_server_get_default(),
- UBUS_PLACE_VIEW_CLOSE_REQUEST,
- NULL);
+
+ if (!self->enabled_)
+ {
+ return FALSE;
+ }
+
+ self->ubus_manager_.SendMessage(UBUS_PLACE_VIEW_CLOSE_REQUEST);
if (self->visible_)
{
self->view_->SetupBackground(true);
- self->fade_out_animator_->Stop();
- self->fade_in_animator_->Start(self->view_window_->GetOpacity());
+ self->fade_out_animator_.Stop();
+ self->fade_in_animator_.Start(self->view_window_->GetOpacity());
}
self->show_timer_ = 0;
@@ -176,8 +184,8 @@ void Controller::Hide()
if (view_window_)
{
view_->SetupBackground(false);
- fade_in_animator_->Stop();
- fade_out_animator_->Start(1.0 - view_window_->GetOpacity());
+ fade_in_animator_.Stop();
+ fade_out_animator_.Start(1.0 - view_window_->GetOpacity());
}
if (show_timer_)
@@ -190,5 +198,15 @@ bool Controller::Visible()
return visible_;
}
+bool Controller::IsEnabled()
+{
+ return enabled_;
+}
+
+void Controller::SetEnabled(bool enabled)
+{
+ enabled_ = enabled;
+}
+
} // namespace shortcut
} // namespace unity
diff --git a/plugins/unityshell/src/ShortcutController.h b/plugins/unityshell/src/ShortcutController.h
index 4fb51ff28..8a276c440 100644
--- a/plugins/unityshell/src/ShortcutController.h
+++ b/plugins/unityshell/src/ShortcutController.h
@@ -29,6 +29,7 @@
#include "Animator.h"
#include "ShortcutModel.h"
#include "ShortcutView.h"
+#include "UBusWrapper.h"
namespace unity
{
@@ -49,13 +50,15 @@ public:
void Hide();
bool Visible();
+ bool IsEnabled();
void SetWorkspace(nux::Geometry const& geo);
+ void SetEnabled(bool enabled);
private:
// Private Methods
void ConstructView();
- static void OnBackgroundUpdate(GVariant* data, Controller* self);
+ void OnBackgroundUpdate(GVariant* data);
void OnFadeInUpdated(double opacity);
void OnFadeInEnded();
void OnFadeOutUpdated(double opacity);
@@ -72,13 +75,15 @@ private:
nux::HLayout* main_layout_;
bool visible_;
+ bool enabled_;
nux::Color bg_color_;
guint show_timer_;
- guint bg_update_handle_;
- Animator* fade_in_animator_;
- Animator* fade_out_animator_;
-};
+ Animator fade_in_animator_;
+ Animator fade_out_animator_;
+
+ UBusManager ubus_manager_;
+};
} // namespace shortcut
} // namespace unity
diff --git a/plugins/unityshell/src/SoftwareCenterLauncherIcon.cpp b/plugins/unityshell/src/SoftwareCenterLauncherIcon.cpp
new file mode 100644
index 000000000..90e4a9f82
--- /dev/null
+++ b/plugins/unityshell/src/SoftwareCenterLauncherIcon.cpp
@@ -0,0 +1,102 @@
+// -*- 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: Bilal Akhtar <bilalakhtar@ubuntu.com>
+ */
+
+#include "Nux/Nux.h"
+#include "Nux/BaseWindow.h"
+
+#include "BamfLauncherIcon.h"
+#include "Launcher.h"
+#include "LauncherController.h"
+#include "PluginAdapter.h"
+#include "FavoriteStore.h"
+
+#include "ubus-server.h"
+#include "UBusMessages.h"
+
+#include <glib.h>
+#include <glib/gvariant.h>
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+#include <libindicator/indicator-desktop-shortcuts.h>
+#include <core/core.h>
+#include <core/atoms.h>
+
+#include "SoftwareCenterLauncherIcon.h"
+
+namespace unity
+{
+namespace launcher
+{
+
+SoftwareCenterLauncherIcon::SoftwareCenterLauncherIcon(Launcher* IconManager, BamfApplication* app, char* aptdaemon_trans_id, char* icon_path)
+: BamfLauncherIcon(IconManager, app)
+{
+ _aptdaemon_trans_id = aptdaemon_trans_id;
+
+ g_debug("Aptdaemon transaction ID: %s", _aptdaemon_trans_id);
+
+ _aptdaemon_trans = new unity::glib::DBusProxy("org.debian.apt",
+ _aptdaemon_trans_id,
+ "org.debian.apt.transaction",
+ G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START);
+
+ _aptdaemon_trans->Connect("Finished", sigc::mem_fun(this, &SoftwareCenterLauncherIcon::OnFinished));
+ _aptdaemon_trans->Connect("PropertyChanged", sigc::mem_fun(this, &SoftwareCenterLauncherIcon::OnPropertyChanged));
+
+ icon_name = icon_path;
+}
+
+SoftwareCenterLauncherIcon::~SoftwareCenterLauncherIcon() {
+
+}
+
+void
+SoftwareCenterLauncherIcon::OnFinished(GVariant* params) {
+
+ tooltip_text = BamfName();
+
+ SetQuirk(LauncherIcon::QUIRK_PROGRESS, FALSE);
+}
+
+void
+SoftwareCenterLauncherIcon::OnPropertyChanged(GVariant* params) {
+
+ gint32 progress;
+ gchar* property_name;
+ GVariant* property_value;
+
+ g_variant_get_child (params, 0, "s", &property_name);
+ if (g_strcmp0 (property_name, "Progress") == 0) {
+ g_variant_get_child (params,1,"v",&property_value);
+ g_variant_get (property_value, "i", &progress);
+
+ if (progress < 100) {
+ SetQuirk(LauncherIcon::QUIRK_PROGRESS, TRUE);
+ tooltip_text = _("Waiting to install");
+ }
+ SetProgress(((float)progress) / ((float)100));
+ }
+ g_variant_unref(property_value);
+ g_free(property_name);
+
+}
+
+}
+}
diff --git a/plugins/unityshell/src/SoftwareCenterLauncherIcon.h b/plugins/unityshell/src/SoftwareCenterLauncherIcon.h
new file mode 100644
index 000000000..c6f441c11
--- /dev/null
+++ b/plugins/unityshell/src/SoftwareCenterLauncherIcon.h
@@ -0,0 +1,60 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+ * Copyright (C) 2010 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: Bilal Akhtar <bilalakhtar@ubuntu.com>
+ */
+
+#ifndef SOFTWARECENTERLAUNCHERICON_H
+#define SOFTWARECENTERLAUNCHERICON_H
+
+#include "BamfLauncherIcon.h"
+#include <Nux/BaseWindow.h>
+#include <NuxCore/Math/MathInc.h>
+#include <core/core.h>
+#include <gio/gio.h>
+#include <glib.h>
+#include <glib/gvariant.h>
+#include <UnityCore/GLibDBusProxy.h>
+
+
+namespace unity
+{
+namespace launcher
+{
+
+
+class SoftwareCenterLauncherIcon : public BamfLauncherIcon
+{
+public:
+
+ SoftwareCenterLauncherIcon(Launcher* IconManager, BamfApplication* app, char* aptdaemon_trans_id, char* icon_path);
+ virtual ~SoftwareCenterLauncherIcon();
+
+ gchar* original_tooltip_text;
+
+private:
+ char* _aptdaemon_trans_id;
+ unity::glib::DBusProxy* _aptdaemon_trans;
+
+ void OnFinished(GVariant* params);
+
+ void OnPropertyChanged(GVariant* params);
+};
+
+}
+}
+
+#endif
diff --git a/plugins/unityshell/src/compizminimizedwindowhandler.h b/plugins/unityshell/src/compizminimizedwindowhandler.h
index d5533210e..8125a036f 100644
--- a/plugins/unityshell/src/compizminimizedwindowhandler.h
+++ b/plugins/unityshell/src/compizminimizedwindowhandler.h
@@ -63,9 +63,8 @@ public:
static void handleEvent (XEvent *event);
static std::list<CompWindow *> minimizingWindows;
- typedef CompizMinimizedWindowHandler<Screen, Window> CompizMinimizedWindowHandler_complete;
- typedef boost::shared_ptr<CompizMinimizedWindowHandler_complete> Ptr;
- typedef std::list <Ptr> List;
+ typedef CompizMinimizedWindowHandler<Screen, Window> Type;
+ typedef std::list <Type *> List;
protected:
virtual std::vector<unsigned int> getTransients ();
@@ -74,10 +73,14 @@ private:
PrivateCompizMinimizedWindowHandler *priv;
static bool handleEvents;
- static std::list<Ptr> minimizedWindows;
+ static List minimizedWindows;
};
}
+/* XXX minimizedWindows should be removed because it is dangerous to keep
+ * a list of windows separate to compiz-core. The list could get out of
+ * sync and cause more crashes like LP: #918329, LP: #864758.
+ */
template <typename Screen, typename Window>
typename compiz::CompizMinimizedWindowHandler<Screen, Window>::List compiz::CompizMinimizedWindowHandler<Screen, Window>::minimizedWindows;
@@ -100,12 +103,7 @@ compiz::CompizMinimizedWindowHandler<Screen, Window>::CompizMinimizedWindowHandl
template <typename Screen, typename Window>
compiz::CompizMinimizedWindowHandler<Screen, Window>::~CompizMinimizedWindowHandler ()
{
- typedef compiz::CompizMinimizedWindowHandler<Screen, Window> minimized_window_handler_full;
-
- compiz::CompizMinimizedWindowHandler<Screen, Window>::Ptr compizMinimizeHandler =
- boost::dynamic_pointer_cast <minimized_window_handler_full> (Window::get (priv->mWindow)->mMinimizeHandler);
-
- minimizedWindows.remove (compizMinimizeHandler);
+ minimizedWindows.remove (this);
}
template <typename Screen, typename Window>
@@ -144,18 +142,13 @@ compiz::CompizMinimizedWindowHandler<Screen, Window>::minimize ()
Atom wmState = XInternAtom (screen->dpy (), "WM_STATE", 0);
unsigned long data[2];
- typedef compiz::CompizMinimizedWindowHandler<Screen, Window> minimized_window_handler_full;
-
std::vector<unsigned int> transients = getTransients ();
handleEvents = true;
priv->mWindow->windowNotify (CompWindowNotifyMinimize);
priv->mWindow->changeState (priv->mWindow->state () | CompWindowStateHiddenMask);
- compiz::CompizMinimizedWindowHandler<Screen, Window>::Ptr compizMinimizeHandler =
- boost::dynamic_pointer_cast <minimized_window_handler_full> (Window::get (priv->mWindow)->mMinimizeHandler);
-
- minimizedWindows.push_back (compizMinimizeHandler);
+ minimizedWindows.push_back (this);
for (unsigned int &w : transients)
{
@@ -163,8 +156,10 @@ compiz::CompizMinimizedWindowHandler<Screen, Window>::minimize ()
if (win)
{
- Window::get (win)->mMinimizeHandler = MinimizedWindowHandler::Ptr (new CompizMinimizedWindowHandler (win));
- Window::get (win)->mMinimizeHandler->minimize ();
+ Window *w = Window::get (win);
+ if (!w->mMinimizeHandler)
+ w->mMinimizeHandler = new Type (win);
+ w->mMinimizeHandler->minimize ();
}
}
@@ -226,14 +221,9 @@ compiz::CompizMinimizedWindowHandler<Screen, Window>::unminimize ()
Atom wmState = XInternAtom (screen->dpy (), "WM_STATE", 0);
unsigned long data[2];
- typedef compiz::CompizMinimizedWindowHandler<Screen, Window> minimized_window_handler_full;
-
std::vector<unsigned int> transients = getTransients ();
- compiz::CompizMinimizedWindowHandler<Screen, Window>::Ptr compizMinimizeHandler =
- boost::dynamic_pointer_cast <minimized_window_handler_full> (Window::get (priv->mWindow)->mMinimizeHandler);
-
- minimizedWindows.remove (compizMinimizeHandler);
+ minimizedWindows.remove (this);
priv->mWindow->focusSetEnabled (Window::get (priv->mWindow), true);
@@ -247,10 +237,13 @@ compiz::CompizMinimizedWindowHandler<Screen, Window>::unminimize ()
if (win)
{
- if (Window::get (win)->mMinimizeHandler)
- Window::get (win)->mMinimizeHandler->unminimize ();
-
- Window::get (win)->mMinimizeHandler.reset ();
+ Window *w = Window::get (win);
+ if (w && w->mMinimizeHandler)
+ {
+ w->mMinimizeHandler->unminimize ();
+ delete w->mMinimizeHandler;
+ w->mMinimizeHandler = NULL;
+ }
}
}
@@ -330,10 +323,9 @@ compiz::CompizMinimizedWindowHandler<Screen, Window>::handleEvent (XEvent *event
if (w)
{
- typedef compiz::CompizMinimizedWindowHandler<Screen, Window> plugin_handler;
Window *pw = Window::get (w);
- plugin_handler::Ptr compizMinimizeHandler =
- boost::dynamic_pointer_cast <plugin_handler> (pw->mMinimizeHandler);
+ Type *compizMinimizeHandler = pw->mMinimizeHandler;
+
/* Restore and re-save input shape and remove */
if (compizMinimizeHandler)
{
diff --git a/plugins/unityshell/src/unityshell.cpp b/plugins/unityshell/src/unityshell.cpp
index f35bd4e20..bc948351d 100644
--- a/plugins/unityshell/src/unityshell.cpp
+++ b/plugins/unityshell/src/unityshell.cpp
@@ -52,7 +52,6 @@
#include "unitya11y.h"
-#include "ubus-server.h"
#include "UBusMessages.h"
#include "UScreen.h"
@@ -108,13 +107,16 @@ UnityScreen::UnityScreen(CompScreen* screen)
, _edge_trigger_handle(0)
, _redraw_handle(0)
, _edge_pointerY(0)
+ , _escape_action(nullptr)
, newFocusedWindow(nullptr)
, doShellRepaint(false)
, allowWindowPaint(false)
, damaged(false)
, _key_nav_mode_requested(false)
, _last_output(nullptr)
+#ifndef USE_GLES
, _active_fbo (0)
+#endif
, dash_is_open_ (false)
, grab_index_ (0)
, painting_tray_ (false)
@@ -128,6 +130,7 @@ UnityScreen::UnityScreen(CompScreen* screen)
int (*old_handler)(Display*, XErrorEvent*);
old_handler = XSetErrorHandler(NULL);
+#ifndef USE_GLES
/* Ensure OpenGL version is 1.4+. */
version = get_opengl_version_f32((const gchar*) glGetString(GL_VERSION));
if (version < 1.4f)
@@ -183,6 +186,7 @@ UnityScreen::UnityScreen(CompScreen* screen)
failed = true;
}
}
+#endif
if (!failed)
{
@@ -199,16 +203,27 @@ UnityScreen::UnityScreen(CompScreen* screen)
CompositeScreenInterface::setHandler(cScreen);
GLScreenInterface::setHandler(gScreen);
+#ifdef USE_GLES
+ gScreen->glPaintCompositedOutputSetEnabled (this, true);
+#endif
+
PluginAdapter::Initialize(screen);
WindowManager::SetDefault(PluginAdapter::Default());
StartupNotifyService::Default()->SetSnDisplay(screen->snDisplay(), screen->screenNum());
nux::NuxInitialize(0);
+#ifndef USE_GLES
wt = nux::CreateFromForeignWindow(cScreen->output(),
glXGetCurrentContext(),
&UnityScreen::initUnity,
this);
+#else
+ wt = nux::CreateFromForeignWindow(cScreen->output(),
+ eglGetCurrentContext(),
+ &UnityScreen::initUnity,
+ this);
+#endif
wt->RedrawRequested.connect(sigc::mem_fun(this, &UnityScreen::onRedrawRequested));
@@ -226,6 +241,7 @@ UnityScreen::UnityScreen(CompScreen* screen)
_edge_timeout = optionGetLauncherRevealEdgeTimeout ();
_in_paint = false;
+#ifndef USE_GLES
void *dlhand = dlopen ("libunityshell.so", RTLD_LAZY);
if (dlhand)
@@ -242,6 +258,7 @@ UnityScreen::UnityScreen(CompScreen* screen)
uScreen->_fbo = ScreenEffectFramebufferObject::Ptr (new ScreenEffectFramebufferObject (glXGetProcAddressP, geometry));
uScreen->_fbo->onScreenSizeChanged (geometry);
}
+#endif
optionSetBackgroundColorNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
optionSetLauncherHideModeNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
@@ -294,26 +311,16 @@ UnityScreen::UnityScreen(CompScreen* screen)
optionSetLauncherSwitcherPrevInitiate(boost::bind(&UnityScreen::launcherSwitcherPrevInitiate, this, _1, _2, _3));
optionSetLauncherSwitcherForwardTerminate(boost::bind(&UnityScreen::launcherSwitcherTerminate, this, _1, _2, _3));
- optionSetShowMinimizedWindowsNotify (boost::bind (&UnityScreen::optionChanged, this, _1, _2));
+ optionSetShowMinimizedWindowsNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
- for (unsigned int i = 0; i < G_N_ELEMENTS(_ubus_handles); i++)
- _ubus_handles[i] = 0;
+ ubus_manager_.RegisterInterest(UBUS_LAUNCHER_START_KEY_NAV,
+ sigc::mem_fun(this, &UnityScreen::OnLauncherStartKeyNav));
- UBusServer* ubus = ubus_server_get_default();
- _ubus_handles[0] = ubus_server_register_interest(ubus,
- UBUS_LAUNCHER_START_KEY_NAV,
- (UBusCallback)&UnityScreen::OnLauncherStartKeyNav,
- this);
+ ubus_manager_.RegisterInterest(UBUS_LAUNCHER_END_KEY_NAV,
+ sigc::mem_fun(this, &UnityScreen::OnLauncherEndKeyNav));
- _ubus_handles[1] = ubus_server_register_interest(ubus,
- UBUS_LAUNCHER_END_KEY_NAV,
- (UBusCallback)&UnityScreen::OnLauncherEndKeyNav,
- this);
-
- _ubus_handles[2] = ubus_server_register_interest(ubus,
- UBUS_QUICKLIST_END_KEY_NAV,
- (UBusCallback)&UnityScreen::OnQuicklistEndKeyNav,
- this);
+ ubus_manager_.RegisterInterest(UBUS_QUICKLIST_END_KEY_NAV,
+ sigc::mem_fun(this, &UnityScreen::OnQuicklistEndKeyNav));
g_idle_add_full (G_PRIORITY_DEFAULT, &UnityScreen::initPluginActions, this, NULL);
super_keypressed_ = false;
@@ -343,13 +350,6 @@ UnityScreen::~UnityScreen()
unity_a11y_finalize();
- UBusServer* ubus = ubus_server_get_default();
- for (unsigned int i = 0; i < G_N_ELEMENTS(_ubus_handles); i++)
- {
- if (_ubus_handles[i] != 0)
- ubus_server_unregister_interest(ubus, _ubus_handles[i]);
- }
-
if (relayoutSourceId != 0)
g_source_remove(relayoutSourceId);
@@ -363,7 +363,7 @@ void UnityScreen::initAltTabNextWindow()
{
KeyboardUtil key_util (screen->dpy());
guint above_tab_keycode = key_util.GetKeycodeAboveKeySymbol (XStringToKeysym("Tab"));
- KeySym above_tab_keysym = XKeycodeToKeysym (screen->dpy(), above_tab_keycode, 0);
+ KeySym above_tab_keysym = XkbKeycodeToKeysym (screen->dpy(), above_tab_keycode, 0, 0);
if (above_tab_keysym != NoSymbol)
{
@@ -441,8 +441,28 @@ void UnityScreen::CreateSuperNewAction(char shortcut, bool use_shift, bool use_n
_shortcut_actions.push_back(action);
}
+void UnityScreen::EnableCancelAction(bool enabled, int modifiers)
+{
+ if (enabled)
+ {
+ /* Create a new keybinding for the Escape key and the current modifiers */
+ CompAction::KeyBinding binding(9, modifiers);
+
+ _escape_action = CompActionPtr(new CompAction());
+ _escape_action->setKey(binding);
+
+ screen->addAction(_escape_action.get());
+ }
+ else if (!enabled && _escape_action.get())
+ {
+ screen->removeAction(_escape_action.get());
+ _escape_action = nullptr;
+ }
+}
+
void UnityScreen::nuxPrologue()
{
+#ifndef USE_GLES
/* Vertex lighting isn't used in Unity, we disable that state as it could have
* been leaked by another plugin. That should theoretically be switched off
* right after PushAttrib since ENABLE_BIT is meant to restore the LIGHTING
@@ -459,12 +479,14 @@ void UnityScreen::nuxPrologue()
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
+#endif
glGetError();
}
void UnityScreen::nuxEpilogue()
{
+#ifndef USE_GLES
(*GL::bindFramebuffer)(GL_FRAMEBUFFER_EXT, _active_fbo);
glMatrixMode(GL_PROJECTION);
@@ -486,6 +508,11 @@ void UnityScreen::nuxEpilogue()
glReadBuffer(GL_BACK);
glPopAttrib();
+#else
+ glDepthRangef(0, 1);
+ //glViewport(-1, -1, 2, 2);
+ gScreen->resetRasterPos();
+#endif
glDisable(GL_SCISSOR_TEST);
}
@@ -500,6 +527,7 @@ void UnityScreen::OnLauncherHiddenChanged()
void UnityScreen::paintPanelShadow(const GLMatrix& matrix)
{
+#ifndef USE_GLES
if (relayoutSourceId > 0)
return;
@@ -559,6 +587,86 @@ void UnityScreen::paintPanelShadow(const GLMatrix& matrix)
glDisable(GL_BLEND);
}
}
+#else
+#warning Panel shadow not properly implemented for GLES2
+ return;
+
+ if (relayoutSourceId > 0)
+ return;
+
+ if (PluginAdapter::Default()->IsExpoActive())
+ return;
+
+ nuxPrologue();
+
+ CompOutput* output = _last_output;
+ float vc[4];
+ float h = 20.0f;
+ float w = 1.0f;
+ float panel_h = 24.0f;
+
+ float x1 = output->x();
+ float y1 = output->y() + panel_h;
+ float x2 = x1 + output->width();
+ float y2 = y1 + h;
+
+ vc[0] = x1;
+ vc[1] = x2;
+ vc[2] = y1;
+ vc[3] = y2;
+
+ if (!dash_is_open_ && panel_controller_->opacity() > 0.0f)
+ {
+ foreach(GLTexture * tex, _shadow_texture)
+ {
+ std::vector<GLfloat> vertexData;
+ std::vector<GLfloat> textureData;
+ std::vector<GLushort> colorData;
+ GLVertexBuffer *streamingBuffer = GLVertexBuffer::streamingBuffer();
+ bool wasBlend = glIsEnabled(GL_BLEND);
+
+ if (!wasBlend)
+ glEnable(GL_BLEND);
+
+ GL::activeTexture(GL_TEXTURE0);
+ tex->enable(GLTexture::Fast);
+
+ glTexParameteri(tex->target(), GL_TEXTURE_WRAP_S, GL_REPEAT);
+
+ colorData = { 0xFFFF, 0xFFFF, 0xFFFF,
+ (GLushort)(panel_controller_->opacity() * 0xFFFF)
+ };
+
+ vertexData = {
+ vc[0], vc[2], 0,
+ vc[0], vc[3], 0,
+ vc[1], vc[2], 0,
+ vc[1], vc[3], 0,
+ };
+
+ textureData = {
+ COMP_TEX_COORD_X(tex->matrix(), 0), COMP_TEX_COORD_Y(tex->matrix(), 0),
+ COMP_TEX_COORD_X(tex->matrix(), 0), COMP_TEX_COORD_Y(tex->matrix(), h),
+ COMP_TEX_COORD_X(tex->matrix(), w), COMP_TEX_COORD_Y(tex->matrix(), 0),
+ COMP_TEX_COORD_X(tex->matrix(), w), COMP_TEX_COORD_Y(tex->matrix(), h),
+ };
+
+ streamingBuffer->begin(GL_TRIANGLE_STRIP);
+
+ streamingBuffer->addColors(1, &colorData[0]);
+ streamingBuffer->addVertices(4, &vertexData[0]);
+ streamingBuffer->addTexCoords(0, 4, &textureData[0]);
+
+ streamingBuffer->end();
+ streamingBuffer->render(matrix);
+
+ tex->disable();
+ if (!wasBlend)
+ glDisable(GL_BLEND);
+ }
+ }
+ nuxEpilogue();
+#endif
}
void
@@ -573,11 +681,16 @@ UnityWindow::updateIconPos (int &wx,
wy = y + (last_bound.height - height) / 2;
}
+#ifdef USE_GLES
+void UnityScreen::paintDisplay()
+#else
void UnityScreen::paintDisplay(const CompRegion& region, const GLMatrix& transform, unsigned int mask)
+#endif
{
CompOutput *output = _last_output;
Window tray_xid = panel_controller_->GetTrayXid ();
+#ifndef USE_GLES
bool was_bound = _fbo->bound ();
_fbo->unbind ();
@@ -596,6 +709,11 @@ void UnityScreen::paintDisplay(const CompRegion& region, const GLMatrix& transfo
nux::ObjectPtr<nux::IOpenGLTexture2D> device_texture =
nux::GetGraphicsDisplay()->GetGpuDevice()->CreateTexture2DFromID(_fbo->texture(),
screen->width (), screen->height(), 1, nux::BITFMT_R8G8B8A8);
+#else
+ nux::ObjectPtr<nux::IOpenGLTexture2D> device_texture =
+ nux::GetGraphicsDisplay()->GetGpuDevice()->CreateTexture2DFromID(gScreen->fbo ()->tex ()->name (),
+ output->width(), output->height(), 1, nux::BITFMT_R8G8B8A8);
+#endif
nux::GetGraphicsDisplay()->GetGpuDevice()->backup_texture0_ = device_texture;
@@ -603,6 +721,13 @@ void UnityScreen::paintDisplay(const CompRegion& region, const GLMatrix& transfo
nux::Geometry oGeo = nux::Geometry (output->x (), output->y (), output->width (), output->height ());
BackgroundEffectHelper::monitor_rect_ = geo;
+#ifdef USE_GLES
+ GLint fboID;
+ // Nux renders to the referenceFramebuffer when it's embedded.
+ glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fboID);
+ wt->GetWindowCompositor().SetReferenceFramebuffer(fboID, geo);
+#endif
+
nuxPrologue();
_in_paint = true;
wt->RenderInterfaceFromForeignCmd (&oGeo);
@@ -617,36 +742,56 @@ void UnityScreen::paintDisplay(const CompRegion& region, const GLMatrix& transfo
{
GLMatrix oTransform;
UnityWindow *uTrayWindow = UnityWindow::get (tray);
+#ifndef USE_GLES
GLFragment::Attrib attrib (uTrayWindow->gWindow->lastPaintAttrib());
+#else
+ GLWindowPaintAttrib attrib (uTrayWindow->gWindow->lastPaintAttrib());
+#endif
unsigned int oldGlAddGeometryIndex = uTrayWindow->gWindow->glAddGeometryGetCurrentIndex ();
unsigned int oldGlDrawIndex = uTrayWindow->gWindow->glDrawGetCurrentIndex ();
+#ifndef USE_GLES
unsigned int oldGlDrawGeometryIndex = uTrayWindow->gWindow->glDrawGeometryGetCurrentIndex ();
+#endif
+#ifndef USE_GLES
attrib.setOpacity (OPAQUE);
attrib.setBrightness (BRIGHT);
attrib.setSaturation (COLOR);
+#else
+ attrib.opacity = OPAQUE;
+ attrib.brightness = BRIGHT;
+ attrib.saturation = COLOR;
+#endif
oTransform.toScreenSpace (output, -DEFAULT_Z_CAMERA);
+#ifndef USE_GLES
glPushMatrix ();
glLoadMatrixf (oTransform.getMatrix ());
+#endif
painting_tray_ = true;
/* force the use of the core functions */
uTrayWindow->gWindow->glDrawSetCurrentIndex (MAXSHORT);
uTrayWindow->gWindow->glAddGeometrySetCurrentIndex ( MAXSHORT);
+#ifndef USE_GLES
uTrayWindow->gWindow->glDrawGeometrySetCurrentIndex (MAXSHORT);
+#endif
uTrayWindow->gWindow->glDraw (oTransform, attrib, infiniteRegion,
PAINT_WINDOW_TRANSFORMED_MASK |
PAINT_WINDOW_BLEND_MASK |
PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK);
+#ifndef USE_GLES
uTrayWindow->gWindow->glDrawGeometrySetCurrentIndex (oldGlDrawGeometryIndex);
+#endif
uTrayWindow->gWindow->glAddGeometrySetCurrentIndex (oldGlAddGeometryIndex);
uTrayWindow->gWindow->glDrawSetCurrentIndex (oldGlDrawIndex);
painting_tray_ = false;
+#ifndef USE_GLES
glPopMatrix ();
+#endif
}
}
@@ -1009,6 +1154,7 @@ bool UnityScreen::glPaintOutput(const GLScreenPaintAttrib& attrib,
allowWindowPaint = true;
_last_output = output;
+#ifndef USE_GLES
/* bind the framebuffer here
* - it will be unbound and flushed
* to the backbuffer when some
@@ -1020,16 +1166,43 @@ bool UnityScreen::glPaintOutput(const GLScreenPaintAttrib& attrib,
* its bind reference so make sure that
* you always unbind as much as you bind */
_fbo->bind (nux::Geometry (output->x (), output->y (), output->width (), output->height ()));
+#endif
/* glPaintOutput is part of the opengl plugin, so we need the GLScreen base class. */
ret = gScreen->glPaintOutput(attrib, transform, region, output, mask);
+#ifndef USE_GLES
if (doShellRepaint)
paintDisplay(region, transform, mask);
+#endif
return ret;
}
+#ifdef USE_GLES
+void UnityScreen::glPaintCompositedOutput (const CompRegion &region,
+ GLFramebufferObject *fbo,
+ unsigned int mask)
+{
+ bool useFbo = false;
+
+ if (doShellRepaint)
+ {
+ oldFbo = fbo->bind ();
+ useFbo = fbo->checkStatus () && fbo->tex ();
+ if (!useFbo) {
+ printf ("bailing from UnityScreen::glPaintCompositedOutput");
+ GLFramebufferObject::rebind (oldFbo);
+ return;
+ }
+ paintDisplay();
+ GLFramebufferObject::rebind (oldFbo);
+ }
+
+ gScreen->glPaintCompositedOutput(region, fbo, mask);
+}
+#endif
+
/* called whenever a plugin needs to paint the entire scene
* transformed */
@@ -1111,11 +1284,20 @@ void UnityScreen::handleEvent(XEvent* event)
PluginAdapter::Default()->OnScreenGrabbed();
else if (event->xfocus.mode == NotifyUngrab)
PluginAdapter::Default()->OnScreenUngrabbed();
+#ifndef USE_GLES
cScreen->damageScreen(); // evil hack
+#endif
if (_key_nav_mode_requested)
launcher.startKeyNavMode();
_key_nav_mode_requested = false;
break;
+ case ButtonPress:
+ if (super_keypressed_)
+ {
+ launcher.KeySwitcherCancel();
+ EnableCancelAction(false);
+ }
+ break;
case KeyPress:
{
KeySym key_sym;
@@ -1127,9 +1309,18 @@ void UnityScreen::handleEvent(XEvent* event)
// we should just say "key_string[1] = 0" because that is the only
// thing that could possibly make sense here.
key_string[result] = 0;
- if (super_keypressed_)
+ if (super_keypressed_ && key_sym != XK_Escape)
{
- shortcut_controller_->Hide();
+ g_idle_add([] (gpointer data) -> gboolean {
+ auto self = static_cast<UnityScreen*>(data);
+ if (!self->launcher_controller_->launcher().KeySwitcherIsActive())
+ {
+ self->shortcut_controller_->SetEnabled(false);
+ self->shortcut_controller_->Hide();
+ }
+ return FALSE;
+ }, this);
+
skip_other_plugins = launcher.CheckSuperShortcutPressed(screen->dpy(), key_sym, event->xkey.keycode, event->xkey.state, key_string);
if (!skip_other_plugins)
{
@@ -1225,10 +1416,9 @@ void UnityScreen::handleCompizEvent(const char* plugin,
PluginAdapter::Default()->NotifyCompizEvent(plugin, event, option);
compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow>::handleCompizEvent (plugin, event, option);
- if (dash_is_open_ &&
- strcmp(event, "start_viewport_switch") == 0)
+ if (dash_is_open_ && g_strcmp0(event, "start_viewport_switch") == 0)
{
- ubus_server_send_message(ubus_server_get_default(), UBUS_PLACE_VIEW_CLOSE_REQUEST, NULL);
+ ubus_manager_.SendMessage(UBUS_PLACE_VIEW_CLOSE_REQUEST);
}
screen->handleCompizEvent(plugin, event, option);
@@ -1245,33 +1435,33 @@ bool UnityScreen::showLauncherKeyInitiate(CompAction* action,
super_keypressed_ = true;
launcher_controller_->launcher().StartKeyShowLauncher();
EnsureSuperKeybindings ();
-
- if (enable_shortcut_overlay_ and !shortcut_controller_->Visible())
+
+ if (!shortcut_controller_->Visible() && shortcut_controller_->IsEnabled())
{
static nux::Geometry last_geo;
UScreen* uscreen = UScreen::GetDefault();
int primary_monitor = uscreen->GetPrimaryMonitor();
auto monitor_geo = uscreen->GetMonitorGeometry(primary_monitor);
-
+
int width = 970;
int height = 680;
int launcher_width = optionGetIconSize() + 18;
int panel_height = 24;
int x = monitor_geo.x + launcher_width + (monitor_geo.width - launcher_width- width) / 2;
int y = monitor_geo.y + panel_height + (monitor_geo.height - panel_height - height) / 2;
-
+
nux::Geometry geo (x, y, width, height);
-
+
if (last_geo != geo)
{
shortcut_controller_->SetWorkspace(geo);
last_geo = geo;
}
-
+
if (last_geo.x > monitor_geo.x and last_geo.y > monitor_geo.y)
shortcut_controller_->Show();
}
-
+
return false;
}
@@ -1279,9 +1469,13 @@ bool UnityScreen::showLauncherKeyTerminate(CompAction* action,
CompAction::State state,
CompOption::Vector& options)
{
+ if (state & CompAction::StateCancel)
+ return false;
+
super_keypressed_ = false;
launcher_controller_->launcher().EndKeyShowLauncher();
- launcher_controller_->launcher().KeySwitcherTerminate();
+
+ shortcut_controller_->SetEnabled(enable_shortcut_overlay_);
shortcut_controller_->Hide();
return false;
}
@@ -1370,12 +1564,8 @@ bool UnityScreen::launcherRevealEdgeInitiate(CompAction* action,
void UnityScreen::SendExecuteCommand()
{
- ubus_server_send_message(ubus_server_get_default(),
- UBUS_PLACE_ENTRY_ACTIVATE_REQUEST,
- g_variant_new("(sus)",
- "commands.lens",
- 0,
- ""));
+ ubus_manager_.SendMessage(UBUS_PLACE_ENTRY_ACTIVATE_REQUEST,
+ g_variant_new("(sus)", "commands.lens", 0, ""));
}
bool UnityScreen::executeCommand(CompAction* action,
@@ -1544,32 +1734,53 @@ bool UnityScreen::launcherSwitcherForwardInitiate(CompAction* action, CompAction
Launcher& launcher = launcher_controller_->launcher();
if (!launcher.KeySwitcherIsActive())
+ {
+ EnableCancelAction(true, action->key().modifiers());
launcher.KeySwitcherActivate();
+ }
else
+ {
launcher.KeySwitcherNext();
+ }
+ action->setState(action->state() | CompAction::StateTermKey);
return false;
}
+
bool UnityScreen::launcherSwitcherPrevInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options)
{
launcher_controller_->launcher().KeySwitcherPrevious();
return false;
}
+
bool UnityScreen::launcherSwitcherTerminate(CompAction* action, CompAction::State state, CompOption::Vector& options)
{
- launcher_controller_->launcher().KeySwitcherTerminate();
+ Launcher& launcher = launcher_controller_->launcher();
+
+ if (launcher.KeySwitcherIsActive())
+ {
+ if (state & CompAction::StateCancel)
+ {
+ launcher.KeySwitcherCancel();
+ }
+ else
+ {
+ launcher.KeySwitcherTerminate();
+ }
+
+ EnableCancelAction(false);
+ }
return false;
}
-void UnityScreen::OnLauncherStartKeyNav(GVariant* data, void* value)
+void UnityScreen::OnLauncherStartKeyNav(GVariant* data)
{
- UnityScreen* self = reinterpret_cast<UnityScreen*>(value);
- self->startLauncherKeyNav();
+ startLauncherKeyNav();
}
-void UnityScreen::OnLauncherEndKeyNav(GVariant* data, void* value)
+void UnityScreen::OnLauncherEndKeyNav(GVariant* data)
{
bool preserve_focus = false;
@@ -1584,10 +1795,9 @@ void UnityScreen::OnLauncherEndKeyNav(GVariant* data, void* value)
PluginAdapter::Default ()->restoreInputFocus ();
}
-void UnityScreen::OnQuicklistEndKeyNav(GVariant* data, void* value)
+void UnityScreen::OnQuicklistEndKeyNav(GVariant* data)
{
- UnityScreen* self = reinterpret_cast<UnityScreen*>(value);
- self->restartLauncherKeyNav();
+ restartLauncherKeyNav();
}
gboolean UnityScreen::initPluginActions(gpointer data)
@@ -1742,11 +1952,7 @@ bool UnityWindow::glPaint(const GLWindowPaintAttrib& attrib,
if (mMinimizeHandler)
{
- typedef compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow> minimized_window_handler_unity;
-
- compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow>::Ptr compizMinimizeHandler =
- boost::dynamic_pointer_cast <minimized_window_handler_unity> (mMinimizeHandler);
- mask |= compizMinimizeHandler->getPaintMask ();
+ mask |= mMinimizeHandler->getPaintMask ();
}
else if (mShowdesktopHandler)
{
@@ -1774,7 +1980,11 @@ bool UnityWindow::glPaint(const GLWindowPaintAttrib& attrib,
* and if so paint nux and stop us from painting
* other windows or on top of the whole screen */
bool UnityWindow::glDraw(const GLMatrix& matrix,
+#ifndef USE_GLES
GLFragment::Attrib& attrib,
+#else
+ const GLWindowPaintAttrib& attrib,
+#endif
const CompRegion& region,
unsigned int mask)
{
@@ -1790,7 +2000,11 @@ bool UnityWindow::glDraw(const GLMatrix& matrix,
{
if (xwns[i] == id)
{
+#ifdef USE_GLES
+ uScreen->paintDisplay();
+#else
uScreen->paintDisplay(region, matrix, mask);
+#endif
break;
}
}
@@ -1815,7 +2029,7 @@ UnityWindow::minimize ()
if (!mMinimizeHandler)
{
- mMinimizeHandler = compiz::MinimizedWindowHandler::Ptr (new compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow> (window));
+ mMinimizeHandler = new UnityMinimizedHandler (window);
mMinimizeHandler->minimize ();
}
}
@@ -1826,14 +2040,15 @@ UnityWindow::unminimize ()
if (mMinimizeHandler)
{
mMinimizeHandler->unminimize ();
- mMinimizeHandler.reset ();
+ delete mMinimizeHandler;
+ mMinimizeHandler = nullptr;
}
}
bool
UnityWindow::focus ()
{
- if (!mMinimizeHandler.get ())
+ if (!mMinimizeHandler)
return window->focus ();
if (window->overrideRedirect ())
@@ -1865,7 +2080,7 @@ UnityWindow::focus ()
bool
UnityWindow::minimized ()
{
- return mMinimizeHandler.get () != NULL;
+ return mMinimizeHandler != nullptr;
}
gboolean
@@ -1928,16 +2143,12 @@ void UnityWindow::windowNotify(CompWindowNotify n)
window->windowNotify(n);
- if (mMinimizeHandler.get () != NULL)
+ if (mMinimizeHandler)
{
/* The minimize handler will short circuit the frame
* region update func and ensure that the frame
* does not have a region */
- typedef compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow> minimized_window_handler_unity;
-
- compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow>::Ptr compizMinimizeHandler =
- boost::dynamic_pointer_cast <minimized_window_handler_unity> (mMinimizeHandler);
- compizMinimizeHandler->windowNotify (n);
+ mMinimizeHandler->windowNotify (n);
}
else if (mShowdesktopHandler)
{
@@ -1976,13 +2187,9 @@ void UnityWindow::updateFrameRegion(CompRegion &region)
/* The minimize handler will short circuit the frame
* region update func and ensure that the frame
* does not have a region */
- typedef compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow> minimized_window_handler_unity;
- compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow>::Ptr compizMinimizeHandler =
- boost::dynamic_pointer_cast <minimized_window_handler_unity> (mMinimizeHandler);
-
- if (compizMinimizeHandler)
- compizMinimizeHandler->updateFrameRegion (region);
+ if (mMinimizeHandler)
+ mMinimizeHandler->updateFrameRegion (region);
else if (mShowdesktopHandler)
mShowdesktopHandler->updateFrameRegion (region);
else
@@ -2242,6 +2449,7 @@ void UnityScreen::optionChanged(CompOption* opt, UnityshellOptions::Options num)
break;
case UnityshellOptions::ShortcutOverlay:
enable_shortcut_overlay_ = optionGetShortcutOverlay();
+ shortcut_controller_->SetEnabled(enable_shortcut_overlay_);
break;
case UnityshellOptions::ShowDesktopIcon:
launcher_controller_->SetShowDesktopIcon(optionGetShowDesktopIcon());
@@ -2269,11 +2477,13 @@ void UnityScreen::Relayout()
if (!needsRelayout)
return;
+#ifndef USE_GLES
if (GL::fbo)
{
uScreen->_fbo = ScreenEffectFramebufferObject::Ptr (new ScreenEffectFramebufferObject (glXGetProcAddressP, geometry));
uScreen->_fbo->onScreenSizeChanged (geometry);
}
+#endif
UScreen *uscreen = UScreen::GetDefault();
int primary_monitor = uscreen->GetPrimaryMonitor();
@@ -2361,6 +2571,7 @@ void UnityScreen::initLauncher()
/* Setup panel */
timer.Reset();
panel_controller_.reset(new panel::Controller());
+ AddChild(panel_controller_.get());
panel_controller_->SetMenuShowTimings(optionGetMenusFadein(),
optionGetMenusFadeout(),
optionGetMenusDiscoveryDuration(),
@@ -2399,7 +2610,7 @@ void UnityScreen::InitHints()
hints_.push_back(new shortcut::Hint(launcher, "", "", _("Switch applications via Launcher."), shortcut::HARDCODED_OPTION, "Super + Tab"));
hints_.push_back(new shortcut::Hint(launcher, "", _(" + 1 to 9"), _("Same as clicking on a Launcher icon."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher"));
hints_.push_back(new shortcut::Hint(launcher, "", _(" + Shift + 1 to 9"), _("Open new window of the app."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher"));
- hints_.push_back(new shortcut::Hint(launcher, "", " + T", _("Open the Rubbish Bin."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher"));
+ hints_.push_back(new shortcut::Hint(launcher, "", " + T", _("Open the Trash."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher"));
// Dash...
std::string const dash = _("Dash");
@@ -2453,6 +2664,7 @@ UnityWindow::UnityWindow(CompWindow* window)
, PluginClassHandler<UnityWindow, CompWindow>(window)
, window(window)
, gWindow(GLWindow::get(window))
+ , mMinimizeHandler(nullptr)
, mShowdesktopHandler(nullptr)
, focusdesktop_handle_(0)
{
@@ -2519,8 +2731,10 @@ UnityWindow::~UnityWindow()
window->minimizedSetEnabled (this, false);
window->minimize ();
- mMinimizeHandler.reset ();
+ delete mMinimizeHandler;
+ mMinimizeHandler = nullptr;
}
+
if (mShowdesktopHandler)
delete mShowdesktopHandler;
diff --git a/plugins/unityshell/src/unityshell.h b/plugins/unityshell/src/unityshell.h
index 8e9608cc8..18d95ed31 100644
--- a/plugins/unityshell/src/unityshell.h
+++ b/plugins/unityshell/src/unityshell.h
@@ -49,7 +49,9 @@
#include "DebugDBusInterface.h"
#include "SwitcherController.h"
#include "UBusWrapper.h"
+#ifndef USE_GLES
#include "ScreenEffectFramebufferObject.h"
+#endif
#include "compizminimizedwindowhandler.h"
#include "BGHash.h"
@@ -130,7 +132,11 @@ public:
void nuxEpilogue();
/* nux draw wrapper */
+#ifdef USE_GLES
+ void paintDisplay();
+#else
void paintDisplay(const CompRegion& region, const GLMatrix& transform, unsigned int mask);
+#endif
void paintPanelShadow(const GLMatrix& matrix);
void preparePaint (int ms);
@@ -151,6 +157,11 @@ public:
const CompRegion&,
CompOutput*,
unsigned int);
+#ifdef USE_GLES
+ void glPaintCompositedOutput (const CompRegion &region,
+ GLFramebufferObject *fbo,
+ unsigned int mask);
+#endif
/* paint in the special case that the output is transformed */
void glPaintTransformedOutput(const GLScreenPaintAttrib&,
@@ -225,6 +236,7 @@ private:
void EnsureSuperKeybindings ();
void CreateSuperNewAction(char shortcut, bool use_shift=false, bool use_numpad=false);
+ void EnableCancelAction(bool enabled, int modifiers = 0);
static gboolean initPluginActions(gpointer data);
void initLauncher();
@@ -245,10 +257,10 @@ private:
void OnDashRealized ();
- static void OnQuicklistEndKeyNav(GVariant* data, void* value);
- static void OnLauncherStartKeyNav(GVariant* data, void* value);
- static void OnLauncherEndKeyNav(GVariant* data, void* value);
-
+ void OnQuicklistEndKeyNav(GVariant* data);
+ void OnLauncherStartKeyNav(GVariant* data);
+ void OnLauncherEndKeyNav(GVariant* data);
+
void InitHints();
dash::Settings dash_settings_;
@@ -277,11 +289,11 @@ private:
guint _edge_trigger_handle;
guint32 _redraw_handle;
gint _edge_pointerY;
- guint _ubus_handles[3];
-
+
typedef std::shared_ptr<CompAction> CompActionPtr;
typedef std::vector<CompActionPtr> ShortcutActions;
ShortcutActions _shortcut_actions;
+ CompActionPtr _escape_action;
bool super_keypressed_;
/* keyboard-nav mode */
@@ -302,8 +314,12 @@ private:
unity::BGHash _bghash;
+#ifdef USE_GLES
+ GLFramebufferObject *oldFbo;
+#else
ScreenEffectFramebufferObject::Ptr _fbo;
GLuint _active_fbo;
+#endif
bool queryForShader ();
@@ -314,7 +330,9 @@ private:
bool painting_tray_;
unsigned int tray_paint_mask_;
+#ifndef USE_GLES
ScreenEffectFramebufferObject::GLXGetProcAddressProc glXGetProcAddressP;
+#endif
friend class UnityWindow;
};
@@ -351,7 +369,11 @@ public:
/* basic window draw function */
bool glDraw(const GLMatrix& matrix,
+#ifndef USE_GLES
GLFragment::Attrib& attrib,
+#else
+ const GLWindowPaintAttrib& attrib,
+#endif
const CompRegion& region,
unsigned intmask);
@@ -376,7 +398,10 @@ public:
void leaveShowDesktop ();
bool handleAnimations (unsigned int ms);
- compiz::MinimizedWindowHandler::Ptr mMinimizeHandler;
+ typedef compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow>
+ UnityMinimizedHandler;
+ UnityMinimizedHandler *mMinimizeHandler;
+
UnityShowdesktopHandler *mShowdesktopHandler;
private:
diff --git a/po/POTFILES.in b/po/POTFILES.in
index c3b59400e..9154d35f1 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -3,7 +3,6 @@ plugins/unityshell/src/DeviceLauncherIcon.cpp
plugins/unityshell/src/LauncherController.cpp
plugins/unityshell/src/PanelMenuView.cpp
plugins/unityshell/src/PlacesGroup.cpp
-plugins/unityshell/src/PlacesHomeView.cpp
plugins/unityshell/src/SpacerLauncherIcon.cpp
plugins/unityshell/src/TrashLauncherIcon.cpp
plugins/unityshell/src/BFBLauncherIcon.cpp
diff --git a/services/panel-service.c b/services/panel-service.c
index faab66bf9..e9ca7c449 100644
--- a/services/panel-service.c
+++ b/services/panel-service.c
@@ -31,6 +31,7 @@
#include <gdk/gdkx.h>
#include <X11/extensions/XInput2.h>
+#include <X11/XKBlib.h>
#include "panel-marshal.h"
@@ -249,9 +250,9 @@ event_filter (GdkXEvent *ev, GdkEvent *gev, PanelService *self)
if (event->evtype == XI_KeyRelease)
{
- if (XKeycodeToKeysym(event->display, event->detail, 0) == GDK_KEY_F10)
+ if (XkbKeycodeToKeysym(event->display, event->detail, 0, 0) == GDK_KEY_F10)
{
- if (GTK_MENU (priv->last_menu))
+ if (GTK_IS_MENU (priv->last_menu))
gtk_menu_popdown (GTK_MENU (priv->last_menu));
}
}
@@ -1513,7 +1514,7 @@ panel_service_show_entry (PanelService *self,
* active application (which will make it change colour (as state changes), which
* then looks like flickering to the user.
*/
- if (GTK_MENU (last_menu))
+ if (GTK_IS_MENU (last_menu))
gtk_menu_popdown (GTK_MENU (last_menu));
}
diff --git a/standalone-clients/CMakeLists.txt b/standalone-clients/CMakeLists.txt
index a8dcd29ee..8a763eec9 100644
--- a/standalone-clients/CMakeLists.txt
+++ b/standalone-clients/CMakeLists.txt
@@ -76,8 +76,6 @@ add_executable (dash
${UNITY_SRC}/FontSettings.h
${UNITY_SRC}/IMTextEntry.cpp
${UNITY_SRC}/IMTextEntry.h
- ${UNITY_SRC}/PlacesHomeView.cpp
- ${UNITY_SRC}/PlacesHomeView.h
${UNITY_SRC}/PlacesGroup.cpp
${UNITY_SRC}/PlacesGroup.h
${UNITY_SRC}/PlacesTile.cpp
@@ -86,8 +84,6 @@ add_executable (dash
${UNITY_SRC}/PlacesSimpleTile.h
${UNITY_SRC}/PlacesVScrollBar.cpp
${UNITY_SRC}/PlacesVScrollBar.h
- ${UNITY_SRC}/HomeView.cpp
- ${UNITY_SRC}/HomeView.h
${UNITY_SRC}/DashStyle.cpp
${UNITY_SRC}/IconLoader.cpp
${UNITY_SRC}/IconLoader.h
diff --git a/standalone-clients/TestScreenEffectFramebufferObject.cpp b/standalone-clients/TestScreenEffectFramebufferObject.cpp
index d913f4741..71ceebe16 100644
--- a/standalone-clients/TestScreenEffectFramebufferObject.cpp
+++ b/standalone-clients/TestScreenEffectFramebufferObject.cpp
@@ -175,6 +175,12 @@ Square::glDraw (unsigned int width, unsigned int height)
glEnd();
}
+enum class MonitorLayout
+{
+ LayoutTopBottom = 1,
+ LayoutLeftRight
+};
+
class BaseContext
{
public:
@@ -187,7 +193,7 @@ class BaseContext
protected:
bool eventHandler ();
- bool paintDispatch ();
+ bool paintDispatch (const MonitorLayout &);
enum class ModifierApplication
{
@@ -414,7 +420,6 @@ BaseContext::onNewEvents (GIOChannel *channel,
gpointer data)
{
BaseContext *self = static_cast <BaseContext *> (data);
- gboolean keep_going = TRUE;
if (condition & G_IO_IN)
{
@@ -432,7 +437,14 @@ BaseContext::onPaintTimeout (gpointer data)
{
BaseContext *self = static_cast <BaseContext *> (data);
- if (self->paintDispatch ())
+ static MonitorLayout l = MonitorLayout::LayoutLeftRight;
+
+ if (l == MonitorLayout::LayoutLeftRight)
+ l = MonitorLayout::LayoutTopBottom;
+ else
+ l = MonitorLayout::LayoutLeftRight;
+
+ if (self->paintDispatch (l))
return TRUE;
return FALSE;
@@ -528,109 +540,131 @@ void EffectView::DrawContent (nux::GraphicsEngine &GfxContext, bool force_draw)
}
bool
-BaseContext::paintDispatch ()
+BaseContext::paintDispatch (const MonitorLayout &l)
{
- if (mFbo)
- {
- switch (mRotating)
+ std::vector <nux::Geometry> monitors (0);
+
+ switch (l)
{
- case ModifierApplication::Both:
- BackgroundEffectHelper::ProcessDamage (nux::Geometry (0, 0, mWidth, mHeight));
+ case MonitorLayout::LayoutTopBottom:
+ monitors.push_back (nux::Geometry (0, 0, mWidth, mHeight / 2));
+ monitors.push_back (nux::Geometry (0, mHeight / 2, mWidth, mHeight / 2));
break;
- case ModifierApplication::Triangle:
- BackgroundEffectHelper::ProcessDamage (nux::Geometry (0, 0, mWidth / 2, mHeight));
+ case MonitorLayout::LayoutLeftRight:
+ monitors.push_back (nux::Geometry (0, 0, mWidth / 2, mHeight));
+ monitors.push_back (nux::Geometry (mWidth / 2, 0, mWidth / 2, mHeight));
break;
- case ModifierApplication::Square:
- BackgroundEffectHelper::ProcessDamage (nux::Geometry (mWidth / 2, 0, mWidth / 2, mHeight));
+ default:
break;
}
- mFbo->bind (nux::Geometry (0, 0, mWidth, mHeight));
-
- if (!mFbo->status ())
- LOG_INFO (logger) << "FBO not ok!";
- }
- glClearColor (1, 1, 1, 1);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- glPushMatrix ();
- glLoadIdentity();
- glTranslatef(-0.5f, -0.5f, -0.866025404f);
- glScalef (1.0f / mWidth, 1.0f / mHeight, 0.0f);
- glTranslatef(mWidth * 0.25, 0, 0);
- glRotatef(mTriangle->rotation (), 0.0f, 1.0f, 0.0f);
- glTranslatef(-(mWidth * 0.25), 0, 0);
-
- mTriangle->draw (mWidth, mHeight);
-
- glLoadIdentity();
- glTranslatef(-0.5f, -0.5f, -0.866025404f);
- glScalef (1.0f / mWidth, 1.0f / mHeight, 0.0f);
- glTranslatef(mWidth * 0.75, 0, 0);
- glRotatef(mSquare->rotation (), 0.0f, 1.0f, 0.0f);
- glTranslatef(-(mWidth * 0.75), 0, 0);
-
- mSquare->draw (mWidth, mHeight);
+ for (const nux::Geometry &m : monitors)
+ {
+ if (mFbo)
+ {
+ switch (mRotating)
+ {
+ case ModifierApplication::Both:
+ BackgroundEffectHelper::ProcessDamage (nux::Geometry (0, 0, mWidth, mHeight));
+ break;
+ case ModifierApplication::Triangle:
+ BackgroundEffectHelper::ProcessDamage (nux::Geometry (0, 0, mWidth / 2, mHeight));
+ break;
+ case ModifierApplication::Square:
+ BackgroundEffectHelper::ProcessDamage (nux::Geometry (mWidth / 2, 0, mWidth / 2, mHeight));
+ break;
+ }
- glColor4f (1.0f, 1.0f, 1.0f, 5.0f);
- glPopMatrix ();
+ mFbo->bind (nux::Geometry (0, 0, mWidth, mHeight));
- if (mFbo)
- mFbo->unbind ();
+ if (!mFbo->status ())
+ {
+ LOG_INFO (logger) << "FBO not ok!";
+ }
+ }
- if (mFbo && mFbo->status ())
- {
glClearColor (1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix ();
glLoadIdentity();
- glTranslatef(-0.5f, 0.5f, -0.866025404f);
- glScalef (1.0f / mWidth, -(1.0f / mHeight), 0.0f);
- mFbo->paint (nux::Geometry (0, 0, mWidth, mHeight));
- glPopMatrix ();
+ glTranslatef(-0.5f, -0.5f, -0.866025404f);
+ glScalef (1.0f / mWidth, 1.0f / mHeight, 0.0f);
+ glTranslatef(mWidth * 0.25, 0, 0);
+ glRotatef(mTriangle->rotation (), 0.0f, 1.0f, 0.0f);
+ glTranslatef(-(mWidth * 0.25), 0, 0);
- nux::ObjectPtr<nux::IOpenGLTexture2D> device_texture =
- nux::GetGraphicsDisplay()->GetGpuDevice()->CreateTexture2DFromID (mFbo->texture(),
- mWidth, mHeight, 1, nux::BITFMT_R8G8B8A8);
+ mTriangle->draw (mWidth, mHeight);
- nux::GetGraphicsDisplay()->GetGpuDevice()->backup_texture0_ = device_texture;
+ glLoadIdentity();
+ glTranslatef(-0.5f, -0.5f, -0.866025404f);
+ glScalef (1.0f / mWidth, 1.0f / mHeight, 0.0f);
+ glTranslatef(mWidth * 0.75, 0, 0);
+ glRotatef(mSquare->rotation (), 0.0f, 1.0f, 0.0f);
+ glTranslatef(-(mWidth * 0.75), 0, 0);
- nux::Geometry geo = nux::Geometry (0, 0, mWidth, mHeight);
- BackgroundEffectHelper::monitor_rect_ = geo;
- }
+ mSquare->draw (mWidth, mHeight);
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
+ glColor4f (1.0f, 1.0f, 1.0f, 5.0f);
+ glPopMatrix ();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT |
- GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT | GL_SCISSOR_BIT);
- mRootView->ProcessDraw (mWindowThread->GetGraphicsEngine (), true);
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
+ if (mFbo)
+ mFbo->unbind ();
- glDrawBuffer(GL_BACK);
- glReadBuffer(GL_BACK);
+ if (mFbo && mFbo->status ())
+ {
+ glClearColor (1, 1, 1, 1);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glPushMatrix ();
+ glLoadIdentity();
+ glTranslatef(-0.5f, 0.5f, -0.866025404f);
+ glScalef (1.0f / mWidth, -(1.0f / mHeight), 0.0f);
+ mFbo->paint (m);
+ glPopMatrix ();
+
+ nux::ObjectPtr<nux::IOpenGLTexture2D> device_texture =
+ nux::GetGraphicsDisplay()->GetGpuDevice()->CreateTexture2DFromID (mFbo->texture(),
+ mWidth, mHeight, 1, nux::BITFMT_R8G8B8A8);
+
+ nux::GetGraphicsDisplay()->GetGpuDevice()->backup_texture0_ = device_texture;
+
+ nux::Geometry geo = nux::Geometry (0, 0, mWidth, mHeight);
+ BackgroundEffectHelper::monitor_rect_ = geo;
+ }
- glPopAttrib();
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
- glXSwapBuffers (mDisplay, mGlxWindow);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT |
+ GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT | GL_SCISSOR_BIT);
+ mRootView->ProcessDraw (mWindowThread->GetGraphicsEngine (), true);
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
- switch (mRotating)
- {
- case ModifierApplication::Both:
- mTriangle->rotate ();
- mSquare->rotate ();
- break;
- case ModifierApplication::Triangle:
- mTriangle->rotate ();
- break;
- case ModifierApplication::Square:
- mSquare->rotate ();
- break;
+ glDrawBuffer(GL_BACK);
+ glReadBuffer(GL_BACK);
+
+ glPopAttrib();
+
+ glXSwapBuffers (mDisplay, mGlxWindow);
+
+ switch (mRotating)
+ {
+ case ModifierApplication::Both:
+ mTriangle->rotate ();
+ mSquare->rotate ();
+ break;
+ case ModifierApplication::Triangle:
+ mTriangle->rotate ();
+ break;
+ case ModifierApplication::Square:
+ mSquare->rotate ();
+ break;
+ }
}
return true;
diff --git a/standalone-clients/TestShortcut.cpp b/standalone-clients/TestShortcut.cpp
index db8722494..8a658c115 100644
--- a/standalone-clients/TestShortcut.cpp
+++ b/standalone-clients/TestShortcut.cpp
@@ -42,7 +42,7 @@ void ThreadWidgetInit(nux::NThread* thread, void* InitData)
hints.push_back(new shortcut::MockHint(_("Launcher"), "", "", _("Switch application via Launcher."), shortcut::HARDCODED_OPTION, "Super + Tab"));
hints.push_back(new shortcut::MockHint(_("Launcher"), "", _(" + 1 to 9"), _("Same as clicking on a Launcher icon."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher"));
hints.push_back(new shortcut::MockHint(_("Launcher"), "", _(" + Shift + 1 to 9"), _("Open a new window of the app."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher"));
- hints.push_back(new shortcut::MockHint(_("Launcher"), "", " + T", _("Open the Rubbish Bin."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher"));
+ hints.push_back(new shortcut::MockHint(_("Launcher"), "", " + T", _("Open the Trash."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher"));
// Dash...
hints.push_back(new shortcut::MockHint(_("Dash"), "", _(" (Tap)"), _("Open the Dash Home."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher"));
diff --git a/standalone-clients/standalone_dash.cpp b/standalone-clients/standalone_dash.cpp
index 937214ceb..6f9363303 100644
--- a/standalone-clients/standalone_dash.cpp
+++ b/standalone-clients/standalone_dash.cpp
@@ -77,18 +77,8 @@ void TestRunner::InitWindowThread(nux::NThread* thread, void* InitData)
self->Init ();
}
-void
-ControlThread (nux::NThread* thread,
- void* data)
-{
- // sleep for 3 seconds
- nux::SleepForMilliseconds (3000);
- printf ("ControlThread successfully started\n");
-}
-
int main(int argc, char **argv)
{
- nux::SystemThread* st = NULL;
nux::WindowThread* wt = NULL;
gtk_init (&argc, &argv);
@@ -109,13 +99,7 @@ int main(int argc, char **argv)
&TestRunner::InitWindowThread,
test_runner);
- st = nux::CreateSystemThread (NULL, ControlThread, wt);
-
- if (st)
- st->Start (NULL);
-
wt->Run (NULL);
- delete st;
delete wt;
return 0;
}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index e5155877d..80a738161 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -119,11 +119,13 @@ if (GTEST_FOUND AND
test_glib_variant.cpp
${CMAKE_CURRENT_BINARY_DIR}/test_glib_signals_utils_marshal.cpp
test_favorite_store_gsettings.cpp
+ test_favorite_store_private.cpp
+ test_home_lens.cpp
test_shortcut_model.cpp
test_shortcut_private.cpp
test_introspection.cpp
test_main_xless.cpp
- test_grabhandle.cpp
+ test_grabhandle.cpp
${UNITY_SRC}/AbstractLauncherIcon.h
${UNITY_SRC}/AbstractShortcutHint.h
${UNITY_SRC}/Animator.cpp
@@ -136,6 +138,8 @@ if (GTEST_FOUND AND
${UNITY_SRC}/FavoriteStore.h
${UNITY_SRC}/FavoriteStoreGSettings.cpp
${UNITY_SRC}/FavoriteStoreGSettings.h
+ ${UNITY_SRC}/FavoriteStorePrivate.cpp
+ ${UNITY_SRC}/FavoriteStorePrivate.h
${UNITY_SRC}/MockLauncherIcon.h
${UNITY_SRC}/MockShortcutHint.h
${UNITY_SRC}/ShortcutModel.cpp
@@ -152,11 +156,11 @@ if (GTEST_FOUND AND
${UNITY_SRC}/Timer.h
${UNITY_SRC}/WindowManager.cpp
${UNITY_SRC}/WindowManager.h
- ${CMAKE_SOURCE_DIR}/plugins/unity-mt-grab-handles/src/unity-mt-grab-handle.cpp
- ${CMAKE_SOURCE_DIR}/plugins/unity-mt-grab-handles/src/unity-mt-grab-handle-group.cpp
- ${CMAKE_SOURCE_DIR}/plugins/unity-mt-grab-handles/src/unity-mt-grab-handle-impl-factory.cpp
- ${CMAKE_SOURCE_DIR}/plugins/unity-mt-grab-handles/src/unity-mt-grab-handle-layout.cpp
- ${CMAKE_SOURCE_DIR}/plugins/unity-mt-grab-handles/src/unity-mt-texture.cpp
+ ${CMAKE_SOURCE_DIR}/plugins/unity-mt-grab-handles/src/unity-mt-grab-handle.cpp
+ ${CMAKE_SOURCE_DIR}/plugins/unity-mt-grab-handles/src/unity-mt-grab-handle-group.cpp
+ ${CMAKE_SOURCE_DIR}/plugins/unity-mt-grab-handles/src/unity-mt-grab-handle-impl-factory.cpp
+ ${CMAKE_SOURCE_DIR}/plugins/unity-mt-grab-handles/src/unity-mt-grab-handle-layout.cpp
+ ${CMAKE_SOURCE_DIR}/plugins/unity-mt-grab-handles/src/unity-mt-texture.cpp
)
target_link_libraries(test-gtest-xless ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIB} ${GMOCK_MAIN_LIB})
add_test(UnityGTestXless test-gtest-xless)
@@ -184,10 +188,15 @@ if (GTEST_FOUND AND
test_dashview_impl.cpp
test_texture_cache.cpp
test_main.cpp
+ test_icon_loader.cpp
${UNITY_SRC}/DashViewPrivate.cpp
${UNITY_SRC}/DashViewPrivate.h
${UNITY_SRC}/TextureCache.cpp
${UNITY_SRC}/TextureCache.h
+ ${UNITY_SRC}/IconLoader.cpp
+ ${UNITY_SRC}/IconLoader.h
+ ${UNITY_SRC}/Timer.cpp
+ ${UNITY_SRC}/Timer.h
)
target_link_libraries(test-gtest ${GTEST_BOTH_LIBRARIES})
add_test(UnityGTest test-gtest)
diff --git a/tests/test_favorite_store_gsettings.cpp b/tests/test_favorite_store_gsettings.cpp
index 33413bd09..deed131fd 100644
--- a/tests/test_favorite_store_gsettings.cpp
+++ b/tests/test_favorite_store_gsettings.cpp
@@ -42,8 +42,8 @@ namespace {
const gchar* SCHEMA_DIRECTORY = BUILDDIR"/settings";
const gchar* BASE_STORE_FILE = BUILDDIR"/settings/test-favorite-store-gsettings.store";
const gchar* BASE_STORE_CONTENTS = "[desktop/unity/launcher]\n" \
- "favorites=['%s', '%s', '%s']";
-
+ "favorites=['%s', '%s', '%s']";
+
const char* base_store_favs[] = { BUILDDIR"/tests/data/ubuntuone-installer.desktop",
BUILDDIR"/tests/data/ubuntu-software-center.desktop",
BUILDDIR"/tests/data/update-manager.desktop",
@@ -222,5 +222,271 @@ TEST_F(TestFavoriteStoreGSettings, TestMoveFavoriteBad)
EXPECT_EQ(at(favs, 2), base_store_favs[2]);
}
+TEST_F(TestFavoriteStoreGSettings, TestFavoriteAddedSignalFirst)
+{
+ internal::FavoriteStoreGSettings settings(backend.RawPtr());
+ bool signal_received = false;
+ std::string position;
+ bool before = false;
+
+ settings.favorite_added.connect([&](std::string const& path, std::string const& pos, bool bef)
+ {
+ signal_received = true;
+ position = pos;
+ before = bef;
+ });
+
+ FavoriteList favs;
+ favs.push_back(other_desktop);
+ favs.push_back(base_store_favs[0]);
+ favs.push_back(base_store_favs[1]);
+ favs.push_back(base_store_favs[2]);
+ settings.SaveFavorites(favs, false);
+
+ sleep(1);
+
+ ASSERT_TRUE(signal_received);
+ EXPECT_EQ(position, base_store_favs[0]);
+ EXPECT_TRUE(before);
+}
+
+TEST_F(TestFavoriteStoreGSettings, TestFavoriteAddedSignalMiddle)
+{
+ internal::FavoriteStoreGSettings settings(backend.RawPtr());
+ bool signal_received = false;
+ std::string position;
+ bool before = true;
+
+ settings.favorite_added.connect([&](std::string const& path, std::string const& pos, bool bef)
+ {
+ signal_received = true;
+ position = pos;
+ before = bef;
+ });
+
+ FavoriteList favs;
+ favs.push_back(base_store_favs[0]);
+ favs.push_back(base_store_favs[1]);
+ favs.push_back(other_desktop);
+ favs.push_back(base_store_favs[2]);
+ settings.SaveFavorites(favs, false);
+
+ sleep(1);
+
+ ASSERT_TRUE(signal_received);
+ EXPECT_EQ(position, base_store_favs[1]);
+ EXPECT_FALSE(before);
+}
+
+TEST_F(TestFavoriteStoreGSettings, TestFavoriteAddedSignalEnd)
+{
+ internal::FavoriteStoreGSettings settings(backend.RawPtr());
+ bool signal_received = false;
+ std::string position;
+ bool before = true;
+
+ settings.favorite_added.connect([&](std::string const& path, std::string const& pos, bool bef)
+ {
+ signal_received = true;
+ position = pos;
+ before = bef;
+ });
+
+ FavoriteList favs;
+ favs.push_back(base_store_favs[0]);
+ favs.push_back(base_store_favs[1]);
+ favs.push_back(base_store_favs[2]);
+ favs.push_back(other_desktop);
+ settings.SaveFavorites(favs, false);
+
+ sleep(1);
+
+ ASSERT_TRUE(signal_received);
+ EXPECT_EQ(position, base_store_favs[2]);
+ EXPECT_FALSE(before);
+}
+
+TEST_F(TestFavoriteStoreGSettings, TestFavoriteAddedSignalEmpty)
+{
+ internal::FavoriteStoreGSettings settings(backend.RawPtr());
+ bool signal_received = false;
+ std::string position;
+ bool before = false;
+
+ settings.favorite_added.connect([&](std::string const& path, std::string const& pos, bool bef)
+ {
+ signal_received = true;
+ position = pos;
+ before = bef;
+ });
+
+ FavoriteList favs;
+ favs.push_back(other_desktop);
+ settings.SaveFavorites(favs, false);
+
+ sleep(1);
+
+ ASSERT_TRUE(signal_received);
+ EXPECT_EQ(position, "");
+ EXPECT_TRUE(before);
+}
+
+TEST_F(TestFavoriteStoreGSettings, TestFavoriteRemoved)
+{
+ internal::FavoriteStoreGSettings settings(backend.RawPtr());
+ bool signal_received = false;
+ std::string path_removed;
+
+ settings.favorite_removed.connect([&](std::string const& path)
+ {
+ signal_received = true;
+ path_removed = path;
+ });
+
+ FavoriteList favs;
+ favs.push_back(base_store_favs[0]);
+ favs.push_back(base_store_favs[2]);
+ settings.SaveFavorites(favs, false);
+
+ sleep(1);
+
+ ASSERT_TRUE(signal_received);
+ EXPECT_EQ(path_removed, base_store_favs[1]);
+}
+
+TEST_F(TestFavoriteStoreGSettings, TestFavoriteReordered)
+{
+ internal::FavoriteStoreGSettings settings(backend.RawPtr());
+ bool signal_received = false;
+
+ settings.reordered.connect([&]()
+ {
+ signal_received = true;
+ });
+
+ FavoriteList favs;
+ favs.push_back(base_store_favs[0]);
+ favs.push_back(base_store_favs[2]);
+ favs.push_back(base_store_favs[1]);
+ settings.SaveFavorites(favs, false);
+
+ sleep(1);
+
+ ASSERT_TRUE(signal_received);
+
+ signal_received = false;
+ favs.push_back(base_store_favs[0]);
+ favs.push_back(base_store_favs[2]);
+ favs.push_back(base_store_favs[1]);
+ settings.SaveFavorites(favs, false);
+
+ sleep(1);
+
+ ASSERT_FALSE(signal_received);
+}
+
+TEST_F(TestFavoriteStoreGSettings, TestFavoriteSignalsMixed1)
+{
+ internal::FavoriteStoreGSettings settings(backend.RawPtr());
+ bool added_received = false;
+ bool removed_received = false;
+ bool reordered_received = false;
+
+ settings.favorite_added.connect([&](std::string const& path, std::string const& pos, bool bef)
+ {
+ added_received = true;
+ });
+
+ settings.favorite_removed.connect([&](std::string const& path)
+ {
+ removed_received = true;
+ });
+
+ settings.reordered.connect([&]()
+ {
+ reordered_received = true;
+ });
+
+ FavoriteList favs;
+ favs.push_back(base_store_favs[0]);
+ favs.push_back(base_store_favs[1]);
+ favs.push_back(other_desktop);
+ settings.SaveFavorites(favs, false);
+
+ sleep(1);
+
+ EXPECT_TRUE(added_received);
+ EXPECT_TRUE(removed_received);
+ EXPECT_FALSE(reordered_received);
+}
+
+TEST_F(TestFavoriteStoreGSettings, TestFavoriteSignalsMixed2)
+{
+ internal::FavoriteStoreGSettings settings(backend.RawPtr());
+ bool added_received = false;
+ bool removed_received = false;
+ bool reordered_received = false;
+
+ settings.favorite_added.connect([&](std::string const& path, std::string const& pos, bool bef)
+ {
+ added_received = true;
+ });
+
+ settings.favorite_removed.connect([&](std::string const& path)
+ {
+ removed_received = true;
+ });
+
+ settings.reordered.connect([&]()
+ {
+ reordered_received = true;
+ });
+
+ FavoriteList favs;
+ favs.push_back(base_store_favs[1]);
+ favs.push_back(other_desktop);
+ favs.push_back(base_store_favs[0]);
+ settings.SaveFavorites(favs, false);
+
+ sleep(1);
+
+ EXPECT_TRUE(added_received);
+ EXPECT_TRUE(removed_received);
+ EXPECT_TRUE(reordered_received);
+}
+
+TEST_F(TestFavoriteStoreGSettings, TestFavoriteSignalsMixed3)
+{
+ internal::FavoriteStoreGSettings settings(backend.RawPtr());
+ bool added_received = false;
+ bool removed_received = false;
+ bool reordered_received = false;
+
+ settings.favorite_added.connect([&](std::string const& path, std::string const& pos, bool bef)
+ {
+ added_received = true;
+ });
+
+ settings.favorite_removed.connect([&](std::string const& path)
+ {
+ removed_received = true;
+ });
+
+ settings.reordered.connect([&]()
+ {
+ reordered_received = true;
+ });
+
+ FavoriteList favs;
+ favs.push_back(base_store_favs[1]);
+ favs.push_back(base_store_favs[0]);
+ settings.SaveFavorites(favs, false);
+
+ sleep(1);
+
+ EXPECT_FALSE(added_received);
+ EXPECT_TRUE(removed_received);
+ EXPECT_TRUE(reordered_received);
+}
} // anonymous namespace
diff --git a/tests/test_favorite_store_private.cpp b/tests/test_favorite_store_private.cpp
new file mode 100644
index 000000000..093888150
--- /dev/null
+++ b/tests/test_favorite_store_private.cpp
@@ -0,0 +1,417 @@
+/*
+ * Copyright 2011 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied 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 <azzaronea@gmail.com>
+ *
+ */
+
+#include <gtest/gtest.h>
+
+#include "FavoriteStorePrivate.h"
+
+using namespace unity;
+
+TEST(TestFavoriteStorePrivate, TestGetNewbies)
+{
+ std::list<std::string> old;
+ std::list<std::string> fresh;
+ std::vector<std::string> result;
+
+ old.push_back("a");
+ old.push_back("b");
+ old.push_back("c");
+ old.push_back("d");
+
+ // No change.
+ fresh.push_back("a");
+ fresh.push_back("b");
+ fresh.push_back("c");
+ fresh.push_back("d");
+
+ result = internal::impl::GetNewbies(old, fresh);
+
+ EXPECT_TRUE(result.empty());
+
+ // Permutation.
+ fresh.clear();
+ result.clear();
+ fresh.push_back("a");
+ fresh.push_back("c");
+ fresh.push_back("b");
+ fresh.push_back("d");
+
+ result = internal::impl::GetNewbies(old, fresh);
+
+ EXPECT_TRUE(result.empty());
+
+ // a b c d -> a c b
+ fresh.clear();
+ result.clear();
+ fresh.push_back("a");
+ fresh.push_back("c");
+ fresh.push_back("b");
+
+ result = internal::impl::GetNewbies(old, fresh);
+
+ EXPECT_TRUE(result.empty());
+
+ // a b c d -> a b c d e f
+ fresh.clear();
+ result.clear();
+ fresh.push_back("a");
+ fresh.push_back("b");
+ fresh.push_back("c");
+ fresh.push_back("d");
+ fresh.push_back("e");
+ fresh.push_back("f");
+
+ result = internal::impl::GetNewbies(old, fresh);
+
+ EXPECT_EQ(result.size(), 2);
+ EXPECT_EQ(result[0], "e");
+ EXPECT_EQ(result[1], "f");
+
+ // a b c d -> a b c e f
+ fresh.clear();
+ result.clear();
+ fresh.push_back("a");
+ fresh.push_back("b");
+ fresh.push_back("c");
+ fresh.push_back("e");
+ fresh.push_back("f");
+
+ result = internal::impl::GetNewbies(old, fresh);
+
+ EXPECT_EQ(result.size(), 2);
+ EXPECT_EQ(result[0], "e");
+ EXPECT_EQ(result[1], "f");
+}
+
+TEST(TestFavoriteStorePrivate, TestGetSignalAddedInfo)
+{
+ std::list<std::string> favs;
+ std::vector<std::string> newbies;
+ std::string position;
+ bool before;
+
+ favs.push_back("a");
+ favs.push_back("b");
+ favs.push_back("c");
+ favs.push_back("d");
+ favs.push_back("e");
+
+ // b c d e -> a b c d e
+ newbies.push_back("a");
+ internal::impl::GetSignalAddedInfo(favs, newbies, "a", position, before);
+ EXPECT_TRUE(before);
+ EXPECT_EQ(position, "b");
+
+ // a c d e -> a b c d e
+ newbies.clear();
+ newbies.push_back("b");
+ internal::impl::GetSignalAddedInfo(favs, newbies, "b", position, before);
+ EXPECT_FALSE(before);
+ EXPECT_EQ(position, "a");
+
+ // a b d e -> a b c d e
+ newbies.clear();
+ newbies.push_back("c");
+ internal::impl::GetSignalAddedInfo(favs, newbies, "c", position, before);
+ EXPECT_FALSE(before);
+ EXPECT_EQ(position, "b");
+
+ // a b c e -> a b c d e
+ newbies.clear();
+ newbies.push_back("d");
+ internal::impl::GetSignalAddedInfo(favs, newbies, "d", position, before);
+ EXPECT_FALSE(before);
+ EXPECT_EQ(position, "c");
+
+ // a b c d -> a b c d e
+ newbies.clear();
+ newbies.push_back("e");
+ internal::impl::GetSignalAddedInfo(favs, newbies, "e", position, before);
+ EXPECT_FALSE(before);
+ EXPECT_EQ(position, "d");
+
+ // -> b a c
+ favs.clear();
+ favs.push_back("b");
+ favs.push_back("a");
+ favs.push_back("c");
+ newbies.clear();
+ newbies.push_back("a");
+ newbies.push_back("b");
+ newbies.push_back("c");
+
+ internal::impl::GetSignalAddedInfo(favs, newbies, "b", position, before);
+ EXPECT_TRUE(before);
+ EXPECT_EQ(position, "");
+
+ internal::impl::GetSignalAddedInfo(favs, newbies, "a", position, before);
+ EXPECT_FALSE(before);
+ EXPECT_EQ(position, "b");
+
+ internal::impl::GetSignalAddedInfo(favs, newbies, "c", position, before);
+ EXPECT_FALSE(before);
+ EXPECT_EQ(position, "a");
+}
+
+
+TEST(TestFavoriteStorePrivate, TestGetRemoved)
+{
+ std::list<std::string> old;
+ std::list<std::string> fresh;
+ std::vector<std::string> result;
+
+ old.push_back("a");
+ old.push_back("b");
+ old.push_back("c");
+ old.push_back("d");
+
+ // No change.
+ fresh.push_back("a");
+ fresh.push_back("b");
+ fresh.push_back("c");
+ fresh.push_back("d");
+
+ result = internal::impl::GetRemoved(old, fresh);
+
+ EXPECT_TRUE(result.empty());
+
+ // Permutation.
+ fresh.clear();
+ result.clear();
+ fresh.push_back("a");
+ fresh.push_back("c");
+ fresh.push_back("b");
+ fresh.push_back("d");
+
+ result = internal::impl::GetRemoved(old, fresh);
+
+ EXPECT_TRUE(result.empty());
+
+ // a b c d -> b c
+ fresh.clear();
+ result.clear();
+ fresh.push_back("b");
+ fresh.push_back("c");
+
+ result = internal::impl::GetRemoved(old, fresh);
+
+ EXPECT_EQ(result.size(), 2);
+ EXPECT_EQ(result[0], "a");
+ EXPECT_EQ(result[1], "d");
+
+ // a b c d -> a e f d
+ fresh.clear();
+ result.clear();
+ fresh.push_back("a");
+ fresh.push_back("e");
+ fresh.push_back("f");
+ fresh.push_back("d");
+
+
+ result = internal::impl::GetRemoved(old, fresh);
+
+ EXPECT_EQ(result.size(), 2);
+ EXPECT_EQ(result[0], "b");
+ EXPECT_EQ(result[1], "c");
+}
+
+
+TEST(TestFavoriteStorePrivate, TestNeedToBeReorderedBasic)
+{
+ std::list<std::string> old;
+ std::list<std::string> fresh;
+
+ old.push_back("a");
+ old.push_back("b");
+ old.push_back("c");
+ old.push_back("d");
+
+ // No change.
+ fresh.push_back("a");
+ fresh.push_back("b");
+ fresh.push_back("c");
+ fresh.push_back("d");
+
+ EXPECT_FALSE(internal::impl::NeedToBeReordered(old, fresh));
+
+ // Permutation.
+ fresh.clear();
+ fresh.push_back("a");
+ fresh.push_back("c");
+ fresh.push_back("b");
+ fresh.push_back("d");
+
+ EXPECT_TRUE(internal::impl::NeedToBeReordered(old, fresh));
+
+ // Empty.
+ fresh.clear();
+
+ EXPECT_FALSE(internal::impl::NeedToBeReordered(old, fresh));
+}
+
+TEST(TestFavoriteStorePrivate, TestNeedToBeReorderedLess)
+{
+ std::list<std::string> old;
+ std::list<std::string> fresh;
+
+ old.push_back("a");
+ old.push_back("b");
+ old.push_back("c");
+ old.push_back("d");
+
+ // a b c d -> a b c
+ fresh.clear();
+ fresh.push_back("a");
+ fresh.push_back("b");
+ fresh.push_back("c");
+
+ EXPECT_FALSE(internal::impl::NeedToBeReordered(old, fresh));
+
+ // a b c d -> b c d
+ fresh.clear();
+ fresh.push_back("b");
+ fresh.push_back("c");
+ fresh.push_back("d");
+
+ EXPECT_FALSE(internal::impl::NeedToBeReordered(old, fresh));
+
+ // a b c d -> a b d
+ fresh.clear();
+ fresh.push_back("a");
+ fresh.push_back("b");
+ fresh.push_back("d");
+
+ EXPECT_FALSE(internal::impl::NeedToBeReordered(old, fresh));
+
+ // a b c d -> a
+ fresh.clear();
+ fresh.push_back("a");
+
+ EXPECT_FALSE(internal::impl::NeedToBeReordered(old, fresh));
+
+ // a b c d -> a d b
+ fresh.clear();
+ fresh.push_back("a");
+ fresh.push_back("d");
+ fresh.push_back("b");
+
+ EXPECT_TRUE(internal::impl::NeedToBeReordered(old, fresh));
+
+ // a b c d -> b a c
+ fresh.clear();
+ fresh.push_back("b");
+ fresh.push_back("a");
+ fresh.push_back("c");
+
+ EXPECT_TRUE(internal::impl::NeedToBeReordered(old, fresh));
+}
+
+TEST(TestFavoriteStorePrivate, TestNeedToBeReorderedPlus)
+{
+ std::list<std::string> old;
+ std::list<std::string> fresh;
+
+ old.push_back("a");
+ old.push_back("b");
+ old.push_back("c");
+ old.push_back("d");
+
+ // All new elements.
+ fresh.clear();
+ fresh.push_back("e");
+ fresh.push_back("f");
+ fresh.push_back("g");
+ fresh.push_back("h");
+
+ EXPECT_FALSE(internal::impl::NeedToBeReordered(old, fresh));
+
+ // a b c d -> a b c d e
+ fresh.clear();
+ fresh.push_back("a");
+ fresh.push_back("b");
+ fresh.push_back("c");
+ fresh.push_back("d");
+ fresh.push_back("e");
+
+ EXPECT_FALSE(internal::impl::NeedToBeReordered(old, fresh));
+
+ // a b c d -> a b e c d
+ fresh.clear();
+ fresh.push_back("a");
+ fresh.push_back("b");
+ fresh.push_back("e");
+ fresh.push_back("c");
+ fresh.push_back("d");
+
+ EXPECT_FALSE(internal::impl::NeedToBeReordered(old, fresh));
+
+ // a b c d -> a b e d c
+ fresh.clear();
+ fresh.push_back("a");
+ fresh.push_back("b");
+ fresh.push_back("e");
+ fresh.push_back("d");
+ fresh.push_back("c");
+
+ EXPECT_TRUE(internal::impl::NeedToBeReordered(old, fresh));
+
+ // a b c d -> f a b c d
+ fresh.clear();
+ fresh.push_back("f");
+ fresh.push_back("a");
+ fresh.push_back("b");
+ fresh.push_back("c");
+ fresh.push_back("d");
+
+ EXPECT_FALSE(internal::impl::NeedToBeReordered(old, fresh));
+}
+
+TEST(TestFavoriteStorePrivate, TestNeedToBeReorderedMixed)
+{
+ std::list<std::string> old;
+ std::list<std::string> fresh;
+
+ old.push_back("a");
+ old.push_back("b");
+ old.push_back("c");
+ old.push_back("d");
+
+ // a b c d -> b f c g h
+ fresh.clear();
+ fresh.push_back("b");
+ fresh.push_back("f");
+ fresh.push_back("c");
+ fresh.push_back("g");
+ fresh.push_back("h");
+
+ EXPECT_FALSE(internal::impl::NeedToBeReordered(old, fresh));
+
+
+ // a b c d -> c f b g h
+ fresh.clear();
+ fresh.push_back("c");
+ fresh.push_back("f");
+ fresh.push_back("b");
+ fresh.push_back("g");
+ fresh.push_back("h");
+
+ EXPECT_TRUE(internal::impl::NeedToBeReordered(old, fresh));
+}
+
diff --git a/tests/test_home_lens.cpp b/tests/test_home_lens.cpp
new file mode 100644
index 000000000..069175ab5
--- /dev/null
+++ b/tests/test_home_lens.cpp
@@ -0,0 +1,362 @@
+#include <gtest/gtest.h>
+#include <glib-object.h>
+#include <dee.h>
+#include <string>
+#include <iostream>
+#include <stdexcept>
+#include <map>
+#include <memory>
+#include <sigc++/signal.h>
+#include <sigc++/trackable.h>
+
+#include <UnityCore/GLibWrapper.h>
+#include <UnityCore/Variant.h>
+#include <UnityCore/HomeLens.h>
+#include <UnityCore/Lens.h>
+#include <UnityCore/Lenses.h>
+
+#include "test_utils.h"
+
+using namespace std;
+using namespace unity::dash;
+
+namespace
+{
+
+/*
+ * FORWARDS
+ */
+
+class StaticTestLens;
+
+typedef struct {
+ StaticTestLens* lens;
+ gchar* search_string;
+} LensSearchClosure;
+
+static gboolean dispatch_global_search(gpointer userdata);
+
+
+/*
+ * Mock Lens instance that does not use DBus. The default search does like this:
+ * For input "bar" output:
+ *
+ * i = 0
+ * for letter in "bar":
+ * put result row [ "uri+$letter+$lens_id", "icon+$letter+$lens_id", i % 3, "mime+$letter+$lens_id", ...]
+ * i++
+ *
+ * The mock lens has 3 categories:
+ *
+ * 0) "cat0+$lens_id"
+ * 1) "cat1+$lens_id"
+ * 2) "Shared cat"
+ */
+class StaticTestLens : public Lens
+{
+public:
+ typedef std::shared_ptr<StaticTestLens> Ptr;
+
+ StaticTestLens(string const& id, string const& name, string const& description, string const& search_hint)
+ : Lens(id, "", "", name, "lens-icon.png",
+ description, search_hint, true, "",
+ ModelType::LOCAL)
+ {
+ search_in_global(true);
+
+ DeeModel* cats = categories()->model();
+ DeeModel* results = global_results()->model();
+ DeeModel* flters = filters()->model();
+
+ // Set model schemas
+ dee_model_set_schema(cats, "s", "s", "s", "a{sv}", NULL);
+ dee_model_set_schema(results, "s", "s", "u", "s", "s", "s", "s", NULL);
+ dee_model_set_schema(flters, "s", "s", "s", "s", "a{sv}", "b", "b", "b", NULL);
+
+ // Populate categories model
+ ostringstream cat0, cat1;
+ cat0 << "cat0+" << id;
+ cat1 << "cat1+" << id;
+ GVariantBuilder b;
+ g_variant_builder_init(&b, G_VARIANT_TYPE_VARDICT);
+ GVariant *asv = g_variant_builder_end(&b);
+
+ dee_model_append(cats, cat0.str().c_str(), "icon.png", "tile-vertical", asv);
+ dee_model_append(cats, cat1.str().c_str(), "icon.png", "tile-vertical", asv);
+ dee_model_append(cats, "Shared cat", "icon.png", "tile-vertical", asv);
+ }
+
+ virtual ~StaticTestLens() {}
+
+ virtual void DoGlobalSearch(string const& search_string)
+ {
+ DeeModel* model = global_results()->model();
+ GVariant** row_buf = g_new(GVariant*, 8);
+
+ row_buf[1] = g_variant_new_string("");
+ row_buf[3] = g_variant_new_string("");
+ row_buf[4] = g_variant_new_string("");
+ row_buf[5] = g_variant_new_string("");
+ row_buf[6] = g_variant_new_string("");
+ row_buf[7] = NULL;
+
+ unsigned int i;
+ for (i = 0; i < search_string.size(); i++)
+ {
+ ostringstream uri;
+ uri << "uri+" << search_string.at(i) << "+" << id();
+ row_buf[0] = g_variant_new_string(uri.str().c_str());
+ row_buf[2] = g_variant_new_uint32(i % 3);
+
+ dee_model_append_row(model, row_buf);
+ }
+
+ g_free(row_buf);
+ }
+
+ void GlobalSearch(string const& search_string)
+ {
+ /* Dispatch search async, because that's */
+ LensSearchClosure* closure = g_new0(LensSearchClosure, 1);
+ closure->lens = this;
+ closure->search_string = g_strdup(search_string.c_str());
+ g_idle_add(dispatch_global_search, closure);
+ }
+
+ void Search(string const& search_string)
+ {
+
+ }
+
+ void Activate(string const& uri)
+ {
+
+ }
+
+ void Preview(string const& uri)
+ {
+
+ }
+
+};
+
+static gboolean dispatch_global_search(gpointer userdata)
+{
+ LensSearchClosure* closure = (LensSearchClosure*) userdata;
+
+ closure->lens->DoGlobalSearch(closure->search_string);
+
+ g_free(closure->search_string);
+ g_free(closure);
+
+ return FALSE;
+}
+
+/*
+ * Mock Lenses class
+ */
+class StaticTestLenses : public Lenses
+{
+public:
+ typedef std::shared_ptr<StaticTestLenses> Ptr;
+
+ StaticTestLenses()
+ {
+ count.SetGetterFunction(sigc::mem_fun(&list_, &Lenses::LensList::size));
+ }
+
+ virtual ~StaticTestLenses() {}
+
+ Lenses::LensList GetLenses() const
+ {
+ return list_;
+ }
+
+ Lens::Ptr GetLens(std::string const& lens_id) const
+ {
+ for (auto lens : list_)
+ {
+ if (lens->id() == lens_id)
+ return lens;
+ }
+ return Lens::Ptr();
+ }
+
+ Lens::Ptr GetLensAtIndex(std::size_t index) const
+ {
+ return list_.at(index);
+ }
+
+protected:
+ Lenses::LensList list_;
+};
+
+class TwoStaticTestLenses : public StaticTestLenses
+{
+public:
+ TwoStaticTestLenses()
+ : lens_1_(new StaticTestLens("first.lens", "First Lens", "The very first lens", "First search hint"))
+ , lens_2_(new StaticTestLens("second.lens", "Second Lens", "The second lens", "Second search hint"))
+ {
+ list_.push_back(lens_1_);
+ list_.push_back(lens_2_);
+ }
+
+private:
+ Lens::Ptr lens_1_;
+ Lens::Ptr lens_2_;
+};
+
+TEST(TestHomeLens, TestConstruction)
+{
+ HomeLens home_lens_("name", "description", "searchhint");
+
+ EXPECT_EQ(home_lens_.id(), "home.lens");
+ EXPECT_EQ(home_lens_.connected, false);
+ EXPECT_EQ(home_lens_.search_in_global, false);
+ EXPECT_EQ(home_lens_.name, "name");
+ EXPECT_EQ(home_lens_.description, "description");
+ EXPECT_EQ(home_lens_.search_hint, "searchhint");
+}
+
+TEST(TestHomeLens, TestInitiallyEmpty)
+{
+ HomeLens home_lens_("name", "description", "searchhint");
+ DeeModel* results = home_lens_.results()->model();
+ DeeModel* categories = home_lens_.categories()->model();;
+ DeeModel* filters = home_lens_.filters()->model();;
+
+ EXPECT_EQ(dee_model_get_n_rows(results), 0);
+ EXPECT_EQ(dee_model_get_n_rows(categories), 0);
+ EXPECT_EQ(dee_model_get_n_rows(filters), 0);
+
+ EXPECT_EQ(home_lens_.count(), 0);
+}
+
+TEST(TestHomeLens, TestTwoStaticLenses)
+{
+ HomeLens home_lens_("name", "description", "searchhint");
+ TwoStaticTestLenses lenses_;
+
+ home_lens_.AddLenses(lenses_);
+
+ EXPECT_EQ(home_lens_.count, (size_t) 2);
+
+ /* Test iteration of registered lensess */
+ map<string,string> remaining;
+ remaining["first.lens"] = "";
+ remaining["second.lens"] = "";
+ for (auto lens : home_lens_.GetLenses())
+ {
+ remaining.erase(lens->id());
+ }
+
+ EXPECT_EQ(remaining.size(), 0);
+
+ /* Test sorting and GetAtIndex */
+ EXPECT_EQ(home_lens_.GetLensAtIndex(0)->id(), "first.lens");
+ EXPECT_EQ(home_lens_.GetLensAtIndex(1)->id(), "second.lens");
+}
+
+TEST(TestHomeLens, TestCategoryMerging)
+{
+ HomeLens home_lens_("name", "description", "searchhint");
+ TwoStaticTestLenses lenses_;
+ DeeModel* cats = home_lens_.categories()->model();
+ DeeModelIter* iter;
+ unsigned int cat0_first = 0,
+ cat1_first = 1,
+ cat_shared = 2,
+ cat0_second = 3,
+ cat1_second = 4;
+ const unsigned int NAME_COLUMN = 0;
+
+ home_lens_.AddLenses(lenses_);
+
+ EXPECT_EQ(dee_model_get_n_rows(cats), 5); // 5 because each lens has 3 cats, but 1 is shared between them
+
+ /* Validate the merged categories */
+ iter = dee_model_get_iter_at_row(cats, cat0_first);
+ EXPECT_EQ("cat0+first.lens", string(dee_model_get_string(cats, iter, NAME_COLUMN)));
+
+ iter = dee_model_get_iter_at_row(cats, cat1_first);
+ EXPECT_EQ("cat1+first.lens", string(dee_model_get_string(cats, iter, NAME_COLUMN)));
+
+ iter = dee_model_get_iter_at_row(cats, cat_shared);
+ EXPECT_EQ("Shared cat", string(dee_model_get_string(cats, iter, NAME_COLUMN)));
+
+ iter = dee_model_get_iter_at_row(cats, cat0_second);
+ EXPECT_EQ("cat0+second.lens", string(dee_model_get_string(cats, iter, NAME_COLUMN)));
+
+ iter = dee_model_get_iter_at_row(cats, cat1_second);
+ EXPECT_EQ("cat1+second.lens", string(dee_model_get_string(cats, iter, NAME_COLUMN)));
+}
+
+// It's not that we must not support filters. It is just not implemented yet.
+// But we actively test against it to make sure we don't end up with broken
+// filters in the UI. When/if we land support for filters on the home screen
+// this test should obviously be removed
+TEST(TestHomeLens, TestIgnoreFilters)
+{
+ HomeLens home_lens_("name", "description", "searchhint");
+ TwoStaticTestLenses lenses_;
+ DeeModel* filters = home_lens_.filters()->model();
+
+ EXPECT_EQ(dee_model_get_n_rows(filters), 0);
+}
+
+TEST(TestHomeLens, TestOneSearch)
+{
+ HomeLens home_lens_("name", "description", "searchhint");
+ TwoStaticTestLenses lenses_;
+ DeeModel* results = home_lens_.results()->model();
+ DeeModel* cats = home_lens_.categories()->model();
+ DeeModel* filters = home_lens_.filters()->model();
+ DeeModelIter* iter;
+ unsigned int cat0_first = 0,
+ cat1_first = 1,
+ cat_shared = 2,
+ cat0_second = 3,
+ cat1_second = 4;
+ const unsigned int URI_COLUMN = 0;
+ const unsigned int CAT_COLUMN = 2;
+
+ home_lens_.AddLenses(lenses_);
+
+ home_lens_.Search("ape");
+
+ Utils::WaitForTimeoutMSec();
+
+ /* Validate counts */
+ EXPECT_EQ(dee_model_get_n_rows(results), 6); // 3 hits from each lens
+ EXPECT_EQ(dee_model_get_n_rows(cats), 5); // 5 because each lens has 3 cats, but 1 is shared between them
+ EXPECT_EQ(dee_model_get_n_rows(filters), 0); // We ignore filters deliberately currently
+
+ /* Validate results. In particular that we get the correct merged
+ * category offsets assigned */
+ iter = dee_model_get_iter_at_row(results, 0);
+ EXPECT_EQ(string("uri+a+first.lens"), string(dee_model_get_string(results, iter, URI_COLUMN)));
+ EXPECT_EQ(cat0_first, dee_model_get_uint32(results, iter, CAT_COLUMN));
+
+ iter = dee_model_get_iter_at_row(results, 1);
+ EXPECT_EQ(string("uri+p+first.lens"), string(dee_model_get_string(results, iter, URI_COLUMN)));
+ EXPECT_EQ(cat1_first, dee_model_get_uint32(results, iter, CAT_COLUMN));
+
+ iter = dee_model_get_iter_at_row(results, 2);
+ EXPECT_EQ(string("uri+e+first.lens"), string(dee_model_get_string(results, iter, URI_COLUMN)));
+ EXPECT_EQ(cat_shared, dee_model_get_uint32(results, iter, CAT_COLUMN));
+
+ iter = dee_model_get_iter_at_row(results, 3);
+ EXPECT_EQ(string("uri+a+second.lens"), string(dee_model_get_string(results, iter, URI_COLUMN)));
+ EXPECT_EQ(cat0_second, dee_model_get_uint32(results, iter, CAT_COLUMN));
+
+ iter = dee_model_get_iter_at_row(results, 4);
+ EXPECT_EQ(string("uri+p+second.lens"), string(dee_model_get_string(results, iter, URI_COLUMN)));
+ EXPECT_EQ(cat1_second, dee_model_get_uint32(results, iter, CAT_COLUMN));
+
+ iter = dee_model_get_iter_at_row(results, 5);
+ EXPECT_EQ(string("uri+e+second.lens"), string(dee_model_get_string(results, iter, URI_COLUMN)));
+ EXPECT_EQ(cat_shared, dee_model_get_uint32(results, iter, CAT_COLUMN));
+}
+
+}
diff --git a/tests/test_icon_loader.cpp b/tests/test_icon_loader.cpp
new file mode 100644
index 000000000..0c9a42a1b
--- /dev/null
+++ b/tests/test_icon_loader.cpp
@@ -0,0 +1,191 @@
+/*
+ * 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: Michal Hruby <michal.hruby@canonical.com>
+ */
+
+#include <gmock/gmock.h>
+
+#include "IconLoader.h"
+
+using namespace testing;
+using namespace unity;
+
+namespace
+{
+bool IsValidPixbuf(GdkPixbuf *pixbuf)
+{
+ return GDK_IS_PIXBUF (pixbuf);
+}
+
+gboolean TimeoutReached (gpointer data)
+{
+ bool *b = static_cast<bool*>(data);
+
+ *b = true;
+
+ return FALSE;
+}
+
+struct LoadResult
+{
+ GdkPixbuf *pixbuf;
+ bool got_callback;
+
+ LoadResult() : pixbuf(NULL), got_callback(false) {}
+ void IconLoaded(std::string const& icon_name, unsigned size,
+ GdkPixbuf *buf)
+ {
+ pixbuf = buf;
+
+ got_callback = true;
+ }
+};
+
+TEST(TestIconLoader, TestGetDefault)
+{
+ // we need to initialize gtk
+ int args_cnt = 0;
+ gtk_init (&args_cnt, NULL);
+
+ IconLoader::GetDefault();
+}
+
+TEST(TestIconLoader, TestGetOneIcon)
+{
+ LoadResult load_result;
+ IconLoader& icon_loader = IconLoader::GetDefault();
+ volatile bool timeout_reached = false;
+
+ icon_loader.LoadFromIconName("gedit-icon", 48, sigc::mem_fun(load_result,
+ &LoadResult::IconLoaded));
+
+ guint tid = g_timeout_add (10000, TimeoutReached, (gpointer)(&timeout_reached));
+ while (!timeout_reached && !load_result.got_callback)
+ {
+ g_main_context_iteration (NULL, TRUE);
+ }
+
+ EXPECT_TRUE(load_result.got_callback);
+ EXPECT_TRUE(IsValidPixbuf(load_result.pixbuf));
+
+ g_source_remove (tid);
+}
+
+TEST(TestIconLoader, TestGetManyIcons)
+{
+ std::vector<LoadResult> results;
+ IconLoader& icon_loader = IconLoader::GetDefault();
+ volatile bool timeout_reached = false;
+ int i = 0;
+ int icon_count;
+
+ GList *icons = gtk_icon_theme_list_icons (gtk_icon_theme_get_default (),
+ "Applications");
+ // loading 100 icons should suffice
+ icon_count = MIN (100, g_list_length (icons));
+ results.resize (icon_count);
+ for (GList *it = icons; it != NULL; it = it->next)
+ {
+ const char *icon_name = static_cast<char*>(it->data);
+ icon_loader.LoadFromIconName(icon_name, 48, sigc::mem_fun(results[i++],
+ &LoadResult::IconLoaded));
+ if (i >= icon_count) break;
+ }
+
+ guint tid = g_timeout_add (30000, TimeoutReached, (gpointer)(&timeout_reached));
+ while (!timeout_reached)
+ {
+ g_main_context_iteration (NULL, TRUE);
+ bool all_loaded = true;
+ for (auto loader: results)
+ {
+ all_loaded &= loader.got_callback;
+ if (!all_loaded) break;
+ }
+ if (all_loaded) break;
+ }
+
+ for (auto load_result: results)
+ {
+ EXPECT_TRUE(load_result.got_callback);
+ EXPECT_TRUE(IsValidPixbuf(load_result.pixbuf));
+ }
+
+ g_source_remove (tid);
+}
+
+TEST(TestIconLoader, TestCancelSome)
+{
+ std::vector<LoadResult> results;
+ std::vector<int> handles;
+ IconLoader& icon_loader = IconLoader::GetDefault();
+ volatile bool timeout_reached = false;
+ int i = 0;
+ int icon_count;
+
+ GList *icons = gtk_icon_theme_list_icons (gtk_icon_theme_get_default (),
+ "Emblems");
+ // loading 100 icons should suffice
+ icon_count = MIN (100, g_list_length (icons));
+ results.resize (icon_count);
+ handles.resize (icon_count);
+ for (GList *it = icons; it != NULL; it = it->next)
+ {
+ const char *icon_name = static_cast<char*>(it->data);
+ int handle = icon_loader.LoadFromIconName(icon_name, 48, sigc::mem_fun(
+ results[i], &LoadResult::IconLoaded));
+ handles[i++] = handle;
+ if (i >= icon_count) break;
+ }
+
+ // disconnect every other handler
+ for (i = 0; i < icon_count; i += 2)
+ {
+ icon_loader.DisconnectHandle(handles[i]);
+ }
+
+ guint tid = g_timeout_add (30000, TimeoutReached, (gpointer)(&timeout_reached));
+ while (!timeout_reached)
+ {
+ g_main_context_iteration (NULL, TRUE);
+ bool all_loaded = true;
+ for (int i = 1; i < icon_count; i += 2)
+ {
+ all_loaded &= results[i].got_callback;
+ if (!all_loaded) break;
+ }
+ if (all_loaded) break;
+ }
+
+ for (i = 0; i < icon_count; i++)
+ {
+ if (i % 2)
+ {
+ EXPECT_TRUE(results[i].got_callback);
+ EXPECT_TRUE(IsValidPixbuf(results[i].pixbuf));
+ }
+ else
+ {
+ EXPECT_FALSE(results[i].got_callback);
+ }
+ }
+
+ g_source_remove (tid);
+}
+
+
+}
diff --git a/tests/test_utils.h b/tests/test_utils.h
index fa0c47414..a378487fe 100644
--- a/tests/test_utils.h
+++ b/tests/test_utils.h
@@ -51,6 +51,33 @@ public:
return g_timeout_add_seconds(timeout_duration, TimeoutCallback, timeout_reached);
}
+ static guint32 ScheduleTimeoutMSec(bool* timeout_reached, unsigned int timeout_duration = 10)
+ {
+ return g_timeout_add(timeout_duration, TimeoutCallback, timeout_reached);
+ }
+
+ static void WaitForTimeout(unsigned int timeout_duration = 10)
+ {
+ bool timeout_reached = false;
+ guint32 timeout_id = ScheduleTimeout(&timeout_reached, timeout_duration);
+
+ while (!timeout_reached)
+ g_main_context_iteration(g_main_context_get_thread_default(), TRUE);
+
+ g_source_remove(timeout_id);
+ }
+
+ static void WaitForTimeoutMSec(unsigned int timeout_duration = 10)
+ {
+ bool timeout_reached = false;
+ guint32 timeout_id = ScheduleTimeoutMSec(&timeout_reached, timeout_duration);
+
+ while (!timeout_reached)
+ g_main_context_iteration(g_main_context_get_thread_default(), TRUE);
+
+ g_source_remove(timeout_id);
+ }
+
private:
static gboolean TimeoutCallback(gpointer data)
{
diff --git a/tools/unity-introspection-visualiser.py b/tools/unity-introspection-visualiser.py
new file mode 100755
index 000000000..fae236e2c
--- /dev/null
+++ b/tools/unity-introspection-visualiser.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+
+#
+# Script to generate a nice PNG file of the currently running unity introspection tree.
+from sys import argv
+import dbus
+
+try:
+ from autopilot.emulators.unity import Unity
+except ImportError:
+ print "Error: could not import the autopilot python module."
+ print "Make sure the autopilot module is in your $PYTHONPATH."
+ exit(1)
+
+try:
+ import pydot
+except ImportError:
+ print "Error: the 'pydot' module is required to run this script."
+ print "Try installing the 'python-pydot' package."
+ exit(1)
+
+NEXT_NODE_ID=1
+
+def string_rep(dbus_type):
+ """Get a string representation of various dbus types."""
+ if type(dbus_type) == dbus.Boolean:
+ return repr(bool(dbus_type))
+ if type(dbus_type) == dbus.String:
+ return str(dbus_type)
+ if type(dbus_type) in (dbus.Int16, dbus.UInt16, dbus.Int32, dbus.UInt32, dbus.Int64, dbus.UInt64):
+ return repr(int(dbus_type))
+ if type(dbus_type) == dbus.Double:
+ return repr(float(dbus_type))
+ if type(dbus_type) == dbus.Array:
+ return ', '.join([string_rep(i) for i in dbus_type])
+ else:
+ return repr(dbus_type)
+
+
+def escape(s):
+ """Escape a string so it can be use in a dot label."""
+ return pydot.quote_if_necessary(s).replace('<','\\<').replace('>', '\\>')
+
+
+def traverse_tree(state, parent, graph):
+ """Recursively traverse state tree, building dot graph as we go."""
+ global NEXT_NODE_ID
+ lbl = parent.get_comment() + "|"
+ # first, set labels for this node:
+ bits = ["%s=%s" % (k, string_rep(state[k])) for k in state.keys() if k != 'Children']
+ lbl += "\l".join(bits)
+ parent.set_label(escape('"{' + lbl + '}"'))
+ if state.has_key('Children'):
+ # Add all array nodes as children of this node.
+ for child_name, child_state in state['Children']:
+ child = pydot.Node(str(NEXT_NODE_ID))
+ NEXT_NODE_ID+=1
+ child.set_comment(child_name)
+ graph.add_node(child)
+ graph.add_edge(pydot.Edge(parent, child))
+
+ traverse_tree(child_state, child, graph)
+
+
+if __name__ == '__main__':
+ if len(argv) != 2:
+ print """Usage: %s output_file.png.
+
+This script queries the currently running Unity process and dumps the entire
+introspection tree into a graph, and renders this to a PNG file.
+""" % (argv[0])
+ exit(1)
+
+ u = Unity()
+ introspection_tree = u.get_state()
+ graph = pydot.Dot()
+ graph.set_simplify(False)
+ graph.set_node_defaults(shape='Mrecord')
+ graph.set_fontname('Ubuntu')
+ graph.set_fontsize('10')
+
+ gnode_unity = pydot.Node("Unity")
+ gnode_unity.set_comment("Unity")
+ traverse_tree(introspection_tree[0], gnode_unity, graph)
+
+ graph.write(argv[1], format='png')
+
diff --git a/tools/unity.cmake b/tools/unity.cmake
index a1694ce81..579aee4b9 100755
--- a/tools/unity.cmake
+++ b/tools/unity.cmake
@@ -138,6 +138,10 @@ def process_and_start_unity (verbose, debug_mode, compiz_args, log_file):
if log_file:
cli.extend(['2>&1', '|', 'tee', log_file])
+ # kill a previous compiz if was there (this is a hack as compiz can
+ # sometimes get stuck and not exit on --replace)
+ subprocess.call (["pkill", "-9", "compiz"])
+
# shell = True as it's the simpest way to | tee.
# In this case, we need a string and not a list
# FIXME: still some bug with 2>&1 not showing everything before wait()