diff options
154 files changed, 7549 insertions, 3514 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a7ac1f28..9e24d383b 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 # @@ -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/UnityCore/CMakeLists.txt b/UnityCore/CMakeLists.txt index 91eb12b95..5e8b04f29 100644 --- a/UnityCore/CMakeLists.txt +++ b/UnityCore/CMakeLists.txt @@ -22,6 +22,7 @@ set (CORE_HEADERS GLibSignal-inl.h GLibWrapper.h GLibWrapper-inl.h + HomeLens.h IndicatorEntry.h Indicator.h Indicators.h @@ -55,6 +56,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/Menus.txt b/manual-tests/Menus.txt new file mode 100644 index 000000000..f039c5f40 --- /dev/null +++ b/manual-tests/Menus.txt @@ -0,0 +1,10 @@ +Menu Color +---------- +This test shows the color of the menus using the Ambiance theme: + +#. Start with a clean screen +#. Open an application window with menus +#. Go on the top panel and open a menu + +Outcome: + The menu should have a black background (i.e. #403f3a) 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/AbstractIconRenderer.h b/plugins/unityshell/src/AbstractIconRenderer.h index 5c98dbf99..8571ecec6 100644 --- a/plugins/unityshell/src/AbstractIconRenderer.h +++ b/plugins/unityshell/src/AbstractIconRenderer.h @@ -41,6 +41,7 @@ class RenderArg public: RenderArg() : icon(0) + , colorify(nux::color::White) , x_rotation(0) , y_rotation(0) , z_rotation(0) @@ -70,6 +71,7 @@ public: launcher::AbstractLauncherIcon* icon; nux::Point3 render_center; nux::Point3 logical_center; + nux::Color colorify; float x_rotation; float y_rotation; float z_rotation; @@ -103,6 +105,7 @@ public: virtual ~AbstractIconRenderer() {} nux::Property<PipRenderStyle> pip_style; + nux::Property<int> monitor; // RenderArgs not const in case processor needs to modify positions to do a perspective correct. virtual void PreprocessIcons(std::list<RenderArg>& args, nux::Geometry const& target_window) = 0; diff --git a/plugins/unityshell/src/AbstractLauncherIcon.h b/plugins/unityshell/src/AbstractLauncherIcon.h index 14afb45f3..c84f6cc7e 100644 --- a/plugins/unityshell/src/AbstractLauncherIcon.h +++ b/plugins/unityshell/src/AbstractLauncherIcon.h @@ -33,6 +33,7 @@ #include "DndData.h" #include "Introspectable.h" +#include "LauncherEntryRemote.h" namespace unity { @@ -53,19 +54,22 @@ public: : source(OTHER) , button(0) , target(0) + , monitor(-1) { } - ActionArg(Source source, int button, Window target = 0) + ActionArg(Source source, int button, Window target = 0, int monitor = -1) : source(source) , button(button) , target(target) + , monitor(monitor) { } Source source; int button; Window target; + int monitor; }; class AbstractLauncherIcon : public nux::InitiallyUnownedObject, public debug::Introspectable @@ -104,6 +108,7 @@ public: QUIRK_DROP_DIM, QUIRK_DESAT, QUIRK_PULSE_ONCE, + QUIRK_LAST_ACTION, QUIRK_LAST, } Quirk; @@ -129,13 +134,17 @@ public: virtual void SetSortPriority(int priority) = 0; - virtual bool OpenQuicklist(bool default_to_first_item = false) = 0; + virtual bool OpenQuicklist(bool default_to_first_item = false, int monitor = -1) = 0; - virtual void SetCenter(nux::Point3 center) = 0; + virtual void SetCenter(nux::Point3 center, int monitor, nux::Geometry parent_geo) = 0; - virtual nux::Point3 GetCenter() = 0; + virtual nux::Point3 GetCenter(int monitor) = 0; - virtual std::vector<nux::Vector4> & GetTransform(TransformIndex index) = 0; + virtual nux::Point3 GetSavedCenter(int monitor) = 0; + + virtual void SaveCenter() = 0; + + virtual std::vector<nux::Vector4> & GetTransform(TransformIndex index, int monitor) = 0; virtual void Activate(ActionArg arg) = 0; @@ -143,13 +152,13 @@ public: virtual int SortPriority() = 0; - virtual int RelatedWindows() = 0; + virtual std::vector<Window> Windows() = 0; - virtual std::vector<Window> RelatedXids () = 0; + virtual std::vector<Window> WindowsForMonitor(int monitor) = 0; virtual std::string NameForWindow (Window window) = 0; - virtual const bool HasWindowOnViewport() = 0; + virtual const bool WindowVisibleOnMonitor(int monitor) = 0; virtual bool IsSpacer() = 0; @@ -157,7 +166,7 @@ public: virtual float GetProgress() = 0; - virtual bool ShowInSwitcher() = 0; + virtual bool ShowInSwitcher(bool current) = 0; virtual unsigned long long SwitcherPriority() = 0; @@ -167,6 +176,8 @@ public: virtual struct timespec GetQuirkTime(Quirk quirk) = 0; + virtual void ResetQuirkTime(Quirk quirk) = 0; + virtual IconType Type() = 0; virtual nux::Color BackgroundColor() = 0; @@ -189,16 +200,26 @@ public: virtual void SendDndLeave() = 0; - sigc::signal<void, int> mouse_down; - sigc::signal<void, int> mouse_up; - sigc::signal<void, int> mouse_click; - sigc::signal<void> mouse_enter; - sigc::signal<void> mouse_leave; + virtual void InsertEntryRemote(LauncherEntryRemote* remote) = 0; + + virtual void RemoveEntryRemote(LauncherEntryRemote* remote) = 0; + + sigc::signal<void, int, int> mouse_down; + sigc::signal<void, int, int> mouse_up; + sigc::signal<void, int, int> mouse_click; + sigc::signal<void, int> mouse_enter; + sigc::signal<void, int> mouse_leave; sigc::signal<void, AbstractLauncherIcon*> show; sigc::signal<void, AbstractLauncherIcon*> hide; sigc::signal<void, AbstractLauncherIcon*> needs_redraw; + sigc::signal<void, AbstractLauncherIcon*> remove; + sigc::connection needs_redraw_connection; + sigc::connection on_icon_added_connection; + sigc::connection on_icon_removed_connection; + sigc::connection on_order_changed_connection; + sigc::connection on_expo_terminated_connection; }; } diff --git a/plugins/unityshell/src/BFBLauncherIcon.cpp b/plugins/unityshell/src/BFBLauncherIcon.cpp index 11e05de4a..c7d6f46ac 100644 --- a/plugins/unityshell/src/BFBLauncherIcon.cpp +++ b/plugins/unityshell/src/BFBLauncherIcon.cpp @@ -32,8 +32,8 @@ namespace launcher UBusManager BFBLauncherIcon::ubus_manager_; -BFBLauncherIcon::BFBLauncherIcon(Launcher* IconManager) - : SimpleLauncherIcon(IconManager) +BFBLauncherIcon::BFBLauncherIcon() + : SimpleLauncherIcon() { tooltip_text = _("Dash home"); icon_name = PKGDATADIR"/launcher_bfb.png"; @@ -43,7 +43,7 @@ BFBLauncherIcon::BFBLauncherIcon(Launcher* IconManager) background_color_ = nux::color::White; - mouse_enter.connect([&]() { ubus_manager_.SendMessage(UBUS_DASH_ABOUT_TO_SHOW, NULL); }); + mouse_enter.connect([&](int m) { ubus_manager_.SendMessage(UBUS_DASH_ABOUT_TO_SHOW, NULL); }); } nux::Color BFBLauncherIcon::BackgroundColor() diff --git a/plugins/unityshell/src/BFBLauncherIcon.h b/plugins/unityshell/src/BFBLauncherIcon.h index 115c416bc..441448e73 100644 --- a/plugins/unityshell/src/BFBLauncherIcon.h +++ b/plugins/unityshell/src/BFBLauncherIcon.h @@ -35,7 +35,7 @@ class BFBLauncherIcon : public SimpleLauncherIcon { public: - BFBLauncherIcon(Launcher* launcher); + BFBLauncherIcon(); virtual nux::Color BackgroundColor(); virtual nux::Color GlowColor(); diff --git a/plugins/unityshell/src/BamfLauncherIcon.cpp b/plugins/unityshell/src/BamfLauncherIcon.cpp index 7a3d76aea..10a330002 100644 --- a/plugins/unityshell/src/BamfLauncherIcon.cpp +++ b/plugins/unityshell/src/BamfLauncherIcon.cpp @@ -166,8 +166,8 @@ void BamfLauncherIcon::ActivateLauncherIcon(ActionArg arg) ubus_server_send_message(ubus_server_get_default(), UBUS_LAUNCHER_ACTION_DONE, NULL); } -BamfLauncherIcon::BamfLauncherIcon(Launcher* IconManager, BamfApplication* app) - : SimpleLauncherIcon(IconManager) +BamfLauncherIcon::BamfLauncherIcon(BamfApplication* app) + : SimpleLauncherIcon() , _supported_types_filled(false) , _fill_supported_types_id(0) { @@ -177,7 +177,6 @@ BamfLauncherIcon::BamfLauncherIcon(Launcher* IconManager, BamfApplication* app) _remote_uri = 0; _dnd_hover_timer = 0; _dnd_hovered = false; - _launcher = IconManager; _desktop_file_monitor = NULL; _menu_desktop_shortcuts = NULL; _on_desktop_file_changed_handler_id = 0; @@ -215,8 +214,6 @@ BamfLauncherIcon::BamfLauncherIcon(Launcher* IconManager, BamfApplication* app) WindowManager::Default()->window_moved.connect(sigc::mem_fun(this, &BamfLauncherIcon::OnWindowMoved)); 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 SetProgress(0.0f); @@ -285,7 +282,7 @@ BamfLauncherIcon::~BamfLauncherIcon() g_free(_cached_name); } -std::vector<Window> BamfLauncherIcon::RelatedXids () +std::vector<Window> BamfLauncherIcon::Windows () { std::vector<Window> results; GList* children, *l; @@ -301,9 +298,32 @@ std::vector<Window> BamfLauncherIcon::RelatedXids () guint32 xid = bamf_window_get_xid(BAMF_WINDOW(view)); if (wm->IsWindowMapped(xid)) - { - results.push_back (xid); - } + results.push_back ((Window) xid); + } + } + + g_list_free(children); + return results; +} + +std::vector<Window> BamfLauncherIcon::WindowsForMonitor (int monitor) +{ + std::vector<Window> results; + GList* children, *l; + BamfView* view; + WindowManager *wm = WindowManager::Default (); + + children = bamf_view_get_children(BAMF_VIEW(m_App)); + for (l = children; l; l = l->next) + { + view = static_cast <BamfView*> (l->data); + if (BAMF_IS_WINDOW(view) && bamf_window_get_monitor(BAMF_WINDOW(view)) == monitor) + { + guint32 xid = bamf_window_get_xid(BAMF_WINDOW(view)); + bool user_visible = bamf_view_user_visible(view); + + if (user_visible && wm->IsWindowMapped(xid) && wm->IsWindowOnCurrentDesktop(xid)) + results.push_back ((Window) xid); } } @@ -323,9 +343,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; } } @@ -334,11 +352,6 @@ std::string BamfLauncherIcon::NameForWindow (Window window) return result; } -void BamfLauncherIcon::OnLauncherHiddenChanged() -{ - UpdateIconGeometries(GetCenter()); -} - void BamfLauncherIcon::OnWindowMinimized(guint32 xid) { if (!OwnsWindow(xid)) @@ -596,18 +609,18 @@ void BamfLauncherIcon::Focus(ActionArg arg) if (any_visible) { WindowManager::Default()->FocusWindowGroup(windows, - WindowManager::FocusVisibility::ForceUnminimizeInvisible); + WindowManager::FocusVisibility::ForceUnminimizeInvisible, arg.monitor); } else { WindowManager::Default()->FocusWindowGroup(windows, - WindowManager::FocusVisibility::ForceUnminimizeOnCurrentDesktop); + WindowManager::FocusVisibility::ForceUnminimizeOnCurrentDesktop, arg.monitor); } } else { WindowManager::Default()->FocusWindowGroup(windows, - WindowManager::FocusVisibility::OnlyVisible); + WindowManager::FocusVisibility::OnlyVisible, arg.monitor); } } @@ -664,7 +677,7 @@ void BamfLauncherIcon::OnRunningChanged(BamfView* view, gboolean running, if (running) { self->EnsureWindowState(); - self->UpdateIconGeometries(self->GetCenter()); + self->UpdateIconGeometries(self->GetCenters()); } } @@ -683,9 +696,9 @@ void BamfLauncherIcon::OnUrgentChanged(BamfView* view, gboolean urgent, gpointer void BamfLauncherIcon::EnsureWindowState() { GList* children, *l; - bool has_win_on_current_vp = false; - unsigned int user_visible_count = 0; - unsigned int children_count = 0; + + std::vector<bool> monitors; + monitors.resize(max_num_monitors); children = bamf_view_get_children(BAMF_VIEW(m_App)); for (l = children; l; l = l->next) @@ -694,29 +707,13 @@ void BamfLauncherIcon::EnsureWindowState() continue; Window xid = bamf_window_get_xid(BAMF_WINDOW(l->data)); - if (WindowManager::Default()->IsWindowOnCurrentDesktop(xid)) - { - has_win_on_current_vp = true; - - if (bamf_view_user_visible (BAMF_VIEW (l->data))) - { - user_visible_count++; - } - } - - children_count++; - } - - if (user_visible_count > 0) - { - SetRelatedWindows(user_visible_count); - } - else if (children_count > 0) - { - SetRelatedWindows(1); + int monitor = bamf_window_get_monitor(BAMF_WINDOW(l->data)); + if (monitor >= 0 && WindowManager::Default()->IsWindowOnCurrentDesktop(xid)) + monitors[monitor] = true; } - SetHasWindowOnViewport(has_win_on_current_vp); + for (int i = 0; i < max_num_monitors; i++) + SetWindowVisibleOnMonitor(monitors[i], i); g_list_free(children); } @@ -726,13 +723,17 @@ void BamfLauncherIcon::OnChildAdded(BamfView* view, BamfView* child, gpointer da BamfLauncherIcon* self = static_cast <BamfLauncherIcon*> (data); self->EnsureWindowState(); self->UpdateMenus(); - self->UpdateIconGeometries(self->GetCenter()); + self->UpdateIconGeometries(self->GetCenters()); + + self->needs_redraw.emit(self); } void BamfLauncherIcon::OnChildRemoved(BamfView* view, BamfView* child, gpointer data) { BamfLauncherIcon* self = static_cast <BamfLauncherIcon*> (data); self->EnsureWindowState(); + + self->needs_redraw.emit(self); } void BamfLauncherIcon::UpdateDesktopQuickList() @@ -873,7 +874,7 @@ void BamfLauncherIcon::Quit() g_list_free(children); } -void BamfLauncherIcon::Stick() +void BamfLauncherIcon::Stick(bool save) { BamfView* view = BAMF_VIEW(m_App); @@ -883,7 +884,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); } @@ -1124,22 +1125,14 @@ std::list<DbusmenuMenuitem*> BamfLauncherIcon::GetMenus() } -void BamfLauncherIcon::UpdateIconGeometries(nux::Point3 center) +void BamfLauncherIcon::UpdateIconGeometries(std::vector<nux::Point3> center) { GList* children, *l; BamfView* view; nux::Geometry geo; - if (_launcher->Hidden() && !_launcher->ShowOnEdge()) - { - geo.x = 0; - geo.y = 0; - } - else - { - geo.x = center.x - 24; - geo.y = center.y - 24; - } + geo.x = center[0].x - 24; + geo.y = center[0].y - 24; geo.width = 48; geo.height = 48; @@ -1159,7 +1152,7 @@ void BamfLauncherIcon::UpdateIconGeometries(nux::Point3 center) g_list_free(children); } -void BamfLauncherIcon::OnCenterStabilized(nux::Point3 center) +void BamfLauncherIcon::OnCenterStabilized(std::vector<nux::Point3> center) { UpdateIconGeometries(center); } @@ -1262,9 +1255,30 @@ void BamfLauncherIcon::OnDesktopFileChanged(GFileMonitor* monitor, } bool -BamfLauncherIcon::ShowInSwitcher() +BamfLauncherIcon::ShowInSwitcher(bool current) { - return GetQuirk(QUIRK_RUNNING) && GetQuirk(QUIRK_VISIBLE); + bool result = false; + + if (GetQuirk(QUIRK_RUNNING) && GetQuirk(QUIRK_VISIBLE)) + { + if (current) + { + result = true; + } + else + { + for (int i = 0; i < max_num_monitors; i++) + { + if (WindowVisibleOnMonitor(i)) + { + result = true; + break; + } + } + } + } + + return result; } unsigned long long diff --git a/plugins/unityshell/src/BamfLauncherIcon.h b/plugins/unityshell/src/BamfLauncherIcon.h index 4dc0cc0eb..80409aa41 100644 --- a/plugins/unityshell/src/BamfLauncherIcon.h +++ b/plugins/unityshell/src/BamfLauncherIcon.h @@ -41,29 +41,30 @@ class Launcher; class BamfLauncherIcon : public SimpleLauncherIcon { public: - BamfLauncherIcon(Launcher* IconManager, BamfApplication* app); + BamfLauncherIcon(BamfApplication* app); virtual ~BamfLauncherIcon(); const char* DesktopFile(); bool IsSticky(); - void Quit(); - void Stick(); + void Stick(bool save = true); void UnStick(); + void Quit(); void ActivateLauncherIcon(ActionArg arg); - virtual bool ShowInSwitcher(); + virtual bool ShowInSwitcher(bool current); virtual unsigned long long SwitcherPriority(); - std::vector<Window> RelatedXids (); + std::vector<Window> Windows (); + std::vector<Window> WindowsForMonitor(int monitor); std::string NameForWindow (Window window); protected: std::list<DbusmenuMenuitem*> GetMenus(); - void UpdateIconGeometries(nux::Point3 center); - void OnCenterStabilized(nux::Point3 center); + void UpdateIconGeometries(std::vector<nux::Point3> center); + void OnCenterStabilized(std::vector<nux::Point3> center); void OnLauncherHiddenChanged(); @@ -86,7 +87,6 @@ protected: private: BamfApplication* m_App; - Launcher* _launcher; std::map<std::string, DbusmenuClient*> _menu_clients; std::map<std::string, DbusmenuMenuitem*> _menu_items; std::map<std::string, DbusmenuMenuitem*> _menu_items_extra; diff --git a/plugins/unityshell/src/DashController.cpp b/plugins/unityshell/src/DashController.cpp index d0e2cbac9..592b8f9be 100644 --- a/plugins/unityshell/src/DashController.cpp +++ b/plugins/unityshell/src/DashController.cpp @@ -151,7 +151,7 @@ void Controller::OnWindowConfigure(int window_width, int window_height, nux::Geometry Controller::GetIdealWindowGeometry() { UScreen *uscreen = UScreen::GetDefault(); - int primary_monitor = uscreen->GetPrimaryMonitor(); + int primary_monitor = uscreen->GetMonitorWithMouse(); auto monitor_geo = uscreen->GetMonitorGeometry(primary_monitor); // We want to cover as much of the screen as possible to grab any mouse events outside @@ -169,6 +169,7 @@ void Controller::Relayout(GdkScreen*screen) nux::Geometry geo = GetIdealWindowGeometry(); window_->SetGeometry(geo); view_->Relayout(); + view_->SetMonitorOffset(launcher_width, panel_height); } void Controller::OnMouseDownOutsideWindow(int x, int y, @@ -242,7 +243,7 @@ void Controller::ShowDash() StartShowHideTimeline(); - ubus_manager_.SendMessage(UBUS_PLACE_VIEW_SHOWN); + ubus_manager_.SendMessage(UBUS_PLACE_VIEW_SHOWN, g_variant_new_int32(UScreen::GetDefault()->GetMonitorWithMouse())); } void Controller::HideDash(bool restore) 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/DashSettings.cpp b/plugins/unityshell/src/DashSettings.cpp index 7833f79a5..e1a417853 100644 --- a/plugins/unityshell/src/DashSettings.cpp +++ b/plugins/unityshell/src/DashSettings.cpp @@ -80,7 +80,7 @@ void Settings::Impl::Refresh() if (raw_from_factor == 0) //Automatic { UScreen *uscreen = UScreen::GetDefault(); - int primary_monitor = uscreen->GetPrimaryMonitor(); + int primary_monitor = uscreen->GetMonitorWithMouse(); auto geo = uscreen->GetMonitorGeometry(primary_monitor); form_factor_ = geo.height > 799 ? FormFactor::DESKTOP : FormFactor::NETBOOK; diff --git a/plugins/unityshell/src/DashView.cpp b/plugins/unityshell/src/DashView.cpp index 36cf739d6..bde256eee 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"); } @@ -76,11 +79,34 @@ DashView::~DashView() g_source_remove (searching_timeout_id_); } +void DashView::SetMonitorOffset(int x, int y) +{ + renderer_.x_offset = x; + renderer_.y_offset = y; +} + 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 +114,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 +148,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(); @@ -239,7 +276,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_) @@ -336,7 +372,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); @@ -362,15 +397,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; @@ -553,6 +590,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..938950665 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" @@ -56,6 +56,7 @@ public: void Relayout(); void DisableBlur(); void OnActivateRequest(GVariant* args); + void SetMonitorOffset(int x, int y); std::string const GetIdForShortcutActivation(std::string const& shortcut) const; std::vector<char> GetAllShortcuts(); @@ -95,6 +96,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 +110,7 @@ private: private: UBusManager ubus_manager_; FilesystemLenses lenses_; + HomeLens::Ptr home_lens_; LensViews lens_views_; @@ -118,7 +121,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/Decaymulator.cpp b/plugins/unityshell/src/Decaymulator.cpp new file mode 100644 index 000000000..03fe54a09 --- /dev/null +++ b/plugins/unityshell/src/Decaymulator.cpp @@ -0,0 +1,58 @@ +// -*- 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: Jason Smith <jason.smith@canonical.com> + */ + +#include "Decaymulator.h" + +namespace unity { +namespace ui { + +Decaymulator::Decaymulator() +{ + on_decay_handle = 0; + value.changed.connect(sigc::mem_fun(this, &Decaymulator::OnValueChanged)); +} + +void Decaymulator::OnValueChanged(int value) +{ + if (!on_decay_handle && value > 0) + { + on_decay_handle = g_timeout_add(10, &Decaymulator::OnDecayTimeout, this); + } +} + +gboolean Decaymulator::OnDecayTimeout(gpointer data) +{ + Decaymulator* self = (Decaymulator*) data; + + int partial_decay = self->rate_of_decay / 100; + + if (self->value <= partial_decay) + { + self->value = 0; + self->on_decay_handle = 0; + return FALSE; + } + + + self->value = self->value - partial_decay; + return TRUE; +} + +} +} \ No newline at end of file diff --git a/plugins/unityshell/src/Decaymulator.h b/plugins/unityshell/src/Decaymulator.h new file mode 100644 index 000000000..a0f26aa13 --- /dev/null +++ b/plugins/unityshell/src/Decaymulator.h @@ -0,0 +1,51 @@ +// -*- 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: Jason Smith <jason.smith@canonical.com> + */ + +#ifndef UNITY_DECAYMULATOR_H +#define UNITY_DECAYMULATOR_H + +#include <Nux/Nux.h> +#include <glib.h> + +namespace unity +{ +namespace ui +{ + +class Decaymulator +{ +public: + typedef std::shared_ptr<Decaymulator> Ptr; + + nux::Property<int> rate_of_decay; + nux::Property<int> value; + + Decaymulator(); + +private: + void OnValueChanged(int value); + static gboolean OnDecayTimeout (gpointer value); + + guint on_decay_handle; +}; + +} +} + +#endif \ No newline at end of file diff --git a/plugins/unityshell/src/DesktopLauncherIcon.cpp b/plugins/unityshell/src/DesktopLauncherIcon.cpp index 0adc79de7..ae474aade 100644 --- a/plugins/unityshell/src/DesktopLauncherIcon.cpp +++ b/plugins/unityshell/src/DesktopLauncherIcon.cpp @@ -27,14 +27,14 @@ namespace unity namespace launcher { -DesktopLauncherIcon::DesktopLauncherIcon(Launcher* IconManager) - : SimpleLauncherIcon(IconManager) +DesktopLauncherIcon::DesktopLauncherIcon() + : SimpleLauncherIcon() , show_in_switcher_(true) { tooltip_text = _("Show Desktop"); icon_name = "desktop"; SetQuirk(QUIRK_VISIBLE, true); - SetQuirk(QUIRK_RUNNING, true); + SetQuirk(QUIRK_RUNNING, false); SetIconType(TYPE_BEGIN); } diff --git a/plugins/unityshell/src/DesktopLauncherIcon.h b/plugins/unityshell/src/DesktopLauncherIcon.h index 078228bde..05ad51f31 100644 --- a/plugins/unityshell/src/DesktopLauncherIcon.h +++ b/plugins/unityshell/src/DesktopLauncherIcon.h @@ -31,7 +31,7 @@ class DesktopLauncherIcon : public SimpleLauncherIcon { public: - DesktopLauncherIcon(Launcher* launcher); + DesktopLauncherIcon(); ~DesktopLauncherIcon(); virtual nux::Color BackgroundColor(); @@ -42,12 +42,7 @@ public: show_in_switcher_ = show_in_switcher; } - const bool HasWindowOnViewport() - { - return true; - } - - bool ShowInSwitcher() + bool ShowInSwitcher(bool current) { return show_in_switcher_; } diff --git a/plugins/unityshell/src/DeviceLauncherIcon.cpp b/plugins/unityshell/src/DeviceLauncherIcon.cpp index dac1c9f76..eca15f17a 100644 --- a/plugins/unityshell/src/DeviceLauncherIcon.cpp +++ b/plugins/unityshell/src/DeviceLauncherIcon.cpp @@ -43,8 +43,8 @@ GduDevice* get_device_for_device_file (const gchar *device_file); } -DeviceLauncherIcon::DeviceLauncherIcon(Launcher* launcher, GVolume* volume) - : SimpleLauncherIcon(launcher) +DeviceLauncherIcon::DeviceLauncherIcon(GVolume* volume) + : SimpleLauncherIcon() , volume_(volume) , device_file_(g_volume_get_identifier(volume_, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE)) , gdu_device_(get_device_for_device_file(device_file_)) diff --git a/plugins/unityshell/src/DeviceLauncherIcon.h b/plugins/unityshell/src/DeviceLauncherIcon.h index 28b8204a7..4c52b451b 100644 --- a/plugins/unityshell/src/DeviceLauncherIcon.h +++ b/plugins/unityshell/src/DeviceLauncherIcon.h @@ -36,7 +36,7 @@ class DeviceLauncherIcon : public SimpleLauncherIcon { public: - DeviceLauncherIcon(Launcher* launcher, GVolume* volume); + DeviceLauncherIcon(GVolume* volume); virtual nux::Color BackgroundColor(); virtual nux::Color GlowColor(); diff --git a/plugins/unityshell/src/DeviceLauncherSection.cpp b/plugins/unityshell/src/DeviceLauncherSection.cpp index cf9c79f09..6958f0a12 100644 --- a/plugins/unityshell/src/DeviceLauncherSection.cpp +++ b/plugins/unityshell/src/DeviceLauncherSection.cpp @@ -23,9 +23,8 @@ namespace unity namespace launcher { -DeviceLauncherSection::DeviceLauncherSection(Launcher* launcher) - : launcher_(launcher) - , monitor_(g_volume_monitor_get()) +DeviceLauncherSection::DeviceLauncherSection() + : monitor_(g_volume_monitor_get()) { on_volume_added_handler_id_ = g_signal_connect(monitor_, "volume-added", @@ -79,7 +78,7 @@ bool DeviceLauncherSection::PopulateEntries(DeviceLauncherSection* self) for (GList* v = volumes; v; v = v->next) { glib::Object<GVolume> volume((GVolume* )v->data); - DeviceLauncherIcon* icon = new DeviceLauncherIcon(self->launcher_, volume); + DeviceLauncherIcon* icon = new DeviceLauncherIcon(volume); self->map_[volume] = icon; self->IconAdded.emit(icon); @@ -100,7 +99,7 @@ void DeviceLauncherSection::OnVolumeAdded(GVolumeMonitor* monitor, GVolume* volume, DeviceLauncherSection* self) { - DeviceLauncherIcon* icon = new DeviceLauncherIcon(self->launcher_, volume); + DeviceLauncherIcon* icon = new DeviceLauncherIcon(volume); self->map_[volume] = icon; self->IconAdded.emit(icon); diff --git a/plugins/unityshell/src/DeviceLauncherSection.h b/plugins/unityshell/src/DeviceLauncherSection.h index e940eec89..6cc770d9f 100644 --- a/plugins/unityshell/src/DeviceLauncherSection.h +++ b/plugins/unityshell/src/DeviceLauncherSection.h @@ -39,7 +39,7 @@ namespace launcher class DeviceLauncherSection : public sigc::trackable { public: - DeviceLauncherSection(Launcher* launcher); + DeviceLauncherSection(); ~DeviceLauncherSection(); sigc::signal<void, LauncherIcon*> IconAdded; @@ -64,7 +64,6 @@ private: DeviceLauncherSection* self); private: - Launcher* launcher_; glib::Object<GVolumeMonitor> monitor_; std::map<GVolume*, DeviceLauncherIcon*> map_; gulong on_volume_added_handler_id_; 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..4b1e46c90 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. @@ -55,14 +63,14 @@ namespace ui */ // halfed lumin values to provide darkening while desaturating in shader -#define LUMIN_RED "0.15" -#define LUMIN_GREEN "0.295" -#define LUMIN_BLUE "0.055" +#define LUMIN_RED "0.30" +#define LUMIN_GREEN "0.59" +#define LUMIN_BLUE "0.11" 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,14 +83,15 @@ 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\ uniform vec4 color0; \n\ uniform vec4 desat_factor; \n\ +uniform vec4 colorify_color; \n\ vec4 SampleTexture(sampler2D TexObject, vec4 TexCoord) \n\ { \n\ return texture2D(TexObject, TexCoord.st); \n\ @@ -97,6 +106,7 @@ void main() \n\ vec4 texel = color0 * SampleTexture(TextureObject0, tex); \n\ vec4 desat = vec4 ("LUMIN_RED"*texel.r + "LUMIN_GREEN"*texel.g + "LUMIN_BLUE"*texel.b); \n\ vec4 final_color = (vec4 (1.0, 1.0, 1.0, 1.0) - desat_factor) * desat + desat_factor * texel; \n\ + final_color = colorify_color * final_color; \n\ final_color.a = texel.a; \n\ gl_FragColor = final_color; \n\ } \n\ @@ -361,7 +371,7 @@ void IconRenderer::UpdateIconSectionTransform(launcher::AbstractLauncherIcon* ic v3.y = -geo.height * (v3.y - 1.0f) / 2.0f - geo.height / 2.0f + yy + hh / 2.0f; - std::vector<nux::Vector4>& vectors = icon->GetTransform(index); + std::vector<nux::Vector4>& vectors = icon->GetTransform(index, monitor); vectors[0] = v0; vectors[1] = v1; @@ -384,6 +394,7 @@ void IconRenderer::RenderIcon(nux::GraphicsEngine& GfxContext, RenderArg const& nux::Color background_color = arg.icon->BackgroundColor(); nux::Color glow_color = arg.icon->GlowColor(); nux::Color edge_color(0x55555555); + nux::Color colorify = arg.colorify; float backlight_intensity = arg.backlight_intensity; float glow_intensity = arg.glow_intensity; @@ -391,11 +402,14 @@ void IconRenderer::RenderIcon(nux::GraphicsEngine& GfxContext, RenderArg const& nux::BaseTexture* glow = local::icon_glow[size]; nux::BaseTexture* shine = local::icon_shine[size]; + + if (arg.keyboard_nav_hl) { background_color = nux::color::White; glow_color = nux::color::White; edge_color = nux::color::White; + colorify = nux::color::White; backlight_intensity = 0.95; glow_intensity = 1.0f; @@ -412,7 +426,7 @@ void IconRenderer::RenderIcon(nux::GraphicsEngine& GfxContext, RenderArg const& shine = local::squircle_shine; } - auto tile_transform = arg.icon->GetTransform(launcher::AbstractLauncherIcon::TRANSFORM_TILE); + auto tile_transform = arg.icon->GetTransform(launcher::AbstractLauncherIcon::TRANSFORM_TILE, monitor); // draw tile if (backlight_intensity > 0 && !arg.draw_edge_only) @@ -421,6 +435,7 @@ void IconRenderer::RenderIcon(nux::GraphicsEngine& GfxContext, RenderArg const& arg, background->GetDeviceTexture(), background_color, + arg.colorify, backlight_intensity * arg.alpha, tile_transform); } @@ -433,6 +448,7 @@ void IconRenderer::RenderIcon(nux::GraphicsEngine& GfxContext, RenderArg const& arg, local::icon_edge[size]->GetDeviceTexture(), edge_color, + arg.colorify, arg.alpha, tile_transform); } @@ -443,14 +459,16 @@ void IconRenderer::RenderIcon(nux::GraphicsEngine& GfxContext, RenderArg const& arg, arg.icon->TextureForSize(image_size)->GetDeviceTexture(), nux::color::White, + arg.colorify, arg.alpha, - arg.icon->GetTransform(launcher::AbstractLauncherIcon::TRANSFORM_IMAGE)); + arg.icon->GetTransform(launcher::AbstractLauncherIcon::TRANSFORM_IMAGE, monitor)); // draw overlay shine RenderElement(GfxContext, arg, shine->GetDeviceTexture(), nux::color::White, + arg.colorify, arg.alpha, tile_transform); @@ -461,8 +479,9 @@ void IconRenderer::RenderIcon(nux::GraphicsEngine& GfxContext, RenderArg const& arg, glow->GetDeviceTexture(), glow_color, + nux::color::White, glow_intensity * arg.alpha, - arg.icon->GetTransform(launcher::AbstractLauncherIcon::TRANSFORM_GLOW)); + arg.icon->GetTransform(launcher::AbstractLauncherIcon::TRANSFORM_GLOW, monitor)); } // draw shimmer @@ -481,8 +500,9 @@ void IconRenderer::RenderIcon(nux::GraphicsEngine& GfxContext, RenderArg const& arg, local::icon_glow[size]->GetDeviceTexture(), arg.icon->GlowColor(), + nux::color::White, fade_out * arg.alpha, - arg.icon->GetTransform(launcher::AbstractLauncherIcon::TRANSFORM_GLOW)); + arg.icon->GetTransform(launcher::AbstractLauncherIcon::TRANSFORM_GLOW, monitor)); GfxContext.PopClippingRectangle(); } @@ -502,6 +522,7 @@ void IconRenderer::RenderIcon(nux::GraphicsEngine& GfxContext, RenderArg const& arg, local::offscreen_progress_texture, nux::color::White, + nux::color::White, arg.alpha, tile_transform); } @@ -512,8 +533,9 @@ void IconRenderer::RenderIcon(nux::GraphicsEngine& GfxContext, RenderArg const& arg, arg.icon->Emblem()->GetDeviceTexture(), nux::color::White, + nux::color::White, arg.alpha, - arg.icon->GetTransform(launcher::AbstractLauncherIcon::TRANSFORM_EMBLEM)); + arg.icon->GetTransform(launcher::AbstractLauncherIcon::TRANSFORM_EMBLEM, monitor)); } // draw indicators @@ -536,6 +558,7 @@ void IconRenderer::RenderIcon(nux::GraphicsEngine& GfxContext, RenderArg const& arg, local::label_map[shortcut]->GetDeviceTexture(), nux::Color(0xFFFFFFFF), + nux::color::White, arg.alpha, tile_transform); } @@ -603,6 +626,7 @@ void IconRenderer::RenderElement(nux::GraphicsEngine& GfxContext, RenderArg const& arg, nux::ObjectPtr<nux::IOpenGLBaseTexture> icon, nux::Color bkg_color, + nux::Color colorify, float alpha, std::vector<nux::Vector4>& xform_coords) { @@ -649,8 +673,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)); @@ -660,6 +689,7 @@ void IconRenderer::RenderElement(nux::GraphicsEngine& GfxContext, int VertexLocation; int TextureCoord0Location; int FragmentColor; + int ColorifyColor; int DesatFactor; if (nux::GetWindowThread()->GetGraphicsEngine().UsingGLSLCodePath()) @@ -670,6 +700,7 @@ void IconRenderer::RenderElement(nux::GraphicsEngine& GfxContext, VertexLocation = local::shader_program_uv_persp_correction->GetAttributeLocation("iVertex"); TextureCoord0Location = local::shader_program_uv_persp_correction->GetAttributeLocation("iTexCoord0"); FragmentColor = local::shader_program_uv_persp_correction->GetUniformLocationARB("color0"); + ColorifyColor = local::shader_program_uv_persp_correction->GetUniformLocationARB("colorify_color"); DesatFactor = local::shader_program_uv_persp_correction->GetUniformLocationARB("desat_factor"); if (TextureObjectLocation != -1) @@ -681,6 +712,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 +730,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)); @@ -712,12 +745,22 @@ void IconRenderer::RenderElement(nux::GraphicsEngine& GfxContext, if (nux::GetWindowThread()->GetGraphicsEngine().UsingGLSLCodePath()) { + colorify.red += (0.5f + 0.5f * arg.saturation) * (nux::color::White.red - colorify.red); + colorify.green += (0.5f + 0.5f * arg.saturation) * (nux::color::White.green - colorify.green); + colorify.blue += (0.5f + 0.5f * arg.saturation) * (nux::color::White.blue - colorify.blue); + CHECKGL(glUniform4fARB(FragmentColor, bg_color.red, bg_color.green, bg_color.blue, bg_color.alpha)); + CHECKGL(glUniform4fARB(ColorifyColor, colorify.red, colorify.green, colorify.blue, colorify.alpha)); 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 +769,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)); @@ -766,7 +810,7 @@ void IconRenderer::RenderIndicators(nux::GraphicsEngine& GfxContext, } else { - auto bounds = arg.icon->GetTransform(launcher::AbstractLauncherIcon::TRANSFORM_TILE); + auto bounds = arg.icon->GetTransform(launcher::AbstractLauncherIcon::TRANSFORM_TILE, monitor); markerX = bounds[0].x + 2; scale = 2; } diff --git a/plugins/unityshell/src/IconRenderer.h b/plugins/unityshell/src/IconRenderer.h index 51e91d360..cd147f6d6 100644 --- a/plugins/unityshell/src/IconRenderer.h +++ b/plugins/unityshell/src/IconRenderer.h @@ -53,6 +53,7 @@ protected: RenderArg const& arg, nux::ObjectPtr<nux::IOpenGLBaseTexture> icon, nux::Color bkg_color, + nux::Color colorify, float alpha, std::vector<nux::Vector4>& xform_coords); 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 d94045835..d7a5022fd 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 5a1db0c7e..40363c3b9 100644 --- a/plugins/unityshell/src/Launcher.cpp +++ b/plugins/unityshell/src/Launcher.cpp @@ -36,7 +36,7 @@ #include <Nux/WindowCompositor.h> #include "Launcher.h" -#include "LauncherIcon.h" +#include "AbstractLauncherIcon.h" #include "SpacerLauncherIcon.h" #include "LauncherModel.h" #include "QuicklistManager.h" @@ -44,6 +44,7 @@ #include "IconRenderer.h" #include "TimeUtil.h" #include "WindowManager.h" +#include "UScreen.h" #include "ubus-server.h" #include "UBusMessages.h" @@ -54,6 +55,8 @@ namespace unity { using ui::RenderArg; +using ui::PointerBarrierWrapper; +using ui::Decaymulator; namespace launcher { @@ -72,6 +75,7 @@ const int STARTING_BLINK_LAMBDA = 3; const int PULSE_BLINK_LAMBDA = 2; const float BACKLIGHT_STRENGTH = 0.9f; +const int panel_height = 24; } @@ -94,19 +98,6 @@ const float BACKLIGHT_STRENGTH = 0.9f; NUX_IMPLEMENT_OBJECT_TYPE(Launcher); -void SetTimeBack(struct timespec* timeref, int remove) -{ - timeref->tv_sec -= remove / 1000; - remove = remove % 1000; - - if (remove > timeref->tv_nsec / 1000000) - { - timeref->tv_sec--; - timeref->tv_nsec += 1000000000; - } - timeref->tv_nsec -= remove * 1000000; -} - const gchar Launcher::introspection_xml[] = "<node>" " <interface name='com.canonical.Unity.Launcher'>" @@ -134,8 +125,6 @@ GDBusInterfaceVTable Launcher::interface_vtable = Launcher::Launcher(nux::BaseWindow* parent, NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) - , m_ContentOffsetY(0) - , m_BackgroundLayer(0) , _model(0) , _collection_window(NULL) , _background_color(nux::color::DimGray) @@ -143,10 +132,13 @@ Launcher::Launcher(nux::BaseWindow* parent, { _parent = parent; - _active_quicklist = 0; + _active_quicklist = nullptr; + + monitor = 0; _hide_machine = new LauncherHideMachine(); _hide_machine->should_hide_changed.connect(sigc::mem_fun(this, &Launcher::SetHidden)); + _hover_machine = new LauncherHoverMachine(); _hover_machine->should_hover_changed.connect(sigc::mem_fun(this, &Launcher::SetHover)); @@ -161,8 +153,6 @@ Launcher::Launcher(nux::BaseWindow* parent, mouse_leave.connect(sigc::mem_fun(this, &Launcher::RecvMouseLeave)); mouse_move.connect(sigc::mem_fun(this, &Launcher::RecvMouseMove)); mouse_wheel.connect(sigc::mem_fun(this, &Launcher::RecvMouseWheel)); - key_down.connect(sigc::mem_fun(this, &Launcher::RecvKeyPressed)); - mouse_down_outside_pointer_grab_area.connect(sigc::mem_fun(this, &Launcher::RecvMouseDownOutsideArea)); //OnEndFocus.connect (sigc::mem_fun (this, &Launcher::exitKeyNavMode)); CaptureMouseDownAnyWhereElse(true); @@ -199,10 +189,6 @@ Launcher::Launcher(nux::BaseWindow* parent, display.changed.connect(sigc::mem_fun(this, &Launcher::OnDisplayChanged)); - _current_icon = NULL; - _current_icon_index = -1; - _last_icon_index = -1; - SetCompositionLayout(m_Layout); _folded_angle = 1.0f; @@ -231,23 +217,15 @@ Launcher::Launcher(nux::BaseWindow* parent, _dnd_delta_x = 0; _autoscroll_handle = 0; - _super_show_launcher_handle = 0; - _super_hide_launcher_handle = 0; - _super_show_shortcuts_handle = 0; _start_dragicon_handle = 0; - _focus_keynav_handle = 0; _dnd_check_handle = 0; - _ignore_repeat_shortcut_handle = 0; - _latest_shortcut = 0; _shortcuts_shown = false; _floating = false; _hovered = false; _hidden = false; _render_drag_window = false; _drag_edge_touching = false; - _keynav_activated = false; - _key_switcher_activated = false; _backlight_mode = BACKLIGHT_NORMAL; _last_button_press = 0; _selection_atom = 0; @@ -261,10 +239,6 @@ Launcher::Launcher(nux::BaseWindow* parent, _postreveal_mousemove_delta_x = 0; _postreveal_mousemove_delta_y = 0; - // set them to 1 instead of 0 to avoid :0 in case something is racy - _bfb_width = 1; - _bfb_height = 1; - _data_checked = false; _collection_window = new unity::DNDCollectionWindow(); _collection_window->SinkReference(); @@ -326,6 +300,12 @@ Launcher::Launcher(nux::BaseWindow* parent, launcher_sheen_->UnReference(); } + _pointer_barrier = PointerBarrierWrapper::Ptr(new PointerBarrierWrapper()); + _pointer_barrier->barrier_event.connect(sigc::mem_fun(this, &Launcher::OnPointerBarrierEvent)); + + decaymulator_ = Decaymulator::Ptr(new Decaymulator()); + + options.changed.connect (sigc::mem_fun (this, &Launcher::OnOptionsChanged)); } Launcher::~Launcher() @@ -336,18 +316,8 @@ Launcher::~Launcher() g_source_remove(_dnd_check_handle); if (_autoscroll_handle) g_source_remove(_autoscroll_handle); - if (_focus_keynav_handle) - g_source_remove(_focus_keynav_handle); - if (_super_show_launcher_handle) - g_source_remove(_super_show_launcher_handle); - if (_super_show_shortcuts_handle) - g_source_remove(_super_show_shortcuts_handle); if (_start_dragicon_handle) g_source_remove(_start_dragicon_handle); - if (_ignore_repeat_shortcut_handle) - g_source_remove(_ignore_repeat_shortcut_handle); - if (_super_hide_launcher_handle) - g_source_remove(_super_hide_launcher_handle); if (_launcher_animation_timeout > 0) g_source_remove(_launcher_animation_timeout); @@ -414,93 +384,20 @@ Launcher::OnDragFinish(GeisAdapter::GeisDragData* data) { if (_drag_out_delta_x >= DRAG_OUT_PIXELS - 90.0f) _hide_machine->SetQuirk(LauncherHideMachine::MT_DRAG_OUT, true); - SetTimeStruct(&_times[TIME_DRAG_OUT], &_times[TIME_DRAG_OUT], ANIM_DURATION_SHORT); + TimeUtil::SetTimeStruct(&_times[TIME_DRAG_OUT], &_times[TIME_DRAG_OUT], ANIM_DURATION_SHORT); _drag_out_id = 0; EnsureAnimation(); } } void -Launcher::startKeyNavMode() -{ - SetStateKeyNav(true); - _hide_machine->SetQuirk(LauncherHideMachine::LAST_ACTION_ACTIVATE, false); - - GrabKeyboard(); - - // FIXME: long term solution is to rewrite the keynav handle - if (_focus_keynav_handle > 0) - g_source_remove(_focus_keynav_handle); - _focus_keynav_handle = g_timeout_add(ANIM_DURATION_SHORT, &Launcher::MoveFocusToKeyNavModeTimeout, this); - -} - -gboolean -Launcher::MoveFocusToKeyNavModeTimeout(gpointer data) -{ - Launcher* self = (Launcher*) data; - - // move focus to key nav mode when activated - if (!(self->_keynav_activated)) - return false; - - if (self->_last_icon_index == -1) - { - self->_current_icon_index = 0; - } - else - self->_current_icon_index = self->_last_icon_index; - self->EnsureAnimation(); - - ubus_server_send_message(ubus_server_get_default(), - UBUS_LAUNCHER_START_KEY_NAV, - NULL); - - self->selection_change.emit(); - self->_focus_keynav_handle = 0; - - return false; -} - -void -Launcher::leaveKeyNavMode(bool preserve_focus) -{ - _last_icon_index = _current_icon_index; - _current_icon_index = -1; - QueueDraw(); - - ubus_server_send_message(ubus_server_get_default(), - UBUS_LAUNCHER_END_KEY_NAV, - g_variant_new_boolean(preserve_focus)); - - selection_change.emit(); -} - -void -Launcher::exitKeyNavMode() -{ - if (!_keynav_activated) - return; - - UnGrabKeyboard(); - UnGrabPointer(); - SetStateKeyNav(false); - - _current_icon_index = -1; - _last_icon_index = _current_icon_index; - QueueDraw(); - ubus_server_send_message(ubus_server_get_default(), - UBUS_LAUNCHER_END_KEY_NAV, - g_variant_new_boolean(true)); - selection_change.emit(); -} - -void Launcher::AddProperties(GVariantBuilder* builder) { timespec current; clock_gettime(CLOCK_MONOTONIC, ¤t); + nux::Geometry abs_geo = GetAbsoluteGeometry(); + unity::variant::BuilderWrapper(builder) .add("hover-progress", GetHoverProgress(current)) .add("dnd-exit-progress", DnDExitProgress(current)) @@ -510,6 +407,12 @@ Launcher::AddProperties(GVariantBuilder* builder) .add("hovered", _hovered) .add("hidemode", _hidemode) .add("hidden", _hidden) + .add("x", abs_geo.x) + .add("y", abs_geo.y) + .add("width", abs_geo.width) + .add("height", abs_geo.height) + .add("monitor", monitor()) + .add("quicklist-open", _hide_machine->GetQuirk(LauncherHideMachine::QUICKLIST_OPEN)) .add("hide-quirks", _hide_machine->DebugHideQuirks().c_str()) .add("hover-quirks", _hover_machine->DebugHoverQuirks().c_str()); } @@ -520,7 +423,7 @@ void Launcher::SetMousePosition(int x, int y) _mouse_position = nux::Point2(x, y); if (beyond_drag_threshold != MouseBeyondDragThreshold()) - SetTimeStruct(&_times[TIME_DRAG_THRESHOLD], &_times[TIME_DRAG_THRESHOLD], ANIM_DURATION_SHORT); + TimeUtil::SetTimeStruct(&_times[TIME_DRAG_THRESHOLD], &_times[TIME_DRAG_THRESHOLD], ANIM_DURATION_SHORT); EnsureScrollTimer(); } @@ -528,24 +431,11 @@ void Launcher::SetMousePosition(int x, int y) void Launcher::SetStateMouseOverLauncher(bool over_launcher) { _hide_machine->SetQuirk(LauncherHideMachine::MOUSE_OVER_LAUNCHER, over_launcher); + _hide_machine->SetQuirk(LauncherHideMachine::REVEAL_PRESSURE_PASS, false); _hover_machine->SetQuirk(LauncherHoverMachine::MOUSE_OVER_LAUNCHER, over_launcher); - - if (!over_launcher) - { - // reset state for some corner case like x=0, show dash (leave event not received) - _hide_machine->SetQuirk(LauncherHideMachine::MOUSE_OVER_ACTIVE_EDGE, false); - } -} - -void Launcher::SetStateKeyNav(bool keynav_activated) -{ - _hide_machine->SetQuirk(LauncherHideMachine::KEY_NAV_ACTIVE, keynav_activated); - _hover_machine->SetQuirk(LauncherHoverMachine::KEY_NAV_ACTIVE, keynav_activated); - - _keynav_activated = keynav_activated; } -bool Launcher::MouseBeyondDragThreshold() +bool Launcher::MouseBeyondDragThreshold() const { if (GetActionState() == ACTION_DRAG_ICON) return _mouse_position.x > GetGeometry().width + _icon_size / 2; @@ -553,7 +443,7 @@ bool Launcher::MouseBeyondDragThreshold() } /* Render Layout Logic */ -float Launcher::GetHoverProgress(struct timespec const& current) +float Launcher::GetHoverProgress(struct timespec const& current) const { if (_hovered) return CLAMP((float)(unity::TimeUtil::TimeDelta(¤t, &_times[TIME_ENTER])) / (float) ANIM_DURATION, 0.0f, 1.0f); @@ -561,12 +451,12 @@ float Launcher::GetHoverProgress(struct timespec const& current) return 1.0f - CLAMP((float)(unity::TimeUtil::TimeDelta(¤t, &_times[TIME_LEAVE])) / (float) ANIM_DURATION, 0.0f, 1.0f); } -float Launcher::DnDExitProgress(struct timespec const& current) +float Launcher::DnDExitProgress(struct timespec const& current) const { return pow(1.0f - CLAMP((float)(unity::TimeUtil::TimeDelta(¤t, &_times[TIME_DRAG_END])) / (float) ANIM_DURATION_LONG, 0.0f, 1.0f), 2); } -float Launcher::DragOutProgress(struct timespec const& current) +float Launcher::DragOutProgress(struct timespec const& current) const { float timeout = CLAMP((float)(unity::TimeUtil::TimeDelta(¤t, &_times[TIME_DRAG_OUT])) / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f); float progress = CLAMP(_drag_out_delta_x / DRAG_OUT_PIXELS, 0.0f, 1.0f); @@ -576,7 +466,7 @@ float Launcher::DragOutProgress(struct timespec const& current) return progress * (1.0f - timeout); } -float Launcher::AutohideProgress(struct timespec const& current) +float Launcher::AutohideProgress(struct timespec const& current) const { // time-based progress (full scale or finish the TRIGGER_AUTOHIDE_MIN -> 0.00f on bfb) float animation_progress; @@ -587,7 +477,7 @@ float Launcher::AutohideProgress(struct timespec const& current) return 1.0f - animation_progress; } -float Launcher::DragHideProgress(struct timespec const& current) +float Launcher::DragHideProgress(struct timespec const& current) const { if (_drag_edge_touching) return CLAMP((float)(unity::TimeUtil::TimeDelta(¤t, &_times[TIME_DRAG_EDGE_TOUCH])) / (float)(ANIM_DURATION * 3), 0.0f, 1.0f); @@ -595,7 +485,7 @@ float Launcher::DragHideProgress(struct timespec const& current) return 1.0f - CLAMP((float)(unity::TimeUtil::TimeDelta(¤t, &_times[TIME_DRAG_EDGE_TOUCH])) / (float)(ANIM_DURATION * 3), 0.0f, 1.0f); } -float Launcher::DragThresholdProgress(struct timespec const& current) +float Launcher::DragThresholdProgress(struct timespec const& current) const { if (MouseBeyondDragThreshold()) return 1.0f - CLAMP((float)(unity::TimeUtil::TimeDelta(¤t, &_times[TIME_DRAG_THRESHOLD])) / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f); @@ -616,60 +506,60 @@ void Launcher::EnsureAnimation() NeedRedraw(); } -bool Launcher::IconNeedsAnimation(LauncherIcon* icon, struct timespec const& current) +bool Launcher::IconNeedsAnimation(AbstractLauncherIcon* icon, struct timespec const& current) const { - struct timespec time = icon->GetQuirkTime(LauncherIcon::QUIRK_VISIBLE); + struct timespec time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_VISIBLE); if (unity::TimeUtil::TimeDelta(¤t, &time) < ANIM_DURATION_SHORT) return true; - time = icon->GetQuirkTime(LauncherIcon::QUIRK_RUNNING); + time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_RUNNING); if (unity::TimeUtil::TimeDelta(¤t, &time) < ANIM_DURATION_SHORT) return true; - time = icon->GetQuirkTime(LauncherIcon::QUIRK_STARTING); + time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_STARTING); if (unity::TimeUtil::TimeDelta(¤t, &time) < (ANIM_DURATION_LONG * MAX_STARTING_BLINKS * STARTING_BLINK_LAMBDA * 2)) return true; - time = icon->GetQuirkTime(LauncherIcon::QUIRK_URGENT); + time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_URGENT); if (unity::TimeUtil::TimeDelta(¤t, &time) < (ANIM_DURATION_LONG * URGENT_BLINKS * 2)) return true; - time = icon->GetQuirkTime(LauncherIcon::QUIRK_PULSE_ONCE); + time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_PULSE_ONCE); if (unity::TimeUtil::TimeDelta(¤t, &time) < (ANIM_DURATION_LONG * PULSE_BLINK_LAMBDA * 2)) return true; - time = icon->GetQuirkTime(LauncherIcon::QUIRK_PRESENTED); + time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_PRESENTED); if (unity::TimeUtil::TimeDelta(¤t, &time) < ANIM_DURATION) return true; - time = icon->GetQuirkTime(LauncherIcon::QUIRK_SHIMMER); + time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_SHIMMER); if (unity::TimeUtil::TimeDelta(¤t, &time) < ANIM_DURATION_LONG) return true; - time = icon->GetQuirkTime(LauncherIcon::QUIRK_CENTER_SAVED); + time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_CENTER_SAVED); if (unity::TimeUtil::TimeDelta(¤t, &time) < ANIM_DURATION) return true; - time = icon->GetQuirkTime(LauncherIcon::QUIRK_PROGRESS); + time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_PROGRESS); if (unity::TimeUtil::TimeDelta(¤t, &time) < ANIM_DURATION) return true; - time = icon->GetQuirkTime(LauncherIcon::QUIRK_DROP_DIM); + time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_DROP_DIM); if (unity::TimeUtil::TimeDelta(¤t, &time) < ANIM_DURATION) return true; - time = icon->GetQuirkTime(LauncherIcon::QUIRK_DESAT); + time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_DESAT); if (unity::TimeUtil::TimeDelta(¤t, &time) < ANIM_DURATION_SHORT_SHORT) return true; - time = icon->GetQuirkTime(LauncherIcon::QUIRK_DROP_PRELIGHT); + time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_DROP_PRELIGHT); if (unity::TimeUtil::TimeDelta(¤t, &time) < ANIM_DURATION) return true; return false; } -bool Launcher::AnimationInProgress() +bool Launcher::AnimationInProgress() const { // performance here can be improved by caching the longer remaining animation found and short circuiting to that each time // this way extra checks may be avoided @@ -715,27 +605,8 @@ bool Launcher::AnimationInProgress() return false; } -void Launcher::SetTimeStruct(struct timespec* timer, struct timespec* sister, int sister_relation) -{ - struct timespec current; - clock_gettime(CLOCK_MONOTONIC, ¤t); - - if (sister) - { - int diff = unity::TimeUtil::TimeDelta(¤t, sister); - - if (diff < sister_relation) - { - int remove = sister_relation - diff; - SetTimeBack(¤t, remove); - } - } - - timer->tv_sec = current.tv_sec; - timer->tv_nsec = current.tv_nsec; -} /* Min is when you are on the trigger */ -float Launcher::GetAutohidePositionMin() +float Launcher::GetAutohidePositionMin() const { if (_autohide_animation == SLIDE_ONLY || _autohide_animation == FADE_AND_SLIDE) return 0.35f; @@ -743,7 +614,7 @@ float Launcher::GetAutohidePositionMin() return 0.25f; } /* Max is the initial state over the bfb */ -float Launcher::GetAutohidePositionMax() +float Launcher::GetAutohidePositionMax() const { if (_autohide_animation == SLIDE_ONLY || _autohide_animation == FADE_AND_SLIDE) return 1.00f; @@ -752,17 +623,17 @@ float Launcher::GetAutohidePositionMax() } -float IconVisibleProgress(LauncherIcon* icon, struct timespec const& current) +float Launcher::IconVisibleProgress(AbstractLauncherIcon* icon, struct timespec const& current) const { - if (icon->GetQuirk(LauncherIcon::QUIRK_VISIBLE)) + if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_VISIBLE)) { - struct timespec icon_visible_time = icon->GetQuirkTime(LauncherIcon::QUIRK_VISIBLE); + struct timespec icon_visible_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_VISIBLE); int enter_ms = unity::TimeUtil::TimeDelta(¤t, &icon_visible_time); return CLAMP((float) enter_ms / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f); } else { - struct timespec icon_hide_time = icon->GetQuirkTime(LauncherIcon::QUIRK_VISIBLE); + struct timespec icon_hide_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_VISIBLE); int hide_ms = unity::TimeUtil::TimeDelta(¤t, &icon_hide_time); return 1.0f - CLAMP((float) hide_ms / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f); } @@ -770,7 +641,7 @@ float IconVisibleProgress(LauncherIcon* icon, struct timespec const& current) void Launcher::SetDndDelta(float x, float y, nux::Geometry const& geo, timespec const& current) { - LauncherIcon* anchor = 0; + AbstractLauncherIcon* anchor = nullptr; LauncherModel::iterator it; anchor = MouseIconIntersection(x, _enter_y); @@ -794,21 +665,21 @@ void Launcher::SetDndDelta(float x, float y, nux::Geometry const& geo, timespec } } -float Launcher::IconPresentProgress(LauncherIcon* icon, struct timespec const& current) +float Launcher::IconPresentProgress(AbstractLauncherIcon* icon, struct timespec const& current) const { - struct timespec icon_present_time = icon->GetQuirkTime(LauncherIcon::QUIRK_PRESENTED); + struct timespec icon_present_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_PRESENTED); int ms = unity::TimeUtil::TimeDelta(¤t, &icon_present_time); float result = CLAMP((float) ms / (float) ANIM_DURATION, 0.0f, 1.0f); - if (icon->GetQuirk(LauncherIcon::QUIRK_PRESENTED)) + if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_PRESENTED)) return result; else return 1.0f - result; } -float Launcher::IconUrgentProgress(LauncherIcon* icon, struct timespec const& current) +float Launcher::IconUrgentProgress(AbstractLauncherIcon* icon, struct timespec const& current) const { - struct timespec urgent_time = icon->GetQuirkTime(LauncherIcon::QUIRK_URGENT); + struct timespec urgent_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_URGENT); int urgent_ms = unity::TimeUtil::TimeDelta(¤t, &urgent_time); float result; @@ -817,118 +688,118 @@ float Launcher::IconUrgentProgress(LauncherIcon* icon, struct timespec const& cu else result = CLAMP((float) urgent_ms / (float)(ANIM_DURATION_LONG * URGENT_BLINKS * 2), 0.0f, 1.0f); - if (icon->GetQuirk(LauncherIcon::QUIRK_URGENT)) + if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_URGENT)) return result; else return 1.0f - result; } -float Launcher::IconDropDimValue(LauncherIcon* icon, struct timespec const& current) +float Launcher::IconDropDimValue(AbstractLauncherIcon* icon, struct timespec const& current) const { - struct timespec dim_time = icon->GetQuirkTime(LauncherIcon::QUIRK_DROP_DIM); + struct timespec dim_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_DROP_DIM); int dim_ms = unity::TimeUtil::TimeDelta(¤t, &dim_time); float result = CLAMP((float) dim_ms / (float) ANIM_DURATION, 0.0f, 1.0f); - if (icon->GetQuirk(LauncherIcon::QUIRK_DROP_DIM)) + if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_DROP_DIM)) return 1.0f - result; else return result; } -float Launcher::IconDesatValue(LauncherIcon* icon, struct timespec const& current) +float Launcher::IconDesatValue(AbstractLauncherIcon* icon, struct timespec const& current) const { - struct timespec dim_time = icon->GetQuirkTime(LauncherIcon::QUIRK_DESAT); + struct timespec dim_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_DESAT); int ms = unity::TimeUtil::TimeDelta(¤t, &dim_time); float result = CLAMP((float) ms / (float) ANIM_DURATION_SHORT_SHORT, 0.0f, 1.0f); - if (icon->GetQuirk(LauncherIcon::QUIRK_DESAT)) + if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_DESAT)) return 1.0f - result; else return result; } -float Launcher::IconShimmerProgress(LauncherIcon* icon, struct timespec const& current) +float Launcher::IconShimmerProgress(AbstractLauncherIcon* icon, struct timespec const& current) const { - struct timespec shimmer_time = icon->GetQuirkTime(LauncherIcon::QUIRK_SHIMMER); + struct timespec shimmer_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_SHIMMER); int shimmer_ms = unity::TimeUtil::TimeDelta(¤t, &shimmer_time); return CLAMP((float) shimmer_ms / (float) ANIM_DURATION_LONG, 0.0f, 1.0f); } -float Launcher::IconCenterTransitionProgress(LauncherIcon* icon, struct timespec const& current) +float Launcher::IconCenterTransitionProgress(AbstractLauncherIcon* icon, struct timespec const& current) const { - struct timespec save_time = icon->GetQuirkTime(LauncherIcon::QUIRK_CENTER_SAVED); + struct timespec save_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_CENTER_SAVED); int save_ms = unity::TimeUtil::TimeDelta(¤t, &save_time); return CLAMP((float) save_ms / (float) ANIM_DURATION, 0.0f, 1.0f); } -float Launcher::IconUrgentPulseValue(LauncherIcon* icon, struct timespec const& current) +float Launcher::IconUrgentPulseValue(AbstractLauncherIcon* icon, struct timespec const& current) const { - if (!icon->GetQuirk(LauncherIcon::QUIRK_URGENT)) + if (!icon->GetQuirk(AbstractLauncherIcon::QUIRK_URGENT)) return 1.0f; // we are full on in a normal condition double urgent_progress = (double) IconUrgentProgress(icon, current); return 0.5f + (float)(std::cos(M_PI * (float)(URGENT_BLINKS * 2) * urgent_progress)) * 0.5f; } -float Launcher::IconPulseOnceValue(LauncherIcon *icon, struct timespec const ¤t) +float Launcher::IconPulseOnceValue(AbstractLauncherIcon *icon, struct timespec const ¤t) const { - struct timespec pulse_time = icon->GetQuirkTime(LauncherIcon::QUIRK_PULSE_ONCE); + struct timespec pulse_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_PULSE_ONCE); int pulse_ms = unity::TimeUtil::TimeDelta(¤t, &pulse_time); double pulse_progress = (double) CLAMP((float) pulse_ms / (ANIM_DURATION_LONG * PULSE_BLINK_LAMBDA * 2), 0.0f, 1.0f); if (pulse_progress == 1.0f) - icon->SetQuirk(LauncherIcon::QUIRK_PULSE_ONCE, false); + icon->SetQuirk(AbstractLauncherIcon::QUIRK_PULSE_ONCE, false); return 0.5f + (float) (std::cos(M_PI * 2.0 * pulse_progress)) * 0.5f; } -float Launcher::IconUrgentWiggleValue(LauncherIcon* icon, struct timespec const& current) +float Launcher::IconUrgentWiggleValue(AbstractLauncherIcon* icon, struct timespec const& current) const { - if (!icon->GetQuirk(LauncherIcon::QUIRK_URGENT)) + if (!icon->GetQuirk(AbstractLauncherIcon::QUIRK_URGENT)) return 0.0f; // we are full on in a normal condition double urgent_progress = (double) IconUrgentProgress(icon, current); return 0.3f * (float)(std::sin(M_PI * (float)(WIGGLE_CYCLES * 2) * urgent_progress)) * 0.5f; } -float Launcher::IconStartingBlinkValue(LauncherIcon* icon, struct timespec const& current) +float Launcher::IconStartingBlinkValue(AbstractLauncherIcon* icon, struct timespec const& current) const { - struct timespec starting_time = icon->GetQuirkTime(LauncherIcon::QUIRK_STARTING); + struct timespec starting_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_STARTING); int starting_ms = unity::TimeUtil::TimeDelta(¤t, &starting_time); double starting_progress = (double) CLAMP((float) starting_ms / (float)(ANIM_DURATION_LONG * STARTING_BLINK_LAMBDA), 0.0f, 1.0f); double val = IsBackLightModeToggles() ? 3.0f : 4.0f; return 0.5f + (float)(std::cos(M_PI * val * starting_progress)) * 0.5f; } -float Launcher::IconStartingPulseValue(LauncherIcon* icon, struct timespec const& current) +float Launcher::IconStartingPulseValue(AbstractLauncherIcon* icon, struct timespec const& current) const { - struct timespec starting_time = icon->GetQuirkTime(LauncherIcon::QUIRK_STARTING); + struct timespec starting_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_STARTING); int starting_ms = unity::TimeUtil::TimeDelta(¤t, &starting_time); double starting_progress = (double) CLAMP((float) starting_ms / (float)(ANIM_DURATION_LONG * MAX_STARTING_BLINKS * STARTING_BLINK_LAMBDA * 2), 0.0f, 1.0f); - if (starting_progress == 1.0f && !icon->GetQuirk(LauncherIcon::QUIRK_RUNNING)) + if (starting_progress == 1.0f && !icon->GetQuirk(AbstractLauncherIcon::QUIRK_RUNNING)) { - icon->SetQuirk(LauncherIcon::QUIRK_STARTING, false); - icon->ResetQuirkTime(LauncherIcon::QUIRK_STARTING); + icon->SetQuirk(AbstractLauncherIcon::QUIRK_STARTING, false); + icon->ResetQuirkTime(AbstractLauncherIcon::QUIRK_STARTING); } return 0.5f + (float)(std::cos(M_PI * (float)(MAX_STARTING_BLINKS * 2) * starting_progress)) * 0.5f; } -float Launcher::IconBackgroundIntensity(LauncherIcon* icon, struct timespec const& current) +float Launcher::IconBackgroundIntensity(AbstractLauncherIcon* icon, struct timespec const& current) const { float result = 0.0f; - struct timespec running_time = icon->GetQuirkTime(LauncherIcon::QUIRK_RUNNING); + struct timespec running_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_RUNNING); int running_ms = unity::TimeUtil::TimeDelta(¤t, &running_time); float running_progress = CLAMP((float) running_ms / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f); - if (!icon->GetQuirk(LauncherIcon::QUIRK_RUNNING)) + if (!icon->GetQuirk(AbstractLauncherIcon::QUIRK_RUNNING)) running_progress = 1.0f - running_progress; // After we finish a fade in from running, we can reset the quirk - if (running_progress == 1.0f && icon->GetQuirk(LauncherIcon::QUIRK_RUNNING)) - icon->SetQuirk(LauncherIcon::QUIRK_STARTING, false); + if (running_progress == 1.0f && icon->GetQuirk(AbstractLauncherIcon::QUIRK_RUNNING)) + icon->SetQuirk(AbstractLauncherIcon::QUIRK_STARTING, false); float backlight_strength; if (_backlight_mode == BACKLIGHT_ALWAYS_ON) @@ -952,8 +823,8 @@ float Launcher::IconBackgroundIntensity(LauncherIcon* icon, struct timespec cons result = backlight_strength; // The blink concept is a failure in this case (it just doesn't work right) break; case LAUNCH_ANIMATION_PULSE: - if (running_progress == 1.0f && icon->GetQuirk(LauncherIcon::QUIRK_RUNNING)) - icon->ResetQuirkTime(LauncherIcon::QUIRK_STARTING); + if (running_progress == 1.0f && icon->GetQuirk(AbstractLauncherIcon::QUIRK_RUNNING)) + icon->ResetQuirkTime(AbstractLauncherIcon::QUIRK_STARTING); result = backlight_strength; if (_backlight_mode == BACKLIGHT_ALWAYS_ON) @@ -965,7 +836,7 @@ float Launcher::IconBackgroundIntensity(LauncherIcon* icon, struct timespec cons break; } - if (icon->GetQuirk(LauncherIcon::QUIRK_PULSE_ONCE)) + if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_PULSE_ONCE)) { if (_backlight_mode == BACKLIGHT_ALWAYS_ON) result *= CLAMP(running_progress + IconPulseOnceValue(icon, current), 0.0f, 1.0f); @@ -976,44 +847,45 @@ float Launcher::IconBackgroundIntensity(LauncherIcon* icon, struct timespec cons } // urgent serves to bring the total down only - if (icon->GetQuirk(LauncherIcon::QUIRK_URGENT) && _urgent_animation == URGENT_ANIMATION_PULSE) + if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_URGENT) && _urgent_animation == URGENT_ANIMATION_PULSE) result *= 0.2f + 0.8f * IconUrgentPulseValue(icon, current); return result; } -float Launcher::IconProgressBias(LauncherIcon* icon, struct timespec const& current) +float Launcher::IconProgressBias(AbstractLauncherIcon* icon, struct timespec const& current) const { - struct timespec icon_progress_time = icon->GetQuirkTime(LauncherIcon::QUIRK_PROGRESS); + struct timespec icon_progress_time = icon->GetQuirkTime(AbstractLauncherIcon::QUIRK_PROGRESS); int ms = unity::TimeUtil::TimeDelta(¤t, &icon_progress_time); float result = CLAMP((float) ms / (float) ANIM_DURATION, 0.0f, 1.0f); - if (icon->GetQuirk(LauncherIcon::QUIRK_PROGRESS)) + if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_PROGRESS)) return -1.0f + result; else return result; } -bool Launcher::IconDrawEdgeOnly(LauncherIcon* icon) +bool Launcher::IconDrawEdgeOnly(AbstractLauncherIcon* icon) const { if (_backlight_mode == BACKLIGHT_EDGE_TOGGLE) return true; - if (_backlight_mode == BACKLIGHT_NORMAL_EDGE_TOGGLE && !icon->HasWindowOnViewport()) + if (_backlight_mode == BACKLIGHT_NORMAL_EDGE_TOGGLE && !icon->WindowVisibleOnMonitor(monitor)) return true; return false; } -void Launcher::SetupRenderArg(LauncherIcon* icon, struct timespec const& current, RenderArg& arg) +void Launcher::SetupRenderArg(AbstractLauncherIcon* icon, struct timespec const& current, RenderArg& arg) { float desat_value = IconDesatValue(icon, current); arg.icon = icon; arg.alpha = 0.5f + 0.5f * desat_value; arg.saturation = desat_value; - arg.running_arrow = icon->GetQuirk(LauncherIcon::QUIRK_RUNNING); - arg.running_colored = icon->GetQuirk(LauncherIcon::QUIRK_URGENT); - arg.running_on_viewport = icon->HasWindowOnViewport(); + arg.colorify = nux::color::White; + arg.running_arrow = icon->GetQuirk(AbstractLauncherIcon::QUIRK_RUNNING); + arg.running_colored = icon->GetQuirk(AbstractLauncherIcon::QUIRK_URGENT); + arg.running_on_viewport = icon->WindowVisibleOnMonitor(monitor); arg.draw_edge_only = IconDrawEdgeOnly(icon); arg.active_colored = false; arg.x_rotation = 0.0f; @@ -1025,12 +897,12 @@ void Launcher::SetupRenderArg(LauncherIcon* icon, struct timespec const& current arg.progress_bias = IconProgressBias(icon, current); arg.progress = CLAMP(icon->GetProgress(), 0.0f, 1.0f); arg.draw_shortcut = _shortcuts_shown && !_hide_machine->GetQuirk(LauncherHideMachine::PLACES_VISIBLE); - arg.system_item = icon->Type() == LauncherIcon::TYPE_HOME; + arg.system_item = icon->Type() == AbstractLauncherIcon::TYPE_HOME; if (_dash_is_open) - arg.active_arrow = icon->Type() == LauncherIcon::TYPE_HOME; + arg.active_arrow = icon->Type() == AbstractLauncherIcon::TYPE_HOME; else - arg.active_arrow = icon->GetQuirk(LauncherIcon::QUIRK_ACTIVE); + arg.active_arrow = icon->GetQuirk(AbstractLauncherIcon::QUIRK_ACTIVE); guint64 shortcut = icon->GetShortcut(); if (shortcut > 32) @@ -1039,9 +911,9 @@ void Launcher::SetupRenderArg(LauncherIcon* icon, struct timespec const& current arg.shortcut_label = 0; // we dont need to show strays - if (!icon->GetQuirk(LauncherIcon::QUIRK_RUNNING)) + if (!icon->GetQuirk(AbstractLauncherIcon::QUIRK_RUNNING)) { - if (icon->GetQuirk(LauncherIcon::QUIRK_URGENT)) + if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_URGENT)) { arg.running_arrow = true; arg.window_indicators = 1; @@ -1051,7 +923,7 @@ void Launcher::SetupRenderArg(LauncherIcon* icon, struct timespec const& current } else { - arg.window_indicators = icon->RelatedWindows(); + arg.window_indicators = std::max<int> (icon->WindowsForMonitor(monitor).size(), 1); } arg.backlight_intensity = IconBackgroundIntensity(icon, current); @@ -1059,31 +931,28 @@ void Launcher::SetupRenderArg(LauncherIcon* icon, struct timespec const& current float urgent_progress = IconUrgentProgress(icon, current); - if (icon->GetQuirk(LauncherIcon::QUIRK_URGENT)) + if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_URGENT)) urgent_progress = CLAMP(urgent_progress * 3.0f, 0.0f, 1.0f); // we want to go 3x faster than the urgent normal cycle else urgent_progress = CLAMP(urgent_progress * 3.0f - 2.0f, 0.0f, 1.0f); // we want to go 3x faster than the urgent normal cycle arg.glow_intensity = urgent_progress; - if (icon->GetQuirk(LauncherIcon::QUIRK_URGENT) && _urgent_animation == URGENT_ANIMATION_WIGGLE) + if (icon->GetQuirk(AbstractLauncherIcon::QUIRK_URGENT) && _urgent_animation == URGENT_ANIMATION_WIGGLE) { arg.z_rotation = IconUrgentWiggleValue(icon, current); } - // we've to walk the list since it is a STL-list and not a STL-vector, thus - // we can't use the random-access operator [] :( - LauncherModel::iterator it; - int i; - for (it = _model->begin(), i = 0; it != _model->end(); it++, ++i) - if (i == _current_icon_index && *it == icon) - { + if (IsInKeyNavMode()) + { + if (icon == _model->Selection()) arg.keyboard_nav_hl = true; - } + } } -void Launcher::FillRenderArg(LauncherIcon* icon, +void Launcher::FillRenderArg(AbstractLauncherIcon* icon, RenderArg& arg, nux::Point3& center, + nux::Geometry const& parent_abs_geo, float folding_threshold, float folded_size, float folded_spacing, @@ -1133,7 +1002,7 @@ void Launcher::FillRenderArg(LauncherIcon* icon, float half_size = (folded_size / 2.0f) + (_icon_size / 2.0f - folded_size / 2.0f) * (1.0f - folding_progress); float icon_hide_offset = autohide_offset; - icon_hide_offset *= 1.0f - (present_progress * (_hide_machine->GetShowOnEdge() ? icon->PresentUrgency() : 0.0f)); + icon_hide_offset *= 1.0f - (present_progress * icon->PresentUrgency()); // icon is crossing threshold, start folding center.z += folded_z_distance * folding_progress; @@ -1146,7 +1015,7 @@ void Launcher::FillRenderArg(LauncherIcon* icon, float center_transit_progress = IconCenterTransitionProgress(icon, current); if (center_transit_progress <= 1.0f) { - centerOffset.y = (icon->_saved_center.y - (center.y + (half_size * size_modifier))) * (1.0f - center_transit_progress); + centerOffset.y = (icon->GetSavedCenter(monitor).y - (center.y + (half_size * size_modifier))) * (1.0f - center_transit_progress); } center.y += half_size * size_modifier; // move to center @@ -1154,7 +1023,7 @@ void Launcher::FillRenderArg(LauncherIcon* icon, arg.render_center = nux::Point3(roundf(center.x + icon_hide_offset), roundf(center.y + centerOffset.y), roundf(center.z)); arg.logical_center = nux::Point3(roundf(center.x + icon_hide_offset), roundf(center.y), roundf(center.z)); - icon->SetCenter(nux::Point3(roundf(center.x), roundf(center.y), roundf(center.z))); + icon->SetCenter(nux::Point3(roundf(center.x), roundf(center.y), roundf(center.z)), monitor, parent_abs_geo); // FIXME: this is a hack, we should have a look why SetAnimationTarget is necessary in SetAnimationTarget // we should ideally just need it at start to set the target @@ -1173,8 +1042,15 @@ float Launcher::DragLimiter(float x) return -result; } +nux::Color FullySaturateColor (nux::Color color) +{ + float max = std::max<float>(color.red, std::max<float>(color.green, color.blue)); + color = color * (1.0f / max); + return color; +} + void Launcher::RenderArgs(std::list<RenderArg> &launcher_args, - nux::Geometry& box_geo, float* launcher_alpha) + nux::Geometry& box_geo, float* launcher_alpha, nux::Geometry const& parent_abs_geo) { nux::Geometry geo = GetGeometry(); LauncherModel::iterator it; @@ -1182,6 +1058,8 @@ void Launcher::RenderArgs(std::list<RenderArg> &launcher_args, struct timespec current; clock_gettime(CLOCK_MONOTONIC, ¤t); + nux::Color colorify = FullySaturateColor(_background_color); + float hover_progress = GetHoverProgress(current); float folded_z_distance = _folded_z_distance * (1.0f - hover_progress); float animation_neg_rads = _neg_folded_angle * (1.0f - hover_progress); @@ -1223,7 +1101,9 @@ void Launcher::RenderArgs(std::list<RenderArg> &launcher_args, float autohide_progress = AutohideProgress(current) * (1.0f - DragOutProgress(current)); if (_autohide_animation == FADE_ONLY) + { *launcher_alpha = 1.0f - autohide_progress; + } else { if (autohide_progress > 0.0f) @@ -1311,11 +1191,11 @@ void Launcher::RenderArgs(std::list<RenderArg> &launcher_args, for (it = _model->main_begin(); it != _model->main_end(); it++) { RenderArg arg; - LauncherIcon* icon = *it; + AbstractLauncherIcon* icon = *it; - FillRenderArg(icon, arg, center, folding_threshold, folded_size, folded_spacing, + FillRenderArg(icon, arg, center, parent_abs_geo, folding_threshold, folded_size, folded_spacing, autohide_offset, folded_z_distance, animation_neg_rads, current); - + arg.colorify = colorify; launcher_args.push_back(arg); index++; } @@ -1339,9 +1219,9 @@ void Launcher::RenderArgs(std::list<RenderArg> &launcher_args, for (it = _model->shelf_begin(); it != _model->shelf_end(); it++) { RenderArg arg; - LauncherIcon* icon = *it; + AbstractLauncherIcon* icon = *it; - FillRenderArg(icon, arg, center, folding_threshold, folded_size, folded_spacing, + FillRenderArg(icon, arg, center, parent_abs_geo, folding_threshold, folded_size, folded_spacing, autohide_offset, folded_z_distance, animation_neg_rads, current); launcher_args.push_back(arg); @@ -1350,100 +1230,15 @@ void Launcher::RenderArgs(std::list<RenderArg> &launcher_args, /* End Render Layout Logic */ -gboolean Launcher::TapOnSuper() -{ - struct timespec current; - clock_gettime(CLOCK_MONOTONIC, ¤t); - - return (unity::TimeUtil::TimeDelta(¤t, &_times[TIME_TAP_SUPER]) < SUPER_TAP_DURATION); -} - -/* Launcher Show/Hide logic */ - -void Launcher::StartKeyShowLauncher() -{ - _hide_machine->SetQuirk(LauncherHideMachine::LAST_ACTION_ACTIVATE, false); - - SetTimeStruct(&_times[TIME_TAP_SUPER]); - SetTimeStruct(&_times[TIME_SUPER_PRESSED]); - - if (_super_show_launcher_handle > 0) - g_source_remove(_super_show_launcher_handle); - _super_show_launcher_handle = g_timeout_add(SUPER_TAP_DURATION, &Launcher::SuperShowLauncherTimeout, this); - - if (_super_show_shortcuts_handle > 0) - g_source_remove(_super_show_shortcuts_handle); - _super_show_shortcuts_handle = g_timeout_add(SHORTCUTS_SHOWN_DELAY, &Launcher::SuperShowShortcutsTimeout, this); - - ubus_server_send_message(ubus_server_get_default(), UBUS_DASH_ABOUT_TO_SHOW, NULL); - ubus_server_force_message_pump(ubus_server_get_default()); -} - -void Launcher::EndKeyShowLauncher() -{ - int remaining_time_before_hide; - struct timespec current; - clock_gettime(CLOCK_MONOTONIC, ¤t); - - _hover_machine->SetQuirk(LauncherHoverMachine::SHORTCUT_KEYS_VISIBLE, false); - _shortcuts_shown = false; - QueueDraw(); - - // remove further show launcher (which can happen when we close the dash with super) - if (_super_show_launcher_handle > 0) - g_source_remove(_super_show_launcher_handle); - if (_super_show_shortcuts_handle > 0) - g_source_remove(_super_show_shortcuts_handle); - _super_show_launcher_handle = 0; - _super_show_shortcuts_handle = 0; - - // it's a tap on super and we didn't use any shortcuts - if (TapOnSuper() && !_latest_shortcut) - ubus_server_send_message(ubus_server_get_default(), - UBUS_PLACE_ENTRY_ACTIVATE_REQUEST, - g_variant_new("(sus)", "home.lens", 0, "")); - - remaining_time_before_hide = BEFORE_HIDE_LAUNCHER_ON_SUPER_DURATION - CLAMP((int)(unity::TimeUtil::TimeDelta(¤t, &_times[TIME_SUPER_PRESSED])), 0, BEFORE_HIDE_LAUNCHER_ON_SUPER_DURATION); - - if (_super_hide_launcher_handle > 0) - g_source_remove(_super_hide_launcher_handle); - _super_hide_launcher_handle = g_timeout_add(remaining_time_before_hide, &Launcher::SuperHideLauncherTimeout, this); -} - -gboolean Launcher::SuperHideLauncherTimeout(gpointer data) +void Launcher::ForceReveal(bool force_reveal) { - Launcher* self = (Launcher*) data; - - self->_hide_machine->SetQuirk(LauncherHideMachine::TRIGGER_BUTTON_SHOW, false); - - self->_super_hide_launcher_handle = 0; - return false; + _hide_machine->SetQuirk(LauncherHideMachine::TRIGGER_BUTTON_SHOW, force_reveal); } -gboolean Launcher::SuperShowLauncherTimeout(gpointer data) +void Launcher::ShowShortcuts(bool show) { - Launcher* self = (Launcher*) data; - - self->_hide_machine->SetQuirk(LauncherHideMachine::TRIGGER_BUTTON_SHOW, true); - - self->_super_show_launcher_handle = 0; - return false; -} - -gboolean Launcher::SuperShowShortcutsTimeout(gpointer data) -{ - Launcher* self = (Launcher*) data; - - if (!self->_key_switcher_activated) - { - self->_shortcuts_shown = true; - self->_hover_machine->SetQuirk(LauncherHoverMachine::SHORTCUT_KEYS_VISIBLE, true); - - self->QueueDraw(); - } - - self->_super_show_shortcuts_handle = 0; - return false; + _shortcuts_shown = show; + _hover_machine->SetQuirk(LauncherHoverMachine::SHORTCUT_KEYS_VISIBLE, show); } void Launcher::OnBGColorChanged(GVariant *data) @@ -1460,15 +1255,13 @@ void Launcher::OnLockHideChanged(GVariant *data) gboolean enable_lock = FALSE; g_variant_get(data, "(b)", &enable_lock); - if (enable_lock) + if (enable_lock) { _hide_machine->SetQuirk(LauncherHideMachine::LOCK_HIDE, true); - _hide_machine->SetShowOnEdge(false); } else { _hide_machine->SetQuirk(LauncherHideMachine::LOCK_HIDE, false); - _hide_machine->SetShowOnEdge(true); } } @@ -1476,8 +1269,8 @@ void Launcher::DesaturateIcons() { for (auto icon : *_model) { - if (icon->Type () != LauncherIcon::TYPE_HOME) - icon->SetQuirk(LauncherIcon::QUIRK_DESAT, true); + if (icon->Type () != AbstractLauncherIcon::TYPE_HOME) + icon->SetQuirk(AbstractLauncherIcon::QUIRK_DESAT, true); icon->HideTooltip(); } } @@ -1486,12 +1279,15 @@ void Launcher::SaturateIcons() { for (auto icon : *_model) { - icon->SetQuirk(LauncherIcon::QUIRK_DESAT, false); + icon->SetQuirk(AbstractLauncherIcon::QUIRK_DESAT, false); } } void Launcher::OnPlaceViewShown(GVariant* data) { + if (g_variant_get_int32(data) != monitor) + return; + LauncherModel::iterator it; _dash_is_open = true; @@ -1504,6 +1300,9 @@ void Launcher::OnPlaceViewShown(GVariant* data) void Launcher::OnPlaceViewHidden(GVariant* data) { + if (!_dash_is_open) + return; + LauncherModel::iterator it; _dash_is_open = false; @@ -1535,12 +1334,10 @@ void Launcher::SetHidden(bool hidden) _hover_machine->SetQuirk(LauncherHoverMachine::LAUNCHER_HIDDEN, hidden); _hide_machine->SetQuirk(LauncherHideMachine::LAST_ACTION_ACTIVATE, false); - if (_hide_machine->GetQuirk(LauncherHideMachine::MOUSE_OVER_ACTIVE_EDGE)) - _hide_machine->SetQuirk(LauncherHideMachine::MOUSE_MOVE_POST_REVEAL, true); - else - _hide_machine->SetQuirk(LauncherHideMachine::MOUSE_MOVE_POST_REVEAL, false); - if (hidden) { + if (hidden) + { + _hide_machine->SetQuirk(LauncherHideMachine::MOUSE_MOVE_POST_REVEAL, false); _hide_machine->SetQuirk(LauncherHideMachine::MT_DRAG_OUT, false); SetStateMouseOverLauncher(false); } @@ -1548,7 +1345,7 @@ void Launcher::SetHidden(bool hidden) _postreveal_mousemove_delta_x = 0; _postreveal_mousemove_delta_y = 0; - SetTimeStruct(&_times[TIME_AUTOHIDE], &_times[TIME_AUTOHIDE], ANIM_DURATION_SHORT); + TimeUtil::SetTimeStruct(&_times[TIME_AUTOHIDE], &_times[TIME_AUTOHIDE], ANIM_DURATION_SHORT); _parent->EnableInputWindow(!hidden, "launcher", false, false); @@ -1561,13 +1358,13 @@ void Launcher::SetHidden(bool hidden) } int -Launcher::GetMouseX() +Launcher::GetMouseX() const { return _mouse_position.x; } int -Launcher::GetMouseY() +Launcher::GetMouseY() const { return _mouse_position.y; } @@ -1719,7 +1516,7 @@ Launcher::OnViewPortSwitchEnded() CheckWindowOverLauncher(); } -Launcher::LauncherHideMode Launcher::GetHideMode() +LauncherHideMode Launcher::GetHideMode() const { return _hidemode; } @@ -1738,6 +1535,40 @@ gboolean Launcher::StrutHack(gpointer data) return false; } +void +Launcher::OnOptionsChanged(Options::Ptr options) +{ + UpdateOptions(options); + + options->option_changed.connect(sigc::mem_fun(this, &Launcher::OnOptionChanged)); +} + +void +Launcher::OnOptionChanged() +{ + UpdateOptions(options()); +} + +void +Launcher::UpdateOptions(Options::Ptr options) +{ + SetHideMode(options->hide_mode); + SetAutoHideAnimation(options->auto_hide_animation); + SetFloating(options->floating); + SetBacklightMode(options->backlight_mode); + SetLaunchAnimation(options->launch_animation); + SetUrgentAnimation(options->urgent_animation); + SetIconSize(options->tile_size, options->icon_size); + decaymulator_->rate_of_decay = options->edge_decay_rate(); + + _pointer_barrier->threshold = options->edge_stop_velocity(); + _pointer_barrier->DestroyBarrier(); + _pointer_barrier->ConstructBarrier(); + + _hide_machine->reveal_pressure = options->edge_reveal_pressure(); + _hide_machine->edge_decay_rate = options->edge_decay_rate(); +} + void Launcher::SetHideMode(LauncherHideMode hidemode) { if (_hidemode == hidemode) @@ -1759,7 +1590,7 @@ void Launcher::SetHideMode(LauncherHideMode hidemode) EnsureAnimation(); } -Launcher::AutoHideAnimation Launcher::GetAutoHideAnimation() +AutoHideAnimation Launcher::GetAutoHideAnimation() const { return _autohide_animation; } @@ -1790,12 +1621,12 @@ void Launcher::SetBacklightMode(BacklightMode mode) EnsureAnimation(); } -Launcher::BacklightMode Launcher::GetBacklightMode() +BacklightMode Launcher::GetBacklightMode() const { return _backlight_mode; } -bool Launcher::IsBackLightModeToggles() +bool Launcher::IsBackLightModeToggles() const { switch (_backlight_mode) { case BACKLIGHT_NORMAL: @@ -1816,8 +1647,8 @@ Launcher::SetLaunchAnimation(LaunchAnimation animation) _launch_animation = animation; } -Launcher::LaunchAnimation -Launcher::GetLaunchAnimation() +LaunchAnimation +Launcher::GetLaunchAnimation() const { return _launch_animation; } @@ -1831,8 +1662,8 @@ Launcher::SetUrgentAnimation(UrgentAnimation animation) _urgent_animation = animation; } -Launcher::UrgentAnimation -Launcher::GetUrgentAnimation() +UrgentAnimation +Launcher::GetUrgentAnimation() const { return _urgent_animation; } @@ -1846,13 +1677,10 @@ Launcher::SetActionState(LauncherActionState actionstate) _launcher_action_state = actionstate; _hover_machine->SetQuirk(LauncherHoverMachine::LAUNCHER_IN_ACTION, (actionstate != ACTION_NONE)); - - if (_keynav_activated) - exitKeyNavMode(); } Launcher::LauncherActionState -Launcher::GetActionState() +Launcher::GetActionState() const { return _launcher_action_state; } @@ -1868,11 +1696,11 @@ void Launcher::SetHover(bool hovered) if (_hovered) { _enter_y = (int) _mouse_position.y; - SetTimeStruct(&_times[TIME_ENTER], &_times[TIME_LEAVE], ANIM_DURATION); + TimeUtil::SetTimeStruct(&_times[TIME_ENTER], &_times[TIME_LEAVE], ANIM_DURATION); } else { - SetTimeStruct(&_times[TIME_LEAVE], &_times[TIME_ENTER], ANIM_DURATION); + TimeUtil::SetTimeStruct(&_times[TIME_LEAVE], &_times[TIME_ENTER], ANIM_DURATION); } if (_dash_is_open && !_hide_machine->GetQuirk(LauncherHideMachine::EXTERNAL_DND_ACTIVE)) @@ -1888,7 +1716,7 @@ void Launcher::SetHover(bool hovered) bool Launcher::MouseOverTopScrollArea() { - return _mouse_position.y < 24; + return _mouse_position.y < panel_height; } bool Launcher::MouseOverTopScrollExtrema() @@ -1898,7 +1726,7 @@ bool Launcher::MouseOverTopScrollExtrema() bool Launcher::MouseOverBottomScrollArea() { - return _mouse_position.y > GetGeometry().height - 24; + return _mouse_position.y > GetGeometry().height - panel_height; } bool Launcher::MouseOverBottomScrollExtrema() @@ -1911,7 +1739,7 @@ gboolean Launcher::OnScrollTimeout(gpointer data) Launcher* self = (Launcher*) data; nux::Geometry geo = self->GetGeometry(); - if (self->_keynav_activated || self->_key_switcher_activated || !self->_hovered || + if (self->IsInKeyNavMode() || !self->_hovered || self->GetActionState() == ACTION_DRAG_LAUNCHER) return TRUE; @@ -1951,16 +1779,36 @@ void Launcher::EnsureScrollTimer() void Launcher::SetIconSize(int tile_size, int icon_size) { - nux::Geometry geo = _parent->GetGeometry(); - _icon_size = tile_size; _icon_image_size = icon_size; _icon_image_size_delta = tile_size - icon_size; _icon_glow_size = icon_size + 14; - _parent->SetGeometry(nux::Geometry(geo.x, geo.y, tile_size + 12, geo.height)); - icon_renderer->SetTargetSize(_icon_size, _icon_image_size, _space_between_icons); + + Resize(); +} + +void Launcher::Resize() +{ + UScreen* uscreen = UScreen::GetDefault(); + auto geo = uscreen->GetMonitorGeometry(monitor()); + + nux::Geometry new_geometry(geo.x, geo.y + panel_height, _icon_size + 12, geo.height - panel_height); + SetMaximumHeight(new_geometry.height); + _parent->SetGeometry(new_geometry); + SetGeometry(new_geometry); + + _pointer_barrier->DestroyBarrier(); + + _pointer_barrier->x1 = new_geometry.x; + _pointer_barrier->x2 = new_geometry.x; + _pointer_barrier->y1 = new_geometry.y; + _pointer_barrier->y2 = new_geometry.y + new_geometry.height; + _pointer_barrier->threshold = options()->edge_stop_velocity(); + + _pointer_barrier->ConstructBarrier(); + } void Launcher::SetBackgroundAlpha(float background_alpha) @@ -1972,29 +1820,26 @@ void Launcher::SetBackgroundAlpha(float background_alpha) NeedRedraw(); } -void Launcher::OnIconAdded(LauncherIcon* icon) +void Launcher::OnIconAdded(AbstractLauncherIcon* icon) { EnsureAnimation(); - // needs to be disconnected - icon->needs_redraw_connection = icon->needs_redraw.connect(sigc::mem_fun(this, &Launcher::OnIconNeedsRedraw)); + icon->needs_redraw.connect(sigc::mem_fun(this, &Launcher::OnIconNeedsRedraw)); AddChild(icon); } -void Launcher::OnIconRemoved(LauncherIcon* icon) +void Launcher::OnIconRemoved(AbstractLauncherIcon* icon) { if (icon->needs_redraw_connection.connected()) icon->needs_redraw_connection.disconnect(); - if (icon == _current_icon) - _current_icon = 0; if (icon == _icon_under_mouse) - _icon_under_mouse = 0; + _icon_under_mouse = nullptr; if (icon == _icon_mouse_down) - _icon_mouse_down = 0; + _icon_mouse_down = nullptr; if (icon == _drag_icon) - _drag_icon = 0; + _drag_icon = nullptr; EnsureAnimation(); RemoveChild(icon); @@ -2009,22 +1854,47 @@ void Launcher::SetModel(LauncherModel* model) { _model = model; - if (_model->on_icon_added_connection.connected()) - _model->on_icon_added_connection.disconnect(); - _model->on_icon_added_connection = _model->icon_added.connect(sigc::mem_fun(this, &Launcher::OnIconAdded)); + _model->icon_added.connect(sigc::mem_fun(this, &Launcher::OnIconAdded)); + _model->icon_removed.connect(sigc::mem_fun(this, &Launcher::OnIconRemoved)); + _model->order_changed.connect(sigc::mem_fun(this, &Launcher::OnOrderChanged)); + _model->selection_changed.connect(sigc::mem_fun(this, &Launcher::OnSelectionChanged)); +} + +LauncherModel* Launcher::GetModel() const +{ + return _model; +} + +void Launcher::EnsureIconOnScreen(AbstractLauncherIcon* selection) +{ + nux::Point3 center = selection->GetCenter(monitor); + nux::Geometry geo = GetGeometry(); + + int natural_y = 0; + for (auto icon : *_model) + { + if (!icon->GetQuirk(AbstractLauncherIcon::QUIRK_VISIBLE)) + continue; + + if (icon == selection) + break; - if (_model->on_icon_removed_connection.connected()) - _model->on_icon_removed_connection.disconnect(); - _model->on_icon_removed_connection = _model->icon_removed.connect(sigc::mem_fun(this, &Launcher::OnIconRemoved)); + natural_y += _icon_size + _space_between_icons; + } - if (_model->on_order_changed_connection.connected()) - _model->on_order_changed_connection.disconnect(); - _model->on_order_changed_connection = _model->order_changed.connect(sigc::mem_fun(this, &Launcher::OnOrderChanged)); + int max_drag_delta = geo.height - (natural_y + _icon_size + (2 * _space_between_icons)); + int min_drag_delta = -natural_y; + + _launcher_drag_delta = std::max<int>(min_drag_delta, std::min<int>(max_drag_delta, _launcher_drag_delta)); } -LauncherModel* Launcher::GetModel() +void Launcher::OnSelectionChanged(AbstractLauncherIcon* selection) { - return _model; + if (IsInKeyNavMode()) + { + EnsureIconOnScreen(selection); + EnsureAnimation(); + } } void Launcher::OnIconNeedsRedraw(AbstractLauncherIcon* icon) @@ -2037,11 +1907,10 @@ void Launcher::Draw(nux::GraphicsEngine& GfxContext, bool force_draw) } - - - void Launcher::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) { + icon_renderer->monitor = monitor(); + nux::Geometry base = GetGeometry(); nux::Geometry bkg_box; std::list<RenderArg> args; @@ -2057,7 +1926,8 @@ void Launcher::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) ROP.SrcBlend = GL_ONE; ROP.DstBlend = GL_ONE_MINUS_SRC_ALPHA; - RenderArgs(args, bkg_box, &launcher_alpha); + nux::Geometry geo_absolute = GetAbsoluteGeometry(); + RenderArgs(args, bkg_box, &launcher_alpha, geo_absolute); if (_drag_icon && _render_drag_window) { @@ -2084,8 +1954,6 @@ void Launcher::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) { if (BackgroundEffectHelper::blur_type != unity::BLUR_NONE && (bkg_box.x + bkg_box.width > 0)) { - nux::Geometry geo_absolute = GetAbsoluteGeometry(); - nux::Geometry blur_geo(geo_absolute.x, geo_absolute.y, base.width, base.height); auto blur_texture = bg_effect_helper_.GetBlurRegion(blur_geo); @@ -2126,8 +1994,8 @@ void Launcher::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) nux::TexCoordXForm texxform; texxform.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD); texxform.SetWrap(nux::TEXWRAP_CLAMP, nux::TEXWRAP_CLAMP); - texxform.uoffset = (1.0f / launcher_sheen_->GetWidth()) * (GetAbsoluteGeometry().x); // TODO (gord) don't use absolute values here - texxform.voffset = (1.0f / launcher_sheen_->GetHeight()) * (GetAbsoluteGeometry().y); + texxform.uoffset = (1.0f / launcher_sheen_->GetWidth()); // TODO (gord) don't use absolute values here + texxform.voffset = (1.0f / launcher_sheen_->GetHeight()) * panel_height; GfxContext.QRP_1Tex(base.x, base.y, base.width, base.height, launcher_sheen_->GetDeviceTexture(), texxform, @@ -2238,8 +2106,8 @@ gboolean Launcher::StartIconDragTimeout(gpointer data) { if (self->_icon_under_mouse) { - self->_icon_under_mouse->mouse_leave.emit(); - self->_icon_under_mouse = 0; + self->_icon_under_mouse->mouse_leave.emit(self->monitor); + self->_icon_under_mouse = nullptr; } self->_initial_drag_animation = true; self->StartIconDragRequest(self->GetMouseX(), self->GetMouseY()); @@ -2250,7 +2118,7 @@ gboolean Launcher::StartIconDragTimeout(gpointer data) void Launcher::StartIconDragRequest(int x, int y) { - LauncherIcon* drag_icon = MouseIconIntersection((int)(GetGeometry().x / 2.0f), y); + AbstractLauncherIcon* drag_icon = MouseIconIntersection((int)(GetGeometry().x / 2.0f), y); // FIXME: nux doesn't give nux::GetEventButton (button_flags) there, relying // on an internal Launcher property then @@ -2258,7 +2126,7 @@ void Launcher::StartIconDragRequest(int x, int y) { SetActionState(ACTION_DRAG_ICON); StartIconDrag(drag_icon); - UpdateDragWindowPosition(drag_icon->GetCenter().x, drag_icon->GetCenter().y); + UpdateDragWindowPosition(drag_icon->GetCenter(monitor).x, drag_icon->GetCenter(monitor).y); if (_initial_drag_animation) { _drag_window->SetAnimationTarget(x, y + _drag_window->GetGeometry().height / 2); @@ -2279,7 +2147,7 @@ void Launcher::StartIconDragRequest(int x, int y) } } -void Launcher::StartIconDrag(LauncherIcon* icon) +void Launcher::StartIconDrag(AbstractLauncherIcon* icon) { if (!icon) return; @@ -2308,11 +2176,11 @@ void Launcher::EndIconDrag() { if (_drag_window) { - LauncherIcon* hovered_icon = MouseIconIntersection(_mouse_position.x, _mouse_position.y); + AbstractLauncherIcon* hovered_icon = MouseIconIntersection(_mouse_position.x, _mouse_position.y); - if (hovered_icon && hovered_icon->Type() == LauncherIcon::TYPE_TRASH) + if (hovered_icon && hovered_icon->Type() == AbstractLauncherIcon::TYPE_TRASH) { - hovered_icon->SetQuirk(LauncherIcon::QUIRK_PULSE_ONCE, true); + hovered_icon->SetQuirk(AbstractLauncherIcon::QUIRK_PULSE_ONCE, true); launcher_removerequest.emit(_drag_icon); @@ -2323,7 +2191,7 @@ void Launcher::EndIconDrag() { _model->Save(); - _drag_window->SetAnimationTarget((int)(_drag_icon->GetCenter().x), (int)(_drag_icon->GetCenter().y)); + _drag_window->SetAnimationTarget((int)(_drag_icon->GetCenter(monitor).x), (int)(_drag_icon->GetCenter(monitor).y)); _drag_window->StartAnimation(); if (_drag_window->on_anim_completed.connected()) @@ -2333,7 +2201,7 @@ void Launcher::EndIconDrag() } if (MouseBeyondDragThreshold()) - SetTimeStruct(&_times[TIME_DRAG_THRESHOLD], &_times[TIME_DRAG_THRESHOLD], ANIM_DURATION_SHORT); + TimeUtil::SetTimeStruct(&_times[TIME_DRAG_THRESHOLD], &_times[TIME_DRAG_THRESHOLD], ANIM_DURATION_SHORT); _render_drag_window = false; @@ -2349,7 +2217,7 @@ void Launcher::UpdateDragWindowPosition(int x, int y) nux::Geometry geo = _drag_window->GetGeometry(); _drag_window->SetBaseXY(x - geo.width / 2 + _parent->GetGeometry().x, y - geo.height / 2 + _parent->GetGeometry().y); - LauncherIcon* hovered_icon = MouseIconIntersection((int)(GetGeometry().x / 2.0f), y); + AbstractLauncherIcon* hovered_icon = MouseIconIntersection((int)(GetGeometry().x / 2.0f), y); struct timespec current; clock_gettime(CLOCK_MONOTONIC, ¤t); @@ -2374,12 +2242,6 @@ void Launcher::RecvMouseDown(int x, int y, unsigned long button_flags, unsigned EnsureAnimation(); } -void Launcher::RecvMouseDownOutsideArea(int x, int y, unsigned long button_flags, unsigned long key_flags) -{ - if (_keynav_activated) - exitKeyNavMode(); -} - void Launcher::RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags) { SetMousePosition(x, y); @@ -2423,8 +2285,8 @@ void Launcher::RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_ if (_icon_under_mouse) { - _icon_under_mouse->mouse_leave.emit(); - _icon_under_mouse = 0; + _icon_under_mouse->mouse_leave.emit(monitor); + _icon_under_mouse = nullptr; } if (GetActionState() == ACTION_NONE) @@ -2460,10 +2322,6 @@ void Launcher::RecvMouseEnter(int x, int y, unsigned long button_flags, unsigned SetMousePosition(x, y); SetStateMouseOverLauncher(true); - // make sure we actually get a chance to get events before turning this off - if (x > 0) - _hide_machine->SetQuirk(LauncherHideMachine::MOUSE_OVER_ACTIVE_EDGE, false); - EventLogic(); EnsureAnimation(); } @@ -2472,7 +2330,7 @@ void Launcher::RecvMouseLeave(int x, int y, unsigned long button_flags, unsigned { SetMousePosition(x, y); SetStateMouseOverLauncher(false); - LauncherIcon::SetSkipTooltipDelay(false); + //AbstractLauncherIcon::SetSkipTooltipDelay(false); EventLogic(); EnsureAnimation(); @@ -2482,18 +2340,18 @@ void Launcher::RecvMouseMove(int x, int y, int dx, int dy, unsigned long button_ { SetMousePosition(x, y); - // make sure we actually get a chance to get events before turning this off - if (x > 0) - _hide_machine->SetQuirk(LauncherHideMachine::MOUSE_OVER_ACTIVE_EDGE, false); + if (!_hidden) + { + _postreveal_mousemove_delta_x += dx; + _postreveal_mousemove_delta_y += dy; - _postreveal_mousemove_delta_x += dx; - _postreveal_mousemove_delta_y += dy; + // check the state before changing it to avoid uneeded hide calls + if (!_hide_machine->GetQuirk(LauncherHideMachine::MOUSE_MOVE_POST_REVEAL) && + (nux::Abs(_postreveal_mousemove_delta_x) > MOUSE_DEADZONE || + nux::Abs(_postreveal_mousemove_delta_y) > MOUSE_DEADZONE)) + _hide_machine->SetQuirk(LauncherHideMachine::MOUSE_MOVE_POST_REVEAL, true); + } - // check the state before changing it to avoid uneeded hide calls - if (!_hide_machine->GetQuirk(LauncherHideMachine::MOUSE_MOVE_POST_REVEAL) && - (nux::Abs(_postreveal_mousemove_delta_x) > MOUSE_DEADZONE || - nux::Abs(_postreveal_mousemove_delta_y) > MOUSE_DEADZONE)) - _hide_machine->SetQuirk(LauncherHideMachine::MOUSE_MOVE_POST_REVEAL, true); // Every time the mouse moves, we check if it is inside an icon... @@ -2519,283 +2377,53 @@ void Launcher::RecvMouseWheel(int x, int y, int wheel_delta, unsigned long butto EnsureAnimation(); } - -gboolean -Launcher::ResetRepeatShorcutTimeout(gpointer data) +void Launcher::OnPointerBarrierEvent(ui::PointerBarrierWrapper* owner, ui::BarrierEvent::Ptr event) { - Launcher* self = (Launcher*) data; - - self->_latest_shortcut = 0; - - self->_ignore_repeat_shortcut_handle = 0; - return false; -} - -gboolean -Launcher::CheckSuperShortcutPressed(Display *x_display, - unsigned int key_sym, - unsigned long key_code, - unsigned long key_state, - char* key_string) -{ - LauncherModel::iterator it; - - // Shortcut to start launcher icons. Only relies on Keycode, ignore modifier - for (it = _model->begin(); it != _model->end(); it++) + nux::Geometry abs_geo = GetAbsoluteGeometry(); + if (_hidden && event->x >= abs_geo.x && event->x <= abs_geo.x + abs_geo.width) { - if ((XKeysymToKeycode(x_display, (*it)->GetShortcut()) == key_code) || - ((gchar)((*it)->GetShortcut()) == key_string[0])) - { - if (_latest_shortcut == (*it)->GetShortcut()) - return true; - - if (g_ascii_isdigit((gchar)(*it)->GetShortcut()) && (key_state & ShiftMask)) - (*it)->OpenInstance(ActionArg(ActionArg::LAUNCHER, 0)); - else - (*it)->Activate(ActionArg(ActionArg::LAUNCHER, 0)); - - SetLatestShortcut((*it)->GetShortcut()); - - // disable the "tap on super" check - _times[TIME_TAP_SUPER].tv_sec = 0; - _times[TIME_TAP_SUPER].tv_nsec = 0; - return true; - } + _hide_machine->AddRevealPressure(event->velocity); + decaymulator_->value = 0; } - - return false; -} - -void Launcher::SetLatestShortcut(guint64 shortcut) -{ - _latest_shortcut = shortcut; - /* - * start a timeout while repressing the same shortcut will be ignored. - * This is because the keypress repeat is handled by Xorg and we have no - * way to know if a press is an actual press or just an automated repetition - * because the button is hold down. (key release events are sent in both cases) - */ - if (_ignore_repeat_shortcut_handle > 0) - g_source_remove(_ignore_repeat_shortcut_handle); - _ignore_repeat_shortcut_handle = g_timeout_add(IGNORE_REPEAT_SHORTCUT_DURATION, &Launcher::ResetRepeatShorcutTimeout, this); -} - -void -Launcher::EdgeRevealTriggered(int mouse_x, int mouse_y) -{ - SetMousePosition(mouse_x, mouse_y - GetAbsoluteGeometry().y); - - _hide_machine->SetQuirk(LauncherHideMachine::MOUSE_OVER_ACTIVE_EDGE, true); - _hide_machine->SetQuirk(LauncherHideMachine::MOUSE_MOVE_POST_REVEAL, true); -} - -void Launcher::SelectPreviousIcon() -{ - if (_current_icon_index > 0) + else { - LauncherModel::iterator it; - int temp_current_icon_index = _current_icon_index; - do + decaymulator_->value = decaymulator_->value + event->velocity; + if (decaymulator_->value > options()->edge_overcome_pressure) { - temp_current_icon_index --; - it = _model->at(temp_current_icon_index); + _pointer_barrier->ReleaseBarrier(event->event_id); } - while (it != (LauncherModel::iterator)NULL && !(*it)->GetQuirk(LauncherIcon::QUIRK_VISIBLE)); - - if (it != (LauncherModel::iterator)NULL) - { - _current_icon_index = temp_current_icon_index; - - if ((*it)->GetCenter().y + - _icon_size/ 2 < GetGeometry().y) - _launcher_drag_delta += (_icon_size + _space_between_icons); - } - EnsureAnimation(); - selection_change.emit(); } } -void Launcher::SelectNextIcon() +bool Launcher::IsInKeyNavMode() const { - if (_current_icon_index < _model->Size() - 1) - { - LauncherModel::iterator it; - int temp_current_icon_index = _current_icon_index; - - do - { - temp_current_icon_index ++; - it = _model->at(temp_current_icon_index); - } - while (it != (LauncherModel::iterator)nullptr && - !(*it)->GetQuirk(LauncherIcon::QUIRK_VISIBLE)); - - if (it != (LauncherModel::iterator)nullptr) - { - _current_icon_index = temp_current_icon_index; - - if ((*it)->GetCenter().y + _icon_size / 2 > GetGeometry().height) - _launcher_drag_delta -= (_icon_size + _space_between_icons); - } - - EnsureAnimation(); - selection_change.emit(); - } + return _hide_machine->GetQuirk(LauncherHideMachine::KEY_NAV_ACTIVE); } -void Launcher::KeySwitcherActivate() +void Launcher::EnterKeyNavMode() { - if (_key_switcher_activated) - return; - _hide_machine->SetQuirk(LauncherHideMachine::KEY_NAV_ACTIVE, true); _hover_machine->SetQuirk(LauncherHoverMachine::KEY_NAV_ACTIVE, true); - - _key_switcher_activated = true; - - ubus_server_send_message(ubus_server_get_default(), - UBUS_LAUNCHER_START_KEY_SWTICHER, - g_variant_new_boolean(true)); - - KeySwitcherNext(); } -void Launcher::KeySwitcherTerminate() +void Launcher::ExitKeyNavMode() { - if (!_key_switcher_activated) - return; - - LauncherModel::iterator it = _model->at(_current_icon_index); - - if (it != (LauncherModel::iterator)NULL) - (*it)->Activate(ActionArg(ActionArg::LAUNCHER, 0)); - _hide_machine->SetQuirk(LauncherHideMachine::KEY_NAV_ACTIVE, false); _hover_machine->SetQuirk(LauncherHoverMachine::KEY_NAV_ACTIVE, false); - - ubus_server_send_message(ubus_server_get_default(), - UBUS_LAUNCHER_END_KEY_SWTICHER, - g_variant_new_boolean(true)); - - _key_switcher_activated = false; - _current_icon_index = -1; - _last_icon_index = -1; - QueueDraw(); - - selection_change.emit(); } -bool Launcher::KeySwitcherIsActive() -{ - return _key_switcher_activated; -} - -void Launcher::KeySwitcherNext() -{ - if (!_key_switcher_activated) - return; - - SelectNextIcon(); -} - -void Launcher::KeySwitcherPrevious() -{ - if (!_key_switcher_activated) - return; - - SelectPreviousIcon(); -} - -void -Launcher::RecvKeyPressed(unsigned long eventType, - unsigned long key_sym, - unsigned long key_state, - const char* character, - unsigned short keyCount) +void Launcher::RecvQuicklistOpened(QuicklistView* quicklist) { - - LauncherModel::iterator it; - - /* - * all key events below are related to keynavigation. Make an additional - * check that we are in a keynav mode when we inadvertadly receive the focus - */ - if (!_keynav_activated) - return; - - switch (key_sym) + UScreen* uscreen = UScreen::GetDefault(); + if (uscreen->GetMonitorGeometry(monitor).IsInside(nux::Point(quicklist->GetGeometry().x, quicklist->GetGeometry().y))) { - // up (move selection up or go to global-menu if at top-most icon) - case NUX_VK_UP: - case NUX_KP_UP: - SelectPreviousIcon(); - break; - - // down (move selection down and unfold launcher if needed) - case NUX_VK_DOWN: - case NUX_KP_DOWN: - SelectNextIcon(); - break; - - // esc/left (close quicklist or exit laucher key-focus) - case NUX_VK_LEFT: - case NUX_KP_LEFT: - case NUX_VK_ESCAPE: - // hide again - exitKeyNavMode(); - break; - - // right/shift-f10 (open quicklist of currently selected icon) - case XK_F10: - if (!(key_state & nux::NUX_STATE_SHIFT)) - break; - case NUX_VK_RIGHT: - case NUX_KP_RIGHT: - case XK_Menu: - // open quicklist of currently selected icon - it = _model->at(_current_icon_index); - if (it != (LauncherModel::iterator)NULL) - { - if ((*it)->OpenQuicklist(true)) - leaveKeyNavMode(false); - } - break; - - // <SPACE> (open a new instance) - case NUX_VK_SPACE: - // start currently selected icon - it = _model->at(_current_icon_index); - if (it != (LauncherModel::iterator)NULL) - { - (*it)->OpenInstance(ActionArg(ActionArg::LAUNCHER, 0)); - } - exitKeyNavMode(); - break; - - // <RETURN> (start/activate currently selected icon) - case NUX_VK_ENTER: - case NUX_KP_ENTER: - { - // start currently selected icon - it = _model->at(_current_icon_index); - if (it != (LauncherModel::iterator)NULL) - (*it)->Activate(ActionArg(ActionArg::LAUNCHER, 0)); - } - exitKeyNavMode(); - break; - - default: - break; + _hide_machine->SetQuirk(LauncherHideMachine::QUICKLIST_OPEN, true); + _hover_machine->SetQuirk(LauncherHoverMachine::QUICKLIST_OPEN, true); + EventLogic(); + EnsureAnimation(); } } -void Launcher::RecvQuicklistOpened(QuicklistView* quicklist) -{ - _hide_machine->SetQuirk(LauncherHideMachine::QUICKLIST_OPEN, true); - _hover_machine->SetQuirk(LauncherHoverMachine::QUICKLIST_OPEN, true); - EventLogic(); - EnsureAnimation(); -} - void Launcher::RecvQuicklistClosed(QuicklistView* quicklist) { nux::Point pt = nux::GetWindowCompositor().GetMousePosition(); @@ -2821,10 +2449,9 @@ void Launcher::EventLogic() GetActionState() == ACTION_DRAG_LAUNCHER) return; - LauncherIcon* launcher_icon = 0; + AbstractLauncherIcon* launcher_icon = nullptr; - if (_hide_machine->GetQuirk(LauncherHideMachine::MOUSE_OVER_LAUNCHER) - && _hide_machine->GetQuirk(LauncherHideMachine::MOUSE_MOVE_POST_REVEAL)) + if (!_hidden && !IsInKeyNavMode() && _hovered) { launcher_icon = MouseIconIntersection(_mouse_position.x, _mouse_position.y); } @@ -2832,13 +2459,13 @@ void Launcher::EventLogic() if (_icon_under_mouse && (_icon_under_mouse != launcher_icon)) { - _icon_under_mouse->mouse_leave.emit(); - _icon_under_mouse = 0; + _icon_under_mouse->mouse_leave.emit(monitor); + _icon_under_mouse = nullptr; } if (launcher_icon && (_icon_under_mouse != launcher_icon)) { - launcher_icon->mouse_enter.emit(); + launcher_icon->mouse_enter.emit(monitor); _icon_under_mouse = launcher_icon; _hide_machine->SetQuirk(LauncherHideMachine::LAST_ACTION_ACTIVATE, false); @@ -2847,7 +2474,7 @@ void Launcher::EventLogic() void Launcher::MouseDownLogic(int x, int y, unsigned long button_flags, unsigned long key_flags) { - LauncherIcon* launcher_icon = 0; + AbstractLauncherIcon* launcher_icon = nullptr; launcher_icon = MouseIconIntersection(_mouse_position.x, _mouse_position.y); _hide_machine->SetQuirk(LauncherHideMachine::LAST_ACTION_ACTIVATE, false); @@ -2860,19 +2487,13 @@ void Launcher::MouseDownLogic(int x, int y, unsigned long button_flags, unsigned g_source_remove(_start_dragicon_handle); _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(); - } + launcher_icon->mouse_down.emit(nux::GetEventButton(button_flags), monitor); } } void Launcher::MouseUpLogic(int x, int y, unsigned long button_flags, unsigned long key_flags) { - LauncherIcon* launcher_icon = 0; + AbstractLauncherIcon* launcher_icon = nullptr; launcher_icon = MouseIconIntersection(_mouse_position.x, _mouse_position.y); @@ -2882,28 +2503,28 @@ void Launcher::MouseUpLogic(int x, int y, unsigned long button_flags, unsigned l if (_icon_mouse_down && (_icon_mouse_down == launcher_icon)) { - _icon_mouse_down->mouse_up.emit(nux::GetEventButton(button_flags)); + _icon_mouse_down->mouse_up.emit(nux::GetEventButton(button_flags), monitor); if (GetActionState() == ACTION_NONE) { - _icon_mouse_down->mouse_click.emit(nux::GetEventButton(button_flags)); + _icon_mouse_down->mouse_click.emit(nux::GetEventButton(button_flags), monitor); } } if (launcher_icon && (_icon_mouse_down != launcher_icon)) { - launcher_icon->mouse_up.emit(nux::GetEventButton(button_flags)); + launcher_icon->mouse_up.emit(nux::GetEventButton(button_flags), monitor); } if (GetActionState() == ACTION_DRAG_LAUNCHER) { - SetTimeStruct(&_times[TIME_DRAG_END]); + TimeUtil::SetTimeStruct(&_times[TIME_DRAG_END]); } - _icon_mouse_down = 0; + _icon_mouse_down = nullptr; } -LauncherIcon* Launcher::MouseIconIntersection(int x, int y) +AbstractLauncherIcon* Launcher::MouseIconIntersection(int x, int y) { LauncherModel::iterator it; // We are looking for the icon at screen coordinates x, y; @@ -2912,13 +2533,13 @@ LauncherIcon* Launcher::MouseIconIntersection(int x, int y) for (it = _model->begin(); it != _model->end(); it++) { - if (!(*it)->GetQuirk(LauncherIcon::QUIRK_VISIBLE)) + if (!(*it)->GetQuirk(AbstractLauncherIcon::QUIRK_VISIBLE)) continue; nux::Point2 screen_coord [4]; for (int i = 0; i < 4; ++i) { - auto hit_transform = (*it)->GetTransform(AbstractLauncherIcon::TRANSFORM_HIT_AREA); + auto hit_transform = (*it)->GetTransform(AbstractLauncherIcon::TRANSFORM_HIT_AREA, monitor); screen_coord [i].x = hit_transform [i].x; screen_coord [i].y = hit_transform [i].y; } @@ -2931,7 +2552,7 @@ LauncherIcon* Launcher::MouseIconIntersection(int x, int y) } void -Launcher::RenderIconToTexture(nux::GraphicsEngine& GfxContext, LauncherIcon* icon, nux::ObjectPtr<nux::IOpenGLBaseTexture> texture) +Launcher::RenderIconToTexture(nux::GraphicsEngine& GfxContext, AbstractLauncherIcon* icon, nux::ObjectPtr<nux::IOpenGLBaseTexture> texture) { RenderArg arg; struct timespec current; @@ -2962,14 +2583,17 @@ Launcher::SetOffscreenRenderTarget(nux::ObjectPtr<nux::IOpenGLBaseTexture> textu int width = texture->GetWidth(); int height = texture->GetHeight(); - nux::GetGraphicsDisplay()->GetGpuDevice()->FormatFrameBufferObject(width, height, nux::BITFMT_R8G8B8A8); - nux::GetGraphicsDisplay()->GetGpuDevice()->SetColorRenderTargetSurface(0, texture->GetSurfaceLevel(0)); - nux::GetGraphicsDisplay()->GetGpuDevice()->ActivateFrameBuffer(); + auto graphics_display = nux::GetGraphicsDisplay(); + auto gpu_device = graphics_display->GetGpuDevice(); + gpu_device->FormatFrameBufferObject(width, height, nux::BITFMT_R8G8B8A8); + gpu_device->SetColorRenderTargetSurface(0, texture->GetSurfaceLevel(0)); + gpu_device->ActivateFrameBuffer(); - nux::GetGraphicsDisplay()->GetGraphicsEngine()->SetContext(0, 0, width, height); - nux::GetGraphicsDisplay()->GetGraphicsEngine()->SetViewport(0, 0, width, height); - nux::GetGraphicsDisplay()->GetGraphicsEngine()->Push2DWindow(width, height); - nux::GetGraphicsDisplay()->GetGraphicsEngine()->EmptyClippingRegion(); + auto graphics_engine = graphics_display->GetGraphicsEngine(); + graphics_engine->SetContext(0, 0, width, height); + graphics_engine->SetViewport(0, 0, width, height); + graphics_engine->Push2DWindow(width, height); + graphics_engine->EmptyClippingRegion(); } void @@ -3015,9 +2639,9 @@ void Launcher::OnDNDDataCollected(const std::list<char*>& mimes) for (auto it : *_model) { if (it->QueryAcceptDrop(_dnd_data) != nux::DNDACTION_NONE) - it->SetQuirk(LauncherIcon::QUIRK_DROP_PRELIGHT, true); + it->SetQuirk(AbstractLauncherIcon::QUIRK_DROP_PRELIGHT, true); else - it->SetQuirk(LauncherIcon::QUIRK_DROP_DIM, true); + it->SetQuirk(AbstractLauncherIcon::QUIRK_DROP_DIM, true); } } } @@ -3032,7 +2656,7 @@ Launcher::ProcessDndEnter() _steal_drag = false; _data_checked = false; _drag_edge_touching = false; - _dnd_hovered_icon = 0; + _dnd_hovered_icon = nullptr; } void @@ -3042,8 +2666,8 @@ Launcher::DndReset() for (auto it : *_model) { - it->SetQuirk(LauncherIcon::QUIRK_DROP_PRELIGHT, false); - it->SetQuirk(LauncherIcon::QUIRK_DROP_DIM, false); + it->SetQuirk(AbstractLauncherIcon::QUIRK_DROP_PRELIGHT, false); + it->SetQuirk(AbstractLauncherIcon::QUIRK_DROP_DIM, false); } DndHoveredIconReset(); @@ -3056,18 +2680,18 @@ void Launcher::DndHoveredIconReset() if (_steal_drag && _dnd_hovered_icon) { - _dnd_hovered_icon->SetQuirk(LauncherIcon::QUIRK_VISIBLE, false); + _dnd_hovered_icon->SetQuirk(AbstractLauncherIcon::QUIRK_VISIBLE, false); _dnd_hovered_icon->remove.emit(_dnd_hovered_icon); } if (!_steal_drag && _dnd_hovered_icon) { _dnd_hovered_icon->SendDndLeave(); - _dnd_hovered_icon = 0; + _dnd_hovered_icon = nullptr; } _steal_drag = false; - _dnd_hovered_icon = 0; + _dnd_hovered_icon = nullptr; } void @@ -3118,9 +2742,9 @@ Launcher::ProcessDndMove(int x, int y, std::list<char*> mimes) for (auto it : *_model) { if (it->QueryAcceptDrop(_dnd_data) != nux::DNDACTION_NONE) - it->SetQuirk(LauncherIcon::QUIRK_DROP_PRELIGHT, true); + it->SetQuirk(AbstractLauncherIcon::QUIRK_DROP_PRELIGHT, true); else - it->SetQuirk(LauncherIcon::QUIRK_DROP_DIM, true); + it->SetQuirk(AbstractLauncherIcon::QUIRK_DROP_DIM, true); } } } @@ -3133,26 +2757,26 @@ Launcher::ProcessDndMove(int x, int y, std::list<char*> mimes) _dnd_hovered_icon->SendDndLeave(); _drag_edge_touching = true; - SetTimeStruct(&_times[TIME_DRAG_EDGE_TOUCH], &_times[TIME_DRAG_EDGE_TOUCH], ANIM_DURATION * 3); + TimeUtil::SetTimeStruct(&_times[TIME_DRAG_EDGE_TOUCH], &_times[TIME_DRAG_EDGE_TOUCH], ANIM_DURATION * 3); EnsureAnimation(); } else if (_mouse_position.x != 0 && _drag_edge_touching) { _drag_edge_touching = false; - SetTimeStruct(&_times[TIME_DRAG_EDGE_TOUCH], &_times[TIME_DRAG_EDGE_TOUCH], ANIM_DURATION * 3); + TimeUtil::SetTimeStruct(&_times[TIME_DRAG_EDGE_TOUCH], &_times[TIME_DRAG_EDGE_TOUCH], ANIM_DURATION * 3); EnsureAnimation(); } EventLogic(); - LauncherIcon* hovered_icon = MouseIconIntersection(_mouse_position.x, _mouse_position.y); + AbstractLauncherIcon* hovered_icon = MouseIconIntersection(_mouse_position.x, _mouse_position.y); bool hovered_icon_is_appropriate = false; if (hovered_icon) { - if (hovered_icon->Type() == LauncherIcon::TYPE_TRASH) + if (hovered_icon->Type() == AbstractLauncherIcon::TYPE_TRASH) _steal_drag = false; - if (hovered_icon->Type() == LauncherIcon::TYPE_APPLICATION || hovered_icon->Type() == LauncherIcon::TYPE_EXPO) + if (hovered_icon->Type() == AbstractLauncherIcon::TYPE_APPLICATION || hovered_icon->Type() == AbstractLauncherIcon::TYPE_EXPO) hovered_icon_is_appropriate = true; } @@ -3161,7 +2785,7 @@ Launcher::ProcessDndMove(int x, int y, std::list<char*> mimes) _drag_action = nux::DNDACTION_COPY; if (!_dnd_hovered_icon && hovered_icon_is_appropriate) { - _dnd_hovered_icon = new SpacerLauncherIcon(this); + _dnd_hovered_icon = new SpacerLauncherIcon(); _dnd_hovered_icon->SetSortPriority(G_MAXINT); _model->AddIcon(_dnd_hovered_icon); _model->ReorderBefore(_dnd_hovered_icon, hovered_icon, true); @@ -3176,9 +2800,9 @@ Launcher::ProcessDndMove(int x, int y, std::list<char*> mimes) } else { - _dnd_hovered_icon->SetQuirk(LauncherIcon::QUIRK_VISIBLE, false); + _dnd_hovered_icon->SetQuirk(AbstractLauncherIcon::QUIRK_VISIBLE, false); _dnd_hovered_icon->remove.emit(_dnd_hovered_icon); - _dnd_hovered_icon = 0; + _dnd_hovered_icon = nullptr; } } } @@ -3222,7 +2846,7 @@ Launcher::ProcessDndDrop(int x, int y) { if (g_str_has_suffix(it.c_str(), ".desktop")) { - char* path = 0; + char* path = nullptr; if (g_str_has_prefix(it.c_str(), "application://")) { @@ -3261,20 +2885,12 @@ Launcher::ProcessDndDrop(int x, int y) * Returns the current selected icon if it is in keynavmode * It will return NULL if it is not on keynavmode */ -LauncherIcon* -Launcher::GetSelectedMenuIcon() +AbstractLauncherIcon* +Launcher::GetSelectedMenuIcon() const { - LauncherModel::iterator it; - - if (_current_icon_index == -1) - return NULL; - - it = _model->at(_current_icon_index); - - if (it != (LauncherModel::iterator)NULL) - return *it; - else + if (!IsInKeyNavMode()) return NULL; + return _model->Selection(); } /* dbus handlers */ diff --git a/plugins/unityshell/src/Launcher.h b/plugins/unityshell/src/Launcher.h index 961272702..28f716e49 100644 --- a/plugins/unityshell/src/Launcher.h +++ b/plugins/unityshell/src/Launcher.h @@ -28,12 +28,14 @@ #include <Nux/TimerProc.h> #include <NuxGraphics/IOpenGLAsmShader.h> +#include "PointerBarrier.h" #include "AbstractIconRenderer.h" #include "BackgroundEffectHelper.h" #include "DNDCollectionWindow.h" #include "DndData.h" #include "GeisAdapter.h" #include "Introspectable.h" +#include "LauncherOptions.h" #include "LauncherDragWindow.h" #include "LauncherHideMachine.h" #include "LauncherHoverMachine.h" @@ -44,128 +46,81 @@ #define ANIM_DURATION 200 #define ANIM_DURATION_LONG 350 -#define SUPER_TAP_DURATION 250 -#define SHORTCUTS_SHOWN_DELAY 750 -#define START_DRAGICON_DURATION 250 -#define BEFORE_HIDE_LAUNCHER_ON_SUPER_DURATION 1000 - -#define IGNORE_REPEAT_SHORTCUT_DURATION 250 - #define MAX_SUPERKEY_LABELS 10 +#define START_DRAGICON_DURATION 250 + class QuicklistView; namespace unity { namespace launcher { -class LauncherIcon; +class AbstractLauncherIcon; class LauncherModel; class Launcher : public unity::debug::Introspectable, public nux::View { NUX_DECLARE_OBJECT_TYPE(Launcher, nux::View); public: - typedef enum - { - LAUNCHER_HIDE_NEVER, - LAUNCHER_HIDE_AUTOHIDE, - LAUNCHER_HIDE_DODGE_WINDOWS, - LAUNCHER_HIDE_DODGE_ACTIVE_WINDOW, - } LauncherHideMode; - - typedef enum - { - LAUNCH_ANIMATION_NONE, - LAUNCH_ANIMATION_PULSE, - LAUNCH_ANIMATION_BLINK, - } LaunchAnimation; - - typedef enum - { - URGENT_ANIMATION_NONE, - URGENT_ANIMATION_PULSE, - URGENT_ANIMATION_WIGGLE, - } UrgentAnimation; - - typedef enum - { - FADE_OR_SLIDE, - SLIDE_ONLY, - FADE_ONLY, - FADE_AND_SLIDE, - } AutoHideAnimation; - - typedef enum - { - BACKLIGHT_ALWAYS_ON, - BACKLIGHT_NORMAL, - BACKLIGHT_ALWAYS_OFF, - BACKLIGHT_EDGE_TOGGLE, - BACKLIGHT_NORMAL_EDGE_TOGGLE - } BacklightMode; Launcher(nux::BaseWindow* parent, NUX_FILE_LINE_PROTO); ~Launcher(); nux::Property<Display*> display; + nux::Property<int> monitor; + nux::Property<Options::Ptr> options; virtual void Draw(nux::GraphicsEngine& GfxContext, bool force_draw); virtual void DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw); virtual void PostDraw(nux::GraphicsEngine& GfxContext, bool force_draw); - LauncherIcon* GetSelectedMenuIcon(); + AbstractLauncherIcon* GetSelectedMenuIcon() const; void SetIconSize(int tile_size, int icon_size); void SetBackgroundAlpha(float background_alpha); LauncherHideMachine* HideMachine() { return _hide_machine; } - bool Hidden() + bool Hidden() const { return _hidden; } - bool ShowOnEdge() - { - return _hide_machine->GetShowOnEdge(); - } + + void ForceReveal(bool force); + void ShowShortcuts(bool show); void SetModel(LauncherModel* model); - LauncherModel* GetModel(); + LauncherModel* GetModel() const; void SetFloating(bool floating); void SetHideMode(LauncherHideMode hidemode); - LauncherHideMode GetHideMode(); + LauncherHideMode GetHideMode() const; void StartKeyShowLauncher(); void EndKeyShowLauncher(); + void EnsureIconOnScreen(AbstractLauncherIcon* icon); + void SetBacklightMode(BacklightMode mode); - BacklightMode GetBacklightMode(); - bool IsBackLightModeToggles(); + BacklightMode GetBacklightMode() const; + bool IsBackLightModeToggles() const; void SetLaunchAnimation(LaunchAnimation animation); - LaunchAnimation GetLaunchAnimation(); + LaunchAnimation GetLaunchAnimation() const; void SetUrgentAnimation(UrgentAnimation animation); - UrgentAnimation GetUrgentAnimation(); + UrgentAnimation GetUrgentAnimation() const; void SetAutoHideAnimation(AutoHideAnimation animation); - AutoHideAnimation GetAutoHideAnimation(); + AutoHideAnimation GetAutoHideAnimation() const; - void EdgeRevealTriggered(int x, int y); - - gboolean CheckSuperShortcutPressed(Display *x_display, unsigned int key_sym, unsigned long key_code, unsigned long key_state, char* key_string); - void SetLatestShortcut(guint64 shortcut); - - nux::BaseWindow* GetParent() + nux::BaseWindow* GetParent() const { return _parent; }; - static void SetTimeStruct(struct timespec* timer, struct timespec* sister = 0, int sister_relation = 0); - virtual void RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); virtual void RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); virtual void RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); @@ -173,47 +128,31 @@ public: virtual void RecvMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags); virtual void RecvMouseMove(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); virtual void RecvMouseWheel(int x, int y, int wheel_delta, unsigned long button_flags, unsigned long key_flags); - virtual void RecvMouseDownOutsideArea(int x, int y, unsigned long button_flags, unsigned long key_flags); - - virtual void RecvKeyPressed(unsigned long eventType , /*event type*/ - unsigned long keysym , /*event keysym*/ - unsigned long state , /*event state*/ - const char* character , /*character*/ - unsigned short keyCount /*key repeat count*/); virtual void RecvQuicklistOpened(QuicklistView* quicklist); virtual void RecvQuicklistClosed(QuicklistView* quicklist); - void startKeyNavMode(); - void leaveKeyNavMode(bool preserve_focus = true); + int GetMouseX() const; + int GetMouseY() const; - void exitKeyNavMode(); // Connected to signal OnEndFocus - - int GetMouseX(); - int GetMouseY(); + void Resize(); void CheckWindowOverLauncher(); 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, char*, AbstractLauncherIcon*> launcher_addrequest; + sigc::signal<void, char*, AbstractLauncherIcon*, char*, char*> launcher_addrequest_special; + sigc::signal<void, AbstractLauncherIcon*> launcher_removerequest; sigc::signal<void> selection_change; sigc::signal<void> hidden_changed; - // Key navigation virtual bool InspectKeyEvent(unsigned int eventType, unsigned int keysym, const char* character); - void SelectPreviousIcon(); - void SelectNextIcon(); - - void KeySwitcherActivate(); - void KeySwitcherTerminate(); - bool KeySwitcherIsActive(); - void KeySwitcherNext(); - void KeySwitcherPrevious(); + void EnterKeyNavMode(); + void ExitKeyNavMode(); + bool IsInKeyNavMode() const; protected: // Introspectable methods @@ -250,6 +189,10 @@ private: TIME_LAST } LauncherActionTimes; + void OnOptionsChanged(Options::Ptr options); + void OnOptionChanged(); + void UpdateOptions(Options::Ptr options); + void OnWindowMaybeIntellihide(guint32 xid); void OnWindowMaybeIntellihideDelayed(guint32 xid); static gboolean CheckWindowOverLauncherSync(Launcher* self); @@ -260,35 +203,33 @@ private: void OnDragUpdate(GeisAdapter::GeisDragData* data); void OnDragFinish(GeisAdapter::GeisDragData* data); + void OnPointerBarrierEvent(ui::PointerBarrierWrapper* owner, ui::BarrierEvent::Ptr event); + void OnPluginStateChanged(); + void OnSelectionChanged(AbstractLauncherIcon* selection); + void OnViewPortSwitchStarted(); void OnViewPortSwitchEnded(); static gboolean AnimationTimeout(gpointer data); - static gboolean SuperShowLauncherTimeout(gpointer data); - static gboolean SuperHideLauncherTimeout(gpointer data); - static gboolean SuperShowShortcutsTimeout(gpointer data); static gboolean StrutHack(gpointer data); - static gboolean MoveFocusToKeyNavModeTimeout(gpointer data); static gboolean StartIconDragTimeout(gpointer data); - static gboolean ResetRepeatShorcutTimeout(gpointer data); void SetMousePosition(int x, int y); void SetStateMouseOverLauncher(bool over_launcher); - void SetStateKeyNav(bool keynav_activated); - bool MouseBeyondDragThreshold(); + bool MouseBeyondDragThreshold() const; void OnDragWindowAnimCompleted(); - bool IconNeedsAnimation(LauncherIcon* icon, struct timespec const& current); - bool IconDrawEdgeOnly(LauncherIcon* icon); - bool AnimationInProgress(); + bool IconNeedsAnimation(AbstractLauncherIcon* icon, struct timespec const& current) const; + bool IconDrawEdgeOnly(AbstractLauncherIcon* icon) const; + bool AnimationInProgress() const; void SetActionState(LauncherActionState actionstate); - LauncherActionState GetActionState(); + LauncherActionState GetActionState() const; void EnsureAnimation(); void EnsureScrollTimer(); @@ -302,26 +243,27 @@ private: static gboolean OnScrollTimeout(gpointer data); static gboolean OnUpdateDragManagerTimeout(gpointer data); - float DnDStartProgress(struct timespec const& current); - float DnDExitProgress(struct timespec const& current); - float GetHoverProgress(struct timespec const& current); - float AutohideProgress(struct timespec const& current); - float DragThresholdProgress(struct timespec const& current); - float DragHideProgress(struct timespec const& current); - float DragOutProgress(struct timespec const& current); - float IconDesatValue(LauncherIcon* icon, struct timespec const& current); - float IconPresentProgress(LauncherIcon* icon, struct timespec const& current); - float IconUrgentProgress(LauncherIcon* icon, struct timespec const& current); - float IconShimmerProgress(LauncherIcon* icon, struct timespec const& current); - float IconUrgentPulseValue(LauncherIcon* icon, struct timespec const& current); - float IconPulseOnceValue(LauncherIcon *icon, struct timespec const ¤t); - float IconUrgentWiggleValue(LauncherIcon* icon, struct timespec const& current); - float IconStartingBlinkValue(LauncherIcon* icon, struct timespec const& current); - float IconStartingPulseValue(LauncherIcon* icon, struct timespec const& current); - float IconBackgroundIntensity(LauncherIcon* icon, struct timespec const& current); - float IconProgressBias(LauncherIcon* icon, struct timespec const& current); - float IconDropDimValue(LauncherIcon* icon, struct timespec const& current); - float IconCenterTransitionProgress(LauncherIcon* icon, struct timespec const& current); + float DnDStartProgress(struct timespec const& current) const; + float DnDExitProgress(struct timespec const& current) const; + float GetHoverProgress(struct timespec const& current) const; + float AutohideProgress(struct timespec const& current) const; + float DragThresholdProgress(struct timespec const& current) const; + float DragHideProgress(struct timespec const& current) const; + float DragOutProgress(struct timespec const& current) const; + float IconDesatValue(AbstractLauncherIcon* icon, struct timespec const& current) const; + float IconPresentProgress(AbstractLauncherIcon* icon, struct timespec const& current) const; + float IconUrgentProgress(AbstractLauncherIcon* icon, struct timespec const& current) const; + float IconShimmerProgress(AbstractLauncherIcon* icon, struct timespec const& current) const; + float IconUrgentPulseValue(AbstractLauncherIcon* icon, struct timespec const& current) const; + float IconPulseOnceValue(AbstractLauncherIcon *icon, struct timespec const ¤t) const; + float IconUrgentWiggleValue(AbstractLauncherIcon* icon, struct timespec const& current) const; + float IconStartingBlinkValue(AbstractLauncherIcon* icon, struct timespec const& current) const; + float IconStartingPulseValue(AbstractLauncherIcon* icon, struct timespec const& current) const; + float IconBackgroundIntensity(AbstractLauncherIcon* icon, struct timespec const& current) const; + float IconProgressBias(AbstractLauncherIcon* icon, struct timespec const& current) const; + float IconDropDimValue(AbstractLauncherIcon* icon, struct timespec const& current) const; + float IconCenterTransitionProgress(AbstractLauncherIcon* icon, struct timespec const& current) const; + float IconVisibleProgress(AbstractLauncherIcon* icon, struct timespec const& current) const; void SetHover(bool hovered); void SetHidden(bool hidden); @@ -329,10 +271,11 @@ private: void SetDndDelta(float x, float y, nux::Geometry const& geo, timespec const& current); float DragLimiter(float x); - void SetupRenderArg(LauncherIcon* icon, struct timespec const& current, ui::RenderArg& arg); - void FillRenderArg(LauncherIcon* icon, + void SetupRenderArg(AbstractLauncherIcon* icon, struct timespec const& current, ui::RenderArg& arg); + void FillRenderArg(AbstractLauncherIcon* icon, ui::RenderArg& arg, nux::Point3& center, + nux::Geometry const& parent_abs_geo, float folding_threshold, float folded_size, float folded_spacing, @@ -342,10 +285,10 @@ private: struct timespec const& current); void RenderArgs(std::list<ui::RenderArg> &launcher_args, - nux::Geometry& box_geo, float* launcher_alpha); + nux::Geometry& box_geo, float* launcher_alpha, nux::Geometry const& parent_abs_geo); - void OnIconAdded(LauncherIcon* icon); - void OnIconRemoved(LauncherIcon* icon); + void OnIconAdded(AbstractLauncherIcon* icon); + void OnIconRemoved(AbstractLauncherIcon* icon); void OnOrderChanged(); void OnIconNeedsRedraw(AbstractLauncherIcon* icon); @@ -362,20 +305,20 @@ private: void OnActionDone(GVariant* data); - void RenderIconToTexture(nux::GraphicsEngine& GfxContext, LauncherIcon* icon, nux::ObjectPtr<nux::IOpenGLBaseTexture> texture); + void RenderIconToTexture(nux::GraphicsEngine& GfxContext, AbstractLauncherIcon* icon, nux::ObjectPtr<nux::IOpenGLBaseTexture> texture); - LauncherIcon* MouseIconIntersection(int x, int y); + AbstractLauncherIcon* MouseIconIntersection(int x, int y); void EventLogic(); void MouseDownLogic(int x, int y, unsigned long button_flags, unsigned long key_flags); void MouseUpLogic(int x, int y, unsigned long button_flags, unsigned long key_flags); void StartIconDragRequest(int x, int y); - void StartIconDrag(LauncherIcon* icon); + void StartIconDrag(AbstractLauncherIcon* icon); void EndIconDrag(); void UpdateDragWindowPosition(int x, int y); - float GetAutohidePositionMin(); - float GetAutohidePositionMax(); + float GetAutohidePositionMin() const; + float GetAutohidePositionMax() const; virtual void PreLayoutManagement(); virtual long PostLayoutManagement(long LayoutResult); @@ -384,8 +327,6 @@ private: void SetOffscreenRenderTarget(nux::ObjectPtr<nux::IOpenGLBaseTexture> texture); void RestoreSystemRenderTarget(); - gboolean TapOnSuper(); - void OnDisplayChanged(Display* display); void OnDNDDataCollected(const std::list<char*>& mimes); @@ -393,17 +334,11 @@ private: void DndHoveredIconReset(); nux::HLayout* m_Layout; - int m_ContentOffsetY; // used by keyboard/a11y-navigation - LauncherIcon* _current_icon; - LauncherIcon* m_ActiveTooltipIcon; - LauncherIcon* _icon_under_mouse; - LauncherIcon* _icon_mouse_down; - LauncherIcon* _drag_icon; - - int _current_icon_index; - int _last_icon_index; + AbstractLauncherIcon* _icon_under_mouse; + AbstractLauncherIcon* _icon_mouse_down; + AbstractLauncherIcon* _drag_icon; QuicklistView* _active_quicklist; @@ -414,9 +349,6 @@ private: bool _check_window_over_launcher; bool _shortcuts_shown; - bool _keynav_activated; - bool _key_switcher_activated; - guint64 _latest_shortcut; BacklightMode _backlight_mode; @@ -435,6 +367,9 @@ private: nux::ObjectPtr<nux::IOpenGLBaseTexture> _offscreen_drag_texture; + ui::PointerBarrierWrapper::Ptr _pointer_barrier; + ui::Decaymulator::Ptr decaymulator_; + int _space_between_icons; int _icon_size; int _icon_image_size; @@ -451,21 +386,11 @@ private: float _drag_out_delta_x; float _background_alpha; - int _bfb_width; - int _bfb_height; - guint _autoscroll_handle; - guint _focus_keynav_handle; - guint _super_show_launcher_handle; - guint _super_hide_launcher_handle; - guint _super_show_shortcuts_handle; guint _start_dragicon_handle; guint _dnd_check_handle; - guint _ignore_repeat_shortcut_handle; nux::Point2 _mouse_position; - nux::Point2 _bfb_mouse_position; - nux::AbstractPaintLayer* m_BackgroundLayer; nux::BaseWindow* _parent; LauncherModel* _model; LauncherDragWindow* _drag_window; @@ -477,7 +402,7 @@ private: bool _data_checked; bool _steal_drag; bool _drag_edge_touching; - LauncherIcon* _dnd_hovered_icon; + AbstractLauncherIcon* _dnd_hovered_icon; unity::DNDCollectionWindow* _collection_window; sigc::connection _on_data_collected_connection; diff --git a/plugins/unityshell/src/LauncherController.cpp b/plugins/unityshell/src/LauncherController.cpp index f8063a02b..784666b8c 100644 --- a/plugins/unityshell/src/LauncherController.cpp +++ b/plugins/unityshell/src/LauncherController.cpp @@ -20,14 +20,13 @@ #include <glib/gi18n-lib.h> #include <libbamf/libbamf.h> -/* Compiz */ -#include <core/core.h> #include <Nux/Nux.h> #include <Nux/HLayout.h> #include <Nux/BaseWindow.h> #include <NuxCore/Logger.h> +#include "LauncherOptions.h" #include "BamfLauncherIcon.h" #include "DesktopLauncherIcon.h" #include "DeviceLauncherIcon.h" @@ -37,12 +36,16 @@ #include "LauncherController.h" #include "LauncherEntryRemote.h" #include "LauncherEntryRemoteModel.h" -#include "LauncherIcon.h" +#include "AbstractLauncherIcon.h" #include "SoftwareCenterLauncherIcon.h" #include "LauncherModel.h" #include "WindowManager.h" #include "TrashLauncherIcon.h" #include "BFBLauncherIcon.h" +#include "UScreen.h" +#include "UBusWrapper.h" +#include "UBusMessages.h" +#include "TimeUtil.h" namespace unity { @@ -53,38 +56,71 @@ namespace nux::logging::Logger logger("unity.launcher"); } +namespace local +{ +namespace +{ + const int super_tap_duration = 250; + const int launcher_minimum_show_duration = 1250; + const int shortcuts_show_delay = 750; + const int ignore_repeat_shortcut_duration = 250; +} +} + +// FIXME: key-code defines for Up/Down/Left/Right of numeric keypad - needs to +// be moved to the correct place in NuxGraphics-headers +#define NUX_KP_DOWN 0xFF99 +#define NUX_KP_UP 0xFF97 +#define NUX_KP_LEFT 0xFF96 +#define NUX_KP_RIGHT 0xFF98 + class Controller::Impl { public: - Impl(Display* display); + Impl(Display* display, Controller* parent); ~Impl(); void UpdateNumWorkspaces(int workspaces); + Launcher* CreateLauncher(int monitor); + void Save(); void SortAndUpdate(); - void OnIconAdded(LauncherIcon* icon); - void OnIconRemoved(LauncherIcon* icon); + void OnIconAdded(AbstractLauncherIcon* icon); + void OnIconRemoved(AbstractLauncherIcon* 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 OnLauncherAddRequest(char* path, AbstractLauncherIcon* before); + void OnLauncherAddRequestSpecial(char* path, AbstractLauncherIcon* before, char* aptdaemon_trans_id, char* icon_path); + void OnLauncherRemoveRequest(AbstractLauncherIcon* 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(); void InsertDesktopIcon(); void RemoveDesktopIcon(); + bool TapTimeUnderLimit(); + + void SendHomeActivationRequest(); + + int TimeSinceLauncherKeyPress(); + + int MonitorWithMouse(); + void InsertTrash(); - void RegisterIcon(LauncherIcon* icon); + void RegisterIcon(AbstractLauncherIcon* icon); - LauncherIcon* CreateFavorite(const char* file_path); + AbstractLauncherIcon* CreateFavorite(const char* file_path); SoftwareCenterLauncherIcon* CreateSCLauncherIcon(const char* file_path, const char* aptdaemon_trans_id, char* icon_path); @@ -92,14 +128,25 @@ public: void OnExpoActivated(); + void OnScreenChanged(int primary_monitor, std::vector<nux::Geometry>& monitors); + + void ReceiveMouseDownOutsideArea(int x, int y, unsigned long button_flags, unsigned long key_flags); + + void ReceiveLauncherKeyPress(unsigned long eventType, + unsigned long keysym, + unsigned long state, + const char* character, + unsigned short keyCount); + /* statics */ static void OnViewOpened(BamfMatcher* matcher, BamfView* view, gpointer data); + Controller* parent_; glib::Object<BamfMatcher> matcher_; LauncherModel::Ptr model_; - nux::ObjectPtr<nux::BaseWindow> launcher_window_; nux::ObjectPtr<Launcher> launcher_; + nux::ObjectPtr<Launcher> keyboard_launcher_; int sort_priority_; DeviceLauncherSection* device_section_; LauncherEntryRemoteModel remote_model_; @@ -108,53 +155,59 @@ public: nux::ObjectPtr<AbstractLauncherIcon> desktop_icon_; int num_workspaces_; bool show_desktop_icon_; + Display* display_; + + guint bamf_timer_handler_id_; + guint on_view_opened_id_; + guint launcher_key_press_handler_id_; + guint launcher_label_show_handler_id_; + guint launcher_hide_handler_id_; + + bool launcher_open; + bool launcher_keynav; + bool launcher_grabbed; + bool reactivate_keynav; + int reactivate_index; - guint bamf_timer_handler_id_; + UBusManager ubus; - guint32 on_view_opened_id_; + struct timespec launcher_key_press_time_; + + LauncherList launchers; sigc::connection on_expoicon_activate_connection_; + sigc::connection launcher_key_press_connection_; + sigc::connection launcher_event_outside_connection_; }; -Controller::Impl::Impl(Display* display) - : matcher_(nullptr) +Controller::Impl::Impl(Display* display, Controller* parent) + : parent_(parent) + , matcher_(nullptr) , model_(new LauncherModel()) , sort_priority_(0) , show_desktop_icon_(false) + , display_(display) { - // NOTE: should the launcher itself hold the base window? - // seems like it probably should... - launcher_window_ = new nux::BaseWindow(TEXT("LauncherWindow")); - - Launcher* raw_launcher = new Launcher(launcher_window_.GetPointer()); - launcher_ = raw_launcher; - launcher_->display = display; - launcher_->SetIconSize(54, 48); - launcher_->SetBacklightMode(Launcher::BACKLIGHT_ALWAYS_ON); - launcher_->SetHideMode(Launcher::LAUNCHER_HIDE_DODGE_WINDOWS); - launcher_->SetLaunchAnimation(Launcher::LAUNCH_ANIMATION_PULSE); - launcher_->SetUrgentAnimation(Launcher::URGENT_ANIMATION_WIGGLE); + UScreen* uscreen = UScreen::GetDefault(); + auto monitors = uscreen->GetMonitors(); - nux::HLayout* layout = new nux::HLayout(NUX_TRACKER_LOCATION); - layout->AddView(raw_launcher, 1); - layout->SetContentDistribution(nux::eStackLeft); - layout->SetVerticalExternalMargin(0); - layout->SetHorizontalExternalMargin(0); + launcher_open = false; + launcher_keynav = false; + launcher_grabbed = false; + reactivate_keynav = false; - launcher_window_->SetLayout(layout); - launcher_window_->SetBackgroundColor(nux::color::Transparent); - launcher_window_->ShowWindow(true); - launcher_window_->EnableInputWindow(true, "launcher", false, false); - launcher_window_->InputWindowEnableStruts(false); - launcher_window_->SetEnterFocusInputArea(raw_launcher); + int i = 0; + for (auto monitor : monitors) + { + Launcher* launcher = CreateLauncher(i); + launchers.push_back(nux::ObjectPtr<Launcher> (launcher)); + i++; + } - 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)); + launcher_ = launchers[0]; - device_section_ = new DeviceLauncherSection(raw_launcher); + device_section_ = new DeviceLauncherSection(); device_section_->IconAdded.connect(sigc::mem_fun(this, &Impl::OnIconAdded)); num_workspaces_ = WindowManager::Default()->WorkspaceCount(); @@ -180,8 +233,22 @@ 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)); - RegisterIcon(new BFBLauncherIcon(raw_launcher)); - desktop_icon_ = new DesktopLauncherIcon(raw_launcher); + 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()); + desktop_icon_ = new DesktopLauncherIcon(); + + uscreen->changed.connect(sigc::mem_fun(this, &Controller::Impl::OnScreenChanged)); + + launcher_key_press_time_ = { 0, 0 }; + + ubus.RegisterInterest(UBUS_QUICKLIST_END_KEY_NAV, [&](GVariant * args) { + if (reactivate_keynav) + parent_->KeyNavGrab(); + model_->SetSelection(reactivate_index); + }); } Controller::Impl::~Impl() @@ -195,8 +262,53 @@ Controller::Impl::~Impl() delete device_section_; } +void Controller::Impl::OnScreenChanged(int primary_monitor, std::vector<nux::Geometry>& monitors) +{ + unsigned int num_monitors = monitors.size(); + + for (unsigned int i = 0; i < num_monitors; i++) + { + if (i >= launchers.size()) + launchers.push_back(nux::ObjectPtr<Launcher> (CreateLauncher(i))); + + launchers[i]->Resize(); + } -void Controller::Impl::OnLauncherAddRequest(char* path, LauncherIcon* before) + launchers.resize(num_monitors); +} + +Launcher* Controller::Impl::CreateLauncher(int monitor) +{ + nux::BaseWindow* launcher_window = new nux::BaseWindow(TEXT("LauncherWindow")); + + Launcher* launcher = new Launcher(launcher_window); + launcher->display = display_; + launcher->monitor = monitor; + launcher->options = parent_->options(); + + nux::HLayout* layout = new nux::HLayout(NUX_TRACKER_LOCATION); + layout->AddView(launcher, 1); + layout->SetContentDistribution(nux::eStackLeft); + layout->SetVerticalExternalMargin(0); + layout->SetHorizontalExternalMargin(0); + + launcher_window->SetLayout(layout); + launcher_window->SetBackgroundColor(nux::color::Transparent); + launcher_window->ShowWindow(true); + launcher_window->EnableInputWindow(true, "launcher", false, false); + launcher_window->InputWindowEnableStruts(false); + launcher_window->SetEnterFocusInputArea(launcher); + + launcher->SetModel(model_.get()); + launcher->launcher_addrequest.connect(sigc::mem_fun(this, &Impl::OnLauncherAddRequest)); + launcher->launcher_removerequest.connect(sigc::mem_fun(this, &Impl::OnLauncherRemoveRequest)); + + parent_->AddChild(launcher); + + return launcher; +} + +void Controller::Impl::OnLauncherAddRequest(char* path, AbstractLauncherIcon* before) { for (auto it : model_->GetSublist<BamfLauncherIcon> ()) { @@ -209,7 +321,7 @@ void Controller::Impl::OnLauncherAddRequest(char* path, LauncherIcon* before) } } - LauncherIcon* result = CreateFavorite(path); + AbstractLauncherIcon* result = CreateFavorite(path); if (result) { RegisterIcon(result); @@ -241,7 +353,7 @@ void Controller::Impl::Save() } void -Controller::Impl::OnLauncherAddRequestSpecial(char* path, LauncherIcon* before, char* aptdaemon_trans_id, char* icon_path) +Controller::Impl::OnLauncherAddRequestSpecial(char* path, AbstractLauncherIcon* before, char* aptdaemon_trans_id, char* icon_path) { std::list<BamfLauncherIcon*> launchers; std::list<BamfLauncherIcon*>::iterator it; @@ -272,7 +384,7 @@ void Controller::Impl::SortAndUpdate() std::list<BamfLauncherIcon*> launchers = model_->GetSublist<BamfLauncherIcon> (); for (auto it : launchers) { - if (shortcut < 11 && it->GetQuirk(LauncherIcon::QUIRK_VISIBLE)) + if (shortcut < 11 && it->GetQuirk(AbstractLauncherIcon::QUIRK_VISIBLE)) { buff = g_strdup_printf("%d", shortcut % 10); it->SetShortcut(buff[0]); @@ -287,21 +399,21 @@ void Controller::Impl::SortAndUpdate() } } -void Controller::Impl::OnIconAdded(LauncherIcon* icon) +void Controller::Impl::OnIconAdded(AbstractLauncherIcon* icon) { this->RegisterIcon(icon); } -void Controller::Impl::OnIconRemoved(LauncherIcon* icon) +void Controller::Impl::OnIconRemoved(AbstractLauncherIcon* icon) { SortAndUpdate(); } -void Controller::Impl::OnLauncherRemoveRequest(LauncherIcon* icon) +void Controller::Impl::OnLauncherRemoveRequest(AbstractLauncherIcon* icon) { switch (icon->Type()) { - case LauncherIcon::TYPE_APPLICATION: + case AbstractLauncherIcon::TYPE_APPLICATION: { BamfLauncherIcon* bamf_icon = dynamic_cast<BamfLauncherIcon*>(icon); @@ -313,7 +425,7 @@ void Controller::Impl::OnLauncherRemoveRequest(LauncherIcon* icon) break; } - case LauncherIcon::TYPE_DEVICE: + case AbstractLauncherIcon::TYPE_DEVICE: { DeviceLauncherIcon* device_icon = dynamic_cast<DeviceLauncherIcon*>(icon); @@ -349,6 +461,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>(); + AbstractLauncherIcon* other = (bamf_list.size() > 0) ? *(bamf_list.begin()) : nullptr; + + if (!pos.empty()) + { + for (auto it : bamf_list) + { + if (it->GetQuirk(AbstractLauncherIcon::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; + } + } + + AbstractLauncherIcon* 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(); @@ -357,7 +545,7 @@ void Controller::Impl::OnExpoActivated() void Controller::Impl::InsertTrash() { TrashLauncherIcon* icon; - icon = new TrashLauncherIcon(launcher_.GetPointer()); + icon = new TrashLauncherIcon(); RegisterIcon(icon); } @@ -377,13 +565,13 @@ void Controller::Impl::UpdateNumWorkspaces(int workspaces) void Controller::Impl::InsertExpoAction() { - expo_icon_ = new SimpleLauncherIcon(launcher_.GetPointer()); + expo_icon_ = new SimpleLauncherIcon(); expo_icon_->tooltip_text = _("Workspace Switcher"); expo_icon_->icon_name = "workspace-switcher"; - expo_icon_->SetQuirk(LauncherIcon::QUIRK_VISIBLE, true); - expo_icon_->SetQuirk(LauncherIcon::QUIRK_RUNNING, false); - expo_icon_->SetIconType(LauncherIcon::TYPE_EXPO); + expo_icon_->SetQuirk(AbstractLauncherIcon::QUIRK_VISIBLE, true); + expo_icon_->SetQuirk(AbstractLauncherIcon::QUIRK_RUNNING, false); + expo_icon_->SetIconType(AbstractLauncherIcon::TYPE_EXPO); expo_icon_->SetShortcut('s'); on_expoicon_activate_connection_ = expo_icon_->activate.connect(sigc::mem_fun(this, &Impl::OnExpoActivated)); @@ -400,8 +588,8 @@ void Controller::Impl::RemoveExpoAction() void Controller::Impl::InsertDesktopIcon() { - desktop_launcher_icon_ = new DesktopLauncherIcon(launcher_.GetPointer()); - desktop_launcher_icon_->SetIconType(LauncherIcon::TYPE_DESKTOP); + desktop_launcher_icon_ = new DesktopLauncherIcon(); + desktop_launcher_icon_->SetIconType(AbstractLauncherIcon::TYPE_DESKTOP); desktop_launcher_icon_->SetShowInSwitcher(false); RegisterIcon(desktop_launcher_icon_); @@ -412,7 +600,7 @@ void Controller::Impl::RemoveDesktopIcon() model_->RemoveIcon(desktop_launcher_icon_); } -void Controller::Impl::RegisterIcon(LauncherIcon* icon) +void Controller::Impl::RegisterIcon(AbstractLauncherIcon* icon) { model_->AddIcon(icon); @@ -446,14 +634,14 @@ void Controller::Impl::OnViewOpened(BamfMatcher* matcher, BamfView* view, gpoint return; } - BamfLauncherIcon* icon = new BamfLauncherIcon(self->launcher_.GetPointer(), app); - icon->SetIconType(LauncherIcon::TYPE_APPLICATION); + BamfLauncherIcon* icon = new BamfLauncherIcon(app); + icon->SetIconType(AbstractLauncherIcon::TYPE_APPLICATION); icon->SetSortPriority(self->sort_priority_++); self->RegisterIcon(icon); } -LauncherIcon* Controller::Impl::CreateFavorite(const char* file_path) +AbstractLauncherIcon* Controller::Impl::CreateFavorite(const char* file_path) { BamfApplication* app; BamfLauncherIcon* icon; @@ -471,8 +659,8 @@ LauncherIcon* Controller::Impl::CreateFavorite(const char* file_path) 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 BamfLauncherIcon(launcher_.GetPointer(), app); - icon->SetIconType(LauncherIcon::TYPE_APPLICATION); + icon = new BamfLauncherIcon(app); + icon->SetIconType(AbstractLauncherIcon::TYPE_APPLICATION); icon->SetSortPriority(sort_priority_++); return icon; @@ -497,7 +685,7 @@ Controller::Impl::CreateSCLauncherIcon(const char* file_path, const char* aptdae 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 = new SoftwareCenterLauncherIcon(app, (char*)aptdaemon_trans_id, icon_path); icon->SetIconType(LauncherIcon::TYPE_APPLICATION); icon->SetSortPriority(sort_priority_++); @@ -521,7 +709,7 @@ void Controller::Impl::SetupBamf() for (FavoriteList::const_iterator i = favs.begin(), end = favs.end(); i != end; ++i) { - LauncherIcon* fav = CreateFavorite(i->c_str()); + AbstractLauncherIcon* fav = CreateFavorite(i->c_str()); if (fav) { @@ -542,7 +730,7 @@ void Controller::Impl::SetupBamf() continue; g_object_set_qdata(G_OBJECT(app), g_quark_from_static_string("unity-seen"), GINT_TO_POINTER(1)); - icon = new BamfLauncherIcon(launcher_.GetPointer(), app); + icon = new BamfLauncherIcon(app); icon->SetSortPriority(sort_priority_++); RegisterIcon(icon); } @@ -554,10 +742,42 @@ void Controller::Impl::SetupBamf() bamf_timer_handler_id_ = 0; } +int Controller::Impl::TimeSinceLauncherKeyPress() +{ + struct timespec current; + unity::TimeUtil::SetTimeStruct(¤t); + return unity::TimeUtil::TimeDelta(¤t, &launcher_key_press_time_); +} + +bool Controller::Impl::TapTimeUnderLimit() +{ + int time_difference = TimeSinceLauncherKeyPress(); + return time_difference < local::super_tap_duration; +} + +void Controller::Impl::SendHomeActivationRequest() +{ + ubus.SendMessage(UBUS_PLACE_ENTRY_ACTIVATE_REQUEST, g_variant_new("(sus)", "home.lens", 0, "")); +} Controller::Controller(Display* display) - : pimpl(new Impl(display)) { + options = Options::Ptr(new Options()); + + // defaults must match XML file + options()->tile_size = 54; + options()->icon_size = 48; + options()->backlight_mode = BACKLIGHT_ALWAYS_ON; + options()->hide_mode = LAUNCHER_HIDE_DODGE_WINDOWS; + options()->launch_animation = LAUNCH_ANIMATION_PULSE; + options()->urgent_animation = URGENT_ANIMATION_WIGGLE; + options()->edge_reveal_pressure = 2000; + options()->edge_overcome_pressure = 2000; + options()->edge_decay_rate = 1500; + options()->edge_stop_velocity = 4500; + + // options must be set before creating pimpl which loads launchers + pimpl = new Impl(display, this); } Controller::~Controller() @@ -570,12 +790,17 @@ void Controller::UpdateNumWorkspaces(int workspaces) pimpl->UpdateNumWorkspaces(workspaces); } -Launcher& Controller::launcher() +Launcher& Controller::launcher() const { return *(pimpl->launcher_); } -std::vector<char> Controller::GetAllShortcuts() +Controller::LauncherList& Controller::launchers() const +{ + return pimpl->launchers; +} + +std::vector<char> Controller::GetAllShortcuts() const { std::vector<char> shortcuts; for (auto icon : *(pimpl->model_)) @@ -588,50 +813,34 @@ std::vector<char> Controller::GetAllShortcuts() return shortcuts; } -std::vector<AbstractLauncherIcon*> Controller::GetAltTabIcons() +std::vector<AbstractLauncherIcon*> Controller::GetAltTabIcons(bool current) const { std::vector<AbstractLauncherIcon*> results; results.push_back(pimpl->desktop_icon_.GetPointer()); for (auto icon : *(pimpl->model_)) - if (icon->ShowInSwitcher()) + if (icon->ShowInSwitcher(current)) results.push_back(icon); return results; } -void Controller::PrimaryMonitorGeometryChanged(nux::Geometry const& rect) +Window Controller::LauncherWindowId(int launcher) const { - const int panel_height = 24; - - int launcher_width = pimpl->launcher_window_->GetGeometry().width; - - nux::Geometry new_geometry(rect.x, - rect.y + panel_height, - launcher_width, - rect.height - panel_height); - - LOG_DEBUG(logger) << "Setting to launcher rect:" - << " x=" << new_geometry.x - << " y=" << new_geometry.y - << " w=" << new_geometry.width - << " h=" << new_geometry.height; - - pimpl->launcher_->SetMaximumHeight(new_geometry.height); - - pimpl->launcher_window_->SetGeometry(new_geometry); - pimpl->launcher_->SetGeometry(new_geometry); + return pimpl->launchers[launcher]->GetParent()->GetInputWindowId(); } -Window Controller::launcher_input_window_id() +Window Controller::KeyNavLauncherInputWindowId() const { - return pimpl->launcher_window_->GetInputWindowId(); + if (KeyNavIsActive()) + return pimpl->keyboard_launcher_->GetParent()->GetInputWindowId(); + return 0; } void Controller::PushToFront() { - pimpl->launcher_window_->PushToFront(); + pimpl->launcher_->GetParent()->PushToFront(); } void Controller::SetShowDesktopIcon(bool show_desktop_icon) @@ -647,6 +856,298 @@ void Controller::SetShowDesktopIcon(bool show_desktop_icon) pimpl->RemoveDesktopIcon(); } +int Controller::Impl::MonitorWithMouse() +{ + UScreen* uscreen = UScreen::GetDefault(); + return uscreen->GetMonitorWithMouse(); +} + +void Controller::HandleLauncherKeyPress() +{ + unity::TimeUtil::SetTimeStruct(&pimpl->launcher_key_press_time_); + + auto show_launcher = [](gpointer user_data) -> gboolean + { + Impl* self = static_cast<Impl*>(user_data); + if (self->keyboard_launcher_.IsNull()) + self->keyboard_launcher_ = self->launchers[self->MonitorWithMouse()]; + + if (self->launcher_hide_handler_id_ > 0) + { + g_source_remove(self->launcher_hide_handler_id_); + self->launcher_hide_handler_id_ = 0; + } + + self->keyboard_launcher_->ForceReveal(true); + self->launcher_open = true; + self->launcher_key_press_handler_id_ = 0; + return FALSE; + }; + pimpl->launcher_key_press_handler_id_ = g_timeout_add(local::super_tap_duration, show_launcher, pimpl); + + auto show_shortcuts = [](gpointer user_data) -> gboolean + { + Impl* self = static_cast<Impl*>(user_data); + if (!self->launcher_keynav) + { + if (self->keyboard_launcher_.IsNull()) + self->keyboard_launcher_ = self->launchers[self->MonitorWithMouse()]; + + self->keyboard_launcher_->ShowShortcuts(true); + self->launcher_open = true; + self->launcher_label_show_handler_id_ = 0; + } + return FALSE; + }; + pimpl->launcher_label_show_handler_id_ = g_timeout_add(local::shortcuts_show_delay, show_shortcuts, pimpl); +} + +void Controller::HandleLauncherKeyRelease() +{ + if (pimpl->TapTimeUnderLimit()) + { + pimpl->SendHomeActivationRequest(); + } + + if (pimpl->launcher_label_show_handler_id_) + { + g_source_remove(pimpl->launcher_label_show_handler_id_); + pimpl->launcher_label_show_handler_id_ = 0; + } + + if (pimpl->launcher_key_press_handler_id_) + { + g_source_remove(pimpl->launcher_key_press_handler_id_); + pimpl->launcher_key_press_handler_id_ = 0; + } + + if (pimpl->keyboard_launcher_.IsValid()) + { + pimpl->keyboard_launcher_->ShowShortcuts(false); + + int ms_since_show = pimpl->TimeSinceLauncherKeyPress(); + if (ms_since_show > local::launcher_minimum_show_duration) + { + pimpl->keyboard_launcher_->ForceReveal(false); + pimpl->launcher_open = false; + + if (!pimpl->launcher_keynav) + pimpl->keyboard_launcher_.Release(); + } + else + { + int time_left = local::launcher_minimum_show_duration - ms_since_show; + auto hide_launcher = [](gpointer user_data) -> gboolean + { + Impl *self = static_cast<Impl*>(user_data); + if (self->keyboard_launcher_.IsValid()) + { + self->keyboard_launcher_->ForceReveal(false); + self->launcher_open = false; + + if (!self->launcher_keynav) + self->keyboard_launcher_.Release(); + } + + self->launcher_hide_handler_id_ = 0; + return FALSE; + }; + + pimpl->launcher_hide_handler_id_ = g_timeout_add(time_left, hide_launcher, pimpl); + } + } +} + +bool Controller::HandleLauncherKeyEvent(Display *display, unsigned int key_sym, unsigned long key_code, unsigned long key_state, char* key_string) +{ + LauncherModel::iterator it; + + // Shortcut to start launcher icons. Only relies on Keycode, ignore modifier + for (it = pimpl->model_->begin(); it != pimpl->model_->end(); it++) + { + if ((XKeysymToKeycode(display, (*it)->GetShortcut()) == key_code) || + ((gchar)((*it)->GetShortcut()) == key_string[0])) + { + struct timespec last_action_time = (*it)->GetQuirkTime(AbstractLauncherIcon::QUIRK_LAST_ACTION); + struct timespec current; + TimeUtil::SetTimeStruct(¤t); + if (TimeUtil::TimeDelta(¤t, &last_action_time) > local::ignore_repeat_shortcut_duration) + { + if (g_ascii_isdigit((gchar)(*it)->GetShortcut()) && (key_state & ShiftMask)) + (*it)->OpenInstance(ActionArg(ActionArg::LAUNCHER, 0)); + else + (*it)->Activate(ActionArg(ActionArg::LAUNCHER, 0)); + } + + // disable the "tap on super" check + pimpl->launcher_key_press_time_ = { 0, 0 }; + return true; + } + } + + return false; +} + +void Controller::Impl::ReceiveMouseDownOutsideArea(int x, int y, unsigned long button_flags, unsigned long key_flags) +{ + if (launcher_grabbed) + parent_->KeyNavTerminate(false); +} + +void Controller::KeyNavGrab() +{ + KeyNavActivate(); + pimpl->keyboard_launcher_->GrabKeyboard(); + pimpl->launcher_grabbed = true; + + pimpl->launcher_key_press_connection_ = + pimpl->keyboard_launcher_->key_down.connect(sigc::mem_fun(pimpl, &Controller::Impl::ReceiveLauncherKeyPress)); + pimpl->launcher_event_outside_connection_ = + pimpl->keyboard_launcher_->mouse_down_outside_pointer_grab_area.connect(sigc::mem_fun(pimpl, &Controller::Impl::ReceiveMouseDownOutsideArea)); +} + +void Controller::KeyNavActivate() +{ + if (pimpl->launcher_keynav) + return; + + pimpl->reactivate_keynav = false; + pimpl->launcher_keynav = true; + pimpl->keyboard_launcher_ = pimpl->launchers[pimpl->MonitorWithMouse()]; + pimpl->keyboard_launcher_->ShowShortcuts(false); + + pimpl->keyboard_launcher_->EnterKeyNavMode(); + pimpl->model_->SetSelection(0); + + pimpl->ubus.SendMessage(UBUS_LAUNCHER_START_KEY_SWTICHER, g_variant_new_boolean(true)); +} + +void Controller::KeyNavNext() +{ + pimpl->model_->SelectNext(); +} + +void Controller::KeyNavPrevious() +{ + pimpl->model_->SelectPrevious(); +} + +void Controller::KeyNavTerminate(bool activate) +{ + if (!pimpl->launcher_keynav) + return; + + pimpl->keyboard_launcher_->ExitKeyNavMode(); + if (pimpl->launcher_grabbed) + { + pimpl->keyboard_launcher_->UnGrabKeyboard(); + pimpl->launcher_key_press_connection_.disconnect(); + pimpl->launcher_event_outside_connection_.disconnect(); + pimpl->launcher_grabbed = false; + } + + if (activate) + pimpl->model_->Selection()->Activate(ActionArg(ActionArg::LAUNCHER, 0)); + + pimpl->launcher_keynav = false; + if (!pimpl->launcher_open) + pimpl->keyboard_launcher_.Release(); + + pimpl->ubus.SendMessage(UBUS_LAUNCHER_END_KEY_SWTICHER, g_variant_new_boolean(true)); +} + +bool Controller::KeyNavIsActive() const +{ + return pimpl->launcher_keynav; +} + +std::string +Controller::GetName() const +{ + return "LauncherController"; +} + +void +Controller::AddProperties(GVariantBuilder* builder) +{ + timespec current; + clock_gettime(CLOCK_MONOTONIC, ¤t); + + unity::variant::BuilderWrapper(builder) + .add("key_nav_is_active", KeyNavIsActive()) + .add("key_nav_launcher_monitor", pimpl->keyboard_launcher_.IsValid() ? pimpl->keyboard_launcher_->monitor : -1) + .add("key_nav_selection", pimpl->model_->SelectionIndex()) + .add("key_nav_is_grabbed", pimpl->launcher_grabbed); +} + +void Controller::Impl::ReceiveLauncherKeyPress(unsigned long eventType, + unsigned long keysym, + unsigned long state, + const char* character, + unsigned short keyCount) +{ + /* + * all key events below are related to keynavigation. Make an additional + * check that we are in a keynav mode when we inadvertadly receive the focus + */ + if (!launcher_grabbed) + return; + + switch (keysym) + { + // up (move selection up or go to global-menu if at top-most icon) + case NUX_VK_UP: + case NUX_KP_UP: + parent_->KeyNavPrevious(); + break; + + // down (move selection down and unfold launcher if needed) + case NUX_VK_DOWN: + case NUX_KP_DOWN: + parent_->KeyNavNext(); + break; + + // esc/left (close quicklist or exit laucher key-focus) + case NUX_VK_LEFT: + case NUX_KP_LEFT: + case NUX_VK_ESCAPE: + // hide again + parent_->KeyNavTerminate(false); + break; + + // right/shift-f10 (open quicklist of currently selected icon) + case XK_F10: + if (!(state & nux::NUX_STATE_SHIFT)) + break; + case NUX_VK_RIGHT: + case NUX_KP_RIGHT: + case XK_Menu: + if (model_->Selection()->OpenQuicklist(true, keyboard_launcher_->monitor())) + { + reactivate_keynav = true; + reactivate_index = model_->SelectionIndex(); + parent_->KeyNavTerminate(false); + } + break; + + // <SPACE> (open a new instance) + case NUX_VK_SPACE: + model_->Selection()->OpenInstance(ActionArg(ActionArg::LAUNCHER, 0)); + parent_->KeyNavTerminate(false); + break; + + // <RETURN> (start/activate currently selected icon) + case NUX_VK_ENTER: + case NUX_KP_ENTER: + model_->Selection()->Activate(ActionArg(ActionArg::LAUNCHER, 0)); + parent_->KeyNavTerminate(false); + break; + + default: + break; + } +} + } // namespace launcher } // namespace unity diff --git a/plugins/unityshell/src/LauncherController.h b/plugins/unityshell/src/LauncherController.h index d8492a2ad..b9cb20601 100644 --- a/plugins/unityshell/src/LauncherController.h +++ b/plugins/unityshell/src/LauncherController.h @@ -24,7 +24,6 @@ #include <memory> #include <vector> #include <sigc++/sigc++.h> -#include <core/core.h> #include "SoftwareCenterLauncherIcon.h" @@ -36,26 +35,50 @@ class AbstractLauncherIcon; class Launcher; class LauncherModel; -class Controller : public sigc::trackable +class Controller : public unity::debug::Introspectable, public sigc::trackable { public: typedef std::shared_ptr<Controller> Ptr; + typedef std::vector<nux::ObjectPtr<Launcher> > LauncherList; + + nux::Property<Options::Ptr> options; Controller(Display* display); ~Controller(); - Launcher& launcher(); - Window launcher_input_window_id(); + Launcher& launcher() const; + LauncherList& launchers() const; + Window LauncherWindowId(int launcher) const; + Window KeyNavLauncherInputWindowId() const; void UpdateNumWorkspaces(int workspaces); - std::vector<char> GetAllShortcuts(); - std::vector<AbstractLauncherIcon*> GetAltTabIcons(); + std::vector<char> GetAllShortcuts() const; + std::vector<AbstractLauncherIcon*> GetAltTabIcons(bool current) const; - void PrimaryMonitorGeometryChanged(nux::Geometry const& geo); void PushToFront(); void SetShowDesktopIcon(bool show_desktop_icon); + void HandleLauncherKeyPress(); + void HandleLauncherKeyRelease(); + bool HandleLauncherKeyEvent(Display *display, + unsigned int key_sym, + unsigned long key_code, + unsigned long key_state, + char* key_string); + + void KeyNavActivate(); + void KeyNavGrab(); + void KeyNavTerminate(bool activate = true); + void KeyNavNext(); + void KeyNavPrevious(); + bool KeyNavIsActive() const; + +protected: + // Introspectable methods + std::string GetName() const; + void AddProperties(GVariantBuilder* builder); + private: class Impl; Impl* pimpl; diff --git a/plugins/unityshell/src/LauncherHideMachine.cpp b/plugins/unityshell/src/LauncherHideMachine.cpp index e7fc62c1c..2389fd851 100644 --- a/plugins/unityshell/src/LauncherHideMachine.cpp +++ b/plugins/unityshell/src/LauncherHideMachine.cpp @@ -35,13 +35,23 @@ LauncherHideMachine::LauncherHideMachine() _mode = HIDE_NEVER; _quirks = DEFAULT; _should_hide = false; - _show_on_edge = true; _latest_emit_should_hide = false; _hide_changed_emit_handle = 0; + reveal_progress = 0; _hide_delay_handle = 0; _hide_delay_timeout_length = 750; + + decaymulator_ = unity::ui::Decaymulator::Ptr(new unity::ui::Decaymulator()); + decaymulator_->value.changed.connect([&](int value) -> void { reveal_progress = (float)value / (float)reveal_pressure; }); + + edge_decay_rate.changed.connect(sigc::mem_fun (this, &LauncherHideMachine::OnDecayRateChanged)); +} + +void LauncherHideMachine::OnDecayRateChanged(int value) +{ + decaymulator_->rate_of_decay = value; } LauncherHideMachine::~LauncherHideMachine() @@ -59,6 +69,19 @@ LauncherHideMachine::~LauncherHideMachine() } void +LauncherHideMachine::AddRevealPressure(int pressure) +{ + decaymulator_->value = decaymulator_->value + pressure; + + if (decaymulator_->value > reveal_pressure) + { + SetQuirk(REVEAL_PRESSURE_PASS, true); + SetQuirk(MOUSE_MOVE_POST_REVEAL, true); + decaymulator_->value = 0; + } +} + +void LauncherHideMachine::SetShouldHide(bool value, bool skip_delay) { if (_should_hide == value) @@ -99,7 +122,6 @@ LauncherHideMachine::SetShouldHide(bool value, bool skip_delay) SCALE_ACTIVE = 1 << 16, 64k #VISIBLE_REQUIRED EXPO_ACTIVE = 1 << 17, 128k #VISIBLE_REQUIRED MT_DRAG_OUT = 1 << 18, 256k #VISIBLE_REQUIRED - MOUSE_OVER_ACTIVE_EDGE = 1 << 19, 512k LAUNCHER_PULSE = 1 << 20, 1M #VISIBLE_REQUIRED LOCK_HIDE = 1 << 21, 2M */ @@ -156,11 +178,7 @@ LauncherHideMachine::EnsureHideState(bool skip_delay) HideQuirk _should_show_quirk; if (GetQuirk(LAUNCHER_HIDDEN)) { - _should_show_quirk = (HideQuirk)(VISIBLE_REQUIRED); - - if (_show_on_edge) - _should_show_quirk = (HideQuirk)(_should_show_quirk | MOUSE_OVER_ACTIVE_EDGE); - + _should_show_quirk = (HideQuirk) ((VISIBLE_REQUIRED) | REVEAL_PRESSURE_PASS); } else { @@ -168,9 +186,6 @@ LauncherHideMachine::EnsureHideState(bool skip_delay) // mouse position over launcher is only taken into account if we move it after the revealing state if (GetQuirk(MOUSE_MOVE_POST_REVEAL)) _should_show_quirk = (HideQuirk)(_should_show_quirk | MOUSE_OVER_LAUNCHER); - - if (_show_on_edge) - _should_show_quirk = (HideQuirk)(_should_show_quirk | MOUSE_OVER_ACTIVE_EDGE); } if (GetQuirk(_should_show_quirk)) @@ -199,7 +214,7 @@ LauncherHideMachine::SetMode(LauncherHideMachine::HideMode mode) } LauncherHideMachine::HideMode -LauncherHideMachine::GetMode() +LauncherHideMachine::GetMode() const { return _mode; } @@ -229,7 +244,7 @@ LauncherHideMachine::SetQuirk(LauncherHideMachine::HideQuirk quirk, bool active) } bool -LauncherHideMachine::GetQuirk(LauncherHideMachine::HideQuirk quirk, bool allow_partial) +LauncherHideMachine::GetQuirk(LauncherHideMachine::HideQuirk quirk, bool allow_partial) const { if (allow_partial) return _quirks & quirk; @@ -237,28 +252,11 @@ LauncherHideMachine::GetQuirk(LauncherHideMachine::HideQuirk quirk, bool allow_p } bool -LauncherHideMachine::ShouldHide() +LauncherHideMachine::ShouldHide() const { return _should_hide; } -void -LauncherHideMachine::SetShowOnEdge(bool value) -{ - if (value == _show_on_edge) - return; - - _show_on_edge = value; - - LOG_DEBUG(logger) << "Shows on edge: " << _show_on_edge; -} - -bool -LauncherHideMachine::GetShowOnEdge() -{ - return _show_on_edge; -} - gboolean LauncherHideMachine::OnHideDelayTimeout(gpointer data) { @@ -285,7 +283,7 @@ LauncherHideMachine::EmitShouldHideChanged(gpointer data) } std::string -LauncherHideMachine::DebugHideQuirks() +LauncherHideMachine::DebugHideQuirks() const { // Although I do wonder why we are returning a string representation // of the enum value as an integer anyway. diff --git a/plugins/unityshell/src/LauncherHideMachine.h b/plugins/unityshell/src/LauncherHideMachine.h index e5efeacb5..efe4835ed 100644 --- a/plugins/unityshell/src/LauncherHideMachine.h +++ b/plugins/unityshell/src/LauncherHideMachine.h @@ -24,6 +24,8 @@ #include <glib.h> #include <string> +#include "Decaymulator.h" + class LauncherHideMachine : public sigc::trackable { public: @@ -55,28 +57,32 @@ public: SCALE_ACTIVE = 1 << 16, EXPO_ACTIVE = 1 << 17, MT_DRAG_OUT = 1 << 18, - MOUSE_OVER_ACTIVE_EDGE = 1 << 19, + REVEAL_PRESSURE_PASS = 1 << 19, LAUNCHER_PULSE = 1 << 20, LOCK_HIDE = 1 << 21 } HideQuirk; + nux::Property<int> reveal_pressure; + nux::Property<int> edge_decay_rate; + + nux::Property<float> reveal_progress; + LauncherHideMachine(); virtual ~LauncherHideMachine(); void SetMode(HideMode mode); - HideMode GetMode(); + HideMode GetMode() const; - void SetShowOnEdge(bool value); - bool GetShowOnEdge(); + void AddRevealPressure(int pressure); void SetQuirk(HideQuirk quirk, bool active); - bool GetQuirk(HideQuirk quirk, bool allow_partial = true); + bool GetQuirk(HideQuirk quirk, bool allow_partial = true) const; - bool ShouldHide(); + bool ShouldHide() const; sigc::signal<void, bool> should_hide_changed; - std::string DebugHideQuirks(); + std::string DebugHideQuirks() const; private: void EnsureHideState(bool skip_delay); @@ -85,9 +91,12 @@ private: static gboolean OnHideDelayTimeout(gpointer data); static gboolean EmitShouldHideChanged(gpointer data); + void OnDecayRateChanged (int value); + + unity::ui::Decaymulator::Ptr decaymulator_; + bool _should_hide; bool _latest_emit_should_hide; - bool _show_on_edge; HideQuirk _quirks; HideMode _mode; unsigned int _hide_delay_timeout_length; diff --git a/plugins/unityshell/src/LauncherIcon.cpp b/plugins/unityshell/src/LauncherIcon.cpp index cdfbd8b52..0addde9ce 100644 --- a/plugins/unityshell/src/LauncherIcon.cpp +++ b/plugins/unityshell/src/LauncherIcon.cpp @@ -33,6 +33,7 @@ #include "CairoTexture.h" #include "LauncherIcon.h" #include "Launcher.h" +#include "TimeUtil.h" #include "QuicklistManager.h" #include "QuicklistMenuItem.h" @@ -69,12 +70,9 @@ QuicklistView* LauncherIcon::_current_quicklist = 0; int LauncherIcon::_current_theme_is_mono = -1; GtkIconTheme* LauncherIcon::_unity_theme = NULL; -gboolean LauncherIcon::_skip_tooltip_delay = false; -LauncherIcon::LauncherIcon(Launcher* launcher) - : _launcher(launcher) - , _menuclient_dynamic_quicklist(nullptr) - , _has_visible_window(false) +LauncherIcon::LauncherIcon() + : _menuclient_dynamic_quicklist(nullptr) , _quicklist_is_initialized(false) , _remote_urgent(false) , _present_urgency(0) @@ -82,14 +80,19 @@ LauncherIcon::LauncherIcon(Launcher* launcher) , _center_stabilize_handle(0) , _present_time_handle(0) , _time_delay_handle(0) - , _tooltip_delay_handle(0) - , _related_windows(0) , _sort_priority(0) , _background_color(nux::color::White) , _glow_color(nux::color::White) , _shortcut(0) , _icon_type(TYPE_NONE) { + _has_visible_window.resize(max_num_monitors); + _center.resize(max_num_monitors); + _saved_center.resize(max_num_monitors); + _last_stable.resize(max_num_monitors); + _parent_geo.resize(max_num_monitors); + transform_map.resize(max_num_monitors); + for (int i = 0; i < QUIRK_LAST; i++) { _quirks[i] = false; @@ -141,9 +144,6 @@ LauncherIcon::~LauncherIcon() g_source_remove(_time_delay_handle); _time_delay_handle = 0; - if (_tooltip_delay_handle) - g_source_remove(_tooltip_delay_handle); - _tooltip_delay_handle = 0; // clean up the whole signal-callback mess if (needs_redraw_connection.connected()) needs_redraw_connection.disconnect(); @@ -168,9 +168,9 @@ LauncherIcon::~LauncherIcon() } const bool -LauncherIcon::HasWindowOnViewport() +LauncherIcon::WindowVisibleOnMonitor(int monitor) { - return _has_visible_window; + return _has_visible_window[monitor]; } std::string @@ -183,10 +183,10 @@ void LauncherIcon::AddProperties(GVariantBuilder* builder) { unity::variant::BuilderWrapper(builder) - .add("x", _center.x) - .add("y", _center.y) - .add("z", _center.z) - .add("related-windows", _related_windows) + .add("x", _center[0].x) + .add("y", _center[0].y) + .add("z", _center[0].z) + .add("related-windows", (int)Windows().size()) .add("icon-type", _icon_type) .add("tooltip-text", tooltip_text().c_str()) .add("sort-priority", _sort_priority) @@ -206,6 +206,8 @@ LauncherIcon::Activate(ActionArg arg) WindowManager::Default()->TerminateScale(); ActivateLauncherIcon(arg); + + UpdateQuirkTime(QUIRK_LAST_ACTION); } void @@ -215,6 +217,8 @@ LauncherIcon::OpenInstance(ActionArg arg) WindowManager::Default()->TerminateScale(); OpenInstanceLauncherIcon(arg); + + UpdateQuirkTime(QUIRK_LAST_ACTION); } nux::Color LauncherIcon::BackgroundColor() @@ -479,71 +483,51 @@ LauncherIcon::GetShortcut() } void -LauncherIcon::SetSkipTooltipDelay(gboolean skip_tooltip_delay) -{ - _skip_tooltip_delay = skip_tooltip_delay; -} - -gboolean -LauncherIcon::OnTooltipTimeout(gpointer data) +LauncherIcon::ShowTooltip() { - LauncherIcon* self = (LauncherIcon*) data; - - if (!self->_launcher) - return FALSE; - - nux::Geometry geo = self->_launcher->GetAbsoluteGeometry(); - int tip_x = geo.x + geo.width + 1; - int tip_y = geo.y + self->_center.y; - - self->_tooltip->ShowTooltipWithTipAt(tip_x, tip_y); + if (_quicklist->IsVisible()) + return; - if (!self->_quicklist->IsVisible()) + int tip_x = 100; + int tip_y = 100; + if (_last_monitor >= 0) { - self->_tooltip->ShowWindow(!self->tooltip_text().empty()); - _skip_tooltip_delay = TRUE; + nux::Geometry geo = _parent_geo[_last_monitor]; + tip_x = geo.x + geo.width + 1; + tip_y = geo.y + _center[_last_monitor].y; } - self->_tooltip_delay_handle = 0; - return FALSE; + _tooltip->ShowTooltipWithTipAt(tip_x, tip_y); + _tooltip->ShowWindow(!tooltip_text().empty()); } void -LauncherIcon::RecvMouseEnter() +LauncherIcon::RecvMouseEnter(int monitor) { + _last_monitor = monitor; if (QuicklistManager::Default()->Current()) { // A quicklist is active return; } - if (!_skip_tooltip_delay) - _tooltip_delay_handle = g_timeout_add(500, &LauncherIcon::OnTooltipTimeout, this); - else - OnTooltipTimeout(this); + ShowTooltip(); } -void LauncherIcon::RecvMouseLeave() +void LauncherIcon::RecvMouseLeave(int monitor) { - if (_tooltip_delay_handle) - g_source_remove(_tooltip_delay_handle); - _tooltip_delay_handle = 0; + _last_monitor = -1; _tooltip->ShowWindow(false); } -bool LauncherIcon::OpenQuicklist(bool default_to_first_item) +bool LauncherIcon::OpenQuicklist(bool default_to_first_item, int monitor) { std::list<DbusmenuMenuitem*> menus = Menus(); if (menus.empty()) return false; - if (_tooltip_delay_handle) - g_source_remove(_tooltip_delay_handle); - _tooltip_delay_handle = 0; - _skip_tooltip_delay = false; - _tooltip->ShowWindow(false); _quicklist->RemoveAllMenuItem(); @@ -582,19 +566,18 @@ bool LauncherIcon::OpenQuicklist(bool default_to_first_item) if (default_to_first_item) _quicklist->DefaultToFirstItem(); - int tip_x, tip_y; - if (_launcher) + if (monitor < 0) { - nux::Geometry geo = _launcher->GetAbsoluteGeometry(); - tip_x = geo.x + geo.width + 1; - tip_y = geo.y + _center.y; - } - else - { - tip_x = 0; - tip_y = _center.y; + if (_last_monitor >= 0) + monitor = _last_monitor; + else + monitor = 0; } + nux::Geometry geo = _parent_geo[monitor]; + int tip_x = geo.x + geo.width + 1; + int tip_y = geo.y + _center[monitor].y; + auto win_manager = WindowManager::Default(); if (win_manager->IsScaleActive()) @@ -617,13 +600,13 @@ bool LauncherIcon::OpenQuicklist(bool default_to_first_item) return true; } -void LauncherIcon::RecvMouseDown(int button) +void LauncherIcon::RecvMouseDown(int button, int monitor) { if (button == 3) OpenQuicklist(); } -void LauncherIcon::RecvMouseUp(int button) +void LauncherIcon::RecvMouseUp(int button, int monitor) { if (button == 3) { @@ -632,9 +615,11 @@ void LauncherIcon::RecvMouseUp(int button) } } -void LauncherIcon::RecvMouseClick(int button) +void LauncherIcon::RecvMouseClick(int button, int monitor) { ActionArg arg(ActionArg::LAUNCHER, button); + arg.monitor = monitor; + if (button == 1) Activate(arg); else if (button == 2) @@ -643,11 +628,6 @@ void LauncherIcon::RecvMouseClick(int button) void LauncherIcon::HideTooltip() { - if (_tooltip_delay_handle) - g_source_remove(_tooltip_delay_handle); - _tooltip_delay_handle = 0; - _skip_tooltip_delay = false; - _tooltip->ShowWindow(false); } @@ -656,7 +636,7 @@ LauncherIcon::OnCenterTimeout(gpointer data) { LauncherIcon* self = (LauncherIcon*)data; - if (self->_last_stable != self->_center) + if (!std::equal(self->_center.begin(), self->_center.end(), self->_last_stable.begin())) { self->OnCenterStabilized(self->_center); self->_last_stable = self->_center; @@ -667,27 +647,22 @@ LauncherIcon::OnCenterTimeout(gpointer data) } void -LauncherIcon::SetCenter(nux::Point3 center) +LauncherIcon::SetCenter(nux::Point3 center, int monitor, nux::Geometry geo) { - _center = center; + _center[monitor] = center; + _parent_geo[monitor] = geo; - int tip_x, tip_y; - if (_launcher) + if (monitor == _last_monitor) { - nux::Geometry geo = _launcher->GetAbsoluteGeometry(); + int tip_x, tip_y; tip_x = geo.x + geo.width + 1; - tip_y = geo.y + _center.y; - } - else - { - tip_x = 0; - tip_y = _center.y; - } + tip_y = geo.y + _center[monitor].y; - if (_quicklist->IsVisible()) - QuicklistManager::Default()->ShowQuicklist(_quicklist, tip_x, tip_y); - else if (_tooltip->IsVisible()) - _tooltip->ShowTooltipWithTipAt(tip_x, tip_y); + if (_quicklist->IsVisible()) + QuicklistManager::Default()->ShowQuicklist(_quicklist, tip_x, tip_y); + else if (_tooltip->IsVisible()) + _tooltip->ShowTooltipWithTipAt(tip_x, tip_y); + } if (_center_stabilize_handle) g_source_remove(_center_stabilize_handle); @@ -696,7 +671,18 @@ LauncherIcon::SetCenter(nux::Point3 center) } nux::Point3 -LauncherIcon::GetCenter() +LauncherIcon::GetCenter(int monitor) +{ + return _center[monitor]; +} + +nux::Point3 +LauncherIcon::GetSavedCenter(int monitor) +{ + return _saved_center[monitor]; +} + +std::vector<nux::Point3> LauncherIcon::GetCenters() { return _center; } @@ -709,12 +695,12 @@ LauncherIcon::SaveCenter() } void -LauncherIcon::SetHasWindowOnViewport(bool val) +LauncherIcon::SetWindowVisibleOnMonitor(bool val, int monitor) { - if (_has_visible_window == val) + if (_has_visible_window[monitor] == val) return; - _has_visible_window = val; + _has_visible_window[monitor] = val; needs_redraw.emit(this); } @@ -763,16 +749,6 @@ LauncherIcon::Unpresent() } void -LauncherIcon::SetRelatedWindows(int windows) -{ - if (_related_windows == windows) - return; - - _related_windows = windows; - needs_redraw.emit(this); -} - -void LauncherIcon::Remove() { if (_quicklist->IsVisible()) @@ -817,13 +793,10 @@ LauncherIcon::SetQuirk(LauncherIcon::Quirk quirk, bool value) { if (_quirks[quirk] == value) return; - - if (quirk == QUIRK_PULSE_ONCE) - _launcher->HideMachine()->SetQuirk(LauncherHideMachine::LAUNCHER_PULSE, value); _quirks[quirk] = value; if (quirk == QUIRK_VISIBLE) - Launcher::SetTimeStruct(&(_quirk_times[quirk]), &(_quirk_times[quirk]), ANIM_DURATION_SHORT); + TimeUtil::SetTimeStruct(&(_quirk_times[quirk]), &(_quirk_times[quirk]), ANIM_DURATION_SHORT); else clock_gettime(CLOCK_MONOTONIC, &(_quirk_times[quirk])); needs_redraw.emit(this); @@ -887,12 +860,6 @@ LauncherIcon::GetQuirkTime(LauncherIcon::Quirk quirk) return _quirk_times[quirk]; } -int -LauncherIcon::RelatedWindows() -{ - return _related_windows; -} - void LauncherIcon::SetProgress(float progress) { @@ -949,12 +916,12 @@ LauncherIcon::SetEmblemIconName(const char* name) } std::vector<nux::Vector4> & -LauncherIcon::GetTransform(TransformIndex index) +LauncherIcon::GetTransform(TransformIndex index, int monitor) { - auto iter = transform_map.find(index); - if (iter == transform_map.end()) + auto iter = transform_map[monitor].find(index); + if (iter == transform_map[monitor].end()) { - auto iter2 = transform_map.insert(std::map<TransformIndex, std::vector<nux::Vector4> >::value_type(index, std::vector<nux::Vector4>(4))); + auto iter2 = transform_map[monitor].insert(std::map<TransformIndex, std::vector<nux::Vector4> >::value_type(index, std::vector<nux::Vector4>(4))); return iter2.first->second; } diff --git a/plugins/unityshell/src/LauncherIcon.h b/plugins/unityshell/src/LauncherIcon.h index 5d455f7a2..d6e95e435 100644 --- a/plugins/unityshell/src/LauncherIcon.h +++ b/plugins/unityshell/src/LauncherIcon.h @@ -51,6 +51,8 @@ namespace unity namespace launcher { +const int max_num_monitors = 6; + class Launcher; class LauncherIcon : public AbstractLauncherIcon @@ -60,15 +62,10 @@ class LauncherIcon : public AbstractLauncherIcon public: typedef nux::ObjectPtr<nux::BaseTexture> BaseTexturePtr; - LauncherIcon(Launcher* launcher); + LauncherIcon(); virtual ~LauncherIcon(); - Launcher* GetLauncher() - { - return _launcher; - }; - bool SetTooltipText(std::string& target, std::string const& value); void SetShortcut(guint64 shortcut); @@ -77,23 +74,25 @@ public: void SetSortPriority(int priority); - void RecvMouseEnter(); + void RecvMouseEnter(int monitor); - void RecvMouseLeave(); + void RecvMouseLeave(int monitor); - void RecvMouseDown(int button); + void RecvMouseDown(int button, int monitor); - void RecvMouseUp(int button); + void RecvMouseUp(int button, int monitor); - void RecvMouseClick(int button); + void RecvMouseClick(int button, int monitor); void HideTooltip(); - bool OpenQuicklist(bool default_to_first_item = false); + void ShowTooltip(); - void SetCenter(nux::Point3 center); + bool OpenQuicklist(bool default_to_first_item = false, int monitor = -1); - nux::Point3 GetCenter(); + void SetCenter(nux::Point3 center, int parent_monitor, nux::Geometry parent_geo); + + nux::Point3 GetCenter(int monitor); virtual void Activate(ActionArg arg); @@ -101,15 +100,17 @@ public: void SaveCenter(); + nux::Point3 GetSavedCenter(int monitor); + int SortPriority(); - int RelatedWindows(); + virtual std::vector<Window> Windows () { return std::vector<Window> (); } - virtual std::vector<Window> RelatedXids () { return std::vector<Window> (); } + virtual std::vector<Window> WindowsForMonitor (int monitor) { return std::vector<Window> (); } virtual std::string NameForWindow (Window window) { return std::string(); } - const bool HasWindowOnViewport(); + const bool WindowVisibleOnMonitor(int monitor); virtual bool IsSpacer() { @@ -126,7 +127,7 @@ public: void DeleteEmblem(); - virtual bool ShowInSwitcher() + virtual bool ShowInSwitcher(bool current) { return false; }; @@ -185,19 +186,11 @@ public: void SetIconType(IconType type); - std::vector<nux::Vector4> & GetTransform(TransformIndex index); - - static void SetSkipTooltipDelay(gboolean skip_tooltip_delay); - - sigc::signal<void, LauncherIcon*> remove; - - sigc::connection needs_redraw_connection; - sigc::connection on_icon_added_connection; - sigc::connection on_icon_removed_connection; - sigc::connection on_order_changed_connection; - sigc::connection on_expo_terminated_connection; + std::vector<nux::Vector4> & GetTransform(TransformIndex index, int monitor); protected: + std::vector<nux::Point3> GetCenters(); + std::string GetName() const; void AddProperties(GVariantBuilder* builder); @@ -208,13 +201,11 @@ protected: void ResetQuirkTime(Quirk quirk); - void SetRelatedWindows(int windows); - void Remove(); void SetProgress(float progress); - void SetHasWindowOnViewport(bool val); + void SetWindowVisibleOnMonitor(bool val, int monitor); void Present(float urgency, int length); @@ -226,7 +217,7 @@ protected: virtual nux::BaseTexture* GetTextureForSize(int size) = 0; - virtual void OnCenterStabilized(nux::Point3 center) {} + virtual void OnCenterStabilized(std::vector<nux::Point3> center) {} virtual const gchar* GetRemoteUri() { @@ -276,8 +267,6 @@ protected: void OnRemoteProgressVisibleChanged(LauncherEntryRemote* remote); - Launcher* _launcher; - nux::Tooltip* _tooltip; QuicklistView* _quicklist; @@ -304,31 +293,29 @@ private: static gboolean OnPresentTimeout(gpointer data); static gboolean OnCenterTimeout(gpointer data); static gboolean OnDelayedUpdateTimeout(gpointer data); - static gboolean OnTooltipTimeout(gpointer data); void ColorForIcon(GdkPixbuf* pixbuf, nux::Color& background, nux::Color& glow); - bool _has_visible_window; - bool _quicklist_is_initialized; - bool _remote_urgent; - float _present_urgency; - float _progress; - guint _center_stabilize_handle; - guint _present_time_handle; - guint _time_delay_handle; - guint _tooltip_delay_handle; - int _related_windows; - int _sort_priority; - nux::Color _background_color; - nux::Color _glow_color; - static gboolean _skip_tooltip_delay; - - gint64 _shortcut; - - nux::Point3 _center; - nux::Point3 _last_stable; - nux::Point3 _saved_center; - IconType _icon_type; + std::vector<bool> _has_visible_window; + bool _quicklist_is_initialized; + bool _remote_urgent; + float _present_urgency; + float _progress; + guint _center_stabilize_handle; + guint _present_time_handle; + guint _time_delay_handle; + int _sort_priority; + int _last_monitor; + nux::Color _background_color; + nux::Color _glow_color; + + gint64 _shortcut; + + std::vector<nux::Point3> _center; + std::vector<nux::Point3> _last_stable; + std::vector<nux::Point3> _saved_center; + std::vector<nux::Geometry> _parent_geo; + IconType _icon_type; static GtkIconTheme* _unity_theme; @@ -338,7 +325,7 @@ private: struct timespec _quirk_times[QUIRK_LAST]; std::list<LauncherEntryRemote*> _entry_list; - std::map<TransformIndex, std::vector<nux::Vector4> > transform_map; + std::vector<std::map<TransformIndex, std::vector<nux::Vector4> > > transform_map; }; diff --git a/plugins/unityshell/src/LauncherModel.cpp b/plugins/unityshell/src/LauncherModel.cpp index dc862b76a..fff074786 100644 --- a/plugins/unityshell/src/LauncherModel.cpp +++ b/plugins/unityshell/src/LauncherModel.cpp @@ -18,7 +18,7 @@ */ #include "LauncherModel.h" -#include "LauncherIcon.h" +#include "AbstractLauncherIcon.h" namespace unity { @@ -27,12 +27,13 @@ namespace launcher typedef struct { - LauncherIcon* icon; + AbstractLauncherIcon* icon; LauncherModel* self; } RemoveArg; LauncherModel::LauncherModel() { + selection_ = 0; } LauncherModel::~LauncherModel() @@ -44,12 +45,12 @@ LauncherModel::~LauncherModel() icon->UnReference(); } -bool LauncherModel::IconShouldShelf(LauncherIcon* icon) +bool LauncherModel::IconShouldShelf(AbstractLauncherIcon* icon) const { - return icon->Type() == LauncherIcon::TYPE_TRASH; + return icon->Type() == AbstractLauncherIcon::TYPE_TRASH; } -bool LauncherModel::CompareIcons(LauncherIcon* first, LauncherIcon* second) +bool LauncherModel::CompareIcons(AbstractLauncherIcon* first, AbstractLauncherIcon* second) { if (first->Type() < second->Type()) return true; @@ -72,27 +73,29 @@ LauncherModel::Populate() for (it = main_begin(); it != main_end(); it++) { _inner.push_back(*it); - (*it)->SetSortPriority(i++); + (*it)->SetSortPriority(i); + ++i; } for (it = shelf_begin(); it != shelf_end(); it++) { _inner.push_back(*it); - (*it)->SetSortPriority(i++); + (*it)->SetSortPriority(i); + ++i; } - return !std::equal(begin(), end(), copy.begin()); + return copy.size() == _inner.size() && !std::equal(begin(), end(), copy.begin()); } void -LauncherModel::AddIcon(LauncherIcon* icon) +LauncherModel::AddIcon(AbstractLauncherIcon* icon) { icon->SinkReference(); if (IconShouldShelf(icon)) - _inner_shelf.push_front(icon); + _inner_shelf.push_back(icon); else - _inner_main.push_front(icon); + _inner_main.push_back(icon); Sort(); @@ -104,15 +107,15 @@ LauncherModel::AddIcon(LauncherIcon* icon) } void -LauncherModel::RemoveIcon(LauncherIcon* icon) +LauncherModel::RemoveIcon(AbstractLauncherIcon* icon) { size_t size; - _inner_shelf.remove(icon); - _inner_main.remove(icon); + _inner_shelf.erase(std::remove(_inner_shelf.begin(), _inner_shelf.end(), icon), _inner_shelf.end()); + _inner_main.erase(std::remove(_inner_main.begin(), _inner_main.end(), icon), _inner_main.end()); size = _inner.size(); - _inner.remove(icon); + _inner.erase(std::remove(_inner.begin(), _inner.end(), icon), _inner.end()); if (size != _inner.size()) { @@ -133,7 +136,7 @@ LauncherModel::RemoveCallback(gpointer data) } void -LauncherModel::OnIconRemove(LauncherIcon* icon) +LauncherModel::OnIconRemove(AbstractLauncherIcon* icon) { RemoveArg* arg = (RemoveArg*) g_malloc0(sizeof(RemoveArg)); arg->icon = icon; @@ -151,36 +154,36 @@ LauncherModel::Save() void LauncherModel::Sort() { - _inner_shelf.sort(&LauncherModel::CompareIcons); - _inner_main.sort(&LauncherModel::CompareIcons); + std::stable_sort(_inner_shelf.begin(), _inner_shelf.end(), &LauncherModel::CompareIcons); + std::stable_sort(_inner_main.begin(), _inner_main.end(), &LauncherModel::CompareIcons); if (Populate()) order_changed.emit(); } bool -LauncherModel::IconHasSister(LauncherIcon* icon) +LauncherModel::IconHasSister(AbstractLauncherIcon* icon) const { - iterator it; - iterator end; + const_iterator it; + const_iterator end; if (icon && icon->Type() == AbstractLauncherIcon::TYPE_DEVICE) return true; if (IconShouldShelf(icon)) { - it = shelf_begin(); - end = shelf_end(); + it = _inner_shelf.begin(); + end = _inner_shelf.end(); } else { - it = main_begin(); - end = main_end(); + it = _inner_main.begin(); + end = _inner_main.end(); } for (; it != end; ++it) { - LauncherIcon* iter_icon = *it; + AbstractLauncherIcon* iter_icon = *it; if ((iter_icon != icon) && iter_icon->Type() == icon->Type()) return true; @@ -190,40 +193,68 @@ LauncherModel::IconHasSister(LauncherIcon* icon) } void -LauncherModel::ReorderBefore(LauncherIcon* icon, LauncherIcon* other, bool save) +LauncherModel::ReorderAfter(AbstractLauncherIcon* icon, AbstractLauncherIcon* 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(AbstractLauncherIcon* icon, AbstractLauncherIcon* 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++; @@ -233,53 +264,51 @@ LauncherModel::ReorderBefore(LauncherIcon* icon, LauncherIcon* other, bool save) } void -LauncherModel::ReorderSmart(LauncherIcon* icon, LauncherIcon* other, bool save) +LauncherModel::ReorderSmart(AbstractLauncherIcon* icon, AbstractLauncherIcon* 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++; @@ -289,11 +318,73 @@ LauncherModel::ReorderSmart(LauncherIcon* icon, LauncherIcon* other, bool save) } int -LauncherModel::Size() +LauncherModel::Size() const { return _inner.size(); } +AbstractLauncherIcon* LauncherModel::Selection () const +{ + return _inner[selection_]; +} + +int LauncherModel::SelectionIndex() const +{ + return selection_; +} + +void LauncherModel::SetSelection(int selection) +{ + int new_selection = std::min<int>(Size() - 1, std::max<int> (0, selection)); + + if (new_selection == selection_) + return; + + selection_ = new_selection; + selection_changed.emit(Selection()); +} + +void LauncherModel::SelectNext() +{ + int temp = selection_; + + temp++; + while (temp != selection_) + { + if (temp >= Size()) + temp = 0; + + if (_inner[temp]->GetQuirk(AbstractLauncherIcon::QUIRK_VISIBLE)) + { + selection_ = temp; + selection_changed.emit(Selection()); + break; + } + temp++; + } +} + +void LauncherModel::SelectPrevious() +{ + int temp = selection_; + + temp--; + while (temp != selection_) + { + if (temp < 0) + temp = Size() - 1; + + if (_inner[temp]->GetQuirk(AbstractLauncherIcon::QUIRK_VISIBLE)) + { + selection_ = temp; + selection_changed.emit(Selection()); + break; + } + temp--; + } +} + + /* iterators */ LauncherModel::iterator diff --git a/plugins/unityshell/src/LauncherModel.h b/plugins/unityshell/src/LauncherModel.h index fa27fb011..bbf80d45e 100644 --- a/plugins/unityshell/src/LauncherModel.h +++ b/plugins/unityshell/src/LauncherModel.h @@ -22,7 +22,7 @@ #include <memory> -#include "LauncherIcon.h" +#include "AbstractLauncherIcon.h" #include <sigc++/sigc++.h> namespace unity @@ -34,26 +34,35 @@ class LauncherModel : public sigc::trackable { public: typedef std::shared_ptr<LauncherModel> Ptr; - typedef std::list<LauncherIcon*> Base; + typedef std::vector<AbstractLauncherIcon*> Base; typedef Base::iterator iterator; + typedef Base::const_iterator const_iterator; typedef Base::reverse_iterator reverse_iterator; + typedef Base::reverse_iterator const_reverse_iterator; LauncherModel(); ~LauncherModel(); - void AddIcon(LauncherIcon* icon); - void RemoveIcon(LauncherIcon* icon); + void AddIcon(AbstractLauncherIcon* icon); + void RemoveIcon(AbstractLauncherIcon* icon); void Save(); void Sort(); - int Size(); + int Size() const; - void OnIconRemove(LauncherIcon* icon); + void OnIconRemove(AbstractLauncherIcon* icon); - bool IconHasSister(LauncherIcon* icon); + bool IconHasSister(AbstractLauncherIcon* icon) const; - void ReorderBefore(LauncherIcon* icon, LauncherIcon* other, bool save); + void ReorderAfter(AbstractLauncherIcon* icon, AbstractLauncherIcon* other); + void ReorderBefore(AbstractLauncherIcon* icon, AbstractLauncherIcon* other, bool save); - void ReorderSmart(LauncherIcon* icon, LauncherIcon* other, bool save); + void ReorderSmart(AbstractLauncherIcon* icon, AbstractLauncherIcon* other, bool save); + + AbstractLauncherIcon* Selection() const; + int SelectionIndex() const; + void SetSelection(int selection); + void SelectNext(); + void SelectPrevious(); iterator begin(); iterator end(); @@ -71,28 +80,25 @@ public: reverse_iterator shelf_rbegin(); reverse_iterator shelf_rend(); - sigc::signal<void, LauncherIcon*> icon_added; - sigc::signal<void, LauncherIcon*> icon_removed; + sigc::signal<void, AbstractLauncherIcon*> icon_added; + sigc::signal<void, AbstractLauncherIcon*> icon_removed; sigc::signal<void> order_changed; sigc::signal<void> saved; - - // connected to from class Launcher - sigc::connection on_icon_added_connection; - sigc::connection on_icon_removed_connection; - sigc::connection on_order_changed_connection; - + sigc::signal<void, AbstractLauncherIcon*> selection_changed; + private: Base _inner; Base _inner_shelf; Base _inner_main; + int selection_; bool Populate(); - bool IconShouldShelf(LauncherIcon* icon); + bool IconShouldShelf(AbstractLauncherIcon* icon) const; static gboolean RemoveCallback(gpointer data); - static bool CompareIcons(LauncherIcon* first, LauncherIcon* second); + static bool CompareIcons(AbstractLauncherIcon* first, AbstractLauncherIcon* second); /* Template Methods */ public: diff --git a/plugins/unityshell/src/LauncherOptions.cpp b/plugins/unityshell/src/LauncherOptions.cpp new file mode 100644 index 000000000..edf15e267 --- /dev/null +++ b/plugins/unityshell/src/LauncherOptions.cpp @@ -0,0 +1,97 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2010, 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: Jason Smith <jason.smith@canonical.com> + * Tim Penhey <tim.penhey@canonical.com> + */ + +#include "LauncherOptions.h" + +namespace unity +{ +namespace launcher +{ + +Options::Options() +{ + hide_mode.changed.connect(sigc::mem_fun (this, &Options::OnHideModeChanged)); + launch_animation.changed.connect(sigc::mem_fun (this, &Options::OnLaunchAnimationChanged)); + urgent_animation.changed.connect(sigc::mem_fun (this, &Options::OnUrgentAnimationChanged)); + auto_hide_animation.changed.connect(sigc::mem_fun (this, &Options::OnAutoHideAnimationChanged)); + backlight_mode.changed.connect(sigc::mem_fun (this, &Options::OnBacklightModeChanged)); + icon_size.changed.connect(sigc::mem_fun (this, &Options::OnIconSizeChanged)); + tile_size.changed.connect(sigc::mem_fun (this, &Options::OnTileSizeChanged)); + floating.changed.connect(sigc::mem_fun (this, &Options::OnFloatingChanged)); + background_alpha.changed.connect(sigc::mem_fun (this, &Options::OnBackgroundAlphaChanged)); + edge_decay_rate.changed.connect(sigc::mem_fun (this, &Options::OnEdgeOptionChanged)); + edge_overcome_pressure.changed.connect(sigc::mem_fun (this, &Options::OnEdgeOptionChanged)); + edge_stop_velocity.changed.connect(sigc::mem_fun (this, &Options::OnEdgeOptionChanged)); + edge_reveal_pressure.changed.connect(sigc::mem_fun (this, &Options::OnEdgeOptionChanged)); +} + +void Options::OnEdgeOptionChanged(int value) +{ + option_changed.emit(); +} + +void Options::OnHideModeChanged(LauncherHideMode value) +{ + option_changed.emit(); +} + +void Options::OnLaunchAnimationChanged(LaunchAnimation value) +{ + option_changed.emit(); +} + +void Options::OnUrgentAnimationChanged(UrgentAnimation value) +{ + option_changed.emit(); +} + +void Options::OnAutoHideAnimationChanged(AutoHideAnimation value) +{ + option_changed.emit(); +} + +void Options::OnBacklightModeChanged(BacklightMode value) +{ + option_changed.emit(); +} + +void Options::OnIconSizeChanged(int value) +{ + option_changed.emit(); +} + +void Options::OnTileSizeChanged(int value) +{ + option_changed.emit(); +} + +void Options::OnFloatingChanged(bool value) +{ + option_changed.emit(); +} + +void Options::OnBackgroundAlphaChanged(float value) +{ + option_changed.emit(); +} + + +} +} \ No newline at end of file diff --git a/plugins/unityshell/src/LauncherOptions.h b/plugins/unityshell/src/LauncherOptions.h new file mode 100644 index 000000000..bd042b7f2 --- /dev/null +++ b/plugins/unityshell/src/LauncherOptions.h @@ -0,0 +1,114 @@ +// -*- 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: Jason Smith <jason.smith@canonical.com> + * Tim Penhey <tim.penhey@canonical.com> + */ + +#ifndef LAUNCHEROPTIONS_H +#define LAUNCHEROPTIONS_H + +#include <memory> +#include <vector> +#include <sigc++/sigc++.h> +#include <core/core.h> + +#include <Nux/Nux.h> + +namespace unity +{ +namespace launcher +{ + +typedef enum +{ + LAUNCHER_HIDE_NEVER, + LAUNCHER_HIDE_AUTOHIDE, + LAUNCHER_HIDE_DODGE_WINDOWS, + LAUNCHER_HIDE_DODGE_ACTIVE_WINDOW, +} LauncherHideMode; + +typedef enum +{ + LAUNCH_ANIMATION_NONE, + LAUNCH_ANIMATION_PULSE, + LAUNCH_ANIMATION_BLINK, +} LaunchAnimation; + +typedef enum +{ + URGENT_ANIMATION_NONE, + URGENT_ANIMATION_PULSE, + URGENT_ANIMATION_WIGGLE, +} UrgentAnimation; + +typedef enum +{ + FADE_OR_SLIDE, + SLIDE_ONLY, + FADE_ONLY, + FADE_AND_SLIDE, +} AutoHideAnimation; + +typedef enum +{ + BACKLIGHT_ALWAYS_ON, + BACKLIGHT_NORMAL, + BACKLIGHT_ALWAYS_OFF, + BACKLIGHT_EDGE_TOGGLE, + BACKLIGHT_NORMAL_EDGE_TOGGLE +} BacklightMode; + +class Options : public sigc::trackable +{ +public: + typedef std::shared_ptr<Options> Ptr; + + Options(); + + nux::Property<LauncherHideMode> hide_mode; + nux::Property<LaunchAnimation> launch_animation; + nux::Property<UrgentAnimation> urgent_animation; + nux::Property<AutoHideAnimation> auto_hide_animation; + nux::Property<BacklightMode> backlight_mode; + nux::Property<int> icon_size; + nux::Property<int> tile_size; + nux::Property<bool> floating; + nux::Property<float> background_alpha; + nux::Property<int> edge_decay_rate; + nux::Property<int> edge_overcome_pressure; + nux::Property<int> edge_stop_velocity; + nux::Property<int> edge_reveal_pressure; + + sigc::signal<void> option_changed; + +private: + void OnHideModeChanged(LauncherHideMode value); + void OnLaunchAnimationChanged(LaunchAnimation value); + void OnUrgentAnimationChanged(UrgentAnimation value); + void OnAutoHideAnimationChanged(AutoHideAnimation value); + void OnBacklightModeChanged(BacklightMode value); + void OnIconSizeChanged(int value); + void OnEdgeOptionChanged(int value); + void OnTileSizeChanged(int value); + void OnFloatingChanged(bool value); + void OnBackgroundAlphaChanged(float value); +}; + +} +} + +#endif // LAUNCHEROPTIONS_H diff --git a/plugins/unityshell/src/LensBar.cpp b/plugins/unityshell/src/LensBar.cpp index 23bf429b9..c59fdb683 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/MockLauncherIcon.h b/plugins/unityshell/src/MockLauncherIcon.h index f8cba68a2..835a54197 100644 --- a/plugins/unityshell/src/MockLauncherIcon.h +++ b/plugins/unityshell/src/MockLauncherIcon.h @@ -27,6 +27,8 @@ #include <Nux/BaseWindow.h> #include <Nux/View.h> +#include <gtk/gtk.h> + #include <sigc++/sigc++.h> #include <libdbusmenu-glib/menuitem.h> @@ -45,6 +47,9 @@ public: : icon_(0) { tooltip_text = "Mock Icon"; + transform_map.resize(10); + sort_priority_ = 0; + type_ = TYPE_APPLICATION; } std::string GetName() const { return "MockLauncherIcon"; } @@ -60,7 +65,23 @@ public: return 0; } - std::vector<Window> RelatedXids () + std::vector<Window> Windows () + { + std::vector<Window> result; + + result.push_back ((100 << 16) + 200); + result.push_back ((500 << 16) + 200); + result.push_back ((300 << 16) + 200); + result.push_back ((200 << 16) + 200); + result.push_back ((300 << 16) + 200); + result.push_back ((100 << 16) + 200); + result.push_back ((300 << 16) + 200); + result.push_back ((600 << 16) + 200); + + return result; + } + + std::vector<Window> WindowsForMonitor (int monitor) { std::vector<Window> result; @@ -81,26 +102,37 @@ public: return std::string(); } - void SetSortPriority(int priority) {} + void SetSortPriority(int priority) { sort_priority_ = priority; } - bool OpenQuicklist(bool default_to_first_item = false) + bool OpenQuicklist(bool default_to_first_item = false, int monitor = -1) { return false; } - void SetCenter(nux::Point3 center) {} + void SetCenter(nux::Point3 center, int monitor, nux::Geometry geo) {} - nux::Point3 GetCenter() + nux::Point3 GetCenter(int monitor) { return nux::Point3(); } - std::vector<nux::Vector4> & GetTransform(TransformIndex index) + nux::Point3 GetSavedCenter(int monitor) + { + return nux::Point3(); + } + + void SaveCenter() {} + + std::vector<nux::Vector4> & GetTransform(TransformIndex index, int monitor) { - if (transform_map.find(index) == transform_map.end()) - transform_map[index] = std::vector<nux::Vector4> (4); + auto iter = transform_map[monitor].find(index); + if (iter == transform_map[monitor].end()) + { + auto iter2 = transform_map[monitor].insert(std::map<TransformIndex, std::vector<nux::Vector4> >::value_type(index, std::vector<nux::Vector4>(4))); + return iter2.first->second; + } - return transform_map[index]; + return iter->second; } void Activate(ActionArg arg) {} @@ -109,7 +141,7 @@ public: int SortPriority() { - return 0; + return sort_priority_; } int RelatedWindows() @@ -117,7 +149,7 @@ public: return 7; } - const bool HasWindowOnViewport() + const bool WindowVisibleOnMonitor(int monitor) { return false; } @@ -137,11 +169,15 @@ public: return 0.0f; } - bool ShowInSwitcher() + bool ShowInSwitcher(bool current) { return true; } + void InsertEntryRemote(LauncherEntryRemote* remote) {} + + void RemoveEntryRemote(LauncherEntryRemote* remote) {} + unsigned long long SwitcherPriority() { return 0; @@ -154,6 +190,8 @@ public: void SetQuirk(Quirk quirk, bool value) {} + void ResetQuirkTime(Quirk quirk) {}; + struct timespec GetQuirkTime(Quirk quirk) { timespec tv; @@ -162,7 +200,7 @@ public: IconType Type() { - return TYPE_APPLICATION; + return type_; } nux::Color BackgroundColor() @@ -263,9 +301,10 @@ private: } - std::map<TransformIndex, std::vector<nux::Vector4> > transform_map; + std::vector<std::map<TransformIndex, std::vector<nux::Vector4> > > transform_map; nux::BaseTexture* icon_; - + int sort_priority_; + IconType type_; }; } diff --git a/plugins/unityshell/src/OverlayRenderer.cpp b/plugins/unityshell/src/OverlayRenderer.cpp index f976ee073..d0cecee8c 100644 --- a/plugins/unityshell/src/OverlayRenderer.cpp +++ b/plugins/unityshell/src/OverlayRenderer.cpp @@ -277,8 +277,8 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c texxform_absolute_bg.flip_v_coord = false; - texxform_absolute_bg.uoffset = (1.0f / bg_shine_texture_->GetWidth()) * (absolute_geo.x); - texxform_absolute_bg.voffset = (1.0f / bg_shine_texture_->GetHeight()) * (absolute_geo.y); + texxform_absolute_bg.uoffset = (1.0f / bg_shine_texture_->GetWidth()) * parent->x_offset; + texxform_absolute_bg.voffset = (1.0f / bg_shine_texture_->GetHeight()) * parent->y_offset; gfx_context.GetRenderStates().SetColorMask(true, true, true, false); gfx_context.GetRenderStates().SetBlend(true, GL_DST_COLOR, GL_ONE); @@ -384,8 +384,8 @@ void OverlayRendererImpl::DrawContent(nux::GraphicsEngine& gfx_context, nux::Geo rop.SrcBlend = GL_DST_COLOR; rop.DstBlend = GL_ONE; texxform_absolute_bg.flip_v_coord = false; - texxform_absolute_bg.uoffset = (1.0f / bg_shine_texture_->GetWidth()) * (absolute_geo.x); - texxform_absolute_bg.voffset = (1.0f / bg_shine_texture_->GetHeight()) * (absolute_geo.y); + texxform_absolute_bg.uoffset = (1.0f / bg_shine_texture_->GetWidth()) * parent->x_offset; + texxform_absolute_bg.voffset = (1.0f / bg_shine_texture_->GetHeight()) * parent->y_offset; nux::GetPainter().PushTextureLayer(gfx_context, bg_layer_->GetGeometry(), bg_shine_texture_, diff --git a/plugins/unityshell/src/OverlayRenderer.h b/plugins/unityshell/src/OverlayRenderer.h index ba41c22b2..f4bd624f1 100644 --- a/plugins/unityshell/src/OverlayRenderer.h +++ b/plugins/unityshell/src/OverlayRenderer.h @@ -36,6 +36,9 @@ public: // We only ever want one OverlayRenderer per view, so if you must take a pointer, take this unique one that will die // when it goes out of scope typedef std::unique_ptr<OverlayRenderer> Ptr; + + nux::Property<int> x_offset; + nux::Property<int> y_offset; OverlayRenderer(); ~OverlayRenderer(); 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 c7a1f61d9..facfcb55f 100644 --- a/plugins/unityshell/src/PanelView.cpp +++ b/plugins/unityshell/src/PanelView.cpp @@ -182,7 +182,7 @@ void PanelView::OnDashHidden(GVariant* data, PanelView* self) void PanelView::OnDashShown(GVariant* data, PanelView* self) { - if (self->_is_primary) + if (self->_monitor == g_variant_get_int32(data)) { self->bg_effect_helper_.enabled = true; self->_dash_is_open = true; @@ -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 b631a5e59..a1be6b336 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 1bc3e0dd2..82e18fd92 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; @@ -569,10 +572,11 @@ PluginAdapter::Lower(guint32 xid) } void -PluginAdapter::FocusWindowGroup(std::vector<Window> window_ids, FocusVisibility focus_visibility) +PluginAdapter::FocusWindowGroup(std::vector<Window> window_ids, FocusVisibility focus_visibility, int monitor) { CompPoint target_vp = m_Screen->vp(); - CompWindow* top_win = NULL; + CompWindow* top_window = NULL; + CompWindow* top_window_on_monitor = NULL; bool any_on_current = false; bool any_mapped = false; bool forced_unminimize = false; @@ -629,7 +633,9 @@ PluginAdapter::FocusWindowGroup(std::vector<Window> window_ids, FocusVisibility win->mapNum () == 0)) { bool is_mapped = win->mapNum () != 0; - top_win = win; + top_window = win; + if (monitor >= 0 && win->outputDevice() == monitor) + top_window_on_monitor = win; win->unminimize (); forced_unminimize = true; @@ -643,14 +649,18 @@ PluginAdapter::FocusWindowGroup(std::vector<Window> window_ids, FocusVisibility if (!forced_unminimize || target_vp == m_Screen->vp()) { win->raise(); - top_win = win; + top_window = win; + if (monitor >= 0 && win->outputDevice() == monitor) + top_window_on_monitor = win; } } } } - if (top_win) - top_win->activate(); + if (monitor > 0 && top_window_on_monitor) + top_window_on_monitor->activate(); + else if (top_window) + top_window->activate(); } bool @@ -923,6 +933,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/PluginAdapter.h b/plugins/unityshell/src/PluginAdapter.h index 153fe563c..8071a3a4a 100644 --- a/plugins/unityshell/src/PluginAdapter.h +++ b/plugins/unityshell/src/PluginAdapter.h @@ -128,7 +128,7 @@ public: void SetWindowIconGeometry(Window window, nux::Geometry const& geo); - void FocusWindowGroup(std::vector<Window> windows, FocusVisibility); + void FocusWindowGroup(std::vector<Window> windows, FocusVisibility, int monitor = -1); bool ScaleWindowGroup(std::vector<Window> windows, int state, bool force); bool IsScreenGrabbed(); diff --git a/plugins/unityshell/src/PointerBarrier.cpp b/plugins/unityshell/src/PointerBarrier.cpp new file mode 100644 index 000000000..2e48dbfef --- /dev/null +++ b/plugins/unityshell/src/PointerBarrier.cpp @@ -0,0 +1,173 @@ +// -*- 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/>. +*/ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <X11/extensions/Xfixes.h> + +#include "PointerBarrier.h" + +namespace unity +{ +namespace ui +{ + +namespace local +{ +namespace +{ + bool is_selected_for = false; +} +} + +PointerBarrierWrapper::PointerBarrierWrapper() +{ + last_event_ = 0; + last_y_ = 0; + last_x_ = 0; + active = false; + smoothing = 75; + smoothing_count_ = 0; + smoothing_accum_ = 0; +} + +void PointerBarrierWrapper::ConstructBarrier() +{ + if (active) + return; + + Display *dpy = nux::GetGraphicsDisplay()->GetX11Display(); + + XFixesQueryExtension(dpy, &event_base_, &error_base_); + + int maj,min; + XFixesQueryVersion(dpy, &maj, &min); + + barrier = XFixesCreatePointerBarrierVelocity(dpy, + DefaultRootWindow(dpy), + x1, y1, + x2, y2, + 0, + threshold, + 0, + NULL); + + if (!local::is_selected_for) + { + XFixesSelectBarrierInput(dpy, DefaultRootWindow(dpy), 0xdeadbeef); + local::is_selected_for = true; + } + + active = true; + + nux::GraphicsDisplay::EventFilterArg event_filter; + event_filter.filter = &PointerBarrierWrapper::HandleEventWrapper; + event_filter.data = this; + + nux::GetGraphicsDisplay()->AddEventFilter(event_filter); +} + +void PointerBarrierWrapper::DestroyBarrier() +{ + if (!active) + return; + + active = false; + + Display *dpy = nux::GetGraphicsDisplay()->GetX11Display(); + XFixesDestroyPointerBarrier(dpy, barrier); + + nux::GetGraphicsDisplay()->RemoveEventFilter(this); +} + +void PointerBarrierWrapper::ReleaseBarrier(int event_id) +{ + XFixesBarrierReleasePointer (nux::GetGraphicsDisplay()->GetX11Display(), barrier, event_id); +} + +void PointerBarrierWrapper::EmitCurrentData() +{ + if (smoothing_count_ <= 0) + return; + + BarrierEvent::Ptr event (new BarrierEvent()); + event->x = last_x_; + event->y = last_y_; + event->velocity = std::min<int> (600, smoothing_accum_ / smoothing_count_); + event->event_id = last_event_; + + barrier_event.emit(this, event); + + smoothing_accum_ = 0; + smoothing_count_ = 0; +} + +bool PointerBarrierWrapper::HandleEvent(XEvent xevent) +{ + if(xevent.type - event_base_ == XFixesBarrierNotify) + { + XFixesBarrierNotifyEvent *notify_event = (XFixesBarrierNotifyEvent *)&xevent; + + if (notify_event->barrier == barrier && notify_event->subtype == XFixesBarrierHitNotify) + { + if (notify_event->event_id != last_event_) + { + EmitCurrentData(); + if (smoothing_handle_) + { + g_source_remove(smoothing_handle_); + smoothing_handle_ = 0; + } + } + + last_x_ = notify_event->x; + last_y_ = notify_event->y; + last_event_ = notify_event->event_id; + smoothing_accum_ += notify_event->velocity; + smoothing_count_++; + + if (!smoothing_handle_) + { + auto smoothing_cb = [](gpointer user_data) -> gboolean + { + PointerBarrierWrapper* self = (PointerBarrierWrapper*)user_data; + self->EmitCurrentData(); + + self->smoothing_handle_ = 0; + return FALSE; + }; + + smoothing_handle_ = g_timeout_add(smoothing(), smoothing_cb, this); + } + + } + + return notify_event->barrier == barrier; + } + + return false; +} + +bool PointerBarrierWrapper::HandleEventWrapper(XEvent event, void* data) +{ + PointerBarrierWrapper* wrapper = (PointerBarrierWrapper*)data; + return wrapper->HandleEvent(event); +} + +} +} diff --git a/plugins/unityshell/src/PointerBarrier.h b/plugins/unityshell/src/PointerBarrier.h new file mode 100644 index 000000000..00761f03f --- /dev/null +++ b/plugins/unityshell/src/PointerBarrier.h @@ -0,0 +1,89 @@ +// -*- 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: Jason Smith <jason.smith@canonical.com> + */ + +#ifndef UNITY_POINTERWRAPPER_H +#define UNITY_POINTERWRAPPER_H + +#include <Nux/Nux.h> +#include <X11/Xlib.h> +#include <X11/extensions/Xfixes.h> +#include <sigc++/sigc++.h> + +namespace unity +{ +namespace ui +{ + +class BarrierEvent +{ +public: + typedef std::shared_ptr<BarrierEvent> Ptr; + + int x; + int y; + int velocity; + int event_id; +}; + +class PointerBarrierWrapper +{ +public: + typedef std::shared_ptr<PointerBarrierWrapper> Ptr; + + nux::Property<int> x1; + nux::Property<int> x2; + nux::Property<int> y1; + nux::Property<int> y2; + + nux::Property<int> threshold; + + nux::Property<bool> active; + + nux::Property<int> smoothing; + + PointerBarrierWrapper(); + + void ConstructBarrier(); + void DestroyBarrier(); + void ReleaseBarrier(int event_id); + + sigc::signal<void, PointerBarrierWrapper*, BarrierEvent::Ptr> barrier_event; + +private: + void EmitCurrentData(); + bool HandleEvent (XEvent event); + static bool HandleEventWrapper(XEvent event, void* data); + + int last_event_; + int last_x_; + int last_y_; + + int event_base_; + int error_base_; + PointerBarrier barrier; + + int smoothing_count_; + int smoothing_accum_; + guint smoothing_handle_; +}; + +} +} + +#endif \ No newline at end of file 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..b659633ef 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,39 +99,46 @@ 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); - model_->Fill(); - visible_ = true; + if (enabled_) + { + show_timer_ = g_timeout_add(SUPER_TAP_DURATION, &Controller::OnShowTimer, this); + model_->Fill(); + visible_ = true; + } + } 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 +186,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 +200,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/ShortcutView.cpp b/plugins/unityshell/src/ShortcutView.cpp index de2e39fb9..ef75e824d 100644 --- a/plugins/unityshell/src/ShortcutView.cpp +++ b/plugins/unityshell/src/ShortcutView.cpp @@ -42,19 +42,14 @@ namespace NUX_IMPLEMENT_OBJECT_TYPE(View); -View::View(NUX_FILE_LINE_DECL) - : nux::View(NUX_FILE_LINE_PARAM) +View::View() + : ui::UnityWindowView() { layout_ = new nux::VLayout(); layout_->SetPadding(50, 38); layout_->SetSpaceBetweenChildren(20); SetLayout(layout_); - background_top_ = nux::CreateTexture2DFromFile(PKGDATADIR"/switcher_top.png", -1, true); - background_left_ = nux::CreateTexture2DFromFile(PKGDATADIR"/switcher_left.png", -1, true); - background_corner_ = nux::CreateTexture2DFromFile(PKGDATADIR"/switcher_corner.png", -1, true); - rounding_texture_ = nux::CreateTexture2DFromFile(PKGDATADIR"/switcher_round_rect.png", -1, true); - std::string header = "<b>"; header += _("Keyboard Shortcuts"); header += "</b>"; @@ -77,23 +72,10 @@ View::View(NUX_FILE_LINE_DECL) // Column 2... columns_.push_back(new nux::VLayout()); columns_layout_->AddLayout(columns_[1], 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL); - - bg_effect_helper_.owner = this; } View::~View() { - if (background_top_ != NULL) - background_top_->UnReference(); - - if (background_left_ != NULL) - background_left_->UnReference(); - - if (background_corner_ != NULL) - background_corner_->UnReference(); - - if (rounding_texture_ != NULL) - rounding_texture_->UnReference(); } void View::SetModel(Model::Ptr model) @@ -109,11 +91,6 @@ Model::Ptr View::GetModel() return model_; } -void View::SetupBackground(bool enabled) -{ - bg_effect_helper_.enabled = enabled; -} - nux::LinearLayout* View::CreateSectionLayout(const char* section_name) { nux::VLayout* layout = new nux::VLayout(NUX_TRACKER_LOCATION); @@ -197,19 +174,9 @@ nux::LinearLayout* View::CreateIntermediateLayout() return layout; } -void View::Draw(nux::GraphicsEngine& GfxContext, bool force_draw) +nux::Geometry View::GetBackgroundGeometry() { - return; -} - -void View::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) -{ nux::Geometry base = GetGeometry(); - GfxContext.PushClippingRectangle(base); - - // clear region - gPainter.PaintBackground(GfxContext, base); - nux::Geometry background_geo; background_geo.width = base.width; @@ -217,165 +184,12 @@ void View::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) background_geo.x = (base.width - background_geo.width)/2; background_geo.y = (base.height - background_geo.height)/2; - // magic constant comes from texture contents (distance to cleared area) - const int internal_offset = 20; - nux::Geometry internal_clip(background_geo.x + internal_offset, - background_geo.y + internal_offset, - background_geo.width - internal_offset * 2, - background_geo.height - internal_offset * 2); - GfxContext.PushClippingRectangle(internal_clip); - - nux::Geometry geo_absolute = GetAbsoluteGeometry(); - if (BackgroundEffectHelper::blur_type != BLUR_NONE) - { - nux::Geometry blur_geo(geo_absolute.x, geo_absolute.y, base.width, base.height); - auto blur_texture = bg_effect_helper_.GetBlurRegion(blur_geo); - - if (blur_texture.IsValid()) - { - nux::TexCoordXForm texxform_blur_bg; - texxform_blur_bg.flip_v_coord = true; - texxform_blur_bg.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD); - texxform_blur_bg.uoffset = ((float) base.x) / geo_absolute.width; - texxform_blur_bg.voffset = ((float) base.y) / geo_absolute.height; - - nux::ROPConfig rop; - rop.Blend = false; - rop.SrcBlend = GL_ONE; - rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA; - - gPainter.PushDrawTextureLayer(GfxContext, base, - blur_texture, - texxform_blur_bg, - nux::color::White, - true, - rop); - } - } - - nux::ROPConfig rop; - rop.Blend = true; - rop.SrcBlend = GL_ONE; - rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA; - gPainter.PushDrawColorLayer(GfxContext, internal_clip, background_color, false, rop); - - // Make round corners - rop.Blend = true; - rop.SrcBlend = GL_ZERO; - rop.DstBlend = GL_SRC_ALPHA; - gPainter.PaintShapeCornerROP(GfxContext, - internal_clip, - nux::color::White, - nux::eSHAPE_CORNER_ROUND4, - nux::eCornerTopLeft | nux::eCornerTopRight | - nux::eCornerBottomLeft | nux::eCornerBottomRight, - true, - rop); - - GfxContext.GetRenderStates().SetPremultipliedBlend(nux::SRC_OVER); - - GfxContext.PopClippingRectangle(); - GfxContext.PopClippingRectangle(); - - DrawBackground(GfxContext, background_geo); - - - layout_->ProcessDraw(GfxContext, force_draw); + return background_geo; } - -void View::DrawBackground(nux::GraphicsEngine& GfxContext, nux::Geometry const& geo) -{ - int border = 30; - - GfxContext.GetRenderStates().SetBlend(TRUE, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - nux::TexCoordXForm texxform; - texxform.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD); - texxform.SetWrap(nux::TEXWRAP_REPEAT, nux::TEXWRAP_REPEAT); - - // Draw TOP-LEFT CORNER - texxform.u0 = 0; - texxform.v0 = 0; - texxform.u1 = border; - texxform.v1 = border; - GfxContext.QRP_1Tex(geo.x, geo.y, - border, border, background_corner_->GetDeviceTexture(), texxform, nux::color::White); - - // Draw TOP-RIGHT CORNER - texxform.u0 = 0; - texxform.v0 = 0; - texxform.u1 = border; - texxform.v1 = border; - texxform.flip_u_coord = true; - texxform.flip_v_coord = false; - GfxContext.QRP_1Tex(geo.x + geo.width - border, geo.y, - border, border, background_corner_->GetDeviceTexture(), texxform, nux::color::White); - - // Draw BOTTOM-LEFT CORNER - texxform.u0 = 0; - texxform.v0 = 0; - texxform.u1 = border; - texxform.v1 = border; - texxform.flip_u_coord = false; - texxform.flip_v_coord = true; - GfxContext.QRP_1Tex(geo.x, geo.y + geo.height - border, - border, border, background_corner_->GetDeviceTexture(), texxform, nux::color::White); - - // Draw BOTTOM-RIGHT CORNER - texxform.u0 = 0; - texxform.v0 = 0; - texxform.u1 = border; - texxform.v1 = border; - texxform.flip_u_coord = true; - texxform.flip_v_coord = true; - GfxContext.QRP_1Tex(geo.x + geo.width - border, geo.y + geo.height - border, - border, border, background_corner_->GetDeviceTexture(), texxform, nux::color::White); - - int top_width = background_top_->GetWidth(); - int top_height = background_top_->GetHeight(); - - // Draw TOP BORDER - texxform.u0 = 0; - texxform.v0 = 0; - texxform.u1 = top_width; - texxform.v1 = top_height; - texxform.flip_u_coord = false; - texxform.flip_v_coord = false; - GfxContext.QRP_1Tex(geo.x + border, geo.y, geo.width - border - border, border, background_top_->GetDeviceTexture(), texxform, nux::color::White); - - // Draw BOTTOM BORDER - texxform.u0 = 0; - texxform.v0 = 0; - texxform.u1 = top_width; - texxform.v1 = top_height; - texxform.flip_u_coord = false; - texxform.flip_v_coord = true; - GfxContext.QRP_1Tex(geo.x + border, geo.y + geo.height - border, geo.width - border - border, border, background_top_->GetDeviceTexture(), texxform, nux::color::White); - - - int left_width = background_left_->GetWidth(); - int left_height = background_left_->GetHeight(); - - // Draw LEFT BORDER - texxform.u0 = 0; - texxform.v0 = 0; - texxform.u1 = left_width; - texxform.v1 = left_height; - texxform.flip_u_coord = false; - texxform.flip_v_coord = false; - GfxContext.QRP_1Tex(geo.x, geo.y + border, border, geo.height - border - border, background_left_->GetDeviceTexture(), texxform, nux::color::White); - - // Draw RIGHT BORDER - texxform.u0 = 0; - texxform.v0 = 0; - texxform.u1 = left_width; - texxform.v1 = left_height; - texxform.flip_u_coord = true; - texxform.flip_v_coord = false; - GfxContext.QRP_1Tex(geo.x + geo.width - border, geo.y + border, border, geo.height - border - border, background_left_->GetDeviceTexture(), texxform, nux::color::White); - - GfxContext.GetRenderStates().SetBlend(FALSE); +void View::DrawOverlay(nux::GraphicsEngine& GfxContext, bool force_draw, nux::Geometry clip) +{ + layout_->ProcessDraw(GfxContext, force_draw); } void View::RenderColumns() diff --git a/plugins/unityshell/src/ShortcutView.h b/plugins/unityshell/src/ShortcutView.h index 2f58c4f7e..259a1f0f1 100644 --- a/plugins/unityshell/src/ShortcutView.h +++ b/plugins/unityshell/src/ShortcutView.h @@ -28,6 +28,7 @@ #include <Nux/View.h> #include <Nux/VLayout.h> +#include "UnityWindowView.h" #include "BackgroundEffectHelper.h" #include "ShortcutModel.h" @@ -36,29 +37,24 @@ namespace unity namespace shortcut { -class View : public nux::View +class View : public ui::UnityWindowView { - NUX_DECLARE_OBJECT_TYPE(View, nux::View); + NUX_DECLARE_OBJECT_TYPE(View, ui::UnityWindowView); public: typedef nux::ObjectPtr<View> Ptr; // Ctor and dtor - View(NUX_FILE_LINE_PROTO); + View(); ~View(); // Public methods void SetModel(Model::Ptr model); Model::Ptr GetModel(); - - void SetupBackground(bool enabled); - - // Properties - nux::Property<nux::Color> background_color; protected: // Protected methods - void Draw(nux::GraphicsEngine& GfxContext, bool force_draw); - void DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw); + void DrawOverlay(nux::GraphicsEngine& GfxContext, bool force_draw, nux::Geometry clip); + nux::Geometry GetBackgroundGeometry(); private: // Private methods @@ -66,23 +62,14 @@ private: nux::LinearLayout* CreateShortKeyEntryLayout(AbstractHint* hint); nux::LinearLayout* CreateIntermediateLayout(); - void DrawBackground(nux::GraphicsEngine& GfxContext, nux::Geometry const& geo); void RenderColumns(); // Private members Model::Ptr model_; - nux::BaseTexture* background_top_; - nux::BaseTexture* background_left_; - nux::BaseTexture* background_corner_; - nux::BaseTexture* rounding_texture_; - nux::VLayout* layout_; nux::HLayout* columns_layout_; std::vector<nux::VLayout*> columns_; - - BackgroundEffectHelper bg_effect_helper_; - }; } // namespace shortcut diff --git a/plugins/unityshell/src/SimpleLauncherIcon.cpp b/plugins/unityshell/src/SimpleLauncherIcon.cpp index 3731a6c40..6d04ee58e 100644 --- a/plugins/unityshell/src/SimpleLauncherIcon.cpp +++ b/plugins/unityshell/src/SimpleLauncherIcon.cpp @@ -17,12 +17,14 @@ * Authored by: Jason Smith <jason.smith@canonical.com> */ +#ifndef UNITY_SIMPLELAUNCHERICON_H +#define UNITY_SIMPLELAUNCHERICON_H + #include <NuxCore/Logger.h> #include <Nux/Nux.h> #include <Nux/BaseWindow.h> #include "SimpleLauncherIcon.h" -#include "Launcher.h" #include "PluginAdapter.h" #include "ubus-server.h" @@ -38,8 +40,8 @@ namespace nux::logging::Logger logger("unity.dash.CategoryViewGrid"); } -SimpleLauncherIcon::SimpleLauncherIcon(Launcher* IconManager) - : LauncherIcon(IconManager) +SimpleLauncherIcon::SimpleLauncherIcon() + : LauncherIcon() , icon_name("", sigc::mem_fun(this, &SimpleLauncherIcon::SetIconName)) , theme_changed_id_(0) { @@ -65,23 +67,23 @@ SimpleLauncherIcon::~SimpleLauncherIcon() g_signal_handler_disconnect(gtk_icon_theme_get_default(), theme_changed_id_); } -void SimpleLauncherIcon::OnMouseDown(int button) +void SimpleLauncherIcon::OnMouseDown(int button, int monitor) { } -void SimpleLauncherIcon::OnMouseUp(int button) +void SimpleLauncherIcon::OnMouseUp(int button, int monitor) { } -void SimpleLauncherIcon::OnMouseClick(int button) +void SimpleLauncherIcon::OnMouseClick(int button, int monitor) { } -void SimpleLauncherIcon::OnMouseEnter() +void SimpleLauncherIcon::OnMouseEnter(int monitor) { } -void SimpleLauncherIcon::OnMouseLeave() +void SimpleLauncherIcon::OnMouseLeave(int monitor) { } @@ -142,3 +144,5 @@ void SimpleLauncherIcon::OnIconThemeChanged(GtkIconTheme* icon_theme, gpointer d } // namespace launcher } // namespace unity + +#endif \ No newline at end of file diff --git a/plugins/unityshell/src/SimpleLauncherIcon.h b/plugins/unityshell/src/SimpleLauncherIcon.h index af3af5264..15479ec4c 100644 --- a/plugins/unityshell/src/SimpleLauncherIcon.h +++ b/plugins/unityshell/src/SimpleLauncherIcon.h @@ -32,7 +32,7 @@ class Launcher; class SimpleLauncherIcon : public LauncherIcon { public: - SimpleLauncherIcon(Launcher* IconManager); + SimpleLauncherIcon(); virtual ~SimpleLauncherIcon(); // override @@ -45,11 +45,11 @@ public: sigc::signal<void> activate; protected: - virtual void OnMouseDown(int button); - virtual void OnMouseUp(int button); - virtual void OnMouseClick(int button); - virtual void OnMouseEnter(); - virtual void OnMouseLeave(); + virtual void OnMouseDown(int button, int monitor); + virtual void OnMouseUp(int button, int monitor); + virtual void OnMouseClick(int button, int monitor); + virtual void OnMouseEnter(int monitor); + virtual void OnMouseLeave(int monitor); virtual void ActivateLauncherIcon(ActionArg arg); private: diff --git a/plugins/unityshell/src/SoftwareCenterLauncherIcon.cpp b/plugins/unityshell/src/SoftwareCenterLauncherIcon.cpp index 90e4a9f82..d07060404 100644 --- a/plugins/unityshell/src/SoftwareCenterLauncherIcon.cpp +++ b/plugins/unityshell/src/SoftwareCenterLauncherIcon.cpp @@ -44,8 +44,8 @@ namespace unity namespace launcher { -SoftwareCenterLauncherIcon::SoftwareCenterLauncherIcon(Launcher* IconManager, BamfApplication* app, char* aptdaemon_trans_id, char* icon_path) -: BamfLauncherIcon(IconManager, app) +SoftwareCenterLauncherIcon::SoftwareCenterLauncherIcon(BamfApplication* app, char* aptdaemon_trans_id, char* icon_path) +: BamfLauncherIcon(app) { _aptdaemon_trans_id = aptdaemon_trans_id; diff --git a/plugins/unityshell/src/SoftwareCenterLauncherIcon.h b/plugins/unityshell/src/SoftwareCenterLauncherIcon.h index c6f441c11..e12bc9918 100644 --- a/plugins/unityshell/src/SoftwareCenterLauncherIcon.h +++ b/plugins/unityshell/src/SoftwareCenterLauncherIcon.h @@ -40,7 +40,7 @@ class SoftwareCenterLauncherIcon : public BamfLauncherIcon { public: - SoftwareCenterLauncherIcon(Launcher* IconManager, BamfApplication* app, char* aptdaemon_trans_id, char* icon_path); + SoftwareCenterLauncherIcon(BamfApplication* app, char* aptdaemon_trans_id, char* icon_path); virtual ~SoftwareCenterLauncherIcon(); gchar* original_tooltip_text; diff --git a/plugins/unityshell/src/SpacerLauncherIcon.cpp b/plugins/unityshell/src/SpacerLauncherIcon.cpp index 98dbcca36..74d420ba2 100644 --- a/plugins/unityshell/src/SpacerLauncherIcon.cpp +++ b/plugins/unityshell/src/SpacerLauncherIcon.cpp @@ -27,8 +27,8 @@ namespace unity namespace launcher { -SpacerLauncherIcon::SpacerLauncherIcon(Launcher* IconManager) - : SimpleLauncherIcon(IconManager) +SpacerLauncherIcon::SpacerLauncherIcon() + : SimpleLauncherIcon() { SetQuirk(QUIRK_VISIBLE, true); SetQuirk(QUIRK_RUNNING, false); diff --git a/plugins/unityshell/src/SpacerLauncherIcon.h b/plugins/unityshell/src/SpacerLauncherIcon.h index 41d76ce2f..a326357aa 100644 --- a/plugins/unityshell/src/SpacerLauncherIcon.h +++ b/plugins/unityshell/src/SpacerLauncherIcon.h @@ -30,7 +30,7 @@ namespace launcher class SpacerLauncherIcon : public SimpleLauncherIcon { public: - SpacerLauncherIcon(Launcher* launcher); + SpacerLauncherIcon(); bool IsSpacer() { diff --git a/plugins/unityshell/src/SwitcherController.cpp b/plugins/unityshell/src/SwitcherController.cpp index bc3df3307..0a4e5a46e 100644 --- a/plugins/unityshell/src/SwitcherController.cpp +++ b/plugins/unityshell/src/SwitcherController.cpp @@ -45,6 +45,7 @@ Controller::Controller() timeout_length = 150; detail_on_timeout = true; detail_timeout_length = 1500; + monitor_ = 0; bg_color_ = nux::Color(0.0, 0.0, 0.0, 0.5); @@ -72,11 +73,6 @@ void Controller::OnBackgroundUpdate(GVariant* data, Controller* self) self->view_->background_color = self->bg_color_; } -bool IsOnOtherViewport (AbstractLauncherIcon* icon) -{ - return !icon->HasWindowOnViewport(); -} - void Controller::Show(ShowMode show, SortMode sort, bool reverse, std::vector<AbstractLauncherIcon*> results) { @@ -85,11 +81,6 @@ void Controller::Show(ShowMode show, SortMode sort, bool reverse, std::sort(results.begin(), results.end(), CompareSwitcherItemsPriority); } - if (show == ShowMode::CURRENT_VIEWPORT) - { - results.erase(std::remove_if(results.begin(), results.end(), IsOnOtherViewport), results.end()); - } - model_.reset(new SwitcherModel(results)); AddChild(model_.get()); model_->selection_changed.connect(sigc::mem_fun(this, &Controller::OnModelSelectionChanged)); @@ -177,6 +168,7 @@ void Controller::ConstructView() AddChild(view_.GetPointer()); view_->SetModel(model_); view_->background_color = bg_color_; + view_->monitor = monitor_; if (!view_window_) { @@ -197,9 +189,13 @@ void Controller::ConstructView() view_window_->ShowWindow(true); } -void Controller::SetWorkspace(nux::Geometry geo) +void Controller::SetWorkspace(nux::Geometry geo, int monitor) { + monitor_ = monitor; workarea_ = geo; + + if (view_) + view_->monitor = monitor_; } void Controller::Hide(bool accept_state) @@ -269,7 +265,7 @@ void Controller::Next() switch (detail_mode_) { case TAB_NEXT_WINDOW: - if (model_->detail_selection_index < model_->Selection()->RelatedXids ().size () - 1) + if (model_->detail_selection_index < model_->Selection()->Windows().size () - 1) model_->NextDetail(); else model_->Next(); @@ -324,7 +320,7 @@ SwitcherView* Controller::GetView() void Controller::SetDetail(bool value, unsigned int min_windows) { - if (value && model_->Selection()->RelatedXids().size () >= min_windows) + if (value && model_->Selection()->Windows().size () >= min_windows) { model_->detail_selection = true; detail_mode_ = TAB_NEXT_WINDOW_LOOP; @@ -409,7 +405,7 @@ void Controller::SelectFirstItem() unsigned int first_second = 0; // first icons second highest active unsigned int second_first = 0; // second icons first highest active - for (guint32 xid : first->RelatedXids()) + for (guint32 xid : first->Windows()) { unsigned int num = WindowManager::Default()->GetWindowActiveNumber(xid); @@ -424,7 +420,7 @@ void Controller::SelectFirstItem() } } - for (guint32 xid : second->RelatedXids()) + for (guint32 xid : second->Windows()) { second_first = MAX (WindowManager::Default()->GetWindowActiveNumber(xid), second_first); } diff --git a/plugins/unityshell/src/SwitcherController.h b/plugins/unityshell/src/SwitcherController.h index 81cd29dbf..1c1afe134 100644 --- a/plugins/unityshell/src/SwitcherController.h +++ b/plugins/unityshell/src/SwitcherController.h @@ -87,7 +87,7 @@ public: void SelectFirstItem(); - void SetWorkspace(nux::Geometry geo); + void SetWorkspace(nux::Geometry geo, int monitor); SwitcherView * GetView (); @@ -120,6 +120,7 @@ private: nux::BaseWindow* view_window_; nux::HLayout* main_layout_; + int monitor_; bool visible_; guint show_timer_; guint detail_timer_; diff --git a/plugins/unityshell/src/SwitcherModel.cpp b/plugins/unityshell/src/SwitcherModel.cpp index f475b30d1..9141ea509 100644 --- a/plugins/unityshell/src/SwitcherModel.cpp +++ b/plugins/unityshell/src/SwitcherModel.cpp @@ -152,7 +152,7 @@ std::vector<Window> SwitcherModel::DetailXids() { std::vector<Window> results; - results = Selection()->RelatedXids (); + results = Selection()->Windows(); if (only_detail_on_viewport) { diff --git a/plugins/unityshell/src/SwitcherView.cpp b/plugins/unityshell/src/SwitcherView.cpp index eb73b7102..a75ee16bb 100644 --- a/plugins/unityshell/src/SwitcherView.cpp +++ b/plugins/unityshell/src/SwitcherView.cpp @@ -40,8 +40,8 @@ namespace switcher NUX_IMPLEMENT_OBJECT_TYPE(SwitcherView); -SwitcherView::SwitcherView(NUX_FILE_LINE_DECL) - : View(NUX_FILE_LINE_PARAM) +SwitcherView::SwitcherView() + : UnityWindowView() , target_sizes_set_(false) , redraw_handle_(0) { @@ -57,6 +57,7 @@ SwitcherView::SwitcherView(NUX_FILE_LINE_DECL) vertical_size = tile_size + 80; text_size = 15; animation_length = 250; + monitor = -1; spread_size = 3.5f; render_boxes = false; @@ -67,9 +68,6 @@ SwitcherView::SwitcherView(NUX_FILE_LINE_DECL) render_targets_.clear (); - background_top_ = nux::CreateTexture2DFromFile(PKGDATADIR"/switcher_top.png", -1, true); - background_left_ = nux::CreateTexture2DFromFile(PKGDATADIR"/switcher_left.png", -1, true); - background_corner_ = nux::CreateTexture2DFromFile(PKGDATADIR"/switcher_corner.png", -1, true); rounding_texture_ = nux::CreateTexture2DFromFile(PKGDATADIR"/switcher_round_rect.png", -1, true); text_view_ = new nux::StaticCairoText("Testing"); @@ -81,15 +79,10 @@ SwitcherView::SwitcherView(NUX_FILE_LINE_DECL) icon_size.changed.connect (sigc::mem_fun (this, &SwitcherView::OnIconSizeChanged)); tile_size.changed.connect (sigc::mem_fun (this, &SwitcherView::OnTileSizeChanged)); - - bg_effect_helper_.owner = this; } SwitcherView::~SwitcherView() { - background_top_->UnReference(); - background_left_->UnReference(); - background_corner_->UnReference(); rounding_texture_->UnReference(); text_view_->UnReference(); if (redraw_handle_ > 0) @@ -116,11 +109,7 @@ void SwitcherView::AddProperties(GVariantBuilder* builder) .add("spread-size", (float)spread_size); } -void -SwitcherView::SetupBackground() -{ - bg_effect_helper_.enabled = true; -} + LayoutWindowList SwitcherView::ExternalTargets () { @@ -196,11 +185,6 @@ SwitcherModel::Ptr SwitcherView::GetModel() return model_; } -void SwitcherView::Draw(nux::GraphicsEngine& GfxContext, bool force_draw) -{ - return; -} - RenderArg SwitcherView::CreateBaseArgForIcon(AbstractLauncherIcon* icon) { RenderArg arg; @@ -210,7 +194,7 @@ RenderArg SwitcherView::CreateBaseArgForIcon(AbstractLauncherIcon* icon) // tells the renderer to render arrows by number arg.running_on_viewport = true; - arg.window_indicators = icon->RelatedWindows(); + arg.window_indicators = icon->WindowsForMonitor(monitor).size(); if (arg.window_indicators > 1) arg.running_arrow = true; else @@ -555,104 +539,9 @@ gboolean SwitcherView::OnDrawTimeout(gpointer data) return FALSE; } -void SwitcherView::DrawBackground(nux::GraphicsEngine& GfxContext, nux::Geometry const& geo) -{ - int border = 30; - - GfxContext.GetRenderStates().SetBlend (TRUE, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - nux::TexCoordXForm texxform; - texxform.SetTexCoordType (nux::TexCoordXForm::OFFSET_COORD); - texxform.SetWrap(nux::TEXWRAP_REPEAT, nux::TEXWRAP_REPEAT); - - // Draw TOP-LEFT CORNER - texxform.u0 = 0; - texxform.v0 = 0; - texxform.u1 = border; - texxform.v1 = border; - GfxContext.QRP_1Tex (geo.x, geo.y, - border, border, background_corner_->GetDeviceTexture(), texxform, nux::color::White); - - // Draw TOP-RIGHT CORNER - texxform.u0 = 0; - texxform.v0 = 0; - texxform.u1 = border; - texxform.v1 = border; - texxform.flip_u_coord = true; - texxform.flip_v_coord = false; - GfxContext.QRP_1Tex (geo.x + geo.width - border, geo.y, - border, border, background_corner_->GetDeviceTexture(), texxform, nux::color::White); - - // Draw BOTTOM-LEFT CORNER - texxform.u0 = 0; - texxform.v0 = 0; - texxform.u1 = border; - texxform.v1 = border; - texxform.flip_u_coord = false; - texxform.flip_v_coord = true; - GfxContext.QRP_1Tex (geo.x, geo.y + geo.height - border, - border, border, background_corner_->GetDeviceTexture(), texxform, nux::color::White); - - // Draw BOTTOM-RIGHT CORNER - texxform.u0 = 0; - texxform.v0 = 0; - texxform.u1 = border; - texxform.v1 = border; - texxform.flip_u_coord = true; - texxform.flip_v_coord = true; - GfxContext.QRP_1Tex (geo.x + geo.width - border, geo.y + geo.height - border, - border, border, background_corner_->GetDeviceTexture(), texxform, nux::color::White); - - int top_width = background_top_->GetWidth(); - int top_height = background_top_->GetHeight(); - - // Draw TOP BORDER - texxform.u0 = 0; - texxform.v0 = 0; - texxform.u1 = top_width; - texxform.v1 = top_height; - texxform.flip_u_coord = false; - texxform.flip_v_coord = false; - GfxContext.QRP_1Tex (geo.x + border, geo.y, geo.width - border - border, border, background_top_->GetDeviceTexture(), texxform, nux::color::White); - - // Draw BOTTOM BORDER - texxform.u0 = 0; - texxform.v0 = 0; - texxform.u1 = top_width; - texxform.v1 = top_height; - texxform.flip_u_coord = false; - texxform.flip_v_coord = true; - GfxContext.QRP_1Tex (geo.x + border, geo.y + geo.height - border, geo.width - border - border, border, background_top_->GetDeviceTexture(), texxform, nux::color::White); - - - int left_width = background_left_->GetWidth(); - int left_height = background_left_->GetHeight(); - - // Draw LEFT BORDER - texxform.u0 = 0; - texxform.v0 = 0; - texxform.u1 = left_width; - texxform.v1 = left_height; - texxform.flip_u_coord = false; - texxform.flip_v_coord = false; - GfxContext.QRP_1Tex (geo.x, geo.y + border, border, geo.height - border - border, background_left_->GetDeviceTexture(), texxform, nux::color::White); - - // Draw RIGHT BORDER - texxform.u0 = 0; - texxform.v0 = 0; - texxform.u1 = left_width; - texxform.v1 = left_height; - texxform.flip_u_coord = true; - texxform.flip_v_coord = false; - GfxContext.QRP_1Tex (geo.x + geo.width - border, geo.y + border, border, geo.height - border - border, background_left_->GetDeviceTexture(), texxform, nux::color::White); - - GfxContext.GetRenderStates().SetBlend (FALSE); -} - -void SwitcherView::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) +void SwitcherView::PreDraw(nux::GraphicsEngine& GfxContext, bool force_draw) { - timespec current; - clock_gettime(CLOCK_MONOTONIC, ¤t); + clock_gettime(CLOCK_MONOTONIC, ¤t_); if (!target_sizes_set_) { @@ -660,74 +549,21 @@ void SwitcherView::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) target_sizes_set_ = true; } - nux::Geometry base = GetGeometry(); - GfxContext.PushClippingRectangle(base); - - // clear region - gPainter.PaintBackground(GfxContext, base); - nux::Geometry background_geo; - - last_args_ = RenderArgsFlat(background_geo, model_->SelectionIndex(), current); + last_args_ = RenderArgsFlat(background_geo, model_->SelectionIndex(), current_); last_background_ = background_geo; - // magic constant comes from texture contents (distance to cleared area) - const int internal_offset = 20; - nux::Geometry internal_clip(background_geo.x + internal_offset, - background_geo.y + internal_offset, - background_geo.width - internal_offset * 2, - background_geo.height - internal_offset * 2); - GfxContext.PushClippingRectangle(internal_clip); - - - nux::Geometry geo_absolute = GetAbsoluteGeometry (); - if (BackgroundEffectHelper::blur_type != BLUR_NONE) - { - nux::Geometry blur_geo(geo_absolute.x, geo_absolute.y, base.width, base.height); - auto blur_texture = bg_effect_helper_.GetBlurRegion(blur_geo); + icon_renderer_->PreprocessIcons(last_args_, GetGeometry()); +} - if (blur_texture.IsValid()) - { - nux::TexCoordXForm texxform_blur_bg; - texxform_blur_bg.flip_v_coord = true; - texxform_blur_bg.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD); - texxform_blur_bg.uoffset = ((float) base.x) / geo_absolute.width; - texxform_blur_bg.voffset = ((float) base.y) / geo_absolute.height; - - nux::ROPConfig rop; - rop.Blend = false; - rop.SrcBlend = GL_ONE; - rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA; - - gPainter.PushDrawTextureLayer(GfxContext, base, - blur_texture, - texxform_blur_bg, - nux::color::White, - true, - rop); - } - } +nux::Geometry SwitcherView::GetBackgroundGeometry() +{ + return last_background_; +} - nux::ROPConfig rop; - rop.Blend = true; - rop.SrcBlend = GL_ONE; - rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA; - gPainter.PushDrawColorLayer (GfxContext, internal_clip, background_color, false, rop); - - // Make round corners - rop.Blend = true; - rop.SrcBlend = GL_ZERO; - rop.DstBlend = GL_SRC_ALPHA; - gPainter.PaintShapeCornerROP(GfxContext, - internal_clip, - nux::color::White, - nux::eSHAPE_CORNER_ROUND4, - nux::eCornerTopLeft | nux::eCornerTopRight | - nux::eCornerBottomLeft | nux::eCornerBottomRight, - true, - rop); - - icon_renderer_->PreprocessIcons(last_args_, base); +void SwitcherView::DrawOverlay(nux::GraphicsEngine& GfxContext, bool force_draw, nux::Geometry internal_clip) +{ + nux::Geometry base = GetGeometry(); GfxContext.GetRenderStates().SetPremultipliedBlend(nux::SRC_OVER); std::list<RenderArg>::iterator it; @@ -779,6 +615,7 @@ void SwitcherView::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) // render orange box that will encirlce active item(s) for (LayoutWindow::Ptr window : ExternalTargets()) { + nux::Geometry geo_absolute = GetAbsoluteGeometry(); if (window->alpha >= 1.0f) { nux::Geometry orange_box = window->result; @@ -790,15 +627,10 @@ void SwitcherView::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) } } - GfxContext.PopClippingRectangle(); - GfxContext.PopClippingRectangle(); - - DrawBackground(GfxContext, background_geo); - - text_view_->SetBaseY(background_geo.y + background_geo.height - 45); + text_view_->SetBaseY(last_background_.y + last_background_.height - 45); text_view_->Draw(GfxContext, force_draw); - int ms_since_change = TimeUtil::TimeDelta(¤t, &save_time_); + int ms_since_change = TimeUtil::TimeDelta(¤t_, &save_time_); if (ms_since_change < animation_length && redraw_handle_ == 0) redraw_handle_ = g_idle_add_full (G_PRIORITY_DEFAULT, &SwitcherView::OnDrawTimeout, this, NULL); diff --git a/plugins/unityshell/src/SwitcherView.h b/plugins/unityshell/src/SwitcherView.h index 2058aaba8..f0e460fcd 100644 --- a/plugins/unityshell/src/SwitcherView.h +++ b/plugins/unityshell/src/SwitcherView.h @@ -25,6 +25,7 @@ #include "StaticCairoText.h" #include "LayoutSystem.h" #include "BackgroundEffectHelper.h" +#include "UnityWindowView.h" #include "Introspectable.h" @@ -36,6 +37,8 @@ #include <NuxCore/Property.h> + + namespace unity { namespace launcher @@ -45,13 +48,13 @@ class AbstractLauncherIcon; namespace switcher { -class SwitcherView : public debug::Introspectable, public nux::View +class SwitcherView : public debug::Introspectable, public ui::UnityWindowView { - NUX_DECLARE_OBJECT_TYPE(SwitcherView, nux::View); + NUX_DECLARE_OBJECT_TYPE(SwitcherView, ui::UnityWindowView); public: typedef nux::ObjectPtr<SwitcherView> Ptr; - SwitcherView(NUX_FILE_LINE_PROTO); + SwitcherView(); virtual ~SwitcherView(); ui::LayoutWindowList ExternalTargets (); @@ -59,8 +62,6 @@ public: void SetModel(SwitcherModel::Ptr model); SwitcherModel::Ptr GetModel(); - void SetupBackground (); - nux::Property<bool> render_boxes; nux::Property<int> border_size; nux::Property<int> flat_spacing; @@ -70,16 +71,17 @@ public: nux::Property<int> vertical_size; nux::Property<int> text_size; nux::Property<int> animation_length; + nux::Property<int> monitor; nux::Property<double> spread_size; - nux::Property<nux::Color> background_color; protected: // Introspectable methods std::string GetName() const; void AddProperties(GVariantBuilder* builder); - void Draw(nux::GraphicsEngine& GfxContext, bool force_draw); - void DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw); + void PreDraw(nux::GraphicsEngine& GfxContext, bool force_draw); + void DrawOverlay(nux::GraphicsEngine& GfxContext, bool force_draw, nux::Geometry clip); + nux::Geometry GetBackgroundGeometry(); ui::RenderArg InterpolateRenderArgs(ui::RenderArg const& start, ui::RenderArg const& end, float progress); nux::Geometry InterpolateBackground (nux::Geometry const& start, nux::Geometry const& end, float progress); @@ -88,8 +90,6 @@ protected: ui::RenderArg CreateBaseArgForIcon(launcher::AbstractLauncherIcon* icon); private: - void DrawBackground(nux::GraphicsEngine& GfxContext, nux::Geometry const& geo); - void OnSelectionChanged(launcher::AbstractLauncherIcon* selection); void OnDetailSelectionChanged (bool detail); void OnDetailSelectionIndexChanged (unsigned int index); @@ -121,9 +121,6 @@ private: guint redraw_handle_; - nux::BaseTexture* background_top_; - nux::BaseTexture* background_left_; - nux::BaseTexture* background_corner_; nux::BaseTexture* rounding_texture_; nux::StaticCairoText* text_view_; @@ -136,11 +133,10 @@ private: ui::LayoutWindowList render_targets_; + timespec current_; timespec save_time_; bool animation_draw_; - - BackgroundEffectHelper bg_effect_helper_; }; } diff --git a/plugins/unityshell/src/TimeUtil.h b/plugins/unityshell/src/TimeUtil.h index 9f4e4fddc..ab4d109db 100644 --- a/plugins/unityshell/src/TimeUtil.h +++ b/plugins/unityshell/src/TimeUtil.h @@ -25,13 +25,44 @@ namespace unity { class TimeUtil { public: -static int TimeDelta (struct timespec const* x, struct timespec const* y); + static int TimeDelta (struct timespec const* x, struct timespec const* y) + { + return ((x->tv_sec - y->tv_sec) * 1000) + ((x->tv_nsec - y->tv_nsec) / 1000000); + } + + static void SetTimeStruct(struct timespec* timer, struct timespec* sister = 0, int sister_relation = 0) + { + struct timespec current; + clock_gettime(CLOCK_MONOTONIC, ¤t); + + if (sister) + { + int diff = TimeDelta(¤t, sister); + + if (diff < sister_relation) + { + int remove = sister_relation - diff; + SetTimeBack(¤t, remove); + } + } + + timer->tv_sec = current.tv_sec; + timer->tv_nsec = current.tv_nsec; + } + + static void SetTimeBack(struct timespec* timeref, int remove) + { + timeref->tv_sec -= remove / 1000; + remove = remove % 1000; + + if (remove > timeref->tv_nsec / 1000000) + { + timeref->tv_sec--; + timeref->tv_nsec += 1000000000; + } + timeref->tv_nsec -= remove * 1000000; + } }; -inline -int TimeUtil::TimeDelta (struct timespec const* x, struct timespec const* y) -{ - return ((x->tv_sec - y->tv_sec) * 1000) + ((x->tv_nsec - y->tv_nsec) / 1000000); -} } diff --git a/plugins/unityshell/src/TrashLauncherIcon.cpp b/plugins/unityshell/src/TrashLauncherIcon.cpp index 2c666d27e..68d6c89fd 100644 --- a/plugins/unityshell/src/TrashLauncherIcon.cpp +++ b/plugins/unityshell/src/TrashLauncherIcon.cpp @@ -32,8 +32,8 @@ namespace unity namespace launcher { -TrashLauncherIcon::TrashLauncherIcon(Launcher* IconManager) - : SimpleLauncherIcon(IconManager) +TrashLauncherIcon::TrashLauncherIcon() + : SimpleLauncherIcon() , proxy_("org.gnome.Nautilus", "/org/gnome/Nautilus", "org.gnome.Nautilus.FileOperations") { tooltip_text = _("Trash"); diff --git a/plugins/unityshell/src/TrashLauncherIcon.h b/plugins/unityshell/src/TrashLauncherIcon.h index d6b461193..f09319cc7 100644 --- a/plugins/unityshell/src/TrashLauncherIcon.h +++ b/plugins/unityshell/src/TrashLauncherIcon.h @@ -36,7 +36,7 @@ class TrashLauncherIcon : public SimpleLauncherIcon { public: - TrashLauncherIcon(Launcher* launcher); + TrashLauncherIcon(); ~TrashLauncherIcon(); virtual nux::Color BackgroundColor(); diff --git a/plugins/unityshell/src/UScreen.cpp b/plugins/unityshell/src/UScreen.cpp index 1f4ec8131..51b86c9bf 100644 --- a/plugins/unityshell/src/UScreen.cpp +++ b/plugins/unityshell/src/UScreen.cpp @@ -54,6 +54,24 @@ UScreen::GetDefault() } int +UScreen::GetMonitorWithMouse() +{ + GdkScreen* screen; + GdkDevice* device; + GdkDisplay *display; + int x; + int y; + + screen = gdk_screen_get_default(); + display = gdk_display_get_default(); + device = gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(display)); + + gdk_device_get_position(device, NULL, &x, &y); + + return gdk_screen_get_monitor_at_point(screen, x, y); +} + +int UScreen::GetPrimaryMonitor() { return primary_; diff --git a/plugins/unityshell/src/UScreen.h b/plugins/unityshell/src/UScreen.h index b66a8b607..bb0a60312 100644 --- a/plugins/unityshell/src/UScreen.h +++ b/plugins/unityshell/src/UScreen.h @@ -33,6 +33,7 @@ public: static UScreen* GetDefault(); int GetPrimaryMonitor(); + int GetMonitorWithMouse(); nux::Geometry& GetMonitorGeometry(int monitor); std::vector<nux::Geometry>& GetMonitors(); diff --git a/plugins/unityshell/src/UnityWindowStyle.cpp b/plugins/unityshell/src/UnityWindowStyle.cpp new file mode 100644 index 000000000..826f7669d --- /dev/null +++ b/plugins/unityshell/src/UnityWindowStyle.cpp @@ -0,0 +1,64 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2012 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Jason Smith <jason.smith@canonical.com> + */ + +#include "UnityWindowStyle.h" + +namespace unity { +namespace ui { + +UnityWindowStyle::UnityWindowStyle() +{ + background_top_ = BaseTexturePtr(nux::CreateTexture2DFromFile(PKGDATADIR"/switcher_top.png", -1, true)); + background_left_ = BaseTexturePtr(nux::CreateTexture2DFromFile(PKGDATADIR"/switcher_left.png", -1, true)); + background_corner_ = BaseTexturePtr(nux::CreateTexture2DFromFile(PKGDATADIR"/switcher_corner.png", -1, true)); +} + +UnityWindowStyle::~UnityWindowStyle() +{ + // nothing to do +} + +int UnityWindowStyle::GetBorderSize() const +{ + return 30; // as measured from textures +} + +int UnityWindowStyle::GetInternalOffset() const +{ + return 20; +} + +nux::BaseTexture* UnityWindowStyle::GetBackgroundTop() const +{ + return background_top_.GetPointer(); +} + +nux::BaseTexture* UnityWindowStyle::GetBackgroundLeft() const +{ + return background_left_.GetPointer(); +} + +nux::BaseTexture* UnityWindowStyle::GetBackgroundCorner() const +{ + return background_corner_.GetPointer(); +} + + +} +} \ No newline at end of file diff --git a/plugins/unityshell/src/UnityWindowStyle.h b/plugins/unityshell/src/UnityWindowStyle.h new file mode 100644 index 000000000..ca0a5b797 --- /dev/null +++ b/plugins/unityshell/src/UnityWindowStyle.h @@ -0,0 +1,54 @@ +// -*- 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: Jason Smith <jason.smith@canonical.com> + */ + +#ifndef UNITYWINDOWSTYLE_H +#define UNITYWINDOWSTYLE_H + +#include <sigc++/sigc++.h> +#include <Nux/Nux.h> + +namespace unity { +namespace ui { + +class UnityWindowStyle +{ +public: + typedef std::shared_ptr<UnityWindowStyle> Ptr; + typedef nux::ObjectPtr<nux::BaseTexture> BaseTexturePtr; + + UnityWindowStyle(); + ~UnityWindowStyle(); + + nux::BaseTexture* GetBackgroundTop() const; + nux::BaseTexture* GetBackgroundLeft() const; + nux::BaseTexture* GetBackgroundCorner() const; + int GetBorderSize() const; + int GetInternalOffset() const; + +private: + BaseTexturePtr background_top_; + BaseTexturePtr background_left_; + BaseTexturePtr background_corner_; + +}; + +} +} + +#endif diff --git a/plugins/unityshell/src/UnityWindowView.cpp b/plugins/unityshell/src/UnityWindowView.cpp new file mode 100644 index 000000000..5f5448af8 --- /dev/null +++ b/plugins/unityshell/src/UnityWindowView.cpp @@ -0,0 +1,222 @@ +// -*- 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: Jason Smith <jason.smith@canonical.com> + */ + +#include "UnityWindowView.h" + +namespace unity { +namespace ui { + +NUX_IMPLEMENT_OBJECT_TYPE(UnityWindowView); + +UnityWindowView::UnityWindowView(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) +{ + style = UnityWindowStyle::Ptr(new UnityWindowStyle()); + bg_helper_.owner = this; +} + +UnityWindowView::~UnityWindowView() +{ + +} + +void +UnityWindowView::SetupBackground(bool enabled) +{ + bg_helper_.enabled = enabled; +} + +void UnityWindowView::Draw(nux::GraphicsEngine& GfxContext, bool force_draw) +{ + // fixme??? +} + +void UnityWindowView::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) +{ + PreDraw(GfxContext, force_draw); + + nux::Geometry base = GetGeometry(); + GfxContext.PushClippingRectangle(base); + + // clear region + gPainter.PaintBackground(GfxContext, base); + + nux::Geometry background_geo = GetBackgroundGeometry(); + int internal_offset = style()->GetInternalOffset(); + + nux::Geometry internal_clip(background_geo.x + internal_offset, + background_geo.y + internal_offset, + background_geo.width - internal_offset * 2, + background_geo.height - internal_offset * 2); + GfxContext.PushClippingRectangle(internal_clip); + + + nux::Geometry geo_absolute = GetAbsoluteGeometry (); + if (BackgroundEffectHelper::blur_type != BLUR_NONE) + { + nux::Geometry blur_geo(geo_absolute.x, geo_absolute.y, base.width, base.height); + auto blur_texture = bg_helper_.GetBlurRegion(blur_geo); + + if (blur_texture.IsValid()) + { + nux::TexCoordXForm texxform_blur_bg; + texxform_blur_bg.flip_v_coord = true; + texxform_blur_bg.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD); + texxform_blur_bg.uoffset = ((float) base.x) / geo_absolute.width; + texxform_blur_bg.voffset = ((float) base.y) / geo_absolute.height; + + nux::ROPConfig rop; + rop.Blend = false; + rop.SrcBlend = GL_ONE; + rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA; + + gPainter.PushDrawTextureLayer(GfxContext, base, + blur_texture, + texxform_blur_bg, + nux::color::White, + true, + rop); + } + } + + nux::ROPConfig rop; + rop.Blend = true; + rop.SrcBlend = GL_ONE; + rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA; + gPainter.PushDrawColorLayer (GfxContext, internal_clip, background_color, false, rop); + + // Make round corners + rop.Blend = true; + rop.SrcBlend = GL_ZERO; + rop.DstBlend = GL_SRC_ALPHA; + gPainter.PaintShapeCornerROP(GfxContext, + internal_clip, + nux::color::White, + nux::eSHAPE_CORNER_ROUND4, + nux::eCornerTopLeft | nux::eCornerTopRight | + nux::eCornerBottomLeft | nux::eCornerBottomRight, + true, + rop); + + DrawOverlay(GfxContext, force_draw, internal_clip); + + GfxContext.PopClippingRectangle(); + GfxContext.PopClippingRectangle(); + + DrawBackground(GfxContext, background_geo); + + PostDraw(GfxContext, force_draw); +} + +void UnityWindowView::DrawBackground(nux::GraphicsEngine& GfxContext, nux::Geometry const& geo) +{ + int border = style()->GetBorderSize(); + + GfxContext.GetRenderStates().SetBlend (TRUE, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + nux::TexCoordXForm texxform; + texxform.SetTexCoordType (nux::TexCoordXForm::OFFSET_COORD); + texxform.SetWrap(nux::TEXWRAP_REPEAT, nux::TEXWRAP_REPEAT); + + // Draw TOP-LEFT CORNER + texxform.u0 = 0; + texxform.v0 = 0; + texxform.u1 = border; + texxform.v1 = border; + GfxContext.QRP_1Tex (geo.x, geo.y, + border, border, style()->GetBackgroundCorner()->GetDeviceTexture(), texxform, nux::color::White); + + // Draw TOP-RIGHT CORNER + texxform.u0 = 0; + texxform.v0 = 0; + texxform.u1 = border; + texxform.v1 = border; + texxform.flip_u_coord = true; + texxform.flip_v_coord = false; + GfxContext.QRP_1Tex (geo.x + geo.width - border, geo.y, + border, border, style()->GetBackgroundCorner()->GetDeviceTexture(), texxform, nux::color::White); + + // Draw BOTTOM-LEFT CORNER + texxform.u0 = 0; + texxform.v0 = 0; + texxform.u1 = border; + texxform.v1 = border; + texxform.flip_u_coord = false; + texxform.flip_v_coord = true; + GfxContext.QRP_1Tex (geo.x, geo.y + geo.height - border, + border, border, style()->GetBackgroundCorner()->GetDeviceTexture(), texxform, nux::color::White); + + // Draw BOTTOM-RIGHT CORNER + texxform.u0 = 0; + texxform.v0 = 0; + texxform.u1 = border; + texxform.v1 = border; + texxform.flip_u_coord = true; + texxform.flip_v_coord = true; + GfxContext.QRP_1Tex (geo.x + geo.width - border, geo.y + geo.height - border, + border, border, style()->GetBackgroundCorner()->GetDeviceTexture(), texxform, nux::color::White); + + int top_width = style()->GetBackgroundTop()->GetWidth(); + int top_height = style()->GetBackgroundTop()->GetHeight(); + + // Draw TOP BORDER + texxform.u0 = 0; + texxform.v0 = 0; + texxform.u1 = top_width; + texxform.v1 = top_height; + texxform.flip_u_coord = false; + texxform.flip_v_coord = false; + GfxContext.QRP_1Tex (geo.x + border, geo.y, geo.width - border - border, border, style()->GetBackgroundTop()->GetDeviceTexture(), texxform, nux::color::White); + + // Draw BOTTOM BORDER + texxform.u0 = 0; + texxform.v0 = 0; + texxform.u1 = top_width; + texxform.v1 = top_height; + texxform.flip_u_coord = false; + texxform.flip_v_coord = true; + GfxContext.QRP_1Tex (geo.x + border, geo.y + geo.height - border, geo.width - border - border, border, style()->GetBackgroundTop()->GetDeviceTexture(), texxform, nux::color::White); + + + int left_width = style()->GetBackgroundLeft()->GetWidth(); + int left_height = style()->GetBackgroundLeft()->GetHeight(); + + // Draw LEFT BORDER + texxform.u0 = 0; + texxform.v0 = 0; + texxform.u1 = left_width; + texxform.v1 = left_height; + texxform.flip_u_coord = false; + texxform.flip_v_coord = false; + GfxContext.QRP_1Tex (geo.x, geo.y + border, border, geo.height - border - border, style()->GetBackgroundLeft()->GetDeviceTexture(), texxform, nux::color::White); + + // Draw RIGHT BORDER + texxform.u0 = 0; + texxform.v0 = 0; + texxform.u1 = left_width; + texxform.v1 = left_height; + texxform.flip_u_coord = true; + texxform.flip_v_coord = false; + GfxContext.QRP_1Tex (geo.x + geo.width - border, geo.y + border, border, geo.height - border - border, style()->GetBackgroundLeft()->GetDeviceTexture(), texxform, nux::color::White); + + GfxContext.GetRenderStates().SetBlend (FALSE); +} + + +} +} diff --git a/plugins/unityshell/src/UnityWindowView.h b/plugins/unityshell/src/UnityWindowView.h new file mode 100644 index 000000000..f5342982b --- /dev/null +++ b/plugins/unityshell/src/UnityWindowView.h @@ -0,0 +1,65 @@ +// -*- 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: Jason Smith <jason.smith@canonical.com> + */ + +#ifndef UNITYWINDOWVIEW_H +#define UNITYWINDOWVIEW_H + +#include "BackgroundEffectHelper.h" +#include "UnityWindowStyle.h" +#include <sigc++/sigc++.h> + +#include <Nux/Nux.h> +#include <Nux/View.h> +#include <NuxCore/ObjectPtr.h> +#include <NuxCore/Property.h> + +namespace unity { +namespace ui { + +class UnityWindowView : public nux::View +{ + NUX_DECLARE_OBJECT_TYPE(UnityWindowView, nux::View) +public: + nux::Property<nux::Color> background_color; + nux::Property<UnityWindowStyle::Ptr> style; + + UnityWindowView(NUX_FILE_LINE_PROTO); + virtual ~UnityWindowView(); + + void SetupBackground(bool enabled = true); + +protected: + void Draw(nux::GraphicsEngine& GfxContext, bool force_draw); + void DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw); + + virtual void PreDraw(nux::GraphicsEngine& GfxContext, bool force_draw) {}; + virtual void DrawOverlay(nux::GraphicsEngine& GfxContext, bool force_draw, nux::Geometry clip) = 0; + virtual void PostDraw(nux::GraphicsEngine& GfxContext, bool force_draw) {}; + virtual nux::Geometry GetBackgroundGeometry() = 0; + +private: + void DrawBackground(nux::GraphicsEngine& GfxContext, nux::Geometry const& geo); + + BackgroundEffectHelper bg_helper_; +}; + +} +} + +#endif diff --git a/plugins/unityshell/src/WindowManager.cpp b/plugins/unityshell/src/WindowManager.cpp index 979609046..39c66de6a 100644 --- a/plugins/unityshell/src/WindowManager.cpp +++ b/plugins/unityshell/src/WindowManager.cpp @@ -103,7 +103,7 @@ class WindowManagerDummy : public WindowManager g_debug("%s", G_STRFUNC); } - void FocusWindowGroup(std::vector<Window> windows, FocusVisibility) + void FocusWindowGroup(std::vector<Window> windows, FocusVisibility, int monitor) { g_debug("%s", G_STRFUNC); } diff --git a/plugins/unityshell/src/WindowManager.h b/plugins/unityshell/src/WindowManager.h index 6d2a0809d..5663483b7 100644 --- a/plugins/unityshell/src/WindowManager.h +++ b/plugins/unityshell/src/WindowManager.h @@ -78,7 +78,7 @@ public: virtual void InitiateExpo() = 0; virtual bool IsExpoActive() = 0; - virtual void FocusWindowGroup(std::vector<Window> windows, FocusVisibility) = 0; + virtual void FocusWindowGroup(std::vector<Window> windows, FocusVisibility, int monitor = -1) = 0; virtual bool ScaleWindowGroup(std::vector<Window> windows, int state, bool force) = 0; virtual void Decorate(guint32 xid) {}; diff --git a/plugins/unityshell/src/unity-launcher-accessible.cpp b/plugins/unityshell/src/unity-launcher-accessible.cpp index e7cffcd96..7f9eacb52 100644 --- a/plugins/unityshell/src/unity-launcher-accessible.cpp +++ b/plugins/unityshell/src/unity-launcher-accessible.cpp @@ -23,7 +23,7 @@ * @see_also: Launcher * * #UnityLauncherAccessible implements the required ATK interfaces for - * #Launcher, ie: exposing the different LauncherIcon on the model as + * #Launcher, ie: exposing the different AbstractLauncherIcon on the model as * #child of the object. * */ @@ -38,7 +38,7 @@ #include "LauncherModel.h" using unity::launcher::Launcher; -using unity::launcher::LauncherIcon; +using unity::launcher::AbstractLauncherIcon; using unity::launcher::LauncherModel; /* GObject */ @@ -64,8 +64,8 @@ static gboolean unity_launcher_accessible_is_child_selected(AtkSelection* sele /* private */ static void on_selection_change_cb(UnityLauncherAccessible* launcher_accessible); -static void on_icon_added_cb(LauncherIcon* icon, UnityLauncherAccessible* self); -static void on_icon_removed_cb(LauncherIcon* icon, UnityLauncherAccessible* self); +static void on_icon_added_cb(AbstractLauncherIcon* icon, UnityLauncherAccessible* self); +static void on_icon_removed_cb(AbstractLauncherIcon* icon, UnityLauncherAccessible* self); static void on_order_change_cb(UnityLauncherAccessible* self); static void update_children_index(UnityLauncherAccessible* self); @@ -287,7 +287,7 @@ unity_launcher_accessible_ref_selection(AtkSelection* selection, gint i) { Launcher* launcher = NULL; - LauncherIcon* selected_icon = NULL; + AbstractLauncherIcon* selected_icon = NULL; nux::Object* nux_object = NULL; AtkObject* accessible_selected = NULL; @@ -315,7 +315,7 @@ static gint unity_launcher_accessible_get_selection_count(AtkSelection* selection) { Launcher* launcher = NULL; - LauncherIcon* selected_icon = NULL; + AbstractLauncherIcon* selected_icon = NULL; nux::Object* nux_object = NULL; g_return_val_if_fail(UNITY_IS_LAUNCHER_ACCESSIBLE(selection), 0); @@ -338,8 +338,8 @@ unity_launcher_accessible_is_child_selected(AtkSelection* selection, gint i) { Launcher* launcher = NULL; - LauncherIcon* icon = NULL; - LauncherIcon* selected_icon = NULL; + AbstractLauncherIcon* icon = NULL; + AbstractLauncherIcon* selected_icon = NULL; LauncherModel* launcher_model = NULL; LauncherModel::iterator it; nux::Object* nux_object = NULL; @@ -354,7 +354,7 @@ unity_launcher_accessible_is_child_selected(AtkSelection* selection, launcher_model = launcher->GetModel(); it = launcher_model->begin(); std::advance(it, i); - icon = dynamic_cast<LauncherIcon*>(*it); + icon = dynamic_cast<AbstractLauncherIcon*>(*it); selected_icon = launcher->GetSelectedMenuIcon(); @@ -372,7 +372,7 @@ static void on_selection_change_cb(UnityLauncherAccessible* launcher_accessible) static void -on_icon_added_cb(LauncherIcon* icon, +on_icon_added_cb(AbstractLauncherIcon* icon, UnityLauncherAccessible* self) { AtkObject* icon_accessible = NULL; @@ -396,7 +396,7 @@ on_icon_added_cb(LauncherIcon* icon, } static void -on_icon_removed_cb(LauncherIcon* icon, +on_icon_removed_cb(AbstractLauncherIcon* icon, UnityLauncherAccessible* self) { AtkObject* icon_accessible = NULL; diff --git a/plugins/unityshell/src/unity-switcher-accessible.cpp b/plugins/unityshell/src/unity-switcher-accessible.cpp index e49ccbf22..a61fcfbd7 100644 --- a/plugins/unityshell/src/unity-switcher-accessible.cpp +++ b/plugins/unityshell/src/unity-switcher-accessible.cpp @@ -391,7 +391,7 @@ create_children(UnitySwitcherAccessible* self) SwitcherView* switcher = NULL; SwitcherModel::Ptr switcher_model; SwitcherModel::iterator it; - LauncherIcon* child = NULL; + AbstractLauncherIcon* child = NULL; AtkObject* child_accessible = NULL; nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(self)); @@ -406,7 +406,7 @@ create_children(UnitySwitcherAccessible* self) for (it = switcher_model->begin(); it != switcher_model->end(); it++) { - child = dynamic_cast<LauncherIcon*>(*it); + child = dynamic_cast<AbstractLauncherIcon*>(*it); child_accessible = unity_launcher_icon_accessible_new(child); atk_object_set_parent(child_accessible, ATK_OBJECT(self)); self->priv->children = g_slist_append(self->priv->children, diff --git a/plugins/unityshell/src/unitya11ytests.cpp b/plugins/unityshell/src/unitya11ytests.cpp index 9ffbd122c..70bf6bb7b 100644 --- a/plugins/unityshell/src/unitya11ytests.cpp +++ b/plugins/unityshell/src/unitya11ytests.cpp @@ -224,7 +224,7 @@ a11y_unit_test_launcher_connection(void) g_debug("[a11y] Launcher accessible created correctly"); } - launcher_icon = new SimpleLauncherIcon(launcher); + launcher_icon = new SimpleLauncherIcon(); launcher_icon->SinkReference(); launcher_icon_accessible = unity_a11y_get_accessible(launcher_icon); diff --git a/plugins/unityshell/src/unityshell.cpp b/plugins/unityshell/src/unityshell.cpp index 05228efce..2d0f81913 100644 --- a/plugins/unityshell/src/unityshell.cpp +++ b/plugins/unityshell/src/unityshell.cpp @@ -67,6 +67,7 @@ COMPIZ_PLUGIN_20090315(unityshell, unity::UnityPluginVTable); namespace unity { +using namespace launcher; using launcher::AbstractLauncherIcon; using launcher::Launcher; using ui::KeyboardUtil; @@ -105,16 +106,16 @@ UnityScreen::UnityScreen(CompScreen* screen) , needsRelayout(false) , _in_paint(false) , relayoutSourceId(0) - , _edge_trigger_handle(0) , _redraw_handle(0) - , _edge_pointerY(0) , 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 +129,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 +185,7 @@ UnityScreen::UnityScreen(CompScreen* screen) failed = true; } } +#endif if (!failed) { @@ -199,16 +202,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)); @@ -223,9 +237,9 @@ UnityScreen::UnityScreen(CompScreen* screen) debugger = new unity::debug::DebugDBusInterface(this, this->screen); - _edge_timeout = optionGetLauncherRevealEdgeTimeout (); _in_paint = false; +#ifndef USE_GLES void *dlhand = dlopen ("libunityshell.so", RTLD_LAZY); if (dlhand) @@ -242,6 +256,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)); @@ -269,8 +284,6 @@ UnityScreen::UnityScreen(CompScreen* screen) optionSetExecuteCommandInitiate(boost::bind(&UnityScreen::executeCommand, this, _1, _2, _3)); optionSetPanelFirstMenuInitiate(boost::bind(&UnityScreen::showPanelFirstMenuKeyInitiate, this, _1, _2, _3)); optionSetPanelFirstMenuTerminate(boost::bind(&UnityScreen::showPanelFirstMenuKeyTerminate, this, _1, _2, _3)); - optionSetLauncherRevealEdgeInitiate(boost::bind(&UnityScreen::launcherRevealEdgeInitiate, this, _1, _2, _3)); - optionSetLauncherRevealEdgeTimeoutNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetAutomaximizeValueNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetAltTabTimeoutNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetAltTabBiasViewportNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); @@ -294,26 +307,17 @@ 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)); + optionSetStopVelocityNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); + optionSetRevealPressureNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); + optionSetOvercomePressureNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); + optionSetDecayRateNotify(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_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_LAUNCHER_END_KEY_NAV, + sigc::mem_fun(this, &UnityScreen::OnLauncherEndKeyNav)); g_idle_add_full (G_PRIORITY_DEFAULT, &UnityScreen::initPluginActions, this, NULL); super_keypressed_ = false; @@ -330,6 +334,7 @@ UnityScreen::UnityScreen(CompScreen* screen) ubus_manager_.RegisterInterest(UBUS_PLACE_VIEW_SHOWN, [&](GVariant * args) { dash_is_open_ = true; + dash_monitor_ = g_variant_get_int32(args); RaiseInputWindows(); }); ubus_manager_.RegisterInterest(UBUS_PLACE_VIEW_HIDDEN, [&](GVariant * args) { dash_is_open_ = false; }); @@ -343,13 +348,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); @@ -443,6 +441,7 @@ void UnityScreen::CreateSuperNewAction(char shortcut, bool use_shift, bool use_n 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 +458,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,20 +487,18 @@ void UnityScreen::nuxEpilogue() glReadBuffer(GL_BACK); glPopAttrib(); +#else + glDepthRangef(0, 1); + //glViewport(-1, -1, 2, 2); + gScreen->resetRasterPos(); +#endif glDisable(GL_SCISSOR_TEST); } -void UnityScreen::OnLauncherHiddenChanged() -{ - if (launcher_controller_->launcher().Hidden()) - screen->addAction(&optionGetLauncherRevealEdge()); - else - screen->removeAction(&optionGetLauncherRevealEdge()); -} - void UnityScreen::paintPanelShadow(const GLMatrix& matrix) { +#ifndef USE_GLES if (relayoutSourceId > 0) return; @@ -525,7 +524,22 @@ void UnityScreen::paintPanelShadow(const GLMatrix& matrix) vc[2] = y1; vc[3] = y2; - if (!dash_is_open_ && panel_controller_->opacity() > 0.0f) + // compiz doesn't use the same method of tracking monitors as our toolkit + // we need to make sure we properly associate with the right monitor + int current_monitor = -1; + auto monitors = UScreen::GetDefault()->GetMonitors(); + int i = 0; + for (auto monitor : monitors) + { + if (monitor.x == output->x() && monitor.y == output->y()) + { + current_monitor = i; + break; + } + i++; + } + + if (!(dash_is_open_ && current_monitor == dash_monitor_) && panel_controller_->opacity() > 0.0f) { foreach(GLTexture * tex, _shadow_texture) { @@ -559,6 +573,101 @@ 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; + + // compiz doesn't use the same method of tracking monitors as our toolkit + // we need to make sure we properly associate with the right monitor + int current_monitor = -1; + auto monitors = UScreen::GetDefault()->GetMonitors(); + int i = 0; + for (auto monitor : monitors) + { + if (monitor.x == output->x() && monitor.y == output->y()) + { + current_monitor = i; + break; + } + i++; + } + + if (!(dash_is_open_ && current_monitor == dash_monitor_) && 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 +682,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 +710,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 +722,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 +743,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 } } @@ -699,6 +845,25 @@ void UnityWindow::paintThumbnail (nux::Geometry const& bounding, float alpha) geo.height); } +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::enterShowDesktopMode () { for (CompWindow *w : screen->windows ()) @@ -1009,6 +1174,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 +1186,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 ®ion, + 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 */ @@ -1102,7 +1295,6 @@ void UnityScreen::damageNuxRegions() void UnityScreen::handleEvent(XEvent* event) { bool skip_other_plugins = false; - Launcher& launcher = launcher_controller_->launcher(); switch (event->type) { case FocusIn: @@ -1111,11 +1303,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(); + launcher_controller_->KeyNavGrab(); _key_nav_mode_requested = false; break; + case ButtonPress: + if (super_keypressed_) + { + launcher_controller_->KeyNavTerminate(false); + EnableCancelAction(false); + } + break; case KeyPress: { KeySym key_sym; @@ -1127,16 +1328,21 @@ 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(); - skip_other_plugins = launcher.CheckSuperShortcutPressed(screen->dpy(), key_sym, event->xkey.keycode, event->xkey.state, key_string); + g_idle_add([] (gpointer data) -> gboolean { + auto self = static_cast<UnityScreen*>(data); + if (!self->launcher_controller_->KeyNavIsActive()) + { + self->shortcut_controller_->SetEnabled(false); + self->shortcut_controller_->Hide(); + } + return FALSE; + }, this); + + skip_other_plugins = launcher_controller_->HandleLauncherKeyEvent(screen->dpy(), key_sym, event->xkey.keycode, event->xkey.state, key_string); if (!skip_other_plugins) - { skip_other_plugins = dash_controller_->CheckShortcutActivation(key_string); - if (skip_other_plugins) - launcher.SetLatestShortcut(key_string[0]); - } } } break; @@ -1225,10 +1431,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); @@ -1243,35 +1448,35 @@ bool UnityScreen::showLauncherKeyInitiate(CompAction* action, action->setState(action->state() | CompAction::StateTermKey); super_keypressed_ = true; - launcher_controller_->launcher().StartKeyShowLauncher(); + launcher_controller_->HandleLauncherKeyPress(); 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(); + int primary_monitor = uscreen->GetMonitorWithMouse(); 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,10 +1484,19 @@ bool UnityScreen::showLauncherKeyTerminate(CompAction* action, CompAction::State state, CompOption::Vector& options) { + if (state & CompAction::StateCancel) + return false; + + bool accept_state = (state & CompAction::StateCancel) == 0; + super_keypressed_ = false; - launcher_controller_->launcher().EndKeyShowLauncher(); - launcher_controller_->launcher().KeySwitcherTerminate(); + launcher_controller_->KeyNavTerminate(accept_state); + launcher_controller_->HandleLauncherKeyRelease(); + EnableCancelAction(false); + + shortcut_controller_->SetEnabled(enable_shortcut_overlay_); shortcut_controller_->Hide(); + action->setState (action->state() & (unsigned)~(CompAction::StateTermKey)); return false; } @@ -1307,75 +1521,10 @@ bool UnityScreen::showPanelFirstMenuKeyTerminate(CompAction* action, return false; } -gboolean UnityScreen::OnEdgeTriggerTimeout(gpointer data) -{ - UnityScreen* self = reinterpret_cast<UnityScreen*>(data); - - if (pointerX <= 1) - { - if (pointerY <= 24) - return true; - - if (abs(pointerY - self->_edge_pointerY) <= 5) - { - self->launcher_controller_->launcher().EdgeRevealTriggered(pointerX, pointerY); - } - else - { - /* We are still in the edge, but moving in Y, maybe we need another chance */ - - if (abs(pointerY - self->_edge_pointerY) > 20) - { - /* We're quite far from the first hit spot, let's wait again */ - self->_edge_pointerY = pointerY; - return true; - } - else - { - /* We're quite near to the first hit spot, so we can reduce our timeout */ - self->_edge_pointerY = pointerY; - g_source_remove(self->_edge_trigger_handle); - self->_edge_trigger_handle = g_timeout_add(self->_edge_timeout/2, - &UnityScreen::OnEdgeTriggerTimeout, - self); - return false; - } - } - } - - self->_edge_trigger_handle = 0; - return false; -} - -bool UnityScreen::launcherRevealEdgeInitiate(CompAction* action, - CompAction::State state, - CompOption::Vector& options) -{ - if (screen->grabbed()) - return false; - - if (_edge_trigger_handle) - g_source_remove(_edge_trigger_handle); - - if (pointerX <= 1) - { - _edge_pointerY = pointerY; - _edge_trigger_handle = g_timeout_add(_edge_timeout, - &UnityScreen::OnEdgeTriggerTimeout, - this); - } - - return false; -} - 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, @@ -1386,20 +1535,10 @@ bool UnityScreen::executeCommand(CompAction* action, return false; } -void UnityScreen::restartLauncherKeyNav() -{ - // set input-focus on launcher-window and start key-nav mode - if (newFocusedWindow != NULL) - { - newFocusedWindow->moveInputFocusTo(); - launcher_controller_->launcher().startKeyNavMode(); - } -} - void UnityScreen::startLauncherKeyNav() { // get CompWindow* of launcher-window - newFocusedWindow = screen->findWindow(launcher_controller_->launcher_input_window_id()); + newFocusedWindow = screen->findWindow(launcher_controller_->KeyNavLauncherInputWindowId()); // check if currently focused window isn't the launcher-window if (newFocusedWindow != screen->findWindow(screen->activeWindow())) @@ -1434,8 +1573,6 @@ bool UnityScreen::altTabInitiateCommon(CompAction *action, if (!grab_index_) return false; - std::vector<unity::launcher::AbstractLauncherIcon*> results = launcher_controller_->GetAltTabIcons(); - screen->addAction(&optionGetAltTabRight()); screen->addAction(&optionGetAltTabDetailStart()); screen->addAction(&optionGetAltTabDetailStop()); @@ -1447,12 +1584,19 @@ bool UnityScreen::altTabInitiateCommon(CompAction *action, switcher_controller_->SetWorkspace(nux::Geometry(screen->outputDevs()[device].x1() + 100, screen->outputDevs()[device].y1() + 100, screen->outputDevs()[device].width() - 200, - screen->outputDevs()[device].height() - 200)); + screen->outputDevs()[device].height() - 200), device); switcher::ShowMode show_mode = optionGetAltTabBiasViewport() ? switcher::ShowMode::CURRENT_VIEWPORT : switcher::ShowMode::ALL; RaiseInputWindows(); - switcher_controller_->Show(show_mode, switcher::SortMode::FOCUS_ORDER, false, results); + + int show_monitor = (show_mode == switcher::ShowMode::CURRENT_VIEWPORT) ? device : -1; + + std::vector<unity::launcher::AbstractLauncherIcon*> results = launcher_controller_->GetAltTabIcons(show_monitor); + + if (!(results.size() == 1 && results[0]->Type() == AbstractLauncherIcon::IconType::TYPE_BEGIN)) + switcher_controller_->Show(show_mode, switcher::SortMode::FOCUS_ORDER, false, results); + return true; } @@ -1541,35 +1685,41 @@ bool UnityScreen::altTabPrevWindowInitiate(CompAction* action, CompAction::State bool UnityScreen::launcherSwitcherForwardInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options) { - Launcher& launcher = launcher_controller_->launcher(); - - if (!launcher.KeySwitcherIsActive()) - launcher.KeySwitcherActivate(); + if (!launcher_controller_->KeyNavIsActive()) + { + launcher_controller_->KeyNavActivate(); + EnableCancelAction(true, action->key().modifiers()); + } else - launcher.KeySwitcherNext(); + { + launcher_controller_->KeyNavNext(); + } + action->setState(action->state() | CompAction::StateTermKey); return false; } bool UnityScreen::launcherSwitcherPrevInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options) { - launcher_controller_->launcher().KeySwitcherPrevious(); + launcher_controller_->KeyNavPrevious(); return false; } bool UnityScreen::launcherSwitcherTerminate(CompAction* action, CompAction::State state, CompOption::Vector& options) { - launcher_controller_->launcher().KeySwitcherTerminate(); + bool accept_state = (state & CompAction::StateCancel) == 0; + launcher_controller_->KeyNavTerminate(accept_state); + EnableCancelAction(false); + action->setState (action->state() & (unsigned)~(CompAction::StateTermKey)); 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,12 +1734,6 @@ void UnityScreen::OnLauncherEndKeyNav(GVariant* data, void* value) PluginAdapter::Default ()->restoreInputFocus (); } -void UnityScreen::OnQuicklistEndKeyNav(GVariant* data, void* value) -{ - UnityScreen* self = reinterpret_cast<UnityScreen*>(value); - self->restartLauncherKeyNav(); -} - gboolean UnityScreen::initPluginActions(gpointer data) { CompPlugin* p = CompPlugin::find("expo"); @@ -1770,7 +1914,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) { @@ -1786,7 +1934,11 @@ bool UnityWindow::glDraw(const GLMatrix& matrix, { if (xwns[i] == id) { +#ifdef USE_GLES + uScreen->paintDisplay(); +#else uScreen->paintDisplay(region, matrix, mask); +#endif break; } } @@ -1945,7 +2097,7 @@ void UnityWindow::windowNotify(CompWindowNotify n) if (us->dash_is_open_) { - lw = screen->findWindow(us->launcher_controller_->launcher_input_window_id()); + lw = screen->findWindow(us->launcher_controller_->LauncherWindowId(0)); lw->moveInputFocusTo(); } } @@ -1993,81 +2145,51 @@ void UnityWindow::resizeNotify(int x, int y, int w, int h) CompPoint UnityWindow::tryNotIntersectUI(CompPoint& pos) { UnityScreen* us = UnityScreen::get(screen); - Launcher& launcher = us->launcher_controller_->launcher(); - nux::Geometry geo = launcher.GetAbsoluteGeometry(); - CompRegion allowedWorkArea (screen->workArea ()); - CompRect launcherGeo(geo.x, geo.y, geo.width, geo.height); - CompRegion wRegion (window->borderRect ()); - CompRegion intRegion; + auto window_geo = window->borderRect (); + nux::Geometry target_monitor; + nux::Point result(pos.x(), pos.y()); - wRegion.translate (pos.x () - wRegion.boundingRect ().x (), - pos.y () - wRegion.boundingRect ().y ()); - - /* subtract launcher and panel geometries from allowed workarea */ - if (!launcher.Hidden()) + // seriously why does compiz not track monitors XRandR style??? + auto monitors = UScreen::GetDefault()->GetMonitors(); + for (auto monitor : monitors) { - switch (launcher.GetHideMode()) + if (monitor.IsInside(result)) { - case Launcher::LAUNCHER_HIDE_DODGE_WINDOWS: - case Launcher::LAUNCHER_HIDE_DODGE_ACTIVE_WINDOW: - allowedWorkArea -= launcherGeo; - break; - - default: - break; + target_monitor = monitor; + break; } } - for (nux::Geometry &g : us->panel_controller_->GetGeometries ()) + auto launchers = us->launcher_controller_->launchers(); + for (auto launcher : launchers) { - CompRect pg (g.x, g.y, g.width, g.height); - allowedWorkArea -= pg; - } - - /* Invert allowed work area */ - allowedWorkArea = CompRegion (screen->workArea ()) - allowedWorkArea; - - /* Now intersect the window region with the allowed work area - * region, such that it splits up into a number of rects */ - intRegion = wRegion.intersected (allowedWorkArea); - - if (intRegion.rects ().size () > 1) - { - /* Now find the largest rect, this will be the area that we want to move to */ - CompRect largest; - - for (CompRect &r : intRegion.rects ()) + nux::Geometry geo = launcher->GetAbsoluteGeometry(); + + if (launcher->Hidden() || launcher->GetHideMode() == LAUNCHER_HIDE_NEVER || launcher->GetHideMode() == LAUNCHER_HIDE_AUTOHIDE) + continue; + + if (geo.IsInside(result)) { - if (r.area () > largest.area ()) - largest = r; + if (geo.x + geo.width + 1 + window_geo.width() < target_monitor.x + target_monitor.width) + { + result.x = geo.x + geo.width + 1; + } } + } - /* Now pad the largest rect with the other rectangles that - * were intersecting, padding the opposite side to the one - * that they are currently on on the large rect - */ - - intRegion -= largest; - - for (CompRect &r : intRegion.rects ()) + for (nux::Geometry &geo : us->panel_controller_->GetGeometries ()) + { + if (geo.IsInside(result)) { - if (r.x1 () > largest.x2 ()) - largest.setX (largest.x () - r.width ()); - else if (r.x2 () < largest.x ()) - largest.setWidth (largest.width () + r.width ()); - - if (r.y1 () > largest.y2 ()) - largest.setY (largest.y () - r.height ()); - else if (r.y2 () < largest.y ()) - largest.setWidth (largest.height () + r.height ()); + if (geo.y + geo.height + window_geo.height() < target_monitor.y + target_monitor.height) + { + result.y = geo.y + geo.height; + } } - - pos = largest.pos (); } - if (launcherGeo.contains(pos)) - pos.setX(launcherGeo.x() + launcherGeo.width() + 1); - + pos.setX(result.x); + pos.setY(result.y); return pos; } @@ -2131,7 +2253,7 @@ void UnityScreen::onRedrawRequested() void UnityScreen::optionChanged(CompOption* opt, UnityshellOptions::Options num) { // Note: perhaps we should put the options here into the controller. - Launcher& launcher = launcher_controller_->launcher(); + unity::launcher::Options::Ptr launcher_options = launcher_controller_->options(); switch (num) { case UnityshellOptions::BackgroundColor: @@ -2148,16 +2270,16 @@ void UnityScreen::optionChanged(CompOption* opt, UnityshellOptions::Options num) break; } case UnityshellOptions::LauncherHideMode: - launcher.SetHideMode((Launcher::LauncherHideMode) optionGetLauncherHideMode()); + launcher_options->hide_mode = (unity::launcher::LauncherHideMode) optionGetLauncherHideMode(); break; case UnityshellOptions::BacklightMode: - launcher.SetBacklightMode((Launcher::BacklightMode) optionGetBacklightMode()); + launcher_options->backlight_mode = (unity::launcher::BacklightMode) optionGetBacklightMode(); break; case UnityshellOptions::LaunchAnimation: - launcher.SetLaunchAnimation((Launcher::LaunchAnimation) optionGetLaunchAnimation()); + launcher_options->launch_animation = (unity::launcher::LaunchAnimation) optionGetLaunchAnimation(); break; case UnityshellOptions::UrgentAnimation: - launcher.SetUrgentAnimation((Launcher::UrgentAnimation) optionGetUrgentAnimation()); + launcher_options->urgent_animation = (unity::launcher::UrgentAnimation) optionGetUrgentAnimation(); break; case UnityshellOptions::PanelOpacity: panel_controller_->SetOpacity(optionGetPanelOpacity()); @@ -2177,13 +2299,15 @@ void UnityScreen::optionChanged(CompOption* opt, UnityshellOptions::Options num) optionGetMenusDiscoveryFadeout()); break; case UnityshellOptions::LauncherOpacity: - launcher.SetBackgroundAlpha(optionGetLauncherOpacity()); + launcher_options->background_alpha = optionGetLauncherOpacity(); break; case UnityshellOptions::IconSize: { CompPlugin *p = CompPlugin::find ("expo"); - launcher.SetIconSize(optionGetIconSize() + 6, optionGetIconSize()); + launcher_options->icon_size = optionGetIconSize(); + launcher_options->tile_size = optionGetIconSize() + 6; + dash_controller_->launcher_width = optionGetIconSize() + 18; if (p) @@ -2205,7 +2329,7 @@ void UnityScreen::optionChanged(CompOption* opt, UnityshellOptions::Options num) break; } case UnityshellOptions::AutohideAnimation: - launcher.SetAutoHideAnimation((Launcher::AutoHideAnimation) optionGetAutohideAnimation()); + launcher_options->auto_hide_animation = (unity::launcher::AutoHideAnimation) optionGetAutohideAnimation(); break; case UnityshellOptions::DashBlurExperimental: BackgroundEffectHelper::blur_type = (unity::BlurType)optionGetDashBlurExperimental(); @@ -2216,9 +2340,6 @@ void UnityScreen::optionChanged(CompOption* opt, UnityshellOptions::Options num) case UnityshellOptions::DevicesOption: unity::DevicesSettings::GetDefault().SetDevicesOption((unity::DevicesSettings::DevicesOption) optionGetDevicesOption()); break; - case UnityshellOptions::LauncherRevealEdgeTimeout: - _edge_timeout = optionGetLauncherRevealEdgeTimeout(); - break; case UnityshellOptions::AltTabTimeout: switcher_controller_->detail_on_timeout = optionGetAltTabTimeout(); case UnityshellOptions::AltTabBiasViewport: @@ -2231,10 +2352,23 @@ 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()); break; + case UnityshellOptions::DecayRate: + launcher_options->edge_decay_rate = optionGetDecayRate() * 100; + break; + case UnityshellOptions::OvercomePressure: + launcher_options->edge_overcome_pressure = optionGetOvercomePressure() * 100; + break; + case UnityshellOptions::StopVelocity: + launcher_options->edge_stop_velocity = optionGetStopVelocity() * 100; + break; + case UnityshellOptions::RevealPressure: + launcher_options->edge_reveal_pressure = optionGetRevealPressure() * 100; + break; default: break; } @@ -2258,11 +2392,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(); @@ -2335,12 +2471,7 @@ void UnityScreen::initLauncher() { Timer timer; launcher_controller_.reset(new launcher::Controller(screen->dpy())); - primary_monitor_.changed.connect(sigc::mem_fun(launcher_controller_.get(), - &launcher::Controller::PrimaryMonitorGeometryChanged)); - - Launcher& launcher = launcher_controller_->launcher(); - launcher.hidden_changed.connect(sigc::mem_fun(this, &UnityScreen::OnLauncherHiddenChanged)); - AddChild(&launcher); + AddChild(launcher_controller_.get()); switcher_controller_.reset(new switcher::Controller()); AddChild(switcher_controller_.get()); @@ -2350,6 +2481,7 @@ void UnityScreen::initLauncher() /* Setup panel */ timer.Reset(); panel_controller_.reset(new panel::Controller()); + AddChild(panel_controller_.get()); panel_controller_->SetMenuShowTimings(optionGetMenusFadein(), optionGetMenusFadeout(), optionGetMenusDiscoveryDuration(), @@ -2367,13 +2499,7 @@ void UnityScreen::initLauncher() AddChild(dash_controller_.get()); - launcher.SetHideMode(Launcher::LAUNCHER_HIDE_DODGE_WINDOWS); - launcher.SetLaunchAnimation(Launcher::LAUNCH_ANIMATION_PULSE); - launcher.SetUrgentAnimation(Launcher::URGENT_ANIMATION_WIGGLE); - ScheduleRelayout(0); - - OnLauncherHiddenChanged(); } void UnityScreen::InitHints() @@ -2388,7 +2514,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"); diff --git a/plugins/unityshell/src/unityshell.h b/plugins/unityshell/src/unityshell.h index d81b1de29..0b05ef4f4 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 ®ion, + GLFramebufferObject *fbo, + unsigned int mask); +#endif /* paint in the special case that the output is transformed */ void glPaintTransformedOutput(const GLScreenPaintAttrib&, @@ -176,7 +187,6 @@ public: bool executeCommand(CompAction* action, CompAction::State state, CompOption::Vector& options); bool setKeyboardFocusKeyInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options); - bool launcherRevealEdgeInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options); bool altTabInitiateCommon(CompAction* action, CompAction::State state, @@ -225,6 +235,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(); @@ -236,19 +247,16 @@ private: static void initUnity(nux::NThread* thread, void* InitData); static void OnStartKeyNav(GVariant* data, void* value); static void OnExitKeyNav(GVariant* data, void* value); - static gboolean OnEdgeTriggerTimeout(gpointer data); static gboolean OnRedrawTimeout(gpointer data); void startLauncherKeyNav(); void restartLauncherKeyNav(); - void OnLauncherHiddenChanged(); void OnDashRealized (); - static void OnQuicklistEndKeyNav(GVariant* data, void* value); - static void OnLauncherStartKeyNav(GVariant* data, void* value); - static void OnLauncherEndKeyNav(GVariant* data, void* value); - + void OnLauncherStartKeyNav(GVariant* data); + void OnLauncherEndKeyNav(GVariant* data); + void InitHints(); dash::Settings dash_settings_; @@ -273,16 +281,12 @@ private: bool needsRelayout; bool _in_paint; guint32 relayoutSourceId; - guint _edge_timeout; - 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; bool super_keypressed_; + CompActionPtr _escape_action; /* keyboard-nav mode */ CompWindow* newFocusedWindow; @@ -302,19 +306,26 @@ private: unity::BGHash _bghash; +#ifdef USE_GLES + GLFramebufferObject *oldFbo; +#else ScreenEffectFramebufferObject::Ptr _fbo; GLuint _active_fbo; +#endif bool queryForShader (); UBusManager ubus_manager_; bool dash_is_open_; + int dash_monitor_; CompScreen::GrabHandle grab_index_; CompWindowList fullscreen_windows_; bool painting_tray_; unsigned int tray_paint_mask_; +#ifndef USE_GLES ScreenEffectFramebufferObject::GLXGetProcAddressProc glXGetProcAddressP; +#endif friend class UnityWindow; }; @@ -351,7 +362,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); diff --git a/plugins/unityshell/unityshell.xml.in b/plugins/unityshell/unityshell.xml.in index 8a12f90a1..6ec3de09b 100644 --- a/plugins/unityshell/unityshell.xml.in +++ b/plugins/unityshell/unityshell.xml.in @@ -42,20 +42,6 @@ <options> <group> <_short>Behaviour</_short> - <option name="launcher_reveal_edge" type="edge"> - <_short>Reveal Mode</_short> - <_long>From which edge should the launcher reveal.</_long> - <default> - <edge name="Left"/> - </default> - </option> - <option name="launcher_reveal_edge_timeout" type="int"> - <_short>Edge Reveal Timeout</_short> - <_long>How long (in ms) wait before revealing the launcher when the mouse pointer is touching the edge.</_long> - <min>1</min> - <max>1000</max> - <default>150</default> - </option> <option name="launcher_hide_mode" type="int"> <_short>Hide Launcher</_short> <_long>Make the launcher hide automatically after some time of inactivity: always or just when the focussed window is not over the launcher</_long> @@ -282,6 +268,38 @@ <max>64</max> <precision>1</precision> </option> + <option name="reveal_pressure" type="int"> + <_short>Launcher Reveal Pressure</_short> + <_long>Amount of mouse pressure required to reveal launcher</_long> + <default>20</default> + <min>1</min> + <max>1000</max> + <precision>1</precision> + </option> + <option name="overcome_pressure" type="int"> + <_short>Launcher Edge Stop Overcome Pressure</_short> + <_long>Amount of mouse pressure required to push into the next monitor</_long> + <default>20</default> + <min>1</min> + <max>1000</max> + <precision>1</precision> + </option> + <option name="decay_rate" type="int"> + <_short>Pressure Decay Rate</_short> + <_long>The rate at which mouse pressure decays</_long> + <default>15</default> + <min>1</min> + <max>1000</max> + <precision>1</precision> + </option> + <option name="stop_velocity" type="int"> + <_short>Edge Stop Velocity</_short> + <_long>The maximum velocity at which the mouse will still be stoped</_long> + <default>45</default> + <min>1</min> + <max>1000</max> + <precision>1</precision> + </option> <option name="autohide_animation" type="int"> <_short>Hide Animation</_short> <_long>Animation played when the launcher is showing or hiding</_long> 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/CMakeLists.txt b/services/CMakeLists.txt index 095784536..a1dc073f8 100644 --- a/services/CMakeLists.txt +++ b/services/CMakeLists.txt @@ -2,7 +2,7 @@ # Panel Service # find_package(PkgConfig) -pkg_check_modules(SERVICE_DEPS REQUIRED gtk+-3.0 gobject-2.0 gio-2.0 gthread-2.0 indicator3-0.4=>0.4.90 x11 gconf-2.0) +pkg_check_modules(SERVICE_DEPS REQUIRED gtk+-3.0>=3.3 gobject-2.0 gio-2.0 gthread-2.0 indicator3-0.4=>0.4.90 x11 gconf-2.0) execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} indicator3-0.4 --variable indicatordir OUTPUT_VARIABLE _indicatordir OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} indicator3-0.4 --variable iconsdir OUTPUT_VARIABLE _iconsdir OUTPUT_STRIP_TRAILING_WHITESPACE) diff --git a/services/panel-service.c b/services/panel-service.c index c2ce7e3db..cbd8368ad 100644 --- a/services/panel-service.c +++ b/services/panel-service.c @@ -32,6 +32,7 @@ #include <gdk/gdkx.h> #include <X11/extensions/XInput2.h> +#include <X11/XKBlib.h> #include "panel-marshal.h" @@ -55,6 +56,8 @@ struct _PanelServicePrivate gint32 timeouts[N_TIMEOUT_SLOTS]; IndicatorObjectEntry *last_entry; + GtkWidget *menubar; + GtkWidget *offscreen_window; GtkMenu *last_menu; guint32 last_menu_id; guint32 last_menu_move_id; @@ -138,6 +141,24 @@ panel_service_class_dispose (GObject *object) gdk_window_remove_filter (NULL, (GdkFilterFunc)event_filter, object); + if (G_IS_OBJECT (priv->menubar)) + { + g_object_unref (priv->menubar); + priv->menubar = NULL; + } + + if (G_IS_OBJECT (priv->offscreen_window)) + { + g_object_unref (priv->offscreen_window); + priv->offscreen_window = NULL; + } + + if (G_IS_OBJECT (priv->last_menu)) + { + g_object_unref (priv->last_menu); + priv->last_menu = NULL; + } + if (priv->initial_sync_id) { g_source_remove (priv->initial_sync_id); @@ -249,9 +270,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)); } } @@ -443,6 +464,10 @@ panel_service_init (PanelService *self) PanelServicePrivate *priv; priv = self->priv = GET_PRIVATE (self); + priv->offscreen_window = gtk_offscreen_window_new (); + priv->menubar = gtk_menu_bar_new (); + gtk_container_add (GTK_CONTAINER (priv->offscreen_window), priv->menubar); + gdk_window_add_filter (NULL, (GdkFilterFunc)event_filter, self); priv->panel2entries_hash = g_hash_table_new_full (g_str_hash, g_str_equal, @@ -1121,6 +1146,11 @@ on_active_menu_hidden (GtkMenu *menu, PanelService *self) g_signal_handler_disconnect (priv->last_menu, priv->last_menu_id); g_signal_handler_disconnect (priv->last_menu, priv->last_menu_move_id); + + GtkWidget *top_win = gtk_widget_get_toplevel (GTK_WIDGET (priv->last_menu)); + if (GTK_IS_WINDOW (top_win)) + gtk_window_set_attached_to (GTK_WINDOW (top_win), NULL); + priv->last_menu = NULL; priv->last_menu_id = 0; priv->last_menu_move_id = 0; @@ -1521,6 +1551,16 @@ panel_service_actually_show_entry (PanelService *self, G_CALLBACK (gtk_widget_destroyed), &priv->last_menu); } + GtkWidget *top_widget = gtk_widget_get_toplevel (GTK_WIDGET (priv->last_menu)); + + if (GTK_IS_WINDOW (top_widget)) + { + GtkWindow *top_win = GTK_WINDOW (top_widget); + + if (gtk_window_get_attached_to (top_win) != priv->menubar) + gtk_window_set_attached_to (top_win, priv->menubar); + } + priv->last_entry = entry; priv->last_x = x; priv->last_y = y; @@ -1557,7 +1597,7 @@ panel_service_actually_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 110424524..85b016ac7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -121,6 +121,7 @@ if (GTEST_FOUND AND # The actual test executable (xless) - do not put anything that requires X in here add_executable(test-gtest-xless test_animator.cpp + test_launcher_model.cpp test_glib_object.cpp test_glib_object_utils.cpp test_glib_object_utils.h @@ -130,11 +131,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 @@ -147,6 +150,10 @@ if (GTEST_FOUND AND ${UNITY_SRC}/FavoriteStore.h ${UNITY_SRC}/FavoriteStoreGSettings.cpp ${UNITY_SRC}/FavoriteStoreGSettings.h + ${UNITY_SRC}/LauncherModel.cpp + ${UNITY_SRC}/LauncherModel.h + ${UNITY_SRC}/FavoriteStorePrivate.cpp + ${UNITY_SRC}/FavoriteStorePrivate.h ${UNITY_SRC}/MockLauncherIcon.h ${UNITY_SRC}/MockShortcutHint.h ${UNITY_SRC}/ShortcutModel.cpp @@ -163,11 +170,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) @@ -195,10 +202,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/autopilot/autopilot/emulators/X11.py b/tests/autopilot/autopilot/emulators/X11.py index 5d2fd7606..8ee7c0d65 100644 --- a/tests/autopilot/autopilot/emulators/X11.py +++ b/tests/autopilot/autopilot/emulators/X11.py @@ -22,16 +22,22 @@ from Xlib import X from Xlib import XK from Xlib.display import Display from Xlib.ext.xtest import fake_input +import gtk.gdk class Keyboard(object): '''Wrapper around xlib to make faking keyboard input possible''' _lame_hardcoded_keycodes = { + 'E' : 9, # escape 'A' : 64, 'C' : 37, 'S' : 50, 'T' : 23, 'W' : 133, - 'U' : 111 + 'U' : 111, # up arrow + 'D' : 116, # down arrow + 'L' : 113, # left arrow + 'R' : 114, # right arrow + '1' : 67 # f1 } _special_X_keysyms = { @@ -168,7 +174,7 @@ class Keyboard(object): class Mouse(object): '''Wrapper around xlib to make moving the mouse easier''' - + def __init__(self): self._display = Display() @@ -179,62 +185,90 @@ class Mouse(object): @property def y(self): return self.position()[1] - + def press(self, button=1): '''Press mouse button at current mouse location''' fake_input(self._display, X.ButtonPress, button) self._display.sync() - + def release(self, button=1): '''Releases mouse button at current mouse location''' fake_input(self._display, X.ButtonRelease, button) self._display.sync() - + def click(self, button=1): '''Click mouse at current location''' self.press(button) sleep(0.25) self.release(button) - - def move(self, x, y, animate=True): - '''Moves mouse to location (x, y)''' - def perform_move(x, y): - fake_input(self._display, X.MotionNotify, x=x, y=y) + + def move(self, x, y, animate=True, rate=100, time_between_events=0.001): + '''Moves mouse to location (x, y, pixels_per_event, time_between_event)''' + def perform_move(x, y, sync): + fake_input(self._display, X.MotionNotify, sync, X.CurrentTime, X.NONE, x=x, y=y) self._display.sync() - sleep(0.001) + sleep(time_between_events) if not animate: - perform_move(x, y) - + perform_move(x, y, False) + dest_x, dest_y = x, y curr_x, curr_y = self.position() - + # calculate a path from our current position to our destination dy = float(curr_y - dest_y) dx = float(curr_x - dest_x) slope = dy/dx if dx > 0 else 0 yint = curr_y - (slope * curr_x) - xscale = 1 if dest_x > curr_x else -1 - + xscale = rate if dest_x > curr_x else -rate + while (int(curr_x) != dest_x): - curr_x += xscale; - curr_y = int(slope * curr_x + yint) if curr_y > 0 else dest_y - - perform_move(curr_x, curr_y) - + target_x = min(curr_x + xscale, dest_x) if dest_x > curr_x else max(curr_x + xscale, dest_x) + perform_move(target_x - curr_x, 0, True) + curr_x = target_x; + if (curr_y != dest_y): - yscale = 1 if dest_y > curr_y else -1 + yscale = rate if dest_y > curr_y else -rate while (curr_y != dest_y): - curr_y += yscale - perform_move(curr_x, curr_y) - + target_y = min(curr_y + yscale, dest_y) if dest_y > curr_y else max(curr_y + yscale, dest_y) + perform_move(0, target_y - curr_y, True) + curr_y = target_y + def position(self): '''Returns the current position of the mouse pointer''' coord = self._display.screen().root.query_pointer()._data x, y = coord["root_x"], coord["root_y"] return x, y - + def reset(self): self.move(16, 13, animate=False) self.click() self.move(800, 500, animate=False) + + +class ScreenGeometry: + """Get details about screen geometry.""" + + def __init__(self): + self._default_screen = gtk.gdk.screen_get_default() + + def get_num_monitors(self): + """Get the number of monitors attached to the PC.""" + return self._default_screen.get_n_monitors() + + def get_monitor_geometry(self, monitor_number): + """Get the geometry for a particular monitor. + + Returns a tuple containing (x,y,width,height). + + """ + if monitor_number >= self.get_num_monitors(): + raise ValueError('Specified monitor number is out of range.') + return tuple(self._default_screen.get_monitor_geometry(monitor_number)) + + def move_mouse_to_monitor(self, monitor_number): + """Move the mouse to the center of the specified monitor.""" + geo = self.get_monitor_geometry(monitor_number) + x = geo[0] + (geo[2]/2) + y = geo[1] + (geo[3]/2) + Mouse().move(x,y, False) #dont animate this or it might not get there due to barriers diff --git a/tests/autopilot/autopilot/emulators/unity.py b/tests/autopilot/autopilot/emulators/unity.py index c3f5219e4..dfcd89a14 100644 --- a/tests/autopilot/autopilot/emulators/unity.py +++ b/tests/autopilot/autopilot/emulators/unity.py @@ -2,11 +2,11 @@ # Copyright 2011 Canonical # Author: Alex Launi # -# 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 +# 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 script is designed to run unity in a test drive manner. It will drive +# This script is designed to run unity in a test drive manner. It will drive # X and test the GL calls that Unity makes, so that we can easily find out if # we are triggering graphics driver/X bugs. @@ -19,7 +19,7 @@ from compizconfig import Plugin import dbus from time import sleep -from autopilot.emulators.X11 import Keyboard, Mouse +from autopilot.emulators.X11 import Keyboard, Mouse, ScreenGeometry from autopilot.globals import global_context class Unity(object): @@ -39,6 +39,7 @@ class Unity(object): self.INTROSPECTION_IFACE = 'com.canonical.Unity.Debug.Introspection' self._mouse = Mouse() self._keyboard = Keyboard() + self._screen = ScreenGeometry() self._bus = dbus.SessionBus() self._debug_proxy_obj = self._bus.get_object(self.UNITY_BUS_NAME, @@ -67,22 +68,113 @@ class Launcher(Unity): self.height = 0 self.show_timeout = 1 self.hide_timeout = 1 + self.grabbed = False - def move_mouse_to_reveal_pos(self): - self._mouse.move(self.x, self.y) + def move_mouse_to_right_of_launcher(self, monitor): + (x, y, w, h) = self.launcher_geometry(monitor) + self._mouse.move(x + w + 15, y + h / 2, False) sleep(self.show_timeout) + + def move_mouse_over_launcher(self, monitor): + (x, y, w, h) = self.launcher_geometry(monitor) + self._screen.move_mouse_to_monitor(monitor); + self._mouse.move(x + w / 2, y + h / 2); + + def reveal_launcher(self, monitor): + (x, y, w, h) = self.launcher_geometry(monitor) + self._mouse.move(x - 920, y + h / 2, True, 5, .002) + sleep(self.show_timeout) + + def keyboard_reveal_launcher(self): + self._keyboard.press('^W') + sleep(1) + + def keyboard_unreveal_launcher(self): + self._keyboard.release('^W') + sleep(1) - def move_mouse_outside_of_boundry(self): - self._mouse.move(self.x + (self.width *2), self._mouse.y) - sleep(self.hide_timeout) + def grab_switcher(self): + self._keyboard.press_and_release('^A^1') + self.grabbed = True - def is_showing(self): - state = self.__get_state() + def switcher_enter_quicklist(self): + if self.grabbed: + self._keyboard.press_and_release('^R') + + def switcher_exit_quicklist(self): + if self.grabbed: + self._keyboard.press_and_release('^L') + + def start_switcher(self): + self._keyboard.press('^W^T') + self._keyboard.release('^T') + sleep(1) + + def end_switcher(self, cancel): + if cancel: + self._keyboard.press_and_release('^E') + if self.grabbed != True: + self._keyboard.release('^W') + else: + if self.grabbed: + self._keyboard.press_and_release('\n') + else: + self._keyboard.release('^W') + self.grabbed = False + + def switcher_next(self): + if self.grabbed: + self._keyboard.press_and_release('^D') + else: + self._keyboard.press_and_release('^T') + + def switcher_prev(self): + if self.grabbed: + self._keyboard.press_and_release('^U') + else: + self._keyboard.press_and_release('^S^T') + + def quicklist_open(self, monitor): + state = self.__get_state(monitor) + return bool(state['quicklist-open']) + + def is_showing(self, monitor): + state = self.__get_state(monitor) return not bool(state['hidden']) - - def __get_state(self): + + def key_nav_is_active(self): + state = self.__get_controller_state() + return bool(state['key_nav_is_active']) + + def key_nav_monitor(self): + state = self.__get_controller_state() + return int(state['key_nav_launcher_monitor']) + + def key_nav_is_grabbed(self): + state = self.__get_controller_state() + return bool(state['key_nav_is_grabbed']) + + def key_nav_selection(self): + state = self.__get_controller_state() + return int(state['key_nav_selection']) + + def launcher_geometry(self, monitor): + state = self.__get_state(monitor); + x = int(state['x']) + y = int(state['y']) + width = int(state['width']) + height = int(state['height']) + return (x, y, width, height) + + def num_launchers(self): + return len(super(Launcher, self).get_state('/Unity/LauncherController/Launcher')) + + def __get_controller_state(self): + return super(Launcher, self).get_state('/Unity/LauncherController')[0] + + def __get_state(self, monitor): # get the state for the 'launcher' piece - return super(Launcher, self).get_state('/Unity/Launcher')[0] + return super(Launcher, self).get_state('/Unity/LauncherController/Launcher[monitor=%s]' % (monitor))[0] class UnityLauncherIconTooltip(Unity): diff --git a/tests/autopilot/autopilot/tests/test_launcher.py b/tests/autopilot/autopilot/tests/test_launcher.py index 924def309..c53831448 100644 --- a/tests/autopilot/autopilot/tests/test_launcher.py +++ b/tests/autopilot/autopilot/tests/test_launcher.py @@ -1,9 +1,12 @@ from testtools import TestCase from testtools.matchers import Equals +from testtools.matchers import LessThan from autopilot.emulators.unity import Launcher from autopilot.glibrunner import GlibRunner +from time import sleep + class LauncherTests(TestCase): run_test_with = GlibRunner @@ -11,7 +14,108 @@ class LauncherTests(TestCase): super(LauncherTests, self).setUp() self.server = Launcher() + def test_launcher_switcher_ungrabbed(self): + """Tests basic key nav integration without keyboard grabs.""" + sleep(.5) + + self.server.start_switcher() + sleep(.5) + + self.assertThat(self.server.key_nav_is_active(), Equals(True)) + self.assertThat(self.server.key_nav_is_grabbed(), Equals(False)) + self.assertThat(self.server.key_nav_selection(), Equals(0)) + + self.server.switcher_next() + sleep(.5) + self.assertThat(0, LessThan(self.server.key_nav_selection())) + + self.server.switcher_prev() + sleep(.5) + self.assertThat(self.server.key_nav_selection(), Equals(0)) + + self.server.end_switcher(True) + sleep(.5) + self.assertThat(self.server.key_nav_is_active(), Equals(False)) + + def test_launcher_switcher_grabbed(self): + """Tests basic key nav integration via keyboard grab.""" + sleep(.5) + + self.server.grab_switcher() + sleep(.5) + + self.assertThat(self.server.key_nav_is_active(), Equals(True)) + self.assertThat(self.server.key_nav_is_grabbed(), Equals(True)) + self.assertThat(self.server.key_nav_selection(), Equals(0)) + + self.server.switcher_next() + sleep(.5) + self.assertThat(0, LessThan(self.server.key_nav_selection())) + + self.server.switcher_prev() + sleep(.5) + self.assertThat(self.server.key_nav_selection(), Equals(0)) + + self.server.end_switcher(True) + sleep(.5) + self.assertThat(self.server.key_nav_is_active(), Equals(False)) + + def test_launcher_switcher_quicklist_interaction(self): + """Tests that the key nav opens and closes quicklists properly and regrabs afterwards.""" + self.server.move_mouse_to_right_of_launcher(0) + sleep(.5) + + self.server.grab_switcher() + sleep(.5) + + self.assertThat(self.server.key_nav_is_active(), Equals(True)) + self.assertThat(self.server.key_nav_is_grabbed(), Equals(True)) + + self.server.switcher_next() + sleep(.5) + + self.server.switcher_enter_quicklist() + sleep(.5) + self.assertThat(self.server.quicklist_open(0), Equals(True)) + self.server.switcher_exit_quicklist() + sleep(.5) + + self.assertThat(self.server.quicklist_open(0), Equals(False)) + self.assertThat(self.server.key_nav_is_active(), Equals(True)) + self.assertThat(self.server.key_nav_is_grabbed(), Equals(True)) + + self.server.end_switcher(True) + sleep(.5) + self.assertThat(self.server.key_nav_is_active(), Equals(False)) + def test_reveal_on_mouse_to_edge(self): - self.server.move_mouse_outside_of_boundry() - self.server.move_mouse_to_reveal_pos() - self.assertThat(self.server.is_showing(), Equals(True)) + """Tests reveal of launchers by mouse pressure.""" + num_launchers = self.server.num_launchers() + + for x in range(num_launchers): + self.server.move_mouse_to_right_of_launcher(x) + self.server.reveal_launcher(x) + self.assertThat(self.server.is_showing(x), Equals(True)) + + def test_reveal_with_mouse_under_launcher(self): + """Tests that the launcher hides properly if the + mouse is under the launcher when it is revealed.""" + num_launchers = self.server.num_launchers() + + for x in range(num_launchers): + self.server.move_mouse_over_launcher(x) + self.server.keyboard_reveal_launcher() + self.server.keyboard_unreveal_launcher() + self.assertThat(self.server.is_showing(x), Equals(False)) + + def test_reveal_does_not_hide_again(self): + """Tests reveal of launchers by mouse pressure to ensure it doesn't automatically hide again.""" + num_launchers = self.server.num_launchers() + + for x in range(num_launchers): + self.server.move_mouse_to_right_of_launcher(x) + self.server.reveal_launcher(x) + sleep(2) + self.assertThat(self.server.is_showing(x), Equals(True)) + + 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_launcher_model.cpp b/tests/test_launcher_model.cpp new file mode 100644 index 000000000..e64d3b9d6 --- /dev/null +++ b/tests/test_launcher_model.cpp @@ -0,0 +1,216 @@ +/* + * 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: Jason Smith <jason.smith@canonical.com> + * + */ + +#include <gtest/gtest.h> + +#include "LauncherModel.h" +#include "MockLauncherIcon.h" +#include "AbstractLauncherIcon.h" + +#include <vector> + + +using namespace unity::launcher; + +namespace +{ + +class EventListener +{ + public: + EventListener() + { + icon_added = false; + icon_removed = false; + } + + void OnIconAdded (AbstractLauncherIcon* icon) + { + icon_added = true; + } + + void OnIconRemoved (AbstractLauncherIcon* icon) + { + icon_removed = true; + } + + bool icon_added; + bool icon_removed; +}; +//bool seen_result; + +TEST(TestLauncherModel, TestConstructor) +{ + LauncherModel::Ptr model(new LauncherModel()); + EXPECT_EQ(model->Size(), 0); +} + +TEST(TestLauncherModel, TestAdd) +{ + AbstractLauncherIcon* first = new MockLauncherIcon(); + LauncherModel::Ptr model(new LauncherModel()); + + EXPECT_EQ(model->Size(), 0); + model->AddIcon(first); + EXPECT_EQ(model->Size(), 1); +} + +TEST(TestLauncherModel, TestRemove) +{ + AbstractLauncherIcon* first = new MockLauncherIcon(); + LauncherModel::Ptr model(new LauncherModel()); + + EXPECT_EQ(model->Size(), 0); + model->AddIcon(first); + EXPECT_EQ(model->Size(), 1); + model->RemoveIcon(first); + EXPECT_EQ(model->Size(), 0); +} + +TEST(TestLauncherModel, TestAddSignal) +{ + AbstractLauncherIcon* first = new MockLauncherIcon(); + LauncherModel::Ptr model(new LauncherModel()); + + EventListener *listener = new EventListener(); + + model->icon_added.connect(sigc::mem_fun(listener, &EventListener::OnIconAdded)); + model->AddIcon(first); + EXPECT_EQ(listener->icon_added, true); + + delete listener; +} + +TEST(TestLauncherModel, TestRemoveSignal) +{ + AbstractLauncherIcon* first = new MockLauncherIcon(); + LauncherModel::Ptr model(new LauncherModel()); + + EventListener *listener = new EventListener(); + + model->icon_removed.connect(sigc::mem_fun(listener, &EventListener::OnIconRemoved)); + model->AddIcon(first); + EXPECT_EQ(listener->icon_removed, false); + model->RemoveIcon(first); + EXPECT_EQ(listener->icon_removed, true); + + delete listener; +} + +TEST(TestLauncherModel, TestSort) +{ + AbstractLauncherIcon* first = new MockLauncherIcon(); + AbstractLauncherIcon* second = new MockLauncherIcon(); + AbstractLauncherIcon* third = new MockLauncherIcon(); + AbstractLauncherIcon* fourth = new MockLauncherIcon(); + + LauncherModel::Ptr model(new LauncherModel()); + + third->SetSortPriority(0); + model->AddIcon(third); + + first->SetSortPriority(-1); + model->AddIcon(first); + + fourth->SetSortPriority(2); + model->AddIcon(fourth); + + second->SetSortPriority(0); + model->AddIcon(second); + + LauncherModel::iterator it; + it = model->begin(); + + EXPECT_EQ(first, *it); + it++; + EXPECT_EQ(second, *it); + it++; + EXPECT_EQ(third, *it); + it++; + EXPECT_EQ(fourth, *it); +} + +TEST(TestLauncherModel, TestReorderBefore) +{ + AbstractLauncherIcon* first = new MockLauncherIcon(); + AbstractLauncherIcon* second = new MockLauncherIcon(); + AbstractLauncherIcon* third = new MockLauncherIcon(); + AbstractLauncherIcon* fourth = new MockLauncherIcon(); + + LauncherModel::Ptr model(new LauncherModel()); + + first->SetSortPriority(0); + second->SetSortPriority(1); + third->SetSortPriority(2); + fourth->SetSortPriority(3); + + model->AddIcon(first); + model->AddIcon(second); + model->AddIcon(third); + model->AddIcon(fourth); + + model->ReorderBefore(third, second, false); + + LauncherModel::iterator it; + it = model->begin(); + + EXPECT_EQ(first, *it); + it++; + EXPECT_EQ(third, *it); + it++; + EXPECT_EQ(second, *it); + it++; + EXPECT_EQ(fourth, *it); +} + +TEST(TestLauncherModel, TestReorderSmart) +{ + AbstractLauncherIcon* first = new MockLauncherIcon(); + AbstractLauncherIcon* second = new MockLauncherIcon(); + AbstractLauncherIcon* third = new MockLauncherIcon(); + AbstractLauncherIcon* fourth = new MockLauncherIcon(); + + LauncherModel::Ptr model(new LauncherModel()); + + first->SetSortPriority(0); + second->SetSortPriority(1); + third->SetSortPriority(2); + fourth->SetSortPriority(3); + + model->AddIcon(first); + model->AddIcon(second); + model->AddIcon(third); + model->AddIcon(fourth); + + model->ReorderSmart(third, second, false); + + LauncherModel::iterator it; + it = model->begin(); + + EXPECT_EQ(first, *it); + it++; + EXPECT_EQ(third, *it); + it++; + EXPECT_EQ(second, *it); + it++; + EXPECT_EQ(fourth, *it); +} + +} 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') + |
