| 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 |