| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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. | |
| 4 | |
| 5 #include "ash/common/wm/workspace/multi_window_resize_controller.h" | |
| 6 | |
| 7 #include "ash/common/wm/workspace/workspace_window_resizer.h" | |
| 8 #include "ash/common/wm_window.h" | |
| 9 #include "ash/public/cpp/shell_window_ids.h" | |
| 10 #include "ash/resources/grit/ash_resources.h" | |
| 11 #include "ash/root_window_controller.h" | |
| 12 #include "ui/base/cursor/cursor.h" | |
| 13 #include "ui/base/hit_test.h" | |
| 14 #include "ui/base/resource/resource_bundle.h" | |
| 15 #include "ui/display/screen.h" | |
| 16 #include "ui/gfx/canvas.h" | |
| 17 #include "ui/gfx/image/image.h" | |
| 18 #include "ui/views/view.h" | |
| 19 #include "ui/views/widget/widget.h" | |
| 20 #include "ui/views/widget/widget_delegate.h" | |
| 21 #include "ui/wm/core/compound_event_filter.h" | |
| 22 | |
| 23 namespace ash { | |
| 24 namespace { | |
| 25 | |
| 26 // Delay before showing. | |
| 27 const int kShowDelayMS = 400; | |
| 28 | |
| 29 // Delay before hiding. | |
| 30 const int kHideDelayMS = 500; | |
| 31 | |
| 32 // Padding from the bottom/right edge the resize widget is shown at. | |
| 33 const int kResizeWidgetPadding = 15; | |
| 34 | |
| 35 bool ContainsX(WmWindow* window, int x) { | |
| 36 return x >= 0 && x <= window->GetBounds().width(); | |
| 37 } | |
| 38 | |
| 39 bool ContainsScreenX(WmWindow* window, int x_in_screen) { | |
| 40 gfx::Point window_loc = | |
| 41 window->ConvertPointFromScreen(gfx::Point(x_in_screen, 0)); | |
| 42 return ContainsX(window, window_loc.x()); | |
| 43 } | |
| 44 | |
| 45 bool ContainsY(WmWindow* window, int y) { | |
| 46 return y >= 0 && y <= window->GetBounds().height(); | |
| 47 } | |
| 48 | |
| 49 bool ContainsScreenY(WmWindow* window, int y_in_screen) { | |
| 50 gfx::Point window_loc = | |
| 51 window->ConvertPointFromScreen(gfx::Point(0, y_in_screen)); | |
| 52 return ContainsY(window, window_loc.y()); | |
| 53 } | |
| 54 | |
| 55 bool Intersects(int x1, int max_1, int x2, int max_2) { | |
| 56 return x2 <= max_1 && max_2 > x1; | |
| 57 } | |
| 58 | |
| 59 } // namespace | |
| 60 | |
| 61 // View contained in the widget. Passes along mouse events to the | |
| 62 // MultiWindowResizeController so that it can start/stop the resize loop. | |
| 63 class MultiWindowResizeController::ResizeView : public views::View { | |
| 64 public: | |
| 65 explicit ResizeView(MultiWindowResizeController* controller, | |
| 66 Direction direction) | |
| 67 : controller_(controller), direction_(direction), image_(NULL) { | |
| 68 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 69 int image_id = direction == TOP_BOTTOM ? IDR_AURA_MULTI_WINDOW_RESIZE_H | |
| 70 : IDR_AURA_MULTI_WINDOW_RESIZE_V; | |
| 71 image_ = rb.GetImageNamed(image_id).ToImageSkia(); | |
| 72 } | |
| 73 | |
| 74 // views::View overrides: | |
| 75 gfx::Size GetPreferredSize() const override { | |
| 76 return gfx::Size(image_->width(), image_->height()); | |
| 77 } | |
| 78 void OnPaint(gfx::Canvas* canvas) override { | |
| 79 canvas->DrawImageInt(*image_, 0, 0); | |
| 80 } | |
| 81 bool OnMousePressed(const ui::MouseEvent& event) override { | |
| 82 gfx::Point location(event.location()); | |
| 83 views::View::ConvertPointToScreen(this, &location); | |
| 84 controller_->StartResize(location); | |
| 85 return true; | |
| 86 } | |
| 87 bool OnMouseDragged(const ui::MouseEvent& event) override { | |
| 88 gfx::Point location(event.location()); | |
| 89 views::View::ConvertPointToScreen(this, &location); | |
| 90 controller_->Resize(location, event.flags()); | |
| 91 return true; | |
| 92 } | |
| 93 void OnMouseReleased(const ui::MouseEvent& event) override { | |
| 94 controller_->CompleteResize(); | |
| 95 } | |
| 96 void OnMouseCaptureLost() override { controller_->CancelResize(); } | |
| 97 gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override { | |
| 98 int component = (direction_ == LEFT_RIGHT) ? HTRIGHT : HTBOTTOM; | |
| 99 return ::wm::CompoundEventFilter::CursorForWindowComponent(component); | |
| 100 } | |
| 101 | |
| 102 private: | |
| 103 MultiWindowResizeController* controller_; | |
| 104 const Direction direction_; | |
| 105 const gfx::ImageSkia* image_; | |
| 106 | |
| 107 DISALLOW_COPY_AND_ASSIGN(ResizeView); | |
| 108 }; | |
| 109 | |
| 110 // MouseWatcherHost implementation for MultiWindowResizeController. Forwards | |
| 111 // Contains() to MultiWindowResizeController. | |
| 112 class MultiWindowResizeController::ResizeMouseWatcherHost | |
| 113 : public views::MouseWatcherHost { | |
| 114 public: | |
| 115 ResizeMouseWatcherHost(MultiWindowResizeController* host) : host_(host) {} | |
| 116 | |
| 117 // MouseWatcherHost overrides: | |
| 118 bool Contains(const gfx::Point& point_in_screen, | |
| 119 MouseEventType type) override { | |
| 120 return (type == MOUSE_PRESS) ? host_->IsOverResizeWidget(point_in_screen) | |
| 121 : host_->IsOverWindows(point_in_screen); | |
| 122 } | |
| 123 | |
| 124 private: | |
| 125 MultiWindowResizeController* host_; | |
| 126 | |
| 127 DISALLOW_COPY_AND_ASSIGN(ResizeMouseWatcherHost); | |
| 128 }; | |
| 129 | |
| 130 MultiWindowResizeController::ResizeWindows::ResizeWindows() | |
| 131 : window1(nullptr), window2(nullptr), direction(TOP_BOTTOM) {} | |
| 132 | |
| 133 MultiWindowResizeController::ResizeWindows::ResizeWindows( | |
| 134 const ResizeWindows& other) = default; | |
| 135 | |
| 136 MultiWindowResizeController::ResizeWindows::~ResizeWindows() {} | |
| 137 | |
| 138 bool MultiWindowResizeController::ResizeWindows::Equals( | |
| 139 const ResizeWindows& other) const { | |
| 140 return window1 == other.window1 && window2 == other.window2 && | |
| 141 direction == other.direction; | |
| 142 } | |
| 143 | |
| 144 MultiWindowResizeController::MultiWindowResizeController() {} | |
| 145 | |
| 146 MultiWindowResizeController::~MultiWindowResizeController() { | |
| 147 window_resizer_.reset(); | |
| 148 Hide(); | |
| 149 } | |
| 150 | |
| 151 void MultiWindowResizeController::Show(WmWindow* window, | |
| 152 int component, | |
| 153 const gfx::Point& point_in_window) { | |
| 154 // When the resize widget is showing we ignore Show() requests. Instead we | |
| 155 // only care about mouse movements from MouseWatcher. This is necessary as | |
| 156 // WorkspaceEventHandler only sees mouse movements over the windows, not all | |
| 157 // windows or over the desktop. | |
| 158 if (resize_widget_) | |
| 159 return; | |
| 160 | |
| 161 ResizeWindows windows(DetermineWindows(window, component, point_in_window)); | |
| 162 if (IsShowing() && windows_.Equals(windows)) | |
| 163 return; | |
| 164 | |
| 165 Hide(); | |
| 166 if (!windows.is_valid()) { | |
| 167 windows_ = ResizeWindows(); | |
| 168 return; | |
| 169 } | |
| 170 | |
| 171 windows_ = windows; | |
| 172 windows_.window1->aura_window()->AddObserver(this); | |
| 173 windows_.window2->aura_window()->AddObserver(this); | |
| 174 show_location_in_parent_ = | |
| 175 window->ConvertPointToTarget(window->GetParent(), point_in_window); | |
| 176 show_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kShowDelayMS), | |
| 177 this, | |
| 178 &MultiWindowResizeController::ShowIfValidMouseLocation); | |
| 179 } | |
| 180 | |
| 181 void MultiWindowResizeController::Hide() { | |
| 182 if (window_resizer_) | |
| 183 return; // Ignore hides while actively resizing. | |
| 184 | |
| 185 if (windows_.window1) { | |
| 186 windows_.window1->aura_window()->RemoveObserver(this); | |
| 187 windows_.window1 = NULL; | |
| 188 } | |
| 189 if (windows_.window2) { | |
| 190 windows_.window2->aura_window()->RemoveObserver(this); | |
| 191 windows_.window2 = NULL; | |
| 192 } | |
| 193 | |
| 194 show_timer_.Stop(); | |
| 195 | |
| 196 if (!resize_widget_) | |
| 197 return; | |
| 198 | |
| 199 for (size_t i = 0; i < windows_.other_windows.size(); ++i) | |
| 200 windows_.other_windows[i]->aura_window()->RemoveObserver(this); | |
| 201 mouse_watcher_.reset(); | |
| 202 resize_widget_.reset(); | |
| 203 windows_ = ResizeWindows(); | |
| 204 } | |
| 205 | |
| 206 void MultiWindowResizeController::MouseMovedOutOfHost() { | |
| 207 Hide(); | |
| 208 } | |
| 209 | |
| 210 void MultiWindowResizeController::OnWindowDestroying(aura::Window* window) { | |
| 211 // Have to explicitly reset the WindowResizer, otherwise Hide() does nothing. | |
| 212 window_resizer_.reset(); | |
| 213 Hide(); | |
| 214 } | |
| 215 | |
| 216 MultiWindowResizeController::ResizeWindows | |
| 217 MultiWindowResizeController::DetermineWindowsFromScreenPoint( | |
| 218 WmWindow* window) const { | |
| 219 gfx::Point mouse_location( | |
| 220 display::Screen::GetScreen()->GetCursorScreenPoint()); | |
| 221 mouse_location = window->ConvertPointFromScreen(mouse_location); | |
| 222 const int component = window->GetNonClientComponent(mouse_location); | |
| 223 return DetermineWindows(window, component, mouse_location); | |
| 224 } | |
| 225 | |
| 226 void MultiWindowResizeController::CreateMouseWatcher() { | |
| 227 mouse_watcher_.reset( | |
| 228 new views::MouseWatcher(new ResizeMouseWatcherHost(this), this)); | |
| 229 mouse_watcher_->set_notify_on_exit_time( | |
| 230 base::TimeDelta::FromMilliseconds(kHideDelayMS)); | |
| 231 mouse_watcher_->Start(); | |
| 232 } | |
| 233 | |
| 234 MultiWindowResizeController::ResizeWindows | |
| 235 MultiWindowResizeController::DetermineWindows(WmWindow* window, | |
| 236 int window_component, | |
| 237 const gfx::Point& point) const { | |
| 238 ResizeWindows result; | |
| 239 gfx::Point point_in_parent = | |
| 240 window->ConvertPointToTarget(window->GetParent(), point); | |
| 241 switch (window_component) { | |
| 242 case HTRIGHT: | |
| 243 result.direction = LEFT_RIGHT; | |
| 244 result.window1 = window; | |
| 245 result.window2 = FindWindowByEdge( | |
| 246 window, HTLEFT, window->GetBounds().right(), point_in_parent.y()); | |
| 247 break; | |
| 248 case HTLEFT: | |
| 249 result.direction = LEFT_RIGHT; | |
| 250 result.window1 = FindWindowByEdge( | |
| 251 window, HTRIGHT, window->GetBounds().x(), point_in_parent.y()); | |
| 252 result.window2 = window; | |
| 253 break; | |
| 254 case HTTOP: | |
| 255 result.direction = TOP_BOTTOM; | |
| 256 result.window1 = FindWindowByEdge(window, HTBOTTOM, point_in_parent.x(), | |
| 257 window->GetBounds().y()); | |
| 258 result.window2 = window; | |
| 259 break; | |
| 260 case HTBOTTOM: | |
| 261 result.direction = TOP_BOTTOM; | |
| 262 result.window1 = window; | |
| 263 result.window2 = FindWindowByEdge(window, HTTOP, point_in_parent.x(), | |
| 264 window->GetBounds().bottom()); | |
| 265 break; | |
| 266 default: | |
| 267 break; | |
| 268 } | |
| 269 return result; | |
| 270 } | |
| 271 | |
| 272 WmWindow* MultiWindowResizeController::FindWindowByEdge( | |
| 273 WmWindow* window_to_ignore, | |
| 274 int edge_want, | |
| 275 int x_in_parent, | |
| 276 int y_in_parent) const { | |
| 277 WmWindow* parent = window_to_ignore->GetParent(); | |
| 278 std::vector<WmWindow*> windows = parent->GetChildren(); | |
| 279 for (auto i = windows.rbegin(); i != windows.rend(); ++i) { | |
| 280 WmWindow* window = *i; | |
| 281 if (window == window_to_ignore || !window->IsVisible()) | |
| 282 continue; | |
| 283 | |
| 284 // Ignore windows without a non-client area. | |
| 285 if (!window->HasNonClientArea()) | |
| 286 continue; | |
| 287 | |
| 288 gfx::Point p = parent->ConvertPointToTarget( | |
| 289 window, gfx::Point(x_in_parent, y_in_parent)); | |
| 290 switch (edge_want) { | |
| 291 case HTLEFT: | |
| 292 if (ContainsY(window, p.y()) && p.x() == 0) | |
| 293 return window; | |
| 294 break; | |
| 295 case HTRIGHT: | |
| 296 if (ContainsY(window, p.y()) && p.x() == window->GetBounds().width()) | |
| 297 return window; | |
| 298 break; | |
| 299 case HTTOP: | |
| 300 if (ContainsX(window, p.x()) && p.y() == 0) | |
| 301 return window; | |
| 302 break; | |
| 303 case HTBOTTOM: | |
| 304 if (ContainsX(window, p.x()) && p.y() == window->GetBounds().height()) | |
| 305 return window; | |
| 306 break; | |
| 307 default: | |
| 308 NOTREACHED(); | |
| 309 } | |
| 310 // Window doesn't contain the edge, but if window contains |point| | |
| 311 // it's obscuring any other window that could be at the location. | |
| 312 if (window->GetBounds().Contains(x_in_parent, y_in_parent)) | |
| 313 return NULL; | |
| 314 } | |
| 315 return NULL; | |
| 316 } | |
| 317 | |
| 318 WmWindow* MultiWindowResizeController::FindWindowTouching( | |
| 319 WmWindow* window, | |
| 320 Direction direction) const { | |
| 321 int right = window->GetBounds().right(); | |
| 322 int bottom = window->GetBounds().bottom(); | |
| 323 WmWindow* parent = window->GetParent(); | |
| 324 std::vector<WmWindow*> windows = parent->GetChildren(); | |
| 325 for (auto i = windows.rbegin(); i != windows.rend(); ++i) { | |
| 326 WmWindow* other = *i; | |
| 327 if (other == window || !other->IsVisible()) | |
| 328 continue; | |
| 329 switch (direction) { | |
| 330 case TOP_BOTTOM: | |
| 331 if (other->GetBounds().y() == bottom && | |
| 332 Intersects(other->GetBounds().x(), other->GetBounds().right(), | |
| 333 window->GetBounds().x(), window->GetBounds().right())) { | |
| 334 return other; | |
| 335 } | |
| 336 break; | |
| 337 case LEFT_RIGHT: | |
| 338 if (other->GetBounds().x() == right && | |
| 339 Intersects(other->GetBounds().y(), other->GetBounds().bottom(), | |
| 340 window->GetBounds().y(), window->GetBounds().bottom())) { | |
| 341 return other; | |
| 342 } | |
| 343 break; | |
| 344 default: | |
| 345 NOTREACHED(); | |
| 346 } | |
| 347 } | |
| 348 return NULL; | |
| 349 } | |
| 350 | |
| 351 void MultiWindowResizeController::FindWindowsTouching( | |
| 352 WmWindow* start, | |
| 353 Direction direction, | |
| 354 std::vector<WmWindow*>* others) const { | |
| 355 while (start) { | |
| 356 start = FindWindowTouching(start, direction); | |
| 357 if (start) | |
| 358 others->push_back(start); | |
| 359 } | |
| 360 } | |
| 361 | |
| 362 void MultiWindowResizeController::ShowIfValidMouseLocation() { | |
| 363 if (DetermineWindowsFromScreenPoint(windows_.window1).Equals(windows_) || | |
| 364 DetermineWindowsFromScreenPoint(windows_.window2).Equals(windows_)) { | |
| 365 ShowNow(); | |
| 366 } else { | |
| 367 Hide(); | |
| 368 } | |
| 369 } | |
| 370 | |
| 371 void MultiWindowResizeController::ShowNow() { | |
| 372 DCHECK(!resize_widget_.get()); | |
| 373 DCHECK(windows_.is_valid()); | |
| 374 show_timer_.Stop(); | |
| 375 resize_widget_.reset(new views::Widget); | |
| 376 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); | |
| 377 params.name = "MultiWindowResizeController"; | |
| 378 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; | |
| 379 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | |
| 380 windows_.window1->GetRootWindowController() | |
| 381 ->ConfigureWidgetInitParamsForContainer( | |
| 382 resize_widget_.get(), kShellWindowId_AlwaysOnTopContainer, ¶ms); | |
| 383 ResizeView* view = new ResizeView(this, windows_.direction); | |
| 384 resize_widget_->set_focus_on_creation(false); | |
| 385 resize_widget_->Init(params); | |
| 386 WmWindow::Get(resize_widget_->GetNativeWindow()) | |
| 387 ->SetVisibilityAnimationType(::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE); | |
| 388 resize_widget_->SetContentsView(view); | |
| 389 show_bounds_in_screen_ = windows_.window1->GetParent()->ConvertRectToScreen( | |
| 390 CalculateResizeWidgetBounds(show_location_in_parent_)); | |
| 391 resize_widget_->SetBounds(show_bounds_in_screen_); | |
| 392 resize_widget_->Show(); | |
| 393 CreateMouseWatcher(); | |
| 394 } | |
| 395 | |
| 396 bool MultiWindowResizeController::IsShowing() const { | |
| 397 return resize_widget_.get() || show_timer_.IsRunning(); | |
| 398 } | |
| 399 | |
| 400 void MultiWindowResizeController::StartResize( | |
| 401 const gfx::Point& location_in_screen) { | |
| 402 DCHECK(!window_resizer_.get()); | |
| 403 DCHECK(windows_.is_valid()); | |
| 404 gfx::Point location_in_parent = | |
| 405 windows_.window2->GetParent()->ConvertPointFromScreen(location_in_screen); | |
| 406 std::vector<WmWindow*> windows; | |
| 407 windows.push_back(windows_.window2); | |
| 408 DCHECK(windows_.other_windows.empty()); | |
| 409 FindWindowsTouching(windows_.window2, windows_.direction, | |
| 410 &windows_.other_windows); | |
| 411 for (size_t i = 0; i < windows_.other_windows.size(); ++i) { | |
| 412 windows_.other_windows[i]->aura_window()->AddObserver(this); | |
| 413 windows.push_back(windows_.other_windows[i]); | |
| 414 } | |
| 415 int component = windows_.direction == LEFT_RIGHT ? HTRIGHT : HTBOTTOM; | |
| 416 wm::WindowState* window_state = windows_.window1->GetWindowState(); | |
| 417 window_state->CreateDragDetails(location_in_parent, component, | |
| 418 aura::client::WINDOW_MOVE_SOURCE_MOUSE); | |
| 419 window_resizer_.reset(WorkspaceWindowResizer::Create(window_state, windows)); | |
| 420 | |
| 421 // Do not hide the resize widget while a drag is active. | |
| 422 mouse_watcher_.reset(); | |
| 423 } | |
| 424 | |
| 425 void MultiWindowResizeController::Resize(const gfx::Point& location_in_screen, | |
| 426 int event_flags) { | |
| 427 gfx::Point location_in_parent = | |
| 428 windows_.window1->GetParent()->ConvertPointFromScreen(location_in_screen); | |
| 429 window_resizer_->Drag(location_in_parent, event_flags); | |
| 430 gfx::Rect bounds = windows_.window1->GetParent()->ConvertRectToScreen( | |
| 431 CalculateResizeWidgetBounds(location_in_parent)); | |
| 432 | |
| 433 if (windows_.direction == LEFT_RIGHT) | |
| 434 bounds.set_y(show_bounds_in_screen_.y()); | |
| 435 else | |
| 436 bounds.set_x(show_bounds_in_screen_.x()); | |
| 437 resize_widget_->SetBounds(bounds); | |
| 438 } | |
| 439 | |
| 440 void MultiWindowResizeController::CompleteResize() { | |
| 441 window_resizer_->CompleteDrag(); | |
| 442 window_resizer_->GetTarget()->GetWindowState()->DeleteDragDetails(); | |
| 443 window_resizer_.reset(); | |
| 444 | |
| 445 // Mouse may still be over resizer, if not hide. | |
| 446 gfx::Point screen_loc = display::Screen::GetScreen()->GetCursorScreenPoint(); | |
| 447 if (!resize_widget_->GetWindowBoundsInScreen().Contains(screen_loc)) { | |
| 448 Hide(); | |
| 449 } else { | |
| 450 // If the mouse is over the resizer we need to remove observers on any of | |
| 451 // the |other_windows|. If we start another resize we'll recalculate the | |
| 452 // |other_windows| and invoke AddObserver() as necessary. | |
| 453 for (size_t i = 0; i < windows_.other_windows.size(); ++i) | |
| 454 windows_.other_windows[i]->aura_window()->RemoveObserver(this); | |
| 455 windows_.other_windows.clear(); | |
| 456 | |
| 457 CreateMouseWatcher(); | |
| 458 } | |
| 459 } | |
| 460 | |
| 461 void MultiWindowResizeController::CancelResize() { | |
| 462 if (!window_resizer_) | |
| 463 return; // Happens if window was destroyed and we nuked the WindowResizer. | |
| 464 window_resizer_->RevertDrag(); | |
| 465 window_resizer_->GetTarget()->GetWindowState()->DeleteDragDetails(); | |
| 466 window_resizer_.reset(); | |
| 467 Hide(); | |
| 468 } | |
| 469 | |
| 470 gfx::Rect MultiWindowResizeController::CalculateResizeWidgetBounds( | |
| 471 const gfx::Point& location_in_parent) const { | |
| 472 gfx::Size pref = resize_widget_->GetContentsView()->GetPreferredSize(); | |
| 473 int x = 0, y = 0; | |
| 474 if (windows_.direction == LEFT_RIGHT) { | |
| 475 x = windows_.window1->GetBounds().right() - pref.width() / 2; | |
| 476 y = location_in_parent.y() + kResizeWidgetPadding; | |
| 477 if (y + pref.height() / 2 > windows_.window1->GetBounds().bottom() && | |
| 478 y + pref.height() / 2 > windows_.window2->GetBounds().bottom()) { | |
| 479 y = location_in_parent.y() - kResizeWidgetPadding - pref.height(); | |
| 480 } | |
| 481 } else { | |
| 482 x = location_in_parent.x() + kResizeWidgetPadding; | |
| 483 if (x + pref.height() / 2 > windows_.window1->GetBounds().right() && | |
| 484 x + pref.height() / 2 > windows_.window2->GetBounds().right()) { | |
| 485 x = location_in_parent.x() - kResizeWidgetPadding - pref.width(); | |
| 486 } | |
| 487 y = windows_.window1->GetBounds().bottom() - pref.height() / 2; | |
| 488 } | |
| 489 return gfx::Rect(x, y, pref.width(), pref.height()); | |
| 490 } | |
| 491 | |
| 492 bool MultiWindowResizeController::IsOverResizeWidget( | |
| 493 const gfx::Point& location_in_screen) const { | |
| 494 return resize_widget_->GetWindowBoundsInScreen().Contains(location_in_screen); | |
| 495 } | |
| 496 | |
| 497 bool MultiWindowResizeController::IsOverWindows( | |
| 498 const gfx::Point& location_in_screen) const { | |
| 499 if (IsOverResizeWidget(location_in_screen)) | |
| 500 return true; | |
| 501 | |
| 502 if (windows_.direction == TOP_BOTTOM) { | |
| 503 if (!ContainsScreenX(windows_.window1, location_in_screen.x()) || | |
| 504 !ContainsScreenX(windows_.window2, location_in_screen.x())) { | |
| 505 return false; | |
| 506 } | |
| 507 } else { | |
| 508 if (!ContainsScreenY(windows_.window1, location_in_screen.y()) || | |
| 509 !ContainsScreenY(windows_.window2, location_in_screen.y())) { | |
| 510 return false; | |
| 511 } | |
| 512 } | |
| 513 | |
| 514 // Check whether |location_in_screen| is in the event target's resize region. | |
| 515 // This is tricky because a window's resize region can extend outside a | |
| 516 // window's bounds. | |
| 517 WmWindow* target = | |
| 518 windows_.window1->GetRootWindowController()->FindEventTarget( | |
| 519 location_in_screen); | |
| 520 if (target == windows_.window1) { | |
| 521 return IsOverComponent( | |
| 522 windows_.window1, location_in_screen, | |
| 523 windows_.direction == TOP_BOTTOM ? HTBOTTOM : HTRIGHT); | |
| 524 } | |
| 525 if (target == windows_.window2) { | |
| 526 return IsOverComponent(windows_.window2, location_in_screen, | |
| 527 windows_.direction == TOP_BOTTOM ? HTTOP : HTLEFT); | |
| 528 } | |
| 529 return false; | |
| 530 } | |
| 531 | |
| 532 bool MultiWindowResizeController::IsOverComponent( | |
| 533 WmWindow* window, | |
| 534 const gfx::Point& location_in_screen, | |
| 535 int component) const { | |
| 536 gfx::Point window_loc = window->ConvertPointFromScreen(location_in_screen); | |
| 537 return window->GetNonClientComponent(window_loc) == component; | |
| 538 } | |
| 539 | |
| 540 } // namespace ash | |
| OLD | NEW |