summaryrefslogtreecommitdiffstats
path: root/ash/wm
diff options
context:
space:
mode:
authorsadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-13 02:58:56 +0000
committersadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-13 02:58:56 +0000
commit1d0dfbce01312325b5ce383218740530a446a0cf (patch)
treea12e233e9d8a945582487ac7bec2d9af8f30e80b /ash/wm
parent84ff1e9c512b93641613927257a39e4d2def3987 (diff)
downloadchromium_src-1d0dfbce01312325b5ce383218740530a446a0cf.zip
chromium_src-1d0dfbce01312325b5ce383218740530a446a0cf.tar.gz
chromium_src-1d0dfbce01312325b5ce383218740530a446a0cf.tar.bz2
ash: Add gesture support for the window-maximize button.
BUG=132282 TEST=aura_shell_unittests Review URL: https://chromiumcodereview.appspot.com/10536124 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@141843 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash/wm')
-rw-r--r--ash/wm/custom_frame_view_ash.h15
-rw-r--r--ash/wm/custom_frame_view_ash_unittest.cc194
-rw-r--r--ash/wm/workspace/frame_maximize_button.cc121
-rw-r--r--ash/wm/workspace/frame_maximize_button.h17
4 files changed, 307 insertions, 40 deletions
diff --git a/ash/wm/custom_frame_view_ash.h b/ash/wm/custom_frame_view_ash.h
index fc31015..fea059f 100644
--- a/ash/wm/custom_frame_view_ash.h
+++ b/ash/wm/custom_frame_view_ash.h
@@ -35,6 +35,21 @@ class ASH_EXPORT CustomFrameViewAsh : public views::NonClientFrameView,
CustomFrameViewAsh();
virtual ~CustomFrameViewAsh();
+ // For testing.
+ class TestApi {
+ public:
+ explicit TestApi(CustomFrameViewAsh* frame) : frame_(frame) {
+ }
+
+ views::ImageButton* maximize_button() const {
+ return frame_->maximize_button_;
+ }
+
+ private:
+ TestApi();
+ CustomFrameViewAsh* frame_;
+ };
+
void Init(views::Widget* frame);
views::ImageButton* close_button() { return close_button_; }
diff --git a/ash/wm/custom_frame_view_ash_unittest.cc b/ash/wm/custom_frame_view_ash_unittest.cc
new file mode 100644
index 0000000..d6149df
--- /dev/null
+++ b/ash/wm/custom_frame_view_ash_unittest.cc
@@ -0,0 +1,194 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/wm/custom_frame_view_ash.h"
+
+#include "ash/shell.h"
+#include "ash/test/ash_test_base.h"
+#include "ash/wm/window_util.h"
+#include "ash/wm/workspace/snap_sizer.h"
+#include "base/command_line.h"
+#include "ui/aura/aura_switches.h"
+#include "ui/aura/test/event_generator.h"
+#include "ui/aura/window.h"
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/test/test_views_delegate.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
+
+namespace ash {
+namespace internal {
+
+namespace {
+
+class ShellViewsDelegate : public views::TestViewsDelegate {
+ public:
+ ShellViewsDelegate() {}
+ virtual ~ShellViewsDelegate() {}
+
+ // Overridden from views::TestViewsDelegate:
+ virtual views::NonClientFrameView* CreateDefaultNonClientFrameView(
+ views::Widget* widget) OVERRIDE {
+ return ash::Shell::GetInstance()->CreateDefaultNonClientFrameView(widget);
+ }
+ bool UseTransparentWindows() const OVERRIDE {
+ // Ash uses transparent window frames.
+ return true;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ShellViewsDelegate);
+};
+
+class TestWidgetDelegate : public views::WidgetDelegateView {
+ public:
+ TestWidgetDelegate() {}
+ virtual ~TestWidgetDelegate() {}
+
+ // Overridden from views::WidgetDelegate:
+ virtual views::View* GetContentsView() OVERRIDE {
+ return this;
+ }
+ virtual bool CanResize() const OVERRIDE {
+ return true;
+ }
+ virtual bool CanMaximize() const OVERRIDE {
+ return true;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestWidgetDelegate);
+};
+
+} // namespace
+
+class CustomFrameViewAshTest : public ash::test::AshTestBase {
+ public:
+ CustomFrameViewAshTest() {}
+ virtual ~CustomFrameViewAshTest() {}
+
+ views::Widget* CreateWidget() {
+ views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
+ views::Widget* widget = new views::Widget;
+ params.delegate = new TestWidgetDelegate;
+ widget->Init(params);
+ widget->Show();
+ return widget;
+ }
+
+ CustomFrameViewAsh* custom_frame_view_ash(views::Widget* widget) const {
+ return static_cast<CustomFrameViewAsh*>(widget->non_client_view()->
+ frame_view());
+ }
+
+ virtual void SetUp() OVERRIDE {
+ AshTestBase::SetUp();
+ if (!views::ViewsDelegate::views_delegate) {
+ views_delegate_.reset(new ShellViewsDelegate);
+ views::ViewsDelegate::views_delegate = views_delegate_.get();
+ }
+ }
+
+ virtual void TearDown() OVERRIDE {
+ if (views_delegate_.get()) {
+ views::ViewsDelegate::views_delegate = NULL;
+ views_delegate_.reset();
+ }
+ AshTestBase::TearDown();
+ }
+
+ private:
+ scoped_ptr<views::ViewsDelegate> views_delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(CustomFrameViewAshTest);
+};
+
+// Tests that clicking on the resize-button toggles between maximize and normal
+// state.
+TEST_F(CustomFrameViewAshTest, ResizeButtonToggleMaximize) {
+ views::Widget* widget = CreateWidget();
+ aura::Window* window = widget->GetNativeWindow();
+ CustomFrameViewAsh* frame = custom_frame_view_ash(widget);
+ CustomFrameViewAsh::TestApi test(frame);
+ views::View* view = test.maximize_button();
+ gfx::Point center = view->GetScreenBounds().CenterPoint();
+
+ aura::test::EventGenerator generator(window->GetRootWindow(), center);
+
+ EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
+
+ generator.ClickLeftButton();
+ RunAllPendingInMessageLoop();
+ EXPECT_TRUE(ash::wm::IsWindowMaximized(window));
+
+ center = view->GetScreenBounds().CenterPoint();
+ generator.MoveMouseTo(center);
+ generator.ClickLeftButton();
+ RunAllPendingInMessageLoop();
+ EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
+
+ widget->Close();
+}
+
+// Tests that click+dragging on the resize-button tiles or minimizes the window.
+TEST_F(CustomFrameViewAshTest, ResizeButtonDrag) {
+ views::Widget* widget = CreateWidget();
+ aura::Window* window = widget->GetNativeWindow();
+ CustomFrameViewAsh* frame = custom_frame_view_ash(widget);
+ CustomFrameViewAsh::TestApi test(frame);
+ views::View* view = test.maximize_button();
+ gfx::Point center = view->GetScreenBounds().CenterPoint();
+ const int kGridSize = ash::Shell::GetInstance()->GetGridSize();
+
+ aura::test::EventGenerator generator(window->GetRootWindow(), center);
+
+ EXPECT_TRUE(ash::wm::IsWindowNormal(window));
+
+ // Snap right.
+ {
+ generator.PressLeftButton();
+ generator.MoveMouseBy(10, 0);
+ generator.ReleaseLeftButton();
+ RunAllPendingInMessageLoop();
+
+ EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
+ EXPECT_FALSE(ash::wm::IsWindowMinimized(window));
+ internal::SnapSizer sizer(window, center,
+ internal::SnapSizer::RIGHT_EDGE, kGridSize);
+ EXPECT_EQ(sizer.target_bounds().ToString(), window->bounds().ToString());
+ }
+
+ // Snap left.
+ {
+ center = view->GetScreenBounds().CenterPoint();
+ generator.MoveMouseTo(center);
+ generator.PressLeftButton();
+ generator.MoveMouseBy(-10, 0);
+ generator.ReleaseLeftButton();
+ RunAllPendingInMessageLoop();
+
+ EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
+ EXPECT_FALSE(ash::wm::IsWindowMinimized(window));
+ internal::SnapSizer sizer(window, center,
+ internal::SnapSizer::LEFT_EDGE, kGridSize);
+ EXPECT_EQ(sizer.target_bounds().ToString(), window->bounds().ToString());
+ }
+
+ // Minimize.
+ {
+ center = view->GetScreenBounds().CenterPoint();
+ generator.MoveMouseTo(center);
+ generator.PressLeftButton();
+ generator.MoveMouseBy(0, 10);
+ generator.ReleaseLeftButton();
+ RunAllPendingInMessageLoop();
+
+ EXPECT_TRUE(ash::wm::IsWindowMinimized(window));
+ }
+
+ widget->Close();
+}
+
+} // namespace internal
+} // namespace ash
diff --git a/ash/wm/workspace/frame_maximize_button.cc b/ash/wm/workspace/frame_maximize_button.cc
index 06afc02..061d33f 100644
--- a/ash/wm/workspace/frame_maximize_button.cc
+++ b/ash/wm/workspace/frame_maximize_button.cc
@@ -116,17 +116,8 @@ FrameMaximizeButton::~FrameMaximizeButton() {
bool FrameMaximizeButton::OnMousePressed(const views::MouseEvent& event) {
is_snap_enabled_ = event.IsLeftMouseButton();
- if (is_snap_enabled_) {
- snap_sizer_.reset(NULL);
- InstallEventFilter();
- snap_type_ = SNAP_NONE;
- press_location_ = event.location();
- exceeded_drag_threshold_ = false;
- update_timer_.Start(
- FROM_HERE,
- base::TimeDelta::FromMilliseconds(kUpdateDelayMS),
- this, &FrameMaximizeButton::UpdateSnapFromCursorScreenPoint);
- }
+ if (is_snap_enabled_)
+ ProcessStartEvent(event);
ImageButton::OnMousePressed(event);
return true;
}
@@ -140,34 +131,14 @@ void FrameMaximizeButton::OnMouseExited(const views::MouseEvent& event) {
}
bool FrameMaximizeButton::OnMouseDragged(const views::MouseEvent& event) {
- if (is_snap_enabled_) {
- int delta_x = event.location().x() - press_location_.x();
- int delta_y = event.location().y() - press_location_.y();
- if (!exceeded_drag_threshold_) {
- exceeded_drag_threshold_ =
- views::View::ExceededDragThreshold(delta_x, delta_y);
- }
- if (exceeded_drag_threshold_)
- UpdateSnap(event.location());
- }
+ if (is_snap_enabled_)
+ ProcessUpdateEvent(event);
return ImageButton::OnMouseDragged(event);
}
void FrameMaximizeButton::OnMouseReleased(const views::MouseEvent& event) {
- update_timer_.Stop();
- UninstallEventFilter();
- bool should_snap = is_snap_enabled_;
- is_snap_enabled_ = false;
- if (should_snap && snap_type_ != SNAP_NONE) {
- SetState(BS_NORMAL);
- // SetState will not call SchedulePaint() if state was already set to
- // BS_NORMAL during a drag.
- SchedulePaint();
- phantom_window_.reset();
- Snap();
- } else {
+ if (!ProcessEndEvent(event))
ImageButton::OnMouseReleased(event);
- }
}
void FrameMaximizeButton::OnMouseCaptureLost() {
@@ -175,6 +146,38 @@ void FrameMaximizeButton::OnMouseCaptureLost() {
ImageButton::OnMouseCaptureLost();
}
+ui::GestureStatus FrameMaximizeButton::OnGestureEvent(
+ const views::GestureEvent& event) {
+ if (event.type() == ui::ET_GESTURE_TAP_DOWN) {
+ is_snap_enabled_ = true;
+ ProcessStartEvent(event);
+ return ui::GESTURE_STATUS_CONSUMED;
+ }
+
+ if (event.type() == ui::ET_GESTURE_TAP ||
+ event.type() == ui::ET_GESTURE_SCROLL_END) {
+ if (event.type() == ui::ET_GESTURE_TAP)
+ snap_type_ = SnapTypeForLocation(event.location());
+ ProcessEndEvent(event);
+ return ui::GESTURE_STATUS_CONSUMED;
+ }
+
+ if (event.type() == ui::ET_GESTURE_END && event.delta_x() == 1 &&
+ is_snap_enabled_) {
+ snap_type_ = SnapTypeForLocation(event.location());
+ ProcessEndEvent(event);
+ return ui::GESTURE_STATUS_CONSUMED;
+ }
+
+ if (event.type() == ui::ET_GESTURE_SCROLL_UPDATE ||
+ event.type() == ui::ET_GESTURE_SCROLL_BEGIN) {
+ ProcessUpdateEvent(event);
+ return ui::GESTURE_STATUS_CONSUMED;
+ }
+
+ return ImageButton::OnGestureEvent(event);
+}
+
gfx::ImageSkia FrameMaximizeButton::GetImageToPaint() {
if (is_snap_enabled_) {
int id = 0;
@@ -223,6 +226,50 @@ gfx::ImageSkia FrameMaximizeButton::GetImageToPaint() {
return ImageButton::GetImageToPaint();
}
+void FrameMaximizeButton::ProcessStartEvent(const views::LocatedEvent& event) {
+ DCHECK(is_snap_enabled_);
+ snap_sizer_.reset(NULL);
+ InstallEventFilter();
+ snap_type_ = SNAP_NONE;
+ press_location_ = event.location();
+ exceeded_drag_threshold_ = false;
+ update_timer_.Start(
+ FROM_HERE,
+ base::TimeDelta::FromMilliseconds(kUpdateDelayMS),
+ this,
+ &FrameMaximizeButton::UpdateSnapFromEventLocation);
+}
+
+void FrameMaximizeButton::ProcessUpdateEvent(const views::LocatedEvent& event) {
+ DCHECK(is_snap_enabled_);
+ int delta_x = event.x() - press_location_.x();
+ int delta_y = event.y() - press_location_.y();
+ if (!exceeded_drag_threshold_) {
+ exceeded_drag_threshold_ =
+ views::View::ExceededDragThreshold(delta_x, delta_y);
+ }
+ if (exceeded_drag_threshold_)
+ UpdateSnap(event.location());
+}
+
+bool FrameMaximizeButton::ProcessEndEvent(const views::LocatedEvent& event) {
+ update_timer_.Stop();
+ UninstallEventFilter();
+ bool should_snap = is_snap_enabled_;
+ is_snap_enabled_ = false;
+
+ if (!should_snap || snap_type_ == SNAP_NONE)
+ return false;
+
+ SetState(BS_NORMAL);
+ // SetState will not call SchedulePaint() if state was already set to
+ // BS_NORMAL during a drag.
+ SchedulePaint();
+ phantom_window_.reset();
+ Snap();
+ return true;
+}
+
void FrameMaximizeButton::Cancel() {
UninstallEventFilter();
is_snap_enabled_ = false;
@@ -243,14 +290,12 @@ void FrameMaximizeButton::UninstallEventFilter() {
escape_event_filter_.reset(NULL);
}
-void FrameMaximizeButton::UpdateSnapFromCursorScreenPoint() {
+void FrameMaximizeButton::UpdateSnapFromEventLocation() {
// If the drag threshold has been exceeded the snap location is up to date.
if (exceeded_drag_threshold_)
return;
exceeded_drag_threshold_ = true;
- gfx::Point cursor_point(gfx::Screen::GetCursorScreenPoint());
- ConvertPointFromScreen(this, &cursor_point);
- UpdateSnap(cursor_point);
+ UpdateSnap(press_location_);
}
void FrameMaximizeButton::UpdateSnap(const gfx::Point& location) {
diff --git a/ash/wm/workspace/frame_maximize_button.h b/ash/wm/workspace/frame_maximize_button.h
index c95e515..4d51ae3 100644
--- a/ash/wm/workspace/frame_maximize_button.h
+++ b/ash/wm/workspace/frame_maximize_button.h
@@ -35,6 +35,8 @@ class ASH_EXPORT FrameMaximizeButton : public views::ImageButton {
virtual bool OnMouseDragged(const views::MouseEvent& event) OVERRIDE;
virtual void OnMouseReleased(const views::MouseEvent& event) OVERRIDE;
virtual void OnMouseCaptureLost() OVERRIDE;
+ virtual ui::GestureStatus OnGestureEvent(
+ const views::GestureEvent& event) OVERRIDE;
protected:
// ImageButton overrides:
@@ -53,6 +55,17 @@ class ASH_EXPORT FrameMaximizeButton : public views::ImageButton {
SNAP_NONE
};
+ // Initializes the snap-gesture based on the event. This should only be called
+ // when the event is confirmed to have started a snap gesture.
+ void ProcessStartEvent(const views::LocatedEvent& event);
+
+ // Updates the snap-state based on the current event. This should only be
+ // called after the snap gesture has already started.
+ void ProcessUpdateEvent(const views::LocatedEvent& event);
+
+ // Returns true if the window was snapped. Returns false otherwise.
+ bool ProcessEndEvent(const views::LocatedEvent& event);
+
// Cancels snap behavior.
void Cancel();
@@ -60,9 +73,9 @@ class ASH_EXPORT FrameMaximizeButton : public views::ImageButton {
void InstallEventFilter();
void UninstallEventFilter();
- // Updates the snap position from the current location. This is invoked by
+ // Updates the snap position from the event location. This is invoked by
// |update_timer_|.
- void UpdateSnapFromCursorScreenPoint();
+ void UpdateSnapFromEventLocation();
// Updates |snap_type_| based on a mouse drag.
void UpdateSnap(const gfx::Point& location);