summaryrefslogtreecommitdiff
diff options
authorDaniel van Vugt <vanvugt@gmail.com>2012-02-07 15:42:12 +0800
committerDaniel van Vugt <vanvugt@gmail.com>2012-02-07 15:42:12 +0800
commit2d1db98b35885672f7602142e87431f437aedd3f (patch)
tree2c0f364c5865958947787db7f89f8fcfaa95afda
parentb4d7573a88ea2c532938e65f4b8ae42bb4b287e2 (diff)
parentff8f505e2eeb3d7c32f8cb7126b6b98156e1e754 (diff)
Rebase.
(bzr r1827.1.3)
-rw-r--r--CMakeLists.txt2
-rw-r--r--UnityCore/CMakeLists.txt2
-rw-r--r--UnityCore/GLibDBusProxy.cpp4
-rw-r--r--UnityCore/Hud.cpp255
-rw-r--r--UnityCore/Hud.h127
-rw-r--r--manual-tests/Hud.txt57
-rw-r--r--manual-tests/Showdesktop.txt15
-rw-r--r--plugins/unityshell/resources/close_dash.pngbin469 -> 1292 bytes
-rw-r--r--plugins/unityshell/resources/close_dash_prelight.pngbin469 -> 1383 bytes
-rw-r--r--plugins/unityshell/resources/close_dash_pressed.pngbin483 -> 1302 bytes
-rw-r--r--plugins/unityshell/resources/maximize_dash.pngbin367 -> 1185 bytes
-rw-r--r--plugins/unityshell/resources/maximize_dash_prelight.pngbin375 -> 1316 bytes
-rw-r--r--plugins/unityshell/resources/maximize_dash_pressed.pngbin413 -> 1211 bytes
-rw-r--r--plugins/unityshell/resources/minimize_dash.pngbin345 -> 1191 bytes
-rw-r--r--plugins/unityshell/resources/minimize_dash_prelight.pngbin345 -> 1191 bytes
-rw-r--r--plugins/unityshell/resources/minimize_dash_pressed.pngbin345 -> 1191 bytes
-rw-r--r--plugins/unityshell/resources/unmaximize_dash.pngbin376 -> 1187 bytes
-rw-r--r--plugins/unityshell/resources/unmaximize_dash_prelight.pngbin376 -> 1316 bytes
-rw-r--r--plugins/unityshell/resources/unmaximize_dash_pressed.pngbin424 -> 1211 bytes
-rw-r--r--plugins/unityshell/src/DashController.cpp12
-rw-r--r--plugins/unityshell/src/DashStyle.cpp140
-rw-r--r--plugins/unityshell/src/DashStyle.h11
-rw-r--r--plugins/unityshell/src/DashView.cpp1
-rw-r--r--plugins/unityshell/src/DashView.h2
-rw-r--r--plugins/unityshell/src/DeviceLauncherIcon.cpp1
-rw-r--r--plugins/unityshell/src/FilterAllButton.cpp1
-rw-r--r--plugins/unityshell/src/HudButton.cpp208
-rw-r--r--plugins/unityshell/src/HudButton.h81
-rw-r--r--plugins/unityshell/src/HudController.cpp385
-rw-r--r--plugins/unityshell/src/HudController.h113
-rw-r--r--plugins/unityshell/src/HudIcon.cpp95
-rw-r--r--plugins/unityshell/src/HudIcon.h73
-rw-r--r--plugins/unityshell/src/HudIconTextureSource.cpp110
-rw-r--r--plugins/unityshell/src/HudIconTextureSource.h51
-rw-r--r--plugins/unityshell/src/HudView.cpp398
-rw-r--r--plugins/unityshell/src/HudView.h118
-rw-r--r--plugins/unityshell/src/IMTextEntry.cpp5
-rw-r--r--plugins/unityshell/src/IMTextEntry.h3
-rw-r--r--plugins/unityshell/src/IconTexture.cpp15
-rw-r--r--plugins/unityshell/src/IconTexture.h7
-rw-r--r--plugins/unityshell/src/Introspectable.h9
-rw-r--r--plugins/unityshell/src/Launcher.cpp3
-rw-r--r--plugins/unityshell/src/LauncherController.cpp9
-rw-r--r--plugins/unityshell/src/LensBar.cpp10
-rw-r--r--plugins/unityshell/src/OverlayRenderer.cpp10
-rw-r--r--plugins/unityshell/src/OverlayRenderer.h2
-rw-r--r--plugins/unityshell/src/PanelTray.cpp5
-rw-r--r--plugins/unityshell/src/PointerBarrier.cpp5
-rw-r--r--plugins/unityshell/src/PointerBarrier.h1
-rw-r--r--plugins/unityshell/src/QuicklistMenuItemCheckmark.cpp42
-rw-r--r--plugins/unityshell/src/QuicklistMenuItemRadio.cpp46
-rw-r--r--plugins/unityshell/src/QuicklistView.cpp3
-rw-r--r--plugins/unityshell/src/SearchBar.cpp (renamed from plugins/unityshell/src/DashSearchBar.cpp)177
-rw-r--r--plugins/unityshell/src/SearchBar.h (renamed from plugins/unityshell/src/DashSearchBar.h)19
-rw-r--r--plugins/unityshell/src/SearchBarSpinner.cpp (renamed from plugins/unityshell/src/DashSearchBarSpinner.cpp)5
-rw-r--r--plugins/unityshell/src/SearchBarSpinner.h (renamed from plugins/unityshell/src/DashSearchBarSpinner.h)7
-rw-r--r--plugins/unityshell/src/SwitcherModel.cpp18
-rw-r--r--plugins/unityshell/src/UBusMessages.h2
-rw-r--r--plugins/unityshell/src/unity-root-accessible.cpp2
-rw-r--r--plugins/unityshell/src/unity-search-bar-accessible.cpp6
-rw-r--r--plugins/unityshell/src/unitya11y.cpp2
-rw-r--r--plugins/unityshell/src/unityshell.cpp88
-rw-r--r--plugins/unityshell/src/unityshell.h9
-rw-r--r--plugins/unityshell/unityshell.xml.in87
-rw-r--r--po/POTFILES.in2
-rw-r--r--standalone-clients/CMakeLists.txt69
-rw-r--r--standalone-clients/StandaloneHud.cpp171
-rw-r--r--standalone-clients/TestFilterBar.cpp2
-rw-r--r--standalone-clients/TestFilters.cpp10
-rw-r--r--standalone-clients/nux_automated_test_framework.cpp461
-rw-r--r--standalone-clients/nux_automated_test_framework.h127
-rw-r--r--standalone-clients/nux_test_framework.cpp129
-rw-r--r--standalone-clients/nux_test_framework.h61
-rw-r--r--standalone-clients/ui/TestQuicklist.cpp428
-rw-r--r--standalone-clients/ui/TestQuicklistVisuals.cpp52
-rw-r--r--tests/CMakeLists.txt5
-rw-r--r--tests/autopilot/autopilot/emulators/X11.py234
-rw-r--r--tests/autopilot/autopilot/emulators/bamf.py341
-rw-r--r--tests/autopilot/autopilot/emulators/unity.py278
-rw-r--r--tests/autopilot/autopilot/tests/__init__.py13
-rw-r--r--tests/autopilot/autopilot/tests/test_dash.py57
-rw-r--r--tests/autopilot/autopilot/tests/test_launcher.py21
-rw-r--r--tests/autopilot/autopilot/tests/test_showdesktop.py138
-rw-r--r--tests/autopilot/autopilot/tests/test_switcher.py48
-rw-r--r--tests/test_hud.cpp104
-rw-r--r--tests/test_service_hud.c268
-rw-r--r--tests/test_service_hud.h46
-rw-r--r--tests/test_service_main.c8
-rw-r--r--tests/unit/TestQuicklistMenuitems.cpp1
-rwxr-xr-xtools/unity-introspection-visualiser.py41
90 files changed, 5191 insertions, 783 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 14206c816..2c3998808 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -113,7 +113,7 @@ if (BOOT_LOGGER)
SET (BOOT_LOGGER_FLAG "-DENABLE_LOGGER")
endif (BOOT_LOGGER)
-SET (MAINTAINER_CFLAGS "-Werror -Wall -Wcast-align -Wno-uninitialized -Wempty-body -Wformat-security -Winit-self -Warray-bounds")
+SET (MAINTAINER_CFLAGS "-Wall -Wcast-align -Wno-uninitialized -Wempty-body -Wformat-security -Winit-self -Warray-bounds")
option (DISABLE_MAINTAINER_CFLAGS "Disable maintainer CFlags" OFF)
if (DISABLE_MAINTAINER_CFLAGS)
SET (MAINTAINER_CFLAGS "")
diff --git a/UnityCore/CMakeLists.txt b/UnityCore/CMakeLists.txt
index 3b0d5140b..0242eecab 100644
--- a/UnityCore/CMakeLists.txt
+++ b/UnityCore/CMakeLists.txt
@@ -21,6 +21,7 @@ set (CORE_HEADERS
GLibSignal-inl.h
GLibWrapper.h
GLibWrapper-inl.h
+ Hud.h
HomeLens.h
IndicatorEntry.h
Indicator.h
@@ -54,6 +55,7 @@ set (CORE_SOURCES
GLibDBusProxy.cpp
GLibSignal.cpp
GLibWrapper.cpp
+ Hud.cpp
HomeLens.cpp
Indicator.cpp
IndicatorEntry.cpp
diff --git a/UnityCore/GLibDBusProxy.cpp b/UnityCore/GLibDBusProxy.cpp
index 1cafe872c..bf77b0b08 100644
--- a/UnityCore/GLibDBusProxy.cpp
+++ b/UnityCore/GLibDBusProxy.cpp
@@ -141,11 +141,7 @@ void DBusProxy::Impl::OnNameAppeared(GDBusConnection* connection,
gpointer impl)
{
DBusProxy::Impl* self = static_cast<DBusProxy::Impl*>(impl);
-
LOG_DEBUG(logger) << self->name_ << " appeared";
-
- self->connected_ = true;
- self->owner_->connected.emit();
}
void DBusProxy::Impl::OnNameVanished(GDBusConnection* connection,
diff --git a/UnityCore/Hud.cpp b/UnityCore/Hud.cpp
new file mode 100644
index 000000000..d938d80a3
--- /dev/null
+++ b/UnityCore/Hud.cpp
@@ -0,0 +1,255 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+ * Copyright (C) 2011 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Gordon Allott <gord.allott@canonical.com>
+ */
+//
+#include "Hud.h"
+
+#include <gio/gio.h>
+#include <glib.h>
+#include <NuxCore/Logger.h>
+#include "GLibWrapper.h"
+#include "GLibDBusProxy.h"
+
+#include "config.h"
+
+#include <sigc++/bind.h>
+
+namespace unity
+{
+namespace hud
+{
+
+namespace
+{
+nux::logging::Logger logger("unity.hud.hud");
+const int request_number_of_results = 6;
+}
+
+// Impl classes
+class HudImpl
+{
+public:
+ HudImpl(std::string const& dbus_name,
+ std::string const& dbus_path,
+ Hud *parent)
+ : query_key_(NULL)
+ , proxy_(dbus_name, dbus_path, "com.canonical.hud")
+ , parent_(parent)
+ {
+ LOG_DEBUG(logger) << "Hud init with name: " << dbus_name << "and path: " << dbus_path;
+ proxy_.connected.connect([&]() {
+ LOG_DEBUG(logger) << "Hud Connected";
+ parent_->connected = true;
+ });
+
+ proxy_.Connect("UpdatedQuery", sigc::mem_fun(this, &HudImpl::UpdateQueryCallback));
+ }
+
+ void QueryCallback(GVariant* data);
+ void UpdateQueryCallback(GVariant* data);
+ void BuildQueries(GVariant* query_array);
+ void ExecuteByKey(GVariant* key, unsigned int timestamp);
+ void ExecuteQueryByStringCallback(GVariant* query, unsigned int timestamp);
+ void CloseQuery();
+
+ GVariant* query_key_;
+ Hud::Queries queries_;
+ glib::DBusProxy proxy_;
+ Hud* parent_;
+};
+
+void HudImpl::ExecuteByKey(GVariant* key, unsigned int timestamp)
+{
+ LOG_DEBUG(logger) << "Executing by Key";
+
+ GVariantBuilder tuple;
+ g_variant_builder_init(&tuple, G_VARIANT_TYPE_TUPLE);
+ g_variant_builder_add_value(&tuple, g_variant_new_variant(key));
+ g_variant_builder_add_value(&tuple, g_variant_new_uint32(timestamp));
+
+ proxy_.Call("ExecuteQuery", g_variant_builder_end(&tuple));
+}
+
+void HudImpl::ExecuteQueryByStringCallback(GVariant* query, unsigned int timestamp)
+{
+ if (g_variant_n_children(query) < 3)
+ {
+ LOG_ERROR(logger) << "Received (" << g_variant_n_children(query) << ") children in a query, expected 3";
+ return;
+ }
+
+ queries_.clear();
+
+ GVariant* query_key = g_variant_get_child_value(query, 2);
+ query_key_ = query_key;
+
+ GVariant* queries = g_variant_get_child_value(query, 1);
+ BuildQueries(queries);
+ g_variant_unref(queries);
+
+ if (queries_.empty() == false)
+ {
+ // we now execute based off the first result
+ ExecuteByKey(queries_.front()->key, timestamp);
+ CloseQuery();
+ }
+}
+
+void HudImpl::QueryCallback(GVariant* query)
+{
+ if (g_variant_n_children(query) < 3)
+ {
+ LOG_ERROR(logger) << "Received (" << g_variant_n_children(query) << ") children in a query, expected 3";
+ return;
+ }
+ queries_.clear();
+
+ // extract the information from the GVariants
+ GVariant* target = g_variant_get_child_value(query, 0);
+ g_variant_unref(target);
+
+ GVariant* query_key = g_variant_get_child_value(query, 2);
+ query_key_ = query_key;
+
+ GVariant* queries = g_variant_get_child_value(query, 1);
+ BuildQueries(queries);
+ g_variant_unref(queries);
+
+ parent_->queries_updated.emit(queries_);
+}
+
+void HudImpl::UpdateQueryCallback(GVariant* query)
+{
+ if (g_variant_n_children(query) < 3)
+ {
+ LOG_ERROR(logger) << "Received (" << g_variant_n_children(query) << ") children in a query, expected 3";
+ return;
+ }
+ // as we are expecting an update, we want to check
+ // and make sure that we are the actual receivers of
+ // the signal
+
+ GVariant* query_key = g_variant_get_child_value(query, 2);
+ if (g_variant_equal(query_key_, query_key))
+ {
+ GVariant* queries = g_variant_get_child_value(query, 1);
+ BuildQueries(queries);
+ g_variant_unref(queries);
+ }
+}
+
+void HudImpl::BuildQueries(GVariant* query_array)
+{
+ GVariantIter iter;
+ g_variant_iter_init(&iter, query_array);
+ glib::String formatted_text;
+ glib::String icon;
+ glib::String item_icon;
+ glib::String completion_text;
+ glib::String shortcut;
+ GVariant* key = NULL;
+
+ while (g_variant_iter_loop(&iter, "(sssssv)",
+ &formatted_text, &icon, &item_icon, &completion_text, &shortcut, &key))
+ {
+ queries_.push_back(Query::Ptr(new Query(formatted_text,
+ icon,
+ item_icon,
+ completion_text,
+ shortcut,
+ key)));
+ }
+}
+
+void HudImpl::CloseQuery()
+{
+ if (query_key_ == NULL)
+ {
+ LOG_WARN(logger) << "Attempted to close the hud connection without starting it";
+ }
+ else
+ {
+ GVariant* paramaters = g_variant_new("(v)", query_key_);
+ proxy_.Call("CloseQuery", paramaters);
+ g_variant_unref(query_key_);
+ query_key_ = NULL;
+ queries_.clear();
+ }
+}
+
+
+Hud::Hud(std::string const& dbus_name,
+ std::string const& dbus_path)
+ : connected(false)
+ , pimpl_(new HudImpl(dbus_name, dbus_path, this))
+{
+ pimpl_->parent_ = this;
+}
+
+Hud::~Hud()
+{
+ delete pimpl_;
+}
+
+void Hud::RequestQuery(std::string const& search_string)
+{
+ LOG_DEBUG(logger) << "Getting Query: " << search_string;
+ if (pimpl_->query_key_ != NULL)
+ {
+ CloseQuery();
+ }
+
+ GVariant* paramaters = g_variant_new("(si)",
+ search_string.c_str(),
+ request_number_of_results);
+ pimpl_->proxy_.Call("StartQuery", paramaters, sigc::mem_fun(this->pimpl_, &HudImpl::QueryCallback));
+}
+
+
+void Hud::ExecuteQuery(Query::Ptr query, unsigned int timestamp)
+{
+ LOG_DEBUG(logger) << "Executing query: " << query->formatted_text;
+ pimpl_->ExecuteByKey(query->key, timestamp);
+}
+
+void Hud::ExecuteQueryBySearch(std::string execute_string, unsigned int timestamp)
+{
+ //Does a search then executes the result based on that search
+ LOG_DEBUG(logger) << "Executing by string" << execute_string;
+ if (pimpl_->query_key_ != NULL)
+ {
+ CloseQuery();
+ }
+
+ GVariant* paramaters = g_variant_new("(si)",
+ execute_string.c_str(),
+ 1);
+
+ auto functor = sigc::mem_fun(this->pimpl_, &HudImpl::ExecuteQueryByStringCallback);
+
+ pimpl_->proxy_.Call("StartQuery", paramaters, sigc::bind(functor, timestamp));
+}
+
+void Hud::CloseQuery()
+{
+ //Send close hint to the hud
+ pimpl_->CloseQuery();
+}
+
+}
+}
diff --git a/UnityCore/Hud.h b/UnityCore/Hud.h
new file mode 100644
index 000000000..01acdf666
--- /dev/null
+++ b/UnityCore/Hud.h
@@ -0,0 +1,127 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+ * Copyright (C) 2011 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Gordon Allott <gord.allott@canonical.com>
+ */
+
+#ifndef UNITY_HUD_H
+#define UNITY_HUD_H
+
+#include <deque>
+#include <string>
+#include <memory>
+#include <NuxCore/Property.h>
+#include <glib/gvariant.h>
+
+namespace unity
+{
+namespace hud
+{
+
+
+class Query
+{
+public:
+ typedef std::shared_ptr<Query> Ptr;
+
+ Query(std::string const& formatted_text_, std::string const& icon_name_,
+ std::string const& item_icon_, std::string const& completion_text_,
+ std::string const& shortcut_, GVariant* key_)
+ : formatted_text(formatted_text_)
+ , icon_name(icon_name_)
+ , item_icon(item_icon_)
+ , completion_text(completion_text_)
+ , shortcut(shortcut_)
+ , key(key_)
+ {
+ g_variant_ref(key);
+ }
+
+ ~Query()
+ {
+ g_variant_unref(key);
+ }
+
+ Query(const Query &rhs);
+ Query& operator=(Query);
+
+ std::string formatted_text; // Pango formatted text
+ std::string icon_name; // icon name using standard lookups
+ std::string item_icon; // Future API
+ std::string completion_text; // Non formatted text f or completion
+ std::string shortcut; // Shortcut key
+ GVariant *key;
+};
+
+
+class HudImpl;
+class Hud
+{
+public:
+ typedef std::shared_ptr<Hud> Ptr;
+ typedef std::deque<Query::Ptr> Queries;
+
+ /*
+ * Constructor for the hud
+ * \param dbus_name string that specifies the name of the hud service
+ * \param dbus_path string that specifies the path of the hud service
+ */
+ Hud(std::string const& dbus_name,
+ std::string const& dbus_path);
+
+ ~Hud();
+
+ Hud(const Hud &rhs);
+ Hud& operator=(Hud);
+
+ nux::Property<std::string> target;
+ nux::Property<bool> connected;
+
+ /*
+ * Queries the service for new suggestions, will fire off the
+ * suggestion_search_finished signal when the suggestions are returned
+ */
+ void RequestQuery(std::string const& search_string);
+
+ /*
+ * Executes a Query
+ */
+ void ExecuteQuery(Query::Ptr query, unsigned int timestamp);
+
+ /*
+ * Executes a query that returns from a search,
+ * Implicitly calls CloseQuery();
+ */
+ void ExecuteQueryBySearch(std::string execute_string, unsigned int timestamp);
+
+ /*
+ * Closes the query connection, call when the hud closes
+ */
+ void CloseQuery();
+
+ /*
+ * Returns a deque of Query types when the service provides them
+ */
+ sigc::signal<void, Queries> queries_updated;
+
+private:
+ HudImpl *pimpl_;
+};
+
+}
+}
+
+#endif /* UNITY_HUD_H */
diff --git a/manual-tests/Hud.txt b/manual-tests/Hud.txt
new file mode 100644
index 000000000..9975bee38
--- /dev/null
+++ b/manual-tests/Hud.txt
@@ -0,0 +1,57 @@
+For reference, the term Tap means to press the indicated key and release it, within a timeframe of 50ms
+
+Hud Invocate
+-----------
+This test makes sure that the hud presents itself, the launcher hides
+and the panel changes
+
+#. Tap Alt
+
+Outcome
+ The hud interface presents itself with no other interface such as the dash present.
+ The Launcher hides, the panel becomes transparent with a colour tint matching the hud
+
+Hud Search
+-----------
+This test makes sure that the hud will search and activate items.
+
+#. Ensure the devices indicator is present
+#. Tap Alt
+#. Type "system" to search for the "System settings..." item in the devices indicator
+#. Press return to activate the search query.
+
+Outcome
+ The system settings interface presents itself, the hud disappears.
+ If the hud does not disappear, this test failed. If the system settings interface
+ did not present itself, this test did *not* fail.
+
+
+Hud Key-Navigation
+-----------
+This test ensures the hud key navigation is intact
+
+#. Ensure the messaging indicator is present
+#. Tap Alt
+#. Type "Message" to search for items from the messaging indicator
+#. Press down twice
+#. Press return
+
+Outcome
+ The item selected will activate and the hud with disappear.
+ If the hud does not disappear, this test failed.
+ If the buttons under the search box do not highlight, this test failed.
+
+
+Hud Dismiss
+----------
+This test ensures that the hud is dismissable
+
+#. Tap Alt
+#. Type "test"
+#. Press escape
+#. Click anywhere on the screen that is not the hud interface
+
+Outcome
+ After pressing escape in step three, the text "test" should be removed from the hud search
+ After step four, the hud should dismiss itself and not be present.
+
diff --git a/manual-tests/Showdesktop.txt b/manual-tests/Showdesktop.txt
deleted file mode 100644
index e06ca4704..000000000
--- a/manual-tests/Showdesktop.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-Test Showdesktop Mode
--------------------
-This test shows that the "show desktop" mode works correctly
-
-#. Open two applications
-#. Use either alt-tab or ctrl-alt-d to activate "show desktop" mode
-#. Use either alt-tab or ctrl-alt-d to deactivate "show desktop" mode
-#. Use either alt-tab or ctrl-alt-d to activate "show desktop" mode
-#. Select an active application from the launcher
-#. Use either alt-tab or ctrl-alt-d to deactivate "show desktop" mode
-
-Outcome
- Both windows will fade out, both windows will fade in, both windows
- will fade out, the clicked application will fade in only, all other
- windows will fade in.
diff --git a/plugins/unityshell/resources/close_dash.png b/plugins/unityshell/resources/close_dash.png
index 876d39e41..3925bda11 100644
--- a/plugins/unityshell/resources/close_dash.png
+++ b/plugins/unityshell/resources/close_dash.png
Binary files differ
diff --git a/plugins/unityshell/resources/close_dash_prelight.png b/plugins/unityshell/resources/close_dash_prelight.png
index 876d39e41..2d6233509 100644
--- a/plugins/unityshell/resources/close_dash_prelight.png
+++ b/plugins/unityshell/resources/close_dash_prelight.png
Binary files differ
diff --git a/plugins/unityshell/resources/close_dash_pressed.png b/plugins/unityshell/resources/close_dash_pressed.png
index 90c1f7e89..bdcc40787 100644
--- a/plugins/unityshell/resources/close_dash_pressed.png
+++ b/plugins/unityshell/resources/close_dash_pressed.png
Binary files differ
diff --git a/plugins/unityshell/resources/maximize_dash.png b/plugins/unityshell/resources/maximize_dash.png
index a9102870c..6c48f11da 100644
--- a/plugins/unityshell/resources/maximize_dash.png
+++ b/plugins/unityshell/resources/maximize_dash.png
Binary files differ
diff --git a/plugins/unityshell/resources/maximize_dash_prelight.png b/plugins/unityshell/resources/maximize_dash_prelight.png
index b9ce8f341..05d4d4653 100644
--- a/plugins/unityshell/resources/maximize_dash_prelight.png
+++ b/plugins/unityshell/resources/maximize_dash_prelight.png
Binary files differ
diff --git a/plugins/unityshell/resources/maximize_dash_pressed.png b/plugins/unityshell/resources/maximize_dash_pressed.png
index 739d07a02..a1b26e20d 100644
--- a/plugins/unityshell/resources/maximize_dash_pressed.png
+++ b/plugins/unityshell/resources/maximize_dash_pressed.png
Binary files differ
diff --git a/plugins/unityshell/resources/minimize_dash.png b/plugins/unityshell/resources/minimize_dash.png
index c934104d0..05352beca 100644
--- a/plugins/unityshell/resources/minimize_dash.png
+++ b/plugins/unityshell/resources/minimize_dash.png
Binary files differ
diff --git a/plugins/unityshell/resources/minimize_dash_prelight.png b/plugins/unityshell/resources/minimize_dash_prelight.png
index c934104d0..05352beca 100644
--- a/plugins/unityshell/resources/minimize_dash_prelight.png
+++ b/plugins/unityshell/resources/minimize_dash_prelight.png
Binary files differ
diff --git a/plugins/unityshell/resources/minimize_dash_pressed.png b/plugins/unityshell/resources/minimize_dash_pressed.png
index c934104d0..05352beca 100644
--- a/plugins/unityshell/resources/minimize_dash_pressed.png
+++ b/plugins/unityshell/resources/minimize_dash_pressed.png
Binary files differ
diff --git a/plugins/unityshell/resources/unmaximize_dash.png b/plugins/unityshell/resources/unmaximize_dash.png
index 133e7058b..9cd411bea 100644
--- a/plugins/unityshell/resources/unmaximize_dash.png
+++ b/plugins/unityshell/resources/unmaximize_dash.png
Binary files differ
diff --git a/plugins/unityshell/resources/unmaximize_dash_prelight.png b/plugins/unityshell/resources/unmaximize_dash_prelight.png
index 133e7058b..2b836fd14 100644
--- a/plugins/unityshell/resources/unmaximize_dash_prelight.png
+++ b/plugins/unityshell/resources/unmaximize_dash_prelight.png
Binary files differ
diff --git a/plugins/unityshell/resources/unmaximize_dash_pressed.png b/plugins/unityshell/resources/unmaximize_dash_pressed.png
index f2bdc3a9f..ad305cb04 100644
--- a/plugins/unityshell/resources/unmaximize_dash_pressed.png
+++ b/plugins/unityshell/resources/unmaximize_dash_pressed.png
Binary files differ
diff --git a/plugins/unityshell/src/DashController.cpp b/plugins/unityshell/src/DashController.cpp
index bd994f99d..da1cd0159 100644
--- a/plugins/unityshell/src/DashController.cpp
+++ b/plugins/unityshell/src/DashController.cpp
@@ -118,6 +118,18 @@ void Controller::RegisterUBusInterests()
sigc::mem_fun(this, &Controller::OnActivateRequest));
ubus_manager_.RegisterInterest(UBUS_DASH_ABOUT_TO_SHOW,
[&] (GVariant*) { EnsureDash(); });
+ ubus_manager_.RegisterInterest(UBUS_OVERLAY_SHOWN, [&] (GVariant *data) {
+ 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);
+
+ // hide if something else is coming up
+ if (g_strcmp0(overlay_identity, "dash"))
+ {
+ HideDash(true);
+ }
+ });
}
void Controller::EnsureDash()
diff --git a/plugins/unityshell/src/DashStyle.cpp b/plugins/unityshell/src/DashStyle.cpp
index 94f819f62..a3f39c585 100644
--- a/plugins/unityshell/src/DashStyle.cpp
+++ b/plugins/unityshell/src/DashStyle.cpp
@@ -119,6 +119,7 @@ public:
void Text(cairo_t* cr,
nux::Color const& color,
std::string const& label,
+ int font_size = -1,
double horizMargin = 10.0,
Alignment alignment = Alignment::CENTER);
@@ -1325,6 +1326,7 @@ void Style::Impl::GetTextExtents(int& width,
void Style::Impl::Text(cairo_t* cr,
nux::Color const& color,
std::string const& label,
+ int text_size,
double horizMargin,
Alignment alignment)
{
@@ -1358,6 +1360,11 @@ void Style::Impl::Text(cairo_t* cr,
else
desc = pango_font_description_from_string(fontName);
+ if (text_size > 0)
+ {
+ pango_font_description_set_absolute_size(desc, text_size * PANGO_SCALE);
+ }
+
PangoWeight weight;
switch (regular_text_weight_)
{
@@ -1428,6 +1435,7 @@ void Style::Impl::Text(cairo_t* cr,
pango_layout_get_extents(layout, &ink, &log);
x = horizMargin; // let pango alignment handle the x position
y = ((double) h - pango_units_to_double(log.height)) / 2.0;
+
cairo_move_to(cr, x, y);
pango_cairo_show_layout(cr, layout);
@@ -1530,7 +1538,9 @@ void Style::Impl::DrawOverlay(cairo_t* cr,
cairo_set_operator(cr, old);
}
-bool Style::Button(cairo_t* cr, nux::ButtonVisualState state, std::string const& label, Alignment alignment)
+bool Style::Button(cairo_t* cr, nux::ButtonVisualState state,
+ std::string const& label, int font_size,
+ Alignment alignment, bool zeromargin)
{
// sanity checks
if (cairo_status(cr) != CAIRO_STATUS_SUCCESS)
@@ -1539,8 +1549,10 @@ bool Style::Button(cairo_t* cr, nux::ButtonVisualState state, std::string const&
if (cairo_surface_get_type(cairo_get_target(cr)) != CAIRO_SURFACE_TYPE_IMAGE)
return false;
- unsigned int garnish = GetButtonGarnishSize();
-
+ unsigned int garnish = 0;
+ if (zeromargin == false)
+ garnish = GetButtonGarnishSize();
+
//ButtonOutlinePath(cr, true);
double w = cairo_image_surface_get_width(cairo_get_target(cr));
double h = cairo_image_surface_get_height(cairo_get_target(cr));
@@ -1571,7 +1583,6 @@ bool Style::Button(cairo_t* cr, nux::ButtonVisualState state, std::string const&
cairo_fill_preserve(cr);
}
cairo_set_source_rgba(cr, pimpl->button_label_border_color_[state]);
- //cairo_set_line_width(cr, pimpl->button_label_border_size_[state]);
cairo_stroke(cr);
pimpl->DrawOverlay(cr,
@@ -1582,12 +1593,133 @@ bool Style::Button(cairo_t* cr, nux::ButtonVisualState state, std::string const&
pimpl->Text(cr,
pimpl->button_label_text_color_[state],
label,
+ font_size,
10.0,
alignment);
return true;
}
+bool Style::SquareButton(cairo_t* cr, nux::ButtonVisualState state,
+ std::string const& label, bool curve_bottom,
+ int font_size, Alignment alignment,
+ bool zeromargin)
+{
+ // sanity checks
+ if (cairo_status(cr) != CAIRO_STATUS_SUCCESS)
+ return false;
+
+ if (cairo_surface_get_type(cairo_get_target(cr)) != CAIRO_SURFACE_TYPE_IMAGE)
+ return false;
+
+ unsigned int garnish = 0;
+ if (zeromargin == false)
+ garnish = GetButtonGarnishSize();
+
+ double w = cairo_image_surface_get_width(cairo_get_target(cr));
+ double h = cairo_image_surface_get_height(cairo_get_target(cr));
+
+ double x = garnish;
+ double y = garnish;
+
+ double width = w - (2.0 * garnish) - 1.0;
+ double height = h - (2.0 * garnish) - 1.0;
+
+ bool odd = true;
+ double radius = 7.0;
+
+ // draw the grid background
+ {
+ cairo_set_line_width(cr, 1);
+ cairo_move_to(cr, _align(x + width, odd), _align(y, odd));
+ if (curve_bottom)
+ {
+ 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));
+
+ // line to 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);
+
+ // line to bottom-left, right of the corner
+ cairo_line_to(cr, _align(x + radius, odd), _align(y + height, odd));
+
+ // line to 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);
+
+ // line to top
+ cairo_line_to(cr, _align(x, odd), _align(y, odd));
+ }
+ else
+ {
+ cairo_line_to(cr, _align(x + width, odd), _align(y + height, odd));
+ cairo_line_to(cr, _align(x, odd), _align(x + height, odd));
+ cairo_line_to(cr, _align(x, odd), _align(y, odd));
+ }
+
+ cairo_set_source_rgba(cr, pimpl->button_label_border_color_[nux::ButtonVisualState::VISUAL_STATE_NORMAL]);
+ cairo_stroke(cr);
+ }
+
+ cairo_set_line_width(cr, pimpl->button_label_border_size_[state]);
+ odd = cairo_get_line_width(cr) == 2.0 ? false : true;
+
+
+ if (pimpl->button_label_border_size_[state] == 2.0)
+ {
+ x += 1;
+ y += 1;
+ width -= 1.0;
+ height -= 1.0;
+ }
+
+ if (state == nux::ButtonVisualState::VISUAL_STATE_PRESSED)
+ {
+ RoundedRect(cr,
+ 1.0,
+ _align(x, odd), _align(y, odd),
+ 5.0,
+ _align(width, odd), _align(height, odd));
+
+ 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);
+ }
+
+ pimpl->DrawOverlay(cr,
+ pimpl->button_label_overlay_opacity_[state],
+ pimpl->button_label_overlay_mode_[state],
+ pimpl->button_label_blur_size_[state] * 0.75);
+
+ // FIXME - magic value of 42 here for the offset in the HUD,
+ // replace with a nicer style system that lets hud override
+ // default values when it needs to
+ pimpl->Text(cr,
+ pimpl->button_label_text_color_[state],
+ label,
+ font_size,
+ 42.0 + 10.0,
+ alignment);
+
+ cairo_surface_write_to_png(cairo_get_target(cr), "/tmp/wut.png");
+
+ return true;
+}
+
bool Style::StarEmpty(cairo_t* cr, nux::ButtonVisualState state)
{
// sanity checks
diff --git a/plugins/unityshell/src/DashStyle.h b/plugins/unityshell/src/DashStyle.h
index 0c06244f6..ba10f7c9d 100644
--- a/plugins/unityshell/src/DashStyle.h
+++ b/plugins/unityshell/src/DashStyle.h
@@ -87,8 +87,15 @@ public:
static Style& Instance();
virtual bool Button(cairo_t* cr, nux::ButtonVisualState state,
- std::string const& label,
- Alignment alignment = Alignment::CENTER);
+ std::string const& label, int font_size=-1,
+ Alignment alignment = Alignment::CENTER,
+ bool zeromargin=false);
+
+ virtual bool SquareButton(cairo_t* cr, nux::ButtonVisualState state,
+ std::string const& label, bool curve_bottom,
+ int font_size=-1,
+ Alignment alignment = Alignment::CENTER,
+ bool zeromargin=false);
virtual bool StarEmpty(cairo_t* cr, nux::ButtonVisualState state);
diff --git a/plugins/unityshell/src/DashView.cpp b/plugins/unityshell/src/DashView.cpp
index bde256eee..c341bd137 100644
--- a/plugins/unityshell/src/DashView.cpp
+++ b/plugins/unityshell/src/DashView.cpp
@@ -154,6 +154,7 @@ void DashView::SetupViews()
lenses_layout_->AddView(home_view_);
lens_bar_ = new LensBar();
+ AddChild(lens_bar_);
lens_bar_->lens_activated.connect(sigc::mem_fun(this, &DashView::OnLensBarActivated));
content_layout_->AddView(lens_bar_, 0, nux::MINOR_POSITION_CENTER);
}
diff --git a/plugins/unityshell/src/DashView.h b/plugins/unityshell/src/DashView.h
index 938950665..80b64ada5 100644
--- a/plugins/unityshell/src/DashView.h
+++ b/plugins/unityshell/src/DashView.h
@@ -30,7 +30,7 @@
#include <UnityCore/HomeLens.h>
#include "BackgroundEffectHelper.h"
-#include "DashSearchBar.h"
+#include "SearchBar.h"
#include "Introspectable.h"
#include "LensBar.h"
#include "LensView.h"
diff --git a/plugins/unityshell/src/DeviceLauncherIcon.cpp b/plugins/unityshell/src/DeviceLauncherIcon.cpp
index eca15f17a..ec0e5ce4e 100644
--- a/plugins/unityshell/src/DeviceLauncherIcon.cpp
+++ b/plugins/unityshell/src/DeviceLauncherIcon.cpp
@@ -130,6 +130,7 @@ std::list<DbusmenuMenuitem*> DeviceLauncherIcon::GetMenus()
{
menu_item = dbusmenu_menuitem_new();
+ // TRANSLATORS: This refers to the action of formatting a device
dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Format..."));
dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
diff --git a/plugins/unityshell/src/FilterAllButton.cpp b/plugins/unityshell/src/FilterAllButton.cpp
index e3473d2ad..dc42e94f2 100644
--- a/plugins/unityshell/src/FilterAllButton.cpp
+++ b/plugins/unityshell/src/FilterAllButton.cpp
@@ -59,6 +59,7 @@ void FilterAllButton::OnStateChanged(nux::View* view)
{
if (filter_ and Active())
filter_->Clear();
+ QueueDraw();
}
void FilterAllButton::OnFilteringChanged(bool filtering)
diff --git a/plugins/unityshell/src/HudButton.cpp b/plugins/unityshell/src/HudButton.cpp
new file mode 100644
index 000000000..269ee401f
--- /dev/null
+++ b/plugins/unityshell/src/HudButton.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2011 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: Gordon Allott <gord.allott@canonical.com>
+ *
+ */
+#include "config.h"
+
+#include <pango/pango.h>
+#include <pango/pangocairo.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+#include <Nux/Nux.h>
+#include <NuxCore/Logger.h>
+#include <NuxImage/CairoGraphics.h>
+#include <NuxGraphics/NuxGraphics.h>
+#include <UnityCore/GLibWrapper.h>
+#include "DashStyle.h"
+
+#include "HudButton.h"
+
+namespace
+{
+nux::logging::Logger logger("unity.hud.HudButton");
+}
+
+namespace unity
+{
+namespace hud
+{
+
+
+HudButton::HudButton (nux::TextureArea *image, NUX_FILE_LINE_DECL)
+ : nux::Button (image, NUX_FILE_LINE_PARAM)
+ , is_rounded(false)
+ , is_focused_(false)
+{
+ InitTheme();
+ key_nav_focus_change.connect([this](nux::Area *area, bool recieving, nux::KeyNavDirection direction){ QueueDraw(); });
+}
+
+HudButton::HudButton (const std::string label_, NUX_FILE_LINE_DECL)
+ : nux::Button (NUX_FILE_LINE_PARAM)
+ , is_rounded(false)
+ , is_focused_(false)
+{
+ InitTheme();
+}
+
+HudButton::HudButton (const std::string label_, nux::TextureArea *image, NUX_FILE_LINE_DECL)
+ : nux::Button (image, NUX_FILE_LINE_PARAM)
+ , is_rounded(false)
+ , is_focused_(false)
+{
+ InitTheme();
+}
+
+HudButton::HudButton (NUX_FILE_LINE_DECL)
+ : nux::Button (NUX_FILE_LINE_PARAM)
+ , is_rounded(false)
+ , is_focused_(false)
+{
+ InitTheme();
+}
+
+HudButton::~HudButton() {
+}
+
+void HudButton::InitTheme()
+{
+ is_rounded.changed.connect([&] (bool rounded)
+ {
+ nux::Geometry geo = GetGeometry();
+ prelight_->Invalidate(geo);
+ active_->Invalidate(geo);
+ normal_->Invalidate(geo);
+ });
+
+ SetMinimumHeight(42);
+ if (!active_)
+ {
+ nux::Geometry const& geo = GetGeometry();
+
+ prelight_.reset(new nux::CairoWrapper(geo, sigc::bind(sigc::mem_fun(this, &HudButton::RedrawTheme), nux::ButtonVisualState::VISUAL_STATE_PRELIGHT)));
+ active_.reset(new nux::CairoWrapper(geo, sigc::bind(sigc::mem_fun(this, &HudButton::RedrawTheme), nux::ButtonVisualState::VISUAL_STATE_PRESSED)));
+ normal_.reset(new nux::CairoWrapper(geo, sigc::bind(sigc::mem_fun(this, &HudButton::RedrawTheme), nux::ButtonVisualState::VISUAL_STATE_NORMAL)));
+ }
+}
+
+void HudButton::RedrawTheme(nux::Geometry const& geom, cairo_t* cr, nux::ButtonVisualState faked_state)
+{
+ dash::Style::Instance().SquareButton(cr, faked_state, label_,
+ is_rounded, 17,
+ dash::Alignment::LEFT, true);
+}
+
+bool HudButton::AcceptKeyNavFocus()
+{
+ return true;
+}
+
+
+long HudButton::ComputeContentSize ()
+{
+ long ret = nux::Button::ComputeContentSize();
+ nux::Geometry const& geo = GetGeometry();
+
+ if (cached_geometry_ != geo)
+ {
+ prelight_->Invalidate(geo);
+ active_->Invalidate(geo);
+ normal_->Invalidate(geo);
+
+ cached_geometry_ = geo;
+ }
+
+ return ret;
+}
+
+void HudButton::Draw(nux::GraphicsEngine& GfxContext, bool force_draw)
+{
+ nux::Geometry const& geo = GetGeometry();
+ gPainter.PaintBackground(GfxContext, geo);
+ // set up our texture mode
+ nux::TexCoordXForm texxform;
+ texxform.SetWrap(nux::TEXWRAP_CLAMP, nux::TEXWRAP_CLAMP);
+ texxform.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD);
+
+ // clear what is behind us
+ unsigned int alpha = 0, src = 0, dest = 0;
+ GfxContext.GetRenderStates().GetBlend(alpha, src, dest);
+ GfxContext.GetRenderStates().SetPremultipliedBlend(nux::SRC_OVER);
+ GfxContext.GetRenderStates().SetBlend(true);
+
+ nux::Color col = nux::color::Black;
+ col.alpha = 0;
+ GfxContext.QRP_Color(geo.x,
+ geo.y,
+ geo.width,
+ geo.height,
+ col);
+
+ nux::BaseTexture* texture = normal_->GetTexture();
+ if (HasKeyFocus())
+ texture = active_->GetTexture();
+ else if (HasKeyFocus())
+ texture = prelight_->GetTexture();
+ else if (GetVisualState() == nux::ButtonVisualState::VISUAL_STATE_PRESSED)
+ texture = active_->GetTexture();
+
+ GfxContext.QRP_1Tex(geo.x,
+ geo.y,
+ texture->GetWidth() + 1, // FIXME !! - jay, nux has gone crazy, unless i specify +1 here, it won't render the entire texture
+ texture->GetHeight(),
+ texture->GetDeviceTexture(),
+ texxform,
+ nux::Color(1.0f, 1.0f, 1.0f, 1.0f));
+
+ GfxContext.GetRenderStates().SetBlend(alpha, src, dest);
+}
+
+void HudButton::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) {
+}
+
+void HudButton::PostDraw(nux::GraphicsEngine& GfxContext, bool force_draw) {
+ nux::Button::PostDraw(GfxContext, force_draw);
+}
+
+void HudButton::SetQuery(Query::Ptr query)
+{
+ query_ = query;
+ label_ = query->formatted_text;
+ label = query->formatted_text;
+}
+
+Query::Ptr HudButton::GetQuery()
+{
+ return query_;
+}
+
+// Introspectable
+std::string HudButton::GetName() const
+{
+ return "HudButton";
+}
+
+void HudButton::AddProperties(GVariantBuilder* builder)
+{
+ g_variant_builder_add(builder, "{sv}", "label", g_variant_new_string(label_.c_str()));
+}
+
+}
+}
diff --git a/plugins/unityshell/src/HudButton.h b/plugins/unityshell/src/HudButton.h
new file mode 100644
index 000000000..ef55760d3
--- /dev/null
+++ b/plugins/unityshell/src/HudButton.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2011 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: Gordon Allott <gord.allott@canonical.com>
+ *
+ */
+
+
+
+#ifndef FILTERBASICBUTTON_H
+#define FILTERBASICBUTTON_H
+
+#include <Nux/Nux.h>
+#include <Nux/CairoWrapper.h>
+#include <Nux/Button.h>
+#include <Nux/TextureArea.h>
+#include <UnityCore/Hud.h>
+#include "Introspectable.h"
+
+namespace unity {
+namespace hud {
+class HudButton : public nux::Button, public unity::debug::Introspectable
+{
+ typedef nux::ObjectPtr<nux::BaseTexture> BaseTexturePtr;
+public:
+ typedef nux::ObjectPtr<HudButton> Ptr;
+ HudButton (nux::TextureArea *image, NUX_FILE_LINE_PROTO);
+ HudButton (const std::string label, NUX_FILE_LINE_PROTO);
+ HudButton (const std::string label, nux::TextureArea *image, NUX_FILE_LINE_PROTO);
+ HudButton (NUX_FILE_LINE_PROTO);
+ virtual ~HudButton();
+
+ void SetQuery(Query::Ptr query);
+ std::shared_ptr<Query> GetQuery();
+
+ nux::Property<std::string> label;
+ nux::Property<std::string> hint;
+ nux::Property<bool> is_rounded;
+protected:
+
+ virtual bool AcceptKeyNavFocus();
+ virtual long ComputeContentSize();
+ virtual void Draw(nux::GraphicsEngine& GfxContext, bool force_draw);
+ virtual void DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw);
+ virtual void PostDraw(nux::GraphicsEngine& GfxContext, bool force_draw);
+
+ std::string GetName() const;
+ void AddProperties(GVariantBuilder* builder);
+
+ void InitTheme ();
+ void RedrawTheme(nux::Geometry const& geom, cairo_t* cr, nux::ButtonVisualState faked_state);
+ typedef std::unique_ptr<nux::CairoWrapper> NuxCairoPtr;
+
+ NuxCairoPtr prelight_;
+ NuxCairoPtr active_;
+ NuxCairoPtr normal_;
+
+private:
+ std::string label_;
+
+ Query::Ptr query_;
+ nux::Geometry cached_geometry_;
+ bool is_focused_;
+};
+}
+}
+#endif // FILTERBASICBUTTON_H
diff --git a/plugins/unityshell/src/HudController.cpp b/plugins/unityshell/src/HudController.cpp
new file mode 100644
index 000000000..bf02375f2
--- /dev/null
+++ b/plugins/unityshell/src/HudController.cpp
@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) 2010 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Gord Allott <gord.allott@canonical.com>
+ */
+
+#include "HudController.h"
+
+#include <NuxCore/Logger.h>
+#include <Nux/HLayout.h>
+#include "PluginAdapter.h"
+#include "UBusMessages.h"
+#include "UScreen.h"
+namespace unity
+{
+namespace hud
+{
+
+namespace
+{
+nux::logging::Logger logger("unity.hud.controller");
+}
+
+Controller::Controller()
+ : launcher_width(66)
+ , panel_height(24)
+ , hud_service_("com.canonical.hud", "/com/canonical/hud")
+ , window_(0)
+ , visible_(false)
+ , need_show_(false)
+ , timeline_id_(0)
+ , last_opacity_(0.0f)
+ , start_time_(0)
+{
+ LOG_DEBUG(logger) << "hud startup";
+ SetupRelayoutCallbacks();
+
+ ubus.RegisterInterest(UBUS_HUD_CLOSE_REQUEST, sigc::mem_fun(this, &Controller::OnExternalHideHud));
+
+ //!!FIXME!! - just hijacks the dash close request so we get some more requests than normal,
+ ubus.RegisterInterest(UBUS_PLACE_VIEW_CLOSE_REQUEST, sigc::mem_fun(this, &Controller::OnExternalHideHud));
+
+ ubus.RegisterInterest(UBUS_OVERLAY_SHOWN, [&] (GVariant *data) {
+ 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);
+
+ if (g_strcmp0(overlay_identity, "hud"))
+ {
+ HideHud(true);
+ }
+ });
+
+ PluginAdapter::Default()->compiz_screen_ungrabbed.connect(sigc::mem_fun(this, &Controller::OnScreenUngrabbed));
+
+ hud_service_.queries_updated.connect(sigc::mem_fun(this, &Controller::OnQueriesFinished));
+ EnsureHud();
+}
+
+Controller::~Controller()
+{
+ if (window_)
+ window_->UnReference();
+ window_ = 0;
+
+ g_source_remove(timeline_id_);
+ g_source_remove(ensure_id_);
+}
+
+void Controller::SetupWindow()
+{
+ window_ = new nux::BaseWindow("Hud");
+ window_->SinkReference();
+ window_->SetBackgroundColor(nux::Color(0.0f, 0.0f, 0.0f, 0.0f));
+ window_->SetConfigureNotifyCallback(&Controller::OnWindowConfigure, this);
+ window_->ShowWindow(false);
+ window_->SetOpacity(0.0f);
+ window_->mouse_down_outside_pointer_grab_area.connect(sigc::mem_fun(this, &Controller::OnMouseDownOutsideWindow));
+}
+
+void Controller::SetupHudView()
+{
+ LOG_DEBUG(logger) << "SetupHudView called";
+ view_ = new View();
+
+ layout_ = new nux::HLayout(NUX_TRACKER_LOCATION);
+ layout_->AddView(view_, 1);
+ window_->SetLayout(layout_);
+
+ view_->mouse_down_outside_pointer_grab_area.connect(sigc::mem_fun(this, &Controller::OnMouseDownOutsideWindow));
+
+ LOG_DEBUG(logger) << "connecting to signals";
+ view_->search_changed.connect(sigc::mem_fun(this, &Controller::OnSearchChanged));
+ view_->search_activated.connect(sigc::mem_fun(this, &Controller::OnSearchActivated));
+ view_->query_activated.connect(sigc::mem_fun(this, &Controller::OnQueryActivated));
+ view_->query_selected.connect(sigc::mem_fun(this, &Controller::OnQuerySelected));
+}
+
+void Controller::SetupRelayoutCallbacks()
+{
+ GdkScreen* screen = gdk_screen_get_default();
+
+ sig_manager_.Add(new glib::Signal<void, GdkScreen*>(screen,
+ "monitors-changed", sigc::mem_fun(this, &Controller::Relayout)));
+ sig_manager_.Add(new glib::Signal<void, GdkScreen*>(screen,
+ "size-changed", sigc::mem_fun(this, &Controller::Relayout)));
+}
+
+void Controller::EnsureHud()
+{
+ if (window_)
+ return;
+
+ LOG_DEBUG(logger) << "Initializing Hud";
+
+ SetupWindow();
+ SetupHudView();
+ Relayout();
+ ensure_id_ = 0;
+}
+
+nux::BaseWindow* Controller::window() const
+{
+ return window_;
+}
+
+// We update the @geo that's sent in with our desired width and height
+void Controller::OnWindowConfigure(int window_width, int window_height,
+ nux::Geometry& geo, void* data)
+{
+ Controller* self = static_cast<Controller*>(data);
+ geo = self->GetIdealWindowGeometry();
+}
+
+nux::Geometry Controller::GetIdealWindowGeometry()
+{
+ UScreen *uscreen = UScreen::GetDefault();
+ int primary_monitor = uscreen->GetPrimaryMonitor();
+ auto monitor_geo = uscreen->GetMonitorGeometry(primary_monitor);
+
+ // We want to cover as much of the screen as possible to grab any mouse events outside
+ // of our window
+ return nux::Geometry (monitor_geo.x,
+ monitor_geo.y + panel_height,
+ monitor_geo.width,
+ monitor_geo.height - panel_height);
+}
+
+void Controller::Relayout(GdkScreen*screen)
+{
+ EnsureHud();
+ nux::Geometry content_geo = view_->GetGeometry();
+ nux::Geometry geo = GetIdealWindowGeometry();
+
+ window_->SetGeometry(geo);
+ layout_->SetMinMaxSize(content_geo.width, content_geo.height);
+ view_->SetWindowGeometry(window_->GetAbsoluteGeometry(), window_->GetGeometry());
+ view_->Relayout();
+}
+
+void Controller::OnMouseDownOutsideWindow(int x, int y,
+ unsigned long bflags, unsigned long kflags)
+{
+ LOG_DEBUG(logger) << "OnMouseDownOutsideWindow called";
+ HideHud();
+}
+
+void Controller::OnScreenUngrabbed()
+{
+ LOG_DEBUG(logger) << "OnScreenUngrabbed called";
+ if (need_show_)
+ {
+ EnsureHud();
+ ShowHud();
+ }
+}
+
+void Controller::OnExternalShowHud(GVariant* variant)
+{
+ EnsureHud();
+ visible_ ? HideHud() : ShowHud();
+}
+
+void Controller::OnExternalHideHud(GVariant* variant)
+{
+ LOG_DEBUG(logger) << "External Hiding the hud";
+ EnsureHud();
+ HideHud();
+}
+
+void Controller::ShowHideHud()
+{
+ EnsureHud();
+ visible_ ? HideHud(true) : ShowHud();
+}
+
+bool Controller::IsVisible()
+{
+ return visible_;
+}
+
+void Controller::ShowHud()
+{
+ LOG_DEBUG(logger) << "Showing the hud";
+ EnsureHud();
+ view_->AboutToShow();
+
+ window_->ShowWindow(true);
+ window_->PushToFront();
+ window_->EnableInputWindow(true, "Hud", true, false);
+ window_->SetInputFocus();
+ nux::GetWindowCompositor().SetKeyFocusArea(view_->default_focus());
+ window_->CaptureMouseDownAnyWhereElse(true);
+ view_->CaptureMouseDownAnyWhereElse(true);
+ window_->QueueDraw();
+
+ view_->ResetToDefault();
+
+ view_->SetIcon("");
+ hud_service_.RequestQuery("");
+ need_show_ = false;
+ visible_ = true;
+
+ StartShowHideTimeline();
+ view_->SetWindowGeometry(window_->GetAbsoluteGeometry(), window_->GetGeometry());
+
+ // 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, 0);
+ ubus.SendMessage(UBUS_OVERLAY_SHOWN, info);
+}
+void Controller::HideHud(bool restore)
+{
+ LOG_DEBUG (logger) << "hiding the hud";
+ if (visible_ == false)
+ return;
+
+ EnsureHud();
+ view_->AboutToHide();
+ window_->CaptureMouseDownAnyWhereElse(false);
+ window_->EnableInputWindow(false, "Hud", true, false);
+ visible_ = false;
+
+ StartShowHideTimeline();
+
+ restore = true;
+ if (restore)
+ PluginAdapter::Default ()->restoreInputFocus ();
+
+ hud_service_.CloseQuery();
+
+ //unhide the launcher
+ 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, 0);
+ ubus.SendMessage(UBUS_OVERLAY_HIDDEN, info);
+}
+
+void Controller::StartShowHideTimeline()
+{
+ EnsureHud();
+
+ if (timeline_id_)
+ g_source_remove(timeline_id_);
+
+ timeline_id_ = g_timeout_add(15, (GSourceFunc)Controller::OnViewShowHideFrame, this);
+ last_opacity_ = window_->GetOpacity();
+ start_time_ = g_get_monotonic_time();
+
+}
+
+gboolean Controller::OnViewShowHideFrame(Controller* self)
+{
+#define _LENGTH_ 90000
+ float diff = g_get_monotonic_time() - self->start_time_;
+ float progress = diff / (float)_LENGTH_;
+ float last_opacity = self->last_opacity_;
+
+ if (self->visible_)
+ {
+ self->window_->SetOpacity(last_opacity + ((1.0f - last_opacity) * progress));
+ }
+ else
+ {
+ self->window_->SetOpacity(last_opacity - (last_opacity * progress));
+ }
+
+ if (diff > _LENGTH_)
+ {
+ self->timeline_id_ = 0;
+
+ // Make sure the state is right
+ self->window_->SetOpacity(self->visible_ ? 1.0f : 0.0f);
+ if (!self->visible_)
+ {
+ self->window_->ShowWindow(false);
+ }
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void Controller::OnActivateRequest(GVariant* variant)
+{
+ EnsureHud();
+ ShowHud();
+}
+
+void Controller::OnSearchChanged(std::string search_string)
+{
+ LOG_DEBUG(logger) << "Search Changed";
+ hud_service_.RequestQuery(search_string);
+}
+
+void Controller::OnSearchActivated(std::string search_string)
+{
+ unsigned int timestamp = nux::GetWindowThread()->GetGraphicsDisplay().GetCurrentEvent().x11_timestamp;
+ hud_service_.ExecuteQueryBySearch(search_string, timestamp);
+ HideHud();
+}
+
+void Controller::OnQueryActivated(Query::Ptr query)
+{
+ LOG_DEBUG(logger) << "Activating query, " << query->formatted_text;
+ unsigned int timestamp = nux::GetWindowThread()->GetGraphicsDisplay().GetCurrentEvent().x11_timestamp;
+ hud_service_.ExecuteQuery(query, timestamp);
+ HideHud();
+}
+
+void Controller::OnQuerySelected(Query::Ptr query)
+{
+ LOG_DEBUG(logger) << "Selected query, " << query->formatted_text;
+ view_->SetIcon(query->icon_name);
+}
+
+
+void Controller::OnQueriesFinished(Hud::Queries queries)
+{
+ view_->SetQueries(queries);
+ std::string icon_name = "";
+ for (auto query = queries.begin(); query != queries.end(); query++)
+ {
+ if (!(*query)->icon_name.empty())
+ {
+ icon_name = (*query)->icon_name;
+ break;
+ }
+ }
+
+ LOG_DEBUG(logger) << "setting icon to - " << icon_name;
+ view_->SetIcon(icon_name);
+}
+
+// Introspectable
+std::string Controller::GetName() const
+{
+ return "HudController";
+}
+
+void Controller::AddProperties(GVariantBuilder* builder)
+{
+ g_variant_builder_add(builder, "{sv}", "visible", g_variant_new_boolean (visible_));
+}
+
+
+}
+}
diff --git a/plugins/unityshell/src/HudController.h b/plugins/unityshell/src/HudController.h
new file mode 100644
index 000000000..211842404
--- /dev/null
+++ b/plugins/unityshell/src/HudController.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2010 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
+ */
+
+#ifndef UNITY_HUD_CONTROLLER_H_
+#define UNITY_HUD_CONTROLLER_H_
+
+#include <memory>
+
+#include <gdk/gdk.h>
+#include <UnityCore/GLibSignal.h>
+#include <UnityCore/Hud.h>
+
+#include <NuxCore/Property.h>
+#include <NuxGraphics/GraphicsEngine.h>
+#include <Nux/Nux.h>
+#include <Nux/BaseWindow.h>
+
+#include "HudView.h"
+#include "UBusWrapper.h"
+
+namespace unity
+{
+namespace hud
+{
+
+class Controller : public unity::debug::Introspectable
+{
+public:
+ typedef std::shared_ptr<Controller> Ptr;
+
+ Controller();
+ ~Controller();
+
+ nux::BaseWindow* window() const;
+
+ nux::Property<int> launcher_width;
+ nux::Property<int> panel_height;
+
+ void ShowHideHud();
+ void ShowHud();
+ void HideHud(bool restore_focus = true);
+ bool IsVisible();
+protected:
+ std::string GetName() const;
+ void AddProperties(GVariantBuilder* builder);
+
+private:
+ void EnsureHud();
+ void SetupWindow();
+ void SetupHudView();
+ void SetupRelayoutCallbacks();
+ void RegisterUBusInterests();
+
+ nux::Geometry GetIdealWindowGeometry();
+ void Relayout(GdkScreen*screen=NULL);
+
+ void OnMouseDownOutsideWindow(int x, int y, unsigned long bflags, unsigned long kflags);
+ void OnScreenUngrabbed();
+ void OnExternalShowHud(GVariant* variant);
+ void OnExternalHideHud(GVariant* variant);
+ void OnActivateRequest(GVariant* variant);
+
+ void OnSearchChanged(std::string search_string);
+ void OnSearchActivated(std::string search_string);
+ void OnQueryActivated(Query::Ptr query);
+ void OnQuerySelected(Query::Ptr query);
+
+
+private:
+ void StartShowHideTimeline();
+ static gboolean OnViewShowHideFrame(Controller* self);
+
+ static void OnWindowConfigure(int width, int height, nux::Geometry& geo, void* data);
+
+ void OnQueriesFinished(Hud::Queries queries);
+
+private:
+ UBusManager ubus;
+ Hud hud_service_;
+ glib::SignalManager sig_manager_;
+ nux::BaseWindow* window_;
+ bool visible_;
+ bool need_show_;
+
+ guint timeline_id_;
+ float last_opacity_;
+ gint64 start_time_;
+
+ View* view_;
+ guint ensure_id_;
+
+ nux::Layout* layout_;
+};
+
+
+}
+}
+#endif
diff --git a/plugins/unityshell/src/HudIcon.cpp b/plugins/unityshell/src/HudIcon.cpp
new file mode 100644
index 000000000..d0128ff42
--- /dev/null
+++ b/plugins/unityshell/src/HudIcon.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2010 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Gord Allott <gord.allott@canonical.com>
+ */
+
+
+#include "HudIcon.h"
+#include "NuxCore/Logger.h"
+namespace
+{
+ nux::logging::Logger logger("unity.hud.icon");
+}
+
+namespace unity
+{
+namespace hud
+{
+
+Icon::Icon(nux::BaseTexture* texture, guint width, guint height)
+ : unity::IconTexture(texture, width, height)
+{
+ Init();
+ icon_renderer_.SetTargetSize(54, 46, 0);
+}
+
+Icon::Icon(const char* icon_name, unsigned int size, bool defer_icon_loading)
+ : unity::IconTexture(icon_name, size, defer_icon_loading)
+{
+ Init();
+}
+
+Icon::~Icon()
+{
+}
+
+void Icon::Init()
+{
+ SetMinimumWidth(66);
+ SetMinimumHeight(66);
+ background_ = nux::CreateTexture2DFromFile(PKGDATADIR"/launcher_icon_back_54.png", -1, true);
+ gloss_ = nux::CreateTexture2DFromFile(PKGDATADIR"/launcher_icon_shine_54.png", -1, true);
+ edge_ = nux::CreateTexture2DFromFile(PKGDATADIR"/launcher_icon_edge_54.png", -1, true);
+
+ texture_updated.connect([&] (nux::BaseTexture* texture)
+ {
+ icon_texture_source_ = new HudIconTextureSource(nux::ObjectPtr<nux::BaseTexture>(texture));
+ icon_texture_source_->ColorForIcon(_pixbuf_cached);
+ QueueDraw();
+ LOG_DEBUG(logger) << "got our texture";
+ });
+}
+
+void Icon::Draw(nux::GraphicsEngine& GfxContext, bool force_draw)
+{
+ if (texture() == nullptr)
+ return;
+
+ unity::ui::RenderArg arg;
+ arg.icon = icon_texture_source_.GetPointer();
+ arg.colorify = nux::color::White;
+ arg.running_arrow = true;
+ arg.running_on_viewport = true;
+ arg.render_center = nux::Point3(32, 32, 0);
+ arg.logical_center = nux::Point3(52, 50, 0);
+ arg.window_indicators = true;
+ arg.backlight_intensity = 1.0f;
+ arg.alpha = 1.0f;
+
+ std::list<unity::ui::RenderArg> args;
+ args.push_front(arg);
+
+
+ auto toplevel = GetToplevel();
+ icon_renderer_.SetTargetSize(54, 46, 0);
+ icon_renderer_.PreprocessIcons(args, toplevel->GetGeometry());
+ icon_renderer_.RenderIcon(GfxContext, arg, toplevel->GetGeometry(), toplevel->GetGeometry());
+}
+
+
+}
+}
+
diff --git a/plugins/unityshell/src/HudIcon.h b/plugins/unityshell/src/HudIcon.h
new file mode 100644
index 000000000..5e24b518b
--- /dev/null
+++ b/plugins/unityshell/src/HudIcon.h
@@ -0,0 +1,73 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+ * Copyright (C) 2010 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Gord Allott <gord.allott@canonical.com>
+ *
+ */
+
+#ifndef HUDICON_H
+#define HUDICON_H
+
+#include <set>
+#include <string>
+
+#include "config.h"
+
+#include <Nux/Nux.h>
+#include <Nux/BaseWindow.h>
+#include <NuxCore/Math/MathInc.h>
+
+#include <sigc++/trackable.h>
+#include <sigc++/signal.h>
+#include <sigc++/functors/ptr_fun.h>
+#include <sigc++/functors/mem_fun.h>
+
+#include <gtk/gtk.h>
+
+#include "IconTexture.h"
+#include "HudIconTextureSource.h"
+#include "IconRenderer.h"
+#include "Introspectable.h"
+
+namespace unity
+{
+namespace hud
+{
+
+class Icon : public unity::IconTexture
+{
+public:
+ typedef nux::ObjectPtr<IconTexture> Ptr;
+ Icon(nux::BaseTexture* texture, guint width, guint height);
+ Icon(const char* icon_name, unsigned int size, bool defer_icon_loading = false);
+ ~Icon();
+
+protected:
+ void Draw(nux::GraphicsEngine& GfxContext, bool force_draw);
+ void Init();
+
+ nux::ObjectPtr<nux::BaseTexture> background_;
+ nux::ObjectPtr<nux::BaseTexture> gloss_;
+ nux::ObjectPtr<nux::BaseTexture> edge_;
+ nux::ObjectPtr<HudIconTextureSource> icon_texture_source_;
+ unity::ui::IconRenderer icon_renderer_;
+};
+
+}
+
+}
+
+#endif /* HUDICON_H */
diff --git a/plugins/unityshell/src/HudIconTextureSource.cpp b/plugins/unityshell/src/HudIconTextureSource.cpp
new file mode 100644
index 000000000..3e9f06736
--- /dev/null
+++ b/plugins/unityshell/src/HudIconTextureSource.cpp
@@ -0,0 +1,110 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+ * Copyright (C) 2011 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Gordon Allott <gord.allott@canonical.com>
+ */
+
+
+#include "HudIconTextureSource.h"
+#include "config.h"
+
+#include <glib.h>
+
+#include <Nux/Nux.h>
+#include <NuxCore/Logger.h>
+
+
+namespace unity
+{
+namespace hud
+{
+
+HudIconTextureSource::HudIconTextureSource(nux::ObjectPtr<nux::BaseTexture> texture)
+ : unity::ui::IconTextureSource()
+ , icon_texture_(texture)
+{
+}
+
+HudIconTextureSource::~HudIconTextureSource()
+{
+}
+
+void HudIconTextureSource::ColorForIcon(GdkPixbuf* pixbuf)
+{
+ unsigned int width = gdk_pixbuf_get_width(pixbuf);
+ unsigned int height = gdk_pixbuf_get_height(pixbuf);
+ unsigned int row_bytes = gdk_pixbuf_get_rowstride(pixbuf);
+
+ long int rtotal = 0, gtotal = 0, btotal = 0;
+ float total = 0.0f;
+
+ guchar* img = gdk_pixbuf_get_pixels(pixbuf);
+
+ for (unsigned int i = 0; i < width; i++)
+ {
+ for (unsigned int j = 0; j < height; j++)
+ {
+ guchar* pixels = img + (j * row_bytes + i * 4);
+ guchar r = *(pixels + 0);
+ guchar g = *(pixels + 1);
+ guchar b = *(pixels + 2);
+ guchar a = *(pixels + 3);
+
+ float saturation = (MAX(r, MAX(g, b)) - MIN(r, MIN(g, b))) / 255.0f;
+ float relevance = .1 + .9 * (a / 255.0f) * saturation;
+
+ rtotal += (guchar)(r * relevance);
+ gtotal += (guchar)(g * relevance);
+ btotal += (guchar)(b * relevance);
+
+ total += relevance * 255;
+ }
+ }
+
+ nux::color::RedGreenBlue rgb(rtotal / total,
+ gtotal / total,
+ btotal / total);
+ nux::color::HueSaturationValue hsv(rgb);
+
+ if (hsv.saturation > 0.15f)
+ hsv.saturation = 0.65f;
+
+ hsv.value = 0.90f;
+ bg_color = nux::Color(nux::color::RedGreenBlue(hsv));
+}
+
+nux::Color HudIconTextureSource::BackgroundColor()
+{
+ return bg_color;
+}
+
+nux::BaseTexture* HudIconTextureSource::TextureForSize(int size)
+{
+ return icon_texture_.GetPointer();
+}
+
+nux::Color HudIconTextureSource::GlowColor()
+{
+ return nux::Color(0.0f, 0.0f, 0.0f, 0.0f);
+}
+
+nux::BaseTexture* HudIconTextureSource::Emblem()
+{
+ return nullptr;
+}
+
+}
+} \ No newline at end of file
diff --git a/plugins/unityshell/src/HudIconTextureSource.h b/plugins/unityshell/src/HudIconTextureSource.h
new file mode 100644
index 000000000..e0537f9c2
--- /dev/null
+++ b/plugins/unityshell/src/HudIconTextureSource.h
@@ -0,0 +1,51 @@
+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
+/*
+ * Copyright (C) 2011 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Gordon Allott <gord.allott@canonical.com>
+ */
+
+
+#ifndef HUDICONTEXTURESOURCE_H
+#define HUDICONTEXTURESOURCE_H
+
+#include "IconTextureSource.h"
+
+namespace unity
+{
+namespace hud
+{
+
+class HudIconTextureSource : public unity::ui::IconTextureSource
+{
+public:
+ HudIconTextureSource(nux::ObjectPtr<nux::BaseTexture> texture);
+ ~HudIconTextureSource();
+
+ virtual nux::Color BackgroundColor();
+ virtual nux::BaseTexture* TextureForSize(int size);
+ virtual nux::Color GlowColor();
+ virtual nux::BaseTexture* Emblem();
+ void ColorForIcon(GdkPixbuf* pixbuf);
+
+private:
+ nux::Color bg_color;
+ nux::ObjectPtr<nux::BaseTexture> icon_texture_;
+};
+
+}
+}
+
+#endif // HUDICONTEXTURESOURCE_H
diff --git a/plugins/unityshell/src/HudView.cpp b/plugins/unityshell/src/HudView.cpp
new file mode 100644
index 000000000..3abbd01c8
--- /dev/null
+++ b/plugins/unityshell/src/HudView.cpp
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2010 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Gord Allott <gord.allott@canonical.com>
+ */
+
+#include "HudView.h"
+
+#include <math.h>
+
+#include <gio/gdesktopappinfo.h>
+#include <glib/gi18n-lib.h>
+#include <gtk/gtk.h>
+#include <Nux/Button.h>
+#include <iostream>
+#include <sstream>
+
+#include <NuxCore/Logger.h>
+#include <UnityCore/GLibWrapper.h>
+#include <UnityCore/RadioOptionFilter.h>
+#include <Nux/HLayout.h>
+#include <Nux/LayeredLayout.h>
+
+#include <NuxCore/Logger.h>
+#include "HudButton.h"
+#include "UBusMessages.h"
+#include "DashStyle.h"
+
+namespace unity
+{
+namespace hud
+{
+
+namespace
+{
+nux::logging::Logger logger("unity.hud.view");
+int icon_size = 42;
+const std::string default_text = _("Type your command");
+}
+
+NUX_IMPLEMENT_OBJECT_TYPE(View);
+
+View::View()
+ : nux::View(NUX_TRACKER_LOCATION)
+ , button_views_(NULL)
+{
+ renderer_.SetOwner(this);
+ renderer_.need_redraw.connect([this] () {
+ QueueDraw();
+ });
+
+ nux::ROPConfig rop;
+ rop.Blend = true;
+ rop.SrcBlend = GL_ONE;
+ rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA;
+
+ SetupViews();
+ search_bar_->key_down.connect (sigc::mem_fun (this, &View::OnKeyDown));
+
+ search_bar_->activated.connect ([&]() {
+ search_activated.emit(search_bar_->search_string);
+ });
+
+ mouse_down.connect(sigc::mem_fun(this, &View::OnMouseButtonDown));
+
+ Relayout();
+
+}
+
+View::~View()
+{
+ RemoveChild(search_bar_.GetPointer());
+ for (auto button = buttons_.begin(); button != buttons_.end(); button++)
+ {
+ RemoveChild((*button).GetPointer());
+ }
+}
+
+void View::ResetToDefault()
+{
+ search_bar_->search_string = "";
+ search_bar_->search_hint = default_text;
+}
+
+void View::Relayout()
+{
+ nux::Geometry geo = GetGeometry();
+ content_geo_ = GetBestFitGeometry(geo);
+ LOG_DEBUG(logger) << "content_geo: " << content_geo_.width << "x" << content_geo_.height;
+
+ layout_->SetMinMaxSize(content_geo_.width, content_geo_.height);
+
+ QueueDraw();
+}
+
+long View::PostLayoutManagement(long LayoutResult)
+{
+ Relayout();
+ return LayoutResult;
+}
+
+
+nux::View* View::default_focus() const
+{
+ return search_bar_->text_entry();
+}
+
+void View::SetQueries(Hud::Queries queries)
+{
+ // remove the previous children
+ for (auto button = buttons_.begin(); button != buttons_.end(); button++)
+ {
+ RemoveChild((*button).GetPointer());
+ }
+
+ queries_ = queries_;
+ buttons_.clear();
+ button_views_->Clear();
+ int found_items = 0;
+ for (auto query = queries.begin(); query != queries.end(); query++)
+ {
+ if (found_items > 5)
+ break;
+
+ HudButton::Ptr button = HudButton::Ptr(new HudButton());
+ buttons_.push_front(button);
+ button->SetQuery(*query);
+ button_views_->AddView(button.GetPointer(), 0, nux::MINOR_POSITION_LEFT);
+
+ button->click.connect([&](nux::View* view) {
+ query_activated.emit(dynamic_cast<HudButton*>(view)->GetQuery());
+ });
+
+ button->key_nav_focus_activate.connect([&](nux::Area *area) {
+ query_activated.emit(dynamic_cast<HudButton*>(area)->GetQuery());
+ });
+
+ button->key_nav_focus_change.connect([&](nux::Area *area, bool recieving, KeyNavDirection direction){
+ if (recieving)
+ query_selected.emit(dynamic_cast<HudButton*>(area)->GetQuery());
+ });
+
+ button->is_rounded = (query == --(queries.end())) ? true : false;
+ button->SetMinimumWidth(941);
+ found_items++;
+ }
+
+ QueueRelayout();
+ QueueDraw();
+}
+
+void View::SetIcon(std::string icon_name)
+{
+ LOG_DEBUG(logger) << "Setting icon to " << icon_name;
+ icon_->SetByIconName(icon_name.c_str(), icon_size);
+ QueueDraw();
+}
+
+// Gives us the width and height of the contents that will give us the best "fit",
+// which means that the icons/views will not have uneccessary padding, everything will
+// look tight
+nux::Geometry View::GetBestFitGeometry(nux::Geometry const& for_geo)
+{
+ //FIXME - remove magic values, replace with scalable text depending on DPI
+ // requires smarter font settings really...
+ int width, height = 0;
+ width = 1024;
+ height = 276;
+
+ LOG_DEBUG (logger) << "best fit is, " << width << ", " << height;
+
+ return nux::Geometry(0, 0, width, height);
+}
+
+void View::AboutToShow()
+{
+ renderer_.AboutToShow();
+}
+
+void View::AboutToHide()
+{
+ renderer_.AboutToHide();
+}
+
+void View::SetWindowGeometry(nux::Geometry const& absolute_geo, nux::Geometry const& geo)
+{
+ window_geometry_ = geo;
+ window_geometry_.x = 0;
+ window_geometry_.y = 0;
+ absolute_window_geometry_ = absolute_geo;
+}
+
+namespace
+{
+ const int top_spacing = 9;
+ const int content_width = 941;
+ const int icon_vertical_margin = 5;
+ const int spacing_between_icon_and_content = 8;
+}
+
+void View::SetupViews()
+{
+ layout_ = new nux::HLayout();
+
+ icon_ = new Icon("", icon_size, true);
+ nux::Layout* icon_layout = new nux::VLayout();
+ icon_layout->SetVerticalExternalMargin(icon_vertical_margin);
+ icon_layout->AddView(icon_.GetPointer(), 0, nux::MINOR_POSITION_LEFT, nux::MINOR_SIZE_FULL);
+ layout_->AddLayout(icon_layout, 0, nux::MINOR_POSITION_TOP, nux::MINOR_SIZE_MATCHCONTENT);
+ layout_->AddLayout(new nux::SpaceLayout(spacing_between_icon_and_content,
+ spacing_between_icon_and_content,
+ spacing_between_icon_and_content,
+ spacing_between_icon_and_content), 0);
+
+
+ content_layout_ = new nux::VLayout();
+ layout_->AddLayout(content_layout_.GetPointer(), 1, nux::MINOR_POSITION_TOP);
+ SetLayout(layout_.GetPointer());
+
+ // add the top spacing
+ content_layout_->AddLayout(new nux::SpaceLayout(top_spacing,top_spacing,top_spacing,top_spacing), 0);
+
+ // add the search bar to the composite
+ search_bar_ = new unity::SearchBar(content_width, true);
+ search_bar_->disable_glow = true;
+ search_bar_->search_hint = default_text;
+ search_bar_->search_changed.connect(sigc::mem_fun(this, &View::OnSearchChanged));
+ AddChild(search_bar_.GetPointer());
+ content_layout_->AddView(search_bar_.GetPointer(), 0, nux::MINOR_POSITION_LEFT);
+
+ button_views_ = new nux::VLayout();
+ button_views_->SetMaximumWidth(content_width);
+
+ content_layout_->AddLayout(button_views_.GetPointer(), 1, nux::MINOR_POSITION_LEFT);
+}
+
+void View::OnSearchChanged(std::string const& search_string)
+{
+ LOG_DEBUG(logger) << "got search change";
+ search_changed.emit(search_string);
+ if (search_string.empty())
+ {
+ search_bar_->search_hint = default_text;
+ }
+ else
+ {
+ search_bar_->search_hint = "";
+ }
+}
+
+
+void View::OnKeyDown (unsigned long event_type, unsigned long keysym,
+ unsigned long event_state, const TCHAR* character,
+ unsigned short key_repeat_count)
+{
+ if (keysym == NUX_VK_ESCAPE)
+ {
+ LOG_DEBUG(logger) << "got escape key";
+ ubus.SendMessage(UBUS_HUD_CLOSE_REQUEST);
+ }
+}
+
+void View::OnMouseButtonDown(int x, int y, unsigned long button, unsigned long key)
+{
+ if (!content_geo_.IsPointInside(x, y))
+ {
+ ubus.SendMessage(UBUS_HUD_CLOSE_REQUEST);
+ }
+}
+
+void View::Draw(nux::GraphicsEngine& gfx_context, bool force_draw)
+{
+ renderer_.DrawFull(gfx_context, layout_->GetGeometry(), absolute_window_geometry_, window_geometry_, true);
+}
+
+void View::DrawContent(nux::GraphicsEngine& gfx_context, bool force_draw)
+{
+ renderer_.DrawInner(gfx_context, layout_->GetGeometry(), absolute_window_geometry_, window_geometry_);
+
+ if (IsFullRedraw())
+ {
+ nux::GetPainter().PushBackgroundStack();
+ layout_->ProcessDraw(gfx_context, force_draw);
+ nux::GetPainter().PopBackgroundStack();
+ }
+ else
+ {
+ layout_->ProcessDraw(gfx_context, force_draw);
+ }
+
+ renderer_.DrawInnerCleanup(gfx_context, layout_->GetGeometry(), absolute_window_geometry_, window_geometry_);
+}
+
+// Keyboard navigation
+bool View::AcceptKeyNavFocus()
+{
+ return false;
+}
+
+// Introspectable
+std::string View::GetName() const
+{
+ return "HudView";
+}
+
+void View::AddProperties(GVariantBuilder* builder)
+{
+
+}
+
+bool View::InspectKeyEvent(unsigned int eventType,
+ unsigned int key_sym,
+ const char* character)
+{
+ if ((eventType == nux::NUX_KEYDOWN) && (key_sym == NUX_VK_ESCAPE))
+ {
+ if (search_bar_->search_string == "")
+ {
+ ubus.SendMessage(UBUS_HUD_CLOSE_REQUEST);
+ }
+ else
+ {
+ search_bar_->search_string = "";
+ search_bar_->search_hint = default_text;
+ }
+ return true;
+ }
+ return false;
+}
+
+nux::Area* View::FindKeyFocusArea(unsigned int key_symbol,
+ unsigned long x11_key_code,
+ unsigned long special_keys_state)
+{
+ // Do what nux::View does, but if the event isn't a key navigation,
+ // designate the text entry to process it.
+
+ nux::KeyNavDirection direction = nux::KEY_NAV_NONE;
+ switch (x11_key_code)
+ {
+ case NUX_VK_UP:
+ direction = nux::KEY_NAV_UP;
+ break;
+ case NUX_VK_DOWN:
+ direction = nux::KEY_NAV_DOWN;
+ break;
+ case NUX_VK_LEFT:
+ direction = nux::KEY_NAV_LEFT;
+ break;
+ case NUX_VK_RIGHT:
+ direction = nux::KEY_NAV_RIGHT;
+ break;
+ case NUX_VK_LEFT_TAB:
+ direction = nux::KEY_NAV_TAB_PREVIOUS;
+ break;
+ case NUX_VK_TAB:
+ direction = nux::KEY_NAV_TAB_NEXT;
+ break;
+ case NUX_VK_ENTER:
+ case NUX_KP_ENTER:
+ // Not sure if Enter should be a navigation key
+ direction = nux::KEY_NAV_ENTER;
+ break;
+ default:
+ direction = nux::KEY_NAV_NONE;
+ break;
+ }
+
+ if (has_key_focus_)
+ {
+ return this;
+ }
+ else if (direction == nux::KEY_NAV_NONE)
+ {
+ // then send the event to the search entry
+ return search_bar_->text_entry();
+ }
+ else if (next_object_to_key_focus_area_)
+ {
+ return next_object_to_key_focus_area_->FindKeyFocusArea(key_symbol, x11_key_code, special_keys_state);
+ }
+ return NULL;
+}
+
+}
+}
diff --git a/plugins/unityshell/src/HudView.h b/plugins/unityshell/src/HudView.h
new file mode 100644
index 000000000..b0a54d740
--- /dev/null
+++ b/plugins/unityshell/src/HudView.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2010 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Gordon Allott <gord.allott@canonical.com>
+ */
+
+#ifndef UNITY_HUD_VIEW_H_
+#define UNITY_HUD_VIEW_H_
+
+#include <string>
+
+#include <NuxGraphics/GraphicsEngine.h>
+#include <Nux/Nux.h>
+#include <Nux/PaintLayer.h>
+#include <Nux/View.h>
+#include <Nux/VLayout.h>
+#include <StaticCairoText.h>
+
+#include <glib.h>
+
+#include <UnityCore/Hud.h>
+#include "Introspectable.h"
+
+#include "UBusWrapper.h"
+#include "HudIcon.h"
+#include "HudButton.h"
+#include "SearchBar.h"
+#include "OverlayRenderer.h"
+
+namespace unity
+{
+namespace hud
+{
+
+class View : public nux::View, public unity::debug::Introspectable
+{
+ NUX_DECLARE_OBJECT_TYPE(HudView, nux::View);
+ typedef nux::ObjectPtr<View> Ptr;
+public:
+ View();
+ ~View();
+
+ void ResetToDefault();
+
+ void Relayout();
+ nux::View* default_focus() const;
+
+ void SetQueries(Hud::Queries queries);
+ void SetIcon(std::string icon_name);
+
+ void AboutToShow();
+ void AboutToHide();
+
+ void SetWindowGeometry(nux::Geometry const& absolute_geo, nux::Geometry const& geo);
+
+ sigc::signal<void, std::string> search_changed;
+ sigc::signal<void, std::string> search_activated;
+ sigc::signal<void, Query::Ptr> query_activated;
+ sigc::signal<void, Query::Ptr> query_selected;
+
+protected:
+ virtual Area* FindKeyFocusArea(unsigned int key_symbol,
+ unsigned long x11_key_code,
+ unsigned long special_keys_state);
+
+ void SetupViews();
+ void OnSearchChanged(std::string const& search_string);
+ virtual long PostLayoutManagement(long LayoutResult);
+private:
+ void OnMouseButtonDown(int x, int y, unsigned long button, unsigned long key);
+ void OnKeyDown (unsigned long event_type, unsigned long event_keysym,
+ unsigned long event_state, const TCHAR* character,
+ unsigned short key_repeat_count);
+ void Draw(nux::GraphicsEngine& gfx_context, bool force_draw);
+ void DrawContent(nux::GraphicsEngine& gfx_context, bool force_draw);
+ bool InspectKeyEvent(unsigned int eventType, unsigned int key_sym, const char* character);
+ bool AcceptKeyNavFocus();
+ nux::Geometry GetBestFitGeometry(nux::Geometry const& for_geo);
+
+ std::string GetName() const;
+ void AddProperties(GVariantBuilder* builder);
+
+private:
+ UBusManager ubus;
+ nux::ObjectPtr<nux::Layout> layout_;
+ nux::ObjectPtr<nux::Layout> content_layout_;
+ nux::ObjectPtr<nux::VLayout> button_views_;
+ std::list<HudButton::Ptr> buttons_;
+
+ //FIXME - replace with dash search bar once modifications to dash search bar land
+ SearchBar::Ptr search_bar_;
+ Icon::Ptr icon_;
+ bool visible_;
+
+ Hud::Queries queries_;
+ nux::Geometry content_geo_;
+ OverlayRenderer renderer_;
+ nux::Geometry window_geometry_;
+ nux::Geometry absolute_window_geometry_;
+};
+
+
+}
+}
+#endif
+
diff --git a/plugins/unityshell/src/IMTextEntry.cpp b/plugins/unityshell/src/IMTextEntry.cpp
index 1704a5561..bc1b217c6 100644
--- a/plugins/unityshell/src/IMTextEntry.cpp
+++ b/plugins/unityshell/src/IMTextEntry.cpp
@@ -27,12 +27,10 @@
namespace unity
{
-namespace dash
-{
namespace
{
-nux::logging::Logger logger("unity.dash.imtextentry");
+nux::logging::Logger logger("unity.imtextentry");
}
NUX_IMPLEMENT_OBJECT_TYPE(IMTextEntry);
@@ -338,4 +336,3 @@ void IMTextEntry::OnMouseButtonUp(int x, int y, unsigned long bflags, unsigned l
}
}
-}
diff --git a/plugins/unityshell/src/IMTextEntry.h b/plugins/unityshell/src/IMTextEntry.h
index 9209c84f5..ab847bae6 100644
--- a/plugins/unityshell/src/IMTextEntry.h
+++ b/plugins/unityshell/src/IMTextEntry.h
@@ -30,8 +30,6 @@
namespace unity
{
-namespace dash
-{
using namespace unity::glib;
using namespace nux;
@@ -80,6 +78,5 @@ private:
};
}
-}
#endif
diff --git a/plugins/unityshell/src/IconTexture.cpp b/plugins/unityshell/src/IconTexture.cpp
index 24a9910ea..0741e63e6 100644
--- a/plugins/unityshell/src/IconTexture.cpp
+++ b/plugins/unityshell/src/IconTexture.cpp
@@ -24,6 +24,7 @@
#include <pango/pangocairo.h>
#include <Nux/Nux.h>
+#include <NuxCore/Logger.h>
#include <NuxGraphics/GLThread.h>
#include <UnityCore/GLibWrapper.h>
#include <UnityCore/Variant.h>
@@ -37,6 +38,7 @@ namespace unity
namespace
{
const char* const DEFAULT_ICON = "text-x-preview";
+nux::logging::Logger logger("unity.icontexture");
}
using namespace unity;
@@ -67,7 +69,7 @@ IconTexture::IconTexture(const char* icon_name, unsigned int size, bool defer_ic
{
_icon_name = g_strdup(icon_name ? icon_name : DEFAULT_ICON);
- if (!g_strcmp0(_icon_name, "") == 0 && !defer_icon_loading)
+ if (g_strcmp0(_icon_name, "") != 0 && !defer_icon_loading)
LoadIcon();
}
@@ -95,8 +97,11 @@ void IconTexture::SetByFilePath(const char* file_path, unsigned int size)
void IconTexture::LoadIcon()
{
- static const char* const DEFAULT_GICON = ". GThemedIcon text-x-preview";
-
+ LOG_DEBUG(logger) << "LoadIcon called (" << _icon_name << ") - loading: " << _loading;
+static const char* const DEFAULT_GICON = ". GThemedIcon text-x-preview";
+ if (!g_strcmp0(_icon_name, ""))
+ return;
+
if (_loading)
return;
_loading = true;
@@ -144,6 +149,7 @@ void IconTexture::Refresh(GdkPixbuf* pixbuf)
_texture_height,
sigc::mem_fun(this, &IconTexture::CreateTextureCallback));
QueueDraw();
+ _loading = false;
}
void IconTexture::IconLoaded(std::string const& icon_name, unsigned size,
@@ -162,6 +168,9 @@ void IconTexture::IconLoaded(std::string const& icon_name, unsigned size,
if (icon_name != DEFAULT_ICON)
SetByIconName(DEFAULT_ICON, _size);
}
+
+ texture_updated.emit(_texture_cached.GetPointer());
+ QueueDraw();
}
void IconTexture::Draw(nux::GraphicsEngine& GfxContext, bool force_draw)
diff --git a/plugins/unityshell/src/IconTexture.h b/plugins/unityshell/src/IconTexture.h
index 57a0aa4f9..7bfdc1a64 100644
--- a/plugins/unityshell/src/IconTexture.h
+++ b/plugins/unityshell/src/IconTexture.h
@@ -53,6 +53,8 @@ public:
nux::BaseTexture* texture();
+ sigc::signal<void, nux::BaseTexture*> texture_updated;
+
protected:
// Key navigation
virtual bool AcceptKeyNavFocus();
@@ -61,7 +63,8 @@ protected:
std::string GetName() const;
void AddProperties(GVariantBuilder* builder);
virtual bool DoCanFocus();
-
+ GdkPixbuf* _pixbuf_cached;
+
protected:
void Draw(nux::GraphicsEngine& GfxContext, bool force_draw);
@@ -74,7 +77,7 @@ private:
char* _icon_name;
unsigned int _size;
- GdkPixbuf* _pixbuf_cached;
+
nux::ObjectPtr<nux::BaseTexture> _texture_cached;
// FIXME: make these two a nux::Size.
int _texture_width;
diff --git a/plugins/unityshell/src/Introspectable.h b/plugins/unityshell/src/Introspectable.h
index d7a5022fd..baa40fde9 100644
--- a/plugins/unityshell/src/Introspectable.h
+++ b/plugins/unityshell/src/Introspectable.h
@@ -52,13 +52,8 @@ protected:
* AddProperties should be implemented as such ...
* void ClassFoo::AddProperties (GVariantBuilder *builder)
* {
- * g_variant_builder_add (builder, "{sv}", "label", g_variant_new_string ("_File") );
- * g_variant_builder_add (builder, "{sv}", "image", g_variant_new_string ("") );
- * g_variant_builder_add (builder, "{sv}", "visible", g_variant_new_boolean (TRUE) );
- * g_variant_builder_add (builder, "{sv}", "sensitive", g_variant_new_boolean (TRUE) );
- * g_variant_builder_add (builder, "{sv}", "active", g_variant_new_boolean (FALSE) );
- * g_variant_builder_add (builder, "{sv}", "label", g_variant_new_int32 (34) );
- * g_variant_builder_add (builder, "{sv}", "label", g_variant_new_int32 (24) );
+ * unity::variant::BuilderWrapper wrapper(builder);
+ * wrapper.add("label", some_value);
* }
* That's all. Just add a bunch of key-value properties to the builder.
*/
diff --git a/plugins/unityshell/src/Launcher.cpp b/plugins/unityshell/src/Launcher.cpp
index 1fc19b935..70b79f1ae 100644
--- a/plugins/unityshell/src/Launcher.cpp
+++ b/plugins/unityshell/src/Launcher.cpp
@@ -411,7 +411,8 @@ Launcher::AddProperties(GVariantBuilder* builder)
.add("monitor", monitor())
.add("quicklist-open", _hide_machine->GetQuirk(LauncherHideMachine::QUICKLIST_OPEN))
.add("hide-quirks", _hide_machine->DebugHideQuirks().c_str())
- .add("hover-quirks", _hover_machine->DebugHoverQuirks().c_str());
+ .add("hover-quirks", _hover_machine->DebugHoverQuirks().c_str())
+ .add("icon-size", _icon_size);
}
void Launcher::SetMousePosition(int x, int y)
diff --git a/plugins/unityshell/src/LauncherController.cpp b/plugins/unityshell/src/LauncherController.cpp
index 4a59590b7..fdc64ef65 100644
--- a/plugins/unityshell/src/LauncherController.cpp
+++ b/plugins/unityshell/src/LauncherController.cpp
@@ -273,7 +273,8 @@ void Controller::Impl::OnScreenChanged(int primary_monitor, std::vector<nux::Geo
{
unsigned int num_monitors = monitors.size();
- for (unsigned int i = 0; i < num_monitors; i++)
+ unsigned int i;
+ for (i = 0; i < num_monitors; i++)
{
if (i >= launchers.size())
launchers.push_back(nux::ObjectPtr<Launcher> (CreateLauncher(i)));
@@ -281,6 +282,12 @@ void Controller::Impl::OnScreenChanged(int primary_monitor, std::vector<nux::Geo
launchers[i]->Resize();
}
+ for (; i < launchers.size(); ++i)
+ {
+ auto launcher = launchers[i];
+ if (launcher.IsValid())
+ launcher->GetParent()->UnReference();
+ }
launchers.resize(num_monitors);
}
diff --git a/plugins/unityshell/src/LensBar.cpp b/plugins/unityshell/src/LensBar.cpp
index c59fdb683..d28d0d0e0 100644
--- a/plugins/unityshell/src/LensBar.cpp
+++ b/plugins/unityshell/src/LensBar.cpp
@@ -220,7 +220,15 @@ std::string LensBar::GetName() const
}
void LensBar::AddProperties(GVariantBuilder* builder)
-{}
+{
+ unity::variant::BuilderWrapper wrapper(builder);
+ for( auto icon : icons_)
+ {
+ if (icon->active)
+ wrapper.add("active-lens", icon->id.Get());
+ }
+
+}
}
}
diff --git a/plugins/unityshell/src/OverlayRenderer.cpp b/plugins/unityshell/src/OverlayRenderer.cpp
index 1ca54b8b1..88cde19f5 100644
--- a/plugins/unityshell/src/OverlayRenderer.cpp
+++ b/plugins/unityshell/src/OverlayRenderer.cpp
@@ -50,7 +50,7 @@ public:
void Init();
void OnBackgroundColorChanged(GVariant* args);
- void Draw(nux::GraphicsEngine& gfx_context, nux::Geometry content_geo, nux::Geometry absolute_geo, nux::Geometry geometry);
+ void Draw(nux::GraphicsEngine& gfx_context, nux::Geometry content_geo, nux::Geometry absolute_geo, nux::Geometry geometry, bool force_draw);
void DrawContent(nux::GraphicsEngine& gfx_context, nux::Geometry content_geo, nux::Geometry absolute_geo, nux::Geometry geometry);
void DrawContentCleanup(nux::GraphicsEngine& gfx_context, nux::Geometry content_geo, nux::Geometry absolute_geo, nux::Geometry geometry);
@@ -118,12 +118,12 @@ void OverlayRendererImpl::OnBackgroundColorChanged(GVariant* args)
parent->need_redraw.emit();
}
-void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry content_geo, nux::Geometry absolute_geo, nux::Geometry geometry)
+void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry content_geo, nux::Geometry absolute_geo, nux::Geometry geometry, bool force_edges)
{
bool paint_blur = BackgroundEffectHelper::blur_type != BLUR_NONE;
nux::Geometry geo = content_geo;
- if (dash::Settings::Instance().GetFormFactor() != dash::FormFactor::NETBOOK)
+ if (dash::Settings::Instance().GetFormFactor() != dash::FormFactor::NETBOOK || force_edges)
{
// Paint the edges
{
@@ -475,9 +475,9 @@ void OverlayRenderer::DisableBlur()
pimpl_->bg_effect_helper_.blur_type = BLUR_NONE;
}
-void OverlayRenderer::DrawFull(nux::GraphicsEngine& gfx_context, nux::Geometry content_geo, nux::Geometry absolute_geo, nux::Geometry geo)
+void OverlayRenderer::DrawFull(nux::GraphicsEngine& gfx_context, nux::Geometry content_geo, nux::Geometry absolute_geo, nux::Geometry geo, bool force_edges)
{
- pimpl_->Draw(gfx_context, content_geo, absolute_geo, geo);
+ pimpl_->Draw(gfx_context, content_geo, absolute_geo, geo, force_edges);
}
void OverlayRenderer::DrawInner(nux::GraphicsEngine& gfx_context, nux::Geometry content_geo, nux::Geometry absolute_geo, nux::Geometry geo)
diff --git a/plugins/unityshell/src/OverlayRenderer.h b/plugins/unityshell/src/OverlayRenderer.h
index f4bd624f1..25290f5e5 100644
--- a/plugins/unityshell/src/OverlayRenderer.h
+++ b/plugins/unityshell/src/OverlayRenderer.h
@@ -70,7 +70,7 @@ public:
* absolute_geo: your views GetAbsoluteGeometry()
* geo: your views GetGeometry()
*/
- void DrawFull(nux::GraphicsEngine& gfx_context, nux::Geometry content_geo, nux::Geometry absolute_geo, nux::Geometry geo);
+ void DrawFull(nux::GraphicsEngine& gfx_context, nux::Geometry content_geo, nux::Geometry absolute_geo, nux::Geometry geo, bool force_edges=false);
/*
* Draws just the stack that is overlay behind the inner_geometry using push/pop layers, call in DrawContent() before drawing your content
diff --git a/plugins/unityshell/src/PanelTray.cpp b/plugins/unityshell/src/PanelTray.cpp
index 562ff3e4c..6900a4cd7 100644
--- a/plugins/unityshell/src/PanelTray.cpp
+++ b/plugins/unityshell/src/PanelTray.cpp
@@ -95,7 +95,6 @@ PanelTray::~PanelTray()
if (_tray)
{
g_signal_handler_disconnect(na_tray_get_manager(_tray), _tray_icon_added_id);
- g_object_unref (_tray);
_tray = NULL;
}
@@ -104,9 +103,7 @@ PanelTray::~PanelTray()
if (_tray_expose_id)
g_signal_handler_disconnect(_window, _tray_expose_id);
- // DISABLED to see if we can get compiz to cleanly exit.
- // This currently blocks on X.
- // gtk_widget_destroy(_window);
+ gtk_widget_destroy(_window);
g_strfreev(_whitelist);
g_object_unref(_settings);
}
diff --git a/plugins/unityshell/src/PointerBarrier.cpp b/plugins/unityshell/src/PointerBarrier.cpp
index 81fae0be9..ddfaf52b5 100644
--- a/plugins/unityshell/src/PointerBarrier.cpp
+++ b/plugins/unityshell/src/PointerBarrier.cpp
@@ -48,6 +48,11 @@ PointerBarrierWrapper::PointerBarrierWrapper()
max_velocity_multiplier = 1.0f;
}
+PointerBarrierWrapper::~PointerBarrierWrapper()
+{
+ DestroyBarrier();
+}
+
void PointerBarrierWrapper::ConstructBarrier()
{
if (active)
diff --git a/plugins/unityshell/src/PointerBarrier.h b/plugins/unityshell/src/PointerBarrier.h
index 10af894ec..9ebde0918 100644
--- a/plugins/unityshell/src/PointerBarrier.h
+++ b/plugins/unityshell/src/PointerBarrier.h
@@ -60,6 +60,7 @@ public:
nux::Property<float> max_velocity_multiplier;
PointerBarrierWrapper();
+ ~PointerBarrierWrapper();
void ConstructBarrier();
void DestroyBarrier();
diff --git a/plugins/unityshell/src/QuicklistMenuItemCheckmark.cpp b/plugins/unityshell/src/QuicklistMenuItemCheckmark.cpp
index b6f4455c9..3b2686b25 100644
--- a/plugins/unityshell/src/QuicklistMenuItemCheckmark.cpp
+++ b/plugins/unityshell/src/QuicklistMenuItemCheckmark.cpp
@@ -110,13 +110,12 @@ QuicklistMenuItemCheckmark::PostLayoutManagement(long layoutResult)
}
void
-QuicklistMenuItemCheckmark::Draw(nux::GraphicsEngine& gfxContext,
- bool forceDraw)
+QuicklistMenuItemCheckmark::Draw(nux::GraphicsEngine& gfxContext, bool forceDraw)
{
nux::ObjectPtr<nux::IOpenGLBaseTexture> texture;
// Check if the texture have been computed. If they haven't, exit the function.
- if (!_normalTexture[0])
+ if (!_normalTexture[0] || !_prelightTexture[0])
return;
nux::Geometry base = GetGeometry();
@@ -130,42 +129,19 @@ QuicklistMenuItemCheckmark::Draw(nux::GraphicsEngine& gfxContext,
gfxContext.GetRenderStates().SetBlend(true);
gfxContext.GetRenderStates().SetPremultipliedBlend(nux::SRC_OVER);
- if (GetEnabled())
+ unsigned int texture_idx = GetActive() ? 1 : 0;
+
+ if (!_prelight || !GetEnabled())
{
- if (GetActive() && _prelight)
- {
- texture = _prelightTexture[0]->GetDeviceTexture();
- }
- else if (GetActive())
- {
- texture = _normalTexture[0]->GetDeviceTexture();
- }
-
- if ((!GetActive()) && _prelight)
- {
- texture = _prelightTexture[1]->GetDeviceTexture();
- }
- else if (!GetActive())
- {
- texture = _normalTexture[1]->GetDeviceTexture();
- }
-
- _color = nux::color::White;
+ texture = _normalTexture[texture_idx]->GetDeviceTexture();
}
else
{
- if (GetActive())
- {
- texture = _prelightTexture[0]->GetDeviceTexture();
- }
- else
- {
- texture = _normalTexture[0]->GetDeviceTexture();
- }
-
- _color = nux::Color(0.8f, 0.8f, 0.8f, 1.0f);
+ texture = _prelightTexture[texture_idx]->GetDeviceTexture();
}
+ _color = GetEnabled() ? nux::color::White : nux::Color(0.8f, 0.8f, 0.8f, 1.0f);
+
gfxContext.QRP_1Tex(base.x,
base.y,
base.width,
diff --git a/plugins/unityshell/src/QuicklistMenuItemRadio.cpp b/plugins/unityshell/src/QuicklistMenuItemRadio.cpp
index c4b8c164e..2092c40d5 100644
--- a/plugins/unityshell/src/QuicklistMenuItemRadio.cpp
+++ b/plugins/unityshell/src/QuicklistMenuItemRadio.cpp
@@ -109,15 +109,14 @@ QuicklistMenuItemRadio::PostLayoutManagement(long layoutResult)
}
void
-QuicklistMenuItemRadio::Draw(nux::GraphicsEngine& gfxContext,
- bool forceDraw)
+QuicklistMenuItemRadio::Draw(nux::GraphicsEngine& gfxContext, bool forceDraw)
{
+ nux::ObjectPtr<nux::IOpenGLBaseTexture> texture;
+
// Check if the texture have been computed. If they haven't, exit the function.
- if (!_normalTexture[0])
+ if (!_normalTexture[0] || !_prelightTexture[0])
return;
- nux::ObjectPtr<nux::IOpenGLBaseTexture> texture;
-
nux::Geometry base = GetGeometry();
gfxContext.PushClippingRectangle(base);
@@ -129,42 +128,19 @@ QuicklistMenuItemRadio::Draw(nux::GraphicsEngine& gfxContext,
gfxContext.GetRenderStates().SetBlend(true);
gfxContext.GetRenderStates().SetPremultipliedBlend(nux::SRC_OVER);
- if (GetEnabled())
+ unsigned int texture_idx = GetActive() ? 1 : 0;
+
+ if (!_prelight || !GetEnabled())
{
- if (GetActive() && _prelight)
- {
- texture = _prelightTexture[0]->GetDeviceTexture();
- }
- else if (GetActive())
- {
- texture = _normalTexture[0]->GetDeviceTexture();
- }
-
- if ((!GetActive()) && _prelight)
- {
- texture = _prelightTexture[1]->GetDeviceTexture();
- }
- else if (!GetActive())
- {
- texture = _normalTexture[1]->GetDeviceTexture();
- }
-
- _color = nux::color::White;
+ texture = _normalTexture[texture_idx]->GetDeviceTexture();
}
else
{
- if (GetActive())
- {
- texture = _prelightTexture[0]->GetDeviceTexture();
- }
- else
- {
- texture = _normalTexture[0]->GetDeviceTexture();
- }
-
- _color = nux::Color(0.8f, 0.8f, 0.8f, 1.0f);
+ texture = _prelightTexture[texture_idx]->GetDeviceTexture();
}
+ _color = GetEnabled() ? nux::color::White : nux::Color(0.8f, 0.8f, 0.8f, 1.0f);
+
gfxContext.QRP_1Tex(base.x,
base.y,
base.width,
diff --git a/plugins/unityshell/src/QuicklistView.cpp b/plugins/unityshell/src/QuicklistView.cpp
index 98a9e2c1c..4003b1a06 100644
--- a/plugins/unityshell/src/QuicklistView.cpp
+++ b/plugins/unityshell/src/QuicklistView.cpp
@@ -905,8 +905,7 @@ QuicklistMenuItemType QuicklistView::GetNthType(int index)
std::list<QuicklistMenuItem*> QuicklistView::GetChildren()
{
- std::list<QuicklistMenuItem*> l;
- return l;
+ return _item_list;
}
void QuicklistView::DefaultToFirstItem()
diff --git a/plugins/unityshell/src/DashSearchBar.cpp b/plugins/unityshell/src/SearchBar.cpp
index 090d70ebc..a72647ae6 100644
--- a/plugins/unityshell/src/DashSearchBar.cpp
+++ b/plugins/unityshell/src/SearchBar.cpp
@@ -25,6 +25,7 @@
#include <Nux/VLayout.h>
#include <Nux/Layout.h>
#include <Nux/WindowCompositor.h>
+#include <NuxCore/Logger.h>
#include <NuxImage/CairoGraphics.h>
#include <NuxImage/ImageSurface.h>
@@ -36,7 +37,7 @@
#include <glib.h>
#include <glib/gi18n-lib.h>
-#include "DashSearchBar.h"
+#include "SearchBar.h"
#include <UnityCore/Variant.h>
#include "CairoTexture.h"
@@ -48,11 +49,16 @@
namespace
{
const float kExpandDefaultIconOpacity = 1.0f;
+const int external_margin_vertical = 8;
+const int external_margin_horizontal = 7;
}
-namespace unity
+namespace
{
-namespace dash
+ nux::logging::Logger logger("unity");
+}
+
+namespace unity
{
NUX_IMPLEMENT_OBJECT_TYPE(SearchBar);
@@ -62,18 +68,53 @@ SearchBar::SearchBar(NUX_FILE_LINE_DECL)
, search_hint("")
, showing_filters(false)
, can_refine_search(false)
+ , disable_glow(false)
+ , show_filter_hint_(true)
, search_bar_width_(642)
, live_search_timeout_(0)
, start_spinner_timeout_(0)
{
+ Init();
+}
+
+SearchBar::SearchBar(int search_bar_width, bool show_filter_hint_, NUX_FILE_LINE_DECL)
+ : View(NUX_FILE_LINE_PARAM)
+ , search_hint("")
+ , showing_filters(false)
+ , can_refine_search(false)
+ , disable_glow(false)
+ , show_filter_hint_(show_filter_hint_)
+ , search_bar_width_(search_bar_width)
+ , live_search_timeout_(0)
+ , start_spinner_timeout_(0)
+{
+ Init();
+}
+
+SearchBar::SearchBar(int search_bar_width, NUX_FILE_LINE_DECL)
+ : View(NUX_FILE_LINE_PARAM)
+ , search_hint("")
+ , showing_filters(false)
+ , can_refine_search(false)
+ , disable_glow(false)
+ , show_filter_hint_(true)
+ , search_bar_width_(search_bar_width)
+ , live_search_timeout_(0)
+ , start_spinner_timeout_(0)
+{
+ Init();
+}
+
+void SearchBar::Init()
+{
nux::BaseTexture* icon = dash::Style::Instance().GetSearchMagnifyIcon();
bg_layer_ = new nux::ColorLayer(nux::Color(0xff595853), true);
layout_ = new nux::HLayout(NUX_TRACKER_LOCATION);
layout_->SetHorizontalInternalMargin(0);
- layout_->SetVerticalExternalMargin(8);
- layout_->SetHorizontalExternalMargin(7);
+ layout_->SetVerticalExternalMargin(external_margin_vertical);
+ layout_->SetHorizontalExternalMargin(external_margin_horizontal);
SetLayout(layout_);
spinner_ = new SearchBarSpinner();
@@ -102,42 +143,44 @@ SearchBar::SearchBar(NUX_FILE_LINE_DECL)
layered_layout_->SetMaximumWidth(search_bar_width_);
layout_->AddView(layered_layout_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FIX);
- std::string filter_str = _("<small><b>Filter results</b></small>");
- show_filters_ = new nux::StaticCairoText(filter_str.c_str());
- show_filters_->SetVisible(false);
- show_filters_->SetFont("Ubuntu 10");
- show_filters_->SetTextColor(nux::Color(1.0f, 1.0f, 1.0f, 1.0f));
- show_filters_->SetTextAlignment(nux::StaticCairoText::NUX_ALIGN_LEFT);
- show_filters_->mouse_click.connect([&] (int x, int y, unsigned long b, unsigned long k) { showing_filters = !showing_filters; });
-
- nux::BaseTexture* arrow;
- arrow = dash::Style::Instance().GetGroupExpandIcon();
- expand_icon_ = new IconTexture(arrow,
- arrow->GetWidth(),
- arrow->GetHeight());
- expand_icon_->SetOpacity(kExpandDefaultIconOpacity);
- expand_icon_->SetMinimumSize(arrow->GetWidth(), arrow->GetHeight());
- expand_icon_->SetVisible(false);
- expand_icon_->mouse_click.connect([&] (int x, int y, unsigned long b, unsigned long k) { showing_filters = !showing_filters; });
-
- filter_layout_ = new nux::HLayout();
- filter_layout_->SetHorizontalInternalMargin(8);
- filter_layout_->SetHorizontalExternalMargin(6);
- filter_space_ = new nux::SpaceLayout(100, 10000, 0, 1);
- filter_layout_->AddLayout(filter_space_, 1);
- filter_layout_->AddView(show_filters_, 0, nux::MINOR_POSITION_CENTER);
-
- arrow_layout_ = new nux::VLayout();
- arrow_top_space_ = new nux::SpaceLayout(2, 2, 12, 12);
- arrow_bottom_space_ = new nux::SpaceLayout(2, 2, 8, 8);
- arrow_layout_->AddView(arrow_top_space_, 0, nux::MINOR_POSITION_CENTER);
- arrow_layout_->AddView(expand_icon_, 0, nux::MINOR_POSITION_CENTER);
- arrow_layout_->AddView(arrow_bottom_space_, 0, nux::MINOR_POSITION_CENTER);
-
- filter_layout_->AddView(arrow_layout_, 0, nux::MINOR_POSITION_CENTER);
-
- layout_->AddView(filter_layout_, 1, nux::MINOR_POSITION_RIGHT, nux::MINOR_SIZE_FULL);
-
+ if (show_filter_hint_)
+ {
+ std::string filter_str = _("<small><b>Filter results</b></small>");
+ show_filters_ = new nux::StaticCairoText(filter_str.c_str());
+ show_filters_->SetVisible(false);
+ show_filters_->SetFont("Ubuntu 10");
+ show_filters_->SetTextColor(nux::Color(1.0f, 1.0f, 1.0f, 1.0f));
+ show_filters_->SetTextAlignment(nux::StaticCairoText::NUX_ALIGN_LEFT);
+ show_filters_->mouse_click.connect([&] (int x, int y, unsigned long b, unsigned long k) { showing_filters = !showing_filters; });
+
+ nux::BaseTexture* arrow;
+ arrow = dash::Style::Instance().GetGroupExpandIcon();
+ expand_icon_ = new IconTexture(arrow,
+ arrow->GetWidth(),
+ arrow->GetHeight());
+ expand_icon_->SetOpacity(kExpandDefaultIconOpacity);
+ expand_icon_->SetMinimumSize(arrow->GetWidth(), arrow->GetHeight());
+ expand_icon_->SetVisible(false);
+ expand_icon_->mouse_click.connect([&] (int x, int y, unsigned long b, unsigned long k) { showing_filters = !showing_filters; });
+
+ filter_layout_ = new nux::HLayout();
+ filter_layout_->SetHorizontalInternalMargin(8);
+ filter_layout_->SetHorizontalExternalMargin(6);
+ filter_space_ = new nux::SpaceLayout(100, 10000, 0, 1);
+ filter_layout_->AddLayout(filter_space_, 1);
+ filter_layout_->AddView(show_filters_, 0, nux::MINOR_POSITION_CENTER);
+
+ arrow_layout_ = new nux::VLayout();
+ arrow_top_space_ = new nux::SpaceLayout(2, 2, 12, 12);
+ arrow_bottom_space_ = new nux::SpaceLayout(2, 2, 8, 8);
+ arrow_layout_->AddView(arrow_top_space_, 0, nux::MINOR_POSITION_CENTER);
+ arrow_layout_->AddView(expand_icon_, 0, nux::MINOR_POSITION_CENTER);
+ arrow_layout_->AddView(arrow_bottom_space_, 0, nux::MINOR_POSITION_CENTER);
+
+ filter_layout_->AddView(arrow_layout_, 0, nux::MINOR_POSITION_CENTER);
+
+ layout_->AddView(filter_layout_, 1, nux::MINOR_POSITION_RIGHT, nux::MINOR_SIZE_FULL);
+ }
sig_manager_.Add(new Signal<void, GtkSettings*, GParamSpec*>
(gtk_settings_get_default(),
"notify::gtk-font-name",
@@ -151,9 +194,21 @@ SearchBar::SearchBar(NUX_FILE_LINE_DECL)
showing_filters.changed.connect(sigc::mem_fun(this, &SearchBar::OnShowingFiltersChanged));
can_refine_search.changed.connect([&] (bool can_refine)
{
- show_filters_->SetVisible(can_refine);
- expand_icon_->SetVisible(can_refine);
+ if (show_filter_hint_)
+ {
+ show_filters_->SetVisible(can_refine);
+ expand_icon_->SetVisible(can_refine);
+ }
});
+
+ disable_glow.changed.connect([&](bool disabled)
+ {
+ layout_->SetVerticalExternalMargin(0);
+ layout_->SetHorizontalExternalMargin(0);
+ UpdateBackground(true);
+ QueueDraw();
+ });
+
}
SearchBar::~SearchBar()
@@ -259,18 +314,21 @@ gboolean SearchBar::OnSpinnerStartCb(SearchBar* sef)
void SearchBar::OnShowingFiltersChanged(bool is_showing)
{
- dash::Style& style = dash::Style::Instance();
- if (is_showing)
- expand_icon_->SetTexture(style.GetGroupUnexpandIcon());
- else
- expand_icon_->SetTexture(style.GetGroupExpandIcon());
+ if (show_filter_hint_)
+ {
+ dash::Style& style = dash::Style::Instance();
+ if (is_showing)
+ expand_icon_->SetTexture(style.GetGroupUnexpandIcon());
+ else
+ expand_icon_->SetTexture(style.GetGroupExpandIcon());
+ }
}
void SearchBar::Draw(nux::GraphicsEngine& GfxContext, bool force_draw)
{
nux::Geometry geo = GetGeometry();
- UpdateBackground();
+ UpdateBackground(false);
GfxContext.PushClippingRectangle(geo);
@@ -344,21 +402,33 @@ SearchBar::SearchFinished()
spinner_->SetState(is_empty ? STATE_READY : STATE_CLEAR);
}
-void SearchBar::UpdateBackground()
+void SearchBar::UpdateBackground(bool force)
{
-#define PADDING 12
-#define RADIUS 5
+ int PADDING = 12;
+ int RADIUS = 5;
int x, y, width, height;
nux::Geometry geo = GetGeometry();
geo.width = layered_layout_->GetGeometry().width;
- if (geo.width == last_width_ && geo.height == last_height_)
+ LOG_DEBUG(logger) << "height: "
+ << geo.height << " - "
+ << layered_layout_->GetGeometry().height << " - "
+ << pango_entry_->GetGeometry().height;
+
+ if (geo.width == last_width_
+ && geo.height == last_height_
+ && force == false)
return;
last_width_ = geo.width;
last_height_ = geo.height;
+ if (disable_glow)
+ PADDING = 2;
+
+
x = y = PADDING - 1;
+
width = last_width_ - (2 * PADDING);
height = last_height_ - (2 * PADDING) + 1;
@@ -473,5 +543,4 @@ void SearchBar::AddProperties(GVariantBuilder* builder)
g_variant_builder_add (builder, "{sv}", "search_string", g_variant_new_string (pango_entry_->GetText().c_str()) );
}
-} // namespace dash
} // namespace unity
diff --git a/plugins/unityshell/src/DashSearchBar.h b/plugins/unityshell/src/SearchBar.h
index 7bc8c5e37..bb2d2fe86 100644
--- a/plugins/unityshell/src/DashSearchBar.h
+++ b/plugins/unityshell/src/SearchBar.h
@@ -17,8 +17,8 @@
* Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
*/
-#ifndef DASH_SEARCH_BAR_H
-#define DASH_SEARCH_BAR_H
+#ifndef SEARCH_BAR_H
+#define SEARCH_BAR_H
#include <gtk/gtk.h>
@@ -32,7 +32,7 @@
#include <Nux/TextEntry.h>
#include <UnityCore/GLibSignal.h>
-#include "DashSearchBarSpinner.h"
+#include "SearchBarSpinner.h"
#include "IconTexture.h"
#include "IMTextEntry.h"
#include "Introspectable.h"
@@ -40,8 +40,6 @@
namespace unity
{
-namespace dash
-{
using namespace unity::glib;
@@ -49,7 +47,10 @@ class SearchBar : public unity::debug::Introspectable, public nux::View
{
NUX_DECLARE_OBJECT_TYPE(SearchBar, nux::View);
public:
+ typedef nux::ObjectPtr<SearchBar> Ptr;
SearchBar(NUX_FILE_LINE_PROTO);
+ SearchBar(int search_width, bool show_filter_hint, NUX_FILE_LINE_PROTO);
+ SearchBar(int search_width, NUX_FILE_LINE_PROTO);
~SearchBar();
void SearchFinished();
@@ -59,6 +60,7 @@ public:
nux::Property<std::string> search_hint;
nux::Property<bool> showing_filters;
nux::Property<bool> can_refine_search;
+ nux::Property<bool> disable_glow;
nux::ROProperty<bool> im_active;
sigc::signal<void> activated;
@@ -67,6 +69,8 @@ public:
private:
+ void Init();
+
void OnFontChanged(GtkSettings* settings, GParamSpec* pspec=NULL);
void OnSearchHintChanged();
@@ -76,7 +80,7 @@ private:
void OnMouseButtonDown(int x, int y, unsigned long button_flags, unsigned long key_flags);
void OnEndKeyFocus();
- void UpdateBackground();
+ void UpdateBackground(bool force);
void OnSearchChanged(nux::TextEntry* text_entry);
void OnClearClicked(int x, int y, unsigned long button_flags, unsigned long key_flags);
void OnEntryActivated();
@@ -85,6 +89,7 @@ private:
std::string get_search_string() const;
bool set_search_string(std::string const& string);
bool get_im_active() const;
+ bool show_filter_hint_;
static gboolean OnLiveSearchTimeout(SearchBar* self);
static gboolean OnSpinnerStartCb(SearchBar* self);
@@ -110,7 +115,6 @@ private:
IconTexture* expand_icon_;
int search_bar_width_;
-
int last_width_;
int last_height_;
@@ -121,6 +125,5 @@ private:
};
}
-}
#endif
diff --git a/plugins/unityshell/src/DashSearchBarSpinner.cpp b/plugins/unityshell/src/SearchBarSpinner.cpp
index 3efc7726e..66cdbca63 100644
--- a/plugins/unityshell/src/DashSearchBarSpinner.cpp
+++ b/plugins/unityshell/src/SearchBarSpinner.cpp
@@ -17,7 +17,7 @@
* Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
*/
-#include "DashSearchBarSpinner.h"
+#include "SearchBarSpinner.h"
#include <Nux/VLayout.h>
@@ -25,8 +25,6 @@
namespace unity
{
-namespace dash
-{
NUX_IMPLEMENT_OBJECT_TYPE(SearchBarSpinner);
@@ -236,4 +234,3 @@ SearchBarSpinner::AcceptKeyNavFocus()
}
}
-}
diff --git a/plugins/unityshell/src/DashSearchBarSpinner.h b/plugins/unityshell/src/SearchBarSpinner.h
index 097693053..4435208bd 100644
--- a/plugins/unityshell/src/DashSearchBarSpinner.h
+++ b/plugins/unityshell/src/SearchBarSpinner.h
@@ -17,8 +17,8 @@
* Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
*/
-#ifndef DASH_SEARCH_BAR_SPINNER_H
-#define DASH_SEARCH_BAR_SPINNER_H
+#ifndef SEARCH_BAR_SPINNER_H
+#define SEARCH_BAR_SPINNER_H
#include <Nux/Nux.h>
#include <Nux/View.h>
@@ -29,8 +29,6 @@
namespace unity
{
-namespace dash
-{
enum SpinnerState
{
@@ -80,6 +78,5 @@ private:
};
}
-}
#endif
diff --git a/plugins/unityshell/src/SwitcherModel.cpp b/plugins/unityshell/src/SwitcherModel.cpp
index 9141ea509..37f63991f 100644
--- a/plugins/unityshell/src/SwitcherModel.cpp
+++ b/plugins/unityshell/src/SwitcherModel.cpp
@@ -40,13 +40,19 @@ SwitcherModel::SwitcherModel(std::vector<AbstractLauncherIcon*> icons)
only_detail_on_viewport = false;
for (auto icon : _inner)
+ {
+ AddChild(icon);
icon->Reference();
+ }
}
SwitcherModel::~SwitcherModel()
{
for (auto icon : _inner)
+ {
+ RemoveChild(icon);
icon->UnReference();
+ }
}
std::string SwitcherModel::GetName() const
@@ -56,22 +62,12 @@ std::string SwitcherModel::GetName() const
void SwitcherModel::AddProperties(GVariantBuilder* builder)
{
- GVariantBuilder children_builder;
- g_variant_builder_init(&children_builder, G_VARIANT_TYPE("a(sv)"));
-
- for (auto icon : _inner)
- {
- if (icon->GetName() != "")
- g_variant_builder_add(&children_builder, "(sv)", icon->GetName().c_str(), icon->Introspect());
- }
-
unity::variant::BuilderWrapper(builder)
.add("detail-selection", detail_selection)
.add("detail-selection-index", (int)detail_selection_index)
.add("only-detail-on-viewport", only_detail_on_viewport)
.add("selection-index", SelectionIndex())
- .add("last-selection-index", LastSelectionIndex())
- .add("children-of-men", g_variant_builder_end(&children_builder));
+ .add("last-selection-index", LastSelectionIndex());
}
SwitcherModel::iterator
diff --git a/plugins/unityshell/src/UBusMessages.h b/plugins/unityshell/src/UBusMessages.h
index 69ba90366..1200e3045 100644
--- a/plugins/unityshell/src/UBusMessages.h
+++ b/plugins/unityshell/src/UBusMessages.h
@@ -78,6 +78,8 @@
// FIXME - fix the nux focus api so we don't need this
#define UBUS_RESULT_VIEW_KEYNAV_CHANGED "RESULT_VIEW_KEYNAV_CHANGED"
+#define UBUS_HUD_CLOSE_REQUEST "HUD_CLOSE_REQUEST"
+
// Signals sent when the switcher is shown, hidden or changes selection
#define UBUS_SWITCHER_SHOWN "SWITCHER_SHOWN"
#define UBUS_SWITCHER_SELECTION_CHANGED "SWITCHER_SELECTION_CHANGED"
diff --git a/plugins/unityshell/src/unity-root-accessible.cpp b/plugins/unityshell/src/unity-root-accessible.cpp
index c571cc72e..789f83210 100644
--- a/plugins/unityshell/src/unity-root-accessible.cpp
+++ b/plugins/unityshell/src/unity-root-accessible.cpp
@@ -338,7 +338,7 @@ search_for_launcher_window(UnityRootAccessible* self)
nux_object = nux_object_accessible_get_object(accessible);
bwindow = dynamic_cast<nux::BaseWindow*>(nux_object);
- if ((bwindow!= NULL) && (g_strcmp0(bwindow->GetWindowName().GetTCharPtr(), "Launcher") == 0))
+ if ((bwindow!= NULL) && (g_strcmp0(bwindow->GetWindowName().GetTCharPtr(), "LauncherWindow") == 0))
{
found = TRUE;
break;
diff --git a/plugins/unityshell/src/unity-search-bar-accessible.cpp b/plugins/unityshell/src/unity-search-bar-accessible.cpp
index 82ad67293..2e3fbabbb 100644
--- a/plugins/unityshell/src/unity-search-bar-accessible.cpp
+++ b/plugins/unityshell/src/unity-search-bar-accessible.cpp
@@ -20,7 +20,7 @@
* SECTION:unity-search_bar-accessible
* @Title: UnitySearchBarAccessible
* @short_description: Implementation of the ATK interfaces for #SearchBar
- * @see_also: SearchBar at DashSearchBar.h
+ * @see_also: SearchBar at SearchBar.h
*
* #UnitySearchBarAccessible implements the required ATK interfaces for
* #SearchBar, ie: exposing the different SearchBarIcon on the model as
@@ -33,9 +33,9 @@
#include "unity-search-bar-accessible.h"
#include "unitya11y.h"
-#include "DashSearchBar.h"
+#include "SearchBar.h"
-using namespace unity::dash;
+using namespace unity;
/* GObject */
static void unity_search_bar_accessible_class_init(UnitySearchBarAccessibleClass* klass);
diff --git a/plugins/unityshell/src/unitya11y.cpp b/plugins/unityshell/src/unitya11y.cpp
index c37ae14dc..f5b310b53 100644
--- a/plugins/unityshell/src/unitya11y.cpp
+++ b/plugins/unityshell/src/unitya11y.cpp
@@ -299,7 +299,7 @@ unity_a11y_create_accessible(nux::Object* object)
if (object->Type().IsDerivedFromType(unity::dash::ResultViewGrid::StaticObjectType))
return unity_rvgrid_accessible_new(object);
- if (object->Type().IsDerivedFromType(unity::dash::SearchBar::StaticObjectType))
+ if (object->Type().IsDerivedFromType(unity::SearchBar::StaticObjectType))
return unity_search_bar_accessible_new(object);
if (object->Type().IsDerivedFromType(unity::switcher::SwitcherView::StaticObjectType))
diff --git a/plugins/unityshell/src/unityshell.cpp b/plugins/unityshell/src/unityshell.cpp
index 065707bcd..46c792b98 100644
--- a/plugins/unityshell/src/unityshell.cpp
+++ b/plugins/unityshell/src/unityshell.cpp
@@ -52,7 +52,6 @@
#include "unitya11y.h"
-#include "ubus-server.h"
#include "UBusMessages.h"
#include "UScreen.h"
@@ -120,6 +119,7 @@ UnityScreen::UnityScreen(CompScreen* screen)
, dash_is_open_ (false)
, grab_index_ (0)
, painting_tray_ (false)
+ , last_hud_show_time_(0)
{
Timer timer;
gfloat version;
@@ -278,6 +278,8 @@ UnityScreen::UnityScreen(CompScreen* screen)
}
#endif
+ optionSetShowHudInitiate(boost::bind(&UnityScreen::ShowHudInitiate, this, _1, _2, _3));
+ optionSetShowHudTerminate(boost::bind(&UnityScreen::ShowHudTerminate, this, _1, _2, _3));
optionSetBackgroundColorNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
optionSetLauncherHideModeNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
optionSetBacklightModeNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
@@ -393,7 +395,7 @@ void UnityScreen::initAltTabNextWindow()
sout << "<Alt>" << XKeysymToString(above_tab_keysym);
screen->removeAction(&optionGetAltTabNextWindow());
-
+
CompAction action = CompAction();
action.keyFromString(sout.str());
action.setState (CompAction::StateInitKey | CompAction::StateAutoGrab);
@@ -408,7 +410,7 @@ void UnityScreen::initAltTabNextWindow()
sout << "<Alt><Shift>" << XKeysymToString(above_tab_keysym);
screen->removeAction(&optionGetAltTabPrevWindow());
-
+
CompAction action = CompAction();
action.keyFromString(sout.str());
action.setState (CompAction::StateInitKey | CompAction::StateAutoGrab);
@@ -842,8 +844,8 @@ void UnityScreen::paintDisplay(const CompRegion& region, const GLMatrix& transfo
bool UnityScreen::forcePaintOnTop ()
{
return !allowWindowPaint ||
- ((switcher_controller_->Visible() ||
- dash_is_open_) && !fullscreen_windows_.empty () && (!(screen->grabbed () && !screen->otherGrabExist (NULL))));
+ ((switcher_controller_->Visible() ||
+ dash_is_open_) && !fullscreen_windows_.empty () && (!(screen->grabbed () && !screen->otherGrabExist (NULL))));
}
void UnityWindow::paintThumbnail (nux::Geometry const& bounding, float alpha)
@@ -989,7 +991,7 @@ bool UnityWindow::handleAnimations (unsigned int ms)
{
if (mShowdesktopHandler)
if (mShowdesktopHandler->animate (ms))
- {
+ {
delete mShowdesktopHandler;
mShowdesktopHandler = NULL;
return true;
@@ -1018,7 +1020,7 @@ bool UnityShowdesktopHandler::shouldHide (CompWindow *w)
return false;
if (w->state () & (CompWindowStateSkipPagerMask |
- CompWindowStateSkipTaskbarMask))
+ CompWindowStateSkipTaskbarMask))
return false;
if ((w->state () & CompWindowStateHiddenMask))
@@ -1691,7 +1693,7 @@ bool UnityScreen::altTabNextWindowInitiate(CompAction* action, CompAction::State
altTabInitiateCommon(action, state, options);
switcher_controller_->Select(1); // always select the current application
}
-
+
switcher_controller_->NextDetail();
action->setState(action->state() | CompAction::StateTermKey);
@@ -1702,7 +1704,7 @@ bool UnityScreen::altTabPrevWindowInitiate(CompAction* action, CompAction::State
{
if (switcher_controller_->Visible())
switcher_controller_->PrevDetail();
-
+
return false;
}
@@ -1757,6 +1759,44 @@ void UnityScreen::OnLauncherEndKeyNav(GVariant* data)
PluginAdapter::Default ()->restoreInputFocus ();
}
+bool UnityScreen::ShowHudInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options)
+{
+ // to receive the Terminate event
+ if (state & CompAction::StateInitKey)
+ action->setState(action->state() | CompAction::StateTermKey);
+
+ last_hud_show_time_ = g_get_monotonic_time();
+
+ return false;
+}
+
+bool UnityScreen::ShowHudTerminate(CompAction* action, CompAction::State state, CompOption::Vector& options)
+{
+ if (optionGetShowHud().key().toString() == action->key().toString())
+ {
+ if (switcher_controller_->Visible())
+ return false; // early exit if the switcher is open
+
+ gint64 current_time = g_get_monotonic_time();
+ if (current_time - last_hud_show_time_ < 150 * 1000)
+ {
+ if (hud_controller_->IsVisible())
+ {
+ ubus_manager_.SendMessage(UBUS_HUD_CLOSE_REQUEST);
+ }
+ else
+ {
+ hud_controller_->ShowHud();
+ }
+ last_hud_show_time_ = 0;
+ }
+ }
+
+ action->setState(action->state() & ~CompAction::StateTermKey);
+
+ return false;
+}
+
gboolean UnityScreen::initPluginActions(gpointer data)
{
CompPlugin* p = CompPlugin::find("expo");
@@ -1843,7 +1883,7 @@ bool UnityScreen::initPluginForScreen(CompPlugin* p)
bool result = screen->initPluginForScreen(p);
if (p->vTable->name() == "unityshell")
initAltTabNextWindow();
-
+
return result;
}
@@ -1856,8 +1896,8 @@ std::string UnityScreen::GetName() const
return "Unity";
}
-bool isNuxWindow (CompWindow* value)
-{
+bool isNuxWindow (CompWindow* value)
+{
std::vector<Window> const& xwns = nux::XInputWindow::NativeHandleList();
auto id = value->id();
@@ -1884,7 +1924,7 @@ const CompWindowList& UnityScreen::getWindowPaintList()
void UnityScreen::RaiseInputWindows()
{
std::vector<Window> const& xwns = nux::XInputWindow::NativeHandleList();
-
+
for (auto window : xwns)
{
CompWindow* cwin = screen->findWindow(window);
@@ -2017,7 +2057,7 @@ UnityWindow::focus ()
if (!window->onCurrentDesktop ())
return false;
- /* Only withdrawn windows
+ /* Only withdrawn windows
* which are marked hidden
* are excluded */
if (!window->shaded () &&
@@ -2025,8 +2065,8 @@ UnityWindow::focus ()
(window->state () & CompWindowStateHiddenMask))
return false;
- if (window->geometry ().x () + window->geometry ().width () <= 0 ||
- window->geometry ().y () + window->geometry ().height () <= 0 ||
+ if (window->geometry ().x () + window->geometry ().width () <= 0 ||
+ window->geometry ().y () + window->geometry ().height () <= 0 ||
window->geometry ().x () >= (int) screen->width ()||
window->geometry ().y () >= (int) screen->height ())
return false;
@@ -2132,7 +2172,7 @@ void UnityWindow::stateChangeNotify(unsigned int lastState)
!(lastState & CompWindowStateFullscreenMask))
UnityScreen::get (screen)->fullscreen_windows_.push_back(window);
else if (lastState & CompWindowStateFullscreenMask &&
- !(window->state () & CompWindowStateFullscreenMask))
+ !(window->state () & CompWindowStateFullscreenMask))
UnityScreen::get (screen)->fullscreen_windows_.remove(window);
PluginAdapter::Default()->NotifyStateChange(window, window->state(), lastState);
@@ -2281,9 +2321,9 @@ void UnityScreen::optionChanged(CompOption* opt, UnityshellOptions::Options num)
{
case UnityshellOptions::BackgroundColor:
{
- nux::Color override_color (optionGetBackgroundColorRed() / 65535.0f,
- optionGetBackgroundColorGreen() / 65535.0f,
- optionGetBackgroundColorBlue() / 65535.0f,
+ nux::Color override_color (optionGetBackgroundColorRed() / 65535.0f,
+ optionGetBackgroundColorGreen() / 65535.0f,
+ optionGetBackgroundColorBlue() / 65535.0f,
optionGetBackgroundColorAlpha() / 65535.0f);
override_color.red = override_color.red / override_color.alpha;
@@ -2331,6 +2371,7 @@ void UnityScreen::optionChanged(CompOption* opt, UnityshellOptions::Options num)
launcher_options->icon_size = optionGetIconSize();
launcher_options->tile_size = optionGetIconSize() + 6;
+ hud_controller_->launcher_width = launcher_controller_->launcher().GetAbsoluteWidth() - 1;
/* The launcher geometry includes 1px used to draw the right margin
* that must not be considered when drawing the dash */
dash_controller_->launcher_width = launcher_controller_->launcher().GetAbsoluteWidth() - 1;
@@ -2519,6 +2560,11 @@ void UnityScreen::initLauncher()
/* Setup Places */
dash_controller_.reset(new dash::Controller());
dash_controller_->on_realize.connect(sigc::mem_fun(this, &UnityScreen::OnDashRealized));
+
+ /* Setup Hud */
+ hud_controller_.reset(new hud::Controller());
+ AddChild(hud_controller_.get());
+ LOG_INFO(logger) << "initLauncher-hud " << timer.ElapsedSeconds() << "s";
// Setup Shortcut Hint
InitHints();
@@ -2668,7 +2714,7 @@ UnityWindow::~UnityWindow()
if (mShowdesktopHandler)
delete mShowdesktopHandler;
-
+
if (focusdesktop_handle_)
g_source_remove(focusdesktop_handle_);
diff --git a/plugins/unityshell/src/unityshell.h b/plugins/unityshell/src/unityshell.h
index 6066e575b..d8ba88dd8 100644
--- a/plugins/unityshell/src/unityshell.h
+++ b/plugins/unityshell/src/unityshell.h
@@ -58,6 +58,8 @@
#include <compiztoolbox/compiztoolbox.h>
#include <dlfcn.h>
+#include "HudController.h"
+
namespace unity
{
@@ -202,6 +204,9 @@ public:
bool altTabNextWindowInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options);
bool altTabPrevWindowInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options);
+ /* handle hud key activations */
+ bool ShowHudInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options);
+ bool ShowHudTerminate(CompAction* action, CompAction::State state, CompOption::Vector& options);
bool launcherSwitcherForwardInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options);
bool launcherSwitcherPrevInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options);
bool launcherSwitcherTerminate(CompAction* action, CompAction::State state, CompOption::Vector& options);
@@ -268,6 +273,7 @@ private:
dash::Controller::Ptr dash_controller_;
panel::Controller::Ptr panel_controller_;
switcher::Controller::Ptr switcher_controller_;
+ hud::Controller::Ptr hud_controller_;
shortcut::Controller::Ptr shortcut_controller_;
std::list<shortcut::AbstractHint*> hints_;
@@ -322,6 +328,7 @@ private:
CompWindowList fullscreen_windows_;
bool painting_tray_;
unsigned int tray_paint_mask_;
+ gint64 last_hud_show_time_;
#ifndef USE_GLES
ScreenEffectFramebufferObject::GLXGetProcAddressProc glXGetProcAddressP;
@@ -396,7 +403,7 @@ public:
UnityMinimizedHandler *mMinimizeHandler;
UnityShowdesktopHandler *mShowdesktopHandler;
-
+
private:
guint focusdesktop_handle_;
diff --git a/plugins/unityshell/unityshell.xml.in b/plugins/unityshell/unityshell.xml.in
index f59218603..4dd37d46b 100644
--- a/plugins/unityshell/unityshell.xml.in
+++ b/plugins/unityshell/unityshell.xml.in
@@ -40,9 +40,14 @@
</requirement>
</deps>
<options>
- <group>
+ <group>
<_short>Behaviour</_short>
- <option name="launcher_hide_mode" type="int">
+ <option name="show_hud" type="key">
+ <_short>Key to show the HUD</_short>
+ <_long>Make the HUD appear with this key</_long>
+ <default>&lt;Alt&gt;</default>
+ </option>
+ <option name="launcher_hide_mode" type="int">
<_short>Hide Launcher</_short>
<_long>Make the launcher hide automatically after some time of inactivity: always or just when the focussed window is not over the launcher</_long>
<min>0</min>
@@ -64,16 +69,16 @@
<value>3</value>
<_name>Dodge Active Window</_name>
</desc>
- </option>
- <option name="show_launcher" type="key">
+ </option>
+ <option name="show_launcher" type="key">
<_short>Key to show the launcher</_short>
<_long>Make the launcher appear with that key</_long>
<default>&lt;Super&gt;</default>
</option>
<option name="keyboard_focus" type="key">
- <_short>Key to put keyboard-focus on launcher</_short>
- <_long>Set the keyboard-focus on the launcher so it can be navigated with the cursor-keys</_long>
- <default>&lt;Alt&gt;F1</default>
+ <_short>Key to put keyboard-focus on launcher</_short>
+ <_long>Set the keyboard-focus on the launcher so it can be navigated with the cursor-keys</_long>
+ <default>&lt;Alt&gt;F1</default>
</option>
<option name="execute_command" type="key">
<_short>Key to execute a command</_short>
@@ -118,37 +123,37 @@
<_long>fixme</_long>
<default>&lt;Alt&gt;&lt;Shift&gt;Tab</default>
</option>
- <option name="alt_tab_right" type="key">
- <_short>Go right in the switcher</_short>
- <_long>fixme</_long>
- <default>&lt;Alt&gt;Right</default>
- <passive_grab>false</passive_grab>
- <internal/>
- </option>
- <option name="alt_tab_left" type="key">
- <_short>Go left in the switcher</_short>
- <_long>fixme</_long>
- <default>&lt;Alt&gt;Left</default>
- <passive_grab>false</passive_grab>
- <internal/>
- </option>
+ <option name="alt_tab_right" type="key">
+ <_short>Go right in the switcher</_short>
+ <_long>fixme</_long>
+ <default>&lt;Alt&gt;Right</default>
+ <passive_grab>false</passive_grab>
+ <internal/>
+ </option>
+ <option name="alt_tab_left" type="key">
+ <_short>Go left in the switcher</_short>
+ <_long>fixme</_long>
+ <default>&lt;Alt&gt;Left</default>
+ <passive_grab>false</passive_grab>
+ <internal/>
+ </option>
<option name="alt_tab_detail_start" type="key">
- <_short>Key to expose the windows in the switcher</_short>
- <_long>fixme</_long>
- <default>&lt;Alt&gt;Down</default>
- <passive_grab>false</passive_grab>
- <internal/>
+ <_short>Key to expose the windows in the switcher</_short>
+ <_long>fixme</_long>
+ <default>&lt;Alt&gt;Down</default>
+ <passive_grab>false</passive_grab>
+ <internal/>
</option>
- <option name="alt_tab_detail_stop" type="key">
- <_short>Key to collapse windows in the switcher</_short>
- <_long>fixme</_long>
- <default>&lt;Alt&gt;Up</default>
- <passive_grab>false</passive_grab>
- <internal/>
- </option>
+ <option name="alt_tab_detail_stop" type="key">
+ <_short>Key to collapse windows in the switcher</_short>
+ <_long>fixme</_long>
+ <default>&lt;Alt&gt;Up</default>
+ <passive_grab>false</passive_grab>
+ <internal/>
+ </option>
<option name="alt_tab_next_window" type="key">
- <_short>Key to flip through windows in the switcher</_short>
- <_long>fixme</_long>
+ <_short>Key to flip through windows in the switcher</_short>
+ <_long>fixme</_long>
<passive_grab>false</passive_grab>
</option>
<option name="alt_tab_prev_window" type="key">
@@ -156,11 +161,11 @@
<_long>fixme</_long>
<passive_grab>false</passive_grab>
</option>
- <option name="show_minimized_windows" type="bool">
- <_short>Show minimized windows in switcher</_short>
- <_long>Hack to enable minimized windows in switcher. Disable and report bugs if problems are caused</_long>
- <default>true</default>
- </option>
+ <option name="show_minimized_windows" type="bool">
+ <_short>Show minimized windows in switcher</_short>
+ <_long>Hack to enable minimized windows in switcher. Disable and report bugs if problems are caused</_long>
+ <default>true</default>
+ </option>
</group>
<group>
<_short>Experimental</_short>
@@ -359,7 +364,7 @@
<max>100</max>
<default>75</default>
</option>
-
+
<option name="devices_option" type="int">
<_short>Show Devices</_short>
<_long>Show devices in the launcher</_long>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 9154d35f1..18a88b12e 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -6,7 +6,7 @@ plugins/unityshell/src/PlacesGroup.cpp
plugins/unityshell/src/SpacerLauncherIcon.cpp
plugins/unityshell/src/TrashLauncherIcon.cpp
plugins/unityshell/src/BFBLauncherIcon.cpp
-plugins/unityshell/src/DashSearchBar.cpp
+plugins/unityshell/src/SearchBar.cpp
plugins/unityshell/src/DashView.cpp
plugins/unityshell/src/DesktopLauncherIcon.cpp
plugins/unityshell/src/FilterExpanderLabel.cpp
diff --git a/standalone-clients/CMakeLists.txt b/standalone-clients/CMakeLists.txt
index 8a763eec9..3345dc4e3 100644
--- a/standalone-clients/CMakeLists.txt
+++ b/standalone-clients/CMakeLists.txt
@@ -8,7 +8,7 @@ set(UNITY_SRC ../plugins/unityshell/src)
# Unit tests
#
find_package (PkgConfig)
-set (TEST_DEPS "${UNITY_PLUGIN_DEPS};unity>=4.0.0")
+set (TEST_DEPS "${UNITY_PLUGIN_DEPS};unity>=4.0.0 xtst")
pkg_check_modules (TEST_UNIT_DEPS REQUIRED ${TEST_DEPS})
set (TESTDATADIR "${CMAKE_CURRENT_SOURCE_DIR}/data")
@@ -26,7 +26,7 @@ set (CFLAGS
)
add_definitions (${CFLAGS})
-set (LIBS ${TEST_UNIT_DEPS_LIBRARIES} "-lunity-core-${UNITY_API_VERSION} -lm -lGL -lGLU")
+set (LIBS ${TEST_UNIT_DEPS_LIBRARIES} "-lunity-core-${UNITY_API_VERSION} -lm -lGL -lGLU -lXtst")
link_libraries (${LIBS})
set (LIB_PATHS ${TEST_UNIT_DEPS_LIBRARY_DIRS})
@@ -47,10 +47,10 @@ add_executable (dash
${UNITY_SRC}/BackgroundEffectHelper.h
${UNITY_SRC}/BGHash.cpp
${UNITY_SRC}/BGHash.h
- ${UNITY_SRC}/DashSearchBar.cpp
- ${UNITY_SRC}/DashSearchBar.h
- ${UNITY_SRC}/DashSearchBarSpinner.cpp
- ${UNITY_SRC}/DashSearchBarSpinner.h
+ ${UNITY_SRC}/SearchBar.cpp
+ ${UNITY_SRC}/SearchBar.h
+ ${UNITY_SRC}/SearchBarSpinner.cpp
+ ${UNITY_SRC}/SearchBarSpinner.h
${UNITY_SRC}/DashView.cpp
${UNITY_SRC}/DashView.h
${UNITY_SRC}/DashViewPrivate.cpp
@@ -84,6 +84,10 @@ add_executable (dash
${UNITY_SRC}/PlacesSimpleTile.h
${UNITY_SRC}/PlacesVScrollBar.cpp
${UNITY_SRC}/PlacesVScrollBar.h
+ ${UNITY_SRC}/DashView.cpp
+ ${UNITY_SRC}/DashView.h
+ ${UNITY_SRC}/DashViewPrivate.cpp
+ ${UNITY_SRC}/DashViewPrivate.h
${UNITY_SRC}/DashStyle.cpp
${UNITY_SRC}/IconLoader.cpp
${UNITY_SRC}/IconLoader.h
@@ -178,6 +182,8 @@ add_executable (switcher
${UNITY_SRC}/WindowManager.cpp
${UNITY_SRC}/IconRenderer.cpp
${UNITY_SRC}/IconRenderer.h
+ ${UNITY_SRC}/Introspectable.cpp
+ ${UNITY_SRC}/Introspectable.h
${UNITY_SRC}/MockLauncherIcon.h
${UNITY_SRC}/BackgroundEffectHelper.h
${UNITY_SRC}/BackgroundEffectHelper.cpp
@@ -251,6 +257,8 @@ add_executable (launcher
${UNITY_SRC}/BackgroundEffectHelper.cpp
${UNITY_SRC}/StaticCairoText.cpp
${UNITY_SRC}/StaticCairoText.h
+ ${UNITY_SRC}/SoftwareCenterLauncherIcon.cpp
+ ${UNITY_SRC}/SoftwareCenterLauncherIcon.h
${UNITY_SRC}/Introspectable.cpp
${UNITY_SRC}/Introspectable.h
${UNITY_SRC}/QuicklistMenuItem.cpp
@@ -286,8 +294,10 @@ add_dependencies (keyutil unity-core-${UNITY_API_VERSION})
add_executable (quicklist
ui/TestQuicklist.cpp
- ui/EventFaker.cpp
- ui/EventFaker.h
+ nux_test_framework.cpp
+ nux_test_framework.h
+ nux_automated_test_framework.cpp
+ nux_automated_test_framework.h
${UNITY_SRC}/Introspectable.cpp
${UNITY_SRC}/Introspectable.h
${UNITY_SRC}/QuicklistMenuItem.cpp
@@ -347,16 +357,18 @@ add_dependencies(filters unity-core-${UNITY_API_VERSION})
add_executable (filter-bar
TestFilterBar.cpp
+ ${UNITY_SRC}/FilterAllButton.cpp
+ ${UNITY_SRC}/FilterBar.cpp
+ ${UNITY_SRC}/FilterBasicButton.cpp
${UNITY_SRC}/FilterExpanderLabel.cpp
${UNITY_SRC}/FilterFactory.cpp
- ${UNITY_SRC}/FilterBasicButton.cpp
- ${UNITY_SRC}/FilterRatingsButton.cpp
- ${UNITY_SRC}/FilterRatingsWidget.cpp
${UNITY_SRC}/FilterMultiRangeWidget.cpp
${UNITY_SRC}/FilterMultiRangeButton.cpp
${UNITY_SRC}/FilterGenreButton.cpp
${UNITY_SRC}/FilterGenreWidget.cpp
- ${UNITY_SRC}/FilterBar.cpp
+ ${UNITY_SRC}/FilterRatingsButton.cpp
+ ${UNITY_SRC}/FilterRatingsWidget.cpp
+ ${UNITY_SRC}/FilterWidget.cpp
${UNITY_SRC}/DashStyle.cpp
${UNITY_SRC}/JSONParser.cpp
)
@@ -456,6 +468,39 @@ add_executable (bg-hash
)
add_dependencies (bg-hash unity-core-${UNITY_API_VERSION})
+add_executable (hud
+ StandaloneHud.cpp
+ ${UNITY_SRC}/BackgroundEffectHelper.cpp
+ ${UNITY_SRC}/BackgroundEffectHelper.h
+ ${UNITY_SRC}/DashSettings.cpp
+ ${UNITY_SRC}/DashSettings.h
+ ${UNITY_SRC}/DashStyle.cpp
+ ${UNITY_SRC}/HudButton.cpp
+ ${UNITY_SRC}/HudIcon.cpp
+ ${UNITY_SRC}/HudIcon.h
+ ${UNITY_SRC}/HudIconTextureSource.cpp
+ ${UNITY_SRC}/HudIconTextureSource.h
+ ${UNITY_SRC}/HudView.cpp
+ ${UNITY_SRC}/IMTextEntry.cpp
+ ${UNITY_SRC}/Introspectable.cpp
+ ${UNITY_SRC}/IconTexture.cpp
+ ${UNITY_SRC}/IconLoader.cpp
+ ${UNITY_SRC}/IconRenderer.cpp
+ ${UNITY_SRC}/IconTextureSource.cpp
+ ${UNITY_SRC}/JSONParser.cpp
+ ${UNITY_SRC}/OverlayRenderer.cpp
+ ${UNITY_SRC}/SearchBar.cpp
+ ${UNITY_SRC}/SearchBarSpinner.cpp
+ ${UNITY_SRC}/StaticCairoText.cpp
+ ${UNITY_SRC}/TextureCache.cpp
+ ${UNITY_SRC}/Timer.cpp
+ ${UNITY_SRC}/UBusWrapper.cpp
+ ${UNITY_SRC}/ubus-server.cpp
+ ${UNITY_SRC}/UScreen.cpp
+ ${UNITY_SRC}/UScreen.h
+ )
+add_dependencies (hud unity-core-${UNITY_API_VERSION})
+
add_executable (test-shortcut
TestShortcut.cpp
${UNITY_SRC}/AbstractSeparator.cpp
diff --git a/standalone-clients/StandaloneHud.cpp b/standalone-clients/StandaloneHud.cpp
new file mode 100644
index 000000000..03d1aab85
--- /dev/null
+++ b/standalone-clients/StandaloneHud.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2010 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied 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: Gordon Allott <gord.allott@canonical.com>
+ *
+ */
+
+#include <sstream>
+#include "Nux/Nux.h"
+#include "Nux/VLayout.h"
+#include "Nux/Button.h"
+#include "Nux/TextureArea.h"
+#include "Nux/WindowThread.h"
+#include "NuxGraphics/GraphicsEngine.h"
+#include <gtk/gtk.h>
+
+#include "HudView.h"
+#include "DashStyle.h"
+#include "DashSettings.h"
+#include <NuxCore/Logger.h>
+
+namespace
+{
+ nux::logging::Logger logger("unity.tests.Hud");
+}
+
+class TestRunner
+{
+public:
+ TestRunner ();
+ ~TestRunner ();
+
+ static void InitWindowThread (nux::NThread* thread, void* InitData);
+ void Init ();
+ nux::Layout *layout;
+ unity::hud::View* hud_view_;
+ unity::dash::Settings dash_settings_;
+
+private:
+ unity::hud::Hud hud_service_;
+};
+
+TestRunner::TestRunner ()
+ : hud_service_("com.canonical.hud", "/com/canonical/hud")
+{
+}
+
+TestRunner::~TestRunner ()
+{
+}
+
+void TestRunner::Init ()
+{
+ LOG_WARNING(logger) << "test init";
+ layout = new nux::VLayout();
+
+ hud_view_ = new unity::hud::View();
+
+ layout->AddView (hud_view_, 1, nux::MINOR_POSITION_TOP, nux::MINOR_SIZE_FULL);
+ nux::GetWindowCompositor().SetKeyFocusArea(hud_view_->default_focus());
+
+ nux::GetWindowThread()->SetLayout (layout);
+
+ // things the controller normally does
+ hud_service_.queries_updated.connect([&] (unity::hud::Hud::Queries queries) {
+ hud_view_->SetQueries(queries);
+ std::string icon_name = "";
+ for (auto query = queries.begin(); query != queries.end(); query++)
+ {
+ if (!(*query)->icon_name.empty())
+ {
+ LOG_DEBUG(logger) << "Setting icon name to: " << (*query)->icon_name;
+ icon_name = (*query)->icon_name;
+ break;
+ }
+ }
+
+ hud_view_->SetIcon(icon_name);
+
+ });
+
+ hud_view_->query_activated.connect([&] (unity::hud::Query::Ptr query) {
+ hud_service_.ExecuteQuery(query, 0);
+ });
+
+ hud_view_->query_selected.connect([&] (unity::hud::Query::Ptr query) {
+ hud_view_->SetIcon(query->icon_name);
+ });
+
+ hud_view_->search_changed.connect([&] (std::string search_string) {
+ hud_service_.RequestQuery(search_string);
+ });
+
+ hud_view_->search_activated.connect([&] (std::string search_string) {
+ hud_service_.ExecuteQueryBySearch(search_string, 0);
+ });
+
+ hud_service_.RequestQuery("");
+
+ hud_view_->SetWindowGeometry(layout->GetAbsoluteGeometry(), layout->GetGeometry());
+
+}
+
+void TestRunner::InitWindowThread(nux::NThread* thread, void* InitData)
+{
+ TestRunner *self = (TestRunner *) InitData;
+ self->Init ();
+}
+
+void
+ControlThread (nux::NThread* thread,
+ void* data)
+{
+ // sleep for 3 seconds
+ nux::SleepForMilliseconds (3000);
+ printf ("ControlThread successfully started\n");
+}
+
+
+int main(int argc, char **argv)
+{
+ nux::SystemThread* st = NULL;
+ nux::WindowThread* wt = NULL;
+
+ // no real tests right now, just make sure we don't get any criticals and such
+ // waiting on nice perceptual diff support before we can build real tests
+ // for views
+
+ g_type_init ();
+ gtk_init (&argc, &argv);
+
+ nux::NuxInitialize(0);
+
+ // Slightly higher as we're more likely to test things we know will fail
+ nux::logging::configure_logging("unity.hud=debug");
+
+ nux::logging::configure_logging(::getenv("UNITY_LOG_SEVERITY"));
+ LOG_DEBUG(logger) << "starting the standalone hud";
+ // The instances for the pseudo-singletons.
+ unity::dash::Style dash_style;
+
+ TestRunner *test_runner = new TestRunner ();
+ wt = nux::CreateGUIThread(TEXT("Hud Prototype Test"),
+ 1200, 768,
+ 0,
+ &TestRunner::InitWindowThread,
+ test_runner);
+
+ st = nux::CreateSystemThread (NULL, ControlThread, wt);
+
+ if (st)
+ st->Start (NULL);
+
+ wt->Run (NULL);
+ delete st;
+ delete wt;
+ return 0;
+}
diff --git a/standalone-clients/TestFilterBar.cpp b/standalone-clients/TestFilterBar.cpp
index 020a4ffb7..e12e2dd06 100644
--- a/standalone-clients/TestFilterBar.cpp
+++ b/standalone-clients/TestFilterBar.cpp
@@ -53,7 +53,7 @@ TestRunner::~TestRunner ()
void TestRunner::Init ()
{
- unity::FilterBar *filterbar = new unity::FilterBar(NUX_TRACKER_LOCATION);
+ auto *filterbar = new unity::dash::FilterBar(NUX_TRACKER_LOCATION);
layout = new nux::VLayout(NUX_TRACKER_LOCATION);
diff --git a/standalone-clients/TestFilters.cpp b/standalone-clients/TestFilters.cpp
index 1e4689b13..cddf2ac0d 100644
--- a/standalone-clients/TestFilters.cpp
+++ b/standalone-clients/TestFilters.cpp
@@ -57,13 +57,13 @@ TestRunner::~TestRunner ()
void TestRunner::Init ()
{
- unity::FilterBasicButton *button = new unity::FilterBasicButton ("hello world", NUX_TRACKER_LOCATION);
- unity::FilterRatingsWidget *ratings = new unity::FilterRatingsWidget (NUX_TRACKER_LOCATION);
- unity::FilterGenreButton *genre_button = new unity::FilterGenreButton ("genre button", NUX_TRACKER_LOCATION);
+ auto *button = new unity::dash::FilterBasicButton ("hello world", NUX_TRACKER_LOCATION);
+ auto *ratings = new unity::dash::FilterRatingsWidget (NUX_TRACKER_LOCATION);
+ auto *genre_button = new unity::dash::FilterGenreButton ("genre button", NUX_TRACKER_LOCATION);
- unity::FilterGenre *genre = new unity::FilterGenre(NUX_TRACKER_LOCATION);
+ auto *genre = new unity::dash::FilterGenre(3, NUX_TRACKER_LOCATION);
- unity::FilterMultiRange *multi_range = new unity::FilterMultiRange (NUX_TRACKER_LOCATION);
+ auto *multi_range = new unity::dash::FilterMultiRange (NUX_TRACKER_LOCATION);
layout = new nux::VLayout(NUX_TRACKER_LOCATION);
diff --git a/standalone-clients/nux_automated_test_framework.cpp b/standalone-clients/nux_automated_test_framework.cpp
new file mode 100644
index 000000000..970db58ea
--- /dev/null
+++ b/standalone-clients/nux_automated_test_framework.cpp
@@ -0,0 +1,461 @@
+/*
+ * Copyright 2010 Inalogic Inc.
+ *
+ * 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: Jay Taoko <jaytaoko@inalogic.com>
+ *
+ */
+
+#include "Nux/Nux.h"
+#include <X11/extensions/XTest.h>
+#include <X11/keysym.h>
+#include "nux_automated_test_framework.h"
+
+
+int NuxAutomatedTestFramework::mouse_motion_time_span = 1000; // milliseconds
+int NuxAutomatedTestFramework::mouse_click_time_span = 300; // milliseconds
+int NuxAutomatedTestFramework::minimum_sleep_time = 600; // milliseconds
+int NuxAutomatedTestFramework::safety_border_inside_view = 1; // pixels
+
+NuxAutomatedTestFramework::NuxAutomatedTestFramework(nux::WindowThread *window_thread)
+{
+ ready_to_start_ = false;
+ display_ = NULL;
+ window_thread_ = window_thread;
+ window_x_ = 0;
+ window_y_ = 0;
+ window_width_ = 0;
+ window_height_ = 0;
+ terminate_when_test_over_ = false;
+}
+
+NuxAutomatedTestFramework::~NuxAutomatedTestFramework()
+{
+ XCloseDisplay(display_);
+}
+
+void NuxAutomatedTestFramework::SetTerminateProgramWhenDone(bool terminate)
+{
+ terminate_when_test_over_ = terminate;
+}
+
+bool NuxAutomatedTestFramework::WhenDoneTerminateProgram()
+{
+ return terminate_when_test_over_;
+}
+
+void NuxAutomatedTestFramework::Startup()
+{
+ display_ = XOpenDisplay(NULL);
+ nux::Geometry rect = window_thread_->GetGraphicsDisplay().GetWindowGeometry();
+ //nuxDebugMsg("Window geometry: (%d, %d, %d, %d)", rect.x, rect.y, rect.width, rect.height);
+
+ window_x_ = rect.x;
+ window_y_ = rect.y;
+ window_width_ = rect.width;
+ window_height_ = rect.height;
+}
+
+void NuxAutomatedTestFramework::ViewSendMouseClick(nux::View *view, int button)
+{
+ nux::Rect r;
+ if (view)
+ {
+ r = view->GetAbsoluteGeometry();
+ r.OffsetPosition(window_x_ + r.width/2, window_y_ + r.height/2);
+ }
+ else
+ {
+ r = window_thread_->GetGraphicsDisplay().GetWindowGeometry();
+ r.OffsetPosition(r.width/2, r.height/2);
+ }
+
+ SendFakeMouseMotionEvent(r.x, r.y, NuxAutomatedTestFramework::mouse_motion_time_span);
+ SendFakeMouseEvent(button, true);
+ nux::SleepForMilliseconds(NuxAutomatedTestFramework::mouse_click_time_span);
+ SendFakeMouseEvent(button, false);
+
+ XSync(display_, False);
+ nux::SleepForMilliseconds(NuxAutomatedTestFramework::minimum_sleep_time);
+}
+
+void NuxAutomatedTestFramework::ViewSendMouseDoubleClick(nux::View *view, int button)
+{
+ nux::Rect r;
+ if (view)
+ {
+ r = view->GetAbsoluteGeometry();
+ r.OffsetPosition(window_x_ + r.width/2, window_y_ + r.height/2);
+ }
+ else
+ {
+ r = window_thread_->GetGraphicsDisplay().GetWindowGeometry();
+ r.OffsetPosition(r.width/2, r.height/2);
+ }
+
+ // Send the mouse to the center of the view
+ SendFakeMouseMotionEvent(r.x, r.y, NuxAutomatedTestFramework::mouse_motion_time_span);
+
+ XTestFakeButtonEvent(display_, button, true, CurrentTime);
+ XTestFakeButtonEvent(display_, button, false, CurrentTime);
+ XTestFakeButtonEvent(display_, button, true, CurrentTime);
+ XTestFakeButtonEvent(display_, button, false, CurrentTime);
+ XSync(display_, False);
+ nux::SleepForMilliseconds(NuxAutomatedTestFramework::minimum_sleep_time);
+}
+
+void NuxAutomatedTestFramework::ViewSendMouseDown(nux::View *view, int button)
+{
+ XEvent event;
+ /* Get the current pointer position */
+ XQueryPointer(display_, RootWindow(display_, 0),
+ &event.xbutton.root, &event.xbutton.window,
+ &event.xbutton.x_root, &event.xbutton.y_root,
+ &event.xbutton.x, &event.xbutton.y,
+ &event.xbutton.state);
+
+ int current_x = event.xbutton.x - window_x_;
+ int current_y = event.xbutton.y - window_y_;
+
+ nux::Rect r = view->GetAbsoluteGeometry();
+
+ if (!r.IsInside(nux::Point(current_x, current_y)))
+ {
+ // The mouse pointer is not inside the view.
+ // Move the mouse pointer to the center of the view.
+ r.OffsetPosition(window_x_, window_y_);
+
+ // Go to the center of the view
+ int view_center_x = r.x + r.width/2;
+ int view_center_y = r.y + r.height/2;
+ SendFakeMouseMotionEvent(view_center_x, view_center_y, NuxAutomatedTestFramework::mouse_motion_time_span);
+ nux::SleepForMilliseconds(minimum_sleep_time);
+ }
+ SendFakeMouseEvent(button, true);
+}
+
+void NuxAutomatedTestFramework::ViewSendMouseUp(nux::View *view, int button)
+{
+ // nux::Rect r = view->GetAbsoluteGeometry();
+ // r.OffsetPosition(window_x_, window_y_);
+
+ // int view_center_x = r.x + r.width/2;
+ // int view_center_y = r.y + r.height/2;
+
+ // SendFakeMouseMotionEvent(view_center_x, view_center_y, 1000);
+ // nux::SleepForMilliseconds(minimum_sleep_time);
+ SendFakeMouseEvent(button, false);
+}
+
+void NuxAutomatedTestFramework::ViewSendMouseDrag(nux::View *view, int button_index, int x0, int y0, int x1, int y1)
+{
+ nux::Rect r0 = view->GetAbsoluteGeometry();
+ nux::Rect r1 = view->GetAbsoluteGeometry();
+ r0.OffsetPosition(window_x_ + x0, window_y_ + y0);
+ r1.OffsetPosition(window_x_ + x1, window_y_ + y1);
+
+ // Go to first point
+ SendFakeMouseMotionEvent(r0.x, r0.y, NuxAutomatedTestFramework::mouse_motion_time_span);
+ nux::SleepForMilliseconds(minimum_sleep_time);
+
+ // Mouse down
+ ViewSendMouseDown(view, button_index);
+
+ // Drag to second point
+ SendFakeMouseMotionEvent(r1.x, r1.y, NuxAutomatedTestFramework::mouse_motion_time_span);
+ nux::SleepForMilliseconds(minimum_sleep_time);
+
+ // Mouse up
+ ViewSendMouseUp(view, button_index);
+}
+
+void NuxAutomatedTestFramework::ViewSendMouseMotionTo(nux::View *view, int x, int y)
+{
+ nux::Rect r;
+ if (view)
+ {
+ r = view->GetAbsoluteGeometry();
+ r.OffsetPosition(window_x_ + x, window_y_ + y);
+ }
+ else
+ {
+ r = window_thread_->GetGraphicsDisplay().GetWindowGeometry();
+ r.OffsetPosition(x, y);
+ }
+
+ SendFakeMouseMotionEvent(r.x, r.y, NuxAutomatedTestFramework::mouse_motion_time_span);
+}
+
+void NuxAutomatedTestFramework::ViewSendMouseMotionToCenter(nux::View *view)
+{
+ nux::Rect r;
+ if (view)
+ {
+ r = view->GetAbsoluteGeometry();
+ r.OffsetPosition(window_x_, window_y_);
+ }
+ else
+ {
+ r = window_thread_->GetGraphicsDisplay().GetWindowGeometry();
+ }
+
+ int view_center_x = r.x + r.width/2;
+ int view_center_y = r.y + r.height/2;
+
+ SendFakeMouseMotionEvent(view_center_x, view_center_y, NuxAutomatedTestFramework::mouse_motion_time_span);
+}
+
+void NuxAutomatedTestFramework::ViewSendMouseMotionToTopLeft(nux::View *view)
+{
+ nux::Rect r = view->GetAbsoluteGeometry();
+ r.OffsetPosition(window_x_, window_y_);
+
+ SendFakeMouseMotionEvent(r.x + safety_border_inside_view, r.y + safety_border_inside_view, NuxAutomatedTestFramework::mouse_motion_time_span);
+}
+
+void NuxAutomatedTestFramework::ViewSendMouseMotionToTopRight(nux::View *view)
+{
+ nux::Rect r = view->GetAbsoluteGeometry();
+ r.OffsetPosition(window_x_, window_y_);
+
+ SendFakeMouseMotionEvent(r.x + r.width-1, r.y+safety_border_inside_view, NuxAutomatedTestFramework::mouse_motion_time_span);
+}
+
+void NuxAutomatedTestFramework::ViewSendMouseMotionToBottomLeft(nux::View *view)
+{
+ nux::Rect r = view->GetAbsoluteGeometry();
+ r.OffsetPosition(window_x_, window_y_);
+
+ SendFakeMouseMotionEvent(r.x+safety_border_inside_view, r.y + r.height-1, NuxAutomatedTestFramework::mouse_motion_time_span);
+}
+
+void NuxAutomatedTestFramework::ViewSendMouseMotionToBottomRight(nux::View *view)
+{
+ nux::Rect r = view->GetAbsoluteGeometry();
+ r.OffsetPosition(window_x_, window_y_);
+
+ SendFakeMouseMotionEvent(r.x + r.width-1, r.y + r.height-1, NuxAutomatedTestFramework::mouse_motion_time_span);
+}
+
+void NuxAutomatedTestFramework::ViewSendChar(const char c)
+{
+ KeySym modifier = 0;
+
+ if ((c >= 'A') && (c <= 'Z'))
+ {
+ modifier = XK_Shift_L;
+ }
+
+ std::string s(1, c);
+ SendFakeKeyEvent(XStringToKeysym(s.c_str()), modifier);
+ nux::SleepForMilliseconds(300);
+}
+
+void NuxAutomatedTestFramework::ViewSendString(const std::string &str)
+{
+ int l = str.length();
+ if (l == 0)
+ return;
+
+ int i = 0;
+
+ while (i < l)
+ {
+ KeySym modifier = 0;
+ char c = str[i++];
+
+ if ((c >= 'A') && (c <= 'Z'))
+ {
+ modifier = XK_Shift_L;
+ }
+
+ std::string s(1, c);
+ SendFakeKeyEvent(XStringToKeysym(s.c_str()), modifier);
+ nux::SleepForMilliseconds(300);
+ }
+}
+
+void NuxAutomatedTestFramework::ViewSendKeyCombo(KeySym modsym0, KeySym modsym1, KeySym modsym2, const char c)
+{
+ KeyCode keycode = 0;
+ KeyCode modcode0 = 0;
+ KeyCode modcode1 = 0;
+ KeyCode modcode2 = 0;
+
+ std::string s(1, c);
+ keycode = XKeysymToKeycode(display_, XStringToKeysym(s.c_str()));
+ XTestGrabControl(display_, True);
+
+ /* Generate modkey press */
+ if (modsym0 != 0)
+ {
+ modcode0 = XKeysymToKeycode(display_, modsym0);
+ XTestFakeKeyEvent(display_, modcode0, True, 0);
+ }
+ if (modsym1 != 0)
+ {
+ modcode1 = XKeysymToKeycode(display_, modsym1);
+ XTestFakeKeyEvent(display_, modcode1, True, 0);
+ }
+ if (modsym2 != 0)
+ {
+ modcode2 = XKeysymToKeycode(display_, modsym2);
+ XTestFakeKeyEvent(display_, modcode2, True, 0);
+ }
+
+ /* Generate regular key press and release */
+ XTestFakeKeyEvent(display_, keycode, True, 0);
+ XTestFakeKeyEvent(display_, keycode, False, 0);
+
+ /* Generate modkey release */
+ if (modsym0 != 0)
+ {
+ XTestFakeKeyEvent(display_, modcode0, False, 0);
+ }
+ if (modsym1 != 0)
+ {
+ XTestFakeKeyEvent(display_, modcode1, False, 0);
+ }
+ if (modsym2 != 0)
+ {
+ XTestFakeKeyEvent(display_, modcode2, False, 0);
+ }
+
+ XSync(display_, False);
+ XTestGrabControl(display_, False);
+}
+
+void NuxAutomatedTestFramework::ViewSendCtrlA()
+{
+ ViewSendKeyCombo(XK_Control_L, 0, 0, 'a');
+}
+
+void NuxAutomatedTestFramework::ViewSendDelete()
+{
+ SendFakeKeyEvent(XK_Delete, 0);
+}
+
+void NuxAutomatedTestFramework::ViewSendBackspace()
+{
+ SendFakeKeyEvent(XK_BackSpace, 0);
+}
+
+void NuxAutomatedTestFramework::ViewSendEscape()
+{
+ SendFakeKeyEvent(XK_Escape, 0);
+}
+
+void NuxAutomatedTestFramework::ViewSendTab()
+{
+ SendFakeKeyEvent(XK_Tab, 0);
+}
+
+void NuxAutomatedTestFramework::ViewSendReturn()
+{
+ SendFakeKeyEvent(XK_Return, 0);
+}
+
+void NuxAutomatedTestFramework::PutMouseAt(int x, int y)
+{
+ XTestFakeMotionEvent(display_, XScreenNumberOfScreen(DefaultScreenOfDisplay(display_)), x, y, CurrentTime);
+ XSync(display_, False);
+}
+
+void NuxAutomatedTestFramework::SendFakeKeyEvent(KeySym keysym, KeySym modsym)
+{
+ KeyCode keycode = 0;
+ KeyCode modcode = 0;
+
+ keycode = XKeysymToKeycode(display_, keysym);
+ XTestGrabControl(display_, True);
+
+ /* Generate modkey press */
+ if (modsym != 0)
+ {
+ modcode = XKeysymToKeycode(display_, modsym);
+ XTestFakeKeyEvent(display_, modcode, True, 0);
+ }
+
+ /* Generate regular key press and release */
+ XTestFakeKeyEvent(display_, keycode, True, 0);
+ XTestFakeKeyEvent(display_, keycode, False, 0);
+
+ /* Generate modkey release */
+ if (modsym != 0)
+ {
+ XTestFakeKeyEvent(display_, modcode, False, 0);
+ }
+
+ XSync(display_, False);
+ XTestGrabControl(display_, False);
+}
+
+void NuxAutomatedTestFramework::SendFakeMouseEvent(int mouse_button_index, bool pressed)
+{
+ XTestFakeButtonEvent(display_, mouse_button_index, pressed, CurrentTime);
+ XSync(display_, False);
+}
+
+void NuxAutomatedTestFramework::SendFakeMouseMotionEvent(int x, int y, int ms_delay)
+{
+ XEvent event;
+ /* Get the current pointer position */
+ XQueryPointer(display_, RootWindow(display_, 0),
+ &event.xbutton.root, &event.xbutton.window,
+ &event.xbutton.x_root, &event.xbutton.y_root,
+ &event.xbutton.x, &event.xbutton.y,
+ &event.xbutton.state);
+
+ int old_x = event.xbutton.x;
+ int old_y = event.xbutton.y;
+
+ int n_iteration = ms_delay / 16.0f;
+
+ //nuxDebugMsg("n_iteration: %d", n_iteration);
+
+ if (n_iteration < 1)
+ {
+ n_iteration = 1;
+ }
+
+ XSync(display_, False);
+
+ for (int i = 0; i < n_iteration; i++)
+ {
+ float t = ((float)i + 1.0f) / n_iteration;
+
+ int cx = (1.0f - t) * old_x + t * x;
+ int cy = (1.0f - t) * old_y + t * y;
+ XTestFakeMotionEvent(display_, XScreenNumberOfScreen(DefaultScreenOfDisplay(display_)), cx, cy, CurrentTime);
+ XSync(display_, False);
+ usleep(16*1000);
+ }
+
+ XTestFakeMotionEvent(display_, XScreenNumberOfScreen(DefaultScreenOfDisplay(display_)), x, y, CurrentTime);
+ XSync(display_, False);
+ nux::SleepForMilliseconds(NuxAutomatedTestFramework::minimum_sleep_time);
+}
+
+void NuxAutomatedTestFramework::TestReportMsg(bool b, const char* msg)
+{
+ if (b)
+ {
+ nuxOkMsg("%s: %s", msg, "Ok");
+ }
+ else
+ {
+ nuxAlertMsg("%s: %s", msg, "Failed");
+ }
+} \ No newline at end of file
diff --git a/standalone-clients/nux_automated_test_framework.h b/standalone-clients/nux_automated_test_framework.h
new file mode 100644
index 000000000..63c9b52d7
--- /dev/null
+++ b/standalone-clients/nux_automated_test_framework.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2010 Inalogic Inc.
+ *
+ * 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: Jay Taoko <jaytaoko@inalogic.com>
+ *
+ */
+
+#include <X11/extensions/XTest.h>
+#include <X11/keysym.h>
+
+#ifndef NUX_AUTOMATED_TEST_FRAMEWORK_H
+#define NUX_AUTOMATED_TEST_FRAMEWORK_H
+
+class NuxAutomatedTestFramework
+{
+public:
+ NuxAutomatedTestFramework(nux::WindowThread *window_thread);
+ virtual ~NuxAutomatedTestFramework();
+
+ //! Initialize the testing framework.
+ void Startup();
+
+ //! Simulate a mouse click event on a view.
+ /*!
+ Move the mouse to the middle of the view (if it isn't there already) and perform a click event.
+ */
+ void ViewSendMouseClick(nux::View *view, int button);
+ //! Simulate a mouse double click event on a view.
+ /*!
+ Move the mouse to the middle of the view (if it isn't there already) and perform a double click event.
+ */
+ void ViewSendMouseDoubleClick(nux::View *view, int button);
+ //! Simulate a mouse down event on a view.
+ void ViewSendMouseDown(nux::View *view, int button);
+ //! Simulate a mouse up event on a view.
+ void ViewSendMouseUp(nux::View *view, int button);
+ //! Simulate a drag event on a view from (x0, y0) to (x1, y1).
+ void ViewSendMouseDrag(nux::View *view, int button, int x0, int y0, int x1, int y1);
+ //! Simulate mouse motion to (x, y).
+ void ViewSendMouseMotionTo(nux::View *view, int x, int y);
+ //! Simulate mouse motion to the center of a view.
+ void ViewSendMouseMotionToCenter(nux::View *view);
+ //! Simulate mouse motion to the top left corner of a view.
+ void ViewSendMouseMotionToTopLeft(nux::View *view);
+ //! Simulate mouse motion to the top right corner of a view.
+ void ViewSendMouseMotionToTopRight(nux::View *view);
+ //! Simulate mouse motion to the bottom left corner of a view.
+ void ViewSendMouseMotionToBottomLeft(nux::View *view);
+ //! Simulate mouse motion to the bottom right corner of a view.
+ void ViewSendMouseMotionToBottomRight(nux::View *view);
+
+ //! Simulate a key event.
+ void ViewSendChar(const char c);
+ //! Simulate a succession of key events.
+ void ViewSendString(const std::string &str);
+ //! Simulate a key combo.
+ void ViewSendKeyCombo(KeySym modsym0, KeySym modsym1, KeySym modsym2, const char c);
+ //! Simulate Ctrl+a.
+ void ViewSendCtrlA();
+ //! Simulate Delete key.
+ void ViewSendDelete();
+ //! Simulate Backspace key.
+ void ViewSendBackspace();
+ //! Simulate Escape key.
+ void ViewSendEscape();
+ //! Simulate Tab key.
+ void ViewSendTab();
+ //! Simulate Return key.
+ void ViewSendReturn();
+
+ //! Put the mouse pointer anywhere on the display.
+ void PutMouseAt(int x, int y);
+
+ //! Simulate a mouse event.
+ void SendFakeMouseEvent(int mouse_button_index, bool pressed);
+ //! Simulate a key event.
+ void SendFakeKeyEvent(KeySym keysym, KeySym modsym);
+ //! Simulate a mouse motion event.
+ void SendFakeMouseMotionEvent(int x, int y, int ms_delay);
+
+ /*!
+ Set the test thread to terminae the program when testing is over.
+ */
+ void SetTerminateProgramWhenDone(bool terminate);
+ /*!
+ Return true if the test thread is allowed to terminate the program after testing is over.
+ */
+ bool WhenDoneTerminateProgram();
+
+ /*!
+ Print a report message to the console.
+ */
+ void TestReportMsg(bool b, const char* msg);
+
+private:
+ void WindowConfigSignal(int x, int y, int width, int height);
+
+ bool ready_to_start_;
+ Display* display_;
+ nux::WindowThread *window_thread_;
+ int window_x_;
+ int window_y_;
+ int window_width_;
+ int window_height_;
+ bool terminate_when_test_over_;
+
+ static int mouse_motion_time_span; // in milliseconds
+ static int mouse_click_time_span; // in milliseconds
+ static int minimum_sleep_time; // in milliseconds
+ static int safety_border_inside_view; // in pixels
+};
+
+#endif // NUX_AUTOMATED_TEST_FRAMEWORK_H
+
diff --git a/standalone-clients/nux_test_framework.cpp b/standalone-clients/nux_test_framework.cpp
new file mode 100644
index 000000000..f839e169e
--- /dev/null
+++ b/standalone-clients/nux_test_framework.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2010 Inalogic Inc.
+ *
+ * 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: Jay Taoko <jaytaoko@inalogic.com>
+ *
+ */
+
+#include "Nux/Nux.h"
+#include "Nux/VLayout.h"
+#include "Nux/HLayout.h"
+#include "Nux/WindowThread.h"
+#include "Nux/TextEntry.h"
+#include "nux_test_framework.h"
+
+
+NuxTestFramework::NuxTestFramework(const char* program_name,
+ int window_width,
+ int window_height,
+ int program_life_span)
+{
+ ready_to_go_ = false;
+ window_width_ = window_width;
+ window_height_ = window_height;
+
+ if (window_width_ < 100)
+ window_width_ = 100;
+
+ if (window_height_ < 100)
+ window_height_ = 100;
+
+ timeout_signal_ = NULL;
+ window_thread_ = NULL;
+ program_name_ = program_name;
+ program_life_span_ = program_life_span;
+
+ if (program_life_span_ > 0 && program_life_span_ < 1000)
+ {
+ // Minimum life span is 1 second.
+ program_life_span_ = 1000;
+ }
+}
+
+NuxTestFramework::~NuxTestFramework()
+{
+ if (window_thread_)
+ delete window_thread_;
+}
+
+void NuxTestFramework::Startup()
+{
+ nux::NuxInitialize(0);
+ window_thread_ = nux::CreateGUIThread(program_name_.c_str(), window_width_, window_height_, NULL, NULL, NULL);
+
+ window_thread_->window_configuration.connect(sigc::mem_fun(this, &NuxTestFramework::WaitForConfigureEvent));
+}
+
+void NuxTestFramework::UserInterfaceSetup()
+{
+ // nux::VLayout *MainVLayout = new nux::VLayout(NUX_TRACKER_LOCATION);
+ // nux::TextEntry *text_entry_0 = new nux::TextEntry(TEXT("0123456789abcdefghij"), NUX_TRACKER_LOCATION);
+
+ // MainVLayout->AddView(text_entry_0, 0, nux::eCenter, nux::eFull);
+ // MainVLayout->SetVerticalInternalMargin(10);
+ // MainVLayout->SetContentDistribution(nux::eStackCenter);
+
+ // nux::GetWindowThread()->SetLayout(MainVLayout);
+ // nux::ColorLayer background(nux::Color(0xFF4D4D4D));
+ // window_thread_->SetWindowBackgroundPaintLayer(&background);
+}
+
+void NuxTestFramework::Run()
+{
+ if (window_thread_ == NULL)
+ return;
+
+ if (program_life_span_ > 0)
+ {
+ timeout_signal_ = new nux::TimeOutSignal();
+ timeout_signal_->time_expires.connect(sigc::mem_fun(this, &NuxTestFramework::ProgramExitCall));
+ window_thread_->GetTimerHandler().AddTimerHandler(program_life_span_, timeout_signal_, NULL, NULL);
+ }
+
+ window_thread_->Run(NULL);
+}
+
+bool NuxTestFramework::ReadyToGo()
+{
+ return window_thread_;
+}
+
+nux::WindowThread* NuxTestFramework::GetWindowThread()
+{
+ return window_thread_;
+}
+
+void NuxTestFramework::ProgramExitCall(void *data)
+{
+ if (window_thread_)
+ window_thread_->ExitMainLoop();
+}
+
+void NuxTestFramework::WaitForConfigureEvent(int x, int y, int width, int height)
+{
+ ready_to_go_ = true;
+}
+
+
+// int main(int argc, char **argv)
+// {
+// NuxTestFramework test("Text Entry", 300, 300, 3000);
+// test.Startup();
+// test.UserInterfaceSetup();
+// test.Run();
+
+// return 0;
+// }
diff --git a/standalone-clients/nux_test_framework.h b/standalone-clients/nux_test_framework.h
new file mode 100644
index 000000000..59855c986
--- /dev/null
+++ b/standalone-clients/nux_test_framework.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2010 Inalogic Inc.
+ *
+ * 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: Jay Taoko <jaytaoko@inalogic.com>
+ *
+ */
+
+#include "Nux/Nux.h"
+#include "Nux/VLayout.h"
+#include "Nux/HLayout.h"
+#include "Nux/WindowThread.h"
+#include "Nux/TextEntry.h"
+
+#ifndef NUXTESTFRAMEWORK_H
+#define NUXTESTFRAMEWORK_H
+
+class NuxTestFramework
+{
+public:
+ NuxTestFramework(const char* program_name, int window_width, int window_height, int program_life_span);
+ virtual ~NuxTestFramework();
+
+ virtual void Startup();
+ virtual void UserInterfaceSetup();
+ virtual void Run();
+
+ bool ReadyToGo();
+
+ nux::WindowThread* GetWindowThread();
+
+public:
+ std::string program_name_;
+ int program_life_span_; //!< The program will auto-terminate after a delay in milliseconds.
+ nux::TimeOutSignal *timeout_signal_;
+
+ nux::WindowThread *window_thread_;
+
+ int window_width_;
+ int window_height_;
+
+private:
+ void ProgramExitCall(void *data);
+ void WaitForConfigureEvent(int x, int y, int width, int height);
+ bool ready_to_go_;
+};
+
+#endif // NUXTESTFRAMEWORK_H
+
diff --git a/standalone-clients/ui/TestQuicklist.cpp b/standalone-clients/ui/TestQuicklist.cpp
index 7b484e5af..75ac309fc 100644
--- a/standalone-clients/ui/TestQuicklist.cpp
+++ b/standalone-clients/ui/TestQuicklist.cpp
@@ -14,11 +14,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authored by: Mirco Müller <mirco.mueller@canonical.com>
+ * Marco Trevisan (Treviño) <3v1n0@ubuntu.com>
*/
#include <glib.h>
#include <gtk/gtk.h>
-#include <dbus/dbus-glib.h>
#include "Nux/Nux.h"
#include "Nux/VLayout.h"
@@ -31,101 +31,175 @@
#include "QuicklistMenuItemCheckmark.h"
#include "QuicklistMenuItemRadio.h"
-#include "EventFaker.h"
-#include <X11/Xlib.h>
+#include "nux_test_framework.h"
+#include "nux_automated_test_framework.h"
#define WIN_WIDTH 400
-#define WIN_HEIGHT 300
+#define WIN_HEIGHT 400
-gboolean gResult[3] = {false, false, false};
+class TestQuicklist: public NuxTestFramework
+{
+public:
+ TestQuicklist(const char *program_name, int window_width, int window_height, int program_life_span);
+ ~TestQuicklist();
+
+ virtual void UserInterfaceSetup();
+ int ItemNaturalPosition(QuicklistMenuItem* item);
+ bool HasNthItemActivated(unsigned int index);
+
+ QuicklistView* quicklist_;
+ std::map<QuicklistMenuItem*,bool> activated_;
+
+private:
+ QuicklistMenuItemSeparator* createSeparatorItem();
+ QuicklistMenuItemLabel* createLabelItem(std::string const& label, bool enabled = true);
+ QuicklistMenuItemCheckmark* createCheckmarkItem(std::string const& label, bool enabled, bool checked);
+ QuicklistMenuItemRadio* createRadioItem(std::string const& label, bool enabled, bool checked);
+ void AddItem(QuicklistMenuItem* item);
+
+ void connectToActivatedSignal(DbusmenuMenuitem* item);
+ static void activatedCallback(DbusmenuMenuitem* item, int time, gpointer data);
+
+ std::map<DbusmenuMenuitem*, QuicklistMenuItem*> menus2qitem_;
+};
+
+TestQuicklist::TestQuicklist(const char *program_name, int window_width, int window_height, int program_life_span)
+ : NuxTestFramework(program_name, window_width, window_height, program_life_span),
+ quicklist_(nullptr)
+{}
+
+TestQuicklist::~TestQuicklist()
+{
+ if (quicklist_)
+ quicklist_->UnReference();
+}
+
+int TestQuicklist::ItemNaturalPosition(QuicklistMenuItem* item)
+{
+ int pos = 1;
+
+ for (auto it : quicklist_->GetChildren())
+ {
+ if (it == item)
+ return pos;
+
+ if (it->GetItemType() != MENUITEM_TYPE_SEPARATOR)
+ pos++;
+ }
-QuicklistView* gQuicklist = NULL;
-QuicklistMenuItemCheckmark* gCheckmark = NULL;
-QuicklistMenuItemRadio* gRadio = NULL;
-QuicklistMenuItemLabel* gLabel = NULL;
+ return -1;
+}
-void
-activatedCallback (DbusmenuMenuitem* item,
- int time,
- gpointer data)
+bool TestQuicklist::HasNthItemActivated(unsigned int index)
{
- gboolean* result = (gboolean*) data;
+ return activated_[quicklist_->GetNthItems(index)];
+}
- *result = true;
+void TestQuicklist::activatedCallback(DbusmenuMenuitem* item, int time, gpointer data)
+{
+ auto self = static_cast<TestQuicklist*>(data);
+ QuicklistMenuItem* qitem = self->menus2qitem_[item];
+
+ if (!self->activated_[qitem])
+ {
+ self->activated_[qitem] = true;
+ g_debug("Quicklist-item %d activated", self->ItemNaturalPosition(qitem));
+ }
+}
- g_print ("Quicklist-item activated\n");
+void TestQuicklist::connectToActivatedSignal(DbusmenuMenuitem* item)
+{
+ g_signal_connect (item,
+ DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
+ G_CALLBACK (&TestQuicklist::activatedCallback),
+ this);
}
-QuicklistMenuItemCheckmark*
-createCheckmarkItem ()
+QuicklistMenuItemSeparator* TestQuicklist::createSeparatorItem()
{
DbusmenuMenuitem* item = NULL;
- QuicklistMenuItemCheckmark* checkmark = NULL;
+ QuicklistMenuItemSeparator* separator = NULL;
+
+ item = dbusmenu_menuitem_new ();
+
+ dbusmenu_menuitem_property_set_bool (item,
+ DBUSMENU_MENUITEM_PROP_ENABLED,
+ true);
+
+ separator = new QuicklistMenuItemSeparator (item, true);
+ menus2qitem_[item] = separator;
+
+ return separator;
+}
+
+QuicklistMenuItemRadio* TestQuicklist::createRadioItem(std::string const& label, bool enabled, bool checked)
+{
+ DbusmenuMenuitem* item = NULL;
+ QuicklistMenuItemRadio* radio = NULL;
item = dbusmenu_menuitem_new ();
dbusmenu_menuitem_property_set (item,
DBUSMENU_MENUITEM_PROP_LABEL,
- "Unchecked");
+ label.c_str());
dbusmenu_menuitem_property_set (item,
DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE,
- DBUSMENU_MENUITEM_TOGGLE_CHECK);
+ DBUSMENU_MENUITEM_TOGGLE_RADIO);
dbusmenu_menuitem_property_set_bool (item,
DBUSMENU_MENUITEM_PROP_ENABLED,
- true);
+ enabled);
dbusmenu_menuitem_property_set_int (item,
DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
- DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED);
+ (checked ?
+ DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED :
+ DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED
+ ));
- checkmark = new QuicklistMenuItemCheckmark (item, true);
-
- g_signal_connect (item,
- DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
- G_CALLBACK (activatedCallback),
- &gResult[0]);
+ connectToActivatedSignal(item);
+ radio = new QuicklistMenuItemRadio (item, true);
+ menus2qitem_[item] = radio;
- return checkmark;
+ return radio;
}
-QuicklistMenuItemRadio*
-createRadioItem ()
+QuicklistMenuItemCheckmark* TestQuicklist::createCheckmarkItem(std::string const& label, bool enabled, bool checked)
{
- DbusmenuMenuitem* item = NULL;
- QuicklistMenuItemRadio* radio = NULL;
+ DbusmenuMenuitem* item = NULL;
+ QuicklistMenuItemCheckmark* checkmark = NULL;
item = dbusmenu_menuitem_new ();
dbusmenu_menuitem_property_set (item,
DBUSMENU_MENUITEM_PROP_LABEL,
- "Radio Active");
+ label.c_str());
dbusmenu_menuitem_property_set (item,
DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE,
- DBUSMENU_MENUITEM_TOGGLE_RADIO);
+ DBUSMENU_MENUITEM_TOGGLE_CHECK);
dbusmenu_menuitem_property_set_bool (item,
DBUSMENU_MENUITEM_PROP_ENABLED,
- false);
+ enabled);
dbusmenu_menuitem_property_set_int (item,
DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
- DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
+ (checked ?
+ DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED :
+ DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED
+ ));
- radio = new QuicklistMenuItemRadio (item, true);
+ connectToActivatedSignal(item);
- g_signal_connect (item,
- DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
- G_CALLBACK (activatedCallback),
- &gResult[1]);
+ checkmark = new QuicklistMenuItemCheckmark (item, true);
+ menus2qitem_[item] = checkmark;
- return radio;
+ return checkmark;
}
-QuicklistMenuItemLabel*
-createLabelItem ()
+QuicklistMenuItemLabel* TestQuicklist::createLabelItem(std::string const& title, bool enabled)
{
DbusmenuMenuitem* item = NULL;
QuicklistMenuItemLabel* label = NULL;
@@ -134,172 +208,144 @@ createLabelItem ()
dbusmenu_menuitem_property_set (item,
DBUSMENU_MENUITEM_PROP_LABEL,
- "A Label");
+ title.c_str());
dbusmenu_menuitem_property_set_bool (item,
DBUSMENU_MENUITEM_PROP_ENABLED,
- true);
+ enabled);
- label = new QuicklistMenuItemLabel (item, true);
+ connectToActivatedSignal(item);
- g_signal_connect (item,
- DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
- G_CALLBACK (activatedCallback),
- &gResult[2]);
+ label = new QuicklistMenuItemLabel (item, true);
+ menus2qitem_[item] = label;
return label;
}
-void
-ThreadWidgetInit (nux::NThread* thread,
- void* initData)
+void TestQuicklist::AddItem(QuicklistMenuItem* item)
{
- gQuicklist = new QuicklistView ();
- gQuicklist->Reference ();
+ if (!quicklist_)
+ return;
- gCheckmark = createCheckmarkItem ();
- gQuicklist->AddMenuItem (gCheckmark);
- gRadio = createRadioItem ();
- gQuicklist->AddMenuItem (gRadio);
- gLabel = createLabelItem ();
- gQuicklist->AddMenuItem (gLabel);
+ quicklist_->AddMenuItem(item);
+}
+
+void TestQuicklist::UserInterfaceSetup()
+{
+ QuicklistMenuItem *item;
- gQuicklist->EnableQuicklistForTesting (true);
+ quicklist_ = new QuicklistView();
+ quicklist_->EnableQuicklistForTesting(true);
+ quicklist_->SetBaseXY(0, 0);
- gQuicklist->SetBaseXY (0, 0);
- gQuicklist->ShowWindow (true);
+ item = createLabelItem("Item1, normal");
+ AddItem(item);
+
+ item = createSeparatorItem();
+ AddItem(item);
+
+ item = createRadioItem("Item2, radio, checked", true, true);
+ AddItem(item);
+
+ item = createRadioItem("Item3, radio, unchecked", true, false);
+ AddItem(item);
+
+ item = createRadioItem("Item4, disabled radio, checked", false, true);
+ AddItem(item);
+
+ item = createRadioItem("Item5, disabled radio, unchecked", false, false);
+ AddItem(item);
+
+ item = createCheckmarkItem("Item6, checkmark, checked", true, true);
+ AddItem(item);
+
+ item = createCheckmarkItem("Item7, checkmark, unchecked", true, false);
+ AddItem(item);
+
+ item = createCheckmarkItem("Item8, disabled checkmark, checked", false, true);
+ AddItem(item);
+
+ item = createCheckmarkItem("Item9, disabled checkmark, unchecked", false, false);
+ AddItem(item);
+
+ item = createLabelItem("Item10, disabled", false);
+ AddItem(item);
+
+ quicklist_->ShowWindow(true);
+
+ auto wt = static_cast<nux::WindowThread*>(window_thread_);
+ nux::ColorLayer background (nux::Color (0x772953));
+ wt->SetWindowBackgroundPaintLayer(&background);
}
-void
-ControlThread (nux::NThread* thread,
- void* data)
+TestQuicklist *test_quicklist = NULL;
+
+void TestingThread(nux::NThread *thread, void *user_data)
{
- // sleep for 3 seconds
- nux::SleepForMilliseconds (3000);
- printf ("ControlThread successfully started\n");
-
- nux::WindowThread* mainWindowThread = NUX_STATIC_CAST (nux::WindowThread*,
- data);
-
- mainWindowThread->SetFakeEventMode (true);
- Display* display = mainWindowThread->GetWindow ().GetX11Display ();
-
- // assemble first button-click event
- XEvent buttonPressEvent;
- buttonPressEvent.xbutton.type = ButtonPress;
- buttonPressEvent.xbutton.serial = 0;
- buttonPressEvent.xbutton.send_event = False;
- buttonPressEvent.xbutton.display = display;
- buttonPressEvent.xbutton.window = 0;
- buttonPressEvent.xbutton.root = 0;
- buttonPressEvent.xbutton.subwindow = 0;
- buttonPressEvent.xbutton.time = CurrentTime;
- buttonPressEvent.xbutton.x = 50;
- buttonPressEvent.xbutton.y = 30;
- buttonPressEvent.xbutton.x_root = 0;
- buttonPressEvent.xbutton.y_root = 0;
- buttonPressEvent.xbutton.state = 0;
- buttonPressEvent.xbutton.button = Button1;
- buttonPressEvent.xbutton.same_screen = True;
-
- mainWindowThread->PumpFakeEventIntoPipe (mainWindowThread,
- (XEvent*) &buttonPressEvent);
-
- while (!mainWindowThread->ReadyForNextFakeEvent ())
- nux::SleepForMilliseconds (10);
-
- XEvent buttonReleaseEvent;
- buttonReleaseEvent.xbutton.type = ButtonRelease;
- buttonReleaseEvent.xbutton.serial = 0;
- buttonReleaseEvent.xbutton.send_event = False;
- buttonReleaseEvent.xbutton.display = display;
- buttonReleaseEvent.xbutton.window = 0;
- buttonReleaseEvent.xbutton.root = 0;
- buttonReleaseEvent.xbutton.subwindow = 0;
- buttonReleaseEvent.xbutton.time = CurrentTime;
- buttonReleaseEvent.xbutton.x = 50;
- buttonReleaseEvent.xbutton.y = 30;
- buttonReleaseEvent.xbutton.x_root = 0;
- buttonReleaseEvent.xbutton.y_root = 0;
- buttonReleaseEvent.xbutton.state = 0;
- buttonReleaseEvent.xbutton.button = Button1;
- buttonReleaseEvent.xbutton.same_screen = True;
-
- mainWindowThread->PumpFakeEventIntoPipe (mainWindowThread,
- (XEvent*) &buttonReleaseEvent);
-
- while (!mainWindowThread->ReadyForNextFakeEvent ())
- nux::SleepForMilliseconds (10);
-
- // assemble second button-click event
- buttonPressEvent.xbutton.time = CurrentTime;
- buttonPressEvent.xbutton.x = 50;
- buttonPressEvent.xbutton.y = 50;
- mainWindowThread->PumpFakeEventIntoPipe (mainWindowThread,
- (XEvent*) &buttonPressEvent);
- while (!mainWindowThread->ReadyForNextFakeEvent ())
- nux::SleepForMilliseconds (10);
-
- buttonReleaseEvent.xbutton.time = CurrentTime;
- buttonReleaseEvent.xbutton.x = 50;
- buttonReleaseEvent.xbutton.y = 50;
- mainWindowThread->PumpFakeEventIntoPipe (mainWindowThread,
- (XEvent*) &buttonReleaseEvent);
- while (!mainWindowThread->ReadyForNextFakeEvent ())
- nux::SleepForMilliseconds (10);
-
- // assemble third button-click event
- buttonPressEvent.xbutton.time = CurrentTime;
- buttonPressEvent.xbutton.x = 50;
- buttonPressEvent.xbutton.y = 70;
- mainWindowThread->PumpFakeEventIntoPipe (mainWindowThread,
- (XEvent*) &buttonPressEvent);
- while (!mainWindowThread->ReadyForNextFakeEvent ())
- nux::SleepForMilliseconds (10);
-
- buttonReleaseEvent.xbutton.time = CurrentTime;
- buttonReleaseEvent.xbutton.x = 50;
- buttonReleaseEvent.xbutton.y = 70;
- mainWindowThread->PumpFakeEventIntoPipe (mainWindowThread,
- (XEvent*) &buttonReleaseEvent);
- while (!mainWindowThread->ReadyForNextFakeEvent ())
- nux::SleepForMilliseconds (10);
-
- mainWindowThread->SetFakeEventMode (false);
+ while (test_quicklist->ReadyToGo() == false)
+ {
+ nuxDebugMsg("Waiting to start");
+ nux::SleepForMilliseconds(300);
+ }
+
+ nux::SleepForMilliseconds(1300);
+
+ auto *wnd_thread = static_cast<nux::WindowThread*>(user_data);
+
+ NuxAutomatedTestFramework test(wnd_thread);
+
+ test.Startup();
+
+ for (auto child : test_quicklist->quicklist_->GetChildren())
+ {
+ test.ViewSendMouseMotionToCenter(child);
+ test.ViewSendMouseClick(child, 1);
+ bool activated = test_quicklist->activated_[child];
+ bool should_be_activated = (child->GetItemType() != MENUITEM_TYPE_SEPARATOR && child->GetEnabled());
+
+ std::string msg = std::string(child->GetLabel());
+ msg += should_be_activated ? " | Activated" : " | NOT Activated";
+
+ test.TestReportMsg(activated == should_be_activated, msg.c_str());
+ nux::SleepForMilliseconds(200);
+ }
+
+ if (test.WhenDoneTerminateProgram())
+ {
+ wnd_thread->ExitMainLoop();
+ }
+ nuxDebugMsg("Exit testing thread");
}
int
main (int argc, char **argv)
{
- nux::WindowThread* wt = NULL;
- nux::SystemThread* st = NULL;
-
- g_type_init ();
-
- gtk_init (&argc, &argv);
- dbus_g_thread_init ();
- nux::NuxInitialize (0);
-
- wt = nux::CreateGUIThread (TEXT ("Unity Quicklist"),
- WIN_WIDTH,
- WIN_HEIGHT,
- 0,
- &ThreadWidgetInit,
- NULL);
-
- st = nux::CreateSystemThread (NULL, ControlThread, wt);
- if (st)
- st->Start (NULL);
-
- wt->Run (NULL);
-
- gQuicklist->UnReference ();
- delete st;
- delete wt;
-
- g_assert_cmpint (gResult[0], ==, true);
- g_assert_cmpint (gResult[1], ==, true);
- g_assert_cmpint (gResult[2], ==, true);
+ gtk_init(&argc, &argv);
+ nuxAssertMsg(XInitThreads() > 0, "XInitThreads has failed");
+
+ test_quicklist = new TestQuicklist("Quicklist Test", WIN_WIDTH, WIN_HEIGHT, 100000);
+ test_quicklist->Startup();
+ test_quicklist->UserInterfaceSetup();
+
+ auto *test_thread = nux::CreateSystemThread(NULL, &TestingThread, test_quicklist->GetWindowThread());
+ test_thread->Start(test_quicklist);
+
+ test_quicklist->Run();
+
+ g_assert_cmpint (test_quicklist->HasNthItemActivated(0), ==, true);
+ g_assert_cmpint (test_quicklist->HasNthItemActivated(1), ==, false);
+ g_assert_cmpint (test_quicklist->HasNthItemActivated(2), ==, true);
+ g_assert_cmpint (test_quicklist->HasNthItemActivated(3), ==, true);
+ g_assert_cmpint (test_quicklist->HasNthItemActivated(4), ==, false);
+ g_assert_cmpint (test_quicklist->HasNthItemActivated(5), ==, false);
+ g_assert_cmpint (test_quicklist->HasNthItemActivated(6), ==, true);
+ g_assert_cmpint (test_quicklist->HasNthItemActivated(7), ==, true);
+ g_assert_cmpint (test_quicklist->HasNthItemActivated(8), ==, false);
+ g_assert_cmpint (test_quicklist->HasNthItemActivated(9), ==, false);
+ g_assert_cmpint (test_quicklist->HasNthItemActivated(10), ==, false);
+
+ delete test_thread;
+ delete test_quicklist;
return 0;
}
diff --git a/standalone-clients/ui/TestQuicklistVisuals.cpp b/standalone-clients/ui/TestQuicklistVisuals.cpp
index 03ff93672..107412668 100644
--- a/standalone-clients/ui/TestQuicklistVisuals.cpp
+++ b/standalone-clients/ui/TestQuicklistVisuals.cpp
@@ -18,7 +18,6 @@
#include <glib.h>
#include <gtk/gtk.h>
-#include <dbus/dbus-glib.h>
#include "Nux/Nux.h"
#include "Nux/VLayout.h"
@@ -60,14 +59,12 @@ createRadioItem (const gchar* label,
DBUSMENU_MENUITEM_PROP_ENABLED,
enabled);
- if (checked)
- dbusmenu_menuitem_property_set_int (item,
- DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
- DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
- else
- dbusmenu_menuitem_property_set_int (item,
- DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
- DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED);
+ dbusmenu_menuitem_property_set_int (item,
+ DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
+ (checked ?
+ DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED :
+ DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED
+ ));
radio = new QuicklistMenuItemRadio (item, true);
@@ -96,14 +93,12 @@ createCheckmarkItem (const gchar* label,
DBUSMENU_MENUITEM_PROP_ENABLED,
enabled);
- if (checked)
- dbusmenu_menuitem_property_set_int (item,
- DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
- DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
- else
- dbusmenu_menuitem_property_set_int (item,
- DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
- DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED);
+ dbusmenu_menuitem_property_set_int (item,
+ DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
+ (checked ?
+ DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED :
+ DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED
+ ));
checkmark = new QuicklistMenuItemCheckmark (item, true);
@@ -111,7 +106,7 @@ createCheckmarkItem (const gchar* label,
}
QuicklistMenuItemLabel*
-createLabelItem (const gchar* string)
+createLabelItem (const gchar* string, bool enabled = true)
{
DbusmenuMenuitem* item = NULL;
QuicklistMenuItemLabel* label = NULL;
@@ -124,7 +119,7 @@ createLabelItem (const gchar* string)
dbusmenu_menuitem_property_set_bool (item,
DBUSMENU_MENUITEM_PROP_ENABLED,
- true);
+ enabled);
label = new QuicklistMenuItemLabel (item, true);
@@ -170,7 +165,8 @@ ThreadWidgetInit (nux::NThread* thread,
gQuicklists[0]->AddMenuItem (radio);
separator = createSeparatorItem ();
gQuicklists[0]->AddMenuItem (separator);
- label = createLabelItem ("Application Name");
+ label = createLabelItem ("<b>Application Name</b>");
+ label->EnableLabelMarkup(true);
gQuicklists[0]->AddMenuItem (label);
separator = createSeparatorItem ();
gQuicklists[0]->AddMenuItem (separator);
@@ -193,7 +189,8 @@ ThreadWidgetInit (nux::NThread* thread,
gQuicklists[1]->AddMenuItem (checkmark);
separator = createSeparatorItem ();
gQuicklists[1]->AddMenuItem (separator);
- label = createLabelItem ("Application Name");
+ label = createLabelItem ("<b>Application Name</b>");
+ label->EnableLabelMarkup(true);
gQuicklists[1]->AddMenuItem (label);
separator = createSeparatorItem ();
gQuicklists[1]->AddMenuItem (separator);
@@ -214,11 +211,12 @@ ThreadWidgetInit (nux::NThread* thread,
gQuicklists[2]->AddMenuItem (separator);
checkmark = createCheckmarkItem ("Option 03", false, true);
gQuicklists[2]->AddMenuItem (checkmark);
- checkmark = createCheckmarkItem ("Option 04", false, true);
- gQuicklists[2]->AddMenuItem (checkmark);
+ label = createLabelItem ("Option 04", false);
+ gQuicklists[2]->AddMenuItem (label);
separator = createSeparatorItem ();
gQuicklists[2]->AddMenuItem (separator);
- label = createLabelItem ("Application Name");
+ label = createLabelItem ("<b>Application Name</b>");
+ label->EnableLabelMarkup(true);
gQuicklists[2]->AddMenuItem (label);
separator = createSeparatorItem ();
gQuicklists[2]->AddMenuItem (separator);
@@ -227,6 +225,9 @@ ThreadWidgetInit (nux::NThread* thread,
gQuicklists[2]->EnableQuicklistForTesting (true);
gQuicklists[2]->SetBaseXY (45, 290);
gQuicklists[2]->ShowWindow (true);
+
+ nux::ColorLayer background (nux::Color (0x772953));
+ static_cast<nux::WindowThread*>(thread)->SetWindowBackgroundPaintLayer(&background);
}
int
@@ -234,10 +235,7 @@ main (int argc, char **argv)
{
nux::WindowThread* wt = NULL;
- g_type_init ();
-
gtk_init (&argc, &argv);
- dbus_g_thread_init ();
nux::NuxInitialize (0);
wt = nux::CreateGUIThread (TEXT ("Unity visual Quicklist-test"),
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 840f0fa51..1759638f2 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -99,6 +99,8 @@ if (GTEST_FOUND AND
# The service that provides DBus services to test against
add_executable(test-gtest-service
+ test_service_hud.c
+ test_service_hud.h
test_service_lens.c
test_service_lens.h
test_service_main.c
@@ -183,7 +185,8 @@ if (GTEST_FOUND AND
test_utils.h
test_ratings_filter.cpp
test_results.cpp
- )
+ test_hud.cpp
+ )
target_link_libraries(test-gtest-dbus ${GTEST_BOTH_LIBRARIES})
add_test(UnityGTestDBus test-gtest-dbus)
add_dependencies(test-gtest-dbus unity-core-${UNITY_API_VERSION} test-gtest-service)
diff --git a/tests/autopilot/autopilot/emulators/X11.py b/tests/autopilot/autopilot/emulators/X11.py
index 8ee7c0d65..a668d529c 100644
--- a/tests/autopilot/autopilot/emulators/X11.py
+++ b/tests/autopilot/autopilot/emulators/X11.py
@@ -2,17 +2,18 @@
# Copyright 2010 Canonical
# Author: Alex Launi
#
-# This program is free software: you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 3, as published
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
-# This script is designed to run unity in a test drive manner. It will drive
+# This script is designed to run unity in a test drive manner. It will drive
# X and test the GL calls that Unity makes, so that we can easily find out if
# we are triggering graphics driver/X bugs.
-"""
-A collection of emulators for X11 - namely keyboards and mice. In the future we may
-also need other devices.
+"""A collection of emulators for X11 - namely keyboards and mice.
+
+In the future we may also need other devices.
+
"""
@@ -24,21 +25,12 @@ from Xlib.display import Display
from Xlib.ext.xtest import fake_input
import gtk.gdk
+_PRESSED_KEYS = []
+_DISPLAY = Display()
+
+
class Keyboard(object):
- '''Wrapper around xlib to make faking keyboard input possible'''
- _lame_hardcoded_keycodes = {
- 'E' : 9, # escape
- 'A' : 64,
- 'C' : 37,
- 'S' : 50,
- 'T' : 23,
- 'W' : 133,
- 'U' : 111, # up arrow
- 'D' : 116, # down arrow
- 'L' : 113, # left arrow
- 'R' : 114, # right arrow
- '1' : 67 # f1
- }
+ """Wrapper around xlib to make faking keyboard input possible."""
_special_X_keysyms = {
' ' : "space",
@@ -79,69 +71,110 @@ class Keyboard(object):
'}' : "braceright",
'~' : "asciitilde"
}
-
+
+ _keysym_translations = {
+ 'Control' : 'Control_L',
+ 'Ctrl' : 'Control_L',
+ 'Alt' : 'Alt_L',
+ 'Super' : 'Super_L',
+ 'Shift' : 'Shift_L',
+ 'Enter' : 'Return',
+ }
+
def __init__(self):
- self._display = Display()
+ self.shifted_keys = [k[1] for k in _DISPLAY._keymap_codes if k]
- def press(self, keys):
- """
- Send key press events for every key in the 'keys' string.
- """
- self.__perform_on_keys(keys, X.KeyPress)
- sleep(0.2)
+ def press(self, keys, delay=0.2):
+ """Send key press events only.
+
+ The 'keys' argument must be a string of keys you want
+ pressed. For example:
+
+ press('Alt+F2')
+
+ presses the 'Alt' and 'F2' keys.
- def release(self, keys):
- """
- Send key release events for every key in the 'keys' string.
"""
- self.__perform_on_keys(keys, X.KeyRelease)
- sleep(0.2)
-
- def press_and_release(self, keys):
+ if not isinstance(keys, basestring):
+ raise TypeError("'keys' argument must be a string.")
+ self.__perform_on_keys(self.__translate_keys(keys), X.KeyPress)
+ sleep(delay)
+
+ def release(self, keys, delay=0.2):
+ """Send key release events only.
+
+ The 'keys' argument must be a string of keys you want
+ released. For example:
+
+ release('Alt+F2')
+
+ releases the 'Alt' and 'F2' keys.
+
"""
- Send key press events for every key in the 'keys' string, then send
- key release events for every key in the 'keys' string.
+ if not isinstance(keys, basestring):
+ raise TypeError("'keys' argument must be a string.")
+ self.__perform_on_keys(self.__translate_keys(keys), X.KeyRelease)
+ sleep(delay)
+
+ def press_and_release(self, keys, delay=0.2):
+ """Press and release all items in 'keys'.
+
+ This is the same as calling 'press(keys);release(keys)'.
+
+ The 'keys' argument must be a string of keys you want
+ pressed and released.. For example:
+
+ press_and_release('Alt+F2'])
+
+ presses both the 'Alt' and 'F2' keys, and then releases both keys.
- This method is not appropriate for simulating a user typing a string
- of text, since it presses all the keys, and then releases them all.
"""
- self.press(keys)
- self.release(keys)
- def type(self, keys):
+ self.press(keys, delay)
+ self.release(keys, delay)
+
+ def type(self, string, delay=0.1):
+ """Simulate a user typing a string of text.
+
+ Only 'normal' keys can be typed with this method. Control characters
+ (such as 'Alt' will be interpreted as an 'A', and 'l', and a 't').
+
"""
- Simulate a user typing the keys specified in 'keys'.
+ if not isinstance(string, basestring):
+ raise TypeError("'keys' argument must be a string.")
+ for key in string:
+ self.press(key, delay)
+ self.release(key, delay)
+
+ @staticmethod
+ def cleanup():
+ """Generate KeyRelease events for any un-released keys.
+
+ Make sure you call this at the end of any test to release
+ any keys that were pressed and not released.
- Each key will be pressed and released before the next key is processed. If
- you need to simulate multiple keys being pressed at the same time, use the
- 'press_and_release' method above.
"""
- for key in keys:
- self.press(key)
- self.release(key)
+ for keycode in _PRESSED_KEYS:
+ print "Releasing key: %r" % (keycode)
+ fake_input(_DISPLAY, X.KeyRelease, keycode)
def __perform_on_keys(self, keys, event):
- control_key = False
keycode = 0
shift_mask = 0
- for index in range(len(keys)):
- key = keys[index]
- if control_key:
- keycode = self._lame_hardcoded_keycodes[key]
- shift_mask = 0
- control_key = False
- elif index < len(keys) and key == '^' and keys[index+1] in self._lame_hardcoded_keycodes:
- control_key = True
- continue
- else:
- keycode, shift_mask = self.__char_to_keycode(key)
+ for key in keys:
+ keycode, shift_mask = self.__char_to_keycode(key)
if shift_mask != 0:
- fake_input(self._display, event, 50)
+ fake_input(_DISPLAY, event, 50)
+
+ if event == X.KeyPress:
+ _PRESSED_KEYS.append(keycode)
+ elif event == X.KeyRelease:
+ _PRESSED_KEYS.remove(keycode)
- fake_input(self._display, event, keycode)
- self._display.sync()
+ fake_input(_DISPLAY, event, keycode)
+ _DISPLAY.sync()
def __get_keysym(self, key) :
keysym = XK.string_to_keysym(key)
@@ -151,70 +184,68 @@ class Keyboard(object):
# the subsequent display.keysym_to_keycode("numbersign") is 0.
keysym = XK.string_to_keysym(self._special_X_keysyms[key])
return keysym
-
+
def __is_shifted(self, key) :
- if key.isupper() :
- return True
- if "~!@#$%^&*()_+{}|:\"<>?".find(key) >= 0 :
- return True
- return False
+ return len(key) == 1 and ord(key) in self.shifted_keys
def __char_to_keycode(self, key) :
keysym = self.__get_keysym(key)
- keycode = self._display.keysym_to_keycode(keysym)
+ keycode = _DISPLAY.keysym_to_keycode(keysym)
if keycode == 0 :
print "Sorry, can't map", key
-
+
if (self.__is_shifted(key)) :
shift_mask = X.ShiftMask
else :
shift_mask = 0
-
return keycode, shift_mask
+ def __translate_keys(self, key_string):
+ return [self._keysym_translations.get(k,k) for k in key_string.split('+')]
+
+
class Mouse(object):
- '''Wrapper around xlib to make moving the mouse easier'''
-
- def __init__(self):
- self._display = Display()
+ """Wrapper around xlib to make moving the mouse easier."""
@property
def x(self):
+ """Mouse position X coordinate."""
return self.position()[0]
@property
def y(self):
+ """Mouse position Y coordinate."""
return self.position()[1]
-
+
def press(self, button=1):
- '''Press mouse button at current mouse location'''
- fake_input(self._display, X.ButtonPress, button)
- self._display.sync()
-
+ """Press mouse button at current mouse location."""
+ fake_input(_DISPLAY, X.ButtonPress, button)
+ _DISPLAY.sync()
+
def release(self, button=1):
- '''Releases mouse button at current mouse location'''
- fake_input(self._display, X.ButtonRelease, button)
- self._display.sync()
-
+ """Releases mouse button at current mouse location."""
+ fake_input(_DISPLAY, X.ButtonRelease, button)
+ _DISPLAY.sync()
+
def click(self, button=1):
- '''Click mouse at current location'''
+ """Click mouse at current location."""
self.press(button)
sleep(0.25)
self.release(button)
-
+
def move(self, x, y, animate=True, rate=100, time_between_events=0.001):
'''Moves mouse to location (x, y, pixels_per_event, time_between_event)'''
def perform_move(x, y, sync):
- fake_input(self._display, X.MotionNotify, sync, X.CurrentTime, X.NONE, x=x, y=y)
- self._display.sync()
+ fake_input(_DISPLAY, X.MotionNotify, sync, X.CurrentTime, X.NONE, x=x, y=y)
+ _DISPLAY.sync()
sleep(time_between_events)
if not animate:
perform_move(x, y, False)
-
+
dest_x, dest_y = x, y
curr_x, curr_y = self.position()
-
+
# calculate a path from our current position to our destination
dy = float(curr_y - dest_y)
dx = float(curr_x - dest_x)
@@ -226,24 +257,25 @@ class Mouse(object):
target_x = min(curr_x + xscale, dest_x) if dest_x > curr_x else max(curr_x + xscale, dest_x)
perform_move(target_x - curr_x, 0, True)
curr_x = target_x;
-
+
if (curr_y != dest_y):
yscale = rate if dest_y > curr_y else -rate
while (curr_y != dest_y):
target_y = min(curr_y + yscale, dest_y) if dest_y > curr_y else max(curr_y + yscale, dest_y)
perform_move(0, target_y - curr_y, True)
curr_y = target_y
-
+
def position(self):
- '''Returns the current position of the mouse pointer'''
- coord = self._display.screen().root.query_pointer()._data
+ """Returns the current position of the mouse pointer."""
+ coord = _DISPLAY.screen().root.query_pointer()._data
x, y = coord["root_x"], coord["root_y"]
return x, y
-
- def reset(self):
- self.move(16, 13, animate=False)
- self.click()
- self.move(800, 500, animate=False)
+
+ @staticmethod
+ def cleanup():
+ """Put mouse in a known safe state."""
+ sg = ScreenGeometry()
+ sg.move_mouse_to_monitor(0)
class ScreenGeometry:
diff --git a/tests/autopilot/autopilot/emulators/bamf.py b/tests/autopilot/autopilot/emulators/bamf.py
new file mode 100644
index 000000000..461e6eb22
--- /dev/null
+++ b/tests/autopilot/autopilot/emulators/bamf.py
@@ -0,0 +1,341 @@
+# Copyright 2011 Canonical
+# Author: Thomi Richards
+#
+# 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.
+
+"Various classes for interacting with BAMF."
+
+import dbus
+from dbus.mainloop.glib import DBusGMainLoop
+import gio
+import gobject
+from Xlib import display, X, protocol
+
+__all__ = ["Bamf",
+ "BamfApplication",
+ "BamfWindow",
+ ]
+
+
+_BAMF_BUS_NAME = 'org.ayatana.bamf'
+DBusGMainLoop(set_as_default=True)
+_session_bus = dbus.SessionBus()
+_X_DISPLAY = display.Display()
+
+
+def _filter_user_visible(win):
+ """Filter out non-user-visible objects.
+
+ In some cases the DBus method we need to call hasn't been registered yet,
+ in which case we do the safe thing and return False.
+
+ """
+ try:
+ return win.user_visible
+ except dbus.DBusException:
+ return False
+
+
+class Bamf:
+ """High-level class for interacting with Bamf from within a test.
+
+ Use this class to inspect the state of running applications and open
+ windows.
+
+ """
+
+ def __init__(self):
+ matcher_path = '/org/ayatana/bamf/matcher'
+ self.matcher_interface_name = 'org.ayatana.bamf.matcher'
+ self.matcher_proxy = _session_bus.get_object(_BAMF_BUS_NAME, matcher_path)
+ self.matcher_interface = dbus.Interface(self.matcher_proxy, self.matcher_interface_name)
+
+ def get_running_applications(self, user_visible_only=True):
+ """Get a list of the currently running applications.
+
+ If user_visible_only is True (the default), only applications
+ visible to the user in the switcher will be returned.
+
+ """
+ apps = [BamfApplication(p) for p in self.matcher_interface.RunningApplications()]
+ if user_visible_only:
+ return filter(_filter_user_visible, apps)
+ return apps
+
+ def get_running_applications_by_title(self, app_title):
+ """Return a list of applications that have the title `app_title`.
+
+ This method may return an empty list, if no applications
+ are found with the specified title.
+
+ """
+ return [a for a in self.get_running_applications() if a.name == app_title]
+
+ def get_open_windows(self, user_visible_only=True):
+ """Get a list of currently open windows.
+
+ If user_visible_only is True (the default), only applications
+ visible to the user in the switcher will be returned.
+
+ """
+
+ windows = [BamfWindow(w) for w in self.matcher_interface.WindowPaths()]
+ if user_visible_only:
+ return filter(_filter_user_visible, windows)
+ return windows
+
+ def get_open_windows_by_title(self, win_title):
+ """Get a list of all open windows with a specific window title.
+
+ This method may return an empty list if no currently open windows have
+ the specified title.
+
+ """
+ return [w for w in self.get_open_windows() if w.title == win_title]
+
+ def application_is_running(self, app_name):
+ """Detect if an application with a given name is currently running.
+
+ 'app_name' is the name of the application you are looking for.
+ """
+ return app_name in [a.name for a in self.get_running_applications()]
+
+ def wait_until_application_is_running(self, app_name, timeout):
+ """Wait until a given application is running.
+
+ 'app_name' is the name of the application.
+ 'timeout' is the maximum time to wait, in seconds. If set to
+ something less than 0, this method will wait forever.
+
+ This method returns true once the application is found, or false
+ if the application was not found until the timeout was reached.
+ """
+ # python workaround since you can't assign to variables in the enclosing scope:
+ # see on_timeout_reached below...
+ found_app = [True]
+
+ # maybe the app is running already?
+ if not self.application_is_running(app_name):
+ wait_forever = timeout < 0
+ gobject_loop = gobject.MainLoop()
+ # No, so define a callback to watch the ViewOpened signal:
+ def on_view_added(bamf_path, name):
+ if bamf_path.split('/')[-1].startswith('application'):
+ app = BamfApplication(bamf_path)
+ if app.name == app_name:
+ gobject_loop.quit()
+
+ # ...and one for when the user-defined timeout has been reached:
+ def on_timeout_reached():
+ gobject_loop.quit()
+ found_app[0] = False
+ return False
+
+ # need a timeout? if so, connect it:
+ if not wait_forever:
+ gobject.timeout_add(timeout * 1000, on_timeout_reached)
+ # connect signal handler:
+ _session_bus.add_signal_receiver(on_view_added, 'ViewOpened')
+ # pump the gobject main loop until either the correct signal is emitted, or the
+ # timeout happens.
+ gobject_loop.run()
+
+ return found_app[0]
+
+ def launch_application(self, desktop_file, wait=True):
+ """Launch an application by specifying a desktop file.
+
+ Returns the Gobject process object. if wait is True (the default),
+ this method will not return until an instance of this application
+ appears in the BAMF application list.
+ """
+ proc = gio.unix.DesktopAppInfo(desktop_file)
+ proc.launch()
+ if wait:
+ self.wait_until_application_is_running(proc.get_name(), -1)
+ return proc
+
+
+class BamfApplication:
+ """Represents an application, with information as returned by Bamf.
+
+ Don't instantiate this class yourself. instead, use the methods as
+ provided by the Bamf class.
+
+ """
+ def __init__(self, bamf_app_path):
+ self.bamf_app_path = bamf_app_path
+ try:
+ self._app_proxy = _session_bus.get_object(_BAMF_BUS_NAME, bamf_app_path)
+ self._view_iface = dbus.Interface(self._app_proxy, 'org.ayatana.bamf.view')
+ except dbus.DBusException, e:
+ e.message += 'bamf_app_path=%r' % (bamf_app_path)
+ raise
+
+ @property
+ def name(self):
+ """Get the application name."""
+ return self._view_iface.Name()
+
+ @property
+ def is_active(self):
+ """Is the application active (i.e.- has keyboard focus)?"""
+ return self._view_iface.IsActive()
+
+ @property
+ def is_urgent(self):
+ """Is the application currently signalling urgency?"""
+ return self._view_iface.IsUrgent()
+
+ @property
+ def user_visible(self):
+ """Is this application visible to the user?
+
+ Some applications (such as the panel) are hidden to the user but will
+ still be returned by bamf.
+
+ """
+ return self._view_iface.UserVisible()
+
+ def get_windows(self):
+ """Get a list of the application windows."""
+ return [BamfWindow(w) for w in self._view_iface.Children()]
+
+ def __repr__(self):
+ return "<BamfApplication '%s'>" % (self.name)
+
+
+class BamfWindow:
+ """Represents an application window, as returned by Bamf.
+
+ Don't instantiate this class yourself. Instead, use the appropriate methods
+ in BamfApplication.
+
+ """
+ def __init__(self, window_path):
+ self._bamf_win_path = window_path
+ self._app_proxy = _session_bus.get_object(_BAMF_BUS_NAME, window_path)
+ self._window_iface = dbus.Interface(self._app_proxy, 'org.ayatana.bamf.window')
+ self._view_iface = dbus.Interface(self._app_proxy, 'org.ayatana.bamf.view')
+
+ self._xid = int(self._window_iface.GetXid())
+ self._x_root_win = _X_DISPLAY.screen().root
+ self._x_win = _X_DISPLAY.create_resource_object('window', self._xid)
+
+
+ @property
+ def x_id(self):
+ """Get the X11 Window Id."""
+ return self._xid
+
+ @property
+ def title(self):
+ """Get the window title.
+
+ This may be different from the application name.
+
+ """
+ return self._getProperty('_NET_WM_NAME')
+
+ @property
+ def geometry(self):
+ """Get the geometry for this window.
+
+ Returns a tuple containing (x, y, width, height).
+
+ """
+
+ geometry = self._x_win.get_geometry()
+ return (geometry.x, geometry.y, geometry.width, geometry.height)
+
+ @property
+ def is_maximized(self):
+ """Is the window maximized?
+
+ Maximized in this case means both maximized
+ vertically and horizontally. If a window is only maximized in one
+ direction it is not considered maximized.
+
+ """
+ win_state = self._get_window_states()
+ return '_NET_WM_STATE_MAXIMIZED_VERT' in win_state and \
+ '_NET_WM_STATE_MAXIMIZED_HORZ' in win_state
+
+ @property
+ def application(self):
+ """Get the application that owns this window.
+
+ This method may return None if the window does not have an associated
+ application. The 'desktop' window is one such example.
+
+ """
+ # BAMF returns a list of parents since some windows don't have an
+ # associated application. For these windows we return none.
+ parents = self._view_iface.Parents()
+ if parents:
+ return BamfApplication(parents[0])
+ else:
+ return None
+
+ @property
+ def user_visible(self):
+ """Is this window visible to the user in the switcher?"""
+ return self._view_iface.UserVisible()
+
+ @property
+ def is_hidden(self):
+ """Is this window hidden?
+
+ Windows are hidden when the 'Show Desktop' mode is activated.
+
+ """
+ win_state = self._get_window_states()
+ return '_NET_WM_STATE_HIDDEN' in win_state
+
+ @property
+ def is_valid(self):
+ """Is this window object valid?
+
+ Invalid windows are caused by windows closing during the construction of
+ this object instance.
+
+ """
+ return not self._x_win is None
+
+ def close(self):
+ """Close the window."""
+
+ self._setProperty('_NET_CLOSE_WINDOW', [0, 0])
+
+ def __repr__(self):
+ return "<BamfWindow '%s'>" % (self.title if self._x_win else str(self._xid))
+
+ def _getProperty(self, _type):
+ """Get an X11 property.
+
+ _type is a string naming the property type. win is the X11 window object.
+
+ """
+ atom = self._x_win.get_full_property(_X_DISPLAY.get_atom(_type), X.AnyPropertyType)
+ if atom: return atom.value
+
+ def _setProperty(self, _type, data, mask=None):
+ if type(data) is str:
+ dataSize = 8
+ else:
+ data = (data+[0]*(5-len(data)))[:5]
+ dataSize = 32
+
+ ev = protocol.event.ClientMessage(window=self._x_win, client_type=_X_DISPLAY.get_atom(_type), data=(dataSize, data))
+
+ if not mask:
+ mask = (X.SubstructureRedirectMask|X.SubstructureNotifyMask)
+ self._x_root_win.send_event(ev, event_mask=mask)
+ _X_DISPLAY.sync()
+
+ def _get_window_states(self):
+ """Return a list of strings representing the current window state."""
+
+ return map(_X_DISPLAY.get_atom_name, self._getProperty('_NET_WM_STATE'))
diff --git a/tests/autopilot/autopilot/emulators/unity.py b/tests/autopilot/autopilot/emulators/unity.py
index dfcd89a14..4768827e1 100644
--- a/tests/autopilot/autopilot/emulators/unity.py
+++ b/tests/autopilot/autopilot/emulators/unity.py
@@ -10,9 +10,7 @@
# X and test the GL calls that Unity makes, so that we can easily find out if
# we are triggering graphics driver/X bugs.
-"""
-A collection of emulators that make it easier to interact with Unity.
-"""
+"""A collection of emulators that make it easier to interact with Unity."""
from compizconfig import Setting
from compizconfig import Plugin
@@ -23,12 +21,12 @@ from autopilot.emulators.X11 import Keyboard, Mouse, ScreenGeometry
from autopilot.globals import global_context
class Unity(object):
- '''
- High level class to abstract interactions with the unity shell.
+ """High level class to abstract interactions with the unity shell.
- This class should not be used directly. Instead, use one of the derived classes to
- interact with a different piece of the Unity system.
- '''
+ This class should not be used directly. Instead, use one of the derived
+ classes to interact with a different piece of the Unity system.
+
+ """
def __init__(self):
## TODO
@@ -48,16 +46,12 @@ class Unity(object):
self.INTROSPECTION_IFACE)
def get_state(self, piece='/Unity'):
- '''
- returns a full dump of unity's state via the introspection interface
- '''
+ """Returns a full dump of unity's state."""
return self._introspection_iface.GetState(piece)
class Launcher(Unity):
- """
- Interact with the unity Launcher.
- """
+ """Interact with the unity Launcher."""
def __init__(self):
super(Launcher, self).__init__()
@@ -70,11 +64,14 @@ class Launcher(Unity):
self.hide_timeout = 1
self.grabbed = False
+ state = self.__get_state(0)
+ self.icon_width = int(state['icon-size'])
+
def move_mouse_to_right_of_launcher(self, monitor):
(x, y, w, h) = self.launcher_geometry(monitor)
- self._mouse.move(x + w + 15, y + h / 2, False)
+ self._mouse.move(x + w + 10, y + h / 2, False)
sleep(self.show_timeout)
-
+
def move_mouse_over_launcher(self, monitor):
(x, y, w, h) = self.launcher_geometry(monitor)
self._screen.move_mouse_to_monitor(monitor);
@@ -82,57 +79,57 @@ class Launcher(Unity):
def reveal_launcher(self, monitor):
(x, y, w, h) = self.launcher_geometry(monitor)
- self._mouse.move(x - 920, y + h / 2, True, 5, .002)
+ self._mouse.move(x - 1200, y + h / 2)
sleep(self.show_timeout)
def keyboard_reveal_launcher(self):
- self._keyboard.press('^W')
+ self._keyboard.press('Super')
sleep(1)
-
+
def keyboard_unreveal_launcher(self):
- self._keyboard.release('^W')
+ self._keyboard.release('Super')
sleep(1)
def grab_switcher(self):
- self._keyboard.press_and_release('^A^1')
+ self._keyboard.press_and_release('Alt+F1')
self.grabbed = True
def switcher_enter_quicklist(self):
if self.grabbed:
- self._keyboard.press_and_release('^R')
+ self._keyboard.press_and_release('Right')
def switcher_exit_quicklist(self):
if self.grabbed:
- self._keyboard.press_and_release('^L')
+ self._keyboard.press_and_release('Left')
def start_switcher(self):
- self._keyboard.press('^W^T')
- self._keyboard.release('^T')
+ self._keyboard.press('Super+Tab')
+ self._keyboard.release('Tab')
sleep(1)
def end_switcher(self, cancel):
if cancel:
- self._keyboard.press_and_release('^E')
+ self._keyboard.press_and_release('Escape')
if self.grabbed != True:
- self._keyboard.release('^W')
+ self._keyboard.release('Super')
else:
if self.grabbed:
self._keyboard.press_and_release('\n')
else:
- self._keyboard.release('^W')
+ self._keyboard.release('Super')
self.grabbed = False
def switcher_next(self):
if self.grabbed:
- self._keyboard.press_and_release('^D')
+ self._keyboard.press_and_release('Down')
else:
- self._keyboard.press_and_release('^T')
+ self._keyboard.press_and_release('Tab')
def switcher_prev(self):
if self.grabbed:
- self._keyboard.press_and_release('^U')
+ self._keyboard.press_and_release('Up')
else:
- self._keyboard.press_and_release('^S^T')
+ self._keyboard.press_and_release('Shift+Tab')
def quicklist_open(self, monitor):
state = self.__get_state(monitor)
@@ -176,76 +173,96 @@ class Launcher(Unity):
# get the state for the 'launcher' piece
return super(Launcher, self).get_state('/Unity/LauncherController/Launcher[monitor=%s]' % (monitor))[0]
+ def get_launcher_icons(self):
+ """Get a list of launcher icons in this launcher."""
+ icons = self.get_state("//Launcher/LauncherIcon")
+ return [LauncherIcon(icon_dict) for icon_dict in icons]
-class UnityLauncherIconTooltip(Unity):
- """
- Interact with the Launcher Icon Tooltips?
- """
- RENDER_TIMEOUT_MS = 0
- SHOW_X_POS = 0
- SHOW_Y_POS = 32
- HIDE_X_POS = 64
- HIDE_Y_POS = 0
- WIDTH = 0
- HEIGHT = 0
-
- def __init__(self, TooltipText=None):
- self.mouse = Mouse()
+ def click_launcher_icon(self, icon, monitor=0, button=1):
+ """Move the mouse over the launcher icon, and click it."""
+ self.reveal_launcher(monitor)
+ self._mouse.move(icon.x, icon.y + (self.icon_width / 2))
+ self._mouse.click(button)
+ self.move_mouse_to_right_of_launcher(monitor)
- def setUp(self):
- self.mouse.move(200, 200)
+class LauncherIcon:
+ """Holds information about a launcher icon.
- def show_on_mouse_hover(self):
- self.mouse.move(self.SHOW_X_POS, self.SHOW_Y_POS)
- sleep(self.RENDER_TIMEOUT_MS)
+ Do not instantiate an instance of this class yourself. Instead, use the
+ appropriate methods in the Launcher class instead.
- def hide_on_mouse_out(self):
- self.mouse.move(self.HIDE_X_POS, self.HIDE_Y_POS)
-
- def isRendered(self):
- return False
+ """
+ def __init__(self, icon_dict):
+ self.tooltip_text = icon_dict['tooltip-text']
+ self.x = icon_dict['x']
+ self.y = icon_dict['y']
+ self.num_windows = icon_dict['related-windows']
+ self.visible = icon_dict['quirk-visible']
+ self.active = icon_dict['quirk-active']
+ self.running = icon_dict['quirk-running']
+ self.presented = icon_dict['quirk-presented']
+ self.urgent = icon_dict['quirk-urgent']
class Switcher(Unity):
- """
- Interact with the Unity switcher.
- """
+ """Interact with the Unity switcher."""
def __init__(self):
super(Switcher, self).__init__()
def initiate(self):
- self._keyboard.press('^A^T')
- self._keyboard.release('^T')
+ """Start the switcher with alt+tab."""
+ self._keyboard.press('Alt')
+ self._keyboard.press_and_release('Tab')
+ sleep(1)
def initiate_detail_mode(self):
- self._keyboard.press('^A`')
- self._keyboard.release('`')
+ """Start detail mode with alt+`"""
+ self._keyboard.press('Alt')
+ self._keyboard.press_and_release('`')
def terminate(self):
- self._keyboard.release('^A')
+ """Stop switcher."""
+ self._keyboard.release('Alt')
def next_icon(self):
- self._keyboard.press_and_release('^T')
+ """Move to the next application."""
+ self._keyboard.press_and_release('Tab')
def previous_icon(self):
- self._keyboard.press_and_release('^S^T')
+ """Move to the previous application."""
+ self._keyboard.press_and_release('Shift+Tab')
def show_details(self):
+ """Show detail mode."""
self._keyboard.press_and_release('`')
def hide_details(self):
- self._keyboard.press_and_release('^U')
+ """Hide detail mode."""
+ self._keyboard.press_and_release('Up')
def next_detail(self):
+ """Move to next detail in the switcher."""
self._keyboard.press_and_release('`')
def previous_detail(self):
- self._keyboard.press_and_release('^S`')
+ """Move to the previous detail in the switcher."""
+ self._keyboard.press_and_release('Shift+`')
def __get_icon(self, index):
- import ipdb; ipdb.set_trace()
- return self.get_state('/Unity/SwitcherController/SwitcherModel')[0]['children-of-men'][index][1][0]
+ return self.__get_model()['Children'][index][1][0]
+
+ @property
+ def current_icon(self):
+ """Get the currently-selected icon."""
+ if not self.get_is_visible:
+ return None
+ model = self.__get_model()
+ sel_idx = self.get_selection_index()
+ try:
+ return LauncherIcon(model['Children'][sel_idx][1])
+ except KeyError:
+ return None
def get_icon_name(self, index):
return self.__get_icon(index)['tooltip-text']
@@ -257,56 +274,93 @@ class Switcher(Unity):
return None
def get_model_size(self):
- return len(self.get_state('/Unity/SwitcherController/SwitcherModel')[0]['children-of-men'])
+ return len(self.__get_model()['Children'])
def get_selection_index(self):
- return int(self.get_state('/Unity/SwitcherController/SwitcherModel')[0]['selection-index'])
+ return int(self.__get_model()['selection-index'])
def get_last_selection_index(self):
- return bool(self.get_state('/Unity/SwitcherController/SwitcherModel')[0]['last-selection-index'])
+ return bool(self.__get_model()['last-selection-index'])
def get_is_visible(self):
- return bool(self.get_state('/Unity/SwitcherController')[0]['visible'])
+ return bool(self.__get_controller()['visible'])
+
+ def __get_model(self):
+ return self.get_state('/Unity/SwitcherController/SwitcherModel')[0]
+
+ def __get_controller(self):
+ return self.set_state('/unity/SwitcherController')[0]
class Dash(Unity):
- """
- An emulator class that makes it easier to interact with the unity dash.
- """
-
- def __init__(self):
- self.plugin = Plugin(global_context, "unityshell")
- self.setting = Setting(self.plugin, "show_launcher")
- super(Dash, self).__init__()
-
- def toggle_reveal(self):
- """
- Reveals the dash if it's currently hidden, hides it otherwise.
- """
- self._keyboard.press_and_release("^W")
- sleep(1)
-
- def ensure_visible(self):
- """
- Ensures the dash is visible.
- """
- if not self.get_is_visible():
- self.toggle_reveal();
-
- def ensure_hidden(self):
- """
- Ensures the dash is hidden.
- """
- if self.get_is_visible():
- self.toggle_reveal();
-
- def get_is_visible(self):
- """
- Is the dash visible?
- """
+ """
+ An emulator class that makes it easier to interact with the unity dash.
+ """
+
+ def __init__(self):
+ self.plugin = Plugin(global_context, "unityshell")
+ self.setting = Setting(self.plugin, "show_launcher")
+ super(Dash, self).__init__()
+
+ def toggle_reveal(self):
+ """
+ Reveals the dash if it's currently hidden, hides it otherwise.
+ """
+ self._keyboard.press_and_release("Super")
+ sleep(1)
+
+ def ensure_visible(self):
+ """
+ Ensures the dash is visible.
+ """
+ if not self.get_is_visible():
+ self.toggle_reveal();
+
+ def ensure_hidden(self):
+ """
+ Ensures the dash is hidden.
+ """
+ if self.get_is_visible():
+ self.toggle_reveal();
+
+ def get_is_visible(self):
+ """
+ Is the dash visible?
+ """
return bool(self.get_state("/Unity/DashController")[0]["visible"])
- def get_search_string(self):
- """
- Return the current dash search bar search string.
- """
+ def get_search_string(self):
+ """
+ Return the current dash search bar search string.
+ """
return unicode(self.get_state("//SearchBar")[0]['search_string'])
+
+ def get_current_lens(self):
+ """Returns the id of the current lens.
+
+ For example, the default lens is 'home.lens', the run-command lens is
+ 'commands.lens'.
+
+ """
+ return unicode(self.get_state("//DashController/DashView/LensBar")[0]['active-lens'])
+
+ def reveal_application_lens(self):
+ """Reveal the application lense."""
+ self._keyboard.press('Super')
+ self._keyboard.press_and_release("a")
+ self._keyboard.release('Super')
+
+ def reveal_music_lens(self):
+ """Reveal the music lense."""
+ self._keyboard.press('Super')
+ self._keyboard.press_and_release("m")
+ self._keyboard.release('Super')
+
+ def reveal_file_lens(self):
+ """Reveal the file lense."""
+ self._keyboard.press('Super')
+ self._keyboard.press_and_release("f")
+ self._keyboard.release('Super')
+
+ def reveal_command_lens(self):
+ """Reveal the 'run command' lens."""
+ self._keyboard.press_and_release('Alt+F2')
diff --git a/tests/autopilot/autopilot/tests/__init__.py b/tests/autopilot/autopilot/tests/__init__.py
index f08df6284..17904e51f 100644
--- a/tests/autopilot/autopilot/tests/__init__.py
+++ b/tests/autopilot/autopilot/tests/__init__.py
@@ -1,3 +1,14 @@
"""
Autopilot tests for Unity.
-""" \ No newline at end of file
+"""
+
+from testtools import TestCase
+from autopilot.emulators.X11 import Keyboard, Mouse
+
+class AutopilotTestCase(TestCase):
+ """Wrapper around testtools.TestCase that takes care of some cleaning."""
+
+ def tearDown(self):
+ Keyboard.cleanup()
+ Mouse.cleanup()
+ super(AutopilotTestCase, self).tearDown()
diff --git a/tests/autopilot/autopilot/tests/test_dash.py b/tests/autopilot/autopilot/tests/test_dash.py
index ceb20252a..e9f6b4024 100644
--- a/tests/autopilot/autopilot/tests/test_dash.py
+++ b/tests/autopilot/autopilot/tests/test_dash.py
@@ -1,25 +1,33 @@
-from testtools import TestCase
+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
+# Copyright 2010 Canonical
+# Author: Alex Launi
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 3, as published
+# by the Free Software Foundation.
+
from time import sleep
from autopilot.emulators.unity import Dash
from autopilot.emulators.X11 import Keyboard
+from autopilot.tests import AutopilotTestCase
from autopilot.glibrunner import GlibRunner
-class DashTests(TestCase):
- """
- Test the unity Dash.
- """
+class DashTests(AutopilotTestCase):
+ """Test the unity Dash."""
run_test_with = GlibRunner
-
+
def setUp(self):
super(DashTests, self).setUp()
self.dash = Dash()
+ def tearDown(self):
+ super(DashTests, self).tearDown()
+ self.dash.ensure_hidden()
+
def test_dash_reveal(self):
- """
- Ensure we can show and hide the dash.
- """
+ """Ensure we can show and hide the dash."""
self.dash.ensure_hidden()
self.assertFalse(self.dash.get_is_visible())
@@ -29,9 +37,7 @@ class DashTests(TestCase):
self.assertFalse(self.dash.get_is_visible())
def test_dash_keyboard_focus(self):
- """
- Dash must put keyboard focus on the search bar at all times.
- """
+ """Dash must put keyboard focus on the search bar at all times."""
self.dash.ensure_hidden()
self.assertFalse(self.dash.get_is_visible())
@@ -43,5 +49,30 @@ class DashTests(TestCase):
self.dash.toggle_reveal()
self.assertFalse(self.dash.get_is_visible())
+ def test_application_lens_shortcut(self):
+ """Application lense must reveal when Super+a is pressed."""
+ self.dash.ensure_hidden()
+ self.dash.reveal_application_lens()
+ self.assertEqual(self.dash.get_current_lens(), u'applications.lens')
+
+ def test_music_lens_shortcut(self):
+ """Music lense must reveal when Super+w is pressed."""
+ self.dash.ensure_hidden()
+ self.dash.reveal_music_lens()
+ self.assertEqual(self.dash.get_current_lens(), u'music.lens')
+
+ def test_file_lens_shortcut(self):
+ """File lense must reveal when Super+f is pressed."""
+ self.dash.ensure_hidden()
+ self.dash.reveal_file_lens()
+ self.assertEqual(self.dash.get_current_lens(), u'files.lens')
+
+ def test_command_lens_shortcut(self):
+ """Run Command lens must reveat on alt+F2."""
+ self.dash.ensure_hidden()
+ self.dash.reveal_command_lens()
+ self.assertEqual(self.dash.get_current_lens(), u'commands.lens')
+
+
+
-
diff --git a/tests/autopilot/autopilot/tests/test_launcher.py b/tests/autopilot/autopilot/tests/test_launcher.py
index c53831448..b3e532c1a 100644
--- a/tests/autopilot/autopilot/tests/test_launcher.py
+++ b/tests/autopilot/autopilot/tests/test_launcher.py
@@ -1,13 +1,15 @@
-from testtools import TestCase
from testtools.matchers import Equals
from testtools.matchers import LessThan
+from autopilot.tests import AutopilotTestCase
from autopilot.emulators.unity import Launcher
from autopilot.glibrunner import GlibRunner
from time import sleep
-class LauncherTests(TestCase):
+
+class LauncherTests(AutopilotTestCase):
+ """Test the launcher."""
run_test_with = GlibRunner
def setUp(self):
@@ -90,6 +92,9 @@ class LauncherTests(TestCase):
def test_reveal_on_mouse_to_edge(self):
"""Tests reveal of launchers by mouse pressure."""
+ # XXX: re-enable test when launcher reeal behavior is no longer resolution-dependant.
+ self.skipTest("Launcher reveal behavior is resolution dependant.")
+
num_launchers = self.server.num_launchers()
for x in range(num_launchers):
@@ -98,8 +103,11 @@ class LauncherTests(TestCase):
self.assertThat(self.server.is_showing(x), Equals(True))
def test_reveal_with_mouse_under_launcher(self):
- """Tests that the launcher hides properly if the
+ """Tests that the launcher hides properly if the
mouse is under the launcher when it is revealed."""
+ # XXX: re-enable test when launcher reeal behavior is no longer resolution-dependant.
+ self.skipTest("Launcher reveal behavior is resolution dependant.")
+
num_launchers = self.server.num_launchers()
for x in range(num_launchers):
@@ -107,9 +115,12 @@ class LauncherTests(TestCase):
self.server.keyboard_reveal_launcher()
self.server.keyboard_unreveal_launcher()
self.assertThat(self.server.is_showing(x), Equals(False))
-
+
def test_reveal_does_not_hide_again(self):
"""Tests reveal of launchers by mouse pressure to ensure it doesn't automatically hide again."""
+ # XXX: re-enable test when launcher reeal behavior is no longer resolution-dependant.
+ self.skipTest("Launcher reveal behavior is resolution dependant.")
+
num_launchers = self.server.num_launchers()
for x in range(num_launchers):
@@ -117,5 +128,5 @@ class LauncherTests(TestCase):
self.server.reveal_launcher(x)
sleep(2)
self.assertThat(self.server.is_showing(x), Equals(True))
-
+
diff --git a/tests/autopilot/autopilot/tests/test_showdesktop.py b/tests/autopilot/autopilot/tests/test_showdesktop.py
new file mode 100644
index 000000000..dedac49b9
--- /dev/null
+++ b/tests/autopilot/autopilot/tests/test_showdesktop.py
@@ -0,0 +1,138 @@
+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
+# Copyright 2010 Canonical
+# Author: Thomi Richards
+#
+# 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 time import sleep
+from subprocess import call
+
+from autopilot.emulators.bamf import Bamf
+from autopilot.emulators.X11 import Keyboard
+from autopilot.emulators.unity import Launcher, Switcher
+from autopilot.tests import AutopilotTestCase
+from autopilot.glibrunner import GlibRunner
+
+
+class ShowDesktopTests(AutopilotTestCase):
+ """Test the 'Show Desktop' functionality."""
+ run_test_with = GlibRunner
+
+ def setUp(self):
+ super(ShowDesktopTests, self).setUp()
+ self.addCleanup(Keyboard.cleanup)
+ self.bamf = Bamf()
+
+ def launch_test_apps(self):
+ """Launch character map and calculator apps."""
+ self.bamf.launch_application("gucharmap.desktop")
+ self.addCleanup(call, ["killall", "gucharmap"])
+ self.bamf.launch_application("gcalctool.desktop")
+ self.addCleanup(call, ["killall", "gcalctool"])
+
+ def test_showdesktop_hides_apps(self):
+ """Show Desktop keyboard shortcut must hide applications."""
+ self.launch_test_apps()
+
+ # show desktop, verify all windows are hidden:
+ kb = Keyboard()
+ kb.press_and_release('Control+Alt+d')
+ self.addCleanup(kb.press_and_release, keys='Control+Alt+d')
+ sleep(1)
+ open_wins = self.bamf.get_open_windows()
+ self.assertGreaterEqual(len(open_wins), 2)
+ for win in open_wins:
+ self.assertTrue(win.is_valid)
+ self.assertTrue(win.is_hidden, "Window '%s' is not hidden after show desktop activated." % (win.title))
+
+ def test_showdesktop_unhides_apps(self):
+ """Show desktop shortcut must re-show all hidden apps."""
+ self.launch_test_apps()
+
+ # show desktop, verify all windows are hidden:
+ kb = Keyboard()
+ kb.press_and_release('Control+Alt+d')
+ sleep(1)
+ open_wins = self.bamf.get_open_windows()
+ self.assertGreaterEqual(len(open_wins), 2)
+ for win in open_wins:
+ self.assertTrue(win.is_valid)
+ self.assertTrue(win.is_hidden, "Window '%s' is not hidden after show desktop activated." % (win.title))
+
+ # un-show desktop, verify all windows are shown:
+ kb.press_and_release('Control+Alt+d')
+ sleep(1)
+ for win in self.bamf.get_open_windows():
+ self.assertTrue(win.is_valid)
+ self.assertFalse(win.is_hidden, "Window '%s' is shown after show desktop deactivated." % (win.title))
+
+ def test_unhide_single_app(self):
+ """Un-hide a single app from launcher after hiding all apps."""
+ self.launch_test_apps()
+
+ # show desktop, verify all windows are hidden:
+ kb = Keyboard()
+ kb.press_and_release('Control+Alt+d')
+ sleep(1)
+ open_wins = self.bamf.get_open_windows()
+ self.assertGreaterEqual(len(open_wins), 2)
+ for win in open_wins:
+ self.assertTrue(win.is_valid)
+ self.assertTrue(win.is_hidden, "Window '%s' is not hidden after show desktop activated." % (win.title))
+
+ # We'll un-minimise the character map - find it's launcherIcon in the launcher:
+ l = Launcher()
+
+ launcher_icons = l.get_launcher_icons()
+ found = False
+ for icon in launcher_icons:
+ if icon.tooltip_text == 'Character Map':
+ found = True
+ l.click_launcher_icon(icon)
+ self.assertTrue(found, "Could not find launcher icon in launcher.")
+
+ sleep(1)
+ for win in self.bamf.get_open_windows():
+ if win.is_valid:
+ if win.title == 'Character Map':
+ self.assertFalse(win.is_hidden, "Character map did not un-hide from launcher.")
+ else:
+ self.assertTrue(win.is_hidden, "Window '%s' should still be hidden." % (win.title))
+
+ # hide desktop - now all windows should be visible:
+ kb.press_and_release('Control+Alt+d')
+ sleep(1)
+ for win in self.bamf.get_open_windows():
+ if win.is_valid:
+ self.assertFalse(win.is_hidden, "Window '%s' is not shown after show desktop deactivated." % (win.title))
+
+ def test_showdesktop_switcher(self):
+ """Show desktop item in switcher should hide all hidden apps."""
+ self.launch_test_apps()
+
+ # show desktop, verify all windows are hidden:
+ switcher = Switcher()
+ switcher.initiate()
+ sleep(0.5)
+ found = False
+ for i in range(switcher.get_model_size()):
+ current_icon = switcher.current_icon
+ self.assertIsNotNone(current_icon)
+ if current_icon.tooltip_text == 'Show Desktop':
+ found = True
+ break
+ switcher.previous_icon()
+ sleep(0.5)
+ self.assertTrue(found, "Could not find 'Show Desktop' entry in switcher.")
+ switcher.terminate()
+ kb = Keyboard()
+ self.addCleanup(kb.press_and_release, keys='Control+Alt+d')
+
+ sleep(1)
+ open_wins = self.bamf.get_open_windows()
+ self.assertGreaterEqual(len(open_wins), 2)
+ for win in open_wins:
+ self.assertTrue(win.is_valid)
+ self.assertTrue(win.is_hidden, "Window '%s' is not hidden after show desktop activated." % (win.title))
diff --git a/tests/autopilot/autopilot/tests/test_switcher.py b/tests/autopilot/autopilot/tests/test_switcher.py
index f78f9d2c6..a4917bc99 100644
--- a/tests/autopilot/autopilot/tests/test_switcher.py
+++ b/tests/autopilot/autopilot/tests/test_switcher.py
@@ -1,8 +1,14 @@
-import gio
+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
+# Copyright 2010 Canonical
+# Author: Thomi Richards
+#
+# 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 subprocess import call
from time import sleep
-from testtools import TestCase
from testtools.matchers import Equals
from testtools.matchers import NotEquals
@@ -11,32 +17,30 @@ from compizconfig import Plugin
from autopilot.globals import global_context
from autopilot.emulators.unity import Switcher
+from autopilot.emulators.bamf import Bamf
+from autopilot.tests import AutopilotTestCase
from autopilot.glibrunner import GlibRunner
-
-class SwitcherTests(TestCase):
+class SwitcherTests(AutopilotTestCase):
+ """Test the switcher."""
run_test_with = GlibRunner
- def launch_application(self, desktop_file):
- proc = gio.unix.DesktopAppInfo(desktop_file)
- proc.launch()
-
def set_timeout_setting(self, value):
self.setting.Value = value
global_context.Write()
-
+
def setUp(self):
self.plugin = Plugin(global_context, "unityshell")
self.setting = Setting(self.plugin, "alt_tab_timeout")
+ self.bamf = Bamf()
+
+ self.bamf.launch_application("gucharmap.desktop")
+ self.bamf.launch_application("gcalctool.desktop")
+ self.bamf.launch_application("mahjongg.desktop")
- self.launch_application("gucharmap.desktop")
- self.launch_application("gcalctool.desktop")
- self.launch_application("mahjongg.desktop")
-
- sleep(5)
super(SwitcherTests, self).setUp()
-
+
self.server = Switcher()
def tearDown(self):
@@ -52,32 +56,32 @@ class SwitcherTests(TestCase):
self.server.initiate()
sleep(.2)
-
+
start = self.server.get_selection_index()
self.server.next_icon()
sleep(.2)
-
+
end = self.server.get_selection_index()
self.server.terminate()
-
+
self.assertThat(start, NotEquals(0))
self.assertThat(end, Equals(start+1))
self.set_timeout_setting(True)
-
+
def test_switcher_move_prev(self):
self.set_timeout_setting(False)
sleep(1)
self.server.initiate()
sleep(.2)
-
+
start = self.server.get_selection_index()
self.server.previous_icon()
sleep(.2)
-
+
end = self.server.get_selection_index()
self.server.terminate()
-
+
self.assertThat(start, NotEquals(0))
self.assertThat(end, Equals(start-1))
self.set_timeout_setting(True)
diff --git a/tests/test_hud.cpp b/tests/test_hud.cpp
new file mode 100644
index 000000000..36f2c876b
--- /dev/null
+++ b/tests/test_hud.cpp
@@ -0,0 +1,104 @@
+#include <gtest/gtest.h>
+#include <glib-object.h>
+#include <UnityCore/GLibWrapper.h>
+#include <UnityCore/Hud.h>
+
+using namespace std;
+
+namespace
+{
+
+GMainLoop* loop_ = NULL;
+unity::hud::Hud *hud;
+
+class TestHud : public ::testing::Test
+{
+public:
+ TestHud()
+ : query_return_result(false)
+ , connected_result(false)
+ {
+ }
+ unity::hud::Hud::Queries queries;
+ bool query_return_result;
+ bool connected_result;
+};
+
+TEST_F(TestHud, TestConstruction)
+{
+ loop_ = g_main_loop_new(NULL, FALSE);
+ hud = new unity::hud::Hud("com.canonical.Unity.Test", "/com/canonical/hud");
+
+ // performs a check on the hud, if the hud is connected, report a sucess
+ auto timeout_check = [] (gpointer data) -> gboolean
+ {
+ TestHud* self = static_cast<TestHud*>(data);
+ if (hud->connected)
+ {
+ self->connected_result = true;
+ g_main_loop_quit(loop_);
+ return FALSE;
+ }
+ else
+ {
+ self->connected_result = false;
+ return TRUE;
+ }
+ };
+
+
+ // if the hud is not connected when this lambda runs, fail.
+ auto timeout_bailout = [] (gpointer data) -> gboolean
+ {
+ TestHud* self = static_cast<TestHud*>(data);
+ // reached timeout, failed testing
+ self->connected_result = false;
+ g_main_loop_quit(loop_);
+ return FALSE;
+ };
+
+ g_timeout_add_seconds(1, timeout_check, this);
+ g_timeout_add_seconds(10, timeout_bailout, this);
+
+ g_main_loop_run(loop_);
+
+ EXPECT_EQ(connected_result, true);
+}
+
+TEST_F(TestHud, TestQueryReturn)
+{
+ query_return_result = false;
+
+ // make sure we receive the queries
+ auto query_connection = [this](unity::hud::Hud::Queries queries_)
+ {
+ query_return_result = true;
+ g_main_loop_quit(loop_);
+ queries = queries_;
+ };
+
+ auto timeout_bailout = [] (gpointer data) -> gboolean
+ {
+ TestHud* self = static_cast<TestHud*>(data);
+ self->query_return_result = false;
+ g_main_loop_quit(loop_);
+ return FALSE;
+ };
+
+ hud->queries_updated.connect(query_connection);
+
+ guint source_id = g_timeout_add_seconds(10, timeout_bailout, this);
+
+ // next check we get 30 entries from this specific known callback
+ hud->RequestQuery("Request30Queries");
+ g_main_loop_run(loop_);
+ EXPECT_EQ(query_return_result, true);
+ EXPECT_NE(queries.size(), 0);
+ g_source_remove(source_id);
+
+ // finally close the connection - Nothing to check for here
+ hud->CloseQuery();
+}
+
+
+}
diff --git a/tests/test_service_hud.c b/tests/test_service_hud.c
new file mode 100644
index 000000000..bfdf47ce1
--- /dev/null
+++ b/tests/test_service_hud.c
@@ -0,0 +1,268 @@
+#include "test_service_hud.h"
+#include <unity.h>
+#include <gio/gio.h>
+
+const char * hud_interface =
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+"<node name=\"/\">\n"
+" <interface name=\"com.canonical.hud\">\n"
+"<!-- Properties -->\n"
+" <!-- None -->\n"
+"\n"
+"<!-- Functions -->\n"
+" <method name=\"StartQuery\">\n"
+" <!-- in -->\n"
+" <arg type=\"s\" name=\"query\" direction=\"in\" />\n"
+" <arg type=\"i\" name=\"entries\" direction=\"in\" />\n"
+" <!-- out -->\n"
+" <arg type=\"s\" name=\"target\" direction=\"out\" />\n"
+" <arg type=\"a(sssssv)\" name=\"suggestions\" direction=\"out\" />\n"
+" <arg type=\"v\" name=\"querykey\" direction=\"out\" />\n"
+" </method>\n"
+"\n"
+" <method name=\"ExecuteQuery\">\n"
+" <arg type=\"v\" name=\"key\" direction=\"in\" />\n"
+" <arg type=\"u\" name=\"timestamp\" direction=\"in\" />\n"
+" </method>\n"
+"\n"
+" <method name=\"CloseQuery\">\n"
+" <arg type=\"v\" name=\"querykey\" direction=\"in\" />\n"
+" </method>\n"
+"\n"
+"<!-- Signals -->\n"
+" <signal name=\"UpdatedQuery\">\n"
+" <arg type=\"s\" name=\"target\" direction=\"out\" />\n"
+" <arg type=\"a(sssssv)\" name=\"suggestions\" direction=\"out\" />\n"
+" <arg type=\"v\" name=\"querykey\" 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(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;
+};
+
+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;
+ }
+
+}
+
+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;
+ }
+
+ 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, "StartQuery") == 0)
+ {
+ GVariant * ret = NULL;
+ gchar * query = NULL;
+ int num_entries = 0;
+
+ g_variant_get(parameters, "(si)", &query, &num_entries);
+
+ /* Build into into a variant */
+ GVariantBuilder ret_builder;
+ 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++)
+ {
+ gchar* target = g_strdup_printf("test-%i", i);
+ gchar* icon = g_strdup_printf("icon-%i", i);
+ gchar* future_icon = g_strdup(icon);
+ gchar* completion_text = g_strdup_printf("completion-%i", i);
+ gchar* accelerator = g_strdup_printf("<alt>+whatever");
+
+ GVariantBuilder tuple;
+ g_variant_builder_init(&tuple, G_VARIANT_TYPE_TUPLE);
+ g_variant_builder_add_value(&tuple, g_variant_new_string(target));
+ g_variant_builder_add_value(&tuple, g_variant_new_string(icon));
+ g_variant_builder_add_value(&tuple, g_variant_new_string(future_icon));
+ g_variant_builder_add_value(&tuple, g_variant_new_string(completion_text));
+ g_variant_builder_add_value(&tuple, g_variant_new_string(accelerator));
+ // build a fake key
+ GVariant* key;
+ {
+ GVariantBuilder keybuilder;
+ g_variant_builder_init(&keybuilder, G_VARIANT_TYPE_TUPLE);
+ g_variant_builder_add_value(&keybuilder, g_variant_new_string("dummy string"));
+ g_variant_builder_add_value(&keybuilder, g_variant_new_string("dummy string"));
+ g_variant_builder_add_value(&keybuilder, g_variant_new_string("dummy string"));
+ g_variant_builder_add_value(&keybuilder, g_variant_new_int32(1986));
+
+ key = g_variant_new_variant(g_variant_builder_end(&keybuilder));
+ }
+ g_variant_ref_sink(key);
+ g_variant_builder_add_value(&tuple, key);
+ g_variant_builder_add_value(&builder, g_variant_builder_end(&tuple));
+ g_free(target);
+ g_free(icon);
+ g_free(future_icon);
+ g_free(completion_text);
+ }
+ g_variant_builder_add_value(&ret_builder, g_variant_builder_end(&builder));
+
+ GVariant* query_key;
+ {
+ GVariantBuilder keybuilder;
+ g_variant_builder_init(&keybuilder, G_VARIANT_TYPE_TUPLE);
+ g_variant_builder_add_value(&keybuilder, g_variant_new_string("dummy string"));
+ g_variant_builder_add_value(&keybuilder, g_variant_new_string("dummy string"));
+ g_variant_builder_add_value(&keybuilder, g_variant_new_string("dummy string"));
+ g_variant_builder_add_value(&keybuilder, g_variant_new_int32(1986));
+
+ query_key = g_variant_new_variant(g_variant_builder_end(&keybuilder));
+ }
+ 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)
+ {
+ 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)
+ {
+ GVariant * key = NULL;
+ key = g_variant_get_child_value(parameters, 0);
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ g_variant_unref(key);
+ }
+
+ return;
+}
+
diff --git a/tests/test_service_hud.h b/tests/test_service_hud.h
new file mode 100644
index 000000000..df069962a
--- /dev/null
+++ b/tests/test_service_hud.h
@@ -0,0 +1,46 @@
+#ifndef _SERVICE_HUD_H_
+#define _SERVICE_HUD_H_
+
+#include <glib-object.h>
+G_BEGIN_DECLS
+
+#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;
+
+struct _ServiceHud
+{
+ GObject parent;
+
+ ServiceHudPrivate *priv;
+};
+
+struct _ServiceHudClass
+{
+ GObjectClass parent_class;
+};
+
+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_main.c b/tests/test_service_main.c
index 7e2bdc15c..e03bef41c 100644
--- a/tests/test_service_main.c
+++ b/tests/test_service_main.c
@@ -2,6 +2,7 @@
#include "test_service_lens.h"
#include "test_service_model.h"
+#include "test_service_hud.h"
static void on_bus_aquired(GDBusConnection* conn, const gchar* name, gpointer null);
static void handle_method_call(GDBusConnection *connection,
@@ -34,6 +35,7 @@ static const GDBusInterfaceVTable interface_vtable =
static GMainLoop* loop_ = NULL;
static ServiceLens* lens_ = NULL;
static ServiceModel* model_ = NULL;
+static ServiceHud* hud_ = NULL;
gint
main(gint argc, gchar** argv)
@@ -44,6 +46,7 @@ main(gint argc, gchar** argv)
lens_ = service_lens_new();
model_ = service_model_new();
+ hud_ = service_hud_new();
g_bus_own_name(G_BUS_TYPE_SESSION,
"com.canonical.Unity.Test",
@@ -57,8 +60,9 @@ main(gint argc, gchar** argv)
g_main_loop_run(loop_);
g_main_loop_unref(loop_);
- g_object_unref(lens_);
- g_object_unref(model_);
+ //g_object_unref(lens_);
+ //g_object_unref(model_);
+ g_object_unref(hud_);
g_dbus_node_info_unref(introspection_data);
return 0;
diff --git a/tests/unit/TestQuicklistMenuitems.cpp b/tests/unit/TestQuicklistMenuitems.cpp
index 823715f8e..716e0dc03 100644
--- a/tests/unit/TestQuicklistMenuitems.cpp
+++ b/tests/unit/TestQuicklistMenuitems.cpp
@@ -241,6 +241,7 @@ TestQuicklistMenuItem()
g_assert_cmpstr(quicklist->GetNthItems(2)->GetLabel(), == , "label 1");
g_assert_cmpstr(quicklist->GetNthItems(3)->GetLabel(), == , "check mark 0");
+ g_assert_cmpint(quicklist->GetChildren().size(), == , 4);
quicklist->Dispose();
}
diff --git a/tools/unity-introspection-visualiser.py b/tools/unity-introspection-visualiser.py
index fae236e2c..bdefe0b51 100755
--- a/tools/unity-introspection-visualiser.py
+++ b/tools/unity-introspection-visualiser.py
@@ -2,7 +2,9 @@
#
# Script to generate a nice PNG file of the currently running unity introspection tree.
-from sys import argv
+from argparse import ArgumentParser
+from os import remove
+from os.path import splitext
import dbus
try:
@@ -21,6 +23,7 @@ except ImportError:
NEXT_NODE_ID=1
+
def string_rep(dbus_type):
"""Get a string representation of various dbus types."""
if type(dbus_type) == dbus.Boolean:
@@ -60,16 +63,17 @@ def traverse_tree(state, parent, graph):
graph.add_edge(pydot.Edge(parent, child))
traverse_tree(child_state, child, graph)
-
+
if __name__ == '__main__':
- if len(argv) != 2:
- print """Usage: %s output_file.png.
+ parser = ArgumentParser()
+ mg = parser.add_mutually_exclusive_group(required=True)
+ mg.add_argument('-o', '--output', nargs=1,
+ help='Store output in specified file on disk.')
+ mg.add_argument('-d','--display', action='store_true',
+ help='Display output in image viewer.')
-This script queries the currently running Unity process and dumps the entire
-introspection tree into a graph, and renders this to a PNG file.
-""" % (argv[0])
- exit(1)
+ args = parser.parse_args()
u = Unity()
introspection_tree = u.get_state()
@@ -78,10 +82,27 @@ introspection tree into a graph, and renders this to a PNG file.
graph.set_node_defaults(shape='Mrecord')
graph.set_fontname('Ubuntu')
graph.set_fontsize('10')
-
+
gnode_unity = pydot.Node("Unity")
gnode_unity.set_comment("Unity")
traverse_tree(introspection_tree[0], gnode_unity, graph)
- graph.write(argv[1], format='png')
+ if args.output:
+ base, extension = splitext(args.output[0])
+ write_method_name = 'write_' + extension[1:]
+ if hasattr(graph, write_method_name):
+ getattr(graph, write_method_name)(args.output[0])
+ else:
+ print "Error: unsupported format: '%s'" % (extension)
+ elif args.display:
+ from tempfile import NamedTemporaryFile
+ from subprocess import call
+ tf = NamedTemporaryFile(suffix='.png', delete=False)
+ tf.write(graph.create_png())
+ tf.close()
+ call(["eog", tf.name])
+ remove(tf.name)
+ else:
+ print 'unknown output mode!'
+