diff options
82 files changed, 3732 insertions, 166 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 60e12c9d5..4cde7cb0d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -230,6 +230,7 @@ set(UNITY_PLUGIN_SHARED_DEPS indicator3-0.4>=0.4.90 json-glib-1.0 libbamf3>=0.5.0 + gnome-desktop-3.0 libnotify libstartup-notification-1.0 nux-4.0>=4.0.5 @@ -263,6 +264,7 @@ add_subdirectory(dash) add_subdirectory(launcher) if (ENABLE_X_SUPPORT) add_subdirectory(hud) + add_subdirectory(lockscreen) add_subdirectory(panel) add_subdirectory(decorations) add_subdirectory(plugins/unityshell) diff --git a/UnityCore/DBusIndicators.cpp b/UnityCore/DBusIndicators.cpp index 7267af913..e924d7ae5 100644 --- a/UnityCore/DBusIndicators.cpp +++ b/UnityCore/DBusIndicators.cpp @@ -36,7 +36,8 @@ DECLARE_LOGGER(logger, "unity.indicator.dbus"); namespace { -const std::string SERVICE_NAME("com.canonical.Unity.Panel.Service"); +const std::string SERVICE_NAME_DESKTOP("com.canonical.Unity.Panel.Service.Desktop"); +const std::string SERVICE_NAME_LOCKSCREEN("com.canonical.Unity.Panel.Service.LockScreen"); const std::string SERVICE_PATH("/com/canonical/Unity/Panel/Service"); const std::string SERVICE_IFACE("com.canonical.Unity.Panel.Service"); } // anonymous namespace @@ -456,13 +457,17 @@ void DBusIndicators::Impl::SyncGeometries(std::string const& name, } DBusIndicators::DBusIndicators() - : pimpl(new Impl(SERVICE_NAME, this)) + : pimpl(new Impl(SERVICE_NAME_DESKTOP, this)) {} DBusIndicators::DBusIndicators(std::string const& dbus_name) : pimpl(new Impl(dbus_name, this)) {} +LockScreenDBusIndicators::LockScreenDBusIndicators() + : DBusIndicators(SERVICE_NAME_LOCKSCREEN) +{} + DBusIndicators::~DBusIndicators() {} diff --git a/UnityCore/DBusIndicators.h b/UnityCore/DBusIndicators.h index f0c9edace..a888ec86d 100644 --- a/UnityCore/DBusIndicators.h +++ b/UnityCore/DBusIndicators.h @@ -22,7 +22,6 @@ #include "Indicators.h" - namespace unity { namespace indicator @@ -56,6 +55,11 @@ private: std::unique_ptr<Impl> pimpl; }; +struct LockScreenDBusIndicators : DBusIndicators +{ + LockScreenDBusIndicators(); +}; + } } diff --git a/UnityCore/GnomeSessionManager.cpp b/UnityCore/GnomeSessionManager.cpp index 4edddf80a..f1dcdbcd6 100644 --- a/UnityCore/GnomeSessionManager.cpp +++ b/UnityCore/GnomeSessionManager.cpp @@ -87,6 +87,23 @@ GnomeManager::Impl::Impl(GnomeManager* manager, bool test_mode) shell_object_ = shell_server_.GetObject(shell::DBUS_INTERFACE); shell_object_->SetMethodsCallsHandler(sigc::mem_fun(this, &Impl::OnShellMethodCall)); + { + const char* session_id = test_mode_ ? "id0" : g_getenv("XDG_SESSION_ID"); + + login_proxy_ = std::make_shared<glib::DBusProxy>(test_mode_ ? testing::DBUS_NAME : "org.freedesktop.login1", + "/org/freedesktop/login1/session/" + glib::gchar_to_string(session_id), + "org.freedesktop.login1.Session", + test_mode_ ? G_BUS_TYPE_SESSION : G_BUS_TYPE_SYSTEM); + + login_proxy_->Connect("Lock", [this](GVariant*){ + manager_->lock_requested.emit(); + }); + + login_proxy_->Connect("Unlock", [this](GVariant*){ + manager_->unlock_requested.emit(); + }); + } + CallLogindMethod("CanHibernate", nullptr, [this] (GVariant* variant, glib::Error const& err) { if (err) { @@ -376,9 +393,7 @@ GnomeManager::~GnomeManager() std::string GnomeManager::RealName() const { - const char* name = g_get_real_name(); - - std::string real_name(name ? name : ""); + std::string real_name = glib::gchar_to_string(g_get_real_name()); if (real_name == "Unknown") real_name.clear(); @@ -388,22 +403,25 @@ std::string GnomeManager::RealName() const std::string GnomeManager::UserName() const { - const char* name = g_get_user_name(); + return glib::gchar_to_string(g_get_user_name()); +} - return name ? name : ""; +std::string GnomeManager::HostName() const +{ + return glib::gchar_to_string(g_get_host_name()); } void GnomeManager::LockScreen() { impl_->EnsureCancelPendingAction(); - auto proxy = std::make_shared<glib::DBusProxy>(impl_->test_mode_ ? testing::DBUS_NAME : "org.gnome.ScreenSaver", - "/org/gnome/ScreenSaver", "org.gnome.ScreenSaver"); - - // By passing the proxy to the lambda we ensure that it will stay alive - // until we get the last callback. - proxy->Call("Lock", nullptr, [proxy] (GVariant*) {}); - proxy->Call("SimulateUserActivity", nullptr, [proxy] (GVariant*) {}); + // FIXME (andy) we should ask gnome-session to emit the logind signal + if (UserName().find("guest-") == 0) + { + LOG_INFO(logger) << "Impossible to lock a guest session"; + return; + } + lock_requested.emit(); } void GnomeManager::Logout() diff --git a/UnityCore/GnomeSessionManager.h b/UnityCore/GnomeSessionManager.h index 6adb0593a..d32296d66 100644 --- a/UnityCore/GnomeSessionManager.h +++ b/UnityCore/GnomeSessionManager.h @@ -35,6 +35,7 @@ public: std::string RealName() const; std::string UserName() const; + std::string HostName() const; void LockScreen(); void Logout(); diff --git a/UnityCore/GnomeSessionManagerImpl.h b/UnityCore/GnomeSessionManagerImpl.h index 991d88e1c..320c0f4dd 100644 --- a/UnityCore/GnomeSessionManagerImpl.h +++ b/UnityCore/GnomeSessionManagerImpl.h @@ -69,6 +69,7 @@ struct GnomeManager::Impl shell::Action pending_action_; glib::DBusServer shell_server_; glib::DBusObject::Ptr shell_object_; + glib::DBusProxy::Ptr login_proxy_; }; } // namespace session diff --git a/UnityCore/SessionManager.h b/UnityCore/SessionManager.h index 64f931899..ea8b13c60 100644 --- a/UnityCore/SessionManager.h +++ b/UnityCore/SessionManager.h @@ -38,6 +38,7 @@ public: virtual std::string RealName() const = 0; virtual std::string UserName() const = 0; + virtual std::string HostName() const = 0; virtual void LockScreen() = 0; virtual void Logout() = 0; @@ -56,6 +57,10 @@ public: Manager(const Manager&) = delete; Manager& operator=(const Manager&) = delete; + sigc::signal<void> lock_requested; + sigc::signal<void> unlock_requested; + sigc::signal<void> locked; + sigc::signal<void> unlocked; sigc::signal<void, bool /* inhibitors */> logout_requested; sigc::signal<void, bool /* inhibitors */> reboot_requested; sigc::signal<void, bool /* inhibitors */> shutdown_requested; diff --git a/debian/changelog b/debian/changelog index a8d4bb0f1..a8e58d4c3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,35 @@ +unity (7.1.2+14.04.20140311-0ubuntu1) trusty; urgency=low + + [ CI bot ] + * Lockscreen: Multimonitor support, use greeter settings and don't + paint popup windows In detail: - Use proper fonts for text input - + Make text cursor to blink as expected (needs + lp:~3v1n0/nux/textentry-toggle-cursor-visibility) - Use bullet as + password char - Support multi-monitor correctly, switching view on + mouse movement (as the greeter does) - Fixed lockscreen not showing + on newly attached monitors - Never paint windows that might popup + under the lockscreen (such as tooltips or notifications) - Use + unity greeter gsettings values for painting the Background (support + color, or disable user bg) - Don't lock guest sessions + + [ Stephen M. Webb ] + * Bump Nux build-dep to 4.0.6 for ABI change. + + [ Andrea Azzarone ] + * Implement the lockscreen in Unity that looks like unity-greeter. + Also allow to fallback to lightdm + greeter (tty switching) in case + you need more pam power. (LP: #878836) + + [ Marco Trevisan (Treviño) ] + * LockScreenPanel: added a light version of PanelView for Lockscreen + only, using PanelIndicatorsView - Indicators scrubbing using mouse + works again - Indicators key navigation is supported (Alt+F10 + included) - Indicators will be correctly visible in light themes as + well - Show hostname (optionally) on the top left side of the panel + - LockScreenSettings now bind settings from unity-greeter dconf path + + -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 11 Mar 2014 18:37:36 +0000 + unity (7.1.2+14.04.20140305-0ubuntu1) trusty; urgency=low [ Chris Townsend ] diff --git a/debian/control b/debian/control index 396e11905..111609b22 100644 --- a/debian/control +++ b/debian/control @@ -9,24 +9,21 @@ Build-Depends: cmake, dh-migrations, dh-translations (>= 94), google-mock (>= 1.6.0+svn437), - google-mock, gsettings-desktop-schemas-dev, gsettings-ubuntu-schemas (>= 0.0.1+14.04.20140219), intltool (>= 0.35.0), libatk1.0-dev, libbamf3-dev (>= 0.5.0+13.10.20130731), libboost-dev, - libboost-serialization-dev, libcairo2-dev, libdbus-1-dev, - libcompizconfig0-dev (>= 1:0.9.11), libdbusmenu-glib-dev (>= 0.3.91), libdee-dev (>= 1.2.6), libgee-dev (>= 0.5.0), libgeis-dev (>= 2.0.10), libgl1-mesa-dri, libglib2.0-dev (>= 2.39.1), - libgrail-dev (>= 1.0.20), + libgnome-desktop-3-dev, libgtest-dev, libgtk-3-dev (>= 3.1), libido3-0.1-dev (>= 13.10.0), @@ -37,14 +34,14 @@ Build-Depends: cmake, libnih-dbus-dev, libnih-dev, libnotify-dev, - libnux-4.0-dev (>= 4.0.5), + libnux-4.0-dev (>= 4.0.6), + libpam0g-dev, libpango1.0-dev, libsigc++-2.0-dev, libstartup-notification0-dev, libunique-dev, libunity-dev (>= 7.1.0), libunity-misc-dev (>= 4.0.4), - libunity-scopes-json-def-desktop, libupstart-dev, libxcb-icccm4-dev, libxfixes-dev (>= 1:5.0.1-1), @@ -77,6 +74,7 @@ Depends: ${shlibs:Depends}, nux-tools, dconf-cli, unity-asset-pool (>= 0.8.18), + unity-greeter, bamfdaemon, libxfixes3 (>= 1:5.0.1-1), libxi6 (>= 2:1.7.1.901), diff --git a/hud/HudView.cpp b/hud/HudView.cpp index b52aed55a..035a30c9f 100644 --- a/hud/HudView.cpp +++ b/hud/HudView.cpp @@ -507,8 +507,6 @@ void View::DrawContent(nux::GraphicsEngine& gfx_context, bool force_draw) GetLayout()->ProcessDraw(gfx_context, force_draw); } - overlay_window_buttons_->QueueDraw(); - gfx_context.PopClippingRectangle(); renderer_.DrawInnerCleanup(gfx_context, draw_content_geo, GetAbsoluteGeometry(), GetGeometry()); diff --git a/lockscreen/BackgroundSettings.cpp b/lockscreen/BackgroundSettings.cpp new file mode 100644 index 000000000..44dd94436 --- /dev/null +++ b/lockscreen/BackgroundSettings.cpp @@ -0,0 +1,153 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2013 Canonical Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> +*/ + +#include <Nux/Nux.h> +#include "BackgroundSettings.h" + +#include <libgnome-desktop/gnome-bg.h> + +#include "LockScreenSettings.h" +#include "unity-shared/CairoTexture.h" +#include "unity-shared/PanelStyle.h" +#include "unity-shared/UScreen.h" + +namespace unity +{ +namespace lockscreen +{ +namespace +{ +const std::string SETTINGS_NAME = "org.gnome.desktop.background"; + +constexpr int GetGridOffset(int size) { return (size % Settings::GRID_SIZE) / 2; } +} + +BackgroundSettings::BackgroundSettings() + : gnome_bg_(gnome_bg_new()) +{ + glib::Object<GSettings> settings(g_settings_new(SETTINGS_NAME.c_str())); + gnome_bg_load_from_preferences(gnome_bg_, settings); +} + +BackgroundSettings::~BackgroundSettings() +{} + +BaseTexturePtr BackgroundSettings::GetBackgroundTexture(int monitor) +{ + nux::Geometry const& geo = UScreen::GetDefault()->GetMonitorGeometry(monitor); + auto& settings = Settings::Instance(); + + nux::CairoGraphics cairo_graphics(CAIRO_FORMAT_ARGB32, geo.width, geo.height); + cairo_t* c = cairo_graphics.GetInternalContext(); + + cairo_surface_t* bg_surface = nullptr; + + if (settings.use_user_background()) + { + bg_surface = gnome_bg_create_surface(gnome_bg_, gdk_get_default_root_window(), geo.width, geo.height, FALSE); + } + else if (!settings.background().empty()) + { + glib::Object<GdkPixbuf> pixbuf(gdk_pixbuf_new_from_file_at_scale(settings.background().c_str(), geo.width, geo.height, FALSE, NULL)); + + if (pixbuf) + bg_surface = gdk_cairo_surface_create_from_pixbuf(pixbuf, 0, NULL); + } + + if (bg_surface) + { + cairo_set_source_surface(c, bg_surface, 0, 0); + cairo_paint(c); + cairo_surface_destroy(bg_surface); + } + else + { + auto const& bg_color = settings.background_color(); + cairo_set_source_rgb(c, bg_color.red, bg_color.green, bg_color.blue); + cairo_paint(c); + } + + if (!settings.logo().empty()) + { + int grid_x_offset = GetGridOffset(geo.width); + int grid_y_offset = GetGridOffset(geo.height); + cairo_surface_t* logo_surface = cairo_image_surface_create_from_png(settings.logo().c_str()); + + if (logo_surface) + { + int height = cairo_image_surface_get_height(logo_surface); + int x = grid_x_offset; + int y = grid_y_offset + Settings::GRID_SIZE * (geo.height / Settings::GRID_SIZE - 1) - height; + + cairo_save(c); + cairo_translate(c, x, y); + + cairo_set_source_surface(c, logo_surface, 0, 0); + cairo_paint_with_alpha(c, 0.5); + cairo_surface_destroy(logo_surface); + cairo_restore(c); + } + } + + if (settings.draw_grid()) + { + int width = geo.width; + int height = geo.height; + int grid_x_offset = GetGridOffset(width); + int grid_y_offset = GetGridOffset(height) + panel::Style().Instance().PanelHeight(monitor); + + // overlay grid + cairo_surface_t* overlay_surface = cairo_surface_create_similar(cairo_graphics.GetSurface(), + CAIRO_CONTENT_COLOR_ALPHA, + Settings::GRID_SIZE, + Settings::GRID_SIZE); + + cairo_t* oc = cairo_create(overlay_surface); + cairo_rectangle(oc, 0, 0, 1, 1); + cairo_rectangle(oc, Settings::GRID_SIZE - 1, 0, 1, 1); + cairo_rectangle(oc, 0, Settings::GRID_SIZE - 1, 1, 1); + cairo_rectangle(oc, Settings::GRID_SIZE - 1, Settings::GRID_SIZE - 1, 1, 1); + cairo_set_source_rgba(oc, 1.0, 1.0, 1.0, 0.25); + cairo_fill(oc); + + cairo_pattern_t* overlay = cairo_pattern_create_for_surface(overlay_surface); + + cairo_matrix_t matrix; + cairo_matrix_init_identity(&matrix); + cairo_matrix_translate(&matrix, -grid_x_offset, -grid_y_offset); + + cairo_pattern_set_matrix(overlay, &matrix); + cairo_pattern_set_extend(overlay, CAIRO_EXTEND_REPEAT); + + cairo_save(c); + cairo_set_source(c, overlay); + cairo_rectangle(c, 0, 0, width, height); + cairo_fill(c); + cairo_restore(c); + + cairo_pattern_destroy(overlay); + cairo_surface_destroy(overlay_surface); + cairo_destroy(oc); + } + + return texture_ptr_from_cairo_graphics(cairo_graphics); +} + +} // lockscreen +} // unity diff --git a/lockscreen/BackgroundSettings.h b/lockscreen/BackgroundSettings.h new file mode 100644 index 000000000..c6abcbfc2 --- /dev/null +++ b/lockscreen/BackgroundSettings.h @@ -0,0 +1,55 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2013 Canonical Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> +*/ + +#ifndef UNITY_BACKGROUND_SETTINGS_H +#define UNITY_BACKGROUND_SETTINGS_H + +#include <NuxCore/ObjectPtr.h> +#include <UnityCore/GLibWrapper.h> + +namespace nux +{ +class BaseTexture; +} + +class _GnomeBG; + +namespace unity +{ +typedef nux::ObjectPtr<nux::BaseTexture> BaseTexturePtr; + +namespace lockscreen +{ + +class BackgroundSettings +{ +public: + BackgroundSettings(); + ~BackgroundSettings(); + + BaseTexturePtr GetBackgroundTexture(int monitor); + +private: + glib::Object<_GnomeBG> gnome_bg_; +}; + +} +} + +#endif diff --git a/lockscreen/CMakeLists.txt b/lockscreen/CMakeLists.txt new file mode 100644 index 000000000..e755e7fee --- /dev/null +++ b/lockscreen/CMakeLists.txt @@ -0,0 +1,33 @@ +set(UNITY_SRC ../plugins/unityshell/src) + +set (CFLAGS + ${CACHED_UNITY_DEPS_CFLAGS} + ${CACHED_UNITY_DEPS_CFLAGS_OTHER} + ${PIC_FLAGS} + ) + +string (REPLACE ";" " " CFLAGS "${CFLAGS}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CFLAGS}") + +set (LIBS ${CACHED_UNITY_DEPS_LDFLAGS} ${UNITY_STANDALONE_LADD}) + +include_directories (.. ../services ../UnityCore ${UNITY_SRC} ${CMAKE_BINARY_DIR}) + +# +# Headers & Sources +# +set (LOCKSCREEN_SOURCES + BackgroundSettings.cpp + CofView.cpp + LockScreenController.cpp + LockScreenSettings.cpp + LockScreenShield.cpp + LockScreenShieldFactory.cpp + LockScreenPanel.cpp + UserAuthenticatorPam.cpp + UserPromptView.cpp + ) + +add_library (lockscreen-lib STATIC ${LOCKSCREEN_SOURCES}) +add_dependencies (lockscreen-lib unity-core-${UNITY_API_VERSION} unity-shared panel-lib pam) +add_pch(pch/lockscreen_pch.hh lockscreen-lib) diff --git a/lockscreen/CofView.cpp b/lockscreen/CofView.cpp new file mode 100644 index 000000000..40ad382ca --- /dev/null +++ b/lockscreen/CofView.cpp @@ -0,0 +1,41 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2013 Canonical Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> +*/ + +#include "CofView.h" + +#include "config.h" + +namespace unity +{ +namespace lockscreen +{ + +CofView::CofView() + // FIXME (andy) if we get an svg cof we can make it fullscreen independent. + : IconTexture(PKGDATADIR"/cof.png", 66) +{} + +nux::Area* CofView::FindAreaUnderMouse(nux::Point const& mouse_position, + nux::NuxEventType event_type) +{ + return nullptr; +} + +} +} diff --git a/lockscreen/CofView.h b/lockscreen/CofView.h new file mode 100644 index 000000000..60c1ca7b9 --- /dev/null +++ b/lockscreen/CofView.h @@ -0,0 +1,42 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2013 Canonical Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> +*/ + +#ifndef UNITYSHELL_COF_VIEW_H +#define UNITYSHELL_COF_VIEW_H + +#include "unity-shared/IconTexture.h" + +namespace unity +{ +namespace lockscreen +{ + +class CofView : public unity::IconTexture +{ +public: + CofView(); + + nux::Area* FindAreaUnderMouse(nux::Point const& mouse_position, + nux::NuxEventType event_type) override; +}; + +} +} + +#endif \ No newline at end of file diff --git a/lockscreen/LockScreenAbstractShield.h b/lockscreen/LockScreenAbstractShield.h new file mode 100644 index 000000000..584a66fe3 --- /dev/null +++ b/lockscreen/LockScreenAbstractShield.h @@ -0,0 +1,60 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2014 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 <marco.trevisan@canonical.com> + */ + +#ifndef UNITY_LOCKSCREEN_ABSTRACT_SHIELD_H +#define UNITY_LOCKSCREEN_ABSTRACT_SHIELD_H + +#include <NuxCore/Property.h> +#include <UnityCore/SessionManager.h> +#include <UnityCore/Indicators.h> + +#include "unity-shared/MockableBaseWindow.h" + +namespace unity +{ +namespace lockscreen +{ + +class AbstractShield : public MockableBaseWindow +{ +public: + AbstractShield(session::Manager::Ptr const& session, indicator::Indicators::Ptr const& indicators, int monitor_num, bool is_primary) + : MockableBaseWindow("Unity Lockscreen") + , primary(is_primary) + , monitor(monitor_num) + , session_manager_(session) + , indicators_(indicators) + {} + + nux::Property<bool> primary; + nux::Property<int> monitor; + + virtual bool IsIndicatorOpen() const = 0; + + sigc::signal<void, int, int> grab_motion; + +protected: + session::Manager::Ptr session_manager_; + indicator::Indicators::Ptr indicators_; +}; + +} // lockscreen +} // unity + +#endif // UNITY_LOCKSCREEN_ABSTRACT_SHIELD_H diff --git a/lockscreen/LockScreenController.cpp b/lockscreen/LockScreenController.cpp new file mode 100644 index 000000000..8b4487906 --- /dev/null +++ b/lockscreen/LockScreenController.cpp @@ -0,0 +1,260 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2013-2014 Canonical Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> +*/ + +#include "LockScreenController.h" + +#include <UnityCore/DBusIndicators.h> +#include "LockScreenShield.h" +#include "LockScreenSettings.h" +#include "unity-shared/AnimationUtils.h" +#include "unity-shared/UScreen.h" +#include "unity-shared/WindowManager.h" + +namespace unity +{ +namespace lockscreen +{ +namespace +{ +const unsigned int FADE_DURATION = 400; +} + +namespace testing +{ +const std::string DBUS_NAME = "com.canonical.Unity.Test.DisplayManager"; +} + +Controller::Controller(session::Manager::Ptr const& session_manager, + UpstartWrapper::Ptr const& upstart_wrapper, + ShieldFactoryInterface::Ptr const& shield_factory, + bool test_mode) + : session_manager_(session_manager) + , upstart_wrapper_(upstart_wrapper) + , shield_factory_(shield_factory) + , fade_animator_(FADE_DURATION) + , test_mode_(test_mode) +{ + uscreen_connection_ = UScreen::GetDefault()->changed.connect([this] (int, std::vector<nux::Geometry> const& monitors) { + EnsureShields(monitors); + }); + uscreen_connection_->block(); + + session_manager_->lock_requested.connect(sigc::mem_fun(this, &Controller::OnLockRequested)); + session_manager_->unlock_requested.connect(sigc::mem_fun(this, &Controller::OnUnlockRequested)); + + fade_animator_.updated.connect([this](double value) { + std::for_each(shields_.begin(), shields_.end(), [value](nux::ObjectPtr<Shield> const& shield) { + shield->SetOpacity(value); + }); + }); + + fade_animator_.finished.connect([this] { + if (animation::GetDirection(fade_animator_) == animation::Direction::BACKWARD) + { + motion_connection_->disconnect(); + uscreen_connection_->block(); + session_manager_->unlocked.emit(); + shields_.clear(); + + if (Settings::Instance().lockscreen_type() == Type::UNITY) + { + upstart_wrapper_->Emit("desktop-unlock"); + indicators_.reset(); + } + } + }); +} + +void Controller::OnPrimaryShieldMotion(int x, int y) +{ + if (!primary_shield_->GetAbsoluteGeometry().IsPointInside(x, y)) + { + for (auto const& shield : shields_) + { + if (!shield->GetAbsoluteGeometry().IsPointInside(x, y)) + continue; + + primary_shield_->primary = false; + primary_shield_ = shield; + shield->primary = true; + auto move_cb = sigc::mem_fun(this, &Controller::OnPrimaryShieldMotion); + motion_connection_ = shield->grab_motion.connect(move_cb); + break; + } + } +} + +void Controller::EnsureShields(std::vector<nux::Geometry> const& monitors) +{ + int num_monitors = monitors.size(); + int shields_size = shields_.size(); + bool unity_mode = (Settings::Instance().lockscreen_type() == Type::UNITY); + int primary = unity_mode ? UScreen::GetDefault()->GetMonitorWithMouse() : -1; + + shields_.resize(num_monitors); + + for (int i = 0; i < num_monitors; ++i) + { + auto& shield = shields_[i]; + bool is_new = false; + + if (i >= shields_size) + { + shield = shield_factory_->CreateShield(session_manager_, indicators_, i, i == primary); + is_new = true; + } + + shield->SetGeometry(monitors[i]); + shield->SetMinMaxSize(monitors[i].width, monitors[i].height); + shield->primary = (i == primary); + shield->monitor = i; + + if (is_new && fade_animator_.GetCurrentValue() > 0) + { + shield->SetOpacity(fade_animator_.GetCurrentValue()); + shield->ShowWindow(true); + shield->PushToFront(); + } + } + + if (unity_mode) + { + primary_shield_ = shields_[primary]; + primary_shield_->primary = true; + auto move_cb = sigc::mem_fun(this, &Controller::OnPrimaryShieldMotion); + motion_connection_ = primary_shield_->grab_motion.connect(move_cb); + } +} + +void Controller::OnLockRequested() +{ + if (IsLocked()) + return; + + auto lockscreen_type = Settings::Instance().lockscreen_type(); + + if (lockscreen_type == Type::NONE) + { + session_manager_->unlocked.emit(); + return; + } + + if (lockscreen_type == Type::LIGHTDM) + { + LockScreenUsingDisplayManager(); + } + else if (lockscreen_type == Type::UNITY) + { + LockScreenUsingUnity(); + } + + session_manager_->locked.emit(); +} + +void Controller::LockScreenUsingDisplayManager() +{ + // TODO (andy) Move to a different class (DisplayManagerWrapper) + const char* session_path = g_getenv("XDG_SESSION_PATH"); + + if (!session_path) + return; + + auto proxy = std::make_shared<glib::DBusProxy>(test_mode_ ? testing::DBUS_NAME : "org.freedesktop.DisplayManager", + session_path, + "org.freedesktop.DisplayManager.Session", + test_mode_ ? G_BUS_TYPE_SESSION : G_BUS_TYPE_SYSTEM); + + proxy->Call("Lock", nullptr, [proxy] (GVariant*) {}); + + ShowShields(); + animation::Skip(fade_animator_); +} + +void Controller::LockScreenUsingUnity() +{ + indicators_ = std::make_shared<indicator::LockScreenDBusIndicators>(); + upstart_wrapper_->Emit("desktop-lock"); + + ShowShields(); +} + +void Controller::ShowShields() +{ + old_blur_type_ = BackgroundEffectHelper::blur_type; + BackgroundEffectHelper::blur_type = BLUR_NONE; + + WindowManager::Default().SaveInputFocus(); + EnsureShields(UScreen::GetDefault()->GetMonitors()); + uscreen_connection_->unblock(); + + std::for_each(shields_.begin(), shields_.end(), [] (nux::ObjectPtr<Shield> const& shield) { + shield->SetOpacity(0.0f); + shield->ShowWindow(true); + shield->PushToFront(); + }); + + animation::StartOrReverse(fade_animator_, animation::Direction::FORWARD); +} + +void Controller::OnUnlockRequested() +{ + if (!IsLocked()) + return; + + auto lockscreen_type = Settings::Instance().lockscreen_type(); + + if (lockscreen_type == Type::NONE) + return; + + HideShields(); + + if (lockscreen_type == Type::LIGHTDM) + animation::Skip(fade_animator_); +} + +void Controller::HideShields() +{ + std::for_each(shields_.begin(), shields_.end(), [](nux::ObjectPtr<Shield> const& shield) { + shield->UnGrabPointer(); + shield->UnGrabKeyboard(); + }); + + WindowManager::Default().RestoreInputFocus(); + animation::StartOrReverse(fade_animator_, animation::Direction::BACKWARD); + + BackgroundEffectHelper::blur_type = old_blur_type_; +} + +bool Controller::IsLocked() const +{ + return !shields_.empty(); +} + +double Controller::Opacity() const +{ + return fade_animator_.GetCurrentValue(); +} + +bool Controller::HasOpenMenu() const +{ + return primary_shield_.IsValid() ? primary_shield_->IsIndicatorOpen() : false; +} + +} // lockscreen +} // unity diff --git a/lockscreen/LockScreenController.h b/lockscreen/LockScreenController.h new file mode 100644 index 000000000..3e42bfd52 --- /dev/null +++ b/lockscreen/LockScreenController.h @@ -0,0 +1,76 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2013-2014 Canonical Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> +*/ + +#ifndef UNITY_LOCKSCREEN_CONTROLLER_H +#define UNITY_LOCKSCREEN_CONTROLLER_H + +#include <NuxCore/Animation.h> +#include <UnityCore/ConnectionManager.h> + +#include "LockScreenShieldFactory.h" +#include "unity-shared/BackgroundEffectHelper.h" +#include "unity-shared/UpstartWrapper.h" + +namespace unity +{ +namespace lockscreen +{ + +class Controller : public sigc::trackable +{ +public: + Controller(session::Manager::Ptr const& session_manager, + UpstartWrapper::Ptr const& upstart_wrapper = std::make_shared<UpstartWrapper>(), + ShieldFactoryInterface::Ptr const& shield_factory = std::make_shared<ShieldFactory>(), + bool test_mode = false); + + bool IsLocked() const; + bool HasOpenMenu() const; + double Opacity() const; + +private: + friend class TestLockScreenController; + + void EnsureShields(std::vector<nux::Geometry> const& monitors); + void LockScreenUsingDisplayManager(); + void LockScreenUsingUnity(); + void ShowShields(); + void HideShields(); + + void OnLockRequested(); + void OnUnlockRequested(); + void OnPrimaryShieldMotion(int x, int y); + + std::vector<nux::ObjectPtr<AbstractShield>> shields_; + nux::ObjectWeakPtr<AbstractShield> primary_shield_; + session::Manager::Ptr session_manager_; + indicator::Indicators::Ptr indicators_; + UpstartWrapper::Ptr upstart_wrapper_; + ShieldFactoryInterface::Ptr shield_factory_; + nux::animation::AnimateValue<double> fade_animator_; + connection::Wrapper uscreen_connection_; + connection::Wrapper motion_connection_; + bool test_mode_; + BlurType old_blur_type_; +}; + +} +} + +#endif \ No newline at end of file diff --git a/lockscreen/LockScreenPanel.cpp b/lockscreen/LockScreenPanel.cpp new file mode 100644 index 000000000..b110ec70c --- /dev/null +++ b/lockscreen/LockScreenPanel.cpp @@ -0,0 +1,225 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2014 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 <marco.trevisan@canonical.com> + */ + +#include "LockScreenPanel.h" + +#include <boost/algorithm/string/trim.hpp> +#include <Nux/HLayout.h> + +#include "LockScreenSettings.h" +#include "panel/PanelIndicatorsView.h" +#include "unity-shared/CairoTexture.h" +#include "unity-shared/StaticCairoText.h" +#include "unity-shared/PanelStyle.h" +#include "unity-shared/RawPixel.h" +#include "unity-shared/UnitySettings.h" +#include "unity-shared/WindowManager.h" + +namespace unity +{ +namespace lockscreen +{ +namespace +{ +const RawPixel PADDING = 5_em; +} + +using namespace indicator; +using namespace panel; + +Panel::Panel(int monitor_, Indicators::Ptr const& indicators, session::Manager::Ptr const& session_manager) + : nux::View(NUX_TRACKER_LOCATION) + , active(false) + , monitor(monitor_) + , indicators_(indicators) + , needs_geo_sync_(true) +{ + double scale = unity::Settings::Instance().em(monitor)->DPIScale(); + auto* layout = new nux::HLayout(); + layout->SetLeftAndRightPadding(PADDING.CP(scale), 0); + SetLayout(layout); + + BuildTexture(); + + // Add setting + auto *hostname = new StaticCairoText(session_manager->HostName()); + hostname->SetFont(Settings::Instance().font_name()); + hostname->SetTextColor(nux::color::White); + hostname->SetInputEventSensitivity(false); + hostname->SetScale(scale); + hostname->SetVisible(Settings::Instance().show_hostname()); + layout->AddView(hostname, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL); + + indicators_view_ = new PanelIndicatorsView(); + indicators_view_->SetMonitor(monitor); + indicators_view_->OverlayShown(); + indicators_view_->on_indicator_updated.connect(sigc::mem_fun(this, &Panel::OnIndicatorViewUpdated)); + layout->AddView(indicators_view_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL); + + for (auto const& indicator : indicators_->GetIndicators()) + AddIndicator(indicator); + + indicators_->on_object_added.connect(sigc::mem_fun(this, &Panel::AddIndicator)); + indicators_->on_object_removed.connect(sigc::mem_fun(this, &Panel::RemoveIndicator)); + indicators_->on_entry_show_menu.connect(sigc::mem_fun(this, &Panel::OnEntryShowMenu)); + indicators_->on_entry_activated.connect(sigc::mem_fun(this, &Panel::OnEntryActivated)); + indicators_->on_entry_activate_request.connect(sigc::mem_fun(this, &Panel::OnEntryActivateRequest)); + + monitor.changed.connect([this, hostname] (int monitor) { + hostname->SetScale(unity::Settings::Instance().em(monitor)->DPIScale()); + indicators_view_->SetMonitor(monitor); + BuildTexture(); + QueueRelayout(); + }); +} + +void Panel::BuildTexture() +{ + int height = panel::Style::Instance().PanelHeight(monitor); + nux::CairoGraphics context(CAIRO_FORMAT_ARGB32, 1, height); + auto* cr = context.GetInternalContext(); + cairo_set_source_rgb(cr, 0.1, 0.1, 0.1); + cairo_paint_with_alpha(cr, 0.4); + bg_texture_ = texture_ptr_from_cairo_graphics(context); + + view_layout_->SetMinimumHeight(height); + view_layout_->SetMaximumHeight(height); +} + +void Panel::AddIndicator(Indicator::Ptr const& indicator) +{ + if (indicator->IsAppmenu()) + return; + + indicators_view_->AddIndicator(indicator); + QueueRelayout(); + QueueDraw(); +} + +void Panel::RemoveIndicator(indicator::Indicator::Ptr const& indicator) +{ + indicators_view_->RemoveIndicator(indicator); + QueueRelayout(); + QueueDraw(); +} + +std::string Panel::GetPanelName() const +{ + return "LockScreenPanel" + std::to_string(monitor); +} + +void Panel::OnIndicatorViewUpdated() +{ + needs_geo_sync_ = true; + QueueRelayout(); + QueueDraw(); +} + +void Panel::OnEntryShowMenu(std::string const& entry_id, unsigned xid, int x, int y, unsigned button) +{ + if (!GetInputEventSensitivity()) + return; + + // This is ugly... But Nux fault! + WindowManager::Default().UnGrabMousePointer(CurrentTime, button, x, y); + + active = true; +} + +void Panel::OnEntryActivateRequest(std::string const& entry_id) +{ + if (GetInputEventSensitivity()) + indicators_view_->ActivateEntry(entry_id, 0); +} + +void Panel::ActivateFirst() +{ + if (GetInputEventSensitivity()) + indicators_view_->ActivateIfSensitive(); +} + +void Panel::OnEntryActivated(std::string const& panel, std::string const& entry_id, nux::Rect const&) +{ + if (!GetInputEventSensitivity() || (!panel.empty() && panel != GetPanelName())) + return; + + bool active = !entry_id.empty(); + if (active && !track_menu_pointer_timeout_) + { + track_menu_pointer_timeout_.reset(new glib::Timeout(16)); + track_menu_pointer_timeout_->Run([this] { + nux::Point const& mouse = nux::GetGraphicsDisplay()->GetMouseScreenCoord(); + if (tracked_pointer_pos_ != mouse) + { + if (GetAbsoluteGeometry().IsPointInside(mouse.x, mouse.y)) + indicators_view_->ActivateEntryAt(mouse.x, mouse.y); + + tracked_pointer_pos_ = mouse; + } + + return true; + }); + } + else if (!active) + { + track_menu_pointer_timeout_.reset(); + tracked_pointer_pos_ = {-1, -1}; + this->active = false; + } +} + +void Panel::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw) +{ + auto const& geo = GetGeometry(); + + unsigned int alpha, src, dest = 0; + graphics_engine.GetRenderStates().GetBlend(alpha, src, dest); + graphics_engine.GetRenderStates().SetBlend(true, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + graphics_engine.PushClippingRectangle(geo); + nux::GetPainter().PaintBackground(graphics_engine, geo); + + nux::TexCoordXForm texxform; + texxform.SetWrap(nux::TEXWRAP_REPEAT, nux::TEXWRAP_CLAMP); + graphics_engine.QRP_1Tex(geo.x, geo.y, geo.width, geo.height, + bg_texture_->GetDeviceTexture(), texxform, + nux::color::White); + + view_layout_->ProcessDraw(graphics_engine, force_draw); + + graphics_engine.PopClippingRectangle(); + graphics_engine.GetRenderStates().SetBlend(alpha, src, dest); + + if (needs_geo_sync_) + { + EntryLocationMap locations; + indicators_view_->GetGeometryForSync(locations); + indicators_->SyncGeometries(GetPanelName(), locations); + needs_geo_sync_ = false; + } +} + +bool Panel::InspectKeyEvent(unsigned int event_type, unsigned int keysym, const char*) +{ + ActivateFirst(); + return true; +} + +} +} diff --git a/lockscreen/LockScreenPanel.h b/lockscreen/LockScreenPanel.h new file mode 100644 index 000000000..4221cc430 --- /dev/null +++ b/lockscreen/LockScreenPanel.h @@ -0,0 +1,75 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2014 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 <marco.trevisan@canonical.com> + */ + +#ifndef UNITY_LOCKSCREEN_PANEL +#define UNITY_LOCKSCREEN_PANEL + +#include <Nux/Nux.h> +#include <Nux/View.h> +#include <UnityCore/Indicators.h> +#include <UnityCore/GLibSource.h> +#include <UnityCore/SessionManager.h> + +namespace unity +{ +namespace panel +{ +class PanelIndicatorsView; +} + +namespace lockscreen +{ + +class Panel : public nux::View +{ +public: + Panel(int monitor, indicator::Indicators::Ptr const&, session::Manager::Ptr const&); + + nux::Property<bool> active; + nux::Property<int> monitor; + +protected: + void Draw(nux::GraphicsEngine& GfxContext, bool force_draw) override; + bool InspectKeyEvent(unsigned int event_type, unsigned int keysym, const char*) override; + +private: + void ActivateFirst(); + void AddIndicator(indicator::Indicator::Ptr const&); + void RemoveIndicator(indicator::Indicator::Ptr const&); + void OnIndicatorViewUpdated(); + void OnEntryActivated(std::string const& panel, std::string const& entry_id, nux::Rect const& geo); + void OnEntryShowMenu(std::string const& entry_id, unsigned xid, int x, int y, unsigned button); + void OnEntryActivateRequest(std::string const& entry_id); + + void BuildTexture(); + std::string GetPanelName() const; + + indicator::Indicators::Ptr indicators_; + panel::PanelIndicatorsView* indicators_view_; + nux::ObjectPtr<nux::BaseTexture> bg_texture_; + + bool needs_geo_sync_; + nux::Point tracked_pointer_pos_; + glib::Source::UniquePtr track_menu_pointer_timeout_; +}; + +} // lockscreen namespace +} // unity namespace + +#endif // UNITY_LOCKSCREEN_PANEL diff --git a/lockscreen/LockScreenSettings.cpp b/lockscreen/LockScreenSettings.cpp new file mode 100644 index 000000000..c791be237 --- /dev/null +++ b/lockscreen/LockScreenSettings.cpp @@ -0,0 +1,104 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2013 Canonical Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> +*/ + +#include "LockScreenSettings.h" + +#include <NuxCore/Logger.h> +#include <sigc++/adaptors/hide.h> +#include <UnityCore/GLibSignal.h> +#include <UnityCore/GLibWrapper.h> + +namespace unity +{ +namespace lockscreen +{ + +DECLARE_LOGGER(logger, "unity.lockscreen.settings"); + +namespace +{ +Settings* settings_instance = nullptr; + +const std::string GREETER_SETTINGS = "com.canonical.unity-greeter"; +const std::string LOGO_KEY = "logo"; +const std::string FONT_KEY = "font-name"; +const std::string BACKGROUND_KEY = "background"; +const std::string BACKGROUND_COLOR_KEY = "background-color"; +const std::string USER_BG_KEY = "draw-user-backgrounds"; +const std::string DRAW_GRID_KEY = "draw-grid"; +const std::string SHOW_HOSTNAME_KEY = "show-hostname"; +} + +struct Settings::Impl +{ + Impl() + : greeter_settings_(g_settings_new(GREETER_SETTINGS.c_str())) + , signal_(greeter_settings_, "changed", sigc::hide(sigc::hide(sigc::mem_fun(this, &Impl::UpdateSettings)))) + { + UpdateSettings(); + } + + void UpdateSettings() + { + auto* s = settings_instance; + s->font_name = glib::String(g_settings_get_string(greeter_settings_, FONT_KEY.c_str())).Str(); + s->logo = glib::String(g_settings_get_string(greeter_settings_, LOGO_KEY.c_str())).Str(); + s->background = glib::String(g_settings_get_string(greeter_settings_, BACKGROUND_KEY.c_str())).Str(); + s->background_color = nux::Color(glib::String(g_settings_get_string(greeter_settings_, BACKGROUND_COLOR_KEY.c_str())).Str()); + s->show_hostname = g_settings_get_boolean(greeter_settings_, SHOW_HOSTNAME_KEY.c_str()) != FALSE; + s->use_user_background = g_settings_get_boolean(greeter_settings_, USER_BG_KEY.c_str()) != FALSE; + s->draw_grid = g_settings_get_boolean(greeter_settings_, DRAW_GRID_KEY.c_str()) != FALSE; + } + + glib::Object<GSettings> greeter_settings_; + glib::Signal<void, GSettings*, const gchar*> signal_; +}; + +Settings::Settings() +{ + if (settings_instance) + { + LOG_ERROR(logger) << "More than one lockscreen::Settings created."; + } + else + { + lockscreen_type = Type::UNITY; + settings_instance = this; + impl_.reset(new Impl()); + } +} + +Settings::~Settings() +{ + if (settings_instance == this) + settings_instance = nullptr; +} + +Settings& Settings::Instance() +{ + if (!settings_instance) + { + LOG_ERROR(logger) << "No lockscreen::Settings created yet."; + } + + return *settings_instance; +} + +} +} diff --git a/lockscreen/LockScreenSettings.h b/lockscreen/LockScreenSettings.h new file mode 100644 index 000000000..4e1148673 --- /dev/null +++ b/lockscreen/LockScreenSettings.h @@ -0,0 +1,66 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2013 Canonical Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> +*/ + +#ifndef UNITY_LOCKSCREEN_SETTINGS_H +#define UNITY_LOCKSCREEN_SETTINGS_H + +#include <NuxCore/Property.h> + +namespace unity +{ +namespace lockscreen +{ + +enum class Type : int +{ + NONE = 0, // Do nothing + LIGHTDM, // Fallback to lightdm + UNITY // Use custom Unity lockscreen +}; + +// TODO (andy) use the same options of unity-greeter + +class Settings +{ +public: + Settings(); + ~Settings(); + + static Settings& Instance(); + + nux::Property<Type> lockscreen_type; + nux::Property<std::string> font_name; + nux::Property<std::string> logo; + nux::Property<std::string> background; + nux::Property<nux::Color> background_color; + nux::Property<bool> show_hostname; + nux::Property<bool> use_user_background; + nux::Property<bool> draw_grid; + + static const int GRID_SIZE = 40; + +private: + struct Impl; + std::unique_ptr<Impl> impl_; +}; + +} +} + +#endif diff --git a/lockscreen/LockScreenShield.cpp b/lockscreen/LockScreenShield.cpp new file mode 100644 index 000000000..da8372103 --- /dev/null +++ b/lockscreen/LockScreenShield.cpp @@ -0,0 +1,220 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2013 Canonical Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> +*/ + +#include "LockScreenShield.h" + +#include <Nux/VLayout.h> +#include <Nux/HLayout.h> +#include <Nux/PaintLayer.h> + +#include "BackgroundSettings.h" +#include "CofView.h" +#include "LockScreenPanel.h" +#include "LockScreenSettings.h" +#include "UserPromptView.h" +#include "unity-shared/UScreen.h" +#include "unity-shared/WindowManager.h" + +namespace unity +{ +namespace lockscreen +{ + +Shield::Shield(session::Manager::Ptr const& session_manager, indicator::Indicators::Ptr const& indicators, int monitor_num, bool is_primary) + : AbstractShield(session_manager, indicators, monitor_num, is_primary) + , bg_settings_(std::make_shared<BackgroundSettings>()) + , prompt_view_(nullptr) + , panel_view_(nullptr) +{ + is_primary ? ShowPrimaryView() : ShowSecondaryView(); + + EnableInputWindow(true); + + geometry_changed.connect([this] (nux::Area*, nux::Geometry&) { UpdateBackgroundTexture();}); + + monitor.changed.connect([this] (int monitor) { + if (panel_view_) + panel_view_->monitor = monitor; + + UpdateBackgroundTexture(); + }); + + primary.changed.connect([this] (bool is_primary) { + if (!is_primary) + { + UnGrabPointer(); + UnGrabKeyboard(); + } + + is_primary ? ShowPrimaryView() : ShowSecondaryView(); + if (panel_view_) panel_view_->SetInputEventSensitivity(is_primary); + QueueRelayout(); + QueueDraw(); + }); + + mouse_move.connect([this] (int x, int y, int, int, unsigned long, unsigned long) { + auto const& abs_geo = GetAbsoluteGeometry(); + grab_motion.emit(abs_geo.x + x, abs_geo.y + y); + }); +} + +void Shield::UpdateBackgroundTexture() +{ + auto const& monitor_geo = UScreen::GetDefault()->GetMonitorGeometry(monitor); + + if (!background_layer_ || monitor_geo != background_layer_->GetGeometry()) + { + auto background_texture = bg_settings_->GetBackgroundTexture(monitor); + background_layer_.reset(new nux::TextureLayer(background_texture->GetDeviceTexture(), nux::TexCoordXForm(), nux::color::White, true)); + SetBackgroundLayer(background_layer_.get()); + } +} + +void Shield::ShowPrimaryView() +{ + GrabPointer(); + GrabKeyboard(); + + if (primary_layout_) + { + SetLayout(primary_layout_.GetPointer()); + return; + } + + nux::Layout* main_layout = new nux::VLayout(); + primary_layout_ = main_layout; + SetLayout(primary_layout_.GetPointer()); + + main_layout->AddView(CreatePanel()); + + nux::HLayout* prompt_layout = new nux::HLayout(); + prompt_layout->SetLeftAndRightPadding(2 * Settings::GRID_SIZE); + + prompt_view_ = CreatePromptView(); + prompt_layout->AddView(prompt_view_); + + // 10 is just a random number to center the prompt view. + main_layout->AddSpace(0, 10); + main_layout->AddLayout(prompt_layout); + main_layout->AddSpace(0, 10); +} + +void Shield::ShowSecondaryView() +{ + if (cof_layout_) + { + SetLayout(cof_layout_.GetPointer()); + return; + } + + nux::Layout* main_layout = new nux::VLayout(); + cof_layout_ = main_layout; + SetLayout(cof_layout_.GetPointer()); + + // The circle of friends + CofView* cof_view = new CofView(); + main_layout->AddView(cof_view); +} + +Panel* Shield::CreatePanel() +{ + if (!indicators_ || !session_manager_) + return nullptr; + + panel_view_ = new Panel(monitor, indicators_, session_manager_); + panel_active_conn_ = panel_view_->active.changed.connect([this] (bool active) { + if (primary()) + { + if (active) + { + UnGrabPointer(); + UnGrabKeyboard(); + } + else + { + GrabPointer(); + GrabKeyboard(); + } + } + }); + + return panel_view_; +} + +UserPromptView* Shield::CreatePromptView() +{ + auto* prompt_view = new UserPromptView(session_manager_); + + auto width = 8 * Settings::GRID_SIZE; + auto height = 3 * Settings::GRID_SIZE; + + prompt_view->SetMinimumWidth(width); + prompt_view->SetMaximumWidth(width); + prompt_view->SetMinimumHeight(height); + + return prompt_view; +} + +nux::Area* Shield::FindKeyFocusArea(unsigned etype, unsigned long key_code, unsigned long modifiers) +{ + if (primary) + { + if (panel_view_) + { + modifiers &= (nux::NUX_STATE_ALT | nux::NUX_STATE_CTRL | nux::NUX_STATE_SUPER | nux::NUX_STATE_SHIFT); + auto const& indicators_key = WindowManager::Default().activate_indicators_key(); + + if (indicators_key.first == modifiers && indicators_key.second == key_code) + return panel_view_; + } + + if (prompt_view_) + { + auto* focus_view = prompt_view_->focus_view(); + + if (focus_view && focus_view->GetInputEventSensitivity()) + return focus_view; + } + } + + return nullptr; +} + +bool Shield::AcceptKeyNavFocus() +{ + return false; +} + +nux::Area* Shield::FindAreaUnderMouse(nux::Point const& mouse, nux::NuxEventType event_type) +{ + nux::Area* area = BaseWindow::FindAreaUnderMouse(mouse, event_type); + + if (!area && primary) + return this; + + return area; +} + +bool Shield::IsIndicatorOpen() const +{ + return panel_view_ ? panel_view_->active() : false; +} + +} +} diff --git a/lockscreen/LockScreenShield.h b/lockscreen/LockScreenShield.h new file mode 100644 index 000000000..b4c951bab --- /dev/null +++ b/lockscreen/LockScreenShield.h @@ -0,0 +1,67 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2013 Canonical Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> +*/ + +#ifndef UNITY_LOCKSCREEN_SHIELD_H +#define UNITY_LOCKSCREEN_SHIELD_H + +#include <UnityCore/ConnectionManager.h> +#include "LockScreenAbstractShield.h" + +namespace unity +{ +namespace lockscreen +{ + +class BackgroundSettings; +class UserAuthenticator; +class UserPromptView; +class Panel; + +class Shield : public AbstractShield +{ +public: + Shield(session::Manager::Ptr const&, indicator::Indicators::Ptr const&, int monitor, bool is_primary); + + bool IsIndicatorOpen() const; + +protected: + bool AcceptKeyNavFocus() override; + nux::Area* FindKeyFocusArea(unsigned int, unsigned long, unsigned long) override; + nux::Area* FindAreaUnderMouse(nux::Point const&, nux::NuxEventType) override; + +private: + void UpdateBackgroundTexture(); + void ShowPrimaryView(); + void ShowSecondaryView(); + Panel* CreatePanel(); + UserPromptView* CreatePromptView(); + + std::shared_ptr<BackgroundSettings> bg_settings_; + std::unique_ptr<nux::AbstractPaintLayer> background_layer_; + nux::ObjectPtr<nux::Layout> primary_layout_; + nux::ObjectPtr<nux::Layout> cof_layout_; + connection::Wrapper panel_active_conn_; + UserPromptView* prompt_view_; + Panel* panel_view_; +}; + +} +} + +#endif \ No newline at end of file diff --git a/lockscreen/LockScreenShieldFactory.cpp b/lockscreen/LockScreenShieldFactory.cpp new file mode 100644 index 000000000..4932ca5c4 --- /dev/null +++ b/lockscreen/LockScreenShieldFactory.cpp @@ -0,0 +1,34 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2014 Canonical Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> +*/ + +#include "LockScreenShieldFactory.h" +#include "LockScreenShield.h" + +namespace unity +{ +namespace lockscreen +{ + +nux::ObjectPtr<AbstractShield> ShieldFactory::CreateShield(session::Manager::Ptr const& session_manager, indicator::Indicators::Ptr const& indicators, int monitor, bool is_primary) +{ + return nux::ObjectPtr<Shield>(new Shield(session_manager, indicators, monitor, is_primary)); +} + +} +} diff --git a/lockscreen/LockScreenShieldFactory.h b/lockscreen/LockScreenShieldFactory.h new file mode 100644 index 000000000..19b3894fa --- /dev/null +++ b/lockscreen/LockScreenShieldFactory.h @@ -0,0 +1,51 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2014 Canonical Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> +*/ + +#ifndef UNITY_LOCKSCREEN_SHIELD_FACTORY +#define UNITY_LOCKSCREEN_SHIELD_FACTORY + +#include <Nux/Nux.h> +#include "LockScreenAbstractShield.h" + +namespace unity +{ + +class MockableBaseWindow; + +namespace lockscreen +{ + +struct ShieldFactoryInterface +{ + typedef std::shared_ptr<ShieldFactoryInterface> Ptr; + + virtual ~ShieldFactoryInterface() = default; + + virtual nux::ObjectPtr<AbstractShield> CreateShield(session::Manager::Ptr const&, indicator::Indicators::Ptr const&, int monitor, bool is_primary) = 0; +}; + +struct ShieldFactory : ShieldFactoryInterface +{ + nux::ObjectPtr<AbstractShield> CreateShield(session::Manager::Ptr const&, indicator::Indicators::Ptr const&, int monitor, bool is_primary) override; +}; + +} +} + +#endif diff --git a/lockscreen/UserAuthenticator.h b/lockscreen/UserAuthenticator.h new file mode 100644 index 000000000..a8b46b816 --- /dev/null +++ b/lockscreen/UserAuthenticator.h @@ -0,0 +1,56 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2013 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + */ + +#ifndef UNITY_USER_AUTHENTICATOR_H +#define UNITY_USER_AUTHENTICATOR_H + +#include <future> +#include <functional> +#include <memory> +#include <sigc++/signal.h> +#include <string> + +namespace unity +{ +namespace lockscreen +{ + +typedef std::shared_ptr<std::promise<std::string>> PromiseAuthCodePtr; + +class UserAuthenticator +{ +public: + typedef std::function<void(bool)> AuthenticateEndCallback; + + virtual ~UserAuthenticator() = default; + + // Authenticate the user in a background thread. + virtual bool AuthenticateStart(std::string const& username, AuthenticateEndCallback const&) = 0; + + sigc::signal<void, std::string, PromiseAuthCodePtr const&> echo_on_requested; + sigc::signal<void, std::string, PromiseAuthCodePtr const&> echo_off_requested; + sigc::signal<void, std::string> message_requested; + sigc::signal<void, std::string> error_requested; + sigc::signal<void> clear_prompts; +}; + +} // lockscreen +} // unity + + #endif // UNITY_USER_AUTHENTICATOR_H diff --git a/lockscreen/UserAuthenticatorPam.cpp b/lockscreen/UserAuthenticatorPam.cpp new file mode 100644 index 000000000..73e3c1d70 --- /dev/null +++ b/lockscreen/UserAuthenticatorPam.cpp @@ -0,0 +1,171 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2013 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + */ + +// Kindly inspired by user_authenticator_linux.cc of chromium project +// In the future would be nice to have something less static. For the moment +// let's just fallcback to lightdm. + +#include "UserAuthenticatorPam.h" + +#include <cstring> +#include <security/pam_appl.h> +#include <vector> + +namespace unity +{ +namespace lockscreen +{ + +bool UserAuthenticatorPam::AuthenticateStart(std::string const& username, + AuthenticateEndCallback const& authenticate_cb) +{ + first_prompt_ = true; + username_ = username; + authenticate_cb_ = authenticate_cb; + + if (!InitPam()) + return false; + + glib::Object<GTask> task(g_task_new(nullptr, cancellable_, [] (GObject*, GAsyncResult*, gpointer data) { + auto self = static_cast<UserAuthenticatorPam*>(data); + pam_end(self->pam_handle_, self->status_); + self->authenticate_cb_(self->status_ == PAM_SUCCESS); + }, this)); + + g_task_set_task_data(task, this, nullptr); + + g_task_run_in_thread(task, [] (GTask* task, gpointer, gpointer data, GCancellable*) { + auto self = static_cast<UserAuthenticatorPam*>(data); + self->status_ = pam_authenticate(self->pam_handle_, 0); + }); + + return true; +} + +bool UserAuthenticatorPam::InitPam() +{ + pam_conv conversation; + conversation.conv = ConversationFunction; + conversation.appdata_ptr = static_cast<void*>(this); + + // FIXME (andy) We should install our own unityshell pam file. + return pam_start("lightdm", username_.c_str(), + &conversation, &pam_handle_) == PAM_SUCCESS; +} + +int UserAuthenticatorPam::ConversationFunction(int num_msg, + const pam_message** msg, + pam_response** resp, + void* appdata_ptr) +{ + if (num_msg <= 0) + return PAM_CONV_ERR; + + auto* tmp_response = static_cast<pam_response*>(calloc(num_msg, sizeof(pam_response))); + + if (!tmp_response) + return PAM_CONV_ERR; + + UserAuthenticatorPam* user_auth = static_cast<UserAuthenticatorPam*>(appdata_ptr); + + if (!user_auth->first_prompt_) + { + // Adding a timeout ensures that the signal is emitted in the main thread + user_auth->source_manager_.AddTimeout(0, [user_auth] { user_auth->clear_prompts.emit(); return false; }); + } + + user_auth->first_prompt_ = false; + + bool raise_error = false; + int count; + std::vector<PromiseAuthCodePtr> promises; + + for (count = 0; count < num_msg && !raise_error; ++count) + { + switch (msg[count]->msg_style) + { + case PAM_PROMPT_ECHO_ON: + { + auto promise = std::make_shared<std::promise<std::string>>(); + promises.push_back(promise); + + // Adding a timeout ensures that the signal is emitted in the main thread + std::string message(msg[count]->msg); + user_auth->source_manager_.AddTimeout(0, [user_auth, message, promise] { user_auth->echo_on_requested.emit(message, promise); return false; }); + break; + } + case PAM_PROMPT_ECHO_OFF: + { + auto promise = std::make_shared<std::promise<std::string>>(); + promises.push_back(promise); + + // Adding a timeout ensures that the signal is emitted in the main thread + std::string message(msg[count]->msg); + user_auth->source_manager_.AddTimeout(0, [user_auth, message, promise] { user_auth->echo_off_requested.emit(message, promise); return false; }); + break; + } + case PAM_TEXT_INFO: + { + // Adding a timeout ensures that the signal is emitted in the main thread + std::string message(msg[count]->msg); + user_auth->source_manager_.AddTimeout(0, [user_auth, message] { user_auth->message_requested.emit(message); return false; }); + break; + } + default: + { + // Adding a timeout ensures that the signal is emitted in the main thread + std::string message(msg[count]->msg); + user_auth->source_manager_.AddTimeout(0, [user_auth, message] { user_auth->error_requested.emit(message); return false; }); + } + } + } + + int i = 0; + + for (auto const& promise : promises) + { + auto future = promise->get_future(); + pam_response* resp_item = &tmp_response[i++]; + resp_item->resp_retcode = 0; + resp_item->resp = strdup(future.get().c_str()); + + if (!resp_item->resp) + { + raise_error = true; + break; + } + } + + if (raise_error) + { + for (int i = 0; i < count; ++i) + free(tmp_response[i].resp); + + free(tmp_response); + return PAM_CONV_ERR; + } + else + { + *resp = tmp_response; + return PAM_SUCCESS; + } +} + +} // lockscreen +} // unity diff --git a/lockscreen/UserAuthenticatorPam.h b/lockscreen/UserAuthenticatorPam.h new file mode 100644 index 000000000..5174aec81 --- /dev/null +++ b/lockscreen/UserAuthenticatorPam.h @@ -0,0 +1,66 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2013 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + */ + +#ifndef UNITY_USER_AUTHENTICATOR_PAM_H +#define UNITY_USER_AUTHENTICATOR_PAM_H + +#include <boost/noncopyable.hpp> +#include <UnityCore/GLibWrapper.h> +#include <UnityCore/GLibSource.h> + +#include "UserAuthenticator.h" + +// Forward declarations +struct pam_handle; +struct pam_message; +struct pam_response; + +namespace unity +{ +namespace lockscreen +{ + +class UserAuthenticatorPam : public UserAuthenticator, private boost::noncopyable +{ +public: + bool AuthenticateStart(std::string const& username, AuthenticateEndCallback const&) override; + +private: + // TODO (andy) move to pimpl + bool InitPam(); + + static int ConversationFunction(int num_msg, + const pam_message** msg, + pam_response** resp, + void* appdata_ptr); + + std::string username_; + AuthenticateEndCallback authenticate_cb_; + + int status_; + bool first_prompt_; + pam_handle* pam_handle_; + glib::Cancellable cancellable_; + glib::SourceManager source_manager_; +}; + +} // lockscreen +} // unity + +#endif // UNITY_USER_AUTHENTICATOR_PAM_H diff --git a/lockscreen/UserPromptView.cpp b/lockscreen/UserPromptView.cpp new file mode 100644 index 000000000..28163b9d8 --- /dev/null +++ b/lockscreen/UserPromptView.cpp @@ -0,0 +1,282 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2014 Canonical Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> +*/ + +#include "UserPromptView.h" + +#include <boost/algorithm/string/trim.hpp> +#include <Nux/VLayout.h> + +#include "LockScreenSettings.h" +#include "unity-shared/CairoTexture.h" +#include "unity-shared/TextInput.h" +#include "unity-shared/StaticCairoText.h" +#include "unity-shared/RawPixel.h" + +namespace unity +{ +namespace lockscreen +{ +namespace +{ +const RawPixel PADDING = 10_em; +const RawPixel LAYOUT_MARGIN = 10_em; +const RawPixel MSG_LAYOUT_MARGIN = 15_em; +const RawPixel PROMPT_LAYOUT_MARGIN = 5_em; +const int PROMPT_FONT_SIZE = 13; + +nux::AbstractPaintLayer* CrateBackgroundLayer(int width, int height) +{ + nux::CairoGraphics cg(CAIRO_FORMAT_ARGB32, width, height); + cairo_t* cr = cg.GetInternalContext(); + + cairo_set_source_rgba(cr, 0.1, 0.1, 0.1, 0.4); + + cg.DrawRoundedRectangle(cr, + 1.0, + 0, 0, + Settings::GRID_SIZE * 0.3, + width, height); + + cairo_fill_preserve(cr); + + cairo_set_source_rgba (cr, 0.4, 0.4, 0.4, 0.4); + cairo_set_line_width (cr, 1); + cairo_stroke (cr); + + // Create the texture layer + nux::TexCoordXForm texxform; + + nux::ROPConfig rop; + rop.Blend = true; + rop.SrcBlend = GL_ONE; + rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA; + + return (new nux::TextureLayer(texture_ptr_from_cairo_graphics(cg)->GetDeviceTexture(), + texxform, + nux::color::White, + true, + rop)); +} + +std::string SanitizeMessage(std::string const& message) +{ + std::string msg = boost::algorithm::trim_copy(message); + + if (msg.empty()) + return msg; + + if (msg[msg.size()-1] == ':') + msg = msg.substr(0, msg.size()-1); + + if (msg == "Password") + return _("Password"); + + if (msg == "login") + return _("Username"); + + return msg; +} + +} + +UserPromptView::UserPromptView(session::Manager::Ptr const& session_manager) + : nux::View(NUX_TRACKER_LOCATION) + , session_manager_(session_manager) +{ + user_authenticator_.echo_on_requested.connect([this](std::string const& message, PromiseAuthCodePtr const& promise){ + AddPrompt(message, /* visible */ true, promise); + }); + + user_authenticator_.echo_off_requested.connect([this](std::string const& message, PromiseAuthCodePtr const& promise){ + AddPrompt(message, /* visible */ false, promise); + }); + + user_authenticator_.message_requested.connect([this](std::string const& message){ + AddMessage(message, nux::color::White); + }); + + user_authenticator_.error_requested.connect([this](std::string const& message){ + AddMessage(message, nux::color::Red); + }); + + user_authenticator_.clear_prompts.connect([this](){ + ResetLayout(); + }); + + ResetLayout(); + + user_authenticator_.AuthenticateStart(session_manager_->UserName(), + sigc::mem_fun(this, &UserPromptView::AuthenticationCb)); +} + +void UserPromptView::ResetLayout() +{ + focus_queue_.clear(); + + SetLayout(new nux::VLayout()); + + GetLayout()->SetLeftAndRightPadding(PADDING); + GetLayout()->SetTopAndBottomPadding(PADDING); + static_cast<nux::VLayout*>(GetLayout())->SetVerticalInternalMargin(LAYOUT_MARGIN); + + auto const& real_name = session_manager_->RealName(); + auto const& name = (real_name.empty() ? session_manager_->UserName() : real_name); + + unity::StaticCairoText* username = new unity::StaticCairoText(name); + username->SetFont("Ubuntu "+std::to_string(PROMPT_FONT_SIZE)); + GetLayout()->AddView(username); + + msg_layout_ = new nux::VLayout(); + msg_layout_->SetVerticalInternalMargin(MSG_LAYOUT_MARGIN); + msg_layout_->SetReconfigureParentLayoutOnGeometryChange(true); + GetLayout()->AddLayout(msg_layout_); + + prompt_layout_ = new nux::VLayout(); + prompt_layout_->SetVerticalInternalMargin(PROMPT_LAYOUT_MARGIN); + prompt_layout_->SetReconfigureParentLayoutOnGeometryChange(true); + GetLayout()->AddLayout(prompt_layout_); + + QueueRelayout(); + QueueDraw(); +} + +void UserPromptView::AuthenticationCb(bool authenticated) +{ + ResetLayout(); + + if (authenticated) + { + session_manager_->unlock_requested.emit(); + } + else + { + AddMessage(_("Invalid password, please try again"), nux::color::Red); + + user_authenticator_.AuthenticateStart(session_manager_->UserName(), + sigc::mem_fun(this, &UserPromptView::AuthenticationCb)); + } +} + +void UserPromptView::Draw(nux::GraphicsEngine& graphics_engine, bool /* force_draw */) +{ + nux::Geometry const& geo = GetGeometry(); + + graphics_engine.PushClippingRectangle(geo); + nux::GetPainter().PaintBackground(graphics_engine, geo); + + bg_layer_.reset(CrateBackgroundLayer(geo.width, geo.height)); + nux::GetPainter().PushDrawLayer(graphics_engine, geo, bg_layer_.get()); + + nux::GetPainter().PopBackground(); + graphics_engine.PopClippingRectangle(); +} + +void UserPromptView::DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw) +{ + nux::Geometry const& geo = GetGeometry(); + graphics_engine.PushClippingRectangle(geo); + + if (!IsFullRedraw()) + { + bg_layer_.reset(CrateBackgroundLayer(geo.width, geo.height)); + nux::GetPainter().PushLayer(graphics_engine, geo, bg_layer_.get()); + } + + if (GetLayout()) + GetLayout()->ProcessDraw(graphics_engine, force_draw); + + if (!IsFullRedraw()) + nux::GetPainter().PopBackground(); + + graphics_engine.PopClippingRectangle(); +} + +nux::View* UserPromptView::focus_view() +{ + if (focus_queue_.empty()) + return nullptr; + + for (auto* view : focus_queue_) + if (view->HasKeyboardFocus()) + return view; + + return focus_queue_.front(); +} + +void UserPromptView::AddPrompt(std::string const& message, bool visible, PromiseAuthCodePtr const& promise) +{ + auto* text_input = new unity::TextInput(); + auto* text_entry = text_input->text_entry(); + + text_input->input_hint = SanitizeMessage(message); + text_input->hint_font_size = PROMPT_FONT_SIZE; + text_entry->SetPasswordMode(!visible); + text_entry->SetPasswordChar("•"); + text_entry->SetToggleCursorVisibilityOnKeyFocus(true); + + text_input->SetMinimumHeight(Settings::GRID_SIZE); + text_input->SetMaximumHeight(Settings::GRID_SIZE); + prompt_layout_->AddView(text_input, 1); + focus_queue_.push_back(text_entry); + + // Don't remove it, it helps with a11y. + if (focus_queue_.size() == 1) + nux::GetWindowCompositor().SetKeyFocusArea(text_entry); + + text_entry->activated.connect([this, text_input, promise](){ + if (focus_queue_.size() == 1) + { + text_input->SetSpinnerVisible(true); + text_input->SetSpinnerState(STATE_SEARCHING); + } + + focus_queue_.pop_front(); + auto* text_entry = text_input->text_entry(); + text_entry->SetInputEventSensitivity(false); + QueueRelayout(); + QueueDraw(); + + std::string const& password = text_entry->GetText(); + if (promise) + promise->set_value(password); + }); + + GetLayout()->ComputeContentPosition(0, 0); + ComputeContentSize(); + QueueRelayout(); + QueueDraw(); +} + +void UserPromptView::AddMessage(std::string const& message, nux::Color const& color) +{ + auto* view = new unity::StaticCairoText(""); + view->SetFont(Settings::Instance().font_name()); + view->SetTextColor(color); + view->SetText(message); + + msg_layout_->AddView(view); + + GetLayout()->ComputeContentPosition(0, 0); + ComputeContentSize(); + QueueRelayout(); + QueueDraw(); +} + +} +} diff --git a/lockscreen/UserPromptView.h b/lockscreen/UserPromptView.h new file mode 100644 index 000000000..7d5ea4336 --- /dev/null +++ b/lockscreen/UserPromptView.h @@ -0,0 +1,81 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2014 Canonical Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> +*/ + +#ifndef UNITY_USER_PROMPT_BOX +#define UNITY_USER_PROMPT_BOX + +#include <memory> +#include <deque> + +#include <Nux/Nux.h> +#include <Nux/View.h> +#include <UnityCore/SessionManager.h> + +#include "UserAuthenticatorPam.h" +#include "unity-shared/IMTextEntry.h" +#include "unity-shared/SearchBarSpinner.h" + +namespace nux +{ +class VLayout; +} + +namespace unity +{ + +class StaticCairoText; +class TextInput; + +namespace lockscreen +{ + +class UserPromptView : public nux::View +{ +public: + UserPromptView(session::Manager::Ptr const& session_manager); + ~UserPromptView() {}; + + nux::View* focus_view(); + + void AddPrompt(std::string const& message, bool visible, PromiseAuthCodePtr const&); + void AddMessage(std::string const& message, nux::Color const& color); + void AuthenticationCb(bool authenticated); + +protected: + void Draw(nux::GraphicsEngine& graphics_engine, bool force_draw) override; + void DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw) override; + +private: + void ResetLayout(); + + session::Manager::Ptr session_manager_; + UserAuthenticatorPam user_authenticator_; + std::shared_ptr<nux::AbstractPaintLayer> bg_layer_; + nux::VLayout* msg_layout_; + nux::VLayout* prompt_layout_; + StaticCairoText* message_; + StaticCairoText* error_; + StaticCairoText* invalid_login_; + std::deque<IMTextEntry*> focus_queue_; +}; + +} +} + +#endif diff --git a/lockscreen/pch/lockscreen_pch.hh b/lockscreen/pch/lockscreen_pch.hh new file mode 100644 index 000000000..09f3d0a20 --- /dev/null +++ b/lockscreen/pch/lockscreen_pch.hh @@ -0,0 +1,32 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2013 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + */ + +/* + * These are the precompiled header includes for this module. + * Only system header files can be listed here. + */ + +#include <memory> +#include <vector> +#include <deque> +#include <security/pam_appl.h> + +#include <Nux/Nux.h> +#include <UnityCore/SessionManager.h> +#include <UnityCore/Indicators.h> \ No newline at end of file diff --git a/panel/PanelIndicatorEntryView.cpp b/panel/PanelIndicatorEntryView.cpp index 5dba6ec2a..42aff3fbf 100644 --- a/panel/PanelIndicatorEntryView.cpp +++ b/panel/PanelIndicatorEntryView.cpp @@ -387,7 +387,7 @@ void PanelIndicatorEntryView::DrawEntryContent(cairo_t *cr, unsigned int width, pango_layout_get_pixel_size(layout, &extents.width, &extents.height); int y = (height - extents.height) / 2; - if (overlay_showing_) + if (overlay_showing_ && !IsActive()) { cairo_move_to(cr, x, y); cairo_set_source_rgb(cr, 1.0f, 1.0f, 1.0f); diff --git a/panel/PanelIndicatorsView.cpp b/panel/PanelIndicatorsView.cpp index b65530b84..90fb67176 100644 --- a/panel/PanelIndicatorsView.cpp +++ b/panel/PanelIndicatorsView.cpp @@ -42,6 +42,7 @@ PanelIndicatorsView::PanelIndicatorsView() , opacity(1.0f, sigc::mem_fun(this, &PanelIndicatorsView::SetOpacity)) , layout_(new nux::HLayout("", NUX_TRACKER_LOCATION)) , monitor_(0) +, overlay_showing_(false) { opacity.DisableNotifications(); layout_->SetContentDistribution(nux::MAJOR_POSITION_END); @@ -327,6 +328,9 @@ PanelIndicatorEntryView *PanelIndicatorsView::AddEntry(Entry::Ptr const& entry, auto view = new PanelIndicatorEntryView(entry, padding, type); AddEntryView(view, pos); + if (overlay_showing_) + view->OverlayShown(); + return view; } @@ -368,12 +372,16 @@ void PanelIndicatorsView::RemoveEntry(std::string const& entry_id) void PanelIndicatorsView::OverlayShown() { + overlay_showing_ = true; + for (auto const& entry: entries_) entry.second->OverlayShown(); } void PanelIndicatorsView::OverlayHidden() { + overlay_showing_ = false; + for (auto const& entry: entries_) entry.second->OverlayHidden(); } diff --git a/panel/PanelIndicatorsView.h b/panel/PanelIndicatorsView.h index 0f6f7c44e..0219a407c 100644 --- a/panel/PanelIndicatorsView.h +++ b/panel/PanelIndicatorsView.h @@ -98,6 +98,7 @@ protected: Entries entries_; int monitor_; + bool overlay_showing_; private: bool SetOpacity(double& target, double const& new_value); diff --git a/panel/PanelMenuView.cpp b/panel/PanelMenuView.cpp index 185192558..a30b2af68 100644 --- a/panel/PanelMenuView.cpp +++ b/panel/PanelMenuView.cpp @@ -64,7 +64,6 @@ PanelMenuView::PanelMenuView(menu::Manager::Ptr const& menus) , is_desktop_focused_(false) , last_active_view_(nullptr) , new_application_(nullptr) - , overlay_showing_(false) , switcher_showing_(false) , spread_showing_(false) , launcher_keynav_(false) diff --git a/panel/PanelMenuView.h b/panel/PanelMenuView.h index cf62915b9..9ee842450 100644 --- a/panel/PanelMenuView.h +++ b/panel/PanelMenuView.h @@ -176,7 +176,6 @@ private: nux::Geometry last_geo_; nux::Geometry title_geo_; - bool overlay_showing_; bool switcher_showing_; bool spread_showing_; bool launcher_keynav_; diff --git a/panel/PanelView.cpp b/panel/PanelView.cpp index a6ce660a1..4debdd8d3 100644 --- a/panel/PanelView.cpp +++ b/panel/PanelView.cpp @@ -19,20 +19,11 @@ */ #include <Nux/Nux.h> -#include <Nux/BaseWindow.h> #include <Nux/HLayout.h> -#include <Nux/Layout.h> -#include <Nux/WindowCompositor.h> -#include <NuxGraphics/CairoGraphics.h> #include <NuxCore/Logger.h> #include <UnityCore/GLibWrapper.h> -#include <NuxGraphics/GLThread.h> -#include <NuxGraphics/RenderingPipe.h> - -#include <glib.h> - #include "unity-shared/PanelStyle.h" #include "unity-shared/TextureCache.h" #include "unity-shared/WindowManager.h" @@ -556,7 +547,11 @@ void PanelView::PreLayoutManagement() { View::PreLayoutManagement(); - int menu_width = GetMaximumWidth() - indicators_->GetBaseWidth() - tray_->GetBaseWidth(); + int tray_width = 0; + if (tray_) + tray_width = tray_->GetBaseWidth(); + + int menu_width = GetMaximumWidth() - indicators_->GetBaseWidth() - tray_width; menu_view_->SetMinimumWidth(menu_width); menu_view_->SetMaximumWidth(menu_width); diff --git a/plugins/unityshell/CMakeLists.txt b/plugins/unityshell/CMakeLists.txt index 5fa3917b1..43e46e4bc 100644 --- a/plugins/unityshell/CMakeLists.txt +++ b/plugins/unityshell/CMakeLists.txt @@ -13,7 +13,7 @@ endif() compiz_plugin (unityshell PKGDEPS ${UNITY_PLUGIN_DEPS} PLUGINDEPS composite opengl compiztoolbox scale - CFLAGSADD "-DINSTALLPREFIX='\"${CMAKE_INSTALL_PREFIX}\"' -DPKGDATADIR='\"${PKGDATADIR}\"' -I${CMAKE_BINARY_DIR} -I${CMAKE_SOURCE_DIR} ${BOOT_LOGGER_FLAG} -DGETTEXT_PACKAGE='\"unity\"' ${MAINTAINER_CXXFLAGS} -I${CMAKE_SOURCE_DIR}/dash/ -I${CMAKE_SOURCE_DIR}/launcher/ -I${CMAKE_SOURCE_DIR}/hud/ -I${CMAKE_SOURCE_DIR}/panel/ -I${CMAKE_SOURCE_DIR}/shortcuts/ -I${CMAKE_SOURCE_DIR}/shutdown/ -I${CMAKE_SOURCE_DIR}/unity-shared/" + CFLAGSADD "-DINSTALLPREFIX='\"${CMAKE_INSTALL_PREFIX}\"' -DPKGDATADIR='\"${PKGDATADIR}\"' -I${CMAKE_BINARY_DIR} -I${CMAKE_SOURCE_DIR} ${BOOT_LOGGER_FLAG} -DGETTEXT_PACKAGE='\"unity\"' ${MAINTAINER_CXXFLAGS} -I${CMAKE_SOURCE_DIR}/dash/ -I${CMAKE_SOURCE_DIR}/launcher/ -I${CMAKE_SOURCE_DIR}/lockscreen/ -I${CMAKE_SOURCE_DIR}/hud/ -I${CMAKE_SOURCE_DIR}/panel/ -I${CMAKE_SOURCE_DIR}/shortcuts/ -I${CMAKE_SOURCE_DIR}/shutdown/ -I${CMAKE_SOURCE_DIR}/unity-shared/" LIBDIRS "${CMAKE_BINARY_DIR}/UnityCore" ) @@ -26,6 +26,8 @@ add_dependencies(unityshell decorations-lib hud-lib launcher-lib + pam + lockscreen-lib panel-lib shortcuts-lib shutdown-lib @@ -39,6 +41,8 @@ target_link_libraries(unityshell decorations-lib hud-lib launcher-lib + pam + lockscreen-lib panel-lib shortcuts-lib shutdown-lib diff --git a/plugins/unityshell/src/nux-text-entry-accessible.cpp b/plugins/unityshell/src/nux-text-entry-accessible.cpp index e948f2827..bda50a611 100644 --- a/plugins/unityshell/src/nux-text-entry-accessible.cpp +++ b/plugins/unityshell/src/nux-text-entry-accessible.cpp @@ -48,36 +48,19 @@ static AtkStateSet* nux_text_entry_accessible_ref_state_set(AtkObject* obj); G_DEFINE_TYPE(NuxTextEntryAccessible, nux_text_entry_accessible, NUX_TYPE_VIEW_ACCESSIBLE); -#define NUX_TEXT_ENTRY_ACCESSIBLE_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NUX_TYPE_TEXT_ENTRY_ACCESSIBLE, \ - NuxTextEntryAccessiblePrivate)) - -struct _NuxTextEntryAccessiblePrivate -{ -}; - - static void nux_text_entry_accessible_class_init(NuxTextEntryAccessibleClass* klass) { - GObjectClass* gobject_class = G_OBJECT_CLASS(klass); AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); /* AtkObject */ atk_class->ref_state_set = nux_text_entry_accessible_ref_state_set; atk_class->initialize = nux_text_entry_accessible_initialize; - - g_type_class_add_private(gobject_class, sizeof(NuxTextEntryAccessiblePrivate)); } static void nux_text_entry_accessible_init(NuxTextEntryAccessible* self) -{ - NuxTextEntryAccessiblePrivate* priv = - NUX_TEXT_ENTRY_ACCESSIBLE_GET_PRIVATE(self); - - self->priv = priv; -} +{} AtkObject* nux_text_entry_accessible_new(nux::Object* object) @@ -98,9 +81,15 @@ static void nux_text_entry_accessible_initialize(AtkObject* accessible, gpointer data) { + nux::Object* nux_object = NULL; + nux::TextEntry* text_entry = NULL; + ATK_OBJECT_CLASS(nux_text_entry_accessible_parent_class)->initialize(accessible, data); - atk_object_set_role(accessible, ATK_ROLE_ENTRY); + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + text_entry = dynamic_cast<nux::TextEntry*>(nux_object); + + atk_object_set_role(accessible, text_entry->PasswordMode() ? ATK_ROLE_PASSWORD_TEXT : ATK_ROLE_ENTRY); } static AtkStateSet* diff --git a/plugins/unityshell/src/unity-text-input-accessible.cpp b/plugins/unityshell/src/unity-text-input-accessible.cpp new file mode 100644 index 000000000..57d1a490a --- /dev/null +++ b/plugins/unityshell/src/unity-text-input-accessible.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2014 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + */ + +#include "unity-text-input-accessible.h" + +#include "unitya11y.h" +#include "TextInput.h" + +using namespace unity; + +/* GObject */ +static void unity_text_input_accessible_class_init(UnityTextInputAccessibleClass* klass); +static void unity_text_input_accessible_init(UnityTextInputAccessible* self); +//static void unity_text_input_accessible_finalize(GObject* object); + +/* AtkObject.h */ +static void unity_text_input_accessible_initialize(AtkObject* accessible, + gpointer data); + +G_DEFINE_TYPE(UnityTextInputAccessible, unity_text_input_accessible, NUX_TYPE_VIEW_ACCESSIBLE) + +static void +unity_text_input_accessible_class_init(UnityTextInputAccessibleClass* klass) +{ + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + /* AtkObject */ + atk_class->initialize = unity_text_input_accessible_initialize; +} + +static void +unity_text_input_accessible_init(UnityTextInputAccessible* self) +{} + +AtkObject* +unity_text_input_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<TextInput*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_TEXT_INPUT_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + + return accessible; +} + +static void +unity_text_input_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + nux::Object* nux_object = NULL; + TextInput* text_input = NULL; + nux::TextEntry* text_entry = NULL; + + ATK_OBJECT_CLASS(unity_text_input_accessible_parent_class)->initialize(accessible, data); + + accessible->role = ATK_ROLE_PANEL; + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + text_input = dynamic_cast<TextInput*>(nux_object); + + if (text_input == NULL) + return; + + text_entry = text_input->text_entry(); + + if (text_entry != NULL) + { + AtkObject* text_entry_accessible = NULL; + text_entry_accessible = unity_a11y_get_accessible(text_entry); + atk_object_set_name(text_entry_accessible, text_input->input_hint().c_str()); + } +} diff --git a/plugins/unityshell/src/unity-text-input-accessible.h b/plugins/unityshell/src/unity-text-input-accessible.h new file mode 100644 index 000000000..c1ab85636 --- /dev/null +++ b/plugins/unityshell/src/unity-text-input-accessible.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + */ + +#ifndef UNITY_TEXT_INPUT_ACCESSIBLE_H +#define UNITY_TEXT_INPUT_ACCESSIBLE_H + +#include <atk/atk.h> + +#include "nux-view-accessible.h" + +G_BEGIN_DECLS + +#define UNITY_TYPE_TEXT_INPUT_ACCESSIBLE (unity_text_input_accessible_get_type ()) +#define UNITY_TEXT_INPUT_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_TEXT_INPUT_ACCESSIBLE, UnityTextInputAccessible)) +#define UNITY_TEXT_INPUT_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_TEXT_INPUT_ACCESSIBLE, UnityTextInputAccessibleClass)) +#define UNITY_IS_TEXT_INPUT_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_TEXT_INPUT_ACCESSIBLE)) +#define UNITY_IS_TEXT_INPUT_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_TEXT_INPUT_ACCESSIBLE)) +#define UNITY_TEXT_INPUT_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_TEXT_INPUT_ACCESSIBLE, UnityTextInputAccessibleClass)) + +typedef struct _UnityTextInputAccessible UnityTextInputAccessible; +typedef struct _UnityTextInputAccessibleClass UnityTextInputAccessibleClass; +typedef struct _UnityTextInputAccessiblePrivate UnityTextInputAccessiblePrivate; + +struct _UnityTextInputAccessible +{ + NuxViewAccessible parent; + + /*< private >*/ + UnityTextInputAccessiblePrivate* priv; +}; + +struct _UnityTextInputAccessibleClass +{ + NuxViewAccessibleClass parent_class; +}; + +GType unity_text_input_accessible_get_type(void); +AtkObject* unity_text_input_accessible_new(nux::Object* object); + +G_END_DECLS + +#endif diff --git a/plugins/unityshell/src/unitya11y.cpp b/plugins/unityshell/src/unitya11y.cpp index 50a72a380..346c915ae 100644 --- a/plugins/unityshell/src/unitya11y.cpp +++ b/plugins/unityshell/src/unitya11y.cpp @@ -42,6 +42,7 @@ #include "QuicklistView.h" #include "QuicklistMenuItem.h" #include "SwitcherView.h" +#include "TextInput.h" #include "SessionButton.h" #include "unity-launcher-accessible.h" #include "unity-launcher-icon-accessible.h" @@ -54,6 +55,7 @@ #include "unity-quicklist-accessible.h" #include "unity-quicklist-menu-item-accessible.h" #include "unity-switcher-accessible.h" +#include "unity-text-input-accessible.h" #include "unity-session-button-accessible.h" using namespace unity; @@ -187,6 +189,9 @@ unity_a11y_create_accessible(nux::Object* object) if (object->Type().IsDerivedFromType(unity::SearchBar::StaticObjectType)) return unity_search_bar_accessible_new(object); + if (object->Type().IsDerivedFromType(unity::TextInput::StaticObjectType)) + return unity_text_input_accessible_new(object); + if (object->Type().IsDerivedFromType(unity::switcher::SwitcherView::StaticObjectType)) return unity_switcher_accessible_new(object); diff --git a/plugins/unityshell/src/unityshell.cpp b/plugins/unityshell/src/unityshell.cpp index 7f794253e..af09ebc3b 100644 --- a/plugins/unityshell/src/unityshell.cpp +++ b/plugins/unityshell/src/unityshell.cpp @@ -338,12 +338,14 @@ UnityScreen::UnityScreen(CompScreen* screen) optionSetShowDesktopKeyInitiate(boost::bind(&UnityScreen::showDesktopKeyInitiate, this, _1, _2, _3)); optionSetPanelFirstMenuInitiate(boost::bind(&UnityScreen::showPanelFirstMenuKeyInitiate, this, _1, _2, _3)); optionSetPanelFirstMenuTerminate(boost::bind(&UnityScreen::showPanelFirstMenuKeyTerminate, this, _1, _2, _3)); + optionSetPanelFirstMenuNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetAutomaximizeValueNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetDashTapDurationNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetAltTabTimeoutNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetAltTabBiasViewportNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetDisableShowDesktopNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetDisableMouseNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); + optionSetLockScreenTypeNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetAltTabForwardAllInitiate(boost::bind(&UnityScreen::altTabForwardAllInitiate, this, _1, _2, _3)); optionSetAltTabForwardInitiate(boost::bind(&UnityScreen::altTabForwardInitiate, this, _1, _2, _3)); @@ -2005,6 +2007,9 @@ bool UnityScreen::showLauncherKeyInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options) { + if (lockscreen_controller_->IsLocked()) + return true; + // to receive the Terminate event if (state & CompAction::StateInitKey) action->setState(action->state() | CompAction::StateTermKey); @@ -2014,7 +2019,8 @@ bool UnityScreen::showLauncherKeyInitiate(CompAction* action, launcher_controller_->HandleLauncherKeyPress(when); EnsureSuperKeybindings (); - if (!shortcut_controller_->Visible() && shortcut_controller_->IsEnabled()) + if (!shortcut_controller_->Visible() && + shortcut_controller_->IsEnabled()) { if (shortcut_controller_->Show()) { @@ -2436,7 +2442,8 @@ bool UnityScreen::ShowHud() return false; // early exit if the switcher is open } - if (PluginAdapter::Default().IsTopWindowFullscreenOnMonitorWithMouse()) + if (PluginAdapter::Default().IsTopWindowFullscreenOnMonitorWithMouse() || + lockscreen_controller_->IsLocked()) { return false; } @@ -2523,7 +2530,11 @@ bool UnityScreen::LockScreenInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options) { - session_controller_->LockScreen(); + sources_.AddIdle([this] { + session_controller_->LockScreen(); + return false; + }); + return true; } @@ -2574,6 +2585,15 @@ void UnityScreen::UpdateCloseWindowKey(CompAction::KeyBinding const& keybind) WindowManager::Default().close_window_key = std::make_pair(modifiers, keysym); } +void UnityScreen::UpdateActivateIndicatorsKey() +{ + CompAction::KeyBinding const& keybind = optionGetPanelFirstMenu().key(); + KeySym keysym = XkbKeycodeToKeysym(screen->dpy(), keybind.keycode(), 0, 0); + unsigned modifiers = CompizModifiersToNux(keybind.modifiers()); + + WindowManager::Default().activate_indicators_key = std::make_pair(modifiers, keysym); +} + bool UnityScreen::initPluginActions() { PluginAdapter& adapter = PluginAdapter::Default(); @@ -2802,6 +2822,24 @@ bool UnityWindow::glPaint(const GLWindowPaintAttrib& attrib, GLWindowPaintAttrib wAttrib = attrib; + if (uScreen->lockscreen_controller_->IsLocked()) + { + if (window->type() != CompWindowTypePopupMenuMask || + !uScreen->lockscreen_controller_->HasOpenMenu()) + { + // For some reasons PAINT_WINDOW_NO_CORE_INSTANCE_MASK doesn't work here + // (well, it works too much, as it applies to menus too), so we need + // to paint the windows at the proper opacity, overriding any other + // paint plugin (animation, fade?) that might interfere with us. + wAttrib.opacity = COMPIZ_COMPOSITE_OPAQUE * (1.0f - uScreen->lockscreen_controller_->Opacity()); + int old_index = gWindow->glPaintGetCurrentIndex(); + gWindow->glPaintSetCurrentIndex(MAXSHORT); + bool ret = gWindow->glPaint(wAttrib, matrix, region, mask); + gWindow->glPaintSetCurrentIndex(old_index); + return ret; + } + } + if (mMinimizeHandler) { mask |= mMinimizeHandler->getPaintMask (); @@ -2830,7 +2868,7 @@ bool UnityWindow::glPaint(const GLWindowPaintAttrib& attrib, paintInnerGlow(scaled_geo, matrix, attrib, mask); } - if (uScreen->session_controller_ && uScreen->session_controller_->Visible()) + if (uScreen->session_controller_->Visible()) { // Let's darken the other windows if the session dialog is visible wAttrib.brightness *= 0.75f; @@ -3485,6 +3523,12 @@ void UnityScreen::optionChanged(CompOption* opt, UnityshellOptions::Options num) case UnityshellOptions::EdgePassedDisabledMs: launcher_options->edge_passed_disabled_ms = optionGetEdgePassedDisabledMs(); break; + case UnityshellOptions::LockScreenType: + lockscreen_settings_.lockscreen_type = static_cast<lockscreen::Type>(optionGetLockScreenType()); + break; + case UnityshellOptions::PanelFirstMenu: + UpdateActivateIndicatorsKey(); + break; default: break; } @@ -3627,9 +3671,14 @@ void UnityScreen::initLauncher() // Setup Session Controller auto manager = std::make_shared<session::GnomeManager>(); + session_dbus_manager_ = std::make_shared<session::DBusManager>(manager); session_controller_ = std::make_shared<session::Controller>(manager); AddChild(session_controller_.get()); + // Setup Lockscreen Controller + lockscreen_controller_ = std::make_shared<lockscreen::Controller>(manager); + UpdateActivateIndicatorsKey(); + auto on_launcher_size_changed = [this] (nux::Area* area, int w, int h) { /* The launcher geometry includes 1px used to draw the right margin * that must not be considered when drawing an overlay */ diff --git a/plugins/unityshell/src/unityshell.h b/plugins/unityshell/src/unityshell.h index 5a8e22b91..a57ce4568 100644 --- a/plugins/unityshell/src/unityshell.h +++ b/plugins/unityshell/src/unityshell.h @@ -58,6 +58,8 @@ #include "FontSettings.h" #include "ShortcutController.h" #include "LauncherController.h" +#include "LockScreenController.h" +#include "LockScreenSettings.h" #include "PanelController.h" #include "PanelStyle.h" #include "UScreen.h" @@ -65,6 +67,7 @@ #include "ScreenIntrospection.h" #include "SwitcherController.h" #include "SessionController.h" +#include "SessionDBusManager.h" #include "SpreadFilter.h" #include "UBusWrapper.h" #include "UnityshellPrivate.h" @@ -297,6 +300,7 @@ private: unsigned XModifiersToNux(unsigned input) const; void UpdateCloseWindowKey(CompAction::KeyBinding const&); + void UpdateActivateIndicatorsKey(); bool getMipmap () override { return false; } @@ -311,6 +315,7 @@ private: FontSettings font_settings_; internal::FavoriteStoreGSettings favorite_store_; ThumbnailGenerator thumbnail_generator_; + lockscreen::Settings lockscreen_settings_; /* The window thread should be the last thing removed, as c++ does it in reverse order */ std::unique_ptr<nux::WindowThread> wt; @@ -326,7 +331,9 @@ private: switcher::Controller::Ptr switcher_controller_; hud::Controller::Ptr hud_controller_; shortcut::Controller::Ptr shortcut_controller_; + session::DBusManager::Ptr session_dbus_manager_; session::Controller::Ptr session_controller_; + std::shared_ptr<lockscreen::Controller> lockscreen_controller_; debug::DebugDBusInterface debugger_; std::unique_ptr<BGHash> bghash_; spread::Filter::Ptr spread_filter_; diff --git a/plugins/unityshell/unityshell.xml.in b/plugins/unityshell/unityshell.xml.in index ca9ab9c21..cefb87537 100644 --- a/plugins/unityshell/unityshell.xml.in +++ b/plugins/unityshell/unityshell.xml.in @@ -146,6 +146,26 @@ <_long>Enables possibility to display an overlay showing available mouse and keyboard shortcuts.</_long> <default>true</default> </option> + + <option name="lock_screen_type" type="int"> + <_short>Lockscreen</_short> + <_long>Set how Unity should handle lockscreen.</_long> + <min>0</min> + <max>2</max> + <default>2</default> + <desc> + <value>0</value> + <_name>None</_name> + </desc> + <desc> + <value>1</value> + <_name>Lightdm</_name> + </desc> + <desc> + <value>2</value> + <_name>Unity</_name> + </desc> + </option> </group> <group> diff --git a/po/POTFILES.in b/po/POTFILES.in index 1e8eff75c..df28a9aa7 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -24,6 +24,7 @@ launcher/SoftwareCenterLauncherIcon.cpp launcher/SpacerLauncherIcon.cpp launcher/TrashLauncherIcon.cpp launcher/VolumeLauncherIcon.cpp +lockscreen/UserPromptView.cpp panel/PanelMenuView.cpp plugins/networkarearegion/networkarearegion.xml.in plugins/unity-mt-grab-handles/unitymtgrabhandles.xml.in diff --git a/resources/cof.png b/resources/cof.png Binary files differnew file mode 100644 index 000000000..09392003e --- /dev/null +++ b/resources/cof.png diff --git a/services/CMakeLists.txt b/services/CMakeLists.txt index 8ce92ca10..103c8854c 100644 --- a/services/CMakeLists.txt +++ b/services/CMakeLists.txt @@ -58,3 +58,6 @@ install(TARGETS unity-panel-service DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/unit configure_file(unity-panel-service.conf.in ${CMAKE_CURRENT_BINARY_DIR}/unity-panel-service.conf) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/unity-panel-service.conf DESTINATION ${CMAKE_INSTALL_PREFIX}/share/upstart/sessions) + +configure_file(unity-panel-service-lockscreen.conf.in ${CMAKE_CURRENT_BINARY_DIR}/unity-panel-service-lockscreen.conf) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/unity-panel-service-lockscreen.conf DESTINATION ${CMAKE_INSTALL_PREFIX}/share/upstart/sessions) diff --git a/services/panel-main.c b/services/panel-main.c index 484c85750..837b036e6 100644 --- a/services/panel-main.c +++ b/services/panel-main.c @@ -106,7 +106,8 @@ static const gchar introspection_xml[] = " </interface>" "</node>"; -#define S_NAME "com.canonical.Unity.Panel.Service" +#define S_NAME_DESKTOP "com.canonical.Unity.Panel.Service.Desktop" +#define S_NAME_LOCKSCREEN "com.canonical.Unity.Panel.Service.LockScreen" #define S_PATH "/com/canonical/Unity/Panel/Service" #define S_IFACE "com.canonical.Unity.Panel.Service" @@ -440,6 +441,13 @@ main (gint argc, gchar **argv) { PanelService *service; guint owner_id; + gboolean lockscreen_mode = FALSE; + GError *error = NULL; + GOptionContext *context; + GOptionEntry entries[] = { + { "lockscreen-mode", 0, 0, G_OPTION_ARG_NONE, &lockscreen_mode, "Load indicators for the lockscreen", NULL }, + { NULL }}; + g_unsetenv ("UBUNTU_MENUPROXY"); g_setenv ("NO_AT_BRIDGE", "1", TRUE); @@ -449,6 +457,17 @@ main (gint argc, gchar **argv) gtk_icon_theme_append_search_path (gtk_icon_theme_get_default(), INDICATORICONDIR); ido_init (); + context = g_option_context_new ("- Unity Panel Service"); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + g_print ("unity-panel-service: %s\n", error->message); + g_print ("Try --help for more information.\n"); + return 1; + } + + panel_service_set_lockscreen_mode (lockscreen_mode); + if (g_getenv ("SILENT_PANEL_SERVICE") != NULL) { g_log_set_default_handler (discard_log_message, NULL); @@ -462,7 +481,7 @@ main (gint argc, gchar **argv) service = panel_service_get_default (); owner_id = g_bus_own_name (G_BUS_TYPE_SESSION, - S_NAME, + !lockscreen_mode ? S_NAME_DESKTOP : S_NAME_LOCKSCREEN, G_BUS_NAME_OWNER_FLAGS_NONE, on_bus_acquired, on_name_acquired, diff --git a/services/panel-service.c b/services/panel-service.c index 01995646e..17789027b 100644 --- a/services/panel-service.c +++ b/services/panel-service.c @@ -53,6 +53,7 @@ G_DEFINE_TYPE (PanelService, panel_service, G_TYPE_OBJECT); #define SHOW_HUD_KEY "show-hud" static PanelService *static_service = NULL; +static gboolean lockscreen_mode = FALSE; struct _PanelServicePrivate { @@ -150,7 +151,7 @@ panel_service_class_dispose (GObject *self) g_idle_remove_by_data (self); gdk_window_remove_filter (NULL, (GdkFilterFunc)event_filter, self); - if (priv->upstart != NULL) + if (priv->upstart != NULL && !lockscreen_mode) { int event_sent = 0; event_sent = upstart_emit_event_sync (NULL, priv->upstart, @@ -461,6 +462,9 @@ event_filter (GdkXEvent *ev, GdkEvent *gev, PanelService *self) { case XI_KeyPress: { + if (lockscreen_mode) + break; + KeySym keysym = XkbKeycodeToKeysym (event->display, event->detail, 0, 0); if (event_matches_keybinding (event->mods.base, keysym, &priv->menu_toggle) || @@ -586,7 +590,7 @@ initial_resync (PanelService *self) static gboolean ready_signal (PanelService *self) { - if (PANEL_IS_SERVICE (self) && self->priv->upstart != NULL) + if (PANEL_IS_SERVICE (self) && self->priv->upstart != NULL && !lockscreen_mode) { int event_sent = 0; event_sent = upstart_emit_event_sync (NULL, self->priv->upstart, "indicator-services-start", NULL, 0); @@ -714,7 +718,7 @@ panel_service_init (PanelService *self) update_keybinding (priv->gsettings, SHOW_HUD_KEY, &priv->show_hud); const gchar *upstartsession = g_getenv ("UPSTART_SESSION"); - if (upstartsession != NULL) + if (upstartsession != NULL && !lockscreen_mode) { DBusConnection *conn = dbus_connection_open (upstartsession, NULL); if (conn != NULL) @@ -859,7 +863,11 @@ initial_load_default_or_custom_indicators (PanelService *self, GList *indicators if (!indicators) { - load_indicators (self); + if (!lockscreen_mode) + { + load_indicators (self); + } + load_indicators_from_indicator_files (self); sort_indicators (self); } @@ -908,6 +916,12 @@ panel_service_get_default_with_indicators (GList *indicators) return self; } +void +panel_service_set_lockscreen_mode (gboolean enable) +{ + lockscreen_mode = enable; +} + guint panel_service_get_n_indicators (PanelService *self) { @@ -1313,7 +1327,7 @@ load_indicators_from_indicator_files (PanelService *self) IndicatorNg *indicator; filename = g_build_filename (INDICATOR_SERVICE_DIR, name, NULL); - indicator = indicator_ng_new_for_profile (filename, "desktop", &error); + indicator = indicator_ng_new_for_profile (filename, !lockscreen_mode ? "desktop" : "desktop_lockscreen", &error); if (indicator) { load_indicator (self, INDICATOR_OBJECT (indicator), name); diff --git a/services/panel-service.h b/services/panel-service.h index f386ffdf1..a4c76ac25 100644 --- a/services/panel-service.h +++ b/services/panel-service.h @@ -71,6 +71,8 @@ GType panel_service_get_type (void) G_GNUC_CONST; PanelService * panel_service_get_default (); PanelService * panel_service_get_default_with_indicators (GList *indicators); +void panel_service_set_lockscreen_mode (gboolean enable); + guint panel_service_get_n_indicators (PanelService *self); IndicatorObject * panel_service_get_indicator_nth (PanelService *self, guint position); diff --git a/services/unity-panel-service-lockscreen.conf.in b/services/unity-panel-service-lockscreen.conf.in new file mode 100644 index 000000000..b6a3cb600 --- /dev/null +++ b/services/unity-panel-service-lockscreen.conf.in @@ -0,0 +1,8 @@ +description "Backing Service for the Unity Panel" +author "Andrea Azzarone <andrea.azzarone@canonical.com>" + +start on desktop-lock +stop on desktop-unlock + +respawn +exec ${CMAKE_INSTALL_PREFIX}/lib/unity/unity-panel-service --lockscreen-mode \ No newline at end of file diff --git a/shutdown/CMakeLists.txt b/shutdown/CMakeLists.txt index df1de7d4e..29e332788 100644 --- a/shutdown/CMakeLists.txt +++ b/shutdown/CMakeLists.txt @@ -19,6 +19,7 @@ include_directories (.. ../services ../UnityCore ${UNITY_SRC} ${CMAKE_BINARY_DIR set (SHUTDOWN_SOURCES SessionButton.cpp SessionController.cpp + SessionDBusManager.cpp SessionView.cpp ) diff --git a/shutdown/SessionDBusManager.cpp b/shutdown/SessionDBusManager.cpp new file mode 100644 index 000000000..f47c7c1cc --- /dev/null +++ b/shutdown/SessionDBusManager.cpp @@ -0,0 +1,180 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2014 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 <marco.trevisan@canonical.com> + */ + +#include "SessionDBusManager.h" + +namespace unity +{ +namespace session +{ +namespace dbus +{ +const std::string NAME = "com.canonical.Unity"; +const std::string INTERFACE = "com.canonical.Unity.Session"; +const std::string OBJECT_PATH = "/com/canonical/Unity/Session"; +const std::string INTROSPECTION_XML = +R"(<node> + <interface name="com.canonical.Unity.Session"> + <method name="RealName"> + <arg type="s" direction="out" name="realname" /> + </method> + <method name="UserName"> + <arg type="s" direction="out" name="username" /> + </method> + <method name="HostName"> + <arg type="s" direction="out" name="hostname" /> + </method> + <method name="Lock" /> + <method name="Logout" /> + <method name="RequestLogout" /> + <method name="Reboot" /> + <method name="RequestReboot" /> + <method name="Shutdown" /> + <method name="RequestShutdown" /> + <method name="Suspend" /> + <method name="Hibernate" /> + <method name="CancelAction" /> + <method name="CanShutdown"> + <arg type="b" direction="out" name="canshutdown" /> + </method> + <method name="CanSuspend"> + <arg type="b" direction="out" name="cansuspend" /> + </method> + <method name="CanHibernate"> + <arg type="b" direction="out" name="canhibernate" /> + </method> + + <signal name="LockRequested" /> + <signal name="Locked" /> + <signal name="UnlockRequested" /> + <signal name="Unlocked" /> + <signal name="LogoutRequested"> + <arg type="b" name="have_inhibitors" /> + </signal> + <signal name="RebootRequested"> + <arg type="b" name="have_inhibitors" /> + </signal> + <signal name="ShutdownRequested"> + <arg type="b" name="have_inhibitors" /> + </signal> + </interface> +</node>)"; +} + +DBusManager::DBusManager(session::Manager::Ptr const& session) + : session_(session) + , server_(dbus::NAME) +{ + server_.AddObjects(dbus::INTROSPECTION_XML, dbus::OBJECT_PATH); + object_ = server_.GetObject(dbus::INTERFACE); + object_->SetMethodsCallsHandler([this] (std::string const& method, GVariant*) -> GVariant* { + if (method == "RealName") + { + return g_variant_new("(s)", session_->RealName().c_str()); + } + else if (method == "UserName") + { + return g_variant_new("(s)", session_->UserName().c_str()); + } + else if (method == "HostName") + { + return g_variant_new("(s)", session_->HostName().c_str()); + } + else if (method == "Lock") + { + session_->LockScreen(); + } + else if (method == "Logout") + { + session_->Logout(); + } + else if (method == "RequestLogout") + { + session_->logout_requested.emit(false); + } + else if (method == "Reboot") + { + session_->Reboot(); + } + else if (method == "RequestReboot") + { + session_->reboot_requested.emit(false); + } + else if (method == "Shutdown") + { + session_->Shutdown(); + } + else if (method == "RequestShutdown") + { + session_->shutdown_requested.emit(false); + } + else if (method == "Suspend") + { + session_->Suspend(); + } + else if (method == "Hibernate") + { + session_->Hibernate(); + } + else if (method == "CancelAction") + { + session_->CancelAction(); + session_->cancel_requested.emit(); + } + else if (method == "CanShutdown") + { + return g_variant_new("(b)", session_->CanShutdown() != FALSE); + } + else if (method == "CanSuspend") + { + return g_variant_new("(b)", session_->CanSuspend() != FALSE); + } + else if (method == "CanHibernate") + { + return g_variant_new("(b)", session_->CanHibernate() != FALSE); + } + + return nullptr; + }); + + connections_.Add(session_->lock_requested.connect([this] { + object_->EmitSignal("LockRequested"); + })); + connections_.Add(session_->locked.connect([this] { + object_->EmitSignal("Locked"); + })); + connections_.Add(session_->unlock_requested.connect([this] { + object_->EmitSignal("UnlockRequested"); + })); + connections_.Add(session_->unlocked.connect([this] { + object_->EmitSignal("Unlocked"); + })); + connections_.Add(session_->logout_requested.connect([this] (bool inhibitors) { + object_->EmitSignal("LogoutRequested", g_variant_new("(b)", inhibitors)); + })); + connections_.Add(session_->reboot_requested.connect([this] (bool inhibitors) { + object_->EmitSignal("RebootRequested", g_variant_new("(b)", inhibitors)); + })); + connections_.Add(session_->shutdown_requested.connect([this] (bool inhibitors) { + object_->EmitSignal("ShutdownRequested", g_variant_new("(b)", inhibitors)); + })); +} + +} // session +} // unity diff --git a/shutdown/SessionDBusManager.h b/shutdown/SessionDBusManager.h new file mode 100644 index 000000000..dbbb2bda9 --- /dev/null +++ b/shutdown/SessionDBusManager.h @@ -0,0 +1,50 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2014 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 <marco.trevisan@canonical.com> + */ + +#ifndef UNITYSHELL_SESSION_DBUS_MANAGER_H +#define UNITYSHELL_SESSION_DBUS_MANAGER_H + +#include <UnityCore/ConnectionManager.h> +#include <UnityCore/GLibDBusServer.h> +#include <UnityCore/SessionManager.h> + +namespace unity +{ +namespace session +{ + +class DBusManager +{ +public: + typedef std::shared_ptr<DBusManager> Ptr; + + DBusManager(session::Manager::Ptr const& manager); + virtual ~DBusManager() = default; + +private: + session::Manager::Ptr session_; + glib::DBusServer server_; + glib::DBusObject::Ptr object_; + connection::Manager connections_; +}; + +} // session +} // unity + +#endif diff --git a/shutdown/StandaloneSession.cpp b/shutdown/StandaloneSession.cpp index 206b233f7..0c64b9afe 100644 --- a/shutdown/StandaloneSession.cpp +++ b/shutdown/StandaloneSession.cpp @@ -38,6 +38,7 @@ public: std::string RealName() const { return "Marco Trevisan"; } std::string UserName() const { return "marco"; } + std::string HostName() const { return "tricky"; } void LockScreen() { std::cout << "LockScreen" << std::endl; } void Logout() { std::cout << "Logout" << std::endl; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 86f88a772..99dfd975f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -243,6 +243,7 @@ if (ENABLE_X_SUPPORT) test_launcher_icon.cpp test_launcher_minimize_speed.cpp test_launcher_tooltip.cpp + test_lockscreen_controller.cpp test_panel_controller.cpp test_panel_indicators_view.cpp test_panel_indicator_entry_dropdown_view.cpp @@ -292,6 +293,8 @@ if (ENABLE_X_SUPPORT) test_unity_settings.cpp test_unity_window_style.cpp test_unity_window_view.cpp + test_upstart_wrapper.cpp + test_user_authenticator_pam.cpp test_volume_launcher_icon.cpp test_window_buttons.cpp test_xdnd_manager_imp.cpp @@ -319,7 +322,9 @@ if (ENABLE_X_SUPPORT) decorations-lib hud-lib launcher-lib + lockscreen-lib panel-lib + pam previews-lib shortcuts-lib shutdown-lib diff --git a/tests/autopilot/unity/tests/launcher/test_icon_behavior.py b/tests/autopilot/unity/tests/launcher/test_icon_behavior.py index 669747ee4..e469be7fa 100644 --- a/tests/autopilot/unity/tests/launcher/test_icon_behavior.py +++ b/tests/autopilot/unity/tests/launcher/test_icon_behavior.py @@ -70,7 +70,7 @@ class LauncherIconsTests(LauncherTestCase): self.unity.dash.ensure_visible() self.addCleanup(self.unity.dash.ensure_hidden) - self.assertThat(bfb.get_tooltip().active, Eventually(Equals(False))) + self.assertThat(bfb.get_tooltip(), Equals(None)) def test_bfb_tooltip_is_disabled_when_dash_is_open(self): """Tests the that bfb tooltip is disabled when the dash is open.""" diff --git a/tests/autopilot/unity/tests/launcher/test_tooltips.py b/tests/autopilot/unity/tests/launcher/test_tooltips.py index 4ea8e53a3..f403a8a80 100644 --- a/tests/autopilot/unity/tests/launcher/test_tooltips.py +++ b/tests/autopilot/unity/tests/launcher/test_tooltips.py @@ -38,14 +38,13 @@ class LauncherTooltipTests(LauncherTestCase): if size > 5: size = 5 - # subsequent tooltips reveal instantly, but hide on exit + # subsequent tooltips reveal instantly, but are destroyed on exit, meaning None a, b = 0, 1 while b < size: self.mouse.move(self.icons[b].center.x, self.icons[b].center.y) self.assertThat(lambda: self.icons[b].get_tooltip(), Eventually(NotEquals(None))) self.assertThat(self.icons[b].get_tooltip().active, Eventually(Equals(True))) - self.assertThat(lambda: self.icons[a].get_tooltip(), Eventually(NotEquals(None))) - self.assertThat(self.icons[a].get_tooltip().active, Eventually(Equals(False))) + self.assertThat(self.icons[a].get_tooltip(), Equals(None)) a, b = a + 1, b + 1 b -= 1 diff --git a/tests/autopilot/unity/tests/test_quicklist.py b/tests/autopilot/unity/tests/test_quicklist.py index 743a9fabb..9e3dd00c9 100644 --- a/tests/autopilot/unity/tests/test_quicklist.py +++ b/tests/autopilot/unity/tests/test_quicklist.py @@ -11,8 +11,9 @@ from __future__ import absolute_import from autopilot.display import move_mouse_to_screen from autopilot.matchers import Eventually +from autopilot.introspection.dbus import StateNotFoundError import os.path -from testtools.matchers import Contains, Equals, NotEquals +from testtools.matchers import Contains, Equals, NotEquals, Not, Raises from time import sleep from xdg.DesktopEntry import DesktopEntry @@ -90,8 +91,7 @@ class QuicklistActionTests(UnityTestCase): self.assertThat(lambda: len(nautilus_windows_fn()), Eventually(Equals(1))) [nautilus_window] = nautilus_windows_fn() - self.assertThat(lambda: self.get_startup_notification_timestamp(nautilus_window), - Eventually(Equals(new_win_ql_item.activate_timestamp))) + self.assertThat(new_win_ql_item.wait_until_destroyed, Not(Raises())) def test_quicklist_application_item_focus_last_active_window(self): """This tests shows that when you activate a quicklist application item @@ -198,7 +198,7 @@ class QuicklistActionTests(UnityTestCase): icon1_ql = self.open_quicklist_for_icon(icons[1]) self.assertThat(icon1_ql.active, Eventually(Equals(True))) - self.assertThat(icon0_ql.active, Eventually(Equals(False))) + self.assertThat(icon0_ql.wait_until_destroyed, Not(Raises())) def test_right_clicking_same_icon_doesnt_reopen_ql(self): """A right click to the same icon in the launcher must @@ -213,8 +213,13 @@ class QuicklistActionTests(UnityTestCase): calc_ql = self.open_quicklist_for_icon(calc_icon) self.assertThat(calc_ql.active, Eventually(Equals(True))) - calc_ql = self.open_quicklist_for_icon(calc_icon) - self.assertThat(calc_ql.active, Eventually(Equals(False))) + # We've to manually open the icon this time, as when the quicklist goes away + # its Destroyed, so its None! + launcher = self.unity.launcher.get_launcher_for_monitor(0) + launcher.click_launcher_icon(calc_icon, button=3) + self.addCleanup(self.keyboard.press_and_release, "Escape") + calc_ql = calc_icon.get_quicklist() + self.assertThat(calc_ql, Equals(None)) class QuicklistKeyNavigationTests(UnityTestCase): diff --git a/tests/autopilot/unity/tests/test_spread.py b/tests/autopilot/unity/tests/test_spread.py index 7093b9303..beaf41f82 100644 --- a/tests/autopilot/unity/tests/test_spread.py +++ b/tests/autopilot/unity/tests/test_spread.py @@ -200,7 +200,7 @@ class SpreadTests(UnityTestCase): self.assertThat(icon.get_tooltip().active, Eventually(Equals(True))) self.initiate_spread_for_screen() - self.assertThat(icon.get_tooltip().active, Eventually(Equals(False))) + self.assertThat(icon.get_tooltip(), Equals(None)) def test_spread_puts_panel_in_overlay_mode(self): """Test that the panel is in overlay mode when in spread""" diff --git a/tests/data/external.gschema.xml b/tests/data/external.gschema.xml index a7e292e0e..160b79723 100644 --- a/tests/data/external.gschema.xml +++ b/tests/data/external.gschema.xml @@ -52,4 +52,28 @@ <default>false</default> </key> </schema> + + <schema id="com.canonical.unity-greeter" path="/com/canonical/unity-greeter/"> + <key type="s" name="logo"> + <default>'/usr/share/unity-greeter/logo.png'</default> + </key> + <key type="s" name="font-name"> + <default>'Ubuntu 11'</default> + </key> + <key type="s" name="background"> + <default>'/usr/share/backgrounds/warty-final-ubuntu.png'</default> + </key> + <key type="s" name="background-color"> + <default>'#2C001E'</default> + </key> + <key type="b" name="draw-user-backgrounds"> + <default>true</default> + </key> + <key type="b" name="draw-grid"> + <default>true</default> + </key> + <key type="b" name="show-hostname"> + <default>true</default> + </key> + </schema> </schemalist> diff --git a/tests/test_gnome_session_manager.cpp b/tests/test_gnome_session_manager.cpp index 79017bdb0..0335012d5 100644 --- a/tests/test_gnome_session_manager.cpp +++ b/tests/test_gnome_session_manager.cpp @@ -37,9 +37,9 @@ const std::string SHELL_INTERFACE = "org.gnome.SessionManager.EndSessionDialog"; const std::string SHELL_OBJECT_PATH = "/org/gnome/SessionManager/EndSessionDialog"; const std::string UPOWER_PATH = "/org/freedesktop/UPower"; -const std::string LOGIND_PATH = "/org/freedesktop/login1"; +const std::string LOGIND_MANAGER_PATH = "/org/freedesktop/login1"; +const std::string LOGIND_SESSION_PATH = "/org/freedesktop/login1/session/id0"; const std::string CONSOLE_KIT_PATH = "/org/freedesktop/ConsoleKit/Manager"; -const std::string SCREEN_SAVER_PATH = "/org/gnome/ScreenSaver"; const std::string SESSION_MANAGER_PATH = "/org/gnome/SessionManager"; const std::string SESSION_OPTIONS = "com.canonical.indicator.session"; @@ -62,7 +62,7 @@ R"(<node> </interface> </node>)"; -const std::string LOGIND = +const std::string LOGIND_MANAGER = R"(<node> <interface name="org.freedesktop.login1.Manager"> <method name="CanSuspend"> @@ -89,6 +89,14 @@ R"(<node> </interface> </node>)"; +const std::string LOGIND_SESSION = +R"(<node> + <interface name="org.freedesktop.login1.Session"> + <signal name="Lock" /> + <signal name="Unlock" /> + </interface> +</node>)"; + const std::string CONSOLE_KIT = R"(<node> <interface name="org.freedesktop.ConsoleKit.Manager"> @@ -100,14 +108,6 @@ R"(<node> </interface> </node>)"; -const std::string SCREEN_SAVER = -R"(<node> - <interface name="org.gnome.ScreenSaver"> - <method name="Lock"/> - <method name="SimulateUserActivity"/> - </interface> -</node>)"; - const std::string SESSION_MANAGER = R"(<node> <interface name="org.gnome.SessionManager"> @@ -162,7 +162,8 @@ struct TestGnomeSessionManager : testing::Test }); logind_ = std::make_shared<DBusServer>(); - logind_->AddObjects(introspection::LOGIND, LOGIND_PATH); + logind_->AddObjects(introspection::LOGIND_MANAGER, LOGIND_MANAGER_PATH); + logind_->AddObjects(introspection::LOGIND_SESSION, LOGIND_SESSION_PATH); logind_->GetObjects().front()->SetMethodsCallsHandler([&] (std::string const& method, GVariant*) -> GVariant* { if (method == "CanSuspend") { @@ -181,9 +182,6 @@ struct TestGnomeSessionManager : testing::Test console_kit_ = std::make_shared<DBusServer>(); console_kit_->AddObjects(introspection::CONSOLE_KIT, CONSOLE_KIT_PATH); - screen_saver_ = std::make_shared<DBusServer>(); - screen_saver_->AddObjects(introspection::SCREEN_SAVER, SCREEN_SAVER_PATH); - session_manager_ = std::make_shared<DBusServer>(); session_manager_->AddObjects(introspection::SESSION_MANAGER, SESSION_MANAGER_PATH); session_manager_->GetObjects().front()->SetMethodsCallsHandler([&] (std::string const& method, GVariant*) -> GVariant* { @@ -215,7 +213,6 @@ struct TestGnomeSessionManager : testing::Test Utils::WaitUntilMSec([] { return upower_->IsConnected(); }); Utils::WaitUntilMSec([] { return logind_->IsConnected(); }); Utils::WaitUntilMSec([] { return console_kit_->IsConnected(); }); - Utils::WaitUntilMSec([] { return screen_saver_->IsConnected(); }); Utils::WaitUntilMSec([] { return session_manager_->IsConnected(); }); Utils::WaitUntilMSec([] { return shell_proxy_->IsConnected();}); ASSERT_TRUE(shell_proxy_->IsConnected()); @@ -267,7 +264,6 @@ struct TestGnomeSessionManager : testing::Test upower_.reset(); logind_.reset(); console_kit_.reset(); - screen_saver_.reset(); session_manager_.reset(); } @@ -327,7 +323,6 @@ struct TestGnomeSessionManager : testing::Test static DBusServer::Ptr upower_; static DBusServer::Ptr console_kit_; static DBusServer::Ptr logind_; - static DBusServer::Ptr screen_saver_; static DBusServer::Ptr session_manager_; static DBusProxy::Ptr shell_proxy_; }; @@ -336,7 +331,6 @@ session::Manager::Ptr TestGnomeSessionManager::manager; DBusServer::Ptr TestGnomeSessionManager::upower_; DBusServer::Ptr TestGnomeSessionManager::console_kit_; DBusServer::Ptr TestGnomeSessionManager::logind_; -DBusServer::Ptr TestGnomeSessionManager::screen_saver_; DBusServer::Ptr TestGnomeSessionManager::session_manager_; DBusProxy::Ptr TestGnomeSessionManager::shell_proxy_; bool TestGnomeSessionManager::can_shutdown_; @@ -375,31 +369,17 @@ TEST_F(TestGnomeSessionManager, UserName) TEST_F(TestGnomeSessionManager, LockScreen) { - bool lock_called = false; - bool simulate_activity_called = false; + bool lock_emitted = false; - screen_saver_->GetObjects().front()->SetMethodsCallsHandler([&] (std::string const& method, GVariant*) -> GVariant* { - if (method == "Lock") - { - lock_called = true; - EXPECT_FALSE(simulate_activity_called); - } - else if (method == "SimulateUserActivity") - { - simulate_activity_called = true; - EXPECT_TRUE(lock_called); - } - - return nullptr; + manager->lock_requested.connect([&lock_emitted]() + { + lock_emitted = true; }); manager->LockScreen(); - Utils::WaitUntilMSec(lock_called); - EXPECT_TRUE(lock_called); - - Utils::WaitUntilMSec(simulate_activity_called); - EXPECT_TRUE(simulate_activity_called); + Utils::WaitUntilMSec(lock_emitted); + EXPECT_TRUE(lock_emitted); } TEST_F(TestGnomeSessionManager, Logout) @@ -1004,4 +984,34 @@ TEST_F(TestGnomeSessionManager, CancelRequested) EXPECT_TRUE(closed); } +TEST_F(TestGnomeSessionManager, DISABLED_LogindLock) +{ + bool lock_emitted = false; + + manager->lock_requested.connect([&lock_emitted]() + { + lock_emitted = true; + }); + + logind_->GetObject("org.freedesktop.login1.Session")->EmitSignal("Lock"); + + Utils::WaitUntilMSec(lock_emitted); + EXPECT_TRUE(lock_emitted); +} + +TEST_F(TestGnomeSessionManager, LogindUnLock) +{ + bool unlock_emitted = false; + + manager->unlock_requested.connect([&unlock_emitted]() + { + unlock_emitted = true; + }); + + logind_->GetObject("org.freedesktop.login1.Session")->EmitSignal("Unlock"); + + Utils::WaitUntilMSec(unlock_emitted); + EXPECT_TRUE(unlock_emitted); +} + } // Namespace diff --git a/tests/test_lockscreen_controller.cpp b/tests/test_lockscreen_controller.cpp new file mode 100644 index 000000000..7e817cff6 --- /dev/null +++ b/tests/test_lockscreen_controller.cpp @@ -0,0 +1,344 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2014 Canonical Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> +*/ + +#include <gmock/gmock.h> +using namespace testing; + +#include "lockscreen/LockScreenController.h" + +#include <Nux/NuxTimerTickSource.h> +#include <NuxCore/AnimationController.h> +#include <UnityCore/GLibDBusServer.h> + + +#include "lockscreen/LockScreenSettings.h" +#include "unity-shared/PanelStyle.h" +#include "unity-shared/UScreen.h" +#include "unity-shared/UnitySettings.h" +#include "test_mock_session_manager.h" +#include "test_uscreen_mock.h" +#include "test_utils.h" + +namespace unity +{ +namespace lockscreen +{ +namespace +{ + +const unsigned ANIMATION_DURATION = 400 * 1000; // in microseconds +const unsigned TICK_DURATION = 10 * 1000; + +const std::string TEST_SERVER_NAME = "com.canonical.Unity.Test.DisplayManager"; +const std::string LIGHTDM_PATH = "/org/freedesktop/DisplayManager/Session0"; + +} + +namespace introspection +{ + +const std::string LIGHTDM = +R"(<node> + <interface name="org.freedesktop.DisplayManager.Session"> + <method name="Lock"/> + </interface> +</node>)"; + +} + +struct MockShield : AbstractShield +{ + MockShield() + : AbstractShield(nullptr, nullptr, 0, false) + {} + + MOCK_CONST_METHOD0(IsIndicatorOpen, bool()); +}; + +struct ShieldFactoryMock : ShieldFactoryInterface +{ + nux::ObjectPtr<AbstractShield> CreateShield(session::Manager::Ptr const&, indicator::Indicators::Ptr const&, int, bool) override + { + return nux::ObjectPtr<AbstractShield>(new MockShield()); + } +}; + +struct TestLockScreenController : Test +{ + TestLockScreenController() + : animation_controller(tick_source) + , session_manager(std::make_shared<NiceMock<session::MockManager>>()) + , upstart_wrapper(std::make_shared<UpstartWrapper>()) + , shield_factory(std::make_shared<ShieldFactoryMock>()) + , controller(session_manager, upstart_wrapper, shield_factory) + { + lightdm_ = std::make_shared<glib::DBusServer>(TEST_SERVER_NAME); + lightdm_->AddObjects(introspection::LIGHTDM, LIGHTDM_PATH); + + Utils::WaitUntilMSec([] { return lightdm_->IsConnected(); }); + } + + struct ControllerWrap : Controller + { + ControllerWrap(session::Manager::Ptr const& session_manager, + UpstartWrapper::Ptr const& upstart_wrapper, + ShieldFactoryInterface::Ptr const& shield_factory) + : Controller(session_manager, upstart_wrapper, shield_factory, /* test_mode */ true) + {} + + using Controller::shields_; + }; + + nux::NuxTimerTickSource tick_source; + nux::animation::AnimationController animation_controller; + + MockUScreen uscreen; + unity::Settings unity_settings; + unity::panel::Style panel_style; + unity::lockscreen::Settings lockscreen_settings; + static glib::DBusServer::Ptr lightdm_; + session::MockManager::Ptr session_manager; + unity::UpstartWrapper::Ptr upstart_wrapper; + + ShieldFactoryMock::Ptr shield_factory; + ControllerWrap controller; +}; + +glib::DBusServer::Ptr TestLockScreenController::lightdm_; + +TEST_F(TestLockScreenController, Construct) +{ + EXPECT_TRUE(controller.shields_.empty()); +} + +TEST_F(TestLockScreenController, DisconnectUScreenSignalsOnDestruction) +{ + size_t before = uscreen.changed.size(); + { + Controller dummy(session_manager); + } + ASSERT_EQ(before, uscreen.changed.size()); + + std::vector<nux::Geometry> monitors; + uscreen.changed.emit(0, monitors); +} + +TEST_F(TestLockScreenController, DisconnectSessionManagerSignalsOnDestruction) +{ + size_t before = session_manager->unlock_requested.size(); + { + Controller dummy(session_manager); + } + ASSERT_EQ(before, session_manager->unlock_requested.size()); + + session_manager->unlock_requested.emit(); +} + +TEST_F(TestLockScreenController, UScreenChangedIgnoredOnScreenUnlocked) +{ + uscreen.SetupFakeMultiMonitor(/*primary*/ 0, /*emit_change*/ true); + EXPECT_TRUE(controller.shields_.empty()); +} + +TEST_F(TestLockScreenController, LockScreenTypeNone) +{ + lockscreen_settings.lockscreen_type = Type::NONE; + session_manager->lock_requested.emit(); + + ASSERT_EQ(0, controller.shields_.size()); +} + +TEST_F(TestLockScreenController, LockScreenTypeLightdmOnSingleMonitor) +{ + g_setenv("XDG_SESSION_PATH", LIGHTDM_PATH.c_str(), true); + + bool lock_called = false; + + lightdm_->GetObjects().front()->SetMethodsCallsHandler([&] (std::string const& method, GVariant*) -> GVariant* { + if (method == "Lock") + lock_called = true; + + return nullptr; + }); + + lockscreen_settings.lockscreen_type = Type::LIGHTDM; + session_manager->lock_requested.emit(); + + ASSERT_EQ(1, controller.shields_.size()); + EXPECT_FALSE(controller.shields_.at(0)->primary()); + Utils::WaitUntilMSec(lock_called); +} + +TEST_F(TestLockScreenController, LockScreenTypeLightdmOnMultiMonitor) +{ + g_setenv("XDG_SESSION_PATH", LIGHTDM_PATH.c_str(), true); + + bool lock_called = false; + + lightdm_->GetObjects().front()->SetMethodsCallsHandler([&] (std::string const& method, GVariant*) -> GVariant* { + if (method == "Lock") + lock_called = true; + + return nullptr; + }); + + lockscreen_settings.lockscreen_type = Type::LIGHTDM; + uscreen.SetupFakeMultiMonitor(/*primary*/ 0, /*emit_change*/ true); + session_manager->lock_requested.emit(); + + ASSERT_EQ(monitors::MAX, controller.shields_.size()); + + for (unsigned int i=0; i < monitors::MAX; ++i) + EXPECT_FALSE(controller.shields_.at(i)->primary()); + + Utils::WaitUntilMSec(lock_called); +} + +TEST_F(TestLockScreenController, UnlockScreenTypeLightdmOnSingleMonitor) +{ + g_setenv("XDG_SESSION_PATH", LIGHTDM_PATH.c_str(), true); + + bool lock_called = false; + + lightdm_->GetObjects().front()->SetMethodsCallsHandler([&] (std::string const& method, GVariant*) -> GVariant* { + if (method == "Lock") + lock_called = true; + + return nullptr; + }); + + lockscreen_settings.lockscreen_type = Type::LIGHTDM; + session_manager->lock_requested.emit(); + + ASSERT_EQ(1, controller.shields_.size()); + Utils::WaitUntilMSec(lock_called); + + session_manager->unlock_requested.emit(); + tick_source.tick(ANIMATION_DURATION); + + ASSERT_EQ(0, controller.shields_.size()); +} + +TEST_F(TestLockScreenController, UnlockScreenTypeLightdmOnMultiMonitor) +{ + g_setenv("XDG_SESSION_PATH", LIGHTDM_PATH.c_str(), true); + + bool lock_called = false; + + lightdm_->GetObjects().front()->SetMethodsCallsHandler([&] (std::string const& method, GVariant*) -> GVariant* { + if (method == "Lock") + lock_called = true; + + return nullptr; + }); + + lockscreen_settings.lockscreen_type = Type::LIGHTDM; + uscreen.SetupFakeMultiMonitor(/*primary*/ 0, /*emit_change*/ true); + session_manager->lock_requested.emit(); + + ASSERT_EQ(monitors::MAX, controller.shields_.size()); + Utils::WaitUntilMSec(lock_called); + + session_manager->unlock_requested.emit(); + tick_source.tick(ANIMATION_DURATION); + + ASSERT_EQ(0, controller.shields_.size()); +} + +TEST_F(TestLockScreenController, LockScreenOnSingleMonitor) +{ + session_manager->lock_requested.emit(); + + ASSERT_EQ(1, controller.shields_.size()); + EXPECT_EQ(uscreen.GetMonitors().at(0), controller.shields_.at(0)->GetGeometry()); +} + +TEST_F(TestLockScreenController, LockScreenOnMultiMonitor) +{ + uscreen.SetupFakeMultiMonitor(); + + session_manager->lock_requested.emit(); + ASSERT_EQ(monitors::MAX, controller.shields_.size()); + + for (unsigned int i=0; i < monitors::MAX; ++i) + EXPECT_EQ(uscreen.GetMonitors().at(i), controller.shields_.at(i)->GetAbsoluteGeometry()); +} + +TEST_F(TestLockScreenController, SwitchToMultiMonitor) +{ + session_manager->lock_requested.emit(); + tick_source.tick(ANIMATION_DURATION); + + ASSERT_EQ(1, controller.shields_.size()); + EXPECT_EQ(uscreen.GetMonitors().at(0), controller.shields_.at(0)->GetGeometry()); + + uscreen.SetupFakeMultiMonitor(/* primary */ 0, /* emit_change */ true); + + ASSERT_EQ(monitors::MAX, controller.shields_.size()); + + for (unsigned int i=0; i < monitors::MAX; ++i) + { + ASSERT_EQ(uscreen.GetMonitors().at(i), controller.shields_.at(i)->GetAbsoluteGeometry()); + ASSERT_TRUE(controller.shields_.at(i)->IsVisible()); + } +} + +TEST_F(TestLockScreenController, SwitchToSingleMonitor) +{ + uscreen.SetupFakeMultiMonitor(/* primary */ 0, /* emit_change */ true); + session_manager->lock_requested.emit(); + + ASSERT_EQ(monitors::MAX, controller.shields_.size()); + + for (unsigned int i=0; i < monitors::MAX; ++i) + ASSERT_EQ(uscreen.GetMonitors().at(i), controller.shields_.at(i)->GetAbsoluteGeometry()); + + uscreen.Reset(/* emit_change */ true); + + ASSERT_EQ(1, controller.shields_.size()); + EXPECT_EQ(uscreen.GetMonitors().at(0), controller.shields_.at(0)->GetGeometry()); +} + +TEST_F(TestLockScreenController, UnlockScreenOnSingleMonitor) +{ + session_manager->lock_requested.emit(); + + ASSERT_EQ(1, controller.shields_.size()); + + session_manager->unlock_requested.emit(); + tick_source.tick(ANIMATION_DURATION); + + EXPECT_TRUE(controller.shields_.empty()); +} + +TEST_F(TestLockScreenController, UnlockScreenOnMultiMonitor) +{ + uscreen.SetupFakeMultiMonitor(/* primary */ 0, /* emit_change */ true); + session_manager->lock_requested.emit(); + + ASSERT_EQ(monitors::MAX, controller.shields_.size()); + + session_manager->unlock_requested.emit(); + tick_source.tick(ANIMATION_DURATION); + + EXPECT_TRUE(controller.shields_.empty()); +} + +} // lockscreen +} // unity diff --git a/tests/test_mock_session_manager.h b/tests/test_mock_session_manager.h index 352e914f8..42da560c5 100644 --- a/tests/test_mock_session_manager.h +++ b/tests/test_mock_session_manager.h @@ -31,6 +31,7 @@ struct MockManager : Manager MOCK_CONST_METHOD0(RealName, std::string()); MOCK_CONST_METHOD0(UserName, std::string()); + MOCK_CONST_METHOD0(HostName, std::string()); MOCK_METHOD0(LockScreen, void()); MOCK_METHOD0(Logout, void()); diff --git a/tests/test_text_input.cpp b/tests/test_text_input.cpp index aad469861..440a1c015 100644 --- a/tests/test_text_input.cpp +++ b/tests/test_text_input.cpp @@ -22,7 +22,9 @@ #include <gtest/gtest.h> +#include "unity-shared/DashStyle.h" #include "unity-shared/TextInput.h" +#include "unity-shared/UnitySettings.h" #include "test_utils.h" using namespace nux; @@ -33,7 +35,6 @@ namespace unity class TextInputMock : public TextInput { public: - using TextInput::Init; using TextInput::OnInputHintChanged; using TextInput::OnMouseButtonDown; using TextInput::OnEndKeyFocus; @@ -50,11 +51,12 @@ class TestTextInput : public ::testing::Test TestTextInput() { entry = new TextInputMock(); - entry->Init(); hint = entry->GetHint(); pango_entry = entry->GetPangoEntry(); } + unity::Settings unity_settings_; + dash::Style dash_style_; nux::ObjectPtr<TextInputMock> entry; StaticCairoText* hint; IMTextEntry* pango_entry; diff --git a/tests/test_upstart_wrapper.cpp b/tests/test_upstart_wrapper.cpp new file mode 100644 index 000000000..95b17d357 --- /dev/null +++ b/tests/test_upstart_wrapper.cpp @@ -0,0 +1,90 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2014 Canonical Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> +*/ + +#include <gtest/gtest.h> +using namespace testing; + +#include "unity-shared/UpstartWrapper.h" + +#include <UnityCore/GLibDBusServer.h> +#include <UnityCore/Variant.h> + +#include "test_utils.h" + +namespace +{ + +const std::string UPSTART = +R"(<node> + <interface name="com.ubuntu.Upstart0_6"> + <method name="EmitEvent"> + <arg name="name" type="s" direction="in" /> + <arg name="env" type="as" direction="in" /> + <arg name="wait" type="b" direction="in" /> + </method> + + <signal name="EventEmitted"> + <arg name="name" type="s" /> + <arg name="env" type="as" /> + </signal> + </interface> +</node>)"; + +struct MockUpstartWrapper : unity::UpstartWrapper { + MockUpstartWrapper() + : UpstartWrapper(UpstartWrapper::TestMode()) + {} +}; + +struct TestUpstartWrapper : public Test +{ + TestUpstartWrapper() + { + upstart_server_ = std::make_shared<unity::glib::DBusServer>("com.canonical.Unity.Test.Upstart"); + upstart_server_->AddObjects(UPSTART, "/com/ubuntu/Upstart"); + + Utils::WaitUntilMSec([this] { return upstart_server_->IsConnected(); }); + } + + unity::glib::DBusServer::Ptr upstart_server_; + MockUpstartWrapper upstart_wrapper_; +}; + + +TEST_F(TestUpstartWrapper, Emit) +{ + bool event_emitted = false; + + upstart_server_->GetObjects().front()->SetMethodsCallsHandler([&] (std::string const& method, GVariant* par) -> GVariant* { + if (method == "EmitEvent") + { + event_emitted = true; + + std::string event_name = glib::Variant(g_variant_get_child_value(par, 0)).GetString(); + EXPECT_EQ("desktop-lock", event_name); + } + + return nullptr; + }); + + upstart_wrapper_.Emit("desktop-lock"); + Utils::WaitUntil(event_emitted); +} + +} diff --git a/tests/test_user_authenticator_pam.cpp b/tests/test_user_authenticator_pam.cpp new file mode 100644 index 000000000..64b9a8431 --- /dev/null +++ b/tests/test_user_authenticator_pam.cpp @@ -0,0 +1,58 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2013 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + */ + +#include <gtest/gtest.h> + +#include "lockscreen/UserAuthenticatorPam.h" +#include "test_utils.h" + +using unity::lockscreen::UserAuthenticatorPam; + +#include <security/pam_appl.h> + +// Would be nice to build a testing pam module, but writing a +// pam_authenticate function here works just fine for the moment. +int pam_authenticate(pam_handle_t *pamh, int flags) +{ + pam_conv* conversation; + struct pam_message msg; + const struct pam_message *msgp; + + pam_get_item(pamh, PAM_CONV, (const void**) &conversation); + + msg.msg_style = PAM_PROMPT_ECHO_OFF; + msgp = &msg; + + pam_response* resp = nullptr; + conversation->conv(1, &msgp, &resp, conversation->appdata_ptr); + + return strcmp(resp[0].resp, "password"); +} + +namespace +{ + +struct TestUserAuthenticatorPam : public ::testing::Test +{ + UserAuthenticatorPam user_authenticator_pam_; +}; + +// FIXME (add tests) + +} diff --git a/tests/test_utils.h b/tests/test_utils.h index 6e989afd6..4b04d8be4 100644 --- a/tests/test_utils.h +++ b/tests/test_utils.h @@ -46,7 +46,7 @@ public: if (result == expected_result) g_source_remove(timeout_id); - EXPECT_EQ(result, expected_result) << (error_msg.empty() ? "" : ("Error: " + error_msg)); + EXPECT_EQ(expected_result, result) << (error_msg.empty() ? "" : ("Error: " + error_msg)); } static void WaitUntil(std::function<bool()> const& check_function, bool result = true, unsigned max_wait = 1, std::string const& error_msg = "") diff --git a/unity-shared/CMakeLists.txt b/unity-shared/CMakeLists.txt index 1e6233aff..b56c77990 100644 --- a/unity-shared/CMakeLists.txt +++ b/unity-shared/CMakeLists.txt @@ -67,6 +67,7 @@ set (UNITY_SHARED_SOURCES UnitySettings.cpp UnityWindowStyle.cpp UnityWindowView.cpp + UpstartWrapper.cpp UserThumbnailProvider.cpp VScrollBarOverlayWindow.cpp WindowButtons.cpp diff --git a/unity-shared/GtkTexture.h b/unity-shared/GtkTexture.h new file mode 100644 index 000000000..9d6e70c49 --- /dev/null +++ b/unity-shared/GtkTexture.h @@ -0,0 +1,64 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright 2013 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 3, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the applicable version of the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of both the GNU Lesser General Public + * License version 3 along with this program. If not, see + * <http://www.gnu.org/licenses/> + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + * + */ + +#ifndef UNITY_GDK_TEXTURE_H +#define UNITY_GDK_TEXTURE_H + +#include <Nux/Nux.h> +#include <NuxGraphics/GdkGraphics.h> +#include <NuxGraphics/NuxGraphics.h> +#include <NuxGraphics/GLTextureResourceManager.h> + +namespace unity +{ + +typedef nux::ObjectPtr<nux::BaseTexture> BaseTexturePtr; + +// Create a texture from the GdkGraphics object. +// +// Returns a new BaseTexture that has a ref count of 1. +inline nux::BaseTexture* texture_from_gdk_graphics(nux::GdkGraphics const& cg) +{ + nux::NBitmapData* bitmap = cg.GetBitmap(); + nux::BaseTexture* tex = nux::GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableTexture(); + tex->Update(bitmap); + delete bitmap; + return tex; +} + +// Create a texture from the GdkGraphics object. +// +// Returns a new smart pointer to a texture where that smart pointer is the +// sole owner of the texture object. +inline BaseTexturePtr texture_ptr_from_gdk_graphics(nux::GdkGraphics const& cg) +{ + BaseTexturePtr result(texture_from_gdk_graphics(cg)); + // Since the ObjectPtr takes a reference, and the texture is initially + // owned, the reference count now is two. + nuxAssert(result->GetReferenceCount() == 2); + result->UnReference(); + return result; +} + +} + +#endif diff --git a/unity-shared/IMTextEntry.cpp b/unity-shared/IMTextEntry.cpp index db7c86c29..0e4e383f3 100644 --- a/unity-shared/IMTextEntry.cpp +++ b/unity-shared/IMTextEntry.cpp @@ -1,4 +1,4 @@ -// -*- Mode: C++; indent-tabs-mode: ni; tab-width: 2 -*- +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright (C) 2011-2012 Canonical Ltd * @@ -26,7 +26,7 @@ namespace unity NUX_IMPLEMENT_OBJECT_TYPE(IMTextEntry); IMTextEntry::IMTextEntry() -: TextEntry("", NUX_TRACKER_LOCATION) + : TextEntry("", NUX_TRACKER_LOCATION) {} void IMTextEntry::CopyClipboard() @@ -85,4 +85,5 @@ bool IMTextEntry::im_preedit() { return !preedit_.empty(); } + } diff --git a/unity-shared/IMTextEntry.h b/unity-shared/IMTextEntry.h index 086b23e51..194077e90 100644 --- a/unity-shared/IMTextEntry.h +++ b/unity-shared/IMTextEntry.h @@ -32,7 +32,7 @@ class IMTextEntry : public nux::TextEntry NUX_DECLARE_OBJECT_TYPE(IMTextEntry, nux::TextEntry); public: IMTextEntry(); - virtual ~IMTextEntry() {} + bool im_preedit(); protected: diff --git a/unity-shared/MockableBaseWindow.h b/unity-shared/MockableBaseWindow.h index 3fa051b12..fb52eef06 100644 --- a/unity-shared/MockableBaseWindow.h +++ b/unity-shared/MockableBaseWindow.h @@ -37,7 +37,6 @@ public: : nux::BaseWindow(window_name, NUX_TRACKER_LOCATION) , struts_enabled_(false) {} - virtual ~MockableBaseWindow() {} /** * Sets the window opacity. diff --git a/unity-shared/TextInput.cpp b/unity-shared/TextInput.cpp index f4f38bbbb..2dfb72769 100644 --- a/unity-shared/TextInput.cpp +++ b/unity-shared/TextInput.cpp @@ -30,9 +30,8 @@ const int TEXT_INPUT_RIGHT_BORDER = 10; const int HIGHLIGHT_HEIGHT = 24; // Fonts -const std::string HINT_LABEL_FONT_SIZE = "12px"; -const std::string HINT_LABEL_FONT_STYLE = "Italic"; -const std::string HINT_LABEL_DEFAULT_FONT = "Ubuntu " + HINT_LABEL_FONT_STYLE + " " + HINT_LABEL_FONT_SIZE; +const std::string HINT_LABEL_DEFAULT_FONT_NAME = "Ubuntu"; +const int HINT_LABEL_FONT_SIZE = 11; const std::string PANGO_ENTRY_DEFAULT_FONT_FAMILY = "Ubuntu"; const int PANGO_ENTRY_FONT_SIZE = 14; @@ -42,34 +41,33 @@ const int PANGO_ENTRY_FONT_SIZE = 14; namespace unity { -nux::logging::Logger logger("unity.dash.textinput"); +nux::logging::Logger logger("unity.textinput"); NUX_IMPLEMENT_OBJECT_TYPE(TextInput); TextInput::TextInput(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) , input_hint("") + , hint_font_name(HINT_LABEL_DEFAULT_FONT_NAME) + , hint_font_size(HINT_LABEL_FONT_SIZE) + , bg_layer_(new nux::ColorLayer(nux::Color(0xff595853), true)) , last_width_(-1) , last_height_(-1) { - Init(); -} - -void TextInput::Init() -{ - bg_layer_.reset(new nux::ColorLayer(nux::Color(0xff595853), true)); - layout_ = new nux::HLayout(NUX_TRACKER_LOCATION); layout_->SetLeftAndRightPadding(LEFT_INTERNAL_PADDING, TEXT_INPUT_RIGHT_BORDER); layout_->SetSpaceBetweenChildren(SPACE_BETWEEN_ENTRY_AND_HIGHLIGHT); SetLayout(layout_); nux::HLayout* hint_layout = new nux::HLayout(NUX_TRACKER_LOCATION); + hint_layout->SetLeftAndRightPadding(3, 3); - hint_ = new StaticCairoText(" "); + hint_ = new StaticCairoText(""); hint_->SetTextColor(nux::Color(1.0f, 1.0f, 1.0f, 0.5f)); - hint_->SetFont(HINT_LABEL_DEFAULT_FONT.c_str()); - hint_layout->AddView(hint_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL); + hint_layout->AddView(hint_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL); + hint_font_name.changed.connect(sigc::hide(sigc::mem_fun(this, &TextInput::UpdateHintFont))); + hint_font_size.changed.connect(sigc::hide(sigc::mem_fun(this, &TextInput::UpdateHintFont))); + UpdateHintFont(); pango_entry_ = new IMTextEntry(); pango_entry_->SetFontFamily(PANGO_ENTRY_DEFAULT_FONT_FAMILY.c_str()); @@ -77,14 +75,22 @@ void TextInput::Init() pango_entry_->cursor_moved.connect([this](int i) { QueueDraw(); }); pango_entry_->mouse_down.connect(sigc::mem_fun(this, &TextInput::OnMouseButtonDown)); pango_entry_->end_key_focus.connect(sigc::mem_fun(this, &TextInput::OnEndKeyFocus)); + pango_entry_->text_changed.connect([this](nux::TextEntry*) { + hint_->SetVisible(input_string().empty()); + }); layered_layout_ = new nux::LayeredLayout(); - layered_layout_->AddLayout(hint_layout); + layered_layout_->AddLayer(hint_layout); layered_layout_->AddLayer(pango_entry_); layered_layout_->SetPaintAll(true); layered_layout_->SetActiveLayerN(1); layout_->AddView(layered_layout_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FIX); + spinner_ = new SearchBarSpinner(); + spinner_->SetVisible(false); + spinner_->SetMinMaxSize(22, 22); + layout_->AddView(spinner_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL); + sig_manager_.Add<void, GtkSettings*, GParamSpec*>(gtk_settings_get_default(), "notify::gtk-font-name", sigc::mem_fun(this, &TextInput::OnFontChanged)); OnFontChanged(gtk_settings_get_default()); @@ -97,11 +103,25 @@ void TextInput::Init() } +void TextInput::SetSpinnerVisible(bool visible) +{ + spinner_->SetVisible(visible); +} + +void TextInput::SetSpinnerState(SpinnerState spinner_state) +{ + spinner_->SetState(spinner_state); +} + +void TextInput::UpdateHintFont() +{ + hint_->SetFont((hint_font_name() + " " + std::to_string(hint_font_size())).c_str()); +} + void TextInput::OnFontChanged(GtkSettings* settings, GParamSpec* pspec) { glib::String font_name; PangoFontDescription* desc; - std::ostringstream font_desc; g_object_get(settings, "gtk-font-name", &font_name, NULL); @@ -112,20 +132,19 @@ void TextInput::OnFontChanged(GtkSettings* settings, GParamSpec* pspec) pango_entry_->SetFontSize(PANGO_ENTRY_FONT_SIZE); pango_entry_->SetFontOptions(gdk_screen_get_font_options(gdk_screen_get_default())); - font_desc << pango_font_description_get_family(desc) << " " << HINT_LABEL_FONT_STYLE << " " << HINT_LABEL_FONT_SIZE; - hint_->SetFont(font_desc.str().c_str()); - - font_desc.str(""); - font_desc.clear(); - - pango_font_description_free(desc); + if (hint_font_name() == HINT_LABEL_DEFAULT_FONT_NAME) + { + std::ostringstream font_desc; + font_desc << pango_font_description_get_family(desc) << " " << hint_font_size(); + hint_->SetFont(font_desc.str().c_str()); + pango_font_description_free(desc); + } } } void TextInput::OnInputHintChanged() { - glib::String tmp(g_markup_escape_text(input_hint().c_str(), -1)); - hint_->SetText(tmp); + hint_->SetText(input_hint().c_str(), true); } void TextInput::Draw(nux::GraphicsEngine& GfxContext, bool force_draw) @@ -184,14 +203,10 @@ void TextInput::UpdateBackground(bool force) { int RADIUS = 5; nux::Geometry geo(GetGeometry()); - geo.width = layered_layout_->GetAbsoluteX() + - layered_layout_->GetAbsoluteWidth() - - GetAbsoluteX() + - TEXT_INPUT_RIGHT_BORDER; LOG_DEBUG(logger) << "height: " << geo.height << " - " - << layered_layout_->GetGeometry().height << " - " + << layout_->GetGeometry().height << " - " << pango_entry_->GetGeometry().height; if (geo.width == last_width_ @@ -250,7 +265,7 @@ void TextInput::OnEndKeyFocus() } -nux::TextEntry* TextInput::text_entry() const +IMTextEntry* TextInput::text_entry() const { return pango_entry_; } diff --git a/unity-shared/TextInput.h b/unity-shared/TextInput.h index 48c0b9018..462474d6e 100644 --- a/unity-shared/TextInput.h +++ b/unity-shared/TextInput.h @@ -39,6 +39,7 @@ #include "unity-shared/IconTexture.h" #include "unity-shared/IMTextEntry.h" #include "unity-shared/Introspectable.h" +#include "unity-shared/SearchBarSpinner.h" #include "unity-shared/StaticCairoText.h" namespace nux @@ -49,6 +50,7 @@ class LinearLayout; namespace unity { + class TextInput : public unity::debug::Introspectable, public nux::View { NUX_DECLARE_OBJECT_TYPE(TextInput, nux::View); @@ -56,18 +58,22 @@ class TextInput : public unity::debug::Introspectable, public nux::View public: typedef nux::ObjectPtr<TextInput> Ptr; TextInput(NUX_FILE_LINE_PROTO); - TextInput(bool show_filter_hint, NUX_FILE_LINE_PROTO); - nux::TextEntry* text_entry() const; + void SetSpinnerVisible(bool visible); + void SetSpinnerState(SpinnerState spinner_state); + + IMTextEntry* text_entry() const; nux::RWProperty<std::string> input_string; nux::Property<std::string> input_hint; + nux::Property<std::string> hint_font_name; + nux::Property<int> hint_font_size; nux::ROProperty<bool> im_active; nux::ROProperty<bool> im_preedit; private: - void OnFontChanged(GtkSettings* settings, GParamSpec* pspec=NULL); + void UpdateHintFont(); void Draw(nux::GraphicsEngine& GfxContext, bool force_draw); void DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw); void UpdateBackground(bool force); @@ -78,11 +84,8 @@ private: bool AcceptKeyNavFocus(); protected: - - void Init(); void OnInputHintChanged(); - void OnMouseButtonDown(int x, int y, unsigned long button_flags, - unsigned long key_flags); + void OnMouseButtonDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnEndKeyFocus(); // getters & setters @@ -104,6 +107,7 @@ private: std::unique_ptr<nux::AbstractPaintLayer> highlight_layer_; nux::HLayout* layout_; nux::LayeredLayout* layered_layout_; + SearchBarSpinner* spinner_; int last_width_; int last_height_; diff --git a/unity-shared/UScreen.cpp b/unity-shared/UScreen.cpp index 0de6dff4f..4a2ad6701 100644 --- a/unity-shared/UScreen.cpp +++ b/unity-shared/UScreen.cpp @@ -98,16 +98,16 @@ nux::Geometry UScreen::GetScreenGeometry() const const std::string UScreen::GetMonitorName(int output_number = 0) const { - if (output_number < 0 || output_number > gdk_screen_get_n_monitors(screen_)) + if (output_number < 0 || output_number >= gdk_screen_get_n_monitors(screen_)) { - LOG_ERROR(logger) << "UScreen::GetMonitorName: Invalid monitor number" << output_number; + LOG_WARN(logger) << "UScreen::GetMonitorName: Invalid monitor number" << output_number; return ""; } glib::String output_name(gdk_screen_get_monitor_plug_name(screen_, output_number)); if (!output_name) { - LOG_ERROR(logger) << "UScreen::GetMonitorName: Failed to get monitor name for monitor" << output_number; + LOG_WARN(logger) << "UScreen::GetMonitorName: Failed to get monitor name for monitor" << output_number; return ""; } diff --git a/unity-shared/UnityWindowView.cpp b/unity-shared/UnityWindowView.cpp index 0ddf5cd07..61124578f 100644 --- a/unity-shared/UnityWindowView.cpp +++ b/unity-shared/UnityWindowView.cpp @@ -245,7 +245,7 @@ void UnityWindowView::Draw(nux::GraphicsEngine& GfxContext, bool force_draw) auto temp_background_color = background_color(); auto blend_mode = nux::LAYER_BLEND_MODE_OVERLAY; - if (Settings::Instance().GetLowGfxMode()) + if (Settings::Instance().GetLowGfxMode() || BackgroundEffectHelper::blur_type == BLUR_NONE) { temp_background_color.alpha = 1.0f; blend_mode = nux::LAYER_BLEND_MODE_NORMAL; diff --git a/unity-shared/UpstartWrapper.cpp b/unity-shared/UpstartWrapper.cpp new file mode 100644 index 000000000..eda82399c --- /dev/null +++ b/unity-shared/UpstartWrapper.cpp @@ -0,0 +1,74 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2014 Canonical Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> +*/ + +#include "UpstartWrapper.h" + +#include <UnityCore/GLibDBusProxy.h> + +namespace unity +{ + +// +// Start private implementation +// + +class UpstartWrapper::Impl +{ +public: + Impl(bool test_mode = false); + + void Emit(std::string const& name); + +private: + glib::DBusProxy::Ptr upstart_proxy_; +}; + +UpstartWrapper::Impl::Impl(bool test_mode) +{ + upstart_proxy_ = std::make_shared<unity::glib::DBusProxy>(test_mode ? "com.canonical.Unity.Test.Upstart" : "com.ubuntu.Upstart", + "/com/ubuntu/Upstart", + "com.ubuntu.Upstart0_6"); +} + +void UpstartWrapper::Impl::Emit(std::string const& name) +{ + upstart_proxy_->Call("EmitEvent", g_variant_new("(sasb)", name.c_str(), nullptr, 0)); +} + +// +// End private implementation +// + +UpstartWrapper::UpstartWrapper() + : pimpl_(new Impl) +{} + +UpstartWrapper::UpstartWrapper(UpstartWrapper::TestMode const& tm) + : pimpl_(new Impl(true)) +{} + +UpstartWrapper::~UpstartWrapper() +{} + +void UpstartWrapper::Emit(std::string const& name) +{ + pimpl_->Emit(name); +} + +} diff --git a/unity-shared/UpstartWrapper.h b/unity-shared/UpstartWrapper.h new file mode 100644 index 000000000..3be88d9cb --- /dev/null +++ b/unity-shared/UpstartWrapper.h @@ -0,0 +1,53 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* +* Copyright (C) 2014 Canonical Ltd +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 3 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> +*/ + +#ifndef UNITY_UPSTART_WRAPPER +#define UNITY_UPSTART_WRAPPER + +#include <memory> + +namespace unity +{ + +class UpstartWrapper +{ +public: + typedef std::shared_ptr<UpstartWrapper> Ptr; + + UpstartWrapper(); + ~UpstartWrapper(); + + void Emit(std::string const& name); + +protected: + struct TestMode {}; + UpstartWrapper(TestMode const&); + +private: + // Noncopyable + UpstartWrapper(UpstartWrapper const&) = delete; + UpstartWrapper& operator=(UpstartWrapper const&) = delete; + + class Impl; + std::unique_ptr<Impl> pimpl_; +}; + +} + +#endif diff --git a/unity-shared/WindowManager.h b/unity-shared/WindowManager.h index 330b9be86..0da719399 100644 --- a/unity-shared/WindowManager.h +++ b/unity-shared/WindowManager.h @@ -166,6 +166,7 @@ public: // Nux Modifiers, Nux Keycode (= X11 KeySym) nux::Property<std::pair<unsigned, unsigned>> close_window_key; + nux::Property<std::pair<unsigned, unsigned>> activate_indicators_key; nux::Property<nux::Color> average_color; // Signals |
