diff options
| -rw-r--r-- | hud/HudView.cpp | 2 | ||||
| -rw-r--r-- | lockscreen/LockScreenShield.cpp | 38 | ||||
| -rw-r--r-- | lockscreen/LockScreenShield.h | 5 | ||||
| -rw-r--r-- | lockscreen/UserAuthenticator.h | 20 | ||||
| -rw-r--r-- | lockscreen/UserAuthenticatorPam.cpp | 67 | ||||
| -rw-r--r-- | lockscreen/UserAuthenticatorPam.h | 5 | ||||
| -rw-r--r-- | lockscreen/UserPromptView.cpp | 140 | ||||
| -rw-r--r-- | lockscreen/UserPromptView.h | 30 | ||||
| -rw-r--r-- | tests/test_upstart_wrapper.cpp | 2 | ||||
| -rw-r--r-- | tests/test_user_authenticator_pam.cpp | 22 | ||||
| -rw-r--r-- | unity-shared/IMTextEntry.h | 3 | ||||
| -rw-r--r-- | unity-shared/TextInput.cpp | 8 | ||||
| -rw-r--r-- | unity-shared/TextInput.h | 2 |
13 files changed, 222 insertions, 122 deletions
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/LockScreenShield.cpp b/lockscreen/LockScreenShield.cpp index 9f99d416b..aef9037ca 100644 --- a/lockscreen/LockScreenShield.cpp +++ b/lockscreen/LockScreenShield.cpp @@ -27,12 +27,10 @@ #include "BackgroundSettings.h" #include "CofView.h" #include "LockScreenSettings.h" -#include "UserAuthenticatorPam.h" #include "UserPromptView.h" #include "panel/PanelView.h" #include "unity-shared/GnomeKeyGrabber.h" #include "unity-shared/PanelStyle.h" -#include "unity-shared/TextInput.h" namespace unity { @@ -43,7 +41,6 @@ Shield::Shield(session::Manager::Ptr const& session_manager, bool is_primary) : primary(is_primary) , session_manager_(session_manager) , bg_settings_(new BackgroundSettings) - , user_authenticator_(new UserAuthenticatorPam) , prompt_view_(nullptr) { SetLayout(new nux::VLayout()); @@ -111,9 +108,7 @@ nux::View* Shield::CreatePanel() nux::View* Shield::CreatePromptView() { - auto const& real_name = session_manager_->RealName(); - auto const& name = (real_name.empty() ? session_manager_->UserName() : real_name); - prompt_view_ = new UserPromptView(name); + prompt_view_ = new UserPromptView(session_manager_); auto width = 8 * Settings::GRID_SIZE; auto height = 3 * Settings::GRID_SIZE; @@ -121,9 +116,6 @@ nux::View* Shield::CreatePromptView() prompt_view_->SetMinimumWidth(width); prompt_view_->SetMaximumWidth(width); prompt_view_->SetMinimumHeight(height); - prompt_view_->SetMaximumHeight(height); - - prompt_view_->text_entry()->activated.connect(sigc::mem_fun(this, &Shield::OnPromptActivated)); return prompt_view_; } @@ -143,39 +135,17 @@ void Shield::OnIndicatorEntryActivated(std::string const& entry, nux::Geometry c } } -void Shield::OnPromptActivated() -{ - prompt_view_->SetSpinnerVisible(true); - prompt_view_->SetSpinnerState(STATE_SEARCHING); - prompt_view_->text_entry()->SetInputEventSensitivity(false); - - user_authenticator_->AuthenticateStart(session_manager_->UserName(), - prompt_view_->text_entry()->GetText(), - sigc::mem_fun(this, &Shield::AuthenticationCb)); -} - -void Shield::AuthenticationCb(bool authenticated) -{ - prompt_view_->text_entry()->SetText(""); - prompt_view_->SetSpinnerVisible(false); - prompt_view_->text_entry()->SetInputEventSensitivity(true); - - if (authenticated) - session_manager_->unlock_requested.emit(); - else - prompt_view_->ShowErrorMessage(); -} - nux::Area* Shield::FindKeyFocusArea(unsigned int, unsigned long, unsigned long) { - if (prompt_view_ && prompt_view_->text_entry() && prompt_view_->text_entry()->GetInputEventSensitivity()) - return prompt_view_->text_entry(); + if (prompt_view_ && prompt_view_->focus_view() && prompt_view_->focus_view()->GetInputEventSensitivity()) + return prompt_view_->focus_view(); else return nullptr; } + bool Shield::AcceptKeyNavFocus() { return false; diff --git a/lockscreen/LockScreenShield.h b/lockscreen/LockScreenShield.h index e02e85622..dbd3bfc0f 100644 --- a/lockscreen/LockScreenShield.h +++ b/lockscreen/LockScreenShield.h @@ -21,8 +21,6 @@ #define UNITY_LOCKSCREEN_SHIELD_H #include <NuxCore/Property.h> -#include <UnityCore/GLibWrapper.h> -#include <UnityCore/GLibSignal.h> #include <UnityCore/SessionManager.h> #include "unity-shared/MockableBaseWindow.h" @@ -59,14 +57,11 @@ private: void OnIndicatorEntryShowMenu(std::string const&, unsigned, int, int, unsigned); void OnIndicatorEntryActivated(std::string const& entry, nux::Geometry const& geo); - void OnPromptActivated(); - void AuthenticationCb(bool authenticated); session::Manager::Ptr session_manager_; std::shared_ptr<BackgroundSettings> bg_settings_; std::unique_ptr<nux::AbstractPaintLayer> background_layer_; - std::shared_ptr<UserAuthenticator> user_authenticator_; UserPromptView* prompt_view_; }; diff --git a/lockscreen/UserAuthenticator.h b/lockscreen/UserAuthenticator.h index 4bebc5c08..58553e210 100644 --- a/lockscreen/UserAuthenticator.h +++ b/lockscreen/UserAuthenticator.h @@ -17,10 +17,13 @@ * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> */ - #ifndef UNITY_USER_AUTHENTICATOR_H - #define UNITY_USER_AUTHENTICATOR_H +#ifndef UNITY_USER_AUTHENTICATOR_H +#define UNITY_USER_AUTHENTICATOR_H +#include <future> #include <functional> +#include <memory> +#include <sigc++/signal.h> #include <string> namespace unity @@ -33,16 +36,21 @@ class UserAuthenticator public: typedef std::function<void(bool)> AuthenticateEndCallback; - virtual ~UserAuthenticator() {} + virtual ~UserAuthenticator() {}; // Authenticate the user in a background thread. virtual bool AuthenticateStart(std::string const& username, - std::string const& password, AuthenticateEndCallback authenticate_cb) = 0; + + // FIXME (andy) found a better name for the promise ptr. + sigc::signal<void, std::string, std::shared_ptr<std::promise<std::string>> const&> echo_on_requested; + sigc::signal<void, std::string, std::shared_ptr<std::promise<std::string>> 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 index 377267081..b2bb89172 100644 --- a/lockscreen/UserAuthenticatorPam.cpp +++ b/lockscreen/UserAuthenticatorPam.cpp @@ -25,6 +25,7 @@ #include <cstring> #include <security/pam_appl.h> +#include <vector> namespace unity { @@ -32,11 +33,10 @@ namespace lockscreen { bool UserAuthenticatorPam::AuthenticateStart(std::string const& username, - std::string const& password, AuthenticateEndCallback authenticate_cb) { + first_prompt_ = true; username_ = username; - password_ = password; authenticate_cb_ = authenticate_cb; if (!InitPam()) @@ -65,7 +65,7 @@ bool UserAuthenticatorPam::InitPam() conversation.appdata_ptr = static_cast<void*>(this); // FIXME (andy) We should install our own unityshell pam file. - return pam_start("common-auth", username_.c_str(), + return pam_start("lightdm", username_.c_str(), &conversation, &pam_handle_) == PAM_SUCCESS; } @@ -83,30 +83,69 @@ int UserAuthenticatorPam::ConversationFunction(int num_msg, 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->clear_prompts.emit(); return false; }); + + user_auth->first_prompt_ = false; + bool raise_error = false; int count; + std::vector<std::shared_ptr<std::promise<std::string>>> promises; + for (count = 0; count < num_msg && !raise_error; ++count) { - pam_response* resp_item = &tmp_response[count]; - resp_item->resp_retcode = 0; - resp_item->resp = nullptr; - switch (msg[count]->msg_style) { case PAM_PROMPT_ECHO_ON: - resp_item->resp = strdup(user_auth->username_.c_str()); - if (!resp_item->resp) - raise_error = true; + { + 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, [&, message, promise]() { user_auth->echo_on_requested.emit(message, promise); return false; }); break; + } case PAM_PROMPT_ECHO_OFF: - resp_item->resp = strdup(user_auth->password_.c_str()); - if (!resp_item->resp) - raise_error = true; + { + 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, [&, 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, [&, message]() { user_auth->message_requested.emit(message); return false; }); break; + } default: - raise_error = true; + { + // 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, [&, message]() { user_auth->error_requested.emit(message); return false; }); + } + } + } + + int i = 0; + + for (auto 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; } } diff --git a/lockscreen/UserAuthenticatorPam.h b/lockscreen/UserAuthenticatorPam.h index ab5b59270..af4fed3c8 100644 --- a/lockscreen/UserAuthenticatorPam.h +++ b/lockscreen/UserAuthenticatorPam.h @@ -22,6 +22,7 @@ #include <boost/noncopyable.hpp> #include <UnityCore/GLibWrapper.h> +#include <UnityCore/GLibSource.h> #include "UserAuthenticator.h" @@ -39,7 +40,6 @@ class UserAuthenticatorPam : public UserAuthenticator, private boost::noncopyabl { public: bool AuthenticateStart(std::string const& username, - std::string const& password, AuthenticateEndCallback authenticate_cb) override; private: @@ -52,12 +52,13 @@ private: void* appdata_ptr); std::string username_; - std::string password_; AuthenticateEndCallback authenticate_cb_; int status_; + bool first_prompt_; pam_handle* pam_handle_; glib::Cancellable cancellable_; + glib::SourceManager source_manager_; }; } // lockscreen diff --git a/lockscreen/UserPromptView.cpp b/lockscreen/UserPromptView.cpp index acc852013..81ad60cd5 100644 --- a/lockscreen/UserPromptView.cpp +++ b/lockscreen/UserPromptView.cpp @@ -65,33 +65,82 @@ nux::AbstractPaintLayer* CrateBackgroundLayer(int width, int height) rop)); } -UserPromptView::UserPromptView(std::string const& name) +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, std::shared_ptr<std::promise<std::string>> const& promise){ + AddPrompt(message, /* visible */ true, promise); + }); + + user_authenticator_.echo_off_requested.connect([this](std::string const& message, std::shared_ptr<std::promise<std::string>> 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_ = std::queue<IMTextEntry*>(); + SetLayout(new nux::VLayout()); GetLayout()->SetLeftAndRightPadding(10); GetLayout()->SetTopAndBottomPadding(10); - static_cast<nux::VLayout*>(GetLayout())->SetVerticalInternalMargin(5); + static_cast<nux::VLayout*>(GetLayout())->SetVerticalInternalMargin(10); + + 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 13"); GetLayout()->AddView(username); - GetLayout()->AddSpace(0, 1); + msg_layout_ = new nux::VLayout(); + msg_layout_->SetVerticalInternalMargin(15); + msg_layout_->SetReconfigureParentLayoutOnGeometryChange(true); + GetLayout()->AddLayout(msg_layout_); + + prompt_layout_ = new nux::VLayout(); + prompt_layout_->SetVerticalInternalMargin(5); + prompt_layout_->SetReconfigureParentLayoutOnGeometryChange(true); + GetLayout()->AddLayout(prompt_layout_); + + QueueRelayout(); + QueueDraw(); +} + +void UserPromptView::AuthenticationCb(bool authenticated) +{ + ResetLayout(); - message_ = new unity::StaticCairoText(_("Invalid password, please try again")); - message_->SetFont("Ubuntu 10"); - message_->SetTextColor(nux::Color("#df382c")); - message_->SetVisible(false); - GetLayout()->AddView(message_); + if (authenticated) + { + session_manager_->unlock_requested.emit(); + } + else + { + AddMessage(_("Invalid password, please try again"), nux::color::Red); - text_input_ = new unity::TextInput(); - text_input_->input_hint = _("Password"); - text_input_->text_entry()->SetPasswordMode(true); - text_input_->SetMinimumHeight(Settings::GRID_SIZE); - text_input_->SetMaximumHeight(Settings::GRID_SIZE); - GetLayout()->AddView(text_input_, 1); + user_authenticator_.AuthenticateStart(session_manager_->UserName(), + sigc::mem_fun(this, &UserPromptView::AuthenticationCb)); + } } void UserPromptView::Draw(nux::GraphicsEngine& graphics_engine, bool /* force_draw */) @@ -128,27 +177,68 @@ void UserPromptView::DrawContent(nux::GraphicsEngine& graphics_engine, bool forc graphics_engine.PopClippingRectangle(); } -nux::TextEntry* UserPromptView::text_entry() +nux::View* UserPromptView::focus_view() { - return text_input_->text_entry(); -} + if (focus_queue_.empty()) + return nullptr; -void UserPromptView::SetSpinnerVisible(bool visible) -{ - text_input_->SetSpinnerVisible(visible); - QueueRelayout(); + focus_queue_.front()->cursor_visible_ = true; + return focus_queue_.front(); } -void UserPromptView::SetSpinnerState(SpinnerState spinner_state) +void UserPromptView::AddPrompt(std::string const& message, bool visible, std::shared_ptr<std::promise<std::string>> const& promise) { - text_input_->SetSpinnerState(spinner_state); + auto text_input = new unity::TextInput(); + + text_input->input_hint = message; + text_input->text_entry()->SetPasswordMode(!visible); + + text_input->text_entry()->cursor_visible_ = false; + if (text_input->text_entry()->cursor_blink_timer_) + g_source_remove(text_input->text_entry()->cursor_blink_timer_); + + text_input->SetMinimumHeight(Settings::GRID_SIZE); + text_input->SetMaximumHeight(Settings::GRID_SIZE); + prompt_layout_->AddView(text_input, 1); + focus_queue_.push(text_input->text_entry()); + + text_input->text_entry()->activated.connect([this, text_input, promise](){ + if (focus_queue_.size() == 1) + { + text_input->SetSpinnerVisible(true); + text_input->SetSpinnerState(STATE_SEARCHING); + } + + this->focus_queue_.pop(); + + text_input->text_entry()->SetInputEventSensitivity(false); + text_input->text_entry()->cursor_visible_ = false; + this->QueueRelayout(); + this->QueueDraw(); + + std::string password = text_input->text_entry()->GetText(); + promise->set_value(password); + }); + + GetLayout()->ComputeContentPosition(0, 0); + ComputeContentSize(); QueueRelayout(); + QueueDraw(); } -void UserPromptView::ShowErrorMessage() +void UserPromptView::AddMessage(std::string const& message, nux::Color const& color) { - message_->SetVisible(true); + auto* view = new unity::StaticCairoText(""); + view->SetFont("Ubuntu 10"); + 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 index ff4cfcd45..ae20b07c4 100644 --- a/lockscreen/UserPromptView.h +++ b/lockscreen/UserPromptView.h @@ -21,12 +21,21 @@ #define UNITY_USER_PROMPT_BOX #include <memory> +#include <queue> #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 { @@ -39,24 +48,31 @@ namespace lockscreen class UserPromptView : public nux::View { public: - UserPromptView(std::string const& name); + UserPromptView(session::Manager::Ptr const& session_manager); ~UserPromptView() {}; - nux::TextEntry* text_entry(); + nux::View* focus_view(); - void SetSpinnerVisible(bool visible); - void SetSpinnerState(SpinnerState spinner_state); - - void ShowErrorMessage(); + void AddPrompt(std::string const& message, bool visible, std::shared_ptr<std::promise<std::string>> const& promise); + 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_; - TextInput* text_input_; + StaticCairoText* error_; + StaticCairoText* invalid_login_; + std::queue<IMTextEntry*> focus_queue_; }; } diff --git a/tests/test_upstart_wrapper.cpp b/tests/test_upstart_wrapper.cpp index 48b3d49ab..4e5cb856f 100644 --- a/tests/test_upstart_wrapper.cpp +++ b/tests/test_upstart_wrapper.cpp @@ -60,7 +60,7 @@ TEST_F(TestUpstartWrapper, Emit) upstart_wrapper_.Emit("desktop-lock"); - Utils::WaitUntil(event_emitted, 5); + Utils::WaitUntil(event_emitted); } } diff --git a/tests/test_user_authenticator_pam.cpp b/tests/test_user_authenticator_pam.cpp index 286c97802..64b9a8431 100644 --- a/tests/test_user_authenticator_pam.cpp +++ b/tests/test_user_authenticator_pam.cpp @@ -53,26 +53,6 @@ struct TestUserAuthenticatorPam : public ::testing::Test UserAuthenticatorPam user_authenticator_pam_; }; -TEST_F(TestUserAuthenticatorPam, AuthenticateStart) -{ - bool authentication_result = false; - - user_authenticator_pam_.AuthenticateStart("andrea", "password", [&authentication_result](bool success) { - authentication_result = success; - }); - - Utils::WaitUntilMSec(authentication_result); -} - -TEST_F(TestUserAuthenticatorPam, AuthenticateStartWrongPassword) -{ - bool authentication_result = false; - - user_authenticator_pam_.AuthenticateStart("maria", "wrong password", [&authentication_result](bool success) { - authentication_result = not success; - }); - - Utils::WaitUntilMSec(authentication_result); -} +// FIXME (add tests) } diff --git a/unity-shared/IMTextEntry.h b/unity-shared/IMTextEntry.h index 086b23e51..410a434bd 100644 --- a/unity-shared/IMTextEntry.h +++ b/unity-shared/IMTextEntry.h @@ -35,6 +35,9 @@ public: virtual ~IMTextEntry() {} bool im_preedit(); + using TextEntry::cursor_visible_; + using TextEntry::cursor_blink_timer_; + protected: virtual void InsertText(std::string const& text); virtual void CopyClipboard(); diff --git a/unity-shared/TextInput.cpp b/unity-shared/TextInput.cpp index 809d1e6ca..e6b8805b4 100644 --- a/unity-shared/TextInput.cpp +++ b/unity-shared/TextInput.cpp @@ -30,8 +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_FONT_SIZE = "14px"; +const std::string HINT_LABEL_FONT_STYLE = ""; const std::string HINT_LABEL_DEFAULT_FONT = "Ubuntu " + HINT_LABEL_FONT_STYLE + " " + HINT_LABEL_FONT_SIZE; const std::string PANGO_ENTRY_DEFAULT_FONT_FAMILY = "Ubuntu"; @@ -82,7 +82,7 @@ void TextInput::Init() }); 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); @@ -265,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 5f45ec63c..cef150424 100644 --- a/unity-shared/TextInput.h +++ b/unity-shared/TextInput.h @@ -63,7 +63,7 @@ public: void SetSpinnerVisible(bool visible); void SetSpinnerState(SpinnerState spinner_state); - nux::TextEntry* text_entry() const; + IMTextEntry* text_entry() const; nux::RWProperty<std::string> input_string; nux::Property<std::string> input_hint; |
