summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/app/generated_resources.grd6
-rw-r--r--chrome/browser/about_flags.cc11
-rw-r--r--chrome/browser/browser_resources.grd3
-rw-r--r--chrome/browser/chromeos/cros_stubs_aura.cc39
-rw-r--r--chrome/browser/chromeos/login/login_performer.cc6
-rw-r--r--chrome/browser/chromeos/login/screen_lock_view.cc2
-rw-r--r--chrome/browser/chromeos/login/screen_locker.cc928
-rw-r--r--chrome/browser/chromeos/login/screen_locker.h131
-rw-r--r--chrome/browser/chromeos/login/screen_locker_browsertest.cc1
-rw-r--r--chrome/browser/chromeos/login/screen_locker_delegate.cc21
-rw-r--r--chrome/browser/chromeos/login/screen_locker_delegate.h61
-rw-r--r--chrome/browser/chromeos/login/screen_locker_tester.cc20
-rw-r--r--chrome/browser/chromeos/login/screen_locker_tester.h4
-rw-r--r--chrome/browser/chromeos/login/screen_locker_views.cc936
-rw-r--r--chrome/browser/chromeos/login/screen_locker_views.h157
-rw-r--r--chrome/browser/chromeos/login/screen_locker_webui.cc353
-rw-r--r--chrome/browser/chromeos/login/screen_locker_webui.h75
-rw-r--r--chrome/browser/chromeos/login/webui_login_view.cc6
-rw-r--r--chrome/browser/chromeos/login/webui_login_view.h3
-rw-r--r--chrome/browser/resources/chromeos/login/lock_screen.css51
-rw-r--r--chrome/browser/resources/chromeos/login/lock_screen.html32
-rw-r--r--chrome/browser/resources/chromeos/login/lock_screen.js51
-rw-r--r--chrome/browser/ui/webui/chrome_web_ui_factory.cc3
-rw-r--r--chrome/browser/ui/webui/chromeos/login/lock_screen_ui.cc80
-rw-r--r--chrome/browser/ui/webui/chromeos/login/lock_screen_ui.h32
-rw-r--r--chrome/chrome_browser.gypi10
-rw-r--r--chrome/common/chrome_switches.cc3
-rw-r--r--chrome/common/chrome_switches.h1
-rw-r--r--chrome/common/url_constants.cc2
-rw-r--r--chrome/common/url_constants.h2
30 files changed, 1989 insertions, 1041 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 4685d49..167e397 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -4733,6 +4733,12 @@ Keep your key file in a safe place. You will need it to create new versions of y
<message name="IDS_FLAGS_USE_MORE_WEBUI_DESCRIPTION" desc="Description for the flag to use more WebUI.">
Enable experimental HTML implementations of some minor UI components such as various dialogs.
</message>
+ <message name="IDS_FLAGS_WEBUI_LOCK_NAME" desc="Title for the flag to use WebUI lock screen.">
+ Use WebUI lock screen.
+ </message>
+ <message name="IDS_FLAGS_WEBUI_LOCK_DESCRIPTION" desc="Description for the flag to use WebUI lock screen.">
+ Use the experimental HTML implementation of the lock screen.
+ </message>
<message name="IDS_FLAGS_ENABLE_NTP_BOOKMARK_FEATURES_NAME" desc="Title for the flag to enable NTP bookmark features.">
Enable NTP bookmark features
</message>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index baca9ce..b085238 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -396,6 +396,17 @@ const Experiment kExperiments[] = {
SINGLE_VALUE_TYPE(switches::kUseMoreWebUI)
},
{
+ "webui-lock-screen",
+ IDS_FLAGS_WEBUI_LOCK_NAME,
+ IDS_FLAGS_WEBUI_LOCK_DESCRIPTION,
+ kOsCrOS,
+#if defined(OS_CHROMEOS)
+ SINGLE_VALUE_TYPE(switches::kWebUILockScreen)
+#else
+ SINGLE_VALUE_TYPE("")
+#endif
+ },
+ {
"enable-ntp-bookmark-features",
IDS_FLAGS_ENABLE_NTP_BOOKMARK_FEATURES_NAME,
IDS_FLAGS_ENABLE_NTP_BOOKMARK_FEATURES_DESCRIPTION,
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 43376d8..58e33f5 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -130,6 +130,9 @@
<include name="IDR_KEYBOARD_OVERLAY_DATA_JS" file="resources\keyboard_overlay_data.js" flattenhtml="true" type="BINDATA" />
<include name="IDR_KEYBOARD_OVERLAY_HTML" file="resources\keyboard_overlay.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_KEYBOARD_OVERLAY_JS" file="resources\keyboard_overlay.js" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_LOCK_SCREEN_CSS" file="resources\chromeos\login\lock_screen.css" type="BINDATA" />
+ <include name="IDR_LOCK_SCREEN_HTML" file="resources\chromeos\login\lock_screen.html" type="BINDATA" />
+ <include name="IDR_LOCK_SCREEN_JS" file="resources\chromeos\login\lock_screen.js" type="BINDATA" />
<include name="IDR_LOGIN_HTML" file="resources\chromeos\login\login.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_MENU_HTML" file="resources\menu.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_MOBILE_MANIFEST" file="resources\mobile_app\manifest.json" type="BINDATA" />
diff --git a/chrome/browser/chromeos/cros_stubs_aura.cc b/chrome/browser/chromeos/cros_stubs_aura.cc
index 265198d..01a5293 100644
--- a/chrome/browser/chromeos/cros_stubs_aura.cc
+++ b/chrome/browser/chromeos/cros_stubs_aura.cc
@@ -125,6 +125,10 @@ ScreenLocker::ScreenLocker(const UserManager::User& user) {
NOTIMPLEMENTED();
}
+ScreenLocker::~ScreenLocker() {
+ NOTIMPLEMENTED();
+}
+
void ScreenLocker::Init() {
NOTIMPLEMENTED();
}
@@ -142,25 +146,6 @@ void ScreenLocker::OnLoginSuccess(
NOTIMPLEMENTED();
}
-void ScreenLocker::BubbleClosing(Bubble* bubble, bool closed_by_escape) {
- NOTIMPLEMENTED();
-}
-
-bool ScreenLocker::CloseOnEscape() {
- return true;
-}
-
-bool ScreenLocker::FadeInOnShow() {
- return false;
-}
-
-void ScreenLocker::OnLinkActivated(size_t index) {
-}
-
-void ScreenLocker::OnCaptchaEntered(const std::string& captcha) {
- NOTIMPLEMENTED();
-}
-
void ScreenLocker::Authenticate(const string16& password) {
NOTIMPLEMENTED();
}
@@ -178,23 +163,15 @@ void ScreenLocker::Signout() {
}
void ScreenLocker::ShowCaptchaAndErrorMessage(const GURL& captcha_url,
- const std::wstring& message) {
+ const string16& message) {
NOTIMPLEMENTED();
}
-void ScreenLocker::ShowErrorMessage(const std::wstring& message,
+void ScreenLocker::ShowErrorMessage(const string16& message,
bool sign_out_only) {
NOTIMPLEMENTED();
}
-void ScreenLocker::OnGrabInputs() {
- NOTIMPLEMENTED();
-}
-
-views::View* ScreenLocker::GetViewByID(int id) {
- return NULL;
-}
-
void ScreenLocker::SetLoginStatusConsumer(
chromeos::LoginStatusConsumer* consumer) {
NOTIMPLEMENTED();
@@ -220,6 +197,10 @@ void ScreenLocker::InitClass() {
NOTIMPLEMENTED();
}
+void ScreenLocker::ScreenLockReady() {
+ NOTIMPLEMENTED();
+}
+
} // namespace chromeos
class BalloonCollectionStub : public BalloonCollection {
diff --git a/chrome/browser/chromeos/login/login_performer.cc b/chrome/browser/chromeos/login/login_performer.cc
index 9b2de10..a58c4cf 100644
--- a/chrome/browser/chromeos/login/login_performer.cc
+++ b/chrome/browser/chromeos/login/login_performer.cc
@@ -513,8 +513,7 @@ void LoginPerformer::ResolveLockNetworkAuthFailure() {
captcha_token_ = last_login_failure_.error().captcha().token;
msg = l10n_util::GetStringUTF16(IDS_LOGIN_ERROR_PASSWORD_CHANGED);
ScreenLocker::default_screen_locker()->ShowCaptchaAndErrorMessage(
- last_login_failure_.error().captcha().image_url,
- UTF16ToWide(msg));
+ last_login_failure_.error().captcha().image_url, msg);
return;
default:
// Unless there's new GoogleServiceAuthError state has been added.
@@ -522,8 +521,7 @@ void LoginPerformer::ResolveLockNetworkAuthFailure() {
break;
}
- ScreenLocker::default_screen_locker()->ShowErrorMessage(UTF16ToWide(msg),
- sign_out_only);
+ ScreenLocker::default_screen_locker()->ShowErrorMessage(msg, sign_out_only);
}
void LoginPerformer::ResolveScreenLocked() {
diff --git a/chrome/browser/chromeos/login/screen_lock_view.cc b/chrome/browser/chromeos/login/screen_lock_view.cc
index 900a9ac..6a572eb 100644
--- a/chrome/browser/chromeos/login/screen_lock_view.cc
+++ b/chrome/browser/chromeos/login/screen_lock_view.cc
@@ -17,7 +17,6 @@
#include "chrome/common/chrome_notification_types.h"
#include "content/common/notification_service.h"
#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "views/background.h"
@@ -27,6 +26,7 @@
#include "views/controls/textfield/native_textfield_wrapper.h"
#include "views/controls/textfield/textfield.h"
#include "views/layout/grid_layout.h"
+#include "views/widget/native_widget_gtk.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/login/screen_locker.cc b/chrome/browser/chromeos/login/screen_locker.cc
index 489935c..26a0762 100644
--- a/chrome/browser/chromeos/login/screen_locker.cc
+++ b/chrome/browser/chromeos/login/screen_locker.cc
@@ -4,14 +4,8 @@
#include "chrome/browser/chromeos/login/screen_locker.h"
-#include <X11/extensions/XTest.h>
-#include <X11/keysym.h>
-#include <gdk/gdkkeysyms.h>
-#include <gdk/gdkx.h>
#include <string>
#include <vector>
-// Evil hack to undo X11 evil #define. See crosbug.com/
-#undef Status
#include "base/bind.h"
#include "base/command_line.h"
@@ -30,14 +24,10 @@
#include "chrome/browser/chromeos/input_method/xkeyboard.h"
#include "chrome/browser/chromeos/language_preferences.h"
#include "chrome/browser/chromeos/login/authenticator.h"
-#include "chrome/browser/chromeos/login/background_view.h"
#include "chrome/browser/chromeos/login/login_performer.h"
#include "chrome/browser/chromeos/login/login_utils.h"
-#include "chrome/browser/chromeos/login/message_bubble.h"
-#include "chrome/browser/chromeos/login/screen_lock_view.h"
-#include "chrome/browser/chromeos/login/shutdown_button.h"
-#include "chrome/browser/chromeos/system_key_event_listener.h"
-#include "chrome/browser/chromeos/view_ids.h"
+#include "chrome/browser/chromeos/login/screen_locker_views.h"
+#include "chrome/browser/chromeos/login/screen_locker_webui.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/sync/profile_sync_service.h"
@@ -46,19 +36,13 @@
#include "chrome/browser/ui/browser_window.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/pref_names.h"
#include "content/browser/browser_thread.h"
#include "content/browser/user_metrics.h"
#include "content/common/notification_service.h"
#include "googleurl/src/gurl.h"
#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
#include "third_party/cros_system_api/window_manager/chromeos_wm_ipc_enums.h"
#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/base/x/x11_util.h"
-#include "ui/gfx/screen.h"
-#include "views/widget/native_widget_gtk.h"
#if defined(TOOLKIT_USES_GTK)
#include "chrome/browser/chromeos/wm_ipc.h"
@@ -66,18 +50,6 @@
namespace {
-// The maximum duration for which locker should try to grab the keyboard and
-// mouse and its interval for regrabbing on failure.
-const int kMaxGrabFailureSec = 30;
-const int64 kRetryGrabIntervalMs = 500;
-
-// Maximum number of times we'll try to grab the keyboard and mouse before
-// giving up. If we hit the limit, Chrome exits and the session is terminated.
-const int kMaxGrabFailures = kMaxGrabFailureSec * 1000 / kRetryGrabIntervalMs;
-
-// A idle time to show the screen saver in seconds.
-const int kScreenSaverIdleTimeout = 15;
-
// Observer to start ScreenLocker when the screen lock
class ScreenLockObserver : public chromeos::ScreenLockLibrary::Observer,
public NotificationObserver {
@@ -202,377 +174,6 @@ class ScreenLockObserver : public chromeos::ScreenLockLibrary::Observer,
static base::LazyInstance<ScreenLockObserver> g_screen_lock_observer(
base::LINKER_INITIALIZED);
-// A ScreenLock window that covers entire screen to keep the keyboard
-// focus/events inside the grab widget.
-class LockWindow : public views::NativeWidgetGtk {
- public:
- LockWindow()
- : views::NativeWidgetGtk(new views::Widget),
- toplevel_focus_widget_(NULL) {
- EnableDoubleBuffer(true);
- }
-
- // GTK propagates key events from parents to children.
- // Make sure LockWindow will never handle key events.
- virtual gboolean OnEventKey(GtkWidget* widget, GdkEventKey* event) OVERRIDE {
- // Don't handle key event in the lock window.
- return false;
- }
-
- virtual gboolean OnButtonPress(GtkWidget* widget,
- GdkEventButton* event) OVERRIDE {
- // Don't handle mouse event in the lock wnidow and
- // nor propagate to child.
- return true;
- }
-
- virtual void OnDestroy(GtkWidget* object) OVERRIDE {
- VLOG(1) << "OnDestroy: LockWindow destroyed";
- views::NativeWidgetGtk::OnDestroy(object);
- }
-
- virtual void ClearNativeFocus() OVERRIDE {
- DCHECK(toplevel_focus_widget_);
- gtk_widget_grab_focus(toplevel_focus_widget_);
- }
-
- // Sets the widget to move the focus to when clearning the native
- // widget's focus.
- void set_toplevel_focus_widget(GtkWidget* widget) {
- gtk_widget_set_can_focus(widget, TRUE);
- toplevel_focus_widget_ = widget;
- }
-
- private:
- // The widget we set focus to when clearning the focus on native
- // widget. In screen locker, gdk input is grabbed in GrabWidget,
- // and resetting the focus by using gtk_window_set_focus seems to
- // confuse gtk and doesn't let focus move to native widget under
- // GrabWidget.
- GtkWidget* toplevel_focus_widget_;
-
- DISALLOW_COPY_AND_ASSIGN(LockWindow);
-};
-
-// GrabWidget's root view to layout the ScreenLockView at the center
-// and the Shutdown button at the left top.
-class GrabWidgetRootView
- : public views::View,
- public chromeos::ScreenLocker::ScreenLockViewContainer {
- public:
- explicit GrabWidgetRootView(chromeos::ScreenLockView* screen_lock_view)
- : screen_lock_view_(screen_lock_view),
- shutdown_button_(new chromeos::ShutdownButton()) {
- shutdown_button_->Init();
- AddChildView(screen_lock_view_);
- AddChildView(shutdown_button_);
- }
-
- // views::View implementation.
- virtual void Layout() OVERRIDE {
- gfx::Size size = screen_lock_view_->GetPreferredSize();
- gfx::Rect b = bounds();
- screen_lock_view_->SetBounds(
- b.width() - size.width(), b.height() - size.height(),
- size.width(), size.height());
- shutdown_button_->LayoutIn(this);
- }
-
- // ScreenLocker::ScreenLockViewContainer implementation:
- void SetScreenLockView(views::View* screen_lock_view) OVERRIDE {
- if (screen_lock_view_) {
- RemoveChildView(screen_lock_view_);
- }
- screen_lock_view_ = screen_lock_view;
- if (screen_lock_view_) {
- AddChildViewAt(screen_lock_view_, 0);
- }
- Layout();
- }
-
- private:
- views::View* screen_lock_view_;
-
- chromeos::ShutdownButton* shutdown_button_;
-
- DISALLOW_COPY_AND_ASSIGN(GrabWidgetRootView);
-};
-
-// A child widget that grabs both keyboard and pointer input.
-class GrabWidget : public views::NativeWidgetGtk {
- public:
- explicit GrabWidget(chromeos::ScreenLocker* screen_locker)
- : views::NativeWidgetGtk(new views::Widget),
- screen_locker_(screen_locker),
- ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
- grab_failure_count_(0),
- kbd_grab_status_(GDK_GRAB_INVALID_TIME),
- mouse_grab_status_(GDK_GRAB_INVALID_TIME),
- signout_link_(NULL),
- shutdown_(NULL) {
- }
-
- virtual void Show() OVERRIDE {
- views::NativeWidgetGtk::Show();
- signout_link_ =
- screen_locker_->GetViewByID(VIEW_ID_SCREEN_LOCKER_SIGNOUT_LINK);
- shutdown_ = screen_locker_->GetViewByID(VIEW_ID_SCREEN_LOCKER_SHUTDOWN);
- // These can be null in guest mode.
- }
-
- void ClearGtkGrab() {
- GtkWidget* current_grab_window;
- // Grab gtk input first so that the menu holding gtk grab will
- // close itself.
- gtk_grab_add(window_contents());
-
- // Make sure there is no gtk grab widget so that gtk simply propagates
- // an event. This is necessary to allow message bubble and password
- // field, button to process events simultaneously. GTK
- // maintains grab widgets in a linked-list, so we need to remove
- // until it's empty.
- while ((current_grab_window = gtk_grab_get_current()) != NULL)
- gtk_grab_remove(current_grab_window);
- }
-
- virtual gboolean OnEventKey(GtkWidget* widget, GdkEventKey* event) OVERRIDE {
- views::KeyEvent key_event(reinterpret_cast<GdkEvent*>(event));
- // This is a hack to workaround the issue crosbug.com/10655 due to
- // the limitation that a focus manager cannot handle views in
- // TYPE_CHILD NativeWidgetGtk correctly.
- if (signout_link_ &&
- event->type == GDK_KEY_PRESS &&
- (event->keyval == GDK_Tab ||
- event->keyval == GDK_ISO_Left_Tab ||
- event->keyval == GDK_KP_Tab)) {
- DCHECK(shutdown_);
- bool reverse = event->state & GDK_SHIFT_MASK;
- if (reverse && signout_link_->HasFocus()) {
- shutdown_->RequestFocus();
- return true;
- }
- if (!reverse && shutdown_->HasFocus()) {
- signout_link_->RequestFocus();
- return true;
- }
- }
- return views::NativeWidgetGtk::OnEventKey(widget, event);
- }
-
- virtual gboolean OnButtonPress(GtkWidget* widget,
- GdkEventButton* event) OVERRIDE {
- NativeWidgetGtk::OnButtonPress(widget, event);
- // Never propagate event to parent.
- return true;
- }
-
- // Try to grab all inputs. It initiates another try if it fails to
- // grab and the retry count is within a limit, or fails with CHECK.
- void TryGrabAllInputs();
-
- // This method tries to steal pointer/keyboard grab from other
- // client by sending events that will hopefully close menus or windows
- // that have the grab.
- void TryUngrabOtherClients();
-
- private:
- virtual void HandleGtkGrabBroke() OVERRIDE {
- // Input should never be stolen from ScreenLocker once it's
- // grabbed. If this happens, it's a bug and has to be fixed. We
- // let chrome crash to get a crash report and dump, and
- // SessionManager will terminate the session to logout.
- CHECK_NE(GDK_GRAB_SUCCESS, kbd_grab_status_);
- CHECK_NE(GDK_GRAB_SUCCESS, mouse_grab_status_);
- }
-
- // Define separate methods for each error code so that stack trace
- // will tell which error the grab failed with.
- void FailedWithGrabAlreadyGrabbed() {
- LOG(FATAL) << "Grab already grabbed";
- }
- void FailedWithGrabInvalidTime() {
- LOG(FATAL) << "Grab invalid time";
- }
- void FailedWithGrabNotViewable() {
- LOG(FATAL) << "Grab not viewable";
- }
- void FailedWithGrabFrozen() {
- LOG(FATAL) << "Grab frozen";
- }
- void FailedWithUnknownError() {
- LOG(FATAL) << "Grab uknown";
- }
-
- chromeos::ScreenLocker* screen_locker_;
- base::WeakPtrFactory<GrabWidget> weak_factory_;
-
- // The number times the widget tried to grab all focus.
- int grab_failure_count_;
- // Status of keyboard and mouse grab.
- GdkGrabStatus kbd_grab_status_;
- GdkGrabStatus mouse_grab_status_;
-
- views::View* signout_link_;
- views::View* shutdown_;
-
- DISALLOW_COPY_AND_ASSIGN(GrabWidget);
-};
-
-void GrabWidget::TryGrabAllInputs() {
- // Grab x server so that we can atomically grab and take
- // action when grab fails.
- gdk_x11_grab_server();
- if (kbd_grab_status_ != GDK_GRAB_SUCCESS) {
- kbd_grab_status_ = gdk_keyboard_grab(window_contents()->window, FALSE,
- GDK_CURRENT_TIME);
- }
- if (mouse_grab_status_ != GDK_GRAB_SUCCESS) {
- mouse_grab_status_ =
- gdk_pointer_grab(window_contents()->window,
- FALSE,
- static_cast<GdkEventMask>(
- GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
- GDK_POINTER_MOTION_MASK),
- NULL,
- NULL,
- GDK_CURRENT_TIME);
- }
- if ((kbd_grab_status_ != GDK_GRAB_SUCCESS ||
- mouse_grab_status_ != GDK_GRAB_SUCCESS) &&
- grab_failure_count_++ < kMaxGrabFailures) {
- LOG(WARNING) << "Failed to grab inputs. Trying again in "
- << kRetryGrabIntervalMs << " ms: kbd="
- << kbd_grab_status_ << ", mouse=" << mouse_grab_status_;
- TryUngrabOtherClients();
- gdk_x11_ungrab_server();
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&GrabWidget::TryGrabAllInputs, weak_factory_.GetWeakPtr()),
- kRetryGrabIntervalMs);
- } else {
- gdk_x11_ungrab_server();
- GdkGrabStatus status = kbd_grab_status_;
- if (status == GDK_GRAB_SUCCESS) {
- status = mouse_grab_status_;
- }
- switch (status) {
- case GDK_GRAB_SUCCESS:
- break;
- case GDK_GRAB_ALREADY_GRABBED:
- FailedWithGrabAlreadyGrabbed();
- break;
- case GDK_GRAB_INVALID_TIME:
- FailedWithGrabInvalidTime();
- break;
- case GDK_GRAB_NOT_VIEWABLE:
- FailedWithGrabNotViewable();
- break;
- case GDK_GRAB_FROZEN:
- FailedWithGrabFrozen();
- break;
- default:
- FailedWithUnknownError();
- break;
- }
- DVLOG(1) << "Grab Success";
- screen_locker_->OnGrabInputs();
- }
-}
-
-void GrabWidget::TryUngrabOtherClients() {
-#if !defined(NDEBUG)
- {
- int event_base, error_base;
- int major, minor;
- // Make sure we have XTest extension.
- DCHECK(XTestQueryExtension(ui::GetXDisplay(),
- &event_base, &error_base,
- &major, &minor));
- }
-#endif
-
- // The following code is an attempt to grab inputs by closing
- // supposedly opened menu. This happens when a plugin has a menu
- // opened.
- if (mouse_grab_status_ == GDK_GRAB_ALREADY_GRABBED ||
- mouse_grab_status_ == GDK_GRAB_FROZEN) {
- // Successfully grabbed the keyboard, but pointer is still
- // grabbed by other client. Another attempt to close supposedly
- // opened menu by emulating keypress at the left top corner.
- Display* display = ui::GetXDisplay();
- Window root, child;
- int root_x, root_y, win_x, winy;
- unsigned int mask;
- XQueryPointer(display,
- ui::GetX11WindowFromGtkWidget(window_contents()),
- &root, &child, &root_x, &root_y,
- &win_x, &winy, &mask);
- XTestFakeMotionEvent(display, -1, -10000, -10000, CurrentTime);
- XTestFakeButtonEvent(display, 1, True, CurrentTime);
- XTestFakeButtonEvent(display, 1, False, CurrentTime);
- // Move the pointer back.
- XTestFakeMotionEvent(display, -1, root_x, root_y, CurrentTime);
- XFlush(display);
- } else if (kbd_grab_status_ == GDK_GRAB_ALREADY_GRABBED ||
- kbd_grab_status_ == GDK_GRAB_FROZEN) {
- // Successfully grabbed the pointer, but keyboard is still grabbed
- // by other client. Another attempt to close supposedly opened
- // menu by emulating escape key. Such situation must be very
- // rare, but handling this just in case
- Display* display = ui::GetXDisplay();
- KeyCode escape = XKeysymToKeycode(display, XK_Escape);
- XTestFakeKeyEvent(display, escape, True, CurrentTime);
- XTestFakeKeyEvent(display, escape, False, CurrentTime);
- XFlush(display);
- }
-}
-
-// BackgroundView for ScreenLocker, which layouts a lock widget in
-// addition to other background components.
-class ScreenLockerBackgroundView
- : public chromeos::BackgroundView,
- public chromeos::ScreenLocker::ScreenLockViewContainer {
- public:
- ScreenLockerBackgroundView(views::Widget* lock_widget,
- views::View* screen_lock_view)
- : lock_widget_(lock_widget),
- screen_lock_view_(screen_lock_view) {
- }
-
- virtual ScreenMode GetScreenMode() const OVERRIDE {
- return kScreenLockerMode;
- }
-
- virtual void Layout() OVERRIDE {
- chromeos::BackgroundView::Layout();
- gfx::Rect screen = bounds();
- if (screen_lock_view_) {
- gfx::Size size = screen_lock_view_->GetPreferredSize();
- gfx::Point origin((screen.width() - size.width()) / 2,
- (screen.height() - size.height()) / 2);
- gfx::Size widget_size(screen.size());
- widget_size.Enlarge(-origin.x(), -origin.y());
- lock_widget_->SetBounds(gfx::Rect(widget_size));
- } else {
- // No password entry. Move the lock widget to off screen.
- lock_widget_->SetBounds(gfx::Rect(-100, -100, 1, 1));
- }
- }
-
- // ScreenLocker::ScreenLockViewContainer implementation:
- virtual void SetScreenLockView(views::View* screen_lock_view) OVERRIDE {
- screen_lock_view_ = screen_lock_view;
- Layout();
- }
-
- private:
- views::Widget* lock_widget_;
-
- views::View* screen_lock_view_;
-
- DISALLOW_COPY_AND_ASSIGN(ScreenLockerBackgroundView);
-};
-
} // namespace
namespace chromeos {
@@ -580,174 +181,11 @@ namespace chromeos {
// static
ScreenLocker* ScreenLocker::screen_locker_ = NULL;
-// A event observer that forwards gtk events from one window to another.
-// See screen_locker.h for more details.
-class MouseEventRelay : public MessageLoopForUI::Observer {
- public:
- MouseEventRelay(GdkWindow* src, GdkWindow* dest)
- : src_(src),
- dest_(dest),
- initialized_(false) {
- DCHECK(src_);
- DCHECK(dest_);
- }
-
- virtual void WillProcessEvent(GdkEvent* event) OVERRIDE {}
-
- virtual void DidProcessEvent(GdkEvent* event) OVERRIDE {
- if (event->any.window != src_)
- return;
- if (!initialized_) {
- gint src_x, src_y, dest_x, dest_y, width, height, depth;
- gdk_window_get_geometry(dest_, &dest_x, &dest_y, &width, &height, &depth);
- // wait to compute offset until the info bubble widget's location
- // is available.
- if (dest_x < 0 || dest_y < 0)
- return;
- gdk_window_get_geometry(src_, &src_x, &src_y, &width, &height, &depth);
- offset_.SetPoint(dest_x - src_x, dest_y - src_y);
- initialized_ = true;
- }
- if (event->type == GDK_BUTTON_PRESS ||
- event->type == GDK_BUTTON_RELEASE) {
- GdkEvent* copy = gdk_event_copy(event);
- copy->button.window = dest_;
- g_object_ref(copy->button.window);
- copy->button.x -= offset_.x();
- copy->button.y -= offset_.y();
-
- gdk_event_put(copy);
- gdk_event_free(copy);
- } else if (event->type == GDK_MOTION_NOTIFY) {
- GdkEvent* copy = gdk_event_copy(event);
- copy->motion.window = dest_;
- g_object_ref(copy->motion.window);
- copy->motion.x -= offset_.x();
- copy->motion.y -= offset_.y();
-
- gdk_event_put(copy);
- gdk_event_free(copy);
- }
- }
-
- private:
- GdkWindow* src_;
- GdkWindow* dest_;
- bool initialized_;
-
- // Offset from src_'s origin to dest_'s origin.
- gfx::Point offset_;
-
- DISALLOW_COPY_AND_ASSIGN(MouseEventRelay);
-};
-
-// A event observer used to unlock the screen upon user's action
-// without asking password. Used in BWSI and auto login mode.
-// TODO(oshima): consolidate InputEventObserver and LockerInputEventObserver.
-class InputEventObserver : public MessageLoopForUI::Observer {
- public:
- explicit InputEventObserver(ScreenLocker* screen_locker)
- : screen_locker_(screen_locker),
- activated_(false) {
- }
-
-#if defined(TOUCH_UI)
- virtual base::EventStatus WillProcessEvent(
- const base::NativeEvent& event) OVERRIDE {
- return base::EVENT_CONTINUE;
- }
-
- virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE {
- }
-#else
- virtual void WillProcessEvent(GdkEvent* event) OVERRIDE {
- if ((event->type == GDK_KEY_PRESS ||
- event->type == GDK_BUTTON_PRESS ||
- event->type == GDK_MOTION_NOTIFY) &&
- !activated_) {
- activated_ = true;
- std::string not_used_string;
- GaiaAuthConsumer::ClientLoginResult not_used;
- screen_locker_->OnLoginSuccess(not_used_string,
- not_used_string,
- not_used,
- false,
- false);
- }
- }
-
- virtual void DidProcessEvent(GdkEvent* event) OVERRIDE {
- }
-#endif
-
- private:
- chromeos::ScreenLocker* screen_locker_;
-
- bool activated_;
-
- DISALLOW_COPY_AND_ASSIGN(InputEventObserver);
-};
-
-// A event observer used to show the screen locker upon
-// user action: mouse or keyboard interactions.
-// TODO(oshima): this has to be disabled while authenticating.
-class LockerInputEventObserver : public MessageLoopForUI::Observer {
- public:
- explicit LockerInputEventObserver(ScreenLocker* screen_locker)
- : screen_locker_(screen_locker),
- ALLOW_THIS_IN_INITIALIZER_LIST(
- timer_(FROM_HERE,
- base::TimeDelta::FromSeconds(kScreenSaverIdleTimeout), this,
- &LockerInputEventObserver::StartScreenSaver)) {
- }
-
-#if defined(TOUCH_UI)
- virtual base::EventStatus WillProcessEvent(
- const base::NativeEvent& event) OVERRIDE {
- return base::EVENT_CONTINUE;
- }
-
- virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE {
- }
-#else
- virtual void WillProcessEvent(GdkEvent* event) OVERRIDE {
- if ((event->type == GDK_KEY_PRESS ||
- event->type == GDK_BUTTON_PRESS ||
- event->type == GDK_MOTION_NOTIFY)) {
- timer_.Reset();
- screen_locker_->StopScreenSaver();
- }
- }
-
- virtual void DidProcessEvent(GdkEvent* event) OVERRIDE {
- }
-#endif
-
- private:
- void StartScreenSaver() {
- screen_locker_->StartScreenSaver();
- }
-
- chromeos::ScreenLocker* screen_locker_;
- base::DelayTimer<LockerInputEventObserver> timer_;
-
- DISALLOW_COPY_AND_ASSIGN(LockerInputEventObserver);
-};
-
//////////////////////////////////////////////////////////////////////////////
// ScreenLocker, public:
ScreenLocker::ScreenLocker(const UserManager::User& user)
- : lock_window_(NULL),
- lock_widget_(NULL),
- screen_lock_view_(NULL),
- captcha_view_(NULL),
- grab_container_(NULL),
- background_container_(NULL),
- user_(user),
- error_info_(NULL),
- drawn_(false),
- input_grabbed_(false),
+ : user_(user),
// TODO(oshima): support auto login mode (this is not implemented yet)
// http://crosbug.com/1881
unlock_on_input_(user_.email().empty()),
@@ -759,107 +197,12 @@ ScreenLocker::ScreenLocker(const UserManager::User& user)
}
void ScreenLocker::Init() {
- static const GdkColor kGdkBlack = {0, 0, 0, 0};
-
authenticator_ = LoginUtils::Get()->CreateAuthenticator(this);
-
- gfx::Point left_top(1, 1);
- gfx::Rect init_bounds(gfx::Screen::GetMonitorAreaNearestPoint(left_top));
-
- LockWindow* lock_window = new LockWindow();
- lock_window_ = lock_window->GetWidget();
- views::Widget::InitParams params(
- views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
- params.bounds = init_bounds;
- params.native_widget = lock_window;
- lock_window_->Init(params);
- gtk_widget_modify_bg(
- lock_window_->GetNativeView(), GTK_STATE_NORMAL, &kGdkBlack);
-
- g_signal_connect(lock_window_->GetNativeView(), "client-event",
- G_CALLBACK(OnClientEventThunk), this);
-
- // GTK does not like zero width/height.
- if (!unlock_on_input_) {
- screen_lock_view_ = new ScreenLockView(this);
- screen_lock_view_->Init();
- screen_lock_view_->SetEnabled(false);
- screen_lock_view_->StartThrobber();
- } else {
- input_event_observer_.reset(new InputEventObserver(this));
- MessageLoopForUI::current()->AddObserver(input_event_observer_.get());
- }
-
- // Hang on to a cast version of the grab widget so we can call its
- // TryGrabAllInputs() method later. (Nobody else needs to use it, so moving
- // its declaration to the header instead of keeping it in an anonymous
- // namespace feels a bit ugly.)
- GrabWidget* grab_widget = new GrabWidget(this);
- lock_widget_ = grab_widget->GetWidget();
- views::Widget::InitParams lock_params(
- views::Widget::InitParams::TYPE_CONTROL);
- lock_params.transparent = true;
- lock_params.parent_widget = lock_window_;
- lock_params.native_widget = grab_widget;
- lock_widget_->Init(lock_params);
- if (screen_lock_view_) {
- GrabWidgetRootView* root_view = new GrabWidgetRootView(screen_lock_view_);
- grab_container_ = root_view;
- lock_widget_->SetContentsView(root_view);
- }
- lock_widget_->Show();
-
- // Configuring the background url.
- std::string url_string =
- CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kScreenSaverUrl);
- ScreenLockerBackgroundView* screen_lock_background_view_ =
- new ScreenLockerBackgroundView(lock_widget_, screen_lock_view_);
- background_container_ = screen_lock_background_view_;
- background_view_ = screen_lock_background_view_;
- background_view_->Init(GURL(url_string));
-
- // Gets user profile and sets default user 24hour flag since we don't
- // expose user profile in ScreenLockerBackgroundView.
- Profile* profile = ProfileManager::GetDefaultProfile();
- if (profile) {
- background_view_->SetDefaultUse24HourClock(
- profile->GetPrefs()->GetBoolean(prefs::kUse24HourClock));
- }
-
- if (background_view_->ScreenSaverEnabled())
- StartScreenSaver();
-
-#if defined(TOOLKIT_USES_GTK)
- DCHECK(GTK_WIDGET_REALIZED(lock_window_->GetNativeView()));
- WmIpc::instance()->SetWindowType(
- lock_window_->GetNativeView(),
- WM_IPC_WINDOW_CHROME_SCREEN_LOCKER,
- NULL);
-#endif
-
- lock_window_->SetContentsView(background_view_);
- lock_window_->Show();
-
- grab_widget->ClearGtkGrab();
-
- // Call this after lock_window_->Show(); otherwise the 1st invocation
- // of gdk_xxx_grab() will always fail.
- grab_widget->TryGrabAllInputs();
-
- // Add the window to its own group so that its grab won't be stolen if
- // gtk_grab_add() gets called on behalf on a non-screen-locker widget (e.g.
- // a modal dialog) -- see http://crosbug.com/8999. We intentionally do this
- // after calling ClearGtkGrab(), as want to be in the default window group
- // then so we can break any existing GTK grabs.
- GtkWindowGroup* window_group = gtk_window_group_new();
- gtk_window_group_add_window(window_group,
- GTK_WINDOW(lock_window_->GetNativeView()));
- g_object_unref(window_group);
-
- lock_window->set_toplevel_focus_widget(
- static_cast<views::NativeWidgetGtk*>(lock_widget_->native_widget())->
- window_contents());
+ if (UseWebUILockScreen())
+ delegate_.reset(new ScreenLockerWebUI(this));
+ else
+ delegate_.reset(new ScreenLockerViews(this));
+ delegate_->Init(unlock_on_input_);
}
void ScreenLocker::OnLoginFailure(const LoginFailure& error) {
@@ -895,7 +238,7 @@ void ScreenLocker::OnLoginFailure(const LoginFailure& error) {
msg += ASCIIToUTF16("\n") +
l10n_util::GetStringUTF16(IDS_LOGIN_ERROR_KEYBOARD_SWITCH_HINT);
- ShowErrorBubble(UTF16ToWide(msg), views::BubbleBorder::BOTTOM_LEFT);
+ delegate_->ShowErrorMessage(msg, false);
if (login_status_consumer_)
login_status_consumer_->OnLoginFailure(error);
@@ -934,54 +277,11 @@ void ScreenLocker::OnLoginSuccess(
using_oauth);
}
-void ScreenLocker::BubbleClosing(Bubble* bubble, bool closed_by_escape) {
- error_info_ = NULL;
- screen_lock_view_->SetSignoutEnabled(true);
- if (mouse_event_relay_.get()) {
- MessageLoopForUI::current()->RemoveObserver(mouse_event_relay_.get());
- mouse_event_relay_.reset();
- }
-}
-
-bool ScreenLocker::CloseOnEscape() {
- return true;
-}
-
-bool ScreenLocker::FadeInOnShow() {
- return false;
-}
-
-void ScreenLocker::OnLinkActivated(size_t index) {
-}
-
-void ScreenLocker::OnCaptchaEntered(const std::string& captcha) {
- // Captcha dialog is only shown when LoginPerformer instance exists,
- // i.e. blocking UI after password change is in place.
- DCHECK(LoginPerformer::default_performer());
- LoginPerformer::default_performer()->set_captcha(captcha);
-
- // ScreenLockView ownership is passed to grab_container_.
- // Need to save return value here so that compile
- // doesn't fail with "unused result" warning.
- views::View* view = secondary_view_.release();
- view = NULL;
- captcha_view_->SetVisible(false);
- grab_container_->SetScreenLockView(screen_lock_view_);
- background_container_->SetScreenLockView(screen_lock_view_);
- screen_lock_view_->SetVisible(true);
- screen_lock_view_->ClearAndSetFocusToPassword();
-
- // Take CaptchaView ownership now that it's removed from grab_container_.
- secondary_view_.reset(captcha_view_);
- ShowErrorMessage(postponed_error_message_, false);
- postponed_error_message_.clear();
-}
-
void ScreenLocker::Authenticate(const string16& password) {
authentication_start_time_ = base::Time::Now();
- screen_lock_view_->SetEnabled(false);
- screen_lock_view_->SetSignoutEnabled(false);
- screen_lock_view_->StartThrobber();
+ delegate_->SetInputEnabled(false);
+ delegate_->SetSignoutEnabled(false);
+ delegate_->OnAuthenticate();
// If LoginPerformer instance exists,
// initial online login phase is still active.
@@ -997,80 +297,38 @@ void ScreenLocker::Authenticate(const string16& password) {
}
}
+void ScreenLocker::ShowCaptchaAndErrorMessage(const GURL& captcha_url,
+ const string16& message) {
+ delegate_->ShowCaptchaAndErrorMessage(captcha_url, message);
+}
+
void ScreenLocker::ClearErrors() {
- if (error_info_) {
- error_info_->Close();
- error_info_ = NULL;
- }
+ delegate_->ClearErrors();
}
void ScreenLocker::EnableInput() {
- if (screen_lock_view_) {
- screen_lock_view_->SetEnabled(true);
- screen_lock_view_->ClearAndSetFocusToPassword();
- screen_lock_view_->StopThrobber();
- }
+ delegate_->SetInputEnabled(true);
}
void ScreenLocker::Signout() {
- if (!error_info_) {
- UserMetrics::RecordAction(UserMetricsAction("ScreenLocker_Signout"));
+ // TODO(flackr): For proper functionality, check if (error_info) is NULL.
+ delegate_->ClearErrors();
+ UserMetrics::RecordAction(UserMetricsAction("ScreenLocker_Signout"));
#if defined(TOOLKIT_USES_GTK)
- WmIpc::instance()->NotifyAboutSignout();
+ WmIpc::instance()->NotifyAboutSignout();
#endif
- if (CrosLibrary::Get()->EnsureLoaded()) {
- CrosLibrary::Get()->GetLoginLibrary()->StopSession("");
- }
-
- // Don't hide yet the locker because the chrome screen may become visible
- // briefly.
- }
-}
+ if (CrosLibrary::Get()->EnsureLoaded())
+ CrosLibrary::Get()->GetLoginLibrary()->StopSession("");
-void ScreenLocker::ShowCaptchaAndErrorMessage(const GURL& captcha_url,
- const std::wstring& message) {
- postponed_error_message_ = message;
- if (captcha_view_) {
- captcha_view_->SetCaptchaURL(captcha_url);
- } else {
- captcha_view_ = new CaptchaView(captcha_url, true);
- captcha_view_->Init();
- captcha_view_->set_delegate(this);
- }
- // CaptchaView ownership is passed to grab_container_.
- views::View* view = secondary_view_.release();
- view = NULL;
- screen_lock_view_->SetVisible(false);
- grab_container_->SetScreenLockView(captcha_view_);
- background_container_->SetScreenLockView(captcha_view_);
- captcha_view_->SetVisible(true);
- // Take ScreenLockView ownership now that it's removed from grab_container_.
- secondary_view_.reset(screen_lock_view_);
+ // Don't hide yet the locker because the chrome screen may become visible
+ // briefly.
}
-void ScreenLocker::ShowErrorMessage(const std::wstring& message,
+void ScreenLocker::ShowErrorMessage(const string16& message,
bool sign_out_only) {
- if (sign_out_only) {
- screen_lock_view_->SetEnabled(false);
- } else {
- EnableInput();
- }
- screen_lock_view_->SetSignoutEnabled(sign_out_only);
- // Make sure that active Sign Out button is not hidden behind the bubble.
- ShowErrorBubble(
- message, sign_out_only ?
- views::BubbleBorder::BOTTOM_RIGHT : views::BubbleBorder::BOTTOM_LEFT);
-}
-
-void ScreenLocker::OnGrabInputs() {
- DVLOG(1) << "OnGrabInputs";
- input_grabbed_ = true;
- if (drawn_)
- ScreenLockReady();
-}
-
-views::View* ScreenLocker::GetViewByID(int id) {
- return lock_widget_->GetRootView()->GetViewByID(id);
+ delegate_->SetInputEnabled(!sign_out_only);
+ delegate_->SetSignoutEnabled(sign_out_only);
+ delegate_->ShowErrorMessage(message, sign_out_only);
}
void ScreenLocker::SetLoginStatusConsumer(
@@ -1097,10 +355,13 @@ void ScreenLocker::Show() {
ScreenLocker* locker =
new ScreenLocker(UserManager::Get()->logged_in_user());
#if defined(TOUCH_UI)
- // The screen locker does not reliably work on TOUCH_UI builds. In order
- // to effectively "lock" the screen we will sign out the user for now.
+ // The views screen locker does not reliably work on TOUCH_UI builds. In
+ // order to effectively "lock" the screen we will sign out the user for now.
// TODO(flackr): Implement lock screen in WebUI and remove this hack.
- locker->Signout();
+ if (ScreenLocker::UseWebUILockScreen())
+ locker->Init();
+ else
+ locker->Signout();
#else
locker->Init();
#endif
@@ -1141,6 +402,12 @@ void ScreenLocker::UnlockScreenFailed() {
}
// static
+bool ScreenLocker::UseWebUILockScreen() {
+ return CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kWebUILockScreen);
+}
+
+// static
void ScreenLocker::InitClass() {
g_screen_lock_observer.Get();
}
@@ -1151,22 +418,7 @@ void ScreenLocker::InitClass() {
ScreenLocker::~ScreenLocker() {
DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI);
ClearErrors();
- if (input_event_observer_.get())
- MessageLoopForUI::current()->RemoveObserver(input_event_observer_.get());
- if (locker_input_event_observer_.get()) {
- lock_widget_->GetFocusManager()->UnregisterAccelerator(
- views::Accelerator(ui::VKEY_ESCAPE, false, false, false), this);
- MessageLoopForUI::current()->RemoveObserver(
- locker_input_event_observer_.get());
- }
- gdk_keyboard_ungrab(GDK_CURRENT_TIME);
- gdk_pointer_ungrab(GDK_CURRENT_TIME);
-
- DCHECK(lock_window_);
- VLOG(1) << "~ScreenLocker(): Closing ScreenLocker window.";
- lock_window_->Close();
- // lock_widget_ will be deleted by gtk's destroy signal.
screen_locker_ = NULL;
bool state = false;
NotificationService::current()->Notify(
@@ -1188,17 +440,6 @@ void ScreenLocker::ScreenLockReady() {
VLOG(1) << "Screen lock time: " << delta.InSecondsF();
UMA_HISTOGRAM_TIMES("ScreenLocker.ScreenLockTime", delta);
- if (background_view_->ScreenSaverEnabled()) {
- lock_widget_->GetFocusManager()->RegisterAccelerator(
- views::Accelerator(ui::VKEY_ESCAPE, false, false, false), this);
- locker_input_event_observer_.reset(new LockerInputEventObserver(this));
- MessageLoopForUI::current()->AddObserver(
- locker_input_event_observer_.get());
- } else {
- // Don't enable the password field until we grab all inputs.
- EnableInput();
- }
-
bool state = true;
NotificationService::current()->Notify(
chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED,
@@ -1208,87 +449,4 @@ void ScreenLocker::ScreenLockReady() {
CrosLibrary::Get()->GetScreenLockLibrary()->NotifyScreenLockCompleted();
}
-void ScreenLocker::OnClientEvent(GtkWidget* widge, GdkEventClient* event) {
-#if defined(TOOLKIT_USES_GTK)
- WmIpc::Message msg;
- WmIpc::instance()->DecodeMessage(*event, &msg);
- if (msg.type() == WM_IPC_MESSAGE_CHROME_NOTIFY_SCREEN_REDRAWN_FOR_LOCK) {
- OnWindowManagerReady();
- }
-#endif
-}
-
-void ScreenLocker::OnWindowManagerReady() {
- DVLOG(1) << "OnClientEvent: drawn for lock";
- drawn_ = true;
- if (input_grabbed_)
- ScreenLockReady();
-}
-
-void ScreenLocker::ShowErrorBubble(
- const std::wstring& message,
- views::BubbleBorder::ArrowLocation arrow_location) {
- if (error_info_)
- error_info_->Close();
-
- gfx::Rect rect = screen_lock_view_->GetPasswordBoundsRelativeTo(
- lock_widget_->GetRootView());
- gfx::Rect lock_widget_bounds = lock_widget_->GetClientAreaScreenBounds();
- rect.Offset(lock_widget_bounds.x(), lock_widget_bounds.y());
- error_info_ = MessageBubble::ShowNoGrab(
- lock_window_,
- rect,
- arrow_location,
- ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_WARNING),
- message,
- std::wstring(), // TODO(nkostylev): Add help link.
- this);
-
-#if !defined(TOUCH_UI)
- if (mouse_event_relay_.get())
- MessageLoopForUI::current()->RemoveObserver(mouse_event_relay_.get());
- mouse_event_relay_.reset(
- new MouseEventRelay(lock_widget_->GetNativeView()->window,
- error_info_->GetNativeView()->window));
- MessageLoopForUI::current()->AddObserver(mouse_event_relay_.get());
-#endif
-}
-
-void ScreenLocker::StopScreenSaver() {
- if (background_view_->IsScreenSaverVisible()) {
- VLOG(1) << "StopScreenSaver";
- if (screen_lock_view_) {
- screen_lock_view_->SetVisible(true);
- // Place the screen_lock_view_ to the center of the screen.
- // Must be called when the view is visible: crosbug.com/15213.
- background_view_->Layout();
- screen_lock_view_->RequestFocus();
- }
- background_view_->HideScreenSaver();
- EnableInput();
- }
-}
-
-void ScreenLocker::StartScreenSaver() {
- if (!background_view_->IsScreenSaverVisible()) {
- VLOG(1) << "StartScreenSaver";
- UserMetrics::RecordAction(
- UserMetricsAction("ScreenLocker_StartScreenSaver"));
- background_view_->ShowScreenSaver();
- if (screen_lock_view_) {
- screen_lock_view_->SetEnabled(false);
- screen_lock_view_->SetVisible(false);
- }
- ClearErrors();
- }
-}
-
-bool ScreenLocker::AcceleratorPressed(const views::Accelerator& accelerator) {
- if (!background_view_->IsScreenSaverVisible()) {
- StartScreenSaver();
- return true;
- }
- return false;
-}
-
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screen_locker.h b/chrome/browser/chromeos/login/screen_locker.h
index d226c8d..6991c64 100644
--- a/chrome/browser/chromeos/login/screen_locker.h
+++ b/chrome/browser/chromeos/login/screen_locker.h
@@ -11,9 +11,8 @@
#include "base/memory/scoped_ptr.h"
#include "base/task.h"
#include "base/time.h"
-#include "chrome/browser/chromeos/login/captcha_view.h"
#include "chrome/browser/chromeos/login/login_status_consumer.h"
-#include "chrome/browser/chromeos/login/message_bubble.h"
+#include "chrome/browser/chromeos/login/screen_locker_delegate.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "views/accelerator.h"
@@ -28,35 +27,17 @@ class View;
namespace chromeos {
class Authenticator;
-class BackgroundView;
-class InputEventObserver;
-class LockerInputEventObserver;
-class MessageBubble;
-class MouseEventRelay;
-class ScreenLockView;
class LoginFailure;
namespace test {
class ScreenLockerTester;
} // namespace test
-// ScreenLocker creates a background view as well as ScreenLockView to
-// authenticate the user. ScreenLocker manages its life cycle and will
-// delete itself when it's unlocked.
-class ScreenLocker : public LoginStatusConsumer,
- public MessageBubbleDelegate,
- public CaptchaView::Delegate,
- public views::AcceleratorTarget {
+// ScreenLocker creates a ScreenLockerDelegate which will display the lock UI.
+// As well, it takes care of authenticating the user and managing a global
+// instance of itself which will be deleted when the system is unlocked.
+class ScreenLocker : public LoginStatusConsumer {
public:
- // Interface that helps switching from ScreenLockView to CaptchaView.
- class ScreenLockViewContainer {
- public:
- virtual void SetScreenLockView(views::View* screen_lock_view) = 0;
-
- protected:
- virtual ~ScreenLockViewContainer() {}
- };
-
explicit ScreenLocker(const UserManager::User& user);
// Returns the default instance if it has been created.
@@ -80,15 +61,6 @@ class ScreenLocker : public LoginStatusConsumer,
bool pending_requests,
bool using_oauth) OVERRIDE;
- // Overridden from views::BubbleDelegate.
- virtual void BubbleClosing(Bubble* bubble, bool closed_by_escape) OVERRIDE;
- virtual bool CloseOnEscape() OVERRIDE;
- virtual bool FadeInOnShow() OVERRIDE;
- virtual void OnLinkActivated(size_t index) OVERRIDE;
-
- // CaptchaView::Delegate implementation:
- virtual void OnCaptchaEntered(const std::string& captcha) OVERRIDE;
-
// Authenticates the user with given |password| and authenticator.
void Authenticate(const string16& password);
@@ -104,15 +76,12 @@ class ScreenLocker : public LoginStatusConsumer,
// Present user a CAPTCHA challenge with image from |captcha_url|,
// After that shows error bubble with |message|.
void ShowCaptchaAndErrorMessage(const GURL& captcha_url,
- const std::wstring& message);
+ const string16& message);
// Disables all UI needed and shows error bubble with |message|.
// If |sign_out_only| is true then all other input except "Sign Out"
// button is blocked.
- void ShowErrorMessage(const std::wstring& message, bool sign_out_only);
-
- // Called when the all inputs are grabbed.
- void OnGrabInputs();
+ void ShowErrorMessage(const string16& message, bool sign_out_only);
#if defined(TOOLKIT_USES_GTK)
// Returns the user to authenticate.
@@ -121,9 +90,6 @@ class ScreenLocker : public LoginStatusConsumer,
}
#endif
- // Returns a view that has given view |id|, or null if it doesn't exist.
- views::View* GetViewByID(int id);
-
// Allow a LoginStatusConsumer to listen for
// the same login events that ScreenLocker does.
void SetLoginStatusConsumer(chromeos::LoginStatusConsumer* consumer);
@@ -139,17 +105,21 @@ class ScreenLocker : public LoginStatusConsumer,
// Hide the screen locker.
static void Hide();
+ // Queries the value of the webui lock screen flag.
+ static bool UseWebUILockScreen();
+
// Notifies that PowerManager rejected UnlockScreen request.
static void UnlockScreenFailed();
#if defined(TOOLKIT_USES_GTK)
// Returns the tester
static test::ScreenLockerTester* GetTester();
+#endif
private:
friend class DeleteTask<ScreenLocker>;
friend class test::ScreenLockerTester;
- friend class LockerInputEventObserver;
+ friend class ScreenLockerDelegate;
virtual ~ScreenLocker();
@@ -159,83 +129,16 @@ class ScreenLocker : public LoginStatusConsumer,
// Called when the screen lock is ready.
void ScreenLockReady();
- // Called when the window manager is ready to handle locked state.
- void OnWindowManagerReady();
-
- // Shows error_info_ bubble with the |message| and |arrow_location| specified.
- // Assumes that UI controls were locked before that.
- void ShowErrorBubble(const std::wstring& message,
- views::BubbleBorder::ArrowLocation arrow_location);
-
- // Stops screen saver.
- void StopScreenSaver();
-
- // Starts screen saver.
- void StartScreenSaver();
-
- // Overridden from AcceleratorTarget:
- virtual bool AcceleratorPressed(const views::Accelerator& accelerator);
-
- // Event handler for client-event.
- CHROMEGTK_CALLBACK_1(ScreenLocker, void, OnClientEvent, GdkEventClient*);
-
- // The screen locker window.
- views::Widget* lock_window_;
-
- // Child widget to grab the keyboard/mouse input.
- views::Widget* lock_widget_;
-
- // A view that accepts password.
- ScreenLockView* screen_lock_view_;
-
- // A view that can display html page as background.
- BackgroundView* background_view_;
-
- // View used to present CAPTCHA challenge input.
- CaptchaView* captcha_view_;
-
- // Containers that hold currently visible view.
- // Initially it's ScreenLockView instance.
- // When CAPTCHA input dialog is presented it's swapped to CaptchaView
- // instance, then back after CAPTCHA input is done.
- ScreenLockViewContainer* grab_container_;
- ScreenLockViewContainer* background_container_;
-
- // View that's not owned by grab_container_ - either ScreenLockView or
- // CaptchaView instance. Keep that under scoped_ptr so that it's deleted.
- scoped_ptr<views::View> secondary_view_;
-
- // Postponed error message to be shown after CAPTCHA input is done.
- std::wstring postponed_error_message_;
+ // ScreenLockerDelegate instance in use.
+ scoped_ptr<ScreenLockerDelegate> delegate_;
// Logged in user.
UserManager::User user_;
+#if defined(TOOLKIT_USES_GTK)
// Used to authenticate the user to unlock.
scoped_refptr<Authenticator> authenticator_;
-
- // ScreenLocker grabs all keyboard and mouse events on its
- // gdk window and never let other gdk_window to handle inputs.
- // This MouseEventRelay object is used to forward events to
- // the message bubble's gdk_window so that close button works.
- scoped_ptr<MouseEventRelay> mouse_event_relay_;
-
- // A message loop observer to detect user's keyboard/mouse event.
- // Used when |unlock_on_input_| is true.
- scoped_ptr<InputEventObserver> input_event_observer_;
-
- // A message loop observer to detect user's keyboard/mouse event.
- // Used when to show the screen locker upon such an event.
- scoped_ptr<LockerInputEventObserver> locker_input_event_observer_;
-
- // An info bubble to display login failure message.
- MessageBubble* error_info_;
-
- // True if the screen locker's window has been drawn.
- bool drawn_;
-
- // True if both mouse input and keyboard input are grabbed.
- bool input_grabbed_;
+#endif
// Unlock the screen when it detects key/mouse event without asking
// password. True when chrome is in BWSI or auto login mode.
@@ -259,8 +162,6 @@ class ScreenLocker : public LoginStatusConsumer,
// Tests can use this to receive login status events.
LoginStatusConsumer* login_status_consumer_;
-#endif // TOOLKIT_USES_GTK
-
DISALLOW_COPY_AND_ASSIGN(ScreenLocker);
};
diff --git a/chrome/browser/chromeos/login/screen_locker_browsertest.cc b/chrome/browser/chromeos/login/screen_locker_browsertest.cc
index b03517e..3d8c25f 100644
--- a/chrome/browser/chromeos/login/screen_locker_browsertest.cc
+++ b/chrome/browser/chromeos/login/screen_locker_browsertest.cc
@@ -23,6 +23,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "views/controls/textfield/textfield.h"
+#include "views/widget/native_widget_gtk.h"
namespace {
diff --git a/chrome/browser/chromeos/login/screen_locker_delegate.cc b/chrome/browser/chromeos/login/screen_locker_delegate.cc
new file mode 100644
index 0000000..c6b9813
--- /dev/null
+++ b/chrome/browser/chromeos/login/screen_locker_delegate.cc
@@ -0,0 +1,21 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/login/screen_locker.h"
+#include "chrome/browser/chromeos/login/screen_locker_delegate.h"
+
+namespace chromeos {
+
+ScreenLockerDelegate::ScreenLockerDelegate(ScreenLocker* screen_locker)
+ : screen_locker_(screen_locker) {
+}
+
+ScreenLockerDelegate::~ScreenLockerDelegate() {
+}
+
+void ScreenLockerDelegate::ScreenLockReady() {
+ screen_locker_->ScreenLockReady();
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screen_locker_delegate.h b/chrome/browser/chromeos/login/screen_locker_delegate.h
new file mode 100644
index 0000000..bc0a602
--- /dev/null
+++ b/chrome/browser/chromeos/login/screen_locker_delegate.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCKER_DELEGATE_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCKER_DELEGATE_H_
+#pragma once
+
+#include "base/string16.h"
+
+namespace chromeos {
+
+class ScreenLocker;
+
+// ScreenLockerDelegate takes care of displaying the lock screen UI.
+class ScreenLockerDelegate {
+ public:
+ explicit ScreenLockerDelegate(ScreenLocker* screen_locker);
+ virtual ~ScreenLockerDelegate();
+
+ // Initialize the screen locker delegate. This will call ScreenLockReady when
+ // done to notify ScreenLocker.
+ virtual void Init(bool unlock_on_input) = 0;
+
+ // Inform the screen locker that the screen has been locked
+ virtual void ScreenLockReady();
+
+ // This function is called when ScreenLocker::Authenticate is called to
+ // attempt to authenticate with a given password.
+ virtual void OnAuthenticate() = 0;
+
+ // Enable/disable password input.
+ virtual void SetInputEnabled(bool enabled) = 0;
+
+ // Enable/disable signout.
+ virtual void SetSignoutEnabled(bool enabled) = 0;
+
+ // Disables all UI needed and shows error bubble with |message|.
+ // If |sign_out_only| is true then all other input except "Sign Out"
+ // button is blocked.
+ virtual void ShowErrorMessage(const string16& message,
+ bool sign_out_only) = 0;
+
+ // Present user a CAPTCHA challenge with image from |captcha_url|,
+ // After that shows error bubble with |message|.
+ virtual void ShowCaptchaAndErrorMessage(const GURL& captcha_url,
+ const string16& message) = 0;
+
+ // Close message bubble to clear error messages.
+ virtual void ClearErrors() = 0;
+
+ protected:
+ // ScreenLocker that owns this delegate.
+ ScreenLocker* screen_locker_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenLockerDelegate);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCKER_DELEGATE_H_
diff --git a/chrome/browser/chromeos/login/screen_locker_tester.cc b/chrome/browser/chromeos/login/screen_locker_tester.cc
index 81b41b5..2043f84 100644
--- a/chrome/browser/chromeos/login/screen_locker_tester.cc
+++ b/chrome/browser/chromeos/login/screen_locker_tester.cc
@@ -11,6 +11,7 @@
#include "chrome/browser/chromeos/login/mock_authenticator.h"
#include "chrome/browser/chromeos/login/screen_lock_view.h"
#include "chrome/browser/chromeos/login/screen_locker.h"
+#include "chrome/browser/chromeos/login/screen_locker_views.h"
#include "views/controls/button/button.h"
#include "views/controls/label.h"
#include "views/controls/textfield/textfield.h"
@@ -55,29 +56,36 @@ void ScreenLockerTester::EnterPassword(const std::string& password) {
GdkEvent* event = gdk_event_new(GDK_KEY_PRESS);
event->key.keyval = GDK_Return;
views::KeyEvent key_event(event);
- ScreenLocker::screen_locker_->screen_lock_view_->HandleKeyEvent(
- pass, key_event);
+ screen_locker_views()->screen_lock_view_->HandleKeyEvent(pass, key_event);
gdk_event_free(event);
}
void ScreenLockerTester::EmulateWindowManagerReady() {
DCHECK(ScreenLocker::screen_locker_);
- ScreenLocker::screen_locker_->OnWindowManagerReady();
+ screen_locker_views()->OnWindowManagerReady();
}
views::Textfield* ScreenLockerTester::GetPasswordField() const {
DCHECK(ScreenLocker::screen_locker_);
- return ScreenLocker::screen_locker_->screen_lock_view_->password_field_;
+ return screen_locker_views()->screen_lock_view_->password_field_;
}
views::Widget* ScreenLockerTester::GetWidget() const {
DCHECK(ScreenLocker::screen_locker_);
- return ScreenLocker::screen_locker_->lock_window_;
+ return screen_locker_views()->lock_window_;
}
views::Widget* ScreenLockerTester::GetChildWidget() const {
DCHECK(ScreenLocker::screen_locker_);
- return ScreenLocker::screen_locker_->lock_widget_;
+ return screen_locker_views()->lock_widget_;
+}
+
+ScreenLockerViews* ScreenLockerTester::screen_locker_views() const {
+ DCHECK(ScreenLocker::screen_locker_);
+ // TODO(flackr): Generalize testing infrastructure to work with WebUI.
+ DCHECK(!ScreenLocker::UseWebUILockScreen());
+ return static_cast<ScreenLockerViews*>(
+ ScreenLocker::screen_locker_->delegate_.get());
}
} // namespace test
diff --git a/chrome/browser/chromeos/login/screen_locker_tester.h b/chrome/browser/chromeos/login/screen_locker_tester.h
index dc362fa..19975fc 100644
--- a/chrome/browser/chromeos/login/screen_locker_tester.h
+++ b/chrome/browser/chromeos/login/screen_locker_tester.h
@@ -19,6 +19,7 @@ class Widget;
namespace chromeos {
class ScreenLocker;
+class ScreenLockerViews;
namespace test {
@@ -50,6 +51,9 @@ class ScreenLockerTester {
views::Widget* GetChildWidget() const;
+ // Returns the ScreenLockerViews object.
+ ScreenLockerViews* screen_locker_views() const;
+
private:
friend class chromeos::ScreenLocker;
diff --git a/chrome/browser/chromeos/login/screen_locker_views.cc b/chrome/browser/chromeos/login/screen_locker_views.cc
new file mode 100644
index 0000000..d0606f5
--- /dev/null
+++ b/chrome/browser/chromeos/login/screen_locker_views.cc
@@ -0,0 +1,936 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/login/screen_locker_views.h"
+
+#include <X11/extensions/XTest.h>
+#include <X11/keysym.h>
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdkx.h>
+
+// Evil hack to undo X11 evil #define.
+#undef None
+#undef Status
+
+#include "base/command_line.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/chromeos/login/background_view.h"
+#include "chrome/browser/chromeos/login/login_performer.h"
+#include "chrome/browser/chromeos/login/message_bubble.h"
+#include "chrome/browser/chromeos/login/screen_lock_view.h"
+#include "chrome/browser/chromeos/login/screen_locker.h"
+#include "chrome/browser/chromeos/login/shutdown_button.h"
+#include "chrome/browser/chromeos/view_ids.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
+#include "content/browser/user_metrics.h"
+#include "grit/theme_resources.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/gfx/screen.h"
+
+#if defined(TOOLKIT_USES_GTK)
+#include "chrome/browser/chromeos/wm_ipc.h"
+#endif
+
+namespace {
+
+// The active ScreenLockerDelegate.
+chromeos::ScreenLockerViews* screen_locker_view_ = NULL;
+
+// The maximum duration for which locker should try to grab the keyboard and
+// mouse and its interval for regrabbing on failure.
+const int kMaxGrabFailureSec = 30;
+const int64 kRetryGrabIntervalMs = 500;
+
+// Maximum number of times we'll try to grab the keyboard and mouse before
+// giving up. If we hit the limit, Chrome exits and the session is terminated.
+const int kMaxGrabFailures = kMaxGrabFailureSec * 1000 / kRetryGrabIntervalMs;
+
+// A idle time to show the screen saver in seconds.
+const int kScreenSaverIdleTimeout = 15;
+
+// A ScreenLock window that covers entire screen to keep the keyboard
+// focus/events inside the grab widget.
+class LockWindow : public views::NativeWidgetGtk {
+ public:
+ LockWindow()
+ : views::NativeWidgetGtk(new views::Widget),
+ toplevel_focus_widget_(NULL) {
+ EnableDoubleBuffer(true);
+ }
+
+ // GTK propagates key events from parents to children.
+ // Make sure LockWindow will never handle key events.
+ virtual gboolean OnEventKey(GtkWidget* widget, GdkEventKey* event) OVERRIDE {
+ // Don't handle key event in the lock window.
+ return false;
+ }
+
+ virtual gboolean OnButtonPress(GtkWidget* widget,
+ GdkEventButton* event) OVERRIDE {
+ // Don't handle mouse event in the lock wnidow and
+ // nor propagate to child.
+ return true;
+ }
+
+ virtual void OnDestroy(GtkWidget* object) OVERRIDE {
+ VLOG(1) << "OnDestroy: LockWindow destroyed";
+ views::NativeWidgetGtk::OnDestroy(object);
+ }
+
+ virtual void ClearNativeFocus() OVERRIDE {
+ DCHECK(toplevel_focus_widget_);
+ gtk_widget_grab_focus(toplevel_focus_widget_);
+ }
+
+ // Sets the widget to move the focus to when clearning the native
+ // widget's focus.
+ void set_toplevel_focus_widget(GtkWidget* widget) {
+ gtk_widget_set_can_focus(widget, TRUE);
+ toplevel_focus_widget_ = widget;
+ }
+
+ private:
+ // The widget we set focus to when clearning the focus on native
+ // widget. In screen locker, gdk input is grabbed in GrabWidget,
+ // and resetting the focus by using gtk_window_set_focus seems to
+ // confuse gtk and doesn't let focus move to native widget under
+ // GrabWidget.
+ GtkWidget* toplevel_focus_widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(LockWindow);
+};
+
+// GrabWidget's root view to layout the ScreenLockView at the center
+// and the Shutdown button at the left top.
+class GrabWidgetRootView
+ : public views::View,
+ public chromeos::ScreenLockerViews::ScreenLockViewContainer {
+ public:
+ explicit GrabWidgetRootView(chromeos::ScreenLockView* screen_lock_view)
+ : screen_lock_view_(screen_lock_view),
+ shutdown_button_(new chromeos::ShutdownButton()) {
+ shutdown_button_->Init();
+ AddChildView(screen_lock_view_);
+ AddChildView(shutdown_button_);
+ }
+
+ // views::View implementation.
+ virtual void Layout() OVERRIDE {
+ gfx::Size size = screen_lock_view_->GetPreferredSize();
+ gfx::Rect b = bounds();
+ screen_lock_view_->SetBounds(
+ b.width() - size.width(), b.height() - size.height(),
+ size.width(), size.height());
+ shutdown_button_->LayoutIn(this);
+ }
+
+ // ScreenLockerViews::ScreenLockViewContainer implementation:
+ void SetScreenLockView(views::View* screen_lock_view) OVERRIDE {
+ if (screen_lock_view_) {
+ RemoveChildView(screen_lock_view_);
+ }
+ screen_lock_view_ = screen_lock_view;
+ if (screen_lock_view_) {
+ AddChildViewAt(screen_lock_view_, 0);
+ }
+ Layout();
+ }
+
+ private:
+ views::View* screen_lock_view_;
+
+ chromeos::ShutdownButton* shutdown_button_;
+
+ DISALLOW_COPY_AND_ASSIGN(GrabWidgetRootView);
+};
+
+// A child widget that grabs both keyboard and pointer input.
+class GrabWidget : public views::NativeWidgetGtk {
+ public:
+ explicit GrabWidget(chromeos::ScreenLocker* screen_locker)
+ : views::NativeWidgetGtk(new views::Widget),
+ screen_locker_(screen_locker),
+ ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
+ grab_failure_count_(0),
+ kbd_grab_status_(GDK_GRAB_INVALID_TIME),
+ mouse_grab_status_(GDK_GRAB_INVALID_TIME),
+ signout_link_(NULL),
+ shutdown_(NULL) {
+ }
+
+ virtual void Show() OVERRIDE {
+ views::NativeWidgetGtk::Show();
+ signout_link_ =
+ screen_locker_view_->GetViewByID(VIEW_ID_SCREEN_LOCKER_SIGNOUT_LINK);
+ shutdown_ = screen_locker_view_->GetViewByID(
+ VIEW_ID_SCREEN_LOCKER_SHUTDOWN);
+ // These can be null in guest mode.
+ }
+
+ void ClearGtkGrab() {
+ GtkWidget* current_grab_window;
+ // Grab gtk input first so that the menu holding gtk grab will
+ // close itself.
+ gtk_grab_add(window_contents());
+
+ // Make sure there is no gtk grab widget so that gtk simply propagates
+ // an event. This is necessary to allow message bubble and password
+ // field, button to process events simultaneously. GTK
+ // maintains grab widgets in a linked-list, so we need to remove
+ // until it's empty.
+ while ((current_grab_window = gtk_grab_get_current()) != NULL)
+ gtk_grab_remove(current_grab_window);
+ }
+
+ virtual gboolean OnEventKey(GtkWidget* widget, GdkEventKey* event) OVERRIDE {
+ views::KeyEvent key_event(reinterpret_cast<GdkEvent*>(event));
+ // This is a hack to workaround the issue crosbug.com/10655 due to
+ // the limitation that a focus manager cannot handle views in
+ // TYPE_CHILD NativeWidgetGtk correctly.
+ if (signout_link_ &&
+ event->type == GDK_KEY_PRESS &&
+ (event->keyval == GDK_Tab ||
+ event->keyval == GDK_ISO_Left_Tab ||
+ event->keyval == GDK_KP_Tab)) {
+ DCHECK(shutdown_);
+ bool reverse = event->state & GDK_SHIFT_MASK;
+ if (reverse && signout_link_->HasFocus()) {
+ shutdown_->RequestFocus();
+ return true;
+ }
+ if (!reverse && shutdown_->HasFocus()) {
+ signout_link_->RequestFocus();
+ return true;
+ }
+ }
+ return views::NativeWidgetGtk::OnEventKey(widget, event);
+ }
+
+ virtual gboolean OnButtonPress(GtkWidget* widget,
+ GdkEventButton* event) OVERRIDE {
+ NativeWidgetGtk::OnButtonPress(widget, event);
+ // Never propagate event to parent.
+ return true;
+ }
+
+ // Try to grab all inputs. It initiates another try if it fails to
+ // grab and the retry count is within a limit, or fails with CHECK.
+ void TryGrabAllInputs();
+
+ // This method tries to steal pointer/keyboard grab from other
+ // client by sending events that will hopefully close menus or windows
+ // that have the grab.
+ void TryUngrabOtherClients();
+
+ private:
+ virtual void HandleGtkGrabBroke() OVERRIDE {
+ // Input should never be stolen from ScreenLocker once it's
+ // grabbed. If this happens, it's a bug and has to be fixed. We
+ // let chrome crash to get a crash report and dump, and
+ // SessionManager will terminate the session to logout.
+ CHECK_NE(GDK_GRAB_SUCCESS, kbd_grab_status_);
+ CHECK_NE(GDK_GRAB_SUCCESS, mouse_grab_status_);
+ }
+
+ // Define separate methods for each error code so that stack trace
+ // will tell which error the grab failed with.
+ void FailedWithGrabAlreadyGrabbed() {
+ LOG(FATAL) << "Grab already grabbed";
+ }
+ void FailedWithGrabInvalidTime() {
+ LOG(FATAL) << "Grab invalid time";
+ }
+ void FailedWithGrabNotViewable() {
+ LOG(FATAL) << "Grab not viewable";
+ }
+ void FailedWithGrabFrozen() {
+ LOG(FATAL) << "Grab frozen";
+ }
+ void FailedWithUnknownError() {
+ LOG(FATAL) << "Grab uknown";
+ }
+
+ chromeos::ScreenLocker* screen_locker_;
+ base::WeakPtrFactory<GrabWidget> weak_factory_;
+
+ // The number times the widget tried to grab all focus.
+ int grab_failure_count_;
+ // Status of keyboard and mouse grab.
+ GdkGrabStatus kbd_grab_status_;
+ GdkGrabStatus mouse_grab_status_;
+
+ views::View* signout_link_;
+ views::View* shutdown_;
+
+ DISALLOW_COPY_AND_ASSIGN(GrabWidget);
+};
+
+void GrabWidget::TryGrabAllInputs() {
+ // Grab x server so that we can atomically grab and take
+ // action when grab fails.
+ gdk_x11_grab_server();
+ if (kbd_grab_status_ != GDK_GRAB_SUCCESS) {
+ kbd_grab_status_ = gdk_keyboard_grab(window_contents()->window, FALSE,
+ GDK_CURRENT_TIME);
+ }
+ if (mouse_grab_status_ != GDK_GRAB_SUCCESS) {
+ mouse_grab_status_ =
+ gdk_pointer_grab(window_contents()->window,
+ FALSE,
+ static_cast<GdkEventMask>(
+ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK),
+ NULL,
+ NULL,
+ GDK_CURRENT_TIME);
+ }
+ if ((kbd_grab_status_ != GDK_GRAB_SUCCESS ||
+ mouse_grab_status_ != GDK_GRAB_SUCCESS) &&
+ grab_failure_count_++ < kMaxGrabFailures) {
+ LOG(WARNING) << "Failed to grab inputs. Trying again in "
+ << kRetryGrabIntervalMs << " ms: kbd="
+ << kbd_grab_status_ << ", mouse=" << mouse_grab_status_;
+ TryUngrabOtherClients();
+ gdk_x11_ungrab_server();
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&GrabWidget::TryGrabAllInputs, weak_factory_.GetWeakPtr()),
+ kRetryGrabIntervalMs);
+ } else {
+ gdk_x11_ungrab_server();
+ GdkGrabStatus status = kbd_grab_status_;
+ if (status == GDK_GRAB_SUCCESS) {
+ status = mouse_grab_status_;
+ }
+ switch (status) {
+ case GDK_GRAB_SUCCESS:
+ break;
+ case GDK_GRAB_ALREADY_GRABBED:
+ FailedWithGrabAlreadyGrabbed();
+ break;
+ case GDK_GRAB_INVALID_TIME:
+ FailedWithGrabInvalidTime();
+ break;
+ case GDK_GRAB_NOT_VIEWABLE:
+ FailedWithGrabNotViewable();
+ break;
+ case GDK_GRAB_FROZEN:
+ FailedWithGrabFrozen();
+ break;
+ default:
+ FailedWithUnknownError();
+ break;
+ }
+ DVLOG(1) << "Grab Success";
+ screen_locker_view_->OnGrabInputs();
+ }
+}
+
+void GrabWidget::TryUngrabOtherClients() {
+#if !defined(NDEBUG)
+ {
+ int event_base, error_base;
+ int major, minor;
+ // Make sure we have XTest extension.
+ DCHECK(XTestQueryExtension(ui::GetXDisplay(),
+ &event_base, &error_base,
+ &major, &minor));
+ }
+#endif
+
+ // The following code is an attempt to grab inputs by closing
+ // supposedly opened menu. This happens when a plugin has a menu
+ // opened.
+ if (mouse_grab_status_ == GDK_GRAB_ALREADY_GRABBED ||
+ mouse_grab_status_ == GDK_GRAB_FROZEN) {
+ // Successfully grabbed the keyboard, but pointer is still
+ // grabbed by other client. Another attempt to close supposedly
+ // opened menu by emulating keypress at the left top corner.
+ Display* display = ui::GetXDisplay();
+ Window root, child;
+ int root_x, root_y, win_x, winy;
+ unsigned int mask;
+ XQueryPointer(display,
+ ui::GetX11WindowFromGtkWidget(window_contents()),
+ &root, &child, &root_x, &root_y,
+ &win_x, &winy, &mask);
+ XTestFakeMotionEvent(display, -1, -10000, -10000, CurrentTime);
+ XTestFakeButtonEvent(display, 1, True, CurrentTime);
+ XTestFakeButtonEvent(display, 1, False, CurrentTime);
+ // Move the pointer back.
+ XTestFakeMotionEvent(display, -1, root_x, root_y, CurrentTime);
+ XFlush(display);
+ } else if (kbd_grab_status_ == GDK_GRAB_ALREADY_GRABBED ||
+ kbd_grab_status_ == GDK_GRAB_FROZEN) {
+ // Successfully grabbed the pointer, but keyboard is still grabbed
+ // by other client. Another attempt to close supposedly opened
+ // menu by emulating escape key. Such situation must be very
+ // rare, but handling this just in case
+ Display* display = ui::GetXDisplay();
+ KeyCode escape = XKeysymToKeycode(display, XK_Escape);
+ XTestFakeKeyEvent(display, escape, True, CurrentTime);
+ XTestFakeKeyEvent(display, escape, False, CurrentTime);
+ XFlush(display);
+ }
+}
+
+// BackgroundView for ScreenLocker, which layouts a lock widget in
+// addition to other background components.
+class ScreenLockerBackgroundView
+ : public chromeos::BackgroundView,
+ public chromeos::ScreenLockerViews::ScreenLockViewContainer {
+ public:
+ ScreenLockerBackgroundView(views::Widget* lock_widget,
+ views::View* screen_lock_view)
+ : lock_widget_(lock_widget),
+ screen_lock_view_(screen_lock_view) {
+ }
+
+ virtual ScreenMode GetScreenMode() const OVERRIDE {
+ return kScreenLockerMode;
+ }
+
+ virtual void Layout() OVERRIDE {
+ chromeos::BackgroundView::Layout();
+ gfx::Rect screen = bounds();
+ if (screen_lock_view_) {
+ gfx::Size size = screen_lock_view_->GetPreferredSize();
+ gfx::Point origin((screen.width() - size.width()) / 2,
+ (screen.height() - size.height()) / 2);
+ gfx::Size widget_size(screen.size());
+ widget_size.Enlarge(-origin.x(), -origin.y());
+ lock_widget_->SetBounds(gfx::Rect(widget_size));
+ } else {
+ // No password entry. Move the lock widget to off screen.
+ lock_widget_->SetBounds(gfx::Rect(-100, -100, 1, 1));
+ }
+ }
+
+ // ScreenLockerViews::ScreenLockViewContainer implementation:
+ virtual void SetScreenLockView(views::View* screen_lock_view) OVERRIDE {
+ screen_lock_view_ = screen_lock_view;
+ Layout();
+ }
+
+ private:
+ views::Widget* lock_widget_;
+
+ views::View* screen_lock_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenLockerBackgroundView);
+};
+
+} // namespace
+
+namespace chromeos {
+
+// A event observer that forwards gtk events from one window to another.
+// See screen_locker.h for more details.
+class MouseEventRelay : public MessageLoopForUI::Observer {
+ public:
+ MouseEventRelay(GdkWindow* src, GdkWindow* dest)
+ : src_(src),
+ dest_(dest),
+ initialized_(false) {
+ DCHECK(src_);
+ DCHECK(dest_);
+ }
+
+ virtual void WillProcessEvent(GdkEvent* event) OVERRIDE {}
+
+ virtual void DidProcessEvent(GdkEvent* event) OVERRIDE {
+ if (event->any.window != src_)
+ return;
+ if (!initialized_) {
+ gint src_x, src_y, dest_x, dest_y, width, height, depth;
+ gdk_window_get_geometry(dest_, &dest_x, &dest_y, &width, &height, &depth);
+ // wait to compute offset until the info bubble widget's location
+ // is available.
+ if (dest_x < 0 || dest_y < 0)
+ return;
+ gdk_window_get_geometry(src_, &src_x, &src_y, &width, &height, &depth);
+ offset_.SetPoint(dest_x - src_x, dest_y - src_y);
+ initialized_ = true;
+ }
+ if (event->type == GDK_BUTTON_PRESS ||
+ event->type == GDK_BUTTON_RELEASE) {
+ GdkEvent* copy = gdk_event_copy(event);
+ copy->button.window = dest_;
+ g_object_ref(copy->button.window);
+ copy->button.x -= offset_.x();
+ copy->button.y -= offset_.y();
+
+ gdk_event_put(copy);
+ gdk_event_free(copy);
+ } else if (event->type == GDK_MOTION_NOTIFY) {
+ GdkEvent* copy = gdk_event_copy(event);
+ copy->motion.window = dest_;
+ g_object_ref(copy->motion.window);
+ copy->motion.x -= offset_.x();
+ copy->motion.y -= offset_.y();
+
+ gdk_event_put(copy);
+ gdk_event_free(copy);
+ }
+ }
+
+ private:
+ GdkWindow* src_;
+ GdkWindow* dest_;
+ bool initialized_;
+
+ // Offset from src_'s origin to dest_'s origin.
+ gfx::Point offset_;
+
+ DISALLOW_COPY_AND_ASSIGN(MouseEventRelay);
+};
+
+// A event observer used to unlock the screen upon user's action
+// without asking password. Used in BWSI and auto login mode.
+// TODO(oshima): consolidate InputEventObserver and LockerInputEventObserver.
+class InputEventObserver : public MessageLoopForUI::Observer {
+ public:
+ explicit InputEventObserver(ScreenLocker* screen_locker)
+ : screen_locker_(screen_locker),
+ activated_(false) {
+ }
+
+#if defined(TOUCH_UI)
+ virtual base::EventStatus WillProcessEvent(
+ const base::NativeEvent& event) OVERRIDE {
+ return base::EVENT_CONTINUE;
+ }
+
+ virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE {
+ }
+#else
+ virtual void WillProcessEvent(GdkEvent* event) OVERRIDE {
+ if ((event->type == GDK_KEY_PRESS ||
+ event->type == GDK_BUTTON_PRESS ||
+ event->type == GDK_MOTION_NOTIFY) &&
+ !activated_) {
+ activated_ = true;
+ std::string not_used_string;
+ GaiaAuthConsumer::ClientLoginResult not_used;
+ screen_locker_->OnLoginSuccess(not_used_string,
+ not_used_string,
+ not_used,
+ false,
+ false);
+ }
+ }
+
+ virtual void DidProcessEvent(GdkEvent* event) OVERRIDE {
+ }
+#endif
+
+ private:
+ chromeos::ScreenLocker* screen_locker_;
+
+ bool activated_;
+
+ DISALLOW_COPY_AND_ASSIGN(InputEventObserver);
+};
+
+// A event observer used to show the screen locker upon
+// user action: mouse or keyboard interactions.
+// TODO(oshima): this has to be disabled while authenticating.
+class LockerInputEventObserver : public MessageLoopForUI::Observer {
+ public:
+ explicit LockerInputEventObserver(ScreenLockerViews* screen_locker_view)
+ : screen_locker_view_(screen_locker_view),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ timer_(FROM_HERE,
+ base::TimeDelta::FromSeconds(kScreenSaverIdleTimeout), this,
+ &LockerInputEventObserver::StartScreenSaver)) {
+ }
+
+#if defined(TOUCH_UI)
+ virtual base::EventStatus WillProcessEvent(
+ const base::NativeEvent& event) OVERRIDE {
+ return base::EVENT_CONTINUE;
+ }
+
+ virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE {
+ }
+#else
+ virtual void WillProcessEvent(GdkEvent* event) OVERRIDE {
+ if ((event->type == GDK_KEY_PRESS ||
+ event->type == GDK_BUTTON_PRESS ||
+ event->type == GDK_MOTION_NOTIFY)) {
+ timer_.Reset();
+ screen_locker_view_->StopScreenSaver();
+ }
+ }
+
+ virtual void DidProcessEvent(GdkEvent* event) OVERRIDE {
+ }
+#endif
+
+ private:
+ void StartScreenSaver() {
+ screen_locker_view_->StartScreenSaver();
+ }
+
+ ScreenLockerViews* screen_locker_view_;
+ base::DelayTimer<LockerInputEventObserver> timer_;
+
+ DISALLOW_COPY_AND_ASSIGN(LockerInputEventObserver);
+};
+
+ScreenLockerViews::ScreenLockViewContainer::~ScreenLockViewContainer() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ScreenLockerViews implementation.
+
+ScreenLockerViews::ScreenLockerViews(ScreenLocker* screen_locker)
+ : ScreenLockerDelegate(screen_locker),
+ lock_window_(NULL),
+ lock_widget_(NULL),
+ screen_lock_view_(NULL),
+ captcha_view_(NULL),
+ grab_container_(NULL),
+ background_container_(NULL),
+ error_info_(NULL),
+ drawn_(false),
+ input_grabbed_(false) {
+ screen_locker_view_ = this;
+}
+
+void ScreenLockerViews::Init(bool unlock_on_input) {
+ static const GdkColor kGdkBlack = {0, 0, 0, 0};
+
+ gfx::Point left_top(1, 1);
+ gfx::Rect init_bounds(gfx::Screen::GetMonitorAreaNearestPoint(left_top));
+
+ LockWindow* lock_window = new LockWindow();
+ lock_window_ = lock_window->GetWidget();
+ views::Widget::InitParams params(
+ views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ params.bounds = init_bounds;
+ params.native_widget = lock_window;
+ lock_window_->Init(params);
+ gtk_widget_modify_bg(
+ lock_window_->GetNativeView(), GTK_STATE_NORMAL, &kGdkBlack);
+
+ g_signal_connect(lock_window_->GetNativeView(), "client-event",
+ G_CALLBACK(OnClientEventThunk), this);
+
+ // GTK does not like zero width/height.
+ if (!unlock_on_input) {
+ screen_lock_view_ = new ScreenLockView(screen_locker_);
+ screen_lock_view_->Init();
+ screen_lock_view_->SetEnabled(false);
+ screen_lock_view_->StartThrobber();
+ } else {
+ input_event_observer_.reset(new InputEventObserver(screen_locker_));
+ MessageLoopForUI::current()->AddObserver(input_event_observer_.get());
+ }
+
+ // Hang on to a cast version of the grab widget so we can call its
+ // TryGrabAllInputs() method later. (Nobody else needs to use it, so moving
+ // its declaration to the header instead of keeping it in an anonymous
+ // namespace feels a bit ugly.)
+ GrabWidget* grab_widget = new GrabWidget(screen_locker_);
+ lock_widget_ = grab_widget->GetWidget();
+ views::Widget::InitParams lock_params(
+ views::Widget::InitParams::TYPE_CONTROL);
+ lock_params.transparent = true;
+ lock_params.parent_widget = lock_window_;
+ lock_params.native_widget = grab_widget;
+ lock_widget_->Init(lock_params);
+ if (screen_lock_view_) {
+ GrabWidgetRootView* root_view = new GrabWidgetRootView(screen_lock_view_);
+ grab_container_ = root_view;
+ lock_widget_->SetContentsView(root_view);
+ }
+ lock_widget_->Show();
+
+ // Configuring the background url.
+ std::string url_string =
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kScreenSaverUrl);
+ ScreenLockerBackgroundView* screen_lock_background_view_ =
+ new ScreenLockerBackgroundView(lock_widget_, screen_lock_view_);
+ background_container_ = screen_lock_background_view_;
+ background_view_ = screen_lock_background_view_;
+ background_view_->Init(GURL(url_string));
+
+ // Gets user profile and sets default user 24hour flag since we don't
+ // expose user profile in ScreenLockerBackgroundView.
+ Profile* profile = ProfileManager::GetDefaultProfile();
+ if (profile) {
+ background_view_->SetDefaultUse24HourClock(
+ profile->GetPrefs()->GetBoolean(prefs::kUse24HourClock));
+ }
+
+ if (background_view_->ScreenSaverEnabled())
+ StartScreenSaver();
+
+#if defined(TOOLKIT_USES_GTK)
+ DCHECK(GTK_WIDGET_REALIZED(lock_window_->GetNativeView()));
+ WmIpc::instance()->SetWindowType(
+ lock_window_->GetNativeView(),
+ WM_IPC_WINDOW_CHROME_SCREEN_LOCKER,
+ NULL);
+#endif
+
+ lock_window_->SetContentsView(background_view_);
+ lock_window_->Show();
+
+ grab_widget->ClearGtkGrab();
+
+ // Call this after lock_window_->Show(); otherwise the 1st invocation
+ // of gdk_xxx_grab() will always fail.
+ grab_widget->TryGrabAllInputs();
+
+ // Add the window to its own group so that its grab won't be stolen if
+ // gtk_grab_add() gets called on behalf on a non-screen-locker widget (e.g.
+ // a modal dialog) -- see http://crosbug.com/8999. We intentionally do this
+ // after calling ClearGtkGrab(), as want to be in the default window group
+ // then so we can break any existing GTK grabs.
+ GtkWindowGroup* window_group = gtk_window_group_new();
+ gtk_window_group_add_window(window_group,
+ GTK_WINDOW(lock_window_->GetNativeView()));
+ g_object_unref(window_group);
+
+ lock_window->set_toplevel_focus_widget(
+ static_cast<views::NativeWidgetGtk*>(lock_widget_->native_widget())->
+ window_contents());
+}
+
+void ScreenLockerViews::OnGrabInputs() {
+ DVLOG(1) << "OnGrabInputs";
+ input_grabbed_ = true;
+ if (drawn_)
+ ScreenLockReady();
+}
+
+void ScreenLockerViews::StartScreenSaver() {
+ if (!background_view_->IsScreenSaverVisible()) {
+ VLOG(1) << "StartScreenSaver";
+ UserMetrics::RecordAction(
+ UserMetricsAction("ScreenLocker_StartScreenSaver"));
+ background_view_->ShowScreenSaver();
+ if (screen_lock_view_) {
+ screen_lock_view_->SetEnabled(false);
+ screen_lock_view_->SetVisible(false);
+ }
+ screen_locker_->ClearErrors();
+ }
+}
+
+void ScreenLockerViews::StopScreenSaver() {
+ if (background_view_->IsScreenSaverVisible()) {
+ VLOG(1) << "StopScreenSaver";
+ if (screen_lock_view_) {
+ screen_lock_view_->SetVisible(true);
+ // Place the screen_lock_view_ to the center of the screen.
+ // Must be called when the view is visible: crosbug.com/15213.
+ background_view_->Layout();
+ screen_lock_view_->RequestFocus();
+ }
+ background_view_->HideScreenSaver();
+ screen_locker_->EnableInput();
+ }
+}
+
+views::View* ScreenLockerViews::GetViewByID(int id) {
+ return lock_widget_->GetRootView()->GetViewByID(id);
+}
+
+void ScreenLockerViews::ScreenLockReady() {
+ ScreenLockerDelegate::ScreenLockReady();
+
+ if (background_view_->ScreenSaverEnabled()) {
+ lock_widget_->GetFocusManager()->RegisterAccelerator(
+ views::Accelerator(ui::VKEY_ESCAPE, false, false, false), this);
+ locker_input_event_observer_.reset(new LockerInputEventObserver(this));
+ MessageLoopForUI::current()->AddObserver(
+ locker_input_event_observer_.get());
+ } else {
+ // Don't enable the password field until we grab all inputs.
+ SetInputEnabled(true);
+ }
+}
+
+void ScreenLockerViews::OnAuthenticate() {
+ screen_lock_view_->StartThrobber();
+}
+
+void ScreenLockerViews::SetInputEnabled(bool enabled) {
+ if (screen_lock_view_) {
+ screen_lock_view_->SetEnabled(enabled);
+ if (enabled) {
+ screen_lock_view_->ClearAndSetFocusToPassword();
+ screen_lock_view_->StopThrobber();
+ }
+ }
+}
+
+void ScreenLockerViews::SetSignoutEnabled(bool enabled) {
+ screen_lock_view_->SetSignoutEnabled(enabled);
+}
+
+void ScreenLockerViews::ShowErrorMessage(const string16& message,
+ bool sign_out_only) {
+ // Make sure that active Sign Out button is not hidden behind the bubble.
+ ShowErrorBubble(
+ message, sign_out_only ?
+ views::BubbleBorder::BOTTOM_RIGHT : views::BubbleBorder::BOTTOM_LEFT);
+}
+
+// Present user a CAPTCHA challenge with image from |captcha_url|,
+// After that shows error bubble with |message|.
+void ScreenLockerViews::ShowCaptchaAndErrorMessage(const GURL& captcha_url,
+ const string16& message) {
+ postponed_error_message_ = message;
+ if (captcha_view_) {
+ captcha_view_->SetCaptchaURL(captcha_url);
+ } else {
+ captcha_view_ = new CaptchaView(captcha_url, true);
+ captcha_view_->Init();
+ captcha_view_->set_delegate(this);
+ }
+ // CaptchaView ownership is passed to grab_container_.
+ views::View* view = secondary_view_.release();
+ view = NULL;
+ screen_lock_view_->SetVisible(false);
+ grab_container_->SetScreenLockView(captcha_view_);
+ background_container_->SetScreenLockView(captcha_view_);
+ captcha_view_->SetVisible(true);
+ // Take ScreenLockView ownership now that it's removed from grab_container_.
+ secondary_view_.reset(screen_lock_view_);
+}
+
+void ScreenLockerViews::ClearErrors() {
+ if (error_info_) {
+ error_info_->Close();
+ error_info_ = NULL;
+ }
+}
+
+void ScreenLockerViews::BubbleClosing(Bubble* bubble, bool closed_by_escape) {
+ error_info_ = NULL;
+ SetSignoutEnabled(true);
+ if (mouse_event_relay_.get()) {
+ MessageLoopForUI::current()->RemoveObserver(mouse_event_relay_.get());
+ mouse_event_relay_.reset();
+ }
+}
+
+bool ScreenLockerViews::CloseOnEscape() {
+ return true;
+}
+
+bool ScreenLockerViews::FadeInOnShow() {
+ return false;
+}
+
+void ScreenLockerViews::OnLinkActivated(size_t index) {
+}
+
+void ScreenLockerViews::OnCaptchaEntered(const std::string& captcha) {
+ // Captcha dialog is only shown when LoginPerformer instance exists,
+ // i.e. blocking UI after password change is in place.
+ DCHECK(LoginPerformer::default_performer());
+ LoginPerformer::default_performer()->set_captcha(captcha);
+
+ // ScreenLockView ownership is passed to grab_container_.
+ // Need to save return value here so that compile
+ // doesn't fail with "unused result" warning.
+ views::View* view = secondary_view_.release();
+ view = NULL;
+ captcha_view_->SetVisible(false);
+ grab_container_->SetScreenLockView(screen_lock_view_);
+ background_container_->SetScreenLockView(screen_lock_view_);
+ screen_lock_view_->SetVisible(true);
+ screen_lock_view_->ClearAndSetFocusToPassword();
+
+ // Take CaptchaView ownership now that it's removed from grab_container_.
+ secondary_view_.reset(captcha_view_);
+ ShowErrorMessage(postponed_error_message_, false);
+ postponed_error_message_.clear();
+}
+
+ScreenLockerViews::~ScreenLockerViews() {
+ if (input_event_observer_.get())
+ MessageLoopForUI::current()->RemoveObserver(input_event_observer_.get());
+ if (locker_input_event_observer_.get()) {
+ lock_widget_->GetFocusManager()->UnregisterAccelerator(
+ views::Accelerator(ui::VKEY_ESCAPE, false, false, false), this);
+ MessageLoopForUI::current()->RemoveObserver(
+ locker_input_event_observer_.get());
+ }
+
+ gdk_keyboard_ungrab(GDK_CURRENT_TIME);
+ gdk_pointer_ungrab(GDK_CURRENT_TIME);
+
+ DCHECK(lock_window_);
+ VLOG(1) << "~ScreenLocker(): Closing ScreenLocker window.";
+ lock_window_->Close();
+ // lock_widget_ will be deleted by gtk's destroy signal.
+ screen_locker_view_ = NULL;
+}
+
+void ScreenLockerViews::OnWindowManagerReady() {
+ DVLOG(1) << "OnClientEvent: drawn for lock";
+ drawn_ = true;
+ if (input_grabbed_)
+ ScreenLockReady();
+}
+
+void ScreenLockerViews::ShowErrorBubble(
+ const string16& message,
+ views::BubbleBorder::ArrowLocation arrow_location) {
+ if (error_info_)
+ error_info_->Close();
+
+ gfx::Rect rect = screen_lock_view_->GetPasswordBoundsRelativeTo(
+ lock_widget_->GetRootView());
+ gfx::Rect lock_widget_bounds = lock_widget_->GetClientAreaScreenBounds();
+ rect.Offset(lock_widget_bounds.x(), lock_widget_bounds.y());
+ error_info_ = MessageBubble::ShowNoGrab(
+ lock_window_,
+ rect,
+ arrow_location,
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_WARNING),
+ UTF16ToWide(message),
+ UTF16ToWide(string16()), // TODO(nkostylev): Add help link.
+ this);
+
+#if !defined(TOUCH_UI)
+ if (mouse_event_relay_.get())
+ MessageLoopForUI::current()->RemoveObserver(mouse_event_relay_.get());
+ mouse_event_relay_.reset(
+ new MouseEventRelay(lock_widget_->GetNativeView()->window,
+ error_info_->GetNativeView()->window));
+ MessageLoopForUI::current()->AddObserver(mouse_event_relay_.get());
+#endif
+}
+
+bool ScreenLockerViews::AcceleratorPressed(
+ const views::Accelerator& accelerator) {
+ if (!background_view_->IsScreenSaverVisible()) {
+ screen_locker_view_->StartScreenSaver();
+ return true;
+ }
+ return false;
+}
+
+void ScreenLockerViews::OnClientEvent(GtkWidget* widge, GdkEventClient* event) {
+#if defined(TOOLKIT_USES_GTK)
+ WmIpc::Message msg;
+ WmIpc::instance()->DecodeMessage(*event, &msg);
+ if (msg.type() == WM_IPC_MESSAGE_CHROME_NOTIFY_SCREEN_REDRAWN_FOR_LOCK) {
+ OnWindowManagerReady();
+ }
+#endif
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screen_locker_views.h b/chrome/browser/chromeos/login/screen_locker_views.h
new file mode 100644
index 0000000..89efdcc
--- /dev/null
+++ b/chrome/browser/chromeos/login/screen_locker_views.h
@@ -0,0 +1,157 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCKER_VIEWS_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCKER_VIEWS_H_
+#pragma once
+
+#include "chrome/browser/chromeos/login/captcha_view.h"
+#include "chrome/browser/chromeos/login/message_bubble.h"
+#include "chrome/browser/chromeos/login/screen_locker_delegate.h"
+
+namespace chromeos {
+
+class BackgroundView;
+class InputEventObserver;
+class LockerInputEventObserver;
+class MessageBubble;
+class MouseEventRelay;
+class ScreenLocker;
+class ScreenLockView;
+
+namespace test {
+class ScreenLockerTester;
+}
+
+// This version of ScreenLockerDelegate displays a views interface. This class
+// shows a BackgroundView and a Signout button as well as creating a
+// ScreenLockView to allow the user to log in.
+class ScreenLockerViews : public ScreenLockerDelegate,
+ public MessageBubbleDelegate,
+ public CaptchaView::Delegate,
+ public views::AcceleratorTarget {
+ public:
+ // Interface that helps switching from ScreenLockView to CaptchaView.
+ class ScreenLockViewContainer {
+ public:
+ virtual void SetScreenLockView(views::View* screen_lock_view) = 0;
+
+ protected:
+ virtual ~ScreenLockViewContainer();
+ };
+
+ explicit ScreenLockerViews(ScreenLocker* screen_locker);
+
+ // Called when the all inputs are grabbed.
+ void OnGrabInputs();
+
+ // Starts screen saver.
+ virtual void StartScreenSaver();
+
+ // Stops screen saver.
+ virtual void StopScreenSaver();
+
+ // Returns a view that has given view |id|, or null if it doesn't exist.
+ views::View* GetViewByID(int id);
+
+ // ScreenLockerDelegate implementation:
+ virtual void Init(bool unlock_on_input) OVERRIDE;
+ virtual void ScreenLockReady() OVERRIDE;
+ virtual void OnAuthenticate() OVERRIDE;
+ virtual void SetInputEnabled(bool enabled) OVERRIDE;
+ virtual void SetSignoutEnabled(bool enabled) OVERRIDE;
+ virtual void ShowErrorMessage(const string16& message,
+ bool sign_out_only) OVERRIDE;
+ virtual void ShowCaptchaAndErrorMessage(const GURL& captcha_url,
+ const string16& message) OVERRIDE;
+ virtual void ClearErrors() OVERRIDE;
+
+ // Overridden from views::BubbleDelegate.
+ virtual void BubbleClosing(Bubble* bubble, bool closed_by_escape) OVERRIDE;
+ virtual bool CloseOnEscape() OVERRIDE;
+ virtual bool FadeInOnShow() OVERRIDE;
+ virtual void OnLinkActivated(size_t index) OVERRIDE;
+
+ // CaptchaView::Delegate implementation:
+ virtual void OnCaptchaEntered(const std::string& captcha) OVERRIDE;
+
+ private:
+ friend class LockerInputEventObserver;
+ friend class test::ScreenLockerTester;
+
+ virtual ~ScreenLockerViews();
+
+ // Called when the window manager is ready to handle locked state.
+ void OnWindowManagerReady();
+
+ // Shows error_info_ bubble with the |message| and |arrow_location| specified.
+ // Assumes that UI controls were locked before that.
+ void ShowErrorBubble(const string16& message,
+ views::BubbleBorder::ArrowLocation arrow_location);
+
+ // Overridden from AcceleratorTarget:
+ virtual bool AcceleratorPressed(const views::Accelerator& accelerator)
+ OVERRIDE;
+
+ // Event handler for client-event.
+ CHROMEGTK_CALLBACK_1(ScreenLockerViews, void, OnClientEvent, GdkEventClient*);
+
+ // The screen locker window.
+ views::Widget* lock_window_;
+
+ // Child widget to grab the keyboard/mouse input.
+ views::Widget* lock_widget_;
+
+ // A view that accepts password.
+ ScreenLockView* screen_lock_view_;
+
+ // A view that can display html page as background.
+ BackgroundView* background_view_;
+
+ // View used to present CAPTCHA challenge input.
+ CaptchaView* captcha_view_;
+
+ // Containers that hold currently visible view.
+ // Initially it's ScreenLockView instance.
+ // When CAPTCHA input dialog is presented it's swapped to CaptchaView
+ // instance, then back after CAPTCHA input is done.
+ ScreenLockViewContainer* grab_container_;
+ ScreenLockViewContainer* background_container_;
+
+ // View that's not owned by grab_container_ - either ScreenLockView or
+ // CaptchaView instance. Keep that under scoped_ptr so that it's deleted.
+ scoped_ptr<views::View> secondary_view_;
+
+ // Postponed error message to be shown after CAPTCHA input is done.
+ string16 postponed_error_message_;
+
+ // ScreenLocker grabs all keyboard and mouse events on its
+ // gdk window and never let other gdk_window to handle inputs.
+ // This MouseEventRelay object is used to forward events to
+ // the message bubble's gdk_window so that close button works.
+ scoped_ptr<MouseEventRelay> mouse_event_relay_;
+
+ // A message loop observer to detect user's keyboard/mouse event.
+ // Used when |unlock_on_input_| is true.
+ scoped_ptr<InputEventObserver> input_event_observer_;
+
+ // A message loop observer to detect user's keyboard/mouse event.
+ // Used when to show the screen locker upon such an event.
+ scoped_ptr<LockerInputEventObserver> locker_input_event_observer_;
+
+ // An info bubble to display login failure message.
+ MessageBubble* error_info_;
+
+ // True if the screen locker's window has been drawn.
+ bool drawn_;
+
+ // True if both mouse input and keyboard input are grabbed.
+ bool input_grabbed_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenLockerViews);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCKER_VIEWS_H_
diff --git a/chrome/browser/chromeos/login/screen_locker_webui.cc b/chrome/browser/chromeos/login/screen_locker_webui.cc
new file mode 100644
index 0000000..62ca554
--- /dev/null
+++ b/chrome/browser/chromeos/login/screen_locker_webui.cc
@@ -0,0 +1,353 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/login/screen_locker_webui.h"
+
+#include <X11/extensions/XTest.h>
+#include <X11/keysym.h>
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdkx.h>
+
+// Evil hack to undo X11 evil #define.
+#undef None
+#undef Status
+
+#include "base/command_line.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/chromeos/login/screen_locker.h"
+#include "chrome/browser/chromeos/wm_ipc.h"
+#include "chrome/common/url_constants.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/gfx/screen.h"
+#include "views/widget/native_widget_gtk.h"
+
+namespace {
+
+chromeos::ScreenLockerWebUI* screen_locker_webui_ = NULL;
+
+// A ScreenLock window that covers entire screen to keep the keyboard
+// focus/events inside the grab widget.
+class LockWindow : public views::NativeWidgetGtk {
+ public:
+ LockWindow()
+ : views::NativeWidgetGtk(new views::Widget),
+ toplevel_focus_widget_(NULL) {
+ EnableDoubleBuffer(true);
+ }
+
+ // GTK propagates key events from parents to children.
+ // Make sure LockWindow will never handle key events.
+ virtual gboolean OnEventKey(GtkWidget* widget, GdkEventKey* event) OVERRIDE {
+ // Don't handle key event in the lock window.
+ return false;
+ }
+
+ virtual gboolean OnButtonPress(GtkWidget* widget,
+ GdkEventButton* event) OVERRIDE {
+ // Don't handle mouse event in the lock wnidow and
+ // nor propagate to child.
+ return true;
+ }
+
+ virtual void OnDestroy(GtkWidget* object) OVERRIDE {
+ VLOG(1) << "OnDestroy: LockWindow destroyed";
+ views::NativeWidgetGtk::OnDestroy(object);
+ }
+
+ virtual void ClearNativeFocus() OVERRIDE {
+ DCHECK(toplevel_focus_widget_);
+ gtk_widget_grab_focus(toplevel_focus_widget_);
+ }
+
+ // Sets the widget to move the focus to when clearning the native
+ // widget's focus.
+ void set_toplevel_focus_widget(GtkWidget* widget) {
+ gtk_widget_set_can_focus(widget, TRUE);
+ toplevel_focus_widget_ = widget;
+ }
+
+ private:
+ // The widget we set focus to when clearning the focus on native
+ // widget. In screen locker, gdk input is grabbed in GrabWidget,
+ // and resetting the focus by using gtk_window_set_focus seems to
+ // confuse gtk and doesn't let focus move to native widget under
+ // GrabWidget.
+ GtkWidget* toplevel_focus_widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(LockWindow);
+};
+
+} // namespace
+
+namespace chromeos {
+
+// A event observer used to unlock the screen upon user's action
+// without asking password. Used in BWSI and auto login mode.
+class InputEventObserver : public MessageLoopForUI::Observer {
+ public:
+ explicit InputEventObserver(ScreenLocker* screen_locker)
+ : screen_locker_(screen_locker),
+ activated_(false) {
+ }
+
+#if defined(TOUCH_UI)
+ virtual base::EventStatus WillProcessEvent(
+ const base::NativeEvent& event) OVERRIDE {
+ return base::EVENT_CONTINUE;
+ }
+
+ virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE {
+ }
+#else
+ virtual void WillProcessEvent(GdkEvent* event) OVERRIDE {
+ if ((event->type == GDK_KEY_PRESS ||
+ event->type == GDK_BUTTON_PRESS ||
+ event->type == GDK_MOTION_NOTIFY) &&
+ !activated_) {
+ activated_ = true;
+ std::string not_used_string;
+ GaiaAuthConsumer::ClientLoginResult not_used;
+ screen_locker_->OnLoginSuccess(not_used_string,
+ not_used_string,
+ not_used,
+ false,
+ false);
+ }
+ }
+
+ virtual void DidProcessEvent(GdkEvent* event) OVERRIDE {
+ }
+#endif
+
+ private:
+ chromeos::ScreenLocker* screen_locker_;
+
+ bool activated_;
+
+ DISALLOW_COPY_AND_ASSIGN(InputEventObserver);
+};
+
+// ScreenLockWebUI creates components necessary to authenticate a user to
+// unlock the screen.
+class ScreenLockWebUI : public WebUILoginView {
+ public:
+ explicit ScreenLockWebUI(ScreenLocker* screen_locker);
+ virtual ~ScreenLockWebUI();
+
+ // WebUILoginView overrides:
+ virtual void Init() OVERRIDE;
+
+ // Clears and sets the focus to the password field.
+ void ClearAndSetFocusToPassword();
+
+ // Enable/Disable signout button.
+ void SetSignoutEnabled(bool enabled);
+
+ // Display error message.
+ void DisplayErrorMessage(string16 message);
+
+ void SubmitPassword();
+
+ // Overridden from views::Views:
+ virtual bool AcceleratorPressed(
+ const views::Accelerator& accelerator) OVERRIDE;
+ virtual void HandleKeyboardEvent(
+ const NativeWebKeyboardEvent& event) OVERRIDE;
+
+ protected:
+ // WebUILoginView overrides:
+ virtual views::Widget* GetLoginWindow() OVERRIDE;
+
+ private:
+ friend class test::ScreenLockerTester;
+
+ // ScreenLocker is owned by itself.
+ ScreenLocker* screen_locker_;
+
+ std::string password_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenLockWebUI);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// ScreenLockerWebUI implementation.
+
+ScreenLockerWebUI::ScreenLockerWebUI(ScreenLocker* screen_locker)
+ : ScreenLockerDelegate(screen_locker),
+ lock_window_(NULL),
+ screen_lock_webui_(NULL) {
+ screen_locker_webui_ = this;
+}
+
+void ScreenLockerWebUI::Init(bool unlock_on_input) {
+ static const GdkColor kGdkBlack = {0, 0, 0, 0};
+
+ gfx::Point left_top(1, 1);
+ gfx::Rect init_bounds(gfx::Screen::GetMonitorAreaNearestPoint(left_top));
+
+ LockWindow* lock_window = new LockWindow();
+ lock_window_ = lock_window->GetWidget();
+ views::Widget::InitParams params(
+ views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ params.bounds = init_bounds;
+ params.native_widget = lock_window;
+ lock_window_->Init(params);
+ gtk_widget_modify_bg(
+ lock_window_->GetNativeView(), GTK_STATE_NORMAL, &kGdkBlack);
+
+ g_signal_connect(lock_window_->GetNativeView(), "client-event",
+ G_CALLBACK(OnClientEventThunk), this);
+
+ // GTK does not like zero width/height.
+ if (!unlock_on_input) {
+ screen_lock_webui_ = new ScreenLockWebUI(screen_locker_);
+ screen_lock_webui_->Init();
+ screen_lock_webui_->SetEnabled(false);
+ } else {
+ input_event_observer_.reset(new InputEventObserver(screen_locker_));
+ MessageLoopForUI::current()->AddObserver(input_event_observer_.get());
+ }
+
+ DCHECK(GTK_WIDGET_REALIZED(lock_window_->GetNativeView()));
+ WmIpc::instance()->SetWindowType(
+ lock_window_->GetNativeView(),
+ WM_IPC_WINDOW_CHROME_SCREEN_LOCKER,
+ NULL);
+
+ if (screen_lock_webui_)
+ lock_window_->SetContentsView(screen_lock_webui_);
+ lock_window_->Show();
+
+ // Add the window to its own group so that its grab won't be stolen if
+ // gtk_grab_add() gets called on behalf on a non-screen-locker widget (e.g.
+ // a modal dialog) -- see http://crosbug.com/8999. We intentionally do this
+ // after calling ClearGtkGrab(), as want to be in the default window group
+ // then so we can break any existing GTK grabs.
+ GtkWindowGroup* window_group = gtk_window_group_new();
+ gtk_window_group_add_window(window_group,
+ GTK_WINDOW(lock_window_->GetNativeView()));
+ g_object_unref(window_group);
+
+ lock_window->set_toplevel_focus_widget(lock_window->window_contents());
+}
+
+void ScreenLockerWebUI::ScreenLockReady() {
+ ScreenLockerDelegate::ScreenLockReady();
+ SetInputEnabled(true);
+}
+
+void ScreenLockerWebUI::OnAuthenticate() {
+}
+
+void ScreenLockerWebUI::SetInputEnabled(bool enabled) {
+ // TODO(flackr): Implement enabling / disabling WebUI input.
+}
+
+void ScreenLockerWebUI::SetSignoutEnabled(bool enabled) {
+ // TODO(flackr): Implement enabling / disabling signout.
+}
+
+void ScreenLockerWebUI::ShowErrorMessage(const string16& message,
+ bool sign_out_only) {
+ if (screen_lock_webui_)
+ screen_lock_webui_->DisplayErrorMessage(message);
+}
+
+void ScreenLockerWebUI::ShowCaptchaAndErrorMessage(const GURL& captcha_url,
+ const string16& message) {
+ ShowErrorMessage(message, true);
+}
+
+void ScreenLockerWebUI::ClearErrors() {
+ if (screen_lock_webui_)
+ screen_lock_webui_->DisplayErrorMessage(string16());
+}
+
+ScreenLockerWebUI::~ScreenLockerWebUI() {
+ screen_locker_webui_ = NULL;
+ if (input_event_observer_.get())
+ MessageLoopForUI::current()->RemoveObserver(input_event_observer_.get());
+
+ DCHECK(lock_window_);
+ VLOG(1) << "~ScreenLocker(): Closing ScreenLocker window.";
+ lock_window_->Close();
+}
+
+void ScreenLockerWebUI::OnWindowManagerReady() {
+ DVLOG(1) << "OnClientEvent: drawn for lock";
+ ScreenLockReady();
+}
+
+void ScreenLockerWebUI::OnClientEvent(GtkWidget* widge, GdkEventClient* event) {
+ WmIpc::Message msg;
+ WmIpc::instance()->DecodeMessage(*event, &msg);
+ if (msg.type() == WM_IPC_MESSAGE_CHROME_NOTIFY_SCREEN_REDRAWN_FOR_LOCK)
+ OnWindowManagerReady();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ScreenLockWebUI implementation.
+
+ScreenLockWebUI::ScreenLockWebUI(ScreenLocker* screen_locker)
+ : screen_locker_(screen_locker) {
+ DCHECK(screen_locker_);
+}
+
+ScreenLockWebUI::~ScreenLockWebUI() {
+}
+
+void ScreenLockWebUI::Init() {
+ WebUILoginView::Init();
+ LoadURL(GURL(chrome::kChromeUILockScreenURL));
+}
+
+void ScreenLockWebUI::ClearAndSetFocusToPassword() {
+ // TODO(flackr): Send a javascript message to clear and focus the password
+ // field.
+ NOTIMPLEMENTED();
+}
+
+void ScreenLockWebUI::SetSignoutEnabled(bool enabled) {
+ // TODO(flackr): Send a Javascript message to enable / disable the signout
+ // link.
+ NOTIMPLEMENTED();
+}
+
+void ScreenLockWebUI::DisplayErrorMessage(string16 message) {
+ WebUI* webui = GetWebUI();
+ if (webui) {
+ base::StringValue errorMessage(message);
+ webui->CallJavascriptFunction("lockScreen.displayError", errorMessage);
+ }
+}
+
+void ScreenLockWebUI::SubmitPassword() {
+ screen_locker_->Authenticate(ASCIIToUTF16(password_.c_str()));
+}
+
+bool ScreenLockWebUI::AcceleratorPressed(
+ const views::Accelerator& accelerator) {
+ // Override WebUILoginView::AcceleratorPressed to prevent call to WebUI
+ // cr.ui.Oobe functions.
+ // TODO(flackr): This might be able to be removed once merging with the login
+ // screen WebUI is complete.
+ return true;
+}
+
+void ScreenLockWebUI::HandleKeyboardEvent(
+ const NativeWebKeyboardEvent& event) {
+ // Override WebUILoginView::HandleKeyboardEvent to prevent call to WebUI
+ // cr.ui.Oobe functions.
+ // TODO(flackr): This might be able to be removed once merging with the login
+ // screen WebUI is complete.
+}
+
+views::Widget* ScreenLockWebUI::GetLoginWindow() {
+ DCHECK(screen_locker_webui_);
+ return screen_locker_webui_->lock_window_;
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screen_locker_webui.h b/chrome/browser/chromeos/login/screen_locker_webui.h
new file mode 100644
index 0000000..2eddee7
--- /dev/null
+++ b/chrome/browser/chromeos/login/screen_locker_webui.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCKER_WEBUI_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCKER_WEBUI_H_
+#pragma once
+
+#include "chrome/browser/chromeos/login/helper.h"
+#include "chrome/browser/chromeos/login/screen_locker_delegate.h"
+#include "chrome/browser/chromeos/login/user_view.h"
+#include "chrome/browser/chromeos/login/webui_login_view.h"
+
+#if defined(TOOLKIT_USES_GTK)
+#include "views/widget/native_widget_gtk.h"
+#endif
+
+namespace views {
+class ImageView;
+}
+
+namespace chromeos {
+
+class InputEventObserver;
+class ScreenLocker;
+class ScreenLockWebUI;
+class UserView;
+
+namespace test {
+class ScreenLockerTester;
+}
+
+class ScreenLockerWebUI : public ScreenLockerDelegate {
+ public:
+ explicit ScreenLockerWebUI(ScreenLocker* screen_locker);
+
+ // ScreenLockerDelegate implementation:
+ virtual void Init(bool unlock_on_input) OVERRIDE;
+ virtual void ScreenLockReady() OVERRIDE;
+ virtual void OnAuthenticate() OVERRIDE;
+ virtual void SetInputEnabled(bool enabled) OVERRIDE;
+ virtual void SetSignoutEnabled(bool enabled) OVERRIDE;
+ virtual void ShowErrorMessage(const string16& message,
+ bool sign_out_only) OVERRIDE;
+ virtual void ShowCaptchaAndErrorMessage(const GURL& captcha_url,
+ const string16& message) OVERRIDE;
+ virtual void ClearErrors() OVERRIDE;
+
+ private:
+ friend class ScreenLockWebUI;
+
+ virtual ~ScreenLockerWebUI();
+
+ // Called when the window manager is ready to handle locked state.
+ void OnWindowManagerReady();
+
+ // Event handler for client-event.
+ CHROMEGTK_CALLBACK_1(ScreenLockerWebUI, void, OnClientEvent, GdkEventClient*);
+
+ // The screen locker window.
+ views::Widget* lock_window_;
+
+ // A view that displays a WebUI lock screen.
+ ScreenLockWebUI* screen_lock_webui_;
+
+ // A message loop observer to detect user's keyboard/mouse event.
+ // Used when |unlock_on_input_| is true.
+ scoped_ptr<InputEventObserver> input_event_observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenLockerWebUI);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCKER_WEBUI_H_
diff --git a/chrome/browser/chromeos/login/webui_login_view.cc b/chrome/browser/chromeos/login/webui_login_view.cc
index eef9f8f..fced55a 100644
--- a/chrome/browser/chromeos/login/webui_login_view.cc
+++ b/chrome/browser/chromeos/login/webui_login_view.cc
@@ -330,7 +330,7 @@ void WebUILoginView::InitStatusArea() {
status_area_->Init();
status_area_->SetVisible(status_area_visibility_on_init_);
- views::Widget* login_window = WebUILoginDisplay::GetLoginWindow();
+ views::Widget* login_window = GetLoginWindow();
// Width of |status_window| is meant to be large enough.
// The current value of status_area_->GetPreferredSize().width()
// will be too small when button status is changed.
@@ -415,4 +415,8 @@ void WebUILoginView::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
web_ui->CallJavascriptFunction("cr.ui.Oobe.clearErrors");
}
+views::Widget* WebUILoginView::GetLoginWindow() {
+ return WebUILoginDisplay::GetLoginWindow();
+}
+
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/webui_login_view.h b/chrome/browser/chromeos/login/webui_login_view.h
index 984cff5..36fe431 100644
--- a/chrome/browser/chromeos/login/webui_login_view.h
+++ b/chrome/browser/chromeos/login/webui_login_view.h
@@ -98,6 +98,9 @@ class WebUILoginView : public views::View,
// Creates and adds the status area (separate window).
virtual void InitStatusArea();
+ // Get the views widget hosting this WebUILoginView.
+ virtual views::Widget* GetLoginWindow();
+
StatusAreaView* status_area_;
// DOMView for rendering a webpage as a webui login.
diff --git a/chrome/browser/resources/chromeos/login/lock_screen.css b/chrome/browser/resources/chromeos/login/lock_screen.css
new file mode 100644
index 0000000..aef5c5b3
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/lock_screen.css
@@ -0,0 +1,51 @@
+/* TODO(flackr): Merge the style (and possibly scripting) of the lock screen
+ * with the account picker login screen. See http://crbug.com/97980. */
+body {
+ background-color: black;
+}
+
+#wrapper {
+ -webkit-box-orient: vertical;
+ display: -webkit-box;
+ bottom: 0;
+ left: 0;
+ position: absolute;
+ right: 0;
+ top: 0;
+}
+
+.spacer {
+ -webkit-box-flex: 1;
+}
+
+#login-box {
+ -webkit-border-radius: 10px;
+ background: white;
+ border: 1px solid #777;
+ margin: auto;
+ padding: 10px;
+ text-align: center;
+ width: 280px;
+}
+
+#signout {
+ bottom: 10px;
+ color: white;
+ cursor: pointer;
+ position: absolute;
+ right: 10px;
+}
+
+#error-box {
+ -webkit-border-radius: 10px;
+ background: white;
+ border: 1px solid red;
+ color: black;
+ display: none;
+ text-align: center;
+ margin-top: 15px;
+}
+
+#error-box.visible {
+ display: block;
+}
diff --git a/chrome/browser/resources/chromeos/login/lock_screen.html b/chrome/browser/resources/chromeos/login/lock_screen.html
new file mode 100644
index 0000000..29878f4
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/lock_screen.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html i18n-values="dir:textdirection">
+<head>
+ <meta charset="utf-8">
+ <title>Lock Scree</title>
+ <link rel="stylesheet" href="lock_screen.css">
+ <script src="chrome://lock/strings.js"></script>
+ <script src="chrome://resources/js/cr.js"></script>
+ <script src="chrome://resources/js/i18n_template.js"></script>
+ <script src="chrome://resources/js/util.js"></script>
+ <script src="chrome://lock/lock_screen.js"></script>
+</head>
+<body>
+ <div id="wrapper">
+ <div class="spacer"></div>
+ <div id="login-box">
+ <div><img id="user-image"></div>
+ <div>
+ <p i18n-content="password"></p>
+ <input id="password" type="password" value="">
+ </div>
+ <input id="unlock" type="button" i18n-values="value:unlock">
+ </div>
+ <div class="spacer">
+ <div id="error-box"></div>
+ </div>
+ </div>
+ <div id="signout">
+ <a id="signout-link"><span i18n-content="signout"></span></a>
+ </div>
+</body>
+</html>
diff --git a/chrome/browser/resources/chromeos/login/lock_screen.js b/chrome/browser/resources/chromeos/login/lock_screen.js
new file mode 100644
index 0000000..94efe2f
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/lock_screen.js
@@ -0,0 +1,51 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('lockScreen', function() {
+ 'use strict';
+
+ /**
+ * Initialize the lock screen by setting up buttons and substituting in
+ * translated strings.
+ */
+ function initialize() {
+ i18nTemplate.process(document, templateData);
+
+ $('unlock').onclick = unlockScreen;
+ $('signout-link').onclick = signout;
+ $('user-image').src = 'chrome://userimage/' + templateData.email;
+ $('password').focus();
+ displayError('');
+ }
+
+ function displayError(message) {
+ $('error-box').textContent = message;
+ if (message) {
+ $('error-box').className = 'visible';
+ } else {
+ $('error-box').className = '';
+ }
+ }
+
+ /**
+ * Attempt to unlock the screen with the current password.
+ */
+ function unlockScreen() {
+ chrome.send('unlockScreenRequest', [$('password').value]);
+ }
+
+ /**
+ * Request signing out the current user.
+ */
+ function signout() {
+ chrome.send('signoutRequest');
+ }
+
+ return {
+ initialize: initialize,
+ displayError: displayError,
+ };
+});
+
+document.addEventListener('DOMContentLoaded', lockScreen.initialize);
diff --git a/chrome/browser/ui/webui/chrome_web_ui_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_factory.cc
index 7dc77c3..8a24f7f 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_factory.cc
@@ -50,6 +50,7 @@
#include "chrome/browser/ui/webui/chromeos/enterprise_enrollment_ui.h"
#include "chrome/browser/ui/webui/chromeos/imageburner/imageburner_ui.h"
#include "chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.h"
+#include "chrome/browser/ui/webui/chromeos/login/lock_screen_ui.h"
#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
#include "chrome/browser/ui/webui/chromeos/mobile_setup_ui.h"
#include "chrome/browser/ui/webui/chromeos/proxy_settings_ui.h"
@@ -212,6 +213,8 @@ static WebUIFactoryFunction GetWebUIFactoryFunction(Profile* profile,
return &NewWebUI<ImageBurnUI>;
if (url.host() == chrome::kChromeUIKeyboardOverlayHost)
return &NewWebUI<KeyboardOverlayUI>;
+ if (url.host() == chrome::kChromeUILockScreenHost)
+ return &NewWebUI<chromeos::LockScreenUI>;
if (url.host() == chrome::kChromeUIMobileSetupHost)
return &NewWebUI<MobileSetupUI>;
if (url.host() == chrome::kChromeUIOobeHost)
diff --git a/chrome/browser/ui/webui/chromeos/login/lock_screen_ui.cc b/chrome/browser/ui/webui/chromeos/login/lock_screen_ui.cc
new file mode 100644
index 0000000..dbb99a1
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/login/lock_screen_ui.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/chromeos/login/lock_screen_ui.h"
+
+#include "base/bind.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/chromeos/login/screen_locker.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/chrome_web_ui_data_source.h"
+#include "chrome/browser/ui/webui/options/chromeos/user_image_source.h"
+#include "chrome/common/url_constants.h"
+#include "content/browser/tab_contents/tab_contents.h"
+#include "grit/browser_resources.h"
+#include "grit/generated_resources.h"
+
+namespace chromeos {
+
+LockScreenUI::LockScreenUI(TabContents* contents) : ChromeWebUI(contents) {
+ // Set up the chrome://lock source.
+ ChromeWebUIDataSource* html_source =
+ new ChromeWebUIDataSource(chrome::kChromeUILockScreenHost);
+
+ // Register callback handler.
+ RegisterMessageCallback("unlockScreenRequest",
+ base::Bind(&LockScreenUI::UnlockScreenRequest, base::Unretained(this)));
+ RegisterMessageCallback("signoutRequest",
+ base::Bind(&LockScreenUI::SignoutRequest, base::Unretained(this)));
+
+ // Email address of current user.
+ html_source->AddString("email", ASCIIToUTF16(
+ chromeos::UserManager::Get()->logged_in_user().email()));
+
+ // Localized strings.
+ // TODO(flackr): Change button text to unlock.
+ html_source->AddLocalizedString("unlock", IDS_LOGIN_BUTTON);
+ html_source->AddLocalizedString("password", IDS_LOGIN_PASSWORD);
+ html_source->AddLocalizedString("signout", IDS_SCREEN_LOCK_SIGN_OUT);
+ html_source->set_json_path("strings.js");
+
+ // Add required resources.
+ html_source->add_resource_path("lock_screen.css", IDR_LOCK_SCREEN_CSS);
+ html_source->add_resource_path("lock_screen.js", IDR_LOCK_SCREEN_JS);
+ html_source->set_default_resource(IDR_LOCK_SCREEN_HTML);
+
+ Profile* profile = Profile::FromBrowserContext(contents->browser_context());
+ profile->GetChromeURLDataManager()->AddDataSource(html_source);
+
+ // Set up the chrome://userimage/ source.
+ UserImageSource* user_image_source = new UserImageSource();
+ profile->GetChromeURLDataManager()->AddDataSource(user_image_source);
+}
+
+LockScreenUI::~LockScreenUI() {
+}
+
+void LockScreenUI::UnlockScreenRequest(const base::ListValue* args) {
+ string16 password;
+ if (!args->GetString(0, &password))
+ return;
+
+ chromeos::ScreenLocker* screen_locker_ =
+ chromeos::ScreenLocker::default_screen_locker();
+ if (!screen_locker_)
+ return;
+
+ screen_locker_->Authenticate(password);
+}
+
+void LockScreenUI::SignoutRequest(const base::ListValue* args) {
+ chromeos::ScreenLocker* screen_locker_ =
+ chromeos::ScreenLocker::default_screen_locker();
+ if (!screen_locker_)
+ return;
+
+ screen_locker_->Signout();
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/lock_screen_ui.h b/chrome/browser/ui/webui/chromeos/login/lock_screen_ui.h
new file mode 100644
index 0000000..878a8bd
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/login/lock_screen_ui.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_LOCK_SCREEN_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_LOCK_SCREEN_UI_H_
+#pragma once
+
+#include "base/values.h"
+#include "chrome/browser/ui/webui/chrome_web_ui.h"
+
+namespace chromeos {
+
+// The WebUI for Screen Locker.
+class LockScreenUI : public ChromeWebUI {
+ public:
+ explicit LockScreenUI(TabContents* contents);
+ virtual ~LockScreenUI();
+
+ private:
+ // Send an unlock request to the active screen locker.
+ void UnlockScreenRequest(const base::ListValue* args);
+
+ // Signout the active user.
+ void SignoutRequest(const base::ListValue* args);
+
+ DISALLOW_COPY_AND_ASSIGN(LockScreenUI);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_LOCK_SCREEN_UI_H_
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index fc6a708..c477393 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -602,6 +602,12 @@
'browser/chromeos/login/screen_lock_view.h',
'browser/chromeos/login/screen_locker.cc',
'browser/chromeos/login/screen_locker.h',
+ 'browser/chromeos/login/screen_locker_delegate.cc',
+ 'browser/chromeos/login/screen_locker_delegate.h',
+ 'browser/chromeos/login/screen_locker_views.cc',
+ 'browser/chromeos/login/screen_locker_views.h',
+ 'browser/chromeos/login/screen_locker_webui.cc',
+ 'browser/chromeos/login/screen_locker_webui.h',
'browser/chromeos/login/screen_observer.h',
'browser/chromeos/login/shutdown_button.cc',
'browser/chromeos/login/shutdown_button.h',
@@ -3627,6 +3633,8 @@
'browser/ui/webui/chromeos/login/enterprise_oauth_enrollment_screen_handler.h',
'browser/ui/webui/chromeos/login/eula_screen_handler.cc',
'browser/ui/webui/chromeos/login/eula_screen_handler.h',
+ 'browser/ui/webui/chromeos/login/lock_screen_ui.cc',
+ 'browser/ui/webui/chromeos/login/lock_screen_ui.h',
'browser/ui/webui/chromeos/login/network_dropdown.cc',
'browser/ui/webui/chromeos/login/network_dropdown.h',
'browser/ui/webui/chromeos/login/network_dropdown_handler.cc',
@@ -5088,6 +5096,8 @@
['exclude', '^browser/chromeos/frame/'],
['exclude', '^browser/chromeos/login/background_view.cc'],
['exclude', '^browser/chromeos/login/screen_locker_browsertest.cc'],
+ ['exclude', '^browser/chromeos/login/screen_locker_views.cc'],
+ ['exclude', '^browser/chromeos/login/screen_locker_webui.cc'],
['exclude', '^browser/chromeos/login/screen_locker.cc'],
['exclude', '^browser/chromeos/login/screen_lock_view.cc'],
['exclude', '^browser/chromeos/login/shutdown_button.cc'],
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 1cd7ffa..94fd516 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -1058,6 +1058,9 @@ const char kVersion[] = "version";
const char kWinHttpProxyResolver[] = "winhttp-proxy-resolver";
#if defined(OS_CHROMEOS)
+// Enable WebUI based lock screen.
+const char kWebUILockScreen[] = "webui-lock-screen";
+
// Enable WebUI based OOBE and login.
const char kWebUILogin[] = "webui-login";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 0812fdb..453b166 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -290,6 +290,7 @@ extern const char kVersion[];
extern const char kWinHttpProxyResolver[];
#if defined(OS_CHROMEOS)
+extern const char kWebUILockScreen[];
extern const char kWebUILogin[];
extern const char kSkipOAuthLogin[];
extern const char kEnableBluetooth[];
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index 87370e4..25206ff 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -80,6 +80,7 @@ const char kChromeUIEnterpriseEnrollmentURL[] =
"chrome://enterprise-enrollment/";
const char kChromeUIImageBurnerURL[] = "chrome://imageburner/";
const char kChromeUIKeyboardOverlayURL[] = "chrome://keyboardoverlay/";
+const char kChromeUILockScreenURL[] = "chrome://lock/";
const char kChromeUIMediaplayerURL[] = "chrome://mediaplayer/";
const char kChromeUIMobileSetupURL[] = "chrome://mobilesetup/";
const char kChromeUIOSCreditsURL[] = "chrome://os-credits/";
@@ -192,6 +193,7 @@ const char kChromeUIDiscardsHost[] = "discards";
const char kChromeUIEnterpriseEnrollmentHost[] = "enterprise-enrollment";
const char kChromeUIImageBurnerHost[] = "imageburner";
const char kChromeUIKeyboardOverlayHost[] = "keyboardoverlay";
+const char kChromeUILockScreenHost[] = "lock";
const char kChromeUILoginContainerHost[] = "login-container";
const char kChromeUILoginHost[] = "login";
const char kChromeUIMediaplayerHost[] = "mediaplayer";
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index a3c6a5d..bcea8f1 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -73,6 +73,7 @@ extern const char kChromeUIDiscardsURL[];
extern const char kChromeUIEnterpriseEnrollmentURL[];
extern const char kChromeUIImageBurnerURL[];
extern const char kChromeUIKeyboardOverlayURL[];
+extern const char kChromeUILockScreenURL[];
extern const char kChromeUIMediaplayerURL[];
extern const char kChromeUIMobileSetupURL[];
extern const char kChromeUIOSCreditsURL[];
@@ -183,6 +184,7 @@ extern const char kChromeUIDiscardsHost[];
extern const char kChromeUIEnterpriseEnrollmentHost[];
extern const char kChromeUIImageBurnerHost[];
extern const char kChromeUIKeyboardOverlayHost[];
+extern const char kChromeUILockScreenHost[];
extern const char kChromeUILoginContainerHost[];
extern const char kChromeUILoginHost[];
extern const char kChromeUIMediaplayerHost[];