OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ash/wm/window_positioner.h" | 5 #include "ash/wm/common/window_positioner.h" |
6 | 6 |
7 #include "ash/wm/common/window_positioning_utils.h" | 7 #include "ash/wm/common/window_positioning_utils.h" |
8 #include "ash/wm/common/window_state.h" | 8 #include "ash/wm/common/window_state.h" |
9 #include "ash/wm/common/wm_globals.h" | 9 #include "ash/wm/common/wm_globals.h" |
10 #include "ash/wm/common/wm_screen_util.h" | 10 #include "ash/wm/common/wm_screen_util.h" |
11 #include "ash/wm/common/wm_window.h" | 11 #include "ash/wm/common/wm_window.h" |
12 #include "ui/compositor/layer.h" | 12 #include "ui/compositor/layer.h" |
13 #include "ui/display/screen.h" | 13 #include "ui/display/screen.h" |
14 #include "ui/gfx/geometry/insets.h" | 14 #include "ui/gfx/geometry/insets.h" |
15 | 15 |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 if ((child_bounds.x() <= work_area.x() && | 101 if ((child_bounds.x() <= work_area.x() && |
102 new_child_bounds.x() <= work_area.x()) || | 102 new_child_bounds.x() <= work_area.x()) || |
103 (child_bounds.right() >= work_area.right() && | 103 (child_bounds.right() >= work_area.right() && |
104 new_child_bounds.right() >= work_area.right())) { | 104 new_child_bounds.right() >= work_area.right())) { |
105 continue; | 105 continue; |
106 } | 106 } |
107 if (new_child_bounds.right() > work_area.right()) | 107 if (new_child_bounds.right() > work_area.right()) |
108 new_child_bounds.set_x(work_area.right() - bounds.width()); | 108 new_child_bounds.set_x(work_area.right() - bounds.width()); |
109 else if (new_child_bounds.x() < work_area.x()) | 109 else if (new_child_bounds.x() < work_area.x()) |
110 new_child_bounds.set_x(work_area.x()); | 110 new_child_bounds.set_x(work_area.x()); |
111 SetBoundsAndOffsetTransientChildren(transient_child, | 111 SetBoundsAndOffsetTransientChildren(transient_child, new_child_bounds, |
112 new_child_bounds, work_area, offset); | 112 work_area, offset); |
113 } | 113 } |
114 | 114 |
115 window->SetBoundsWithTransitionDelay( | 115 window->SetBoundsWithTransitionDelay( |
116 bounds, base::TimeDelta::FromMilliseconds(kWindowAutoMoveDurationMS)); | 116 bounds, base::TimeDelta::FromMilliseconds(kWindowAutoMoveDurationMS)); |
117 } | 117 } |
118 | 118 |
119 // Move a |window| to new |bounds|. Animate if desired by user. | 119 // Move a |window| to new |bounds|. Animate if desired by user. |
120 // Note: The function will do nothing if the bounds did not change. | 120 // Note: The function will do nothing if the bounds did not change. |
121 void SetBoundsAnimated(wm::WmWindow* window, | 121 void SetBoundsAnimated(wm::WmWindow* window, |
122 const gfx::Rect& bounds, | 122 const gfx::Rect& bounds, |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
247 *show_state_out = ui::SHOW_STATE_MAXIMIZED; | 247 *show_state_out = ui::SHOW_STATE_MAXIMIZED; |
248 } | 248 } |
249 return; | 249 return; |
250 } | 250 } |
251 | 251 |
252 wm::WindowState* top_window_state = top_window->GetWindowState(); | 252 wm::WindowState* top_window_state = top_window->GetWindowState(); |
253 bool maximized = top_window_state->IsMaximized(); | 253 bool maximized = top_window_state->IsMaximized(); |
254 // We ignore the saved show state, but look instead for the top level | 254 // We ignore the saved show state, but look instead for the top level |
255 // window's show state. | 255 // window's show state. |
256 if (show_state_in == ui::SHOW_STATE_DEFAULT) { | 256 if (show_state_in == ui::SHOW_STATE_DEFAULT) { |
257 *show_state_out = maximized ? ui::SHOW_STATE_MAXIMIZED : | 257 *show_state_out = |
258 ui::SHOW_STATE_DEFAULT; | 258 maximized ? ui::SHOW_STATE_MAXIMIZED : ui::SHOW_STATE_DEFAULT; |
259 } | 259 } |
260 | 260 |
261 if (maximized || top_window_state->IsFullscreen()) { | 261 if (maximized || top_window_state->IsFullscreen()) { |
262 bool has_restore_bounds = top_window_state->HasRestoreBounds(); | 262 bool has_restore_bounds = top_window_state->HasRestoreBounds(); |
263 if (has_restore_bounds) { | 263 if (has_restore_bounds) { |
264 // For a maximized/fullscreen window ignore the real bounds of | 264 // For a maximized/fullscreen window ignore the real bounds of |
265 // the top level window and use its restore bounds | 265 // the top level window and use its restore bounds |
266 // instead. Offset the bounds to prevent the windows from | 266 // instead. Offset the bounds to prevent the windows from |
267 // overlapping exactly when restored. | 267 // overlapping exactly when restored. |
268 *bounds_in_out = top_window_state->GetRestoreBoundsInScreen() + | 268 *bounds_in_out = |
| 269 top_window_state->GetRestoreBoundsInScreen() + |
269 gfx::Vector2d(kMinimumWindowOffset, kMinimumWindowOffset); | 270 gfx::Vector2d(kMinimumWindowOffset, kMinimumWindowOffset); |
270 } | 271 } |
271 if (is_saved_bounds || has_restore_bounds) { | 272 if (is_saved_bounds || has_restore_bounds) { |
272 gfx::Rect work_area = target->GetDisplayNearestWindow().work_area(); | 273 gfx::Rect work_area = target->GetDisplayNearestWindow().work_area(); |
273 bounds_in_out->AdjustToFit(work_area); | 274 bounds_in_out->AdjustToFit(work_area); |
274 // Use adjusted saved bounds or restore bounds, if there is one. | 275 // Use adjusted saved bounds or restore bounds, if there is one. |
275 return; | 276 return; |
276 } | 277 } |
277 } | 278 } |
278 | 279 |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
375 | 376 |
376 WindowPositioner::WindowPositioner(wm::WmGlobals* globals) | 377 WindowPositioner::WindowPositioner(wm::WmGlobals* globals) |
377 : globals_(globals), | 378 : globals_(globals), |
378 pop_position_offset_increment_x(0), | 379 pop_position_offset_increment_x(0), |
379 pop_position_offset_increment_y(0), | 380 pop_position_offset_increment_y(0), |
380 popup_position_offset_from_screen_corner_x(0), | 381 popup_position_offset_from_screen_corner_x(0), |
381 popup_position_offset_from_screen_corner_y(0), | 382 popup_position_offset_from_screen_corner_y(0), |
382 last_popup_position_x_(0), | 383 last_popup_position_x_(0), |
383 last_popup_position_y_(0) {} | 384 last_popup_position_y_(0) {} |
384 | 385 |
385 WindowPositioner::~WindowPositioner() { | 386 WindowPositioner::~WindowPositioner() {} |
386 } | |
387 | 387 |
388 gfx::Rect WindowPositioner::GetDefaultWindowBounds( | 388 gfx::Rect WindowPositioner::GetDefaultWindowBounds( |
389 const display::Display& display) { | 389 const display::Display& display) { |
390 const gfx::Rect work_area = display.work_area(); | 390 const gfx::Rect work_area = display.work_area(); |
391 // There should be a 'desktop' border around the window at the left and right | 391 // There should be a 'desktop' border around the window at the left and right |
392 // side. | 392 // side. |
393 int default_width = work_area.width() - 2 * kDesktopBorderSize; | 393 int default_width = work_area.width() - 2 * kDesktopBorderSize; |
394 // There should also be a 'desktop' border around the window at the top. | 394 // There should also be a 'desktop' border around the window at the top. |
395 // Since the workspace excludes the tray area we only need one border size. | 395 // Since the workspace excludes the tray area we only need one border size. |
396 int default_height = work_area.height() - kDesktopBorderSize; | 396 int default_height = work_area.height() - kDesktopBorderSize; |
397 int offset_x = kDesktopBorderSize; | 397 int offset_x = kDesktopBorderSize; |
398 if (default_width > kMaximumWindowWidth) { | 398 if (default_width > kMaximumWindowWidth) { |
399 // The window should get centered on the screen and not follow the grid. | 399 // The window should get centered on the screen and not follow the grid. |
400 offset_x = (work_area.width() - kMaximumWindowWidth) / 2; | 400 offset_x = (work_area.width() - kMaximumWindowWidth) / 2; |
401 default_width = kMaximumWindowWidth; | 401 default_width = kMaximumWindowWidth; |
402 } | 402 } |
403 return gfx::Rect(work_area.x() + offset_x, | 403 return gfx::Rect(work_area.x() + offset_x, work_area.y() + kDesktopBorderSize, |
404 work_area.y() + kDesktopBorderSize, | 404 default_width, default_height); |
405 default_width, | |
406 default_height); | |
407 } | 405 } |
408 | 406 |
409 gfx::Rect WindowPositioner::GetPopupPosition(const gfx::Rect& old_pos) { | 407 gfx::Rect WindowPositioner::GetPopupPosition(const gfx::Rect& old_pos) { |
410 int grid = kMinimumWindowOffset; | 408 int grid = kMinimumWindowOffset; |
411 popup_position_offset_from_screen_corner_x = grid; | 409 popup_position_offset_from_screen_corner_x = grid; |
412 popup_position_offset_from_screen_corner_y = grid; | 410 popup_position_offset_from_screen_corner_y = grid; |
413 if (!pop_position_offset_increment_x) { | 411 if (!pop_position_offset_increment_x) { |
414 // When the popup position increment is 0, the last popup position | 412 // When the popup position increment is 0, the last popup position |
415 // was not yet initialized. | 413 // was not yet initialized. |
416 last_popup_position_x_ = popup_position_offset_from_screen_corner_x; | 414 last_popup_position_x_ = popup_position_offset_from_screen_corner_x; |
417 last_popup_position_y_ = popup_position_offset_from_screen_corner_y; | 415 last_popup_position_y_ = popup_position_offset_from_screen_corner_y; |
418 } | 416 } |
419 pop_position_offset_increment_x = grid; | 417 pop_position_offset_increment_x = grid; |
420 pop_position_offset_increment_y = grid; | 418 pop_position_offset_increment_y = grid; |
421 // We handle the Multi monitor support by retrieving the active window's | 419 // We handle the Multi monitor support by retrieving the active window's |
422 // work area. | 420 // work area. |
423 wm::WmWindow* window = globals_->GetActiveWindow(); | 421 wm::WmWindow* window = globals_->GetActiveWindow(); |
424 const gfx::Rect work_area = | 422 const gfx::Rect work_area = |
425 window && window->IsVisible() | 423 window && window->IsVisible() |
426 ? window->GetDisplayNearestWindow().work_area() | 424 ? window->GetDisplayNearestWindow().work_area() |
427 : display::Screen::GetScreen()->GetPrimaryDisplay().work_area(); | 425 : display::Screen::GetScreen()->GetPrimaryDisplay().work_area(); |
428 // Only try to reposition the popup when it is not spanning the entire | 426 // Only try to reposition the popup when it is not spanning the entire |
429 // screen. | 427 // screen. |
430 if ((old_pos.width() + popup_position_offset_from_screen_corner_x >= | 428 if ((old_pos.width() + popup_position_offset_from_screen_corner_x >= |
431 work_area.width()) || | 429 work_area.width()) || |
432 (old_pos.height() + popup_position_offset_from_screen_corner_y >= | 430 (old_pos.height() + popup_position_offset_from_screen_corner_y >= |
433 work_area.height())) | 431 work_area.height())) |
434 return AlignPopupPosition(old_pos, work_area, grid); | 432 return AlignPopupPosition(old_pos, work_area, grid); |
435 const gfx::Rect result = SmartPopupPosition(old_pos, work_area, grid); | 433 const gfx::Rect result = SmartPopupPosition(old_pos, work_area, grid); |
436 if (!result.IsEmpty()) | 434 if (!result.IsEmpty()) |
437 return AlignPopupPosition(result, work_area, grid); | 435 return AlignPopupPosition(result, work_area, grid); |
438 return NormalPopupPosition(old_pos, work_area); | 436 return NormalPopupPosition(old_pos, work_area); |
439 } | 437 } |
440 | 438 |
441 // static | 439 // static |
442 void WindowPositioner::SetMaximizeFirstWindow(bool maximize) { | 440 void WindowPositioner::SetMaximizeFirstWindow(bool maximize) { |
443 maximize_first_window = maximize; | 441 maximize_first_window = maximize; |
444 } | 442 } |
445 | 443 |
446 gfx::Rect WindowPositioner::NormalPopupPosition( | 444 gfx::Rect WindowPositioner::NormalPopupPosition(const gfx::Rect& old_pos, |
447 const gfx::Rect& old_pos, | 445 const gfx::Rect& work_area) { |
448 const gfx::Rect& work_area) { | |
449 int w = old_pos.width(); | 446 int w = old_pos.width(); |
450 int h = old_pos.height(); | 447 int h = old_pos.height(); |
451 // Note: The 'last_popup_position' is checked and kept relative to the | 448 // Note: The 'last_popup_position' is checked and kept relative to the |
452 // screen size. The offsetting will be done in the last step when the | 449 // screen size. The offsetting will be done in the last step when the |
453 // target rectangle gets returned. | 450 // target rectangle gets returned. |
454 bool reset = false; | 451 bool reset = false; |
455 if (last_popup_position_y_ + h > work_area.height() || | 452 if (last_popup_position_y_ + h > work_area.height() || |
456 last_popup_position_x_ + w > work_area.width()) { | 453 last_popup_position_x_ + w > work_area.width()) { |
457 // Popup does not fit on screen. Reset to next diagonal row. | 454 // Popup does not fit on screen. Reset to next diagonal row. |
458 last_popup_position_x_ -= last_popup_position_y_ - | 455 last_popup_position_x_ -= last_popup_position_y_ - |
(...skipping 10 matching lines...) Expand all Loading... |
469 } | 466 } |
470 int x = last_popup_position_x_; | 467 int x = last_popup_position_x_; |
471 int y = last_popup_position_y_; | 468 int y = last_popup_position_y_; |
472 if (!reset) { | 469 if (!reset) { |
473 last_popup_position_x_ += pop_position_offset_increment_x; | 470 last_popup_position_x_ += pop_position_offset_increment_x; |
474 last_popup_position_y_ += pop_position_offset_increment_y; | 471 last_popup_position_y_ += pop_position_offset_increment_y; |
475 } | 472 } |
476 return gfx::Rect(x + work_area.x(), y + work_area.y(), w, h); | 473 return gfx::Rect(x + work_area.x(), y + work_area.y(), w, h); |
477 } | 474 } |
478 | 475 |
479 gfx::Rect WindowPositioner::SmartPopupPosition( | 476 gfx::Rect WindowPositioner::SmartPopupPosition(const gfx::Rect& old_pos, |
480 const gfx::Rect& old_pos, | 477 const gfx::Rect& work_area, |
481 const gfx::Rect& work_area, | 478 int grid) { |
482 int grid) { | |
483 const std::vector<wm::WmWindow*> windows = | 479 const std::vector<wm::WmWindow*> windows = |
484 globals_->GetMruWindowListIgnoreModals(); | 480 globals_->GetMruWindowListIgnoreModals(); |
485 | 481 |
486 std::vector<const gfx::Rect*> regions; | 482 std::vector<const gfx::Rect*> regions; |
487 // Process the window list and check if we can bail immediately. | 483 // Process the window list and check if we can bail immediately. |
488 for (size_t i = 0; i < windows.size(); i++) { | 484 for (size_t i = 0; i < windows.size(); i++) { |
489 // We only include opaque and visible windows. | 485 // We only include opaque and visible windows. |
490 if (windows[i] && windows[i]->IsVisible() && windows[i]->GetLayer() && | 486 if (windows[i] && windows[i]->IsVisible() && windows[i]->GetLayer() && |
491 (windows[i]->GetLayer()->fills_bounds_opaquely() || | 487 (windows[i]->GetLayer()->fills_bounds_opaquely() || |
492 windows[i]->GetLayer()->GetTargetOpacity() == 1.0)) { | 488 windows[i]->GetLayer()->GetTargetOpacity() == 1.0)) { |
(...skipping 16 matching lines...) Expand all Loading... |
509 // We parse for a proper location on the screen. We do this in two runs: | 505 // We parse for a proper location on the screen. We do this in two runs: |
510 // The first run will start from the left, parsing down, skipping any | 506 // The first run will start from the left, parsing down, skipping any |
511 // overlapping windows it will encounter until the popup's height can not | 507 // overlapping windows it will encounter until the popup's height can not |
512 // be served anymore. Then the next grid position to the right will be | 508 // be served anymore. Then the next grid position to the right will be |
513 // taken, and the same cycle starts again. This will be repeated until we | 509 // taken, and the same cycle starts again. This will be repeated until we |
514 // hit the middle of the screen (or we find a suitable location). | 510 // hit the middle of the screen (or we find a suitable location). |
515 // In the second run we parse beginning from the right corner downwards and | 511 // In the second run we parse beginning from the right corner downwards and |
516 // then to the left. | 512 // then to the left. |
517 // When no location was found, an empty rectangle will be returned. | 513 // When no location was found, an empty rectangle will be returned. |
518 for (int run = 0; run < 2; run++) { | 514 for (int run = 0; run < 2; run++) { |
519 if (run == 0) { // First run: Start left, parse right till mid screen. | 515 if (run == 0) { // First run: Start left, parse right till mid screen. |
520 x = 0; | 516 x = 0; |
521 x_increment = pop_position_offset_increment_x; | 517 x_increment = pop_position_offset_increment_x; |
522 } else { // Second run: Start right, parse left till mid screen. | 518 } else { // Second run: Start right, parse left till mid screen. |
523 x = work_area.width() - w; | 519 x = work_area.width() - w; |
524 x_increment = -pop_position_offset_increment_x; | 520 x_increment = -pop_position_offset_increment_x; |
525 } | 521 } |
526 // Note: The passing (x,y,w,h) window is always relative to the work area's | 522 // Note: The passing (x,y,w,h) window is always relative to the work area's |
527 // origin. | 523 // origin. |
528 for (; x_increment > 0 ? (x < x_end) : (x > x_end); x += x_increment) { | 524 for (; x_increment > 0 ? (x < x_end) : (x > x_end); x += x_increment) { |
529 int y = 0; | 525 int y = 0; |
530 while (y + h <= work_area.height()) { | 526 while (y + h <= work_area.height()) { |
531 size_t i; | 527 size_t i; |
532 for (i = 0; i < regions.size(); i++) { | 528 for (i = 0; i < regions.size(); i++) { |
533 if (regions[i]->Intersects(gfx::Rect(x + work_area.x(), | 529 if (regions[i]->Intersects( |
534 y + work_area.y(), w, h))) { | 530 gfx::Rect(x + work_area.x(), y + work_area.y(), w, h))) { |
535 y = regions[i]->bottom() - work_area.y(); | 531 y = regions[i]->bottom() - work_area.y(); |
536 break; | 532 break; |
537 } | 533 } |
538 } | 534 } |
539 if (i >= regions.size()) | 535 if (i >= regions.size()) |
540 return gfx::Rect(x + work_area.x(), y + work_area.y(), w, h); | 536 return gfx::Rect(x + work_area.x(), y + work_area.y(), w, h); |
541 } | 537 } |
542 } | 538 } |
543 } | 539 } |
544 return gfx::Rect(0, 0, 0, 0); | 540 return gfx::Rect(0, 0, 0, 0); |
545 } | 541 } |
546 | 542 |
547 gfx::Rect WindowPositioner::AlignPopupPosition( | 543 gfx::Rect WindowPositioner::AlignPopupPosition(const gfx::Rect& pos, |
548 const gfx::Rect& pos, | 544 const gfx::Rect& work_area, |
549 const gfx::Rect& work_area, | 545 int grid) { |
550 int grid) { | |
551 if (grid <= 1) | 546 if (grid <= 1) |
552 return pos; | 547 return pos; |
553 | 548 |
554 int x = pos.x() - (pos.x() - work_area.x()) % grid; | 549 int x = pos.x() - (pos.x() - work_area.x()) % grid; |
555 int y = pos.y() - (pos.y() - work_area.y()) % grid; | 550 int y = pos.y() - (pos.y() - work_area.y()) % grid; |
556 int w = pos.width(); | 551 int w = pos.width(); |
557 int h = pos.height(); | 552 int h = pos.height(); |
558 | 553 |
559 // If the alignment was pushing the window out of the screen, we ignore the | 554 // If the alignment was pushing the window out of the screen, we ignore the |
560 // alignment for that call. | 555 // alignment for that call. |
561 if (abs(pos.right() - work_area.right()) < grid) | 556 if (abs(pos.right() - work_area.right()) < grid) |
562 x = work_area.right() - w; | 557 x = work_area.right() - w; |
563 if (abs(pos.bottom() - work_area.bottom()) < grid) | 558 if (abs(pos.bottom() - work_area.bottom()) < grid) |
564 y = work_area.bottom() - h; | 559 y = work_area.bottom() - h; |
565 return gfx::Rect(x, y, w, h); | 560 return gfx::Rect(x, y, w, h); |
566 } | 561 } |
567 | 562 |
568 } // namespace ash | 563 } // namespace ash |
OLD | NEW |