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 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
202 private: | 202 private: |
203 void RecordEvent(const ui::Event& event) { | 203 void RecordEvent(const ui::Event& event) { |
204 ++event_count_[event.type()]; | 204 ++event_count_[event.type()]; |
205 } | 205 } |
206 | 206 |
207 std::map<ui::EventType, int> event_count_; | 207 std::map<ui::EventType, int> event_count_; |
208 | 208 |
209 DISALLOW_COPY_AND_ASSIGN(EventCountHandler); | 209 DISALLOW_COPY_AND_ASSIGN(EventCountHandler); |
210 }; | 210 }; |
211 | 211 |
| 212 // A helper WidgetDelegate for tests that require hooks into WidgetDelegate |
| 213 // calls, and removes some of the boilerplate for initializing a Widget. Calls |
| 214 // Widget::CloseNow() when destroyed if it hasn't already been done. |
| 215 class TestDesktopWidgetDelegate : public WidgetDelegate { |
| 216 public: |
| 217 TestDesktopWidgetDelegate() : widget_(new Widget) {} |
| 218 |
| 219 ~TestDesktopWidgetDelegate() override { |
| 220 if (widget_) |
| 221 widget_->CloseNow(); |
| 222 EXPECT_FALSE(widget_); |
| 223 } |
| 224 |
| 225 // Initialize the Widget, adding some meaningful default InitParams. |
| 226 void InitWidget(Widget::InitParams init_params) { |
| 227 init_params.delegate = this; |
| 228 #if !defined(OS_CHROMEOS) |
| 229 init_params.native_widget = new PlatformDesktopNativeWidget(widget_); |
| 230 #endif |
| 231 init_params.bounds = initial_bounds_; |
| 232 widget_->Init(init_params); |
| 233 } |
| 234 |
| 235 // Set the contents view to be used during Widget initialization. For Widgets |
| 236 // that use non-client views, this will be the contents_view used to |
| 237 // initialize the ClientView in WidgetDelegate::CreateClientView(). Otherwise, |
| 238 // it is the ContentsView of the Widget's RootView. Ownership passes to the |
| 239 // view hierarchy during InitWidget(). |
| 240 void set_contents_view(View* contents_view) { |
| 241 contents_view_ = contents_view; |
| 242 } |
| 243 |
| 244 int window_closing_count() const { return window_closing_count_; } |
| 245 const gfx::Rect& initial_bounds() { return initial_bounds_; } |
| 246 |
| 247 // WidgetDelegate overrides: |
| 248 void WindowClosing() override { |
| 249 window_closing_count_++; |
| 250 widget_ = nullptr; |
| 251 } |
| 252 |
| 253 Widget* GetWidget() override { return widget_; } |
| 254 const Widget* GetWidget() const override { return widget_; } |
| 255 |
| 256 View* GetContentsView() override { |
| 257 return contents_view_ ? contents_view_ : WidgetDelegate::GetContentsView(); |
| 258 } |
| 259 |
| 260 bool ShouldAdvanceFocusToTopLevelWidget() const override { |
| 261 return true; // Same default as DefaultWidgetDelegate in widget.cc. |
| 262 } |
| 263 |
| 264 private: |
| 265 Widget* widget_; |
| 266 View* contents_view_ = nullptr; |
| 267 int window_closing_count_ = 0; |
| 268 gfx::Rect initial_bounds_ = gfx::Rect(100, 100, 200, 200); |
| 269 |
| 270 DISALLOW_COPY_AND_ASSIGN(TestDesktopWidgetDelegate); |
| 271 }; |
| 272 |
212 TEST_F(WidgetTest, WidgetInitParams) { | 273 TEST_F(WidgetTest, WidgetInitParams) { |
213 // Widgets are not transparent by default. | 274 // Widgets are not transparent by default. |
214 Widget::InitParams init1; | 275 Widget::InitParams init1; |
215 EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init1.opacity); | 276 EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init1.opacity); |
216 } | 277 } |
217 | 278 |
218 TEST_F(WidgetTest, NativeWindowProperty) { | 279 TEST_F(WidgetTest, NativeWindowProperty) { |
219 const char* key = "foo"; | 280 const char* key = "foo"; |
220 int value = 3; | 281 int value = 3; |
221 | 282 |
(...skipping 888 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1110 #endif | 1171 #endif |
1111 | 1172 |
1112 widget->SetFullscreen(false); | 1173 widget->SetFullscreen(false); |
1113 native_widget->GetWindowPlacement(&restored_bounds, &show_state); | 1174 native_widget->GetWindowPlacement(&restored_bounds, &show_state); |
1114 EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state); | 1175 EXPECT_EQ(ui::SHOW_STATE_NORMAL, show_state); |
1115 EXPECT_EQ(expected_bounds, restored_bounds); | 1176 EXPECT_EQ(expected_bounds, restored_bounds); |
1116 | 1177 |
1117 widget->CloseNow(); | 1178 widget->CloseNow(); |
1118 } | 1179 } |
1119 | 1180 |
| 1181 // Test that widget size constraints are properly applied immediately after |
| 1182 // Init(), and that SetBounds() calls are appropriately clamped. |
| 1183 TEST_F(WidgetTest, MinimumSizeConstraints) { |
| 1184 TestDesktopWidgetDelegate delegate; |
| 1185 gfx::Size minimum_size(100, 100); |
| 1186 const gfx::Size smaller_size(90, 90); |
| 1187 |
| 1188 delegate.set_contents_view(new StaticSizedView(minimum_size)); |
| 1189 delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW)); |
| 1190 Widget* widget = delegate.GetWidget(); |
| 1191 |
| 1192 // On desktop Linux, the Widget must be shown to ensure the window is mapped. |
| 1193 // On other platforms this line is optional. |
| 1194 widget->Show(); |
| 1195 |
| 1196 // Sanity checks. |
| 1197 EXPECT_GT(delegate.initial_bounds().width(), minimum_size.width()); |
| 1198 EXPECT_GT(delegate.initial_bounds().height(), minimum_size.height()); |
| 1199 EXPECT_EQ(delegate.initial_bounds().size(), |
| 1200 widget->GetWindowBoundsInScreen().size()); |
| 1201 // Note: StaticSizedView doesn't currently provide a maximum size. |
| 1202 EXPECT_EQ(gfx::Size(), widget->GetMaximumSize()); |
| 1203 |
| 1204 if (!widget->ShouldUseNativeFrame()) { |
| 1205 // The test environment may have dwm disabled on Windows. In this case, |
| 1206 // CustomFrameView is used instead of the NativeFrameView, which will |
| 1207 // provide a minimum size that includes frame decorations. |
| 1208 minimum_size = widget->non_client_view()->GetWindowBoundsForClientBounds( |
| 1209 gfx::Rect(minimum_size)).size(); |
| 1210 } |
| 1211 |
| 1212 EXPECT_EQ(minimum_size, widget->GetMinimumSize()); |
| 1213 EXPECT_EQ(minimum_size, GetNativeWidgetMinimumContentSize(widget)); |
| 1214 |
| 1215 // Trying to resize smaller than the minimum size should restrict the content |
| 1216 // size to the minimum size. |
| 1217 widget->SetBounds(gfx::Rect(smaller_size)); |
| 1218 EXPECT_EQ(minimum_size, widget->GetClientAreaBoundsInScreen().size()); |
| 1219 |
| 1220 widget->SetSize(smaller_size); |
| 1221 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) |
| 1222 // TODO(tapted): Desktop Linux ignores size constraints for SetSize. Fix it. |
| 1223 EXPECT_EQ(smaller_size, widget->GetClientAreaBoundsInScreen().size()); |
| 1224 #else |
| 1225 EXPECT_EQ(minimum_size, widget->GetClientAreaBoundsInScreen().size()); |
| 1226 #endif |
| 1227 } |
| 1228 |
1120 // Tests that SetBounds() and GetWindowBoundsInScreen() is symmetric when the | 1229 // Tests that SetBounds() and GetWindowBoundsInScreen() is symmetric when the |
1121 // widget is visible and not maximized or fullscreen. | 1230 // widget is visible and not maximized or fullscreen. |
1122 TEST_F(WidgetTest, GetWindowBoundsInScreen) { | 1231 TEST_F(WidgetTest, GetWindowBoundsInScreen) { |
1123 // Choose test coordinates away from edges and dimensions that are "small" | 1232 // Choose test coordinates away from edges and dimensions that are "small" |
1124 // (but not too small) to ensure the OS doesn't try to adjust them. | 1233 // (but not too small) to ensure the OS doesn't try to adjust them. |
1125 const gfx::Rect kTestBounds(150, 150, 400, 300); | 1234 const gfx::Rect kTestBounds(150, 150, 400, 300); |
1126 const gfx::Size kTestSize(200, 180); | 1235 const gfx::Size kTestSize(200, 180); |
1127 | 1236 |
1128 // First test a toplevel widget. | 1237 // First test a toplevel widget. |
1129 Widget* widget = CreateTopLevelPlatformWidget(); | 1238 Widget* widget = CreateTopLevelPlatformWidget(); |
(...skipping 631 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1761 generator.ClickLeftButton(); | 1870 generator.ClickLeftButton(); |
1762 | 1871 |
1763 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_PRESSED)); | 1872 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_PRESSED)); |
1764 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_RELEASED)); | 1873 EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_RELEASED)); |
1765 | 1874 |
1766 widget->CloseNow(); | 1875 widget->CloseNow(); |
1767 } | 1876 } |
1768 | 1877 |
1769 #endif // !defined(OS_MACOSX) || defined(USE_AURA) | 1878 #endif // !defined(OS_MACOSX) || defined(USE_AURA) |
1770 | 1879 |
1771 // Used by SingleWindowClosing to count number of times WindowClosing() has | |
1772 // been invoked. | |
1773 class ClosingDelegate : public WidgetDelegate { | |
1774 public: | |
1775 ClosingDelegate() : count_(0), widget_(NULL) {} | |
1776 | |
1777 int count() const { return count_; } | |
1778 | |
1779 void set_widget(views::Widget* widget) { widget_ = widget; } | |
1780 | |
1781 // WidgetDelegate overrides: | |
1782 Widget* GetWidget() override { return widget_; } | |
1783 const Widget* GetWidget() const override { return widget_; } | |
1784 void WindowClosing() override { count_++; } | |
1785 | |
1786 private: | |
1787 int count_; | |
1788 views::Widget* widget_; | |
1789 | |
1790 DISALLOW_COPY_AND_ASSIGN(ClosingDelegate); | |
1791 }; | |
1792 | |
1793 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget | 1880 // Verifies WindowClosing() is invoked correctly on the delegate when a Widget |
1794 // is closed. | 1881 // is closed. |
1795 TEST_F(WidgetTest, SingleWindowClosing) { | 1882 TEST_F(WidgetTest, SingleWindowClosing) { |
1796 scoped_ptr<ClosingDelegate> delegate(new ClosingDelegate()); | 1883 TestDesktopWidgetDelegate delegate; |
1797 Widget* widget = new Widget(); // Destroyed by CloseNow() below. | 1884 delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW)); |
1798 Widget::InitParams init_params = | 1885 EXPECT_EQ(0, delegate.window_closing_count()); |
1799 CreateParams(Widget::InitParams::TYPE_WINDOW); | 1886 delegate.GetWidget()->CloseNow(); |
1800 init_params.bounds = gfx::Rect(0, 0, 200, 200); | 1887 EXPECT_EQ(1, delegate.window_closing_count()); |
1801 init_params.delegate = delegate.get(); | |
1802 #if !defined(OS_CHROMEOS) | |
1803 init_params.native_widget = new PlatformDesktopNativeWidget(widget); | |
1804 #endif | |
1805 widget->Init(init_params); | |
1806 EXPECT_EQ(0, delegate->count()); | |
1807 widget->CloseNow(); | |
1808 EXPECT_EQ(1, delegate->count()); | |
1809 } | 1888 } |
1810 | 1889 |
1811 class WidgetWindowTitleTest : public WidgetTest { | 1890 class WidgetWindowTitleTest : public WidgetTest { |
1812 protected: | 1891 protected: |
1813 void RunTest(bool desktop_native_widget) { | 1892 void RunTest(bool desktop_native_widget) { |
1814 Widget* widget = new Widget(); // Destroyed by CloseNow() below. | 1893 Widget* widget = new Widget(); // Destroyed by CloseNow() below. |
1815 Widget::InitParams init_params = | 1894 Widget::InitParams init_params = |
1816 CreateParams(Widget::InitParams::TYPE_WINDOW); | 1895 CreateParams(Widget::InitParams::TYPE_WINDOW); |
1817 widget->Init(init_params); | 1896 widget->Init(init_params); |
1818 | 1897 |
(...skipping 1267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3086 top_level_widget.Init(init_params); | 3165 top_level_widget.Init(init_params); |
3087 top_level_widget.SetFullscreen(true); | 3166 top_level_widget.SetFullscreen(true); |
3088 EXPECT_EQ(top_level_widget.IsVisible(), | 3167 EXPECT_EQ(top_level_widget.IsVisible(), |
3089 IsNativeWindowVisible(top_level_widget.GetNativeWindow())); | 3168 IsNativeWindowVisible(top_level_widget.GetNativeWindow())); |
3090 top_level_widget.CloseNow(); | 3169 top_level_widget.CloseNow(); |
3091 } | 3170 } |
3092 #endif | 3171 #endif |
3093 } | 3172 } |
3094 #if defined(OS_WIN) | 3173 #if defined(OS_WIN) |
3095 | 3174 |
3096 // Provides functionality to test widget activation via an activation flag | |
3097 // which can be set by an accessor. | |
3098 class ModalWindowTestWidgetDelegate : public WidgetDelegate { | |
3099 public: | |
3100 ModalWindowTestWidgetDelegate() | |
3101 : widget_(NULL), | |
3102 can_activate_(true) {} | |
3103 | |
3104 virtual ~ModalWindowTestWidgetDelegate() {} | |
3105 | |
3106 // Overridden from WidgetDelegate: | |
3107 virtual void DeleteDelegate() override { | |
3108 delete this; | |
3109 } | |
3110 virtual Widget* GetWidget() override { | |
3111 return widget_; | |
3112 } | |
3113 virtual const Widget* GetWidget() const override { | |
3114 return widget_; | |
3115 } | |
3116 virtual bool CanActivate() const override { | |
3117 return can_activate_; | |
3118 } | |
3119 virtual bool ShouldAdvanceFocusToTopLevelWidget() const override { | |
3120 return true; | |
3121 } | |
3122 | |
3123 void set_can_activate(bool can_activate) { | |
3124 can_activate_ = can_activate; | |
3125 } | |
3126 | |
3127 void set_widget(Widget* widget) { | |
3128 widget_ = widget; | |
3129 } | |
3130 | |
3131 private: | |
3132 Widget* widget_; | |
3133 bool can_activate_; | |
3134 | |
3135 DISALLOW_COPY_AND_ASSIGN(ModalWindowTestWidgetDelegate); | |
3136 }; | |
3137 | |
3138 // Tests whether we can activate the top level widget when a modal dialog is | 3175 // Tests whether we can activate the top level widget when a modal dialog is |
3139 // active. | 3176 // active. |
3140 TEST_F(WidgetTest, WindowModalityActivationTest) { | 3177 TEST_F(WidgetTest, WindowModalityActivationTest) { |
3141 // Destroyed when the top level widget created below is destroyed. | 3178 TestDesktopWidgetDelegate widget_delegate; |
3142 ModalWindowTestWidgetDelegate* widget_delegate = | 3179 widget_delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW)); |
3143 new ModalWindowTestWidgetDelegate; | |
3144 // Create a top level widget. | |
3145 Widget top_level_widget; | |
3146 Widget::InitParams init_params = | |
3147 CreateParams(Widget::InitParams::TYPE_WINDOW); | |
3148 init_params.show_state = ui::SHOW_STATE_NORMAL; | |
3149 gfx::Rect initial_bounds(0, 0, 500, 500); | |
3150 init_params.bounds = initial_bounds; | |
3151 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | |
3152 init_params.native_widget = new DesktopNativeWidgetAura(&top_level_widget); | |
3153 init_params.delegate = widget_delegate; | |
3154 top_level_widget.Init(init_params); | |
3155 widget_delegate->set_widget(&top_level_widget); | |
3156 top_level_widget.Show(); | |
3157 EXPECT_TRUE(top_level_widget.IsVisible()); | |
3158 | 3180 |
3159 HWND win32_window = views::HWNDForWidget(&top_level_widget); | 3181 Widget* top_level_widget = widget_delegate.GetWidget(); |
| 3182 top_level_widget->Show(); |
| 3183 EXPECT_TRUE(top_level_widget->IsVisible()); |
| 3184 |
| 3185 HWND win32_window = views::HWNDForWidget(top_level_widget); |
3160 EXPECT_TRUE(::IsWindow(win32_window)); | 3186 EXPECT_TRUE(::IsWindow(win32_window)); |
3161 | 3187 |
3162 // This instance will be destroyed when the dialog is destroyed. | 3188 // This instance will be destroyed when the dialog is destroyed. |
3163 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate; | 3189 ModalDialogDelegate* dialog_delegate = new ModalDialogDelegate; |
3164 | 3190 |
3165 // We should be able to activate the window even if the WidgetDelegate | 3191 // We should be able to activate the window even if the WidgetDelegate |
3166 // says no, when a modal dialog is active. | 3192 // says no, when a modal dialog is active. |
3167 widget_delegate->set_can_activate(false); | 3193 widget_delegate.set_can_activate(false); |
3168 | 3194 |
3169 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget( | 3195 Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget( |
3170 dialog_delegate, NULL, top_level_widget.GetNativeWindow()); | 3196 dialog_delegate, NULL, top_level_widget->GetNativeView()); |
3171 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200)); | 3197 modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200)); |
3172 modal_dialog_widget->Show(); | 3198 modal_dialog_widget->Show(); |
3173 EXPECT_TRUE(modal_dialog_widget->IsVisible()); | 3199 EXPECT_TRUE(modal_dialog_widget->IsVisible()); |
3174 | 3200 |
3175 LRESULT activate_result = ::SendMessage( | 3201 LRESULT activate_result = ::SendMessage( |
3176 win32_window, | 3202 win32_window, |
3177 WM_MOUSEACTIVATE, | 3203 WM_MOUSEACTIVATE, |
3178 reinterpret_cast<WPARAM>(win32_window), | 3204 reinterpret_cast<WPARAM>(win32_window), |
3179 MAKELPARAM(WM_LBUTTONDOWN, HTCLIENT)); | 3205 MAKELPARAM(WM_LBUTTONDOWN, HTCLIENT)); |
3180 EXPECT_EQ(activate_result, MA_ACTIVATE); | 3206 EXPECT_EQ(activate_result, MA_ACTIVATE); |
3181 | 3207 |
3182 modal_dialog_widget->CloseNow(); | 3208 modal_dialog_widget->CloseNow(); |
3183 top_level_widget.CloseNow(); | |
3184 } | 3209 } |
3185 #endif // defined(OS_WIN) | 3210 #endif // defined(OS_WIN) |
3186 #endif // !defined(OS_CHROMEOS) | 3211 #endif // !defined(OS_CHROMEOS) |
3187 | 3212 |
3188 namespace { | 3213 namespace { |
3189 | 3214 |
3190 class FullscreenAwareFrame : public views::NonClientFrameView { | 3215 class FullscreenAwareFrame : public views::NonClientFrameView { |
3191 public: | 3216 public: |
3192 explicit FullscreenAwareFrame(views::Widget* widget) | 3217 explicit FullscreenAwareFrame(views::Widget* widget) |
3193 : widget_(widget), fullscreen_layout_called_(false) {} | 3218 : widget_(widget), fullscreen_layout_called_(false) {} |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3403 bool handled = false; | 3428 bool handled = false; |
3404 target->HandleKeyboardMessage(WM_CHAR, 0, 0, &handled); | 3429 target->HandleKeyboardMessage(WM_CHAR, 0, 0, &handled); |
3405 target->HandleKeyboardMessage(WM_SYSCHAR, 0, 0, &handled); | 3430 target->HandleKeyboardMessage(WM_SYSCHAR, 0, 0, &handled); |
3406 target->HandleKeyboardMessage(WM_SYSDEADCHAR, 0, 0, &handled); | 3431 target->HandleKeyboardMessage(WM_SYSDEADCHAR, 0, 0, &handled); |
3407 widget.CloseNow(); | 3432 widget.CloseNow(); |
3408 } | 3433 } |
3409 #endif | 3434 #endif |
3410 | 3435 |
3411 } // namespace test | 3436 } // namespace test |
3412 } // namespace views | 3437 } // namespace views |
OLD | NEW |