1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ash/frame/caption_buttons/frame_maximize_button.h"
7 #include "ash/ash_switches.h"
8 #include "ash/frame/caption_buttons/frame_caption_button_container_view.h"
9 #include "ash/frame/caption_buttons/maximize_bubble_controller.h"
10 #include "ash/shell.h"
11 #include "ash/test/ash_test_base.h"
12 #include "ash/wm/window_state.h"
13 #include "ash/wm/window_util.h"
14 #include "base/command_line.h"
15 #include "grit/ash_resources.h"
16 #include "ui/aura/client/focus_client.h"
17 #include "ui/aura/test/event_generator.h"
18 #include "ui/aura/window.h"
19 #include "ui/aura/window_tree_host.h"
20 #include "ui/events/event_processor.h"
21 #include "ui/events/event_utils.h"
22 #include "ui/events/gestures/gesture_configuration.h"
23 #include "ui/views/widget/widget.h"
24 #include "ui/views/widget/widget_delegate.h"
31 class CancelCallbackHandler {
33 CancelCallbackHandler(int update_events_before_cancel,
34 FrameMaximizeButton* maximize_button) :
35 update_events_before_cancel_(update_events_before_cancel),
36 maximize_button_(maximize_button) {}
37 virtual ~CancelCallbackHandler() {}
39 void CountedCancelCallback(ui::EventType event_type,
40 const gfx::Vector2dF& pos) {
41 if (event_type == ui::ET_GESTURE_SCROLL_UPDATE &&
42 !(--update_events_before_cancel_)) {
43 // Make sure that we are in the middle of a resizing operation, cancel it
44 // and then test that it is exited.
45 EXPECT_TRUE(maximize_button_->is_snap_enabled());
46 maximize_button_->DestroyMaximizeMenu();
47 EXPECT_FALSE(maximize_button_->is_snap_enabled());
52 // When this counter reaches 0, the gesture maximize action gets cancelled.
53 int update_events_before_cancel_;
55 // The maximize button which needs to get informed of the gesture termination.
56 FrameMaximizeButton* maximize_button_;
58 DISALLOW_COPY_AND_ASSIGN(CancelCallbackHandler);
61 class TestWidgetDelegate : public views::WidgetDelegateView {
63 TestWidgetDelegate() {}
64 virtual ~TestWidgetDelegate() {}
66 // views::WidgetDelegate overrides:
67 virtual views::View* GetContentsView() OVERRIDE {
70 virtual bool CanResize() const OVERRIDE {
73 virtual bool CanMaximize() const OVERRIDE {
77 ash::FrameCaptionButtonContainerView* caption_button_container() {
78 return caption_button_container_;
82 // Overridden from views::View:
83 virtual void Layout() OVERRIDE {
84 caption_button_container_->Layout();
86 // Right align the caption button container.
87 gfx::Size preferred_size = caption_button_container_->GetPreferredSize();
88 caption_button_container_->SetBounds(width() - preferred_size.width(), 0,
89 preferred_size.width(), preferred_size.height());
92 virtual void ViewHierarchyChanged(
93 const ViewHierarchyChangedDetails& details) OVERRIDE {
94 if (details.is_add && details.child == this) {
95 caption_button_container_ = new FrameCaptionButtonContainerView(
96 GetWidget(), FrameCaptionButtonContainerView::MINIMIZE_ALLOWED);
98 // Set arbitrary images for the container's buttons so that the buttons
99 // have non-empty sizes.
100 for (int icon = 0; icon < CAPTION_BUTTON_ICON_COUNT; ++icon) {
101 caption_button_container_->SetButtonImages(
102 static_cast<CaptionButtonIcon>(icon),
103 IDR_AURA_WINDOW_CONTROL_ICON_CLOSE,
104 IDR_AURA_WINDOW_CONTROL_ICON_CLOSE_I,
105 IDR_AURA_WINDOW_CONTROL_BACKGROUND_H,
106 IDR_AURA_WINDOW_CONTROL_BACKGROUND_P);
109 AddChildView(caption_button_container_);
114 ash::FrameCaptionButtonContainerView* caption_button_container_;
116 DISALLOW_COPY_AND_ASSIGN(TestWidgetDelegate);
121 class FrameMaximizeButtonTest : public ash::test::AshTestBase {
123 FrameMaximizeButtonTest() {}
124 virtual ~FrameMaximizeButtonTest() {}
126 // The returned widget takes ownership of |delegate|.
127 views::Widget* CreateWidget(views::WidgetDelegate* delegate) {
128 views::Widget::InitParams params(
129 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
130 views::Widget* widget = new views::Widget;
131 params.context = CurrentContext();
132 params.delegate = delegate;
133 params.bounds = gfx::Rect(10, 10, 100, 100);
134 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
135 widget->Init(params);
146 virtual void SetUp() OVERRIDE {
147 AshTestBase::SetUp();
149 CommandLine::ForCurrentProcess()->AppendSwitch(
150 switches::kAshDisableAlternateFrameCaptionButtonStyle);
152 TestWidgetDelegate* delegate = new TestWidgetDelegate();
153 widget_ = CreateWidget(delegate);
154 FrameCaptionButtonContainerView* caption_button_container =
155 delegate->caption_button_container();
157 FrameCaptionButtonContainerView::TestApi test(caption_button_container);
158 maximize_button_ = static_cast<FrameMaximizeButton*>(
162 virtual void TearDown() OVERRIDE {
164 AshTestBase::TearDown();
167 views::Widget* widget() { return widget_; }
169 FrameMaximizeButton* maximize_button() { return maximize_button_; }
172 views::Widget* widget_;
173 FrameMaximizeButton* maximize_button_;
175 DISALLOW_COPY_AND_ASSIGN(FrameMaximizeButtonTest);
178 // Tests that clicking on the resize-button toggles between maximize and normal
180 TEST_F(FrameMaximizeButtonTest, ResizeButtonToggleMaximize) {
181 wm::WindowState* window_state =
182 wm::GetWindowState(widget()->GetNativeWindow());
183 views::View* view = maximize_button();
184 gfx::Point center = view->GetBoundsInScreen().CenterPoint();
186 aura::test::EventGenerator generator(
187 window_state->window()->GetRootWindow(), center);
189 EXPECT_FALSE(window_state->IsMaximized());
191 generator.ClickLeftButton();
192 RunAllPendingInMessageLoop();
193 EXPECT_TRUE(window_state->IsMaximized());
195 center = view->GetBoundsInScreen().CenterPoint();
196 generator.MoveMouseTo(center);
197 generator.ClickLeftButton();
198 RunAllPendingInMessageLoop();
199 EXPECT_FALSE(window_state->IsMaximized());
201 generator.GestureTapAt(view->GetBoundsInScreen().CenterPoint());
202 EXPECT_TRUE(window_state->IsMaximized());
204 generator.GestureTapAt(view->GetBoundsInScreen().CenterPoint());
205 EXPECT_FALSE(window_state->IsMaximized());
207 generator.GestureTapDownAndUp(view->GetBoundsInScreen().CenterPoint());
208 EXPECT_TRUE(window_state->IsMaximized());
210 generator.GestureTapDownAndUp(view->GetBoundsInScreen().CenterPoint());
211 EXPECT_FALSE(window_state->IsMaximized());
215 // RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962
216 #define MAYBE_ResizeButtonDrag DISABLED_ResizeButtonDrag
218 #define MAYBE_ResizeButtonDrag ResizeButtonDrag
221 // Tests that click+dragging on the resize-button tiles or minimizes the window.
222 TEST_F(FrameMaximizeButtonTest, MAYBE_ResizeButtonDrag) {
223 aura::Window* window = widget()->GetNativeWindow();
224 views::View* view = maximize_button();
225 gfx::Point center = view->GetBoundsInScreen().CenterPoint();
227 aura::test::EventGenerator generator(window->GetRootWindow(), center);
229 wm::WindowState* window_state = wm::GetWindowState(window);
230 EXPECT_TRUE(window_state->IsNormalStateType());
234 generator.PressLeftButton();
235 generator.MoveMouseBy(10, 0);
236 generator.ReleaseLeftButton();
237 RunAllPendingInMessageLoop();
239 EXPECT_FALSE(window_state->IsMaximized());
240 EXPECT_FALSE(window_state->IsMinimized());
241 EXPECT_EQ(wm::GetDefaultRightSnappedWindowBoundsInParent(window).ToString(),
242 window->bounds().ToString());
247 center = view->GetBoundsInScreen().CenterPoint();
248 generator.MoveMouseTo(center);
249 generator.PressLeftButton();
250 generator.MoveMouseBy(-10, 0);
251 generator.ReleaseLeftButton();
252 RunAllPendingInMessageLoop();
254 EXPECT_FALSE(window_state->IsMaximized());
255 EXPECT_FALSE(window_state->IsMinimized());
256 EXPECT_EQ(wm::GetDefaultLeftSnappedWindowBoundsInParent(window).ToString(),
257 window->bounds().ToString());
262 center = view->GetBoundsInScreen().CenterPoint();
263 generator.MoveMouseTo(center);
264 generator.PressLeftButton();
265 generator.MoveMouseBy(0, 10);
266 generator.ReleaseLeftButton();
267 RunAllPendingInMessageLoop();
269 EXPECT_TRUE(window_state->IsMinimized());
272 window_state->Restore();
274 // Now test the same behaviour for gesture events.
278 center = view->GetBoundsInScreen().CenterPoint();
279 gfx::Point end = center;
281 generator.GestureScrollSequence(center, end,
282 base::TimeDelta::FromMilliseconds(100),
284 RunAllPendingInMessageLoop();
286 EXPECT_FALSE(window_state->IsMaximized());
287 EXPECT_FALSE(window_state->IsMinimized());
288 // This is a short resizing distance and different touch behavior
289 // applies which leads in half of the screen being used.
290 EXPECT_EQ("400,0 400x553", window->bounds().ToString());
295 center = view->GetBoundsInScreen().CenterPoint();
296 gfx::Point end = center;
298 generator.GestureScrollSequence(center, end,
299 base::TimeDelta::FromMilliseconds(100),
301 RunAllPendingInMessageLoop();
303 EXPECT_FALSE(window_state->IsMaximized());
304 EXPECT_FALSE(window_state->IsMinimized());
305 EXPECT_EQ(wm::GetDefaultLeftSnappedWindowBoundsInParent(window).ToString(),
306 window->bounds().ToString());
311 center = view->GetBoundsInScreen().CenterPoint();
312 gfx::Point end = center;
314 generator.GestureScrollSequence(center, end,
315 base::TimeDelta::FromMilliseconds(100),
317 RunAllPendingInMessageLoop();
319 EXPECT_TRUE(window_state->IsMinimized());
322 // Test with gesture events.
325 // Test that closing the (browser) window with an opened balloon does not
326 // crash the system. In other words: Make sure that shutting down the frame
327 // destroys the opened balloon in an orderly fashion.
328 TEST_F(FrameMaximizeButtonTest, MaximizeButtonExternalShutDown) {
329 aura::Window* window = widget()->GetNativeWindow();
330 ash::FrameMaximizeButton* maximize_button =
331 FrameMaximizeButtonTest::maximize_button();
332 maximize_button->set_bubble_appearance_delay_ms(0);
333 gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
334 gfx::Point off_pos(button_pos.x() + 100, button_pos.y() + 100);
336 aura::test::EventGenerator generator(window->GetRootWindow(), off_pos);
337 EXPECT_FALSE(maximize_button->maximizer());
338 EXPECT_TRUE(wm::GetWindowState(window)->IsNormalStateType());
340 // Move the mouse cursor over the button to bring up the maximizer bubble.
341 generator.MoveMouseTo(button_pos);
342 EXPECT_TRUE(maximize_button->maximizer());
344 // Even though the widget is closing the bubble menu should not crash upon
345 // its delayed destruction.
349 // Test that maximizing the browser after hovering in does not crash the system
350 // when the observer gets removed in the bubble destruction process.
351 TEST_F(FrameMaximizeButtonTest, MaximizeOnHoverThenClick) {
352 aura::Window* window = widget()->GetNativeWindow();
353 ash::FrameMaximizeButton* maximize_button =
354 FrameMaximizeButtonTest::maximize_button();
355 maximize_button->set_bubble_appearance_delay_ms(0);
356 gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
357 gfx::Point off_pos(button_pos.x() + 100, button_pos.y() + 100);
359 aura::test::EventGenerator generator(window->GetRootWindow(), off_pos);
360 EXPECT_FALSE(maximize_button->maximizer());
361 EXPECT_TRUE(wm::GetWindowState(window)->IsNormalStateType());
363 // Move the mouse cursor over the button to bring up the maximizer bubble.
364 generator.MoveMouseTo(button_pos);
365 EXPECT_TRUE(maximize_button->maximizer());
366 generator.ClickLeftButton();
367 EXPECT_TRUE(wm::GetWindowState(window)->IsMaximized());
370 // Test that hovering over a button in the balloon dialog will show the phantom
371 // window. Moving then away from the button will hide it again. Then check that
372 // pressing and dragging the button itself off the button will also release the
374 TEST_F(FrameMaximizeButtonTest, MaximizeLeftButtonDragOut) {
375 aura::Window* window = widget()->GetNativeWindow();
376 ash::FrameMaximizeButton* maximize_button =
377 FrameMaximizeButtonTest::maximize_button();
378 maximize_button->set_bubble_appearance_delay_ms(0);
379 gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
380 gfx::Point off_pos(button_pos.x() + 100, button_pos.y() + 100);
382 aura::test::EventGenerator generator(window->GetRootWindow(), off_pos);
383 EXPECT_FALSE(maximize_button->maximizer());
384 EXPECT_TRUE(wm::GetWindowState(window)->IsNormalStateType());
385 EXPECT_FALSE(maximize_button->phantom_window_open());
387 // Move the mouse cursor over the button to bring up the maximizer bubble.
388 generator.MoveMouseTo(button_pos);
389 EXPECT_TRUE(maximize_button->maximizer());
391 // Move the mouse over the left maximize button.
392 gfx::Point left_max_pos = maximize_button->maximizer()->
393 GetButtonForUnitTest(SNAP_LEFT)->GetBoundsInScreen().CenterPoint();
395 generator.MoveMouseTo(left_max_pos);
396 // Expect the phantom window to be open.
397 EXPECT_TRUE(maximize_button->phantom_window_open());
399 // Move away to see the window being destroyed.
400 generator.MoveMouseTo(off_pos);
401 EXPECT_FALSE(maximize_button->phantom_window_open());
403 // Move back over the button.
404 generator.MoveMouseTo(button_pos);
405 generator.MoveMouseTo(left_max_pos);
406 EXPECT_TRUE(maximize_button->phantom_window_open());
408 // Press button and drag out of dialog.
409 generator.PressLeftButton();
410 generator.MoveMouseTo(off_pos);
411 generator.ReleaseLeftButton();
413 // Check that the phantom window is also gone.
414 EXPECT_FALSE(maximize_button->phantom_window_open());
417 // Test that clicking a button in the maximizer bubble (in this case the
418 // maximize left button) will do the requested action.
419 TEST_F(FrameMaximizeButtonTest, MaximizeLeftByButton) {
420 aura::Window* window = widget()->GetNativeWindow();
422 ash::FrameMaximizeButton* maximize_button =
423 FrameMaximizeButtonTest::maximize_button();
424 maximize_button->set_bubble_appearance_delay_ms(0);
425 gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
426 gfx::Point off_pos(button_pos.x() + 100, button_pos.y() + 100);
428 aura::test::EventGenerator generator(window->GetRootWindow(), off_pos);
429 EXPECT_FALSE(maximize_button->maximizer());
430 EXPECT_TRUE(wm::GetWindowState(window)->IsNormalStateType());
431 EXPECT_FALSE(maximize_button->phantom_window_open());
433 // Move the mouse cursor over the button to bring up the maximizer bubble.
434 generator.MoveMouseTo(button_pos);
435 EXPECT_TRUE(maximize_button->maximizer());
437 // Move the mouse over the left maximize button.
438 gfx::Point left_max_pos = maximize_button->maximizer()->
439 GetButtonForUnitTest(SNAP_LEFT)->GetBoundsInScreen().CenterPoint();
440 generator.MoveMouseTo(left_max_pos);
441 EXPECT_TRUE(maximize_button->phantom_window_open());
442 generator.ClickLeftButton();
444 EXPECT_FALSE(maximize_button->maximizer());
445 EXPECT_FALSE(maximize_button->phantom_window_open());
447 wm::WindowState* window_state = wm::GetWindowState(window);
448 EXPECT_FALSE(window_state->IsMaximized());
449 EXPECT_FALSE(window_state->IsMinimized());
450 EXPECT_EQ(wm::GetDefaultLeftSnappedWindowBoundsInParent(window).ToString(),
451 window->bounds().ToString());
454 // Test that the activation focus does not change when the bubble gets shown.
455 TEST_F(FrameMaximizeButtonTest, MaximizeKeepFocus) {
456 aura::Window* window = widget()->GetNativeWindow();
457 ash::FrameMaximizeButton* maximize_button =
458 FrameMaximizeButtonTest::maximize_button();
459 maximize_button->set_bubble_appearance_delay_ms(0);
460 gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
461 gfx::Point off_pos(button_pos.x() + 100, button_pos.y() + 100);
463 aura::test::EventGenerator generator(window->GetRootWindow(), off_pos);
464 EXPECT_FALSE(maximize_button->maximizer());
465 EXPECT_TRUE(wm::GetWindowState(window)->IsNormalStateType());
467 aura::Window* active =
468 aura::client::GetFocusClient(window)->GetFocusedWindow();
470 // Move the mouse cursor over the button to bring up the maximizer bubble.
471 generator.MoveMouseTo(button_pos);
472 EXPECT_TRUE(maximize_button->maximizer());
474 // Check that the focused window is still the same.
475 EXPECT_EQ(active, aura::client::GetFocusClient(window)->GetFocusedWindow());
478 TEST_F(FrameMaximizeButtonTest, MaximizeTap) {
479 aura::Window* window = widget()->GetNativeWindow();
480 aura::Window* root_window = window->GetRootWindow();
481 ash::FrameMaximizeButton* maximize_button =
482 FrameMaximizeButtonTest::maximize_button();
483 gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
485 const int touch_default_radius =
486 ui::GestureConfiguration::default_radius();
487 ui::GestureConfiguration::set_default_radius(0);
489 ui::EventProcessor* dispatcher = root_window->GetHost()->event_processor();
490 const int kTouchId = 2;
491 ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
494 ui::EventTimeForNow());
495 ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&press);
496 ASSERT_FALSE(details.dispatcher_destroyed);
498 button_pos.Offset(9, 8);
499 ui::TouchEvent release(
500 ui::ET_TOUCH_RELEASED,
503 press.time_stamp() + base::TimeDelta::FromMilliseconds(50));
504 details = dispatcher->OnEventFromSource(&release);
505 ASSERT_FALSE(details.dispatcher_destroyed);
507 ui::GestureConfiguration::set_default_radius(touch_default_radius);
510 // Test that only the left button will activate the maximize button.
511 TEST_F(FrameMaximizeButtonTest, OnlyLeftButtonMaximizes) {
512 aura::Window* window = widget()->GetNativeWindow();
513 ash::FrameMaximizeButton* maximize_button =
514 FrameMaximizeButtonTest::maximize_button();
515 maximize_button->set_bubble_appearance_delay_ms(0);
516 gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
517 gfx::Point off_pos(button_pos.x() + 100, button_pos.y() + 100);
519 aura::test::EventGenerator generator(window->GetRootWindow(), off_pos);
520 EXPECT_FALSE(maximize_button->maximizer());
521 wm::WindowState* window_state = wm::GetWindowState(window);
522 EXPECT_TRUE(window_state->IsNormalStateType());
523 EXPECT_FALSE(window_state->IsMaximized());
525 // Move the mouse cursor over the button.
526 generator.MoveMouseTo(button_pos);
527 EXPECT_TRUE(maximize_button->maximizer());
528 EXPECT_FALSE(maximize_button->phantom_window_open());
530 // After pressing the left button the button should get triggered.
531 generator.PressLeftButton();
532 RunAllPendingInMessageLoop();
533 EXPECT_TRUE(maximize_button->is_snap_enabled());
534 EXPECT_FALSE(window_state->IsMaximized());
536 // Pressing the right button then should cancel the operation.
537 generator.PressRightButton();
538 RunAllPendingInMessageLoop();
539 EXPECT_FALSE(maximize_button->maximizer());
541 // After releasing the second button the window shouldn't be maximized.
542 generator.ReleaseRightButton();
543 generator.ReleaseLeftButton();
544 RunAllPendingInMessageLoop();
545 EXPECT_FALSE(window_state->IsMaximized());
547 // Second experiment: Starting with right should also not trigger.
548 generator.MoveMouseTo(off_pos);
549 generator.MoveMouseTo(button_pos);
550 EXPECT_TRUE(maximize_button->maximizer());
552 // Pressing first the right button should not activate.
553 generator.PressRightButton();
554 RunAllPendingInMessageLoop();
555 EXPECT_FALSE(maximize_button->is_snap_enabled());
557 // Pressing then additionally the left button shouldn't activate either.
558 generator.PressLeftButton();
559 RunAllPendingInMessageLoop();
560 EXPECT_FALSE(maximize_button->is_snap_enabled());
561 generator.ReleaseRightButton();
562 generator.ReleaseLeftButton();
563 EXPECT_FALSE(window_state->IsMaximized());
566 // Click a button of window maximize functionality.
567 // If |snap_type| is SNAP_NONE the FrameMaximizeButton gets clicked, otherwise
568 // the associated snap button.
569 // |Window| is the window which owns the maximize button.
570 // |maximize_button| is the FrameMaximizeButton which controls the window.
572 ash::FrameMaximizeButton* maximize_button,
573 aura::Window* window,
574 SnapType snap_type) {
575 gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
576 gfx::Point off_pos(button_pos.x() + 100, button_pos.y() + 100);
578 aura::test::EventGenerator generator(window->GetRootWindow(), off_pos);
579 generator.MoveMouseTo(off_pos);
580 EXPECT_FALSE(maximize_button->maximizer());
581 EXPECT_FALSE(maximize_button->phantom_window_open());
583 // Move the mouse cursor over the button.
584 generator.MoveMouseTo(button_pos);
585 EXPECT_TRUE(maximize_button->maximizer());
586 EXPECT_FALSE(maximize_button->phantom_window_open());
588 if (snap_type != SNAP_NONE) {
589 gfx::Point left_max_pos = maximize_button->maximizer()->
590 GetButtonForUnitTest(snap_type)->GetBoundsInScreen().CenterPoint();
591 generator.MoveMouseTo(left_max_pos);
592 EXPECT_TRUE(maximize_button->phantom_window_open());
594 // After pressing the left button the button should get triggered.
595 generator.ClickLeftButton();
596 EXPECT_FALSE(maximize_button->maximizer());
599 // Test that the restore from left/right maximize is properly done.
600 TEST_F(FrameMaximizeButtonTest, MaximizeLeftRestore) {
601 aura::Window* window = widget()->GetNativeWindow();
602 gfx::Rect initial_bounds = widget()->GetWindowBoundsInScreen();
603 ash::FrameMaximizeButton* maximize_button =
604 FrameMaximizeButtonTest::maximize_button();
605 maximize_button->set_bubble_appearance_delay_ms(0);
607 ClickMaxButton(maximize_button, window, SNAP_LEFT);
608 wm::WindowState* window_state = wm::GetWindowState(window);
609 // The window should not be maximized.
610 EXPECT_FALSE(window_state->IsMaximized());
611 // But the bounds should be different.
612 gfx::Rect new_bounds = widget()->GetWindowBoundsInScreen();
613 EXPECT_EQ(0, new_bounds.x());
614 EXPECT_EQ(0, new_bounds.y());
616 // Now click the same button again to see that it restores.
617 ClickMaxButton(maximize_button, window, SNAP_LEFT);
618 // But the bounds should be restored.
619 new_bounds = widget()->GetWindowBoundsInScreen();
620 EXPECT_EQ(new_bounds.x(), initial_bounds.x());
621 EXPECT_EQ(new_bounds.y(), initial_bounds.x());
622 EXPECT_EQ(new_bounds.width(), initial_bounds.width());
623 EXPECT_EQ(new_bounds.height(), initial_bounds.height());
624 // Make sure that there is no restore rectangle left.
625 EXPECT_FALSE(window_state->HasRestoreBounds());
628 // Maximize, left/right maximize and then restore should works.
629 TEST_F(FrameMaximizeButtonTest, MaximizeMaximizeLeftRestore) {
630 aura::Window* window = widget()->GetNativeWindow();
631 gfx::Rect initial_bounds = widget()->GetWindowBoundsInScreen();
632 ash::FrameMaximizeButton* maximize_button =
633 FrameMaximizeButtonTest::maximize_button();
634 maximize_button->set_bubble_appearance_delay_ms(0);
636 ClickMaxButton(maximize_button, window, SNAP_NONE);
638 wm::WindowState* window_state = wm::GetWindowState(window);
639 EXPECT_TRUE(window_state->IsMaximized());
641 ClickMaxButton(maximize_button, window, SNAP_LEFT);
642 EXPECT_FALSE(window_state->IsMaximized());
643 gfx::Rect new_bounds = widget()->GetWindowBoundsInScreen();
644 EXPECT_EQ(0, new_bounds.x());
645 EXPECT_EQ(0, new_bounds.y());
647 // Now click the same button again to see that it restores.
648 ClickMaxButton(maximize_button, window, SNAP_LEFT);
649 RunAllPendingInMessageLoop();
650 // But the bounds should be restored.
651 new_bounds = widget()->GetWindowBoundsInScreen();
652 EXPECT_EQ(new_bounds.x(), initial_bounds.x());
653 EXPECT_EQ(new_bounds.y(), initial_bounds.x());
654 EXPECT_EQ(new_bounds.width(), initial_bounds.width());
655 EXPECT_EQ(new_bounds.height(), initial_bounds.height());
656 // Make sure that there is no restore rectangle left.
657 EXPECT_FALSE(window_state->HasRestoreBounds());
660 // Left/right maximize, maximize and then restore should work.
661 TEST_F(FrameMaximizeButtonTest, MaximizeSnapLeftRestore) {
662 aura::Window* window = widget()->GetNativeWindow();
663 gfx::Rect initial_bounds = widget()->GetWindowBoundsInScreen();
664 ash::FrameMaximizeButton* maximize_button =
665 FrameMaximizeButtonTest::maximize_button();
666 maximize_button->set_bubble_appearance_delay_ms(0);
668 ClickMaxButton(maximize_button, window, SNAP_LEFT);
670 wm::WindowState* window_state = wm::GetWindowState(window);
671 EXPECT_FALSE(window_state->IsMaximized());
673 ClickMaxButton(maximize_button, window, SNAP_NONE);
674 EXPECT_TRUE(window_state->IsMaximized());
676 ClickMaxButton(maximize_button, window, SNAP_NONE);
677 EXPECT_FALSE(window_state->IsMaximized());
678 gfx::Rect new_bounds = widget()->GetWindowBoundsInScreen();
679 EXPECT_EQ(new_bounds.x(), initial_bounds.x());
680 EXPECT_EQ(new_bounds.y(), initial_bounds.x());
681 EXPECT_EQ(new_bounds.width(), initial_bounds.width());
682 EXPECT_EQ(new_bounds.height(), initial_bounds.height());
683 // Make sure that there is no restore rectangle left.
684 EXPECT_FALSE(window_state->HasRestoreBounds());
687 // Test that minimizing the window per keyboard closes the maximize bubble.
688 TEST_F(FrameMaximizeButtonTest, MinimizePerKeyClosesBubble) {
689 aura::Window* window = widget()->GetNativeWindow();
690 ash::FrameMaximizeButton* maximize_button =
691 FrameMaximizeButtonTest::maximize_button();
693 gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
694 gfx::Point off_pos(button_pos.x() + 100, button_pos.y() + 100);
696 aura::test::EventGenerator generator(window->GetRootWindow(), off_pos);
697 generator.MoveMouseTo(off_pos);
698 EXPECT_FALSE(maximize_button->maximizer());
700 // Move the mouse cursor over the maximize button.
701 generator.MoveMouseTo(button_pos);
702 EXPECT_TRUE(maximize_button->maximizer());
704 // We simulate the keystroke by calling minimizeWindow directly.
705 wm::WindowState* window_state = wm::GetWindowState(window);
706 window_state->Minimize();
708 EXPECT_TRUE(window_state->IsMinimized());
709 EXPECT_FALSE(maximize_button->maximizer());
712 // Tests that dragging down on the maximize button minimizes the window.
713 TEST_F(FrameMaximizeButtonTest, MaximizeButtonDragDownMinimizes) {
714 aura::Window* window = widget()->GetNativeWindow();
715 ash::FrameMaximizeButton* maximize_button =
716 FrameMaximizeButtonTest::maximize_button();
718 wm::WindowState* window_state = wm::GetWindowState(window);
719 // Drag down on a maximized window.
720 window_state->Maximize();
721 EXPECT_TRUE(window_state->IsMaximized());
722 gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
723 gfx::Point off_pos(button_pos.x(), button_pos.y() + 100);
725 aura::test::EventGenerator generator(window->GetRootWindow());
726 generator.GestureScrollSequence(button_pos, off_pos,
727 base::TimeDelta::FromMilliseconds(0), 1);
729 EXPECT_TRUE(window_state->IsMinimized());
730 EXPECT_FALSE(maximize_button->maximizer());
732 // Drag down on a restored window.
733 window_state->Restore();
735 button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
736 off_pos = gfx::Point(button_pos.x(), button_pos.y() + 200);
737 generator.GestureScrollSequence(button_pos, off_pos,
738 base::TimeDelta::FromMilliseconds(10), 1);
739 EXPECT_TRUE(window_state->IsMinimized());
740 EXPECT_FALSE(maximize_button->maximizer());
743 // Tests that dragging Left and pressing ESC does properly abort.
744 TEST_F(FrameMaximizeButtonTest, MaximizeButtonDragLeftEscapeExits) {
745 aura::Window* window = widget()->GetNativeWindow();
746 gfx::Rect initial_bounds = widget()->GetWindowBoundsInScreen();
747 ash::FrameMaximizeButton* maximize_button =
748 FrameMaximizeButtonTest::maximize_button();
750 gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
751 gfx::Point off_pos(button_pos.x() - button_pos.x() / 2, button_pos.y());
753 const int kGestureSteps = 10;
754 CancelCallbackHandler cancel_handler(kGestureSteps / 2, maximize_button);
755 aura::test::EventGenerator generator(window->GetRootWindow());
756 generator.GestureScrollSequenceWithCallback(
759 base::TimeDelta::FromMilliseconds(0),
761 base::Bind(&CancelCallbackHandler::CountedCancelCallback,
762 base::Unretained(&cancel_handler)));
764 // Check that there was no size change.
765 EXPECT_EQ(widget()->GetWindowBoundsInScreen().size().ToString(),
766 initial_bounds.size().ToString());
767 // Check that there is no phantom window left open.
768 EXPECT_FALSE(maximize_button->phantom_window_open());
771 // Test that hovering over a button in the maximizer bubble and switching
772 // activation without moving the mouse properly aborts.
773 TEST_F(FrameMaximizeButtonTest, LossOfActivationWhileMaximizeBubbleOpenAborts) {
774 aura::Window* window = widget()->GetNativeWindow();
775 ash::FrameMaximizeButton* maximize_button =
776 FrameMaximizeButtonTest::maximize_button();
777 maximize_button->set_bubble_appearance_delay_ms(0);
779 gfx::Rect initial_bounds = window->GetBoundsInScreen();
780 EXPECT_TRUE(wm::GetWindowState(window)->IsNormalStateType());
781 EXPECT_TRUE(widget()->IsActive());
783 // Move the mouse over the maximize button in order to bring up the maximizer
785 gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
786 gfx::Point off_pos(button_pos.x() + 100, button_pos.y() + 100);
787 aura::test::EventGenerator generator(window->GetRootWindow(), off_pos);
788 generator.MoveMouseTo(button_pos);
789 EXPECT_TRUE(maximize_button->maximizer());
791 // Hover the mouse over the left maximize button in the maximizer bubble to
792 // show the phantom window.
793 gfx::Point left_max_pos = maximize_button->maximizer()->
794 GetButtonForUnitTest(SNAP_LEFT)->GetBoundsInScreen().CenterPoint();
795 generator.MoveMouseTo(left_max_pos);
796 EXPECT_TRUE(maximize_button->phantom_window_open());
798 // Change activation by creating a new window. This could be done via an
799 // accelerator. The root window takes ownership of |just_created|.
800 views::Widget* just_created = views::Widget::CreateWindowWithContextAndBounds(
801 NULL, widget()->GetNativeWindow(), gfx::Rect(100, 100));
802 just_created->Show();
803 just_created->Activate();
804 EXPECT_FALSE(widget()->IsActive());
806 // Test that we have properly reset the state of the now inactive window.
807 EXPECT_FALSE(maximize_button->maximizer());
808 EXPECT_FALSE(maximize_button->phantom_window_open());
809 EXPECT_TRUE(wm::GetWindowState(window)->IsNormalStateType());
810 EXPECT_EQ(initial_bounds.ToString(), window->GetBoundsInScreen().ToString());