summaryrefslogtreecommitdiffstats
path: root/ash
diff options
context:
space:
mode:
authorskuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-11 18:05:47 +0000
committerskuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-11 18:05:47 +0000
commit88fa8bf4bdda72610f727a0a3f7ce5e4fd7d2dc4 (patch)
tree63f8754188d4f1f7ec35e0e07b3bd11d98f060ca /ash
parent75ffa6b04b62224ba97d4b4a6f932ee1effe134e (diff)
downloadchromium_src-88fa8bf4bdda72610f727a0a3f7ce5e4fd7d2dc4.zip
chromium_src-88fa8bf4bdda72610f727a0a3f7ce5e4fd7d2dc4.tar.gz
chromium_src-88fa8bf4bdda72610f727a0a3f7ce5e4fd7d2dc4.tar.bz2
Adding proper dragging behavior for L/R maximized windows.
BUG=141750 TEST=unit tests & visual Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=155840 Review URL: https://chromiumcodereview.appspot.com/10918077 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@156058 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r--ash/wm/default_window_resizer.cc6
-rw-r--r--ash/wm/frame_painter.cc40
-rw-r--r--ash/wm/frame_painter.h3
-rw-r--r--ash/wm/frame_painter_unittest.cc67
-rw-r--r--ash/wm/window_resizer.cc20
-rw-r--r--ash/wm/window_resizer.h4
-rw-r--r--ash/wm/workspace/frame_maximize_button.cc7
-rw-r--r--ash/wm/workspace/workspace_window_resizer.cc12
-rw-r--r--ash/wm/workspace/workspace_window_resizer_unittest.cc33
9 files changed, 187 insertions, 5 deletions
diff --git a/ash/wm/default_window_resizer.cc b/ash/wm/default_window_resizer.cc
index 50cac97..dd874e3 100644
--- a/ash/wm/default_window_resizer.cc
+++ b/ash/wm/default_window_resizer.cc
@@ -7,6 +7,7 @@
#include "ash/shell.h"
#include "ash/wm/coordinate_conversion.h"
#include "ash/wm/cursor_manager.h"
+#include "ash/wm/property_util.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/env.h"
#include "ui/aura/root_window.h"
@@ -42,6 +43,8 @@ void DefaultWindowResizer::Drag(const gfx::Point& location, int event_flags) {
gfx::Rect bounds(CalculateBoundsForDrag(details_, location));
if (bounds != details_.window->bounds()) {
+ if (!did_move_or_resize_ && !details_.restore_bounds.IsEmpty())
+ ClearRestoreBounds(details_.window);
did_move_or_resize_ = true;
details_.window->SetBounds(bounds);
}
@@ -55,6 +58,9 @@ void DefaultWindowResizer::RevertDrag() {
return;
details_.window->SetBounds(details_.initial_bounds);
+
+ if (!details_.restore_bounds.IsEmpty())
+ SetRestoreBoundsInScreen(details_.window, details_.restore_bounds);
}
aura::Window* DefaultWindowResizer::GetTarget() {
diff --git a/ash/wm/frame_painter.cc b/ash/wm/frame_painter.cc
index 1bfede6..a63f68a 100644
--- a/ash/wm/frame_painter.cc
+++ b/ash/wm/frame_painter.cc
@@ -7,6 +7,7 @@
#include "ash/ash_constants.h"
#include "ash/shell.h"
#include "ash/shell_window_ids.h"
+#include "ash/wm/property_util.h"
#include "ash/wm/window_util.h"
#include "ash/wm/workspace_controller.h"
#include "base/logging.h" // DCHECK
@@ -26,6 +27,7 @@
#include "ui/gfx/canvas.h"
#include "ui/gfx/font.h"
#include "ui/gfx/image/image.h"
+#include "ui/gfx/screen.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
@@ -246,6 +248,7 @@ int FramePainter::NonClientHitTest(views::NonClientFrameView* view,
kResizeAreaCornerSize,
kResizeAreaCornerSize,
can_ever_resize);
+ frame_component = AdjustFrameHitCodeForMaximizedModes(frame_component);
if (frame_component != HTNOWHERE)
return frame_component;
@@ -610,6 +613,43 @@ int FramePainter::GetHeaderOpacity(HeaderMode header_mode,
return kInactiveWindowOpacity;
}
+int FramePainter::AdjustFrameHitCodeForMaximizedModes(int hit_code) {
+ if (hit_code != HTNOWHERE && wm::IsWindowNormal(window_) &&
+ GetRestoreBoundsInScreen(window_)) {
+ // When there is a restore rectangle, a left/right maximized window might
+ // be active.
+ const gfx::Rect& bounds = frame_->GetWindowBoundsInScreen();
+ const gfx::Rect& screen =
+ gfx::Screen::GetDisplayMatching(bounds).work_area();
+ if (bounds.y() == screen.y() && bounds.bottom() == screen.bottom()) {
+ // The window is probably either left or right maximized.
+ if (bounds.x() == screen.x()) {
+ // It is left maximized and we can only allow a right resize.
+ return (hit_code == HTBOTTOMRIGHT ||
+ hit_code == HTTOPRIGHT ||
+ hit_code == HTRIGHT) ? HTRIGHT : HTNOWHERE;
+ } else if (bounds.right() == screen.right()) {
+ // It is right maximized and we can only allow a left resize.
+ return (hit_code == HTBOTTOMLEFT ||
+ hit_code == HTTOPLEFT ||
+ hit_code == HTLEFT) ? HTLEFT : HTNOWHERE;
+ }
+ } else if (bounds.x() == screen.x() &&
+ bounds.right() == screen.right()) {
+ // If horizontal fill mode is activated we don't allow a left/right
+ // resizing.
+ if (hit_code == HTTOPRIGHT ||
+ hit_code == HTTOP ||
+ hit_code == HTTOPLEFT)
+ return HTTOP;
+ return (hit_code == HTBOTTOMRIGHT ||
+ hit_code == HTBOTTOM ||
+ hit_code == HTBOTTOMLEFT) ? HTBOTTOM : HTNOWHERE;
+ }
+ }
+ return hit_code;
+}
+
// static
bool FramePainter::UseSoloWindowHeader() {
if (!instances_)
diff --git a/ash/wm/frame_painter.h b/ash/wm/frame_painter.h
index 57045e3..cd725d4 100644
--- a/ash/wm/frame_painter.h
+++ b/ash/wm/frame_painter.h
@@ -141,6 +141,9 @@ class ASH_EXPORT FramePainter : public aura::WindowObserver,
int theme_frame_id,
const gfx::ImageSkia* theme_frame_overlay);
+ // Adjust frame operations for left / right maximized modes.
+ int AdjustFrameHitCodeForMaximizedModes(int hit_code);
+
// Returns true if there is exactly one visible, normal-type window using
// a header painted by this class, in which case we should paint a transparent
// window header.
diff --git a/ash/wm/frame_painter_unittest.cc b/ash/wm/frame_painter_unittest.cc
index c918f23..870761e 100644
--- a/ash/wm/frame_painter_unittest.cc
+++ b/ash/wm/frame_painter_unittest.cc
@@ -7,18 +7,40 @@
#include "ash/shell.h"
#include "ash/shell_window_ids.h"
#include "ash/test/ash_test_base.h"
+#include "ash/wm/property_util.h"
#include "base/memory/scoped_ptr.h"
#include "grit/ui_resources.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/root_window.h"
+#include "ui/base/hit_test.h"
+#include "ui/gfx/screen.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/window/non_client_view.h"
using views::Widget;
using views::ImageButton;
namespace {
+class ResizableWidgetDelegate : public views::WidgetDelegate {
+ public:
+ ResizableWidgetDelegate(views::Widget* widget) {
+ widget_ = widget;
+ }
+
+ virtual bool CanResize() const OVERRIDE { return true; }
+ // Implementations of the widget class.
+ virtual views::Widget* GetWidget() OVERRIDE { return widget_; }
+ virtual const views::Widget* GetWidget() const OVERRIDE { return widget_; }
+
+ private:
+ views::Widget* widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(ResizableWidgetDelegate);
+};
+
// Creates a test widget that owns its native widget.
Widget* CreateTestWidget() {
Widget* widget = new Widget;
@@ -37,6 +59,17 @@ Widget* CreateAlwaysOnTopWidget() {
return widget;
}
+Widget* CreateResizableWidget() {
+ Widget* widget = new Widget;
+ Widget::InitParams params;
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.keep_on_top = true;
+ params.delegate = new ResizableWidgetDelegate(widget);
+ params.type = Widget::InitParams::TYPE_WINDOW;
+ widget->Init(params);
+ return widget;
+}
+
} // namespace
namespace ash {
@@ -161,4 +194,38 @@ TEST_F(FramePainterTest, GetHeaderOpacity) {
&custom_overlay));
}
+// Test the hit test function with windows which are "partially maximized".
+TEST_F(FramePainterTest, HitTestSpecialMaximizedModes) {
+ // Create a widget and a painter for it.
+ scoped_ptr<Widget> w1(CreateResizableWidget());
+ FramePainter p1;
+ ImageButton size1(NULL);
+ ImageButton close1(NULL);
+ p1.Init(w1.get(), NULL, &size1, &close1, FramePainter::SIZE_BUTTON_MAXIMIZES);
+ views::NonClientFrameView* frame = w1->non_client_view()->frame_view();
+ w1->Show();
+ gfx::Rect any_rect = gfx::Rect(0, 0, 100, 100);
+ gfx::Rect screen = gfx::Screen::GetDisplayMatching(any_rect).work_area();
+ w1->SetBounds(any_rect);
+ EXPECT_EQ(HTTOPLEFT, p1.NonClientHitTest(frame, gfx::Point(0, 15)));
+ w1->SetBounds(gfx::Rect(
+ screen.x(), screen.y(), screen.width() / 2, screen.height()));
+ // A hit without a set restore rect should produce a top left hit.
+ EXPECT_EQ(HTTOPLEFT, p1.NonClientHitTest(frame, gfx::Point(0, 15)));
+ ash::SetRestoreBoundsInScreen(w1->GetNativeWindow(), any_rect);
+ // A hit into the corner should produce nowhere - not left.
+ EXPECT_EQ(HTCAPTION, p1.NonClientHitTest(frame, gfx::Point(0, 15)));
+ // A hit into the middle upper area should generate right - not top&right.
+ EXPECT_EQ(HTRIGHT,
+ p1.NonClientHitTest(frame, gfx::Point(screen.width() / 2, 15)));
+ // A hit into the middle should generate right.
+ EXPECT_EQ(HTRIGHT,
+ p1.NonClientHitTest(frame, gfx::Point(screen.width() / 2,
+ screen.height() / 2)));
+ // A hit into the middle lower area should generate right - not bottom&right.
+ EXPECT_EQ(HTRIGHT,
+ p1.NonClientHitTest(frame, gfx::Point(screen.width() / 2,
+ screen.height() - 1)));
+}
+
} // namespace ash
diff --git a/ash/wm/window_resizer.cc b/ash/wm/window_resizer.cc
index 592fd81..c759c91 100644
--- a/ash/wm/window_resizer.cc
+++ b/ash/wm/window_resizer.cc
@@ -6,6 +6,8 @@
#include "ash/screen_ash.h"
#include "ash/shell.h"
+#include "ash/wm/property_util.h"
+#include "ash/wm/window_util.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
@@ -112,6 +114,7 @@ WindowResizer::Details::Details(aura::Window* window,
int window_component)
: window(window),
initial_bounds(window->bounds()),
+ restore_bounds(gfx::Rect()),
initial_location_in_parent(location),
initial_opacity(window->layer()->opacity()),
window_component(window_component),
@@ -121,6 +124,10 @@ WindowResizer::Details::Details(aura::Window* window,
size_change_direction(
GetSizeChangeDirectionForWindowComponent(window_component)),
is_resizable(bounds_change != kBoundsChangeDirection_None) {
+ if (wm::IsWindowNormal(window) &&
+ GetRestoreBoundsInScreen(window) &&
+ window_component == HTCAPTION)
+ restore_bounds = *GetRestoreBoundsInScreen(window);
}
WindowResizer::Details::~Details() {
@@ -175,6 +182,17 @@ gfx::Rect WindowResizer::CalculateBoundsForDrag(
gfx::Size size = GetSizeForDrag(details, &delta_x, &delta_y);
gfx::Point origin = GetOriginForDrag(details, delta_x, delta_y);
+ // When we might want to reposition a window which is also restored to its
+ // previous size, to keep the cursor within the dragged window.
+ if (!details.restore_bounds.IsEmpty() &&
+ details.bounds_change & kBoundsChange_Repositions) {
+ // However - it is not desirable to change the origin if the window would
+ // be still hit by the cursor.
+ if (details.initial_location_in_parent.x() >
+ details.initial_bounds.x() + details.restore_bounds.width())
+ origin.set_x(location.x() - details.restore_bounds.width() / 2);
+ }
+
gfx::Rect new_bounds(origin, size);
// Update bottom edge to stay in the work area when we are resizing
// by dragging the bottome edge or corners.
@@ -229,6 +247,8 @@ gfx::Size WindowResizer::GetSizeForDrag(const Details& details,
gfx::Size min_size = details.window->delegate()->GetMinimumSize();
size.SetSize(GetWidthForDrag(details, min_size.width(), delta_x),
GetHeightForDrag(details, min_size.height(), delta_y));
+ } else if (!details.restore_bounds.IsEmpty()) {
+ size = details.restore_bounds.size();
}
return size;
}
diff --git a/ash/wm/window_resizer.h b/ash/wm/window_resizer.h
index 13ffb13..67dea81 100644
--- a/ash/wm/window_resizer.h
+++ b/ash/wm/window_resizer.h
@@ -64,6 +64,10 @@ class ASH_EXPORT WindowResizer {
// Initial bounds of the window.
gfx::Rect initial_bounds;
+ // Restore bounds (in screen coordinates) of the window before the drag
+ // started. Only set if the window is normal and is being dragged.
+ gfx::Rect restore_bounds;
+
// Location passed to the constructor, in |window->parent()|'s coordinates.
gfx::Point initial_location_in_parent;
diff --git a/ash/wm/workspace/frame_maximize_button.cc b/ash/wm/workspace/frame_maximize_button.cc
index c874f6e..735b1a6 100644
--- a/ash/wm/workspace/frame_maximize_button.cc
+++ b/ash/wm/workspace/frame_maximize_button.cc
@@ -553,9 +553,12 @@ MaximizeBubbleFrameState
gfx::Rect screen = gfx::Screen::GetDisplayMatching(bounds).work_area();
if (bounds.width() < (screen.width() * kMinSnapSizePercent) / 100)
return FRAME_STATE_NONE;
+ // We might still have a horizontally filled window at this point which we
+ // treat as no special state.
+ if (bounds.y() != screen.y() || bounds.height() != screen.height())
+ return FRAME_STATE_NONE;
+
// We have to be in a maximize mode at this point.
- DCHECK(bounds.y() == screen.y());
- DCHECK(bounds.height() >= screen.height());
if (bounds.x() == screen.x())
return FRAME_STATE_SNAP_LEFT;
if (bounds.right() == screen.right())
diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc
index 85bb095..88c9c9f 100644
--- a/ash/wm/workspace/workspace_window_resizer.cc
+++ b/ash/wm/workspace/workspace_window_resizer.cc
@@ -125,8 +125,11 @@ void WorkspaceWindowResizer::Drag(const gfx::Point& location, int event_flags) {
if (wm::IsWindowNormal(window()))
AdjustBoundsForMainWindow(&bounds, grid_size);
if (bounds != window()->bounds()) {
- if (!did_move_or_resize_)
+ if (!did_move_or_resize_) {
+ if (!details_.restore_bounds.IsEmpty())
+ ClearRestoreBounds(window());
RestackWindows();
+ }
did_move_or_resize_ = true;
}
@@ -164,7 +167,9 @@ void WorkspaceWindowResizer::CompleteDrag(int event_flags) {
if (snap_type_ == SNAP_LEFT_EDGE || snap_type_ == SNAP_RIGHT_EDGE) {
if (!GetRestoreBoundsInScreen(window()))
- SetRestoreBoundsInParent(window(), details_.initial_bounds);
+ SetRestoreBoundsInParent(window(), details_.restore_bounds.IsEmpty() ?
+ details_.initial_bounds :
+ details_.restore_bounds);
window()->SetBounds(snap_sizer_->target_bounds());
return;
}
@@ -196,6 +201,9 @@ void WorkspaceWindowResizer::RevertDrag() {
return;
window()->SetBounds(details_.initial_bounds);
+ if (!details_.restore_bounds.IsEmpty())
+ SetRestoreBoundsInScreen(details_.window, details_.restore_bounds);
+
if (details_.window_component == HTRIGHT) {
int last_x = details_.initial_bounds.right();
for (size_t i = 0; i < attached_windows_.size(); ++i) {
diff --git a/ash/wm/workspace/workspace_window_resizer_unittest.cc b/ash/wm/workspace/workspace_window_resizer_unittest.cc
index ba15148..b7eb06f 100644
--- a/ash/wm/workspace/workspace_window_resizer_unittest.cc
+++ b/ash/wm/workspace/workspace_window_resizer_unittest.cc
@@ -458,7 +458,6 @@ TEST_F(WorkspaceWindowResizerTest, Edge) {
EXPECT_EQ("20,30 50x60",
GetRestoreBoundsInScreen(window_.get())->ToString());
}
-
// Try the same with the right side.
scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
window_.get(), gfx::Point(), HTCAPTION, empty_windows()));
@@ -869,5 +868,37 @@ TEST_F(WorkspaceWindowResizerTest, TestProperSizerResolutions) {
EXPECT_EQ("0,0 640x552", rect.ToString());
}
+// Verifies that a dragged window will restore to its pre-maximized size.
+TEST_F(WorkspaceWindowResizerTest, RestoreToPreMaximizeCoordinates) {
+ window_->SetBounds(gfx::Rect(0, 0, 1000, 1000));
+ SetRestoreBoundsInScreen(window_.get(), gfx::Rect(96, 112, 320, 160));
+ scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
+ window_.get(), gfx::Point(), HTCAPTION, empty_windows()));
+ ASSERT_TRUE(resizer.get());
+ // Drag the window to new position by adding (10, 10) to original point,
+ // the window should get restored.
+ resizer->Drag(CalculateDragPoint(*resizer, 10, 10), 0);
+ resizer->CompleteDrag(0);
+ EXPECT_EQ("10,10 320x160", window_->bounds().ToString());
+ // The restore rectangle should get cleared as well.
+ EXPECT_EQ(NULL, GetRestoreBoundsInScreen(window_.get()));
+}
+
+// Verifies that a dragged window will restore to its pre-maximized size.
+TEST_F(WorkspaceWindowResizerTest, RevertResizeOperation) {
+ window_->SetBounds(gfx::Rect(0, 0, 1000, 1000));
+ SetRestoreBoundsInScreen(window_.get(), gfx::Rect(96, 112, 320, 160));
+ scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
+ window_.get(), gfx::Point(), HTCAPTION, empty_windows()));
+ ASSERT_TRUE(resizer.get());
+ // Drag the window to new poistion by adding (180, 16) to original point,
+ // the window should get restored.
+ resizer->Drag(CalculateDragPoint(*resizer, 180, 16), 0);
+ resizer->RevertDrag();
+ EXPECT_EQ("0,0 1000x1000", window_->bounds().ToString());
+ EXPECT_EQ("96,112 320x160",
+ GetRestoreBoundsInScreen(window_.get())->ToString());
+}
+
} // namespace internal
} // namespace ash