wm: Snap to maximized when interactively resizing browser. This makes the interactive resize triggered by dragging a browser window's border snap to maximized mode if the user drags 50 pixels or more beyond the maximum width permitted for unmaximized windows. BUG=chromium-os:17160 TEST=manual; also added a simple test Change-Id: I0514bfecfc6ec913f00fe56111e14c6d1ea826bb Reviewed-on: http://gerrit.chromium.org/gerrit/4965 Tested-by: David Reveman <reveman@chromium.org> Reviewed-by: David Reveman <reveman@chromium.org> Tested-by: Daniel Erat <derat@chromium.org>
diff --git a/layout2/layout_manager2.cc b/layout2/layout_manager2.cc index 198f183..c401a78 100644 --- a/layout2/layout_manager2.cc +++ b/layout2/layout_manager2.cc
@@ -42,6 +42,7 @@ DEFINE_string(xterm_command, "xterm", "Command to launch a terminal"); +using base::TimeTicks; using chromeos::WM_IPC_LAYOUT_MAXIMIZED; using chromeos::WM_IPC_LAYOUT_OVERLAPPING; using chromeos::WmIpcLayoutMode; @@ -53,6 +54,7 @@ using std::string; using std::tr1::shared_ptr; using std::vector; +using window_manager::util::GetMonotonicTime; using window_manager::util::RunCommandInBackgroundCallback; using window_manager::util::ToggleBool; using window_manager::util::XidStr; @@ -86,6 +88,15 @@ // Opacity of the box that we display while the user is resizing a window. const double kResizeBoxOpacity = 0.4; +// When a browser window is being interactively resized, how much wider than the +// maximum width for an unmaximized window does it need to get before we snap it +// to cover the whole screen and enter maximized mode? +const int kResizeSnapThresholdPixels = 50; + +// Duration of the snapping-to-cover-the-whole-screen animation, in +// milliseconds. +const int kResizeBoxSnapAnimMs = 100; + // Duration over which we dim the secondary browser window, in milliseconds. const double kSecondaryBrowserWindowDimAnimMs = 10000; @@ -130,6 +141,7 @@ wm_->CreateInputWindow(Rect(-1, -1, 1, 1), ButtonPressMask)), in_resize_drag_(false), resize_width_at_start_(0), + resize_box_is_snapped_(false), first_browser_window_mapped_(false) { event_consumer_registrar_->RegisterForChromeMessages( chromeos::WM_IPC_MESSAGE_WM_CYCLE_WINDOWS); @@ -1342,6 +1354,8 @@ in_resize_drag_ = true; resize_drag_start_pos_ = absolute_pos; resize_width_at_start_ = active_browser->unmaximized_width(); + resize_box_is_snapped_ = false; + resize_box_unsnap_time_ = TimeTicks(); resize_box_.reset(new ResizeBox(wm_->compositor())); Rect bounds(active_browser->win()->client_x(), workarea_.y, @@ -1361,13 +1375,41 @@ int width = resize_width_at_start_ + (active_browser->anchored_to_left() ? 1 : -1) * dx; - width = ConstrainUnmaximizedWidth(width); - Rect bounds(active_browser->win()->client_x(), workarea_.y, - width, workarea_.height); - if (!active_browser->anchored_to_left()) - bounds.x -= (width - resize_width_at_start_); - resize_box_->SetBounds(bounds, 0); + if (width >= GetMaxUnmaximizedWidth() + kResizeSnapThresholdPixels) { + if (!resize_box_is_snapped_) { + resize_box_is_snapped_ = true; + resize_box_->SetBounds(workarea_, kResizeBoxSnapAnimMs); + last_resize_box_bounds_ = workarea_; + } + } else { + width = ConstrainUnmaximizedWidth(width); + Rect bounds(active_browser->win()->client_x(), workarea_.y, + width, workarea_.height); + if (!active_browser->anchored_to_left()) + bounds.x -= (width - resize_width_at_start_); + + TimeTicks now = GetMonotonicTime(); + if (resize_box_is_snapped_) { + resize_box_is_snapped_ = false; + resize_box_unsnap_time_ = now; + } + + if (bounds != last_resize_box_bounds_) { + int anim_ms = 0; + if (!resize_box_unsnap_time_.is_null()) { + // Restarting the unsnap animation like this is a bit hacky. Ideally, + // we'd be able to adjust the endpoint of the existing unsnap animation + // or make the animations (if any) created by the SetBounds() call start + // at full speed. This seems to look okay, though... + const int elapsed_ms = static_cast<int>( + (now - resize_box_unsnap_time_).InMilliseconds()); + anim_ms = max(0, kResizeBoxSnapAnimMs - elapsed_ms); + } + resize_box_->SetBounds(bounds, anim_ms); + last_resize_box_bounds_ = bounds; + } + } } void LayoutManager2::HandleResizeDragEnd(const Point& absolute_pos) { @@ -1382,7 +1424,11 @@ int new_width = active_browser->unmaximized_width() + (active_browser->anchored_to_left() ? 1 : -1) * dx; - ChangeActiveBrowserUnmaximizedWidth(ConstrainUnmaximizedWidth(new_width)); + + if (new_width >= GetMaxUnmaximizedWidth() + kResizeSnapThresholdPixels) + SetLayoutMode(WM_IPC_LAYOUT_MAXIMIZED, true); + else + ChangeActiveBrowserUnmaximizedWidth(ConstrainUnmaximizedWidth(new_width)); } void LayoutManager2::HandleWindowNoLongerBlockingArrange(Window* win) {
diff --git a/layout2/layout_manager2.h b/layout2/layout_manager2.h index eef942f..feeceb6 100644 --- a/layout2/layout_manager2.h +++ b/layout2/layout_manager2.h
@@ -14,6 +14,7 @@ #include "base/basictypes.h" #include "base/scoped_ptr.h" +#include "base/time.h" #include "cros/chromeos_wm_ipc_enums.h" #include "window_manager/compositor/compositor.h" #include "window_manager/event_consumer.h" @@ -366,6 +367,16 @@ // Box displayed to show the current window dimensions while resizing. scoped_ptr<ResizeBox> resize_box_; + // Is |resize_box_| currently snapped to cover the whole workarea? + bool resize_box_is_snapped_; + + // Last bounds used for configuring |resize_box_|. + Rect last_resize_box_bounds_; + + // When the user drags the resize box to cover the whole screen and then drags + // it back, time at which we unsnapped the box from the maximized state. + base::TimeTicks resize_box_unsnap_time_; + // Have we seen a browser window get mapped yet? bool first_browser_window_mapped_;
diff --git a/layout2/layout_manager2_test.cc b/layout2/layout_manager2_test.cc index 0180d48..fe0a3c5 100644 --- a/layout2/layout_manager2_test.cc +++ b/layout2/layout_manager2_test.cc
@@ -981,6 +981,12 @@ old_width = info1->bounds.width; SendKey(xconn_->GetRootWindow(), kAltPeriodKeyCombo, kEventTime, kEventTime); EXPECT_GT(info1->bounds.width, old_width); + + // Check that we can switch to maximized mode by dragging the resize handle + // all the way over. + DragResizeHandle(kRootBounds.width); + EXPECT_TRUE(layout_manager()->maximized()); + EXPECT_EQ(kRootBounds, info1->bounds); } TEST_F(LayoutManager2Test, SetLayoutMode) {