Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: chrome/browser/chromeos/login/webui_screen_locker.cc

Issue 8573004: Grab inputs on WebUI screen locker. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Grab on RenderWidgetHostView and remove desktop lock screen hacks. Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/login/webui_screen_locker.h" 5 #include "chrome/browser/chromeos/login/webui_screen_locker.h"
6 6
7 #include <X11/extensions/XTest.h> 7 #include <X11/extensions/XTest.h>
8 #include <X11/keysym.h> 8 #include <X11/keysym.h>
9 #include <gdk/gdkkeysyms.h> 9 #include <gdk/gdkkeysyms.h>
10 #include <gdk/gdkx.h> 10 #include <gdk/gdkx.h>
11 11
12 // Evil hack to undo X11 evil #define. 12 // Evil hack to undo X11 evil #define.
13 #undef None 13 #undef None
14 #undef Status 14 #undef Status
15 15
16 #include "base/command_line.h" 16 #include "base/command_line.h"
17 #include "base/utf_string_conversions.h" 17 #include "base/utf_string_conversions.h"
18 #include "base/values.h" 18 #include "base/values.h"
19 #include "chrome/browser/chromeos/cros/cros_library.h" 19 #include "chrome/browser/chromeos/cros/cros_library.h"
20 #include "chrome/browser/chromeos/cros/network_library.h" 20 #include "chrome/browser/chromeos/cros/network_library.h"
21 #include "chrome/browser/chromeos/login/helper.h" 21 #include "chrome/browser/chromeos/login/helper.h"
22 #include "chrome/browser/chromeos/login/screen_locker.h" 22 #include "chrome/browser/chromeos/login/screen_locker.h"
23 #include "chrome/browser/chromeos/login/user_manager.h" 23 #include "chrome/browser/chromeos/login/user_manager.h"
24 #include "chrome/browser/chromeos/login/webui_login_display.h" 24 #include "chrome/browser/chromeos/login/webui_login_display.h"
25 #include "chrome/browser/chromeos/wm_ipc.h" 25 #include "chrome/browser/chromeos/wm_ipc.h"
26 #include "chrome/browser/ui/views/dom_view.h"
26 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" 27 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
27 #include "chrome/common/chrome_notification_types.h" 28 #include "chrome/common/chrome_notification_types.h"
28 #include "chrome/common/url_constants.h" 29 #include "chrome/common/url_constants.h"
30 #include "content/browser/renderer_host/render_widget_host_view.h"
29 #include "content/public/browser/notification_service.h" 31 #include "content/public/browser/notification_service.h"
30 #include "content/public/browser/notification_types.h" 32 #include "content/public/browser/notification_types.h"
31 #include "ui/base/l10n/l10n_util.h" 33 #include "ui/base/l10n/l10n_util.h"
32 #include "ui/base/x/x11_util.h" 34 #include "ui/base/x/x11_util.h"
33 #include "ui/gfx/screen.h" 35 #include "ui/gfx/screen.h"
34 #include "views/widget/native_widget_gtk.h" 36 #include "views/widget/native_widget_gtk.h"
35 37
36 namespace { 38 namespace {
37 39
38 // URL which corresponds to the login WebUI. 40 // URL which corresponds to the login WebUI.
39 const char kLoginURL[] = "chrome://oobe/login"; 41 const char kLoginURL[] = "chrome://oobe/login";
40 42
43 // The maximum duration for which locker should try to grab the keyboard and
44 // mouse and its interval for regrabbing on failure.
45 const int kMaxGrabFailureSec = 30;
46 const int64 kRetryGrabIntervalMs = 500;
47
48 // Maximum number of times we'll try to grab the keyboard and mouse before
49 // giving up. If we hit the limit, Chrome exits and the session is terminated.
50 const int kMaxGrabFailures = kMaxGrabFailureSec * 1000 / kRetryGrabIntervalMs;
51
41 // A ScreenLock window that covers entire screen to keep the keyboard 52 // A ScreenLock window that covers entire screen to keep the keyboard
42 // focus/events inside the grab widget. 53 // focus/events inside the grab widget.
43 class LockWindow : public views::NativeWidgetGtk { 54 class LockWindow : public views::NativeWidgetGtk {
44 public: 55 public:
45 LockWindow() 56 explicit LockWindow(chromeos::WebUIScreenLocker* webui_screen_locker)
46 : views::NativeWidgetGtk(new views::Widget), 57 : views::NativeWidgetGtk(new views::Widget),
47 toplevel_focus_widget_(NULL) { 58 webui_screen_locker_(webui_screen_locker),
59 toplevel_focus_widget_(NULL),
60 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
61 grab_failure_count_(0),
62 kbd_grab_status_(GDK_GRAB_INVALID_TIME),
63 mouse_grab_status_(GDK_GRAB_INVALID_TIME) {
48 EnableDoubleBuffer(true); 64 EnableDoubleBuffer(true);
49 } 65 }
50 66
51 // GTK propagates key events from parents to children.
52 // Make sure LockWindow will never handle key events.
53 virtual gboolean OnEventKey(GtkWidget* widget, GdkEventKey* event) OVERRIDE {
54 // Don't handle key event in the lock window.
55 return false;
56 }
57
58 virtual gboolean OnButtonPress(GtkWidget* widget, 67 virtual gboolean OnButtonPress(GtkWidget* widget,
59 GdkEventButton* event) OVERRIDE { 68 GdkEventButton* event) OVERRIDE {
60 // Don't handle mouse event in the lock wnidow and 69 // Never propagate mouse events to parent.
61 // nor propagate to child.
62 return true; 70 return true;
63 } 71 }
64 72
65 virtual void OnDestroy(GtkWidget* object) OVERRIDE { 73 virtual void OnDestroy(GtkWidget* object) OVERRIDE {
66 VLOG(1) << "OnDestroy: LockWindow destroyed"; 74 VLOG(1) << "OnDestroy: LockWindow destroyed";
67 views::NativeWidgetGtk::OnDestroy(object); 75 views::NativeWidgetGtk::OnDestroy(object);
68 } 76 }
69 77
70 virtual void ClearNativeFocus() OVERRIDE { 78 virtual void ClearNativeFocus() OVERRIDE {
71 DCHECK(toplevel_focus_widget_); 79 DCHECK(toplevel_focus_widget_);
72 gtk_widget_grab_focus(toplevel_focus_widget_); 80 gtk_widget_grab_focus(toplevel_focus_widget_);
73 } 81 }
74 82
75 // Sets the widget to move the focus to when clearning the native 83 // Sets the widget to move the focus to when clearning the native
76 // widget's focus. 84 // widget's focus.
77 void set_toplevel_focus_widget(GtkWidget* widget) { 85 void set_toplevel_focus_widget(GtkWidget* widget) {
78 gtk_widget_set_can_focus(widget, TRUE); 86 gtk_widget_set_can_focus(widget, TRUE);
79 toplevel_focus_widget_ = widget; 87 toplevel_focus_widget_ = widget;
80 } 88 }
81 89
90 void ClearGtkGrab() {
91 GtkWidget* current_grab_window;
92 // Grab gtk input first so that the menu holding gtk grab will
93 // close itself.
94 gtk_grab_add(window_contents());
95
96 // Make sure there is no gtk grab widget so that gtk simply propagates
97 // an event. This is necessary to allow message bubble and password
98 // field, button to process events simultaneously. GTK
99 // maintains grab widgets in a linked-list, so we need to remove
100 // until it's empty.
101 while ((current_grab_window = gtk_grab_get_current()) != NULL)
102 gtk_grab_remove(current_grab_window);
103 }
104
105 // Try to grab all inputs. It initiates another try if it fails to
106 // grab and the retry count is within a limit, or fails with CHECK.
107 void TryGrabAllInputs();
108
109 // This method tries to steal pointer/keyboard grab from other
110 // client by sending events that will hopefully close menus or windows
111 // that have the grab.
112 void TryUngrabOtherClients();
113
82 private: 114 private:
115 virtual void HandleGtkGrabBroke() OVERRIDE {
116 // Input should never be stolen from ScreenLocker once it's
117 // grabbed. If this happens, it's a bug and has to be fixed. We
118 // let chrome crash to get a crash report and dump, and
119 // SessionManager will terminate the session to logout.
120 CHECK_NE(GDK_GRAB_SUCCESS, kbd_grab_status_);
121 CHECK_NE(GDK_GRAB_SUCCESS, mouse_grab_status_);
122 }
123
124 // Define separate methods for each error code so that stack trace
125 // will tell which error the grab failed with.
126 void FailedWithGrabAlreadyGrabbed() {
127 LOG(FATAL) << "Grab already grabbed";
128 }
129 void FailedWithGrabInvalidTime() {
130 LOG(FATAL) << "Grab invalid time";
131 }
132 void FailedWithGrabNotViewable() {
133 LOG(FATAL) << "Grab not viewable";
134 }
135 void FailedWithGrabFrozen() {
136 LOG(FATAL) << "Grab frozen";
137 }
138 void FailedWithUnknownError() {
139 LOG(FATAL) << "Grab uknown";
140 }
141
142 chromeos::WebUIScreenLocker* webui_screen_locker_;
143
83 // The widget we set focus to when clearning the focus on native 144 // The widget we set focus to when clearning the focus on native
84 // widget. In screen locker, gdk input is grabbed in GrabWidget, 145 // widget. Gdk input is grabbed in this class, and resetting the focus
85 // and resetting the focus by using gtk_window_set_focus seems to 146 // by using gtk_window_set_focus seems to confuse gtk and doesn't let focus
86 // confuse gtk and doesn't let focus move to native widget under 147 // move to native widget under this.
87 // GrabWidget.
88 GtkWidget* toplevel_focus_widget_; 148 GtkWidget* toplevel_focus_widget_;
89 149
150 base::WeakPtrFactory<LockWindow> weak_factory_;
151
152 // The number times the widget tried to grab all focus.
153 int grab_failure_count_;
oshima 2011/11/18 17:22:06 new line after this
flackr 2011/11/18 21:49:09 Done.
154 // Status of keyboard and mouse grab.
155 GdkGrabStatus kbd_grab_status_;
156 GdkGrabStatus mouse_grab_status_;
157
90 DISALLOW_COPY_AND_ASSIGN(LockWindow); 158 DISALLOW_COPY_AND_ASSIGN(LockWindow);
91 }; 159 };
92 160
161 void LockWindow::TryGrabAllInputs() {
162 // Grab on the RenderWidgetHostView hosting the WebUI login screen.
163 GdkWindow* grabWidget = webui_screen_locker_->dom_view()->dom_contents()->
sadrul 2011/11/18 17:36:17 ew! grab_widget
flackr 2011/11/18 21:49:09 Done. Forgive me!
164 tab_contents()->GetRenderWidgetHostView()->GetNativeView()->window;
oshima 2011/11/18 17:22:06 Am I correct that grabbing input doesn't require s
flackr 2011/11/18 21:49:09 Done.
165 // Grab x server so that we can atomically grab and take
166 // action when grab fails.
167 gdk_x11_grab_server();
168 gtk_grab_add(webui_screen_locker_->dom_view()->native_view());
oshima 2011/11/18 17:22:06 Have you tried using this dom_view()->native_view(
flackr 2011/11/18 21:49:09 I have, this didn't work.
169 if (kbd_grab_status_ != GDK_GRAB_SUCCESS) {
170 kbd_grab_status_ = gdk_keyboard_grab(grabWidget, FALSE, GDK_CURRENT_TIME);
171 }
oshima 2011/11/18 17:22:06 nuke {}
flackr 2011/11/18 21:49:09 Done. The following if is a single statement, but
oshima 2011/11/18 22:44:55 correct
172 if (mouse_grab_status_ != GDK_GRAB_SUCCESS) {
173 mouse_grab_status_ =
174 gdk_pointer_grab(grabWidget,
175 FALSE,
176 static_cast<GdkEventMask>(
177 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
178 GDK_POINTER_MOTION_MASK),
179 NULL,
180 NULL,
181 GDK_CURRENT_TIME);
182 }
183 if ((kbd_grab_status_ != GDK_GRAB_SUCCESS ||
184 mouse_grab_status_ != GDK_GRAB_SUCCESS) &&
185 grab_failure_count_++ < kMaxGrabFailures) {
186 LOG(WARNING) << "Failed to grab inputs. Trying again in "
187 << kRetryGrabIntervalMs << " ms: kbd="
188 << kbd_grab_status_ << ", mouse=" << mouse_grab_status_;
189 TryUngrabOtherClients();
190 gdk_x11_ungrab_server();
191 MessageLoop::current()->PostDelayedTask(
192 FROM_HERE,
193 base::Bind(&LockWindow::TryGrabAllInputs, weak_factory_.GetWeakPtr()),
194 kRetryGrabIntervalMs);
195 } else {
196 gdk_x11_ungrab_server();
197 GdkGrabStatus status = kbd_grab_status_;
198 if (status == GDK_GRAB_SUCCESS) {
199 status = mouse_grab_status_;
200 }
201 switch (status) {
202 case GDK_GRAB_SUCCESS:
203 break;
204 case GDK_GRAB_ALREADY_GRABBED:
205 FailedWithGrabAlreadyGrabbed();
206 break;
207 case GDK_GRAB_INVALID_TIME:
208 FailedWithGrabInvalidTime();
209 break;
210 case GDK_GRAB_NOT_VIEWABLE:
211 FailedWithGrabNotViewable();
212 break;
213 case GDK_GRAB_FROZEN:
214 FailedWithGrabFrozen();
215 break;
216 default:
217 FailedWithUnknownError();
218 break;
219 }
220 DVLOG(1) << "Grab Success";
221 webui_screen_locker_->OnGrabInputs();
222 }
223 }
224
225 void LockWindow::TryUngrabOtherClients() {
226 #if !defined(NDEBUG)
227 {
228 int event_base, error_base;
229 int major, minor;
230 // Make sure we have XTest extension.
231 DCHECK(XTestQueryExtension(ui::GetXDisplay(),
232 &event_base, &error_base,
233 &major, &minor));
234 }
235 #endif
236
237 // The following code is an attempt to grab inputs by closing
238 // supposedly opened menu. This happens when a plugin has a menu
239 // opened.
240 if (mouse_grab_status_ == GDK_GRAB_ALREADY_GRABBED ||
241 mouse_grab_status_ == GDK_GRAB_FROZEN) {
242 // Successfully grabbed the keyboard, but pointer is still
243 // grabbed by other client. Another attempt to close supposedly
244 // opened menu by emulating keypress at the left top corner.
245 Display* display = ui::GetXDisplay();
246 Window root, child;
247 int root_x, root_y, win_x, winy;
248 unsigned int mask;
249 XQueryPointer(display,
250 ui::GetX11WindowFromGtkWidget(window_contents()),
251 &root, &child, &root_x, &root_y,
252 &win_x, &winy, &mask);
253 XTestFakeMotionEvent(display, -1, -10000, -10000, CurrentTime);
254 XTestFakeButtonEvent(display, 1, True, CurrentTime);
255 XTestFakeButtonEvent(display, 1, False, CurrentTime);
256 // Move the pointer back.
257 XTestFakeMotionEvent(display, -1, root_x, root_y, CurrentTime);
258 XFlush(display);
259 } else if (kbd_grab_status_ == GDK_GRAB_ALREADY_GRABBED ||
260 kbd_grab_status_ == GDK_GRAB_FROZEN) {
261 // Successfully grabbed the pointer, but keyboard is still grabbed
262 // by other client. Another attempt to close supposedly opened
263 // menu by emulating escape key. Such situation must be very
264 // rare, but handling this just in case
265 Display* display = ui::GetXDisplay();
266 KeyCode escape = XKeysymToKeycode(display, XK_Escape);
267 XTestFakeKeyEvent(display, escape, True, CurrentTime);
268 XTestFakeKeyEvent(display, escape, False, CurrentTime);
269 XFlush(display);
270 }
271 }
272
93 } // namespace 273 } // namespace
94 274
95 namespace chromeos { 275 namespace chromeos {
96 276
97 //////////////////////////////////////////////////////////////////////////////// 277 ////////////////////////////////////////////////////////////////////////////////
98 // WebUIScreenLocker implementation. 278 // WebUIScreenLocker implementation.
99 279
100 WebUIScreenLocker::WebUIScreenLocker(ScreenLocker* screen_locker) 280 WebUIScreenLocker::WebUIScreenLocker(ScreenLocker* screen_locker)
101 : ScreenLockerDelegate(screen_locker) { 281 : ScreenLockerDelegate(screen_locker),
282 drawn_(false),
283 input_grabbed_(false) {
102 } 284 }
103 285
104 void WebUIScreenLocker::LockScreen(bool unlock_on_input) { 286 void WebUIScreenLocker::LockScreen(bool unlock_on_input) {
105 static const GdkColor kGdkBlack = {0, 0, 0, 0}; 287 static const GdkColor kGdkBlack = {0, 0, 0, 0};
106 288
107 gfx::Rect bounds(gfx::Screen::GetMonitorAreaNearestWindow(NULL)); 289 gfx::Rect bounds(gfx::Screen::GetMonitorAreaNearestWindow(NULL));
108 290
109 LockWindow* lock_window = new LockWindow(); 291 LockWindow* lock_window = new LockWindow(this);
110 lock_window_ = lock_window->GetWidget(); 292 lock_window_ = lock_window->GetWidget();
111 views::Widget::InitParams params( 293 views::Widget::InitParams params(
112 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); 294 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
113 params.bounds = bounds; 295 params.bounds = bounds;
114 params.native_widget = lock_window; 296 params.native_widget = lock_window;
115 lock_window_->Init(params); 297 lock_window_->Init(params);
116 gtk_widget_modify_bg( 298 gtk_widget_modify_bg(
117 lock_window_->GetNativeView(), GTK_STATE_NORMAL, &kGdkBlack); 299 lock_window_->GetNativeView(), GTK_STATE_NORMAL, &kGdkBlack);
118 300
119 g_signal_connect(lock_window_->GetNativeView(), "client-event", 301 g_signal_connect(lock_window_->GetNativeView(), "client-event",
(...skipping 19 matching lines...) Expand all
139 login_display_->set_parent_window( 321 login_display_->set_parent_window(
140 GTK_WINDOW(lock_window_->GetNativeView())); 322 GTK_WINDOW(lock_window_->GetNativeView()));
141 login_display_->Init(users, false, false); 323 login_display_->Init(users, false, false);
142 324
143 static_cast<OobeUI*>(GetWebUI())->ShowSigninScreen(login_display_.get()); 325 static_cast<OobeUI*>(GetWebUI())->ShowSigninScreen(login_display_.get());
144 326
145 registrar_.Add(this, 327 registrar_.Add(this,
146 chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED, 328 chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
147 content::NotificationService::AllSources()); 329 content::NotificationService::AllSources());
148 330
331 lock_window->ClearGtkGrab();
332
333 // Call this after lock_window_->Show(); otherwise the 1st invocation
334 // of gdk_xxx_grab() will always fail.
335 lock_window->TryGrabAllInputs();
336
149 // Add the window to its own group so that its grab won't be stolen if 337 // Add the window to its own group so that its grab won't be stolen if
150 // gtk_grab_add() gets called on behalf on a non-screen-locker widget (e.g. 338 // gtk_grab_add() gets called on behalf on a non-screen-locker widget (e.g.
151 // a modal dialog) -- see http://crosbug.com/8999. We intentionally do this 339 // a modal dialog) -- see http://crosbug.com/8999. We intentionally do this
152 // after calling ClearGtkGrab(), as want to be in the default window group 340 // after calling ClearGtkGrab(), as want to be in the default window group
153 // then so we can break any existing GTK grabs. 341 // then so we can break any existing GTK grabs.
154 GtkWindowGroup* window_group = gtk_window_group_new(); 342 GtkWindowGroup* window_group = gtk_window_group_new();
155 gtk_window_group_add_window(window_group, 343 gtk_window_group_add_window(window_group,
156 GTK_WINDOW(lock_window_->GetNativeView())); 344 GTK_WINDOW(lock_window_->GetNativeView()));
157 g_object_unref(window_group); 345 g_object_unref(window_group);
158 346
159 lock_window->set_toplevel_focus_widget(lock_window->window_contents()); 347 lock_window->set_toplevel_focus_widget(lock_window->window_contents());
160 } 348 }
161 349
350 void WebUIScreenLocker::OnGrabInputs() {
351 DVLOG(1) << "OnGrabInputs";
352 input_grabbed_ = true;
353 if (drawn_)
354 ScreenLockReady();
355 }
356
357 void WebUIScreenLocker::OnWindowManagerReady() {
358 DVLOG(1) << "OnClientEvent: drawn for lock";
359 drawn_ = true;
360 if (input_grabbed_)
361 ScreenLockReady();
362 }
363
162 void WebUIScreenLocker::ScreenLockReady() { 364 void WebUIScreenLocker::ScreenLockReady() {
163 ScreenLockerDelegate::ScreenLockReady(); 365 ScreenLockerDelegate::ScreenLockReady();
164 SetInputEnabled(true); 366 SetInputEnabled(true);
165 } 367 }
166 368
167 void WebUIScreenLocker::OnAuthenticate() { 369 void WebUIScreenLocker::OnAuthenticate() {
168 } 370 }
169 371
170 void WebUIScreenLocker::SetInputEnabled(bool enabled) { 372 void WebUIScreenLocker::SetInputEnabled(bool enabled) {
171 login_display_->SetUIEnabled(enabled); 373 login_display_->SetUIEnabled(enabled);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
203 405
204 WebUIScreenLocker::~WebUIScreenLocker() { 406 WebUIScreenLocker::~WebUIScreenLocker() {
205 DCHECK(lock_window_); 407 DCHECK(lock_window_);
206 lock_window_->Close(); 408 lock_window_->Close();
207 } 409 }
208 410
209 void WebUIScreenLocker::OnClientEvent(GtkWidget* widge, GdkEventClient* event) { 411 void WebUIScreenLocker::OnClientEvent(GtkWidget* widge, GdkEventClient* event) {
210 WmIpc::Message msg; 412 WmIpc::Message msg;
211 WmIpc::instance()->DecodeMessage(*event, &msg); 413 WmIpc::instance()->DecodeMessage(*event, &msg);
212 if (msg.type() == WM_IPC_MESSAGE_CHROME_NOTIFY_SCREEN_REDRAWN_FOR_LOCK) 414 if (msg.type() == WM_IPC_MESSAGE_CHROME_NOTIFY_SCREEN_REDRAWN_FOR_LOCK)
213 ScreenLockReady(); 415 OnWindowManagerReady();
214 } 416 }
215 417
216 //////////////////////////////////////////////////////////////////////////////// 418 ////////////////////////////////////////////////////////////////////////////////
217 // WebUIScreenLocker, content::NotificationObserver implementation: 419 // WebUIScreenLocker, content::NotificationObserver implementation:
218 420
219 void WebUIScreenLocker::Observe( 421 void WebUIScreenLocker::Observe(
220 int type, 422 int type,
221 const content::NotificationSource& source, 423 const content::NotificationSource& source,
222 const content::NotificationDetails& details) { 424 const content::NotificationDetails& details) {
223 if (type != chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED) 425 if (type != chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED)
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
260 } 462 }
261 463
262 void WebUIScreenLocker::OnUserSelected(const std::string& username) { 464 void WebUIScreenLocker::OnUserSelected(const std::string& username) {
263 } 465 }
264 466
265 void WebUIScreenLocker::OnStartEnterpriseEnrollment() { 467 void WebUIScreenLocker::OnStartEnterpriseEnrollment() {
266 NOTREACHED(); 468 NOTREACHED();
267 } 469 }
268 470
269 } // namespace chromeos 471 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698