summaryrefslogtreecommitdiff
diff options
-rw-r--r--CMakeLists.txt1
-rw-r--r--UnityCore/CMakeLists.txt2
-rw-r--r--UnityCore/GLibDBusProxy.cpp2
-rw-r--r--UnityCore/GLibDBusServer.cpp738
-rw-r--r--UnityCore/GLibDBusServer.h116
-rw-r--r--UnityCore/MultiRangeFilter.cpp78
-rw-r--r--config.h.cmake3
-rw-r--r--dash/DashController.cpp102
-rw-r--r--dash/DashController.h12
-rw-r--r--dash/DashView.cpp12
-rw-r--r--dash/FilterAllButton.cpp2
-rw-r--r--dash/FilterAllButton.h1
-rw-r--r--dash/FilterBasicButton.cpp2
-rw-r--r--dash/FilterBasicButton.h1
-rw-r--r--dash/FilterFactory.cpp2
-rw-r--r--dash/FilterGenreButton.cpp2
-rw-r--r--dash/FilterGenreButton.h1
-rw-r--r--dash/FilterMultiRangeButton.cpp39
-rw-r--r--dash/FilterMultiRangeButton.h3
-rw-r--r--dash/FilterMultiRangeWidget.cpp261
-rw-r--r--dash/FilterMultiRangeWidget.h29
-rw-r--r--dash/FilterRatingsButton.cpp3
-rw-r--r--dash/FilterRatingsButton.h1
-rw-r--r--dash/PreviewStateMachine.cpp1
-rw-r--r--dash/previews/SocialPreviewContent.cpp3
-rw-r--r--debian/changelog130
-rw-r--r--debian/control9
-rwxr-xr-xdebian/rules5
-rwxr-xr-xdebian/scopes-recommends-generator27
-rw-r--r--debian/watch3
-rw-r--r--hud/HudController.cpp40
-rw-r--r--hud/HudView.cpp1
-rw-r--r--launcher/AbstractLauncherIcon.h6
-rw-r--r--launcher/ApplicationLauncherIcon.cpp32
-rw-r--r--launcher/ApplicationLauncherIcon.h4
-rw-r--r--launcher/BFBLauncherIcon.cpp3
-rw-r--r--launcher/CMakeLists.txt1
-rw-r--r--launcher/EdgeBarrierController.cpp36
-rw-r--r--launcher/EdgeBarrierControllerPrivate.h2
-rw-r--r--launcher/ExpoLauncherIcon.cpp5
-rw-r--r--launcher/ExpoLauncherIcon.h1
-rw-r--r--launcher/HudLauncherIcon.cpp3
-rw-r--r--launcher/Launcher.cpp60
-rw-r--r--launcher/Launcher.h10
-rw-r--r--launcher/LauncherController.cpp212
-rw-r--r--launcher/LauncherController.h3
-rw-r--r--launcher/LauncherControllerPrivate.h17
-rw-r--r--launcher/LauncherIcon.cpp18
-rw-r--r--launcher/LauncherIcon.h2
-rw-r--r--launcher/LauncherModel.cpp5
-rw-r--r--launcher/MockLauncherIcon.h6
-rw-r--r--launcher/PointerBarrier.cpp39
-rw-r--r--launcher/PointerBarrier.h6
-rw-r--r--launcher/StandaloneLauncher.cpp1
-rw-r--r--launcher/SwitcherController.cpp13
-rw-r--r--launcher/SwitcherController.h1
-rw-r--r--launcher/SwitcherControllerImpl.h1
-rw-r--r--launcher/SwitcherModel.cpp9
-rw-r--r--launcher/TooltipManager.cpp126
-rw-r--r--launcher/TooltipManager.h57
-rw-r--r--launcher/XdndCollectionWindowImp.cpp19
-rw-r--r--panel/PanelController.cpp12
-rw-r--r--panel/PanelView.cpp17
-rw-r--r--panel/PanelView.h2
-rw-r--r--plugins/unityshell/src/inputremover.cpp453
-rw-r--r--plugins/unityshell/src/inputremover.h37
-rw-r--r--plugins/unityshell/src/minimizedwindowhandler.cpp1
-rw-r--r--plugins/unityshell/src/unity-util-accessible.cpp1
-rw-r--r--plugins/unityshell/src/unitya11ytests.cpp4
-rw-r--r--plugins/unityshell/src/unityshell.cpp84
-rw-r--r--plugins/unityshell/src/unityshell.h1
-rw-r--r--services/panel-service.c53
-rw-r--r--shortcuts/ShortcutHintPrivate.cpp6
-rw-r--r--tests/CMakeLists.txt35
-rw-r--r--tests/autopilot/unity/emulators/launcher.py2
-rw-r--r--tests/autopilot/unity/tests/launcher/test_icon_behavior.py27
-rw-r--r--tests/autopilot/unity/tests/launcher/test_tooltips.py87
-rw-r--r--tests/autopilot/unity/tests/test_dash.py11
-rwxr-xr-xtests/autopilot/unity/tests/test_gobject_introspection.py66
-rw-r--r--tests/autopilot/unity/tests/test_ibus.py127
-rw-r--r--tests/autopilot/unity/tests/test_panel.py23
-rw-r--r--tests/autopilot/unity/tests/test_search.py176
-rw-r--r--tests/test-input-remover/test-input-remover.cpp2
-rw-r--r--tests/test-minimize-window-handler/test-minimize-handler.cpp25
-rw-r--r--tests/test_application_launcher_icon.cpp39
-rw-r--r--tests/test_categories.cpp2
-rw-r--r--tests/test_edge_barrier_controller.cpp25
-rw-r--r--tests/test_expo_launcher_icon.cpp17
-rw-r--r--tests/test_filesystem_lenses.cpp33
-rw-r--r--tests/test_filter_multirange.h75
-rw-r--r--tests/test_filter_widgets.cpp187
-rw-r--r--tests/test_gdbus_proxy.cpp12
-rw-r--r--tests/test_glib_dbus_object.cpp135
-rw-r--r--tests/test_glib_dbus_server.cpp428
-rw-r--r--tests/test_launcher.cpp6
-rw-r--r--tests/test_launcher_controller.cpp178
-rw-r--r--tests/test_lens.cpp57
-rw-r--r--tests/test_main_dbus.cpp22
-rw-r--r--tests/test_model.cpp38
-rw-r--r--tests/test_panel_view.cpp66
-rw-r--r--tests/test_pointer_barrier.cpp92
-rw-r--r--tests/test_quicklist_manager.cpp4
-rw-r--r--tests/test_results.cpp2
-rw-r--r--tests/test_service_gdbus_wrapper.c202
-rw-r--r--tests/test_service_gdbus_wrapper.cpp56
-rw-r--r--tests/test_service_gdbus_wrapper.h47
-rw-r--r--tests/test_service_hud.cpp (renamed from tests/test_service_hud.c)217
-rw-r--r--tests/test_service_hud.h49
-rw-r--r--tests/test_service_lens.cpp (renamed from tests/test_service_lens.c)133
-rw-r--r--tests/test_service_lens.h52
-rw-r--r--tests/test_service_main.c105
-rw-r--r--tests/test_service_main.cpp47
-rw-r--r--tests/test_service_model.c100
-rw-r--r--tests/test_service_model.cpp52
-rw-r--r--tests/test_service_model.h50
-rw-r--r--tests/test_service_panel.c253
-rw-r--r--tests/test_service_panel.cpp123
-rw-r--r--tests/test_service_panel.h50
-rw-r--r--tests/test_software_center_launcher_icon.cpp2
-rw-r--r--tests/test_switcher_model.cpp20
-rw-r--r--tests/test_thumbnail_generator.cpp1
-rw-r--r--tests/test_tooltip_manager.cpp54
-rw-r--r--tests/test_utils.h29
-rwxr-xr-xunity-shared/DashStyle.cpp261
-rwxr-xr-xunity-shared/DashStyle.h1
-rw-r--r--unity-shared/DebugDBusInterface.cpp112
-rw-r--r--unity-shared/DebugDBusInterface.h23
-rw-r--r--unity-shared/LayoutSystem.cpp1
-rw-r--r--unity-shared/MockableBaseWindow.h17
-rw-r--r--unity-shared/OverlayWindowButtons.cpp10
-rw-r--r--unity-shared/PluginAdapter.cpp20
-rw-r--r--unity-shared/PluginAdapter.h1
-rw-r--r--unity-shared/StandaloneWindowManager.cpp5
-rw-r--r--unity-shared/StandaloneWindowManager.h2
-rw-r--r--unity-shared/UBusMessages.h4
-rw-r--r--unity-shared/WindowButtons.cpp6
-rw-r--r--unity-shared/WindowManager.h1
137 files changed, 5012 insertions, 2094 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 48fcdbf7b..2b0324bdd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -135,6 +135,7 @@ set (LOCALE_DIR "${DATADIR}/locale")
set (VERSION "${UNITY_VERSION}")
set (BUILDDIR "${CMAKE_BINARY_DIR}")
set (TESTDATADIR "${CMAKE_CURRENT_SOURCE_DIR}/tests/data")
+set (INDICATOR_SERVICE_DIR "${CMAKE_INSTALL_PREFIX}/share/unity/indicators")
find_package (PkgConfig)
execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} unity --variable lensesdir OUTPUT_VARIABLE LENSES_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
diff --git a/UnityCore/CMakeLists.txt b/UnityCore/CMakeLists.txt
index 3636f1561..7d50c5655 100644
--- a/UnityCore/CMakeLists.txt
+++ b/UnityCore/CMakeLists.txt
@@ -26,6 +26,7 @@ set (CORE_HEADERS
Filters.h
GenericPreview.h
GLibDBusProxy.h
+ GLibDBusServer.h
GLibSignal.h
GLibSignal-inl.h
GLibSource.h
@@ -71,6 +72,7 @@ set (CORE_SOURCES
Filters.cpp
GenericPreview.cpp
GLibDBusProxy.cpp
+ GLibDBusServer.cpp
GLibSignal.cpp
GLibSource.cpp
GLibWrapper.cpp
diff --git a/UnityCore/GLibDBusProxy.cpp b/UnityCore/GLibDBusProxy.cpp
index bd1be335d..8e28b1b08 100644
--- a/UnityCore/GLibDBusProxy.cpp
+++ b/UnityCore/GLibDBusProxy.cpp
@@ -33,7 +33,7 @@ namespace unity
{
namespace glib
{
-DECLARE_LOGGER(logger, "unity.glib.dbusproxy");
+DECLARE_LOGGER(logger, "unity.glib.dbus.proxy");
namespace
{
diff --git a/UnityCore/GLibDBusServer.cpp b/UnityCore/GLibDBusServer.cpp
new file mode 100644
index 000000000..fe854ca7e
--- /dev/null
+++ b/UnityCore/GLibDBusServer.cpp
@@ -0,0 +1,738 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+* Copyright (C) 2013 Canonical Ltd
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 3 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com>
+*/
+
+#include <NuxCore/Logger.h>
+
+#include "GLibDBusServer.h"
+#include "Variant.h"
+
+namespace unity
+{
+namespace glib
+{
+namespace
+{
+void safe_interface_info_unref(GDBusInterfaceInfo* info)
+{
+ if (info) ::g_dbus_interface_info_unref(info);
+}
+
+void safe_node_info_unref(GDBusNodeInfo* info)
+{
+ if (info) ::g_dbus_node_info_unref(info);
+}
+}
+
+DECLARE_LOGGER(logger_o, "unity.glib.dbus.object");
+
+struct DBusObject::Impl
+{
+ Impl(DBusObject* obj, std::string const& introspection_xml, std::string const& interface_name)
+ : object_(obj)
+ , interface_info_(nullptr, safe_interface_info_unref)
+ {
+ glib::Error error;
+ auto xml_int = g_dbus_node_info_new_for_xml(introspection_xml.c_str(), &error);
+ std::shared_ptr<GDBusNodeInfo> node_info(xml_int, safe_node_info_unref);
+
+ if (error)
+ {
+ LOG_ERROR(logger_o) << "Unable to parse the given introspection for "
+ << interface_name << ": " << error.Message();
+ }
+
+ if (!node_info)
+ return;
+
+ interface_info_.reset(g_dbus_node_info_lookup_interface(node_info.get(), interface_name.c_str()));
+
+ if (!interface_info_)
+ {
+ LOG_ERROR(logger_o) << "Unable to find the interface '" << interface_name
+ << "' in the provided introspection XML";
+ return;
+ }
+
+ g_dbus_interface_info_ref(interface_info_.get());
+
+ interface_vtable_.method_call = [] (GDBusConnection* connection, const gchar* sender,
+ const gchar* object_path, const gchar* interface_name,
+ const gchar* method_name, GVariant* parameters,
+ GDBusMethodInvocation* invocation, gpointer user_data) {
+ auto self = static_cast<DBusObject::Impl*>(user_data);
+ GVariant *ret = nullptr;
+
+ if (self->method_cb_)
+ {
+ ret = self->method_cb_(method_name ? method_name : "", parameters);
+
+ LOG_INFO(logger_o) << "Called method: '" << method_name << " "
+ << (parameters ? g_variant_print(parameters, TRUE) : "()")
+ << "' on object '" << object_path << "' with interface '"
+ << interface_name << "' , returning: '"
+ << (ret ? g_variant_print(ret, TRUE) : "()") << "'";
+
+ const GDBusMethodInfo* info = g_dbus_method_invocation_get_method_info(invocation);
+
+ if ((!ret || g_variant_equal(ret, glib::Variant(g_variant_new("()")))) && info->out_args && info->out_args[0])
+ {
+ LOG_ERROR(logger_o) << "Retuning NULL on method call '" << method_name << "' "
+ << "while its interface requires a value";
+
+ std::string error_name = std::string(interface_name)+".Error.BadReturn";
+ std::string error = "Returning invalid value for '"+std::string(method_name)+"' on path '"+std::string(object_path)+"'.";
+ g_dbus_method_invocation_return_dbus_error(invocation, error_name.c_str(), error.c_str());
+ }
+ else
+ {
+ g_dbus_method_invocation_return_value(invocation, ret);
+ }
+ }
+ else
+ {
+ LOG_WARN(logger_o) << "Called method: '" << method_name << " "
+ << (parameters ? g_variant_print(parameters, TRUE) : "()")
+ << "' on object '" << object_path << "' with interface '"
+ << interface_name << "', but no methods handler is set";
+
+ std::string error_name = std::string(interface_name)+".Error.NoHandlerSet";
+ std::string error = "No handler set for method '"+std::string(method_name)+"' on path '"+std::string(object_path)+"'.";
+ g_dbus_method_invocation_return_dbus_error(invocation, error_name.c_str(), error.c_str());
+ }
+ };
+
+ interface_vtable_.get_property = [] (GDBusConnection* connection, const gchar* sender,
+ const gchar* object_path, const gchar* interface_name,
+ const gchar* property_name, GError **error, gpointer user_data) {
+ auto self = static_cast<DBusObject::Impl*>(user_data);
+ GVariant *value = nullptr;
+
+ if (self->property_get_cb_)
+ value = self->property_get_cb_(property_name ? property_name : "");
+
+ LOG_INFO(logger_o) << "Getting property '" << property_name << "' on '"
+ << interface_name << "' , returning: '"
+ << (value ? g_variant_print(value, TRUE) : "()") << "'";
+
+ return value;
+ };
+
+ interface_vtable_.set_property = [] (GDBusConnection* connection, const gchar* sender,
+ const gchar* object_path, const gchar* interface_name,
+ const gchar* property_name, GVariant *value,
+ GError **error, gpointer user_data) {
+ auto self = static_cast<DBusObject::Impl*>(user_data);
+ glib::Variant old_value;
+ gboolean ret = TRUE;
+
+ if (self->property_get_cb_)
+ old_value = self->property_get_cb_(property_name ? property_name : "");
+
+ if (self->property_set_cb_)
+ {
+ if (!self->property_set_cb_(property_name ? property_name : "", value))
+ {
+ ret = FALSE;
+
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "It was impossible " \
+ "to set the property '%s' on '%s'", property_name, interface_name);
+ }
+ }
+
+ if (ret)
+ {
+ LOG_INFO(logger_o) << "Setting property '" << property_name << "' on '"
+ << interface_name << "' , to value: '"
+ << (value ? g_variant_print(value, TRUE) : "<null>") << "'";
+
+ if (!g_variant_equal(old_value, value))
+ self->EmitPropertyChanged(property_name ? property_name : "");
+ }
+ else
+ {
+ LOG_WARN(logger_o) << "It was impossible to set the property '"
+ << property_name << "' on '" << interface_name
+ << "' , to value: '"
+ << (value ? g_variant_print(value, TRUE) : "()")
+ << "'";
+ }
+
+ return ret;
+ };
+ }
+
+ ~Impl()
+ {
+ UnRegister();
+ }
+
+ std::string InterfaceName() const
+ {
+ if (interface_info_ && interface_info_->name)
+ return interface_info_->name;
+
+ return "";
+ }
+
+ bool Register(glib::Object<GDBusConnection> const& conn, std::string const& path)
+ {
+ if (!interface_info_)
+ {
+ LOG_ERROR(logger_o) << "Can't register object '" << InterfaceName()
+ << "', bad interface";
+ return false;
+ }
+
+ if (connection_by_path_.find(path) != connection_by_path_.end())
+ {
+ LOG_ERROR(logger_o) << "Can't register object '" << InterfaceName()
+ << "', it's already registered on path '" << path << "'";
+ return false;
+ }
+
+ if (!conn.IsType(G_TYPE_DBUS_CONNECTION))
+ {
+ LOG_ERROR(logger_o) << "Can't register object '" << InterfaceName()
+ << "', invalid connection";
+ return false;
+ }
+
+ glib::Error error;
+
+ guint id = g_dbus_connection_register_object(conn, path.c_str(), interface_info_.get(),
+ &interface_vtable_, this, nullptr, &error);
+ if (error)
+ {
+ LOG_ERROR(logger_o) << "Could not register object in dbus: "
+ << error.Message();
+ return false;
+ }
+
+ registrations_[id] = path;
+ connection_by_path_[path] = conn;
+ object_->registered.emit(path);
+
+ LOG_INFO(logger_o) << "Registering object '" << InterfaceName() << "'";
+
+ return true;
+ }
+
+ void UnRegister(std::string const& path = "")
+ {
+ if (!path.empty())
+ {
+ auto conn_it = connection_by_path_.find(path);
+
+ if (conn_it == connection_by_path_.end())
+ {
+ LOG_WARN(logger_o) << "Impossible unregistering object for path " << path;
+ return;
+ }
+
+ guint registration_id = 0;
+
+ for (auto const& pair : registrations_)
+ {
+ auto const& obj_path = pair.second;
+
+ if (obj_path == path)
+ {
+ registration_id = pair.first;
+ g_dbus_connection_unregister_object(conn_it->second, registration_id);
+ object_->unregistered.emit(path);
+
+ LOG_INFO(logger_o) << "Unregistering object '" << InterfaceName() << "'"
+ << " on path '" << path << "'";
+ break;
+ }
+ }
+
+ registrations_.erase(registration_id);
+ connection_by_path_.erase(conn_it);
+
+ if (registrations_.empty())
+ object_->fully_unregistered.emit();
+ }
+ else
+ {
+ for (auto const& pair : registrations_)
+ {
+ auto const& registration_id = pair.first;
+ auto const& obj_path = pair.second;
+ auto const& connection = connection_by_path_[obj_path];
+
+ g_dbus_connection_unregister_object(connection, registration_id);
+ object_->unregistered.emit(obj_path);
+
+ LOG_INFO(logger_o) << "Unregistering object '" << InterfaceName() << "'"
+ << " on path '" << obj_path << "'";
+ }
+
+ registrations_.clear();
+ connection_by_path_.clear();
+ object_->fully_unregistered.emit();
+ }
+ }
+
+ void EmitGenericSignal(glib::Object<GDBusConnection> const& conn, std::string const& path,
+ std::string const& interface, std::string const& signal,
+ GVariant* parameters = nullptr)
+ {
+ LOG_INFO(logger_o) << "Emitting signal '" << signal << "'" << " for the interface "
+ << "'" << interface << "' on object path '" << path << "'";
+
+ glib::Error error;
+ g_dbus_connection_emit_signal(conn, nullptr, path.c_str(), interface.c_str(),
+ signal.c_str(), parameters, &error);
+
+ if (error)
+ {
+ LOG_ERROR(logger_o) << "Got error when emitting signal '" << signal << "': "
+ << " for the interface '" << interface << "' on object path '"
+ << path << "': " << error.Message();
+ }
+ }
+
+ void EmitSignal(std::string const& signal, GVariant* parameters, std::string const& path)
+ {
+ glib::Variant reffed_params(parameters);
+
+ if (signal.empty())
+ {
+ LOG_ERROR(logger_o) << "Impossible to emit an empty signal";
+ return;
+ }
+
+ if (!path.empty())
+ {
+ auto conn_it = connection_by_path_.find(path);
+
+ if (conn_it == connection_by_path_.end())
+ {
+ LOG_ERROR(logger_o) << "Impossible to emit signal '" << signal << "' "
+ << "on object path '" << path << "': no connection available";
+ return;
+ }
+
+ EmitGenericSignal(conn_it->second, path, InterfaceName(), signal, parameters);
+ }
+ else
+ {
+ for (auto const& pair : connection_by_path_)
+ {
+ glib::Variant params(parameters);
+ auto const& obj_path = pair.first;
+ auto const& conn = pair.second;
+
+ EmitGenericSignal(conn, obj_path, InterfaceName(), signal, params);
+ }
+ }
+ }
+
+ void EmitPropertyChanged(std::string const& property, std::string const& path = "")
+ {
+ if (property.empty())
+ {
+ LOG_ERROR(logger_o) << "Impossible to emit a changed property for an invalid one";
+ return;
+ }
+
+ if (!property_get_cb_)
+ {
+ LOG_ERROR(logger_o) << "We don't have a property getter for this object";
+ return;
+ }
+
+ auto builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
+ GVariant* value = property_get_cb_(property.c_str());
+ g_variant_builder_add(builder, "{sv}", property.c_str(), value);
+ glib::Variant parameters(g_variant_new("(sa{sv}as)", InterfaceName().c_str(), builder, nullptr));
+
+ if (!path.empty())
+ {
+ auto conn_it = connection_by_path_.find(path);
+
+ if (conn_it == connection_by_path_.end())
+ {
+ LOG_ERROR(logger_o) << "Impossible to emit property changed '" << property << "' "
+ << "on object path '" << path << "': no connection available";
+ return;
+ }
+
+ EmitGenericSignal(conn_it->second, path, "org.freedesktop.DBus.Properties", "PropertiesChanged", parameters);
+ }
+ else
+ {
+ for (auto const& pair : connection_by_path_)
+ {
+ glib::Variant reffed_params(parameters);
+ auto const& obj_path = pair.first;
+ auto const& conn = pair.second;
+
+ EmitGenericSignal(conn, obj_path, "org.freedesktop.DBus.Properties", "PropertiesChanged", reffed_params);
+ }
+ }
+ }
+
+ DBusObject* object_;
+ MethodCallback method_cb_;
+ PropertyGetterCallback property_get_cb_;
+ PropertySetterCallback property_set_cb_;
+
+ GDBusInterfaceVTable interface_vtable_;
+ std::shared_ptr<GDBusInterfaceInfo> interface_info_;
+ std::map<guint, std::string> registrations_;
+ std::map<std::string, glib::Object<GDBusConnection>> connection_by_path_;
+};
+
+DBusObject::DBusObject(std::string const& introspection_xml, std::string const& interface_name)
+ : impl_(new DBusObject::Impl(this, introspection_xml, interface_name))
+{}
+
+DBusObject::~DBusObject()
+{}
+
+void DBusObject::SetMethodsCallsHandler(MethodCallback const& func)
+{
+ impl_->method_cb_ = func;
+}
+
+void DBusObject::SetPropertyGetter(PropertyGetterCallback const& func)
+{
+ impl_->property_get_cb_ = func;
+}
+
+void DBusObject::SetPropertySetter(PropertySetterCallback const& func)
+{
+ impl_->property_set_cb_ = func;
+}
+
+std::string DBusObject::InterfaceName() const
+{
+ return impl_->InterfaceName();
+}
+
+bool DBusObject::Register(glib::Object<GDBusConnection> const& conn, std::string const& path)
+{
+ return impl_->Register(conn, path);
+}
+
+void DBusObject::UnRegister(std::string const& path)
+{
+ impl_->UnRegister(path);
+}
+
+void DBusObject::EmitSignal(std::string const& signal, GVariant* parameters, std::string const& path)
+{
+ impl_->EmitSignal(signal, parameters, path);
+}
+
+void DBusObject::EmitPropertyChanged(std::string const& property, std::string const& path)
+{
+ impl_->EmitPropertyChanged(property, path);
+}
+
+// DBusObjectBuilder
+
+DECLARE_LOGGER(logger_b, "unity.glib.dbus.object.builder");
+
+std::list<DBusObject::Ptr> DBusObjectBuilder::GetObjectsForIntrospection(std::string const& xml)
+{
+ std::list<DBusObject::Ptr> objects;
+ glib::Error error;
+ auto xml_int = g_dbus_node_info_new_for_xml(xml.c_str(), &error);
+ std::shared_ptr<GDBusNodeInfo> node_info(xml_int, safe_node_info_unref);
+
+ if (error || !node_info)
+ {
+ LOG_ERROR(logger_b) << "Unable to parse the given introspection: "
+ << error.Message();
+
+ return objects;
+ }
+
+ for (unsigned i = 0; node_info->interfaces[i]; ++i)
+ {
+ glib::Error error;
+ GDBusInterfaceInfo *interface = node_info->interfaces[i];
+
+ auto obj = std::make_shared<DBusObject>(xml, interface->name);
+ objects.push_back(obj);
+ }
+
+ return objects;
+}
+
+// DBusServer
+
+DECLARE_LOGGER(logger_s, "unity.glib.dbus.server");
+
+struct DBusServer::Impl
+{
+ Impl(DBusServer* server, std::string const& name = "")
+ : server_(server)
+ , name_(name)
+ , name_owned_(false)
+ , owner_name_(0)
+ {}
+
+ Impl(DBusServer* server, std::string const& name, GBusType bus_type)
+ : Impl(server, name)
+ {
+ owner_name_ = g_bus_own_name(bus_type, name.c_str(), G_BUS_NAME_OWNER_FLAGS_NONE,
+ [] (GDBusConnection* conn, const gchar* name, gpointer data)
+ {
+ auto self = static_cast<DBusServer::Impl*>(data);
+
+ LOG_INFO(logger_s) << "DBus name acquired '" << name << "'";
+
+ self->connection_ = glib::Object<GDBusConnection>(conn, glib::AddRef());
+ self->name_owned_ = true;
+ self->server_->name_acquired.emit();
+ self->server_->connected.emit();
+ self->RegisterPendingObjects();
+ }, nullptr,
+ [] (GDBusConnection *connection, const gchar *name, gpointer data)
+ {
+ auto self = static_cast<DBusServer::Impl*>(data);
+
+ LOG_ERROR(logger_s) << "DBus name lost '" << name << "'";
+
+ self->name_owned_ = false;
+ self->server_->name_lost.emit();
+ }, this, nullptr);
+ }
+
+ Impl(DBusServer* server, GBusType bus_type)
+ : Impl(server)
+ {
+ cancellable_ = g_cancellable_new();
+ g_bus_get(bus_type, cancellable_, [] (GObject*, GAsyncResult* res, gpointer data) {
+ auto self = static_cast<DBusServer::Impl*>(data);
+ glib::Error error;
+
+ GDBusConnection* conn = g_bus_get_finish(res, &error);
+
+ if (!error)
+ {
+ self->connection_ = glib::Object<GDBusConnection>(conn, glib::AddRef());
+ self->server_->connected.emit();
+ self->RegisterPendingObjects();
+ }
+ else
+ {
+ LOG_ERROR(logger_s) << "Can't get bus: " << error.Message();
+ }
+ }, this);
+ }
+
+ ~Impl()
+ {
+ if (owner_name_)
+ g_bus_unown_name(owner_name_);
+
+ if (cancellable_)
+ g_cancellable_cancel(cancellable_);
+
+ LOG_INFO(logger_s) << "Removing dbus server";
+ }
+
+ void RegisterPendingObjects()
+ {
+ for (auto const& pair : pending_objects_)
+ AddObject(pair.first, pair.second);
+
+ pending_objects_.clear();
+ }
+
+ bool AddObject(DBusObject::Ptr const& obj, std::string const& path)
+ {
+ if (!obj)
+ {
+ LOG_ERROR(logger_s) << "Can't register an invalid object";
+ return false;
+ }
+
+ if (!connection_)
+ {
+ LOG_WARN(logger_s) << "Can't register object '" << obj->InterfaceName()
+ << "' yet as we don't have a connection, waiting for it...";
+
+ pending_objects_.push_back(std::make_pair(obj, path));
+ }
+ else
+ {
+ if (obj->Register(connection_, path))
+ {
+ objects_.push_back(obj);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool RemoveObject(DBusObject::Ptr const& obj)
+ {
+ if (!obj)
+ return false;
+
+ bool removed = false;
+
+ for (auto it = pending_objects_.begin(); it != pending_objects_.end(); ++it)
+ {
+ if (it->first == obj)
+ {
+ pending_objects_.erase(it);
+ removed = true;
+ LOG_INFO(logger_s) << "Removing object '" << obj->InterfaceName() << "' ...";
+ break;
+ }
+ }
+
+ if (!removed)
+ {
+ auto it = std::find(objects_.begin(), objects_.end(), obj);
+ if (it != objects_.end())
+ {
+ objects_.erase(it);
+ removed = true;
+ LOG_INFO(logger_s) << "Removing object '" << obj->InterfaceName() << "' ...";
+ }
+ }
+
+ if (removed)
+ {
+ obj->UnRegister();
+ }
+
+ return removed;
+ }
+
+ DBusObject::Ptr GetObject(std::string const& interface) const
+ {
+ for (auto const& pair : pending_objects_)
+ {
+ if (pair.first->InterfaceName() == interface)
+ return pair.first;
+ }
+
+ for (auto const& obj : objects_)
+ {
+ if (obj->InterfaceName() == interface)
+ return obj;
+ }
+
+ return DBusObject::Ptr();
+ }
+
+ void EmitSignal(std::string const& interface, std::string const& signal, GVariant* parameters)
+ {
+ auto const& obj = GetObject(interface);
+
+ if (obj)
+ obj->EmitSignal(signal, parameters);
+ }
+
+ DBusServer* server_;
+ std::string name_;
+ bool name_owned_;
+ guint owner_name_;
+ glib::Object<GDBusConnection> connection_;
+ glib::Object<GCancellable> cancellable_;
+ std::vector<DBusObject::Ptr> objects_;
+ std::vector<std::pair<DBusObject::Ptr, std::string>> pending_objects_;
+};
+
+DBusServer::DBusServer(std::string const& name, GBusType bus_type)
+ : impl_(new DBusServer::Impl(this, name, bus_type))
+{}
+
+DBusServer::DBusServer(GBusType bus_type)
+ : impl_(new DBusServer::Impl(this, bus_type))
+{}
+
+DBusServer::~DBusServer()
+{}
+
+bool DBusServer::IsConnected() const
+{
+ return impl_->connection_.IsType(G_TYPE_DBUS_CONNECTION);
+}
+
+std::string const& DBusServer::Name() const
+{
+ return impl_->name_;
+}
+
+bool DBusServer::OwnsName() const
+{
+ return impl_->name_owned_;
+}
+
+void DBusServer::AddObjects(std::string const& introspection_xml, std::string const& path)
+{
+ auto const& objs = DBusObjectBuilder::GetObjectsForIntrospection(introspection_xml);
+
+ if (objs.empty())
+ {
+ LOG_WARN(logger_s) << "Impossible to add empty objects list";
+ }
+ else
+ {
+ for (auto const& obj : objs)
+ AddObject(obj, path);
+ }
+}
+
+bool DBusServer::AddObject(DBusObject::Ptr const& obj, std::string const& path)
+{
+ return impl_->AddObject(obj, path);
+}
+
+bool DBusServer::RemoveObject(DBusObject::Ptr const& obj)
+{
+ return impl_->RemoveObject(obj);
+}
+
+std::list<DBusObject::Ptr> DBusServer::GetObjects() const
+{
+ std::list<DBusObject::Ptr> objects;
+
+ for (auto const& pair : impl_->pending_objects_)
+ objects.push_back(pair.first);
+
+ for (auto const& obj : impl_->objects_)
+ objects.push_back(obj);
+
+ return objects;
+}
+
+DBusObject::Ptr DBusServer::GetObject(std::string const& interface) const
+{
+ return impl_->GetObject(interface);
+}
+
+void DBusServer::EmitSignal(std::string const& interface, std::string const& signal, GVariant* parameters)
+{
+ impl_->EmitSignal(interface, signal, parameters);
+}
+
+} // namespace glib
+} // namespace unity
diff --git a/UnityCore/GLibDBusServer.h b/UnityCore/GLibDBusServer.h
new file mode 100644
index 000000000..42baa74d8
--- /dev/null
+++ b/UnityCore/GLibDBusServer.h
@@ -0,0 +1,116 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+* Copyright (C) 2013 Canonical Ltd
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 3 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*
+* Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com>
+*/
+
+#ifndef UNITY_GLIB_DBUS_SERVER_H
+#define UNITY_GLIB_DBUS_SERVER_H
+
+#include <gio/gio.h>
+#include <memory>
+#include <sigc++/signal.h>
+#include <sigc++/trackable.h>
+
+#include "GLibWrapper.h"
+
+namespace unity
+{
+namespace glib
+{
+
+class DBusObject : public sigc::trackable
+{
+public:
+ typedef std::shared_ptr<DBusObject> Ptr;
+
+ DBusObject(std::string const& introspection_xml, std::string const& interface_name);
+ virtual ~DBusObject();
+
+ typedef std::function<GVariant*(std::string const&, GVariant*)> MethodCallback;
+ typedef std::function<GVariant*(std::string const&)> PropertyGetterCallback;
+ typedef std::function<bool(std::string const&, GVariant*)> PropertySetterCallback;
+
+ void SetMethodsCallsHandler(MethodCallback const&);
+ void SetPropertyGetter(PropertyGetterCallback const&);
+ void SetPropertySetter(PropertySetterCallback const&);
+
+ std::string InterfaceName() const;
+
+ bool Register(glib::Object<GDBusConnection> const&, std::string const& path);
+ void UnRegister(std::string const& path = "");
+
+ void EmitSignal(std::string const& signal, GVariant* parameters = nullptr, std::string const& path = "");
+ void EmitPropertyChanged(std::string const& property, std::string const& path = "");
+
+ sigc::signal<void, std::string const&> registered;
+ sigc::signal<void, std::string const&> unregistered;
+ sigc::signal<void> fully_unregistered;
+
+private:
+ // not copyable class
+ DBusObject(DBusObject const&) = delete;
+ DBusObject& operator=(DBusObject const&) = delete;
+
+ struct Impl;
+ std::unique_ptr<Impl> impl_;
+};
+
+class DBusObjectBuilder
+{
+public:
+ static std::list<DBusObject::Ptr> GetObjectsForIntrospection(std::string const& introspection_xml);
+};
+
+class DBusServer : public sigc::trackable
+{
+public:
+ typedef std::shared_ptr<DBusServer> Ptr;
+
+ DBusServer(GBusType bus_type = G_BUS_TYPE_SESSION);
+ DBusServer(std::string const& name, GBusType bus_type = G_BUS_TYPE_SESSION);
+ virtual ~DBusServer();
+
+ void AddObjects(std::string const& introspection_xml, std::string const& path);
+ bool AddObject(DBusObject::Ptr const&, std::string const& path);
+ bool RemoveObject(DBusObject::Ptr const&);
+
+ std::list<DBusObject::Ptr> GetObjects() const;
+ DBusObject::Ptr GetObject(std::string const& interface) const;
+
+ void EmitSignal(std::string const& interface, std::string const& signal, GVariant* parameters = nullptr);
+
+ bool IsConnected() const;
+ std::string const& Name() const;
+ bool OwnsName() const;
+
+ sigc::signal<void> connected;
+ sigc::signal<void> name_acquired;
+ sigc::signal<void> name_lost;
+
+private:
+ // not copyable class
+ DBusServer(DBusServer const&) = delete;
+ DBusServer& operator=(DBusServer const&) = delete;
+
+ struct Impl;
+ std::unique_ptr<Impl> impl_;
+};
+
+} // namespace glib
+} // namespace unity
+
+#endif //UNITY_GLIB_DBUS_SERVER_H
diff --git a/UnityCore/MultiRangeFilter.cpp b/UnityCore/MultiRangeFilter.cpp
index 0c14a383a..e1247d459 100644
--- a/UnityCore/MultiRangeFilter.cpp
+++ b/UnityCore/MultiRangeFilter.cpp
@@ -88,64 +88,54 @@ void MultiRangeFilter::OptionChanged(bool is_active, std::string const& id)
return;
int position = PositionOfId(id);
+ if (position < 0)
+ return;
+
+ bool activate = is_active;
+ int position_above = position+1;
+ int position_below = position-1;
+ int filter_option_size = options_.size();
+
+ ignore_changes_ = true;
+ // when activating a option, need to make sure we only have continuous ajacent options enabled relative to the enabled option.
if (is_active)
{
- if (left_pos_ == -1 && right_pos_ == -1)
- {
- left_pos_ = position;
- right_pos_ = position;
- }
- else if (left_pos_ > position)
+ while(position_below >= 0)
{
- left_pos_ = position;
+ FilterOption::Ptr const& filter_option = options_[position_below--];
+
+ activate &= filter_option->active;
+ filter_option->active = activate;
}
- else if (right_pos_ < position)
+
+ activate = is_active;
+ while(position_above < filter_option_size)
{
- right_pos_ = position;
+ FilterOption::Ptr const& filter_option = options_[position_above++];
+
+ activate &= filter_option->active;
+ filter_option->active = activate;
}
}
else
{
- // Reset if the one and only block is deactivated
- if (position == right_pos_ && position == left_pos_)
- {
- left_pos_ = -1;
- right_pos_ = -1;
- }
- // If the deactivated block is on either end, remove it
- else if (position == right_pos_)
- {
- right_pos_ = position - 1;
- }
- else if (position == left_pos_)
- {
- left_pos_ = position + 1;
- }
- // It's in the middle of the range, see which side to shorten
- else if (position < (left_pos_ + ((right_pos_ - left_pos_)/2.0f)))
+ // otherwise just ensure there is a single continuous option range
+ bool active_found = false, inactive_found = false;
+ for (FilterOption::Ptr const& option : options_)
{
- left_pos_ = position;
- }
- else
- {
- right_pos_ = position;
+ if (inactive_found)
+ option->active = false;
+ else
+ {
+ if (option->active)
+ active_found = true;
+ else if (active_found)
+ inactive_found = true;
+ }
}
}
- ignore_changes_ = true;
- int i = 0;
- for(auto option: options_)
- {
- if (i < left_pos_)
- option->active = false;
- else if (i <= right_pos_)
- option->active = true;
- else
- option->active = false;
-
- i++;
- }
ignore_changes_ = false;
UpdateState();
diff --git a/config.h.cmake b/config.h.cmake
index 4e3a16e28..f34d365f1 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -17,5 +17,8 @@
#ifndef INDICATORICONDIR
#cmakedefine INDICATORICONDIR "@INDICATORICONDIR@"
#endif
+#ifndef INDICATOR_SERVICE_DIR
+#cmakedefine INDICATOR_SERVICE_DIR "@INDICATOR_SERVICE_DIR@"
+#endif
#endif // CONFIG_H
diff --git a/dash/DashController.cpp b/dash/DashController.cpp
index 13a92d434..7046b7310 100644
--- a/dash/DashController.cpp
+++ b/dash/DashController.cpp
@@ -43,8 +43,10 @@ namespace
{
const unsigned int PRELOAD_TIMEOUT_LENGTH = 40;
-const std::string DBUS_PATH = "/com/canonical/Unity/Dash";
-const std::string DBUS_INTROSPECTION =\
+namespace dbus
+{
+const std::string PATH = "/com/canonical/Unity/Dash";
+const std::string INTROSPECTION =\
"<node>"
" <interface name='com.canonical.Unity.Dash'>"
""
@@ -54,9 +56,7 @@ const std::string DBUS_INTROSPECTION =\
" </interface>"
"</node>";
}
-
-GDBusInterfaceVTable Controller::interface_vtable =
- { Controller::OnDBusMethodCall, NULL, NULL};
+}
Controller::Controller(Controller::WindowCreator const& create_window)
: launcher_width(64)
@@ -66,7 +66,6 @@ Controller::Controller(Controller::WindowCreator const& create_window)
, visible_(false)
, need_show_(false)
, view_(nullptr)
- , dbus_connect_cancellable_(g_cancellable_new())
, ensure_timeout_(PRELOAD_TIMEOUT_LENGTH)
, timeline_animator_(90)
{
@@ -93,7 +92,7 @@ Controller::Controller(Controller::WindowCreator const& create_window)
Settings::Instance().form_factor.changed.connect([this](FormFactor)
{
- if (window_ && view_ && visible_)
+ if (window_ && view_ && visible_)
{
// Relayout here so the input window size updates.
Relayout();
@@ -107,12 +106,13 @@ Controller::Controller(Controller::WindowCreator const& create_window)
auto spread_cb = sigc::bind(sigc::mem_fun(this, &Controller::HideDash), true);
WindowManager::Default().initiate_spread.connect(spread_cb);
- g_bus_get (G_BUS_TYPE_SESSION, dbus_connect_cancellable_, OnBusAcquired, this);
-}
+ dbus_server_.AddObjects(dbus::INTROSPECTION, dbus::PATH);
+ dbus_server_.GetObjects().front()->SetMethodsCallsHandler([this] (std::string const& method, GVariant*) {
+ if (method == "HideDash")
+ HideDash();
-Controller::~Controller()
-{
- g_cancellable_cancel(dbus_connect_cancellable_);
+ return static_cast<GVariant*>(nullptr);
+ });
}
void Controller::SetupWindow()
@@ -124,12 +124,17 @@ void Controller::SetupWindow()
window_->SetOpacity(0.0f);
window_->mouse_down_outside_pointer_grab_area.connect(sigc::mem_fun(this, &Controller::OnMouseDownOutsideWindow));
- /* FIXME - first time we load our windows there is a race that causes the input window not to actually get input, this side steps that by causing an input window show and hide before we really need it. */
- WindowManager& wm = WindowManager::Default();
- wm.SaveInputFocus ();
- window_->EnableInputWindow(true, dash::window_title, true, false);
- window_->EnableInputWindow(false, dash::window_title, true, false);
- wm.RestoreInputFocus ();
+ if (nux::GetWindowThread()->IsEmbeddedWindow())
+ {
+ /* FIXME - first time we load our windows there is a race that causes the input
+ * window not to actually get input, this side steps that by causing an input window
+ * show and hide before we really need it. */
+ WindowManager& wm = WindowManager::Default();
+ wm.SaveInputFocus();
+ window_->EnableInputWindow(true, dash::window_title, true, false);
+ window_->EnableInputWindow(false, dash::window_title, true, false);
+ wm.RestoreInputFocus();
+ }
}
void Controller::SetupDashView()
@@ -165,7 +170,9 @@ void Controller::RegisterUBusInterests()
unity::glib::String overlay_identity;
gboolean can_maximise = FALSE;
gint32 overlay_monitor = 0;
- g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING, &overlay_identity, &can_maximise, &overlay_monitor);
+ int width = 0;
+ int height = 0;
+ g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING, &overlay_identity, &can_maximise, &overlay_monitor, &width, &height);
// hide if something else is coming up
if (overlay_identity.Str() != "dash")
@@ -314,7 +321,9 @@ void Controller::ShowDash()
StartShowHideTimeline();
- GVariant* info = g_variant_new(UBUS_OVERLAY_FORMAT_STRING, "dash", TRUE, monitor_);
+ nux::Geometry const& view_content_geo = view_->GetContentGeometry();
+
+ GVariant* info = g_variant_new(UBUS_OVERLAY_FORMAT_STRING, "dash", TRUE, monitor_, view_content_geo.width, view_content_geo.height);
ubus_manager_.SendMessage(UBUS_OVERLAY_SHOWN, info);
}
@@ -322,8 +331,9 @@ void Controller::FocusWindow()
{
window_->ShowWindow(true);
window_->PushToFront();
- if (!Settings::Instance().is_standalone) // in standalone mode, we do not need an input window. we are one.
+ if (nux::GetWindowThread()->IsEmbeddedWindow())
{
+ // in standalone (i.e. not embedded) mode, we do not need an input window. we are one.
window_->EnableInputWindow(true, dash::window_title, true, false);
// update the input window geometry. This causes the input window to match the actual size of the dash.
window_->UpdateInputWindowGeometry();
@@ -363,7 +373,9 @@ void Controller::HideDash(bool restore)
StartShowHideTimeline();
- GVariant* info = g_variant_new(UBUS_OVERLAY_FORMAT_STRING, "dash", TRUE, monitor_);
+ nux::Geometry const& view_content_geo = view_->GetContentGeometry();
+
+ GVariant* info = g_variant_new(UBUS_OVERLAY_FORMAT_STRING, "dash", TRUE, monitor_, view_content_geo.width, view_content_geo.height);
ubus_manager_.SendMessage(UBUS_OVERLAY_HIDDEN, info);
}
@@ -451,52 +463,6 @@ bool Controller::IsVisible() const
return visible_;
}
-void Controller::OnBusAcquired(GObject *obj, GAsyncResult *result, gpointer user_data)
-{
- glib::Error error;
- glib::Object<GDBusConnection> connection(g_bus_get_finish (result, &error));
-
- if (!connection || error)
- {
- LOG_WARNING(logger) << "Failed to connect to DBus:" << error;
- }
- else
- {
- GDBusNodeInfo* introspection_data = g_dbus_node_info_new_for_xml(DBUS_INTROSPECTION.c_str(), nullptr);
- unsigned int reg_id;
-
- if (!introspection_data)
- {
- LOG_WARNING(logger) << "No introspection data loaded.";
- return;
- }
-
- reg_id = g_dbus_connection_register_object(connection, DBUS_PATH.c_str(),
- introspection_data->interfaces[0],
- &interface_vtable, user_data,
- nullptr, nullptr);
- if (!reg_id)
- {
- LOG_WARNING(logger) << "Object registration failed. Dash DBus interface not available.";
- }
-
- g_dbus_node_info_unref(introspection_data);
- }
-}
-
-void Controller::OnDBusMethodCall(GDBusConnection* connection, const gchar* sender,
- const gchar* object_path, const gchar* interface_name,
- const gchar* method_name, GVariant* parameters,
- GDBusMethodInvocation* invocation, gpointer user_data)
-{
- if (g_strcmp0(method_name, "HideDash") == 0)
- {
- auto self = static_cast<Controller*>(user_data);
- self->HideDash();
- g_dbus_method_invocation_return_value(invocation, nullptr);
- }
-}
-
nux::Geometry Controller::GetInputWindowGeometry()
{
EnsureDash();
diff --git a/dash/DashController.h b/dash/DashController.h
index cf0613a16..28fabc5c4 100644
--- a/dash/DashController.h
+++ b/dash/DashController.h
@@ -22,6 +22,7 @@
#include <memory>
#include <gdk/gdk.h>
+#include <UnityCore/GLibDBusServer.h>
#include <UnityCore/GLibSignal.h>
#include <NuxCore/Animation.h>
@@ -46,7 +47,6 @@ public:
typedef std::function<ResizingBaseWindow*()> WindowCreator;
Controller(WindowCreator const& create_window = nullptr);
- ~Controller();
nux::BaseWindow* window() const;
@@ -92,12 +92,6 @@ private:
void StartShowHideTimeline();
void OnViewShowHideFrame(double progress);
- static void OnBusAcquired(GObject *obj, GAsyncResult *result, gpointer user_data);
- static void OnDBusMethodCall(GDBusConnection* connection, const gchar* sender,
- const gchar* object_path, const gchar* interface_name,
- const gchar* method_name, GVariant* parameters,
- GDBusMethodInvocation* invocation, gpointer user_data);
-
static void OnWindowConfigure(int width, int height, nux::Geometry& geo, void* data);
private:
@@ -110,10 +104,8 @@ private:
DashView* view_;
sigc::connection screen_ungrabbed_slot_;
- unsigned int dbus_owner_;
unsigned place_entry_request_id_;
- glib::Object<GCancellable> dbus_connect_cancellable_;
- static GDBusInterfaceVTable interface_vtable;
+ glib::DBusServer dbus_server_;
glib::TimeoutSeconds ensure_timeout_;
nux::animation::AnimateValue<double> timeline_animator_;
UBusManager ubus_manager_;
diff --git a/dash/DashView.cpp b/dash/DashView.cpp
index 7969354fa..c5ef0e959 100644
--- a/dash/DashView.cpp
+++ b/dash/DashView.cpp
@@ -228,10 +228,13 @@ void DashView::BuildPreview(Preview::Ptr model)
preview_lens_view_->PushFilterExpansion(false);
}
- preview_container_ = previews::PreviewContainer::Ptr(new previews::PreviewContainer());
- preview_container_->SetRedirectRenderingToTexture(true);
- AddChild(preview_container_.GetPointer());
- preview_container_->SetParentObject(this);
+ if (!preview_container_)
+ {
+ preview_container_ = previews::PreviewContainer::Ptr(new previews::PreviewContainer());
+ preview_container_->SetRedirectRenderingToTexture(true);
+ AddChild(preview_container_.GetPointer());
+ preview_container_->SetParentObject(this);
+ }
preview_container_->Preview(model, previews::Navigation::NONE); // no swipe left or right
preview_container_->SetGeometry(lenses_layout_->GetGeometry());
@@ -1522,6 +1525,7 @@ void DashView::AddProperties(GVariantBuilder* builder)
wrapper.add("bottom-border-height", style.GetDashBottomTileHeight());
wrapper.add("preview_displaying", preview_displaying_);
wrapper.add("dash_maximized", style.always_maximised());
+ wrapper.add("overlay_window_buttons_shown", overlay_window_buttons_->IsVisible());
}
nux::Area* DashView::KeyNavIteration(nux::KeyNavDirection direction)
diff --git a/dash/FilterAllButton.cpp b/dash/FilterAllButton.cpp
index 78dc57c7b..474e40134 100644
--- a/dash/FilterAllButton.cpp
+++ b/dash/FilterAllButton.cpp
@@ -32,6 +32,8 @@ namespace unity
namespace dash
{
+NUX_IMPLEMENT_OBJECT_TYPE(FilterAllButton);
+
FilterAllButton::FilterAllButton(NUX_FILE_LINE_DECL)
: FilterBasicButton(_("All"), NUX_FILE_LINE_PARAM)
{
diff --git a/dash/FilterAllButton.h b/dash/FilterAllButton.h
index d4512663a..a31c0213c 100644
--- a/dash/FilterAllButton.h
+++ b/dash/FilterAllButton.h
@@ -35,6 +35,7 @@ namespace dash
class FilterAllButton : public FilterBasicButton
{
+ NUX_DECLARE_OBJECT_TYPE(FilterAllButton, FilterBasicButton);
public:
FilterAllButton(NUX_FILE_LINE_PROTO);
~FilterAllButton();
diff --git a/dash/FilterBasicButton.cpp b/dash/FilterBasicButton.cpp
index 0d8b40a71..700998bde 100644
--- a/dash/FilterBasicButton.cpp
+++ b/dash/FilterBasicButton.cpp
@@ -33,6 +33,8 @@ namespace unity
{
namespace dash
{
+
+NUX_IMPLEMENT_OBJECT_TYPE(FilterBasicButton);
FilterBasicButton::FilterBasicButton(nux::TextureArea* image, NUX_FILE_LINE_DECL)
: nux::ToggleButton(image, NUX_FILE_LINE_PARAM)
diff --git a/dash/FilterBasicButton.h b/dash/FilterBasicButton.h
index db7991ee4..02e77c628 100644
--- a/dash/FilterBasicButton.h
+++ b/dash/FilterBasicButton.h
@@ -33,6 +33,7 @@ namespace dash
class FilterBasicButton : public nux::ToggleButton
{
+ NUX_DECLARE_OBJECT_TYPE(FilterBasicButton, nux::ToggleButton);
public:
FilterBasicButton(nux::TextureArea* image, NUX_FILE_LINE_PROTO);
FilterBasicButton(std::string const& label, NUX_FILE_LINE_PROTO);
diff --git a/dash/FilterFactory.cpp b/dash/FilterFactory.cpp
index 69fd77173..fd51f4bc1 100644
--- a/dash/FilterFactory.cpp
+++ b/dash/FilterFactory.cpp
@@ -64,7 +64,7 @@ FilterExpanderLabel* FilterFactory::WidgetForFilter(Filter::Ptr const& filter)
}
else if (filter_type == renderer_type_multirange)
{
- widget = new FilterMultiRange(NUX_TRACKER_LOCATION);
+ widget = new FilterMultiRangeWidget(NUX_TRACKER_LOCATION);
}
else if (filter_type == renderer_type_radio_options)
{
diff --git a/dash/FilterGenreButton.cpp b/dash/FilterGenreButton.cpp
index 201b10bf0..a0164d247 100644
--- a/dash/FilterGenreButton.cpp
+++ b/dash/FilterGenreButton.cpp
@@ -26,6 +26,8 @@ namespace unity
namespace dash
{
+NUX_IMPLEMENT_OBJECT_TYPE(FilterGenreButton);
+
FilterGenreButton::FilterGenreButton(std::string const& label, NUX_FILE_LINE_DECL)
: FilterBasicButton(label, NUX_FILE_LINE_PARAM)
{
diff --git a/dash/FilterGenreButton.h b/dash/FilterGenreButton.h
index b48b3277b..204076eeb 100644
--- a/dash/FilterGenreButton.h
+++ b/dash/FilterGenreButton.h
@@ -35,6 +35,7 @@ namespace dash
class FilterGenreButton : public FilterBasicButton
{
+ NUX_DECLARE_OBJECT_TYPE(FilterGenreButton, FilterBasicButton);
public:
FilterGenreButton(std::string const& label, NUX_FILE_LINE_PROTO);
FilterGenreButton(NUX_FILE_LINE_PROTO);
diff --git a/dash/FilterMultiRangeButton.cpp b/dash/FilterMultiRangeButton.cpp
index 5fd1701bb..7f2302775 100644
--- a/dash/FilterMultiRangeButton.cpp
+++ b/dash/FilterMultiRangeButton.cpp
@@ -21,6 +21,7 @@
#include "config.h"
#include <Nux/Nux.h>
+#include <Nux/Layout.h>
#include "unity-shared/DashStyle.h"
#include "FilterMultiRangeButton.h"
@@ -30,16 +31,19 @@ namespace unity
namespace dash
{
-FilterMultiRangeButton::FilterMultiRangeButton(std::string const& label, NUX_FILE_LINE_DECL)
- : nux::ToggleButton(label, NUX_FILE_LINE_PARAM)
- , has_arrow_(MultiRangeArrow::NONE)
- , side_(MultiRangeSide::CENTER)
+namespace
{
- Init();
+const int kFontSizePx = 10;
+
+const int kLayoutPadLeftRight = 4;
+const int kLayoutPadtopBottom = 2;
}
+NUX_IMPLEMENT_OBJECT_TYPE(FilterMultiRangeButton);
+
FilterMultiRangeButton::FilterMultiRangeButton(NUX_FILE_LINE_DECL)
: nux::ToggleButton(NUX_FILE_LINE_PARAM)
+ , theme_init_(false)
, has_arrow_(MultiRangeArrow::NONE)
, side_(MultiRangeSide::CENTER)
{
@@ -53,8 +57,9 @@ FilterMultiRangeButton::~FilterMultiRangeButton()
void FilterMultiRangeButton::Init()
{
InitTheme();
+ // Controlled by parent widget
SetAcceptKeyNavFocusOnMouseDown(false);
- SetAcceptKeyNavFocusOnMouseEnter(true);
+ SetAcceptKeyNavFocusOnMouseEnter(false);
state_change.connect(sigc::mem_fun(this, &FilterMultiRangeButton::OnActivated));
key_nav_focus_change.connect([&](nux::Area*, bool, nux::KeyNavDirection) { QueueDraw(); });
@@ -105,23 +110,22 @@ long FilterMultiRangeButton::ComputeContentSize()
{
long ret = nux::ToggleButton::ComputeContentSize();
nux::Geometry const& geo = GetGeometry();
- if (cached_geometry_ != geo)
+ if (theme_init_ && cached_geometry_ != geo)
{
cached_geometry_ = geo;
std::vector<MultiRangeSide> sides = {MultiRangeSide::LEFT, MultiRangeSide::RIGHT, MultiRangeSide::CENTER};
std::vector<MultiRangeArrow> arrows = {MultiRangeArrow::LEFT, MultiRangeArrow::RIGHT, MultiRangeArrow::BOTH, MultiRangeArrow::NONE};
- for (auto arrow : arrows)
+ auto func_invalidate = [geo](std::pair<const MapKey, NuxCairoPtr>& pair)
{
- for (auto side : sides)
- {
- prelight_[MapKey(arrow, side)]->Invalidate(geo);
- active_[MapKey(arrow, side)]->Invalidate(geo);
- normal_[MapKey(arrow, side)]->Invalidate(geo);
- focus_[MapKey(arrow, side)]->Invalidate(geo);
- }
- }
+ pair.second->Invalidate(geo);
+ };
+
+ for_each (prelight_.begin(), prelight_.end(), func_invalidate);
+ for_each (active_.begin(), active_.end(), func_invalidate);
+ for_each (normal_.begin(), normal_.end(), func_invalidate);
+ for_each (focus_.begin(), focus_.end(), func_invalidate);
}
return ret;
@@ -149,6 +153,7 @@ void FilterMultiRangeButton::InitTheme()
}
SetMinimumHeight(dash::Style::Instance().GetFilterButtonHeight() + 3);
+ theme_init_ = true;
}
void FilterMultiRangeButton::RedrawTheme(nux::Geometry const& geom,
@@ -182,7 +187,7 @@ void FilterMultiRangeButton::RedrawTheme(nux::Geometry const& geom,
else
segment = Segment::RIGHT;
- Style::Instance().MultiRangeSegment(cr, faked_state, name, arrow, segment);
+ Style::Instance().MultiRangeSegment(cr, faked_state, name, kFontSizePx, arrow, segment);
NeedRedraw();
}
diff --git a/dash/FilterMultiRangeButton.h b/dash/FilterMultiRangeButton.h
index 2dd52466e..6ff734ac8 100644
--- a/dash/FilterMultiRangeButton.h
+++ b/dash/FilterMultiRangeButton.h
@@ -52,8 +52,8 @@ enum class MultiRangeArrow : unsigned int
class FilterMultiRangeButton : public nux::ToggleButton
{
+ NUX_DECLARE_OBJECT_TYPE(FilterMultiRangeButton, nux::ToggleButton);
public:
- FilterMultiRangeButton (std::string const& label, NUX_FILE_LINE_PROTO);
FilterMultiRangeButton (NUX_FILE_LINE_PROTO);
~FilterMultiRangeButton();
@@ -94,6 +94,7 @@ private:
std::map<MapKey, NuxCairoPtr> focus_;
std::map<MapKey, NuxCairoPtr> normal_;
std::map<MapKey, NuxCairoPtr> prelight_;
+ bool theme_init_;
nux::Geometry cached_geometry_;
MultiRangeArrow has_arrow_;
diff --git a/dash/FilterMultiRangeWidget.cpp b/dash/FilterMultiRangeWidget.cpp
index cefba465f..653045c81 100644
--- a/dash/FilterMultiRangeWidget.cpp
+++ b/dash/FilterMultiRangeWidget.cpp
@@ -37,10 +37,11 @@ namespace unity
namespace dash
{
-NUX_IMPLEMENT_OBJECT_TYPE(FilterMultiRange);
+NUX_IMPLEMENT_OBJECT_TYPE(FilterMultiRangeWidget);
-FilterMultiRange::FilterMultiRange(NUX_FILE_LINE_DECL)
+FilterMultiRangeWidget::FilterMultiRangeWidget(NUX_FILE_LINE_DECL)
: FilterExpanderLabel(_("Multi-range"), NUX_FILE_LINE_PARAM)
+ , dragging_(false)
{
InitTheme();
@@ -59,21 +60,30 @@ FilterMultiRange::FilterMultiRange(NUX_FILE_LINE_DECL)
SetRightHandView(all_button_);
SetContents(layout_);
OnActiveChanged(false);
-}
-FilterMultiRange::~FilterMultiRange()
-{
+ mouse_move.connect(sigc::mem_fun(this, &FilterMultiRangeWidget::RecvMouseMove));
+ mouse_down.connect(sigc::mem_fun(this, &FilterMultiRangeWidget::RecvMouseDown));
+ mouse_up.connect(sigc::mem_fun(this, &FilterMultiRangeWidget::RecvMouseUp));
+
+ mouse_drag.connect(sigc::mem_fun(this, &FilterMultiRangeWidget::RecvMouseDrag));
}
-void FilterMultiRange::SetFilter(Filter::Ptr const& filter)
+void FilterMultiRangeWidget::SetFilter(Filter::Ptr const& filter)
{
+ // Reset filter.
+ layout_->Clear();
+ buttons_.clear();
+ mouse_down_button_.Release();
+ mouse_down_left_active_button_.Release();
+ mouse_down_right_active_button_.Release();
+
filter_ = std::static_pointer_cast<MultiRangeFilter>(filter);
all_button_->SetFilter(filter_);
expanded = !filter_->collapsed();
- filter_->option_added.connect(sigc::mem_fun(this, &FilterMultiRange::OnOptionAdded));
- filter_->option_removed.connect(sigc::mem_fun(this, &FilterMultiRange::OnOptionRemoved));
+ filter_->option_added.connect(sigc::mem_fun(this, &FilterMultiRangeWidget::OnOptionAdded));
+ filter_->option_removed.connect(sigc::mem_fun(this, &FilterMultiRangeWidget::OnOptionRemoved));
// finally - make sure we are up-todate with our filter list
for (auto it : filter_->options())
@@ -82,7 +92,7 @@ void FilterMultiRange::SetFilter(Filter::Ptr const& filter)
SetLabel(filter_->name);
}
-void FilterMultiRange::OnActiveChanged(bool value)
+void FilterMultiRangeWidget::OnActiveChanged(bool value)
{
// go through all the buttons, and set the state :(
int start = 2000;
@@ -91,10 +101,11 @@ void FilterMultiRange::OnActiveChanged(bool value)
for (auto button : buttons_)
{
FilterOption::Ptr filter = button->GetFilter();
- bool tmp_active = filter->active;
- button->SetActive(tmp_active);
if (filter != nullptr)
{
+ bool tmp_active = filter->active;
+ button->SetActive(tmp_active);
+
if (filter->active)
{
if (index < start)
@@ -129,43 +140,249 @@ void FilterMultiRange::OnActiveChanged(bool value)
}
}
-void FilterMultiRange::OnOptionAdded(FilterOption::Ptr const& new_filter)
+void FilterMultiRangeWidget::OnOptionAdded(FilterOption::Ptr const& new_filter)
{
- FilterMultiRangeButton* button = new FilterMultiRangeButton(NUX_TRACKER_LOCATION);
+ FilterMultiRangeButtonPtr button(new FilterMultiRangeButton(NUX_TRACKER_LOCATION));
button->SetFilter(new_filter);
- layout_->AddView(button);
+ layout_->AddView(button.GetPointer());
buttons_.push_back(button);
- new_filter->active.changed.connect(sigc::mem_fun(this, &FilterMultiRange::OnActiveChanged));
+ new_filter->active.changed.connect(sigc::mem_fun(this, &FilterMultiRangeWidget::OnActiveChanged));
OnActiveChanged(false);
+ QueueRelayout();
}
-void FilterMultiRange::OnOptionRemoved(FilterOption::Ptr const& removed_filter)
+void FilterMultiRangeWidget::OnOptionRemoved(FilterOption::Ptr const& removed_filter)
{
for (auto it=buttons_.begin() ; it != buttons_.end(); it++)
{
if ((*it)->GetFilter() == removed_filter)
{
- layout_->RemoveChildObject(*it);
+ layout_->RemoveChildObject(it->GetPointer());
buttons_.erase(it);
break;
}
}
-
OnActiveChanged(false);
+
+ QueueRelayout();
}
-std::string FilterMultiRange::GetFilterType()
+std::string FilterMultiRangeWidget::GetFilterType()
{
- return "FilterMultiRange";
+ return "FilterMultiRangeWidget";
}
-void FilterMultiRange::InitTheme()
+void FilterMultiRangeWidget::InitTheme()
{
//FIXME - build theme here - store images, cache them, fun fun fun
}
-void FilterMultiRange::ClearRedirectedRenderChildArea()
+nux::Area* FilterMultiRangeWidget::FindAreaUnderMouse(const nux::Point& mouse_position, nux::NuxEventType event_type)
+{
+ bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type);
+ if (!mouse_inside)
+ return nullptr;
+
+ nux::Area* area = View::FindAreaUnderMouse(mouse_position, nux::NUX_MOUSE_MOVE);
+ if (area && area->Type().IsDerivedFromType(FilterMultiRangeButton::StaticObjectType))
+ {
+ return this;
+ }
+
+ return area;
+}
+
+void FilterMultiRangeWidget::RecvMouseMove(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags)
+{
+ nux::Geometry geo = GetAbsoluteGeometry();
+ nux::Point abs_cursor(geo.x + x, geo.y + y);
+ UpdateMouseFocus(abs_cursor);
+}
+
+void FilterMultiRangeWidget::RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags)
+{
+ mouse_down_button_.Release();
+ mouse_down_left_active_button_.Release();
+ mouse_down_right_active_button_.Release();
+
+ dragging_ = false;
+ nux::Geometry geo = GetAbsoluteGeometry();
+ nux::Point abs_cursor(geo.x + x, geo.y + y);
+
+ nux::Area* area = View::FindAreaUnderMouse(nux::Point(abs_cursor.x, abs_cursor.y), nux::NUX_MOUSE_PRESSED);
+
+ if (!area || !area->Type().IsDerivedFromType(FilterMultiRangeButton::StaticObjectType))
+ return;
+ mouse_down_button_ = static_cast<FilterMultiRangeButton*>(area);
+
+ // Cache the left/right selected buttons.
+ FilterMultiRangeButtonPtr last_selected_button;
+ for (FilterMultiRangeButtonPtr button : buttons_)
+ {
+ if (button->Active())
+ {
+ if (!mouse_down_left_active_button_.IsValid())
+ mouse_down_left_active_button_ = button;
+ last_selected_button = button;
+ }
+ }
+ mouse_down_right_active_button_ = last_selected_button;
+}
+
+void FilterMultiRangeWidget::RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags)
+{
+ FilterMultiRangeButtonPtr mouse_down_button(mouse_down_button_);
+ mouse_down_button_.Release();
+
+ if (dragging_)
+ {
+ dragging_ = false;
+ return;
+ }
+
+ nux::Geometry geo = GetAbsoluteGeometry();
+ nux::Area* area = View::FindAreaUnderMouse(nux::Point(geo.x + x, geo.y + y), nux::NUX_MOUSE_RELEASED);
+ if (!area || !area->Type().IsDerivedFromType(FilterMultiRangeButton::StaticObjectType))
+ return;
+
+ FilterMultiRangeButtonPtr mouse_up_button;
+ mouse_up_button = static_cast<FilterMultiRangeButton*>(area);
+ if (mouse_up_button == mouse_down_button)
+ Click(mouse_up_button);
+}
+
+void FilterMultiRangeWidget::RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags)
+{
+ nux::Geometry geo = GetAbsoluteGeometry();
+ nux::Point abs_cursor(geo.x + x, geo.y + y);
+ UpdateMouseFocus(abs_cursor);
+
+ if (!CheckDrag())
+ return;
+
+ nux::Area* area = View::FindAreaUnderMouse(nux::Point(abs_cursor.x, abs_cursor.y), nux::NUX_MOUSE_MOVE);
+ if (!area || !area->Type().IsDerivedFromType(FilterMultiRangeButton::StaticObjectType))
+ return;
+
+ FilterMultiRangeButtonPtr drag_over_button;
+ drag_over_button = static_cast<FilterMultiRangeButton*>(area);
+ if (!drag_over_button.IsValid())
+ return;
+ dragging_ = true;
+
+ nux::Geometry mouse_down_button_geometry = mouse_down_button_->GetAbsoluteGeometry();
+
+ nux::Geometry left_active_button_geometry = mouse_down_left_active_button_->GetAbsoluteGeometry();
+ nux::Geometry right_active_button_geometry = mouse_down_right_active_button_->GetAbsoluteGeometry();
+
+ auto end = buttons_.end();
+ int found_buttons = 0;
+ for (auto iter = buttons_.begin(); iter != end; ++iter)
+ {
+ FilterMultiRangeButtonPtr button = *iter;
+ bool activate = false;
+
+ // if we've dragged the left button, we want to activate everything between the "drag over button" and the "right button"
+ if (mouse_down_button_ == mouse_down_left_active_button_ &&
+ button == mouse_down_right_active_button_)
+ {
+ found_buttons++;
+ activate = true;
+ }
+ // if we've dragged the right button, we want to activate everything between the "left button" and the "drag over button"
+ else if (mouse_down_button_ == mouse_down_right_active_button_ &&
+ button == mouse_down_left_active_button_)
+ {
+ found_buttons++;
+ activate = true;
+ }
+
+ if (button == drag_over_button)
+ {
+ found_buttons++;
+ activate = true;
+ }
+
+ if (activate || (found_buttons > 0 && found_buttons < 2))
+ {
+ button->Activate();
+ }
+ else
+ {
+ button->Deactivate();
+ }
+ }
+}
+
+bool FilterMultiRangeWidget::CheckDrag()
+{
+ if (!mouse_down_button_)
+ return false;
+
+ auto end = buttons_.end();
+ bool between = false;
+ bool active_found = false;
+ for (auto iter = buttons_.begin(); iter != end; ++iter)
+ {
+ FilterMultiRangeButtonPtr button = *iter;
+ if (button->Active())
+ {
+ active_found = true;
+ if (button == mouse_down_button_)
+ {
+ between = true;
+ }
+ }
+ else if (active_found)
+ {
+ active_found = false;
+ break;
+ }
+ }
+
+ if (mouse_down_button_ != mouse_down_left_active_button_ && mouse_down_button_ != mouse_down_right_active_button_)
+ {
+ if (between)
+ return false;
+ mouse_down_left_active_button_ = mouse_down_button_;
+ mouse_down_right_active_button_ = mouse_down_button_;
+ }
+
+ return true;
+}
+
+void FilterMultiRangeWidget::UpdateMouseFocus(nux::Point const& abs_cursor_position)
+{
+ nux::Area* area = View::FindAreaUnderMouse(nux::Point(abs_cursor_position.x, abs_cursor_position.y), nux::NUX_MOUSE_MOVE);
+ if (!area || !area->Type().IsDerivedFromType(FilterMultiRangeButton::StaticObjectType))
+ return;
+
+ nux::GetWindowCompositor().SetKeyFocusArea(static_cast<InputArea*>(area), nux::KEY_NAV_NONE);
+}
+
+void FilterMultiRangeWidget::Click(FilterMultiRangeButtonPtr const& activated_button)
+{
+ bool current_activated = activated_button->Active();
+ bool any_others_active = false;
+
+ for (FilterMultiRangeButtonPtr button : buttons_)
+ {
+ if (button != activated_button)
+ {
+ if (button->Active())
+ any_others_active = true;
+ button->Deactivate();
+ }
+ }
+
+ if (!any_others_active && current_activated)
+ activated_button->Deactivate();
+ else
+ activated_button->Activate();
+}
+
+void FilterMultiRangeWidget::ClearRedirectedRenderChildArea()
{
for (auto button : buttons_)
{
diff --git a/dash/FilterMultiRangeWidget.h b/dash/FilterMultiRangeWidget.h
index 7b3c8b47b..8e2313f7e 100644
--- a/dash/FilterMultiRangeWidget.h
+++ b/dash/FilterMultiRangeWidget.h
@@ -39,12 +39,12 @@ namespace dash
class FilterMultiRangeButton;
-class FilterMultiRange : public FilterExpanderLabel
+class FilterMultiRangeWidget : public FilterExpanderLabel
{
- NUX_DECLARE_OBJECT_TYPE(FilterMultiRange, FilterExpanderLabel);
+ NUX_DECLARE_OBJECT_TYPE(FilterMultiRangeWidget, FilterExpanderLabel);
+ typedef nux::ObjectPtr<FilterMultiRangeButton> FilterMultiRangeButtonPtr;
public:
- FilterMultiRange(NUX_FILE_LINE_PROTO);
- virtual ~FilterMultiRange();
+ FilterMultiRangeWidget(NUX_FILE_LINE_PROTO);
void SetFilter(Filter::Ptr const& filter);
std::string GetFilterType();
@@ -52,6 +52,13 @@ public:
protected:
void InitTheme();
+ nux::Area* FindAreaUnderMouse(const nux::Point& mouse_position, nux::NuxEventType event_type);
+
+ void RecvMouseMove(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags);
+ void RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags);
+ void RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags);
+ void RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags);
+
void ClearRedirectedRenderChildArea();
private:
@@ -60,11 +67,23 @@ private:
void OnOptionRemoved(dash::FilterOption::Ptr const& removed_filter);
void OnActiveChanged(bool value);
+ void UpdateMouseFocus(nux::Point const& abs_cursor_position);
+ virtual void Click(FilterMultiRangeButtonPtr const& button);
+
+ bool CheckDrag();
+
nux::HLayout* layout_;
FilterAllButton* all_button_;
- std::vector<FilterMultiRangeButton*> buttons_;
+ std::vector<FilterMultiRangeButtonPtr> buttons_;
MultiRangeFilter::Ptr filter_;
+
+ FilterMultiRangeButtonPtr mouse_down_button_;
+ FilterMultiRangeButtonPtr mouse_down_left_active_button_;
+ FilterMultiRangeButtonPtr mouse_down_right_active_button_;
+ bool dragging_;
+
+ friend class TestFilterMultiRangeWidget;
};
} // unityshell dash
diff --git a/dash/FilterRatingsButton.cpp b/dash/FilterRatingsButton.cpp
index 0c4628c05..2f2374b26 100644
--- a/dash/FilterRatingsButton.cpp
+++ b/dash/FilterRatingsButton.cpp
@@ -38,6 +38,9 @@ namespace unity
{
namespace dash
{
+
+NUX_IMPLEMENT_OBJECT_TYPE(FilterRatingsButton);
+
FilterRatingsButton::FilterRatingsButton(NUX_FILE_LINE_DECL)
: nux::ToggleButton(NUX_FILE_LINE_PARAM)
, focused_star_(-1)
diff --git a/dash/FilterRatingsButton.h b/dash/FilterRatingsButton.h
index 91b510d57..fdafa187a 100644
--- a/dash/FilterRatingsButton.h
+++ b/dash/FilterRatingsButton.h
@@ -36,6 +36,7 @@ namespace dash
class FilterRatingsButton : public nux::ToggleButton
{
+ NUX_DECLARE_OBJECT_TYPE(FilterRatingsButton, nux::ToggleButton);
public:
FilterRatingsButton(NUX_FILE_LINE_PROTO);
virtual ~FilterRatingsButton();
diff --git a/dash/PreviewStateMachine.cpp b/dash/PreviewStateMachine.cpp
index c145f07e0..3a48eeab0 100644
--- a/dash/PreviewStateMachine.cpp
+++ b/dash/PreviewStateMachine.cpp
@@ -30,6 +30,7 @@ PreviewStateMachine::PreviewStateMachine()
, right_results(-1)
, stored_preview_(nullptr)
, requires_activation_(true)
+ , requires_new_position_(false)
{
for (int pos = SplitPosition::START; pos != SplitPosition::END; pos++)
{
diff --git a/dash/previews/SocialPreviewContent.cpp b/dash/previews/SocialPreviewContent.cpp
index 4cff81af2..2e981e9e1 100644
--- a/dash/previews/SocialPreviewContent.cpp
+++ b/dash/previews/SocialPreviewContent.cpp
@@ -223,8 +223,7 @@ void SocialPreviewContent::DrawBubble(cairo_t* cr,
cairo_set_line_width(cr, line_width);
- bool odd = true;
- odd = line_width != double((int)line_width);
+ bool odd = line_width != double((int)line_width);
// top-left, right of the corner
cairo_move_to(cr, _align (x + radius, odd), _align (y, odd));
diff --git a/debian/changelog b/debian/changelog
index 81747fbba..61f04b106 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,133 @@
+unity (6.12.0daily13.03.07-0ubuntu1) raring; urgency=low
+
+ * Automatic snapshot from revision 3194
+
+ -- Automatic PS uploader <ps-jenkins@lists.canonical.com> Thu, 07 Mar 2013 04:02:28 +0000
+
+unity (6.12.0daily13.03.06.1-0ubuntu1) raring; urgency=low
+
+ [ Didier Roche ]
+ * Build-dep on libjson-perl to get debian/scopes-recommends-generator
+ parsing the libunity-common json file successfully (and so having
+ the recommended scopes… recommended)
+
+ [ Alexandre Abreu ]
+ * Web apps - After the user quits a web app that has just been
+ installed the icon doesn't stay in the launcher (LP: #1061056)
+
+ [ Automatic PS uploader ]
+ * Automatic snapshot from revision 3190
+
+ -- Automatic PS uploader <ps-jenkins@lists.canonical.com> Wed, 06 Mar 2013 13:26:28 +0000
+
+unity (6.12.0daily13.03.05-0ubuntu1) raring; urgency=low
+
+ [ Didier Roche ]
+ * Need a .json file for having the list of default installed lens and
+ scopes (LP: #1137303)
+
+ [ Andrea Azzarone ]
+ * [regression] On start up the Hud draws the panel gradient
+ incorrectly (LP: #1136447)
+
+ [ Automatic PS uploader ]
+ * Automatic snapshot from revision 3185
+
+ -- Automatic PS uploader <ps-jenkins@lists.canonical.com> Tue, 05 Mar 2013 04:02:33 +0000
+
+unity (6.12.0daily13.03.01-0ubuntu1) raring; urgency=low
+
+ [ Andrea Azzarone ]
+ * unity.tests.test_dash.DashVisualTests.test_dash_position_with_non_de
+ fault_launcher_width randomly fails (LP: #1135628)
+
+ [ Automatic PS uploader ]
+ * Automatic snapshot from revision 3179
+
+ -- Automatic PS uploader <ps-jenkins@lists.canonical.com> Fri, 01 Mar 2013 04:02:36 +0000
+
+unity (6.12.0daily13.02.28-0ubuntu1) raring; urgency=low
+
+ [ Stephen M. Webb ]
+ * unity watchfile is broken (LP: #1121754)
+
+ [ Andrea Azzarone ]
+ * Switcher does not focus the last active window in detail mode (using
+ alt+grave) (LP: #1133338)
+
+ [ Automatic PS uploader ]
+ * Automatic snapshot from revision 3175
+
+ -- Automatic PS uploader <ps-jenkins@lists.canonical.com> Thu, 28 Feb 2013 04:02:34 +0000
+
+unity (6.12.0daily13.02.26-0ubuntu1) raring; urgency=low
+
+ [ Andrea Azzarone ]
+ * Multi-monitor - Panel and launcher visible on top of multimonitor
+ non-focused fullscreen apps (LP: #748539)
+ * unity.tests.launcher.test_icon_behavior.LauncherIconsTests.* fails
+ randomly (LP: #1131679)
+
+ [ Xiao-Long Chen ]
+ * Add timeout before removing launcher (LP: #1119801)
+
+ [ MC Return ]
+ * cppcheck reports true positives (LP: #1131152)
+
+ [ Automatic PS uploader ]
+ * Automatic snapshot from revision 3171
+
+ -- Automatic PS uploader <ps-jenkins@lists.canonical.com> Tue, 26 Feb 2013 04:02:40 +0000
+
+unity (6.12.0daily13.02.19.1-0ubuntu1) raring; urgency=low
+
+ [ Brandon Schaefer ]
+ * Multi-monitor: Mousepointer hangs when passing between monitors,
+ although no Launcher is there (regression) (LP: #1120223)
+ * Sticky edges should only use horizontal mouse movement (LP: #982543)
+
+ [ Marco Trevisan (Treviño) ]
+ * Launcher - Workspace switcher should not be in the Launcher by
+ default (LP: #868423)
+ * [regression] Unlocking a running application, removes it from the
+ Launcher (LP: #1122311)
+ * Launcher, Workspaces - dragging and dropping the workspaces icon on
+ to the trash should switch Workspaces off (LP: #1118271)
+
+ [ Chris Townsend ]
+ * webapp: alt-tab gets "stucked" on the browser rather than going to
+ the next entry (LP: #1070715)
+
+ [ Nick Dedekind ]
+ * Dash - the "Decade" and "Size" dash filter category widgets are
+ broken (LP: #841899)
+ * Dash Places group is shining on quick mouse over (LP: #1119487)
+
+ [ Lukas Vacek ]
+ * Show window list when right clicking an icon in launcher - enables
+ quick window switching (LP: #1107866)
+
+ [ Marco Trevisan (Treviño) <mail@3v1n0.net>, Lukas Vacek ]
+ * Show window list when right clicking an icon in launcher - enables
+ quick window switching (LP: #1107866)
+
+ [ Andrea Azzarone ]
+ * unity launcher vanishes when switching to mirrored displays (LP:
+ #991637)
+ * Opening an app with super+num shorcut doesn't give focus to the app
+ (LP: #1125331)
+ * Alt+` and detail switcher broken after revision 3153 (LP: #1129372)
+
+ [ Sam Spilsbury ]
+ * Unity unnecessarily clears the ShapeBounding shape of windows on
+ minimize (LP: #1091600)
+ * Can't access minimized window after Unity restarts (LP: #851964)
+
+ [ Automatic PS uploader ]
+ * Automatic snapshot from revision 3163
+
+ -- Automatic PS uploader <ps-jenkins@lists.canonical.com> Tue, 19 Feb 2013 14:26:14 +0000
+
unity (6.12.0daily13.02.08-0ubuntu1) raring; urgency=low
[ Brandon Schaefer ]
diff --git a/debian/control b/debian/control
index 078c06db8..da36c4492 100644
--- a/debian/control
+++ b/debian/control
@@ -9,6 +9,7 @@ Build-Depends: cmake,
pkg-config,
python (>= 2.7),
python-setuptools,
+ libjson-perl,
quilt,
intltool (>= 0.35.0),
libsigc++-2.0-dev,
@@ -39,6 +40,7 @@ Build-Depends: cmake,
libjson-glib-dev,
libgeis-dev (>= 2.0.10),
libunity-dev (>= 6.5.2),
+ libunity-common,
libzeitgeist-dev (>= 0.3.18),
libxfixes-dev (>= 1:5.0-4ubuntu4),
libgtest-dev,
@@ -67,12 +69,7 @@ Depends: ${shlibs:Depends},
unity-asset-pool (>= 0.8.18),
Provides: indicator-renderer
Recommends: gnome-control-center-unity,
- unity-lens-applications,
- unity-lens-files,
- unity-lens-music,
- unity-lens-photos,
- unity-lens-shopping,
- unity-lens-video,
+ ${unity-default-masterscopes}
indicator-appmenu,
indicator-application,
indicator-sound,
diff --git a/debian/rules b/debian/rules
index e8233a7d3..bb9c0c982 100755
--- a/debian/rules
+++ b/debian/rules
@@ -19,6 +19,9 @@ NUX_ABIVERSION := $(shell sed -rn 's/^\#define[[:space:]]+NUX_ABIVERSION[[:space
LIBUNITY_PRIVATE := $(shell pkg-config --libs-only-L unity-protocol-private | sed -e 's/-L\(.*\)/\1/' )
+SCOPES_RECOMMENDS := $(shell perl debian/scopes-recommends-generator /usr/share/unity/client-scopes.json)
+
+
override_dh_auto_configure:
ifeq ($(DEB_HOST_ARCH),$(findstring $(DEB_HOST_ARCH), $(gles2_architectures)))
dh_auto_configure -- -DUSE_GSETTINGS=TRUE -DCOMPIZ_BUILD_WITH_RPATH=FALSE -DCOMPIZ_PACKAGING_ENABLED=TRUE -DCOMPIZ_PLUGIN_INSTALL_TYPE=package -DBUILD_GLES=TRUE -DDISABLE_MAINTAINER_CFLAGS=ON
@@ -42,7 +45,7 @@ override_dh_install:
dh_install --fail-missing
override_dh_gencontrol:
- dh_gencontrol -- -Vcoreabiversion=$(CORE_ABIVERSION) -Vnuxabiversion=$(NUX_ABIVERSION)
+ dh_gencontrol -- -Vcoreabiversion=$(CORE_ABIVERSION) -Vnuxabiversion=$(NUX_ABIVERSION) -Vunity-default-masterscopes="$(SCOPES_RECOMMENDS)"
override_dh_makeshlibs:
dh_makeshlibs -plibunity-core-6.0-5 -V 'libunity-core-6.0-5 (>= 4.14.2)'
diff --git a/debian/scopes-recommends-generator b/debian/scopes-recommends-generator
new file mode 100755
index 000000000..0d688f50e
--- /dev/null
+++ b/debian/scopes-recommends-generator
@@ -0,0 +1,27 @@
+#!/usr/bin/perl -w
+
+use strict;
+binmode STDOUT, ":utf8";
+use utf8;
+
+use JSON;
+
+my $json;
+{
+ local $/; #Enable 'slurp' mode
+ open my $fh, "<", $ARGV[0];
+ $json = <$fh>;
+ close $fh;
+}
+# get it to a scalar
+my $j = "[" . $json . "]";
+
+my $decoded_json = decode_json( $j );
+
+my $recommends_list = "";
+for my $record ( @$decoded_json ) {
+ foreach my $key ( keys(%$record) ) {
+ $recommends_list = $recommends_list . $key . ", ";
+ }
+}
+print $recommends_list;
diff --git a/debian/watch b/debian/watch
index 8ef36d6e6..4fc0e423e 100644
--- a/debian/watch
+++ b/debian/watch
@@ -1,2 +1,3 @@
version=3
-https://launchpad.net/unity/+download .*/unity-([0-9.]+)\.tar\.bz2
+opts=dversionmangle=s/daily.*// \
+ https://launchpad.net/unity/+download .*/unity-([0-9.]+)\.tar\.(?:xz|bz2|gz)
diff --git a/hud/HudController.cpp b/hud/HudController.cpp
index 2f38f4a12..f8687a367 100644
--- a/hud/HudController.cpp
+++ b/hud/HudController.cpp
@@ -86,7 +86,8 @@ Controller::Controller(Controller::ViewCreator const& create_view,
unity::glib::String overlay_identity;
gboolean can_maximise = FALSE;
gint32 overlay_monitor = 0;
- g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING, &overlay_identity, &can_maximise, &overlay_monitor);
+ int width, height;
+ g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING, &overlay_identity, &can_maximise, &overlay_monitor, &width, &height);
if (overlay_identity.Str() != "hud")
{
@@ -119,14 +120,17 @@ void Controller::SetupWindow()
window_->mouse_down_outside_pointer_grab_area.connect(
sigc::mem_fun(this, &Controller::OnMouseDownOutsideWindow));
- /* FIXME - first time we load our windows there is a race that causes the
- * input window not to actually get input, this side steps that by causing
- * an input window show and hide before we really need it. */
- WindowManager& wm = WindowManager::Default();
- wm.SaveInputFocus();
- window_->EnableInputWindow(true, "Hud", true, false);
- window_->EnableInputWindow(false, "Hud", true, false);
- wm.RestoreInputFocus();
+ if (nux::GetWindowThread()->IsEmbeddedWindow())
+ {
+ /* FIXME - first time we load our windows there is a race that causes the
+ * input window not to actually get input, this side steps that by causing
+ * an input window show and hide before we really need it. */
+ WindowManager& wm = WindowManager::Default();
+ wm.SaveInputFocus();
+ window_->EnableInputWindow(true, "Hud", true, false);
+ window_->EnableInputWindow(false, "Hud", true, false);
+ wm.RestoreInputFocus();
+ }
}
void Controller::SetupHudView()
@@ -372,7 +376,10 @@ void Controller::ShowHud()
// hide the launcher
GVariant* message_data = g_variant_new("(b)", TRUE);
ubus.SendMessage(UBUS_LAUNCHER_LOCK_HIDE, message_data);
- GVariant* info = g_variant_new(UBUS_OVERLAY_FORMAT_STRING, "hud", FALSE, monitor_index_);
+
+ auto const& view_content_geometry = view_->GetContentGeometry();
+ GVariant* info = g_variant_new(UBUS_OVERLAY_FORMAT_STRING, "hud", FALSE, monitor_index_,
+ view_content_geometry.width, view_content_geometry.height);
ubus.SendMessage(UBUS_OVERLAY_SHOWN, info);
nux::GetWindowCompositor().SetKeyFocusArea(view_->default_focus());
@@ -383,8 +390,13 @@ void Controller::FocusWindow()
{
window_->ShowWindow(true);
window_->PushToFront();
- window_->EnableInputWindow(true, "Hud", true, false);
- window_->UpdateInputWindowGeometry();
+
+ if (nux::GetWindowThread()->IsEmbeddedWindow())
+ {
+ window_->EnableInputWindow(true, "Hud", true, false);
+ window_->UpdateInputWindowGeometry();
+ }
+
window_->SetInputFocus();
window_->QueueDraw();
}
@@ -416,7 +428,9 @@ void Controller::HideHud(bool restore)
GVariant* message_data = g_variant_new("(b)", FALSE);
ubus.SendMessage(UBUS_LAUNCHER_LOCK_HIDE, message_data);
- GVariant* info = g_variant_new(UBUS_OVERLAY_FORMAT_STRING, "hud", FALSE, monitor_index_);
+ auto const& view_content_geometry = view_->GetContentGeometry();
+ GVariant* info = g_variant_new(UBUS_OVERLAY_FORMAT_STRING, "hud", FALSE, monitor_index_,
+ view_content_geometry.width, view_content_geometry.height);
ubus.SendMessage(UBUS_OVERLAY_HIDDEN, info);
}
diff --git a/hud/HudView.cpp b/hud/HudView.cpp
index e0c08c72a..32d6e548e 100644
--- a/hud/HudView.cpp
+++ b/hud/HudView.cpp
@@ -557,6 +557,7 @@ void View::AddProperties(GVariantBuilder* builder)
variant::BuilderWrapper(builder)
.add(GetGeometry())
.add("selected_button", selected_button_)
+ .add("overlay_window_buttons_shown", overlay_window_buttons_->IsVisible())
.add("num_buttons", num_buttons);
}
diff --git a/launcher/AbstractLauncherIcon.h b/launcher/AbstractLauncherIcon.h
index db8f1492b..36d0eddaf 100644
--- a/launcher/AbstractLauncherIcon.h
+++ b/launcher/AbstractLauncherIcon.h
@@ -59,9 +59,10 @@ public:
{
}
- ActionArg(Source source, int button, Window target = 0, int monitor = -1)
+ ActionArg(Source source, int button, Time timestamp = -1, Window target = 0, int monitor = -1)
: source(source)
, button(button)
+ , timestamp(timestamp)
, target(target)
, monitor(monitor)
{
@@ -69,6 +70,7 @@ public:
Source source;
int button;
+ Time timestamp;
Window target;
int monitor;
};
@@ -131,7 +133,9 @@ public:
nux::Property<std::string> tooltip_text;
nux::Property<bool> tooltip_enabled;
nux::Property<Position> position;
+ nux::Property<bool> removed;
+ virtual void ShowTooltip() = 0;
virtual void HideTooltip() = 0;
virtual void SetShortcut(guint64 shortcut) = 0;
diff --git a/launcher/ApplicationLauncherIcon.cpp b/launcher/ApplicationLauncherIcon.cpp
index 6ff39832c..ade59aacc 100644
--- a/launcher/ApplicationLauncherIcon.cpp
+++ b/launcher/ApplicationLauncherIcon.cpp
@@ -324,7 +324,7 @@ void ApplicationLauncherIcon::ActivateLauncherIcon(ActionArg arg)
return;
SetQuirk(Quirk::STARTING, true);
- OpenInstanceLauncherIcon();
+ OpenInstanceLauncherIcon(arg.timestamp);
}
else // app is running
{
@@ -468,12 +468,19 @@ void ApplicationLauncherIcon::UpdateDesktopFile()
g_file_monitor_set_rate_limit(_desktop_file_monitor, 1000);
auto sig = new glib::Signal<void, GFileMonitor*, GFile*, GFile*, GFileMonitorEvent>(_desktop_file_monitor, "changed",
- [&] (GFileMonitor*, GFile*, GFile*, GFileMonitorEvent event_type) {
+ [&] (GFileMonitor*, GFile* f, GFile*, GFileMonitorEvent event_type) {
switch (event_type)
{
case G_FILE_MONITOR_EVENT_DELETED:
- UnStick();
+ {
+ glib::Object<GFile> file(f, glib::AddRef());
+ _source_manager.AddTimeoutSeconds(1, [this, file] {
+ if (!g_file_query_exists (file, nullptr))
+ UnStick();
+ return false;
+ });
break;
+ }
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
UpdateDesktopQuickList();
UpdateBackgroundColor();
@@ -510,7 +517,7 @@ void ApplicationLauncherIcon::AddProperties(GVariantBuilder* builder)
.add("startup_notification_timestamp", _startup_notification_timestamp);
}
-void ApplicationLauncherIcon::OpenInstanceWithUris(std::set<std::string> const& uris)
+void ApplicationLauncherIcon::OpenInstanceWithUris(std::set<std::string> const& uris, Time timestamp)
{
glib::Error error;
glib::Object<GDesktopAppInfo> desktopInfo(g_desktop_app_info_new_from_filename(DesktopFile().c_str()));
@@ -519,8 +526,9 @@ void ApplicationLauncherIcon::OpenInstanceWithUris(std::set<std::string> const&
GdkDisplay* display = gdk_display_get_default();
glib::Object<GdkAppLaunchContext> app_launch_context(gdk_display_get_app_launch_context(display));
- _startup_notification_timestamp = nux::GetWindowThread()->GetGraphicsDisplay().GetCurrentEvent().x11_timestamp;
- gdk_app_launch_context_set_timestamp(app_launch_context, _startup_notification_timestamp);
+ _startup_notification_timestamp = timestamp;
+ if (_startup_notification_timestamp >= 0)
+ gdk_app_launch_context_set_timestamp(app_launch_context, _startup_notification_timestamp);
if (g_app_info_supports_uris(appInfo))
{
@@ -558,10 +566,10 @@ void ApplicationLauncherIcon::OpenInstanceWithUris(std::set<std::string> const&
UpdateQuirkTime(Quirk::STARTING);
}
-void ApplicationLauncherIcon::OpenInstanceLauncherIcon()
+void ApplicationLauncherIcon::OpenInstanceLauncherIcon(Time timestamp)
{
std::set<std::string> empty;
- OpenInstanceWithUris(empty);
+ OpenInstanceWithUris(empty, timestamp);
}
void ApplicationLauncherIcon::Focus(ActionArg arg)
@@ -576,7 +584,7 @@ void ApplicationLauncherIcon::Focus(ActionArg arg)
else if (app_->type() == "webapp")
{
// Webapps are again special.
- OpenInstanceLauncherIcon();
+ OpenInstanceLauncherIcon(arg.timestamp);
return;
}
@@ -779,7 +787,10 @@ void ApplicationLauncherIcon::UnStick()
if (!IsSticky())
return;
+ SetQuirk(Quirk::VISIBLE, app_->running());
+
app_->sticky = false;
+
if (!app_->running())
Remove();
}
@@ -1143,7 +1154,8 @@ nux::DndAction ApplicationLauncherIcon::OnQueryAcceptDrop(DndData const& dnd_dat
void ApplicationLauncherIcon::OnAcceptDrop(DndData const& dnd_data)
{
- OpenInstanceWithUris(ValidateUrisForLaunch(dnd_data));
+ auto timestamp = nux::GetWindowThread()->GetGraphicsDisplay().GetCurrentEvent().x11_timestamp;
+ OpenInstanceWithUris(ValidateUrisForLaunch(dnd_data), timestamp);
}
bool ApplicationLauncherIcon::ShowInSwitcher(bool current)
diff --git a/launcher/ApplicationLauncherIcon.h b/launcher/ApplicationLauncherIcon.h
index 7bee592c5..04594aa48 100644
--- a/launcher/ApplicationLauncherIcon.h
+++ b/launcher/ApplicationLauncherIcon.h
@@ -77,7 +77,7 @@ protected:
void OnDndEnter();
void OnDndHovered();
void OnDndLeave();
- void OpenInstanceLauncherIcon();
+ void OpenInstanceLauncherIcon(Time timestamp) override;
void ToggleSticky();
bool OnShouldHighlightOnDrag(DndData const& dnd_data);
@@ -114,7 +114,7 @@ private:
void UpdateMenus();
void UpdateDesktopQuickList();
- void OpenInstanceWithUris(std::set<std::string> const& uris);
+ void OpenInstanceWithUris(std::set<std::string> const& uris, Time timestamp);
void Focus(ActionArg arg);
bool Spread(bool current_desktop, int state, bool force);
diff --git a/launcher/BFBLauncherIcon.cpp b/launcher/BFBLauncherIcon.cpp
index a84d71f7b..f7d701020 100644
--- a/launcher/BFBLauncherIcon.cpp
+++ b/launcher/BFBLauncherIcon.cpp
@@ -58,8 +58,9 @@ void BFBLauncherIcon::OnOverlayShown(GVariant *data, bool visible)
unity::glib::String overlay_identity;
gboolean can_maximise = FALSE;
gint32 overlay_monitor = 0;
+ int width, height;
g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING,
- &overlay_identity, &can_maximise, &overlay_monitor);
+ &overlay_identity, &can_maximise, &overlay_monitor, &width, &height);
if (overlay_identity.Str() == "dash" && IsVisibleOnMonitor(overlay_monitor))
{
diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt
index 3987c69cf..b32d93953 100644
--- a/launcher/CMakeLists.txt
+++ b/launcher/CMakeLists.txt
@@ -57,6 +57,7 @@ set (LAUNCHER_SOURCES
SoftwareCenterLauncherIcon.cpp
SpacerLauncherIcon.cpp
Tooltip.cpp
+ TooltipManager.cpp
TrashLauncherIcon.cpp
VolumeImp.cpp
VolumeLauncherIcon.cpp
diff --git a/launcher/EdgeBarrierController.cpp b/launcher/EdgeBarrierController.cpp
index c1d1ad8da..46514431d 100644
--- a/launcher/EdgeBarrierController.cpp
+++ b/launcher/EdgeBarrierController.cpp
@@ -24,8 +24,15 @@
#include "unity-shared/UScreen.h"
#include "UnityCore/GLibSource.h"
-namespace unity {
-namespace ui {
+namespace unity
+{
+namespace ui
+{
+
+namespace
+{
+ int const Y_BREAK_BUFFER = 20;
+}
EdgeBarrierController::Impl::Impl(EdgeBarrierController *parent)
@@ -119,7 +126,14 @@ void EdgeBarrierController::Impl::BarrierReset()
void EdgeBarrierController::Impl::BarrierPush(PointerBarrierWrapper* owner, BarrierEvent::Ptr const& event)
{
- decaymulator_.value = decaymulator_.value + event->velocity;
+ if (EventIsInsideYBreakZone(event))
+ {
+ decaymulator_.value = decaymulator_.value + event->velocity;
+ }
+ else
+ {
+ BarrierReset();
+ }
if (decaymulator_.value > edge_overcome_pressure_)
{
@@ -127,6 +141,22 @@ void EdgeBarrierController::Impl::BarrierPush(PointerBarrierWrapper* owner, Barr
}
}
+bool EdgeBarrierController::Impl::EventIsInsideYBreakZone(BarrierEvent::Ptr const& event)
+{
+ static int y_break_zone = event->y;
+
+ if (decaymulator_.value <= 0)
+ y_break_zone = event->y;
+
+ if (event->y <= y_break_zone + Y_BREAK_BUFFER &&
+ event->y >= y_break_zone - Y_BREAK_BUFFER)
+ {
+ return true;
+ }
+
+ return false;
+}
+
void EdgeBarrierController::Impl::OnPointerBarrierEvent(PointerBarrierWrapper* owner, BarrierEvent::Ptr const& event)
{
if (owner->released)
diff --git a/launcher/EdgeBarrierControllerPrivate.h b/launcher/EdgeBarrierControllerPrivate.h
index c7cef24b8..eb4199d19 100644
--- a/launcher/EdgeBarrierControllerPrivate.h
+++ b/launcher/EdgeBarrierControllerPrivate.h
@@ -42,6 +42,8 @@ struct EdgeBarrierController::Impl
void BarrierRelease(PointerBarrierWrapper* owner, int event);
void BarrierReset();
+ bool EventIsInsideYBreakZone(BarrierEvent::Ptr const& event);
+
std::vector<PointerBarrierWrapper::Ptr> barriers_;
std::vector<EdgeBarrierSubscriber*> subscribers_;
Decaymulator decaymulator_;
diff --git a/launcher/ExpoLauncherIcon.cpp b/launcher/ExpoLauncherIcon.cpp
index 17c2d64d7..8e2adc3a8 100644
--- a/launcher/ExpoLauncherIcon.cpp
+++ b/launcher/ExpoLauncherIcon.cpp
@@ -66,6 +66,11 @@ void ExpoLauncherIcon::OnViewportLayoutChanged(int hsize, int vsize)
}
}
+void ExpoLauncherIcon::AboutToRemove()
+{
+ WindowManager::Default().SetViewportSize(1, 1);
+}
+
void ExpoLauncherIcon::UpdateIcon()
{
auto const& vp = WindowManager::Default().GetCurrentViewport();
diff --git a/launcher/ExpoLauncherIcon.h b/launcher/ExpoLauncherIcon.h
index af1ba244e..f660cdcaa 100644
--- a/launcher/ExpoLauncherIcon.h
+++ b/launcher/ExpoLauncherIcon.h
@@ -32,6 +32,7 @@ class ExpoLauncherIcon : public SimpleLauncherIcon
public:
ExpoLauncherIcon();
void Stick(bool save);
+ void AboutToRemove();
protected:
void ActivateLauncherIcon(ActionArg arg);
diff --git a/launcher/HudLauncherIcon.cpp b/launcher/HudLauncherIcon.cpp
index 7fea6c4f7..39fa01a0d 100644
--- a/launcher/HudLauncherIcon.cpp
+++ b/launcher/HudLauncherIcon.cpp
@@ -89,8 +89,9 @@ void HudLauncherIcon::OnOverlayShown(GVariant* data, bool visible)
unity::glib::String overlay_identity;
gboolean can_maximise = FALSE;
gint32 overlay_monitor = 0;
+ int width, height;
g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING,
- &overlay_identity, &can_maximise, &overlay_monitor);
+ &overlay_identity, &can_maximise, &overlay_monitor, &width, &height);
// If the hud is open, we show the HUD button if we have a locked launcher
if (overlay_identity.Str() == "hud" &&
diff --git a/launcher/Launcher.cpp b/launcher/Launcher.cpp
index 7565dd182..79c8f472f 100644
--- a/launcher/Launcher.cpp
+++ b/launcher/Launcher.cpp
@@ -101,7 +101,7 @@ NUX_IMPLEMENT_OBJECT_TYPE(Launcher);
const int Launcher::Launcher::ANIM_DURATION_SHORT = 125;
-Launcher::Launcher(nux::BaseWindow* parent,
+Launcher::Launcher(MockableBaseWindow* parent,
NUX_FILE_LINE_DECL)
: View(NUX_FILE_LINE_PARAM)
#ifdef USE_X11
@@ -286,6 +286,21 @@ void Launcher::SetStateMouseOverLauncher(bool over_launcher)
_hide_machine.SetQuirk(LauncherHideMachine::MOUSE_OVER_LAUNCHER, over_launcher);
_hide_machine.SetQuirk(LauncherHideMachine::REVEAL_PRESSURE_PASS, false);
_hover_machine.SetQuirk(LauncherHoverMachine::MOUSE_OVER_LAUNCHER, over_launcher);
+ tooltip_manager_.SetHover(over_launcher);
+}
+
+void Launcher::SetIconUnderMouse(AbstractLauncherIcon::Ptr const& icon)
+{
+ if (_icon_under_mouse == icon)
+ return;
+
+ if (_icon_under_mouse)
+ _icon_under_mouse->mouse_leave.emit(monitor);
+ if (icon)
+ icon->mouse_enter.emit(monitor);
+
+ _icon_under_mouse = icon;
+ tooltip_manager_.SetIcon(icon);
}
bool Launcher::MouseBeyondDragThreshold() const
@@ -1210,8 +1225,9 @@ void Launcher::OnOverlayShown(GVariant* data)
unity::glib::String overlay_identity;
gboolean can_maximise = FALSE;
gint32 overlay_monitor = 0;
+ int width, height;
g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING,
- &overlay_identity, &can_maximise, &overlay_monitor);
+ &overlay_identity, &can_maximise, &overlay_monitor, &width, &height);
std::string identity(overlay_identity.Str());
LOG_DEBUG(logger) << "Overlay shown: " << identity
@@ -1251,8 +1267,9 @@ void Launcher::OnOverlayHidden(GVariant* data)
unity::glib::String overlay_identity;
gboolean can_maximise = FALSE;
gint32 overlay_monitor = 0;
+ int width, height;
g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING,
- &overlay_identity, &can_maximise, &overlay_monitor);
+ &overlay_identity, &can_maximise, &overlay_monitor, &width, &height);
std::string identity = overlay_identity.Str();
@@ -1316,7 +1333,8 @@ void Launcher::SetHidden(bool hide_launcher)
TimeUtil::SetTimeStruct(&_times[TIME_AUTOHIDE], &_times[TIME_AUTOHIDE], ANIM_DURATION_SHORT);
- _parent->EnableInputWindow(!hide_launcher, launcher::window_title, false, false);
+ if (nux::GetWindowThread()->IsEmbeddedWindow())
+ _parent->EnableInputWindow(!hide_launcher, launcher::window_title, false, false);
if (!hide_launcher && GetActionState() == ACTION_DRAG_EXTERNAL)
DndReset();
@@ -1600,8 +1618,7 @@ void Launcher::OnIconRemoved(AbstractLauncherIcon::Ptr const& icon)
if (icon->needs_redraw_connection.connected())
icon->needs_redraw_connection.disconnect();
- if (icon == _icon_under_mouse)
- _icon_under_mouse = nullptr;
+ SetIconUnderMouse(AbstractLauncherIcon::Ptr());
if (icon == _icon_mouse_down)
_icon_mouse_down = nullptr;
if (icon == _drag_icon)
@@ -1920,11 +1937,7 @@ bool Launcher::StartIconDragTimeout(int x, int y)
// if we are still waiting…
if (GetActionState() == ACTION_NONE)
{
- if (_icon_under_mouse)
- {
- _icon_under_mouse->mouse_leave.emit(monitor);
- _icon_under_mouse = nullptr;
- }
+ SetIconUnderMouse(AbstractLauncherIcon::Ptr());
_initial_drag_animation = true;
StartIconDragRequest(x, y);
}
@@ -2163,11 +2176,7 @@ void Launcher::RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_
GetActionState() == ACTION_NONE)
return;
- if (_icon_under_mouse)
- {
- _icon_under_mouse->mouse_leave.emit(monitor);
- _icon_under_mouse = nullptr;
- }
+ SetIconUnderMouse(AbstractLauncherIcon::Ptr());
if (GetActionState() == ACTION_NONE)
{
@@ -2219,6 +2228,7 @@ void Launcher::RecvMouseLeave(int x, int y, unsigned long button_flags, unsigned
void Launcher::RecvMouseMove(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags)
{
SetMousePosition(x, y);
+ tooltip_manager_.MouseMoved();
if (!_hidden)
UpdateChangeInMousePosition(dx, dy);
@@ -2297,7 +2307,9 @@ ui::EdgeBarrierSubscriber::Result Launcher::HandleBarrierEvent(ui::PointerBarrie
if (!apply_to_reveal)
return ui::EdgeBarrierSubscriber::Result::IGNORED;
- _hide_machine.AddRevealPressure(event->velocity);
+ if (!owner->IsFirstEvent())
+ _hide_machine.AddRevealPressure(event->velocity);
+
return ui::EdgeBarrierSubscriber::Result::HANDLED;
}
@@ -2365,18 +2377,7 @@ void Launcher::EventLogic()
launcher_icon = MouseIconIntersection(_mouse_position.x, _mouse_position.y);
}
-
- if (_icon_under_mouse && (_icon_under_mouse != launcher_icon))
- {
- _icon_under_mouse->mouse_leave.emit(monitor);
- _icon_under_mouse = nullptr;
- }
-
- if (launcher_icon && (_icon_under_mouse != launcher_icon))
- {
- launcher_icon->mouse_enter.emit(monitor);
- _icon_under_mouse = launcher_icon;
- }
+ SetIconUnderMouse(launcher_icon);
}
void Launcher::MouseDownLogic(int x, int y, unsigned long button_flags, unsigned long key_flags)
@@ -2391,6 +2392,7 @@ void Launcher::MouseDownLogic(int x, int y, unsigned long button_flags, unsigned
sources_.AddTimeout(START_DRAGICON_DURATION, cb_func, START_DRAGICON_TIMEOUT);
launcher_icon->mouse_down.emit(nux::GetEventButton(button_flags), monitor, key_flags);
+ tooltip_manager_.IconClicked();
}
}
diff --git a/launcher/Launcher.h b/launcher/Launcher.h
index 338fa1ab8..ac61275d6 100644
--- a/launcher/Launcher.h
+++ b/launcher/Launcher.h
@@ -39,8 +39,10 @@
#include "LauncherDragWindow.h"
#include "LauncherHideMachine.h"
#include "LauncherHoverMachine.h"
+#include "unity-shared/MockableBaseWindow.h"
#include "unity-shared/UBusWrapper.h"
#include "SoftwareCenterLauncherIcon.h"
+#include "TooltipManager.h"
#ifdef USE_X11
# include "PointerBarrier.h"
@@ -65,7 +67,7 @@ class Launcher : public unity::debug::Introspectable,
NUX_DECLARE_OBJECT_TYPE(Launcher, nux::View);
public:
- Launcher(nux::BaseWindow* parent, NUX_FILE_LINE_PROTO);
+ Launcher(MockableBaseWindow* parent, NUX_FILE_LINE_PROTO);
nux::Property<Display*> display;
nux::Property<int> monitor;
@@ -99,7 +101,7 @@ public:
BacklightMode GetBacklightMode() const;
bool IsBackLightModeToggles() const;
- nux::BaseWindow* GetParent() const
+ MockableBaseWindow* GetParent() const
{
return _parent;
};
@@ -222,6 +224,7 @@ private:
bool OnScrollTimeout();
void SetMousePosition(int x, int y);
+ void SetIconUnderMouse(AbstractLauncherIcon::Ptr const& icon);
void SetStateMouseOverLauncher(bool over_launcher);
@@ -334,7 +337,7 @@ private:
bool DndIsSpecialRequest(std::string const& uri) const;
LauncherModel::Ptr _model;
- nux::BaseWindow* _parent;
+ MockableBaseWindow* _parent;
nux::ObjectPtr<nux::View> _active_tooltip;
QuicklistView* _active_quicklist;
@@ -388,6 +391,7 @@ private:
nux::ObjectPtr<LauncherDragWindow> _drag_window;
LauncherHideMachine _hide_machine;
LauncherHoverMachine _hover_machine;
+ TooltipManager tooltip_manager_;
unity::DndData _dnd_data;
nux::DndAction _drag_action;
diff --git a/launcher/LauncherController.cpp b/launcher/LauncherController.cpp
index f62ecc2be..25da39a3a 100644
--- a/launcher/LauncherController.cpp
+++ b/launcher/LauncherController.cpp
@@ -24,7 +24,6 @@
#include <Nux/Nux.h>
#include <Nux/HLayout.h>
-#include <Nux/BaseWindow.h>
#include <NuxCore/Logger.h>
#include <UnityCore/DesktopUtilities.h>
@@ -68,6 +67,11 @@ const std::string DBUS_INTROSPECTION =
" <arg type='s' name='aptdaemon_task' direction='in'/>"
" </method>"
""
+ " <method name='UpdateLauncherIconFavoriteState'>"
+ " <arg type='s' name='icon_uri' direction='in'/>"
+ " <arg type='b' name='is_sticky' direction='in'/>"
+ " </method>"
+ ""
" </interface>"
"</node>";
}
@@ -89,11 +93,16 @@ namespace
const std::string RUNNING_APPS_URI = FavoriteStore::URI_PREFIX_UNITY + "running-apps";
const std::string DEVICES_URI = FavoriteStore::URI_PREFIX_UNITY + "devices";
}
-}
-GDBusInterfaceVTable Controller::Impl::interface_vtable =
- { Controller::Impl::OnDBusMethodCall, NULL, NULL};
+std::string CreateAppUriNameFromDesktopPath(const std::string &desktop_path)
+{
+ if (desktop_path.empty())
+ return "";
+
+ return FavoriteStore::URI_PREFIX_APP + DesktopUtilities::GetDesktopID(desktop_path);
+}
+}
Controller::Impl::Impl(Controller* parent, XdndManager::Ptr const& xdnd_manager)
: parent_(parent)
@@ -111,10 +120,7 @@ Controller::Impl::Impl(Controller* parent, XdndManager::Ptr const& xdnd_manager)
, launcher_key_press_time_(0)
, last_dnd_monitor_(-1)
, super_tap_duration_(0)
- , dbus_owner_(g_bus_own_name(G_BUS_TYPE_SESSION, DBUS_NAME.c_str(), G_BUS_NAME_OWNER_FLAGS_NONE,
- OnBusAcquired, nullptr, nullptr, this, nullptr))
- , gdbus_connection_(nullptr)
- , reg_id_(0)
+ , dbus_server_(DBUS_NAME)
{
#ifdef USE_X11
edge_barriers_.options = parent_->options();
@@ -179,6 +185,10 @@ Controller::Impl::Impl(Controller* parent, XdndManager::Ptr const& xdnd_manager)
xdnd_manager_->dnd_started.connect(sigc::mem_fun(this, &Impl::OnDndStarted));
xdnd_manager_->dnd_finished.connect(sigc::mem_fun(this, &Impl::OnDndFinished));
xdnd_manager_->monitor_changed.connect(sigc::mem_fun(this, &Impl::OnDndMonitorChanged));
+
+ dbus_server_.AddObjects(DBUS_INTROSPECTION, DBUS_PATH);
+ for (auto const& obj : dbus_server_.GetObjects())
+ obj->SetMethodsCallsHandler(sigc::mem_fun(this, &Impl::OnDBusMethodCall));
}
Controller::Impl::~Impl()
@@ -191,11 +201,6 @@ Controller::Impl::~Impl()
if (launcher_ptr)
launcher_ptr->GetParent()->UnReference();
}
-
- if (gdbus_connection_ && reg_id_)
- g_dbus_connection_unregister_object(gdbus_connection_, reg_id_);
-
- g_bus_unown_name(dbus_owner_);
}
void Controller::Impl::EnsureLaunchers(int primary, std::vector<nux::Geometry> const& monitors)
@@ -216,7 +221,7 @@ void Controller::Impl::EnsureLaunchers(int primary, std::vector<nux::Geometry> c
launchers[i] = nux::ObjectPtr<Launcher>(CreateLauncher());
}
- int monitor = (num_launchers == 1) ? primary : i;
+ int monitor = (num_launchers == 1 && num_monitors > 1) ? primary : i;
if (launchers[i]->monitor() != monitor)
{
@@ -314,7 +319,7 @@ void Controller::Impl::OnDndMonitorChanged(int monitor)
Launcher* Controller::Impl::CreateLauncher()
{
- nux::BaseWindow* launcher_window = new nux::BaseWindow(TEXT("LauncherWindow"));
+ auto* launcher_window = new MockableBaseWindow(TEXT("LauncherWindow"));
Launcher* launcher = new Launcher(launcher_window);
launcher->options = parent_->options();
@@ -329,7 +334,10 @@ Launcher* Controller::Impl::CreateLauncher()
launcher_window->SetLayout(layout);
launcher_window->SetBackgroundColor(nux::color::Transparent);
launcher_window->ShowWindow(true);
- launcher_window->EnableInputWindow(true, launcher::window_title, false, false);
+
+ if (nux::GetWindowThread()->IsEmbeddedWindow())
+ launcher_window->EnableInputWindow(true, launcher::window_title, false, false);
+
launcher_window->InputWindowEnableStruts(parent_->options()->hide_mode == LAUNCHER_HIDE_NEVER);
launcher_window->SetEnterFocusInputArea(launcher);
@@ -348,7 +356,7 @@ void Controller::Impl::OnLauncherAddRequest(std::string const& icon_uri, Abstrac
if (icon_uri.find(FavoriteStore::URI_PREFIX_FILE) == 0)
{
auto const& desktop_path = icon_uri.substr(FavoriteStore::URI_PREFIX_FILE.length());
- app_uri = FavoriteStore::URI_PREFIX_APP + DesktopUtilities::GetDesktopID(desktop_path);
+ app_uri = local::CreateAppUriNameFromDesktopPath(desktop_path);
}
auto const& icon = GetIconByUri(app_uri.empty() ? icon_uri : app_uri);
@@ -433,6 +441,62 @@ void Controller::Impl::SaveIconsOrder()
}
void
+Controller::Impl::OnLauncherUpdateIconStickyState(std::string const& icon_uri, bool sticky)
+{
+ if (icon_uri.empty())
+ return;
+
+ std::string target_uri = icon_uri;
+ if (icon_uri.find(FavoriteStore::URI_PREFIX_FILE) == 0)
+ {
+ auto const& desktop_path =
+ icon_uri.substr(FavoriteStore::URI_PREFIX_FILE.length());
+
+ // app uri instead
+ target_uri = local::CreateAppUriNameFromDesktopPath(desktop_path);
+ }
+ auto const& existing_icon_entry =
+ GetIconByUri(target_uri);
+
+ if (existing_icon_entry)
+ {
+ // use the backgroung mechanism of model updates & propagation
+ bool should_update = (existing_icon_entry->IsSticky() != sticky);
+ if (should_update)
+ {
+ if (sticky)
+ {
+ existing_icon_entry->Stick(true);
+ }
+ else
+ {
+ existing_icon_entry->UnStick();
+ }
+
+ SortAndUpdate();
+ }
+ }
+ else
+ {
+ FavoriteStore& favorite_store = FavoriteStore::Instance();
+
+ bool should_update = (favorite_store.IsFavorite(target_uri) != sticky);
+ if (should_update)
+ {
+ if (sticky)
+ {
+ favorite_store.AddFavorite(target_uri, -1);
+ RegisterIcon(CreateFavoriteIcon(target_uri));
+ }
+ else
+ {
+ favorite_store.RemoveFavorite(target_uri);
+ }
+ }
+ }
+}
+
+void
Controller::Impl::OnLauncherAddRequestSpecial(std::string const& path,
std::string const& aptdaemon_trans_id,
std::string const& icon_path,
@@ -525,7 +589,7 @@ void Controller::Impl::OnLauncherEntryRemoteRemoved(LauncherEntryRemote::Ptr con
void Controller::Impl::OnFavoriteStoreFavoriteAdded(std::string const& entry, std::string const& pos, bool before)
{
- if (entry == local::RUNNING_APPS_URI || entry == local::DEVICES_URI || entry == expo_icon_->RemoteUri())
+ if (entry == local::RUNNING_APPS_URI || entry == local::DEVICES_URI)
{
// Since the running apps and the devices are always shown, when added to
// the model, we only have to re-order them
@@ -570,11 +634,12 @@ void Controller::Impl::OnFavoriteStoreFavoriteAdded(std::string const& entry, st
void Controller::Impl::OnFavoriteStoreFavoriteRemoved(std::string const& entry)
{
- if (entry == local::RUNNING_APPS_URI || entry == local::DEVICES_URI || entry == expo_icon_->RemoteUri())
+ if (entry == local::RUNNING_APPS_URI || entry == local::DEVICES_URI)
{
// Since the running apps and the devices are always shown, when added to
// the model, we only have to re-order them
ResetIconPriorities();
+ SaveIconsOrder();
return;
}
@@ -595,7 +660,6 @@ void Controller::Impl::ResetIconPriorities()
auto const& apps_icons = model_->GetSublist<ApplicationLauncherIcon>();
auto const& volumes_icons = model_->GetSublist<VolumeLauncherIcon>();
bool running_apps_found = false;
- bool expo_icon_found = false;
bool volumes_found = false;
for (auto const& fav : favs)
@@ -622,10 +686,6 @@ void Controller::Impl::ResetIconPriorities()
volumes_found = true;
continue;
}
- else if (fav == expo_icon_->RemoteUri())
- {
- expo_icon_found = true;
- }
auto const& icon = GetIconByUri(fav);
@@ -642,9 +702,6 @@ void Controller::Impl::ResetIconPriorities()
}
}
- if (!expo_icon_found)
- expo_icon_->SetSortPriority(++sort_priority_);
-
if (!volumes_found)
{
for (auto const& ico : volumes_icons)
@@ -655,9 +712,6 @@ void Controller::Impl::ResetIconPriorities()
}
model_->Sort();
-
- if (!expo_icon_found)
- SaveIconsOrder();
}
void Controller::Impl::UpdateNumWorkspaces(int workspaces)
@@ -825,8 +879,6 @@ AbstractLauncherIcon::Ptr Controller::Impl::CreateFavoriteIcon(std::string const
if (!app || app->seen())
return result;
- // Sticky apps are those that are in the launcher when not running.
- app->sticky = true;
result = AbstractLauncherIcon::Ptr(new ApplicationLauncherIcon(app));
}
else if (icon_uri.find(FavoriteStore::URI_PREFIX_DEVICE) == 0)
@@ -923,12 +975,33 @@ void Controller::Impl::AddDevices()
}
}
+void Controller::Impl::MigrateFavorites()
+{
+ // This migrates favorites to new format, ensuring that upgrades won't lose anything
+ auto& favorites = FavoriteStore::Instance();
+ auto const& favs = favorites.GetFavorites();
+
+ auto fav_it = std::find_if(begin(favs), end(favs), [](std::string const& fav) {
+ return (fav.find(FavoriteStore::URI_PREFIX_UNITY) != std::string::npos);
+ });
+
+ if (fav_it == end(favs))
+ {
+ favorites.AddFavorite(local::RUNNING_APPS_URI, -1);
+ favorites.AddFavorite(expo_icon_->RemoteUri(), -1);
+ favorites.AddFavorite(local::DEVICES_URI, -1);
+ }
+}
+
void Controller::Impl::SetupIcons()
{
+ MigrateFavorites();
+
auto& favorite_store = FavoriteStore::Instance();
FavoriteList const& favs = favorite_store.GetFavorites();
bool running_apps_added = false;
bool devices_added = false;
+
for (auto const& fav_uri : favs)
{
if (fav_uri == local::RUNNING_APPS_URI)
@@ -956,23 +1029,15 @@ void Controller::Impl::SetupIcons()
AddRunningApps();
}
- if (model_->IconIndex(expo_icon_) < 0)
- {
- LOG_INFO(logger) << "Adding expo icon";
- RegisterIcon(CreateFavoriteIcon(expo_icon_->RemoteUri()), ++sort_priority_);
- }
-
if (!devices_added)
{
LOG_INFO(logger) << "Adding devices";
AddDevices();
}
- if (std::find(favs.begin(), favs.end(), expo_icon_->RemoteUri()) == favs.end())
- SaveIconsOrder();
-
ApplicationManager::Default().application_started
.connect(sigc::mem_fun(this, &Impl::OnApplicationStarted));
+
device_section_.icon_added.connect(sigc::mem_fun(this, &Impl::OnDeviceIconAdded));
favorite_store.favorite_added.connect(sigc::mem_fun(this, &Impl::OnFavoriteStoreFavoriteAdded));
favorite_store.favorite_removed.connect(sigc::mem_fun(this, &Impl::OnFavoriteStoreFavoriteRemoved));
@@ -1181,7 +1246,7 @@ void Controller::HandleLauncherKeyRelease(bool was_tap, int when)
}
}
-bool Controller::HandleLauncherKeyEvent(Display *display, unsigned int key_sym, unsigned long key_code, unsigned long key_state, char* key_string)
+bool Controller::HandleLauncherKeyEvent(Display *display, unsigned int key_sym, unsigned long key_code, unsigned long key_state, char* key_string, Time timestamp)
{
LauncherModel::iterator it;
@@ -1197,9 +1262,9 @@ bool Controller::HandleLauncherKeyEvent(Display *display, unsigned int key_sym,
if (TimeUtil::TimeDelta(&current, &last_action_time) > local::ignore_repeat_shortcut_duration)
{
if (g_ascii_isdigit((gchar)(*it)->GetShortcut()) && (key_state & ShiftMask))
- (*it)->OpenInstance(ActionArg(ActionArg::LAUNCHER, 0));
+ (*it)->OpenInstance(ActionArg(ActionArg::LAUNCHER, 0, timestamp));
else
- (*it)->Activate(ActionArg(ActionArg::LAUNCHER, 0));
+ (*it)->Activate(ActionArg(ActionArg::LAUNCHER, 0, timestamp));
}
// disable the "tap on super" check
@@ -1319,8 +1384,10 @@ void Controller::KeyNavTerminate(bool activate)
if (activate)
{
- pimpl->sources_.AddIdle([this] {
- pimpl->model_->Selection()->Activate(ActionArg(ActionArg::LAUNCHER, 0));
+ auto timestamp = nux::GetWindowThread()->GetGraphicsDisplay().GetCurrentEvent().x11_timestamp;
+
+ pimpl->sources_.AddIdle([this, timestamp] {
+ pimpl->model_->Selection()->Activate(ActionArg(ActionArg::LAUNCHER, 0, timestamp));
return false;
});
}
@@ -1420,10 +1487,12 @@ void Controller::Impl::ReceiveLauncherKeyPress(unsigned long eventType,
// <SPACE> (open a new instance)
case NUX_VK_SPACE:
- model_->Selection()->OpenInstance(ActionArg(ActionArg::LAUNCHER, 0));
+ {
+ auto timestamp = nux::GetWindowThread()->GetGraphicsDisplay().GetCurrentEvent().x11_timestamp;
+ model_->Selection()->OpenInstance(ActionArg(ActionArg::LAUNCHER, 0, timestamp));
parent_->KeyNavTerminate(false);
break;
-
+ }
// <RETURN> (start/activate currently selected icon)
case NUX_VK_ENTER:
case NUX_KP_ENTER:
@@ -1450,50 +1519,29 @@ void Controller::Impl::OpenQuicklist()
}
}
-void Controller::Impl::OnBusAcquired(GDBusConnection* connection, const gchar* name, gpointer user_data)
-{
- GDBusNodeInfo* introspection_data = g_dbus_node_info_new_for_xml(DBUS_INTROSPECTION.c_str(), nullptr);
-
- if (!introspection_data)
- {
- LOG_WARNING(logger) << "No introspection data loaded. Won't get dynamic launcher addition.";
- return;
- }
-
- auto self = static_cast<Controller::Impl*>(user_data);
-
- self->gdbus_connection_ = connection;
- self->reg_id_ = g_dbus_connection_register_object(connection, DBUS_PATH.c_str(),
- introspection_data->interfaces[0],
- &interface_vtable, user_data,
- nullptr, nullptr);
- if (!self->reg_id_)
- {
- LOG_WARNING(logger) << "Object registration failed. Won't get dynamic launcher addition.";
- }
-
- g_dbus_node_info_unref(introspection_data);
-}
-
-void Controller::Impl::OnDBusMethodCall(GDBusConnection* connection, const gchar* sender,
- const gchar* object_path, const gchar* interface_name,
- const gchar* method_name, GVariant* parameters,
- GDBusMethodInvocation* invocation, gpointer user_data)
+GVariant* Controller::Impl::OnDBusMethodCall(std::string const& method, GVariant *parameters)
{
- if (g_strcmp0(method_name, "AddLauncherItemFromPosition") == 0)
+ if (method == "AddLauncherItemFromPosition")
{
- auto self = static_cast<Controller::Impl*>(user_data);
glib::String icon, icon_title, desktop_file, aptdaemon_task;
gint icon_x, icon_y, icon_size;
g_variant_get(parameters, "(ssiiiss)", &icon_title, &icon, &icon_x, &icon_y,
&icon_size, &desktop_file, &aptdaemon_task);
- self->OnLauncherAddRequestSpecial(desktop_file.Str(), aptdaemon_task.Str(),
- icon.Str(), icon_x, icon_y, icon_size);
+ OnLauncherAddRequestSpecial(desktop_file.Str(), aptdaemon_task.Str(),
+ icon.Str(), icon_x, icon_y, icon_size);
+ }
+ else if (method == "UpdateLauncherIconFavoriteState")
+ {
+ gboolean is_sticky;
+ glib::String icon_uri;
+ g_variant_get(parameters, "(sb)", &icon_uri, &is_sticky);
- g_dbus_method_invocation_return_value(invocation, nullptr);
+ OnLauncherUpdateIconStickyState(icon_uri.Str(), is_sticky);
}
+
+ return nullptr;
}
} // namespace launcher
diff --git a/launcher/LauncherController.h b/launcher/LauncherController.h
index 04504ebc8..d4c0c7744 100644
--- a/launcher/LauncherController.h
+++ b/launcher/LauncherController.h
@@ -70,7 +70,8 @@ public:
unsigned int key_sym,
unsigned long key_code,
unsigned long key_state,
- char* key_string);
+ char* key_string,
+ Time timestamp);
void KeyNavActivate();
void KeyNavGrab();
diff --git a/launcher/LauncherControllerPrivate.h b/launcher/LauncherControllerPrivate.h
index b275ae0de..af2ced337 100644
--- a/launcher/LauncherControllerPrivate.h
+++ b/launcher/LauncherControllerPrivate.h
@@ -24,6 +24,7 @@
#define LAUNCHER_CONTROLLER_PRIVATE_H
#include <Nux/Nux.h>
+#include <UnityCore/GLibDBusServer.h>
#include "AbstractLauncherIcon.h"
#include "DeviceLauncherSection.h"
@@ -71,6 +72,7 @@ public:
void OnLauncherAddRequest(std::string const& icon_uri, AbstractLauncherIcon::Ptr const& before);
void OnLauncherAddRequestSpecial(std::string const& path, std::string const& aptdaemon_trans_id,
std::string const& icon_path, int icon_x, int icon_y, int icon_size);
+ void OnLauncherUpdateIconStickyState(std::string const& desktop_file, bool sticky);
void OnLauncherRemoveRequest(AbstractLauncherIcon::Ptr const& icon);
void OnLauncherEntryRemoteAdded(LauncherEntryRemote::Ptr const& entry);
@@ -91,6 +93,7 @@ public:
SoftwareCenterLauncherIcon::Ptr CreateSCLauncherIcon(std::string const& file_path, std::string const& aptdaemon_trans_id, std::string const& icon_path);
void SetupIcons();
+ void MigrateFavorites();
void AddRunningApps();
void AddDevices();
@@ -115,14 +118,7 @@ public:
void OnDndStarted(std::string const& data, int monitor);
void OnDndFinished();
void OnDndMonitorChanged(int monitor);
-
- static void OnBusAcquired(GDBusConnection* connection, const gchar* name, gpointer user_data);
- static void OnDBusMethodCall(GDBusConnection* connection, const gchar* sender, const gchar* object_path,
- const gchar* interface_name, const gchar* method_name,
- GVariant* parameters, GDBusMethodInvocation* invocation,
- gpointer user_data);
-
- static GDBusInterfaceVTable interface_vtable;
+ GVariant* OnDBusMethodCall(std::string const& method, GVariant *parameters);
Controller* parent_;
LauncherModel::Ptr model_;
@@ -151,10 +147,7 @@ public:
int last_dnd_monitor_;
int super_tap_duration_;
- unsigned dbus_owner_;
- GDBusConnection* gdbus_connection_;
- unsigned reg_id_;
-
+ glib::DBusServer dbus_server_;
glib::SourceManager sources_;
UBusManager ubus;
diff --git a/launcher/LauncherIcon.cpp b/launcher/LauncherIcon.cpp
index f34d7fd65..b0a9a9425 100644
--- a/launcher/LauncherIcon.cpp
+++ b/launcher/LauncherIcon.cpp
@@ -106,6 +106,7 @@ LauncherIcon::LauncherIcon(IconType type)
tooltip_text = "blank";
position = Position::FLOATING;
+ removed = false;
// FIXME: the abstraction is already broken, should be fixed for O
// right now, hooking the dynamic quicklist the less ugly possible way
@@ -230,7 +231,7 @@ LauncherIcon::OpenInstance(ActionArg arg)
if (wm.IsScaleActive())
wm.TerminateScale();
- OpenInstanceLauncherIcon();
+ OpenInstanceLauncherIcon(arg.timestamp);
UpdateQuirkTime(Quirk::LAST_ACTION);
}
@@ -527,23 +528,12 @@ void
LauncherIcon::RecvMouseEnter(int monitor)
{
_last_monitor = monitor;
- if (QuicklistManager::Default()->Current())
- {
- // A quicklist is active
- return;
- }
-
- ShowTooltip();
}
void LauncherIcon::RecvMouseLeave(int monitor)
{
_last_monitor = -1;
_allow_quicklist_to_show = true;
-
- if (_tooltip)
- _tooltip->ShowWindow(false);
- tooltip_visible.emit(nux::ObjectPtr<nux::View>(nullptr));
}
bool LauncherIcon::OpenQuicklist(bool select_first_item, int monitor)
@@ -661,7 +651,9 @@ void LauncherIcon::RecvMouseUp(int button, int monitor, unsigned long key_flags)
void LauncherIcon::RecvMouseClick(int button, int monitor, unsigned long key_flags)
{
- ActionArg arg(ActionArg::LAUNCHER, button);
+ auto timestamp = nux::GetWindowThread()->GetGraphicsDisplay().GetCurrentEvent().x11_timestamp;
+
+ ActionArg arg(ActionArg::LAUNCHER, button, timestamp);
arg.monitor = monitor;
bool shift_pressed = nux::GetKeyModifierState(key_flags, nux::NUX_STATE_SHIFT);
diff --git a/launcher/LauncherIcon.h b/launcher/LauncherIcon.h
index b6712796c..af3f0bed1 100644
--- a/launcher/LauncherIcon.h
+++ b/launcher/LauncherIcon.h
@@ -250,7 +250,7 @@ protected:
virtual void ActivateLauncherIcon(ActionArg arg) {}
- virtual void OpenInstanceLauncherIcon() {}
+ virtual void OpenInstanceLauncherIcon(Time timestamp) {}
virtual bool HandlesSpread () { return false; }
diff --git a/launcher/LauncherModel.cpp b/launcher/LauncherModel.cpp
index 202235d9b..a9e694924 100644
--- a/launcher/LauncherModel.cpp
+++ b/launcher/LauncherModel.cpp
@@ -49,7 +49,8 @@ unity::debug::Introspectable::IntrospectableList LauncherModel::GetIntrospectabl
introspection_results_.clear();
for (auto icon : _inner)
- introspection_results_.push_back(icon.GetPointer());
+ if (!icon->removed)
+ introspection_results_.push_back(icon.GetPointer());
return introspection_results_;
}
@@ -139,6 +140,8 @@ void LauncherModel::RemoveIcon(AbstractLauncherIcon::Ptr const& icon)
void LauncherModel::OnIconRemove(AbstractLauncherIcon::Ptr const& icon)
{
+ icon->removed = true;
+
timeouts_.AddTimeout(1000, [this, icon] {
RemoveIcon(icon);
return false;
diff --git a/launcher/MockLauncherIcon.h b/launcher/MockLauncherIcon.h
index 147b34564..b6d512aa7 100644
--- a/launcher/MockLauncherIcon.h
+++ b/launcher/MockLauncherIcon.h
@@ -68,6 +68,7 @@ public:
, type_(type)
, sort_priority_(DefaultPriority(type))
, remote_uri_("fake")
+ , is_tooltip_visible_(false)
{
tooltip_text = "Mock Icon";
position = Position::FLOATING;
@@ -80,7 +81,9 @@ public:
void AddProperties(GVariantBuilder* builder) {}
- void HideTooltip() {}
+ void ShowTooltip() { is_tooltip_visible_ = true; }
+ void HideTooltip() { is_tooltip_visible_ = false; }
+ bool IsTooltipVisible() { return is_tooltip_visible_; }
void SetShortcut(guint64 shortcut) {}
@@ -366,6 +369,7 @@ private:
timespec quirk_times_[unsigned(Quirk::LAST)];
std::map<int, nux::Point3> center_;
std::string remote_uri_;
+ bool is_tooltip_visible_;
};
}
diff --git a/launcher/PointerBarrier.cpp b/launcher/PointerBarrier.cpp
index 1e3876c16..5d513c5b3 100644
--- a/launcher/PointerBarrier.cpp
+++ b/launcher/PointerBarrier.cpp
@@ -43,6 +43,8 @@ PointerBarrierWrapper::PointerBarrierWrapper()
, max_velocity_multiplier(1.0f)
, direction(BOTH)
, event_base_(0)
+ , last_event_(0)
+ , first_event_(false)
, barrier(0)
, smoothing_count_(0)
, smoothing_accum_(0)
@@ -114,12 +116,22 @@ void PointerBarrierWrapper::EmitCurrentData(int event_id, int x, int y)
return;
int velocity = std::min<int>(600 * max_velocity_multiplier, smoothing_accum_ / smoothing_count_);
+ SendBarrierEvent(x, y, velocity, event_id);
+
+ smoothing_accum_ = 0;
+ smoothing_count_ = 0;
+}
+
+void PointerBarrierWrapper::SendBarrierEvent(int x, int y, int velocity, int event_id)
+{
auto event = std::make_shared<BarrierEvent>(x, y, velocity, event_id);
barrier_event.emit(this, event);
+}
- smoothing_accum_ = 0;
- smoothing_count_ = 0;
+bool PointerBarrierWrapper::IsFirstEvent() const
+{
+ return first_event_;
}
bool PointerBarrierWrapper::HandleEvent(XEvent xevent)
@@ -138,9 +150,9 @@ bool PointerBarrierWrapper::HandleEvent(XEvent xevent)
/* If the barrier is released, just emit the current event without
* waiting, so there won't be any delay on releasing the barrier. */
smoothing_timeout_.reset();
- auto event = std::make_shared<BarrierEvent>(notify_event->x, notify_event->y,
- notify_event->velocity, notify_event->event_id);
- barrier_event.emit(this, event);
+
+ SendBarrierEvent(notify_event->x, notify_event->y,
+ notify_event->velocity, notify_event->event_id);
}
else if (!smoothing_timeout_)
{
@@ -148,15 +160,24 @@ bool PointerBarrierWrapper::HandleEvent(XEvent xevent)
int y = notify_event->y;
int event = notify_event->event_id;
- auto smoothing_cb = [&, event, x, y] ()
+ // If we are a new event, don't delay sending the first event
+ if (last_event_ != event)
{
+ first_event_ = true;
+ last_event_ = event;
+
+ SendBarrierEvent(notify_event->x, notify_event->y,
+ notify_event->velocity, notify_event->event_id);
+
+ first_event_ = false;
+ }
+
+ smoothing_timeout_.reset(new glib::Timeout(smoothing, [this, event, x, y] () {
EmitCurrentData(event, x, y);
smoothing_timeout_.reset();
return false;
- };
-
- smoothing_timeout_.reset(new glib::Timeout(smoothing, smoothing_cb));
+ }));
}
}
diff --git a/launcher/PointerBarrier.h b/launcher/PointerBarrier.h
index 7a796950d..6576c090e 100644
--- a/launcher/PointerBarrier.h
+++ b/launcher/PointerBarrier.h
@@ -86,6 +86,8 @@ public:
sigc::signal<void, PointerBarrierWrapper*, BarrierEvent::Ptr> barrier_event;
+ bool IsFirstEvent() const;
+
protected:
void EmitCurrentData(int event_id, int x, int y);
bool HandleEvent(XEvent event);
@@ -93,7 +95,11 @@ protected:
private:
static bool HandleEventWrapper(XEvent event, void* data);
+ void SendBarrierEvent(int x, int y, int velocity, int event_id);
+
int event_base_;
+ int last_event_;
+ bool first_event_;
PointerBarrier barrier;
int smoothing_count_;
diff --git a/launcher/StandaloneLauncher.cpp b/launcher/StandaloneLauncher.cpp
index ccc5e11e4..777951f6f 100644
--- a/launcher/StandaloneLauncher.cpp
+++ b/launcher/StandaloneLauncher.cpp
@@ -64,7 +64,6 @@ private:
{
SetupBackground();
controller.reset(new launcher::Controller(std::make_shared<XdndManager>()));
- controller->launcher().GetParent()->EnableInputWindow(false);
UScreen* uscreen = UScreen::GetDefault();
std::vector<nux::Geometry> fake_monitor({nux::Geometry(0, 0, win_size.width, win_size.height)});
diff --git a/launcher/SwitcherController.cpp b/launcher/SwitcherController.cpp
index 684918cef..89922e006 100644
--- a/launcher/SwitcherController.cpp
+++ b/launcher/SwitcherController.cpp
@@ -139,6 +139,11 @@ SwitcherView::Ptr Controller::GetView() const
return impl_->GetView();
}
+bool Controller::IsDetailViewShown()
+{
+ return impl_->IsDetailViewShown();
+}
+
void Controller::SetDetail(bool value, unsigned int min_windows)
{
impl_->SetDetail(value, min_windows);
@@ -421,8 +426,9 @@ void Controller::Impl::Hide(bool accept_state)
Selection selection = GetCurrentSelection();
if (selection.application_)
{
+ Time timestamp = -1;
selection.application_->Activate(ActionArg(ActionArg::SWITCHER, 0,
- selection.window_));
+ timestamp, selection.window_));
}
}
@@ -520,6 +526,11 @@ SwitcherView::Ptr Controller::Impl::GetView() const
return view_;
}
+bool Controller::Impl::IsDetailViewShown()
+{
+ return model_ && model_->detail_selection();
+}
+
void Controller::Impl::SetDetail(bool value, unsigned int min_windows)
{
if (value && model_->DetailXids().size() >= min_windows)
diff --git a/launcher/SwitcherController.h b/launcher/SwitcherController.h
index 29c5b7e7c..f291b7182 100644
--- a/launcher/SwitcherController.h
+++ b/launcher/SwitcherController.h
@@ -98,6 +98,7 @@ public:
void Select(int index);
+ bool IsDetailViewShown();
void SetDetail(bool detail,
unsigned int min_windows = 1);
diff --git a/launcher/SwitcherControllerImpl.h b/launcher/SwitcherControllerImpl.h
index 5734f1b05..9a877e5d0 100644
--- a/launcher/SwitcherControllerImpl.h
+++ b/launcher/SwitcherControllerImpl.h
@@ -56,6 +56,7 @@ struct Controller::Impl
void NextDetail();
void PrevDetail();
+ bool IsDetailViewShown();
void SetDetail(bool detail, unsigned int min_windows = 1);
void SelectFirstItem();
diff --git a/launcher/SwitcherModel.cpp b/launcher/SwitcherModel.cpp
index afaec75fb..cb2d41a73 100644
--- a/launcher/SwitcherModel.cpp
+++ b/launcher/SwitcherModel.cpp
@@ -39,11 +39,18 @@ SwitcherModel::SwitcherModel(std::vector<AbstractLauncherIcon::Ptr> const& icons
, index_(0)
, last_index_(0)
{
+ // When using Webapps, there are more than one active icon, so let's just pick
+ // up the first one found which is the web browser.
+ bool found = false;
+
for (auto const& application : applications_)
{
AddChild(application.GetPointer());
- if (application->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE))
+ if (application->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE) && !found)
+ {
last_active_application_ = application;
+ found = true;
+ }
}
}
diff --git a/launcher/TooltipManager.cpp b/launcher/TooltipManager.cpp
new file mode 100644
index 000000000..c34783233
--- /dev/null
+++ b/launcher/TooltipManager.cpp
@@ -0,0 +1,126 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Jacob Edwards <j.johan.edwards@gmail.com>
+ */
+
+#include "TooltipManager.h"
+
+namespace unity
+{
+namespace launcher
+{
+
+namespace
+{
+const unsigned int TOOLTIPS_SHOW_TIMEOUT_LENGTH = 1000;
+}
+
+TooltipManager::TooltipManager()
+ : show_tooltips_(false)
+ , hovered_(false)
+ , timer_locked_(false)
+{}
+
+void TooltipManager::SetIcon(AbstractLauncherIcon::Ptr const& newIcon)
+{
+ if (icon_ == newIcon)
+ return;
+
+ // Unlock hover timer, in case the previous icon had no valid tooltip
+ timer_locked_ = false;
+
+ if (show_tooltips_)
+ {
+ // Show new tooltip, get rid of the old olne
+ if (icon_)
+ icon_->HideTooltip();
+ if (newIcon)
+ newIcon->ShowTooltip();
+ }
+ else if (!newIcon)
+ {
+ // Stop the hover timer for null launcher space
+ StopTimer();
+ }
+ else
+ {
+ AbstractLauncherIcon::IconType type = newIcon->GetIconType();
+ if ((type == AbstractLauncherIcon::IconType::HOME ||
+ type == AbstractLauncherIcon::IconType::HUD) &&
+ newIcon->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE))
+ {
+ // Lock the hover timer for no valid tooltip cases
+ timer_locked_ = true;
+ StopTimer();
+ }
+ }
+
+ icon_ = newIcon;
+}
+
+void TooltipManager::SetHover(bool on_launcher)
+{
+ if (hovered_ == on_launcher)
+ return;
+ hovered_ = on_launcher;
+
+ if (show_tooltips_ && !hovered_)
+ {
+ show_tooltips_ = false;
+ if (icon_)
+ icon_->HideTooltip();
+ }
+}
+
+void TooltipManager::MouseMoved()
+{
+ if (!icon_ || show_tooltips_)
+ return;
+
+ ResetTimer();
+}
+
+void TooltipManager::IconClicked()
+{
+ StopTimer();
+ if (show_tooltips_ && icon_)
+ icon_->HideTooltip();
+
+ show_tooltips_ = false;
+ timer_locked_ = true;
+}
+
+void TooltipManager::ResetTimer()
+{
+ if (timer_locked_)
+ return;
+
+ hover_timer_.reset(new glib::Timeout(TOOLTIPS_SHOW_TIMEOUT_LENGTH));
+ hover_timer_->Run([&] () {
+ show_tooltips_ = true;
+ icon_->ShowTooltip();
+ return false;
+ });
+}
+
+void TooltipManager::StopTimer()
+{
+ hover_timer_.reset();
+}
+
+} // namespace launcher
+} // namespace unity
diff --git a/launcher/TooltipManager.h b/launcher/TooltipManager.h
new file mode 100644
index 000000000..f61fc199f
--- /dev/null
+++ b/launcher/TooltipManager.h
@@ -0,0 +1,57 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Jacob Edwards <j.johan.edwards@gmail.com>
+ */
+
+#ifndef TOOLTIPMANAGER
+#define TOOLTIPMANAGER
+
+#include <boost/noncopyable.hpp>
+#include <UnityCore/GLibSource.h>
+
+#include "AbstractLauncherIcon.h"
+
+namespace unity
+{
+namespace launcher
+{
+
+class TooltipManager : public boost::noncopyable
+{
+public:
+ TooltipManager();
+
+ void SetHover(bool on_launcher);
+ void SetIcon(AbstractLauncherIcon::Ptr const& newIcon);
+ void MouseMoved();
+ void IconClicked();
+
+private:
+ void ResetTimer();
+ void StopTimer();
+
+ bool show_tooltips_;
+ bool hovered_;
+ AbstractLauncherIcon::Ptr icon_;
+ glib::Source::UniquePtr hover_timer_;
+ bool timer_locked_;
+};
+
+} // namespace launcher
+} // namespace unity
+
+#endif
diff --git a/launcher/XdndCollectionWindowImp.cpp b/launcher/XdndCollectionWindowImp.cpp
index e39f373a7..b98075187 100644
--- a/launcher/XdndCollectionWindowImp.cpp
+++ b/launcher/XdndCollectionWindowImp.cpp
@@ -40,9 +40,14 @@ public:
ShowWindow(true);
PushToBack();
- // Hack to create the X Window as soon as possible.
- EnableInputWindow(true, "XdndCollectionWindowImp");
- EnableInputWindow(false, "XdndCollectionWindowImp");
+
+ if (nux::GetWindowThread()->IsEmbeddedWindow())
+ {
+ // Hack to create the X Window as soon as possible.
+ EnableInputWindow(true, "XdndCollectionWindowImp");
+ EnableInputWindow(false, "XdndCollectionWindowImp");
+ }
+
SetDndEnabled(false, true);
uscreen->changed.connect(sigc::mem_fun(this, &PrivateWindow::OnScreenChanged));
@@ -100,13 +105,17 @@ void XdndCollectionWindowImp::Collect()
// the launcher window and the dash window. Don't forget to call PushToBack as
// soon as possible.
window_->PushToFront();
- window_->EnableInputWindow(true, "XdndCollectionWindowImp");
+
+ if (nux::GetWindowThread()->IsEmbeddedWindow())
+ window_->EnableInputWindow(true, "XdndCollectionWindowImp");
}
void XdndCollectionWindowImp::Deactivate()
{
window_->PushToBack();
- window_->EnableInputWindow(false, "XdndCollectionWindowImp");
+
+ if (nux::GetWindowThread()->IsEmbeddedWindow())
+ window_->EnableInputWindow(false, "XdndCollectionWindowImp");
}
}
diff --git a/panel/PanelController.cpp b/panel/PanelController.cpp
index 7436ae006..865743aff 100644
--- a/panel/PanelController.cpp
+++ b/panel/PanelController.cpp
@@ -222,8 +222,11 @@ void Controller::Impl::OnScreenChanged(unsigned int primary_monitor,
view->SetPrimary(i == primary_monitor);
view->SetMonitor(i);
- (*it)->EnableInputWindow(true);
- (*it)->InputWindowEnableStruts(true);
+ if (nux::GetWindowThread()->IsEmbeddedWindow())
+ {
+ (*it)->EnableInputWindow(true);
+ (*it)->InputWindowEnableStruts(true);
+ }
LOG_DEBUG(logger) << "Updated Panel for Monitor " << i;
@@ -261,7 +264,10 @@ void Controller::Impl::OnScreenChanged(unsigned int primary_monitor,
window->SetConfigureNotifyCallback(&Impl::WindowConfigureCallback, window.GetPointer());
window->SetBackgroundColor(nux::Color(0.0f, 0.0f, 0.0f, 0.0f));
window->ShowWindow(true);
- window->EnableInputWindow(true, panel::window_title, false, false);
+
+ if (nux::GetWindowThread()->IsEmbeddedWindow())
+ window->EnableInputWindow(true, panel::window_title, false, false);
+
window->SetGeometry(geo);
window->SetMinMaxSize(geo.width, geo.height);
window->SetLayout(layout);
diff --git a/panel/PanelView.cpp b/panel/PanelView.cpp
index 8e95eef9a..80a57af37 100644
--- a/panel/PanelView.cpp
+++ b/panel/PanelView.cpp
@@ -115,8 +115,7 @@ PanelView::PanelView(NUX_FILE_LINE_DECL)
ubus_manager_.RegisterInterest(UBUS_BACKGROUND_COLOR_CHANGED, sigc::mem_fun(this, &PanelView::OnBackgroundUpdate));
ubus_manager_.RegisterInterest(UBUS_OVERLAY_HIDDEN, sigc::mem_fun(this, &PanelView::OnOverlayHidden));
ubus_manager_.RegisterInterest(UBUS_OVERLAY_SHOWN, sigc::mem_fun(this, &PanelView::OnOverlayShown));
- ubus_manager_.RegisterInterest(UBUS_DASH_SIZE_CHANGED, [&] (GVariant *data)
- {
+ ubus_manager_.RegisterInterest(UBUS_DASH_SIZE_CHANGED, [&] (GVariant *data) {
int width, height;
g_variant_get(data, "(ii)", &width, &height);
stored_dash_width_ = width;
@@ -176,7 +175,7 @@ void PanelView::SetLauncherWidth(int width)
bool PanelView::IsMouseInsideIndicator(nux::Point const& mouse_position) const
{
- return indicators_->GetGeometry().IsInside(mouse_position);
+ return indicators_->GetAbsoluteGeometry().IsInside(mouse_position);
}
void PanelView::OnBackgroundUpdate(GVariant *data)
@@ -197,8 +196,9 @@ void PanelView::OnOverlayHidden(GVariant* data)
unity::glib::String overlay_identity;
gboolean can_maximise = FALSE;
gint32 overlay_monitor = 0;
+ int width, height;
g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING,
- &overlay_identity, &can_maximise, &overlay_monitor);
+ &overlay_identity, &can_maximise, &overlay_monitor, &width, &height);
if (monitor_ == overlay_monitor && overlay_identity.Str() == active_overlay_)
{
@@ -219,11 +219,13 @@ void PanelView::OnOverlayShown(GVariant* data)
unity::glib::String overlay_identity;
gboolean can_maximise = FALSE;
gint32 overlay_monitor = 0;
+ int width, height;
g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING,
- &overlay_identity, &can_maximise, &overlay_monitor);
+ &overlay_identity, &can_maximise, &overlay_monitor, &width, &height);
if (monitor_ == overlay_monitor)
{
+ stored_dash_width_ = width;
bg_effect_helper_.enabled = true;
active_overlay_ = overlay_identity.Str();
overlay_is_open_ = true;
@@ -787,4 +789,9 @@ bool PanelView::IsActive() const
return menu_view_->GetControlsActive();
}
+int PanelView::GetStoredDashWidth() const
+{
+ return stored_dash_width_;
+}
+
} // namespace unity
diff --git a/panel/PanelView.h b/panel/PanelView.h
index 97b2da81a..d0f2f3d2c 100644
--- a/panel/PanelView.h
+++ b/panel/PanelView.h
@@ -23,6 +23,7 @@
#include <vector>
#include <memory>
+#include <Nux/Nux.h>
#include <Nux/View.h>
#include <Nux/TextureArea.h>
#include <NuxGraphics/GraphicsEngine.h>
@@ -63,6 +64,7 @@ public:
int discovery_fadein, int discovery_fadeout);
Window GetTrayXid() const;
+ int GetStoredDashWidth() const;
void SetLauncherWidth(int width);
diff --git a/plugins/unityshell/src/inputremover.cpp b/plugins/unityshell/src/inputremover.cpp
index a6798721d..b28e7a1e2 100644
--- a/plugins/unityshell/src/inputremover.cpp
+++ b/plugins/unityshell/src/inputremover.cpp
@@ -19,36 +19,129 @@
* Sam Spilsbury <sam.spilsbury@canonical.com>
*/
+#include <cstdlib>
+#include <boost/scoped_array.hpp>
#include "inputremover.h"
#include <X11/Xregion.h>
#include <cstdio>
#include <cstring>
+namespace
+{
+const unsigned int propVersion = 2;
+
+void CheckRectanglesCount(XRectangle *rects,
+ int *count,
+ unsigned int width,
+ unsigned int height,
+ unsigned int border)
+{
+ /* check if the returned shape exactly matches the window shape -
+ * if that is true, the window currently has no set input shape */
+ if ((*count == 1) &&
+ (rects[0].x == -((int) border)) &&
+ (rects[0].y == -((int) border)) &&
+ (rects[0].width == (width + border)) &&
+ (rects[0].height == (height + border)))
+ {
+ *count = 0;
+ }
+}
+
+bool CheckWindowExists(Display *dpy, Window shapeWindow,
+ unsigned int *width,
+ unsigned int *height,
+ unsigned int *border)
+{
+ Window root;
+ int x, y;
+ unsigned int depth;
+
+
+ /* FIXME: There should be a generic GetGeometry request we can
+ * use here in order to avoid a round-trip */
+ if (!XGetGeometry (dpy, shapeWindow, &root, &x, &y, width, height,
+ border, &depth))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+XRectangle * QueryRectangles(Display *dpy, Window shapeWindow,
+ int *count,
+ int *ordering,
+ int kind)
+{
+ return XShapeGetRectangles (dpy, shapeWindow, kind,
+ count, ordering);
+}
+
+}
+
compiz::WindowInputRemoverInterface::~WindowInputRemoverInterface ()
{
}
compiz::WindowInputRemover::WindowInputRemover (Display *dpy,
- Window xid) :
+ Window shapeWindow,
+ Window propWindow) :
mDpy (dpy),
- mShapeWindow (xid),
+ mShapeWindow (shapeWindow),
+ mPropWindow (propWindow),
mShapeMask (0),
mInputRects (NULL),
mNInputRects (0),
mInputRectOrdering (0),
- mBoundingRects (NULL),
- mNBoundingRects (0),
- mBoundingRectOrdering (0),
mRemoved (false)
{
/* FIXME: roundtrip */
XShapeQueryExtension (mDpy, &mShapeEvent, &mShapeError);
+
+ /* Check to see if the propWindow has a saved shape,
+ * if so, it means that we are coming from a restart or
+ * a crash where it wasn't properly restored, so we need
+ * to restore the saved input shape before doing anything
+ */
+ XRectangle *rects;
+ int count = 0, ordering;
+
+ if (queryProperty(&rects, &count, &ordering))
+ {
+ bool rectangles_restored = false;
+ unsigned int width, height, border;
+
+ if (CheckWindowExists(mDpy, mShapeWindow, &width, &height, &border))
+ if (checkRectangles(rects, &count, ordering,
+ width, height, border))
+ if (saveRectangles(rects, count, ordering))
+ {
+ /* Tell the shape restore engine that we've got a removed
+ * input shape here */
+ mRemoved = true;
+ if (restoreInput())
+ rectangles_restored = true;
+ }
+
+ /* Something failed and we couldn't restore the
+ * rectangles. Don't leak them */
+ if (!rectangles_restored)
+ {
+ free (rects);
+ }
+ }
+
}
compiz::WindowInputRemover::~WindowInputRemover ()
{
if (mRemoved)
restore ();
+
+ /* Remove the window property as we have already successfully restored
+ * the window shape */
+ clearProperty();
}
void
@@ -109,38 +202,6 @@ compiz::WindowInputRemover::sendShapeNotify ()
XTranslateCoordinates (mDpy, mShapeWindow, parentReturn, 0, 0,
&xOffset, &yOffset, &childReturn);
- xsev.kind = ShapeBounding;
-
- /* Calculate extents of the bounding shape */
- if (!mNBoundingRects)
- {
- /* No set input shape, we must use the client geometry */
- xsev.x = x - xOffset;
- xsev.y = y - yOffset;
- xsev.width = width;
- xsev.height = height;
- xsev.shaped = false;
- }
- else
- {
- Region boundingRegion = XCreateRegion ();
-
- for (int i = 0; i < mNBoundingRects; i++)
- XUnionRectWithRegion (&(mBoundingRects[i]), boundingRegion, boundingRegion);
-
- xsev.x = boundingRegion->extents.x1 - xOffset;
- xsev.y = boundingRegion->extents.y1 - yOffset;
- xsev.width = boundingRegion->extents.x2 - boundingRegion->extents.x1;
- xsev.height = boundingRegion->extents.y2 - boundingRegion->extents.y1;
- xsev.shaped = true;
-
- XDestroyRegion (boundingRegion);
- }
-
- xsev.time = CurrentTime;
-
- XSendEvent (mDpy, mShapeWindow, FALSE, NoEventMask, xev);
- XSendEvent (mDpy, parentReturn, FALSE, NoEventMask, xev);
xsev.kind = ShapeInput;
/* Calculate extents of the bounding shape */
@@ -181,21 +242,15 @@ compiz::WindowInputRemover::sendShapeNotify ()
{
XQueryTree (mDpy, mShapeWindow, &rootReturn, &parentReturn, &children, &nchildren);
- xsev.kind = ShapeBounding;
-
xsev.x = 0;
xsev.y = 0;
xsev.width = 0;
xsev.height = 0;
xsev.shaped = true;
- xsev.time = CurrentTime;
- XSendEvent (mDpy, mShapeWindow, FALSE, NoEventMask, xev);
- XSendEvent (mDpy, parentReturn, FALSE, NoEventMask, xev);
-
xsev.kind = ShapeInput;
- /* Both ShapeBounding and ShapeInput are null */
+ /* ShapeInput is null */
xsev.time = CurrentTime;
@@ -207,66 +262,271 @@ compiz::WindowInputRemover::sendShapeNotify ()
}
bool
-compiz::WindowInputRemover::saveInput ()
+compiz::WindowInputRemover::checkRectangles(XRectangle *input,
+ int *nInput,
+ int inputOrdering,
+ unsigned int width,
+ unsigned int height,
+ unsigned int border)
{
- XRectangle *rects;
- int count = 0, ordering;
- Window root;
- int x, y;
- unsigned int width, height, border, depth;
+ CheckRectanglesCount(input, nInput, width, height, border);
- /* FIXME: There should be a generic GetGeometry request we can
- * use here in order to avoid a round-trip */
- if (!XGetGeometry (mDpy, mShapeWindow, &root, &x, &y, &width, &height,
- &border, &depth))
+ /* There may be other sanity checks in future */
+ return true;
+}
+
+bool
+compiz::WindowInputRemover::queryShapeRectangles(XRectangle **input,
+ int *nInput,
+ int *inputOrdering,
+ unsigned int *width,
+ unsigned int *height,
+ unsigned int *border)
+{
+
+ if (!CheckWindowExists(mDpy, mShapeWindow, width, height, border))
+ return false;
+
+ *input = QueryRectangles(mDpy, mShapeWindow,
+ nInput, inputOrdering, ShapeInput);
+
+ return true;
+}
+
+bool
+compiz::WindowInputRemover::saveRectangles(XRectangle *input,
+ int nInput,
+ int inputOrdering)
+{
+ if (mInputRects)
+ XFree (mInputRects);
+
+ mInputRects = input;
+ mNInputRects = nInput;
+ mInputRectOrdering = inputOrdering;
+
+ return true;
+}
+
+void
+compiz::WindowInputRemover::clearRectangles ()
+{
+ /* Revert save action to local memory */
+ if (mInputRects)
+ XFree (mInputRects);
+
+ mNInputRects = 0;
+ mInputRectOrdering = 0;
+
+ mShapeMask = 0;
+
+ mRemoved = false;
+}
+
+bool
+compiz::WindowInputRemover::writeProperty (XRectangle *input,
+ int nInput,
+ int inputOrdering)
+{
+ Atom prop = XInternAtom (mDpy, "_UNITY_SAVED_WINDOW_SHAPE", FALSE);
+ Atom type = XA_CARDINAL;
+ int fmt = 32;
+
+ const unsigned int headerSize = 3;
+
+ /*
+ * -> version
+ * -> nInput
+ * -> inputOrdering
+ * -> nBounding
+ * -> boundingOrdering
+ *
+ * +
+ *
+ * nRectangles * 4
+ */
+ const size_t dataSize = headerSize + (nInput * 4);
+
+ boost::scoped_array<unsigned long> data(new unsigned long[dataSize]);
+
+ data[0] = propVersion;
+ data[1] = nInput;
+ data[2] = inputOrdering;
+
+ for (int i = 0; i < nInput; ++i)
+ {
+ const unsigned int position = dataSize + (i * 4);
+
+ data[position + 0] = input[i].x;
+ data[position + 1] = input[i].y;
+ data[position + 2] = input[i].width;
+ data[position + 3] = input[i].height;
+ }
+
+ /* No need to check return code, always returns 0 */
+ XChangeProperty(mDpy,
+ mPropWindow,
+ prop,
+ type,
+ fmt,
+ PropModeReplace,
+ reinterpret_cast<unsigned char*>(data.get()),
+ dataSize);
+
+ return true;
+}
+
+bool
+compiz::WindowInputRemover::queryProperty(XRectangle **input,
+ int *nInput,
+ int *inputOrdering)
+
+{
+ Atom prop = XInternAtom (mDpy, "_UNITY_SAVED_WINDOW_SHAPE", FALSE);
+ Atom type = XA_CARDINAL;
+ int fmt = 32;
+
+ Atom actualType;
+ int actualFmt;
+
+ unsigned long nItems;
+ unsigned long nLeft;
+
+ unsigned char *propData;
+
+ const unsigned long headerLength = 3L;
+
+ /* First query the first five bytes to figure out how
+ * long the rest of the property is going to be */
+ if (!XGetWindowProperty(mDpy,
+ mPropWindow,
+ prop,
+ 0L,
+ headerLength,
+ FALSE,
+ type,
+ &actualType,
+ &actualFmt,
+ &nItems,
+ &nLeft,
+ &propData))
{
return false;
}
- rects = XShapeGetRectangles (mDpy, mShapeWindow, ShapeInput,
- &count, &ordering);
+ /* If type or format is mismatched, return false */
+ if (actualType != type ||
+ actualFmt != fmt ||
+ headerLength != nItems)
+ {
+ XFree (propData);
+ return false;
+ }
- /* check if the returned shape exactly matches the window shape -
- * if that is true, the window currently has no set input shape */
- if ((count == 1) &&
- (rects[0].x == -((int) border)) &&
- (rects[0].y == -((int) border)) &&
- (rects[0].width == (width + border)) &&
- (rects[0].height == (height + border)))
+ /* XXX: the cast to void * before the reinterpret_cast is a hack to calm down
+ * gcc on ARM machines and its misalignment cast errors */
+ unsigned long *headerData = reinterpret_cast<unsigned long *>(static_cast<void *>(propData));
+
+ /* If version is mismatched, return false */
+ if (headerData[0] != propVersion)
+ return false;
+
+ /* New length is nInput * 4 + nBounding * 4 + headerSize */
+ unsigned long fullLength = *nInput * 4 + headerLength;
+
+ /* Free data and get the rest */
+ XFree (propData);
+
+ if (!XGetWindowProperty(mDpy,
+ mPropWindow,
+ prop,
+ 0L,
+ fullLength,
+ FALSE,
+ type,
+ &actualType,
+ &actualFmt,
+ &nItems,
+ &nLeft,
+ &propData))
{
- count = 0;
+ return false;
}
- if (mInputRects)
- XFree (mInputRects);
+ /* Check to make sure we got everything */
+ if (fullLength != nItems)
+ {
+ printf ("warning, did not get full legnth");
+ return false;
+ }
- mInputRects = rects;
- mNInputRects = count;
- mInputRectOrdering = ordering;
+ unsigned long *data = reinterpret_cast<unsigned long *>(static_cast<void *>(propData));
- rects = XShapeGetRectangles (mDpy, mShapeWindow, ShapeBounding,
- &count, &ordering);
+ /* Read in the header */
+ *nInput = data[1];
+ *inputOrdering = data[2];
- /* check if the returned shape exactly matches the window shape -
- * if that is true, the window currently has no set bounding shape */
- if ((count == 1) &&
- (rects[0].x == -((int) border)) &&
- (rects[0].y == -((int) border)) &&
- (rects[0].width == (width + border)) &&
- (rects[0].height == (height + border)))
+ /* Read in the rectangles */
+ *input = reinterpret_cast<XRectangle *>(calloc(1, sizeof(XRectangle) * *nInput));
+
+ for (int i = 0; i < *nInput; ++i)
+ {
+ const unsigned int position = headerLength + i * 4;
+
+ (*input)[i].x = data[position + 0];
+ (*input)[i].y = data[position + 1];
+ (*input[i]).width = data[position + 2];
+ (*input[i]).height = data[position + 3];
+ }
+
+ XFree (propData);
+
+ return true;
+}
+
+void
+compiz::WindowInputRemover::clearProperty()
+{
+ Atom prop = XInternAtom (mDpy, "_UNITY_SAVED_WINDOW_SHAPE", FALSE);
+
+ XDeleteProperty(mDpy, mPropWindow, prop);
+}
+
+bool
+compiz::WindowInputRemover::saveInput ()
+{
+ XRectangle *rects;
+ int count = 0, ordering;
+ unsigned int width, height, border;
+
+ /* Never save input for a cleared window */
+ if (mRemoved)
+ return false;
+
+ if (!queryShapeRectangles(&rects, &count, &ordering,
+ &width, &height, &border))
{
- count = 0;
+ clearRectangles ();
+ return false;
}
- if (mBoundingRects)
- XFree (mBoundingRects);
+ if (!checkRectangles(rects, &count, ordering,
+ width, height, border))
+ {
+ clearRectangles ();
+ return false;
+ }
- mBoundingRects = rects;
- mNBoundingRects = count;
- mBoundingRectOrdering = ordering;
+ if (!writeProperty(rects, count, ordering))
+ {
+ clearRectangles ();
+ return false;
+ }
mShapeMask = XShapeInputSelected (mDpy, mShapeWindow);
+ saveRectangles(rects, count, ordering);
+
return true;
}
@@ -281,15 +541,13 @@ compiz::WindowInputRemover::removeInput ()
XShapeCombineRectangles (mDpy, mShapeWindow, ShapeInput, 0, 0,
NULL, 0, ShapeSet, 0);
- XShapeCombineRectangles (mDpy, mShapeWindow, ShapeBounding, 0, 0,
- NULL, 0, ShapeSet, 0);
XShapeSelectInput (mDpy, mShapeWindow, mShapeMask);
- mRemoved = true;
-
sendShapeNotify ();
+ mRemoved = true;
+
return true;
}
@@ -319,25 +577,6 @@ compiz::WindowInputRemover::restoreInput ()
mInputRects = NULL;
mNInputRects = 0;
}
-
- if (mNBoundingRects)
- {
- XShapeCombineRectangles (mDpy, mShapeWindow, ShapeBounding, 0, 0,
- mBoundingRects, mNBoundingRects,
- ShapeSet, mBoundingRectOrdering);
- }
- else
- {
- XShapeCombineMask (mDpy, mShapeWindow, ShapeBounding,
- 0, 0, None, ShapeSet);
- }
-
- if (mBoundingRects)
- {
- XFree (mBoundingRects);
- mBoundingRects = NULL;
- mNBoundingRects = 0;
- }
}
XShapeSelectInput (mDpy, mShapeWindow, mShapeMask);
diff --git a/plugins/unityshell/src/inputremover.h b/plugins/unityshell/src/inputremover.h
index 69284f718..d5c6f5a45 100644
--- a/plugins/unityshell/src/inputremover.h
+++ b/plugins/unityshell/src/inputremover.h
@@ -54,7 +54,9 @@ class WindowInputRemover :
{
public:
- WindowInputRemover (Display *, Window xid);
+ WindowInputRemover (Display *,
+ Window shapeWindow,
+ Window propWindow);
~WindowInputRemover ();
private:
@@ -65,17 +67,44 @@ private:
void sendShapeNotify ();
+ bool queryShapeRectangles(XRectangle **input,
+ int *nInput,
+ int *inputOrdering,
+ unsigned int *width,
+ unsigned int *height,
+ unsigned int *border);
+
+ bool queryProperty(XRectangle **input,
+ int *nInput,
+ int *inputOrdering);
+
+ bool writeProperty(XRectangle *input,
+ int nInput,
+ int inputOrdering);
+
+ bool checkRectangles(XRectangle *input,
+ int *nInput,
+ int inputOrdering,
+ unsigned int width,
+ unsigned int height,
+ unsigned int border);
+
+ bool saveRectangles(XRectangle *input,
+ int nInput,
+ int inputOrdering);
+
+ void clearProperty ();
+ void clearRectangles ();
+
Display *mDpy;
Window mShapeWindow;
+ Window mPropWindow;
unsigned long mShapeMask;
XRectangle *mInputRects;
int mNInputRects;
int mInputRectOrdering;
- XRectangle *mBoundingRects;
- int mNBoundingRects;
- int mBoundingRectOrdering;
bool mRemoved;
int mShapeEvent;
diff --git a/plugins/unityshell/src/minimizedwindowhandler.cpp b/plugins/unityshell/src/minimizedwindowhandler.cpp
index 05abef0cc..e0ec285fb 100644
--- a/plugins/unityshell/src/minimizedwindowhandler.cpp
+++ b/plugins/unityshell/src/minimizedwindowhandler.cpp
@@ -227,6 +227,7 @@ compiz::MinimizedWindowHandler::unminimize ()
int count = 0;
nextStateSize = nItems;
+ nextState = reinterpret_cast<Atom *>(malloc(sizeof(Atom) * nextStateSize));
pbegin = nextState = (Atom *) memcpy (nextState, data, sizeof (Atom) * nextStateSize);
diff --git a/plugins/unityshell/src/unity-util-accessible.cpp b/plugins/unityshell/src/unity-util-accessible.cpp
index 712ab1f81..ca8c6bb54 100644
--- a/plugins/unityshell/src/unity-util-accessible.cpp
+++ b/plugins/unityshell/src/unity-util-accessible.cpp
@@ -286,6 +286,7 @@ atk_key_event_from_nux_event_key(nux::Event* event)
/* we don't call atk_key_event_from_nux_event_key if the event
is different to keydown or keyup */
g_assert_not_reached();
+ g_free(atk_event);
return NULL;
}
diff --git a/plugins/unityshell/src/unitya11ytests.cpp b/plugins/unityshell/src/unitya11ytests.cpp
index 425a32468..efc7968ca 100644
--- a/plugins/unityshell/src/unitya11ytests.cpp
+++ b/plugins/unityshell/src/unitya11ytests.cpp
@@ -204,12 +204,12 @@ static gboolean
a11y_unit_test_launcher_connection(void)
{
Launcher* launcher = NULL;
- nux::BaseWindow* window = NULL;
+ unity::MockableBaseWindow* window = NULL;
AtkObject* launcher_accessible = NULL;
LauncherIcon* launcher_icon = NULL;
AtkObject* launcher_icon_accessible = NULL;
- window = new nux::BaseWindow(TEXT(""));
+ window = new unity::MockableBaseWindow(TEXT(""));
launcher = new Launcher(window, NULL);
launcher->SinkReference();
launcher_accessible = unity_a11y_get_accessible(launcher);
diff --git a/plugins/unityshell/src/unityshell.cpp b/plugins/unityshell/src/unityshell.cpp
index e3eeba3f0..5151a21d5 100644
--- a/plugins/unityshell/src/unityshell.cpp
+++ b/plugins/unityshell/src/unityshell.cpp
@@ -392,8 +392,9 @@ UnityScreen::UnityScreen(CompScreen* screen)
unity::glib::String overlay_identity;
gboolean can_maximise = FALSE;
gint32 overlay_monitor = 0;
+ int width, height;
g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING,
- &overlay_identity, &can_maximise, &overlay_monitor);
+ &overlay_identity, &can_maximise, &overlay_monitor, &width, &height);
overlay_monitor_ = overlay_monitor;
@@ -1137,7 +1138,11 @@ UnityWindow::GetInputRemover ()
if (!input_remover_.expired ())
return input_remover_.lock ();
- compiz::WindowInputRemoverLock::Ptr ret (new compiz::WindowInputRemoverLock (new compiz::WindowInputRemover (screen->dpy (), window->id ())));
+ compiz::WindowInputRemoverLock::Ptr
+ ret (new compiz::WindowInputRemoverLock (
+ new compiz::WindowInputRemover (screen->dpy (),
+ window->id (),
+ window->id ())));
input_remover_ = ret;
return ret;
}
@@ -1271,6 +1276,7 @@ bool UnityScreen::glPaintOutput(const GLScreenPaintAttrib& attrib,
// CompRegion has no clear() method. So this is the fastest alternative.
fullscreenRegion = CompRegion();
nuxRegion = CompRegion();
+ windows_for_monitor_.clear();
/* glPaintOutput is part of the opengl plugin, so we need the GLScreen base class. */
ret = gScreen->glPaintOutput(attrib, transform, region, output, mask);
@@ -1644,7 +1650,7 @@ void UnityScreen::handleEvent(XEvent* event)
if (super_keypressed_)
{
- skip_other_plugins = launcher_controller_->HandleLauncherKeyEvent(screen->dpy(), key_sym, event->xkey.keycode, event->xkey.state, key_string);
+ skip_other_plugins = launcher_controller_->HandleLauncherKeyEvent(screen->dpy(), key_sym, event->xkey.keycode, event->xkey.state, key_string, event->xkey.time);
if (!skip_other_plugins)
skip_other_plugins = dash_controller_->CheckShortcutActivation(key_string);
@@ -2059,10 +2065,14 @@ bool UnityScreen::altTabNextWindowInitiate(CompAction* action, CompAction::State
switcher_controller_->Select((switcher_controller_->StartIndex())); // always select the current application
switcher_controller_->InitiateDetail();
}
- else
+ else if (switcher_controller_->IsDetailViewShown())
{
switcher_controller_->NextDetail();
}
+ else
+ {
+ switcher_controller_->SetDetail(true);
+ }
action->setState(action->state() | CompAction::StateTermKey);
return true;
@@ -2509,17 +2519,32 @@ bool UnityWindow::glPaint(const GLWindowPaintAttrib& attrib,
PAINT_WINDOW_TRANSLUCENT_MASK |
PAINT_WINDOW_TRANSFORMED_MASK |
PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
- if (!(mask & nonOcclusionBits) &&
- (window->state() & CompWindowStateFullscreenMask))
- // And I've been advised to test other things, but they don't work:
- // && (attrib.opacity == OPAQUE)) <-- Doesn't work; Only set in glDraw
- // && !window->alpha() <-- Doesn't work; Opaque windows often have alpha
+
+ if (window->isMapped() &&
+ window->defaultViewport() == uScreen->screen->vp())
{
- uScreen->fullscreenRegion += window->geometry();
- uScreen->fullscreenRegion -= uScreen->nuxRegion;
+ int monitor = window->outputDevice();
+
+ auto it = uScreen->windows_for_monitor_.find(monitor);
+
+ if (it != end(uScreen->windows_for_monitor_))
+ ++(it->second);
+ else
+ uScreen->windows_for_monitor_[monitor] = 1;
+
+ if (!(mask & nonOcclusionBits) &&
+ (window->state() & CompWindowStateFullscreenMask) &&
+ uScreen->windows_for_monitor_[monitor] == 1)
+ // And I've been advised to test other things, but they don't work:
+ // && (attrib.opacity == OPAQUE)) <-- Doesn't work; Only set in glDraw
+ // && !window->alpha() <-- Doesn't work; Opaque windows often have alpha
+ {
+ uScreen->fullscreenRegion += window->geometry();
+ }
+
+ if (uScreen->nuxRegion.isEmpty())
+ uScreen->firstWindowAboveShell = window;
}
- if (uScreen->nuxRegion.isEmpty())
- uScreen->firstWindowAboveShell = window;
}
GLWindowPaintAttrib wAttrib = attrib;
@@ -3348,6 +3373,25 @@ struct UnityWindow::CairoContext
cairo_t *cr_;
};
+namespace
+{
+bool WindowHasInconsistentShapeRects (Display *d,
+ Window w)
+{
+ int n;
+ Atom *atoms = XListProperties(d, w, &n);
+ Atom unity_shape_rects_atom = XInternAtom (d, "_UNITY_SAVED_WINDOW_SHAPE", FALSE);
+ bool has_inconsistent_shape = false;
+
+ for (int i = 0; i < n; ++i)
+ if (atoms[i] == unity_shape_rects_atom)
+ has_inconsistent_shape = true;
+
+ XFree (atoms);
+ return has_inconsistent_shape;
+}
+}
+
UnityWindow::UnityWindow(CompWindow* window)
: BaseSwitchWindow (dynamic_cast<BaseSwitchScreen *> (UnityScreen::get (screen)), window)
, PluginClassHandler<UnityWindow, CompWindow>(window)
@@ -3358,14 +3402,20 @@ UnityWindow::UnityWindow(CompWindow* window)
GLWindowInterface::setHandler(gWindow);
ScaleWindowInterface::setHandler (ScaleWindow::get (window));
+ /* This needs to happen before we set our wrapable functions, since we
+ * need to ask core (and not ourselves) whether or not the window is
+ * minimized */
if (UnityScreen::get (screen)->optionGetShowMinimizedWindows () &&
- window->mapNum ())
+ window->mapNum () &&
+ WindowHasInconsistentShapeRects (screen->dpy (),
+ window->id ()))
{
+ /* Query the core function */
+ window->minimizedSetEnabled (this, false);
+
bool wasMinimized = window->minimized ();
if (wasMinimized)
window->unminimize ();
- window->minimizeSetEnabled (this, true);
- window->unminimizeSetEnabled (this, true);
window->minimizedSetEnabled (this, true);
if (wasMinimized)
@@ -3378,6 +3428,8 @@ UnityWindow::UnityWindow(CompWindow* window)
window->minimizedSetEnabled (this, false);
}
+ /* Keep this after the optionGetShowMinimizedWindows branch */
+
if (window->state () & CompWindowStateFullscreenMask)
UnityScreen::get (screen)->fullscreen_windows_.push_back(window);
diff --git a/plugins/unityshell/src/unityshell.h b/plugins/unityshell/src/unityshell.h
index 0d958673e..a2654e747 100644
--- a/plugins/unityshell/src/unityshell.h
+++ b/plugins/unityshell/src/unityshell.h
@@ -290,6 +290,7 @@ private:
typedef std::vector<CompActionPtr> ShortcutActions;
ShortcutActions _shortcut_actions;
std::map<CancelActionTarget, CompActionPtr> _escape_actions;
+ std::map<int, unsigned int> windows_for_monitor_;
/* keyboard-nav mode */
CompWindow* newFocusedWindow;
diff --git a/services/panel-service.c b/services/panel-service.c
index b23890d9d..8f513b640 100644
--- a/services/panel-service.c
+++ b/services/panel-service.c
@@ -27,6 +27,7 @@
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <glib/gi18n-lib.h>
+#include <libindicator/indicator-ng.h>
#include <X11/extensions/XInput2.h>
#include <X11/XKBlib.h>
@@ -123,6 +124,7 @@ static void load_indicator (PanelService *self,
IndicatorObject *object,
const gchar *_name);
static void load_indicators (PanelService *self);
+static void load_indicators_from_indicator_files (PanelService *self);
static void sort_indicators (PanelService *self);
static void notify_object (IndicatorObject *object);
@@ -557,6 +559,7 @@ panel_service_init (PanelService *self)
suppress_signals = TRUE;
load_indicators (self);
+ load_indicators_from_indicator_files (self);
sort_indicators (self);
suppress_signals = FALSE;
@@ -1011,6 +1014,42 @@ load_indicators (PanelService *self)
g_dir_close (dir);
}
+static void
+load_indicators_from_indicator_files (PanelService *self)
+{
+ GDir *dir;
+ const gchar *name;
+ GError *error = NULL;
+
+ dir = g_dir_open (INDICATOR_SERVICE_DIR, 0, &error);
+ if (!dir)
+ {
+ g_warning ("unable to open indicator service file directory: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ while ((name = g_dir_read_name (dir)))
+ {
+ gchar *filename;
+ IndicatorNg *indicator;
+
+ filename = g_build_filename (INDICATOR_SERVICE_DIR, name, NULL);
+ indicator = indicator_ng_new_for_profile (filename, "desktop", &error);
+ if (indicator)
+ {
+ load_indicator (self, INDICATOR_OBJECT (indicator), NULL);
+ }
+ else
+ {
+ g_warning ("unable to load '%s': %s", name, error->message);
+ g_clear_error (&error);
+ }
+
+ g_free (filename);
+ }
+}
+
static gint
name2order (const gchar * name, const gchar * hint)
{
@@ -1242,10 +1281,6 @@ 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;
@@ -1705,16 +1740,6 @@ panel_service_show_entry_common (PanelService *self,
G_CALLBACK (menuitem_activated), entry);
}
- 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;
diff --git a/shortcuts/ShortcutHintPrivate.cpp b/shortcuts/ShortcutHintPrivate.cpp
index 11e6b2388..8ca036298 100644
--- a/shortcuts/ShortcutHintPrivate.cpp
+++ b/shortcuts/ShortcutHintPrivate.cpp
@@ -35,10 +35,8 @@ namespace impl
std::string GetMetaKey(std::string const& scut)
{
size_t index = scut.find_last_of( ">");
- if (index >= 0)
- return std::string(scut.begin(), scut.begin() + index + 1);
- else
- return "";
+
+ return std::string(scut.begin(), scut.begin() + index + 1);
}
std::string FixShortcutFormat(std::string const& scut)
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index d7ad33749..a4df71ef9 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -16,6 +16,17 @@ configure_file (${CMAKE_CURRENT_SOURCE_DIR}/data/applications/no-icon.desktop
configure_file (${CMAKE_CURRENT_SOURCE_DIR}/data/applications/kde4/afile.desktop
${CMAKE_BINARY_DIR}/tests/data/applications/kde4/afile.desktop)
+configure_file (${CMAKE_CURRENT_SOURCE_DIR}/data/lenses/social/social.lens
+ ${CMAKE_BINARY_DIR}/tests/data/lenses/social/social.lens)
+configure_file (${CMAKE_CURRENT_SOURCE_DIR}/data/lenses/files/files.lens
+ ${CMAKE_BINARY_DIR}/tests/data/lenses/files/files.lens)
+configure_file (${CMAKE_CURRENT_SOURCE_DIR}/data/lenses/applications/applications.lens
+ ${CMAKE_BINARY_DIR}/tests/data/lenses/applications/applications.lens)
+configure_file (${CMAKE_CURRENT_SOURCE_DIR}/data/lenses/invalid-lens-file/invalid-lens-file.lens
+ ${CMAKE_BINARY_DIR}/tests/data/lenses/invalid-lens-file/invalid-lens-file.lens)
+configure_file (${CMAKE_CURRENT_SOURCE_DIR}/data/lenses/invalid-lens-group/invalid-lens-group.lens
+ ${CMAKE_BINARY_DIR}/tests/data/lenses/invalid-lens-group/invalid-lens-group.lens)
+
#
# Unit tests
#
@@ -79,17 +90,12 @@ if (GTEST_SRC_DIR AND
# The service that provides DBus services to test against
add_executable(test-gtest-service
mock-application.cpp
- test_service_gdbus_wrapper.c
- test_service_gdbus_wrapper.h
- test_service_hud.c
- test_service_hud.h
- test_service_lens.c
- test_service_lens.h
- test_service_main.c
- test_service_model.c
- test_service_model.h
- test_service_panel.c
- test_service_panel.c)
+ test_service_gdbus_wrapper.cpp
+ test_service_hud.cpp
+ test_service_lens.cpp
+ test_service_main.cpp
+ test_service_model.cpp
+ test_service_panel.cpp)
target_link_libraries(test-gtest-service unity-shared ${LIBS})
@@ -98,6 +104,7 @@ if (GTEST_SRC_DIR AND
test_main_xless.cpp
test_abstract_interface_generator.cpp
test_launcher_model.cpp
+ test_glib_dbus_object.cpp
test_glib_object.cpp
test_glib_object_utils.cpp
test_glib_object_utils.h
@@ -168,6 +175,7 @@ if (GTEST_SRC_DIR AND
# tests that require dbus, must not require X
add_executable(test-gtest-dbus
test_categories.cpp
+ test_dbus_indicators.cpp
test_filesystem_lenses.cpp
test_filter.cpp
test_gdbus_proxy.cpp
@@ -178,7 +186,6 @@ if (GTEST_SRC_DIR AND
test_utils.h
test_ratings_filter.cpp
test_results.cpp
- test_dbus_indicators.cpp
)
target_link_libraries(test-gtest-dbus gtest unity-shared ${LIBS})
add_test(UnityGTestDBus test-gtest-dbus)
@@ -200,6 +207,8 @@ if (ENABLE_X_SUPPORT)
test_device_launcher_section.cpp
test_edge_barrier_controller.cpp
test_expo_launcher_icon.cpp
+ test_filter_widgets.cpp
+ test_glib_dbus_server.cpp
test_hud_button.cpp
test_hud_controller.cpp
test_hud_launcher_icon.cpp
@@ -220,6 +229,7 @@ if (ENABLE_X_SUPPORT)
test_panel_menu_view.cpp
test_panel_style.cpp
test_panel_tray.cpp
+ test_panel_view.cpp
test_places_group.cpp
test_previews_application.cpp
test_previews_generic.cpp
@@ -247,6 +257,7 @@ if (ENABLE_X_SUPPORT)
test_texture_cache.cpp
test_text_input.cpp
test_thumbnail_generator.cpp
+ test_tooltip_manager.cpp
test_trash_launcher_icon.cpp
test_unity_settings.cpp
test_unity_window_style.cpp
diff --git a/tests/autopilot/unity/emulators/launcher.py b/tests/autopilot/unity/emulators/launcher.py
index 636e986a3..4fce24e98 100644
--- a/tests/autopilot/unity/emulators/launcher.py
+++ b/tests/autopilot/unity/emulators/launcher.py
@@ -473,7 +473,7 @@ class LauncherModel(UnityIntrospectionObject):
looking for an icon. For example, to find an icon with a particular
desktop_id, one might do this from within a test:
- >>> self.launcher.model.get_icon(desktop_id="gcalctool.desktop")
+ >>> self.launcher.model.get_icon(desktop_id="gnome-calculator.desktop")
This method returns only one icon. It is the callers responsibility to
ensure that the filter matches only one icon.
diff --git a/tests/autopilot/unity/tests/launcher/test_icon_behavior.py b/tests/autopilot/unity/tests/launcher/test_icon_behavior.py
index 56e231b57..c7c0847b1 100644
--- a/tests/autopilot/unity/tests/launcher/test_icon_behavior.py
+++ b/tests/autopilot/unity/tests/launcher/test_icon_behavior.py
@@ -12,7 +12,7 @@ from __future__ import absolute_import
from autopilot.matchers import Eventually
from autopilot.testcase import multiply_scenarios
import logging
-from testtools.matchers import Equals, NotEquals
+from testtools.matchers import Equals, NotEquals, GreaterThan
from time import sleep
from unity.emulators.icons import ApplicationLauncherIcon, ExpoLauncherIcon
@@ -149,6 +149,29 @@ class LauncherIconsTests(LauncherTestCase):
self.assertThat(lambda: self.get_startup_notification_timestamp(calc_window), Eventually(Equals(calc_icon.startup_notification_timestamp)))
+ def test_super_number_shortcut_focuses_new_windows(self):
+ """Windows launched using super+number must have
+ keyboard focus.
+
+ """
+ bfb_icon = self.unity.launcher.model.get_bfb_icon()
+ calc_icon = self.ensure_calculator_in_launcher_and_not_running()
+ self.addCleanup(self.close_all_app, "Calculator")
+
+ self.launcher_instance.drag_icon_to_position(
+ calc_icon,
+ IconDragType.AFTER,
+ bfb_icon)
+
+ self.launcher_instance.keyboard_reveal_launcher()
+ self.addCleanup(self.launcher_instance.keyboard_unreveal_launcher)
+ self.keyboard.press_and_release("1");
+
+ calc_app = self.bamf.get_running_applications_by_desktop_file(calc_icon.desktop_id)[0]
+ calc_window = calc_app.get_windows()[0]
+
+ self.assertThat(lambda: calc_window.is_focused, Eventually(Equals(True)))
+
def test_clicking_icon_twice_initiates_spread(self):
"""This tests shows that when you click on a launcher icon twice,
when an application window is focused, the spread is initiated.
@@ -292,7 +315,7 @@ class LauncherDragIconsBehavior(LauncherTestCase):
# not exist, and we don't want to wait for 10 seconds, so we do this
# the old fashioned way.
get_icon_fn = lambda: self.unity.launcher.model.get_children_by_type(
- ApplicationLauncherIcon, desktop_id="gcalctool.desktop")
+ ApplicationLauncherIcon, desktop_id="gnome-calculator.desktop")
calc_icon = get_icon_fn()
if calc_icon:
self.launcher_instance.unlock_from_launcher(calc_icon[0])
diff --git a/tests/autopilot/unity/tests/launcher/test_tooltips.py b/tests/autopilot/unity/tests/launcher/test_tooltips.py
new file mode 100644
index 000000000..09cd786e1
--- /dev/null
+++ b/tests/autopilot/unity/tests/launcher/test_tooltips.py
@@ -0,0 +1,87 @@
+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
+# Copyright 2013 Canonical
+# Authors: Jacob Edwards
+#
+# 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.
+
+from autopilot.matchers import Eventually
+from testtools.matchers import Equals
+from time import sleep
+
+from unity.tests.launcher import LauncherTestCase, _make_scenarios
+
+class LauncherTooltipTests(LauncherTestCase):
+ """Tests whether tooltips display only at appropriate times."""
+
+ def setUp(self):
+ super(LauncherTooltipTests, self).setUp()
+ self.set_unity_option('launcher_hide_mode', 0)
+ self.launcher_instance.move_mouse_to_right_of_launcher()
+ self.icons = self.unity.launcher.model.get_launcher_icons(visible_only=True)
+
+ def test_launcher_tooltip_show(self):
+ """Tests whether icon tooltips delay showing themselves and,
+ once shown, whether subsequent icons show them instantly."""
+ for i in self.icons:
+ tooltip = i.get_tooltip()
+ if not tooltip:
+ continue
+ self.assertThat(tooltip.active, Eventually(Equals(False)))
+
+ # only reveal tooltips after short wait
+ self.assertEqual(self.get_reveal_behavior(self.icons[0]), self.DELAYED)
+
+ # subsequent tooltips reveal instantly, but hide on exit
+ a, b = 0, 1
+ while b < len(self.icons):
+ self.mouse.move(self.icons[b].center_x, self.icons[b].center_y)
+ self.assertTrue(self.icons[b].get_tooltip().active)
+ self.assertFalse(self.icons[a].get_tooltip().active)
+ a, b = a + 1, b + 1
+ b -= 1
+
+ # leaving launcher clears tooltips, and instant reveal
+ self.launcher_instance.move_mouse_to_right_of_launcher()
+ self.assertEqual(self.get_reveal_behavior(self.icons[b]), self.DELAYED)
+
+ def test_launcher_tooltip_disabling(self):
+ """Tests whether clicking on an icon hides its tooltip."""
+ bfb, other = self.icons[0], self.icons[1]
+ self.assertEqual(self.get_reveal_behavior(bfb), self.DELAYED)
+
+ # clicking icon hides its launcher until further input
+ self.mouse.click()
+ self.assertEqual(self.get_reveal_behavior(bfb), self.NEVER)
+ self.mouse.click()
+
+ # normal behavior resumes on moving away from icon
+ self.assertEqual(self.get_reveal_behavior(other), self.DELAYED)
+ self.assertEqual(self.get_reveal_behavior(bfb), self.INSTANT)
+
+ def test_launcher_bfb_tooltip_when_open(self):
+ """Tests whether hovering over the active BFB starts a tooltip timer"""
+ self.unity.dash.ensure_visible()
+ self.addCleanup(self.unity.dash.ensure_hidden)
+ bfb, other = self.icons[0], self.icons[1]
+
+ # hovering an open dash's BFB does not show a tooltip ...
+ self.assertEqual(self.get_reveal_behavior(bfb), self.NEVER)
+
+ # ... nor did it timeout instant tooltips for other icons
+ self.assertEqual(self.get_reveal_behavior(other), self.DELAYED)
+
+ # Tooltip reveal types
+ (INSTANT, DELAYED, NEVER) = range(3)
+
+ def get_reveal_behavior(self, icon):
+ self.mouse.move(icon.center_x, icon.center_y)
+ tooltip = icon.get_tooltip()
+ if tooltip and tooltip.active:
+ return self.INSTANT
+ sleep(1.2)
+ tooltip = icon.get_tooltip()
+ if tooltip and tooltip.active:
+ return self.DELAYED
+ return self.NEVER
diff --git a/tests/autopilot/unity/tests/test_dash.py b/tests/autopilot/unity/tests/test_dash.py
index f65b4963a..26e092402 100644
--- a/tests/autopilot/unity/tests/test_dash.py
+++ b/tests/autopilot/unity/tests/test_dash.py
@@ -73,7 +73,7 @@ class DashRevealTests(DashTestCase):
"""Switch to command lens without closing the dash."""
self.unity.dash.ensure_visible()
self.unity.dash.reveal_command_lens()
- self.assertThat(self.unity.dash.visible, Eventually(Equals(False)))
+ self.assertThat(self.unity.dash.active_lens, Eventually(Equals('commands.lens')))
def test_alt_f4_close_dash(self):
"""Dash must close on alt+F4."""
@@ -610,14 +610,17 @@ class DashVisualTests(DashTestCase):
""""There should be no empty space between launcher and dash when the launcher
has a non-default width.
"""
- self.set_unity_option('icon_size', 60)
- self.unity.dash.ensure_visible()
-
monitor = self.unity.dash.monitor
launcher = self.unity.launcher.get_launcher_for_monitor(monitor)
+ self.set_unity_option('icon_size', 60)
+ self.assertThat(launcher.icon_size, Eventually(Equals(66)))
+
+ self.unity.dash.ensure_visible()
+
self.assertThat(self.unity.dash.geometry[0], Eventually(Equals(launcher.geometry[0] + launcher.geometry[2] - 1)))
+
def test_see_more_result_alignment(self):
"""The see more results label should be baseline aligned
with the category name label.
diff --git a/tests/autopilot/unity/tests/test_gobject_introspection.py b/tests/autopilot/unity/tests/test_gobject_introspection.py
new file mode 100755
index 000000000..58a0c38ea
--- /dev/null
+++ b/tests/autopilot/unity/tests/test_gobject_introspection.py
@@ -0,0 +1,66 @@
+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
+# Copyright 2013 Canonical
+# Author: Iain Lane
+#
+# 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.
+
+from __future__ import absolute_import
+
+from testtools import TestCase
+
+class GirTests(TestCase):
+
+ """ Test that GOBject Intospection bindings can imported """
+
+ def setUp(self):
+ super(GirTests, self).setUp()
+
+ def test_appindicator_import(self):
+ imported = False
+
+ try:
+ from gi.repository import AppIndicator3
+ imported = True
+ except ImportError:
+ # failed
+ pass
+
+ self.assertTrue(imported)
+
+ def test_dbusmenu_import(self):
+ imported = False
+
+ try:
+ from gi.repository import Dbusmenu
+ imported = True
+ except ImportError:
+ # failed
+ pass
+
+ self.assertTrue(imported)
+
+ def test_dee_import(self):
+ imported = False
+
+ try:
+ from gi.repository import Dee
+ imported = True
+ except ImportError:
+ # failed
+ pass
+
+ self.assertTrue(imported)
+
+ def test_unity_import(self):
+ imported = False
+
+ try:
+ from gi.repository import Unity
+ imported = True
+ except ImportError:
+ # failed
+ pass
+
+ self.assertTrue(imported)
diff --git a/tests/autopilot/unity/tests/test_ibus.py b/tests/autopilot/unity/tests/test_ibus.py
index eeb57707d..504e4bc62 100644
--- a/tests/autopilot/unity/tests/test_ibus.py
+++ b/tests/autopilot/unity/tests/test_ibus.py
@@ -1,6 +1,6 @@
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
# Copyright 2012 Canonical
-# Author: Thomi Richards, Martin Mrazik
+# Authors: Thomi Richards, Martin Mrazik, Łukasz 'sil2100' Zemczak
#
# 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
@@ -16,6 +16,7 @@ from autopilot.emulators.ibus import (
get_available_input_engines,
get_gconf_option,
set_gconf_option,
+ get_ibus_bus,
)
from autopilot.matchers import Eventually
from autopilot.testcase import multiply_scenarios
@@ -23,6 +24,84 @@ from testtools.matchers import Equals, NotEquals
from unity.tests import UnityTestCase
+from gi.repository import GLib
+from gi.repository import IBus
+import time
+import dbus
+import threading
+
+
+# See lp:ibus-query
+class IBusQuery:
+ """A simple class allowing string queries to the IBus engine."""
+
+ def __init__(self):
+ self._bus = IBus.Bus()
+ self._dbusconn = dbus.connection.Connection(IBus.get_address())
+
+ # XXX: the new IBus bindings do not export create_input_context for
+ # introspection. This is troublesome - so, to workaround this problem
+ # we're directly fetching a new input context manually
+ ibus_obj = self._dbusconn.get_object(IBus.SERVICE_IBUS, IBus.PATH_IBUS)
+ self._test = dbus.Interface(ibus_obj, dbus_interface="org.freedesktop.IBus")
+ path = self._test.CreateInputContext("IBusQuery")
+ self._context = IBus.InputContext.new(path, self._bus.get_connection(), None)
+
+ self._glibloop = GLib.MainLoop()
+
+ self._context.connect("commit-text", self.__commit_text_cb)
+ self._context.connect("update-preedit-text", self.__update_preedit_cb)
+ self._context.connect("disabled", self.__disabled_cb)
+
+ self._context.set_capabilities (9)
+
+ def __commit_text_cb(self, context, text):
+ self.result += text.text
+ self._preedit = ''
+
+ def __update_preedit_cb(self, context, text, cursor_pos, visible):
+ if visible:
+ self._preedit = text.text
+
+ def __disabled_cb(self, a):
+ self.result += self._preedit
+ self._glibloop.quit()
+
+ def __abort(self):
+ self._abort = True
+
+ def poll(self, engine, ibus_input):
+ if len(ibus_input) <= 0:
+ return None
+
+ self.result = ''
+ self._preedit = ''
+ self._context.focus_in()
+ self._context.set_engine(engine)
+
+ # Timeout in case of the engine not being installed
+ self._abort = False
+ timeout = threading.Timer(4.0, self.__abort)
+ timeout.start()
+ while self._context.get_engine() is None:
+ if self._abort is True:
+ print "Error! Could not set the engine correctly."
+ return None
+ continue
+ timeout.cancel()
+
+ for c in ibus_input:
+ self._context.process_key_event(ord(c), 0, 0)
+
+ self._context.set_engine('')
+ self._context.focus_out()
+
+ GLib.timeout_add_seconds(5, lambda *args: self._glibloop.quit())
+ self._glibloop.run()
+
+ return unicode(self.result, "UTF-8")
+
+
class IBusTests(UnityTestCase):
"""Base class for IBus tests."""
@@ -30,6 +109,7 @@ class IBusTests(UnityTestCase):
def setUp(self):
super(IBusTests, self).setUp()
self.set_correct_ibus_trigger_keys()
+ self._ibus_query = None
def set_correct_ibus_trigger_keys(self):
"""Set the correct keys to trigger IBus.
@@ -96,8 +176,35 @@ class IBusWidgetScenariodTests(IBusTests):
('hud', {'widget': 'hud'})
]
+ def try_ibus_query(self):
+ """This helper method tries to query ibus, and if it has connection problems,
+ it restarts the ibus connection.
+ It is to be used in a loop until it returns True, which means we probably
+ got a proper result - stored in self.result
+
+ """
+ self.result = None
+ try:
+ self._ibus_query = IBusQuery()
+ except:
+ # Here is a tricky situation. Probably for some reason the ibus connection
+ # got busted. In this case, restarting the connection from IBusQuery is not
+ # enough. We have to restart the global ibus connection to be sure
+ self._ibus_query = None
+ get_ibus_bus()
+ return False
+ self.result = self._ibus_query.poll(self.engine_name, self.input)
+ return self.result is not None
+
+
def do_ibus_test(self):
"""Do the basic IBus test on self.widget using self.input and self.result."""
+ try:
+ result = self.result
+ except:
+ self.assertThat(self.try_ibus_query, Eventually(Equals(True)))
+ result = self.result
+
widget = getattr(self.unity, self.widget)
widget.ensure_visible()
self.addCleanup(widget.ensure_hidden)
@@ -107,7 +214,7 @@ class IBusWidgetScenariodTests(IBusTests):
if commit_key:
self.keyboard.press_and_release(commit_key)
self.deactivate_ibus(widget.searchbar)
- self.assertThat(widget.search_string, Eventually(Equals(self.result)))
+ self.assertThat(widget.search_string, Eventually(Equals(result)))
@@ -119,11 +226,11 @@ class IBusTestsPinyin(IBusWidgetScenariodTests):
scenarios = multiply_scenarios(
IBusWidgetScenariodTests.scenarios,
[
- ('basic', {'input': 'abc1', 'result': u'\u963f\u5e03\u4ece'}),
- ('photo', {'input': 'zhaopian ', 'result': u'\u7167\u7247'}),
- ('internet', {'input': 'hulianwang ', 'result': u'\u4e92\u8054\u7f51'}),
- ('disk', {'input': 'cipan ', 'result': u'\u78c1\u76d8'}),
- ('disk_management', {'input': 'cipan guanli ', 'result': u'\u78c1\u76d8\u7ba1\u7406'}),
+ ('basic', {'input': 'abc1'}),
+ ('photo', {'input': 'zhaopian '}),
+ ('internet', {'input': 'hulianwang '}),
+ ('disk', {'input': 'cipan '}),
+ ('disk_management', {'input': 'cipan guanli '}),
]
)
@@ -165,9 +272,9 @@ class IBusTestsAnthy(IBusWidgetScenariodTests):
scenarios = multiply_scenarios(
IBusWidgetScenariodTests.scenarios,
[
- ('system', {'input': 'shisutemu ', 'result': u'\u30b7\u30b9\u30c6\u30e0'}),
- ('game', {'input': 'ge-mu ', 'result': u'\u30b2\u30fc\u30e0'}),
- ('user', {'input': 'yu-za- ', 'result': u'\u30e6\u30fc\u30b6\u30fc'}),
+ ('system', {'input': 'shisutemu '}),
+ ('game', {'input': 'ge-mu '}),
+ ('user', {'input': 'yu-za- '}),
],
[
('commit_j', {'commit_key': 'Ctrl+j'}),
diff --git a/tests/autopilot/unity/tests/test_panel.py b/tests/autopilot/unity/tests/test_panel.py
index a8aeb1f98..94d53011b 100644
--- a/tests/autopilot/unity/tests/test_panel.py
+++ b/tests/autopilot/unity/tests/test_panel.py
@@ -295,8 +295,7 @@ class PanelWindowButtonsTests(PanelTestsBase):
self.unity.dash.ensure_visible()
self.addCleanup(self.unity.dash.ensure_hidden)
- self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(True)))
- self.assertWinButtonsInOverlayMode(True)
+ self.assertThat(self.unity.dash.view.overlay_window_buttons_shown, Eventually(Equals(True)))
def test_window_buttons_work_in_dash_after_launcher_resize(self):
"""When the launcher icons are resized, the window
@@ -319,14 +318,13 @@ class PanelWindowButtonsTests(PanelTestsBase):
self.unity.hud.ensure_visible()
self.addCleanup(self.unity.hud.ensure_hidden)
- self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(True)))
- self.assertWinButtonsInOverlayMode(True)
+ self.assertThat(self.unity.hud.view.overlay_window_buttons_shown, Eventually(Equals(True)))
def test_window_buttons_update_visual_state(self):
"""Window button must update its state in response to mouse events."""
- self.unity.hud.ensure_visible()
- self.addCleanup(self.unity.hud.ensure_hidden)
- button = self.panel.window_buttons.close
+ self.open_new_application_window("Text Editor", maximized=True, move_to_monitor=True)
+ self.panel.move_mouse_over_window_buttons()
+ button = self.panel.window_buttons.unmaximize
self.assertThat(button.visual_state, Eventually(Equals("normal")))
@@ -341,18 +339,17 @@ class PanelWindowButtonsTests(PanelTestsBase):
"""Window buttons must ignore clicks when the mouse released outside
their area.
"""
- self.unity.hud.ensure_visible()
- self.addCleanup(self.unity.hud.ensure_hidden)
+ win = self.open_new_application_window("Text Editor", maximized=True, move_to_monitor=True)
+ self.panel.move_mouse_over_window_buttons()
- button = self.panel.window_buttons.close
+ button = self.panel.window_buttons.unmaximize
button.mouse_move_to()
self.mouse.press()
self.assertThat(button.visual_state, Eventually(Equals("pressed")))
self.panel.move_mouse_below_the_panel()
self.mouse.release()
- self.assertThat(button.visual_state, Eventually(Equals("normal")))
- self.assertThat(self.unity.hud.visible, Eventually(Equals(True)))
+ self.assertThat(win.is_maximized, Equals(True))
def test_window_buttons_close_button_works_for_window(self):
"""Close window button must actually closes a window."""
@@ -959,6 +956,8 @@ class PanelIndicatorEntryTests(PanelTestsBase):
# This assert is for timing purposes only:
self.assertThat(menu_entry.active, Eventually(Equals(True)))
+ # Make sure we wait at least enough time that the menu appeared as well
+ sleep(self.panel.menus.fadein_duration / 1000.0)
self.mouse.click()
self.assertThat(menu_entry.active, Eventually(Equals(False)))
diff --git a/tests/autopilot/unity/tests/test_search.py b/tests/autopilot/unity/tests/test_search.py
new file mode 100644
index 000000000..dc97ab28e
--- /dev/null
+++ b/tests/autopilot/unity/tests/test_search.py
@@ -0,0 +1,176 @@
+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
+# Copyright 2013 Canonical
+# Author: Łukasz 'sil2100' Zemczak
+#
+# 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.
+
+from __future__ import absolute_import
+
+from autopilot.matchers import Eventually
+from testtools.matchers import (
+ Equals,
+ GreaterThan,
+ )
+
+from unity.tests import UnityTestCase
+
+import gettext
+
+class SearchTestsBase(UnityTestCase):
+ """Base class for testing searching in search fields.
+
+ Each deriving class should define the self.input_and_check_result()
+ method that takes 2 arguments: the input string and the expected
+ string. This method will be used during self.do_search_test(), which
+ should be called for every defined scenario of input and result.
+ """
+
+ def setUp(self):
+ super(SearchTestsBase, self).setUp()
+
+ def start_test_app(self):
+ """Start the window mocker for our search testing.
+
+ This method creates a windowmocker application with a custom name and
+ custom menu. We want it to have a locale-independent menu with a
+ more-or-less unique menu entry for HUD testing. Also, the name of
+ the application is rather unique too.
+ """
+ window_spec = {
+ "Title": "Test menu application",
+ "Menu": ["Search entry", "Quit"],
+ }
+ self.launch_test_window(window_spec)
+
+ def do_search_test(self):
+ """Use the input_and_check_result method for a given scenario.
+
+ This method uses the self.input_and_check_result() method which
+ needs to be defined for the given test sub-class. It uses the
+ self.input and self.result strings as defined by a scenario.
+ """
+ self.input_and_check_result(self.input, self.result)
+
+
+# Lens tests
+
+class ApplicationLensSearchTestBase(SearchTestsBase):
+ """Common class for all tests for searching in the application lens."""
+
+ def setUp(self):
+ super(ApplicationLensSearchTestBase, self).setUp()
+ self.app_lens = self.unity.dash.reveal_application_lens()
+ self.addCleanup(self.unity.dash.ensure_hidden)
+ gettext.install("unity-lens-applications", unicode=True)
+
+ def input_and_check_result(self, string, expected):
+ self.keyboard.type(string)
+ self.assertThat(self.unity.dash.search_string, Eventually(Equals(string)))
+ category = self.app_lens.get_category_by_name(_("Installed"))
+ refresh_results_fn = lambda: len(category.get_results())
+ self.assertThat(refresh_results_fn, Eventually(GreaterThan(0)))
+ results = category.get_results()
+ found = False
+ for r in results:
+ if r.name == expected:
+ found = True
+ break
+ self.assertTrue(found)
+
+
+class ApplicationLensSearchTests(ApplicationLensSearchTestBase):
+ """Simple search tests for the application lens."""
+
+ scenarios = [
+ ('basic', {'input': 'Window Mocker', 'result': 'Window Mocker'}),
+ ('lowercase', {'input': 'window mocker', 'result': 'Window Mocker'}),
+ ('uppercase', {'input': 'WINDOW MOCKER', 'result': 'Window Mocker'}),
+ ('partial', {'input': 'Window Mock', 'result': 'Window Mocker'}),
+ ('keyword', {'input': 'arithmetic', 'result': 'Calculator'}),
+ ]
+
+ def setUp(self):
+ super(ApplicationLensSearchTests, self).setUp()
+
+ def test_application_lens_search(self):
+ self.do_search_test()
+
+
+class ApplicationLensFuzzySearchTests(ApplicationLensSearchTestBase):
+ """Fuzzy, erroneous search tests for the application lens.
+ This checks if the application lens will find the searched application
+ (windowmocker here, since we want some app that has the name
+ locale-independent) when small spelling errors are made.
+ """
+
+ scenarios = [
+ ('transposition', {'input': 'Wnidow Mocker', 'result': 'Window Mocker'}),
+ ('duplication', {'input': 'Wiindow Mocker', 'result': 'Window Mocker'}),
+ ('insertion', {'input': 'Wiondow Mocker', 'result': 'Window Mocker'}),
+ ('deletion', {'input': 'Wndow Mocker', 'result': 'Window Mocker'}),
+ ]
+
+ def setUp(self):
+ super(ApplicationLensFuzzySearchTests, self).setUp()
+
+ def test_application_lens_fuzzy_search(self):
+ self.do_search_test()
+
+
+
+# HUD tests
+
+class HudSearchTestBase(SearchTestsBase):
+ """Common class for all tests for searching in the HUD."""
+
+ def setUp(self):
+ super(HudSearchTestBase, self).setUp()
+ self.start_test_app()
+ self.unity.hud.ensure_visible()
+ self.addCleanup(self.unity.hud.ensure_hidden);
+
+ def input_and_check_result(self, string, expected):
+ self.keyboard.type(string)
+ self.assertThat(self.unity.hud.search_string, Eventually(Equals(string)))
+ hud_query_check = lambda: self.unity.hud.selected_hud_button.label_no_formatting
+ self.assertThat(hud_query_check, Eventually(Equals(expected)))
+
+
+class HudSearchTests(HudSearchTestBase):
+ """Simple search tests for the HUD."""
+
+ scenarios = [
+ ('basic', {'input': 'Search entry', 'result': 'Search entry'}),
+ ('lowercase', {'input': 'search entry', 'result': 'Search entry'}),
+ ('uppercase', {'input': 'SEARCH ENTRY', 'result': 'Search entry'}),
+ ('partial', {'input': 'Search ', 'result': 'Search entry'}),
+ ]
+
+ def setUp(self):
+ super(HudSearchTests, self).setUp()
+
+ def test_hud_search(self):
+ self.do_search_test()
+
+
+class HudFuzzySearchTests(HudSearchTestBase):
+ """Fuzzy, erroneous search tests for the HUD.
+ This checks if the HUD will find the searched menu entry from our application
+ (windowmocker here, since we want to have unique, locale-independent menu
+ entries) when small spelling errors are made.
+ """
+
+ scenarios = [
+ ('transposition', {'input': 'Saerch entry', 'result': 'Search entry'}),
+ ('duplication', {'input': 'Seearch entry', 'result': 'Search entry'}),
+ ('insertion', {'input': 'Seasrch entry ', 'result': 'Search entry'}),
+ ('deletion', {'input': 'Serch entry', 'result': 'Search entry'}),
+ ]
+
+ def setUp(self):
+ super(HudFuzzySearchTests, self).setUp()
+
+ def test_hud_fuzzy_search(self):
+ self.do_search_test()
diff --git a/tests/test-input-remover/test-input-remover.cpp b/tests/test-input-remover/test-input-remover.cpp
index 3a3768c7c..79381b0e0 100644
--- a/tests/test-input-remover/test-input-remover.cpp
+++ b/tests/test-input-remover/test-input-remover.cpp
@@ -145,7 +145,7 @@ int main (int argc, char **argv)
if (argc == 3)
std::stringstream (argv[2]) >> std::dec >> time;
- remover = new compiz::WindowInputRemover (dpy, xid);
+ remover = new compiz::WindowInputRemover (dpy, xid, xid);
if (!remover)
return 1;
diff --git a/tests/test-minimize-window-handler/test-minimize-handler.cpp b/tests/test-minimize-window-handler/test-minimize-handler.cpp
index e73dbc225..fb6133f6e 100644
--- a/tests/test-minimize-window-handler/test-minimize-handler.cpp
+++ b/tests/test-minimize-window-handler/test-minimize-handler.cpp
@@ -22,6 +22,7 @@
#define _GNU_SOURCE
#endif
+#include <memory>
#include <minimizedwindowhandler.h>
#include <cstdio>
#include <cstdlib>
@@ -63,7 +64,9 @@ X11WindowFakeMinimizable::GetInputRemover ()
if (!input_remover_.expired ())
return input_remover_.lock ();
- compiz::WindowInputRemoverLock::Ptr ret (new compiz::WindowInputRemoverLock (new compiz::WindowInputRemover (mDpy, mXid)));
+ compiz::WindowInputRemoverLock::Ptr ret (
+ new compiz::WindowInputRemoverLock (
+ new compiz::WindowInputRemover (mDpy, mXid, mXid)));
input_remover_ = ret;
return ret;
}
@@ -116,9 +119,9 @@ int main (int argc, char **argv)
{
Display *dpy;
Window xid = 0;
- X11WindowFakeMinimizable *window;
- X11WindowFakeMinimizable *transient = NULL;
- X11WindowFakeMinimizable *hasClientLeader = NULL;
+ std::unique_ptr <X11WindowFakeMinimizable> window;
+ std::unique_ptr <X11WindowFakeMinimizable> transient;
+ std::unique_ptr <X11WindowFakeMinimizable> hasClientLeader;
std::string option = "";
bool shapeExt;
int shapeEvent;
@@ -151,16 +154,16 @@ int main (int argc, char **argv)
if (argc > 1)
std::stringstream (argv[1]) >> std::hex >> xid;
- window = new X11WindowFakeMinimizable (dpy, xid);
+ window.reset (new X11WindowFakeMinimizable (dpy, xid));
if (!xid)
{
- transient = new X11WindowFakeMinimizable (dpy, 0);
- hasClientLeader = new X11WindowFakeMinimizable (dpy, 0);
+ transient.reset (new X11WindowFakeMinimizable (dpy, 0));
+ hasClientLeader.reset (new X11WindowFakeMinimizable (dpy, 0));
- transient->makeTransientFor (window);
- window->setClientLeader (window);
- hasClientLeader->setClientLeader (window);
+ transient->makeTransientFor (window.get ());
+ window->setClientLeader (window.get ());
+ hasClientLeader->setClientLeader (window.get ());
}
std::cout << "[m]inimize [u]nminimize [q]uit?" << std::endl;
@@ -213,8 +216,6 @@ int main (int argc, char **argv)
} while (!terminate);
- delete window;
-
XCloseDisplay (dpy);
return 0;
diff --git a/tests/test_application_launcher_icon.cpp b/tests/test_application_launcher_icon.cpp
index b44382507..2a6401e02 100644
--- a/tests/test_application_launcher_icon.cpp
+++ b/tests/test_application_launcher_icon.cpp
@@ -108,25 +108,40 @@ TEST_F(TestApplicationLauncherIcon, Stick)
TEST_F(TestApplicationLauncherIcon, StickAndSave)
{
bool saved = false;
- usc_icon->position_saved.connect([&saved] {saved = true;});
+ mock_icon->position_saved.connect([&saved] {saved = true;});
- usc_icon->Stick(true);
- EXPECT_TRUE(usc_app->sticky());
- EXPECT_TRUE(usc_icon->IsSticky());
- EXPECT_TRUE(usc_icon->IsVisible());
+ mock_icon->Stick(true);
+ EXPECT_TRUE(mock_app->sticky());
+ EXPECT_TRUE(mock_icon->IsSticky());
+ EXPECT_TRUE(mock_icon->IsVisible());
EXPECT_TRUE(saved);
}
-TEST_F(TestApplicationLauncherIcon, Unstick)
+TEST_F(TestApplicationLauncherIcon, UnstickNotRunning)
{
bool forgot = false;
- usc_icon->position_forgot.connect([&forgot] {forgot = true;});
+ mock_app->running_ = false;
+ mock_icon->position_forgot.connect([&forgot] {forgot = true;});
+
+ mock_icon->Stick();
+ mock_icon->UnStick();
+ EXPECT_FALSE(mock_app->sticky());
+ EXPECT_FALSE(mock_icon->IsSticky());
+ EXPECT_FALSE(mock_icon->IsVisible());
+ EXPECT_TRUE(forgot);
+}
- usc_icon->Stick(false);
- usc_icon->UnStick();
- EXPECT_FALSE(usc_app->sticky());
- EXPECT_FALSE(usc_icon->IsSticky());
- EXPECT_FALSE(usc_icon->IsVisible());
+TEST_F(TestApplicationLauncherIcon, UnstickRunning)
+{
+ bool forgot = false;
+ mock_app->running_ = true;
+ mock_icon->position_forgot.connect([&forgot] {forgot = true;});
+
+ mock_icon->Stick();
+ mock_icon->UnStick();
+ EXPECT_FALSE(mock_app->sticky());
+ EXPECT_FALSE(mock_icon->IsSticky());
+ EXPECT_TRUE(mock_icon->IsVisible());
EXPECT_TRUE(forgot);
}
diff --git a/tests/test_categories.cpp b/tests/test_categories.cpp
index e43a56e32..2353537ed 100644
--- a/tests/test_categories.cpp
+++ b/tests/test_categories.cpp
@@ -17,7 +17,7 @@ static const unsigned int n_rows = 5;
static void WaitForSynchronize(Categories& model)
{
- ::Utils::WaitForModelSynchronize<Category>(model, n_rows);
+ Utils::WaitUntil([&model] { return model.count == n_rows; });
}
TEST(TestCategories, TestConstruction)
diff --git a/tests/test_edge_barrier_controller.cpp b/tests/test_edge_barrier_controller.cpp
index c1b92971a..b3de41c82 100644
--- a/tests/test_edge_barrier_controller.cpp
+++ b/tests/test_edge_barrier_controller.cpp
@@ -342,4 +342,29 @@ TEST_F(TestEdgeBarrierController, TestTheDirectionIsAlawysSetToBothSides)
ASSERT_EQ(barrier->direction, BarrierDirection::BOTH);
}
+TEST_F(TestEdgeBarrierController, BarrierDoesNotBreakIfYEventToFarApart)
+{
+ MockPointerBarrier owner;
+
+ int velocity = bc.options()->edge_overcome_pressure() * bc.options()->edge_responsiveness();
+ auto firstEvent = std::make_shared<BarrierEvent>(0, 50, velocity, 10);
+ auto secondEvent = std::make_shared<BarrierEvent>(0, 150, velocity, 11);
+
+ EXPECT_CALL(owner, ReleaseBarrier(_)).Times(0);
+ ProcessBarrierEvent(&owner, firstEvent);
+ ProcessBarrierEvent(&owner, secondEvent);
+}
+
+TEST_F(TestEdgeBarrierController, BarrierBreaksInYBreakZone)
+{
+ MockPointerBarrier owner;
+
+ int velocity = bc.options()->edge_overcome_pressure() * bc.options()->edge_responsiveness();
+ auto firstEvent = std::make_shared<BarrierEvent>(0, 50, velocity, 10);
+
+ EXPECT_CALL(owner, ReleaseBarrier(_)).Times(1);
+ ProcessBarrierEvent(&owner, firstEvent);
+ ProcessBarrierEvent(&owner, firstEvent);
+}
+
}
diff --git a/tests/test_expo_launcher_icon.cpp b/tests/test_expo_launcher_icon.cpp
index 81a3dd31c..b5a479750 100644
--- a/tests/test_expo_launcher_icon.cpp
+++ b/tests/test_expo_launcher_icon.cpp
@@ -71,14 +71,14 @@ TEST_F(TestExpoLauncherIcon, Icon2x2Layout)
wm->SetCurrentViewport(nux::Point(0, 1));
wm->screen_viewport_switch_ended.emit();
EXPECT_EQ(icon.icon_name, "workspace-switcher-left-bottom");
-
+
wm->SetCurrentViewport(nux::Point(1, 1));
wm->screen_viewport_switch_ended.emit();
EXPECT_EQ(icon.icon_name, "workspace-switcher-right-bottom");
wm->SetCurrentViewport(nux::Point(0, 0));
wm->screen_viewport_switch_ended.emit();
- EXPECT_EQ(icon.icon_name, "workspace-switcher-top-left");
+ EXPECT_EQ(icon.icon_name, "workspace-switcher-top-left");
}
TEST_F(TestExpoLauncherIcon, Icon2x2Layout_Expo)
@@ -92,14 +92,14 @@ TEST_F(TestExpoLauncherIcon, Icon2x2Layout_Expo)
wm->SetCurrentViewport(nux::Point(0, 1));
wm->terminate_expo.emit();
EXPECT_EQ(icon.icon_name, "workspace-switcher-left-bottom");
-
+
wm->SetCurrentViewport(nux::Point(1, 1));
wm->terminate_expo.emit();
EXPECT_EQ(icon.icon_name, "workspace-switcher-right-bottom");
wm->SetCurrentViewport(nux::Point(0, 0));
wm->terminate_expo.emit();
- EXPECT_EQ(icon.icon_name, "workspace-switcher-top-left");
+ EXPECT_EQ(icon.icon_name, "workspace-switcher-top-left");
}
TEST_F(TestExpoLauncherIcon, IconNot2x2Layout)
@@ -116,4 +116,13 @@ TEST_F(TestExpoLauncherIcon, IconNot2x2Layout)
EXPECT_EQ(icon.icon_name, "workspace-switcher-top-left");
}
+TEST_F(TestExpoLauncherIcon, AboutToRemoveDisablesViewport)
+{
+ wm->SetViewportSize(2, 2);
+
+ icon.AboutToRemove();
+ EXPECT_EQ(wm->GetViewportHSize(), 1);
+ EXPECT_EQ(wm->GetViewportVSize(), 1);
+}
+
}
diff --git a/tests/test_filesystem_lenses.cpp b/tests/test_filesystem_lenses.cpp
index 5a8af9f70..492f3fb31 100644
--- a/tests/test_filesystem_lenses.cpp
+++ b/tests/test_filesystem_lenses.cpp
@@ -1,7 +1,8 @@
#include "config.h"
+
#include <gtest/gtest.h>
-#include <glib-object.h>
#include <UnityCore/FilesystemLenses.h>
+#include "test_utils.h"
using namespace std;
using namespace unity::dash;
@@ -9,52 +10,34 @@ using namespace unity::dash;
namespace
{
-void WaitForResult(bool& result)
-{
- bool timeout_reached;
-
- auto timeout_cb = [](gpointer data) -> gboolean
- {
- *(bool*)data = true;
- return FALSE;
- };
-
- guint32 timeout_id = g_timeout_add(10000, timeout_cb, &timeout_reached);
-
- while (!result && !timeout_reached)
- {
- g_main_context_iteration(g_main_context_get_thread_default(), TRUE);
- }
- if (result)
- g_source_remove(timeout_id);
-}
+const std::string TEST_LENSES_DIR = BUILDDIR"/tests/data/lenses";
void WaitForLensesToLoad(FilesystemLenses& lenses)
{
bool result = false;
lenses.lenses_loaded.connect([&result] {result = true;});
- WaitForResult(result);
+ Utils::WaitUntil(result);
EXPECT_TRUE(result);
}
TEST(TestFilesystemLenses, TestConstruction)
{
FilesystemLenses lenses0;
- LensDirectoryReader::Ptr test_reader(new LensDirectoryReader(TESTDATADIR"/lenses"));
+ LensDirectoryReader::Ptr test_reader(new LensDirectoryReader(TEST_LENSES_DIR));
FilesystemLenses lenses1(test_reader);
}
TEST(TestFilesystemLenses, TestFileLoading)
{
- LensDirectoryReader::Ptr test_reader(new LensDirectoryReader(TESTDATADIR"/lenses"));
+ LensDirectoryReader::Ptr test_reader(new LensDirectoryReader(TEST_LENSES_DIR));
FilesystemLenses lenses(test_reader);
WaitForLensesToLoad(lenses);
}
TEST(TestFilesystemLenses, TestLensesAdded)
{
- LensDirectoryReader::Ptr test_reader(new LensDirectoryReader(TESTDATADIR"/lenses"));
+ LensDirectoryReader::Ptr test_reader(new LensDirectoryReader(TEST_LENSES_DIR));
FilesystemLenses lenses(test_reader);
unsigned int n_lenses = 0;
lenses.lens_added.connect([&n_lenses](Lens::Ptr & p) { ++n_lenses; });
@@ -66,7 +49,7 @@ TEST(TestFilesystemLenses, TestLensesAdded)
TEST(TestFilesystemLenses, TestLensContent)
{
- LensDirectoryReader::Ptr test_reader(new LensDirectoryReader(TESTDATADIR"/lenses"));
+ LensDirectoryReader::Ptr test_reader(new LensDirectoryReader(TEST_LENSES_DIR));
FilesystemLenses lenses(test_reader);
WaitForLensesToLoad(lenses);
diff --git a/tests/test_filter_multirange.h b/tests/test_filter_multirange.h
new file mode 100644
index 000000000..94bf2de0d
--- /dev/null
+++ b/tests/test_filter_multirange.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 3, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the applicable version of the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of both the GNU Lesser General Public
+ * License version 3 along with this program. If not, see
+ * <http://www.gnu.org/licenses/>
+ *
+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
+ *
+ */
+
+#ifndef TEST_FILTER
+#define TEST_FILTER
+
+#include <glib-object.h>
+#include <gtest/gtest.h>
+
+#include "UnityCore/MultiRangeFilter.h"
+
+namespace unity
+{
+namespace testing
+{
+
+GVariantBuilder* AddFilterHint(GVariantBuilder* builder, const char* name, GVariant* value)
+{
+ if (builder == NULL)
+ builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_add (builder, "{sv}", name, value);
+ return builder;
+}
+
+GVariant* AddFilterOptions(std::vector<bool> option_active)
+{
+ GVariantBuilder* builder;
+ builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+
+ int i = 0;
+ for (auto iter = option_active.begin(), end = option_active.end(); iter != end; ++iter)
+ {
+ std::stringstream name;
+ name << i++;
+
+ const char* pstr_name = name.str().c_str();
+
+ g_variant_builder_add (builder, "(sssb)", pstr_name, pstr_name, "", FALSE);
+ }
+ return g_variant_builder_end (builder);
+}
+
+void ExpectFilterRange(unity::dash::MultiRangeFilter::Ptr const& filter, int first, int last)
+{
+ int i = 0;
+ for (auto option : filter->options())
+ {
+ bool should_be_active = i >= first && i <= last;
+ EXPECT_EQ(option->active, should_be_active);
+ i++;
+ }
+}
+
+} // namespace testing
+} // namespace unity
+
+#endif \ No newline at end of file
diff --git a/tests/test_filter_widgets.cpp b/tests/test_filter_widgets.cpp
new file mode 100644
index 000000000..7b33b6bc8
--- /dev/null
+++ b/tests/test_filter_widgets.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 3, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the applicable version of the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of both the GNU Lesser General Public
+ * License version 3 along with this program. If not, see
+ * <http://www.gnu.org/licenses/>
+ *
+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
+ *
+ */
+
+#include <list>
+
+#include <gtest/gtest.h>
+#include "test_filter_multirange.h"
+#include "unity-shared/DashStyle.h"
+#include "unity-shared/UnitySettings.h"
+
+#include <Nux/Nux.h>
+#include <NuxGraphics/Events.h>
+#include <NuxCore/ObjectPtr.h>
+
+#include <UnityCore/GLibWrapper.h>
+#include "UnityCore/MultiRangeFilter.h"
+#include "dash/FilterMultiRangeWidget.h"
+#include "dash/FilterMultiRangeButton.h"
+
+using namespace unity;
+
+namespace unity
+{
+namespace dash
+{
+
+class TestFilterMultiRangeWidget : public ::testing::Test
+{
+public:
+ TestFilterMultiRangeWidget()
+ : model_(dee_sequence_model_new())
+ , filter_widget_(new MockFilterMultiRangeWidget())
+ {
+ dee_model_set_schema(model_, "s", "s", "s", "s", "a{sv}", "b", "b", "b", NULL);
+ }
+
+ void SetFilter(MultiRangeFilter::Ptr const& filter)
+ {
+ filter_widget_->SetFilter(filter);
+
+ filter_widget_->ComputeContentSize();
+ filter_widget_->ComputeContentPosition(0,0);
+ }
+
+ class MockFilterMultiRangeWidget : public FilterMultiRangeWidget
+ {
+ public:
+ MockFilterMultiRangeWidget()
+ : clicked_(false)
+ {
+ }
+
+ void ResetState()
+ {
+ clicked_ = false;
+ }
+
+ bool clicked_;
+
+ using FilterMultiRangeWidget::all_button_;
+ using FilterMultiRangeWidget::buttons_;
+ using FilterMultiRangeWidget::dragging_;
+
+ using InputArea::EmitMouseDownSignal;
+ using InputArea::EmitMouseUpSignal;
+ using InputArea::EmitMouseDragSignal;
+
+ using FilterMultiRangeWidget::mouse_down_button_;
+
+ protected:
+
+ virtual void Click(FilterMultiRangeButtonPtr const& button)
+ {
+ clicked_ = true;
+ FilterMultiRangeWidget::Click(button);
+ }
+ };
+
+
+ static DeeModelIter* AddMultiRangeFilterOptions(glib::Object<DeeModel> const& model)
+ {
+ std::vector<bool> option_active(6, false);
+ GVariantBuilder* builder = nullptr;
+ builder = unity::testing::AddFilterHint(builder, "options", unity::testing::AddFilterOptions(option_active));
+ GVariant* hints = g_variant_builder_end(builder);
+
+ return dee_model_append(model,
+ "genre",
+ "Genre",
+ "gtk-apply",
+ "genre",
+ hints,
+ TRUE,
+ FALSE, // collapsed
+ FALSE);
+ }
+
+ Settings unity_settings_;
+ dash::Style dash_style_;
+
+ glib::Object<DeeModel> model_;
+ nux::ObjectPtr<MockFilterMultiRangeWidget> filter_widget_;
+};
+
+TEST_F(TestFilterMultiRangeWidget, TestConstruction)
+{
+ MultiRangeFilter::Ptr filter(new MultiRangeFilter(model_, AddMultiRangeFilterOptions(model_)));
+ SetFilter(filter);
+
+ ASSERT_EQ(filter_widget_->buttons_.size(), 6);
+}
+
+TEST_F(TestFilterMultiRangeWidget, TestClick)
+{
+ MultiRangeFilter::Ptr filter(new MultiRangeFilter(model_, AddMultiRangeFilterOptions(model_)));
+ SetFilter(filter);
+
+ FilterMultiRangeWidget::FilterMultiRangeButtonPtr filter_button = filter_widget_->buttons_[1];
+ nux::Geometry geo_button = filter_button->GetAbsoluteGeometry();
+ nux::Point center_button1(geo_button.x + geo_button.width/2, geo_button.y + geo_button.height/2);
+
+ filter_widget_->EmitMouseDownSignal(center_button1.x, center_button1.y, NUX_STATE_BUTTON1_DOWN|NUX_EVENT_BUTTON1_DOWN, 0);
+ ASSERT_NE(filter_widget_->mouse_down_button_, nullptr);
+
+ filter_widget_->EmitMouseUpSignal(center_button1.y, center_button1.y, NUX_EVENT_BUTTON1_UP, 0);
+ ASSERT_EQ(filter_widget_->mouse_down_button_, nullptr);
+
+ EXPECT_EQ(filter_widget_->clicked_, true);
+ EXPECT_EQ(filter_button->Active(), true);
+ EXPECT_EQ(filter->options()[1]->active, true);
+}
+
+TEST_F(TestFilterMultiRangeWidget, TestDrag)
+{
+ MultiRangeFilter::Ptr filter(new MultiRangeFilter(model_, AddMultiRangeFilterOptions(model_)));
+ SetFilter(filter);
+
+ // Genre "1"
+ FilterMultiRangeWidget::FilterMultiRangeButtonPtr filter_button1 = filter_widget_->buttons_[1];
+ nux::Geometry geo_button1 = filter_button1->GetAbsoluteGeometry();
+ nux::Point center_button1(geo_button1.x + geo_button1.width/2, geo_button1.y + geo_button1.height/2);
+
+ // Genre "3"
+ FilterMultiRangeWidget::FilterMultiRangeButtonPtr filter_button3 = filter_widget_->buttons_[3];
+ nux::Geometry geo_button3 = filter_button3->GetAbsoluteGeometry();
+ nux::Point center_button3(geo_button3.x + geo_button3.width/2, geo_button3.y + geo_button3.height/2);
+
+ // Genre "4"
+ FilterMultiRangeWidget::FilterMultiRangeButtonPtr filter_button4 = filter_widget_->buttons_[4];
+ nux::Geometry geo_button4 = filter_button4->GetAbsoluteGeometry();
+ nux::Point center_button4(geo_button4.x + geo_button4.width/2, geo_button4.y + geo_button4.height/2);
+
+ filter_widget_->EmitMouseDownSignal(center_button1.x, center_button1.y, NUX_STATE_BUTTON1_DOWN|NUX_EVENT_BUTTON1_DOWN, 0);
+
+ filter_widget_->EmitMouseDragSignal(center_button4.x, center_button4.y, center_button4.x - center_button1.x, center_button4.y - center_button1.y, NUX_STATE_BUTTON1_DOWN, 0);
+ EXPECT_EQ(filter_widget_->dragging_, true);
+ unity::testing::ExpectFilterRange(filter, 1, 4);
+
+
+ // filter_widget_->EmitMouseDragSignal(center_button3.x, center_button3.y, center_button4.x - center_button3.x, center_button4.y - center_button3.y, NUX_STATE_BUTTON1_DOWN, 0);
+ // unity::testing::ExpectFilterRange(filter, 1, 3);
+
+ // filter_widget_->EmitMouseUpSignal(center_button3.x, center_button3.y, NUX_EVENT_BUTTON1_UP, 0);
+ // EXPECT_EQ(filter_widget_->dragging_, false);
+ // unity::testing::ExpectFilterRange(filter, 1, 3);
+}
+
+} // namespace dash
+} // namespace unity
diff --git a/tests/test_gdbus_proxy.cpp b/tests/test_gdbus_proxy.cpp
index 3e46913c3..dc7018a8e 100644
--- a/tests/test_gdbus_proxy.cpp
+++ b/tests/test_gdbus_proxy.cpp
@@ -46,7 +46,7 @@ public:
TEST_F(TestGDBusProxy, TestConstruction)
{
EXPECT_FALSE(proxy.IsConnected());
- Utils::WaitUntil(sigc::mem_fun(proxy, &glib::DBusProxy::IsConnected));
+ Utils::WaitUntil(sigc::mem_fun(proxy, &glib::DBusProxy::IsConnected), 2);
EXPECT_TRUE(proxy.IsConnected());
}
@@ -86,8 +86,8 @@ TEST_F(TestGDBusProxy, TestMethodReturn)
proxy.Connect("TestSignal", signal_connection);
proxy.Call("TestMethod", parameters, method_connection);
- Utils::WaitUntil(got_result_return);
- Utils::WaitUntil(got_signal_return);
+ Utils::WaitUntil(got_result_return, 2);
+ Utils::WaitUntil(got_signal_return, 2);
EXPECT_EQ(returned_result, expected_return);
EXPECT_EQ(returned_signal, expected_return);
@@ -141,7 +141,7 @@ TEST_F(TestGDBusProxy, TestAcquiring)
method_connection, nullptr);
Utils::WaitForTimeoutMSec(150);
}
- Utils::WaitUntil(got_result_return);
+ Utils::WaitUntil(got_result_return, 2);
}
TEST_F(TestGDBusProxyInvalidService, TestTimeouting)
@@ -166,7 +166,7 @@ TEST_F(TestGDBusProxyInvalidService, TestTimeouting)
// be acquired (with a dbus error)
g_usleep(110000);
- Utils::WaitUntil(got_result_return);
+ Utils::WaitUntil(got_result_return, 2);
EXPECT_EQ(call_return, "");
}
@@ -189,7 +189,7 @@ TEST_F(TestGDBusProxy, TestMethodCall)
proxy.Call("TestMethod", g_variant_new("(s)", "TestStringTestString"),
method_connection);
- Utils::WaitUntil(got_result_return);
+ Utils::WaitUntil(got_result_return, 2);
EXPECT_TRUE(proxy.IsConnected());
EXPECT_EQ("TestStringTestString", call_return);
diff --git a/tests/test_glib_dbus_object.cpp b/tests/test_glib_dbus_object.cpp
new file mode 100644
index 000000000..a6fe3b5c4
--- /dev/null
+++ b/tests/test_glib_dbus_object.cpp
@@ -0,0 +1,135 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com>
+ */
+
+#include <gmock/gmock.h>
+#include <UnityCore/GLibDBusServer.h>
+
+using namespace unity::glib;
+
+namespace
+{
+
+namespace introspection
+{
+const std::string SINGLE_OJBECT =
+R"(<node>
+ <interface name="com.canonical.Unity.ObjectTest">
+ <method name="Foo">
+ <arg type="i" name="type" direction="in"/>
+ </method>
+ <method name="Bar">
+ <arg type="i" name="type" direction="out"/>
+ </method>
+ <signal name="SignalWithNoParameters" />
+ <signal name="SignalWithParameter">
+ <arg type="i" name="arg" />
+ </signal>
+ <property name="ReadOnlyProperty" type="i" access="read"/>
+ <property name="WriteOnlyProperty" type="i" access="write"/>
+ <property name="ReadWriteProperty" type="i" access="readwrite"/>
+ </interface>
+</node>
+)";
+
+const std::string MULTIPLE_OJBECTS =
+R"(<node>
+ <interface name="com.canonical.Unity.ObjectTest1">
+ <method name="Test1" />
+ </interface>
+ <interface name="com.canonical.Unity.ObjectTest2">
+ <method name="Test2" />
+ </interface>
+ <interface name="com.canonical.Unity.ObjectTest3">
+ <method name="Test3" />
+ </interface>
+</node>)";
+
+const std::string INVALID_SYNTAX =
+R"(<node>
+ <interface name="com.canonical.Unity.ObjectTest">
+ <method name="Foo">
+)";
+}
+
+TEST(TestGLibDBusObject, InitializeWithOneValidObject)
+{
+ DBusObject object(introspection::SINGLE_OJBECT, "com.canonical.Unity.ObjectTest");
+ EXPECT_EQ(object.InterfaceName(), "com.canonical.Unity.ObjectTest");
+}
+
+TEST(TestGLibDBusObject, InitializeWithOneInvalidObject)
+{
+ DBusObject object(introspection::SINGLE_OJBECT, "foo.invalid");
+ EXPECT_TRUE(object.InterfaceName().empty());
+}
+
+TEST(TestGLibDBusObject, InitializeWithInvalidSyntax)
+{
+ DBusObject object(introspection::INVALID_SYNTAX, "com.canonical.Unity.ObjectTest");
+ EXPECT_TRUE(object.InterfaceName().empty());
+}
+
+TEST(TestGLibDBusObject, InitializeWithMultipleObjects)
+{
+ DBusObject obj1(introspection::MULTIPLE_OJBECTS, "com.canonical.Unity.ObjectTest1");
+ EXPECT_EQ(obj1.InterfaceName(), "com.canonical.Unity.ObjectTest1");
+
+ DBusObject obj2(introspection::MULTIPLE_OJBECTS, "com.canonical.Unity.ObjectTest2");
+ EXPECT_EQ(obj2.InterfaceName(), "com.canonical.Unity.ObjectTest2");
+
+ DBusObject obj3(introspection::MULTIPLE_OJBECTS, "com.canonical.Unity.ObjectTest3");
+ EXPECT_EQ(obj3.InterfaceName(), "com.canonical.Unity.ObjectTest3");
+
+ DBusObject obj4(introspection::MULTIPLE_OJBECTS, "com.canonical.Unity.ObjectTest4");
+ EXPECT_TRUE(obj4.InterfaceName().empty());
+}
+
+TEST(TestGLibDBusObject, InitializeWithNoObject)
+{
+ DBusObject object("", "com.canonical.Unity.ObjectTest");
+ EXPECT_TRUE(object.InterfaceName().empty());
+}
+
+
+// Builder
+
+TEST(TestGLibDBusObjectBuilder, GetObjectsForIntrospectionWithOneObject)
+{
+ auto const& objs = DBusObjectBuilder::GetObjectsForIntrospection(introspection::SINGLE_OJBECT);
+ ASSERT_EQ(objs.size(), 1);
+ EXPECT_EQ(objs.front()->InterfaceName(), "com.canonical.Unity.ObjectTest");
+}
+
+TEST(TestGLibDBusObjectBuilder, GetObjectsForIntrospectionWithMultipleObjects)
+{
+ auto const& objs = DBusObjectBuilder::GetObjectsForIntrospection(introspection::MULTIPLE_OJBECTS);
+ ASSERT_EQ(objs.size(), 3);
+ EXPECT_EQ((*std::next(objs.begin(), 0))->InterfaceName(), "com.canonical.Unity.ObjectTest1");
+ EXPECT_EQ((*std::next(objs.begin(), 1))->InterfaceName(), "com.canonical.Unity.ObjectTest2");
+ EXPECT_EQ((*std::next(objs.begin(), 2))->InterfaceName(), "com.canonical.Unity.ObjectTest3");
+}
+
+TEST(TestGLibDBusObjectBuilder, GetObjectsForIntrospectionWithInvalidObject)
+{
+ auto const& objs = DBusObjectBuilder::GetObjectsForIntrospection(introspection::INVALID_SYNTAX);
+ EXPECT_TRUE(objs.empty());
+}
+
+
+} // Namespace
diff --git a/tests/test_glib_dbus_server.cpp b/tests/test_glib_dbus_server.cpp
new file mode 100644
index 000000000..5d5810481
--- /dev/null
+++ b/tests/test_glib_dbus_server.cpp
@@ -0,0 +1,428 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com>
+ */
+
+#include <gmock/gmock.h>
+#include "test_utils.h"
+#include <UnityCore/GLibDBusServer.h>
+#include <UnityCore/GLibDBusProxy.h>
+#include <UnityCore/Variant.h>
+
+using namespace unity::glib;
+
+namespace
+{
+
+const std::string DBUS_TEST_NAME = "com.canonical.Unity.Test.Server.Name";
+const std::string OBJECT_INTERFACE = "com.canonical.Unity.ObjectTest";
+const std::string TEST_OBJECT_PATH = "/com/canonical/Unity/Test/Object";
+
+namespace introspection
+{
+const std::string SINGLE_OJBECT =
+R"(<node>
+ <interface name="com.canonical.Unity.ObjectTest">
+ <method name="VoidMethod" />
+ <method name="MethodWithParameters">
+ <arg type="i" name="arg_int" direction="in"/>
+ <arg type="s" name="arg_string" direction="in"/>
+ <arg type="u" name="arg_uint" direction="in"/>
+ </method>
+ <method name="MethodWithReturnValue">
+ <arg type="u" name="reply" direction="out"/>
+ </method>
+ <method name="MethodWithParametersAndReturnValue">
+ <arg type="s" name="query" direction="in"/>
+ <arg type="s" name="reply" direction="out"/>
+ </method>
+ <signal name="SignalWithNoParameters" />
+ <signal name="SignalWithParameter">
+ <arg type="s" name="arg" />
+ </signal>
+ <property name="ReadOnlyProperty" type="i" access="read"/>
+ <property name="WriteOnlyProperty" type="i" access="write"/>
+ <property name="ReadWriteProperty" type="i" access="readwrite"/>
+ </interface>
+</node>)";
+
+const std::string MULTIPLE_OJBECTS =
+R"(<node>
+ <interface name="com.canonical.Unity.ObjectTest1">
+ <method name="Test1" />
+ </interface>
+ <interface name="com.canonical.Unity.ObjectTest2">
+ <method name="Test2" />
+ </interface>
+ <interface name="com.canonical.Unity.ObjectTest3">
+ <method name="Test3" />
+ </interface>
+</node>)";
+
+}
+
+TEST(TestGLibDBusServerUnnamed, Connects)
+{
+ bool connected = false;
+ DBusServer server;
+ server.connected.connect([&connected] { connected = true; });
+ Utils::WaitUntilMSec(connected);
+
+ EXPECT_TRUE(connected);
+ EXPECT_TRUE(server.IsConnected());
+ EXPECT_TRUE(server.Name().empty());
+ EXPECT_FALSE(server.OwnsName());
+
+ Utils::WaitForTimeoutMSec(50);
+ EXPECT_TRUE(server.IsConnected());
+}
+
+TEST(TestGLibDBusServerUnnamed, AddsObjectWhenConnected)
+{
+ bool object_registered = false;
+
+ DBusServer server;
+ auto object = std::make_shared<DBusObject>(introspection::SINGLE_OJBECT, OBJECT_INTERFACE);
+
+ object->registered.connect([&object_registered] (std::string const& path) {
+ EXPECT_EQ(path, TEST_OBJECT_PATH);
+ object_registered = true;
+ });
+
+ server.AddObject(object, TEST_OBJECT_PATH);
+ ASSERT_EQ(server.GetObject(OBJECT_INTERFACE), object);
+ ASSERT_EQ(server.GetObjects().front(), object);
+
+ Utils::WaitUntilMSec([&server] { return server.IsConnected(); });
+
+ ASSERT_EQ(server.GetObjects().front(), object);
+ EXPECT_TRUE(object_registered);
+}
+
+struct TestGLibDBusServer : testing::Test
+{
+ TestGLibDBusServer()
+ : server(DBUS_TEST_NAME)
+ {}
+
+ void TearDown()
+ {
+ // We check that the connection is still active
+ Utils::WaitForTimeoutMSec(50);
+ EXPECT_TRUE(server.OwnsName());
+ }
+
+ DBusServer server;
+};
+
+TEST_F(TestGLibDBusServer, Connects)
+{
+ bool connected = false;
+ server.connected.connect([&connected] { connected = true; });
+ Utils::WaitUntilMSec(connected);
+
+ EXPECT_TRUE(connected);
+ EXPECT_TRUE(server.OwnsName());
+ EXPECT_TRUE(server.IsConnected());
+}
+
+TEST_F(TestGLibDBusServer, OwnsName)
+{
+ bool name_owned = false;
+ EXPECT_EQ(server.Name(), DBUS_TEST_NAME);
+
+ server.name_acquired.connect([&name_owned] { name_owned = true; });
+ Utils::WaitUntilMSec(name_owned);
+
+ EXPECT_TRUE(name_owned);
+ EXPECT_TRUE(server.OwnsName());
+ EXPECT_TRUE(server.IsConnected());
+}
+
+TEST_F(TestGLibDBusServer, AddsObjectWhenOwingName)
+{
+ bool object_registered = false;
+
+ auto object = std::make_shared<DBusObject>(introspection::SINGLE_OJBECT, OBJECT_INTERFACE);
+
+ object->registered.connect([&object_registered] (std::string const& path) {
+ EXPECT_EQ(path, TEST_OBJECT_PATH);
+ object_registered = true;
+ });
+
+ server.AddObject(object, TEST_OBJECT_PATH);
+ ASSERT_EQ(server.GetObject(OBJECT_INTERFACE), object);
+ ASSERT_EQ(server.GetObjects().front(), object);
+
+ Utils::WaitUntilMSec([this] { return server.OwnsName(); });
+
+ ASSERT_EQ(server.GetObjects().front(), object);
+ EXPECT_TRUE(object_registered);
+}
+
+TEST_F(TestGLibDBusServer, AddsObjectsWhenOwingName)
+{
+ unsigned objects_registered = 0;
+
+ server.AddObjects(introspection::MULTIPLE_OJBECTS, TEST_OBJECT_PATH);
+ ASSERT_EQ(server.GetObjects().size(), 3);
+
+ for (auto const& obj : server.GetObjects())
+ {
+ ASSERT_EQ(server.GetObject(obj->InterfaceName()), obj);
+
+ obj->registered.connect([&objects_registered] (std::string const& path) {
+ EXPECT_EQ(path, TEST_OBJECT_PATH);
+ ++objects_registered;
+ });
+ }
+
+ Utils::WaitUntilMSec([this] { return server.OwnsName(); });
+
+ EXPECT_EQ(objects_registered, 3);
+}
+
+TEST_F(TestGLibDBusServer, RemovingObjectWontRegisterIt)
+{
+ unsigned objects_registered = 0;
+
+ server.AddObjects(introspection::MULTIPLE_OJBECTS, TEST_OBJECT_PATH);
+ ASSERT_EQ(server.GetObjects().size(), 3);
+
+ server.RemoveObject(server.GetObjects().front());
+ ASSERT_EQ(server.GetObjects().size(), 2);
+
+ for (auto const& obj : server.GetObjects())
+ {
+ obj->registered.connect([&objects_registered] (std::string const& path) {
+ EXPECT_EQ(path, TEST_OBJECT_PATH);
+ ++objects_registered;
+ });
+ }
+
+ Utils::WaitUntilMSec([this] { return server.OwnsName(); });
+
+ EXPECT_EQ(objects_registered, 2);
+}
+
+TEST_F(TestGLibDBusServer, RemovingObjectsUnregistersThem)
+{
+ server.AddObjects(introspection::MULTIPLE_OJBECTS, TEST_OBJECT_PATH);
+ ASSERT_EQ(server.GetObjects().size(), 3);
+
+ Utils::WaitUntilMSec([this] { return server.OwnsName(); });
+
+ unsigned objects_unregistered = 0;
+ for (auto const& obj : server.GetObjects())
+ {
+ obj->unregistered.connect([&objects_unregistered] (std::string const& path) {
+ EXPECT_EQ(path, TEST_OBJECT_PATH);
+ ++objects_unregistered;
+ });
+ }
+
+ server.RemoveObject(server.GetObjects().front());
+ ASSERT_EQ(server.GetObjects().size(), 2);
+ EXPECT_EQ(objects_unregistered, 1);
+
+ server.RemoveObject(server.GetObjects().front());
+ ASSERT_EQ(server.GetObjects().size(), 1);
+ EXPECT_EQ(objects_unregistered, 2);
+
+ server.RemoveObject(server.GetObjects().front());
+ ASSERT_EQ(server.GetObjects().size(), 0);
+ EXPECT_EQ(objects_unregistered, 3);
+}
+
+///
+
+struct TestGLibDBusServerInteractions : testing::Test
+{
+ TestGLibDBusServerInteractions()
+ {}
+
+ static void SetUpTestCase()
+ {
+ server = std::make_shared<DBusServer>(DBUS_TEST_NAME);
+ server->AddObjects(introspection::SINGLE_OJBECT, TEST_OBJECT_PATH);
+ proxy = std::make_shared<DBusProxy>(server->Name(), TEST_OBJECT_PATH, OBJECT_INTERFACE);
+ }
+
+ void SetUp()
+ {
+ Utils::WaitUntilMSec([this] { return server->OwnsName(); });
+ Utils::WaitUntil([this] { return proxy->IsConnected();}, true, 3);
+ ASSERT_TRUE(proxy->IsConnected());
+
+ auto const& objects = server->GetObjects();
+ ASSERT_EQ(objects.size(), 1);
+ object = objects.front();
+ ASSERT_NE(object, nullptr);
+ }
+
+ void TearDown()
+ {
+ object->SetMethodsCallsHandler(nullptr);
+ object->SetPropertyGetter(nullptr);
+ object->SetPropertySetter(nullptr);
+ }
+
+ void TestMethodCall(std::string const& method_name, GVariant* parameters = nullptr, GVariant* returns = nullptr)
+ {
+ std::string const& expected_method = method_name;
+ Variant expected_parameters = parameters ? parameters : g_variant_new("()");
+ Variant returned_value = returns ? returns : g_variant_new("()");
+
+ bool called = false;
+ object->SetMethodsCallsHandler([&] (std::string const& called_method, GVariant* called_parameters) {
+ called = true;
+ EXPECT_EQ(called_method, expected_method);
+ EXPECT_TRUE(g_variant_equal(called_parameters, expected_parameters) != FALSE);
+
+ return returned_value;
+ });
+
+ bool returned = false;
+ proxy->CallBegin(expected_method, expected_parameters, [&returned, &returned_value] (GVariant* ret, Error const& error) {
+ returned = true;
+ EXPECT_TRUE(g_variant_equal(ret, returned_value) != FALSE);
+ EXPECT_FALSE(error);
+ });
+
+ Utils::WaitUntilMSec(called);
+ EXPECT_TRUE(called);
+
+ Utils::WaitUntilMSec(returned);
+ EXPECT_TRUE(returned);
+ }
+
+ static DBusServer::Ptr server;
+ static DBusProxy::Ptr proxy;
+ DBusObject::Ptr object;
+};
+
+DBusServer::Ptr TestGLibDBusServerInteractions::server;
+DBusProxy::Ptr TestGLibDBusServerInteractions::proxy;
+
+TEST_F(TestGLibDBusServerInteractions, VoidMethodCall)
+{
+ TestMethodCall("VoidMethod");
+}
+
+TEST_F(TestGLibDBusServerInteractions, MethodWithParametersCall)
+{
+ auto parameters = g_variant_new("(isu)", 1, "unity", g_random_int());
+ TestMethodCall("MethodWithParameters", parameters);
+}
+
+TEST_F(TestGLibDBusServerInteractions, MethodWithReturnValueCall)
+{
+ auto return_value = g_variant_new("(u)", g_random_int());
+ TestMethodCall("MethodWithReturnValue", nullptr, return_value);
+}
+
+TEST_F(TestGLibDBusServerInteractions, MethodWithParametersAndReturnValueCall)
+{
+ auto parameters = g_variant_new("(s)", "unity?");
+ auto return_value = g_variant_new("(s)", "It's Awesome!");
+ TestMethodCall("MethodWithParametersAndReturnValue", parameters, return_value);
+}
+
+TEST_F(TestGLibDBusServerInteractions, NotHandledMethod)
+{
+ bool got_return = false;
+ proxy->CallBegin("VoidMethod", nullptr, [&got_return] (GVariant* ret, Error const& error) {
+ got_return = TRUE;
+ EXPECT_TRUE(error);
+ });
+
+ Utils::WaitUntilMSec(got_return);
+ EXPECT_TRUE(got_return);
+}
+
+TEST_F(TestGLibDBusServerInteractions, NullReturnOnMethodWithReturn)
+{
+ object->SetMethodsCallsHandler([&] (std::string const& called_method, GVariant* called_parameters) {
+ return static_cast<GVariant*>(nullptr);
+ });
+
+ bool returned = false;
+ proxy->CallBegin("MethodWithReturnValue", nullptr, [&returned] (GVariant*, Error const& error) {
+ returned = true;
+ EXPECT_TRUE(error);
+ });
+
+ Utils::WaitUntilMSec(returned);
+}
+
+TEST_F(TestGLibDBusServerInteractions, EmptyReturnOnMethodWithReturn)
+{
+ object->SetMethodsCallsHandler([&] (std::string const& called_method, GVariant* called_parameters) {
+ return g_variant_new("()");
+ });
+
+ bool returned = false;
+ proxy->CallBegin("MethodWithReturnValue", nullptr, [&returned] (GVariant*, Error const& error) {
+ returned = true;
+ EXPECT_TRUE(error);
+ });
+
+ Utils::WaitUntilMSec(returned);
+}
+
+TEST_F(TestGLibDBusServerInteractions, SignalWithNoParametersEmission)
+{
+ auto const& signal_name = "SignalWithNoParameters";
+
+ bool signal_got = false;
+ proxy->Connect(signal_name, [&signal_got] (GVariant* parameters) {
+ signal_got = true;
+ EXPECT_TRUE(g_variant_equal(g_variant_new("()"), parameters) != FALSE);
+ });
+
+ object->EmitSignal(signal_name);
+ Utils::WaitUntilMSec(signal_got);
+ EXPECT_TRUE(signal_got);
+
+ signal_got = false;
+ server->EmitSignal(object->InterfaceName(), signal_name);
+ Utils::WaitUntilMSec(signal_got);
+ EXPECT_TRUE(signal_got);
+}
+
+TEST_F(TestGLibDBusServerInteractions, SignalWithParameterEmission)
+{
+ auto const& signal_name = "SignalWithParameter";
+ Variant sent_parameters = g_variant_new("(s)", "Unity is Awesome!");
+
+ bool signal_got = false;
+ proxy->Connect(signal_name, [&signal_got, &sent_parameters] (GVariant* parameters) {
+ signal_got = true;
+ EXPECT_TRUE(g_variant_equal(sent_parameters, parameters) != FALSE);
+ });
+
+ object->EmitSignal(signal_name, sent_parameters);
+ Utils::WaitUntilMSec(signal_got);
+ EXPECT_TRUE(signal_got);
+
+ signal_got = false;
+ server->EmitSignal(object->InterfaceName(), signal_name, sent_parameters);
+ Utils::WaitUntilMSec(signal_got);
+ EXPECT_TRUE(signal_got);
+}
+
+} // Namespace
diff --git a/tests/test_launcher.cpp b/tests/test_launcher.cpp
index 2b7814b01..d4cfbd002 100644
--- a/tests/test_launcher.cpp
+++ b/tests/test_launcher.cpp
@@ -62,7 +62,7 @@ public:
class MockLauncher : public Launcher
{
public:
- MockLauncher(nux::BaseWindow* parent)
+ MockLauncher(MockableBaseWindow* parent)
: Launcher(parent)
{}
@@ -119,7 +119,7 @@ public:
};
TestLauncher()
- : parent_window_(new nux::BaseWindow("TestLauncherWindow"))
+ : parent_window_(new MockableBaseWindow("TestLauncherWindow"))
, model_(new LauncherModel)
, options_(new Options)
, launcher_(new MockLauncher(parent_window_.GetPointer()))
@@ -152,7 +152,7 @@ public:
}
MockUScreen uscreen;
- nux::ObjectPtr<nux::BaseWindow> parent_window_;
+ nux::ObjectPtr<MockableBaseWindow> parent_window_;
Settings settings;
panel::Style panel_style;
LauncherModel::Ptr model_;
diff --git a/tests/test_launcher_controller.cpp b/tests/test_launcher_controller.cpp
index e3464caf2..e8a8d281f 100644
--- a/tests/test_launcher_controller.cpp
+++ b/tests/test_launcher_controller.cpp
@@ -25,6 +25,7 @@
#include "ExpoLauncherIcon.h"
#include "DesktopLauncherIcon.h"
#include "DesktopUtilities.h"
+#include "MockableBaseWindow.h"
#include "MockLauncherIcon.h"
#include "BFBLauncherIcon.h"
#include "HudLauncherIcon.h"
@@ -70,9 +71,10 @@ struct MockFavoriteStore : FavoriteStore
{
MockFavoriteStore()
{
- fav_list_ = { FavoriteStore::URI_PREFIX_APP + app::UBUNTU_ONE,
- FavoriteStore::URI_PREFIX_APP + app::SW_CENTER,
- FavoriteStore::URI_PREFIX_APP + app::UPDATE_MANAGER };
+ fav_list_ = { FavoriteStore::URI_PREFIX_APP + DesktopUtilities::GetDesktopID(app::UBUNTU_ONE),
+ FavoriteStore::URI_PREFIX_APP + DesktopUtilities::GetDesktopID(app::SW_CENTER),
+ FavoriteStore::URI_PREFIX_APP + DesktopUtilities::GetDesktopID(app::UPDATE_MANAGER),
+ places::APPS_URI, places::DEVICES_URI };
}
FavoriteList const& GetFavorites() const
@@ -221,7 +223,7 @@ struct TestLauncherController : public testing::Test
bool expired = false;
glib::Idle idle([&] { expired = true; return false; },
glib::Source::Priority::LOW);
- Utils::WaitUntil(expired);
+ Utils::WaitUntilMSec(expired);
}
protected:
@@ -261,7 +263,7 @@ protected:
void DisconnectSignals()
{
- // Impl()->view_opened_signal_.Disconnect();
+ ApplicationManager::Default().application_started.clear();
Impl()->device_section_.icon_added.clear();
Impl()->model_->icon_removed.clear();
Impl()->model_->saved.clear();
@@ -304,6 +306,7 @@ TEST_F(TestLauncherController, Construction)
{
auto model_icon_it = std::find_if(lc.Impl()->model_->begin(), lc.Impl()->model_->end(),
[&fav_uri](AbstractLauncherIcon::Ptr const& i) { return (i->RemoteUri() == fav_uri); });
+
bool valid_iter = (model_icon_it != lc.Impl()->model_->end());
if (fav_uri == places::APPS_URI || fav_uri == places::DEVICES_URI)
@@ -344,6 +347,16 @@ TEST_F(TestLauncherController, MultimonitorSingleLauncher)
}
}
+TEST_F(TestLauncherController, MirroredMultimonitorSingleLauncherOnExternalMonitor)
+{
+ // See lp bug 991637
+ lc.multiple_launchers = false;
+ uscreen.SetPrimary(1);
+
+ ASSERT_EQ(lc.launchers().size(), 1);
+ ASSERT_EQ(lc.launcher().monitor(), 0);
+}
+
TEST_F(TestLauncherController, MultimonitorSwitchToMultipleLaunchers)
{
lc.multiple_launchers = false;
@@ -497,7 +510,7 @@ TEST_F(TestLauncherController, EnabledStrutsOnNeverHide)
};
for (int i = 0; i < max_num_monitors; ++i)
- Utils::WaitUntil(std::bind(check_fn, i));
+ Utils::WaitUntilMSec(std::bind(check_fn, i));
}
TEST_F(TestLauncherController, DisabledStrutsOnAutoHide)
@@ -507,11 +520,11 @@ TEST_F(TestLauncherController, DisabledStrutsOnAutoHide)
lc.options()->hide_mode = LAUNCHER_HIDE_AUTOHIDE;
auto check_fn = [this](int index) {
- return !(lc.launchers()[index]->GetParent()->InputWindowStrutsEnabled());
+ return lc.launchers()[index]->GetParent()->InputWindowStrutsEnabled();
};
for (int i = 0; i < max_num_monitors; ++i)
- Utils::WaitUntil(std::bind(check_fn, i));
+ Utils::WaitUntilMSec(std::bind(check_fn, i), false);
}
TEST_F(TestLauncherController, EnabledStrutsAddingNewLaunchersOnAutoHide)
@@ -532,7 +545,7 @@ TEST_F(TestLauncherController, EnabledStrutsAddingNewLaunchersOnAutoHide)
};
for (int i = 0; i < max_num_monitors; ++i)
- Utils::WaitUntil(std::bind(check_fn, i));
+ Utils::WaitUntilMSec(std::bind(check_fn, i));
}
TEST_F(TestLauncherController, DisabledStrutsAddingNewLaunchersOnNeverHide)
@@ -549,11 +562,11 @@ TEST_F(TestLauncherController, DisabledStrutsAddingNewLaunchersOnNeverHide)
lc.multiple_launchers = true;
auto check_fn = [this](int index) {
- return !(lc.launchers()[index]->GetParent()->InputWindowStrutsEnabled());
+ return lc.launchers()[index]->GetParent()->InputWindowStrutsEnabled();
};
for (int i = 0; i < max_num_monitors; ++i)
- Utils::WaitUntil(std::bind(check_fn, i));
+ Utils::WaitUntilMSec(std::bind(check_fn, i), false);
}
TEST_F(TestLauncherController, CreateFavoriteInvalid)
@@ -591,7 +604,7 @@ TEST_F(TestLauncherController, CreateFavoriteDevice)
{
lc.Impl()->device_section_ = MockDeviceLauncherSection();
auto const& icons = lc.Impl()->device_section_.GetIcons();
- auto const& device_icon = *(icons.begin());
+ auto const& device_icon = icons.front();
ASSERT_TRUE(device_icon.IsValid());
ASSERT_FALSE(device_icon->IsSticky());
@@ -720,7 +733,7 @@ TEST_F(TestLauncherController, RegisteredIconSavesPosition)
TEST_F(TestLauncherController, RegisteredIconForgetsPosition)
{
- auto const& fav = lc.Impl()->GetIconByUri(*(favorite_store.GetFavorites().begin()));
+ auto const& fav = lc.Impl()->GetIconByUri(favorite_store.GetFavorites().front());
ASSERT_TRUE(favorite_store.IsFavorite(fav->RemoteUri()));
fav->UnStick();
@@ -754,6 +767,13 @@ TEST_F(TestLauncherController, GetIconByUriApplications)
auto const& model_icon_it = std::find_if(lc.Impl()->model_->begin(), lc.Impl()->model_->end(),
[&fav_uri](AbstractLauncherIcon::Ptr const& i) { return (i->RemoteUri() == fav_uri); });
+
+ if (fav_uri == places::APPS_URI || fav_uri == places::DEVICES_URI)
+ {
+ ASSERT_EQ(model_icon_it, lc.Impl()->model_->end());
+ continue;
+ }
+
ASSERT_NE(model_icon_it, lc.Impl()->model_->end());
auto const& fav = lc.Impl()->GetIconByUri(fav_uri);
@@ -795,7 +815,7 @@ TEST_F(TestLauncherController, AddDevices)
lc.DisconnectSignals();
lc.Impl()->device_section_ = MockDeviceLauncherSection();
auto const& icons = lc.Impl()->device_section_.GetIcons();
- auto const& device_icon1 = *(icons.begin());
+ auto const& device_icon1 = icons.front();
auto const& device_icon2 = *(std::next(icons.begin()));
device_icon1->Stick(false);
@@ -806,6 +826,36 @@ TEST_F(TestLauncherController, AddDevices)
EXPECT_TRUE(lc.Impl()->GetIconByUri(device_icon2->RemoteUri()).IsValid());
}
+TEST_F(TestLauncherController, MigrateFavorites)
+{
+ favorite_store.SetFavorites({"old_file.desktop"});
+
+ lc.Impl()->MigrateFavorites();
+
+ auto new_favs = favorite_store.GetFavorites();
+
+ EXPECT_EQ(*std::next(new_favs.begin(), 0), "old_file.desktop");
+ EXPECT_EQ(*std::next(new_favs.begin(), 1), places::APPS_URI);
+ EXPECT_EQ(*std::next(new_favs.begin(), 2), lc.Impl()->expo_icon_->RemoteUri());
+ EXPECT_EQ(*std::next(new_favs.begin(), 3), places::DEVICES_URI);
+
+ lc.Impl()->MigrateFavorites();
+
+ auto new_new_favs = favorite_store.GetFavorites();
+
+ EXPECT_EQ(new_favs, new_new_favs);
+}
+
+TEST_F(TestLauncherController, MigrateFavoritesUnneeded)
+{
+ favorite_store.SetFavorites({places::APPS_URI});
+ auto old_favs = favorite_store.GetFavorites();
+ lc.Impl()->MigrateFavorites();
+ auto new_favs = favorite_store.GetFavorites();
+
+ EXPECT_EQ(old_favs, new_favs);
+}
+
TEST_F(TestLauncherController, SetupIcons)
{
lc.ClearModel();
@@ -848,8 +898,6 @@ TEST_F(TestLauncherController, SetupIcons)
auto icon = lc.GetIconByDesktop(path);
ASSERT_EQ(model->IconIndex(icon), ++icon_index);
}
-
- ASSERT_EQ(model->IconIndex(lc.Impl()->expo_icon_), ++icon_index);
}
TEST_F(TestLauncherController, ResetIconPriorities)
@@ -905,7 +953,7 @@ TEST_F(TestLauncherController, GetLastIconPriorityUnSticky)
lc.ClearModel();
lc.Impl()->device_section_ = MockDeviceLauncherSection(3);
auto const& device_icons = lc.Impl()->device_section_.GetIcons();
- auto const& last_device = *(device_icons.rbegin());
+ auto const& last_device = device_icons.back();
favorite_store.SetFavorites({ places::DEVICES_URI,
FavoriteStore::URI_PREFIX_APP + app::SW_CENTER });
@@ -922,7 +970,7 @@ TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithAllStickyIcons)
lc.ClearModel();
lc.Impl()->device_section_ = MockDeviceLauncherSection(3);
auto const& device_icons = lc.Impl()->device_section_.GetIcons();
- auto const& last_device = *(device_icons.rbegin());
+ auto const& last_device = device_icons.back();
favorite_store.SetFavorites({ places::DEVICES_URI,
FavoriteStore::URI_PREFIX_APP + app::SW_CENTER });
@@ -943,7 +991,7 @@ TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithSomeStickyIcons)
lc.Impl()->device_section_ = MockDeviceLauncherSection(3);
auto const& device_icons = lc.Impl()->device_section_.GetIcons();
auto const& first_device = *(std::next(device_icons.rbegin()));
- auto const& last_device = *(device_icons.rbegin());
+ auto const& last_device = device_icons.back();
favorite_store.SetFavorites({ places::DEVICES_URI,
FavoriteStore::URI_PREFIX_APP + app::SW_CENTER });
@@ -1001,7 +1049,7 @@ TEST_F(TestLauncherController, GetLastIconPrioritySticky)
lc.DisconnectSignals();
auto const& device_icons = lc.Impl()->device_section_.GetIcons();
- auto const& first_device = *(device_icons.begin());
+ auto const& first_device = device_icons.front();
int last_priority = lc.Impl()->GetLastIconPriority<VolumeLauncherIcon>("", true);
EXPECT_EQ(last_priority, first_device->SortPriority() - 1);
@@ -1012,7 +1060,7 @@ TEST_F(TestLauncherController, GetLastIconPriorityStickyWithAllStickyIcons)
lc.ClearModel();
lc.Impl()->device_section_ = MockDeviceLauncherSection(3);
auto const& device_icons = lc.Impl()->device_section_.GetIcons();
- auto const& last_device = *(device_icons.rbegin());
+ auto const& last_device = device_icons.back();
favorite_store.SetFavorites({ places::DEVICES_URI,
FavoriteStore::URI_PREFIX_APP + app::SW_CENTER });
@@ -1084,7 +1132,7 @@ TEST_F(TestLauncherController, LauncherAddRequestApplicationStick)
lc.Impl()->RegisterIcon(bamf_icon, std::numeric_limits<int>::max());
auto app_icons = model->GetSublist<ApplicationLauncherIcon>();
- auto const& first_app = *(app_icons.begin());
+ auto const& first_app = app_icons.front();
ASSERT_LT(model->IconIndex(first_app), model->IconIndex(bamf_icon));
EXPECT_CALL(*bamf_icon, Stick(false));
@@ -1098,13 +1146,13 @@ TEST_F(TestLauncherController, LauncherAddRequestDeviceAdd)
auto const& model = lc.Impl()->model_;
lc.Impl()->device_section_ = MockDeviceLauncherSection();
auto const& icons = lc.Impl()->device_section_.GetIcons();
- auto const& device_icon = *(icons.begin());
+ auto const& device_icon = icons.front();
auto const& icon_uri = device_icon->RemoteUri();
ASSERT_FALSE(lc.Impl()->GetIconByUri(icon_uri).IsValid());
auto app_icons = model->GetSublist<ApplicationLauncherIcon>();
- auto const& first_app = *(app_icons.begin());
+ auto const& first_app = app_icons.front();
lc.launcher().add_request.emit(icon_uri, first_app);
@@ -1362,7 +1410,7 @@ TEST_F(TestLauncherController, OnFavoriteStoreFavoriteAddedNewBeforeIcon)
auto const& model = lc.Impl()->model_;
auto app_icons = model->GetSublist<ApplicationLauncherIcon>();
- auto const& first_app = *(app_icons.begin());
+ auto const& first_app = app_icons.front();
favorite_store.favorite_added.emit(icon_uri, first_app->RemoteUri(), true);
auto const& new_icon = lc.Impl()->GetIconByUri(icon_uri);
@@ -1378,7 +1426,7 @@ TEST_F(TestLauncherController, OnFavoriteStoreFavoriteAddedNewAfterIcon)
auto const& model = lc.Impl()->model_;
auto app_icons = model->GetSublist<ApplicationLauncherIcon>();
- auto const& first_app = *(app_icons.begin());
+ auto const& first_app = app_icons.front();
favorite_store.favorite_added.emit(icon_uri, first_app->RemoteUri(), false);
auto const& new_icon = lc.Impl()->GetIconByUri(icon_uri);
@@ -1411,7 +1459,7 @@ TEST_F(TestLauncherController, OnFavoriteStoreFavoriteAddedStickBefore)
lc.Impl()->RegisterIcon(app_icon, std::numeric_limits<int>::max());
auto app_icons = model->GetSublist<ApplicationLauncherIcon>();
- auto const& first_app = *(app_icons.begin());
+ auto const& first_app = app_icons.front();
ASSERT_LT(model->IconIndex(first_app), model->IconIndex(app_icon));
EXPECT_CALL(*app_icon, Stick(false));
@@ -1431,7 +1479,7 @@ TEST_F(TestLauncherController, OnFavoriteStoreFavoriteAddedStickAfter)
lc.Impl()->RegisterIcon(app_icon, std::numeric_limits<int>::max());
auto const& app_icons = model->GetSublist<ApplicationLauncherIcon>();
- auto const& first_app = *(app_icons.begin());
+ auto const& first_app = app_icons.front();
ASSERT_LT(model->IconIndex(first_app), model->IconIndex(app_icon));
EXPECT_CALL(*app_icon, Stick(false));
@@ -1447,7 +1495,7 @@ TEST_F(TestLauncherController, OnFavoriteStoreFavoriteAddedDeviceSection)
lc.Impl()->device_section_ = MockDeviceLauncherSection();
auto const& model = lc.Impl()->model_;
auto const& icons = lc.Impl()->device_section_.GetIcons();
- auto const& device_icon1(*(icons.begin()));
+ auto const& device_icon1(icons.front());
auto const& device_icon2(*(std::next(icons.begin())));
favorite_store.SetFavorites({ lc.Impl()->expo_icon_->RemoteUri(),
@@ -1456,7 +1504,7 @@ TEST_F(TestLauncherController, OnFavoriteStoreFavoriteAddedDeviceSection)
lc.DisconnectSignals();
auto const& app_icons = lc.Impl()->model_->GetSublist<ApplicationLauncherIcon>();
- auto const& last_app = *(app_icons.rbegin());
+ auto const& last_app = app_icons.back();
ASSERT_EQ(model->IconIndex(device_icon1), model->IconIndex(last_app) + 1);
ASSERT_EQ(model->IconIndex(device_icon2), model->IconIndex(last_app) + 2);
@@ -1485,7 +1533,7 @@ TEST_F(TestLauncherController, OnFavoriteStoreFavoriteRemovedDevice)
auto const& model = lc.Impl()->model_;
auto const& icons = lc.Impl()->device_section_.GetIcons();
- auto const& device_icon(*(icons.begin()));
+ auto const& device_icon(icons.front());
favorite_store.SetFavorites({ lc.Impl()->expo_icon_->RemoteUri(),
FavoriteStore::URI_PREFIX_APP + DesktopUtilities::GetDesktopID(app::UBUNTU_ONE),
@@ -1500,7 +1548,7 @@ TEST_F(TestLauncherController, OnFavoriteStoreFavoriteRemovedDevice)
favorite_store.favorite_removed.emit(device_icon->RemoteUri());
auto const& app_icons = lc.Impl()->model_->GetSublist<ApplicationLauncherIcon>();
- auto const& last_app = *(app_icons.rbegin());
+ auto const& last_app = app_icons.back();
EXPECT_EQ(model->IconIndex(device_icon), model->IconIndex(last_app) + 1);
}
@@ -1511,7 +1559,7 @@ TEST_F(TestLauncherController, OnFavoriteStoreFavoriteRemovedDeviceSection)
auto const& model = lc.Impl()->model_;
auto const& icons = lc.Impl()->device_section_.GetIcons();
- auto const& device_icon1(*(icons.begin()));
+ auto const& device_icon1(icons.front());
auto const& device_icon2(*(std::next(icons.begin())));
favorite_store.SetFavorites({ lc.Impl()->expo_icon_->RemoteUri(), places::DEVICES_URI,
@@ -1526,15 +1574,16 @@ TEST_F(TestLauncherController, OnFavoriteStoreFavoriteRemovedDeviceSection)
favorite_store.favorite_removed.emit(places::DEVICES_URI);
auto const& app_icons = lc.Impl()->model_->GetSublist<ApplicationLauncherIcon>();
- auto const& last_app = *(app_icons.rbegin());
+ auto const& last_app = app_icons.back();
EXPECT_EQ(model->IconIndex(device_icon1), model->IconIndex(last_app) + 1);
EXPECT_EQ(model->IconIndex(device_icon2), model->IconIndex(last_app) + 2);
+ EXPECT_TRUE(favorite_store.IsFavorite(places::DEVICES_URI));
}
TEST_F(TestLauncherController, OnViewOpened)
{
auto const& app_icons = lc.Impl()->model_->GetSublist<ApplicationLauncherIcon>();
- auto const& last_app = *(app_icons.rbegin());
+ auto const& last_app = app_icons.back();
testmocks::MockApplicationManager::StartApp(app::BZR_HANDLE_PATCH);
auto const& icon = lc.GetIconByDesktop(app::BZR_HANDLE_PATCH);
@@ -1592,7 +1641,7 @@ TEST_F(TestLauncherController, UpdateLaunchersBackgroundColor)
UBusManager().SendMessage(UBUS_BACKGROUND_COLOR_CHANGED,
g_variant_new("(dddd)", 11/255.0f, 22/255.0f, 33/255.0f, 1.0f));
- Utils::WaitUntil([this] { return lc.options()->background_color == nux::Color(11, 22, 33); });
+ Utils::WaitUntilMSec([this] { return lc.options()->background_color == nux::Color(11, 22, 33); });
}
// thumper: 2012-11-28 disabling the drag and drop tests as they are taking over 20s
@@ -1611,17 +1660,17 @@ TEST_F(TestLauncherController, DISABLED_DragAndDrop_MultipleLaunchers)
xdnd_manager_->dnd_started.emit("my_awesome_file", 0);
for (int i = 0; i < max_num_monitors; ++i)
- Utils::WaitUntil(std::bind(check_fn, i), i != 0);
+ Utils::WaitUntilMSec(std::bind(check_fn, i), i != 0);
xdnd_manager_->monitor_changed.emit(3);
for (int i = 0; i < max_num_monitors; ++i)
- Utils::WaitUntil(std::bind(check_fn, i), i != 3);
+ Utils::WaitUntilMSec(std::bind(check_fn, i), i != 3);
xdnd_manager_->dnd_finished.emit();
for (int i = 0; i < max_num_monitors; ++i)
- Utils::WaitUntil(std::bind(check_fn, i), true);
+ Utils::WaitUntilMSec(std::bind(check_fn, i), true);
}
TEST_F(TestLauncherController, DISABLED_DragAndDrop_SingleLauncher)
@@ -1635,13 +1684,58 @@ TEST_F(TestLauncherController, DISABLED_DragAndDrop_SingleLauncher)
};
xdnd_manager_->dnd_started.emit("my_awesome_file", 0);
- Utils::WaitUntil(check_fn, false);
+ Utils::WaitUntilMSec(check_fn, false);
xdnd_manager_->monitor_changed.emit(2);
- Utils::WaitUntil(check_fn, false);
+ Utils::WaitUntilMSec(check_fn, false);
xdnd_manager_->dnd_finished.emit();
- Utils::WaitUntil(check_fn, true);
+ Utils::WaitUntilMSec(check_fn, true);
+}
+
+TEST_F(TestLauncherController, SetExistingLauncherIconAsFavorite)
+{
+ const char * desktop_file = "normal-icon.desktop";
+ MockApplicationLauncherIcon::Ptr
+ app_icon(new NiceMock<MockApplicationLauncherIcon>(true, desktop_file));
+ lc.Impl()->RegisterIcon(app_icon);
+ ASSERT_FALSE(favorite_store.IsFavorite(app_icon->RemoteUri()));
+
+ const std::string icon_uri = FavoriteStore::URI_PREFIX_APP + desktop_file;
+ lc.Impl()->OnLauncherUpdateIconStickyState(icon_uri, true);
+
+ ASSERT_TRUE(app_icon->IsSticky());
+ EXPECT_TRUE(favorite_store.IsFavorite(app_icon->RemoteUri()));
+}
+
+TEST_F(TestLauncherController, SetExistingLauncherIconAsNonFavorite)
+{
+ const char * desktop_file = "normal-icon.desktop";
+ MockApplicationLauncherIcon::Ptr
+ app_icon(new NiceMock<MockApplicationLauncherIcon>(true, desktop_file));
+ lc.Impl()->RegisterIcon(app_icon);
+ ASSERT_FALSE(favorite_store.IsFavorite(app_icon->RemoteUri()));
+ app_icon->Stick(true);
+
+ EXPECT_CALL(*app_icon, UnStick());
+
+ const std::string icon_uri = FavoriteStore::URI_PREFIX_APP + desktop_file;
+ lc.Impl()->OnLauncherUpdateIconStickyState(icon_uri, false);
+}
+
+TEST_F(TestLauncherController, SetNonExistingLauncherIconAsFavorite)
+{
+ std::string desktop = app::BZR_HANDLE_PATCH;
+ std::string icon_uri = FavoriteStore::URI_PREFIX_APP + DesktopUtilities::GetDesktopID(desktop);
+
+ lc.Impl()->OnLauncherUpdateIconStickyState(icon_uri, true);
+
+ // Make sure that the icon now exists and is sticky
+ EXPECT_TRUE(favorite_store.IsFavorite(icon_uri));
+
+ auto const& icon = lc.Impl()->GetIconByUri(icon_uri);
+ ASSERT_TRUE(icon.IsValid());
+ ASSERT_TRUE(icon->IsSticky());
}
}
diff --git a/tests/test_lens.cpp b/tests/test_lens.cpp
index 629ab52f1..ae36a08e8 100644
--- a/tests/test_lens.cpp
+++ b/tests/test_lens.cpp
@@ -27,10 +27,12 @@ class TestLens : public ::testing::Test
{
public:
TestLens()
- : lens_(new Lens("testlens", lens_name, lens_path,
- "Test Lens", "gtk-apply")),
- n_categories_(0)
+ : lens_(make_shared<Lens>("testlens", lens_name, lens_path, "Test Lens", "gtk-apply"))
+ , n_categories_(0)
, n_filters_(0)
+ {}
+
+ void SetUp()
{
WaitForConnected();
@@ -53,33 +55,15 @@ public:
void WaitForConnected()
{
- bool timeout_reached = false;
- guint32 timeout_id = Utils::ScheduleTimeout(&timeout_reached, 2000);
-
- while (!lens_->connected && !timeout_reached)
- {
- g_main_context_iteration(g_main_context_get_thread_default(), TRUE);
- }
- if (lens_->connected)
- g_source_remove(timeout_id);
-
- EXPECT_FALSE(timeout_reached);
+ Utils::WaitUntil([this] { return lens_->connected(); }, true, 2);
+ ASSERT_TRUE(lens_->connected());
}
template<typename Adaptor>
void WaitForModel(Model<Adaptor>* model, unsigned int n_rows)
{
- bool timeout_reached = false;
- guint32 timeout_id = Utils::ScheduleTimeout(&timeout_reached, 2000);
-
- while (model->count != n_rows && !timeout_reached)
- {
- g_main_context_iteration(g_main_context_get_thread_default(), TRUE);
- }
- if (model->count == n_rows)
- g_source_remove(timeout_id);
-
- EXPECT_FALSE(timeout_reached);
+ Utils::WaitUntil([model, n_rows] { return model->count() == n_rows; }, true, 2);
+ ASSERT_EQ(model->count(), n_rows);
}
std::string PopulateAndGetFirstResultURI()
@@ -120,7 +104,7 @@ TEST_F(TestLens, TestCategories)
WaitForModel<Category>(categories.get(), 3);
EXPECT_EQ(categories->count, (unsigned int)3);
- EXPECT_EQ(n_categories_, 3);
+ EXPECT_EQ(n_categories_, (unsigned int)3);
Category category = categories->RowAtIndex(0);
EXPECT_EQ(category.name, "Category1");
@@ -576,27 +560,22 @@ TEST_F(TestLens, TestFilterMultiRangeLogic)
EXPECT_FALSE (options[3]->active);
options[0]->active = true;
- options[3]->active = true;
+ options[1]->active = true;
EXPECT_TRUE (filter->filtering);
EXPECT_TRUE (options[0]->active);
EXPECT_TRUE (options[1]->active);
- EXPECT_TRUE (options[2]->active);
- EXPECT_TRUE (options[3]->active);
- options[0]->active = true;
- options[2]->active = false;
+ options[3]->active = true;
EXPECT_TRUE (filter->filtering);
- EXPECT_TRUE (options[0]->active);
- EXPECT_TRUE (options[1]->active);
- EXPECT_TRUE (options[2]->active);
- EXPECT_FALSE (options[3]->active);
+ EXPECT_FALSE (options[0]->active);
+ EXPECT_FALSE (options[1]->active);
+ EXPECT_FALSE (options[2]->active);
+ EXPECT_TRUE (options[3]->active);
- options[0]->active = false;
+ options[2]->active = true;
EXPECT_TRUE (filter->filtering);
- EXPECT_FALSE (options[0]->active);
- EXPECT_TRUE (options[1]->active);
EXPECT_TRUE (options[2]->active);
- EXPECT_FALSE (options[3]->active);
+ EXPECT_TRUE (options[3]->active);
filter->Clear();
EXPECT_FALSE (filter->filtering);
diff --git a/tests/test_main_dbus.cpp b/tests/test_main_dbus.cpp
index cac31781a..6592d366c 100644
--- a/tests/test_main_dbus.cpp
+++ b/tests/test_main_dbus.cpp
@@ -2,6 +2,7 @@
#include <gio/gio.h>
#include <NuxCore/Logger.h>
#include <Nux/Nux.h>
+#include "test_utils.h"
static bool wait_until_test_service_appears();
static void tell_service_to_exit();
@@ -12,13 +13,14 @@ int main(int argc, char** argv)
#if G_ENCODE_VERSION (GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION) <= GLIB_VERSION_2_34
g_type_init();
#endif
-
+
nux::NuxInitialize (0);
// We need the service to be ready before we are
+
if (!wait_until_test_service_appears())
{
- std::cerr << "FATAL: Unable to connect to test service";
+ std::cerr << "FATAL: Unable to connect to test service" << std::endl;
return EXIT_FAILURE;
}
@@ -26,7 +28,7 @@ int main(int argc, char** argv)
nux::logging::configure_logging("<root>=error");
// but you can still change it if you're debugging ;)
- nux::logging::configure_logging(::getenv("UNITY_LOG_SEVERITY"));
+ nux::logging::configure_logging(::getenv("UNITY_TEST_LOG_SEVERITY"));
int ret = RUN_ALL_TESTS();
@@ -38,13 +40,6 @@ int main(int argc, char** argv)
static bool wait_until_test_service_appears()
{
bool have_name = false;
- bool timeout_reached = false;
-
- auto timeout_cb = [](gpointer data) -> gboolean
- {
- *(bool*)data = true;
- return FALSE;
- };
auto callback = [](GDBusConnection * conn,
const char * name,
@@ -61,12 +56,11 @@ static bool wait_until_test_service_appears()
NULL,
&have_name,
NULL);
- g_timeout_add(10000, timeout_cb, &timeout_reached);
- while (!have_name && !timeout_reached)
- g_main_context_iteration(g_main_context_get_thread_default(), TRUE);
+ Utils::WaitUntil(have_name, 3);
+ EXPECT_TRUE(have_name);
- return (have_name && !timeout_reached);
+ return have_name;
}
static void tell_service_to_exit()
diff --git a/tests/test_model.cpp b/tests/test_model.cpp
index 77da052b3..159a8e131 100644
--- a/tests/test_model.cpp
+++ b/tests/test_model.cpp
@@ -35,34 +35,25 @@ public:
}
};
-static void WaitForSynchronize(Model<TestAdaptor>& model)
+struct TestModel : public ::testing::Test
{
- ::Utils::WaitForModelSynchronize<TestAdaptor>(model, n_rows);
-}
+ void SetUp()
+ {
+ model.swarm_name = swarm_name;
+ Utils::WaitUntil([this] { return model.count == n_rows; }, true, 2);
+ ASSERT_EQ(model.count, n_rows);
+ }
-TEST(TestModel, TestConstruction)
-{
Model<TestAdaptor> model;
- model.swarm_name = swarm_name;
- ::Utils::WaitForModelSynchronize<TestAdaptor>(model, n_rows);
-}
+};
-TEST(TestModel, TestSynchronization)
+TEST_F(TestModel, TestConstruction)
{
- Model<TestAdaptor> model;
- model.swarm_name = swarm_name;
-
- WaitForSynchronize(model);
- EXPECT_EQ(model.count, n_rows);
+ EXPECT_EQ(model.swarm_name(), swarm_name);
}
-TEST(TestModel, TestRowsValid)
+TEST_F(TestModel, TestRowsValid)
{
- Model<TestAdaptor> model;
- model.swarm_name = swarm_name;
-
- WaitForSynchronize(model);
-
for (unsigned int i = 0; i < n_rows; i++)
{
TestAdaptor adaptor = model.RowAtIndex(i);
@@ -74,13 +65,8 @@ TEST(TestModel, TestRowsValid)
}
// We're testing the model's ability to store and retrieve random pointers
-TEST(TestModel, TestSetGetRenderer)
+TEST_F(TestModel, TestSetGetRenderer)
{
- Model<TestAdaptor> model;
- model.swarm_name = swarm_name;
-
- WaitForSynchronize(model);
-
for (unsigned int i = 0; i < n_rows; i++)
{
TestAdaptor adaptor = model.RowAtIndex(i);
diff --git a/tests/test_panel_view.cpp b/tests/test_panel_view.cpp
new file mode 100644
index 000000000..625b72343
--- /dev/null
+++ b/tests/test_panel_view.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 3 along with this program. If not, see
+ * <http://www.gnu.org/licenses/>
+ *
+ * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
+ *
+ */
+
+#include <gtest/gtest.h>
+
+#include "PanelView.h"
+#include "unity-shared/PanelStyle.h"
+#include "unity-shared/UBusMessages.h"
+#include "unity-shared/UBusWrapper.h"
+#include "unity-shared/UnitySettings.h"
+#include "test_utils.h"
+
+namespace
+{
+
+class TestPanelView : public testing::Test
+{
+public:
+ unity::Settings unity_settings_;
+ unity::panel::Style panel_style_;
+ unity::UBusManager ubus_manager_;
+ nux::ObjectPtr<unity::PanelView> panel_view_;
+
+ TestPanelView()
+ : panel_view_(new unity::PanelView())
+ {}
+
+};
+
+TEST_F(TestPanelView, StoredDashWidth)
+{
+ auto check_function = [this] (int value) {
+ return panel_view_->GetStoredDashWidth() == value;
+ };
+
+ int width = 500;
+ int height = 600;
+
+ GVariant* info = g_variant_new(UBUS_OVERLAY_FORMAT_STRING, "dash", TRUE, 0, width, height);
+ ubus_manager_.SendMessage(UBUS_OVERLAY_SHOWN, info);
+ Utils::WaitUntil(std::bind(check_function, width));
+
+ width = 150;
+
+ ubus_manager_.SendMessage(UBUS_DASH_SIZE_CHANGED, g_variant_new("(ii)", width, height));
+ Utils::WaitUntil(std::bind(check_function, width));
+}
+
+}
diff --git a/tests/test_pointer_barrier.cpp b/tests/test_pointer_barrier.cpp
index 5c07e0d4b..b52fbedad 100644
--- a/tests/test_pointer_barrier.cpp
+++ b/tests/test_pointer_barrier.cpp
@@ -35,6 +35,21 @@ public:
bool HandleEvent(XEvent ev) { return PointerBarrierWrapper::HandleEvent(ev); }
};
+XFixesBarrierNotifyEvent GetGenericEvent (unsigned int id)
+{
+ XFixesBarrierNotifyEvent ev;
+
+ ev.type = XFixesBarrierNotify;
+ ev.subtype = XFixesBarrierHitNotify;
+ ev.barrier = 0;
+ ev.event_id = id;
+ ev.x = 555;
+ ev.y = 333;
+ ev.velocity = std::numeric_limits<int>::max();
+
+ return ev;
+}
+
TEST(TestPointerBarrier, Construction)
{
PointerBarrierWrapper pb;
@@ -76,27 +91,22 @@ TEST(TestPointerBarrier, HandleInvalidEvents)
TEST(TestPointerBarrier, HandleHitNotifyEvents)
{
MockPointerBarrier pb;
- XFixesBarrierNotifyEvent ev;
+ XFixesBarrierNotifyEvent ev = GetGenericEvent(0xdeadbeef);
auto xev = reinterpret_cast<XEvent*>(&ev);
- ev.type = XFixesBarrierNotify;
- ev.subtype = XFixesBarrierHitNotify;
- ev.barrier = 0;
- ev.event_id = 0xdeadbeef;
- ev.x = 555;
- ev.y = 333;
- ev.velocity = std::numeric_limits<int>::max();
-
bool got_event = false;
pb.barrier_event.connect([&] (PointerBarrierWrapper* pbw, BarrierEvent::Ptr bev) {
- got_event = true;
-
- EXPECT_EQ(pbw, &pb);
- EXPECT_EQ(bev->x, ev.x);
- EXPECT_EQ(bev->y, ev.y);
- EXPECT_EQ(bev->velocity, 600 * pb.max_velocity_multiplier);
- EXPECT_EQ(bev->event_id, ev.event_id);
+ if (!pbw->IsFirstEvent())
+ {
+ got_event = true;
+
+ EXPECT_EQ(pbw, &pb);
+ EXPECT_EQ(bev->x, ev.x);
+ EXPECT_EQ(bev->y, ev.y);
+ EXPECT_EQ(bev->velocity, 600 * pb.max_velocity_multiplier);
+ EXPECT_EQ(bev->event_id, ev.event_id);
+ }
});
EXPECT_TRUE(pb.HandleEvent(*xev));
@@ -110,17 +120,8 @@ TEST(TestPointerBarrier, HandleHitNotifyEvents)
TEST(TestPointerBarrier, HandleHitNotifyReleasedEvents)
{
MockPointerBarrier pb;
- XFixesBarrierNotifyEvent ev;
+ XFixesBarrierNotifyEvent ev = GetGenericEvent(0xabba);
auto xev = reinterpret_cast<XEvent*>(&ev);
-
- ev.type = XFixesBarrierNotify;
- ev.subtype = XFixesBarrierHitNotify;
- ev.barrier = 0;
- ev.event_id = 0xabba;
- ev.x = 3333;
- ev.y = 5555;
- ev.velocity = std::numeric_limits<int>::max();
-
bool got_event = false;
pb.barrier_event.connect([&] (PointerBarrierWrapper* pbw, BarrierEvent::Ptr bev) {
@@ -138,4 +139,43 @@ TEST(TestPointerBarrier, HandleHitNotifyReleasedEvents)
EXPECT_TRUE(got_event);
}
+TEST(TestPointerBarrier, ReciveFirstEvent)
+{
+ MockPointerBarrier pb;
+ XFixesBarrierNotifyEvent ev = GetGenericEvent(0xabba);
+ auto xev = reinterpret_cast<XEvent*>(&ev);
+
+ bool first_is_true = false;
+
+ pb.barrier_event.connect([&] (PointerBarrierWrapper* pbw, BarrierEvent::Ptr bev) {
+ first_is_true = true;
+ });
+
+ EXPECT_TRUE(pb.HandleEvent(*xev));
+ EXPECT_TRUE(first_is_true);
+}
+
+TEST(TestPointerBarrier, ReciveSecondEventFirstFalse)
+{
+ MockPointerBarrier pb;
+ XFixesBarrierNotifyEvent ev = GetGenericEvent(0xabba);
+ auto xev = reinterpret_cast<XEvent*>(&ev);
+ int events_recived = 0;
+
+ pb.barrier_event.connect([&] (PointerBarrierWrapper* pbw, BarrierEvent::Ptr bev) {
+ events_recived++;
+
+ if (events_recived == 1)
+ EXPECT_TRUE(pbw->IsFirstEvent());
+ else
+ EXPECT_FALSE(pbw->IsFirstEvent());
+ });
+
+ EXPECT_TRUE(pb.HandleEvent(*xev));
+
+ Utils::WaitForTimeoutMSec(pb.smoothing());
+
+ EXPECT_EQ(events_recived, 2);
+}
+
}
diff --git a/tests/test_quicklist_manager.cpp b/tests/test_quicklist_manager.cpp
index 247181390..78d3d1651 100644
--- a/tests/test_quicklist_manager.cpp
+++ b/tests/test_quicklist_manager.cpp
@@ -34,7 +34,7 @@ struct MockQuicklistView : public unity::QuicklistView
{
void *operator new(size_t uiSize) {
GObjectStats._allocation_list.push_back(buf);
- return (void *)buf;
+ return (void *) buf;
}
void operator delete(void *p) {
@@ -51,7 +51,6 @@ TEST(TestQuicklistManager, RegisterQuicklist)
nux::ObjectPtr<unity::QuicklistView> quicklist1(new MockQuicklistView);
ptr = quicklist1;
ASSERT_EQ(quicklist1->GetReferenceCount(), 1);
- ASSERT_EQ(quicklist1.GetPointer(), (unity::QuicklistView*) buf);
ASSERT_TRUE(unity::QuicklistManager::Default()->RegisterQuicklist(quicklist1));
ASSERT_EQ(quicklist1->GetReferenceCount(), 1);
ASSERT_FALSE(unity::QuicklistManager::Default()->RegisterQuicklist(quicklist1));
@@ -61,7 +60,6 @@ TEST(TestQuicklistManager, RegisterQuicklist)
ASSERT_FALSE(ptr.IsValid());
nux::ObjectPtr<unity::QuicklistView> quicklist2(new MockQuicklistView);
- ASSERT_EQ(quicklist2.GetPointer(), (unity::QuicklistView*) buf);
ASSERT_EQ(quicklist2->GetReferenceCount(), 1);
ASSERT_TRUE(unity::QuicklistManager::Default()->RegisterQuicklist(quicklist2));
ASSERT_EQ(quicklist2->GetReferenceCount(), 1);
diff --git a/tests/test_results.cpp b/tests/test_results.cpp
index e4b4d5165..ead31cd61 100644
--- a/tests/test_results.cpp
+++ b/tests/test_results.cpp
@@ -19,7 +19,7 @@ static const unsigned int n_rows = 200;
static void WaitForSynchronize(Results& model)
{
- ::Utils::WaitForModelSynchronize<Result>(model, n_rows);
+ Utils::WaitUntil([&model] { return model.count == n_rows; });
}
TEST(TestResults, TestConstruction)
diff --git a/tests/test_service_gdbus_wrapper.c b/tests/test_service_gdbus_wrapper.c
deleted file mode 100644
index 982be4cc1..000000000
--- a/tests/test_service_gdbus_wrapper.c
+++ /dev/null
@@ -1,202 +0,0 @@
-#include "test_service_gdbus_wrapper.h"
-#include <unity.h>
-#include <gio/gio.h>
-
-const char * gdbus_wrapper_interface =
-"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
-"<node name=\"/\">\n"
-" <interface name=\"com.canonical.gdbus_wrapper\">\n"
-"<!-- Properties -->\n"
-" <!-- None -->\n"
-"\n"
-"<!-- Functions -->\n"
-" <method name=\"TestMethod\">\n"
-" <!-- in -->\n"
-" <arg type=\"s\" name=\"query\" direction=\"in\" />\n"
-" <!-- out -->\n"
-" <arg type=\"s\" name=\"target\" direction=\"out\" />\n"
-" </method>\n"
-"\n"
-"<!-- Signals -->\n"
-" <signal name=\"TestSignal\">\n"
-" <arg type=\"s\" name=\"target\" direction=\"out\" />\n"
-" </signal>\n"
-"\n"
-"<!-- End of interesting stuff -->\n"
-"\n"
-" </interface>\n"
-"</node>\n"
-;
-static void bus_got_cb (GObject *object, GAsyncResult * res, gpointer user_data);
-static void bus_method (GDBusConnection *connection,
- const gchar *sender,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *method_name,
- GVariant *parameters,
- GDBusMethodInvocation *invocation,
- gpointer user_data);
-
-G_DEFINE_TYPE(ServiceGDBusWrapper, service_gdbus_wrapper, G_TYPE_OBJECT);
-static GDBusNodeInfo * node_info = NULL;
-static GDBusInterfaceInfo * iface_info = NULL;
-static GDBusInterfaceVTable bus_vtable = {
- method_call: bus_method,
- get_property: NULL,
- set_property: NULL,
-};
-
-
-struct _ServiceGDBusWrapperPrivate
-{
- GDBusConnection * bus;
- GCancellable * bus_lookup;
- guint bus_registration;
-};
-
-static void
-service_gdbus_wrapper_dispose(GObject* object)
-{
- ServiceGDBusWrapper* self = SERVICE_GDBUS_WRAPPER(object);
- if (self->priv->bus_lookup != NULL) {
- g_cancellable_cancel(self->priv->bus_lookup);
- g_object_unref(self->priv->bus_lookup);
- self->priv->bus_lookup = NULL;
- }
-
- if (self->priv->bus_registration != 0) {
- g_dbus_connection_unregister_object(self->priv->bus, self->priv->bus_registration);
- self->priv->bus_registration = 0;
- }
-
- if (self->priv->bus != NULL) {
- g_object_unref(self->priv->bus);
- self->priv->bus = NULL;
- }
-
- G_OBJECT_CLASS (service_gdbus_wrapper_parent_class)->dispose (object);
-}
-
-static void
-service_gdbus_wrapper_class_init(ServiceGDBusWrapperClass* klass)
-{
- G_OBJECT_CLASS(klass)->dispose = service_gdbus_wrapper_dispose;
- g_type_class_add_private (klass, sizeof (ServiceGDBusWrapperPrivate));
-
- if (node_info == NULL)
- {
- GError * error = NULL;
-
- node_info = g_dbus_node_info_new_for_xml(gdbus_wrapper_interface, &error);
- if (error != NULL)
- {
- g_error("Unable to parse GDBUS_WRAPPER interface: %s", error->message);
- g_error_free(error);
- }
- }
-
- if (node_info != NULL && iface_info == NULL)
- {
- iface_info = g_dbus_node_info_lookup_interface(node_info,"com.canonical.gdbus_wrapper");
- if (iface_info == NULL)
- {
- g_error("Unable to find interface 'com.canonical.gdbus_wrapper'");
- }
- }
-
-}
-
-static void
-service_gdbus_wrapper_init(ServiceGDBusWrapper* self)
-{
- self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, SERVICE_TYPE_GDBUS_WRAPPER, ServiceGDBusWrapperPrivate);
- self->priv->bus = NULL;
- self->priv->bus_lookup = NULL;
- self->priv->bus_registration = 0;
-
- self->priv->bus_lookup = g_cancellable_new();
- g_bus_get(G_BUS_TYPE_SESSION, self->priv->bus_lookup, bus_got_cb, self);
-
-}
-
-ServiceGDBusWrapper*
-service_gdbus_wrapper_new()
-{
- return g_object_new(SERVICE_TYPE_GDBUS_WRAPPER, NULL);
-}
-
-static void
-bus_got_cb (GObject *object, GAsyncResult * res, gpointer user_data)
-{
- GError * error = NULL;
- ServiceGDBusWrapper * self = SERVICE_GDBUS_WRAPPER(user_data);
- GDBusConnection * bus;
-
- bus = g_bus_get_finish(res, &error);
- if (error != NULL) {
- g_critical("Unable to get bus: %s", error->message);
- g_error_free(error);
- return;
- }
-
- self->priv->bus = bus;
-
- /* Register object */
- self->priv->bus_registration = g_dbus_connection_register_object(bus,
- /* path */ "/com/canonical/gdbus_wrapper",
- /* interface */ iface_info,
- /* vtable */ &bus_vtable,
- /* userdata */ self,
- /* destroy */ NULL,
- /* error */ &error);
-
- if (error != NULL) {
- g_critical ("Unable to create bus connection object, %s", error->message);
- g_error_free(error);
- return;
- }
-
- return;
-}
-
-static void
-bus_method (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data)
-{
- if (g_strcmp0(method_name, "TestMethod") == 0)
- {
- GVariant * ret = NULL;
- GVariant * sig_data = NULL;
- GVariant * tmp = NULL;
- gchar * query = NULL;
- GError * error = NULL;
- g_variant_get(parameters, "(s)", &query);
-
- tmp = g_variant_new_string(query);
- ret = g_variant_new_tuple(&tmp, 1);
- g_dbus_method_invocation_return_value(invocation, ret);
- tmp = NULL;
-
- // emit a signal with the same string as passed in every time this method is called
-
- tmp = g_variant_new_string(query);
- sig_data = g_variant_new_tuple(&tmp, 1);
- g_dbus_connection_emit_signal(connection,
- NULL, /* destination bus, we don't care */
- "/com/canonical/gdbus_wrapper", /* object path */
- "com.canonical.gdbus_wrapper", /* interface name */
- "TestSignal", /* Signal name */
- sig_data, /* parameter */
- &error); /* error */
-
- if (error != NULL)
- {
- g_critical ("could not emit signal TestSignal with data %s", query);
- g_error_free(error);
- }
-
- g_free(query);
- }
-
- return;
-}
-
diff --git a/tests/test_service_gdbus_wrapper.cpp b/tests/test_service_gdbus_wrapper.cpp
new file mode 100644
index 000000000..d07a468d1
--- /dev/null
+++ b/tests/test_service_gdbus_wrapper.cpp
@@ -0,0 +1,56 @@
+#include "test_service_gdbus_wrapper.h"
+
+namespace unity
+{
+namespace service
+{
+namespace
+{
+const char * gdbus_wrapper_interface =
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+"<node name=\"/\">\n"
+" <interface name=\"com.canonical.gdbus_wrapper\">\n"
+"<!-- Properties -->\n"
+" <!-- None -->\n"
+"\n"
+"<!-- Functions -->\n"
+" <method name=\"TestMethod\">\n"
+" <!-- in -->\n"
+" <arg type=\"s\" name=\"query\" direction=\"in\" />\n"
+" <!-- out -->\n"
+" <arg type=\"s\" name=\"target\" direction=\"out\" />\n"
+" </method>\n"
+"\n"
+"<!-- Signals -->\n"
+" <signal name=\"TestSignal\">\n"
+" <arg type=\"s\" name=\"target\" direction=\"out\" />\n"
+" </signal>\n"
+"\n"
+"<!-- End of interesting stuff -->\n"
+"\n"
+" </interface>\n"
+"</node>\n"
+;
+}
+
+GDBus::GDBus()
+{
+ auto object = glib::DBusObjectBuilder::GetObjectsForIntrospection(gdbus_wrapper_interface).front();
+ object->SetMethodsCallsHandler([object] (std::string const& method, GVariant *parameters) {
+ if (method == "TestMethod")
+ {
+ glib::String query;
+ g_variant_get(parameters, "(s)", &query);
+
+ object->EmitSignal("TestSignal", g_variant_new("(s)", query.Value()));
+ return g_variant_new("(s)", query.Value());
+ }
+
+ return static_cast<GVariant*>(nullptr);
+ });
+
+ server_.AddObject(object, "/com/canonical/gdbus_wrapper");
+}
+
+}
+}
diff --git a/tests/test_service_gdbus_wrapper.h b/tests/test_service_gdbus_wrapper.h
index 6344e7569..905c76b5d 100644
--- a/tests/test_service_gdbus_wrapper.h
+++ b/tests/test_service_gdbus_wrapper.h
@@ -1,46 +1,23 @@
#ifndef _SERVICE_GDBUS_WRAPPER_H_
#define _SERVICE_GDBUS_WRAPPER_H_
-#include <glib-object.h>
-G_BEGIN_DECLS
+#include <UnityCore/GLibDBusServer.h>
-#define SERVICE_TYPE_GDBUS_WRAPPER (service_gdbus_wrapper_get_type ())
-
-#define SERVICE_GDBUS_WRAPPER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
- SERVICE_TYPE_GDBUS_WRAPPER, ServiceGDBusWrapper))
-
-#define SERVICE_GDBUS_WRAPPER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
- SERVICE_TYPE_GDBUS_WRAPPER, ServiceGDBusWrapperClass))
-
-#define SERVICE_IS_GDBUS_WRAPPER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
- SERVICE_TYPE_GDBUS_WRAPPER))
-
-#define SERVICE_IS_GDBUS_WRAPPER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
- SERVICE_TYPE_GDBUS_WRAPPER))
-
-#define ServiceGDBusWrapper_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
- SERVICE_TYPE_GDBUS_WRAPPER, ServiceGDBusWrapperClass))
-
-typedef struct _ServiceGDBusWrapper ServiceGDBusWrapper;
-typedef struct _ServiceGDBusWrapperClass ServiceGDBusWrapperClass;
-typedef struct _ServiceGDBusWrapperPrivate ServiceGDBusWrapperPrivate;
-
-struct _ServiceGDBusWrapper
+namespace unity
{
- GObject parent;
-
- ServiceGDBusWrapperPrivate *priv;
-};
-
-struct _ServiceGDBusWrapperClass
+namespace service
{
- GObjectClass parent_class;
-};
-GType service_gdbus_wrapper_get_type(void) G_GNUC_CONST;
+class GDBus
+{
+public:
+ GDBus();
-ServiceGDBusWrapper* service_gdbus_wrapper_new(void);
+private:
+ glib::DBusServer server_;
+};
-G_END_DECLS
+}
+}
#endif /* _SERVICE_GDBUS_WRAPPER_H_ */
diff --git a/tests/test_service_hud.c b/tests/test_service_hud.cpp
index a34f8762f..1dd0cc8bd 100644
--- a/tests/test_service_hud.c
+++ b/tests/test_service_hud.cpp
@@ -1,8 +1,12 @@
#include "test_service_hud.h"
-#include <unity.h>
-#include <gio/gio.h>
-const char * hud_interface =
+namespace unity
+{
+namespace service
+{
+namespace
+{
+const char * hud_interface =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<node name=\"/\">\n"
" <interface name=\"com.canonical.hud\">\n"
@@ -41,159 +45,22 @@ const char * hud_interface =
" </interface>\n"
"</node>\n"
;
-static void bus_got_cb (GObject *object, GAsyncResult * res, gpointer user_data);
-static void bus_method (GDBusConnection *connection,
- const gchar *sender,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *method_name,
- GVariant *parameters,
- GDBusMethodInvocation *invocation,
- gpointer user_data);
-
-static gboolean do_emit_signal(gpointer data);
-static void emit_signal(GDBusConnection *connection);
-
-
-G_DEFINE_TYPE(ServiceHud, service_hud, G_TYPE_OBJECT);
-static GDBusNodeInfo * node_info = NULL;
-static GDBusInterfaceInfo * iface_info = NULL;
-static GDBusInterfaceVTable bus_vtable = {
- method_call: bus_method,
- get_property: NULL,
- set_property: NULL,
-};
-
-struct _ServiceHudPrivate
-{
- GDBusConnection * bus;
- GCancellable * bus_lookup;
- guint bus_registration;
- guint sig_emission_handle;
-};
-
-static void
-service_hud_dispose(GObject* object)
-{
- ServiceHud* self = SERVICE_HUD(object);
- if (self->priv->bus_lookup != NULL) {
- g_cancellable_cancel(self->priv->bus_lookup);
- g_object_unref(self->priv->bus_lookup);
- self->priv->bus_lookup = NULL;
- }
-
- if (self->priv->bus_registration != 0) {
- g_dbus_connection_unregister_object(self->priv->bus, self->priv->bus_registration);
- self->priv->bus_registration = 0;
- }
-
- if (self->priv->bus != NULL) {
- g_object_unref(self->priv->bus);
- self->priv->bus = NULL;
- }
-
- if (self->priv->sig_emission_handle) {
- g_source_remove(self->priv->sig_emission_handle);
- self->priv->sig_emission_handle = 0;
- }
-
- G_OBJECT_CLASS (service_hud_parent_class)->dispose (object);
}
-static void
-service_hud_class_init(ServiceHudClass* klass)
-{
- G_OBJECT_CLASS(klass)->dispose = service_hud_dispose;
- g_type_class_add_private (klass, sizeof (ServiceHudPrivate));
-
- if (node_info == NULL)
- {
- GError * error = NULL;
- node_info = g_dbus_node_info_new_for_xml(hud_interface, &error);
- if (error != NULL)
- {
- g_error("Unable to parse HUD interface: %s", error->message);
- g_error_free(error);
- }
- }
-
- if (node_info != NULL && iface_info == NULL)
- {
- iface_info = g_dbus_node_info_lookup_interface(node_info,"com.canonical.hud");
- if (iface_info == NULL)
- {
- g_error("Unable to find interface 'com.canonical.hud'");
- }
- }
-
-}
-
-static void
-service_hud_init(ServiceHud* self)
-{
- self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, SERVICE_TYPE_HUD, ServiceHudPrivate);
- self->priv->bus = NULL;
- self->priv->bus_lookup = NULL;
- self->priv->bus_registration = 0;
-
- self->priv->bus_lookup = g_cancellable_new();
- g_bus_get(G_BUS_TYPE_SESSION, self->priv->bus_lookup, bus_got_cb, self);
-}
-
-ServiceHud*
-service_hud_new()
-{
- return g_object_new(SERVICE_TYPE_HUD, NULL);
-}
-
-static void
-bus_got_cb (GObject *object, GAsyncResult * res, gpointer user_data)
-{
- GError * error = NULL;
- ServiceHud * self = SERVICE_HUD(user_data);
- GDBusConnection * bus;
-
- bus = g_bus_get_finish(res, &error);
- if (error != NULL) {
- g_critical("Unable to get bus: %s", error->message);
- g_error_free(error);
- return;
- }
-
- self->priv->bus = bus;
-
- /* Register object */
- self->priv->bus_registration = g_dbus_connection_register_object(bus,
- /* path */ "/com/canonical/hud",
- /* interface */ iface_info,
- /* vtable */ &bus_vtable,
- /* userdata */ self,
- /* destroy */ NULL,
- /* error */ &error);
-
- if (error != NULL) {
- g_critical ("Unable to create bus connection object, %s", error->message);
- g_error_free(error);
- return;
- }
- else
- {
- self->priv->sig_emission_handle = g_timeout_add(1000, do_emit_signal, bus);
- }
-
- return;
-}
-
-static gboolean
-do_emit_signal(gpointer data)
+Hud::Hud()
{
- emit_signal(G_DBUS_CONNECTION(data));
- return TRUE;
+ auto object = std::make_shared<glib::DBusObject>(hud_interface, "com.canonical.hud");
+ object->SetMethodsCallsHandler(sigc::mem_fun(this, &Hud::OnMethodCall));
+ object->registered.connect([this] (std::string const&) {
+ timeout_.reset(new glib::TimeoutSeconds(1));
+ timeout_->Run([this] { EmitSignal(); return true; });
+ });
+
+ server_.AddObject(object, "/com/canonical/hud");
}
-static void
-emit_signal(GDBusConnection *connection)
+void Hud::EmitSignal()
{
GVariant *query;
int num_entries = 5;
@@ -203,11 +70,11 @@ emit_signal(GDBusConnection *connection)
g_variant_builder_init(&ret_builder, G_VARIANT_TYPE_TUPLE);
g_variant_builder_add_value(&ret_builder, g_variant_new_string("target"));
GVariantBuilder builder;
-
+
g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
-
+
int i = 0;
- for (i = 0; i < num_entries; i++)
+ for (i = 0; i < num_entries; i++)
{
gchar* target = g_strdup_printf("test-%i", i);
gchar* icon = g_strdup_printf("icon-%i", i);
@@ -243,7 +110,7 @@ emit_signal(GDBusConnection *connection)
g_free(completion_text);
}
g_variant_builder_add_value(&ret_builder, g_variant_builder_end(&builder));
-
+
GVariant* query_key;
{
GVariantBuilder keybuilder;
@@ -257,21 +124,17 @@ emit_signal(GDBusConnection *connection)
}
g_variant_ref_sink(query_key);
g_variant_builder_add_value(&ret_builder, query_key);
-
+
query = g_variant_builder_end(&ret_builder);
-
- g_dbus_connection_emit_signal (connection, NULL, "/com/canonical/hud",
- "com.canonical.hud", "UpdatedQuery",
- query, NULL);
+
+ server_.EmitSignal("com.canonical.hud", "UpdatedQuery", query);
}
-static void
-bus_method (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data)
+GVariant* Hud::OnMethodCall(std::string const& method, GVariant *parameters)
{
- if (g_strcmp0(method_name, "StartQuery") == 0)
+ if (method == "StartQuery")
{
- GVariant * ret = NULL;
- gchar * query = NULL;
+ glib::String query;
int num_entries = 0;
g_variant_get(parameters, "(si)", &query, &num_entries);
@@ -281,11 +144,11 @@ bus_method (GDBusConnection *connection, const gchar *sender, const gchar *objec
g_variant_builder_init(&ret_builder, G_VARIANT_TYPE_TUPLE);
g_variant_builder_add_value(&ret_builder, g_variant_new_string("target"));
GVariantBuilder builder;
-
+
g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
-
+
int i = 0;
- for (i = 0; i < num_entries; i++)
+ for (i = 0; i < num_entries; i++)
{
gchar* target = g_strdup_printf("test-%i", i);
gchar* icon = g_strdup_printf("icon-%i", i);
@@ -321,7 +184,7 @@ bus_method (GDBusConnection *connection, const gchar *sender, const gchar *objec
g_free(completion_text);
}
g_variant_builder_add_value(&ret_builder, g_variant_builder_end(&builder));
-
+
GVariant* query_key;
{
GVariantBuilder keybuilder;
@@ -335,27 +198,25 @@ bus_method (GDBusConnection *connection, const gchar *sender, const gchar *objec
}
g_variant_ref_sink(query_key);
g_variant_builder_add_value(&ret_builder, query_key);
-
- ret = g_variant_builder_end(&ret_builder);
- g_dbus_method_invocation_return_value(invocation, ret);
- g_free(query);
- }
- else if (g_strcmp0(method_name, "ExecuteQuery") == 0)
+ return g_variant_builder_end(&ret_builder);
+ }
+ else if (method == "ExecuteQuery")
{
GVariant * key = NULL;
key = g_variant_get_child_value(parameters, 0);
- g_dbus_method_invocation_return_value(invocation, NULL);
g_variant_unref(key);
}
- else if (g_strcmp0(method_name, "CloseQuery") == 0)
+ else if (method == "CloseQuery")
{
GVariant * key = NULL;
key = g_variant_get_child_value(parameters, 0);
- g_dbus_method_invocation_return_value(invocation, NULL);
g_variant_unref(key);
}
- return;
+ return nullptr;
+}
+
+}
}
diff --git a/tests/test_service_hud.h b/tests/test_service_hud.h
index df069962a..853c9cfac 100644
--- a/tests/test_service_hud.h
+++ b/tests/test_service_hud.h
@@ -1,46 +1,29 @@
#ifndef _SERVICE_HUD_H_
#define _SERVICE_HUD_H_
-#include <glib-object.h>
-G_BEGIN_DECLS
+#include <UnityCore/GLibDBusServer.h>
+#include <UnityCore/GLibSource.h>
-#define SERVICE_TYPE_HUD (service_hud_get_type ())
-
-#define SERVICE_HUD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
- SERVICE_TYPE_HUD, ServiceHud))
-
-#define SERVICE_HUD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
- SERVICE_TYPE_HUD, ServiceHudClass))
-
-#define SERVICE_IS_HUD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
- SERVICE_TYPE_HUD))
-
-#define SERVICE_IS_HUD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
- SERVICE_TYPE_HUD))
-
-#define ServiceHud_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
- SERVICE_TYPE_HUD, ServiceHudClass))
-
-typedef struct _ServiceHud ServiceHud;
-typedef struct _ServiceHudClass ServiceHudClass;
-typedef struct _ServiceHudPrivate ServiceHudPrivate;
+namespace unity
+{
+namespace service
+{
-struct _ServiceHud
+class Hud
{
- GObject parent;
+public:
+ Hud();
- ServiceHudPrivate *priv;
-};
+private:
+ void EmitSignal();
+ GVariant* OnMethodCall(std::string const& method, GVariant *parameters);
-struct _ServiceHudClass
-{
- GObjectClass parent_class;
+ glib::DBusServer server_;
+ glib::Source::UniquePtr timeout_;
};
-GType service_hud_get_type(void) G_GNUC_CONST;
-
-ServiceHud* service_hud_new(void);
+}
+}
-G_END_DECLS
#endif /* _SERVICE_HUD_H_ */
diff --git a/tests/test_service_lens.c b/tests/test_service_lens.cpp
index ad24975e4..58a1820ed 100644
--- a/tests/test_service_lens.c
+++ b/tests/test_service_lens.cpp
@@ -2,110 +2,72 @@
#include <unity.h>
-G_DEFINE_TYPE(ServiceLens, service_lens, G_TYPE_OBJECT);
-
-static void add_categories(ServiceLens* self);
-static void add_filters(ServiceLens *self);
-static void on_search_changed(UnityScope* scope, UnityLensSearch *lens_search, UnitySearchType search_type, GCancellable *canc, ServiceLens* self);
-static UnityActivationResponse* on_activate_uri(UnityScope* scope, const char* uri, ServiceLens* self);
-static UnityPreview* on_preview_uri(UnityScope* scope, const char* uri, ServiceLens *self);
-
-struct _ServiceLensPrivate
+namespace unity
{
- UnityLens* lens;
- UnityScope* scope;
-};
-
-static void
-service_lens_dispose(GObject* object)
+namespace service
{
- ServiceLens* self = SERVICE_LENS(object);
-
- g_object_unref(self->priv->lens);
- g_object_unref(self->priv->scope);
-
- G_OBJECT_CLASS (service_lens_parent_class)->dispose (object);
-}
+static void on_search_changed(UnityScope* scope, UnityLensSearch *lens_search, UnitySearchType search_type, GCancellable *canc, Lens* self);
+static UnityActivationResponse* on_activate_uri(UnityScope* scope, const char* uri, Lens* self);
+static UnityPreview* on_preview_uri(UnityScope* scope, const char* uri, Lens *self);
-static void
-service_lens_class_init(ServiceLensClass* klass)
+Lens::Lens()
+ : lens_(unity_lens_new("/com/canonical/unity/testlens", "testlens"))
+ , scope_(unity_scope_new("/com/canonical/unity/testscope"))
{
- G_OBJECT_CLASS(klass)->dispose = service_lens_dispose;
+ g_object_set(lens_, "search-hint", "Search Test Lens", "visible", TRUE,
+ "search-in-global", TRUE, NULL);
- g_type_class_add_private (klass, sizeof (ServiceLensPrivate));
-}
+ AddCategories();
+ AddFilters();
-static void
-service_lens_init(ServiceLens* self)
-{
- ServiceLensPrivate* priv;
- GError* error = NULL;
-
- priv = self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, SERVICE_TYPE_LENS, ServiceLensPrivate);
-
- /* Setup Lens */
- priv->lens = unity_lens_new("/com/canonical/unity/testlens", "testlens");
- g_object_set(priv->lens,
- "search-hint", "Search Test Lens",
- "visible", TRUE,
- "search-in-global", TRUE,
- NULL);
- add_categories(self);
- add_filters(self);
-
- /* Scope */
- priv->scope = unity_scope_new("/com/canonical/unity/testscope");
- unity_scope_set_search_in_global(priv->scope, TRUE);
-
- g_signal_connect(priv->scope, "search-changed",
- G_CALLBACK(on_search_changed), self);
- g_signal_connect(priv->scope, "activate-uri",
- G_CALLBACK(on_activate_uri), self);
- g_signal_connect(priv->scope, "preview-uri",
- G_CALLBACK(on_preview_uri), self);
+ unity_scope_set_search_in_global(scope_, TRUE);
+
+ g_signal_connect(scope_, "search-changed", G_CALLBACK(on_search_changed), this);
+ g_signal_connect(scope_, "activate-uri", G_CALLBACK(on_activate_uri), this);
+ g_signal_connect(scope_, "preview-uri", G_CALLBACK(on_preview_uri), this);
/* Get ready to export and export */
- unity_lens_add_local_scope(priv->lens, priv->scope);
- unity_lens_export(priv->lens, &error);
+ glib::Error error;
+ unity_lens_add_local_scope(lens_, scope_);
+ unity_lens_export(lens_, &error);
+
if (error)
{
- g_error ("Unable to export Lens: %s", error->message);
- g_error_free (error);
+ g_error ("Unable to export Lens: %s", error.Message().c_str());
}
}
-static void
-add_categories(ServiceLens* self)
+Lens::~Lens()
+{
+ g_signal_handlers_disconnect_by_data(scope_, this);
+}
+
+void Lens::AddCategories()
{
GList *cats = NULL;
- GIcon *icon;
+ glib::Object<GIcon> icon;
icon = g_themed_icon_new("gtk-apply");
cats = g_list_append (cats, unity_category_new("Category1", icon,
UNITY_CATEGORY_RENDERER_VERTICAL_TILE));
- g_object_unref (icon);
-
+
icon = g_themed_icon_new("gtk-cancel");
cats = g_list_append (cats, unity_category_new("Category2", icon,
UNITY_CATEGORY_RENDERER_HORIZONTAL_TILE));
- g_object_unref (icon);
icon = g_themed_icon_new("gtk-close");
cats = g_list_append (cats, unity_category_new("Category3", icon,
UNITY_CATEGORY_RENDERER_FLOW));
- g_object_unref (icon);
-
- unity_lens_set_categories(self->priv->lens, cats);
+ unity_lens_set_categories(lens_, cats);
g_list_free_full (cats, (GDestroyNotify) g_object_unref);
}
-static void
-add_filters(ServiceLens *self)
+void Lens::AddFilters()
{
GList *filters = NULL;
UnityFilter *filter;
- GIcon *icon;
+ glib::Object<GIcon> icon;
filter = UNITY_FILTER (unity_radio_option_filter_new("when", "When",
NULL, FALSE));
@@ -122,17 +84,16 @@ add_filters(ServiceLens *self)
icon = g_themed_icon_new ("gtk-apps");
unity_options_filter_add_option(UNITY_OPTIONS_FILTER (filter),
"apps", "Apps", icon);
- g_object_unref (icon);
+
icon = g_themed_icon_new ("gtk-files");
unity_options_filter_add_option(UNITY_OPTIONS_FILTER (filter),
"files", "Files", icon);
- g_object_unref (icon);
+
icon = g_themed_icon_new ("gtk-music");
unity_options_filter_add_option(UNITY_OPTIONS_FILTER (filter),
"music", "Music", icon);
- g_object_unref (icon);
- filters = g_list_append (filters, filter);
+ filters = g_list_append (filters, filter);
filters = g_list_append (filters, unity_ratings_filter_new("ratings",
"Ratings",
NULL, FALSE));
@@ -143,15 +104,13 @@ add_filters(ServiceLens *self)
unity_options_filter_add_option(UNITY_OPTIONS_FILTER(filter), "100MB", "100MB", NULL);
unity_options_filter_add_option(UNITY_OPTIONS_FILTER(filter), "1000MB", "1000MB", NULL);
filters = g_list_append (filters, filter);
-
- unity_lens_set_filters(self->priv->lens, filters);
+ unity_lens_set_filters(lens_, filters);
g_list_free_full (filters, (GDestroyNotify) g_object_unref);
}
-static void
-on_search_changed(UnityScope* scope, UnityLensSearch *search,
- UnitySearchType search_type, GCancellable *canc, ServiceLens* self)
+
+static void on_search_changed(UnityScope* scope, UnityLensSearch *search, UnitySearchType search_type, GCancellable *canc, Lens* self)
{
int i = 0;
// to differentiate global and non-global searches, we'll return more items
@@ -179,20 +138,17 @@ on_search_changed(UnityScope* scope, UnityLensSearch *search,
unity_lens_search_finished (search);
}
-static UnityActivationResponse*
-on_activate_uri(UnityScope* scope, const char* uri, ServiceLens* self)
+static UnityActivationResponse* on_activate_uri(UnityScope* scope, const char* uri, Lens* self)
{
return unity_activation_response_new(UNITY_HANDLED_TYPE_HIDE_DASH, "");
}
-static UnityActivationResponse*
-preview_action_activated(UnityPreviewAction* action, const char* uri)
+static UnityActivationResponse* preview_action_activated(UnityPreviewAction* action, const char* uri)
{
return unity_activation_response_new(UNITY_HANDLED_TYPE_SHOW_DASH, "");
}
-static UnityPreview*
-on_preview_uri(UnityScope* scope, const char* uri, ServiceLens *self)
+static UnityPreview* on_preview_uri(UnityScope* scope, const char* uri, Lens *self)
{
UnityPreviewAction* action;
UnityMoviePreview* preview;
@@ -208,8 +164,5 @@ on_preview_uri(UnityScope* scope, const char* uri, ServiceLens *self)
return (UnityPreview*) preview;
}
-ServiceLens*
-service_lens_new()
-{
- return g_object_new(SERVICE_TYPE_LENS, NULL);
+}
}
diff --git a/tests/test_service_lens.h b/tests/test_service_lens.h
index ff6d657e4..cae5fcf4f 100644
--- a/tests/test_service_lens.h
+++ b/tests/test_service_lens.h
@@ -1,47 +1,29 @@
#ifndef _SERVICE_LENS_H_
#define _SERVICE_LENS_H_
-#include <dee.h>
+#include <unity.h>
+#include <UnityCore/GLibWrapper.h>
-G_BEGIN_DECLS
-
-#define SERVICE_TYPE_LENS (service_lens_get_type ())
-
-#define SERVICE_LENS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
- SERVICE_TYPE_LENS, ServiceLens))
-
-#define SERVICE_LENS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
- SERVICE_TYPE_LENS, ServiceLensClass))
-
-#define SERVICE_IS_LENS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
- SERVICE_TYPE_LENS))
-
-#define SERVICE_IS_LENS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
- SERVICE_TYPE_LENS))
-
-#define ServiceLens_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
- SERVICE_TYPE_LENS, ServiceLensClass))
-
-typedef struct _ServiceLens ServiceLens;
-typedef struct _ServiceLensClass ServiceLensClass;
-typedef struct _ServiceLensPrivate ServiceLensPrivate;
-
-struct _ServiceLens
+namespace unity
+{
+namespace service
{
- GObject parent;
-
- ServiceLensPrivate *priv;
-};
-struct _ServiceLensClass
+class Lens
{
- GObjectClass parent_class;
-};
+public:
+ Lens();
+ ~Lens();
-GType service_lens_get_type(void) G_GNUC_CONST;
+private:
+ void AddCategories();
+ void AddFilters();
-ServiceLens* service_lens_new(void);
+ glib::Object<UnityLens> lens_;
+ glib::Object<UnityScope> scope_;
+};
-G_END_DECLS
+}
+}
#endif /* _SERVICE_LENS_H_ */
diff --git a/tests/test_service_main.c b/tests/test_service_main.c
deleted file mode 100644
index e5cba13a4..000000000
--- a/tests/test_service_main.c
+++ /dev/null
@@ -1,105 +0,0 @@
-#include <glib-object.h>
-
-#include "test_service_lens.h"
-#include "test_service_model.h"
-#include "test_service_hud.h"
-#include "test_service_panel.h"
-#include "test_service_gdbus_wrapper.h"
-
-static void on_bus_aquired(GDBusConnection* conn, const gchar* name, gpointer null);
-static void handle_method_call(GDBusConnection *connection,
- const gchar *sender,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *method_name,
- GVariant *parameters,
- GDBusMethodInvocation *invocation,
- gpointer user_data);
-
-
-static GDBusNodeInfo* introspection_data = NULL;
-static const gchar introspection_xml[] =
- "<node>"
- " <interface name='com.canonical.Unity.Test'>"
- ""
- " <method name='Exit'>"
- " </method>"
- ""
- " </interface>"
- "</node>";
-static const GDBusInterfaceVTable interface_vtable =
-{
- handle_method_call,
- NULL,
- NULL
-};
-
-static GMainLoop* loop_ = NULL;
-static ServiceLens* lens_ = NULL;
-static ServiceModel* model_ = NULL;
-static ServiceHud* hud_ = NULL;
-static ServicePanel* panel_ = NULL;
-static ServiceGDBusWrapper* gdbus_wrapper_ = NULL;
-gint
-main(gint argc, gchar** argv)
-{
-#if G_ENCODE_VERSION (GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION) <= GLIB_VERSION_2_34
- g_type_init();
-#endif
- loop_ = g_main_loop_new(NULL, FALSE);
-
- lens_ = service_lens_new();
- model_ = service_model_new();
- hud_ = service_hud_new();
- panel_ = service_panel_new();
- gdbus_wrapper_ = service_gdbus_wrapper_new();
-
- g_bus_own_name(G_BUS_TYPE_SESSION,
- "com.canonical.Unity.Test",
- G_BUS_NAME_OWNER_FLAGS_NONE,
- on_bus_aquired,
- NULL,
- NULL,
- NULL,
- NULL);
-
- g_main_loop_run(loop_);
- g_main_loop_unref(loop_);
-
- //g_object_unref(lens_);
- //g_object_unref(model_);
- g_object_unref(hud_);
- g_object_unref(panel_);
- g_dbus_node_info_unref(introspection_data);
-
- return 0;
-}
-
-static void
-on_bus_aquired(GDBusConnection* conn, const gchar* name, gpointer null)
-{
- introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, NULL);
- g_dbus_connection_register_object(conn,
- "/com/canonical/unity/test/controller",
- introspection_data->interfaces[0],
- &interface_vtable,
- NULL,
- NULL,
- NULL);
-}
-
-static void
-handle_method_call(GDBusConnection *connection,
- const gchar *sender,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *method_name,
- GVariant *parameters,
- GDBusMethodInvocation *invocation,
- gpointer user_data)
-{
- if (g_strcmp0(method_name, "Exit") == 0)
- {
- g_main_loop_quit(loop_);
- }
-}
diff --git a/tests/test_service_main.cpp b/tests/test_service_main.cpp
new file mode 100644
index 000000000..d5589c3a8
--- /dev/null
+++ b/tests/test_service_main.cpp
@@ -0,0 +1,47 @@
+#include "test_service_lens.h"
+#include "test_service_model.h"
+#include "test_service_hud.h"
+#include "test_service_panel.h"
+#include "test_service_gdbus_wrapper.h"
+
+using namespace unity;
+
+static const gchar introspection_xml[] =
+ "<node>"
+ " <interface name='com.canonical.Unity.Test'>"
+ ""
+ " <method name='Exit'>"
+ " </method>"
+ ""
+ " </interface>"
+ "</node>";
+
+
+int main(int argc, char** argv)
+{
+#if G_ENCODE_VERSION (GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION) <= GLIB_VERSION_2_34
+ g_type_init();
+#endif
+ auto loop = g_main_loop_new(NULL, FALSE);
+
+ glib::DBusServer controller("com.canonical.Unity.Test");
+ controller.AddObjects(introspection_xml, "/com/canonical/unity/test/controller");
+ auto const& obj = controller.GetObjects().front();
+ obj->SetMethodsCallsHandler([loop] (std::string const& method, GVariant*) {
+ if (method == "Exit")
+ g_main_loop_quit(loop);
+
+ return static_cast<GVariant*>(nullptr);
+ });
+
+ service::Hud hud;
+ service::GDBus gdbus;
+ service::Panel panel;
+ service::Lens lens;
+ service::Model model;
+
+ g_main_loop_run(loop);
+ g_main_loop_unref(loop);
+
+ return 0;
+}
diff --git a/tests/test_service_model.c b/tests/test_service_model.c
deleted file mode 100644
index 9ebf3c65a..000000000
--- a/tests/test_service_model.c
+++ /dev/null
@@ -1,100 +0,0 @@
-#include "test_service_model.h"
-
-G_DEFINE_TYPE(ServiceModel, service_model, G_TYPE_OBJECT);
-
-static void service_model_create_model(ServiceModel* self);
-static void service_model_create_results(ServiceModel* self);
-static void service_model_create_categories(ServiceModel* self);
-
-static void
-service_model_dispose(GObject* object)
-{
- ServiceModel* self = SERVICE_MODEL(object);
-
- g_object_unref(self->model_);
- g_object_unref(self->results_model_);
- g_object_unref(self->categories_model_);
-
- G_OBJECT_CLASS (service_model_parent_class)->dispose (object);
-}
-
-static void
-service_model_class_init(ServiceModelClass* klass)
-{
- G_OBJECT_CLASS(klass)->dispose = service_model_dispose;
-}
-
-static void
-service_model_init(ServiceModel* self)
-{
- service_model_create_model(self);
- service_model_create_results(self);
- service_model_create_categories(self);
-}
-
-static void
-service_model_create_model(ServiceModel* self)
-{
- self->model_ = dee_shared_model_new("com.canonical.test.model");
- dee_model_set_schema(self->model_, "u", "s", NULL);
-
- guint i;
- for (i = 0; i < 100; i++)
- {
- gchar* name = g_strdup_printf("Test%d", i);
- dee_model_append(self->model_, i, name);
- g_free(name);
- }
-}
-
-static void
-service_model_create_results(ServiceModel* self)
-{
- self->results_model_ = dee_shared_model_new("com.canonical.test.resultsmodel");
- dee_model_set_schema(self->results_model_, "s", "s", "u", "s", "s", "s", "s", NULL);
-
- int i;
- for(i = 0; i < 200; i++)
- {
- gchar* name = g_strdup_printf("Result%d", i);
- dee_model_append(self->results_model_,
- name,
- name,
- (guint)(i/50), // new category every 50 results
- name,
- name,
- name,
- name);
- g_free(name);
- }
-}
-
-static void
-service_model_create_categories(ServiceModel* self)
-{
- self->categories_model_ = dee_shared_model_new("com.canonical.test.categoriesmodel");
- dee_model_set_schema(self->categories_model_, "s", "s", "s", "a{sv}", NULL);
-
- GVariantBuilder b;
- g_variant_builder_init(&b, G_VARIANT_TYPE("a{sv}"));
- GVariant *hints = g_variant_builder_end(&b);
-
- int i;
- for(i = 0; i < 5; i++)
- {
- gchar* name = g_strdup_printf("Category%d", i);
- dee_model_append(self->categories_model_,
- name,
- "gtk-apply",
- "grid",
- hints);
- g_free(name);
- }
- g_variant_unref(hints);
-}
-
-ServiceModel*
-service_model_new()
-{
- return g_object_new(SERVICE_TYPE_MODEL, NULL);
-}
diff --git a/tests/test_service_model.cpp b/tests/test_service_model.cpp
new file mode 100644
index 000000000..b02a6615e
--- /dev/null
+++ b/tests/test_service_model.cpp
@@ -0,0 +1,52 @@
+#include "test_service_model.h"
+
+namespace unity
+{
+namespace service
+{
+
+Model::Model()
+ : model_(dee_shared_model_new("com.canonical.test.model"))
+ , results_model_(dee_shared_model_new("com.canonical.test.resultsmodel"))
+ , categories_model_(dee_shared_model_new("com.canonical.test.categoriesmodel"))
+{
+ dee_model_set_schema(model_, "u", "s", nullptr);
+
+ for (unsigned i = 0; i < 100; ++i)
+ dee_model_append(model_, i, ("Test"+std::to_string(i)).c_str());
+
+
+ dee_model_set_schema(results_model_, "s", "s", "u", "s", "s", "s", "s", nullptr);
+
+ for(unsigned i = 0; i < 200; ++i)
+ {
+ auto name = "Result"+std::to_string(i);
+ dee_model_append(results_model_,
+ name.c_str(),
+ name.c_str(),
+ (guint)(i/50), // new category every 50 results
+ name.c_str(),
+ name.c_str(),
+ name.c_str(),
+ name.c_str());
+ }
+
+
+ dee_model_set_schema(categories_model_, "s", "s", "s", "a{sv}", nullptr);
+
+ GVariantBuilder b;
+ g_variant_builder_init(&b, G_VARIANT_TYPE("a{sv}"));
+ GVariant *hints = g_variant_builder_end(&b);
+
+ for(unsigned i = 0; i < 5; ++i)
+ {
+ dee_model_append(categories_model_,
+ ("Category"+std::to_string(i)).c_str(),
+ "gtk-apply",
+ "grid",
+ hints);
+ }
+}
+
+}
+}
diff --git a/tests/test_service_model.h b/tests/test_service_model.h
index e8d144d75..ae451558e 100644
--- a/tests/test_service_model.h
+++ b/tests/test_service_model.h
@@ -2,47 +2,25 @@
#define _SERVICE_MODEL_H_
#include <dee.h>
+#include <UnityCore/GLibWrapper.h>
-G_BEGIN_DECLS
-
-#define SERVICE_TYPE_MODEL (service_model_get_type ())
-
-#define SERVICE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
- SERVICE_TYPE_MODEL, ServiceModel))
-
-#define SERVICE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
- SERVICE_TYPE_MODEL, ServiceModelClass))
-
-#define SERVICE_IS_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
- SERVICE_TYPE_MODEL))
-
-#define SERVICE_IS_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
- SERVICE_TYPE_MODEL))
-
-#define ServiceModel_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
- SERVICE_TYPE_MODEL, ServiceModelClass))
-
-typedef struct _ServiceModel ServiceModel;
-typedef struct _ServiceModelClass ServiceModelClass;
-
-struct _ServiceModel
+namespace unity
{
- GObject parent;
-
- DeeModel* model_;
- DeeModel* results_model_;
- DeeModel* categories_model_;
-};
-
-struct _ServiceModelClass
+namespace service
{
- GObjectClass parent_class;
-};
-GType service_model_get_type(void) G_GNUC_CONST;
+class Model
+{
+public:
+ Model();
-ServiceModel* service_model_new(void);
+private:
+ glib::Object<DeeModel> model_;
+ glib::Object<DeeModel> results_model_;
+ glib::Object<DeeModel> categories_model_;
+};
-G_END_DECLS
+}
+}
#endif /* _SERVICE_MODEL_H_ */
diff --git a/tests/test_service_panel.c b/tests/test_service_panel.c
deleted file mode 100644
index e5c29ffb1..000000000
--- a/tests/test_service_panel.c
+++ /dev/null
@@ -1,253 +0,0 @@
-#include "test_service_panel.h"
-#include <unity.h>
-#include <gio/gio.h>
-
-static const char * panel_interface =
-"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
-"<node name=\"/\">\n"
-" <interface name=\"com.canonical.Unity.Panel.Service\">\n"
-"\n"
-"<!-- Begin of real methods/signals -->\n"
-" <method name='Sync'>"
-" <arg type='a(ssssbbusbbi)' name='state' direction='out'/>"
-" </method>"
-"\n"
-" <signal name='ReSync'>"
-" <arg type='s' name='indicator_id' />"
-" </signal>"
-"\n"
-"<!-- Begin of test only methods/signals -->\n"
-"\n"
-" <method name='TriggerResync1' />"
-"\n"
-" <method name='TriggerResync1Sent'>"
-" <arg type='b' name='sent' direction='out'/>"
-" </method>"
-"\n"
-" </interface>\n"
-"</node>\n"
-;
-static void bus_got_cb (GObject *object, GAsyncResult * res, gpointer user_data);
-static void bus_method (GDBusConnection *connection,
- const gchar *sender,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *method_name,
- GVariant *parameters,
- GDBusMethodInvocation *invocation,
- gpointer user_data);
-
-G_DEFINE_TYPE(ServicePanel, service_panel, G_TYPE_OBJECT);
-static GDBusNodeInfo * node_info = NULL;
-static GDBusInterfaceInfo * iface_info = NULL;
-static GDBusInterfaceVTable bus_vtable = {
- method_call: bus_method,
- get_property: NULL,
- set_property: NULL,
-};
-
-struct _ServicePanelPrivate
-{
- GDBusConnection * bus;
- GCancellable * bus_lookup;
- guint bus_registration;
- guint sig_emission_handle;
-};
-
-static void
-service_panel_dispose(GObject* object)
-{
- ServicePanel* self = SERVICE_PANEL(object);
- if (self->priv->bus_lookup != NULL) {
- g_cancellable_cancel(self->priv->bus_lookup);
- g_object_unref(self->priv->bus_lookup);
- self->priv->bus_lookup = NULL;
- }
-
- if (self->priv->bus_registration != 0) {
- g_dbus_connection_unregister_object(self->priv->bus, self->priv->bus_registration);
- self->priv->bus_registration = 0;
- }
-
- if (self->priv->bus != NULL) {
- g_object_unref(self->priv->bus);
- self->priv->bus = NULL;
- }
-
- if (self->priv->sig_emission_handle) {
- g_source_remove(self->priv->sig_emission_handle);
- self->priv->sig_emission_handle = 0;
- }
-
-}
-
-static void
-service_panel_class_init(ServicePanelClass* klass)
-{
- G_OBJECT_CLASS(klass)->dispose = service_panel_dispose;
- g_type_class_add_private (klass, sizeof (ServicePanelPrivate));
-
- if (node_info == NULL)
- {
- GError * error = NULL;
-
- node_info = g_dbus_node_info_new_for_xml(panel_interface, &error);
- if (error != NULL)
- {
- g_error("Unable to parse Panel interface: %s", error->message);
- g_error_free(error);
- }
- }
-
- if (node_info != NULL && iface_info == NULL)
- {
- iface_info = g_dbus_node_info_lookup_interface(node_info,"com.canonical.Unity.Panel.Service");
- if (iface_info == NULL)
- {
- g_error("Unable to find interface 'com.canonical.Unity.Panel.Service'");
- }
- }
-
-}
-
-static void
-service_panel_init(ServicePanel* self)
-{
- self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, SERVICE_TYPE_PANEL, ServicePanelPrivate);
- self->priv->bus = NULL;
- self->priv->bus_lookup = NULL;
- self->priv->bus_registration = 0;
-
- self->priv->bus_lookup = g_cancellable_new();
- g_bus_get(G_BUS_TYPE_SESSION, self->priv->bus_lookup, bus_got_cb, self);
-}
-
-ServicePanel*
-service_panel_new()
-{
- return g_object_new(SERVICE_TYPE_PANEL, NULL);
-}
-
-static void
-bus_got_cb (GObject *object, GAsyncResult * res, gpointer user_data)
-{
- GError * error = NULL;
- ServicePanel * self = SERVICE_PANEL(user_data);
- GDBusConnection * bus;
-
- bus = g_bus_get_finish(res, &error);
- if (error != NULL) {
- g_critical("Unable to get bus: %s", error->message);
- g_error_free(error);
- return;
- }
-
- self->priv->bus = bus;
-
- /* Register object */
- self->priv->bus_registration = g_dbus_connection_register_object(bus,
- /* path */ "/com/canonical/Unity/Panel/Service",
- /* interface */ iface_info,
- /* vtable */ &bus_vtable,
- /* userdata */ self,
- /* destroy */ NULL,
- /* error */ &error);
-
- if (error != NULL) {
- g_critical ("Unable to create bus connection object, %s", error->message);
- g_error_free(error);
- return;
- }
-
- return;
-}
-
-static void
-add_entry_id(GVariantBuilder *b)
-{
- g_variant_builder_add (b, "(ssssbbusbbi)",
- "test_indicator_id",
- "test_entry_id",
- "test_entry_name_hint",
- "test_entry_label",
- TRUE, /* label sensitive */
- TRUE, /* label visible */
- 0, /* image type */
- "", /* image_data */
- TRUE, /* image sensitive */
- TRUE, /* image visible */
- 1 /* priority */);
-}
-
-static void
-add_entry_id_2(GVariantBuilder *b)
-{
- g_variant_builder_add (b, "(ssssbbusbbi)",
- "test_indicator_id",
- "test_entry_id2",
- "test_entry_name_hint2",
- "test_entry_label2",
- TRUE, /* label sensitive */
- TRUE, /* label visible */
- 0, /* image type */
- "", /* image_data */
- TRUE, /* image sensitive */
- TRUE, /* image visible */
- 1 /* priority */);
-}
-
-static int sync_return_mode = 0;
-static int trigger_resync1_sent = FALSE;
-
-static void
-bus_method (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data)
-{
- if (g_strcmp0(method_name, "Sync") == 0)
- {
- GVariantBuilder b;
-
- g_variant_builder_init (&b, G_VARIANT_TYPE ("(a(ssssbbusbbi))"));
- g_variant_builder_open (&b, G_VARIANT_TYPE ("a(ssssbbusbbi)"));
-
- if (sync_return_mode == 0)
- {
- add_entry_id(&b);
- add_entry_id_2(&b);
- }
- else if (sync_return_mode == 1)
- {
- add_entry_id_2(&b);
- add_entry_id(&b);
- }
-
- g_variant_builder_close (&b);
-
- g_dbus_method_invocation_return_value(invocation, g_variant_builder_end (&b));
-
- if (sync_return_mode == 1)
- {
- trigger_resync1_sent = TRUE;
- }
- }
- else if (g_strcmp0(method_name, "TriggerResync1") == 0)
- {
- sync_return_mode = 1;
- trigger_resync1_sent = FALSE;
-
- g_dbus_method_invocation_return_value(invocation, NULL);
- GVariantBuilder ret_builder;
- g_variant_builder_init(&ret_builder, G_VARIANT_TYPE_TUPLE);
- g_variant_builder_add_value(&ret_builder, g_variant_new_string(""));
- g_dbus_connection_emit_signal (connection, NULL, "/com/canonical/Unity/Panel/Service", "com.canonical.Unity.Panel.Service", "ReSync", g_variant_builder_end(&ret_builder), NULL);
- }
- else if (g_strcmp0(method_name, "TriggerResync1Sent") == 0)
- {
- GVariantBuilder ret_builder;
- g_variant_builder_init(&ret_builder, G_VARIANT_TYPE ("(b)"));
- g_variant_builder_add_value (&ret_builder, g_variant_new_boolean(trigger_resync1_sent));
- g_dbus_method_invocation_return_value(invocation, g_variant_builder_end (&ret_builder));
- }
-
- return;
-}
-
diff --git a/tests/test_service_panel.cpp b/tests/test_service_panel.cpp
new file mode 100644
index 000000000..a00ef5b32
--- /dev/null
+++ b/tests/test_service_panel.cpp
@@ -0,0 +1,123 @@
+#include "test_service_panel.h"
+
+namespace unity
+{
+namespace service
+{
+namespace
+{
+static const char * panel_interface =
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+"<node name=\"/\">\n"
+" <interface name=\"com.canonical.Unity.Panel.Service\">\n"
+"\n"
+"<!-- Begin of real methods/signals -->\n"
+" <method name='Sync'>"
+" <arg type='a(ssssbbusbbi)' name='state' direction='out'/>"
+" </method>"
+"\n"
+" <signal name='ReSync'>"
+" <arg type='s' name='indicator_id' />"
+" </signal>"
+"\n"
+"<!-- Begin of test only methods/signals -->\n"
+"\n"
+" <method name='TriggerResync1' />"
+"\n"
+" <method name='TriggerResync1Sent'>"
+" <arg type='b' name='sent' direction='out'/>"
+" </method>"
+"\n"
+" </interface>\n"
+"</node>\n"
+;
+
+void add_entry_id(GVariantBuilder *b)
+{
+ g_variant_builder_add (b, "(ssssbbusbbi)",
+ "test_indicator_id",
+ "test_entry_id",
+ "test_entry_name_hint",
+ "test_entry_label",
+ TRUE, /* label sensitive */
+ TRUE, /* label visible */
+ 0, /* image type */
+ "", /* image_data */
+ TRUE, /* image sensitive */
+ TRUE, /* image visible */
+ 1 /* priority */);
+}
+
+void add_entry_id_2(GVariantBuilder *b)
+{
+ g_variant_builder_add (b, "(ssssbbusbbi)",
+ "test_indicator_id",
+ "test_entry_id2",
+ "test_entry_name_hint2",
+ "test_entry_label2",
+ TRUE, /* label sensitive */
+ TRUE, /* label visible */
+ 0, /* image type */
+ "", /* image_data */
+ TRUE, /* image sensitive */
+ TRUE, /* image visible */
+ 1 /* priority */);
+}
+}
+
+
+Panel::Panel()
+ : sync_return_mode_(0)
+ , trigger_resync1_sent_(false)
+{
+ auto object = glib::DBusObjectBuilder::GetObjectsForIntrospection(panel_interface).front();
+ object->SetMethodsCallsHandler(sigc::mem_fun(this, &Panel::OnMethodCall));
+
+ server_.AddObject(object, "/com/canonical/Unity/Panel/Service");
+}
+
+GVariant* Panel::OnMethodCall(std::string const& method, GVariant *parameters)
+{
+ if (method == "Sync")
+ {
+ GVariantBuilder b;
+
+ g_variant_builder_init (&b, G_VARIANT_TYPE ("(a(ssssbbusbbi))"));
+ g_variant_builder_open (&b, G_VARIANT_TYPE ("a(ssssbbusbbi)"));
+
+ if (sync_return_mode_ == 0)
+ {
+ add_entry_id(&b);
+ add_entry_id_2(&b);
+ }
+ else if (sync_return_mode_ == 1)
+ {
+ add_entry_id_2(&b);
+ add_entry_id(&b);
+ }
+
+ if (sync_return_mode_ == 1)
+ {
+ trigger_resync1_sent_ = true;
+ }
+
+ g_variant_builder_close (&b);
+ return g_variant_builder_end (&b);
+ }
+ else if (method == "TriggerResync1")
+ {
+ sync_return_mode_ = 1;
+ trigger_resync1_sent_ = false;
+
+ server_.GetObjects().front()->EmitSignal("ReSync", g_variant_new("(s)", ""));
+ }
+ else if (method == "TriggerResync1Sent")
+ {
+ return g_variant_new("(b)", trigger_resync1_sent_ ? TRUE : FALSE);
+ }
+
+ return nullptr;
+}
+
+}
+}
diff --git a/tests/test_service_panel.h b/tests/test_service_panel.h
index aa160e231..a66471409 100644
--- a/tests/test_service_panel.h
+++ b/tests/test_service_panel.h
@@ -1,46 +1,28 @@
#ifndef _SERVICE_PANEL_H_
#define _SERVICE_PANEL_H_
-#include <glib-object.h>
-G_BEGIN_DECLS
+#include <UnityCore/GLibDBusServer.h>
-#define SERVICE_TYPE_PANEL (service_panel_get_type ())
-
-#define SERVICE_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
- SERVICE_TYPE_PANEL, ServicePanel))
-
-#define SERVICE_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
- SERVICE_TYPE_PANEL, ServicePanelClass))
-
-#define SERVICE_IS_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
- SERVICE_TYPE_PANEL))
-
-#define SERVICE_IS_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
- SERVICE_TYPE_PANEL))
-
-#define ServicePanel_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
- SERVICE_TYPE_PANEL, ServicePanelClass))
-
-typedef struct _ServicePanel ServicePanel;
-typedef struct _ServicePanelClass ServicePanelClass;
-typedef struct _ServicePanelPrivate ServicePanelPrivate;
-
-struct _ServicePanel
+namespace unity
+{
+namespace service
{
- GObject parent;
-
- ServicePanelPrivate *priv;
-};
-struct _ServicePanelClass
+class Panel
{
- GObjectClass parent_class;
-};
+public:
+ Panel();
+
+private:
+ GVariant* OnMethodCall(std::string const& method, GVariant *parameters);
-GType service_panel_get_type(void) G_GNUC_CONST;
+ unsigned sync_return_mode_;
+ bool trigger_resync1_sent_;
-ServicePanel* service_panel_new(void);
+ glib::DBusServer server_;
+};
-G_END_DECLS
+}
+}
#endif /* _SERVICE_PANEL_H_ */
diff --git a/tests/test_software_center_launcher_icon.cpp b/tests/test_software_center_launcher_icon.cpp
index a89e33bd7..e8bd920b8 100644
--- a/tests/test_software_center_launcher_icon.cpp
+++ b/tests/test_software_center_launcher_icon.cpp
@@ -124,7 +124,7 @@ TEST_F(TestSoftwareCenterLauncherIcon, Animate)
Settings settings;
panel::Style panel;
- nux::ObjectPtr<nux::BaseWindow> win(new nux::BaseWindow(""));
+ nux::ObjectPtr<MockableBaseWindow> win(new MockableBaseWindow(""));
nux::ObjectPtr<Launcher> launcher(new Launcher(win.GetPointer()));
launcher->options = Options::Ptr(new Options);
launcher->SetModel(LauncherModel::Ptr(new LauncherModel));
diff --git a/tests/test_switcher_model.cpp b/tests/test_switcher_model.cpp
index 9643a39ae..75d995f83 100644
--- a/tests/test_switcher_model.cpp
+++ b/tests/test_switcher_model.cpp
@@ -158,4 +158,24 @@ TEST_F(TestSwitcherModel, SelectionIsActive)
EXPECT_TRUE(model.SelectionIsActive());
}
+TEST_F(TestSwitcherModel, TestWebAppActive)
+{
+ // Create a base case
+ SwitcherModel::Ptr base_model(new SwitcherModel(icons_));
+
+ // Set the first icon as Active to simulate Firefox being active
+ icons_.front()->SetQuirk(AbstractLauncherIcon::Quirk::ACTIVE, true);
+
+ // Set the last icon as Active to simulate that it is a WebApp
+ icons_.back()->SetQuirk(AbstractLauncherIcon::Quirk::ACTIVE, true);
+
+ SwitcherModel::Ptr model(new SwitcherModel(icons_));
+
+ model->DetailXids();
+
+ // model's front Window should be different than the base case due to the
+ // re-sorting in DetailXids().
+ EXPECT_NE(model->DetailXids().front(), base_model->DetailXids().front());
+}
+
}
diff --git a/tests/test_thumbnail_generator.cpp b/tests/test_thumbnail_generator.cpp
index 361837f62..239ee9b32 100644
--- a/tests/test_thumbnail_generator.cpp
+++ b/tests/test_thumbnail_generator.cpp
@@ -30,7 +30,6 @@ using namespace testing;
#include "config.h"
using namespace unity;
-using namespace unity::dash;
namespace
{
diff --git a/tests/test_tooltip_manager.cpp b/tests/test_tooltip_manager.cpp
new file mode 100644
index 000000000..c7f2583ed
--- /dev/null
+++ b/tests/test_tooltip_manager.cpp
@@ -0,0 +1,54 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Jacob Edwards <j.johan.edwards@gmail.com>
+ */
+
+#include <gtest/gtest.h>
+using namespace testing;
+
+#include "launcher/TooltipManager.h"
+#include "launcher/MockLauncherIcon.h"
+#include "test_utils.h"
+
+namespace unity
+{
+namespace launcher
+{
+
+namespace
+{
+
+TEST(TestTooltipManager, TestHideAndShowTooltip)
+{
+ // Makes sure that TooltipManager calls icon->ShowTooltip() when the mouse
+ // hovers it, and icon->HideTooltip() after the mouse dehovers it.
+ TooltipManager tm;
+ MockLauncherIcon* icon = new MockLauncherIcon();
+
+ tm.SetIcon(AbstractLauncherIcon::Ptr(icon));
+ tm.MouseMoved();
+ Utils::WaitForTimeoutMSec(1050);
+
+ EXPECT_TRUE(icon->IsTooltipVisible());
+ tm.SetIcon(AbstractLauncherIcon::Ptr());
+ EXPECT_FALSE(icon->IsTooltipVisible());
+}
+
+}
+
+} // launcher
+} // unity
diff --git a/tests/test_utils.h b/tests/test_utils.h
index 10935d5c7..c31a393bb 100644
--- a/tests/test_utils.h
+++ b/tests/test_utils.h
@@ -1,37 +1,16 @@
#ifndef TEST_UTILS_H
#define TEST_UTILS_H
-#include <UnityCore/Model.h>
+#include <glib.h>
+#include <functional>
+#include <gtest/gtest.h>
namespace
{
-using unity::dash::Model;
-
class Utils
{
public:
- template <typename Adaptor>
- static void WaitForModelSynchronize(Model<Adaptor>& model, unsigned int n_rows)
- {
- bool timeout_reached = false;
-
- auto timeout_cb = [](gpointer data) -> gboolean
- {
- *(bool*)data = true;
- return FALSE;
- };
-
- guint32 timeout_id = g_timeout_add(10000, timeout_cb, &timeout_reached);
-
- while (model.count != n_rows && !timeout_reached)
- {
- g_main_context_iteration(g_main_context_get_thread_default(), TRUE);
- }
- if (model.count == n_rows)
- g_source_remove(timeout_id);
- }
-
static void WaitUntilMSec(bool& success, unsigned int max_wait = 500)
{
WaitUntilMSec([&success] {return success;}, true, max_wait);
@@ -44,6 +23,8 @@ public:
static void WaitUntilMSec(std::function<bool()> const& check_function, bool result = true, unsigned max_wait = 500)
{
+ ASSERT_NE(check_function, nullptr);
+
bool timeout_reached = false;
guint32 timeout_id = ScheduleTimeout(&timeout_reached, max_wait);
diff --git a/unity-shared/DashStyle.cpp b/unity-shared/DashStyle.cpp
index 00724e8a2..4fe69663f 100755
--- a/unity-shared/DashStyle.cpp
+++ b/unity-shared/DashStyle.cpp
@@ -60,6 +60,9 @@ Style* style_instance = nullptr;
const int STATES = 5;
+const double BUTTON_CORNER_RADIUS = 7.0;
+
+
// These cairo overrides may also be reused somewhere...
void cairo_set_source_rgba(cairo_t* cr, nux::Color const& color)
{
@@ -147,6 +150,15 @@ public:
double cornerRadius,
double width,
double height,
+ Segment segment);
+
+ void RoundedRectSegmentBorder(cairo_t* cr,
+ double aspect,
+ double x,
+ double y,
+ double cornerRadius,
+ double width,
+ double height,
Segment segment,
Arrow arrow,
nux::ButtonVisualState state);
@@ -963,6 +975,108 @@ void Style::Impl::RoundedRectSegment(cairo_t* cr,
double cornerRadius,
double width,
double height,
+ Segment segment)
+{
+ double radius = cornerRadius / aspect;
+
+ bool odd = cairo_get_line_width (cr) == 2.0 ? false : true;
+
+ switch (segment)
+ {
+ case Segment::LEFT:
+ // top-left, right of the corner
+ cairo_move_to(cr, _align(x + radius, odd), _align(y, odd));
+
+ // top-right
+ cairo_line_to(cr, _align(x + width, odd), _align(y, odd));
+
+ // bottom-right
+ cairo_line_to(cr, _align(x + width, odd), _align(y + height, odd));
+
+ // bottom-left, right of the corner
+ cairo_line_to(cr, _align(x + radius, odd), _align(y + height, odd));
+
+ // bottom-left, above the corner
+ cairo_arc(cr,
+ _align(x + radius, odd),
+ _align(y + height - radius, odd),
+ radius,
+ 90.0f * G_PI / 180.0f,
+ 180.0f * G_PI / 180.0f);
+
+ // left, right of the corner
+ cairo_line_to(cr, _align(x, odd), _align(y + radius, odd));
+
+ // top-left, right of the corner
+ cairo_arc(cr,
+ _align(x + radius, odd),
+ _align(y + radius, odd),
+ radius,
+ 180.0f * G_PI / 180.0f,
+ 270.0f * G_PI / 180.0f);
+
+ break;
+
+ case Segment::MIDDLE:
+ // top-left
+ cairo_move_to(cr, _align(x, odd), _align(y, odd));
+
+ // top-right
+ cairo_line_to(cr, _align(x + width, odd), _align(y, odd));
+
+ // bottom-right
+ cairo_line_to(cr, _align(x + width, odd), _align(y + height, odd));
+
+ // bottom-left
+ cairo_line_to(cr, _align(x, odd), _align(y + height, odd));
+
+ // back to top-left
+ cairo_close_path(cr);
+ break;
+
+ case Segment::RIGHT:
+ // top-left, right of the corner
+ cairo_move_to(cr, _align(x, odd), _align(y, odd));
+
+ // top-right, left of the corner
+ cairo_line_to(cr, _align(x + width - radius, odd), _align(y, odd));
+
+ // top-right, below the corner
+ cairo_arc(cr,
+ _align(x + width - radius, odd),
+ _align(y + radius, odd),
+ radius,
+ -90.0f * G_PI / 180.0f,
+ 0.0f * G_PI / 180.0f);
+
+ // bottom-right, above the corner
+ cairo_line_to(cr, _align(x + width, odd), _align(y + height - radius, odd));
+
+ // bottom-right, left of the corner
+ cairo_arc(cr,
+ _align(x + width - radius, odd),
+ _align(y + height - radius, odd),
+ radius,
+ 0.0f * G_PI / 180.0f,
+ 90.0f * G_PI / 180.0f);
+
+ // bottom-left
+ cairo_line_to(cr, _align(x, odd), _align(y + height, odd));
+
+ // back to top-left
+ cairo_close_path(cr);
+ break;
+ }
+}
+
+
+void Style::Impl::RoundedRectSegmentBorder(cairo_t* cr,
+ double aspect,
+ double x,
+ double y,
+ double cornerRadius,
+ double width,
+ double height,
Segment segment,
Arrow arrow,
nux::ButtonVisualState state)
@@ -982,24 +1096,29 @@ void Style::Impl::RoundedRectSegment(cairo_t* cr,
// top-right
cairo_line_to(cr, _align(x + width, odd), _align(y, odd));
- if (arrow == Arrow::RIGHT && state == nux::VISUAL_STATE_PRESSED)
- {
+ if (arrow == Arrow::RIGHT || arrow == Arrow::BOTH)
+ {
cairo_line_to(cr, _align(x + width, odd), _align(y + height / 2.0 - arrow_h, odd));
cairo_line_to(cr, _align(x + width - arrow_w, odd), _align(y + height / 2.0, odd));
cairo_line_to(cr, _align(x + width, odd), _align(y + height / 2.0 + arrow_h, odd));
- }
-
- // bottom-right
- cairo_line_to(cr, _align(x + width, odd), _align(y + height, odd));
+
+ // bottom-right
+ cairo_line_to(cr, _align(x + width, odd), _align(y + height, odd));
+ }
+ else
+ {
+ // bottom-right
+ cairo_move_to(cr, _align(x + width, odd), _align(y + height, odd));
+ }
// bottom-left, right of the corner
cairo_line_to(cr, _align(x + radius, odd), _align(y + height, odd));
// bottom-left, above the corner
cairo_arc(cr,
- _align(x, odd) + _align(radius, odd),
- _align(y + height, odd) - _align(radius, odd),
- _align(radius, odd),
+ _align(x + radius, odd),
+ _align(y + height - radius, odd),
+ radius,
90.0f * G_PI / 180.0f,
180.0f * G_PI / 180.0f);
@@ -1008,9 +1127,9 @@ void Style::Impl::RoundedRectSegment(cairo_t* cr,
// top-left, right of the corner
cairo_arc(cr,
- _align(x, odd) + _align(radius, odd),
- _align(y, odd) + _align(radius, odd),
- _align(radius, odd),
+ _align(x + radius, odd),
+ _align(y + radius, odd),
+ radius,
180.0f * G_PI / 180.0f,
270.0f * G_PI / 180.0f);
@@ -1024,27 +1143,33 @@ void Style::Impl::RoundedRectSegment(cairo_t* cr,
cairo_line_to(cr, _align(x + width, odd), _align(y, odd));
if ((arrow == Arrow::RIGHT || arrow == Arrow::BOTH) && state == nux::VISUAL_STATE_PRESSED)
- {
+ {
cairo_line_to(cr, _align(x + width, odd), _align(y + height / 2.0 - arrow_h, odd));
cairo_line_to(cr, _align(x + width - arrow_w, odd), _align(y + height / 2.0, odd));
cairo_line_to(cr, _align(x + width, odd), _align(y + height / 2.0 + arrow_h, odd));
- }
-
- // bottom-right
- cairo_line_to(cr, _align(x + width, odd), _align(y + height, odd));
+
+ // bottom-right
+ cairo_line_to(cr, _align(x + width, odd), _align(y + height, odd));
+ }
+ else
+ {
+ // bottom-right
+ cairo_move_to(cr, _align(x + width, odd), _align(y + height, odd));
+ }
// bottom-left
cairo_line_to(cr, _align(x, odd), _align(y + height, odd));
if ((arrow == Arrow::LEFT || arrow == Arrow::BOTH) && state == nux::VISUAL_STATE_PRESSED)
- {
+ {
cairo_line_to(cr, _align(x, odd), _align(y + height / 2.0 + arrow_h, odd));
cairo_line_to(cr, _align(x + arrow_w, odd), _align(y + height / 2.0, odd));
cairo_line_to(cr, _align(x, odd), _align(y + height / 2.0 - arrow_h, odd));
- }
- // back to top-left
- cairo_close_path(cr);
+ // top-left
+ cairo_line_to(cr, _align(x, odd), _align(y, odd));
+ }
+
break;
case Segment::RIGHT:
@@ -1056,9 +1181,9 @@ void Style::Impl::RoundedRectSegment(cairo_t* cr,
// top-right, below the corner
cairo_arc(cr,
- _align(x + width, odd) - _align(radius, odd),
- _align(y, odd) + _align(radius, odd),
- _align(radius, odd),
+ _align(x + width - radius, odd),
+ _align(y + radius, odd),
+ radius,
-90.0f * G_PI / 180.0f,
0.0f * G_PI / 180.0f);
@@ -1067,28 +1192,30 @@ void Style::Impl::RoundedRectSegment(cairo_t* cr,
// bottom-right, left of the corner
cairo_arc(cr,
- _align(x + width, odd) - _align(radius, odd),
- _align(y + height, odd) - _align(radius, odd),
- _align(radius, odd),
+ _align(x + width - radius, odd),
+ _align(y + height - radius, odd),
+ radius,
0.0f * G_PI / 180.0f,
90.0f * G_PI / 180.0f);
// bottom-left
cairo_line_to(cr, _align(x, odd), _align(y + height, odd));
- if (arrow == Arrow::LEFT && state == nux::VISUAL_STATE_PRESSED)
- {
+ if ((arrow == Arrow::LEFT || arrow == Arrow::BOTH) && state == nux::VISUAL_STATE_PRESSED)
+ {
cairo_line_to(cr, _align(x, odd), _align(y + height / 2.0 + arrow_h, odd));
cairo_line_to(cr, _align(x + arrow_w, odd), _align(y + height / 2.0, odd));
cairo_line_to(cr, _align(x, odd), _align(y + height / 2.0 - arrow_h, odd));
- }
- // back to top-left
- cairo_close_path(cr);
+ // top-left,
+ cairo_line_to(cr, _align(x, odd), _align(y, odd));
+ }
+
break;
}
}
+
void Style::Impl::ButtonOutlinePathSegment(cairo_t* cr, Segment segment)
{
double x = 0.0;
@@ -1563,7 +1690,7 @@ bool Style::Button(cairo_t* cr, nux::ButtonVisualState state,
1.0,
(double) (garnish) + 1.0,
(double) (garnish) + 1.0,
- 7.0,
+ BUTTON_CORNER_RADIUS,
w - (double) (2 * garnish) - 2.0,
h - (double) (2 * garnish) - 2.0);
else
@@ -1571,7 +1698,7 @@ bool Style::Button(cairo_t* cr, nux::ButtonVisualState state,
1.0,
(double) (garnish) + 0.5,
(double) (garnish) + 0.5,
- 7.0,
+ BUTTON_CORNER_RADIUS,
w - (double) (2 * garnish) - 1.0,
h - (double) (2 * garnish) - 1.0);
@@ -1664,7 +1791,7 @@ bool Style::SquareButton(cairo_t* cr, nux::ButtonVisualState state,
cairo_move_to(cr, _align(x + width, odd), y);
if (curve_bottom)
{
- double radius = 7.0;
+ double radius = BUTTON_CORNER_RADIUS;
LOG_DEBUG(logger) << "curve: " << _align(x + width, odd) << " - " << _align(y + height - radius, odd);
// line to bottom-right corner
cairo_line_to(cr, _align(x + width, odd), _align(y + height - radius, odd));
@@ -1771,7 +1898,7 @@ bool Style::ButtonFocusOverlay(cairo_t* cr, float alpha)
1.0,
(double) 0.5,
(double) 0.5,
- 7.0,
+ BUTTON_CORNER_RADIUS,
w - 1.0,
h - 1.0);
@@ -1785,6 +1912,7 @@ bool Style::ButtonFocusOverlay(cairo_t* cr, float alpha)
bool Style::MultiRangeSegment(cairo_t* cr,
nux::ButtonVisualState state,
std::string const& label,
+ int font_px_size,
Arrow arrow,
Segment segment)
{
@@ -1812,42 +1940,51 @@ bool Style::MultiRangeSegment(cairo_t* cr,
w -= 2.0;
}
- cairo_set_line_width(cr, pimpl->button_label_border_size_[state]);
+ cairo_set_line_width(cr, pimpl->button_label_border_size_[nux::VISUAL_STATE_NORMAL]);
- if (pimpl->button_label_border_size_[state] == 2.0)
- pimpl->RoundedRectSegment(cr,
- 1.0,
- x+1.0,
- y+1.0,
- (h-1.0) / 4.0,
- w-1.0,
- h-1.0,
- segment,
- arrow,
- state);
- else
- pimpl->RoundedRectSegment(cr,
+ pimpl->RoundedRectSegment(cr,
+ 1.0,
+ x,
+ y,
+ BUTTON_CORNER_RADIUS,
+ w,
+ h,
+ segment);
+
+ if (pimpl->button_label_fill_color_[state].alpha != 0.0)
+ {
+ cairo_set_source_rgba(cr, pimpl->button_label_fill_color_[state]);
+ cairo_fill_preserve(cr);
+ }
+
+ cairo_set_source_rgba(cr, pimpl->button_label_border_color_[nux::VISUAL_STATE_NORMAL]);
+ cairo_stroke(cr); // do not preseve path
+
+ if (state == nux::VISUAL_STATE_PRESSED)
+ {
+ int line_width = pimpl->button_label_border_size_[state];
+ cairo_set_line_width(cr, line_width);
+
+ pimpl->RoundedRectSegmentBorder(cr,
1.0,
x,
- y,
- h / 4.0,
+ y + line_width/2,
+ BUTTON_CORNER_RADIUS,
w,
- h,
+ h - line_width,
segment,
arrow,
state);
- if (pimpl->button_label_fill_color_[state].alpha != 0.0)
- {
- cairo_set_source_rgba(cr, pimpl->button_label_fill_color_[state]);
- cairo_fill_preserve(cr);
+ cairo_set_source_rgba(cr, pimpl->button_label_border_color_[state]);
+ cairo_stroke(cr); // do not preseve path
}
- cairo_set_source_rgba(cr, pimpl->button_label_border_color_[state]);
- cairo_stroke(cr);
+
+
pimpl->Text(cr,
pimpl->button_label_text_color_[state],
label,
- 10); // 13px = 10pt
+ font_px_size);
return true;
}
@@ -1888,9 +2025,7 @@ bool Style::MultiRangeFocusOverlay(cairo_t* cr,
h / 4.0,
w,
h,
- segment,
- arrow,
- nux::ButtonVisualState::VISUAL_STATE_PRESSED);
+ segment);
cairo_set_source_rgba(cr, nux::Color(1.0f, 1.0f, 1.0f, 0.5f));
cairo_fill_preserve(cr);
diff --git a/unity-shared/DashStyle.h b/unity-shared/DashStyle.h
index 53f70165d..e0154f4ed 100755
--- a/unity-shared/DashStyle.h
+++ b/unity-shared/DashStyle.h
@@ -111,6 +111,7 @@ public:
virtual bool MultiRangeSegment(cairo_t* cr,
nux::ButtonVisualState state,
std::string const& label,
+ int font_px_size,
Arrow arrow,
Segment segment);
diff --git a/unity-shared/DebugDBusInterface.cpp b/unity-shared/DebugDBusInterface.cpp
index 7aedca53a..41f8fc974 100644
--- a/unity-shared/DebugDBusInterface.cpp
+++ b/unity-shared/DebugDBusInterface.cpp
@@ -35,7 +35,6 @@
namespace unity
{
-const std::string DBUS_BUS_NAME = "com.canonical.Unity";
namespace debug
{
@@ -56,9 +55,12 @@ void SetLogSeverity(std::string const& log_component,
void LogMessage(std::string const& severity,
std::string const& message);
-const char* DebugDBusInterface::DBUS_DEBUG_OBJECT_PATH = "/com/canonical/Unity/Debug";
+namespace dbus
+{
+const std::string BUS_NAME = "com.canonical.Unity";
+const std::string OBJECT_PATH = "/com/canonical/Unity/Debug";
-const gchar DebugDBusInterface::introspection_xml[] =
+const std::string INTROSPECTION_XML =
" <node>"
" <interface name='com.canonical.Autopilot.Introspection'>"
""
@@ -90,135 +92,59 @@ const gchar DebugDBusInterface::introspection_xml[] =
""
" </interface>"
" </node>";
-
-GDBusInterfaceVTable DebugDBusInterface::interface_vtable =
-{
- DebugDBusInterface::HandleDBusMethodCall,
- NULL,
- NULL
-};
+}
static Introspectable* _parent_introspectable;
DebugDBusInterface::DebugDBusInterface(Introspectable* parent)
+ : server_(dbus::BUS_NAME)
{
_parent_introspectable = parent;
- _owner_id = g_bus_own_name(G_BUS_TYPE_SESSION,
- unity::DBUS_BUS_NAME.c_str(),
- G_BUS_NAME_OWNER_FLAGS_NONE,
- &DebugDBusInterface::OnBusAcquired,
- &DebugDBusInterface::OnNameAcquired,
- &DebugDBusInterface::OnNameLost,
- this,
- NULL);
-}
-
-DebugDBusInterface::~DebugDBusInterface()
-{
- g_bus_unown_name(_owner_id);
-}
-
-void
-DebugDBusInterface::OnBusAcquired(GDBusConnection* connection, const gchar* name, gpointer data)
-{
- int i = 0;
- GError* error;
-
- GDBusNodeInfo* introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, NULL);
- if (!introspection_data)
- {
- LOG_WARNING(logger) << "No dbus introspection data could be loaded. State introspection will not work";
- return;
- }
- while (introspection_data->interfaces[i] != NULL)
- {
- error = NULL;
- g_dbus_connection_register_object(connection,
- DebugDBusInterface::DBUS_DEBUG_OBJECT_PATH,
- introspection_data->interfaces[i],
- &interface_vtable,
- data,
- NULL,
- &error);
- if (error != NULL)
- {
- g_warning("Could not register debug interface onto d-bus");
- g_error_free(error);
- }
- i++;
- }
- g_dbus_node_info_unref(introspection_data);
-}
+ server_.AddObjects(dbus::INTROSPECTION_XML, dbus::OBJECT_PATH);
-void
-DebugDBusInterface::OnNameAcquired(GDBusConnection* connection, const gchar* name, gpointer data)
-{
+ for (auto const& obj : server_.GetObjects())
+ obj->SetMethodsCallsHandler(&DebugDBusInterface::HandleDBusMethodCall);
}
-void
-DebugDBusInterface::OnNameLost(GDBusConnection* connection, const gchar* name, gpointer data)
+GVariant* DebugDBusInterface::HandleDBusMethodCall(std::string const& method, GVariant* parameters)
{
-}
-
-void
-DebugDBusInterface::HandleDBusMethodCall(GDBusConnection* connection,
- const gchar* sender,
- const gchar* object_path,
- const gchar* interface_name,
- const gchar* method_name,
- GVariant* parameters,
- GDBusMethodInvocation* invocation,
- gpointer user_data)
-{
- if (g_strcmp0(method_name, "GetState") == 0)
+ if (method == "GetState")
{
- GVariant* ret;
const gchar* input;
g_variant_get(parameters, "(&s)", &input);
- ret = GetState(input);
- // GetState returns a floating variant and
- // g_dbus_method_invocation_return_value ref sinks it
- g_dbus_method_invocation_return_value(invocation, ret);
+ return GetState(input);
}
- else if (g_strcmp0(method_name, "StartLogToFile") == 0)
+ else if (method == "StartLogToFile")
{
const gchar* log_path;
g_variant_get(parameters, "(&s)", &log_path);
StartLogToFile(log_path);
- g_dbus_method_invocation_return_value(invocation, NULL);
}
- else if (g_strcmp0(method_name, "ResetLogging") == 0)
+ else if (method == "ResetLogging")
{
ResetLogging();
- g_dbus_method_invocation_return_value(invocation, NULL);
}
- else if (g_strcmp0(method_name, "SetLogSeverity") == 0)
+ else if (method == "SetLogSeverity")
{
const gchar* component;
const gchar* severity;
g_variant_get(parameters, "(&s&s)", &component, &severity);
SetLogSeverity(component, severity);
- g_dbus_method_invocation_return_value(invocation, NULL);
}
- else if (g_strcmp0(method_name, "LogMessage") == 0)
+ else if (method == "LogMessage")
{
const gchar* severity;
const gchar* message;
g_variant_get(parameters, "(&s&s)", &severity, &message);
LogMessage(severity, message);
- g_dbus_method_invocation_return_value(invocation, NULL);
- }
- else
- {
- g_dbus_method_invocation_return_dbus_error(invocation,
- unity::DBUS_BUS_NAME.c_str(),
- "Failed to find method");
}
+
+ return nullptr;
}
diff --git a/unity-shared/DebugDBusInterface.h b/unity-shared/DebugDBusInterface.h
index 3c11a5a0b..99dbb1751 100644
--- a/unity-shared/DebugDBusInterface.h
+++ b/unity-shared/DebugDBusInterface.h
@@ -22,6 +22,8 @@
#ifndef _DEBUG_DBUS_INTERFACE_H
#define _DEBUG_DBUS_INTERFACE_H
+#include <UnityCore/GLibDBusServer.h>
+
class CompScreen;
namespace unity
@@ -37,29 +39,12 @@ class DebugDBusInterface
{
public:
DebugDBusInterface(Introspectable* introspectable);
- ~DebugDBusInterface();
private:
- /* methods */
- static void OnBusAcquired(GDBusConnection* connection, const gchar* name, gpointer data);
- static void OnNameAcquired(GDBusConnection* connection, const gchar* name, gpointer data);
- static void OnNameLost(GDBusConnection* connection, const gchar* name, gpointer data);
- static void HandleDBusMethodCall(GDBusConnection* connection,
- const gchar* sender,
- const gchar* object_path,
- const gchar* interface_name,
- const gchar* method_name,
- GVariant* parameters,
- GDBusMethodInvocation* invocation,
- gpointer user_data);
- static const char* DBUS_DEBUG_OBJECT_PATH;
- static const gchar introspection_xml[];
- static GDBusInterfaceVTable interface_vtable;
-
+ static GVariant* HandleDBusMethodCall(std::string const&, GVariant*);
static GVariant* BuildFakeReturn();
- /* members */
- guint _owner_id;
+ glib::DBusServer server_;
};
}
}
diff --git a/unity-shared/LayoutSystem.cpp b/unity-shared/LayoutSystem.cpp
index 6a73f8b6c..93070ecc9 100644
--- a/unity-shared/LayoutSystem.cpp
+++ b/unity-shared/LayoutSystem.cpp
@@ -264,6 +264,7 @@ LayoutWindow::LayoutWindow(Window xid)
, decoration_height(0)
, selected(false)
, aspect_ratio(geo.width / static_cast<float>(geo.height))
+ , alpha(0.0f)
{
auto& wm = WindowManager::Default();
diff --git a/unity-shared/MockableBaseWindow.h b/unity-shared/MockableBaseWindow.h
index 7888e59a9..fb52eef06 100644
--- a/unity-shared/MockableBaseWindow.h
+++ b/unity-shared/MockableBaseWindow.h
@@ -35,6 +35,7 @@ public:
MockableBaseWindow(char const* window_name = "", NUX_FILE_LINE_PROTO)
: nux::BaseWindow(window_name, NUX_TRACKER_LOCATION)
+ , struts_enabled_(false)
{}
/**
@@ -45,6 +46,22 @@ public:
* testing.
*/
virtual void SetOpacity(float opacity) { BaseWindow::SetOpacity(opacity); }
+
+ virtual void InputWindowEnableStruts(bool enable)
+ {
+ struts_enabled_ = enable;
+ BaseWindow::InputWindowEnableStruts(enable);
+ }
+
+ virtual bool InputWindowStrutsEnabled()
+ {
+ if (!InputWindowEnabled())
+ return struts_enabled_;
+
+ return BaseWindow::InputWindowStrutsEnabled();
+ }
+
+ bool struts_enabled_;
};
}
diff --git a/unity-shared/OverlayWindowButtons.cpp b/unity-shared/OverlayWindowButtons.cpp
index cdba19f8e..bdf609639 100644
--- a/unity-shared/OverlayWindowButtons.cpp
+++ b/unity-shared/OverlayWindowButtons.cpp
@@ -67,10 +67,18 @@ void OverlayWindowButtons::Hide()
QueueDraw();
}
+nux::Point GetRelativeMousePosition(nux::Point const& pos)
+{
+ int monitor = unity::UScreen::GetDefault()->GetMonitorWithMouse();
+ nux::Geometry const& geo = unity::UScreen::GetDefault()->GetMonitorGeometry(monitor);
+
+ return nux::Point(pos.x - geo.x, pos.y - geo.y);
+}
+
nux::Area* OverlayWindowButtons::FindAreaUnderMouse(nux::Point const& mouse_position,
nux::NuxEventType event_type)
{
- return window_buttons_->FindAreaUnderMouse(mouse_position, event_type);
+ return window_buttons_->FindAreaUnderMouse(GetRelativeMousePosition(mouse_position), event_type);
}
void OverlayWindowButtons::Draw(nux::GraphicsEngine& gfx_context, bool force_draw)
diff --git a/unity-shared/PluginAdapter.cpp b/unity-shared/PluginAdapter.cpp
index 9fbc46598..ef033ebbc 100644
--- a/unity-shared/PluginAdapter.cpp
+++ b/unity-shared/PluginAdapter.cpp
@@ -1113,6 +1113,26 @@ nux::Point PluginAdapter::GetCurrentViewport() const
return nux::Point(vp.x(), vp.y());
}
+void PluginAdapter::SetViewportSize(int horizontal, int vertical)
+{
+ if (horizontal < 1 || vertical < 1)
+ {
+ LOG_ERROR(logger) << "Impossible to set viewport to invalid values "
+ << horizontal << "x" << vertical;
+ return;
+ }
+
+ CompOption::Value hsize;
+ hsize.set<int>(horizontal);
+ m_Screen->setOptionForPlugin("core", "hsize", hsize);
+
+ CompOption::Value vsize(vertical);
+ vsize.set<int>(vertical);
+ m_Screen->setOptionForPlugin("core", "vsize", vsize);
+
+ LOG_INFO(logger) << "Setting viewport size to " << hsize.i() << "x" << vsize.i();
+}
+
int PluginAdapter::GetViewportHSize() const
{
return m_Screen->vpSize().width();
diff --git a/unity-shared/PluginAdapter.h b/unity-shared/PluginAdapter.h
index 0827a6cf7..379e645e1 100644
--- a/unity-shared/PluginAdapter.h
+++ b/unity-shared/PluginAdapter.h
@@ -180,6 +180,7 @@ public:
int WorkspaceCount() const;
nux::Point GetCurrentViewport() const override;
+ void SetViewportSize(int horizontal, int vertical) override;
int GetViewportHSize() const override;
int GetViewportVSize() const override;
diff --git a/unity-shared/StandaloneWindowManager.cpp b/unity-shared/StandaloneWindowManager.cpp
index 9bac8bf18..e3c78972d 100644
--- a/unity-shared/StandaloneWindowManager.cpp
+++ b/unity-shared/StandaloneWindowManager.cpp
@@ -492,8 +492,11 @@ void StandaloneWindowManager::CheckWindowIntersections(nux::Geometry const& regi
{
}
-void StandaloneWindowManager::SetViewportSize(unsigned horizontal, unsigned vertical)
+void StandaloneWindowManager::SetViewportSize(int horizontal, int vertical)
{
+ if (horizontal < 1 || vertical < 1)
+ return;
+
nux::Size new_size(horizontal, vertical);
if (viewport_size_ == new_size)
diff --git a/unity-shared/StandaloneWindowManager.h b/unity-shared/StandaloneWindowManager.h
index d34836432..18a468e16 100644
--- a/unity-shared/StandaloneWindowManager.h
+++ b/unity-shared/StandaloneWindowManager.h
@@ -136,6 +136,7 @@ public:
virtual int WorkspaceCount() const;
nux::Point GetCurrentViewport() const override;
+ void SetViewportSize(int horizontal, int vertical);
int GetViewportHSize() const override;
int GetViewportVSize() const override;
@@ -152,7 +153,6 @@ public:
void SetScaleActiveForGroup(bool scale_active_for_group);
void SetCurrentDesktop(unsigned desktop_id);
- void SetViewportSize(unsigned horizontal, unsigned vertical);
void SetCurrentViewport(nux::Point const& vp);
void SetWorkareaGeometry(nux::Geometry const& geo);
diff --git a/unity-shared/UBusMessages.h b/unity-shared/UBusMessages.h
index 034e710ad..ab1a509bf 100644
--- a/unity-shared/UBusMessages.h
+++ b/unity-shared/UBusMessages.h
@@ -35,8 +35,8 @@
#define UBUS_DASH_ABOUT_TO_SHOW "DASH_ABOUT_TO_SHOW"
// Signal sent when an overlay interface is shown, includes a gvariant
-// gvariant format is (sb), (interface-name, can_maximize?)
-#define UBUS_OVERLAY_FORMAT_STRING "(sbi)"
+// gvariant format is (sb), (interface-name, can_maximize?, width, height)
+#define UBUS_OVERLAY_FORMAT_STRING "(sbiii)"
#define UBUS_OVERLAY_HIDDEN "OVERLAY_HIDDEN"
#define UBUS_OVERLAY_SHOWN "OVERLAY_SHOWN"
diff --git a/unity-shared/WindowButtons.cpp b/unity-shared/WindowButtons.cpp
index 83212de5a..101f5c5d4 100644
--- a/unity-shared/WindowButtons.cpp
+++ b/unity-shared/WindowButtons.cpp
@@ -429,8 +429,9 @@ void WindowButtons::OnOverlayShown(GVariant* data)
glib::String overlay_identity;
gboolean can_maximise = FALSE;
gint32 overlay_monitor = 0;
+ int width, height;
g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING,
- &overlay_identity, &can_maximise, &overlay_monitor);
+ &overlay_identity, &can_maximise, &overlay_monitor, &width, &height);
if (overlay_monitor != monitor())
{
@@ -500,8 +501,9 @@ void WindowButtons::OnOverlayHidden(GVariant* data)
glib::String overlay_identity;
gboolean can_maximise = FALSE;
gint32 overlay_monitor = 0;
+ int width, height;
g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING,
- &overlay_identity, &can_maximise, &overlay_monitor);
+ &overlay_identity, &can_maximise, &overlay_monitor, &width, &height);
if (overlay_monitor != monitor())
{
diff --git a/unity-shared/WindowManager.h b/unity-shared/WindowManager.h
index c24355d96..faf653eee 100644
--- a/unity-shared/WindowManager.h
+++ b/unity-shared/WindowManager.h
@@ -145,6 +145,7 @@ public:
virtual int WorkspaceCount() const = 0;
virtual nux::Point GetCurrentViewport() const = 0;
+ virtual void SetViewportSize(int horizontal, int vertical) = 0;
virtual int GetViewportHSize() const = 0;
virtual int GetViewportVSize() const = 0;