OLD | NEW |
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/screen_locker_views.h" | 5 #include "chrome/browser/chromeos/login/screen_locker_views.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> |
(...skipping 13 matching lines...) Expand all Loading... |
24 #include "chrome/browser/chromeos/status/status_area_view_chromeos.h" | 24 #include "chrome/browser/chromeos/status/status_area_view_chromeos.h" |
25 #include "chrome/browser/chromeos/view_ids.h" | 25 #include "chrome/browser/chromeos/view_ids.h" |
26 #include "chrome/browser/prefs/pref_service.h" | 26 #include "chrome/browser/prefs/pref_service.h" |
27 #include "chrome/common/chrome_switches.h" | 27 #include "chrome/common/chrome_switches.h" |
28 #include "chrome/common/pref_names.h" | 28 #include "chrome/common/pref_names.h" |
29 #include "content/browser/user_metrics.h" | 29 #include "content/browser/user_metrics.h" |
30 #include "grit/theme_resources.h" | 30 #include "grit/theme_resources.h" |
31 #include "ui/base/resource/resource_bundle.h" | 31 #include "ui/base/resource/resource_bundle.h" |
32 #include "ui/base/x/x11_util.h" | 32 #include "ui/base/x/x11_util.h" |
33 #include "ui/gfx/screen.h" | 33 #include "ui/gfx/screen.h" |
| 34 #include "views/controls/textfield/textfield.h" |
34 | 35 |
35 #if defined(TOOLKIT_USES_GTK) | 36 #if defined(TOOLKIT_USES_GTK) |
36 #include "chrome/browser/chromeos/legacy_window_manager/wm_ipc.h" | 37 #include "chrome/browser/chromeos/legacy_window_manager/wm_ipc.h" |
| 38 #include "views/widget/native_widget_gtk.h" |
37 #endif | 39 #endif |
38 | 40 |
39 namespace { | 41 namespace { |
40 | 42 |
41 // The active ScreenLockerDelegate. | 43 // The active ScreenLockerDelegate. |
42 chromeos::ScreenLockerViews* screen_locker_view_ = NULL; | 44 chromeos::ScreenLockerViews* screen_locker_view_ = NULL; |
43 | 45 |
44 // The maximum duration for which locker should try to grab the keyboard and | 46 // The maximum duration for which locker should try to grab the keyboard and |
45 // mouse and its interval for regrabbing on failure. | 47 // mouse and its interval for regrabbing on failure. |
46 const int kMaxGrabFailureSec = 30; | 48 const int kMaxGrabFailureSec = 30; |
47 const int64 kRetryGrabIntervalMs = 500; | 49 const int64 kRetryGrabIntervalMs = 500; |
48 | 50 |
49 // Maximum number of times we'll try to grab the keyboard and mouse before | 51 // Maximum number of times we'll try to grab the keyboard and mouse before |
50 // giving up. If we hit the limit, Chrome exits and the session is terminated. | 52 // giving up. If we hit the limit, Chrome exits and the session is terminated. |
51 const int kMaxGrabFailures = kMaxGrabFailureSec * 1000 / kRetryGrabIntervalMs; | 53 const int kMaxGrabFailures = kMaxGrabFailureSec * 1000 / kRetryGrabIntervalMs; |
52 | 54 |
53 // A idle time to show the screen saver in seconds. | 55 // A idle time to show the screen saver in seconds. |
54 const int kScreenSaverIdleTimeout = 15; | 56 const int kScreenSaverIdleTimeout = 15; |
55 | 57 |
56 // A ScreenLock window that covers entire screen to keep the keyboard | 58 // A ScreenLock window that covers entire screen to keep the keyboard |
57 // focus/events inside the grab widget. | 59 // focus/events inside the grab widget. |
58 class LockWindow : public views::NativeWidgetGtk { | 60 class LockWindow : public views::NativeWidgetGtk { |
59 public: | 61 public: |
60 LockWindow() | 62 LockWindow() |
61 : views::NativeWidgetGtk(new views::Widget), | 63 : views::NativeWidgetGtk(new views::Widget), |
62 toplevel_focus_widget_(NULL) { | 64 toplevel_focus_widget_(NULL) { |
63 EnableDoubleBuffer(true); | 65 EnableDoubleBuffer(true); |
| 66 g_signal_connect(GetNativeView(), "client-event", |
| 67 G_CALLBACK(OnClientEventThunk), this); |
64 } | 68 } |
65 | 69 |
66 // GTK propagates key events from parents to children. | 70 // GTK propagates key events from parents to children. |
67 // Make sure LockWindow will never handle key events. | 71 // Make sure LockWindow will never handle key events. |
68 virtual gboolean OnEventKey(GtkWidget* widget, GdkEventKey* event) OVERRIDE { | 72 virtual gboolean OnEventKey(GtkWidget* widget, GdkEventKey* event) OVERRIDE { |
69 // Don't handle key event in the lock window. | 73 // Don't handle key event in the lock window. |
70 return false; | 74 return false; |
71 } | 75 } |
72 | 76 |
73 virtual gboolean OnButtonPress(GtkWidget* widget, | 77 virtual gboolean OnButtonPress(GtkWidget* widget, |
74 GdkEventButton* event) OVERRIDE { | 78 GdkEventButton* event) OVERRIDE { |
75 // Don't handle mouse event in the lock wnidow and | 79 // Don't handle mouse event in the lock wnidow and |
76 // nor propagate to child. | 80 // nor propagate to child. |
77 return true; | 81 return true; |
78 } | 82 } |
79 | 83 |
80 virtual void OnDestroy(GtkWidget* object) OVERRIDE { | 84 virtual void OnDestroy(GtkWidget* object) OVERRIDE { |
81 VLOG(1) << "OnDestroy: LockWindow destroyed"; | 85 VLOG(1) << "OnDestroy: LockWindow destroyed"; |
82 views::NativeWidgetGtk::OnDestroy(object); | 86 views::NativeWidgetGtk::OnDestroy(object); |
83 } | 87 } |
84 | 88 |
85 virtual void ClearNativeFocus() OVERRIDE { | 89 virtual void ClearNativeFocus() OVERRIDE { |
86 DCHECK(toplevel_focus_widget_); | 90 DCHECK(toplevel_focus_widget_); |
87 gtk_widget_grab_focus(toplevel_focus_widget_); | 91 gtk_widget_grab_focus(toplevel_focus_widget_); |
88 } | 92 } |
89 | 93 |
| 94 // Event handler for client-event. |
| 95 CHROMEGTK_CALLBACK_1(LockWindow, void, OnClientEvent, GdkEventClient*); |
| 96 |
90 // Sets the widget to move the focus to when clearning the native | 97 // Sets the widget to move the focus to when clearning the native |
91 // widget's focus. | 98 // widget's focus. |
92 void set_toplevel_focus_widget(GtkWidget* widget) { | 99 void set_toplevel_focus_widget(GtkWidget* widget) { |
93 gtk_widget_set_can_focus(widget, TRUE); | 100 gtk_widget_set_can_focus(widget, TRUE); |
94 toplevel_focus_widget_ = widget; | 101 toplevel_focus_widget_ = widget; |
95 } | 102 } |
96 | 103 |
97 private: | 104 private: |
98 // The widget we set focus to when clearning the focus on native | 105 // The widget we set focus to when clearning the focus on native |
99 // widget. In screen locker, gdk input is grabbed in GrabWidget, | 106 // widget. In screen locker, gdk input is grabbed in GrabWidget, |
100 // and resetting the focus by using gtk_window_set_focus seems to | 107 // and resetting the focus by using gtk_window_set_focus seems to |
101 // confuse gtk and doesn't let focus move to native widget under | 108 // confuse gtk and doesn't let focus move to native widget under |
102 // GrabWidget. | 109 // GrabWidget. |
103 GtkWidget* toplevel_focus_widget_; | 110 GtkWidget* toplevel_focus_widget_; |
104 | 111 |
105 DISALLOW_COPY_AND_ASSIGN(LockWindow); | 112 DISALLOW_COPY_AND_ASSIGN(LockWindow); |
106 }; | 113 }; |
107 | 114 |
| 115 void LockWindow::OnClientEvent(GtkWidget* widget, GdkEventClient* event) { |
| 116 #if defined(TOOLKIT_USES_GTK) |
| 117 chromeos::WmIpc::Message msg; |
| 118 chromeos::WmIpc::instance()->DecodeMessage(*event, &msg); |
| 119 if (msg.type() == |
| 120 chromeos::WM_IPC_MESSAGE_CHROME_NOTIFY_SCREEN_REDRAWN_FOR_LOCK) { |
| 121 screen_locker_view_->OnWindowManagerReady(); |
| 122 } |
| 123 #endif |
| 124 } |
| 125 |
108 // GrabWidget's root view to layout the ScreenLockView at the center | 126 // GrabWidget's root view to layout the ScreenLockView at the center |
109 // and the Shutdown button at the left top. | 127 // and the Shutdown button at the left top. |
110 class GrabWidgetRootView | 128 class GrabWidgetRootView |
111 : public views::View, | 129 : public views::View, |
112 public chromeos::ScreenLockerViews::ScreenLockViewContainer { | 130 public chromeos::ScreenLockerViews::ScreenLockViewContainer { |
113 public: | 131 public: |
114 explicit GrabWidgetRootView(chromeos::ScreenLockView* screen_lock_view) | 132 explicit GrabWidgetRootView(chromeos::ScreenLockView* screen_lock_view) |
115 : screen_lock_view_(screen_lock_view), | 133 : screen_lock_view_(screen_lock_view), |
116 shutdown_button_(new chromeos::ShutdownButton()) { | 134 shutdown_button_(new chromeos::ShutdownButton()) { |
117 shutdown_button_->Init(); | 135 shutdown_button_->Init(); |
(...skipping 491 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
609 LockWindow* lock_window = new LockWindow(); | 627 LockWindow* lock_window = new LockWindow(); |
610 lock_window_ = lock_window->GetWidget(); | 628 lock_window_ = lock_window->GetWidget(); |
611 views::Widget::InitParams params( | 629 views::Widget::InitParams params( |
612 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); | 630 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); |
613 params.bounds = init_bounds; | 631 params.bounds = init_bounds; |
614 params.native_widget = lock_window; | 632 params.native_widget = lock_window; |
615 lock_window_->Init(params); | 633 lock_window_->Init(params); |
616 gtk_widget_modify_bg( | 634 gtk_widget_modify_bg( |
617 lock_window_->GetNativeView(), GTK_STATE_NORMAL, &kGdkBlack); | 635 lock_window_->GetNativeView(), GTK_STATE_NORMAL, &kGdkBlack); |
618 | 636 |
619 g_signal_connect(lock_window_->GetNativeView(), "client-event", | |
620 G_CALLBACK(OnClientEventThunk), this); | |
621 | |
622 // GTK does not like zero width/height. | 637 // GTK does not like zero width/height. |
623 if (!unlock_on_input) { | 638 if (!unlock_on_input) { |
624 screen_lock_view_ = new ScreenLockView(screen_locker_); | 639 screen_lock_view_ = new ScreenLockView(screen_locker_); |
625 screen_lock_view_->Init(); | 640 screen_lock_view_->Init(); |
626 screen_lock_view_->SetEnabled(false); | 641 screen_lock_view_->SetEnabled(false); |
627 screen_lock_view_->StartThrobber(); | 642 screen_lock_view_->StartThrobber(); |
628 } else { | 643 } else { |
629 input_event_observer_.reset(new InputEventObserver(screen_locker_)); | 644 input_event_observer_.reset(new InputEventObserver(screen_locker_)); |
630 MessageLoopForUI::current()->AddObserver(input_event_observer_.get()); | 645 MessageLoopForUI::current()->AddObserver(input_event_observer_.get()); |
631 } | 646 } |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
799 ignore_result(secondary_view_.release()); | 814 ignore_result(secondary_view_.release()); |
800 screen_lock_view_->SetVisible(false); | 815 screen_lock_view_->SetVisible(false); |
801 grab_container_->SetScreenLockView(captcha_view_); | 816 grab_container_->SetScreenLockView(captcha_view_); |
802 background_container_->SetScreenLockView(captcha_view_); | 817 background_container_->SetScreenLockView(captcha_view_); |
803 captcha_view_->SetVisible(true); | 818 captcha_view_->SetVisible(true); |
804 // Take ScreenLockView ownership now that it's removed from grab_container_. | 819 // Take ScreenLockView ownership now that it's removed from grab_container_. |
805 secondary_view_.reset(screen_lock_view_); | 820 secondary_view_.reset(screen_lock_view_); |
806 } | 821 } |
807 | 822 |
808 void ScreenLockerViews::ClearErrors() { | 823 void ScreenLockerViews::ClearErrors() { |
809 if (error_info_) { | 824 if (error_info_) |
810 error_info_->Close(); | 825 error_info_->GetWidget()->Close(); |
811 error_info_ = NULL; | |
812 } | |
813 } | 826 } |
814 | 827 |
815 void ScreenLockerViews::BubbleClosing(Bubble* bubble, bool closed_by_escape) { | 828 void ScreenLockerViews::OnWidgetClosing(views::Widget* widget) { |
| 829 if (!error_info_ || error_info_->GetWidget() != widget) |
| 830 return; |
| 831 |
816 error_info_ = NULL; | 832 error_info_ = NULL; |
817 SetSignoutEnabled(true); | 833 SetSignoutEnabled(true); |
818 if (mouse_event_relay_.get()) { | 834 if (mouse_event_relay_.get()) { |
819 MessageLoopForUI::current()->RemoveObserver(mouse_event_relay_.get()); | 835 MessageLoopForUI::current()->RemoveObserver(mouse_event_relay_.get()); |
820 mouse_event_relay_.reset(); | 836 mouse_event_relay_.reset(); |
821 } | 837 } |
822 } | 838 } |
823 | 839 |
824 bool ScreenLockerViews::CloseOnEscape() { | |
825 return true; | |
826 } | |
827 | |
828 bool ScreenLockerViews::FadeInOnShow() { | |
829 return false; | |
830 } | |
831 | |
832 void ScreenLockerViews::OnLinkActivated(size_t index) { | |
833 } | |
834 | |
835 void ScreenLockerViews::OnCaptchaEntered(const std::string& captcha) { | 840 void ScreenLockerViews::OnCaptchaEntered(const std::string& captcha) { |
836 // Captcha dialog is only shown when LoginPerformer instance exists, | 841 // Captcha dialog is only shown when LoginPerformer instance exists, |
837 // i.e. blocking UI after password change is in place. | 842 // i.e. blocking UI after password change is in place. |
838 DCHECK(LoginPerformer::default_performer()); | 843 DCHECK(LoginPerformer::default_performer()); |
839 LoginPerformer::default_performer()->set_captcha(captcha); | 844 LoginPerformer::default_performer()->set_captcha(captcha); |
840 | 845 |
841 // ScreenLockView ownership is passed to grab_container_. | 846 // ScreenLockView ownership is passed to grab_container_. |
842 // Need to save return value here so that compile | 847 // Need to save return value here so that compile |
843 // doesn't fail with "unused result" warning. | 848 // doesn't fail with "unused result" warning. |
844 ignore_result(secondary_view_.release()); | 849 ignore_result(secondary_view_.release()); |
845 captcha_view_->SetVisible(false); | 850 captcha_view_->SetVisible(false); |
846 grab_container_->SetScreenLockView(screen_lock_view_); | 851 grab_container_->SetScreenLockView(screen_lock_view_); |
847 background_container_->SetScreenLockView(screen_lock_view_); | 852 background_container_->SetScreenLockView(screen_lock_view_); |
848 screen_lock_view_->SetVisible(true); | 853 screen_lock_view_->SetVisible(true); |
849 screen_lock_view_->ClearAndSetFocusToPassword(); | 854 screen_lock_view_->ClearAndSetFocusToPassword(); |
850 | 855 |
851 // Take CaptchaView ownership now that it's removed from grab_container_. | 856 // Take CaptchaView ownership now that it's removed from grab_container_. |
852 secondary_view_.reset(captcha_view_); | 857 secondary_view_.reset(captcha_view_); |
853 ShowErrorMessage(postponed_error_message_, false); | 858 ShowErrorMessage(postponed_error_message_, false); |
854 postponed_error_message_.clear(); | 859 postponed_error_message_.clear(); |
855 } | 860 } |
856 | 861 |
| 862 void ScreenLockerViews::OnWindowManagerReady() { |
| 863 DVLOG(1) << "OnClientEvent: drawn for lock"; |
| 864 drawn_ = true; |
| 865 if (input_grabbed_) |
| 866 ScreenLockReady(); |
| 867 } |
| 868 |
857 ScreenLockerViews::~ScreenLockerViews() { | 869 ScreenLockerViews::~ScreenLockerViews() { |
858 if (input_event_observer_.get()) | 870 if (input_event_observer_.get()) |
859 MessageLoopForUI::current()->RemoveObserver(input_event_observer_.get()); | 871 MessageLoopForUI::current()->RemoveObserver(input_event_observer_.get()); |
860 if (locker_input_event_observer_.get()) { | 872 if (locker_input_event_observer_.get()) { |
861 lock_widget_->GetFocusManager()->UnregisterAccelerator( | 873 lock_widget_->GetFocusManager()->UnregisterAccelerator( |
862 ui::Accelerator(ui::VKEY_ESCAPE, false, false, false), this); | 874 ui::Accelerator(ui::VKEY_ESCAPE, false, false, false), this); |
863 MessageLoopForUI::current()->RemoveObserver( | 875 MessageLoopForUI::current()->RemoveObserver( |
864 locker_input_event_observer_.get()); | 876 locker_input_event_observer_.get()); |
865 } | 877 } |
866 | 878 |
867 gdk_keyboard_ungrab(GDK_CURRENT_TIME); | 879 gdk_keyboard_ungrab(GDK_CURRENT_TIME); |
868 gdk_pointer_ungrab(GDK_CURRENT_TIME); | 880 gdk_pointer_ungrab(GDK_CURRENT_TIME); |
869 | 881 |
870 DCHECK(lock_window_); | 882 DCHECK(lock_window_); |
871 VLOG(1) << "~ScreenLocker(): Closing ScreenLocker window."; | 883 VLOG(1) << "~ScreenLocker(): Closing ScreenLocker window."; |
872 lock_window_->Close(); | 884 lock_window_->Close(); |
873 // lock_widget_ will be deleted by gtk's destroy signal. | 885 // lock_widget_ will be deleted by gtk's destroy signal. |
874 screen_locker_view_ = NULL; | 886 screen_locker_view_ = NULL; |
875 } | 887 } |
876 | 888 |
877 void ScreenLockerViews::OnWindowManagerReady() { | |
878 DVLOG(1) << "OnClientEvent: drawn for lock"; | |
879 drawn_ = true; | |
880 if (input_grabbed_) | |
881 ScreenLockReady(); | |
882 } | |
883 | |
884 void ScreenLockerViews::ShowErrorBubble( | 889 void ScreenLockerViews::ShowErrorBubble( |
885 const string16& message, | 890 const string16& message, |
886 views::BubbleBorder::ArrowLocation arrow_location) { | 891 views::BubbleBorder::ArrowLocation arrow_location) { |
887 if (error_info_) | 892 ClearErrors(); |
888 error_info_->Close(); | |
889 | 893 |
890 gfx::Rect rect = screen_lock_view_->GetPasswordBoundsRelativeTo( | 894 // TODO(nkostylev): Add help link. |
891 lock_widget_->GetRootView()); | 895 error_info_ = new MessageBubble( |
892 gfx::Rect lock_widget_bounds = lock_widget_->GetClientAreaScreenBounds(); | 896 screen_lock_view_->password_field(), |
893 rect.Offset(lock_widget_bounds.x(), lock_widget_bounds.y()); | |
894 error_info_ = MessageBubble::ShowNoGrab( | |
895 lock_window_, | |
896 rect, | |
897 arrow_location, | 897 arrow_location, |
898 ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_WARNING), | 898 ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_WARNING), |
899 UTF16ToWide(message), | 899 message, |
900 UTF16ToWide(string16()), // TODO(nkostylev): Add help link. | 900 string16()); |
901 this); | 901 MessageBubble::ShowBubble(error_info_); |
| 902 error_info_->GetWidget()->AddObserver(this); |
902 | 903 |
903 #if !defined(TOUCH_UI) | 904 #if !defined(TOUCH_UI) |
904 if (mouse_event_relay_.get()) | 905 if (mouse_event_relay_.get()) |
905 MessageLoopForUI::current()->RemoveObserver(mouse_event_relay_.get()); | 906 MessageLoopForUI::current()->RemoveObserver(mouse_event_relay_.get()); |
906 mouse_event_relay_.reset( | 907 mouse_event_relay_.reset( |
907 new MouseEventRelay(lock_widget_->GetNativeView()->window, | 908 new MouseEventRelay(lock_widget_->GetNativeView()->window, |
908 error_info_->GetNativeView()->window)); | 909 error_info_->GetWidget()->GetNativeView()->window)); |
909 MessageLoopForUI::current()->AddObserver(mouse_event_relay_.get()); | 910 MessageLoopForUI::current()->AddObserver(mouse_event_relay_.get()); |
910 #endif | 911 #endif |
911 } | 912 } |
912 | 913 |
913 bool ScreenLockerViews::AcceleratorPressed( | 914 bool ScreenLockerViews::AcceleratorPressed( |
914 const ui::Accelerator& accelerator) { | 915 const ui::Accelerator& accelerator) { |
915 if (!background_view_->IsScreenSaverVisible()) { | 916 if (!background_view_->IsScreenSaverVisible()) { |
916 screen_locker_view_->StartScreenSaver(); | 917 screen_locker_view_->StartScreenSaver(); |
917 return true; | 918 return true; |
918 } | 919 } |
919 return false; | 920 return false; |
920 } | 921 } |
921 | 922 |
922 void ScreenLockerViews::OnClientEvent(GtkWidget* widge, GdkEventClient* event) { | |
923 #if defined(TOOLKIT_USES_GTK) | |
924 WmIpc::Message msg; | |
925 WmIpc::instance()->DecodeMessage(*event, &msg); | |
926 if (msg.type() == WM_IPC_MESSAGE_CHROME_NOTIFY_SCREEN_REDRAWN_FOR_LOCK) { | |
927 OnWindowManagerReady(); | |
928 } | |
929 #endif | |
930 } | |
931 | |
932 } // namespace chromeos | 923 } // namespace chromeos |
OLD | NEW |