diff options
103 files changed, 2131 insertions, 2397 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index e86aae33a..bc034a517 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,7 +127,9 @@ endif (DISABLE_MAINTAINER_CFLAGS) # # Compiz Plugins # -set (UNITY_PLUGIN_DEPS "compiz;nux-2.0>=2.0.0;libbamf3;dee-1.0;gio-2.0;gio-unix-2.0;dbusmenu-glib-0.4;x11;libstartup-notification-1.0;gthread-2.0;indicator3-0.4>=0.4.90;atk;unity-misc>=0.4.0;gconf-2.0;libutouch-geis;gtk+-3.0>=3.1;sigc++-2.0;json-glib-1.0;libnotify;gnome-desktop-3.0;xfixes") + +set (UNITY_PLUGIN_DEPS "compiz;nux-3.0>=3.0.0;libbamf3;dee-1.0;gio-2.0;gio-unix-2.0;dbusmenu-glib-0.4;x11;libstartup-notification-1.0;gthread-2.0;indicator3-0.4>=0.4.90;atk;unity-misc>=0.4.0;gconf-2.0;libutouch-geis;gtk+-3.0>=3.1;sigc++-2.0;json-glib-1.0;libnotify;xfixes") + find_package (PkgConfig) pkg_check_modules (CACHED_UNITY_DEPS REQUIRED ${UNITY_PLUGIN_DEPS}) add_subdirectory(unity-shared) diff --git a/UnityCore/CMakeLists.txt b/UnityCore/CMakeLists.txt index aa6a573a0..962c5475c 100644 --- a/UnityCore/CMakeLists.txt +++ b/UnityCore/CMakeLists.txt @@ -1,5 +1,5 @@ find_package (PkgConfig) -pkg_check_modules (CORE_DEPS REQUIRED glib-2.0 gio-2.0 dee-1.0 sigc++-2.0 nux-core-2.0 gdk-pixbuf-2.0 unity) +pkg_check_modules (CORE_DEPS REQUIRED glib-2.0 gio-2.0 dee-1.0 sigc++-2.0 nux-core-3.0 gdk-pixbuf-2.0 unity) execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} unity --variable lensesdir OUTPUT_VARIABLE _lensesdir OUTPUT_STRIP_TRAILING_WHITESPACE) diff --git a/UnityCore/GLibSignal-inl.h b/UnityCore/GLibSignal-inl.h index 2a8f1baad..0f3e7a9b5 100644 --- a/UnityCore/GLibSignal-inl.h +++ b/UnityCore/GLibSignal-inl.h @@ -1,6 +1,6 @@ // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* -* Copyright (C) 2011 Canonical Ltd +* Copyright (C) 2011-2012 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -15,6 +15,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Authored by: Neil Jagdish patel <neil.patel@canonical.com> +* Marco Trevisan <marco.trevisan@canonical.com> */ #ifndef UNITY_GLIB_SIGNAL_INL_H @@ -25,274 +26,27 @@ namespace unity namespace glib { -template <typename R, typename G> -Signal0<R, G>::Signal0() -{} - -template <typename R, typename G> -void Signal0<R, G>::Connect(G object, - std::string const& signal_name, - SignalCallback callback) -{ - object_ = reinterpret_cast<GObject*>(object); - name_ = signal_name; - callback_ = callback; - connection_id_ = g_signal_connect(object, signal_name.c_str(), - G_CALLBACK(Callback), this); -} - -template <typename R, typename G> -R Signal0<R, G>::Callback(G object, Signal0* self) -{ - return self->callback_(object); -} - -template <typename R, typename G, typename T> -Signal1<R, G, T>::Signal1() -{} - -template <typename R, typename G, typename T> -void Signal1<R, G, T>::Connect(G object, - std::string const& signal_name, - SignalCallback callback) -{ - object_ = reinterpret_cast<GObject*>(object); - name_ = signal_name; - callback_ = callback; - connection_id_ = g_signal_connect(object, signal_name.c_str(), - G_CALLBACK(Callback), this); -} - -template <typename R, typename G, typename T> -R Signal1<R, G, T>::Callback(G object, T data1, Signal1* self) -{ - return self->callback_(object, data1); -} - -template <typename R, typename G, typename T1, typename T2> -Signal2<R, G, T1, T2>::Signal2() -{} - -template <typename R, typename G, typename T1, typename T2> -void Signal2<R, G, T1, T2>::Connect(G object, - std::string const& signal_name, - SignalCallback callback) -{ - object_ = reinterpret_cast<GObject*>(object); - name_ = signal_name; - callback_ = callback; - connection_id_ = g_signal_connect(object, signal_name.c_str(), - G_CALLBACK(Callback), this); -} - -template <typename R, typename G, typename T1, typename T2> -R Signal2<R, G, T1, T2>::Callback(G object, - T1 data1, - T2 data2, - Signal2* self) -{ - return self->callback_(object, data1, data2); -} - -template <typename R, typename G, typename T1, typename T2, typename T3> -Signal3<R, G, T1, T2, T3>::Signal3() -{} - -template <typename R, typename G, typename T1, typename T2, typename T3> -void Signal3<R, G, T1, T2, T3>::Connect(G object, - std::string const& signal_name, - SignalCallback callback) -{ - object_ = reinterpret_cast<GObject*>(object); - name_ = signal_name; - callback_ = callback; - connection_id_ = g_signal_connect(object, signal_name.c_str(), - G_CALLBACK(Callback), this); -} - -template <typename R, typename G, typename T1, typename T2, typename T3> -R Signal3<R, G, T1, T2, T3>::Callback(G object, - T1 data1, - T2 data2, - T3 data3, - Signal3* self) +template <typename R, typename G, typename... Ts> +Signal<R, G, Ts...>::Signal(G object, std::string const& signal_name, + SignalCallback const& callback) { - return self->callback_(object, data1, data2, data3); + Connect(object, signal_name, callback); } -template <typename R, typename G, typename T1, typename T2, typename T3, typename T4> -Signal4<R, G, T1, T2, T3, T4>::Signal4() -{} - -template <typename R, typename G, typename T1, typename T2, typename T3, typename T4> -void Signal4<R, G, T1, T2, T3, T4>::Connect(G object, - std::string const& signal_name, - SignalCallback callback) +template <typename R, typename G, typename... Ts> +void Signal<R, G, Ts...>::Connect(G object, std::string const& signal_name, + SignalCallback const& callback) { object_ = reinterpret_cast<GObject*>(object); name_ = signal_name; callback_ = callback; - connection_id_ = g_signal_connect(object, signal_name.c_str(), - G_CALLBACK(Callback), this); + connection_id_ = g_signal_connect(object, signal_name.c_str(), G_CALLBACK(Callback), this); } -template <typename R, typename G, typename T1, typename T2, typename T3, typename T4> -R Signal4<R, G, T1, T2, T3, T4>::Callback(G object, - T1 data1, - T2 data2, - T3 data3, - T4 data4, - Signal4* self) -{ - return self->callback_(object, data1, data2, data3, data4); -} - - -template < typename R, typename G, typename T1, typename T2, - typename T3, typename T4, typename T5 > -Signal5<R, G, T1, T2, T3, T4, T5>::Signal5() -{} - -template < typename R, typename G, typename T1, typename T2, - typename T3, typename T4, typename T5 > -void Signal5<R, G, T1, T2, T3, T4, T5>::Connect(G object, - std::string const& signal_name, - SignalCallback callback) -{ - object_ = reinterpret_cast<GObject*>(object); - name_ = signal_name; - callback_ = callback; - connection_id_ = g_signal_connect(object, signal_name.c_str(), - G_CALLBACK(Callback), this); -} - -template < typename R, typename G, typename T1, typename T2, - typename T3, typename T4, typename T5 > -R Signal5<R, G, T1, T2, T3, T4, T5>::Callback(G object, - T1 data1, - T2 data2, - T3 data3, - T4 data4, - T5 data5, - Signal5* self) -{ - return self->callback_(object, data1, data2, data3, data4, data5); -} - -template < typename R, typename G, typename T1, typename T2, - typename T3, typename T4, typename T5 , typename T6 > -Signal6<R, G, T1, T2, T3, T4, T5, T6>::Signal6() -{} - -template < typename R, typename G, typename T1, typename T2, - typename T3, typename T4, typename T5 , typename T6 > -void Signal6<R, G, T1, T2, T3, T4, T5, T6>::Connect(G object, - std::string const& signal_name, - SignalCallback callback) -{ - object_ = reinterpret_cast<GObject*>(object); - name_ = signal_name; - callback_ = callback; - connection_id_ = g_signal_connect(object, signal_name.c_str(), - G_CALLBACK(Callback), this); -} - -template < typename R, typename G, typename T1, typename T2, - typename T3, typename T4, typename T5, typename T6 > -R Signal6<R, G, T1, T2, T3, T4, T5, T6>::Callback(G object, - T1 data1, - T2 data2, - T3 data3, - T4 data4, - T5 data5, - T6 data6, - Signal6* self) -{ - return self->callback_(object, data1, data2, data3, data4, data5, data6); -} - -template<typename R, typename G> -Signal<R, G>::Signal() -{} - -template<typename R, typename G> -Signal<R, G>::Signal(G object, std::string const& signal_name, SignalCallback callback) -{ - this->Connect(object, signal_name, callback); -} - -template<typename R, typename G, typename T1> -Signal<R, G, T1>::Signal() -{} - -template<typename R, typename G, typename T1> -Signal<R, G, T1>::Signal(G object, std::string const& signal_name, SignalCallback callback) -{ - this->Connect(object, signal_name, callback); -} - -template<typename R, typename G, typename T1, typename T2> -Signal<R, G, T1, T2>::Signal() -{} - -template<typename R, typename G, typename T1, typename T2> -Signal<R, G, T1, T2>::Signal(G object, - std::string const& signal_name, - SignalCallback callback) -{ - this->Connect(object, signal_name, callback); -} - -template<typename R, typename G, typename T1, typename T2, typename T3> -Signal<R, G, T1, T2, T3>::Signal() -{} - -template<typename R, typename G, typename T1, typename T2, typename T3> -Signal<R, G, T1, T2, T3>::Signal(G object, - std::string const& signal_name, - SignalCallback callback) -{ - this->Connect(object, signal_name, callback); -} - -template<typename R, typename G, typename T1, typename T2, typename T3, typename T4> -Signal<R, G, T1, T2, T3, T4>::Signal() -{} - -template<typename R, typename G, typename T1, typename T2, typename T3, typename T4> -Signal<R, G, T1, T2, T3, T4>::Signal(G object, - std::string const& signal_name, - SignalCallback callback) -{ - this->Connect(object, signal_name, callback); -} - -template < typename R, typename G, typename T1, typename T2, typename T3, typename T4, - typename T5 > -Signal<R, G, T1, T2, T3, T4, T5>::Signal() -{} - -template < typename R, typename G, typename T1, typename T2, typename T3, typename T4, - typename T5 > -Signal<R, G, T1, T2, T3, T4, T5>::Signal(G object, - std::string const& signal_name, - SignalCallback callback) -{ - this->Connect(object, signal_name, callback); -} - -template < typename R, typename G, typename T1, typename T2, typename T3, typename T4, - typename T5, typename T6 > -Signal<R, G, T1, T2, T3, T4, T5, T6>::Signal() -{} - -template < typename R, typename G, typename T1, typename T2, typename T3, typename T4, - typename T5, typename T6 > -Signal<R, G, T1, T2, T3, T4, T5, T6>::Signal(G object, - std::string const& signal_name, - SignalCallback callback) +template <typename R, typename G, typename... Ts> +R Signal<R, G, Ts...>::Callback(G object, Ts... vs, Signal* self) { - this->Connect(object, signal_name, callback); + return self->callback_(object, vs...); } } diff --git a/UnityCore/GLibSignal.cpp b/UnityCore/GLibSignal.cpp index b191d8b9c..d2942aec2 100644 --- a/UnityCore/GLibSignal.cpp +++ b/UnityCore/GLibSignal.cpp @@ -1,6 +1,6 @@ // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* -* Copyright (C) 2011 Canonical Ltd +* Copyright (C) 2011-2012 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -15,6 +15,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Authored by: Neil Jagdish patel <neil.patel@canonical.com> +* Marco Trevisan <marco.trevisan@canonical.com> */ #include "GLibSignal.h" @@ -63,8 +64,12 @@ SignalManager::SignalManager() // opportunity for random bugs, it also made the API bad. void SignalManager::Add(SignalBase* signal) { - SignalBase::Ptr s(signal); - connections_.push_back(s); + Add(SignalBase::Ptr(signal)); +} + +void SignalManager::Add(SignalBase::Ptr const& signal) +{ + connections_.push_back(signal); } // This uses void* to keep in line with the g_signal* functions diff --git a/UnityCore/GLibSignal.h b/UnityCore/GLibSignal.h index c1004a886..b498888bb 100644 --- a/UnityCore/GLibSignal.h +++ b/UnityCore/GLibSignal.h @@ -1,6 +1,6 @@ // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* -* Copyright (C) 2011 Canonical Ltd +* Copyright (C) 2011-2012 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -15,6 +15,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Authored by: Neil Jagdish Patel <neil.patel@canonical.com> +* Marco Trevisan <marco.trevisan@canonical.com> */ #ifndef UNITY_GLIB_SIGNAL_H @@ -22,8 +23,8 @@ #include <string> #include <vector> +#include <memory> #include <boost/noncopyable.hpp> -#include <boost/shared_ptr.hpp> #include <glib-object.h> #include <sigc++/sigc++.h> @@ -32,14 +33,11 @@ namespace unity namespace glib { -using sigc::nil; - -class SignalBase +class SignalBase : boost::noncopyable { public: - typedef boost::shared_ptr<SignalBase> Ptr; + typedef std::shared_ptr<SignalBase> Ptr; - SignalBase(); virtual ~SignalBase(); void Disconnect(); @@ -48,257 +46,58 @@ public: std::string const& name() const; protected: + SignalBase(); + GObject* object_; guint32 connection_id_; std::string name_; }; -template <typename R, typename G> -class Signal0 : public SignalBase -{ -public: - typedef sigc::slot<R, G> SignalCallback; - - Signal0(); - - void Connect(G Object, - std::string const& signal_name, - SignalCallback cb); -private: - static R Callback(G object, Signal0* self); -private: - SignalCallback callback_; -}; - -template <typename R, typename G, typename T> -class Signal1 : public SignalBase -{ -public: - typedef sigc::slot<R, G, T> SignalCallback; - - Signal1(); - - void Connect(G Object, - std::string const& signal_name, - SignalCallback callback); -private: - static R Callback(G object, T data1, Signal1* self); -private: - SignalCallback callback_; -}; - -template <typename R, typename G, typename T1, typename T2> -class Signal2 : public SignalBase -{ -public: - typedef sigc::slot<R, G, T1, T2> SignalCallback; - - Signal2(); - - void Connect(G Object, - std::string const& signal_name, - SignalCallback callback); -private: - static R Callback(G Object, - T1 data1, - T2 data2, - Signal2* self); -private: - SignalCallback callback_; -}; - -template <typename R, typename G, typename T1, typename T2, typename T3> -class Signal3 : public SignalBase -{ -public: - typedef sigc::slot<R, G, T1, T2, T3> SignalCallback; - - Signal3(); - - void Connect(G Object, - std::string const& signal_name, - SignalCallback callback); -private: - static R Callback(G Object, - T1 data1, - T2 data2, - T3 data3, - Signal3* self); -private: - SignalCallback callback_; -}; - -template <typename R, typename G, typename T1, typename T2, typename T3, typename T4> -class Signal4 : public SignalBase +template <typename R, typename G, typename... Ts> +class Signal : public SignalBase { public: - typedef sigc::slot<R, G, T1, T2, T3, T4> SignalCallback; - - Signal4(); +/* Versions of GCC prior to 4.7 doesn't support the Ts... expansion, we can + * workaround this issue using the trick below. + * See GCC bug http://gcc.gnu.org/bugzilla/show_bug.cgi?id=35722 */ +#if !defined(__GNUC__) || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 7) + typedef sigc::slot<R, G, Ts...> SignalCallback; +#else + template<template <typename...> class T, typename... params> + struct expand_variadic { + typedef T<params...> type; + }; - void Connect(G Object, - std::string const& signal_name, - SignalCallback callback); -private: - static R Callback(G Object, - T1 data1, - T2 data2, - T3 data3, - T4 data4, - Signal4* self); -private: - SignalCallback callback_; -}; + typedef typename expand_variadic<sigc::slot, R, G, Ts...>::type SignalCallback; +#endif -template < typename R, typename G, typename T1, typename T2, - typename T3, typename T4, typename T5 > -class Signal5 : public SignalBase -{ -public: - typedef sigc::slot<R, G, T1, T2, T3, T4, T5> SignalCallback; + inline Signal() {}; + inline Signal(G object, std::string const& signal_name, SignalCallback const& callback); - Signal5(); + inline void Connect(G Object, std::string const& signal_name, SignalCallback const& callback); - void Connect(G Object, - std::string const& signal_name, - SignalCallback callback); private: - static R Callback(G Object, - T1 data1, - T2 data2, - T3 data3, - T4 data4, - T5 data5, - Signal5* self); -private: - SignalCallback callback_; -}; - -template < typename R, typename G, typename T1, typename T2, - typename T3, typename T4, typename T5, typename T6 > -class Signal6 : public SignalBase -{ -public: - typedef sigc::slot<R, G, T1, T2, T3, T4, T5, T6> SignalCallback; + static R Callback(G Object, Ts... vs, Signal* self); - Signal6(); - - void Connect(G Object, - std::string const& signal_name, - SignalCallback callback); -private: - static R Callback(G Object, - T1 data1, - T2 data2, - T3 data3, - T4 data4, - T5 data5, - T6 data6, - Signal6* self); -private: SignalCallback callback_; }; -template < typename R, typename G, - typename T1 = nil, typename T2 = nil, - typename T3 = nil, typename T4 = nil, - typename T5 = nil, typename T6 = nil > -class Signal : public Signal6<R, G, T1, T2, T3, T4, T5, T6> -{ -public: - typedef sigc::slot<R, G, T1, T2, T3, T4, T5, T6> SignalCallback; - - inline Signal(); - inline Signal(G Object, - std::string const& signal_name, - SignalCallback callback); -}; - -template <typename R, typename G> -class Signal<R, G, nil, nil, nil, nil, nil, nil> : public Signal0<R, G> -{ -public: - typedef sigc::slot<R, G> SignalCallback; - - inline Signal(); - inline Signal(G Object, - std::string const& signal_name, - SignalCallback callback); -}; - -template <typename R, typename G, typename T1> -class Signal<R, G, T1, nil, nil, nil, nil, nil> : public Signal1<R, G, T1> -{ -public: - typedef sigc::slot<R, G, T1> SignalCallback; - - inline Signal(); - inline Signal(G Object, - std::string const& signal_name, - SignalCallback callback); -}; - -template <typename R, typename G, typename T1, typename T2> -class Signal<R, G, T1, T2, nil, nil, nil, nil> : public Signal2<R, G, T1, T2> +class SignalManager : boost::noncopyable { public: - typedef sigc::slot<R, G, T1, T2> SignalCallback; - - inline Signal(); - inline Signal(G Object, - std::string const& signal_name, - SignalCallback callback); -}; - -template <typename R, typename G, typename T1, typename T2, typename T3> -class Signal<R, G, T1, T2, T3, nil, nil, nil> : public Signal3<R, G, T1, T2 , T3> -{ -public: - typedef sigc::slot<R, G, T1, T2, T3> SignalCallback; - - inline Signal(); - inline Signal(G Object, - std::string const& signal_name, - SignalCallback callback); -}; - -template <typename R, typename G, typename T1, typename T2, typename T3, typename T4> -class Signal<R, G, T1, T2, T3, T4, nil, nil> - : public Signal4<R, G, T1, T2 , T3, T4> -{ -public: - typedef sigc::slot<R, G, T1, T2, T3, T4> SignalCallback; - - inline Signal(); - inline Signal(G Object, - std::string const& signal_name, - SignalCallback callback); -}; - -template <typename R, typename G, typename T1, typename T2, typename T3, typename T4, typename T5> -class Signal<R, G, T1, T2, T3, T4, T5, nil> - : public Signal5<R, G, T1, T2 , T3, T4, T5> -{ -public: - typedef sigc::slot<R, G, T1, T2, T3, T4, T5> SignalCallback; - - inline Signal(); - inline Signal(G Object, - std::string const& signal_name, - SignalCallback callback); -}; - -class SignalManager : public boost::noncopyable -{ -public: - typedef std::vector<SignalBase::Ptr> ConnectionVector; - SignalManager(); void Add(SignalBase* signal); + void Add(SignalBase::Ptr const& signal); + template <typename R, typename G, typename... Ts> + void Add(G object, std::string const& signal_name, typename Signal<R, G, Ts...>::SignalCallback const& callback) + { + Add(std::make_shared<Signal<R, G, Ts...>>(object, signal_name, callback)); + } + void Disconnect(void* object, std::string const& signal_name = ""); -private: - ConnectionVector connections_; +protected: + std::vector<SignalBase::Ptr> connections_; }; } diff --git a/UnityCore/unity-core.pc.cmake b/UnityCore/unity-core.pc.cmake index 66e389236..251209154 100644 --- a/UnityCore/unity-core.pc.cmake +++ b/UnityCore/unity-core.pc.cmake @@ -9,4 +9,4 @@ Description: Core objects and utilities for Unity implementations Version: @VERSION@ Libs: -L${libdir} -lunity-core-@UNITY_API_VERSION@ Cflags: -I${includedir}/Unity-@UNITY_API_VERSION@ -Requires: glib-2.0 gio-2.0 sigc++-2.0 nux-core-2.0 dee-1.0 +Requires: glib-2.0 gio-2.0 sigc++-2.0 nux-core-3.0 dee-1.0 diff --git a/dash/DashController.cpp b/dash/DashController.cpp index 4b611a715..eae21622a 100644 --- a/dash/DashController.cpp +++ b/dash/DashController.cpp @@ -80,7 +80,7 @@ void Controller::SetupWindow() window_->ShowWindow(false); window_->SetOpacity(0.0f); window_->mouse_down_outside_pointer_grab_area.connect(sigc::mem_fun(this, &Controller::OnMouseDownOutsideWindow)); - + /* FIXME - first time we load our windows there is a race that causes the input window not to actually get input, this side steps that by causing an input window show and hide before we really need it. */ auto plugin_adapter = PluginAdapter::Default(); plugin_adapter->saveInputFocus (); @@ -337,6 +337,9 @@ gboolean Controller::CheckShortcutActivation(const char* key_string) std::string lens_id = view_->GetIdForShortcutActivation(std::string(key_string)); if (lens_id != "") { + if (PluginAdapter::Default()->IsScaleActive()) + PluginAdapter::Default()->TerminateScale(); + GVariant* args = g_variant_new("(sus)", lens_id.c_str(), dash::GOTO_DASH_URI, ""); OnActivateRequest(args); g_variant_unref(args); diff --git a/dash/DashView.cpp b/dash/DashView.cpp index e84a3e726..afa1f729f 100644 --- a/dash/DashView.cpp +++ b/dash/DashView.cpp @@ -30,6 +30,7 @@ #include <UnityCore/RadioOptionFilter.h> #include "unity-shared/DashStyle.h" +#include "unity-shared/KeyboardUtil.h" #include "unity-shared/UnitySettings.h" #include "unity-shared/UBusMessages.h" @@ -761,16 +762,17 @@ void DashView::ProcessDndEnter() ubus_manager_.SendMessage(UBUS_PLACE_VIEW_CLOSE_REQUEST); } -Area* DashView::FindKeyFocusArea(unsigned int key_symbol, - unsigned long x11_key_code, - unsigned long special_keys_state) +nux::Area* DashView::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. + using namespace nux; + nux::KeyNavDirection direction = KEY_NAV_NONE; bool ctrl = (special_keys_state & NUX_STATE_CTRL); - nux::KeyNavDirection direction = KEY_NAV_NONE; switch (x11_key_code) { case NUX_VK_UP: @@ -801,14 +803,13 @@ Area* DashView::FindKeyFocusArea(unsigned int key_symbol, case NUX_VK_F4: // Maybe we should not do it here, but it needs to be checked where // we are able to know if alt is pressed. - if (special_keys_state & NUX_STATE_ALT) + if (special_keys_state == NUX_STATE_ALT) { ubus_manager_.SendMessage(UBUS_PLACE_VIEW_CLOSE_REQUEST); } break; default: direction = KEY_NAV_NONE; - break; } // We should not do it here, but I really don't want to make DashView @@ -816,7 +817,7 @@ Area* DashView::FindKeyFocusArea(unsigned int key_symbol, // DashView::KeyNavIteration. nux::InputArea* focus_area = nux::GetWindowCompositor().GetKeyFocusArea(); - if (key_symbol == nux::NUX_KEYDOWN && !search_bar_->im_preedit) + if (direction != KEY_NAV_NONE && key_symbol == nux::NUX_KEYDOWN && !search_bar_->im_preedit) { std::list<nux::Area*> tabs; for (auto category : active_lens_view_->categories()) @@ -891,7 +892,18 @@ Area* DashView::FindKeyFocusArea(unsigned int key_symbol, } } - if (direction == KEY_NAV_NONE || search_bar_->im_preedit) + bool search_key = false; + + if (direction == KEY_NAV_NONE) + { + if (ui::KeyboardUtil::IsPrintableKeySymbol(x11_key_code) || + ui::KeyboardUtil::IsMoveKeySymbol(x11_key_code)) + { + search_key = true; + } + } + + if (search_key || search_bar_->im_preedit) { // then send the event to the search entry return search_bar_->text_entry(); @@ -900,7 +912,8 @@ Area* DashView::FindKeyFocusArea(unsigned int key_symbol, { return next_object_to_key_focus_area_->FindKeyFocusArea(key_symbol, x11_key_code, special_keys_state); } - return NULL; + + return nullptr; } } diff --git a/dash/PlacesVScrollBar.h b/dash/PlacesVScrollBar.h index 54d0b3da7..11bace179 100644 --- a/dash/PlacesVScrollBar.h +++ b/dash/PlacesVScrollBar.h @@ -25,7 +25,7 @@ #include <Nux/ScrollView.h> #include <Nux/BaseWindow.h> #include <Nux/VScrollBar.h> -#include <NuxImage/CairoGraphics.h> +#include <NuxGraphics/CairoGraphics.h> class PlacesVScrollBar : public nux::VScrollBar { diff --git a/dash/ResultRendererHorizontalTile.h b/dash/ResultRendererHorizontalTile.h index d7c68238b..deda4bd71 100644 --- a/dash/ResultRendererHorizontalTile.h +++ b/dash/ResultRendererHorizontalTile.h @@ -29,7 +29,7 @@ #include <NuxCore/Object.h> #include <NuxCore/Property.h> #include <Nux/TextureArea.h> -#include <NuxImage/CairoGraphics.h> +#include <NuxGraphics/CairoGraphics.h> #include "ResultRendererTile.h" diff --git a/dash/ResultRendererTile.h b/dash/ResultRendererTile.h index 54a21faf2..165b60653 100644 --- a/dash/ResultRendererTile.h +++ b/dash/ResultRendererTile.h @@ -30,7 +30,7 @@ #include <NuxCore/ObjectPtr.h> #include <NuxCore/Property.h> #include <Nux/TextureArea.h> -#include <NuxImage/CairoGraphics.h> +#include <NuxGraphics/CairoGraphics.h> #include "unity-shared/IconLoader.h" #include "ResultRenderer.h" diff --git a/dash/ResultView.cpp b/dash/ResultView.cpp index 8c22866e7..5350fc579 100644 --- a/dash/ResultView.cpp +++ b/dash/ResultView.cpp @@ -142,7 +142,7 @@ void ResultView::AddProperties(GVariantBuilder* builder) .add("expanded", expanded); } -debug::Introspectable::IntrospectableList const& ResultView::GetIntrospectableChildren() +debug::Introspectable::IntrospectableList ResultView::GetIntrospectableChildren() { ClearIntrospectableWrappers(); diff --git a/dash/ResultView.h b/dash/ResultView.h index 1cc339b82..224d11637 100644 --- a/dash/ResultView.h +++ b/dash/ResultView.h @@ -61,7 +61,7 @@ public: std::string GetName() const; void AddProperties(GVariantBuilder* builder); - IntrospectableList const& GetIntrospectableChildren(); + IntrospectableList GetIntrospectableChildren(); protected: virtual void Draw(nux::GraphicsEngine& GfxContext, bool force_draw); diff --git a/dash/ResultViewGrid.cpp b/dash/ResultViewGrid.cpp index 2fc07cdf0..173c26c3c 100644 --- a/dash/ResultViewGrid.cpp +++ b/dash/ResultViewGrid.cpp @@ -23,7 +23,7 @@ #include <Nux/Nux.h> #include <NuxCore/Logger.h> #include <Nux/VLayout.h> -#include <NuxImage/GdkGraphics.h> +#include <NuxGraphics/GdkGraphics.h> #include <gtk/gtk.h> #include <gdk/gdk.h> diff --git a/hud/HudButton.cpp b/hud/HudButton.cpp index 138407f30..13159eba7 100644 --- a/hud/HudButton.cpp +++ b/hud/HudButton.cpp @@ -28,7 +28,7 @@ #include <Nux/Nux.h> #include <Nux/HLayout.h> #include <NuxCore/Logger.h> -#include <NuxImage/CairoGraphics.h> +#include <NuxGraphics/CairoGraphics.h> #include <NuxGraphics/NuxGraphics.h> #include <UnityCore/GLibWrapper.h> #include <UnityCore/Variant.h> @@ -52,10 +52,13 @@ namespace unity namespace hud { +NUX_IMPLEMENT_OBJECT_TYPE(HudButton); + HudButton::HudButton(NUX_FILE_LINE_DECL) : nux::Button(NUX_FILE_LINE_PARAM) , is_rounded(false) , is_focused_(false) + , skip_draw_(true) { hlayout_ = new nux::HLayout(NUX_TRACKER_LOCATION); hlayout_->SetLeftAndRightPadding(hlayout_left_padding, -1); @@ -105,7 +108,7 @@ void HudButton::RedrawTheme(nux::Geometry const& geom, cairo_t* cr, nux::ButtonV bool HudButton::AcceptKeyNavFocus() { - // The button will not receive the keyboard focus. The keyboard focus is always to remain with the + // The button will not receive the keyboard focus. The keyboard focus is always to remain with the // text entry in the hud. return false; } @@ -130,7 +133,11 @@ long HudButton::ComputeContentSize() void HudButton::Draw(nux::GraphicsEngine& GfxContext, bool force_draw) { + if (skip_draw_) + return; + nux::Geometry const& geo = GetGeometry(); + GfxContext.PushClippingRectangle(geo); gPainter.PaintBackground(GfxContext, geo); // set up our texture mode @@ -170,12 +177,21 @@ void HudButton::Draw(nux::GraphicsEngine& GfxContext, bool force_draw) nux::color::White); GfxContext.GetRenderStates().SetBlend(alpha, src, dest); + + GfxContext.PopClippingRectangle(); } void HudButton::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) { + if (skip_draw_) + return; + if (IsFullRedraw()) + { + GfxContext.PushClippingRectangle(GetGeometry()); hlayout_->ProcessDraw(GfxContext, force_draw); + GfxContext.PopClippingRectangle(); + } } void HudButton::SetQuery(Query::Ptr query) @@ -188,7 +204,7 @@ void HudButton::SetQuery(Query::Ptr query) hlayout_->Clear(); for (auto item : items) { - nux::StaticCairoText* text = new nux::StaticCairoText(item.first.c_str()); + nux::StaticCairoText* text = new nux::StaticCairoText(item.first); text->SetTextColor(nux::Color(1.0f, 1.0f, 1.0f, item.second ? 1.0f : 0.5f)); text->SetFont(button_font); hlayout_->AddView(text, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL); @@ -200,6 +216,12 @@ Query::Ptr HudButton::GetQuery() return query_; } +void HudButton::SetSkipDraw(bool skip_draw) +{ + skip_draw_ = skip_draw; +} + + // Introspectable std::string HudButton::GetName() const { @@ -209,7 +231,8 @@ std::string HudButton::GetName() const void HudButton::AddProperties(GVariantBuilder* builder) { variant::BuilderWrapper(builder) - .add("label", label()); + .add("label", label()) + .add("focused", fake_focused()); } } // namespace hud diff --git a/hud/HudButton.h b/hud/HudButton.h index 555f5ab38..9ccf43d14 100644 --- a/hud/HudButton.h +++ b/hud/HudButton.h @@ -38,8 +38,8 @@ namespace hud class HudButton : public nux::Button, public unity::debug::Introspectable { - typedef nux::ObjectPtr<nux::BaseTexture> BaseTexturePtr; - typedef std::unique_ptr<nux::CairoWrapper> NuxCairoPtr; + NUX_DECLARE_OBJECT_TYPE(HudButton, nux::Button); + public: typedef nux::ObjectPtr<HudButton> Ptr; @@ -48,6 +48,8 @@ public: void SetQuery(Query::Ptr query); std::shared_ptr<Query> GetQuery(); + void SetSkipDraw(bool skip_draw); + nux::Property<std::string> label; nux::Property<bool> is_rounded; nux::Property<bool> fake_focused; @@ -65,9 +67,13 @@ protected: void RedrawTheme(nux::Geometry const& geom, cairo_t* cr, nux::ButtonVisualState faked_state); private: + typedef std::unique_ptr<nux::CairoWrapper> NuxCairoPtr; + Query::Ptr query_; nux::Geometry cached_geometry_; + bool is_focused_; + bool skip_draw_; NuxCairoPtr prelight_; NuxCairoPtr active_; diff --git a/hud/HudView.cpp b/hud/HudView.cpp index 6c0e02531..d45a741a0 100644 --- a/hud/HudView.cpp +++ b/hud/HudView.cpp @@ -27,6 +27,8 @@ #include <Nux/HLayout.h> #include <Nux/VLayout.h> +#include "unity-shared/Introspectable.h" + #include "unity-shared/UBusMessages.h" #include "unity-shared/DashStyle.h" @@ -116,10 +118,6 @@ View::View() View::~View() { - for (auto button = buttons_.begin(); button != buttons_.end(); button++) - { - RemoveChild((*button).GetPointer()); - } } void View::ProcessGrowShrink() @@ -149,6 +147,11 @@ void View::ProcessGrowShrink() current_height_ = new_height; } + for (auto button : buttons_) + { + button->SetSkipDraw((button->GetAbsoluteY() + button->GetBaseHeight()) > (GetAbsoluteY() + current_height_)); + } + QueueDraw(); if (diff > grow_anim_length + pause_before_grow_length) @@ -238,6 +241,8 @@ void View::SetQueries(Hud::Queries queries) HudButton::Ptr button(new HudButton()); buttons_.push_front(button); + button->SetMinimumWidth(content_width); + button->SetMaximumWidth(content_width); button->SetQuery(query); button_views_->AddView(button.GetPointer(), 0, nux::MINOR_POSITION_LEFT); @@ -250,12 +255,11 @@ void View::SetQueries(Hud::Queries queries) query_activated.emit(dynamic_cast<HudButton*>(area)->GetQuery()); }); - button->key_nav_focus_change.connect([&](nux::Area* area, bool recieving, KeyNavDirection direction){ + button->key_nav_focus_change.connect([&](nux::Area* area, bool recieving, nux::KeyNavDirection direction){ if (recieving) query_selected.emit(dynamic_cast<HudButton*>(area)->GetQuery()); }); - button->SetMinimumWidth(content_width); ++found_items; } @@ -350,7 +354,7 @@ void View::SetupViews() { dash::Style& style = dash::Style::Instance(); - nux::VLayout* super_layout = new nux::VLayout(); + nux::VLayout* super_layout = new nux::VLayout(); layout_ = new nux::HLayout(); { // fill layout with icon @@ -398,7 +402,7 @@ void View::OnSearchChanged(std::string const& search_string) { button->fake_focused = false; } - + if (!buttons_.empty()) buttons_.back()->fake_focused = true; } @@ -417,7 +421,9 @@ void View::OnKeyDown (unsigned long event_type, unsigned long keysym, void View::OnMouseButtonDown(int x, int y, unsigned long button, unsigned long key) { - if (!content_geo_.IsPointInside(x, y)) + nux::Geometry current_geo(content_geo_); + current_geo.height = current_height_; + if (!current_geo.IsPointInside(x, y)) { ubus.SendMessage(UBUS_HUD_CLOSE_REQUEST); } @@ -457,7 +463,7 @@ void View::DrawContent(nux::GraphicsEngine& gfx_context, bool force_draw) x += content_width - 1; nux::GetPainter().Draw2DLine(gfx_context, x, y, x, y + height, nux::color::White * 0.13); } - + GetLayout()->ProcessDraw(gfx_context, force_draw); nux::GetPainter().PopBackgroundStack(); } @@ -500,6 +506,18 @@ void View::AddProperties(GVariantBuilder* builder) .add("num_buttons", num_buttons); } +debug::Introspectable::IntrospectableList View::GetIntrospectableChildren() +{ + introspectable_children_.clear(); + introspectable_children_.merge(debug::Introspectable::GetIntrospectableChildren()); + for (auto button: buttons_) + { + introspectable_children_.push_front(button.GetPointer()); + } + + return introspectable_children_; +} + bool View::InspectKeyEvent(unsigned int eventType, unsigned int key_sym, const char* character) @@ -573,6 +591,12 @@ nux::Area* View::FindKeyFocusArea(unsigned int event_type, // Not sure if Enter should be a navigation key direction = nux::KEY_NAV_ENTER; break; + case NUX_VK_F4: + if (special_keys_state == nux::NUX_STATE_ALT) + { + ubus.SendMessage(UBUS_HUD_CLOSE_REQUEST); + } + break; default: direction = nux::KEY_NAV_NONE; break; diff --git a/hud/HudView.h b/hud/HudView.h index ca1e1a6f4..8e654b49f 100644 --- a/hud/HudView.h +++ b/hud/HudView.h @@ -61,7 +61,7 @@ public: void AboutToHide(); void SetWindowGeometry(nux::Geometry const& absolute_geo, nux::Geometry const& geo); - + protected: virtual Area* FindKeyFocusArea(unsigned int event_type, unsigned long x11_key_code, @@ -87,6 +87,7 @@ private: std::string GetName() const; void AddProperties(GVariantBuilder* builder); + IntrospectableList GetIntrospectableChildren(); private: UBusManager ubus; @@ -94,6 +95,7 @@ private: nux::ObjectPtr<nux::Layout> content_layout_; nux::ObjectPtr<nux::VLayout> button_views_; std::list<HudButton::Ptr> buttons_; + IntrospectableList introspectable_children_; //FIXME - replace with dash search bar once modifications to dash search bar land SearchBar::Ptr search_bar_; diff --git a/launcher/AbstractLauncherIcon.h b/launcher/AbstractLauncherIcon.h index a419a4974..1f4341536 100644 --- a/launcher/AbstractLauncherIcon.h +++ b/launcher/AbstractLauncherIcon.h @@ -218,6 +218,7 @@ public: sigc::signal<void, AbstractLauncherIcon::Ptr> needs_redraw; sigc::signal<void, AbstractLauncherIcon::Ptr> remove; + sigc::signal<void, nux::ObjectPtr<nux::View>> tooltip_visible; sigc::signal<void> visibility_changed; sigc::connection needs_redraw_connection; diff --git a/launcher/FavoriteStoreGSettings.cpp b/launcher/FavoriteStoreGSettings.cpp index 2467b94ab..fe900099b 100644 --- a/launcher/FavoriteStoreGSettings.cpp +++ b/launcher/FavoriteStoreGSettings.cpp @@ -44,7 +44,6 @@ namespace nux::logging::Logger logger("unity.favorites"); const char* SETTINGS_NAME = "com.canonical.Unity.Launcher"; -const char* LATEST_SETTINGS_MIGRATION = "3.2.10"; void on_settings_updated(GSettings* settings, const gchar* key, @@ -68,30 +67,6 @@ FavoriteStoreGSettings::FavoriteStoreGSettings(GSettingsBackend* backend) void FavoriteStoreGSettings::Init() { - /* migrate the favorites if needed and ignore errors */ - glib::String latest_migration_update(g_settings_get_string( - settings_, "favorite-migration")); - if (latest_migration_update.Str() < LATEST_SETTINGS_MIGRATION) - { - glib::Error error; - std::string cmd(PREFIXDIR); - cmd += "/lib/unity/migrate_favorites.py"; - - glib::String output; - - g_spawn_command_line_sync(cmd.c_str(), - &output, - NULL, - NULL, - &error); - if (error) - { - LOG_WARN(logger) << "WARNING: Unable to run the migrate favorites " - << "tools successfully: " << error - << ".\n\tThe output was:" << output; - } - } - g_signal_connect(settings_, "changed", G_CALLBACK(on_settings_updated), this); Refresh(); } diff --git a/launcher/Launcher.cpp b/launcher/Launcher.cpp index 7123c4ed9..b83bae24a 100644 --- a/launcher/Launcher.cpp +++ b/launcher/Launcher.cpp @@ -1520,6 +1520,11 @@ bool Launcher::IsBackLightModeToggles() const } } +nux::ObjectPtr<nux::View> Launcher::GetActiveTooltip() const +{ + return _active_tooltip; +} + void Launcher::SetActionState(LauncherActionState actionstate) { if (_launcher_action_state == actionstate) @@ -1681,6 +1686,7 @@ void Launcher::OnIconAdded(AbstractLauncherIcon::Ptr icon) EnsureAnimation(); icon->needs_redraw.connect(sigc::mem_fun(this, &Launcher::OnIconNeedsRedraw)); + icon->tooltip_visible.connect(sigc::mem_fun(this, &Launcher::OnTooltipVisible)); } void Launcher::OnIconRemoved(AbstractLauncherIcon::Ptr icon) @@ -1757,6 +1763,11 @@ void Launcher::OnIconNeedsRedraw(AbstractLauncherIcon::Ptr icon) EnsureAnimation(); } +void Launcher::OnTooltipVisible(nux::ObjectPtr<nux::View> view) +{ + _active_tooltip = view; +} + void Launcher::Draw(nux::GraphicsEngine& GfxContext, bool force_draw) { diff --git a/launcher/Launcher.h b/launcher/Launcher.h index 77ac52fbe..aee8f95a6 100644 --- a/launcher/Launcher.h +++ b/launcher/Launcher.h @@ -96,6 +96,8 @@ public: return _parent; }; + nux::ObjectPtr<nux::View> GetActiveTooltip() const; // nullptr = no tooltip + virtual void RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); virtual void RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); virtual void RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); @@ -269,6 +271,7 @@ private: void OnOrderChanged(); void OnIconNeedsRedraw(AbstractLauncherIcon::Ptr icon); + void OnTooltipVisible(nux::ObjectPtr<nux::View> view); void OnOverlayHidden(GVariant* data); void OnOverlayShown(GVariant* data); @@ -311,6 +314,7 @@ private: LauncherModel::Ptr _model; nux::BaseWindow* _parent; + nux::ObjectPtr<nux::View> _active_tooltip; QuicklistView* _active_quicklist; nux::HLayout* m_Layout; diff --git a/launcher/LauncherController.cpp b/launcher/LauncherController.cpp index 2886ad1e7..ad7168fcd 100644 --- a/launcher/LauncherController.cpp +++ b/launcher/LauncherController.cpp @@ -196,7 +196,6 @@ public: LauncherList launchers; - glib::Source::UniquePtr activate_idle_; glib::Object<BamfMatcher> matcher_; glib::Signal<void, BamfMatcher*, BamfView*> view_opened_signal_; glib::SourceManager sources_; @@ -373,6 +372,9 @@ void Controller::Impl::OnWindowFocusChanged (guint32 xid) { static bool keynav_first_focus = false; + if (parent_->IsOverlayOpen()) + keynav_first_focus = false; + if (keynav_first_focus) { keynav_first_focus = false; @@ -1098,7 +1100,6 @@ void Controller::Impl::ReceiveMouseDownOutsideArea(int x, int y, unsigned long b void Controller::KeyNavGrab() { - pimpl->ubus.SendMessage(UBUS_PLACE_VIEW_CLOSE_REQUEST); pimpl->launcher_grabbed = true; KeyNavActivate(); pimpl->keyboard_launcher_->GrabKeyboard(); @@ -1197,12 +1198,13 @@ void Controller::KeyNavTerminate(bool activate) g_variant_new_boolean(pimpl->keynav_restore_window_)); } - pimpl->activate_idle_.reset(new glib::Idle([activate, this] () { - if (activate) + if (activate) + { + pimpl->sources_.Add(std::make_shared<glib::Idle>([this] { pimpl->model_->Selection()->Activate(ActionArg(ActionArg::LAUNCHER, 0)); - - return false; - })); + return false; + })); + } pimpl->launcher_keynav = false; if (!pimpl->launcher_open) diff --git a/launcher/LauncherIcon.cpp b/launcher/LauncherIcon.cpp index a17db19b0..d0f02dd6b 100644 --- a/launcher/LauncherIcon.cpp +++ b/launcher/LauncherIcon.cpp @@ -513,6 +513,7 @@ LauncherIcon::ShowTooltip() LoadTooltip(); _tooltip->ShowTooltipWithTipAt(tip_x, tip_y); _tooltip->ShowWindow(!tooltip_text().empty()); + tooltip_visible.emit(_tooltip); } void @@ -534,6 +535,7 @@ void LauncherIcon::RecvMouseLeave(int monitor) if (_tooltip) _tooltip->ShowWindow(false); + tooltip_visible.emit(nux::ObjectPtr<nux::View>(nullptr)); } bool LauncherIcon::OpenQuicklist(bool select_first_item, int monitor) @@ -653,6 +655,7 @@ void LauncherIcon::HideTooltip() { if (_tooltip) _tooltip->ShowWindow(false); + tooltip_visible.emit(nux::ObjectPtr<nux::View>(nullptr)); } bool diff --git a/launcher/LauncherModel.cpp b/launcher/LauncherModel.cpp index c3f0f9f38..8e8d6e504 100644 --- a/launcher/LauncherModel.cpp +++ b/launcher/LauncherModel.cpp @@ -44,7 +44,7 @@ void LauncherModel::AddProperties(GVariantBuilder* builder) .add("selection", selection_); } -unity::debug::Introspectable::IntrospectableList const& LauncherModel::GetIntrospectableChildren() +unity::debug::Introspectable::IntrospectableList LauncherModel::GetIntrospectableChildren() { introspection_results_.clear(); diff --git a/launcher/LauncherModel.h b/launcher/LauncherModel.h index de3e33867..e6295b6cf 100644 --- a/launcher/LauncherModel.h +++ b/launcher/LauncherModel.h @@ -84,7 +84,7 @@ public: sigc::signal<void> saved; sigc::signal<void, AbstractLauncherIcon::Ptr> selection_changed; - IntrospectableList const& GetIntrospectableChildren(); + IntrospectableList GetIntrospectableChildren(); protected: // Introspectable methods std::string GetName() const; diff --git a/launcher/QuicklistMenuItem.h b/launcher/QuicklistMenuItem.h index 25b108634..6a0291428 100644 --- a/launcher/QuicklistMenuItem.h +++ b/launcher/QuicklistMenuItem.h @@ -26,7 +26,7 @@ #include <Nux/Nux.h> #include <Nux/View.h> -#include <NuxImage/CairoGraphics.h> +#include <NuxGraphics/CairoGraphics.h> #include <pango/pango.h> #include <pango/pangocairo.h> diff --git a/launcher/QuicklistMenuItemCheckmark.h b/launcher/QuicklistMenuItemCheckmark.h index 39a31f334..bc5046415 100644 --- a/launcher/QuicklistMenuItemCheckmark.h +++ b/launcher/QuicklistMenuItemCheckmark.h @@ -23,7 +23,7 @@ #include <Nux/Nux.h> #include <Nux/View.h> -#include <NuxImage/CairoGraphics.h> +#include <NuxGraphics/CairoGraphics.h> #include "QuicklistMenuItem.h" diff --git a/launcher/QuicklistMenuItemLabel.h b/launcher/QuicklistMenuItemLabel.h index 421c9ac64..58ce6e2f2 100644 --- a/launcher/QuicklistMenuItemLabel.h +++ b/launcher/QuicklistMenuItemLabel.h @@ -23,7 +23,7 @@ #include <Nux/Nux.h> #include <Nux/View.h> -#include <NuxImage/CairoGraphics.h> +#include <NuxGraphics/CairoGraphics.h> #include "QuicklistMenuItem.h" diff --git a/launcher/QuicklistMenuItemRadio.h b/launcher/QuicklistMenuItemRadio.h index e75a17ad5..e50be8509 100644 --- a/launcher/QuicklistMenuItemRadio.h +++ b/launcher/QuicklistMenuItemRadio.h @@ -22,7 +22,7 @@ #include <Nux/Nux.h> #include <Nux/View.h> -#include <NuxImage/CairoGraphics.h> +#include <NuxGraphics/CairoGraphics.h> #include "QuicklistMenuItem.h" diff --git a/launcher/QuicklistMenuItemSeparator.h b/launcher/QuicklistMenuItemSeparator.h index 50987a120..ce1dd8948 100644 --- a/launcher/QuicklistMenuItemSeparator.h +++ b/launcher/QuicklistMenuItemSeparator.h @@ -22,7 +22,7 @@ #include <Nux/Nux.h> #include <Nux/View.h> -#include <NuxImage/CairoGraphics.h> +#include <NuxGraphics/CairoGraphics.h> #include "QuicklistMenuItem.h" diff --git a/launcher/QuicklistView.cpp b/launcher/QuicklistView.cpp index fd88737c4..125554966 100644 --- a/launcher/QuicklistView.cpp +++ b/launcher/QuicklistView.cpp @@ -27,7 +27,7 @@ #include <Nux/Button.h> #include <NuxGraphics/GraphicsEngine.h> #include <Nux/TextureArea.h> -#include <NuxImage/CairoGraphics.h> +#include <NuxGraphics/CairoGraphics.h> #include <UnityCore/Variant.h> #include "unity-shared/CairoTexture.h" @@ -101,8 +101,6 @@ QuicklistView::QuicklistView() _item_layout = new nux::VLayout(TEXT(""), NUX_TRACKER_LOCATION); _vlayout->AddLayout(_item_layout, 0); - _default_item_layout = new nux::VLayout(TEXT(""), NUX_TRACKER_LOCATION); - _vlayout->AddLayout(_default_item_layout, 0); _vlayout->AddLayout(_bottom_space, 0); _vlayout->SetMinimumWidth(140); @@ -306,10 +304,7 @@ QuicklistView::RecvKeyPressed(unsigned long eventType, case NUX_KP_ENTER: if (IsMenuItemSelectable(_current_item_index)) { - dbusmenu_menuitem_handle_event(GetNthItems(_current_item_index)->_menuItem, - "clicked", - NULL, - 0); + ActivateItem(GetNthItems(_current_item_index)); Hide(); } break; @@ -321,22 +316,13 @@ QuicklistView::RecvKeyPressed(unsigned long eventType, QuicklistView::~QuicklistView() { - std::list<QuicklistMenuItem*>::iterator it; - for (it = _item_list.begin(); it != _item_list.end(); it++) + for (auto item : _item_list) { // Remove from introspection - RemoveChild(*it); - (*it)->UnReference(); + RemoveChild(item); + item->UnReference(); } - for (it = _default_item_list.begin(); it != _default_item_list.end(); it++) - { - // Remove from introspection - RemoveChild(*it); - (*it)->UnReference(); - } - - _default_item_list.clear(); _item_list.clear(); } @@ -353,7 +339,7 @@ void QuicklistView::ShowQuicklistWithTipAt(int anchor_tip_x, int anchor_tip_y) if (!_enable_quicklist_for_testing) { - if ((_item_list.size() != 0) || (_default_item_list.size() != 0)) + if ((_item_list.size() != 0)) { int offscreen_size = GetBaseY() + GetBaseHeight() - @@ -434,17 +420,10 @@ void QuicklistView::Draw(nux::GraphicsEngine& gfxContext, bool forceDraw) gfxContext.PushClippingRectangle(base); - std::list<QuicklistMenuItem*>::iterator it; - for (it = _item_list.begin(); it != _item_list.end(); it++) - { - if ((*it)->GetVisible()) - (*it)->ProcessDraw(gfxContext, forceDraw); - } - - for (it = _default_item_list.begin(); it != _default_item_list.end(); it++) + for (auto item : _item_list) { - if ((*it)->GetVisible()) - (*it)->ProcessDraw(gfxContext, forceDraw); + if (item->GetVisible()) + item->ProcessDraw(gfxContext, forceDraw); } gfxContext.PopClippingRectangle(); @@ -458,40 +437,20 @@ void QuicklistView::PreLayoutManagement() int MaxItemWidth = 0; int TotalItemHeight = 0; - std::list<QuicklistMenuItem*>::iterator it; - for (it = _item_list.begin(); it != _item_list.end(); it++) - { - // Make sure item is in layout if it should be - if (!(*it)->GetVisible()) - { - _item_layout->RemoveChildObject(*it); - continue; - } - else if (!(*it)->GetParentObject()) - _item_layout->AddView(*it, 1, nux::eCenter, nux::eFull); - - int textWidth = 0; - int textHeight = 0; - (*it)->GetTextExtents(textWidth, textHeight); - if (textWidth > MaxItemWidth) - MaxItemWidth = textWidth; - TotalItemHeight += textHeight; - } - - for (it = _default_item_list.begin(); it != _default_item_list.end(); it++) + for (auto item : _item_list) { // Make sure item is in layout if it should be - if (!(*it)->GetVisible()) + if (!item->GetVisible()) { - _default_item_layout->RemoveChildObject(*it); + _item_layout->RemoveChildObject(item); continue; } - else if (!(*it)->GetParentObject()) - _default_item_layout->AddView(*it, 1, nux::eCenter, nux::eFull); + else if (!item->GetParentObject()) + _item_layout->AddView(item, 1, nux::eCenter, nux::eFull); int textWidth = 0; int textHeight = 0; - (*it)->GetTextExtents(textWidth, textHeight); + item->GetTextExtents(textWidth, textHeight); if (textWidth > MaxItemWidth) MaxItemWidth = textWidth; TotalItemHeight += textHeight; @@ -513,7 +472,6 @@ void QuicklistView::PreLayoutManagement() } _item_layout->SetMinimumWidth(MaxItemWidth); - _default_item_layout->SetMinimumWidth(MaxItemWidth); BaseWindow::PreLayoutManagement(); } @@ -527,27 +485,15 @@ long QuicklistView::PostLayoutManagement(long LayoutResult) int x = _padding + _anchor_width + _corner_radius + _offset_correction; int y = _padding + _corner_radius + _offset_correction; - std::list<QuicklistMenuItem*>::iterator it; - for (it = _item_list.begin(); it != _item_list.end(); it++) + for (auto item : _item_list) { - if (!(*it)->GetVisible()) + if (!item->GetVisible()) continue; - (*it)->SetBaseX(x); - (*it)->SetBaseY(y); + item->SetBaseX(x); + item->SetBaseY(y); - y += (*it)->GetBaseHeight(); - } - - for (it = _default_item_list.begin(); it != _default_item_list.end(); it++) - { - if (!(*it)->GetVisible()) - continue; - - (*it)->SetBaseX(x); - (*it)->SetBaseY(y); - - y += (*it)->GetBaseHeight(); + y += item->GetBaseHeight(); } // We must correct the width of line separators. The rendering of the separator can be smaller than the width of the @@ -555,21 +501,10 @@ long QuicklistView::PostLayoutManagement(long LayoutResult) // only after MaxItemWidth is computed in QuicklistView::PreLayoutManagement. // The setting of the separator width is done here after the Layout cycle for this widget is over. The width of the separator // has bee set correctly during the layout cycle, but the cairo rendering still need to be adjusted. - int separator_width = nux::Max<int>(_default_item_layout->GetBaseWidth(), _item_layout->GetBaseWidth()); - - for (it = _item_list.begin(); it != _item_list.end(); it++) - { - QuicklistMenuItem* item = (QuicklistMenuItem*)(*it); - if (item->GetVisible() && item->CairoSurfaceWidth() != separator_width) - { - // Compute textures of the item. - item->UpdateTexture(); - } - } + int separator_width = _item_layout->GetBaseWidth(); - for (it = _default_item_list.begin(); it != _default_item_list.end(); it++) + for (auto item : _item_list) { - QuicklistMenuItem* item = (QuicklistMenuItem*)(*it); if (item->GetVisible() && item->CairoSurfaceWidth() != separator_width) { // Compute textures of the item. @@ -605,41 +540,31 @@ void QuicklistView::RecvItemMouseClick(QuicklistMenuItem* item, int x, int y) void QuicklistView::CheckAndEmitItemSignal(int x, int y) { nux::Geometry geo; - std::list<QuicklistMenuItem*>::iterator it; - for (it = _item_list.begin(); it != _item_list.end(); it++) + for (auto item : _item_list) { - if (!(*it)->GetVisible()) + if (!item->GetVisible()) continue; - geo = (*it)->GetGeometry(); + geo = item->GetGeometry(); geo.width = _item_layout->GetBaseWidth(); if (geo.IsPointInside(x, y)) { // An action is performed: send the signal back to the application - if ((*it)->_menuItem) - { - dbusmenu_menuitem_handle_event((*it)->_menuItem, "clicked", NULL, 0); - } + ActivateItem(item); } } +} - for (it = _default_item_list.begin(); it != _default_item_list.end(); it++) +void QuicklistView::ActivateItem(QuicklistMenuItem* item) +{ + if (item && item->_menuItem) { - if (!(*it)->GetVisible()) - continue; - - geo = (*it)->GetGeometry(); - geo.width = _default_item_layout->GetBaseWidth(); + ubus_server_send_message(ubus_server_get_default(), + UBUS_PLACE_VIEW_CLOSE_REQUEST, + NULL); - if (geo.IsPointInside(x, y)) - { - // An action is performed: send the signal back to the application - if ((*it)->_menuItem) - { - dbusmenu_menuitem_handle_event((*it)->_menuItem, "clicked", NULL, 0); - } - } + dbusmenu_menuitem_handle_event(item->_menuItem, "clicked", NULL, 0); } } @@ -659,30 +584,23 @@ void QuicklistView::RecvItemMouseRelease(QuicklistMenuItem* item, int x, int y) void QuicklistView::CancelItemsPrelightStatus() { - std::list<QuicklistMenuItem*>::iterator it; - for (it = _item_list.begin(); it != _item_list.end(); it++) + for (auto item : _item_list) { - (*it)->_prelight = false; - } - - for (it = _default_item_list.begin(); it != _default_item_list.end(); it++) - { - (*it)->_prelight = false; + item->_prelight = false; } } void QuicklistView::RecvItemMouseDrag(QuicklistMenuItem* item, int x, int y) { nux::Geometry geo; - - for (auto it : _item_list) + for (auto item : _item_list) { - int item_index = GetItemIndex(it); + int item_index = GetItemIndex(item); if (!IsMenuItemSelectable(item_index)) continue; - geo = it->GetGeometry(); + geo = item->GetGeometry(); geo.width = _item_layout->GetBaseWidth(); if (geo.IsPointInside(x + item->GetBaseX(), y + item->GetBaseY())) @@ -690,22 +608,6 @@ void QuicklistView::RecvItemMouseDrag(QuicklistMenuItem* item, int x, int y) SelectItem(item_index); } } - - for (auto it : _default_item_list) - { - int item_index = GetItemIndex(it); - - if (!IsMenuItemSelectable(item_index)) - continue; - - geo = it->GetGeometry(); - geo.width = _default_item_layout->GetBaseWidth(); - - if (geo.IsPointInside(x + item->GetBaseX(), y + item->GetBaseY())) - { - SelectItem(item_index); - } - } } void QuicklistView::RecvItemMouseEnter(QuicklistMenuItem* item) @@ -765,26 +667,17 @@ void QuicklistView::RecvMouseDownOutsideOfQuicklist(int x, int y, unsigned long void QuicklistView::RemoveAllMenuItem() { - std::list<QuicklistMenuItem*>::iterator it; - for (it = _item_list.begin(); it != _item_list.end(); it++) + for (auto item : _item_list) { // Remove from introspection - RemoveChild(*it); - (*it)->UnReference(); + RemoveChild(item); + item->UnReference(); } - for (it = _default_item_list.begin(); it != _default_item_list.end(); it++) - { - // Remove from introspection - RemoveChild(*it); - (*it)->UnReference(); - } _item_list.clear(); - _default_item_list.clear(); _item_layout->Clear(); - _default_item_layout->Clear(); _cairo_text_has_changed = true; nux::GetWindowThread()->QueueObjectLayout(this); } @@ -819,7 +712,7 @@ void QuicklistView::RenderQuicklistView() int QuicklistView::GetNumItems() { - return _item_list.size() + _default_item_list.size(); + return _item_list.size(); } QuicklistMenuItem* QuicklistView::GetNthItems(int index) @@ -827,24 +720,10 @@ QuicklistMenuItem* QuicklistView::GetNthItems(int index) if (index < (int)_item_list.size()) { int i = 0; - std::list<QuicklistMenuItem*>::iterator it; - for (i = 0, it = _item_list.begin(); it != _item_list.end(); i++, it++) + for (auto item : _item_list) { - if (i == index) - return *it; - } - } - - if (index < (int)_item_list.size() + (int)_default_item_list.size()) - { - int i = 0; - if (_item_list.size() > 0) - i = _item_list.size() - 1; - std::list<QuicklistMenuItem*>::iterator it; - for (it = _default_item_list.begin(); it != _default_item_list.end(); i++, it++) - { - if (i == index) - return *it; + if (i++ == index) + return item; } } @@ -863,14 +742,6 @@ int QuicklistView::GetItemIndex(QuicklistMenuItem* item) return index; } - for (auto it : _default_item_list) - { - ++index; - - if (it == item) - return index; - } - return index; } @@ -1304,7 +1175,7 @@ void QuicklistView::UpdateTexture() if (!_enable_quicklist_for_testing) { - if (!_item_list.empty() || !_default_item_list.empty()) + if (!_item_list.empty()) { int offscreen_size = GetBaseY() + height - @@ -1500,7 +1371,7 @@ QuicklistView::GetSelectedMenuItem() return GetNthItems(_current_item_index); } -debug::Introspectable::IntrospectableList const& QuicklistView::GetIntrospectableChildren() +debug::Introspectable::IntrospectableList QuicklistView::GetIntrospectableChildren() { _introspectable_children.clear(); for (auto item: _item_list) diff --git a/launcher/QuicklistView.h b/launcher/QuicklistView.h index 49674aa33..6f2cac675 100644 --- a/launcher/QuicklistView.h +++ b/launcher/QuicklistView.h @@ -25,7 +25,7 @@ #include <Nux/BaseWindow.h> #include <NuxGraphics/GraphicsEngine.h> #include <Nux/TextureArea.h> -#include <NuxImage/CairoGraphics.h> +#include <NuxGraphics/CairoGraphics.h> #include <pango/pango.h> #include <pango/pangocairo.h> @@ -71,7 +71,7 @@ public: // Introspection std::string GetName() const; void AddProperties(GVariantBuilder* builder); - IntrospectableList const& GetIntrospectableChildren(); + IntrospectableList GetIntrospectableChildren(); void EnableQuicklistForTesting(bool enable_testing); @@ -131,6 +131,8 @@ private: //! Check the mouse up event sent by an item. Detect the item where the mous is and emit the appropriate signal. void CheckAndEmitItemSignal(int x, int y); + void ActivateItem(QuicklistMenuItem* item); + void SelectItem(int index); bool IsMenuItemSelectable(int index); @@ -157,7 +159,6 @@ private: nux::HLayout* _hlayout; nux::VLayout* _vlayout; nux::VLayout* _item_layout; - nux::VLayout* _default_item_layout; nux::SpaceLayout* _left_space; //!< Space from the left of the widget to the left of the text. nux::SpaceLayout* _right_space; //!< Space from the right of the text to the right of the widget. nux::SpaceLayout* _top_space; //!< Space from the left of the widget to the left of the text. @@ -166,7 +167,6 @@ private: bool _cairo_text_has_changed; void UpdateTexture(); std::list<QuicklistMenuItem*> _item_list; - std::list<QuicklistMenuItem*> _default_item_list; // used by keyboard/a11y-navigation int _current_item_index; diff --git a/launcher/SwitcherController.cpp b/launcher/SwitcherController.cpp index f96bd6040..f91289d47 100644 --- a/launcher/SwitcherController.cpp +++ b/launcher/SwitcherController.cpp @@ -159,8 +159,11 @@ void Controller::ShowView() ConstructView(); + ubus_manager_.SendMessage(UBUS_SWITCHER_START, NULL); + if (view_window_) { view_window_->ShowWindow(true); + view_window_->PushToFront(); view_window_->SetOpacity(1.0f); } } @@ -179,6 +182,7 @@ void Controller::ConstructWindow() view_window_->SetLayout(main_layout_); view_window_->SetBackgroundColor(nux::Color(0x00000000)); view_window_->SetGeometry(workarea_); + view_window_->EnableInputWindow(true, "Switcher", false, false); } } @@ -240,6 +244,8 @@ void Controller::Hide(bool accept_state) } } + ubus_manager_.SendMessage(UBUS_SWITCHER_END, g_variant_new_boolean(!accept_state)); + sources_.Remove(VIEW_CONSTRUCT_IDLE); sources_.Remove(SHOW_TIMEOUT); sources_.Remove(DETAIL_TIMEOUT); @@ -254,6 +260,8 @@ void Controller::Hide(bool accept_state) { view_window_->SetOpacity(0.0f); view_window_->ShowWindow(false); + view_window_->PushToBack(); + view_window_->EnableInputWindow(false); } ubus_manager_.SendMessage(UBUS_SWITCHER_SHOWN, g_variant_new("(bi)", false, monitor_)); @@ -385,6 +393,11 @@ LayoutWindowList Controller::ExternalRenderTargets() return view_->ExternalTargets(); } +guint Controller::GetSwitcherInputWindowId() const +{ + return view_window_->GetInputWindowId(); +} + bool Controller::CompareSwitcherItemsPriority(AbstractLauncherIcon::Ptr first, AbstractLauncherIcon::Ptr second) { diff --git a/launcher/SwitcherController.h b/launcher/SwitcherController.h index 32f385f27..5f8015c36 100644 --- a/launcher/SwitcherController.h +++ b/launcher/SwitcherController.h @@ -90,6 +90,8 @@ public: ui::LayoutWindowList ExternalRenderTargets (); + guint GetSwitcherInputWindowId() const; + protected: // Introspectable methods std::string GetName() const; diff --git a/launcher/SwitcherModel.cpp b/launcher/SwitcherModel.cpp index e3c26f138..600c2fea8 100644 --- a/launcher/SwitcherModel.cpp +++ b/launcher/SwitcherModel.cpp @@ -171,7 +171,7 @@ SwitcherModel::DetailSelectionWindow () if (detail_selection_index > DetailXids().size() - 1) return 0; - + return DetailXids()[detail_selection_index]; } diff --git a/panel/PanelController.cpp b/panel/PanelController.cpp index f947fe74b..460a61ee8 100644 --- a/panel/PanelController.cpp +++ b/panel/PanelController.cpp @@ -49,6 +49,7 @@ public: void QueueRedraw(); std::vector<Window> GetTrayXids() const; + std::vector<nux::View*> GetPanelViews() const; std::vector<nux::Geometry> GetGeometries() const; // NOTE: nux::Property maybe? @@ -106,6 +107,15 @@ std::vector<Window> Controller::Impl::GetTrayXids() const return xids; } +std::vector<nux::View*> Controller::Impl::GetPanelViews() const +{ + std::vector<nux::View*> views; + views.reserve(windows_.size()); + for (auto window: windows_) + views.push_back(ViewForWindow(window)); + return views; +} + std::vector<nux::Geometry> Controller::Impl::GetGeometries() const { std::vector<nux::Geometry> geometries; @@ -325,6 +335,11 @@ std::vector<Window> Controller::GetTrayXids() const return pimpl->GetTrayXids(); } +std::vector<nux::View*> Controller::GetPanelViews() const +{ + return pimpl->GetPanelViews(); +} + std::vector<nux::Geometry> Controller::GetGeometries() const { return pimpl->GetGeometries(); diff --git a/panel/PanelController.h b/panel/PanelController.h index 282d232eb..2c8a9c1bc 100644 --- a/panel/PanelController.h +++ b/panel/PanelController.h @@ -41,6 +41,7 @@ public: void QueueRedraw(); std::vector<Window> GetTrayXids() const; + std::vector<nux::View*> GetPanelViews() const; std::vector<nux::Geometry> GetGeometries() const; // NOTE: nux::Property maybe? diff --git a/panel/PanelIndicatorEntryView.h b/panel/PanelIndicatorEntryView.h index 949e8681c..dcf3dd5a0 100644 --- a/panel/PanelIndicatorEntryView.h +++ b/panel/PanelIndicatorEntryView.h @@ -23,7 +23,7 @@ #include <Nux/TextureArea.h> #include <Nux/View.h> -#include <NuxImage/CairoGraphics.h> +#include <NuxGraphics/CairoGraphics.h> #include <NuxGraphics/GraphicsEngine.h> #include <UnityCore/IndicatorEntry.h> diff --git a/panel/PanelView.cpp b/panel/PanelView.cpp index 3ced1322f..14f24752d 100644 --- a/panel/PanelView.cpp +++ b/panel/PanelView.cpp @@ -24,8 +24,8 @@ #include <Nux/Layout.h> #include <Nux/WindowCompositor.h> -#include <NuxImage/CairoGraphics.h> -#include <NuxImage/ImageSurface.h> +#include <NuxGraphics/CairoGraphics.h> +#include <NuxGraphics/ImageSurface.h> #include <NuxCore/Logger.h> #include <UnityCore/GLibWrapper.h> diff --git a/panel/PanelView.h b/panel/PanelView.h index 8f45ec884..9dac92ea1 100644 --- a/panel/PanelView.h +++ b/panel/PanelView.h @@ -26,7 +26,7 @@ #include <Nux/View.h> #include <Nux/TextureArea.h> #include <NuxGraphics/GraphicsEngine.h> -#include <NuxImage/CairoGraphics.h> +#include <NuxGraphics/CairoGraphics.h> #include <gdk/gdkx.h> #include <UnityCore/DBusIndicators.h> diff --git a/panel/WindowButtons.cpp b/panel/WindowButtons.cpp index d7bcd32f3..9788989bf 100644 --- a/panel/WindowButtons.cpp +++ b/panel/WindowButtons.cpp @@ -506,7 +506,7 @@ void WindowButtons::OnOverlayShown(GVariant* data) glib::String overlay_identity; gboolean can_maximise = FALSE; gint32 overlay_monitor = 0; - g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING, + g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING, &overlay_identity, &can_maximise, &overlay_monitor); if (overlay_monitor != monitor_) @@ -539,6 +539,9 @@ void WindowButtons::OnOverlayShown(GVariant* data) if (button->GetType() == panel::WindowButtonType::MAXIMIZE) maximize_button = button; + if (button->GetType() == panel::WindowButtonType::MINIMIZE) + button->SetEnabled(false); + button->SetOverlayOpen(true); } } @@ -574,7 +577,7 @@ void WindowButtons::OnOverlayHidden(GVariant* data) glib::String overlay_identity; gboolean can_maximise = FALSE; gint32 overlay_monitor = 0; - g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING, + g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING, &overlay_identity, &can_maximise, &overlay_monitor); if (overlay_monitor != monitor_) diff --git a/plugins/unity-mt-grab-handles/CMakeLists.txt b/plugins/unity-mt-grab-handles/CMakeLists.txt index 9e5a65f4a..3020cf6a3 100644 --- a/plugins/unity-mt-grab-handles/CMakeLists.txt +++ b/plugins/unity-mt-grab-handles/CMakeLists.txt @@ -2,4 +2,4 @@ find_package (Compiz REQUIRED) include (CompizPlugin) -compiz_plugin (unitymtgrabhandles PKGDEPS nux-2.0>=2.0.0 PLUGINDEPS composite opengl CFLAGSADD -std=c++0x) +compiz_plugin (unitymtgrabhandles PKGDEPS nux-3.0>=3.0.0 PLUGINDEPS composite opengl CFLAGSADD -std=c++0x) diff --git a/plugins/unityshell/src/DebugDBusInterface.cpp b/plugins/unityshell/src/DebugDBusInterface.cpp index 9d7a24971..42e55de39 100644 --- a/plugins/unityshell/src/DebugDBusInterface.cpp +++ b/plugins/unityshell/src/DebugDBusInterface.cpp @@ -60,13 +60,17 @@ const char* DebugDBusInterface::DBUS_DEBUG_OBJECT_PATH = "/com/canonical/Unity/D const gchar DebugDBusInterface::introspection_xml[] = " <node>" - " <interface name='com.canonical.Unity.Debug.Introspection'>" + " <interface name='com.canonical.Autopilot.Introspection'>" "" " <method name='GetState'>" " <arg type='s' name='piece' direction='in' />" - " <arg type='aa{sv}' name='state' direction='out' />" + " <arg type='a(sv)' name='state' direction='out' />" " </method>" "" + " </interface>" + "" + " <interface name='com.canonical.Unity.Debug.Logging'>" + "" " <method name='StartLogToFile'>" " <arg type='s' name='file_path' direction='in' />" " </method>" @@ -223,14 +227,17 @@ GVariant* GetState(std::string const& query) // process the XPath query: std::list<Introspectable*> parts = GetIntrospectableNodesFromQuery(query, _parent_introspectable); GVariantBuilder builder; - g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}")); - + g_variant_builder_init(&builder, G_VARIANT_TYPE("a(sv)")); + if (parts.empty()) + { + LOG_WARNING(logger) << "Query '" << query << "' Did not match anything."; + } for (Introspectable *node : parts) { - g_variant_builder_add_value(&builder, node->Introspect()); + g_variant_builder_add(&builder, "(sv)", node->GetName().c_str(), node->Introspect()); } - return g_variant_new("(aa{sv})", &builder); + return g_variant_new("(a(sv))", &builder); } void StartLogToFile(std::string const& file_path) diff --git a/plugins/unityshell/src/XPathQueryPart.cpp b/plugins/unityshell/src/XPathQueryPart.cpp index cf3026733..a42a65c34 100644 --- a/plugins/unityshell/src/XPathQueryPart.cpp +++ b/plugins/unityshell/src/XPathQueryPart.cpp @@ -41,12 +41,12 @@ XPathQueryPart::XPathQueryPart(std::string const& query_part) { std::vector<std::string> part_pieces; boost::algorithm::split(part_pieces, query_part, boost::algorithm::is_any_of("[]=")); - // Boost's split() implementation does not match it's documentation! According to the - // docs, it's not supposed to add empty strings, but it does, which is a PITA. This + // Boost's split() implementation does not match it's documentation! According to the + // docs, it's not supposed to add empty strings, but it does, which is a PITA. This // next line removes them: - part_pieces.erase( std::remove_if( part_pieces.begin(), - part_pieces.end(), - boost::bind( &std::string::empty, _1 ) ), + part_pieces.erase( std::remove_if( part_pieces.begin(), + part_pieces.end(), + boost::bind( &std::string::empty, _1 ) ), part_pieces.end()); if (part_pieces.size() == 1) { @@ -71,7 +71,7 @@ bool XPathQueryPart::Matches(Introspectable* node) const bool matches = false; if (param_name_ == "") { - matches = node->GetName() == node_name_; + matches = (node_name_ == "*" || node->GetName() == node_name_); } else { @@ -85,9 +85,9 @@ bool XPathQueryPart::Matches(Introspectable* node) const if (prop_value != NULL) { GVariantClass prop_val_type = g_variant_classify(prop_value); - // it'd be nice to be able to do all this with one method. However, the booleans need + // it'd be nice to be able to do all this with one method. However, the booleans need // special treatment, and I can't figure out how to group all the integer types together - // without resorting to template functions.... and we all know what happens when you + // without resorting to template functions.... and we all know what happens when you // start doing that... switch (prop_val_type) { @@ -116,7 +116,7 @@ bool XPathQueryPart::Matches(Introspectable* node) const std::stringstream stream(param_value_); int val; // changing this to guchar causes problems. stream >> val; - matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && + matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && val == g_variant_get_byte(prop_value); } break; @@ -125,7 +125,7 @@ bool XPathQueryPart::Matches(Introspectable* node) const std::stringstream stream(param_value_); gint16 val; stream >> val; - matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && + matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && val == g_variant_get_int16(prop_value); } break; @@ -134,8 +134,8 @@ bool XPathQueryPart::Matches(Introspectable* node) const std::stringstream stream(param_value_); guint16 val; stream >> val; - matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && - val == g_variant_get_uint16(prop_value); + matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && + val == g_variant_get_uint16(prop_value); } break; case G_VARIANT_CLASS_INT32: @@ -143,7 +143,7 @@ bool XPathQueryPart::Matches(Introspectable* node) const std::stringstream stream(param_value_); gint32 val; stream >> val; - matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && + matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && val == g_variant_get_int32(prop_value); } break; @@ -152,7 +152,7 @@ bool XPathQueryPart::Matches(Introspectable* node) const std::stringstream stream(param_value_); guint32 val; stream >> val; - matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && + matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && val == g_variant_get_uint32(prop_value); } break; @@ -161,7 +161,7 @@ bool XPathQueryPart::Matches(Introspectable* node) const std::stringstream stream(param_value_); gint64 val; stream >> val; - matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && + matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && val == g_variant_get_int64(prop_value); } break; @@ -170,7 +170,7 @@ bool XPathQueryPart::Matches(Introspectable* node) const std::stringstream stream(param_value_); guint64 val; stream >> val; - matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && + matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && val == g_variant_get_uint64(prop_value); } break; diff --git a/plugins/unityshell/src/compizminimizedwindowhandler.h b/plugins/unityshell/src/compizminimizedwindowhandler.h index a53e9f815..4befd16f0 100644 --- a/plugins/unityshell/src/compizminimizedwindowhandler.h +++ b/plugins/unityshell/src/compizminimizedwindowhandler.h @@ -104,6 +104,7 @@ compiz::CompizMinimizedWindowHandler<Screen, Window>::CompizMinimizedWindowHandl template <typename Screen, typename Window> compiz::CompizMinimizedWindowHandler<Screen, Window>::~CompizMinimizedWindowHandler () { + minimizingWindows.remove (priv->mWindow); minimizedWindows.remove (this); } diff --git a/plugins/unityshell/src/unityshell.cpp b/plugins/unityshell/src/unityshell.cpp index bd273603f..169b5224f 100644 --- a/plugins/unityshell/src/unityshell.cpp +++ b/plugins/unityshell/src/unityshell.cpp @@ -100,7 +100,6 @@ const unsigned int SCROLL_DOWN_BUTTON = 6; const unsigned int SCROLL_UP_BUTTON = 7; const std::string RELAYOUT_TIMEOUT = "relayout-timeout"; -const std::string REDRAW_IDLE = "redraw-idle"; } // namespace local } // anon namespace @@ -118,6 +117,7 @@ UnityScreen::UnityScreen(CompScreen* screen) , super_keypressed_(false) , newFocusedWindow(nullptr) , doShellRepaint(false) + , didShellRepaint(false) , allowWindowPaint(false) , damaged(false) , _key_nav_mode_requested(false) @@ -131,6 +131,7 @@ UnityScreen::UnityScreen(CompScreen* screen) , hud_keypress_time_(0) , panel_texture_has_changed_(true) , paint_panel_(false) + , scale_just_activated_(false) { Timer timer; gfloat version; @@ -353,6 +354,12 @@ UnityScreen::UnityScreen(CompScreen* screen) ubus_manager_.RegisterInterest(UBUS_LAUNCHER_END_KEY_SWTICHER, sigc::mem_fun(this, &UnityScreen::OnLauncherEndKeyNav)); + ubus_manager_.RegisterInterest(UBUS_SWITCHER_START, + sigc::mem_fun(this, &UnityScreen::OnSwitcherStart)); + + ubus_manager_.RegisterInterest(UBUS_SWITCHER_END, + sigc::mem_fun(this, &UnityScreen::OnSwitcherEnd)); + auto init_plugins_cb = sigc::mem_fun(this, &UnityScreen::initPluginActions); sources_.Add(std::make_shared<glib::Idle>(init_plugins_cb, glib::Source::Priority::DEFAULT)); @@ -902,6 +909,7 @@ void UnityScreen::paintDisplay(const CompRegion& region, const GLMatrix& transfo } doShellRepaint = false; + didShellRepaint = true; damaged = false; } @@ -1204,7 +1212,15 @@ bool UnityScreen::glPaintOutput(const GLScreenPaintAttrib& attrib, { bool ret; - doShellRepaint = true; + /* + * Very important! + * Don't waste GPU and CPU rendering the shell on every frame if you don't + * need to. Doing so on every frame causes Nux to hog the GPU and slow down + * ALL rendering. (LP: #988079) + */ + bool force = forcePaintOnTop() || PluginAdapter::Default()->IsExpoActive(); + doShellRepaint = force || !(region.isEmpty() || wt->GetDrawList().empty()); + allowWindowPaint = true; _last_output = output; paint_panel_ = false; @@ -1220,13 +1236,21 @@ bool UnityScreen::glPaintOutput(const GLScreenPaintAttrib& attrib, * attempts to bind it will only increment * its bind reference so make sure that * you always unbind as much as you bind */ - _fbo->bind (nux::Geometry (output->x (), output->y (), output->width (), output->height ())); + if (doShellRepaint) + _fbo->bind (nux::Geometry (output->x (), output->y (), output->width (), output->height ())); #endif + // CompRegion has no clear() method. So this is the fastest alternative. + aboveShell = CompRegion(); + nuxRegion = CompRegion(); + /* glPaintOutput is part of the opengl plugin, so we need the GLScreen base class. */ ret = gScreen->glPaintOutput(attrib, transform, region, output, mask); #ifndef USE_MODERN_COMPIZ_GL + if (doShellRepaint && !force && aboveShell.contains(*output)) + doShellRepaint = false; + if (doShellRepaint) paintDisplay(region, transform, mask); #endif @@ -1279,16 +1303,32 @@ void UnityScreen::preparePaint(int ms) for (ShowdesktopHandlerWindowInterface *wi : ShowdesktopHandler::animating_windows) wi->HandleAnimations (ms); + // Workaround Nux bug LP: #1014610: if (damaged) { damaged = false; - damageNuxRegions(); + nuxDamageCompiz(); } + compizDamageNux(cScreen->currentDamage()); + + didShellRepaint = false; } void UnityScreen::donePaint() { + /* + * It's only safe to clear the draw list if drawing actually occurred + * (i.e. the shell was not obscured behind a fullscreen window). + * If you clear the draw list and drawing has not occured then you'd be + * left with all your views thinking they're queued for drawing still and + * would refuse to redraw when you return from fullscreen. + * I think this is a Nux bug. ClearDrawList should ideally also mark all + * the queued views as draw_cmd_queued_=false. + */ + if (didShellRepaint) + wt->ClearDrawList(); + std::list <ShowdesktopHandlerWindowInterface *> remove_windows; for (ShowdesktopHandlerWindowInterface *wi : ShowdesktopHandler::animating_windows) @@ -1309,42 +1349,100 @@ void UnityScreen::donePaint() cScreen->donePaint (); } -/* Grab changed nux regions and add damage rects for them */ -void UnityScreen::damageNuxRegions() +void UnityScreen::compizDamageNux(CompRegion const& damage) { - CompRegion nux_damage; - - if (damaged) + if (!launcher_controller_) return; - std::vector<nux::Geometry> dirty = wt->GetDrawList(); + CompRect::vector const& rects(damage.rects()); + for (const CompRect &r : rects) + { + nux::Geometry geo(r.x(), r.y(), r.width(), r.height()); + BackgroundEffectHelper::ProcessDamage(geo); + } + + auto launchers = launcher_controller_->launchers(); + for (auto launcher : launchers) + { + if (!launcher->Hidden()) + { + nux::Geometry geo = launcher->GetAbsoluteGeometry(); + CompRegion launcher_region(geo.x, geo.y, geo.width, geo.height); + if (damage.intersects(launcher_region)) + launcher->QueueDraw(); + nux::ObjectPtr<nux::View> tooltip = launcher->GetActiveTooltip(); + if (!tooltip.IsNull()) + { + nux::Geometry tip = tooltip->GetAbsoluteGeometry(); + CompRegion tip_region(tip.x, tip.y, tip.width, tip.height); + if (damage.intersects(tip_region)) + tooltip->QueueDraw(); + } + } + } + + std::vector<nux::View*> const& panels(panel_controller_->GetPanelViews()); + for (nux::View* view : panels) + { + nux::Geometry geo = view->GetAbsoluteGeometry(); + CompRegion panel_region(geo.x, geo.y, geo.width, geo.height); + if (damage.intersects(panel_region)) + view->QueueDraw(); + } + + QuicklistManager* qm = QuicklistManager::Default(); + if (qm) + { + QuicklistView* view = qm->Current(); + if (view) + { + nux::Geometry geo = view->GetAbsoluteGeometry(); + CompRegion quicklist_region(geo.x, geo.y, geo.width, geo.height); + if (damage.intersects(quicklist_region)) + view->QueueDraw(); + } + } +} + +/* Grab changed nux regions and add damage rects for them */ +void UnityScreen::nuxDamageCompiz() +{ + // Workaround Nux bug LP: #1014610 (unbounded DrawList growth) + // Also, ensure we don't dereference null *controller_ on startup. + if (damaged || !launcher_controller_ || !dash_controller_) + return; damaged = true; - for (std::vector<nux::Geometry>::iterator it = dirty.begin(), end = dirty.end(); - it != end; ++it) + CompRegion nux_damage; + + std::vector<nux::Geometry> const& dirty = wt->GetDrawList(); + for (auto geo : dirty) + nux_damage += CompRegion(geo.x, geo.y, geo.width, geo.height); + + if (launcher_controller_->IsOverlayOpen()) { - nux::Geometry const& geo = *it; + nux::BaseWindow* dash_window = dash_controller_->window(); + nux::Geometry const& geo = dash_window->GetAbsoluteGeometry(); nux_damage += CompRegion(geo.x, geo.y, geo.width, geo.height); } - nux::Geometry geo = wt->GetWindowCompositor().GetTooltipMainWindowGeometry(); - nux_damage += CompRegion(geo.x, geo.y, geo.width, geo.height); - - geo = lastTooltipArea; - nux_damage += CompRegion(lastTooltipArea.x, lastTooltipArea.y, - lastTooltipArea.width, lastTooltipArea.height); + auto launchers = launcher_controller_->launchers(); + for (auto launcher : launchers) + { + if (!launcher->Hidden()) + { + nux::ObjectPtr<nux::View> tooltip = launcher->GetActiveTooltip(); + if (!tooltip.IsNull()) + { + nux::Geometry const& g = tooltip->GetAbsoluteGeometry(); + nux_damage += CompRegion(g.x, g.y, g.width, g.height); + } + } + } - /* - * Avoid Nux damaging Nux as recommended by smspillaz. Though I don't - * believe it would be harmful or significantly expensive right now. - */ cScreen->damageRegionSetEnabled(this, false); cScreen->damageRegion(nux_damage); cScreen->damageRegionSetEnabled(this, true); - - wt->ClearDrawList(); - - lastTooltipArea = geo; } /* handle X Events */ @@ -1362,8 +1460,14 @@ void UnityScreen::handleEvent(XEvent* event) #ifndef USE_MODERN_COMPIZ_GL cScreen->damageScreen(); // evil hack #endif - if (_key_nav_mode_requested && !launcher_controller_->IsOverlayOpen()) + if (_key_nav_mode_requested) + { + if (launcher_controller_->IsOverlayOpen()) + { + dash_controller_->HideDash(); + } launcher_controller_->KeyNavGrab(); + } _key_nav_mode_requested = false; break; case ButtonPress: @@ -1394,6 +1498,19 @@ void UnityScreen::handleEvent(XEvent* event) break; case KeyPress: { + if (super_keypressed_) + { + /* We need an idle to postpone this action, after the current event + * has been processed */ + sources_.Add(std::make_shared<glib::Idle>([&]() { + shortcut_controller_->SetEnabled(false); + shortcut_controller_->Hide(); + EnableCancelAction(CancelActionTarget::SHORTCUT_HINT, false); + + return false; + })); + } + KeySym key_sym; char key_string[2]; int result = XLookupString(&(event->xkey), key_string, 2, &key_sym, 0); @@ -1421,21 +1538,6 @@ void UnityScreen::handleEvent(XEvent* event) if (super_keypressed_) { - if (key_sym != XK_Escape || (key_sym == XK_Escape && !launcher_controller_->KeyNavIsActive())) - { - /* We need an idle to postpone this action, after the current event - * has been processed */ - sources_.Add(std::make_shared<glib::Idle>([&]() { - if (!launcher_controller_->KeyNavIsActive()) - { - shortcut_controller_->SetEnabled(false); - shortcut_controller_->Hide(); - EnableCancelAction(CancelActionTarget::SHORTCUT_HINT, false); - } - return false; - })); - } - skip_other_plugins = launcher_controller_->HandleLauncherKeyEvent(screen->dpy(), key_sym, event->xkey.keycode, event->xkey.state, key_string); if (!skip_other_plugins) skip_other_plugins = dash_controller_->CheckShortcutActivation(key_string); @@ -1504,13 +1606,7 @@ void UnityScreen::handleEvent(XEvent* event) void UnityScreen::damageRegion(const CompRegion ®ion) { - const CompRect::vector &rects(region.rects()); - for (const CompRect &r : rects) - { - nux::Geometry geo(r.x(), r.y(), r.width(), r.height()); - BackgroundEffectHelper::ProcessDamage(geo); - } - + compizDamageNux(region); cScreen->damageRegion(region); } @@ -1526,6 +1622,11 @@ void UnityScreen::handleCompizEvent(const char* plugin, ubus_manager_.SendMessage(UBUS_PLACE_VIEW_CLOSE_REQUEST); } + if (PluginAdapter::Default()->IsScaleActive() && g_strcmp0(plugin, "scale") == 0) + { + scale_just_activated_ = true; + } + screen->handleCompizEvent(plugin, event, option); } @@ -1573,6 +1674,18 @@ bool UnityScreen::showLauncherKeyTerminate(CompAction* action, LOG_DEBUG(logger) << "Super released: " << (was_tap ? "tapped" : "released"); int when = options[7].value().i(); // XEvent time in millisec + // hack...if the scale just wasn't activated AND the 'when' time is within time to start the + // dash then assume was_tap is also true, since the ScalePlugin doesn't accept that state... + if (PluginAdapter::Default()->IsScaleActive() && !scale_just_activated_ && launcher_controller_->AboutToShowDash(true, when)) + { + PluginAdapter::Default()->TerminateScale(); + was_tap = true; + } + else if (scale_just_activated_) + { + scale_just_activated_ = false; + } + if (hud_controller_->IsVisible() && launcher_controller_->AboutToShowDash(was_tap, when)) hud_controller_->HideHud(); @@ -1629,6 +1742,12 @@ void UnityScreen::SendExecuteCommand() { hud_controller_->HideHud(); } + + if (PluginAdapter::Default()->IsScaleActive()) + { + PluginAdapter::Default()->TerminateScale(); + } + ubus_manager_.SendMessage(UBUS_PLACE_ENTRY_ACTIVATE_REQUEST, g_variant_new("(sus)", "commands.lens", 0, "")); } @@ -1641,26 +1760,6 @@ bool UnityScreen::executeCommand(CompAction* action, return true; } -void UnityScreen::startLauncherKeyNav() -{ - // get CompWindow* of launcher-window - newFocusedWindow = screen->findWindow(launcher_controller_->KeyNavLauncherInputWindowId()); - - // check if currently focused window isn't the launcher-window - if (newFocusedWindow != screen->findWindow(screen->activeWindow())) - PluginAdapter::Default()->saveInputFocus(); - - // set input-focus on launcher-window and start key-nav mode - if (newFocusedWindow) - { - // Put the launcher BaseWindow at the top of the BaseWindow stack. The - // input focus coming from the XinputWindow will be processed by the - // launcher BaseWindow only. Then the Launcher BaseWindow will decide - // which View will get the input focus. - launcher_controller_->PushToFront(); - newFocusedWindow->moveInputFocusTo(); - } -} bool UnityScreen::setKeyboardFocusKeyInitiate(CompAction* action, CompAction::State state, @@ -1904,11 +2003,31 @@ bool UnityScreen::launcherSwitcherTerminate(CompAction* action, CompAction::Stat void UnityScreen::OnLauncherStartKeyNav(GVariant* data) { - startLauncherKeyNav(); + // Put the launcher BaseWindow at the top of the BaseWindow stack. The + // input focus coming from the XinputWindow will be processed by the + // launcher BaseWindow only. Then the Launcher BaseWindow will decide + // which View will get the input focus. + if (SaveInputThenFocus(launcher_controller_->KeyNavLauncherInputWindowId())) + launcher_controller_->PushToFront(); } void UnityScreen::OnLauncherEndKeyNav(GVariant* data) { + RestoreWindow(data); +} + +void UnityScreen::OnSwitcherStart(GVariant* data) +{ + SaveInputThenFocus(switcher_controller_->GetSwitcherInputWindowId()); +} + +void UnityScreen::OnSwitcherEnd(GVariant* data) +{ + RestoreWindow(data); +} + +void UnityScreen::RestoreWindow(GVariant* data) +{ bool preserve_focus = false; if (data) @@ -1922,6 +2041,24 @@ void UnityScreen::OnLauncherEndKeyNav(GVariant* data) PluginAdapter::Default ()->restoreInputFocus (); } +bool UnityScreen::SaveInputThenFocus(const guint xid) +{ + // get CompWindow* + newFocusedWindow = screen->findWindow(xid); + + // check if currently focused window isn't it self + if (xid != screen->activeWindow()) + PluginAdapter::Default()->saveInputFocus(); + + // set input-focus on window + if (newFocusedWindow) + { + newFocusedWindow->moveInputFocusTo(); + return true; + } + return false; +} + bool UnityScreen::ShowHud() { if (switcher_controller_->Visible()) @@ -2122,14 +2259,6 @@ bool isNuxWindow (CompWindow* value) return false; } -const CompWindowList& UnityScreen::getWindowPaintList() -{ - CompWindowList& pl = _withRemovedNuxWindows = cScreen->getWindowPaintList(); - pl.remove_if(isNuxWindow); - - return pl; -} - void UnityScreen::RaiseInputWindows() { std::vector<Window> const& xwns = nux::XInputWindow::NativeHandleList(); @@ -2154,6 +2283,35 @@ bool UnityWindow::glPaint(const GLWindowPaintAttrib& attrib, const CompRegion& region, unsigned int mask) { + /* + * The occlusion pass tests windows from TOP to BOTTOM. That's opposite to + * the actual painting loop. + */ + if (isNuxWindow(window)) + { + if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK) + { + uScreen->nuxRegion += window->geometry(); + uScreen->nuxRegion -= uScreen->aboveShell; + } + return false; // Ensure nux windows are never painted by compiz + } + else if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK) + { + static const unsigned int nonOcclusionBits = + PAINT_WINDOW_TRANSLUCENT_MASK | + PAINT_WINDOW_TRANSFORMED_MASK | + PAINT_WINDOW_NO_CORE_INSTANCE_MASK; + if (!(mask & nonOcclusionBits)) + // And I've been advised to test other things, but they don't work: + // && (attrib.opacity == OPAQUE)) <-- Doesn't work; Only set in glDraw + // && !window->alpha() <-- Doesn't work; Opaque windows often have alpha + { + uScreen->aboveShell += window->geometry(); + uScreen->aboveShell -= uScreen->nuxRegion; + } + } + GLWindowPaintAttrib wAttrib = attrib; if (mMinimizeHandler) @@ -2212,7 +2370,17 @@ bool UnityWindow::glDraw(const GLMatrix& matrix, } } - if (uScreen->doShellRepaint && !uScreen->forcePaintOnTop ()) + /* + * Paint the shell in *roughly* the compiz stacking order. This is only + * approximate because we're painting all the nux windows as soon as we find + * the bottom-most nux window (from bottom to top). + * But remember to avoid painting the shell if it's within the aboveShell + * region. + */ + if (uScreen->doShellRepaint && + !uScreen->forcePaintOnTop () && + !uScreen->aboveShell.contains(window->geometry()) + ) { std::vector<Window> const& xwns = nux::XInputWindow::NativeHandleList(); unsigned int size = xwns.size(); @@ -2527,25 +2695,7 @@ void UnityScreen::initUnity(nux::NThread* thread, void* InitData) void UnityScreen::onRedrawRequested() { - // disable blur updates so we dont waste perf. This can stall the blur during animations - // but ensures a smooth animation. - if (_in_paint) - { - if (!sources_.GetSource(local::REDRAW_IDLE)) - { - auto redraw_idle(std::make_shared<glib::Idle>(glib::Source::Priority::DEFAULT)); - sources_.Add(redraw_idle, local::REDRAW_IDLE); - - redraw_idle->Run([&]() { - onRedrawRequested(); - return false; - }); - } - } - else - { - damageNuxRegions(); - } + nuxDamageCompiz(); } /* Handle option changes and plug that into nux windows */ diff --git a/plugins/unityshell/src/unityshell.h b/plugins/unityshell/src/unityshell.h index a93e570ff..eb0851515 100644 --- a/plugins/unityshell/src/unityshell.h +++ b/plugins/unityshell/src/unityshell.h @@ -133,9 +133,6 @@ public: CompOutput*, unsigned int); - /* Pop our InputOutput windows from the paint list */ - const CompWindowList& getWindowPaintList(); - /* handle X11 events */ void handleEvent(XEvent*); @@ -212,7 +209,10 @@ private: bool initPluginActions(); void initLauncher(); - void damageNuxRegions(); + + void compizDamageNux(CompRegion const& region); + void nuxDamageCompiz(); + void onRedrawRequested(); void Relayout(); @@ -220,7 +220,6 @@ private: static void OnStartKeyNav(GVariant* data, void* value); static void OnExitKeyNav(GVariant* data, void* value); - void startLauncherKeyNav(); void restartLauncherKeyNav(); void OnDashRealized (); @@ -228,6 +227,12 @@ private: void OnLauncherStartKeyNav(GVariant* data); void OnLauncherEndKeyNav(GVariant* data); + void OnSwitcherStart(GVariant* data); + void OnSwitcherEnd(GVariant* data); + + void RestoreWindow(GVariant* data); + bool SaveInputThenFocus(const guint xid); + void InitHints(); void OnPanelStyleChanged(); @@ -255,7 +260,6 @@ private: bool enable_shortcut_overlay_; GestureEngine gesture_engine_; - nux::Geometry lastTooltipArea; bool needsRelayout; bool _in_paint; bool super_keypressed_; @@ -272,11 +276,14 @@ private: /* handle paint order */ bool doShellRepaint; + bool didShellRepaint; bool allowWindowPaint; bool damaged; bool _key_nav_mode_requested; CompOutput* _last_output; - CompWindowList _withRemovedNuxWindows; + + CompRegion nuxRegion; + CompRegion aboveShell; nux::Property<nux::Geometry> primary_monitor_; @@ -306,6 +313,8 @@ private: bool paint_panel_; nux::ObjectPtr<nux::IOpenGLBaseTexture> panel_texture_; + bool scale_just_activated_; + #ifndef USE_MODERN_COMPIZ_GL ScreenEffectFramebufferObject::GLXGetProcAddressProc glXGetProcAddressP; #endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 894bdcf4c..0cea996e3 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -209,6 +209,7 @@ if (GTEST_SRC_DIR AND test_icon_loader.cpp test_im_text_entry.cpp test_hud_view.cpp + test_keyboard_util.cpp test_resultviewgrid.cpp test_single_monitor_launcher_icon.cpp test_switcher_controller.cpp @@ -270,6 +271,7 @@ if (GTEST_SRC_DIR AND ${CMAKE_SOURCE_DIR}/unity-shared/Introspectable.cpp ${CMAKE_SOURCE_DIR}/unity-shared/IntrospectableWrappers.cpp ${CMAKE_SOURCE_DIR}/unity-shared/JSONParser.cpp + ${CMAKE_SOURCE_DIR}/unity-shared/KeyboardUtil.cpp ${CMAKE_SOURCE_DIR}/unity-shared/OverlayRenderer.cpp ${CMAKE_SOURCE_DIR}/unity-shared/PanelStyle.cpp ${CMAKE_SOURCE_DIR}/unity-shared/PluginAdapterStandalone.cpp diff --git a/tests/autopilot/unity/emulators/__init__.py b/tests/autopilot/unity/emulators/__init__.py index 1f7b6e36f..48f4966a5 100644 --- a/tests/autopilot/unity/emulators/__init__.py +++ b/tests/autopilot/unity/emulators/__init__.py @@ -8,3 +8,12 @@ # """A collection of Unity-specific emulators.""" + + +from autopilot.introspection.dbus import DBusIntrospectionObject + + +class UnityIntrospectionObject(DBusIntrospectionObject): + + DBUS_SERVICE = "com.canonical.Unity" + DBUS_OBJECT = "/com/canonical/Unity/Debug" diff --git a/tests/autopilot/unity/emulators/dash.py b/tests/autopilot/unity/emulators/dash.py index 807886a34..f7d315b65 100644 --- a/tests/autopilot/unity/emulators/dash.py +++ b/tests/autopilot/unity/emulators/dash.py @@ -9,14 +9,11 @@ from __future__ import absolute_import -from autopilot.introspection.unity import ( - get_state_by_path, - make_introspection_object, - UnityIntrospectionObject, - ) +from autopilot.introspection.dbus import make_introspection_object from autopilot.emulators.X11 import Keyboard, Mouse from autopilot.keybindings import KeybindingsHelper +from unity.emulators import UnityIntrospectionObject import logging @@ -294,9 +291,9 @@ class FilterBar(UnityIntrospectionObject): and for some reason the FilterBar stuff is bundled in the SearchBar. """ - state_info = get_state_by_path("//DashView/SearchBar") - assert(len(state_info) == 1) - return make_introspection_object(("SearchBar", state_info[0])) + searchbar_state = self.get_state_by_path("//DashView/SearchBar") + assert(len(searchbar_state) == 1) + return make_introspection_object(searchbar_state[0]) class FilterExpanderLabel(UnityIntrospectionObject): diff --git a/tests/autopilot/unity/emulators/hud.py b/tests/autopilot/unity/emulators/hud.py index e0c7d7656..59c99bc04 100644 --- a/tests/autopilot/unity/emulators/hud.py +++ b/tests/autopilot/unity/emulators/hud.py @@ -9,9 +9,11 @@ from __future__ import absolute_import -from autopilot.introspection.unity import UnityIntrospectionObject from autopilot.keybindings import KeybindingsHelper +from HTMLParser import HTMLParser +import re +from unity.emulators import UnityIntrospectionObject from unity.emulators.dash import SearchBar from unity.emulators.icons import HudEmbeddedIcon, HudLauncherIcon @@ -106,6 +108,19 @@ class Hud(KeybindingsHelper): return 0 @property + def hud_buttons(self): + """Returns a list of current HUD buttons.""" + return self.view.hud_buttons + + @property + def selected_hud_button(self): + try: + [button] = filter(lambda x: x.focused, self.hud_buttons) + return button + except IndexError: + raise RuntimeError("No HUD buttons found, is hud active?") + + @property def num_buttons(self): view = self.controller.get_hud_view() if view: @@ -123,6 +138,10 @@ class HudView(UnityIntrospectionObject): return self.get_children_by_type(SearchBar)[0] @property + def hud_buttons(self): + return self.get_children_by_type(HudButton) + + @property def geometry(self): return (self.x, self.y, self.width, self.height) @@ -133,3 +152,12 @@ class HudController(UnityIntrospectionObject): def get_hud_view(self): views = self.get_children_by_type(HudView) return views[0] if views else None + +class HudButton(UnityIntrospectionObject): + """Proxy object for the hud buttons.""" + + @property + def label_no_formatting(self): + """Returns the label text with the formatting removed.""" + htmlparser = HTMLParser() + return htmlparser.unescape(re.sub("<[^>]*>", "", self.label)) diff --git a/tests/autopilot/unity/emulators/icons.py b/tests/autopilot/unity/emulators/icons.py index 5c084dc44..7097b5a82 100644 --- a/tests/autopilot/unity/emulators/icons.py +++ b/tests/autopilot/unity/emulators/icons.py @@ -9,7 +9,7 @@ from __future__ import absolute_import -from autopilot.introspection.unity import UnityIntrospectionObject +from unity.emulators import UnityIntrospectionObject from unity.emulators.quicklist import Quicklist from unity.emulators.tooltip import ToolTip diff --git a/tests/autopilot/unity/emulators/launcher.py b/tests/autopilot/unity/emulators/launcher.py index b31305c35..a0742df20 100644 --- a/tests/autopilot/unity/emulators/launcher.py +++ b/tests/autopilot/unity/emulators/launcher.py @@ -12,7 +12,6 @@ from __future__ import absolute_import from autopilot.emulators.dbus_handler import session_bus from autopilot.emulators.X11 import Mouse, ScreenGeometry from autopilot.keybindings import KeybindingsHelper -from autopilot.introspection.unity import UnityIntrospectionObject from autopilot.utilities import get_compiz_option import dbus import logging @@ -20,6 +19,7 @@ from math import floor from testtools.matchers import NotEquals from time import sleep +from unity.emulators import UnityIntrospectionObject from unity.emulators.icons import BFBLauncherIcon, BamfLauncherIcon, SimpleLauncherIcon logger = logging.getLogger(__name__) @@ -169,6 +169,52 @@ class Launcher(UnityIntrospectionObject, KeybindingsHelper): if self.hidemode == 1: self.is_showing.wait_for(False) + def keyboard_select_icon(self, **kwargs): + """Using either keynav mode or the switcher, select an icon in the launcher. + + The desired mode (keynav or switcher) must be started already before + calling this methods or a RuntimeError will be raised. + + This method won't activate the icon, it will only select it. + + Icons are selected by passing keyword argument filters to this method. + For example: + + >>> launcher.keyboard_select_icon(tooltip_text="Calculator") + + ...will select the *first* icon that has a 'tooltip_text' attribute equal + to 'Calculator'. If an icon is missing the attribute, it is treated as + not matching. + + If no icon is found, this method will raise a ValueError. + + """ + + if not self.in_keynav_mode and not self.in_switcher_mode: + raise RuntimeError("Launcher must be in keynav or switcher mode") + + [launcher_model] = LauncherModel.get_all_instances() + all_icons = launcher_model.get_launcher_icons() + logger.debug("all_icons = %r", [i.tooltip_text for i in all_icons]) + for icon in all_icons: + # can't iterate over the model icons directly since some are hidden + # from the user. + if not icon.visible: + continue + logger.debug("Selected icon = %s", icon.tooltip_text) + matches = True + for arg,val in kwargs.iteritems(): + if not hasattr(icon, arg) or getattr(icon, arg, None) != val: + matches = False + break + if matches: + return + if self.in_keynav_mode: + self.key_nav_next() + elif self.in_switcher_mode: + self.switcher_next() + raise ValueError("No icon found that matches: %r", kwargs) + def key_nav_start(self): """Start keyboard navigation mode by pressing Alt+F1.""" self._screen.move_mouse_to_monitor(self.monitor) @@ -264,7 +310,7 @@ class Launcher(UnityIntrospectionObject, KeybindingsHelper): `icon` must be an instance of SimpleLauncherIcon or it's descendants. """ if not isinstance(icon, SimpleLauncherIcon): - raise TypeError("icon must be a LauncherIcon") + raise TypeError("icon must be a LauncherIcon, not %s" % type(icon)) logger.debug("Clicking launcher icon %r on monitor %d with mouse button %d", icon, self.monitor, button) diff --git a/tests/autopilot/unity/emulators/panel.py b/tests/autopilot/unity/emulators/panel.py index 275549f95..2b0d69254 100644 --- a/tests/autopilot/unity/emulators/panel.py +++ b/tests/autopilot/unity/emulators/panel.py @@ -12,10 +12,10 @@ from __future__ import absolute_import import logging from time import sleep -from autopilot.introspection.unity import UnityIntrospectionObject from autopilot.emulators.X11 import Mouse from autopilot.keybindings import KeybindingsHelper +from unity.emulators import UnityIntrospectionObject logger = logging.getLogger(__name__) diff --git a/tests/autopilot/unity/emulators/quicklist.py b/tests/autopilot/unity/emulators/quicklist.py index fafab3dc5..c4cbe55b4 100644 --- a/tests/autopilot/unity/emulators/quicklist.py +++ b/tests/autopilot/unity/emulators/quicklist.py @@ -11,9 +11,9 @@ from __future__ import absolute_import import logging -from autopilot.introspection.unity import UnityIntrospectionObject from autopilot.emulators.X11 import Mouse +from unity.emulators import UnityIntrospectionObject logger = logging.getLogger(__name__) diff --git a/tests/autopilot/unity/emulators/shortcut_hint.py b/tests/autopilot/unity/emulators/shortcut_hint.py index dcff2d214..279b4f108 100644 --- a/tests/autopilot/unity/emulators/shortcut_hint.py +++ b/tests/autopilot/unity/emulators/shortcut_hint.py @@ -11,9 +11,9 @@ from __future__ import absolute_import import logging -from autopilot.introspection.unity import UnityIntrospectionObject from autopilot.keybindings import KeybindingsHelper +from unity.emulators import UnityIntrospectionObject logger = logging.getLogger(__name__) diff --git a/tests/autopilot/unity/emulators/switcher.py b/tests/autopilot/unity/emulators/switcher.py index 9491802ad..7525f137b 100644 --- a/tests/autopilot/unity/emulators/switcher.py +++ b/tests/autopilot/unity/emulators/switcher.py @@ -12,9 +12,9 @@ from __future__ import absolute_import import logging from autopilot.emulators.X11 import Mouse -from autopilot.introspection.unity import UnityIntrospectionObject from autopilot.keybindings import KeybindingsHelper +from unity.emulators import UnityIntrospectionObject # even though we don't use these directly, we need to make sure they've been # imported so the classes contained are registered with the introspection API. from unity.emulators.icons import * diff --git a/tests/autopilot/unity/emulators/tooltip.py b/tests/autopilot/unity/emulators/tooltip.py index 60d165460..17c3740a3 100644 --- a/tests/autopilot/unity/emulators/tooltip.py +++ b/tests/autopilot/unity/emulators/tooltip.py @@ -7,13 +7,9 @@ # by the Free Software Foundation. # -import logging -from time import sleep +from __future__ import absolute_import -from autopilot.introspection.unity import UnityIntrospectionObject - - -logger = logging.getLogger(__name__) +from unity.emulators import UnityIntrospectionObject class ToolTip(UnityIntrospectionObject): diff --git a/tests/autopilot/unity/emulators/unity.py b/tests/autopilot/unity/emulators/unity.py index 912dc3f57..69ecab582 100644 --- a/tests/autopilot/unity/emulators/unity.py +++ b/tests/autopilot/unity/emulators/unity.py @@ -15,20 +15,20 @@ from dbus import Interface # acquire the debugging dbus object UNITY_BUS_NAME = 'com.canonical.Unity' DEBUG_PATH = '/com/canonical/Unity/Debug' -INTROSPECTION_IFACE = 'com.canonical.Unity.Debug.Introspection' +LOGGING_IFACE = 'com.canonical.Unity.Debug.Logging' _debug_proxy_obj = session_bus.get_object(UNITY_BUS_NAME, DEBUG_PATH) -_introspection_iface = Interface(_debug_proxy_obj, INTROSPECTION_IFACE) +_logging_iface = Interface(_debug_proxy_obj, LOGGING_IFACE) def start_log_to_file(file_path): """Instruct Unity to start logging to the given file.""" - _introspection_iface.StartLogToFile(file_path) + _logging_iface.StartLogToFile(file_path) def reset_logging(): """Instruct Unity to stop logging to a file.""" - _introspection_iface.ResetLogging() + _logging_iface.ResetLogging() def set_log_severity(component, severity): @@ -39,7 +39,7 @@ def set_log_severity(component, severity): 'severity' is the severity name (like 'DEBUG', 'INFO' etc.) """ - _introspection_iface.SetLogSeverity(component, severity) + _logging_iface.SetLogSeverity(component, severity) def log_unity_message(severity, message): @@ -53,5 +53,5 @@ def log_unity_message(severity, message): test, use the python logging framework instead. """ - _introspection_iface.LogMessage(severity, message) + _logging_iface.LogMessage(severity, message) diff --git a/tests/autopilot/unity/emulators/window_manager.py b/tests/autopilot/unity/emulators/window_manager.py index ceebda3cd..9c0f02a9f 100644 --- a/tests/autopilot/unity/emulators/window_manager.py +++ b/tests/autopilot/unity/emulators/window_manager.py @@ -11,7 +11,8 @@ from __future__ import absolute_import import logging from autopilot.keybindings import KeybindingsHelper -from autopilot.introspection.unity import UnityIntrospectionObject + +from unity.emulators import UnityIntrospectionObject logger = logging.getLogger(__name__) diff --git a/tests/autopilot/unity/tests/__init__.py b/tests/autopilot/unity/tests/__init__.py index 14fbbebc5..e24e19a19 100644 --- a/tests/autopilot/unity/tests/__init__.py +++ b/tests/autopilot/unity/tests/__init__.py @@ -10,8 +10,10 @@ from __future__ import absolute_import +from autopilot.matchers import Eventually from autopilot.testcase import AutopilotTestCase from dbus import DBusException +from logging import getLogger import os from tempfile import mktemp from testtools.content import text_content @@ -31,6 +33,8 @@ from unity.emulators.unity import ( ) +log = getLogger(__name__) + class UnityTestCase(AutopilotTestCase): """Unity test case base class, with improvments specific to Unity tests.""" @@ -57,31 +61,49 @@ class UnityTestCase(AutopilotTestCase): """ well_behaved = True reasons = [] + log.info("Checking system state for badly behaving test...") # Have we switched workspace? if self.workspace.current_workspace != self._initial_workspace_num: well_behaved = False reasons.append("The test changed the active workspace from %d to %d." \ % (self._initial_workspace_num, self.workspace.current_workspace)) + log.warning("Test changed the active workspace, changing it back...") self.workspace.switch_to(self._initial_workspace_num) # Have we left the dash open? if self.dash.visible: well_behaved = False reasons.append("The test left the dash open.") + log.warning("Test left the dash open, closing it...") self.dash.ensure_hidden() # ... or the hud? if self.hud.visible: well_behaved = False reasons.append("The test left the hud open.") + log.warning("Test left the hud open, closing it...") self.hud.ensure_hidden() # Are we in show desktop mode? if self.window_manager.showdesktop_active: well_behaved = False reasons.append("The test left the system in show_desktop mode.") + log.warning("Test left the system in show desktop mode, exiting it...") self.window_manager.leave_show_desktop() + for launcher in self.launcher.get_launchers(): + if launcher.in_keynav_mode: + well_behaved = False + reasons.append("The test left the launcher keynav mode enabled.") + log.warning("Test left the launcher in keynav mode, exiting it...") + launcher.key_nav_cancel() + if launcher.in_switcher_mode: + well_behaved = False + reasons.append("The test left the launcher in switcher mode.") + log.warning("Test left the launcher in switcher mode, exiting it...") + launcher.switcher_cancel() if not well_behaved: self.fail("/n".join(reasons)) + else: + log.info("Test was well behaved.") @property def dash(self): @@ -170,3 +192,7 @@ class UnityTestCase(AutopilotTestCase): raise ValueError("Log level '%s' must be one of: %r" % (level, valid_levels)) set_log_severity(component, level) + def assertNumberWinsIsEventually(self, app, num): + """Asserts that 'app' eventually has 'num' wins. Waits up to 10 seconds.""" + + self.assertThat(lambda: len(app.get_windows()), Eventually(Equals(num))) diff --git a/tests/autopilot/unity/tests/launcher/__init__.py b/tests/autopilot/unity/tests/launcher/__init__.py new file mode 100644 index 000000000..8f7602d92 --- /dev/null +++ b/tests/autopilot/unity/tests/launcher/__init__.py @@ -0,0 +1,59 @@ +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- +# Copyright 2012 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. + +"""Autopilot test case class for all Launcher tests""" + +from autopilot.emulators.X11 import ScreenGeometry +from autopilot.testcase import multiply_scenarios + +from unity.tests import UnityTestCase + + +def _make_scenarios(): + """Make scenarios for launcher test cases based on the number of configured + monitors. + """ + screen_geometry = ScreenGeometry() + num_monitors = screen_geometry.get_num_monitors() + + # it doesn't make sense to set only_primary when we're running in a single-monitor setup. + if num_monitors == 1: + return [('Single Monitor', {'launcher_monitor': 0, 'only_primary': False})] + + monitor_scenarios = [('Monitor %d' % (i), {'launcher_monitor': i}) for i in range(num_monitors)] + launcher_mode_scenarios = [('launcher_on_primary', {'only_primary': True}), + ('launcher on all', {'only_primary': False})] + return multiply_scenarios(monitor_scenarios, launcher_mode_scenarios) + + +class LauncherTestCase(UnityTestCase): + """A base class for all launcher tests that uses scenarios to run on + each launcher (for multi-monitor setups). + """ + scenarios = _make_scenarios() + + def setUp(self): + super(LauncherTestCase, self).setUp() + self.screen_geo = ScreenGeometry() + self.set_unity_log_level("unity.launcher", "DEBUG") + self.addCleanup(self.set_unity_log_level, "unity.launcher", "INFO") + + self.set_unity_option('num_launchers', int(self.only_primary)) + self.launcher_instance = self.get_launcher() + + if self.only_primary: + try: + old_primary_screen = self.screen_geo.get_primary_monitor() + self.screen_geo.set_primary_monitor(self.launcher_monitor) + self.addCleanup(self.screen_geo.set_primary_monitor, old_primary_screen) + except ScreenGeometry.BlacklistedDriverError: + self.skipTest("Impossible to set the monitor %d as primary" % self.launcher_monitor) + + def get_launcher(self): + """Get the launcher for the current scenario.""" + return self.launcher.get_launcher_for_monitor(self.launcher_monitor) diff --git a/tests/autopilot/unity/tests/launcher/test_capture.py b/tests/autopilot/unity/tests/launcher/test_capture.py new file mode 100644 index 000000000..a6f4b602e --- /dev/null +++ b/tests/autopilot/unity/tests/launcher/test_capture.py @@ -0,0 +1,113 @@ +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- +# Copyright 2012 Canonical +# Authors: Thomi Richards, +# Marco Trevisan (Treviño) +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 3, as published +# by the Free Software Foundation. + +from __future__ import absolute_import + +from autopilot.emulators.X11 import ScreenGeometry +from autopilot.matchers import Eventually +import logging +from testtools.matchers import Equals, LessThan, GreaterThan +from time import sleep + +from unity.tests import UnityTestCase + +logger = logging.getLogger(__name__) + + +class LauncherCaptureTests(UnityTestCase): + """Test the launchers ability to capture/not capture the mouse.""" + + screen_geo = ScreenGeometry() + + def setUp(self): + super(LauncherCaptureTests, self).setUp() + + if self.screen_geo.get_num_monitors() <= 1: + self.skipTest("This test requires two or more monitors.") + + self.set_unity_option('launcher_capture_mouse', True) + self.set_unity_option('num_launchers', 0) + self.setHideMode(0) + + def setHideMode(self, mode): + self.set_unity_option('launcher_hide_mode', mode) + launcher = self.launcher.get_launcher_for_monitor(0) + self.assertThat(launcher.hidemode, Eventually(Equals(mode))) + + def leftMostMonitor(self): + x1, y1, width, height = self.screen_geo.get_monitor_geometry(0) + x2, y2, width, height = self.screen_geo.get_monitor_geometry(1) + + if x1 < x2: + return 0 + return 1 + + def rightMostMonitor(self): + # TODO: This will break setups with 3 or more monitors. + return 1 - self.leftMostMonitor() + + + def test_launcher_captures_while_sticky_and_revealed(self): + """Tests that the launcher captures the mouse when moving between monitors + while revealed. + """ + x, y, width, height = self.screen_geo.get_monitor_geometry(self.rightMostMonitor()) + self.mouse.move(x + width / 2, y + height / 2, False) + self.mouse.move(x - width / 2, y + height / 2, True, 5, .002) + + x_fin, y_fin = self.mouse.position() + # The launcher should have held the mouse a little bit + self.assertThat(x_fin, GreaterThan(x - width / 2)) + + def test_launcher_not_capture_while_not_sticky_and_revealed(self): + """Tests that the launcher doesn't captures the mouse when moving between monitors + while revealed and stick is off. + """ + + self.set_unity_option('launcher_capture_mouse', False) + + x, y, width, height = self.screen_geo.get_monitor_geometry(self.rightMostMonitor()) + self.mouse.move(x + width / 2, y + height / 2, False) + self.mouse.move(x - width / 2, y + height / 2, True, 5, .002) + + x_fin, y_fin = self.mouse.position() + # The launcher should have held the mouse a little bit + self.assertThat(x_fin, Equals(x - width / 2)) + + def test_launcher_not_capture_while_not_sticky_and_hidden_moving_right(self): + """Tests that the launcher doesn't capture the mouse when moving between monitors + while hidden and sticky is off. + """ + + self.set_unity_option('launcher_capture_mouse', False) + self.setHideMode(1) + + x, y, width, height = self.screen_geo.get_monitor_geometry(self.leftMostMonitor()) + self.mouse.move(x + width / 2, y + height / 2, False) + sleep(1.5) + self.mouse.move(x + width * 1.5, y + height / 2, True, 5, .002) + + x_fin, y_fin = self.mouse.position() + # The launcher should have held the mouse a little bit + self.assertThat(x_fin, Equals(x + width * 1.5)) + + def test_launcher_capture_while_sticky_and_hidden_moving_right(self): + """Tests that the launcher captures the mouse when moving between monitors + while hidden. + """ + self.setHideMode(1) + + x, y, width, height = self.screen_geo.get_monitor_geometry(self.leftMostMonitor()) + self.mouse.move(x + width / 2, y + height / 2, False) + sleep(1.5) + self.mouse.move(x + width * 1.5, y + height / 2, True, 5, .002) + + x_fin, y_fin = self.mouse.position() + # The launcher should have held the mouse a little bit + self.assertThat(x_fin, LessThan(x + width * 1.5)) diff --git a/tests/autopilot/unity/tests/launcher/test_icon_behavior.py b/tests/autopilot/unity/tests/launcher/test_icon_behavior.py new file mode 100644 index 000000000..1e996a6c3 --- /dev/null +++ b/tests/autopilot/unity/tests/launcher/test_icon_behavior.py @@ -0,0 +1,208 @@ +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- +# Copyright 2012 Canonical +# Authors: Thomi Richards, +# Marco Trevisan (Treviño) +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 3, as published +# by the Free Software Foundation. + +from __future__ import absolute_import + +from autopilot.matchers import Eventually +from autopilot.testcase import multiply_scenarios +import logging +from testtools.matchers import Equals, NotEquals +from time import sleep + +from unity.emulators.launcher import IconDragType +from unity.tests.launcher import LauncherTestCase, _make_scenarios + +logger = logging.getLogger(__name__) + + +class LauncherIconsTests(LauncherTestCase): + """Test the launcher icons interactions""" + + def setUp(self): + super(LauncherIconsTests, self).setUp() + self.set_unity_option('launcher_hide_mode', 0) + + def test_bfb_tooltip_disappear_when_dash_is_opened(self): + """Tests that the bfb tooltip disappear when the dash is opened.""" + bfb = self.launcher.model.get_bfb_icon() + self.mouse.move(bfb.center_x, bfb.center_y) + + self.dash.ensure_visible() + self.addCleanup(self.dash.ensure_hidden) + + self.assertThat(bfb.get_tooltip().active, Eventually(Equals(False))) + + def test_bfb_tooltip_is_disabled_when_dash_is_open(self): + """Tests the that bfb tooltip is disabled when the dash is open.""" + self.dash.ensure_visible() + self.addCleanup(self.dash.ensure_hidden) + + bfb = self.launcher.model.get_bfb_icon() + self.mouse.move(bfb.center_x, bfb.center_y) + + self.assertThat(bfb.get_tooltip().active, Eventually(Equals(False))) + + def test_shift_click_opens_new_application_instance(self): + """Shift+Clicking MUST open a new instance of an already-running application.""" + app = self.start_app("Calculator") + desktop_id = app.desktop_file + icon = self.launcher.model.get_icon_by_desktop_id(desktop_id) + launcher_instance = self.launcher.get_launcher_for_monitor(0) + + self.keyboard.press("Shift") + self.addCleanup(self.keyboard.release, "Shift") + launcher_instance.click_launcher_icon(icon) + + self.assertNumberWinsIsEventually(app, 2) + + def test_launcher_activate_last_focused_window(self): + """Activating a launcher icon must raise only the last focused instance + of that application. + + """ + + mahj = self.start_app("Mahjongg") + [mah_win1] = mahj.get_windows() + self.assertTrue(mah_win1.is_focused) + + calc = self.start_app("Calculator") + [calc_win] = calc.get_windows() + self.assertTrue(calc_win.is_focused) + + self.start_app("Mahjongg") + # Sleeping due to the start_app only waiting for the bamf model to be + # updated with the application. Since the app has already started, + # and we are just waiting on a second window, however a defined sleep + # here is likely to be problematic. + # TODO: fix bamf emulator to enable waiting for new windows. + sleep(1) + [mah_win2] = [w for w in mahj.get_windows() if w.x_id != mah_win1.x_id] + self.assertTrue(mah_win2.is_focused) + self.assertVisibleWindowStack([mah_win2, calc_win, mah_win1]) + + mahj_icon = self.launcher.model.get_icon_by_desktop_id(mahj.desktop_file) + calc_icon = self.launcher.model.get_icon_by_desktop_id(calc.desktop_file) + + self.launcher_instance.click_launcher_icon(calc_icon) + sleep(1) + self.assertTrue(calc_win.is_focused) + self.assertVisibleWindowStack([calc_win, mah_win2, mah_win1]) + + self.launcher_instance.click_launcher_icon(mahj_icon) + sleep(1) + self.assertTrue(mah_win2.is_focused) + self.assertVisibleWindowStack([mah_win2, calc_win, mah_win1]) + + self.keybinding("window/minimize") + sleep(1) + + self.assertTrue(mah_win2.is_hidden) + self.assertTrue(calc_win.is_focused) + self.assertVisibleWindowStack([calc_win, mah_win1]) + + self.launcher_instance.click_launcher_icon(mahj_icon) + sleep(1) + self.assertTrue(mah_win1.is_focused) + self.assertTrue(mah_win2.is_hidden) + self.assertVisibleWindowStack([mah_win1, calc_win]) + + def test_clicking_icon_twice_initiates_spread(self): + """This tests shows that when you click on a launcher icon twice, + when an application window is focused, the spread is initiated. + """ + calc = self.start_app("Calculator") + [calc_win1] = calc.get_windows() + self.assertTrue(calc_win1.is_focused) + + self.start_app("Calculator") + # Sleeping due to the start_app only waiting for the bamf model to be + # updated with the application. Since the app has already started, + # and we are just waiting on a second window, however a defined sleep + # here is likely to be problematic. + # TODO: fix bamf emulator to enable waiting for new windows. + sleep(1) + [calc_win2] = [w for w in calc.get_windows() if w.x_id != calc_win1.x_id] + + self.assertVisibleWindowStack([calc_win2, calc_win1]) + self.assertTrue(calc_win2.is_focused) + + calc_icon = self.launcher.model.get_icon_by_desktop_id(calc.desktop_file) + self.addCleanup(self.keybinding, "spread/cancel") + self.launcher_instance.click_launcher_icon(calc_icon) + + self.assertThat(self.window_manager.scale_active, Eventually(Equals(True))) + self.assertThat(self.window_manager.scale_active_for_group, Eventually(Equals(True))) + + def test_icon_shows_on_quick_application_reopen(self): + """Icons must stay on launcher when an application is quickly closed/reopened.""" + calc = self.start_app("Calculator") + desktop_file = calc.desktop_file + calc_icon = self.launcher.model.get_icon_by_desktop_id(desktop_file) + self.assertThat(calc_icon.visible, Eventually(Equals(True))) + + self.close_all_app("Calculator") + calc = self.start_app("Calculator") + sleep(2) + + calc_icon = self.launcher.model.get_icon_by_desktop_id(desktop_file) + self.assertThat(calc_icon, NotEquals(None)) + self.assertThat(calc_icon.visible, Eventually(Equals(True))) + + +class LauncherDragIconsBehavior(LauncherTestCase): + """Tests dragging icons around the Launcher.""" + + scenarios = multiply_scenarios(_make_scenarios(), + [ + ('inside', {'drag_type': IconDragType.INSIDE}), + ('outside', {'drag_type': IconDragType.OUTSIDE}), + ]) + + def ensure_calc_icon_not_in_launcher(self): + """Wait until the launcher model updates and removes the calc icon.""" + refresh_fn = lambda: self.launcher.model.get_icon_by_desktop_id("gcalctool.desktop") + self.assertThat(refresh_fn, Eventually(Equals(None))) + + def test_can_drag_icon_below_bfb(self): + """Application icons must be draggable to below the BFB.""" + + self.ensure_calc_icon_not_in_launcher() + calc = self.start_app("Calculator") + calc_icon = self.launcher.model.get_icon_by_desktop_id(calc.desktop_file) + + bfb_icon_position = 0 + self.launcher_instance.drag_icon_to_position(calc_icon, + bfb_icon_position, + self.drag_type) + moved_icon = self.launcher.model.\ + get_launcher_icons_for_monitor(self.launcher_monitor)[1] + self.assertThat(moved_icon.id, Equals(calc_icon.id)) + + def test_can_drag_icon_above_window_switcher(self): + """Application icons must be dragable to above the workspace switcher icon.""" + + self.ensure_calc_icon_not_in_launcher() + calc = self.start_app("Calculator") + calc_icon = self.launcher.model.get_icon_by_desktop_id(calc.desktop_file) + + # Move a known icon to the top as it needs to be more than 2 icon + # spaces away for this test to actually do anything + bfb_icon_position = 0 + self.launcher_instance.drag_icon_to_position(calc_icon, + bfb_icon_position, + self.drag_type) + sleep(1) + switcher_pos = -2 + self.launcher_instance.drag_icon_to_position(calc_icon, + switcher_pos, + self.drag_type) + + moved_icon = self.launcher.model.\ + get_launcher_icons_for_monitor(self.launcher_monitor)[-3] + self.assertThat(moved_icon.id, Equals(calc_icon.id)) diff --git a/tests/autopilot/unity/tests/launcher/test_keynav.py b/tests/autopilot/unity/tests/launcher/test_keynav.py new file mode 100644 index 000000000..b65f262b9 --- /dev/null +++ b/tests/autopilot/unity/tests/launcher/test_keynav.py @@ -0,0 +1,191 @@ +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- +# Copyright 2012 Canonical +# Authors: Thomi Richards, +# Marco Trevisan (Treviño) +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 3, as published +# by the Free Software Foundation. + +from __future__ import absolute_import + +from autopilot.matchers import Eventually +import logging +from testtools.matchers import Equals, GreaterThan + +from unity.tests.launcher import LauncherTestCase + +logger = logging.getLogger(__name__) + + +class LauncherKeyNavTests(LauncherTestCase): + """Test the launcher key navigation""" + + def start_keynav_with_cleanup_cancel(self): + """Start keynav mode safely. + + This adds a cleanup action that cancels keynav mode at the end of the + test if it's still running (but does nothing otherwise). + + """ + self.launcher_instance.key_nav_start() + self.addCleanup(self.safe_quit_keynav) + + def safe_quit_keynav(self): + """Quit the keynav mode if it's engaged.""" + if self.launcher.key_nav_is_active: + self.launcher_instance.key_nav_cancel() + + def test_launcher_keynav_initiate(self): + """Tests we can initiate keyboard navigation on the launcher.""" + self.start_keynav_with_cleanup_cancel() + self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(True))) + self.assertThat(self.launcher.key_nav_is_grabbed, Eventually(Equals(True))) + + def test_launcher_keynav_cancel(self): + """Test that we can exit keynav mode.""" + self.launcher_instance.key_nav_start() + self.launcher_instance.key_nav_cancel() + self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(False))) + self.assertThat(self.launcher.key_nav_is_grabbed, Eventually(Equals(False))) + + def test_launcher_keynav_cancel_resume_focus(self): + """Test that ending the launcher keynav resume the focus.""" + calc = self.start_app("Calculator") + self.assertTrue(calc.is_active) + + self.start_keynav_with_cleanup_cancel() + self.assertFalse(calc.is_active) + + self.launcher_instance.key_nav_cancel() + self.assertTrue(calc.is_active) + + def test_launcher_keynav_starts_at_index_zero(self): + """Test keynav mode starts at index 0.""" + self.start_keynav_with_cleanup_cancel() + self.assertThat(self.launcher.key_nav_selection, Eventually(Equals(0))) + + def test_launcher_keynav_forward(self): + """Must be able to move forwards while in keynav mode.""" + self.start_keynav_with_cleanup_cancel() + self.launcher_instance.key_nav_next() + # The launcher model has hidden items, so the keynav indexes do not + # increase by 1 each time. This test was failing because the 2nd icon + # had an index of 2, not 1 as expected. The best we can do here is to + # make sure that the index has increased. This opens us to the + # possibility that the launcher really is skipping forward more than one + # icon at a time, but we can't do much about that. + self.assertThat(self.launcher.key_nav_selection, Eventually(GreaterThan(0))) + + def test_launcher_keynav_prev_works(self): + """Must be able to move backwards while in keynav mode.""" + self.start_keynav_with_cleanup_cancel() + self.launcher_instance.key_nav_next() + self.assertThat(self.launcher.key_nav_selection, Eventually(GreaterThan(0))) + self.launcher_instance.key_nav_prev() + self.assertThat(self.launcher.key_nav_selection, Eventually(Equals(0))) + + def test_launcher_keynav_cycling_forward(self): + """Launcher keynav must loop through icons when cycling forwards""" + self.start_keynav_with_cleanup_cancel() + prev_icon = 0 + for icon in range(1, self.launcher.model.num_launcher_icons()): + self.launcher_instance.key_nav_next() + # FIXME We can't directly check for selection/icon number equalty + # since the launcher model also contains "hidden" icons that aren't + # shown, so the selection index can increment by more than 1. + self.assertThat(self.launcher.key_nav_selection, Eventually(GreaterThan(prev_icon))) + prev_icon = self.launcher.key_nav_selection + + self.launcher_instance.key_nav_next() + self.assertThat(self.launcher.key_nav_selection, Eventually(Equals(0))) + + def test_launcher_keynav_cycling_backward(self): + """Launcher keynav must loop through icons when cycling backwards""" + self.start_keynav_with_cleanup_cancel() + self.launcher_instance.key_nav_prev() + # FIXME We can't directly check for self.launcher.num_launcher_icons - 1 + self.assertThat(self.launcher.key_nav_selection, Eventually(GreaterThan(1))) + + def test_launcher_keynav_can_open_and_close_quicklist(self): + """Tests that we can open and close a quicklist from keynav mode.""" + self.start_keynav_with_cleanup_cancel() + self.launcher_instance.key_nav_next() + self.launcher_instance.key_nav_enter_quicklist() + self.assertThat(self.launcher_instance.quicklist_open, Eventually(Equals(True))) + self.launcher_instance.key_nav_exit_quicklist() + self.assertThat(self.launcher_instance.quicklist_open, Eventually(Equals(False))) + self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(True))) + self.assertThat(self.launcher.key_nav_is_grabbed, Eventually(Equals(True))) + + def test_launcher_keynav_mode_toggles(self): + """Tests that keynav mode toggles with Alt+F1.""" + # was initiated in setup. + self.start_keynav_with_cleanup_cancel() + self.keybinding("launcher/keynav") + self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(False))) + + def test_launcher_keynav_activate_keep_focus(self): + """Activating a running launcher icon must focus it.""" + calc = self.start_app("Calculator") + mahjongg = self.start_app("Mahjongg") + self.assertTrue(mahjongg.is_active) + self.assertFalse(calc.is_active) + + self.start_keynav_with_cleanup_cancel() + + self.launcher_instance.keyboard_select_icon(tooltip_text=calc.name) + self.launcher_instance.key_nav_activate() + + self.assertTrue(calc.is_active) + self.assertFalse(mahjongg.is_active) + + def test_launcher_keynav_expo_focus(self): + """When entering expo mode from KeyNav the Desktop must get focus.""" + self.start_keynav_with_cleanup_cancel() + + self.launcher_instance.keyboard_select_icon(tooltip_text="Workspace Switcher") + self.launcher_instance.key_nav_activate() + self.addCleanup(self.keybinding, "expo/cancel") + + self.assertThat(self.panels.get_active_panel().title, Eventually(Equals("Ubuntu Desktop"))) + + def test_launcher_keynav_expo_exit_on_esc(self): + """Esc should quit expo when entering it from KeyNav.""" + self.start_keynav_with_cleanup_cancel() + + self.launcher_instance.keyboard_select_icon(tooltip_text="Workspace Switcher") + self.launcher_instance.key_nav_activate() + + self.keyboard.press_and_release("Escape") + self.assertThat(self.window_manager.expo_active, Eventually(Equals(False))) + + def test_launcher_keynav_alt_tab_quits(self): + """Tests that alt+tab exits keynav mode.""" + self.start_keynav_with_cleanup_cancel() + + self.keybinding("switcher/reveal_normal") + self.addCleanup(self.switcher.terminate) + self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(False))) + + def test_launcher_keynav_alt_grave_quits(self): + """Tests that alt+` exits keynav mode.""" + self.start_keynav_with_cleanup_cancel() + # Can't use switcher emulat here since the switcher won't appear. + self.keybinding("switcher/reveal_details") + self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(False))) + + def test_launcher_keynav_cancel_doesnt_activate_icon(self): + """This tests when canceling keynav the current icon doesnt activate.""" + self.start_keynav_with_cleanup_cancel() + self.keyboard.press_and_release("Escape") + self.assertThat(self.dash.visible, Eventually(Equals(False))) + + def test_alt_f1_closes_dash(self): + """This test when Alt+F1 is activated it must close the dash.""" + self.dash.ensure_visible() + + self.start_keynav_with_cleanup_cancel() + + self.assertThat(self.dash.visible, Equals(False)) + self.assertThat(self.launcher.key_nav_is_active, Equals(True)) diff --git a/tests/autopilot/unity/tests/launcher/test_reveal.py b/tests/autopilot/unity/tests/launcher/test_reveal.py new file mode 100644 index 000000000..745424b3d --- /dev/null +++ b/tests/autopilot/unity/tests/launcher/test_reveal.py @@ -0,0 +1,87 @@ +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- +# Copyright 2012 Canonical +# Authors: Thomi Richards, +# Marco Trevisan (Treviño) +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 3, as published +# by the Free Software Foundation. + +from __future__ import absolute_import + +from autopilot.matchers import Eventually +import logging +from testtools.matchers import Equals, GreaterThan +from time import sleep + +from unity.tests.launcher import LauncherTestCase + +logger = logging.getLogger(__name__) + + +class LauncherRevealTests(LauncherTestCase): + """Test the launcher reveal behavior when in autohide mode.""" + + def setUp(self): + super(LauncherRevealTests, self).setUp() + # these automatically reset to the original value, as implemented in AutopilotTestCase + self.set_unity_option('launcher_capture_mouse', True) + self.set_unity_option('launcher_hide_mode', 1) + launcher = self.get_launcher() + self.assertThat(launcher.hidemode, Eventually(Equals(1))) + + def test_launcher_keyboard_reveal_works(self): + """Revealing launcher with keyboard must work.""" + self.launcher_instance.keyboard_reveal_launcher() + self.addCleanup(self.launcher_instance.keyboard_unreveal_launcher) + self.assertThat(self.launcher_instance.is_showing, Eventually(Equals(True))) + + def test_reveal_on_mouse_to_edge(self): + """Tests reveal of launchers by mouse pressure.""" + self.launcher_instance.move_mouse_to_right_of_launcher() + self.launcher_instance.mouse_reveal_launcher() + self.assertThat(self.launcher_instance.is_showing, Eventually(Equals(True))) + + def test_reveal_with_mouse_under_launcher(self): + """The Launcher must hide properly if the mouse is under the launcher.""" + + self.launcher_instance.move_mouse_over_launcher() + # we can't use "launcher_instance.keyboard_reveal_launcher()" + # since it moves the mouse out of the way, invalidating the test. + self.keybinding_hold("launcher/reveal") + sleep(1) + self.keybinding_release("launcher/reveal") + self.assertThat(self.launcher_instance.is_showing, Eventually(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. + """ + self.launcher_instance.move_mouse_to_right_of_launcher() + self.launcher_instance.mouse_reveal_launcher() + self.assertThat(self.launcher_instance.is_showing, Eventually(Equals(True))) + + def test_launcher_does_not_reveal_with_mouse_down(self): + """Launcher must not reveal if have mouse button 1 down.""" + self.screen_geo.move_mouse_to_monitor(self.launcher_instance.monitor) + self.mouse.press(1) + self.addCleanup(self.mouse.release, 1) + #FIXME: This is really bad API. it says reveal but it's expected to fail. bad bad bad!! + self.launcher_instance.mouse_reveal_launcher() + # Need a sleep here otherwise this test would pass even if the code failed. + # THis test needs to be rewritten... + sleep(5) + self.assertThat(self.launcher_instance.is_showing, Equals(False)) + + def test_new_icon_has_the_shortcut(self): + """New icons should have an associated shortcut""" + if self.launcher.model.num_bamf_launcher_icons() >= 10: + self.skip("There are already more than 9 icons in the launcher") + + desktop_file = self.KNOWN_APPS['Calculator']['desktop-file'] + if self.launcher.model.get_icon_by_desktop_id(desktop_file) != None: + self.skip("Calculator icon is already on the launcher.") + + self.start_app('Calculator') + icon = self.launcher.model.get_icon_by_desktop_id(desktop_file) + self.assertThat(icon.shortcut, GreaterThan(0)) diff --git a/tests/autopilot/unity/tests/launcher/test_shortcut.py b/tests/autopilot/unity/tests/launcher/test_shortcut.py new file mode 100644 index 000000000..8747b5723 --- /dev/null +++ b/tests/autopilot/unity/tests/launcher/test_shortcut.py @@ -0,0 +1,55 @@ +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- +# Copyright 2012 Canonical +# Authors: Thomi Richards, +# Marco Trevisan (Treviño) +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 3, as published +# by the Free Software Foundation. + +from __future__ import absolute_import + +from autopilot.matchers import Eventually +import logging +from testtools.matchers import Equals +from time import sleep + +from unity.tests.launcher import LauncherTestCase + +logger = logging.getLogger(__name__) + + +class LauncherShortcutTests(LauncherTestCase): + """Tests for the shortcut hint window.""" + + def setUp(self): + super(LauncherShortcutTests, self).setUp() + self.launcher_instance.keyboard_reveal_launcher() + self.addCleanup(self.launcher_instance.keyboard_unreveal_launcher) + sleep(2) + + def test_launcher_keyboard_reveal_shows_shortcut_hints(self): + """Launcher icons must show shortcut hints after revealing with keyboard.""" + self.assertThat(self.launcher_instance.shortcuts_shown, Eventually(Equals(True))) + + def test_launcher_switcher_keeps_shorcuts(self): + """Initiating launcher switcher after showing shortcuts must not hide shortcuts""" + self.launcher_instance.switcher_start() + self.addCleanup(self.launcher_instance.switcher_cancel) + + self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(True))) + self.assertThat(self.launcher_instance.shortcuts_shown, Eventually(Equals(True))) + + def test_launcher_switcher_next_keeps_shortcuts(self): + """Launcher switcher next action must keep shortcuts after they've been shown.""" + self.launcher_instance.switcher_start() + self.addCleanup(self.launcher_instance.switcher_cancel) + self.launcher_instance.switcher_next() + self.assertThat(self.launcher_instance.shortcuts_shown, Eventually(Equals(True))) + + def test_launcher_switcher_prev_keeps_shortcuts(self): + """Launcher switcher prev action must keep shortcuts after they've been shown.""" + self.launcher_instance.switcher_start() + self.addCleanup(self.launcher_instance.switcher_cancel) + self.launcher_instance.switcher_prev() + self.assertThat(self.launcher_instance.shortcuts_shown, Eventually(Equals(True))) diff --git a/tests/autopilot/unity/tests/launcher/test_switcher.py b/tests/autopilot/unity/tests/launcher/test_switcher.py new file mode 100644 index 000000000..786826f12 --- /dev/null +++ b/tests/autopilot/unity/tests/launcher/test_switcher.py @@ -0,0 +1,168 @@ +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- +# Copyright 2012 Canonical +# Authors: Thomi Richards, +# Marco Trevisan (Treviño) +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 3, as published +# by the Free Software Foundation. + +from __future__ import absolute_import + +from autopilot.matchers import Eventually + +import logging +from testtools.matchers import Equals, NotEquals, GreaterThan +from time import sleep + +from unity.tests.launcher import LauncherTestCase + + +logger = logging.getLogger(__name__) + + +class LauncherSwitcherTests(LauncherTestCase): + """ Tests the functionality of the launcher's switcher capability""" + + def start_switcher_with_cleanup_cancel(self): + """Start switcher mode safely. + + This adds a cleanup action that cancels keynav mode at the end of the + test if it's still running (but does nothing otherwise). + + """ + self.launcher_instance.switcher_start() + self.addCleanup(self.safe_quit_switcher) + + def safe_quit_switcher(self): + """Quit the keynav mode if it's engaged.""" + if self.launcher.key_nav_is_active: + self.launcher_instance.switcher_cancel() + + def test_launcher_switcher_cancel(self): + """Test that ending the launcher switcher actually works.""" + self.launcher_instance.switcher_start() + self.launcher_instance.switcher_cancel() + self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(False))) + + def test_launcher_switcher_cancel_resume_focus(self): + """Test that ending the launcher switcher resume the focus.""" + self.close_all_app("Calculator") + calc = self.start_app("Calculator") + self.assertTrue(calc.is_active) + + self.start_switcher_with_cleanup_cancel() + sleep(.5) + self.assertFalse(calc.is_active) + + self.launcher_instance.switcher_cancel() + sleep(.5) + self.assertTrue(calc.is_active) + + def test_launcher_switcher_starts_at_index_zero(self): + """Test that starting the Launcher switcher puts the keyboard focus on item 0.""" + self.start_switcher_with_cleanup_cancel() + + self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(True))) + self.assertThat(self.launcher.key_nav_is_grabbed, Eventually(Equals(False))) + self.assertThat(self.launcher.key_nav_selection, Eventually(Equals(0))) + + def test_launcher_switcher_next(self): + """Moving to the next launcher item while switcher is activated must work.""" + self.start_switcher_with_cleanup_cancel() + self.launcher_instance.switcher_next() + # The launcher model has hidden items, so the keynav indexes do not + # increase by 1 each time. This test was failing because the 2nd icon + # had an index of 2, not 1 as expected. The best we can do here is to + # make sure that the index has increased. This opens us to the + # possibility that the launcher really is skipping forward more than one + # icon at a time, but we can't do much about that. + self.assertThat(self.launcher.key_nav_selection, Eventually(GreaterThan(0))) + + def test_launcher_switcher_prev(self): + """Moving to the previous launcher item while switcher is activated must work.""" + self.start_switcher_with_cleanup_cancel() + self.launcher_instance.switcher_prev() + self.assertThat(self.launcher.key_nav_selection, Eventually(NotEquals(0))) + + def test_launcher_switcher_down(self): + """Pressing the down arrow key while switcher is activated must work.""" + self.start_switcher_with_cleanup_cancel() + self.launcher_instance.switcher_down() + # The launcher model has hidden items, so the keynav indexes do not + # increase by 1 each time. This test was failing because the 2nd icon + # had an index of 2, not 1 as expected. The best we can do here is to + # make sure that the index has increased. This opens us to the + # possibility that the launcher really is skipping forward more than one + # icon at a time, but we can't do much about that. + self.assertThat(self.launcher.key_nav_selection, Eventually(GreaterThan(0))) + + def test_launcher_switcher_up(self): + """Pressing the up arrow key while switcher is activated must work.""" + self.start_switcher_with_cleanup_cancel() + self.launcher_instance.switcher_up() + self.assertThat(self.launcher.key_nav_selection, Eventually(NotEquals(0))) + + def test_launcher_switcher_next_doesnt_show_shortcuts(self): + """Moving forward in launcher switcher must not show launcher shortcuts.""" + self.start_switcher_with_cleanup_cancel() + self.launcher_instance.switcher_next() + # sleep so that the shortcut timeout could be triggered + sleep(2) + self.assertThat(self.launcher_instance.shortcuts_shown, Eventually(Equals(False))) + + def test_launcher_switcher_prev_doesnt_show_shortcuts(self): + """Moving backward in launcher switcher must not show launcher shortcuts.""" + self.start_switcher_with_cleanup_cancel() + self.launcher_instance.switcher_prev() + # sleep so that the shortcut timeout could be triggered + sleep(2) + self.assertThat(self.launcher_instance.shortcuts_shown, Eventually(Equals(False))) + + def test_launcher_switcher_cycling_forward(self): + """Launcher Switcher must loop through icons when cycling forwards""" + self.start_switcher_with_cleanup_cancel() + prev_icon = 0 + num_icons = self.launcher.model.num_launcher_icons() + logger.info("This launcher has %d icons", num_icons) + for icon in range(1, num_icons): + self.launcher_instance.switcher_next() + # FIXME We can't directly check for selection/icon number equalty + # since the launcher model also contains "hidden" icons that aren't + # shown, so the selection index can increment by more than 1. + self.assertThat(self.launcher.key_nav_selection, Eventually(GreaterThan(prev_icon))) + prev_icon = self.launcher.key_nav_selection + + self.launcher_instance.switcher_next() + self.assertThat(self.launcher.key_nav_selection, Eventually(Equals(0))) + + def test_launcher_switcher_cycling_backward(self): + """Launcher Switcher must loop through icons when cycling backwards""" + self.start_switcher_with_cleanup_cancel() + self.launcher_instance.switcher_prev() + # FIXME We can't directly check for self.launcher.num_launcher_icons - 1 + self.assertThat(self.launcher.key_nav_selection, Eventually(GreaterThan(1))) + + def test_launcher_switcher_activate_keep_focus(self): + """Activating a running launcher icon should focus the application.""" + calc = self.start_app("Calculator") + mahjongg = self.start_app("Mahjongg") + self.assertTrue(mahjongg.is_active) + self.assertFalse(calc.is_active) + + self.start_switcher_with_cleanup_cancel() + + self.launcher_instance.keyboard_select_icon(tooltip_text=calc.name) + self.launcher_instance.switcher_activate() + + self.assertThat(lambda: calc.is_active, Eventually(Equals(True))) + self.assertThat(lambda: mahjongg.is_active, Eventually(Equals(False))) + + def test_launcher_switcher_using_shorcuts(self): + """Using some other shortcut while switcher is active must cancel switcher.""" + self.start_switcher_with_cleanup_cancel() + self.keyboard.press_and_release("s") + sleep(.25) + self.keyboard.press_and_release("Escape") + sleep(.25) + self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(False))) diff --git a/tests/autopilot/unity/tests/launcher/test_visual.py b/tests/autopilot/unity/tests/launcher/test_visual.py new file mode 100644 index 000000000..6b1fd7805 --- /dev/null +++ b/tests/autopilot/unity/tests/launcher/test_visual.py @@ -0,0 +1,76 @@ +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- +# Copyright 2012 Canonical +# Authors: Thomi Richards, +# Marco Trevisan (Treviño) +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 3, as published +# by the Free Software Foundation. + +from __future__ import absolute_import + +from autopilot.matchers import Eventually +import logging +from testtools.matchers import Equals +from time import sleep + +from unity.emulators.icons import BFBLauncherIcon +from unity.tests.launcher import LauncherTestCase + +logger = logging.getLogger(__name__) + + +class LauncherVisualTests(LauncherTestCase): + """Tests for visual aspects of the launcher (icon saturation etc.).""" + + def test_keynav_from_dash_saturates_icons(self): + """Starting super+tab switcher from the dash must resaturate launcher icons. + + Tests fix for bug #913569. + """ + bfb = self.launcher.model.get_bfb_icon() + self.mouse.move(bfb.center_x, bfb.center_y) + self.dash.ensure_visible() + sleep(1) + # We can't use 'launcher_instance.switcher_start()' since it moves the mouse. + self.keybinding_hold_part_then_tap("launcher/switcher") + self.addCleanup(self.keybinding_release, "launcher/switcher") + self.addCleanup(self.keybinding, "launcher/switcher/exit") + + self.keybinding_tap("launcher/switcher/next") + for icon in self.launcher.model.get_launcher_icons(): + self.assertThat(icon.desaturated, Eventually(Equals(False))) + + def test_opening_dash_desaturates_icons(self): + """Opening the dash must desaturate all the launcher icons.""" + self.dash.ensure_visible() + self.addCleanup(self.dash.ensure_hidden) + + for icon in self.launcher.model.get_launcher_icons(): + if isinstance(icon, BFBLauncherIcon): + self.assertThat(icon.desaturated, Eventually(Equals(False))) + else: + self.assertThat(icon.desaturated, Eventually(Equals(True))) + + def test_opening_dash_with_mouse_over_launcher_keeps_icon_saturation(self): + """Opening dash with mouse over launcher must not desaturate icons.""" + launcher_instance = self.get_launcher() + x,y,w,h = launcher_instance.geometry + self.mouse.move(x + w/2, y + h/2) + sleep(.5) + self.dash.ensure_visible() + self.addCleanup(self.dash.ensure_hidden) + for icon in self.launcher.model.get_launcher_icons(): + self.assertThat(icon.desaturated, Eventually(Equals(False))) + + def test_mouse_over_with_dash_open_desaturates_icons(self): + """Moving mouse over launcher with dash open must saturate icons.""" + launcher_instance = self.get_launcher() + self.dash.ensure_visible() + self.addCleanup(self.dash.ensure_hidden) + sleep(.5) + x,y,w,h = launcher_instance.geometry + self.mouse.move(x + w/2, y + h/2) + sleep(.5) + for icon in self.launcher.model.get_launcher_icons(): + self.assertThat(icon.desaturated, Eventually(Equals(False))) diff --git a/tests/autopilot/unity/tests/test_dash.py b/tests/autopilot/unity/tests/test_dash.py index b15a9df47..4a1581b24 100644 --- a/tests/autopilot/unity/tests/test_dash.py +++ b/tests/autopilot/unity/tests/test_dash.py @@ -70,6 +70,30 @@ class DashRevealTests(DashTestCase): self.assertThat(self.window_manager.scale_active, Eventually(Equals(True))) self.assertThat(self.dash.visible, Eventually(Equals(False))) + def test_dash_opens_when_in_spread(self): + """This test shows the dash opens when in spread mode.""" + self.keybinding("spread/start") + self.assertThat(self.window_manager.scale_active, Eventually(Equals(True))) + + self.dash.ensure_visible() + self.assertThat(self.dash.visible, Eventually(Equals(True))) + + def test_command_lens_opens_when_in_spread(self): + """This test shows the command lens opens when in spread mode.""" + self.keybinding("spread/start") + self.assertThat(self.window_manager.scale_active, Eventually(Equals(True))) + + self.dash.reveal_command_lens() + self.assertThat(self.dash.active_lens, Eventually(Equals('commands.lens'))) + + def test_lens_opens_when_in_spread(self): + """This test shows that any lens opens when in spread mode.""" + self.keybinding("spread/start") + self.assertThat(self.window_manager.scale_active, Eventually(Equals(True))) + + self.dash.reveal_application_lens() + self.assertThat(self.dash.active_lens, Eventually(Equals('applications.lens'))) + class DashSearchInputTests(DashTestCase): """Test features involving input to the dash search""" @@ -247,16 +271,6 @@ class DashKeyNavTests(DashTestCase): category = lens.get_focused_category() self.assertIsNot(category, None) - def test_alt_f1_disabled(self): - """This test that Alt+F1 is disabled when the dash is opened.""" - self.dash.ensure_visible() - # can't use launcher emulator since we'll fail to start keynav: - self.keybinding("launcher/keynav") - # can't use Eventually here - sleep long enough for the launcher controller - # to react to the keypress (well, hopefully not) - sleep(5) - self.assertThat(self.launcher.key_nav_is_active, Equals(False)) - class DashClipboardTests(DashTestCase): """Test the Unity clipboard""" @@ -514,7 +528,7 @@ class CategoryHeaderTests(DashTestCase): self.mouse.move(self.dash.view.x + self.dash.view.width / 2, category.header_y + category.header_height / 2) - self.mouse.click() + self.mouse.click() self.assertThat(category.is_expanded, Eventually(Equals(not is_expanded))) self.mouse.click() diff --git a/tests/autopilot/unity/tests/test_hud.py b/tests/autopilot/unity/tests/test_hud.py index f4e4fc68c..cc190dd4b 100644 --- a/tests/autopilot/unity/tests/test_hud.py +++ b/tests/autopilot/unity/tests/test_hud.py @@ -180,7 +180,9 @@ class HudBehaviorTests(HudTestsBase): self.hud.ensure_visible() self.keyboard.type("undo") - self.assertThat(self.hud.search_string, Eventually(Equals("undo"))) + hud_query_check = lambda: self.hud.selected_hud_button.label_no_formatting + self.assertThat(hud_query_check, + Eventually(Equals("Edit > Undo"))) self.keyboard.press_and_release('Return') self.assertThat(self.hud.visible, Eventually(Equals(False))) self.keyboard.press_and_release("Ctrl+s") @@ -244,6 +246,38 @@ class HudBehaviorTests(HudTestsBase): self.assertThat(self.window_manager.scale_active, Eventually(Equals(True))) self.assertThat(self.hud.visible, Eventually(Equals(False))) + def test_hud_closes_click_outside_geo_shrunk(self): + """ + Clicking outside the hud when it is shurnk will make it close. + Shurnk is when the hud has no results and is much smaller then normal. + """ + + self.hud.ensure_visible() + (x,y,w,h) = self.hud.view.geometry + self.mouse.move(w/2, h-50) + self.mouse.click() + + self.assertThat(self.hud.visible, Eventually(Equals(False))) + + def test_hud_closes_click_outside_geo(self): + """Clicking outside of the hud will make it close.""" + + self.hud.ensure_visible() + self.keyboard.type("Test") + + (x,y,w,h) = self.hud.view.geometry + self.mouse.move(w/2, h+50) + self.mouse.click() + + self.assertThat(self.hud.visible, Eventually(Equals(False))) + + def test_alt_f4_close_hud(self): + """Hud must close on alt+F4.""" + self.hud.ensure_visible() + self.keyboard.press_and_release("Alt+F4") + self.assertThat(self.hud.visible, Eventually(Equals(False))) + + class HudLauncherInteractionsTests(HudTestsBase): launcher_modes = [('Launcher autohide', {'launcher_autohide': False}), diff --git a/tests/autopilot/unity/tests/test_launcher.py b/tests/autopilot/unity/tests/test_launcher.py deleted file mode 100644 index 8232b9dce..000000000 --- a/tests/autopilot/unity/tests/test_launcher.py +++ /dev/null @@ -1,851 +0,0 @@ -# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- -# Copyright 2012 Canonical -# Authors: Thomi Richards, -# Marco Trevisan (Treviño) -# -# This program is free software: you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 3, as published -# by the Free Software Foundation. - -from __future__ import absolute_import - -from autopilot.emulators.X11 import ScreenGeometry -from autopilot.matchers import Eventually -from autopilot.testcase import multiply_scenarios -import logging -from testtools.matchers import Equals, NotEquals, LessThan, GreaterThan -from time import sleep - -from unity.emulators.icons import BFBLauncherIcon -from unity.emulators.launcher import IconDragType -from unity.tests import UnityTestCase - -logger = logging.getLogger(__name__) - -def _make_scenarios(): - """Make scenarios for launcher test cases based on the number of configured - monitors. - """ - screen_geometry = ScreenGeometry() - num_monitors = screen_geometry.get_num_monitors() - - # it doesn't make sense to set only_primary when we're running in a single-monitor setup. - if num_monitors == 1: - return [('Single Monitor', {'launcher_monitor': 0, 'only_primary': False})] - - monitor_scenarios = [('Monitor %d' % (i), {'launcher_monitor': i}) for i in range(num_monitors)] - launcher_mode_scenarios = [('launcher_on_primary', {'only_primary': True}), - ('launcher on all', {'only_primary': False})] - return multiply_scenarios(monitor_scenarios, launcher_mode_scenarios) - - -class LauncherTestCase(UnityTestCase): - """A base class for all launcher tests that uses scenarios to run on - each launcher (for multi-monitor setups). - """ - scenarios = _make_scenarios() - - def setUp(self): - super(LauncherTestCase, self).setUp() - self.screen_geo = ScreenGeometry() - self.set_unity_log_level("unity.launcher", "DEBUG") - self.addCleanup(self.set_unity_log_level, "unity.launcher", "INFO") - - self.set_unity_option('num_launchers', int(self.only_primary)) - self.launcher_instance = self.get_launcher() - - if self.only_primary: - try: - old_primary_screen = self.screen_geo.get_primary_monitor() - self.screen_geo.set_primary_monitor(self.launcher_monitor) - self.addCleanup(self.screen_geo.set_primary_monitor, old_primary_screen) - except ScreenGeometry.BlacklistedDriverError: - self.skipTest("Impossible to set the monitor %d as primary" % self.launcher_monitor) - - def get_launcher(self): - """Get the launcher for the current scenario.""" - return self.launcher.get_launcher_for_monitor(self.launcher_monitor) - - -class LauncherSwitcherTests(LauncherTestCase): - """ Tests the functionality of the launcher's switcher capability""" - - def start_switcher_with_cleanup_cancel(self): - """Start the launcher switcher and add a cleanup action to cancel it.""" - self.launcher_instance.switcher_start() - self.addCleanup(self.safe_quit_switcher) - - def safe_quit_switcher(self): - """Quit the keynav mode if it's engaged.""" - if self.launcher.key_nav_is_active: - self.launcher_instance.switcher_cancel() - - def test_launcher_switcher_cancel(self): - """Test that ending the launcher switcher actually works.""" - self.launcher_instance.switcher_start() - self.launcher_instance.switcher_cancel() - self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(False))) - - def test_launcher_switcher_cancel_resume_focus(self): - """Test that ending the launcher switcher resume the focus.""" - # TODO either remove this test from the class or don't initiate the - # switcher in setup. - self.close_all_app("Calculator") - calc = self.start_app("Calculator") - self.assertTrue(calc.is_active) - - self.start_switcher_with_cleanup_cancel() - sleep(.5) - self.assertFalse(calc.is_active) - - self.launcher_instance.switcher_cancel() - sleep(.5) - self.assertTrue(calc.is_active) - - def test_launcher_switcher_starts_at_index_zero(self): - """Test that starting the Launcher switcher puts the keyboard focus on item 0.""" - self.start_switcher_with_cleanup_cancel() - - self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(True))) - self.assertThat(self.launcher.key_nav_is_grabbed, Eventually(Equals(False))) - self.assertThat(self.launcher.key_nav_selection, Eventually(Equals(0))) - - def test_launcher_switcher_next(self): - """Moving to the next launcher item while switcher is activated must work.""" - self.start_switcher_with_cleanup_cancel() - self.launcher_instance.switcher_next() - # The launcher model has hidden items, so the keynav indexes do not - # increase by 1 each time. This test was failing because the 2nd icon - # had an index of 2, not 1 as expected. The best we can do here is to - # make sure that the index has increased. This opens us to the - # possibility that the launcher really is skipping forward more than one - # icon at a time, but we can't do much about that. - self.assertThat(self.launcher.key_nav_selection, Eventually(GreaterThan(0))) - - def test_launcher_switcher_prev(self): - """Moving to the previous launcher item while switcher is activated must work.""" - self.start_switcher_with_cleanup_cancel() - self.launcher_instance.switcher_prev() - self.assertThat(self.launcher.key_nav_selection, Eventually(NotEquals(0))) - - def test_launcher_switcher_down(self): - """Pressing the down arrow key while switcher is activated must work.""" - self.start_switcher_with_cleanup_cancel() - self.launcher_instance.switcher_down() - # The launcher model has hidden items, so the keynav indexes do not - # increase by 1 each time. This test was failing because the 2nd icon - # had an index of 2, not 1 as expected. The best we can do here is to - # make sure that the index has increased. This opens us to the - # possibility that the launcher really is skipping forward more than one - # icon at a time, but we can't do much about that. - self.assertThat(self.launcher.key_nav_selection, Eventually(GreaterThan(0))) - - def test_launcher_switcher_up(self): - """Pressing the up arrow key while switcher is activated must work.""" - self.start_switcher_with_cleanup_cancel() - self.launcher_instance.switcher_up() - self.assertThat(self.launcher.key_nav_selection, Eventually(NotEquals(0))) - - def test_launcher_switcher_next_doesnt_show_shortcuts(self): - """Moving forward in launcher switcher must not show launcher shortcuts.""" - self.start_switcher_with_cleanup_cancel() - self.launcher_instance.switcher_next() - # sleep so that the shortcut timeout could be triggered - sleep(2) - self.assertThat(self.launcher_instance.shortcuts_shown, Eventually(Equals(False))) - - def test_launcher_switcher_prev_doesnt_show_shortcuts(self): - """Moving backward in launcher switcher must not show launcher shortcuts.""" - self.start_switcher_with_cleanup_cancel() - self.launcher_instance.switcher_prev() - # sleep so that the shortcut timeout could be triggered - sleep(2) - self.assertThat(self.launcher_instance.shortcuts_shown, Eventually(Equals(False))) - - def test_launcher_switcher_cycling_forward(self): - """Launcher Switcher must loop through icons when cycling forwards""" - self.start_switcher_with_cleanup_cancel() - prev_icon = 0 - num_icons = self.launcher.model.num_launcher_icons() - logger.info("This launcher has %d icons", num_icons) - for icon in range(1, num_icons): - self.launcher_instance.switcher_next() - # FIXME We can't directly check for selection/icon number equalty - # since the launcher model also contains "hidden" icons that aren't - # shown, so the selection index can increment by more than 1. - self.assertThat(self.launcher.key_nav_selection, Eventually(GreaterThan(prev_icon))) - prev_icon = self.launcher.key_nav_selection - - self.launcher_instance.switcher_next() - self.assertThat(self.launcher.key_nav_selection, Eventually(Equals(0))) - - def test_launcher_switcher_cycling_backward(self): - """Launcher Switcher must loop through icons when cycling backwards""" - self.start_switcher_with_cleanup_cancel() - self.launcher_instance.switcher_prev() - # FIXME We can't directly check for self.launcher.num_launcher_icons - 1 - self.assertThat(self.launcher.key_nav_selection, Eventually(GreaterThan(1))) - - def test_launcher_switcher_activate_keep_focus(self): - """Activating a running launcher icon should focus the application.""" - calc = self.start_app("Calculator") - mahjongg = self.start_app("Mahjongg") - self.assertTrue(mahjongg.is_active) - self.assertFalse(calc.is_active) - - self.start_switcher_with_cleanup_cancel() - - found = False - for icon in self.launcher.model.get_launcher_icons_for_monitor(self.launcher_monitor): - if (icon.tooltip_text == calc.name): - found = True - self.launcher_instance.switcher_activate() - break - else: - self.launcher_instance.switcher_next() - - if not found: - self.addCleanup(self.launcher_instance.switcher_cancel) - - self.assertTrue(found) - # TODO - we need to extend the Eventually() matcher to work on regular - # attributes too, at which point we can stop writing ugly stuff in our - # tests like this: - for i in range(10): - if calc.is_active and not mahjongg.is_active: - break - sleep(1) - - self.assertTrue(calc.is_active) - self.assertFalse(mahjongg.is_active) - - def test_launcher_switcher_using_shorcuts(self): - """Using some other shortcut while switcher is active must cancel switcher.""" - self.start_switcher_with_cleanup_cancel() - self.keyboard.press_and_release("s") - sleep(.25) - self.keyboard.press_and_release("Escape") - sleep(.25) - self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(False))) - - -class LauncherShortcutTests(LauncherTestCase): - """Tests for the shortcut hint window.""" - - def setUp(self): - super(LauncherShortcutTests, self).setUp() - self.launcher_instance.keyboard_reveal_launcher() - self.addCleanup(self.launcher_instance.keyboard_unreveal_launcher) - sleep(2) - - def test_launcher_keyboard_reveal_shows_shortcut_hints(self): - """Launcher icons must show shortcut hints after revealing with keyboard.""" - self.assertThat(self.launcher_instance.shortcuts_shown, Eventually(Equals(True))) - - def test_launcher_switcher_keeps_shorcuts(self): - """Initiating launcher switcher after showing shortcuts must not hide shortcuts""" - self.launcher_instance.switcher_start() - self.addCleanup(self.launcher_instance.switcher_cancel) - - self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(True))) - self.assertThat(self.launcher_instance.shortcuts_shown, Eventually(Equals(True))) - - def test_launcher_switcher_next_keeps_shortcuts(self): - """Launcher switcher next action must keep shortcuts after they've been shown.""" - self.launcher_instance.switcher_start() - self.addCleanup(self.launcher_instance.switcher_cancel) - self.launcher_instance.switcher_next() - self.assertThat(self.launcher_instance.shortcuts_shown, Eventually(Equals(True))) - - def test_launcher_switcher_prev_keeps_shortcuts(self): - """Launcher switcher prev action must keep shortcuts after they've been shown.""" - self.launcher_instance.switcher_start() - self.addCleanup(self.launcher_instance.switcher_cancel) - self.launcher_instance.switcher_prev() - self.assertThat(self.launcher_instance.shortcuts_shown, Eventually(Equals(True))) - - -class LauncherKeyNavTests(LauncherTestCase): - """Test the launcher key navigation""" - - def start_keynav_with_cleanup_cancel(self): - self.launcher_instance.key_nav_start() - self.addCleanup(self.safe_quit_keynav) - - def safe_quit_keynav(self): - """Quit the keynav mode if it's engaged.""" - if self.launcher.key_nav_is_active: - self.launcher_instance.key_nav_cancel() - - def test_launcher_keynav_initiate(self): - """Tests we can initiate keyboard navigation on the launcher.""" - self.start_keynav_with_cleanup_cancel() - self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(True))) - self.assertThat(self.launcher.key_nav_is_grabbed, Eventually(Equals(True))) - - def test_launcher_keynav_cancel(self): - """Test that we can exit keynav mode.""" - self.launcher_instance.key_nav_start() - self.launcher_instance.key_nav_cancel() - self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(False))) - self.assertThat(self.launcher.key_nav_is_grabbed, Eventually(Equals(False))) - - def test_launcher_keynav_cancel_resume_focus(self): - """Test that ending the launcher keynav resume the focus.""" - calc = self.start_app("Calculator") - self.assertTrue(calc.is_active) - - self.start_keynav_with_cleanup_cancel() - self.assertFalse(calc.is_active) - - self.launcher_instance.key_nav_cancel() - self.assertTrue(calc.is_active) - - def test_launcher_keynav_starts_at_index_zero(self): - """Test keynav mode starts at index 0.""" - self.start_keynav_with_cleanup_cancel() - self.assertThat(self.launcher.key_nav_selection, Eventually(Equals(0))) - - def test_launcher_keynav_forward(self): - """Must be able to move forwards while in keynav mode.""" - self.start_keynav_with_cleanup_cancel() - self.launcher_instance.key_nav_next() - # The launcher model has hidden items, so the keynav indexes do not - # increase by 1 each time. This test was failing because the 2nd icon - # had an index of 2, not 1 as expected. The best we can do here is to - # make sure that the index has increased. This opens us to the - # possibility that the launcher really is skipping forward more than one - # icon at a time, but we can't do much about that. - self.assertThat(self.launcher.key_nav_selection, Eventually(GreaterThan(0))) - - def test_launcher_keynav_prev_works(self): - """Must be able to move backwards while in keynav mode.""" - self.start_keynav_with_cleanup_cancel() - self.launcher_instance.key_nav_next() - self.assertThat(self.launcher.key_nav_selection, Eventually(GreaterThan(0))) - self.launcher_instance.key_nav_prev() - self.assertThat(self.launcher.key_nav_selection, Eventually(Equals(0))) - - def test_launcher_keynav_cycling_forward(self): - """Launcher keynav must loop through icons when cycling forwards""" - self.start_keynav_with_cleanup_cancel() - prev_icon = 0 - for icon in range(1, self.launcher.model.num_launcher_icons()): - self.launcher_instance.key_nav_next() - # FIXME We can't directly check for selection/icon number equalty - # since the launcher model also contains "hidden" icons that aren't - # shown, so the selection index can increment by more than 1. - self.assertThat(self.launcher.key_nav_selection, Eventually(GreaterThan(prev_icon))) - prev_icon = self.launcher.key_nav_selection - - self.launcher_instance.key_nav_next() - self.assertThat(self.launcher.key_nav_selection, Eventually(Equals(0))) - - def test_launcher_keynav_cycling_backward(self): - """Launcher keynav must loop through icons when cycling backwards""" - self.start_keynav_with_cleanup_cancel() - self.launcher_instance.key_nav_prev() - # FIXME We can't directly check for self.launcher.num_launcher_icons - 1 - self.assertThat(self.launcher.key_nav_selection, Eventually(GreaterThan(1))) - - def test_launcher_keynav_can_open_and_close_quicklist(self): - """Tests that we can open and close a quicklist from keynav mode.""" - self.start_keynav_with_cleanup_cancel() - self.launcher_instance.key_nav_next() - self.launcher_instance.key_nav_enter_quicklist() - self.assertThat(self.launcher_instance.quicklist_open, Eventually(Equals(True))) - self.launcher_instance.key_nav_exit_quicklist() - self.assertThat(self.launcher_instance.quicklist_open, Eventually(Equals(False))) - self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(True))) - self.assertThat(self.launcher.key_nav_is_grabbed, Eventually(Equals(True))) - - def test_launcher_keynav_mode_toggles(self): - """Tests that keynav mode toggles with Alt+F1.""" - # was initiated in setup. - self.start_keynav_with_cleanup_cancel() - self.keybinding("launcher/keynav") - self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(False))) - - def test_launcher_keynav_activate_keep_focus(self): - """Activating a running launcher icon must focus it.""" - calc = self.start_app("Calculator") - mahjongg = self.start_app("Mahjongg") - self.assertTrue(mahjongg.is_active) - self.assertFalse(calc.is_active) - - self.start_keynav_with_cleanup_cancel() - - found = False - for icon in self.launcher.model.get_launcher_icons_for_monitor(self.launcher_monitor): - if (icon.tooltip_text == calc.name): - found = True - self.launcher_instance.key_nav_activate() - break - else: - self.launcher_instance.key_nav_next() - - sleep(.5) - - self.assertTrue(found) - self.assertTrue(calc.is_active) - self.assertFalse(mahjongg.is_active) - - def test_launcher_keynav_expo_focus(self): - """When entering expo mode from KeyNav the Desktop must get focus.""" - self.start_keynav_with_cleanup_cancel() - - for icon in self.launcher.model.get_launcher_icons_for_monitor(self.launcher_monitor): - if (icon.tooltip_text == "Workspace Switcher"): - self.launcher_instance.key_nav_activate() - break - self.launcher_instance.key_nav_next() - - self.assertThat(self.panels.get_active_panel().title, Eventually(Equals("Ubuntu Desktop"))) - - def test_launcher_keynav_expo_exit_on_esc(self): - """Esc should quit expo when entering it from KeyNav.""" - self.start_keynav_with_cleanup_cancel() - - for icon in self.launcher.model.get_launcher_icons_for_monitor(self.launcher_monitor): - if (icon.tooltip_text == "Workspace Switcher"): - self.launcher_instance.key_nav_activate() - break - self.launcher_instance.key_nav_next() - - self.keyboard.press_and_release("Escape") - self.assertThat(self.window_manager.expo_active, Eventually(Equals(False))) - - def test_launcher_keynav_alt_tab_quits(self): - """Tests that alt+tab exits keynav mode.""" - self.start_keynav_with_cleanup_cancel() - - self.keybinding("switcher/reveal_normal") - self.addCleanup(self.switcher.terminate) - self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(False))) - - def test_launcher_keynav_alt_grave_quits(self): - """Tests that alt+` exits keynav mode.""" - self.start_keynav_with_cleanup_cancel() - # Can't use switcher emulat here since the switcher won't appear. - self.keybinding("switcher/reveal_details") - self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(False))) - - def test_launcher_keynav_cancel_doesnt_activate_icon(self): - """This tests when canceling keynav the current icon doesnt activate.""" - self.start_keynav_with_cleanup_cancel() - self.keyboard.press_and_release("Escape") - self.assertThat(self.dash.visible, Eventually(Equals(False))) - -class LauncherIconsBehaviorTests(LauncherTestCase): - """Test the launcher icons interactions""" - - def test_launcher_activate_last_focused_window(self): - """This tests shows that when you activate a launcher icon only the last - focused instance of that application is rasied. - - This is tested by opening 2 Mahjongg and a Calculator. - Then we activate the Calculator launcher icon. - Then we actiavte the Mahjongg launcher icon. - Then we minimize the focused applications. - This should give focus to the next window on the stack. - Then we activate the Mahjongg launcher icon - This should bring to focus the non-minimized window. - If only 1 instance is raised then the Calculator gets the focus. - If ALL the instances are raised then the second Mahjongg gets the focus. - - """ - mahj = self.start_app("Mahjongg") - [mah_win1] = mahj.get_windows() - self.assertTrue(mah_win1.is_focused) - - calc = self.start_app("Calculator") - [calc_win] = calc.get_windows() - self.assertTrue(calc_win.is_focused) - - self.start_app("Mahjongg") - # Sleeping due to the start_app only waiting for the bamf model to be - # updated with the application. Since the app has already started, - # and we are just waiting on a second window, however a defined sleep - # here is likely to be problematic. - # TODO: fix bamf emulator to enable waiting for new windows. - sleep(1) - [mah_win2] = [w for w in mahj.get_windows() if w.x_id != mah_win1.x_id] - self.assertTrue(mah_win2.is_focused) - self.assertVisibleWindowStack([mah_win2, calc_win, mah_win1]) - - mahj_icon = self.launcher.model.get_icon_by_desktop_id(mahj.desktop_file) - calc_icon = self.launcher.model.get_icon_by_desktop_id(calc.desktop_file) - - self.launcher_instance.click_launcher_icon(calc_icon) - sleep(1) - self.assertTrue(calc_win.is_focused) - self.assertVisibleWindowStack([calc_win, mah_win2, mah_win1]) - - self.launcher_instance.click_launcher_icon(mahj_icon) - sleep(1) - self.assertTrue(mah_win2.is_focused) - self.assertVisibleWindowStack([mah_win2, calc_win, mah_win1]) - - self.keybinding("window/minimize") - sleep(1) - - self.assertTrue(mah_win2.is_hidden) - self.assertTrue(calc_win.is_focused) - self.assertVisibleWindowStack([calc_win, mah_win1]) - - self.launcher_instance.click_launcher_icon(mahj_icon) - sleep(1) - self.assertTrue(mah_win1.is_focused) - self.assertTrue(mah_win2.is_hidden) - self.assertVisibleWindowStack([mah_win1, calc_win]) - - def test_icon_shows_on_quick_application_reopen(self): - """Icons should stay on launcher when an application is quickly closed/reopened.""" - calc = self.start_app("Calculator") - desktop_file = calc.desktop_file - calc_icon = self.launcher.model.get_icon_by_desktop_id(desktop_file) - self.assertThat(calc_icon.visible, Eventually(Equals(True))) - - self.close_all_app("Calculator") - calc = self.start_app("Calculator") - sleep(2) - - calc_icon = self.launcher.model.get_icon_by_desktop_id(desktop_file) - self.assertThat(calc_icon, NotEquals(None)) - self.assertThat(calc_icon.visible, Eventually(Equals(True))) - - -class LauncherDragIconsBehavior(LauncherTestCase): - """Tests interation with dragging icons with the Launcher""" - - scenarios = multiply_scenarios(_make_scenarios(), - [ - ('inside', {'drag_type': IconDragType.INSIDE}), - ('outside', {'drag_type': IconDragType.OUTSIDE}), - ]) - - def ensure_calc_icon_not_in_launcher(self): - while 1: - icon = self.launcher.model.get_icon_by_desktop_id("gcalctool.desktop") - if not icon: - break - sleep(1) - - def test_can_drag_icon_below_bfb(self): - """Application icons must be draggable to below the BFB.""" - - self.ensure_calc_icon_not_in_launcher() - calc = self.start_app("Calculator") - calc_icon = self.launcher.model.get_icon_by_desktop_id(calc.desktop_file) - - bfb_icon_position = 0 - self.launcher_instance.drag_icon_to_position(calc_icon, - bfb_icon_position, - self.drag_type) - moved_icon = self.launcher.model.\ - get_launcher_icons_for_monitor(self.launcher_monitor)[1] - self.assertThat(moved_icon.id, Equals(calc_icon.id)) - - def test_can_drag_icon_above_window_switcher(self): - """Launcher icons must be dragable to above the workspace switcher icon.""" - - self.ensure_calc_icon_not_in_launcher() - calc = self.start_app("Calculator") - calc_icon = self.launcher.model.get_icon_by_desktop_id(calc.desktop_file) - - # Move a known icon to the top as it needs to be more than 2 icon - # spaces away for this test to actually do anything - bfb_icon_position = 0 - self.launcher_instance.drag_icon_to_position(calc_icon, - bfb_icon_position, - self.drag_type) - sleep(1) - switcher_pos = -2 - self.launcher_instance.drag_icon_to_position(calc_icon, - switcher_pos, - self.drag_type) - - moved_icon = self.launcher.model.\ - get_launcher_icons_for_monitor(self.launcher_monitor)[-3] - self.assertThat(moved_icon.id, Equals(calc_icon.id)) - - -class LauncherRevealTests(LauncherTestCase): - """Test the launcher reveal behavior when in autohide mode.""" - - def setUp(self): - super(LauncherRevealTests, self).setUp() - # these automatically reset to the original value, as implemented in AutopilotTestCase - self.set_unity_option('launcher_capture_mouse', True) - self.set_unity_option('launcher_hide_mode', 1) - launcher = self.get_launcher() - self.assertThat(launcher.hidemode, Eventually(Equals(1))) - - def test_launcher_keyboard_reveal_works(self): - """Revealing launcher with keyboard must work.""" - self.launcher_instance.keyboard_reveal_launcher() - self.addCleanup(self.launcher_instance.keyboard_unreveal_launcher) - self.assertThat(self.launcher_instance.is_showing, Eventually(Equals(True))) - - def test_reveal_on_mouse_to_edge(self): - """Tests reveal of launchers by mouse pressure.""" - self.launcher_instance.move_mouse_to_right_of_launcher() - self.launcher_instance.mouse_reveal_launcher() - self.assertThat(self.launcher_instance.is_showing, Eventually(Equals(True))) - - def test_reveal_with_mouse_under_launcher(self): - """Tests that the launcher hides properly if the - mouse is under the launcher when it is revealed. - """ - self.launcher_instance.move_mouse_over_launcher() - # we can't use "launcher_instance.keyboard_reveal_launcher()" - # since it moves the mouse out of the way, invalidating the test. - self.keybinding_hold("launcher/reveal") - sleep(1) - self.keybinding_release("launcher/reveal") - self.assertThat(self.launcher_instance.is_showing, Eventually(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. - """ - self.launcher_instance.move_mouse_to_right_of_launcher() - self.launcher_instance.mouse_reveal_launcher() - self.assertThat(self.launcher_instance.is_showing, Eventually(Equals(True))) - - def test_launcher_does_not_reveal_with_mouse_down(self): - """Launcher must not reveal if have mouse button 1 down.""" - self.screen_geo.move_mouse_to_monitor(self.launcher_instance.monitor) - self.mouse.press(1) - self.addCleanup(self.mouse.release, 1) - #FIXME: This is really bad API. it says reveal but it's expected to fail. bad bad bad!! - self.launcher_instance.mouse_reveal_launcher() - # Need a sleep here otherwise this test would pass even if the code failed. - # THis test needs to be rewritten... - sleep(5) - self.assertThat(self.launcher_instance.is_showing, Equals(False)) - - def test_new_icon_has_the_shortcut(self): - """New icons should have an associated shortcut""" - if self.launcher.model.num_bamf_launcher_icons() >= 10: - self.skip("There are already more than 9 icons in the launcher") - - desktop_file = self.KNOWN_APPS['Calculator']['desktop-file'] - if self.launcher.model.get_icon_by_desktop_id(desktop_file) != None: - self.skip("Calculator icon is already on the launcher.") - - self.start_app('Calculator') - icon = self.launcher.model.get_icon_by_desktop_id(desktop_file) - self.assertThat(icon.shortcut, GreaterThan(0)) - - -class LauncherVisualTests(LauncherTestCase): - """Tests for visual aspects of the launcher (icon saturation etc.).""" - - def test_keynav_from_dash_saturates_icons(self): - """Starting super+tab switcher from the dash must resaturate launcher icons. - - Tests fix for bug #913569. - """ - bfb = self.launcher.model.get_bfb_icon() - self.mouse.move(bfb.center_x, bfb.center_y) - self.dash.ensure_visible() - sleep(1) - # We can't use 'launcher_instance.switcher_start()' since it moves the mouse. - self.keybinding_hold_part_then_tap("launcher/switcher") - self.addCleanup(self.keybinding_release, "launcher/switcher") - self.addCleanup(self.keybinding, "launcher/switcher/exit") - - self.keybinding_tap("launcher/switcher/next") - for icon in self.launcher.model.get_launcher_icons(): - self.assertThat(icon.desaturated, Eventually(Equals(False))) - - def test_opening_dash_desaturates_icons(self): - """Opening the dash must desaturate all the launcher icons.""" - self.dash.ensure_visible() - self.addCleanup(self.dash.ensure_hidden) - - for icon in self.launcher.model.get_launcher_icons(): - if isinstance(icon, BFBLauncherIcon): - self.assertThat(icon.desaturated, Eventually(Equals(False))) - else: - self.assertThat(icon.desaturated, Eventually(Equals(True))) - - def test_opening_dash_with_mouse_over_launcher_keeps_icon_saturation(self): - """Opening dash with mouse over launcher must not desaturate icons.""" - launcher_instance = self.get_launcher() - x,y,w,h = launcher_instance.geometry - self.mouse.move(x + w/2, y + h/2) - sleep(.5) - self.dash.ensure_visible() - self.addCleanup(self.dash.ensure_hidden) - for icon in self.launcher.model.get_launcher_icons(): - self.assertThat(icon.desaturated, Eventually(Equals(False))) - - def test_mouse_over_with_dash_open_desaturates_icons(self): - """Moving mouse over launcher with dash open must saturate icons.""" - launcher_instance = self.get_launcher() - self.dash.ensure_visible() - self.addCleanup(self.dash.ensure_hidden) - sleep(.5) - x,y,w,h = launcher_instance.geometry - self.mouse.move(x + w/2, y + h/2) - sleep(.5) - for icon in self.launcher.model.get_launcher_icons(): - self.assertThat(icon.desaturated, Eventually(Equals(False))) - - -class LauncherCaptureTests(UnityTestCase): - """Test the launchers ability to capture/not capture the mouse.""" - - screen_geo = ScreenGeometry() - - def setHideMode(self, mode): - launcher = self.launcher.get_launcher_for_monitor(0) - self.assertThat(launcher.hidemode, Eventually(Equals(mode))) - - def leftMostMonitor(self): - x1, y1, width, height = self.screen_geo.get_monitor_geometry(0) - x2, y2, width, height = self.screen_geo.get_monitor_geometry(1) - - if x1 < x2: - return 0 - return 1 - - def rightMostMonitor(self): - return 1 - self.leftMostMonitor() - - def setUp(self): - super(LauncherCaptureTests, self).setUp() - self.set_unity_option('launcher_capture_mouse', True) - self.set_unity_option('launcher_hide_mode', 0) - self.set_unity_option('num_launchers', 0) - self.setHideMode(0) - - def test_launcher_captures_while_sticky_and_revealed(self): - """Tests that the launcher captures the mouse when moving between monitors - while revealed. - """ - if self.screen_geo.get_num_monitors() <= 1: - self.skipTest("Cannot run this test with a single monitor configured.") - - x, y, width, height = self.screen_geo.get_monitor_geometry(self.rightMostMonitor()) - self.mouse.move(x + width / 2, y + height / 2, False) - self.mouse.move(x - width / 2, y + height / 2, True, 5, .002) - - x_fin, y_fin = self.mouse.position() - # The launcher should have held the mouse a little bit - self.assertThat(x_fin, GreaterThan(x - width / 2)) - - def test_launcher_not_capture_while_not_sticky_and_revealed(self): - """Tests that the launcher doesn't captures the mouse when moving between monitors - while revealed and stick is off. - """ - if self.screen_geo.get_num_monitors() <= 1: - self.skipTest("Cannot run this test with a single monitor configured.") - - self.set_unity_option('launcher_capture_mouse', False) - - x, y, width, height = self.screen_geo.get_monitor_geometry(self.rightMostMonitor()) - self.mouse.move(x + width / 2, y + height / 2, False) - self.mouse.move(x - width / 2, y + height / 2, True, 5, .002) - - x_fin, y_fin = self.mouse.position() - # The launcher should have held the mouse a little bit - self.assertThat(x_fin, Equals(x - width / 2)) - - def test_launcher_not_capture_while_not_sticky_and_hidden_moving_right(self): - """Tests that the launcher doesn't capture the mouse when moving between monitors - while hidden and sticky is off. - """ - if self.screen_geo.get_num_monitors() <= 1: - self.skipTest("Cannot run this test with a single monitor configured.") - - self.set_unity_option('launcher_hide_mode', 1) - self.set_unity_option('launcher_capture_mouse', False) - - self.setHideMode(1) - - x, y, width, height = self.screen_geo.get_monitor_geometry(self.leftMostMonitor()) - self.mouse.move(x + width / 2, y + height / 2, False) - sleep(1.5) - self.mouse.move(x + width * 1.5, y + height / 2, True, 5, .002) - - x_fin, y_fin = self.mouse.position() - # The launcher should have held the mouse a little bit - self.assertThat(x_fin, Equals(x + width * 1.5)) - - def test_launcher_capture_while_sticky_and_hidden_moving_right(self): - """Tests that the launcher captures the mouse when moving between monitors - while hidden. - """ - if self.screen_geo.get_num_monitors() <= 1: - self.skipTest("Cannot run this test with a single monitor configured.") - - self.set_unity_option('launcher_hide_mode', 1) - - self.setHideMode(1) - - x, y, width, height = self.screen_geo.get_monitor_geometry(self.leftMostMonitor()) - self.mouse.move(x + width / 2, y + height / 2, False) - sleep(1.5) - self.mouse.move(x + width * 1.5, y + height / 2, True, 5, .002) - - x_fin, y_fin = self.mouse.position() - # The launcher should have held the mouse a little bit - self.assertThat(x_fin, LessThan(x + width * 1.5)) - - -class LauncherTooltipTests(UnityTestCase): - """Test the launcher tooltips""" - - def setUp(self): - super(LauncherTooltipTests, self).setUp() - self.set_unity_option('launcher_hide_mode', 0) - - def test_bfb_tooltip_disappear_when_dash_is_opened(self): - """Tests that the bfb tooltip disappear when the dash is opened.""" - bfb = self.launcher.model.get_bfb_icon() - self.mouse.move(bfb.center_x, bfb.center_y) - - self.dash.ensure_visible() - self.addCleanup(self.dash.ensure_hidden) - - self.assertThat(bfb.get_tooltip().active, Eventually(Equals(False))) - - def test_bfb_tooltip_is_disabled_when_dash_is_open(self): - """Tests the that bfb tooltip is disabled when the dash is open.""" - self.dash.ensure_visible() - self.addCleanup(self.dash.ensure_hidden) - - bfb = self.launcher.model.get_bfb_icon() - self.mouse.move(bfb.center_x, bfb.center_y) - - self.assertThat(bfb.get_tooltip().active, Eventually(Equals(False))) - - -class LauncherIconTests(UnityTestCase): - """Tests for the launcher icons.""" - - def assertNumberWinsIsEventually(self, app, num): - """Asserts that 'app' eventually has 'num' wins. Waits up to 10 seconds.""" - for i in range(10): - wins = app.get_windows() - if len(wins) == num: - return - sleep(1) - - self.assertThat(len(app.get_windows()), Equals(num)) - - def test_shift_click_opens_new_application_instance(self): - """Shift+Clicking MUST open a new instance of an already-running application.""" - app = self.start_app("Calculator") - desktop_id = app.desktop_file - icon = self.launcher.model.get_icon_by_desktop_id(desktop_id) - launcher_instance = self.launcher.get_launcher_for_monitor(0) - - self.keyboard.press("Shift") - self.addCleanup(self.keyboard.release, "Shift") - launcher_instance.click_launcher_icon(icon) - - self.assertNumberWinsIsEventually(app, 2) diff --git a/tests/autopilot/unity/tests/test_panel.py b/tests/autopilot/unity/tests/test_panel.py index bdcadde94..68a9f13ee 100644 --- a/tests/autopilot/unity/tests/test_panel.py +++ b/tests/autopilot/unity/tests/test_panel.py @@ -10,6 +10,7 @@ from __future__ import absolute_import from autopilot.emulators.X11 import ScreenGeometry from autopilot.emulators.bamf import BamfWindow +from autopilot.matchers import Eventually import logging import os from testtools.matchers import Equals, GreaterThan, NotEquals @@ -360,10 +361,6 @@ class PanelWindowButtonsTests(PanelTestsBase): self.assertTrue(text_win.is_hidden) - icon = self.launcher.model.get_icon_by_desktop_id(text_win.application.desktop_file) - launcher = self.launcher.get_launcher_for_monitor(self.panel_monitor) - launcher.click_launcher_icon(icon) - def test_window_buttons_minimize_follows_fitts_law(self): """Tests that the 'Minimize' button is conform to Fitts's Law. @@ -482,14 +479,13 @@ class PanelWindowButtonsTests(PanelTestsBase): """Tests that the 'Minimize' button is disabled for the dash.""" self.dash.ensure_visible() self.addCleanup(self.dash.ensure_hidden) - sleep(.5) button = self.panel.window_buttons.minimize button.mouse_click() sleep(.5) - self.assertFalse(button.enabled) - self.assertTrue(self.dash.visible) + self.assertThat(button.enabled, Eventually(Equals(False))) + self.assertThat(self.dash.visible, Eventually(Equals(True))) def test_window_buttons_maximization_buttons_works_for_dash(self): """'Maximize' and 'Restore' buttons (when both enabled) must work as expected.""" @@ -715,9 +711,8 @@ class PanelMenuTests(PanelTestsBase): # TODO: This doesn't test what it says on the tin. Setting MENUPROXY to '' # just makes the menu appear inside the app. That's fine, but it's not # what is described in the docstring or test id. - old_env = os.environ["UBUNTU_MENUPROXY"] - os.putenv("UBUNTU_MENUPROXY", "") - self.addCleanup(os.putenv, "UBUNTU_MENUPROXY", old_env) + self.patch_environment("UBUNTU_MENUPROXY", "") + calc_win = self.open_new_application_window("Calculator") sleep(1) diff --git a/tests/autopilot/unity/tests/test_quicklist.py b/tests/autopilot/unity/tests/test_quicklist.py index bdaec248d..f3a0d49b7 100644 --- a/tests/autopilot/unity/tests/test_quicklist.py +++ b/tests/autopilot/unity/tests/test_quicklist.py @@ -140,6 +140,22 @@ class QuicklistActionTests(UnityTestCase): self.assertThat(self.window_manager.scale_active, Eventually(Equals(True))) self.assertThat(self.window_manager.scale_active_for_group, Eventually(Equals(True))) + def test_quicklist_item_triggered_closes_dash(self): + """When any quicklist item is triggered it must close the dash.""" + + calc = self.start_app("Calculator") + [calc_win] = calc.get_windows() + self.assertTrue(calc_win.is_focused) + + self.dash.ensure_visible() + + calc_icon = self.launcher.model.get_icon_by_desktop_id(calc.desktop_file) + calc_ql = self.open_quicklist_for_icon(calc_icon) + + self.keyboard.press_and_release("Down") + self.keyboard.press_and_release("Enter") + self.assertThat(self.dash.visible, Eventually(Equals(False))) + class QuicklistKeyNavigationTests(UnityTestCase): """Tests for the quicklist key navigation.""" @@ -169,17 +185,13 @@ class QuicklistKeyNavigationTests(UnityTestCase): self.ql_launcher.key_nav_start() self.addCleanup(self.ql_launcher.key_nav_cancel) - for icon in self.launcher.model.get_launcher_icons(): - if icon.tooltip_text != self.ql_app.name: - self.ql_launcher.key_nav_next() - else: - self.keybinding("launcher/keynav/open-quicklist") - self.addCleanup(self.keybinding, "launcher/keynav/close-quicklist") - break + self.ql_launcher.keyboard_select_icon(tooltip_text=self.ql_app.name) + self.keybinding("launcher/keynav/open-quicklist") + self.addCleanup(self.keybinding, "launcher/keynav/close-quicklist") + self.assertThat(self.ql_launcher_icon.get_quicklist, Eventually(NotEquals(None))) self.quicklist = self.ql_launcher_icon.get_quicklist() - self.assertThat(self.quicklist, NotEquals(None)) - self.assertThat(self.quicklist.selected_item, NotEquals(None)) + self.assertThat(lambda: self.quicklist.selected_item, Eventually(NotEquals(None))) def test_keynav_selects_first_item_when_unselected(self): """Home key MUST select the first selectable item in a quicklist.""" diff --git a/tests/autopilot/unity/tests/test_shortcut_hint.py b/tests/autopilot/unity/tests/test_shortcut_hint.py index ad3acb2fb..4a0d32eb6 100644 --- a/tests/autopilot/unity/tests/test_shortcut_hint.py +++ b/tests/autopilot/unity/tests/test_shortcut_hint.py @@ -104,6 +104,13 @@ class ShortcutHintInteractionsTests(BaseShortcutHintTests): self.keybinding_tap("expo/start") self.addCleanup(self.keybinding, "expo/cancel") + def test_shortcut_hint_hide_pressing_modifiers(self): + """Pressing a modifer key must hide the shortcut hint.""" + self.shortcut_hint.ensure_visible() + self.addCleanup(self.shortcut_hint.ensure_hidden) + + self.keyboard.press('Control') + self.assertThat(self.shortcut_hint.visible, Eventually(Equals(False))) def test_launcher_switcher_next_doesnt_show_shortcut_hint(self): @@ -133,84 +140,6 @@ class ShortcutHintInteractionsTests(BaseShortcutHintTests): self.assertThat(self.shortcut_hint.visible, Equals(False)) - def test_launcher_switcher_next_keeps_shortcut_hint(self): - """Super+Tab switcher cycling forwards must not dispel an already-showing - shortcut hint. - - """ - show_timeout = self.shortcut_hint.get_show_timeout() - self.shortcut_hint.ensure_visible() - self.addCleanup(self.shortcut_hint.ensure_hidden) - - self.keybinding("launcher/switcher/next") - self.addCleanup(self.keyboard.press_and_release, "Escape") - - self.assertThat(self.launcher.key_nav_is_active, Equals(True)) - - self.keybinding("launcher/switcher/next") - sleep(show_timeout * 2) - self.assertThat(self.shortcut_hint.visible, Equals(True)) - - def test_launcher_switcher_prev_keeps_shortcut_hint(self): - """Super+Tab switcher cycling backwards must not dispel an already-showing - shortcut hint. - - """ - show_timeout = self.shortcut_hint.get_show_timeout() - self.shortcut_hint.ensure_visible() - self.addCleanup(self.shortcut_hint.ensure_visible) - - self.keybinding("launcher/switcher/next") - self.addCleanup(self.keyboard.press_and_release, "Escape") - self.assertThat(self.launcher.key_nav_is_active, Equals(True)) - - self.keybinding("launcher/switcher/prev") - self.keybinding("launcher/switcher/prev") - sleep(show_timeout * 2) - self.assertThat(self.shortcut_hint.visible, Equals(True)) - - def test_launcher_switcher_cancel_doesnt_hide_shortcut_hint(self): - """Cancelling the launcher switcher (by Escape) must not hide the - shortcut hint view. - - """ - self.shortcut_hint.ensure_visible() - self.addCleanup(self.shortcut_hint.ensure_hidden) - - self.keybinding("launcher/switcher/next") - # NOTE: This will generate an extra Escape keypress if the test passes, - # but that's better than the alternative... - self.addCleanup(self.keybinding, "launcher/switcher/exit") - - self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(True))) - self.assertThat(self.shortcut_hint.visible, Equals(True)) - - self.keyboard.press_and_release("Escape") - - self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(False))) - self.assertThat(self.shortcut_hint.visible, Equals(True)) - - def test_launcher_switcher_and_shortcut_hint_escaping(self): - """Cancelling the launcher switcher (by Escape) should not hide the - shortcut hint view, an extra keypress is needed. - - """ - self.shortcut_hint.ensure_visible() - self.addCleanup(self.shortcut_hint.ensure_hidden) - - self.keybinding("launcher/switcher/next") - - self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(True))) - self.assertThat(self.shortcut_hint.visible, Equals(True)) - - self.keyboard.press_and_release("Escape") - - self.assertThat(self.launcher.key_nav_is_active, Eventually(Equals(False))) - self.assertThat(self.shortcut_hint.visible, Equals(True)) - - self.keyboard.press_and_release("Escape") - self.assertThat(self.shortcut_hint.visible, Eventually(Equals(False))) - def test_launcher_icons_hints_show_with_shortcut_hint(self): """When the shortcut hint is shown also the launcer's icons hints should be shown. diff --git a/tests/autopilot/unity/tests/test_switcher.py b/tests/autopilot/unity/tests/test_switcher.py index 5f044d0ed..c16a52f3d 100644 --- a/tests/autopilot/unity/tests/test_switcher.py +++ b/tests/autopilot/unity/tests/test_switcher.py @@ -52,10 +52,10 @@ class SwitcherTests(SwitcherTestCase): """Starting switcher in details mode must show the focused window title.""" app = self.start_app("Text Editor") sleep(1) - self.switcher.initiate(SwitcherMode.DETAIL) - self.addCleanup(self.switcher.terminate) [title] = [w.title for w in app.get_windows() if w.is_focused] + self.switcher.initiate(SwitcherMode.DETAIL) + self.addCleanup(self.switcher.terminate) self.assertThat(self.switcher.controller.view.label, Eventually(Equals(title))) @@ -190,6 +190,22 @@ class SwitcherTests(SwitcherTestCase): self.addCleanup(self.switcher.terminate) self.assertThat(self.switcher.controller.monitor, Eventually(Equals(monitor))) + def test_switcher_alt_f4_is_disabled(self): + """Tests that alt+f4 does not work while switcher is active.""" + + app = self.start_app("Text Editor") + sleep(1) + + self.switcher.initiate(SwitcherMode.DETAIL) + self.addCleanup(self.switcher.terminate) + + self.keyboard.press_and_release("Alt+F4") + [win] = [w for w in app.get_windows()] + + # Need the sleep to allow the window time to close, for jenkins! + sleep(10) + self.assertThat(win.is_valid, Equals(True)) + class SwitcherWindowsManagementTests(SwitcherTestCase): """Test the switcher window management.""" diff --git a/tests/test_glib_signals.cpp b/tests/test_glib_signals.cpp index 7c8f210ca..e3f0fa34c 100644 --- a/tests/test_glib_signals.cpp +++ b/tests/test_glib_signals.cpp @@ -115,26 +115,22 @@ protected: char arg6_; }; +class MockSignalManager : public SignalManager +{ +public: + std::vector<SignalBase::Ptr> GetConnections() const { return connections_; } +}; + TEST_F(TestGLibSignals, TestConstructions) { - SignalBase base; - - Signal0<void, TestSignals*> signal0; - Signal1<void, TestSignals*, string> signal1; - Signal2<void, TestSignals*, string, int> signal2; - Signal3<void, TestSignals*, string, int, float> signal3; - Signal4<void, TestSignals*, string, int, float, double> signal4; - Signal5<void, TestSignals*, string, int, float, double, gboolean> signal5; - Signal6<gboolean, TestSignals*, string, int, float, double, gboolean, char> signal6; - - Signal<void, TestSignals*> signal00; - Signal<void, TestSignals*, string> signal01; - Signal<void, TestSignals*, string, int> signal02; - Signal<void, TestSignals*, string, int, float> signal03; - Signal<void, TestSignals*, string, int, float, double> signal04; - Signal<void, TestSignals*, string, int, float, double, gboolean> signal05; - Signal<gboolean, TestSignals*, string, int, float, double, gboolean, char> signal06; + Signal<void, TestSignals*> signal0; + Signal<void, TestSignals*, string> signal1; + Signal<void, TestSignals*, string, int> signal2; + Signal<void, TestSignals*, string, int, float> signal3; + Signal<void, TestSignals*, string, int, float, double> signal4; + Signal<void, TestSignals*, string, int, float, double, gboolean> signal5; + Signal<gboolean, TestSignals*, string, int, float, double, gboolean, char> signal6; } TEST_F(TestGLibSignals, TestSignal0) @@ -282,12 +278,13 @@ TEST_F(TestGLibSignals, TestCleanDestruction) TEST_F(TestGLibSignals, TestManagerConstruction) { - SignalManager manager; + MockSignalManager manager; + EXPECT_TRUE(manager.GetConnections().empty()); } TEST_F(TestGLibSignals, TestManagerAddition) { - SignalManager manager; + MockSignalManager manager; manager.Add(new Signal<void, TestSignals*>(test_signals_, "signal0", @@ -310,11 +307,34 @@ TEST_F(TestGLibSignals, TestManagerAddition) manager.Add(new Signal<gboolean, TestSignals*, const char*, int, float, double, gboolean, char>(test_signals_, "signal6", sigc::mem_fun(this, &TestGLibSignals::Signal6Callback))); + + EXPECT_EQ(manager.GetConnections().size(), 7); +} + +TEST_F(TestGLibSignals, TestManagerAdditionTemplate) +{ + MockSignalManager manager; + + manager.Add<void, TestSignals*>(test_signals_, "signal0", + sigc::mem_fun(this, &TestGLibSignals::Signal0Callback)); + manager.Add<void, TestSignals*, const char*>(test_signals_, "signal1", + sigc::mem_fun(this, &TestGLibSignals::Signal1Callback)); + manager.Add<void, TestSignals*, const char*, int>(test_signals_, "signal2", + sigc::mem_fun(this, &TestGLibSignals::Signal2Callback)); + manager.Add<void, TestSignals*, const char*, int, float>(test_signals_, "signal3", + sigc::mem_fun(this, &TestGLibSignals::Signal3Callback)); + manager.Add<void, TestSignals*, const char*, int, float, double>(test_signals_, "signal4", + sigc::mem_fun(this, &TestGLibSignals::Signal4Callback)); + manager.Add<void, TestSignals*, const char*, int, float, double, gboolean>(test_signals_, "signal5", + sigc::mem_fun(this, &TestGLibSignals::Signal5Callback)); + manager.Add<gboolean, TestSignals*, const char*, int, float, double, gboolean, char>(test_signals_, "signal6", sigc::mem_fun(this, &TestGLibSignals::Signal6Callback)); + + EXPECT_EQ(manager.GetConnections().size(), 7); } TEST_F(TestGLibSignals, TestManagerConnection) { - SignalManager manager; + MockSignalManager manager; manager.Add(new Signal<void, TestSignals*>(test_signals_, "signal0", @@ -330,9 +350,8 @@ TEST_F(TestGLibSignals, TestManagerConnection) EXPECT_TRUE(signal1_received_); gboolean ret = FALSE; - manager.Add(new Signal<gboolean, TestSignals*, const char*, int, float, double, gboolean, char>(test_signals_, - "signal6", - sigc::mem_fun(this, &TestGLibSignals::Signal6Callback))); + manager.Add<gboolean, TestSignals*, const char*, int, float, double, gboolean, char>(test_signals_, "signal6", + sigc::mem_fun(this, &TestGLibSignals::Signal6Callback)); g_signal_emit_by_name(test_signals_, "signal6", "test", 100, 1.0f, 100.00, FALSE, 'x', &ret); EXPECT_TRUE(signal6_received_); EXPECT_TRUE(ret); diff --git a/tests/test_hud_controller.cpp b/tests/test_hud_controller.cpp index 5ee7b7989..6bd379fe2 100644 --- a/tests/test_hud_controller.cpp +++ b/tests/test_hud_controller.cpp @@ -59,7 +59,7 @@ public: virtual void SetUp() { view = new MockHudView; - controller.reset(new hud::Controller([&view]{ return view.GetPointer(); })); + controller.reset(new hud::Controller([this]{ return view.GetPointer(); })); } Settings unity_settings; @@ -73,6 +73,7 @@ public: TEST_F(TestHudController, TestHideHud) { controller->ShowHud(); + Utils::WaitForTimeout(1); EXPECT_CALL(*view, ResetToDefault()) .Times(1); diff --git a/tests/test_im_text_entry.cpp b/tests/test_im_text_entry.cpp index d10125e36..2c5457119 100644 --- a/tests/test_im_text_entry.cpp +++ b/tests/test_im_text_entry.cpp @@ -24,6 +24,7 @@ using namespace testing; using namespace unity; +using namespace nux; namespace { @@ -48,14 +49,15 @@ public: class MockTextEntry : public IMTextEntry { public: - MOCK_METHOD1(InsertText, void(std::string const&)); - MOCK_METHOD0(Cut, void()); - MOCK_METHOD0(Copy, void()); - MOCK_METHOD1(Paste, void(bool)); + MOCK_METHOD0(CutClipboard, void()); + MOCK_METHOD0(CopyClipboard, void()); + MOCK_METHOD0(PasteClipboard, void()); + MOCK_METHOD0(PastePrimaryClipboard, void()); - bool TryHandleSpecial(nux::Event const& event) + bool InspectKeyEvent(nux::Event const& event) { - return IMTextEntry::TryHandleSpecial(event); + key_down.emit(event.type, event.GetKeySym(), event.GetKeyState(), nullptr, 0); + return IMTextEntry::InspectKeyEvent(event); } }; @@ -66,8 +68,8 @@ TEST(TestIMTextEntry, CopyCtrlC) TestEvent event(KEY_MODIFIER_CTRL, NUX_VK_c); - EXPECT_CALL(text_entry, Copy()); - EXPECT_FALSE(text_entry.TryHandleSpecial(event)); + EXPECT_CALL(text_entry, CopyClipboard()); + EXPECT_TRUE(text_entry.InspectKeyEvent(event)); } TEST(TestIMTextEntry, CopyCtrlIns) @@ -76,8 +78,8 @@ TEST(TestIMTextEntry, CopyCtrlIns) TestEvent event(KEY_MODIFIER_CTRL, NUX_VK_INSERT); - EXPECT_CALL(text_entry, Copy()); - EXPECT_FALSE(text_entry.TryHandleSpecial(event)); + EXPECT_CALL(text_entry, CopyClipboard()); + EXPECT_TRUE(text_entry.InspectKeyEvent(event)); } TEST(TestIMTextEntry, PasteCtrlV) @@ -86,8 +88,8 @@ TEST(TestIMTextEntry, PasteCtrlV) TestEvent event(KEY_MODIFIER_CTRL, NUX_VK_v); - EXPECT_CALL(text_entry, Paste(false)); - EXPECT_FALSE(text_entry.TryHandleSpecial(event)); + EXPECT_CALL(text_entry, PasteClipboard()); + EXPECT_TRUE(text_entry.InspectKeyEvent(event)); } TEST(TestIMTextEntry, PasteShiftIns) @@ -96,8 +98,8 @@ TEST(TestIMTextEntry, PasteShiftIns) TestEvent event(KEY_MODIFIER_SHIFT, NUX_VK_INSERT); - EXPECT_CALL(text_entry, Paste(false)); - EXPECT_FALSE(text_entry.TryHandleSpecial(event)); + EXPECT_CALL(text_entry, PasteClipboard()); + EXPECT_TRUE(text_entry.InspectKeyEvent(event)); } TEST(TestIMTextEntry, CutCtrlX) @@ -106,8 +108,8 @@ TEST(TestIMTextEntry, CutCtrlX) TestEvent event(KEY_MODIFIER_CTRL, NUX_VK_x); - EXPECT_CALL(text_entry, Cut()); - EXPECT_FALSE(text_entry.TryHandleSpecial(event)); + EXPECT_CALL(text_entry, CutClipboard()); + EXPECT_TRUE(text_entry.InspectKeyEvent(event)); } TEST(TestIMTextEntry, CutShiftDel) @@ -116,8 +118,8 @@ TEST(TestIMTextEntry, CutShiftDel) TestEvent event(KEY_MODIFIER_SHIFT, NUX_VK_DELETE); - EXPECT_CALL(text_entry, Cut()); - EXPECT_FALSE(text_entry.TryHandleSpecial(event)); + EXPECT_CALL(text_entry, CutClipboard()); + EXPECT_TRUE(text_entry.InspectKeyEvent(event)); } TEST(TestIMTextEntry, CtrlMoveKeys) @@ -125,16 +127,16 @@ TEST(TestIMTextEntry, CtrlMoveKeys) MockTextEntry text_entry; TestEvent left(KEY_MODIFIER_CTRL, NUX_VK_LEFT); - EXPECT_TRUE(text_entry.TryHandleSpecial(left)); + EXPECT_TRUE(text_entry.InspectKeyEvent(left)); TestEvent right(KEY_MODIFIER_CTRL, NUX_VK_RIGHT); - EXPECT_TRUE(text_entry.TryHandleSpecial(right)); + EXPECT_TRUE(text_entry.InspectKeyEvent(right)); TestEvent home(KEY_MODIFIER_CTRL, NUX_VK_HOME); - EXPECT_TRUE(text_entry.TryHandleSpecial(home)); + EXPECT_TRUE(text_entry.InspectKeyEvent(home)); TestEvent end(KEY_MODIFIER_CTRL, NUX_VK_END); - EXPECT_TRUE(text_entry.TryHandleSpecial(end)); + EXPECT_TRUE(text_entry.InspectKeyEvent(end)); } TEST(TestIMTextEntry, CtrlDeleteKeys) @@ -142,10 +144,10 @@ TEST(TestIMTextEntry, CtrlDeleteKeys) MockTextEntry text_entry; TestEvent del(KEY_MODIFIER_CTRL, NUX_VK_DELETE); - EXPECT_TRUE(text_entry.TryHandleSpecial(del)); + EXPECT_TRUE(text_entry.InspectKeyEvent(del)); TestEvent backspace(KEY_MODIFIER_CTRL, NUX_VK_BACKSPACE); - EXPECT_TRUE(text_entry.TryHandleSpecial(backspace)); + EXPECT_TRUE(text_entry.InspectKeyEvent(backspace)); } TEST(TestIMTextEntry, CtrlA) @@ -153,7 +155,7 @@ TEST(TestIMTextEntry, CtrlA) MockTextEntry text_entry; TestEvent selectall(KEY_MODIFIER_CTRL, NUX_VK_a); - EXPECT_TRUE(text_entry.TryHandleSpecial(selectall)); + EXPECT_TRUE(text_entry.InspectKeyEvent(selectall)); } TEST(TestIMTextEntry, CtrlKeybindings) @@ -165,15 +167,10 @@ TEST(TestIMTextEntry, CtrlKeybindings) NUX_VK_HOME, NUX_VK_END, NUX_VK_BACKSPACE, NUX_VK_DELETE }; - for (unsigned long keysym = 0; keysym < XK_VoidSymbol; ++keysym) + for (auto keysym : allowed_keys) { - bool should_be_handled = false; - - if (std::find(allowed_keys.begin(), allowed_keys.end(), keysym) != allowed_keys.end()) - should_be_handled = true; - TestEvent event(KEY_MODIFIER_CTRL, keysym); - EXPECT_EQ(text_entry.TryHandleSpecial(event), should_be_handled); + EXPECT_TRUE(text_entry.InspectKeyEvent(event)); } } @@ -184,7 +181,7 @@ TEST(TestIMTextEntry, AltKeybindings) for (unsigned long keysym = 0; keysym < XK_VoidSymbol; ++keysym) { TestEvent event(KEY_MODIFIER_ALT, keysym); - EXPECT_FALSE(text_entry.TryHandleSpecial(event)); + EXPECT_FALSE(text_entry.InspectKeyEvent(event)); } } @@ -195,7 +192,7 @@ TEST(TestIMTextEntry, SuperKeybindings) for (unsigned long keysym = 0; keysym < XK_VoidSymbol; ++keysym) { TestEvent event(KEY_MODIFIER_SUPER, keysym); - EXPECT_FALSE(text_entry.TryHandleSpecial(event)); + EXPECT_FALSE(text_entry.InspectKeyEvent(event)); } } diff --git a/tests/test_introspection.cpp b/tests/test_introspection.cpp index a88cbbe90..53b9f626a 100644 --- a/tests/test_introspection.cpp +++ b/tests/test_introspection.cpp @@ -94,12 +94,12 @@ protected: }; -TEST_F(TestIntrospection, TestTest) +TEST_F(TestIntrospection, TestTest) { ASSERT_STREQ("Unity", root_->GetName().c_str()); } -TEST_F(TestIntrospection, TestVariousRootQueries) +TEST_F(TestIntrospection, TestVariousRootQueries) { std::list<Introspectable*> results; std::string query; @@ -108,7 +108,7 @@ TEST_F(TestIntrospection, TestVariousRootQueries) ASSERT_EQ(1, results.size()); EXPECT_STREQ("Unity", results.front()->GetName().c_str()); - query = "/"; + query = "/"; results = GetIntrospectableNodesFromQuery(query, root_.get()); ASSERT_EQ(1, results.size()); EXPECT_STREQ("Unity", results.front()->GetName().c_str()); @@ -119,6 +119,37 @@ TEST_F(TestIntrospection, TestVariousRootQueries) EXPECT_STREQ("Unity", results.front()->GetName().c_str()); } +TEST_F(TestIntrospection, TestAsteriskWildcard) +{ + std::list<Introspectable*> results; + std::string query = "/Unity/*"; + + results = GetIntrospectableNodesFromQuery(query, root_.get()); + ASSERT_EQ(2, results.size()); + + for(auto p : results) + { + ASSERT_TRUE( + p->GetName() == "DashController" || + p->GetName() == "PanelController" + ); + } +} + +TEST_F(TestIntrospection, TestRelativeAsteriskWildcard) +{ + std::list<Introspectable*> results; + std::string query = "//DashController/*"; + + results = GetIntrospectableNodesFromQuery(query, root_.get()); + ASSERT_EQ(3, results.size()); + + for(auto p : results) + { + ASSERT_TRUE(p->GetName() == "Foo"); + } +} + TEST_F(TestIntrospection, TestAbsoluteQueries) { std::list<Introspectable*> results; @@ -136,14 +167,14 @@ TEST_F(TestIntrospection, TestMalformedRelativeQueries) results = GetIntrospectableNodesFromQuery(query, root_.get()); ASSERT_EQ(1, results.size()); - EXPECT_STREQ("Unity", results.front()->GetName().c_str()); + EXPECT_STREQ("Unity", results.front()->GetName().c_str()); query = "Foo"; results = GetIntrospectableNodesFromQuery(query, root_.get()); ASSERT_EQ(3, results.size()); for(auto p : results) { - EXPECT_STREQ("Foo", p->GetName().c_str()); + EXPECT_STREQ("Foo", p->GetName().c_str()); } } @@ -154,14 +185,14 @@ TEST_F(TestIntrospection, TestSimpleRelativeQueries) results = GetIntrospectableNodesFromQuery(query, root_.get()); ASSERT_EQ(1, results.size()); - EXPECT_STREQ("Unity", results.front()->GetName().c_str()); + EXPECT_STREQ("Unity", results.front()->GetName().c_str()); query = "//Foo"; results = GetIntrospectableNodesFromQuery(query, root_.get()); ASSERT_EQ(3, results.size()); for(auto p : results) { - EXPECT_STREQ("Foo", p->GetName().c_str()); + EXPECT_STREQ("Foo", p->GetName().c_str()); } } @@ -174,7 +205,7 @@ TEST_F(TestIntrospection, TestComplexRelativeQueries) ASSERT_EQ(3, results.size()); for(auto p : results) { - EXPECT_STREQ("Foo", p->GetName().c_str()); + EXPECT_STREQ("Foo", p->GetName().c_str()); } } @@ -185,7 +216,7 @@ TEST_F(TestIntrospection, TestQueriesWithNoResults) results = GetIntrospectableNodesFromQuery(query, root_.get()); ASSERT_EQ(0, results.size()); - + query = "DoesNotEverExist"; results = GetIntrospectableNodesFromQuery(query, root_.get()); ASSERT_EQ(0, results.size()); @@ -211,7 +242,7 @@ TEST_F(TestIntrospection, TestQueriesWithParams) ASSERT_EQ(3, results.size()); for(auto p : results) { - EXPECT_STREQ("Foo", p->GetName().c_str()); + EXPECT_STREQ("Foo", p->GetName().c_str()); } // make sure param queries work with descendant nodes as well: @@ -219,7 +250,7 @@ TEST_F(TestIntrospection, TestQueriesWithParams) ASSERT_EQ(3, results.size()); for(auto p : results) { - EXPECT_STREQ("Foo", p->GetName().c_str()); + EXPECT_STREQ("Foo", p->GetName().c_str()); } } @@ -259,7 +290,7 @@ TEST_F(TestIntrospection, TestQueryTypeBool) TEST_F(TestIntrospection, TestQueryTypeInt) { std::list<Introspectable*> results; - + // these should all select the root Unity node: std::list<std::string> queries = {"/Unity[BytePropertyPos=12]", "/Unity[Int16PropertyPos=1012]", @@ -291,7 +322,7 @@ TEST_F(TestIntrospection, TestQueryTypeInt) { results = GetIntrospectableNodesFromQuery(query, root_.get()); ASSERT_EQ(0, results.size()); - } + } } TEST_F(TestIntrospection, TestMalformedQueries) @@ -320,6 +351,6 @@ TEST_F(TestIntrospection, TestMalformedQueries) for (std::string query : queries) { results = GetIntrospectableNodesFromQuery(query, root_.get()); - ASSERT_EQ(0, results.size()) << "Failing query: " << query; + ASSERT_EQ(0, results.size()) << "Failing query: " << query; } -} \ No newline at end of file +} diff --git a/tests/test_keyboard_util.cpp b/tests/test_keyboard_util.cpp new file mode 100644 index 000000000..cc61e336e --- /dev/null +++ b/tests/test_keyboard_util.cpp @@ -0,0 +1,115 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2012 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Marco Trevisan (Treviño) <3v1n0@ubuntu.com> + */ + +#include <gtest/gtest.h> +#include <algorithm> + +#include "KeyboardUtil.h" + +using namespace unity::ui; + +namespace +{ + +void test_key(KeyboardUtil const& key_util, Display* x_display, const char* key) +{ + unsigned int above_keycode = key_util.GetKeycodeAboveKeySymbol(XStringToKeysym(key)); + KeySym above_keysym = XkbKeycodeToKeysym(x_display, above_keycode, 0, 1); + EXPECT_NE(above_keysym, NoSymbol); +} + +TEST(TestKeyboardUtil, AboveKeySymbol) +{ + Display* x_display = XOpenDisplay(NULL); + + KeyboardUtil key_util(x_display); + test_key(key_util, x_display, "Tab"); + test_key(key_util, x_display, "Shift_R"); + test_key(key_util, x_display, "Control_L"); + test_key(key_util, x_display, "space"); + test_key(key_util, x_display, "comma"); + test_key(key_util, x_display, "a"); + test_key(key_util, x_display, "b"); + test_key(key_util, x_display, "c"); + test_key(key_util, x_display, "d"); + test_key(key_util, x_display, "e"); + test_key(key_util, x_display, "f"); + test_key(key_util, x_display, "g"); + test_key(key_util, x_display, "h"); + test_key(key_util, x_display, "i"); + test_key(key_util, x_display, "j"); + test_key(key_util, x_display, "k"); + test_key(key_util, x_display, "l"); + test_key(key_util, x_display, "m"); + test_key(key_util, x_display, "n"); + test_key(key_util, x_display, "o"); + test_key(key_util, x_display, "p"); + test_key(key_util, x_display, "k"); + test_key(key_util, x_display, "r"); + test_key(key_util, x_display, "s"); + test_key(key_util, x_display, "t"); + test_key(key_util, x_display, "u"); + test_key(key_util, x_display, "v"); + test_key(key_util, x_display, "w"); + test_key(key_util, x_display, "x"); + test_key(key_util, x_display, "y"); + test_key(key_util, x_display, "z"); +} + +TEST(TestKeyboardUtil, PrintableKeySymbols) +{ + EXPECT_TRUE(KeyboardUtil::IsPrintableKeySymbol(XK_Delete)); + EXPECT_TRUE(KeyboardUtil::IsPrintableKeySymbol(XK_BackSpace)); + EXPECT_TRUE(KeyboardUtil::IsPrintableKeySymbol(XK_space)); + EXPECT_TRUE(KeyboardUtil::IsPrintableKeySymbol(XK_3)); + EXPECT_TRUE(KeyboardUtil::IsPrintableKeySymbol(XK_v)); + EXPECT_TRUE(KeyboardUtil::IsPrintableKeySymbol(XK_1)); + EXPECT_TRUE(KeyboardUtil::IsPrintableKeySymbol(XK_ntilde)); + EXPECT_TRUE(KeyboardUtil::IsPrintableKeySymbol(XK_0)); + EXPECT_TRUE(KeyboardUtil::IsPrintableKeySymbol(XK_exclam)); + + EXPECT_FALSE(KeyboardUtil::IsPrintableKeySymbol(XK_F1)); + EXPECT_FALSE(KeyboardUtil::IsPrintableKeySymbol(XK_Select)); + EXPECT_FALSE(KeyboardUtil::IsPrintableKeySymbol(XK_Hyper_R)); + EXPECT_FALSE(KeyboardUtil::IsPrintableKeySymbol(XK_Control_L)); + EXPECT_FALSE(KeyboardUtil::IsPrintableKeySymbol(XK_Shift_L)); + EXPECT_FALSE(KeyboardUtil::IsPrintableKeySymbol(XK_Super_L)); + EXPECT_FALSE(KeyboardUtil::IsPrintableKeySymbol(XK_Print)); + EXPECT_FALSE(KeyboardUtil::IsPrintableKeySymbol(XK_Insert)); + EXPECT_FALSE(KeyboardUtil::IsPrintableKeySymbol(XK_Num_Lock)); + EXPECT_FALSE(KeyboardUtil::IsPrintableKeySymbol(XK_Caps_Lock)); + EXPECT_FALSE(KeyboardUtil::IsPrintableKeySymbol(XK_ISO_Level3_Shift)); +} + +TEST(TestKeyboardUtil, MoveKeySymbols) +{ + std::vector<KeySym> move_symbols { XK_Home, XK_Left, XK_Up, XK_Right, XK_Down, + XK_Prior, XK_Page_Up, XK_Next, XK_Page_Down, + XK_End, XK_Begin }; + + for (KeySym sym = 0; sym < XK_VoidSymbol; ++sym) + { + if (std::find(move_symbols.begin(), move_symbols.end(), sym) != move_symbols.end()) + EXPECT_TRUE(KeyboardUtil::IsMoveKeySymbol(sym)); + else + EXPECT_FALSE(KeyboardUtil::IsMoveKeySymbol(sym)); + } +} + +} // Namespace diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 523e56f65..24dfc2280 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,7 +1,7 @@ # # Some unity tools # -install(FILES makebootchart.py migrate_favorites.py PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/unity/) +install(FILES makebootchart.py PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/unity/) configure_file (${CMAKE_CURRENT_SOURCE_DIR}/unity.cmake ${CMAKE_BINARY_DIR}/bin/unity) install(FILES ${CMAKE_BINARY_DIR}/bin/unity PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ diff --git a/tools/build-compiz-glib b/tools/build-compiz-glib index e7453e287..474fd1934 100755 --- a/tools/build-compiz-glib +++ b/tools/build-compiz-glib @@ -23,7 +23,7 @@ PREFIX=$HOME/staging/ PKG_CONFIG_PATH=$PREFIX/lib/pkgconfig LD_LIBRARY_PATH=$PREFIX/lib # These are the dependencies for ubuntu. This script should work on other distros provided the dependencies are met -DEPENDENCIES="git-core cmake libcairo2-dev librsvg2-dev libglib2.0-dev libpng12-dev libdbus-1-dev libboost-dev libboost-serialization-dev libxml2-dev libgl1-mesa-dev libglu1-mesa-dev libwnck-dev libgconf2-dev libx11-xcb-dev libxslt1-dev libnotify-dev libprotobuf-dev libmetacity-dev libgnome-window-settings-dev libgnome-desktop-dev gnome-control-center-dev intltool cython python2.6-dev" +DEPENDENCIES="git-core cmake libcairo2-dev librsvg2-dev libglib2.0-dev libpng12-dev libdbus-1-dev libboost-dev libboost-serialization-dev libxml2-dev libgl1-mesa-dev libglu1-mesa-dev libwnck-dev libgconf2-dev libx11-xcb-dev libxslt1-dev libnotify-dev libprotobuf-dev libmetacity-dev libgnome-window-settings-dev gnome-control-center-dev intltool cython python2.6-dev" COMPONENTS=(core libcompizconfig compizconfig-python ccsm compizconfig-backend-gconf plugins-main plugins-extra plugins-unsupported) echo "Installing dependencies..." diff --git a/tools/migrate_favorites.py b/tools/migrate_favorites.py deleted file mode 100755 index 2ec45bd65..000000000 --- a/tools/migrate_favorites.py +++ /dev/null @@ -1,292 +0,0 @@ -#!/usr/bin/python -# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- -# Copyright 2010 Canonical -# Author: Didier Roche -# -# 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. - -import sys - -try: - import datetime - import gconf - import glob - import gobject - from gobject import GError - import os - import subprocess - from xdg import BaseDirectory -except ImportError, e: - print "No migration because of a missing python module: %s" % e - sys.exit (1) - -LAST_MIGRATION = '3.2.10' - -def get_log_file(): - ''' open the log file and return it ''' - - data_path = "%s/unity" % BaseDirectory.xdg_cache_home - if not os.path.isdir(data_path): - os.makedirs(data_path) - try: - return open("%s/migration_script.log" % data_path, "a") - except (IOError, OSError), e: - print "Can't put log in %s, will print those manually. Error is: %s" % (data_path, e) - return None - -def migrating_chapter_log(name, apps_list, migration_list, log_file): - '''Log migration of new launchers''' - - log(" + Migration for %s.\n Current app list is: %s\n Candidates are: %s" % (name, apps_list, migration_list), log_file) - - -def log(message, log_file): - ''' log if log_file present''' - if log_file: - log_file.write("%s\n" % message) - else: - print message - -def get_desktop_dir(): - ''' no python binding from xdg to get the desktop directory? ''' - - possible_desktop_folder = None - try: - for line in file('%s/user-dirs.dirs' % BaseDirectory.xdg_config_home): - values = line.split('=') - if values[0] == 'XDG_DESKTOP_DIR': - try: - possible_desktop_folder = values[1][1:-2].replace('$HOME', os.path.expanduser('~')) - if os.path.isdir(possible_desktop_folder): - return possible_desktop_folder - else: - possible_desktop_folder = None - break - except IndexError: - continue - except IOError: - pass - return os.path.expanduser('~/Desktop') - -def register_new_app(launcher_location, apps_list, log_file): - ''' append a new app with full desktop path if valid, take care of dups ''' - - # default distribution launcher don't go into that function (as don't have an aboslute path) - entry = "" - if os.path.exists(launcher_location): - log(" == %s: exists" % launcher_location, log_file) - # try to strip the full path we had in unity mutter if it's part of a xdg path: - # or try to get that for other desktop file based on name. - candidate_desktop_filename = launcher_location.split("/")[-1] - # some desktop file with modified exec key (like in cairo-dock contains 01desktopfilename.desktop, strip that) - try: - candidate_cairodock_desktop_filename = candidate_desktop_filename.split("01")[1] - except IndexError: - candidate_cairodock_desktop_filename = "" - for xdg_dir in BaseDirectory.xdg_data_dirs: - xdg_app_dir = os.path.join(xdg_dir, "applications", "") - if launcher_location.startswith(xdg_app_dir): - candidate_desktop_file = launcher_location.split(xdg_app_dir)[1] - # if really the xdg path is the path to the launcher - if not '/' in candidate_desktop_file: - entry = candidate_desktop_file - log(" Direct match found for system desktop file", log_file) - break - # second chance: try to see if the desktop filename is in xdg path and so, assume it's a match - if not entry and os.path.exists("%s/%s" % (xdg_app_dir, candidate_desktop_filename)): - entry = candidate_desktop_filename - log(" Similar desktop file name with system desktop file", log_file) - break - # third chance: try to see if a tweaked cairo-dock like deskto file name is in xdg path - if not entry and os.path.exists("%s/%s" % (xdg_app_dir, candidate_cairodock_desktop_filename)): - entry = candidate_cairodock_desktop_filename - log(" Similar Cairo-Dock -like desktop file name with system desktop file", log_file) - break - # fourth and last chance: try to find a corresponding Exec key. - # Wait! scanning /usr/share/applications is heavy !!! - # Don't panic, we have the bamf.index for that :) - if not entry: - exec_arg = "" - try: - for line in open(launcher_location): - if "Exec=" in line: - exec_arg = line.split("Exec=")[1] - break - except IOError: - log(" Can't open %s for reading Exec" % launcher_location, log_file) - if exec_arg: - try: - for line in open("/usr/share/applications/bamf.index"): - if exec_arg in line: - entry = line.split()[0] - log(" Coherent exec key found with system desktop file", log_file) - break - except IOError: - log(" No bamf.index file found on the system!", log_file) - - if not entry: - entry = launcher_location - log(" %s: real entry is %s" % (launcher_location, entry), log_file) - if entry not in apps_list: - log(" --- adding %s as not in app_list" % entry, log_file) - apps_list.append(entry) - else: - log(" --- NOT adding %s as already in app_list" % entry, log_file) - else: - log(" == %s: doesn't exist" % launcher_location, log_file) - - return apps_list - -def save_gsettings_favorites(apps_list, log_file): - ''' save the app list favorites to gsettings ''' - - #print apps_list - return_code = subprocess.call(["gsettings", "set", "com.canonical.Unity.Launcher", "favorites", str(apps_list)]) - - if return_code != 0: - print "Settings fail to transition to new unity compiz favorites" - log("Settings fail to transition to new unity compiz favorites\n\n", log_file) - if log_file: - log_file.close() - sys.exit(1) - -try: - migration_level = subprocess.Popen(["gsettings", "get", "com.canonical.Unity.Launcher", "favorite-migration"], stdout=subprocess.PIPE).communicate()[0].strip()[1:-1] -except OSError, e: - print "Gsettings not executable or not installed, postponing migration. The error was: %s" % e - sys.exit(1) - -if migration_level >= LAST_MIGRATION: - print "Migration already done" - sys.exit(0) - -client = gconf.client_get_default() - -# get current gsettings defaults into a list -defaults_call = subprocess.Popen(["gsettings", "get", "com.canonical.Unity.Launcher", "favorites"], stdout=subprocess.PIPE) -apps_list = [elem.strip()[1:-1] for elem in defaults_call.communicate()[0].strip()[1:-1].split(',')] - -log_file = get_log_file() -log("Migration script called on %s\n" % str(datetime.datetime.now()), log_file) - -# first migration to unity compiz -if migration_level < '3.2.0': - log("======= Migration to 3.2.0 =======\n", log_file) - - unity_mutter_favorites_list = client.get_list('/desktop/unity/launcher/favorites/favorites_list', gconf.VALUE_STRING) - unity_mutter_launcher_ordered = {} - migrating_chapter_log("unity mutter", apps_list, unity_mutter_favorites_list, log_file) - for candidate in unity_mutter_favorites_list: - candidate_path = '/desktop/unity/launcher/favorites/%s' % candidate - try: - if (candidate and client.get_string('%s/type' % candidate_path) == 'application'): - launcher_location = client.get_string('%s/desktop_file' % candidate_path) - position = client.get_string('%s/desktop_file' % candidate_path) - if launcher_location: - # try to preserve the order, will be done in a second loop - unity_mutter_launcher_ordered[position] = launcher_location - except GError, e: - log("Dont migrate %s: %s" % (candidate_path, e), log_file) - continue - for launcher_location in unity_mutter_launcher_ordered: - apps_list = register_new_app(launcher_location, apps_list, log_file) - - - # import netbook-launcher favorites and convert them - lucid_favorites_list = client.get_list('/apps/netbook-launcher/favorites/favorites_list', gconf.VALUE_STRING) - migrating_chapter_log("netbook-launcher favorites", apps_list, lucid_favorites_list, log_file) - for candidate in lucid_favorites_list: - candidate_path = '/apps/netbook-launcher/favorites/%s' % candidate - try: - if (candidate and client.get_string('%s/type' % candidate_path) == 'application'): - try: - launcher_location = client.get_string('%s/desktop_file' % candidate_path) - except GError, e: - log("Dont migrate %s: %s" % (candidate_path, e), log_file) - continue - if launcher_location: - apps_list = register_new_app(launcher_location, apps_list, log_file) - except GError, e: - log("Dont migrate %s: %s" % (candidate_path, e), log_file) - continue - - # get GNOME panel favorites and convert them - panel_list = client.get_list('/apps/panel/general/toplevel_id_list', gconf.VALUE_STRING) - candidate_objects = client.get_list('/apps/panel/general/object_id_list', gconf.VALUE_STRING) - migrating_chapter_log("gnome-panel items", apps_list, candidate_objects, log_file) - for candidate in candidate_objects: - candidate_path = '/apps/panel/objects/%s' % candidate - try: - if (candidate and client.get_string('%s/object_type' % candidate_path) == 'launcher-object' - and client.get_string('%s/toplevel_id' % candidate_path) in panel_list): - launcher_location = client.get_string('%s/launcher_location' % candidate_path) - if launcher_location: - if not launcher_location.startswith('/'): - launcher_location = os.path.expanduser('~/.gnome2/panel2.d/default/launchers/%s' % launcher_location) - apps_list = register_new_app(launcher_location, apps_list, log_file) - except GError, e: - log("Dont migrate %s: %s" % (candidate_path, e), log_file) - continue - - # get GNOME desktop launchers - desktop_dir = get_desktop_dir() - desktop_items = glob.glob('%s/*.desktop' % desktop_dir) - migrating_chapter_log("desktop items in %s" % desktop_dir, apps_list, desktop_items, log_file) - for launcher_location in glob.glob('%s/*.desktop' % desktop_dir): - # blacklist ubiquity as will have two ubiquity in the netbook live session then - if not "ubiquity" in launcher_location: - apps_list = register_new_app(launcher_location, apps_list, log_file) - - # Now write to gsettings! - save_gsettings_favorites(apps_list, log_file) - - # some autumn cleanage (gconf binding for recursive_unset seems broken) - subprocess.call(["gconftool-2", "--recursive-unset", "/apps/netbook-launcher"]) - subprocess.call(["gconftool-2", "--recursive-unset", "/desktop/unity"]) - -# second migration: transition popular docks entry as well -if migration_level < '3.2.10': - log("======= Migration to 3.2.10 =======\n", log_file) - - # import awn favorites - awn_favorites_list = client.get_list('/apps/awn-applet-taskmanager/launcher_paths', gconf.VALUE_STRING) - migrating_chapter_log("awn favorites", apps_list, awn_favorites_list, log_file) - for launcher_location in awn_favorites_list: - apps_list = register_new_app(launcher_location, apps_list, log_file) - - # import Docky favorites - dock_list = client.get_list('/apps/docky-2/Docky/DockController/ActiveDocks', gconf.VALUE_STRING) - for dock in dock_list: - docky_favorites_list = client.get_list('/apps/docky-2/Docky/Interface/DockPreferences/%s/Launchers' % dock, gconf.VALUE_STRING) - migrating_chapter_log("Docky favorites for %s" % dock, apps_list, docky_favorites_list, log_file) - for launcher_location in docky_favorites_list: - try: - launcher_location = launcher_location.split("file://")[1] - except IndexError: - pass - apps_list = register_new_app(launcher_location, apps_list, log_file) - - # import Cairo-Dock favorites - try: - cairodock_path = "%s/cairo-dock/current_theme/launchers" % BaseDirectory.xdg_config_home - cairodock_favorites_list = os.listdir(cairodock_path) - migrating_chapter_log("Cairo-Dock favorites (in %s)" % cairodock_path, apps_list, cairodock_favorites_list, log_file) - for launcher in cairodock_favorites_list: - launcher_location = "%s/%s" % (cairodock_path, launcher) - apps_list = register_new_app(launcher_location, apps_list, log_file) - except OSError: - log(" + Can't migrate Cairo-Dock as %s doesn't exist" % cairodock_path, log_file) - - # Now write to gsettings! - save_gsettings_favorites(apps_list, log_file) - -log("Migration script ended successfully\n\n", log_file) -if log_file: - log_file.close() - -# stamp that all went well -subprocess.call(["gsettings", "set", "com.canonical.Unity.Launcher", "favorite-migration", "\'%s\'" % LAST_MIGRATION]) -sys.exit(0) - diff --git a/tools/unity.cmake b/tools/unity.cmake index f4897a55f..af7871855 100755 --- a/tools/unity.cmake +++ b/tools/unity.cmake @@ -19,6 +19,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import gconf +import glib import glob from optparse import OptionParser import os @@ -78,7 +79,7 @@ def reset_unity_compiz_profile (): # as compiz set a new schema instead of a value.. try: current_profile_schema = client.get_schema("/apps/compizconfig-1/current_profile") - except (GError, AttributeError), e: + except (glib.GError, AttributeError), e: print "WARNING: environment is incorrect: %s\nDid you just try to reset in a tty?" % e return diff --git a/unity-shared/CMakeLists.txt b/unity-shared/CMakeLists.txt index 2261d9e7b..f2108892b 100644 --- a/unity-shared/CMakeLists.txt +++ b/unity-shared/CMakeLists.txt @@ -41,6 +41,7 @@ set (UNITY_SHARED_SOURCES BackgroundEffectHelper.cpp DashStyle.cpp FontSettings.cpp + KeyboardUtil.cpp IMTextEntry.cpp IconLoader.cpp IconRenderer.cpp diff --git a/unity-shared/CairoTexture.h b/unity-shared/CairoTexture.h index dd08b3c0f..e546a9b32 100644 --- a/unity-shared/CairoTexture.h +++ b/unity-shared/CairoTexture.h @@ -24,7 +24,7 @@ #define UNITY_CAIROTEXTURE_H #include <Nux/Nux.h> -#include <NuxImage/CairoGraphics.h> +#include <NuxGraphics/CairoGraphics.h> #include <NuxGraphics/NuxGraphics.h> #include <NuxGraphics/GLTextureResourceManager.h> diff --git a/unity-shared/DashStyle.cpp b/unity-shared/DashStyle.cpp index 36fd926e8..4fbb32ff2 100644 --- a/unity-shared/DashStyle.cpp +++ b/unity-shared/DashStyle.cpp @@ -32,7 +32,9 @@ #include <NuxCore/Color.h> #include <NuxCore/Logger.h> -#include <NuxImage/CairoGraphics.h> +#include <NuxGraphics/ImageSurface.h> +#include <NuxGraphics/CairoGraphics.h> + #include <Nux/PaintLayer.h> #include <UnityCore/GLibSignal.h> diff --git a/unity-shared/IMTextEntry.cpp b/unity-shared/IMTextEntry.cpp index 2db7db813..db7c86c29 100644 --- a/unity-shared/IMTextEntry.cpp +++ b/unity-shared/IMTextEntry.cpp @@ -1,6 +1,6 @@ // -*- Mode: C++; indent-tabs-mode: ni; tab-width: 2 -*- /* - * Copyright (C) 2011 Canonical Ltd + * Copyright (C) 2011-2012 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Pubic License version 3 as @@ -15,107 +15,39 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Authored by: Neil Jagdish Patel <neil.patel@canonical.com> + * Marco Trevisan <marco.trevisan@canonical.com> */ -#include "config.h" - #include "IMTextEntry.h" - -#include <NuxCore/Logger.h> -#include <UnityCore/GLibWrapper.h> +#include <gtk/gtk.h> namespace unity { - -namespace -{ -nux::logging::Logger logger("unity.imtextentry"); -} - NUX_IMPLEMENT_OBJECT_TYPE(IMTextEntry); IMTextEntry::IMTextEntry() : TextEntry("", NUX_TRACKER_LOCATION) -{ - mouse_up.connect(sigc::mem_fun(this, &IMTextEntry::OnMouseButtonUp)); -} - -bool IMTextEntry::InspectKeyEvent(unsigned int event_type, - unsigned int keysym, - const char* character) -{ - nux::Event const& event = nux::GetGraphicsDisplay()->GetCurrentEvent(); - bool need_to_filter_event = TryHandleSpecial(event); +{} - if (need_to_filter_event) - need_to_filter_event = TextEntry::InspectKeyEvent(event_type, keysym, character); - - return need_to_filter_event; -} - -bool IMTextEntry::TryHandleSpecial(nux::Event const& event) +void IMTextEntry::CopyClipboard() { - /* If there is preedit, handle the event else where, but we - want to be able to copy/paste while ibus is active */ - if (!preedit_.empty()) - return true; - - if (event.type != NUX_KEYDOWN) - return false; - - unsigned int keyval = event.GetKeySym(); - bool shift = event.GetKeyModifierState(KEY_MODIFIER_SHIFT); - bool ctrl = event.GetKeyModifierState(KEY_MODIFIER_CTRL); - bool super = event.GetKeyModifierState(KEY_MODIFIER_SUPER); - bool alt = event.GetKeyModifierState(KEY_MODIFIER_ALT); + int start, end; - if ((ctrl && !shift && keyval == NUX_VK_x) || // Ctrl + X - (shift && !ctrl && keyval == NUX_VK_DELETE)) // Shift + Del - { - Cut(); - } - else if (ctrl && !shift && (keyval == NUX_VK_c || keyval == NUX_VK_INSERT)) // Ctrl + C / Ins - { - Copy(); - } - else if ((ctrl && !shift && keyval == NUX_VK_v) || // Ctrl + V - (shift && !ctrl && keyval == NUX_VK_INSERT)) // Shift + Ins - { - Paste(); - } - else if (ctrl) - { - if (keyval == NUX_VK_LEFT || keyval == NUX_VK_RIGHT || // Ctrl + Move keys - keyval == NUX_VK_HOME || keyval == NUX_VK_END || // Ctrl + Home / End - keyval == NUX_VK_BACKSPACE || keyval == NUX_VK_DELETE || // Ctrl + Backspace / Delete - keyval == NUX_VK_a) // Ctrl + A - { - return true; - } - } - else if (!alt && !super) + if (GetSelectionBounds(&start, &end)) { - return true; + GtkClipboard* clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); + gtk_clipboard_set_text(clip, text_.c_str() + start, end - start); } - - return false; } -void IMTextEntry::Cut() +void IMTextEntry::PasteClipboard() { - Copy(); - DeleteSelection(); - QueueRefresh (true, true); + Paste(); } -void IMTextEntry::Copy() +void IMTextEntry::PastePrimaryClipboard() { - int start=0, end=0; - if (GetSelectionBounds(&start, &end)) - { - GtkClipboard* clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); - gtk_clipboard_set_text(clip, text_.c_str() + start, end - start); - } + Paste(true); } void IMTextEntry::Paste(bool primary) @@ -145,18 +77,7 @@ void IMTextEntry::InsertText(std::string const& text) int cursor = cursor_; SetText(new_text.c_str()); SetCursor(cursor + text.length()); - QueueRefresh (true, true); - } -} - -void IMTextEntry::OnMouseButtonUp(int x, int y, unsigned long bflags, unsigned long kflags) -{ - int button = nux::GetEventButton(bflags); - - if (button == 2) - { - SetCursor(XYToTextIndex(x,y)); - Paste(true); + QueueRefresh(true, true); } } diff --git a/unity-shared/IMTextEntry.h b/unity-shared/IMTextEntry.h index 983ae66ed..b39b37b85 100644 --- a/unity-shared/IMTextEntry.h +++ b/unity-shared/IMTextEntry.h @@ -1,6 +1,6 @@ // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* - * Copyright (C) 2011 Canonical Ltd + * Copyright (C) 2011-2012 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -15,25 +15,18 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Authored by: Neil Jagdish Patel <neil.patel@canonical.com> + * Marco Trevisan <marco.trevisan@canonical.com> */ #ifndef IM_TEXT_ENTRY_H #define IM_TEXT_ENTRY_H -#include <gtk/gtk.h> -#include <gdk/gdkx.h> - #include <Nux/Nux.h> #include <Nux/TextEntry.h> -#include <UnityCore/GLibSignal.h> -#include <UnityCore/GLibWrapper.h> namespace unity { -using namespace unity::glib; -using namespace nux; - class IMTextEntry : public nux::TextEntry { NUX_DECLARE_OBJECT_TYPE(IMTextEntry, nux::TextEntry); @@ -41,16 +34,13 @@ public: IMTextEntry(); bool im_preedit(); -private: - bool InspectKeyEvent(unsigned int eventType, unsigned int keysym, const char* character); - void OnMouseButtonUp(int x, int y, unsigned long bflags, unsigned long kflags); - protected: - bool TryHandleSpecial(nux::Event const& event); virtual void InsertText(std::string const& text); - virtual void Cut(); - virtual void Copy(); - virtual void Paste(bool primary = false); + virtual void CopyClipboard(); + virtual void PasteClipboard(); + virtual void PastePrimaryClipboard(); + + void Paste(bool primary = false); }; } diff --git a/unity-shared/IconRenderer.cpp b/unity-shared/IconRenderer.cpp index bba7dbf43..7e87f9425 100644 --- a/unity-shared/IconRenderer.cpp +++ b/unity-shared/IconRenderer.cpp @@ -25,7 +25,7 @@ #include <NuxGraphics/GpuDevice.h> #include <NuxGraphics/GLTextureResourceManager.h> -#include <NuxImage/CairoGraphics.h> +#include <NuxGraphics/CairoGraphics.h> #include <gtk/gtk.h> diff --git a/unity-shared/IconTexture.h b/unity-shared/IconTexture.h index caf045da4..88428733c 100644 --- a/unity-shared/IconTexture.h +++ b/unity-shared/IconTexture.h @@ -25,7 +25,7 @@ #include <Nux/View.h> // FIXME: Nux/TextureArea.h needs View included first. #include <Nux/TextureArea.h> -#include <NuxImage/CairoGraphics.h> +#include <NuxGraphics/CairoGraphics.h> #include <NuxGraphics/GraphicsEngine.h> #include <UnityCore/GLibWrapper.h> diff --git a/unity-shared/Introspectable.cpp b/unity-shared/Introspectable.cpp index 59050a212..4ecd0fc18 100644 --- a/unity-shared/Introspectable.cpp +++ b/unity-shared/Introspectable.cpp @@ -38,7 +38,7 @@ Introspectable::~Introspectable() child->_parents.remove(this); } -Introspectable::IntrospectableList const& Introspectable::GetIntrospectableChildren() +Introspectable::IntrospectableList Introspectable::GetIntrospectableChildren() { return _children; } @@ -55,14 +55,14 @@ Introspectable::Introspect() AddProperties(&builder); - g_variant_builder_init(&child_builder, G_VARIANT_TYPE("a(sv)")); + g_variant_builder_init(&child_builder, G_VARIANT_TYPE("as")); auto children = GetIntrospectableChildren(); for (auto it = children.begin(); it != children.end(); it++) { if ((*it)->GetName() != "") { - g_variant_builder_add(&child_builder, "(sv)", (*it)->GetName().c_str(), (*it)->Introspect()); + g_variant_builder_add(&child_builder, "s", (*it)->GetName().c_str()); n_children++; } } diff --git a/unity-shared/Introspectable.h b/unity-shared/Introspectable.h index e6b299648..7814ca281 100644 --- a/unity-shared/Introspectable.h +++ b/unity-shared/Introspectable.h @@ -32,7 +32,7 @@ class Introspectable { public: typedef std::list<Introspectable*> IntrospectableList; - + Introspectable(); virtual ~Introspectable(); GVariant* Introspect(); @@ -40,7 +40,7 @@ public: void AddChild(Introspectable* child); void RemoveChild(Introspectable* child); virtual void AddProperties(GVariantBuilder* builder) = 0; - virtual IntrospectableList const& GetIntrospectableChildren(); + virtual IntrospectableList GetIntrospectableChildren(); guint64 GetIntrospectionId() const; protected: diff --git a/plugins/unityshell/src/KeyboardUtil.cpp b/unity-shared/KeyboardUtil.cpp index 50dc200a7..b65fbc15a 100644 --- a/plugins/unityshell/src/KeyboardUtil.cpp +++ b/unity-shared/KeyboardUtil.cpp @@ -17,9 +17,8 @@ * Authored by: Jason Smith <jason.smith@canonical.com> */ +#include <gdk/gdk.h> #include <string.h> - -#include <stdio.h> #include <cmath> #include "KeyboardUtil.h" @@ -31,7 +30,7 @@ KeyboardUtil::KeyboardUtil(Display *display) : display_(display) { unsigned int fetch_mask = XkbGBN_KeyNamesMask | XkbGBN_ClientSymbolsMask | XkbGBN_GeometryMask; - keyboard_ = XkbGetKeyboard (display, fetch_mask, XkbUseCoreKbd); + keyboard_ = XkbGetKeyboard (display, fetch_mask, XkbUseCoreKbd); } KeyboardUtil::~KeyboardUtil() @@ -39,7 +38,7 @@ KeyboardUtil::~KeyboardUtil() XkbFreeKeyboard (keyboard_, 0, True); } -bool KeyboardUtil::FindKeyInGeometry(XkbGeometryPtr geo, char *key_name, int& res_section, XkbBoundsRec& res_bounds) +bool KeyboardUtil::FindKeyInGeometry(XkbGeometryPtr geo, char *key_name, int& res_section, XkbBoundsRec& res_bounds) const { // seems that Xkb does not give null terminated strings... was painful int name_length = XkbKeyNameLength; @@ -73,7 +72,7 @@ bool KeyboardUtil::FindKeyInGeometry(XkbGeometryPtr geo, char *key_name, int& re return false; } -bool KeyboardUtil::CompareOffsets (int current_x, int current_y, int best_x, int best_y) +bool KeyboardUtil::CompareOffsets(int current_x, int current_y, int best_x, int best_y) const { // never EVER prefer something higher on the keyboard than what we have if (current_y > best_y) @@ -85,7 +84,7 @@ bool KeyboardUtil::CompareOffsets (int current_x, int current_y, int best_x, int return false; } -guint KeyboardUtil::ConvertKeyToKeycode (XkbKeyPtr key) +guint KeyboardUtil::ConvertKeyToKeycode(XkbKeyPtr key) const { int min_code = keyboard_->min_key_code; int max_code = keyboard_->max_key_code; @@ -98,7 +97,7 @@ guint KeyboardUtil::ConvertKeyToKeycode (XkbKeyPtr key) return 0; } -XkbBoundsRec KeyboardUtil::GetAbsoluteKeyBounds (XkbKeyPtr key, XkbRowPtr row, XkbSectionPtr section, XkbGeometryPtr geo) +XkbBoundsRec KeyboardUtil::GetAbsoluteKeyBounds(XkbKeyPtr key, XkbRowPtr row, XkbSectionPtr section, XkbGeometryPtr geo) const { XkbShapePtr shape = XkbKeyShape(geo, key); @@ -117,7 +116,7 @@ XkbBoundsRec KeyboardUtil::GetAbsoluteKeyBounds (XkbKeyPtr key, XkbRowPtr row, X y_offset += local_shape->bounds.y2 - local_shape->bounds.y1; else x_offset += local_shape->bounds.x2 - local_shape->bounds.x1; - + i++; } @@ -129,7 +128,7 @@ XkbBoundsRec KeyboardUtil::GetAbsoluteKeyBounds (XkbKeyPtr key, XkbRowPtr row, X return result; } -bool KeyboardUtil::FindKeyInSectionAboveBounds (XkbGeometryPtr geo, int section_index, XkbBoundsRec const& target_bounds, guint &keycode) +bool KeyboardUtil::FindKeyInSectionAboveBounds(XkbGeometryPtr geo, int section_index, XkbBoundsRec const& target_bounds, guint &keycode) const { XkbKeyPtr best = NULL; int best_x_offset = G_MAXINT; @@ -155,7 +154,7 @@ bool KeyboardUtil::FindKeyInSectionAboveBounds (XkbGeometryPtr geo, int section_ int center = (bounds.x1 + bounds.x2) / 2; if (center < target_bounds.x1 || center > target_bounds.x2) continue; - + // make sure the key is actually above our target. int current_y_offset = target_bounds.y1 - bounds.y2; if (current_y_offset < 0) @@ -181,7 +180,7 @@ bool KeyboardUtil::FindKeyInSectionAboveBounds (XkbGeometryPtr geo, int section_ return false; } -guint KeyboardUtil::GetKeycodeAboveKeySymbol(KeySym key_symbol) +guint KeyboardUtil::GetKeycodeAboveKeySymbol(KeySym key_symbol) const { guint result = 0; @@ -208,9 +207,38 @@ guint KeyboardUtil::GetKeycodeAboveKeySymbol(KeySym key_symbol) if (found_key) result = maybe; } - + return result; } +bool KeyboardUtil::IsPrintableKeySymbol(KeySym sym) +{ + bool printable_key = false; + + if (sym == XK_Delete || sym == XK_BackSpace || sym == XK_Return) + { + printable_key = true; + } + else + { + unsigned int unicode = gdk_keyval_to_unicode(sym); + printable_key = g_unichar_isprint(unicode); + } + + return printable_key; +} + +bool KeyboardUtil::IsMoveKeySymbol(KeySym sym) +{ + bool move_key = false; + + if (sym >= XK_Home && sym <= XK_Begin) + { + move_key = true; + } + + return move_key; +} + } } \ No newline at end of file diff --git a/plugins/unityshell/src/KeyboardUtil.h b/unity-shared/KeyboardUtil.h index f88c066f8..0df116299 100644 --- a/plugins/unityshell/src/KeyboardUtil.h +++ b/unity-shared/KeyboardUtil.h @@ -33,22 +33,23 @@ namespace ui class KeyboardUtil { - public: - KeyboardUtil(Display *display); - virtual ~KeyboardUtil(); + ~KeyboardUtil(); + + guint GetKeycodeAboveKeySymbol(KeySym key_symbol) const; - guint GetKeycodeAboveKeySymbol(KeySym key_symbol); + static bool IsPrintableKeySymbol(KeySym key_symbol); + static bool IsMoveKeySymbol(KeySym sym); private: - bool CompareOffsets (int current_x, int current_y, int best_x, int best_y); - guint ConvertKeyToKeycode (XkbKeyPtr key); + bool CompareOffsets (int current_x, int current_y, int best_x, int best_y) const; + guint ConvertKeyToKeycode (XkbKeyPtr key) const; - bool FindKeyInGeometry(XkbGeometryPtr geo, char *key_name, int& res_section, XkbBoundsRec& res_bounds); - bool FindKeyInSectionAboveBounds (XkbGeometryPtr geo, int section, XkbBoundsRec const& target_bounds, guint &keycode); + bool FindKeyInGeometry(XkbGeometryPtr geo, char *key_name, int& res_section, XkbBoundsRec& res_bounds) const; + bool FindKeyInSectionAboveBounds (XkbGeometryPtr geo, int section, XkbBoundsRec const& target_bounds, guint &keycode) const; - XkbBoundsRec GetAbsoluteKeyBounds (XkbKeyPtr key, XkbRowPtr row, XkbSectionPtr section, XkbGeometryPtr geo); + XkbBoundsRec GetAbsoluteKeyBounds (XkbKeyPtr key, XkbRowPtr row, XkbSectionPtr section, XkbGeometryPtr geo) const; XkbDescPtr keyboard_; Display *display_; diff --git a/unity-shared/PanelStyle.cpp b/unity-shared/PanelStyle.cpp index 6ceb965e3..2fce4eacf 100644 --- a/unity-shared/PanelStyle.cpp +++ b/unity-shared/PanelStyle.cpp @@ -27,7 +27,7 @@ #include <Nux/Nux.h> #include <NuxGraphics/GraphicsEngine.h> -#include <NuxImage/CairoGraphics.h> +#include <NuxGraphics/CairoGraphics.h> #include <NuxCore/Logger.h> #include "CairoTexture.h" diff --git a/unity-shared/PluginAdapterCompiz.cpp b/unity-shared/PluginAdapterCompiz.cpp index ee84c0026..567d37f49 100644 --- a/unity-shared/PluginAdapterCompiz.cpp +++ b/unity-shared/PluginAdapterCompiz.cpp @@ -533,9 +533,7 @@ bool PluginAdapter::IsWindowOnTop(guint32 xid) { Window win = xid; - CompWindow* window; - - window = m_Screen->findWindow(win); + CompWindow* window = m_Screen->findWindow(win); if (window) { @@ -543,6 +541,7 @@ PluginAdapter::IsWindowOnTop(guint32 xid) return false; CompPoint window_vp = window->defaultViewport(); + nux::Geometry const& window_vp_geo = GetWorkAreaGeometry(window->id()); std::vector<Window> const& our_xids = nux::XInputWindow::NativeHandleList(); for (CompWindow* sibling = window->next; sibling; sibling = sibling->next) @@ -550,6 +549,13 @@ PluginAdapter::IsWindowOnTop(guint32 xid) if (sibling->defaultViewport() == window_vp && !sibling->minimized() && sibling->isMapped() && sibling->isViewable() && !sibling->inShowDesktopMode() && !(sibling->state() & CompWindowStateAboveMask) && + !(sibling->type() & CompWindowTypeSplashMask) && + !(sibling->type() & CompWindowTypeDockMask) && + /* FIXME: This should be included by the above defaultViewport() check, + * but it doesn't seem to work correctly when there's only one workspace + * enabled, so please drop the line above when bug #996604 is fixed in + * Compiz. */ + !window_vp_geo.Intersect(GetWindowGeometry(sibling->id())).IsNull() && std::find(our_xids.begin(), our_xids.end(), sibling->id()) == our_xids.end()) { return false; diff --git a/unity-shared/SearchBar.cpp b/unity-shared/SearchBar.cpp index e47c0cb63..31f69f100 100644 --- a/unity-shared/SearchBar.cpp +++ b/unity-shared/SearchBar.cpp @@ -23,6 +23,7 @@ #include <Nux/HLayout.h> #include <Nux/VLayout.h> #include <NuxCore/Logger.h> + #include <UnityCore/Variant.h> #include <glib/gi18n-lib.h> @@ -250,7 +251,7 @@ void SearchBar::Init() expand_icon_->mouse_click.connect(mouse_expand); } - sig_manager_.Add(new Signal<void, GtkSettings*, GParamSpec*> + sig_manager_.Add(new glib::Signal<void, GtkSettings*, GParamSpec*> (gtk_settings_get_default(), "notify::gtk-font-name", sigc::mem_fun(this, &SearchBar::OnFontChanged))); diff --git a/unity-shared/SearchBar.h b/unity-shared/SearchBar.h index cc88e817f..130ffe7da 100644 --- a/unity-shared/SearchBar.h +++ b/unity-shared/SearchBar.h @@ -20,7 +20,7 @@ #ifndef SEARCH_BAR_H #define SEARCH_BAR_H - +#include <gtk/gtk.h> #include <NuxCore/Property.h> #include <Nux/LayeredLayout.h> #include <Nux/VLayout.h> diff --git a/unity-shared/StaticCairoText.cpp b/unity-shared/StaticCairoText.cpp index c01a46d25..7d9a3e2e9 100644 --- a/unity-shared/StaticCairoText.cpp +++ b/unity-shared/StaticCairoText.cpp @@ -27,7 +27,7 @@ #include <NuxCore/Size.h> #include <Nux/TextureArea.h> -#include <NuxImage/CairoGraphics.h> +#include <NuxGraphics/CairoGraphics.h> #include <pango/pango.h> #include <pango/pangocairo.h> diff --git a/unity-shared/UBusMessages.h b/unity-shared/UBusMessages.h index 66b7faef5..603baa19f 100644 --- a/unity-shared/UBusMessages.h +++ b/unity-shared/UBusMessages.h @@ -35,7 +35,7 @@ #define UBUS_DASH_ABOUT_TO_SHOW "DASH_ABOUT_TO_SHOW" // Signal sent when an overlay interface is shown, includes a gvariant -// gvariant format is (sb), (interface-name, can_maximize?) +// gvariant format is (sb), (interface-name, can_maximize?) #define UBUS_OVERLAY_FORMAT_STRING "(sbi)" #define UBUS_OVERLAY_HIDDEN "OVERLAY_HIDDEN" #define UBUS_OVERLAY_SHOWN "OVERLAY_SHOWN" @@ -88,6 +88,8 @@ // Signals sent when the switcher is shown, hidden or changes selection #define UBUS_SWITCHER_SHOWN "SWITCHER_SHOWN" +#define UBUS_SWITCHER_START "SWITCHER_SHOWN_START" +#define UBUS_SWITCHER_END "SWITCHER_SHOWN_END" #define UBUS_SWITCHER_SELECTION_CHANGED "SWITCHER_SELECTION_CHANGED" #endif // UBUS_MESSAGES_H |
