OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 <algorithm> | 5 #include <algorithm> |
6 #include <set> | 6 #include <set> |
7 | 7 |
8 #include "base/basictypes.h" | 8 #include "base/basictypes.h" |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
61 bool IsTestingSnowLeopard() { | 61 bool IsTestingSnowLeopard() { |
62 #if defined(OS_MACOSX) | 62 #if defined(OS_MACOSX) |
63 return base::mac::IsOSSnowLeopard(); | 63 return base::mac::IsOSSnowLeopard(); |
64 #else | 64 #else |
65 return false; | 65 return false; |
66 #endif | 66 #endif |
67 } | 67 } |
68 | 68 |
69 } // namespace | 69 } // namespace |
70 | 70 |
71 // A view that keeps track of the events it receives, optionally consuming them. | |
72 class EventCountView : public View { | |
73 public: | |
74 // Whether to call SetHandled() on events as they are received. For some event | |
75 // types, this will allow EventCountView to receives future events in the | |
76 // event sequence, such as a drag. | |
77 enum HandleMode { | |
78 PROPAGATE_EVENTS, | |
79 CONSUME_EVENTS | |
80 }; | |
81 | |
82 EventCountView() | |
83 : last_flags_(0), | |
84 handle_mode_(PROPAGATE_EVENTS) {} | |
85 | |
86 ~EventCountView() override {} | |
87 | |
88 int GetEventCount(ui::EventType type) { | |
89 return event_count_[type]; | |
90 } | |
91 | |
92 void ResetCounts() { | |
93 event_count_.clear(); | |
94 } | |
95 | |
96 int last_flags() const { | |
97 return last_flags_; | |
98 } | |
99 | |
100 void set_handle_mode(HandleMode handle_mode) { | |
101 handle_mode_ = handle_mode; | |
102 } | |
103 | |
104 protected: | |
105 // Overridden from View: | |
106 void OnMouseMoved(const ui::MouseEvent& event) override { | |
107 // MouseMove events are not re-dispatched from the RootView. | |
108 ++event_count_[ui::ET_MOUSE_MOVED]; | |
109 last_flags_ = 0; | |
110 } | |
111 | |
112 // Overridden from ui::EventHandler: | |
113 void OnKeyEvent(ui::KeyEvent* event) override { RecordEvent(event); } | |
114 void OnMouseEvent(ui::MouseEvent* event) override { RecordEvent(event); } | |
115 void OnScrollEvent(ui::ScrollEvent* event) override { RecordEvent(event); } | |
116 void OnGestureEvent(ui::GestureEvent* event) override { RecordEvent(event); } | |
117 | |
118 private: | |
119 void RecordEvent(ui::Event* event) { | |
120 ++event_count_[event->type()]; | |
121 last_flags_ = event->flags(); | |
122 if (handle_mode_ == CONSUME_EVENTS) | |
123 event->SetHandled(); | |
124 } | |
125 | |
126 std::map<ui::EventType, int> event_count_; | |
127 int last_flags_; | |
128 HandleMode handle_mode_; | |
129 | |
130 DISALLOW_COPY_AND_ASSIGN(EventCountView); | |
131 }; | |
132 | |
133 // A view that keeps track of the events it receives, and consumes all scroll | 71 // A view that keeps track of the events it receives, and consumes all scroll |
134 // gesture events and ui::ET_SCROLL events. | 72 // gesture events and ui::ET_SCROLL events. |
135 class ScrollableEventCountView : public EventCountView { | 73 class ScrollableEventCountView : public EventCountView { |
136 public: | 74 public: |
137 ScrollableEventCountView() {} | 75 ScrollableEventCountView() {} |
138 ~ScrollableEventCountView() override {} | 76 ~ScrollableEventCountView() override {} |
139 | 77 |
140 private: | 78 private: |
141 // Overridden from ui::EventHandler: | 79 // Overridden from ui::EventHandler: |
142 void OnGestureEvent(ui::GestureEvent* event) override { | 80 void OnGestureEvent(ui::GestureEvent* event) override { |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
200 private: | 138 private: |
201 void RecordEvent(const ui::Event& event) { | 139 void RecordEvent(const ui::Event& event) { |
202 ++event_count_[event.type()]; | 140 ++event_count_[event.type()]; |
203 } | 141 } |
204 | 142 |
205 std::map<ui::EventType, int> event_count_; | 143 std::map<ui::EventType, int> event_count_; |
206 | 144 |
207 DISALLOW_COPY_AND_ASSIGN(EventCountHandler); | 145 DISALLOW_COPY_AND_ASSIGN(EventCountHandler); |
208 }; | 146 }; |
209 | 147 |
210 // A helper WidgetDelegate for tests that require hooks into WidgetDelegate | |
211 // calls, and removes some of the boilerplate for initializing a Widget. Calls | |
212 // Widget::CloseNow() when destroyed if it hasn't already been done. | |
213 class TestDesktopWidgetDelegate : public WidgetDelegate { | |
214 public: | |
215 TestDesktopWidgetDelegate() : widget_(new Widget) {} | |
216 | |
217 ~TestDesktopWidgetDelegate() override { | |
218 if (widget_) | |
219 widget_->CloseNow(); | |
220 EXPECT_FALSE(widget_); | |
221 } | |
222 | |
223 // Initialize the Widget, adding some meaningful default InitParams. | |
224 void InitWidget(Widget::InitParams init_params) { | |
225 init_params.delegate = this; | |
226 #if !defined(OS_CHROMEOS) | |
227 init_params.native_widget = new PlatformDesktopNativeWidget(widget_); | |
228 #endif | |
229 init_params.bounds = initial_bounds_; | |
230 widget_->Init(init_params); | |
231 } | |
232 | |
233 // Set the contents view to be used during Widget initialization. For Widgets | |
234 // that use non-client views, this will be the contents_view used to | |
235 // initialize the ClientView in WidgetDelegate::CreateClientView(). Otherwise, | |
236 // it is the ContentsView of the Widget's RootView. Ownership passes to the | |
237 // view hierarchy during InitWidget(). | |
238 void set_contents_view(View* contents_view) { | |
239 contents_view_ = contents_view; | |
240 } | |
241 | |
242 int window_closing_count() const { return window_closing_count_; } | |
243 const gfx::Rect& initial_bounds() { return initial_bounds_; } | |
244 | |
245 // WidgetDelegate overrides: | |
246 void WindowClosing() override { | |
247 window_closing_count_++; | |
248 widget_ = nullptr; | |
249 } | |
250 | |
251 Widget* GetWidget() override { return widget_; } | |
252 const Widget* GetWidget() const override { return widget_; } | |
253 | |
254 View* GetContentsView() override { | |
255 return contents_view_ ? contents_view_ : WidgetDelegate::GetContentsView(); | |
256 } | |
257 | |
258 bool ShouldAdvanceFocusToTopLevelWidget() const override { | |
259 return true; // Same default as DefaultWidgetDelegate in widget.cc. | |
260 } | |
261 | |
262 private: | |
263 Widget* widget_; | |
264 View* contents_view_ = nullptr; | |
265 int window_closing_count_ = 0; | |
266 gfx::Rect initial_bounds_ = gfx::Rect(100, 100, 200, 200); | |
267 | |
268 DISALLOW_COPY_AND_ASSIGN(TestDesktopWidgetDelegate); | |
269 }; | |
270 | |
271 TEST_F(WidgetTest, WidgetInitParams) { | 148 TEST_F(WidgetTest, WidgetInitParams) { |
272 // Widgets are not transparent by default. | 149 // Widgets are not transparent by default. |
273 Widget::InitParams init1; | 150 Widget::InitParams init1; |
274 EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init1.opacity); | 151 EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init1.opacity); |
275 } | 152 } |
276 | 153 |
277 TEST_F(WidgetTest, NativeWindowProperty) { | 154 TEST_F(WidgetTest, NativeWindowProperty) { |
278 const char* key = "foo"; | 155 const char* key = "foo"; |
279 int value = 3; | 156 int value = 3; |
280 | 157 |
(...skipping 2765 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3046 DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth) { | 2923 DestroyChildWidgetsInOrderWithDesktopNativeWidgetForBoth) { |
3047 RunDestroyChildWidgetsTest(true, true); | 2924 RunDestroyChildWidgetsTest(true, true); |
3048 } | 2925 } |
3049 #endif // !defined(OS_CHROMEOS) | 2926 #endif // !defined(OS_CHROMEOS) |
3050 | 2927 |
3051 // See description of RunDestroyChildWidgetsTest(). | 2928 // See description of RunDestroyChildWidgetsTest(). |
3052 TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) { | 2929 TEST_F(WidgetChildDestructionTest, DestroyChildWidgetsInOrder) { |
3053 RunDestroyChildWidgetsTest(false, false); | 2930 RunDestroyChildWidgetsTest(false, false); |
3054 } | 2931 } |
3055 | 2932 |
3056 #if !defined(OS_CHROMEOS) | |
3057 // Provides functionality to create a window modal dialog. | |
3058 class ModalDialogDelegate : public DialogDelegateView { | |
3059 public: | |
3060 ModalDialogDelegate() {} | |
3061 ~ModalDialogDelegate() override {} | |
3062 | |
3063 // WidgetDelegate overrides. | |
3064 ui::ModalType GetModalType() const override { return ui::MODAL_TYPE_WINDOW; } | |
3065 | |
3066 private: | |
3067 DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate); | |
3068 }; | |
3069 | |
3070 // This test verifies that whether mouse events when a modal dialog is | |
3071 // displayed are eaten or recieved by the dialog. | |
3072 TEST_F(WidgetTest, WindowMouseModalityTest) { | |
3073 // Create a top level widget. | |
3074 Widget top_level_widget; | |
3075 Widget::InitParams init_params = | |
3076 CreateParams(Widget::InitParams::TYPE_WINDOW); | |
3077 init_params.show_state = ui::SHOW_STATE_NORMAL; | |
3078 gfx::Rect initial_bounds(0, 0, 500, 500); | |
3079 init_params.bounds = initial_bounds; | |
3080 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | |
3081 init_params.native_widget = | |
3082 new PlatformDesktopNativeWidget(&top_level_widget); | |
3083 top_level_widget.Init(init_params); | |
3084 top_level_widget.Show(); | |
3085 EXPECT_TRUE(top_level_widget.IsVisible()); | |
3086 | |
3087 // Create a view and validate that a mouse moves makes it to the view. | |
3088 EventCountView* widget_view = new EventCountView(); | |
3089 widget_view->SetBounds(0, 0, 10, 10); | |
3090 top_level_widget.GetRootView()->AddChildView(widget_view); | |
3091 | |
3092 gfx::Point cursor_location_main(5, 5); | |
3093 ui::MouseEvent move_main(ui::ET_MOUSE_MOVED, cursor_location_main, | |
3094 cursor_location_main, ui::EventTimeForNow(), | |
3095 ui::EF_NONE, ui::EF_NONE); | |
3096 ui::EventDispatchDetails details = | |
3097 GetEventProcessor(&top_level_widget)->OnEventFromSource(&move_main); | |
3098 ASSERT_FALSE(details.dispatcher_destroyed); | |
3099 | |
3100 EXPECT_EQ(1, widget_view->GetEventCount(ui::ET_MOUSE_ENTERED)); | |
3101 widget_view->ResetCounts(); | |
3102 | |
3103 // Create a modal dialog and validate that a mouse down message makes it to | |
3104 // the main view within the dialog. | |
3105 | |
3106 // This instance will be destroyed when the dialog is destroyed. | |
3107 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate; | |
3108 | |
3109 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget( | |
3110 dialog_delegate, NULL, top_level_widget.GetNativeView()); | |
3111 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200)); | |
3112 EventCountView* dialog_widget_view = new EventCountView(); | |
3113 dialog_widget_view->SetBounds(0, 0, 50, 50); | |
3114 modal_dialog_widget->GetRootView()->AddChildView(dialog_widget_view); | |
3115 modal_dialog_widget->Show(); | |
3116 EXPECT_TRUE(modal_dialog_widget->IsVisible()); | |
3117 | |
3118 gfx::Point cursor_location_dialog(100, 100); | |
3119 ui::MouseEvent mouse_down_dialog( | |
3120 ui::ET_MOUSE_PRESSED, cursor_location_dialog, cursor_location_dialog, | |
3121 ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE); | |
3122 details = GetEventProcessor(&top_level_widget)->OnEventFromSource( | |
3123 &mouse_down_dialog); | |
3124 ASSERT_FALSE(details.dispatcher_destroyed); | |
3125 EXPECT_EQ(1, dialog_widget_view->GetEventCount(ui::ET_MOUSE_PRESSED)); | |
3126 | |
3127 // Send a mouse move message to the main window. It should not be received by | |
3128 // the main window as the modal dialog is still active. | |
3129 gfx::Point cursor_location_main2(6, 6); | |
3130 ui::MouseEvent mouse_down_main(ui::ET_MOUSE_MOVED, cursor_location_main2, | |
3131 cursor_location_main2, ui::EventTimeForNow(), | |
3132 ui::EF_NONE, ui::EF_NONE); | |
3133 details = GetEventProcessor(&top_level_widget)->OnEventFromSource( | |
3134 &mouse_down_main); | |
3135 ASSERT_FALSE(details.dispatcher_destroyed); | |
3136 EXPECT_EQ(0, widget_view->GetEventCount(ui::ET_MOUSE_MOVED)); | |
3137 | |
3138 modal_dialog_widget->CloseNow(); | |
3139 top_level_widget.CloseNow(); | |
3140 } | |
3141 | |
3142 // Verifies nativeview visbility matches that of Widget visibility when | 2933 // Verifies nativeview visbility matches that of Widget visibility when |
3143 // SetFullscreen is invoked. | 2934 // SetFullscreen is invoked. |
3144 TEST_F(WidgetTest, FullscreenStatePropagated) { | 2935 TEST_F(WidgetTest, FullscreenStatePropagated) { |
3145 Widget::InitParams init_params = | 2936 Widget::InitParams init_params = |
3146 CreateParams(Widget::InitParams::TYPE_WINDOW); | 2937 CreateParams(Widget::InitParams::TYPE_WINDOW); |
3147 init_params.show_state = ui::SHOW_STATE_NORMAL; | 2938 init_params.show_state = ui::SHOW_STATE_NORMAL; |
3148 init_params.bounds = gfx::Rect(0, 0, 500, 500); | 2939 init_params.bounds = gfx::Rect(0, 0, 500, 500); |
3149 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 2940 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
3150 | 2941 |
3151 { | 2942 { |
(...skipping 10 matching lines...) Expand all Loading... |
3162 init_params.native_widget = | 2953 init_params.native_widget = |
3163 new PlatformDesktopNativeWidget(&top_level_widget); | 2954 new PlatformDesktopNativeWidget(&top_level_widget); |
3164 top_level_widget.Init(init_params); | 2955 top_level_widget.Init(init_params); |
3165 top_level_widget.SetFullscreen(true); | 2956 top_level_widget.SetFullscreen(true); |
3166 EXPECT_EQ(top_level_widget.IsVisible(), | 2957 EXPECT_EQ(top_level_widget.IsVisible(), |
3167 IsNativeWindowVisible(top_level_widget.GetNativeWindow())); | 2958 IsNativeWindowVisible(top_level_widget.GetNativeWindow())); |
3168 top_level_widget.CloseNow(); | 2959 top_level_widget.CloseNow(); |
3169 } | 2960 } |
3170 #endif | 2961 #endif |
3171 } | 2962 } |
3172 #if defined(OS_WIN) | |
3173 | |
3174 // Tests whether we can activate the top level widget when a modal dialog is | |
3175 // active. | |
3176 TEST_F(WidgetTest, WindowModalityActivationTest) { | |
3177 TestDesktopWidgetDelegate widget_delegate; | |
3178 widget_delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW)); | |
3179 | |
3180 Widget* top_level_widget = widget_delegate.GetWidget(); | |
3181 top_level_widget->Show(); | |
3182 EXPECT_TRUE(top_level_widget->IsVisible()); | |
3183 | |
3184 HWND win32_window = views::HWNDForWidget(top_level_widget); | |
3185 EXPECT_TRUE(::IsWindow(win32_window)); | |
3186 | |
3187 // This instance will be destroyed when the dialog is destroyed. | |
3188 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate; | |
3189 | |
3190 // We should be able to activate the window even if the WidgetDelegate | |
3191 // says no, when a modal dialog is active. | |
3192 widget_delegate.set_can_activate(false); | |
3193 | |
3194 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget( | |
3195 dialog_delegate, NULL, top_level_widget->GetNativeView()); | |
3196 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200)); | |
3197 modal_dialog_widget->Show(); | |
3198 EXPECT_TRUE(modal_dialog_widget->IsVisible()); | |
3199 | |
3200 LRESULT activate_result = ::SendMessage( | |
3201 win32_window, | |
3202 WM_MOUSEACTIVATE, | |
3203 reinterpret_cast<WPARAM>(win32_window), | |
3204 MAKELPARAM(WM_LBUTTONDOWN, HTCLIENT)); | |
3205 EXPECT_EQ(activate_result, MA_ACTIVATE); | |
3206 | |
3207 modal_dialog_widget->CloseNow(); | |
3208 } | |
3209 #endif // defined(OS_WIN) | |
3210 #endif // !defined(OS_CHROMEOS) | |
3211 | 2963 |
3212 namespace { | 2964 namespace { |
3213 | 2965 |
3214 class FullscreenAwareFrame : public views::NonClientFrameView { | 2966 class FullscreenAwareFrame : public views::NonClientFrameView { |
3215 public: | 2967 public: |
3216 explicit FullscreenAwareFrame(views::Widget* widget) | 2968 explicit FullscreenAwareFrame(views::Widget* widget) |
3217 : widget_(widget), fullscreen_layout_called_(false) {} | 2969 : widget_(widget), fullscreen_layout_called_(false) {} |
3218 ~FullscreenAwareFrame() override {} | 2970 ~FullscreenAwareFrame() override {} |
3219 | 2971 |
3220 // views::NonClientFrameView overrides: | 2972 // views::NonClientFrameView overrides: |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3438 EXPECT_FALSE(widget->IsAlwaysOnTop()); | 3190 EXPECT_FALSE(widget->IsAlwaysOnTop()); |
3439 widget->SetAlwaysOnTop(true); | 3191 widget->SetAlwaysOnTop(true); |
3440 EXPECT_TRUE(widget->IsAlwaysOnTop()); | 3192 EXPECT_TRUE(widget->IsAlwaysOnTop()); |
3441 widget->SetAlwaysOnTop(false); | 3193 widget->SetAlwaysOnTop(false); |
3442 EXPECT_FALSE(widget->IsAlwaysOnTop()); | 3194 EXPECT_FALSE(widget->IsAlwaysOnTop()); |
3443 widget->CloseNow(); | 3195 widget->CloseNow(); |
3444 } | 3196 } |
3445 | 3197 |
3446 } // namespace test | 3198 } // namespace test |
3447 } // namespace views | 3199 } // namespace views |
OLD | NEW |