15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/wm/workspace/multi_window_resize_controller.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/screen_ash.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/shell.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/shell_window_ids.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/wm/coordinate_conversion.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/wm/window_animations.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/wm/workspace/workspace_event_handler.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/wm/workspace/workspace_window_resizer.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/ash_resources.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/client/screen_position_client.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/root_window.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/window.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/window_delegate.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/hit_test.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/screen.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/corewm/compound_event_filter.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/view.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget_delegate.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using aura::Window;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ash {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace internal {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Delay before showing.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kShowDelayMS = 400;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Delay before hiding.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kHideDelayMS = 500;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Padding from the bottom/right edge the resize widget is shown at.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kResizeWidgetPadding = 15;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ContainsX(Window* window, int x) {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return window->bounds().x() <= x && window->bounds().right() >= x;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ContainsY(Window* window, int y) {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return window->bounds().y() <= y && window->bounds().bottom() >= y;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Intersects(int x1, int max_1, int x2, int max_2) {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return x2 <= max_1 && max_2 > x1;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// View contained in the widget. Passes along mouse events to the
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MultiWindowResizeController so that it can start/stop the resize loop.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MultiWindowResizeController::ResizeView : public views::View {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit ResizeView(MultiWindowResizeController* controller,
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      Direction direction)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : controller_(controller),
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        direction_(direction),
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        image_(NULL) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int image_id =
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        direction == TOP_BOTTOM ? IDR_AURA_MULTI_WINDOW_RESIZE_H :
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  IDR_AURA_MULTI_WINDOW_RESIZE_V;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    image_ = rb.GetImageNamed(image_id).ToImageSkia();
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views::View overrides:
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual gfx::Size GetPreferredSize() OVERRIDE {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return gfx::Size(image_->width(), image_->height());
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    canvas->DrawImageInt(*image_, 0, 0);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Point location(event.location());
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View::ConvertPointToScreen(this, &location);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    controller_->StartResize(location);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Point location(event.location());
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View::ConvertPointToScreen(this, &location);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    controller_->Resize(location, event.flags());
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    controller_->CompleteResize(event.flags());
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnMouseCaptureLost() OVERRIDE {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    controller_->CancelResize();
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual gfx::NativeCursor GetCursor(
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const ui::MouseEvent& event) OVERRIDE {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int component = (direction_ == LEFT_RIGHT) ? HTRIGHT : HTBOTTOM;
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return views::corewm::CompoundEventFilter::CursorForWindowComponent(
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        component);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MultiWindowResizeController* controller_;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Direction direction_;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const gfx::ImageSkia* image_;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ResizeView);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MouseWatcherHost implementation for MultiWindowResizeController. Forwards
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Contains() to MultiWindowResizeController.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MultiWindowResizeController::ResizeMouseWatcherHost :
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   public views::MouseWatcherHost {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ResizeMouseWatcherHost(MultiWindowResizeController* host) : host_(host) {}
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // MouseWatcherHost overrides:
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool Contains(const gfx::Point& point_in_screen,
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        MouseEventType type) OVERRIDE {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return host_->IsOverWindows(point_in_screen);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MultiWindowResizeController* host_;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ResizeMouseWatcherHost);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MultiWindowResizeController::ResizeWindows::ResizeWindows()
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : window1(NULL),
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window2(NULL),
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      direction(TOP_BOTTOM){
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MultiWindowResizeController::ResizeWindows::~ResizeWindows() {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MultiWindowResizeController::ResizeWindows::Equals(
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ResizeWindows& other) const {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return window1 == other.window1 &&
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window2 == other.window2 &&
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      direction == other.direction;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MultiWindowResizeController::MultiWindowResizeController() {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MultiWindowResizeController::~MultiWindowResizeController() {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window_resizer_.reset();
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Hide();
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MultiWindowResizeController::Show(Window* window,
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       int component,
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const gfx::Point& point_in_window) {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // When the resize widget is showing we ignore Show() requests. Instead we
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // only care about mouse movements from MouseWatcher. This is necessary as
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // WorkspaceEventHandler only sees mouse movements over the windows, not all
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // windows or over the desktop.
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (resize_widget_)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ResizeWindows windows(DetermineWindows(window, component, point_in_window));
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsShowing()) {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (windows_.Equals(windows))
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;  // Over the same windows.
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DelayedHide();
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!windows.is_valid())
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Hide();
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  windows_ = windows;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  windows_.window1->AddObserver(this);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  windows_.window2->AddObserver(this);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  show_location_in_parent_ = point_in_window;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Window::ConvertPointToTarget(
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window, window->parent(), &show_location_in_parent_);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (show_timer_.IsRunning())
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  show_timer_.Start(
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE, base::TimeDelta::FromMilliseconds(kShowDelayMS),
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this, &MultiWindowResizeController::ShowIfValidMouseLocation);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MultiWindowResizeController::Hide() {
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hide_timer_.Stop();
193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (window_resizer_)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // Ignore hides while actively resizing.
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (windows_.window1) {
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    windows_.window1->RemoveObserver(this);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    windows_.window1 = NULL;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (windows_.window2) {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    windows_.window2->RemoveObserver(this);
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    windows_.window2 = NULL;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  show_timer_.Stop();
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!resize_widget_)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < windows_.other_windows.size(); ++i)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    windows_.other_windows[i]->RemoveObserver(this);
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mouse_watcher_.reset();
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resize_widget_.reset();
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  windows_ = ResizeWindows();
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MultiWindowResizeController::MouseMovedOutOfHost() {
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Hide();
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MultiWindowResizeController::OnWindowDestroying(
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    aura::Window* window) {
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Have to explicitly reset the WindowResizer, otherwise Hide() does nothing.
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window_resizer_.reset();
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Hide();
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MultiWindowResizeController::ResizeWindows
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MultiWindowResizeController::DetermineWindowsFromScreenPoint(
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    aura::Window* window) const {
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Point mouse_location(
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::Screen::GetScreenFor(window)->GetCursorScreenPoint());
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wm::ConvertPointFromScreen(window, &mouse_location);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int component =
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window->delegate()->GetNonClientComponent(mouse_location);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return DetermineWindows(window, component, mouse_location);
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MultiWindowResizeController::ResizeWindows
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MultiWindowResizeController::DetermineWindows(
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Window* window,
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int window_component,
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Point& point) const {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ResizeWindows result;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Point point_in_parent(point);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Window::ConvertPointToTarget(window, window->parent(), &point_in_parent);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (window_component) {
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case HTRIGHT:
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result.direction = LEFT_RIGHT;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result.window1 = window;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result.window2 = FindWindowByEdge(
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window, HTLEFT, window->bounds().right(), point_in_parent.y());
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case HTLEFT:
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result.direction = LEFT_RIGHT;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result.window1 = FindWindowByEdge(
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window, HTRIGHT, window->bounds().x(), point_in_parent.y());
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result.window2 = window;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case HTTOP:
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result.direction = TOP_BOTTOM;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result.window1 = FindWindowByEdge(
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window, HTBOTTOM, point_in_parent.x(), window->bounds().y());
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result.window2 = window;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case HTBOTTOM:
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result.direction = TOP_BOTTOM;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result.window1 = window;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result.window2 = FindWindowByEdge(
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window, HTTOP, point_in_parent.x(), window->bounds().bottom());
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Window* MultiWindowResizeController::FindWindowByEdge(
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Window* window_to_ignore,
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int edge_want,
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int x,
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int y) const {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Window* parent = window_to_ignore->parent();
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Window::Windows& windows(parent->children());
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (Window::Windows::const_reverse_iterator i = windows.rbegin();
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != windows.rend(); ++i) {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Window* window = *i;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (window == window_to_ignore || !window->IsVisible())
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (edge_want) {
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case HTLEFT:
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (ContainsY(window, y) && window->bounds().x() == x)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return window;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case HTRIGHT:
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (ContainsY(window, y) && window->bounds().right() == x)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return window;
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case HTTOP:
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (ContainsX(window, x) && window->bounds().y() == y)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return window;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case HTBOTTOM:
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (ContainsX(window, x) && window->bounds().bottom() == y)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return window;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Window doesn't contain the edge, but if window contains |point|
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // it's obscuring any other window that could be at the location.
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (window->bounds().Contains(x, y))
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NULL;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)aura::Window* MultiWindowResizeController::FindWindowTouching(
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    aura::Window* window,
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Direction direction) const {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int right = window->bounds().right();
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int bottom = window->bounds().bottom();
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Window* parent = window->parent();
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Window::Windows& windows(parent->children());
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (Window::Windows::const_reverse_iterator i = windows.rbegin();
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != windows.rend(); ++i) {
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Window* other = *i;
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (other == window || !other->IsVisible())
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (direction) {
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case TOP_BOTTOM:
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (other->bounds().y() == bottom &&
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            Intersects(other->bounds().x(), other->bounds().right(),
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       window->bounds().x(), window->bounds().right())) {
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return other;
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case LEFT_RIGHT:
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (other->bounds().x() == right &&
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            Intersects(other->bounds().y(), other->bounds().bottom(),
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       window->bounds().y(), window->bounds().bottom())) {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return other;
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MultiWindowResizeController::FindWindowsTouching(
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    aura::Window* start,
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Direction direction,
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<aura::Window*>* others) const {
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (start) {
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    start = FindWindowTouching(start, direction);
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (start)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      others->push_back(start);
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MultiWindowResizeController::DelayedHide() {
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (hide_timer_.IsRunning())
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hide_timer_.Start(FROM_HERE,
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    base::TimeDelta::FromMilliseconds(kHideDelayMS),
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    this, &MultiWindowResizeController::Hide);
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MultiWindowResizeController::ShowIfValidMouseLocation() {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (DetermineWindowsFromScreenPoint(windows_.window1).Equals(windows_) ||
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DetermineWindowsFromScreenPoint(windows_.window2).Equals(windows_)) {
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ShowNow();
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Hide();
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MultiWindowResizeController::ShowNow() {
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!resize_widget_.get());
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(windows_.is_valid());
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  show_timer_.Stop();
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resize_widget_.reset(new views::Widget);
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
387eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.parent = Shell::GetContainer(
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Shell::GetActiveRootWindow(),
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      internal::kShellWindowId_AlwaysOnTopContainer);
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.can_activate = false;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ResizeView* view = new ResizeView(this, windows_.direction);
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resize_widget_->set_focus_on_creation(false);
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resize_widget_->Init(params);
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  views::corewm::SetWindowVisibilityAnimationType(
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      resize_widget_->GetNativeWindow(),
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      views::corewm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resize_widget_->GetNativeWindow()->SetName("MultiWindowResizeController");
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resize_widget_->SetContentsView(view);
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  show_bounds_in_screen_ = ScreenAsh::ConvertRectToScreen(
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windows_.window1->parent(),
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CalculateResizeWidgetBounds(show_location_in_parent_));
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resize_widget_->SetBounds(show_bounds_in_screen_);
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resize_widget_->Show();
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mouse_watcher_.reset(new views::MouseWatcher(
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           new ResizeMouseWatcherHost(this),
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           this));
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mouse_watcher_->set_notify_on_exit_time(
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(kHideDelayMS));
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mouse_watcher_->Start();
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MultiWindowResizeController::IsShowing() const {
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return resize_widget_.get() || show_timer_.IsRunning();
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MultiWindowResizeController::StartResize(
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Point& location_in_screen) {
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!window_resizer_.get());
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(windows_.is_valid());
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hide_timer_.Stop();
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Point location_in_parent(location_in_screen);
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  aura::client::GetScreenPositionClient(windows_.window2->GetRootWindow())->
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ConvertPointFromScreen(windows_.window2->parent(), &location_in_parent);
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<aura::Window*> windows;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  windows.push_back(windows_.window2);
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(windows_.other_windows.empty());
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FindWindowsTouching(windows_.window2, windows_.direction,
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      &windows_.other_windows);
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < windows_.other_windows.size(); ++i) {
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    windows_.other_windows[i]->AddObserver(this);
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    windows.push_back(windows_.other_windows[i]);
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int component = windows_.direction == LEFT_RIGHT ? HTRIGHT : HTBOTTOM;
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window_resizer_.reset(WorkspaceWindowResizer::Create(
4377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      windows_.window1,
4387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      location_in_parent,
4397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      component,
4407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      aura::client::WINDOW_MOVE_SOURCE_MOUSE,
4417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      windows));
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MultiWindowResizeController::Resize(const gfx::Point& location_in_screen,
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         int event_flags) {
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Point location_in_parent(location_in_screen);
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  aura::client::GetScreenPositionClient(windows_.window1->GetRootWindow())->
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ConvertPointFromScreen(windows_.window1->parent(), &location_in_parent);
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window_resizer_->Drag(location_in_parent, event_flags);
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect bounds = ScreenAsh::ConvertRectToScreen(
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windows_.window1->parent(),
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CalculateResizeWidgetBounds(location_in_parent));
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (windows_.direction == LEFT_RIGHT)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bounds.set_y(show_bounds_in_screen_.y());
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bounds.set_x(show_bounds_in_screen_.x());
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resize_widget_->SetBounds(bounds);
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MultiWindowResizeController::CompleteResize(int event_flags) {
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window_resizer_->CompleteDrag(event_flags);
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window_resizer_.reset();
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Mouse may still be over resizer, if not hide.
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Point screen_loc = Shell::GetScreen()->GetCursorScreenPoint();
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!resize_widget_->GetWindowBoundsInScreen().Contains(screen_loc)) {
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Hide();
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the mouse is over the resizer we need to remove observers on any of
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the |other_windows|. If we start another resize we'll recalculate the
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // |other_windows| and invoke AddObserver() as necessary.
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < windows_.other_windows.size(); ++i)
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windows_.other_windows[i]->RemoveObserver(this);
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    windows_.other_windows.clear();
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MultiWindowResizeController::CancelResize() {
480c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!window_resizer_)
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // Happens if window was destroyed and we nuked the WindowResizer.
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window_resizer_->RevertDrag();
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window_resizer_.reset();
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Hide();
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Rect MultiWindowResizeController::CalculateResizeWidgetBounds(
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Point& location_in_parent) const {
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Size pref = resize_widget_->GetContentsView()->GetPreferredSize();
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int x = 0, y = 0;
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (windows_.direction == LEFT_RIGHT) {
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    x = windows_.window1->bounds().right() - pref.width() / 2;
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    y = location_in_parent.y() + kResizeWidgetPadding;
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (y + pref.height() / 2 > windows_.window1->bounds().bottom() &&
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        y + pref.height() / 2 > windows_.window2->bounds().bottom()) {
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      y = location_in_parent.y() - kResizeWidgetPadding - pref.height();
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    x = location_in_parent.x() + kResizeWidgetPadding;
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (x + pref.height() / 2 > windows_.window1->bounds().right() &&
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        x + pref.height() / 2 > windows_.window2->bounds().right()) {
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      x = location_in_parent.x() - kResizeWidgetPadding - pref.width();
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    y = windows_.window1->bounds().bottom() - pref.height() / 2;
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gfx::Rect(x, y, pref.width(), pref.height());
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MultiWindowResizeController::IsOverWindows(
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Point& location_in_screen) const {
511c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (window_resizer_)
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;  // Ignore hides while actively resizing.
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (resize_widget_->GetWindowBoundsInScreen().Contains(location_in_screen))
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int hit1, hit2;
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (windows_.direction == TOP_BOTTOM) {
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hit1 = HTBOTTOM;
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hit2 = HTTOP;
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hit1 = HTRIGHT;
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hit2 = HTLEFT;
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return IsOverWindow(windows_.window1, location_in_screen, hit1) ||
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IsOverWindow(windows_.window2, location_in_screen, hit2);
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MultiWindowResizeController::IsOverWindow(
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    aura::Window* window,
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Point& location_in_screen,
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int component) const {
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!window->delegate())
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Point window_loc(location_in_screen);
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  aura::Window::ConvertPointToTarget(
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window->GetRootWindow(), window, &window_loc);
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return window->HitTest(window_loc) &&
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window->delegate()->GetNonClientComponent(window_loc) == component;
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace internal
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace ash
546