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