172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chromeos/login/screen_locker.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include <X11/extensions/XTest.h>
8dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include <X11/keysym.h>
972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include <gdk/gdkkeysyms.h>
10201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include <gdk/gdkx.h>
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string>
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <vector>
13201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// Evil hack to undo X11 evil #define. See crosbug.com/
14201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#undef Status
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/command_line.h"
1721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/lazy_instance.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h"
19dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/metrics/histogram.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/timer.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chromeos/cros/input_method_library.h"
243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/chromeos/cros/login_library.h"
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chromeos/cros/screen_lock_library.h"
2672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/chromeos/input_method/input_method_util.h"
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chromeos/language_preferences.h"
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chromeos/login/authenticator.h"
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chromeos/login/background_view.h"
3021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/chromeos/login/login_performer.h"
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chromeos/login/login_utils.h"
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chromeos/login/message_bubble.h"
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chromeos/login/screen_lock_view.h"
34513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/browser/chromeos/login/shutdown_button.h"
35513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/browser/chromeos/system_key_event_listener.h"
3672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/chromeos/view_ids.h"
37dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/chromeos/wm_ipc.h"
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/metrics/user_metrics.h"
39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/profiles/profile.h"
4021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile_manager.h"
41201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "chrome/browser/sync/profile_sync_service.h"
424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser.h"
43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/browser_list.h"
44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/browser_window.h"
453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/chrome_switches.h"
46dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
47dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/common/notification_service.h"
483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "googleurl/src/gurl.h"
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h"
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/theme_resources.h"
5121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "third_party/cros/chromeos_wm_ipc_enums.h"
5272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h"
5372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/resource/resource_bundle.h"
5472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/x/x11_util.h"
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/screen.h"
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/root_view.h"
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/widget_gtk.h"
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
604a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// The maximum duration for which locker should try to grab the keyboard and
624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// mouse and its interval for regrabbing on failure.
63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst int kMaxGrabFailureSec = 30;
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int64 kRetryGrabIntervalMs = 500;
654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
664a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// Maximum number of times we'll try to grab the keyboard and mouse before
674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// giving up.  If we hit the limit, Chrome exits and the session is terminated.
684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochconst int kMaxGrabFailures = kMaxGrabFailureSec * 1000 / kRetryGrabIntervalMs;
694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// A idle time to show the screen saver in seconds.
713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst int kScreenSaverIdleTimeout = 15;
723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Observer to start ScreenLocker when the screen lock
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass ScreenLockObserver : public chromeos::ScreenLockLibrary::Observer,
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           public NotificationObserver {
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScreenLockObserver() {
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    registrar_.Add(this, NotificationType::LOGIN_USER_CHANGED,
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   NotificationService::AllSources());
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // NotificationObserver overrides:
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void Observe(NotificationType type,
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       const NotificationSource& source,
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       const NotificationDetails& details) {
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (type == NotificationType::LOGIN_USER_CHANGED) {
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Register Screen Lock after login screen to make sure
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // we don't show the screen lock on top of the login screen by accident.
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (chromeos::CrosLibrary::Get()->EnsureLoaded())
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        chromeos::CrosLibrary::Get()->GetScreenLockLibrary()->AddObserver(this);
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void LockScreen(chromeos::ScreenLockLibrary* obj) {
95731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "In: ScreenLockObserver::LockScreen";
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SetupInputMethodsForScreenLocker();
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    chromeos::ScreenLocker::Show();
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void UnlockScreen(chromeos::ScreenLockLibrary* obj) {
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    RestoreInputMethods();
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    chromeos::ScreenLocker::Hide();
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void UnlockScreenFailed(chromeos::ScreenLockLibrary* obj) {
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    chromeos::ScreenLocker::UnlockScreenFailed();
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Temporarily deactivates all input methods (e.g. Chinese, Japanese, Arabic)
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // since they are not necessary to input a login password. Users are still
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // able to use/switch active keyboard layouts (e.g. US qwerty, US dvorak,
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // French).
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void SetupInputMethodsForScreenLocker() {
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (chromeos::CrosLibrary::Get()->EnsureLoaded() &&
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // The LockScreen function is also called when the OS is suspended, and
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // in that case |saved_active_input_method_list_| might be non-empty.
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        saved_active_input_method_list_.empty()) {
11972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      chromeos::InputMethodLibrary* library =
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          chromeos::CrosLibrary::Get()->GetInputMethodLibrary();
1213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
12272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      saved_previous_input_method_id_ = library->previous_input_method().id;
12372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      saved_current_input_method_id_ = library->current_input_method().id;
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      scoped_ptr<chromeos::InputMethodDescriptors> active_input_method_list(
12572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          library->GetActiveInputMethods());
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
12772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      const std::string hardware_keyboard_id =
12872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          chromeos::input_method::GetHardwareInputMethodId();
1293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // We'll add the hardware keyboard if it's not included in
1303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // |active_input_method_list| so that the user can always use the hardware
1313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // keyboard on the screen locker.
1323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      bool should_add_hardware_keyboard = true;
1333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      chromeos::ImeConfigValue value;
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      value.type = chromeos::ImeConfigValue::kValueTypeStringList;
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      for (size_t i = 0; i < active_input_method_list->size(); ++i) {
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        const std::string& input_method_id = active_input_method_list->at(i).id;
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        saved_active_input_method_list_.push_back(input_method_id);
139ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        // Skip if it's not a keyboard layout.
140ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if (!chromeos::input_method::IsKeyboardLayout(input_method_id))
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          continue;
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        value.string_list_value.push_back(input_method_id);
14372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        if (input_method_id == hardware_keyboard_id) {
1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          should_add_hardware_keyboard = false;
1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        }
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
1473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (should_add_hardware_keyboard) {
14872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        value.string_list_value.push_back(hardware_keyboard_id);
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
150201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      // We don't want to shut down the IME, even if the hardware layout is the
151201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      // only IME left.
15272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      library->SetEnableAutoImeShutdown(false);
15372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      library->SetImeConfig(
1543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          chromeos::language_prefs::kGeneralSectionName,
1553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          chromeos::language_prefs::kPreloadEnginesConfigName,
1563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          value);
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void RestoreInputMethods() {
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (chromeos::CrosLibrary::Get()->EnsureLoaded() &&
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        !saved_active_input_method_list_.empty()) {
16372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      chromeos::InputMethodLibrary* library =
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          chromeos::CrosLibrary::Get()->GetInputMethodLibrary();
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      chromeos::ImeConfigValue value;
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      value.type = chromeos::ImeConfigValue::kValueTypeStringList;
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      value.string_list_value = saved_active_input_method_list_;
16972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      library->SetEnableAutoImeShutdown(true);
17072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      library->SetImeConfig(
1713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          chromeos::language_prefs::kGeneralSectionName,
1723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          chromeos::language_prefs::kPreloadEnginesConfigName,
1733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          value);
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Send previous input method id first so Ctrl+space would work fine.
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!saved_previous_input_method_id_.empty())
17672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        library->ChangeInputMethod(saved_previous_input_method_id_);
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!saved_current_input_method_id_.empty())
17872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        library->ChangeInputMethod(saved_current_input_method_id_);
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      saved_previous_input_method_id_.clear();
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      saved_current_input_method_id_.clear();
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      saved_active_input_method_list_.clear();
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotificationRegistrar registrar_;
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string saved_previous_input_method_id_;
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string saved_current_input_method_id_;
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<std::string> saved_active_input_method_list_;
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(ScreenLockObserver);
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
19421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenstatic base::LazyInstance<ScreenLockObserver> g_screen_lock_observer(
19521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    base::LINKER_INITIALIZED);
19621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
1974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// A ScreenLock window that covers entire screen to keep the keyboard
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// focus/events inside the grab widget.
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass LockWindow : public views::WidgetGtk {
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  LockWindow()
2024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      : views::WidgetGtk(views::WidgetGtk::TYPE_WINDOW),
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        toplevel_focus_widget_(NULL) {
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EnableDoubleBuffer(true);
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // GTK propagates key events from parents to children.
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make sure LockWindow will never handle key events.
20972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  virtual gboolean OnKeyEvent(GtkWidget* widget, GdkEventKey* event) {
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Don't handle key event in the lock window.
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  virtual void OnDestroy(GtkWidget* object) {
215731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "OnDestroy: LockWindow destroyed";
2163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    views::WidgetGtk::OnDestroy(object);
2173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void ClearNativeFocus() {
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(toplevel_focus_widget_);
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gtk_widget_grab_focus(toplevel_focus_widget_);
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Sets the widget to move the focus to when clearning the native
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // widget's focus.
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void set_toplevel_focus_widget(GtkWidget* widget) {
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_FOCUS);
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    toplevel_focus_widget_ = widget;
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The widget we set focus to when clearning the focus on native
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // widget.  In screen locker, gdk input is grabbed in GrabWidget,
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // and resetting the focus by using gtk_window_set_focus seems to
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // confuse gtk and doesn't let focus move to native widget under
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // GrabWidget.
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GtkWidget* toplevel_focus_widget_;
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(LockWindow);
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
242513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// GrabWidget's root view to layout the ScreenLockView at the center
243513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// and the Shutdown button at the right bottom.
24421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenclass GrabWidgetRootView
24521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    : public views::View,
24621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      public chromeos::ScreenLocker::ScreenLockViewContainer {
247513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch public:
248513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  explicit GrabWidgetRootView(chromeos::ScreenLockView* screen_lock_view)
249513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      : screen_lock_view_(screen_lock_view),
250513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        shutdown_button_(new chromeos::ShutdownButton()) {
251513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    shutdown_button_->Init();
252513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    AddChildView(screen_lock_view_);
253513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    AddChildView(shutdown_button_);
254513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
255513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
256513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // views::View implementation.
257513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  virtual void Layout() {
258513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    gfx::Size size = screen_lock_view_->GetPreferredSize();
259513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    screen_lock_view_->SetBounds(0, 0, size.width(), size.height());
260513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    shutdown_button_->LayoutIn(this);
261513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
262513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
26321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // ScreenLocker::ScreenLockViewContainer implementation:
26421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  void SetScreenLockView(views::View* screen_lock_view) {
26521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (screen_lock_view_) {
26621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      RemoveChildView(screen_lock_view_);
26721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
26821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    screen_lock_view_ =  screen_lock_view;
26921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (screen_lock_view_) {
27072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      AddChildViewAt(screen_lock_view_, 0);
27121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
27221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    Layout();
27321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
27421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
275513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch private:
276513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  views::View* screen_lock_view_;
277513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
278513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  chromeos::ShutdownButton* shutdown_button_;
279513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
280513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DISALLOW_COPY_AND_ASSIGN(GrabWidgetRootView);
281513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch};
282513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// A child widget that grabs both keyboard and pointer input.
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass GrabWidget : public views::WidgetGtk {
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  explicit GrabWidget(chromeos::ScreenLocker* screen_locker)
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : views::WidgetGtk(views::WidgetGtk::TYPE_CHILD),
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        screen_locker_(screen_locker),
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        grab_failure_count_(0),
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        kbd_grab_status_(GDK_GRAB_INVALID_TIME),
29272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        mouse_grab_status_(GDK_GRAB_INVALID_TIME),
29372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        signout_link_(NULL),
29472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        shutdown_(NULL) {
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void Show() {
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    views::WidgetGtk::Show();
29972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    signout_link_ =
30072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        screen_locker_->GetViewByID(VIEW_ID_SCREEN_LOCKER_SIGNOUT_LINK);
30172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    shutdown_ = screen_locker_->GetViewByID(VIEW_ID_SCREEN_LOCKER_SHUTDOWN);
30272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // These can be null in guest mode.
3033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
3043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
305201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  void ClearGtkGrab() {
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GtkWidget* current_grab_window;
307201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // Grab gtk input first so that the menu holding gtk grab will
308201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // close itself.
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gtk_grab_add(window_contents());
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
311201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // Make sure there is no gtk grab widget so that gtk simply propagates
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // an event.  This is necessary to allow message bubble and password
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // field, button to process events simultaneously. GTK
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // maintains grab widgets in a linked-list, so we need to remove
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // until it's empty.
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    while ((current_grab_window = gtk_grab_get_current()) != NULL)
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      gtk_grab_remove(current_grab_window);
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
32072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  virtual gboolean OnKeyEvent(GtkWidget* widget, GdkEventKey* event) {
32172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    views::KeyEvent key_event(reinterpret_cast<GdkEvent*>(event));
32272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // This is a hack to workaround the issue crosbug.com/10655 due to
32372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // the limitation that a focus manager cannot handle views in
32472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // TYPE_CHILD WidgetGtk correctly.
32572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (signout_link_ &&
32672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        event->type == GDK_KEY_PRESS &&
32772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        (event->keyval == GDK_Tab ||
32872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen         event->keyval == GDK_ISO_Left_Tab ||
32972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen         event->keyval == GDK_KP_Tab)) {
33072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      DCHECK(shutdown_);
33172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      bool reverse = event->state & GDK_SHIFT_MASK;
33272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (reverse && signout_link_->HasFocus()) {
33372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        shutdown_->RequestFocus();
33472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        return true;
33572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      }
33672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (!reverse && shutdown_->HasFocus()) {
33772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        signout_link_->RequestFocus();
33872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        return true;
33972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      }
34072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
34172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return views::WidgetGtk::OnKeyEvent(widget, event);
34272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
34372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual gboolean OnButtonPress(GtkWidget* widget, GdkEventButton* event) {
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    WidgetGtk::OnButtonPress(widget, event);
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Never propagate event to parent.
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Try to grab all inputs. It initiates another try if it fails to
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // grab and the retry count is within a limit, or fails with CHECK.
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void TryGrabAllInputs();
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
354201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // This method tries to steal pointer/keyboard grab from other
355201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // client by sending events that will hopefully close menus or windows
356201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // that have the grab.
357201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  void TryUngrabOtherClients();
358201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
360ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void HandleGtkGrabBroke() {
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Input should never be stolen from ScreenLocker once it's
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // grabbed.  If this happens, it's a bug and has to be fixed. We
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // let chrome crash to get a crash report and dump, and
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // SessionManager will terminate the session to logout.
365ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CHECK_NE(GDK_GRAB_SUCCESS, kbd_grab_status_);
366ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CHECK_NE(GDK_GRAB_SUCCESS, mouse_grab_status_);
367ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
368ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
369ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Define separate methods for each error code so that stack trace
370ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // will tell which error the grab failed with.
371ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void FailedWithGrabAlreadyGrabbed() {
372ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    LOG(FATAL) << "Grab already grabbed";
373ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
374ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void FailedWithGrabInvalidTime() {
375ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    LOG(FATAL) << "Grab invalid time";
376ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
377ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void FailedWithGrabNotViewable() {
378ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    LOG(FATAL) << "Grab not viewable";
379ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
380ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void FailedWithGrabFrozen() {
381ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    LOG(FATAL) << "Grab frozen";
382ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
383ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void FailedWithUnknownError() {
384ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    LOG(FATAL) << "Grab uknown";
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  chromeos::ScreenLocker* screen_locker_;
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScopedRunnableMethodFactory<GrabWidget> task_factory_;
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The number times the widget tried to grab all focus.
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int grab_failure_count_;
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Status of keyboard and mouse grab.
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GdkGrabStatus kbd_grab_status_;
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GdkGrabStatus mouse_grab_status_;
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
39672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  views::View* signout_link_;
39772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  views::View* shutdown_;
39872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(GrabWidget);
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GrabWidget::TryGrabAllInputs() {
403201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Grab x server so that we can atomically grab and take
404201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // action when grab fails.
405201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  gdk_x11_grab_server();
4063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (kbd_grab_status_ != GDK_GRAB_SUCCESS) {
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    kbd_grab_status_ = gdk_keyboard_grab(window_contents()->window, FALSE,
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         GDK_CURRENT_TIME);
4093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (mouse_grab_status_ != GDK_GRAB_SUCCESS) {
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    mouse_grab_status_ =
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        gdk_pointer_grab(window_contents()->window,
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         FALSE,
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         static_cast<GdkEventMask>(
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             GDK_POINTER_MOTION_MASK),
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         NULL,
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         NULL,
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         GDK_CURRENT_TIME);
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if ((kbd_grab_status_ != GDK_GRAB_SUCCESS ||
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       mouse_grab_status_ != GDK_GRAB_SUCCESS) &&
4234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      grab_failure_count_++ < kMaxGrabFailures) {
4244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    LOG(WARNING) << "Failed to grab inputs. Trying again in "
4254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                 << kRetryGrabIntervalMs << " ms: kbd="
4264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                 << kbd_grab_status_ << ", mouse=" << mouse_grab_status_;
427201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    TryUngrabOtherClients();
428201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    gdk_x11_ungrab_server();
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MessageLoop::current()->PostDelayedTask(
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        FROM_HERE,
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        task_factory_.NewRunnableMethod(&GrabWidget::TryGrabAllInputs),
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        kRetryGrabIntervalMs);
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
434201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    gdk_x11_ungrab_server();
435ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    GdkGrabStatus status = kbd_grab_status_;
436ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (status == GDK_GRAB_SUCCESS) {
437ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      status = mouse_grab_status_;
438ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
439ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    switch (status) {
440ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      case GDK_GRAB_SUCCESS:
441ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        break;
442ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      case GDK_GRAB_ALREADY_GRABBED:
443ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        FailedWithGrabAlreadyGrabbed();
444ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        break;
445ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      case GDK_GRAB_INVALID_TIME:
446ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        FailedWithGrabInvalidTime();
447ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        break;
448ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      case GDK_GRAB_NOT_VIEWABLE:
449ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        FailedWithGrabNotViewable();
450ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        break;
451ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      case GDK_GRAB_FROZEN:
452ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        FailedWithGrabFrozen();
453ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        break;
454ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      default:
455ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        FailedWithUnknownError();
456ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        break;
457ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
458731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    DVLOG(1) << "Grab Success";
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    screen_locker_->OnGrabInputs();
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
463201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid GrabWidget::TryUngrabOtherClients() {
464201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#if !defined(NDEBUG)
465201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  {
466201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    int event_base, error_base;
467201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    int major, minor;
468201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // Make sure we have XTest extension.
46972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    DCHECK(XTestQueryExtension(ui::GetXDisplay(),
470201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                               &event_base, &error_base,
471201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                               &major, &minor));
472201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
473201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#endif
474201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
475201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // The following code is an attempt to grab inputs by closing
476201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // supposedly opened menu. This happens when a plugin has a menu
477201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // opened.
478201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (mouse_grab_status_ == GDK_GRAB_ALREADY_GRABBED ||
479201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      mouse_grab_status_ == GDK_GRAB_FROZEN) {
480201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // Successfully grabbed the keyboard, but pointer is still
481201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // grabbed by other client. Another attempt to close supposedly
482201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // opened menu by emulating keypress at the left top corner.
48372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    Display* display = ui::GetXDisplay();
484201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    Window root, child;
485201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    int root_x, root_y, win_x, winy;
486201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    unsigned int mask;
487201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    XQueryPointer(display,
48872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                  ui::GetX11WindowFromGtkWidget(window_contents()),
489201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                  &root, &child, &root_x, &root_y,
490201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                  &win_x, &winy, &mask);
491201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    XTestFakeMotionEvent(display, -1, -10000, -10000, CurrentTime);
492201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    XTestFakeButtonEvent(display, 1, True, CurrentTime);
493201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    XTestFakeButtonEvent(display, 1, False, CurrentTime);
494201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // Move the pointer back.
495201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    XTestFakeMotionEvent(display, -1, root_x, root_y, CurrentTime);
496201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    XFlush(display);
497201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  } else if (kbd_grab_status_ == GDK_GRAB_ALREADY_GRABBED ||
498201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch             kbd_grab_status_ == GDK_GRAB_FROZEN) {
499201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // Successfully grabbed the pointer, but keyboard is still grabbed
500201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // by other client. Another attempt to close supposedly opened
501201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // menu by emulating escape key.  Such situation must be very
502201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // rare, but handling this just in case
50372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    Display* display = ui::GetXDisplay();
504201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    KeyCode escape = XKeysymToKeycode(display, XK_Escape);
505201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    XTestFakeKeyEvent(display, escape, True, CurrentTime);
506201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    XTestFakeKeyEvent(display, escape, False, CurrentTime);
507201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    XFlush(display);
508201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
509201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
510201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// BackgroundView for ScreenLocker, which layouts a lock widget in
512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// addition to other background components.
51321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenclass ScreenLockerBackgroundView
51421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    : public chromeos::BackgroundView,
51521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      public chromeos::ScreenLocker::ScreenLockViewContainer {
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
517513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ScreenLockerBackgroundView(views::WidgetGtk* lock_widget,
518513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                             views::View* screen_lock_view)
519513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      : lock_widget_(lock_widget),
520513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        screen_lock_view_(screen_lock_view) {
521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
52372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  virtual ScreenMode GetScreenMode() const {
52472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return kScreenLockerMode;
525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void Layout() {
528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    chromeos::BackgroundView::Layout();
529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gfx::Rect screen = bounds();
530513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (screen_lock_view_) {
531513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      gfx::Size size = screen_lock_view_->GetPreferredSize();
532513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      gfx::Point origin((screen.width() - size.width()) / 2,
533513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                        (screen.height() - size.height()) / 2);
534513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      gfx::Size widget_size(screen.size());
535513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      widget_size.Enlarge(-origin.x(), -origin.y());
536513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      lock_widget_->SetBounds(gfx::Rect(origin, widget_size));
537513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    } else {
538513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // No password entry. Move the lock widget to off screen.
539513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      lock_widget_->SetBounds(gfx::Rect(-100, -100, 1, 1));
540513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
54321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // ScreenLocker::ScreenLockViewContainer implementation:
54421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  void SetScreenLockView(views::View* screen_lock_view) {
54521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    screen_lock_view_ =  screen_lock_view;
54621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    Layout();
54721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
54821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  views::WidgetGtk* lock_widget_;
551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
552513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  views::View* screen_lock_view_;
553513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(ScreenLockerBackgroundView);
555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace chromeos {
560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
562c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochScreenLocker* ScreenLocker::screen_locker_ = NULL;
563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// A event observer that forwards gtk events from one window to another.
565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// See screen_locker.h for more details.
566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass MouseEventRelay : public MessageLoopForUI::Observer {
567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
5683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  MouseEventRelay(GdkWindow* src, GdkWindow* dest)
5693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      : src_(src),
5703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        dest_(dest),
5713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        initialized_(false) {
572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(src_);
573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(dest_);
574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void WillProcessEvent(GdkEvent* event) {}
577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void DidProcessEvent(GdkEvent* event) {
5793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (event->any.window != src_)
580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
5813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!initialized_) {
5823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      gint src_x, src_y, dest_x, dest_y, width, height, depth;
5833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      gdk_window_get_geometry(dest_, &dest_x, &dest_y, &width, &height, &depth);
5843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // wait to compute offset until the info bubble widget's location
5853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // is available.
5863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (dest_x < 0 || dest_y < 0)
5873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        return;
5883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      gdk_window_get_geometry(src_, &src_x, &src_y, &width, &height, &depth);
5893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      offset_.SetPoint(dest_x - src_x, dest_y - src_y);
5903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      initialized_ = true;
591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (event->type == GDK_BUTTON_PRESS ||
593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        event->type == GDK_BUTTON_RELEASE) {
594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GdkEvent* copy = gdk_event_copy(event);
595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      copy->button.window = dest_;
596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      g_object_ref(copy->button.window);
597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      copy->button.x -= offset_.x();
598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      copy->button.y -= offset_.y();
599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      gdk_event_put(copy);
601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      gdk_event_free(copy);
602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (event->type == GDK_MOTION_NOTIFY) {
603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GdkEvent* copy = gdk_event_copy(event);
6043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      copy->motion.window = dest_;
6053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      g_object_ref(copy->motion.window);
606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      copy->motion.x -= offset_.x();
607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      copy->motion.y -= offset_.y();
608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      gdk_event_put(copy);
610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      gdk_event_free(copy);
611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GdkWindow* src_;
616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GdkWindow* dest_;
6173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  bool initialized_;
618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Offset from src_'s origin to dest_'s origin.
620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Point offset_;
621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(MouseEventRelay);
623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// A event observer used to unlock the screen upon user's action
626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// without asking password. Used in BWSI and auto login mode.
6273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// TODO(oshima): consolidate InputEventObserver and LockerInputEventObserver.
628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass InputEventObserver : public MessageLoopForUI::Observer {
629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  explicit InputEventObserver(ScreenLocker* screen_locker)
631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : screen_locker_(screen_locker),
632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        activated_(false) {
633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void WillProcessEvent(GdkEvent* event) {
636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if ((event->type == GDK_KEY_PRESS ||
637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         event->type == GDK_BUTTON_PRESS ||
638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         event->type == GDK_MOTION_NOTIFY) &&
639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        !activated_) {
640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      activated_ = true;
641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::string not_used_string;
642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GaiaAuthConsumer::ClientLoginResult not_used;
643513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      screen_locker_->OnLoginSuccess(not_used_string,
644513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                     not_used_string,
645513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                     not_used,
646513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                     false);
647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void DidProcessEvent(GdkEvent* event) {
651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  chromeos::ScreenLocker* screen_locker_;
655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool activated_;
657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(InputEventObserver);
659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
6613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// A event observer used to show the screen locker upon
6623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// user action: mouse or keyboard interactions.
6633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// TODO(oshima): this has to be disabled while authenticating.
6643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickclass LockerInputEventObserver : public MessageLoopForUI::Observer {
6653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick public:
6663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  explicit LockerInputEventObserver(ScreenLocker* screen_locker)
6673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      : screen_locker_(screen_locker),
6683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        ALLOW_THIS_IN_INITIALIZER_LIST(
6693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            timer_(base::TimeDelta::FromSeconds(kScreenSaverIdleTimeout), this,
6703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                   &LockerInputEventObserver::StartScreenSaver)) {
6713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
6723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
6733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  virtual void WillProcessEvent(GdkEvent* event) {
6743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if ((event->type == GDK_KEY_PRESS ||
6753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick         event->type == GDK_BUTTON_PRESS ||
6763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick         event->type == GDK_MOTION_NOTIFY)) {
6773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      timer_.Reset();
6783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      screen_locker_->StopScreenSaver();
6793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
6803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
6813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
6823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  virtual void DidProcessEvent(GdkEvent* event) {
6833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
6843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
6853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick private:
6863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  void StartScreenSaver() {
6873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    screen_locker_->StartScreenSaver();
6883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
6893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
6903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  chromeos::ScreenLocker* screen_locker_;
6913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  base::DelayTimer<LockerInputEventObserver> timer_;
6923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
6933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DISALLOW_COPY_AND_ASSIGN(LockerInputEventObserver);
6943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick};
6953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
6963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick//////////////////////////////////////////////////////////////////////////////
697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// ScreenLocker, public:
698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
699c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochScreenLocker::ScreenLocker(const UserManager::User& user)
700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : lock_window_(NULL),
701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      lock_widget_(NULL),
702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      screen_lock_view_(NULL),
70321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      captcha_view_(NULL),
70421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      grab_container_(NULL),
70521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      background_container_(NULL),
706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      user_(user),
707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_info_(NULL),
708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      drawn_(false),
709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      input_grabbed_(false),
710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // TODO(oshima): support auto login mode (this is not implemented yet)
711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // http://crosbug.com/1881
712731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      unlock_on_input_(user_.email().empty()),
713513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      locked_(false),
714513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      start_time_(base::Time::Now()) {
715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!screen_locker_);
716c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  screen_locker_ = this;
717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ScreenLocker::Init() {
720ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  static const GdkColor kGdkBlack = {0, 0, 0, 0};
721ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  authenticator_ = LoginUtils::Get()->CreateAuthenticator(this);
723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Point left_top(1, 1);
725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Rect init_bounds(views::Screen::GetMonitorAreaNearestPoint(left_top));
726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  LockWindow* lock_window = new LockWindow();
728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  lock_window_ = lock_window;
729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  lock_window_->Init(NULL, init_bounds);
730ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  gtk_widget_modify_bg(
731ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      lock_window_->GetNativeView(), GTK_STATE_NORMAL, &kGdkBlack);
732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_signal_connect(lock_window_->GetNativeView(), "client-event",
734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnClientEventThunk), this);
735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // GTK does not like zero width/height.
737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!unlock_on_input_) {
738c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    screen_lock_view_ = new ScreenLockView(this);
739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    screen_lock_view_->Init();
740731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    screen_lock_view_->SetEnabled(false);
74121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    screen_lock_view_->StartThrobber();
742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    input_event_observer_.reset(new InputEventObserver(this));
744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MessageLoopForUI::current()->AddObserver(input_event_observer_.get());
745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7474a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // Hang on to a cast version of the grab widget so we can call its
7484a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // TryGrabAllInputs() method later.  (Nobody else needs to use it, so moving
7494a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // its declaration to the header instead of keeping it in an anonymous
7504a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // namespace feels a bit ugly.)
7514a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  GrabWidget* cast_lock_widget = new GrabWidget(this);
7524a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  lock_widget_ = cast_lock_widget;
753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  lock_widget_->MakeTransparent();
754731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  lock_widget_->InitWithWidget(lock_window_, gfx::Rect());
755513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (screen_lock_view_) {
75621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    GrabWidgetRootView* root_view = new GrabWidgetRootView(screen_lock_view_);
75721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    grab_container_ = root_view;
75821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    lock_widget_->SetContentsView(root_view);
759513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  lock_widget_->Show();
761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Configuring the background url.
7633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::string url_string =
7643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
7653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          switches::kScreenSaverUrl);
76621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ScreenLockerBackgroundView* screen_lock_background_view_ =
76721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      new ScreenLockerBackgroundView(lock_widget_, screen_lock_view_);
76821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  background_container_ = screen_lock_background_view_;
76921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  background_view_ = screen_lock_background_view_;
7703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  background_view_->Init(GURL(url_string));
771731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (background_view_->ScreenSaverEnabled())
772731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    StartScreenSaver();
773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(GTK_WIDGET_REALIZED(lock_window_->GetNativeView()));
775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  WmIpc::instance()->SetWindowType(
776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      lock_window_->GetNativeView(),
777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      WM_IPC_WINDOW_CHROME_SCREEN_LOCKER,
778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NULL);
7793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
7803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  lock_window_->SetContentsView(background_view_);
781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  lock_window_->Show();
782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
783201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  cast_lock_widget->ClearGtkGrab();
784201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
785201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Call this after lock_window_->Show(); otherwise the 1st invocation
786201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // of gdk_xxx_grab() will always fail.
7874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  cast_lock_widget->TryGrabAllInputs();
7884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
7894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // Add the window to its own group so that its grab won't be stolen if
7904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // gtk_grab_add() gets called on behalf on a non-screen-locker widget (e.g.
7914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // a modal dialog) -- see http://crosbug.com/8999.  We intentionally do this
792201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // after calling ClearGtkGrab(), as want to be in the default window group
7934a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // then so we can break any existing GTK grabs.
7944a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  GtkWindowGroup* window_group = gtk_window_group_new();
7954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  gtk_window_group_add_window(window_group,
7964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                              GTK_WINDOW(lock_window_->GetNativeView()));
7974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  g_object_unref(window_group);
7984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  lock_window->set_toplevel_focus_widget(lock_widget_->window_contents());
800513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
801513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Create the SystemKeyEventListener so it can listen for system keyboard
802513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // messages regardless of focus while screen locked.
80321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  SystemKeyEventListener::GetInstance();
804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
8063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid ScreenLocker::OnLoginFailure(const LoginFailure& error) {
807731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DVLOG(1) << "OnLoginFailure";
808513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  UserMetrics::RecordAction(UserMetricsAction("ScreenLocker_OnLoginFailure"));
809513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (authentication_start_time_.is_null()) {
810513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    LOG(ERROR) << "authentication_start_time_ is not set";
811513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  } else {
812513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    base::TimeDelta delta = base::Time::Now() - authentication_start_time_;
813513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    VLOG(1) << "Authentication failure time: " << delta.InSecondsF();
814513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    UMA_HISTOGRAM_TIMES("ScreenLocker.AuthenticationFailureTime", delta);
815513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
816513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EnableInput();
818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Don't enable signout button here as we're showing
819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // MessageBubble.
820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
8213f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  string16 msg = l10n_util::GetStringUTF16(IDS_LOGIN_ERROR_AUTHENTICATING);
8223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const std::string error_text = error.GetErrorString();
8233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!error_text.empty())
8243f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    msg += ASCIIToUTF16("\n") + ASCIIToUTF16(error_text);
825c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  InputMethodLibrary* input_method_library =
827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CrosLibrary::Get()->GetInputMethodLibrary();
828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (input_method_library->GetNumActiveInputMethods() > 1)
8293f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    msg += ASCIIToUTF16("\n") +
8303f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen        l10n_util::GetStringUTF16(IDS_LOGIN_ERROR_KEYBOARD_SWITCH_HINT);
831c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
8323f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  ShowErrorBubble(UTF16ToWide(msg), BubbleBorder::BOTTOM_LEFT);
833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
835731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ScreenLocker::OnLoginSuccess(
836731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const std::string& username,
837513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const std::string& password,
838731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const GaiaAuthConsumer::ClientLoginResult& unused,
839731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    bool pending_requests) {
840731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  VLOG(1) << "OnLoginSuccess: Sending Unlock request.";
841513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (authentication_start_time_.is_null()) {
842ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!username.empty())
843ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      LOG(WARNING) << "authentication_start_time_ is not set";
844513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  } else {
845513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    base::TimeDelta delta = base::Time::Now() - authentication_start_time_;
846513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    VLOG(1) << "Authentication success time: " << delta.InSecondsF();
847513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    UMA_HISTOGRAM_TIMES("ScreenLocker.AuthenticationSuccessTime", delta);
848513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
849513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
850201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  Profile* profile = ProfileManager::GetDefaultProfile();
851201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (profile) {
852201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    ProfileSyncService* service = profile->GetProfileSyncService(username);
853201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    if (service && !service->HasSyncSetupCompleted()) {
854201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      // If sync has failed somehow, try setting the sync passphrase here.
85572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      service->SetPassphrase(password, false, true);
856201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    }
857201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
858201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
859c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (CrosLibrary::Get()->EnsureLoaded())
860c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CrosLibrary::Get()->GetScreenLockLibrary()->NotifyScreenUnlockRequested();
861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
863ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ScreenLocker::BubbleClosing(Bubble* bubble, bool closed_by_escape) {
864c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  error_info_ = NULL;
865c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  screen_lock_view_->SetSignoutEnabled(true);
866c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (mouse_event_relay_.get()) {
867c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MessageLoopForUI::current()->RemoveObserver(mouse_event_relay_.get());
868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    mouse_event_relay_.reset();
869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
87221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid ScreenLocker::OnCaptchaEntered(const std::string& captcha) {
87321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Captcha dialog is only shown when LoginPerformer instance exists,
87421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // i.e. blocking UI after password change is in place.
87521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK(LoginPerformer::default_performer());
87621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  LoginPerformer::default_performer()->set_captcha(captcha);
87721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
87821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // ScreenLockView ownership is passed to grab_container_.
87921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Need to save return value here so that compile
88021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // doesn't fail with "unused result" warning.
88121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  views::View* view = secondary_view_.release();
88221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  view = NULL;
88321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  captcha_view_->SetVisible(false);
88421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  grab_container_->SetScreenLockView(screen_lock_view_);
88521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  background_container_->SetScreenLockView(screen_lock_view_);
88621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  screen_lock_view_->SetVisible(true);
88721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  screen_lock_view_->ClearAndSetFocusToPassword();
88821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
88921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Take CaptchaView ownership now that it's removed from grab_container_.
89021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  secondary_view_.reset(captcha_view_);
89121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ShowErrorMessage(postponed_error_message_, false);
89221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  postponed_error_message_.clear();
89321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
89421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
895c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ScreenLocker::Authenticate(const string16& password) {
896ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (password.empty())
897ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
898ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
899513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  authentication_start_time_ = base::Time::Now();
900c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  screen_lock_view_->SetEnabled(false);
901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  screen_lock_view_->SetSignoutEnabled(false);
90221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  screen_lock_view_->StartThrobber();
90321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
90421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // If LoginPerformer instance exists,
90521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // initial online login phase is still active.
90621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (LoginPerformer::default_performer()) {
90721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    DVLOG(1) << "Delegating authentication to LoginPerformer.";
90821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    LoginPerformer::default_performer()->Login(user_.email(),
90921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                               UTF16ToUTF8(password));
91021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  } else {
91121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    BrowserThread::PostTask(
91221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        BrowserThread::UI, FROM_HERE,
91321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        NewRunnableMethod(authenticator_.get(),
91421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                          &Authenticator::AuthenticateToUnlock,
91521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                          user_.email(),
91621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                          UTF16ToUTF8(password)));
91721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
918c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
919c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
920c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ScreenLocker::ClearErrors() {
921c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (error_info_) {
922c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_info_->Close();
923c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_info_ = NULL;
924c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
925c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
926c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
927c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ScreenLocker::EnableInput() {
928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (screen_lock_view_) {
929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    screen_lock_view_->SetEnabled(true);
930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    screen_lock_view_->ClearAndSetFocusToPassword();
93121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    screen_lock_view_->StopThrobber();
932c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
935c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ScreenLocker::Signout() {
936c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!error_info_) {
937513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    UserMetrics::RecordAction(UserMetricsAction("ScreenLocker_Signout"));
9383f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    WmIpc::instance()->NotifyAboutSignout();
9393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (CrosLibrary::Get()->EnsureLoaded()) {
9403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      CrosLibrary::Get()->GetLoginLibrary()->StopSession("");
9413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
942c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
943c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Don't hide yet the locker because the chrome screen may become visible
944c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // briefly.
945c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
946c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
94821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid ScreenLocker::ShowCaptchaAndErrorMessage(const GURL& captcha_url,
94921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                              const std::wstring& message) {
95021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  postponed_error_message_ = message;
95121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (captcha_view_) {
95221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    captcha_view_->SetCaptchaURL(captcha_url);
95321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  } else {
95421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    captcha_view_ = new CaptchaView(captcha_url, true);
95521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    captcha_view_->Init();
95621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    captcha_view_->set_delegate(this);
95721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
95821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // CaptchaView ownership is passed to grab_container_.
95921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  views::View* view = secondary_view_.release();
96021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  view = NULL;
96121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  screen_lock_view_->SetVisible(false);
96221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  grab_container_->SetScreenLockView(captcha_view_);
96321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  background_container_->SetScreenLockView(captcha_view_);
96421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  captcha_view_->SetVisible(true);
96521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Take ScreenLockView ownership now that it's removed from grab_container_.
96621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  secondary_view_.reset(screen_lock_view_);
96721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
96821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
96921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid ScreenLocker::ShowErrorMessage(const std::wstring& message,
97021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                    bool sign_out_only) {
97121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (sign_out_only) {
97221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    screen_lock_view_->SetEnabled(false);
97321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  } else {
97421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    EnableInput();
97521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
97621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  screen_lock_view_->SetSignoutEnabled(sign_out_only);
97721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Make sure that active Sign Out button is not hidden behind the bubble.
97821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ShowErrorBubble(message, sign_out_only ?
97921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      BubbleBorder::BOTTOM_RIGHT : BubbleBorder::BOTTOM_LEFT);
98021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
98121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
982c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ScreenLocker::OnGrabInputs() {
983731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DVLOG(1) << "OnGrabInputs";
984c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  input_grabbed_ = true;
985c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (drawn_)
986c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ScreenLockReady();
987c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
988c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
98972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenviews::View* ScreenLocker::GetViewByID(int id) {
99072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return lock_widget_->GetRootView()->GetViewByID(id);
99172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
99272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
993c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
994c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ScreenLocker::Show() {
995731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  VLOG(1) << "In ScreenLocker::Show";
996513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  UserMetrics::RecordAction(UserMetricsAction("ScreenLocker_Show"));
997c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI);
998c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
999c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Exit fullscreen.
1000c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser = BrowserList::GetLastActive();
10013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // browser can be NULL if we receive a lock request before the first browser
10023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // window is shown.
10033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (browser && browser->window()->IsFullscreen()) {
1004c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser->ToggleFullscreenMode();
1005c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1006c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1007c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!screen_locker_) {
1008731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "Show: Locking screen";
1009c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ScreenLocker* locker =
1010c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new ScreenLocker(UserManager::Get()->logged_in_user());
1011c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    locker->Init();
1012c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
10133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // PowerManager re-sends lock screen signal if it doesn't
10143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // receive the response within timeout. Just send complete
10153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // signal.
1016731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "Show: locker already exists. Just sending completion event.";
1017c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (CrosLibrary::Get()->EnsureLoaded())
1018c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CrosLibrary::Get()->GetScreenLockLibrary()->NotifyScreenLockCompleted();
1019c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1020c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1021c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1022c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
1023c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ScreenLocker::Hide() {
1024c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI);
1025c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(screen_locker_);
1026731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  VLOG(1) << "Hide: Deleting ScreenLocker: " << screen_locker_;
1027c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MessageLoopForUI::current()->DeleteSoon(FROM_HERE, screen_locker_);
1028c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1029c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1030c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
1031c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ScreenLocker::UnlockScreenFailed() {
1032c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI);
1033c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (screen_locker_) {
10343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Power manager decided no to unlock the screen even if a user
10353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // typed in password, for example, when a user closed the lid
10363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // immediately after typing in the password.
1037731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "UnlockScreenFailed: re-enabling screen locker.";
1038c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    screen_locker_->EnableInput();
1039c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
1040c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // This can happen when a user requested unlock, but PowerManager
1041c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // rejected because the computer is closed, then PowerManager unlocked
1042c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // because it's open again and the above failure message arrives.
1043c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // This'd be extremely rare, but may still happen.
1044731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "UnlockScreenFailed: screen is already unlocked.";
1045c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1046c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1047c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1048c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
1049c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ScreenLocker::InitClass() {
105021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  g_screen_lock_observer.Get();
1051c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1052c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1053c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch////////////////////////////////////////////////////////////////////////////////
1054c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// ScreenLocker, private:
1055c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1056c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochScreenLocker::~ScreenLocker() {
1057c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI);
1058c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ClearErrors();
1059c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (input_event_observer_.get())
1060c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MessageLoopForUI::current()->RemoveObserver(input_event_observer_.get());
10613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (locker_input_event_observer_.get()) {
10623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    lock_widget_->GetFocusManager()->UnregisterAccelerator(
106372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        views::Accelerator(ui::VKEY_ESCAPE, false, false, false), this);
10643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    MessageLoopForUI::current()->RemoveObserver(
10653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        locker_input_event_observer_.get());
10663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1067c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1068c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gdk_keyboard_ungrab(GDK_CURRENT_TIME);
1069c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gdk_pointer_ungrab(GDK_CURRENT_TIME);
1070c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1071c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(lock_window_);
1072731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  VLOG(1) << "~ScreenLocker(): Closing ScreenLocker window.";
1073c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  lock_window_->Close();
1074c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // lock_widget_ will be deleted by gtk's destroy signal.
1075c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  screen_locker_ = NULL;
1076c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool state = false;
1077c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotificationService::current()->Notify(
1078c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationType::SCREEN_LOCK_STATE_CHANGED,
1079c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Source<ScreenLocker>(this),
1080c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Details<bool>(&state));
1081c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (CrosLibrary::Get()->EnsureLoaded())
1082c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CrosLibrary::Get()->GetScreenLockLibrary()->NotifyScreenUnlockCompleted();
1083c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1084c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1085c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ScreenLocker::SetAuthenticator(Authenticator* authenticator) {
1086c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  authenticator_ = authenticator;
1087c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1088c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1089c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ScreenLocker::ScreenLockReady() {
1090731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  VLOG(1) << "ScreenLockReady: sending completed signal to power manager.";
1091731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  locked_ = true;
1092513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  base::TimeDelta delta = base::Time::Now() - start_time_;
1093513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  VLOG(1) << "Screen lock time: " << delta.InSecondsF();
1094513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  UMA_HISTOGRAM_TIMES("ScreenLocker.ScreenLockTime", delta);
1095513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
10963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (background_view_->ScreenSaverEnabled()) {
10973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    lock_widget_->GetFocusManager()->RegisterAccelerator(
109872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        views::Accelerator(ui::VKEY_ESCAPE, false, false, false), this);
10993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    locker_input_event_observer_.reset(new LockerInputEventObserver(this));
11003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    MessageLoopForUI::current()->AddObserver(
11013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        locker_input_event_observer_.get());
11023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else {
1103731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // Don't enable the password field until we grab all inputs.
11043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    EnableInput();
11053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
11063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool state = true;
1108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotificationService::current()->Notify(
1109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationType::SCREEN_LOCK_STATE_CHANGED,
1110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Source<ScreenLocker>(this),
1111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Details<bool>(&state));
1112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (CrosLibrary::Get()->EnsureLoaded())
1113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CrosLibrary::Get()->GetScreenLockLibrary()->NotifyScreenLockCompleted();
1114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ScreenLocker::OnClientEvent(GtkWidget* widge, GdkEventClient* event) {
1117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  WmIpc::Message msg;
1118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  WmIpc::instance()->DecodeMessage(*event, &msg);
1119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (msg.type() == WM_IPC_MESSAGE_CHROME_NOTIFY_SCREEN_REDRAWN_FOR_LOCK) {
1120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OnWindowManagerReady();
1121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ScreenLocker::OnWindowManagerReady() {
1125731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DVLOG(1) << "OnClientEvent: drawn for lock";
1126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  drawn_ = true;
1127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (input_grabbed_)
1128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ScreenLockReady();
1129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
113121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid ScreenLocker::ShowErrorBubble(const std::wstring& message,
113221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                   BubbleBorder::ArrowLocation arrow_location) {
113321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (error_info_)
113421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    error_info_->Close();
113521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
113621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  gfx::Rect rect = screen_lock_view_->GetPasswordBoundsRelativeTo(
113721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      lock_widget_->GetRootView());
1138dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  gfx::Rect lock_widget_bounds = lock_widget_->GetClientAreaScreenBounds();
113921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  rect.Offset(lock_widget_bounds.x(), lock_widget_bounds.y());
114021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  error_info_ = MessageBubble::ShowNoGrab(
114121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      lock_window_,
114221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      rect,
114321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      arrow_location,
114421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_WARNING),
114521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      message,
114621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      std::wstring(),  // TODO(nkostylev): Add help link.
114721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      this);
114821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
114921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (mouse_event_relay_.get())
115021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    MessageLoopForUI::current()->RemoveObserver(mouse_event_relay_.get());
115121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  mouse_event_relay_.reset(
115221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      new MouseEventRelay(lock_widget_->GetNativeView()->window,
115321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                          error_info_->GetNativeView()->window));
115421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  MessageLoopForUI::current()->AddObserver(mouse_event_relay_.get());
115521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
115621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
11573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid ScreenLocker::StopScreenSaver() {
11583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (background_view_->IsScreenSaverVisible()) {
1159731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "StopScreenSaver";
11603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    background_view_->HideScreenSaver();
11613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (screen_lock_view_) {
11623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      screen_lock_view_->SetVisible(true);
11633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      screen_lock_view_->RequestFocus();
11643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
11653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    EnableInput();
11663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
11673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
11683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
11693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid ScreenLocker::StartScreenSaver() {
11703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!background_view_->IsScreenSaverVisible()) {
1171731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "StartScreenSaver";
1172513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    UserMetrics::RecordAction(
1173513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        UserMetricsAction("ScreenLocker_StartScreenSaver"));
11743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    background_view_->ShowScreenSaver();
11753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (screen_lock_view_) {
11763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      screen_lock_view_->SetEnabled(false);
11773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      screen_lock_view_->SetVisible(false);
11783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
11793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    ClearErrors();
11803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
11813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
11823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
11833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool ScreenLocker::AcceleratorPressed(const views::Accelerator& accelerator) {
11843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!background_view_->IsScreenSaverVisible()) {
11853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    StartScreenSaver();
11863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return true;
11873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
11883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return false;
11893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
11903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace chromeos
1192