Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Side by Side Diff: ash/wm/workspace/workspace_window_resizer.cc

Issue 23431009: Windows docking should get triggered by pressing against the screen edge (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Windows docking should get triggered by pressing against the screen edge (rebase) Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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/workspace/workspace_window_resizer.h" 5 #include "ash/wm/workspace/workspace_window_resizer.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cmath> 8 #include <cmath>
9 #include <utility> 9 #include <utility>
10 #include <vector> 10 #include <vector>
11 11
12 #include "ash/ash_switches.h" 12 #include "ash/ash_switches.h"
13 #include "ash/display/display_controller.h"
13 #include "ash/root_window_controller.h" 14 #include "ash/root_window_controller.h"
14 #include "ash/screen_ash.h" 15 #include "ash/screen_ash.h"
15 #include "ash/shell.h" 16 #include "ash/shell.h"
16 #include "ash/shell_window_ids.h" 17 #include "ash/shell_window_ids.h"
17 #include "ash/wm/coordinate_conversion.h" 18 #include "ash/wm/coordinate_conversion.h"
18 #include "ash/wm/default_window_resizer.h" 19 #include "ash/wm/default_window_resizer.h"
19 #include "ash/wm/dock/docked_window_resizer.h" 20 #include "ash/wm/dock/docked_window_resizer.h"
20 #include "ash/wm/drag_window_resizer.h" 21 #include "ash/wm/drag_window_resizer.h"
21 #include "ash/wm/panels/panel_window_resizer.h" 22 #include "ash/wm/panels/panel_window_resizer.h"
22 #include "ash/wm/property_util.h" 23 #include "ash/wm/property_util.h"
23 #include "ash/wm/window_properties.h" 24 #include "ash/wm/window_properties.h"
24 #include "ash/wm/window_util.h" 25 #include "ash/wm/window_util.h"
25 #include "ash/wm/workspace/phantom_window_controller.h" 26 #include "ash/wm/workspace/phantom_window_controller.h"
26 #include "ash/wm/workspace/snap_sizer.h" 27 #include "ash/wm/workspace/snap_sizer.h"
27 #include "base/command_line.h" 28 #include "base/command_line.h"
29 #include "base/memory/weak_ptr.h"
28 #include "ui/aura/client/aura_constants.h" 30 #include "ui/aura/client/aura_constants.h"
29 #include "ui/aura/client/screen_position_client.h" 31 #include "ui/aura/client/screen_position_client.h"
30 #include "ui/aura/client/window_types.h" 32 #include "ui/aura/client/window_types.h"
31 #include "ui/aura/root_window.h" 33 #include "ui/aura/root_window.h"
32 #include "ui/aura/window.h" 34 #include "ui/aura/window.h"
33 #include "ui/aura/window_delegate.h" 35 #include "ui/aura/window_delegate.h"
34 #include "ui/base/hit_test.h" 36 #include "ui/base/hit_test.h"
35 #include "ui/compositor/layer.h" 37 #include "ui/compositor/layer.h"
36 #include "ui/gfx/screen.h" 38 #include "ui/gfx/screen.h"
37 #include "ui/gfx/transform.h" 39 #include "ui/gfx/transform.h"
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 if (!did_move_or_resize_) { 379 if (!did_move_or_resize_) {
378 if (!details_.restore_bounds.IsEmpty()) 380 if (!details_.restore_bounds.IsEmpty())
379 ClearRestoreBounds(window()); 381 ClearRestoreBounds(window());
380 RestackWindows(); 382 RestackWindows();
381 } 383 }
382 did_move_or_resize_ = true; 384 did_move_or_resize_ = true;
383 } 385 }
384 386
385 gfx::Point location_in_screen = location_in_parent; 387 gfx::Point location_in_screen = location_in_parent;
386 wm::ConvertPointToScreen(window()->parent(), &location_in_screen); 388 wm::ConvertPointToScreen(window()->parent(), &location_in_screen);
387 const bool in_original_root = 389
388 wm::GetRootWindowAt(location_in_screen) == window()->GetRootWindow(); 390 aura::RootWindow* root = NULL;
391 gfx::Display display =
392 ScreenAsh::FindDisplayContainingPoint(location_in_screen);
393 // Track the last screen that the pointer was on to keep the snap phantom
394 // window there.
395 if (display.is_valid()) {
396 root = Shell::GetInstance()->display_controller()->
397 GetRootWindowForDisplayId(display.id());
398 }
399 if (!attached_windows_.empty())
400 LayoutAttachedWindows(&bounds);
401 if (bounds != window()->bounds()) {
402 // SetBounds needs to be called to update the layout which affects where the
403 // phantom window is drawn. Keep track if the window was destroyed during
404 // the drag and quit early if so.
405 base::WeakPtr<WorkspaceWindowResizer> resizer(
406 weak_ptr_factory_.GetWeakPtr());
407 window()->SetBounds(bounds);
408 if (!resizer)
409 return;
410 }
411 const bool in_original_root = !root || root == window()->GetRootWindow();
389 // Hide a phantom window for snapping if the cursor is in another root window. 412 // Hide a phantom window for snapping if the cursor is in another root window.
390 if (in_original_root && wm::CanResizeWindow(window())) { 413 if (in_original_root) {
391 UpdateSnapPhantomWindow(location_in_parent, bounds); 414 UpdateSnapPhantomWindow(location_in_parent, bounds);
392 } else { 415 } else {
393 snap_type_ = SNAP_NONE; 416 snap_type_ = SNAP_NONE;
394 snap_phantom_window_controller_.reset(); 417 snap_phantom_window_controller_.reset();
418 snap_sizer_.reset();
395 } 419 }
396
397 if (!attached_windows_.empty())
398 LayoutAttachedWindows(&bounds);
399 if (bounds != window()->bounds())
400 window()->SetBounds(bounds);
401 } 420 }
402 421
403 void WorkspaceWindowResizer::CompleteDrag(int event_flags) { 422 void WorkspaceWindowResizer::CompleteDrag(int event_flags) {
404 wm::SetUserHasChangedWindowPositionOrSize(details_.window, true); 423 wm::SetUserHasChangedWindowPositionOrSize(details_.window, true);
405 snap_phantom_window_controller_.reset(); 424 snap_phantom_window_controller_.reset();
406 if (!did_move_or_resize_ || details_.window_component != HTCAPTION) 425 if (!did_move_or_resize_ || details_.window_component != HTCAPTION)
407 return; 426 return;
408 427
409 // When the window is not in the normal show state, we do not snap the window. 428 // When the window is not in the normal show state, we do not snap the window.
410 // This happens when the user minimizes or maximizes the window by keyboard 429 // This happens when the user minimizes or maximizes the window by keyboard
411 // shortcut while dragging it. If the window is the result of dragging a tab 430 // shortcut while dragging it. If the window is the result of dragging a tab
412 // out of a maximized window, it's already in the normal show state when this 431 // out of a maximized window, it's already in the normal show state when this
413 // is called, so it does not matter. 432 // is called, so it does not matter.
414 if (wm::IsWindowNormal(window()) && 433 if (wm::IsWindowNormal(window()) &&
415 (window()->type() != aura::client::WINDOW_TYPE_PANEL || 434 (window()->type() != aura::client::WINDOW_TYPE_PANEL ||
416 !window()->GetProperty(kPanelAttachedKey)) && 435 !window()->GetProperty(kPanelAttachedKey)) &&
417 (snap_type_ == SNAP_LEFT_EDGE || snap_type_ == SNAP_RIGHT_EDGE)) { 436 (snap_type_ == SNAP_LEFT || snap_type_ == SNAP_RIGHT)) {
418 if (!GetRestoreBoundsInScreen(window())) { 437 if (!GetRestoreBoundsInScreen(window())) {
419 gfx::Rect initial_bounds = ScreenAsh::ConvertRectToScreen( 438 gfx::Rect initial_bounds = ScreenAsh::ConvertRectToScreen(
420 window()->parent(), details_.initial_bounds_in_parent); 439 window()->parent(), details_.initial_bounds_in_parent);
421 SetRestoreBoundsInScreen(window(), details_.restore_bounds.IsEmpty() ? 440 SetRestoreBoundsInScreen(window(), details_.restore_bounds.IsEmpty() ?
422 initial_bounds : 441 initial_bounds :
423 details_.restore_bounds); 442 details_.restore_bounds);
424 } 443 }
425 window()->SetBounds(snap_sizer_->target_bounds()); 444 DCHECK(snap_sizer_);
445 if (wm::CanResizeWindow(window()) &&
446 !snap_sizer_->ShouldDockWindow() &&
447 !snap_sizer_->target_bounds().IsEmpty()) {
448 window()->SetBounds(snap_sizer_->target_bounds());
449 }
426 return; 450 return;
427 } 451 }
428 } 452 }
429 453
430 void WorkspaceWindowResizer::RevertDrag() { 454 void WorkspaceWindowResizer::RevertDrag() {
431 snap_phantom_window_controller_.reset(); 455 snap_phantom_window_controller_.reset();
432 456
433 if (!did_move_or_resize_) 457 if (!did_move_or_resize_)
434 return; 458 return;
435 459
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
469 WorkspaceWindowResizer::WorkspaceWindowResizer( 493 WorkspaceWindowResizer::WorkspaceWindowResizer(
470 const Details& details, 494 const Details& details,
471 const std::vector<aura::Window*>& attached_windows) 495 const std::vector<aura::Window*>& attached_windows)
472 : details_(details), 496 : details_(details),
473 attached_windows_(attached_windows), 497 attached_windows_(attached_windows),
474 did_move_or_resize_(false), 498 did_move_or_resize_(false),
475 total_min_(0), 499 total_min_(0),
476 total_initial_size_(0), 500 total_initial_size_(0),
477 snap_type_(SNAP_NONE), 501 snap_type_(SNAP_NONE),
478 num_mouse_moves_since_bounds_change_(0), 502 num_mouse_moves_since_bounds_change_(0),
479 magnetism_window_(NULL) { 503 magnetism_window_(NULL),
504 weak_ptr_factory_(this) {
480 DCHECK(details_.is_resizable); 505 DCHECK(details_.is_resizable);
481 506
482 Shell* shell = Shell::GetInstance(); 507 Shell* shell = Shell::GetInstance();
483 shell->cursor_manager()->LockCursor(); 508 shell->cursor_manager()->LockCursor();
484 509
485 // Only support attaching to the right/bottom. 510 // Only support attaching to the right/bottom.
486 DCHECK(attached_windows_.empty() || 511 DCHECK(attached_windows_.empty() ||
487 (details.window_component == HTRIGHT || 512 (details.window_component == HTRIGHT ||
488 details.window_component == HTBOTTOM)); 513 details.window_component == HTBOTTOM));
489 514
490 // TODO: figure out how to deal with window going off the edge. 515 // TODO: figure out how to deal with window going off the edge.
491 516
492 // Calculate sizes so that we can maintain the ratios if we need to resize. 517 // Calculate sizes so that we can maintain the ratios if we need to resize.
493 int total_available = 0; 518 int total_available = 0;
494 for (size_t i = 0; i < attached_windows_.size(); ++i) { 519 for (size_t i = 0; i < attached_windows_.size(); ++i) {
495 gfx::Size min(attached_windows_[i]->delegate()->GetMinimumSize()); 520 gfx::Size min(attached_windows_[i]->delegate()->GetMinimumSize());
496 int initial_size = PrimaryAxisSize(attached_windows_[i]->bounds().size()); 521 int initial_size = PrimaryAxisSize(attached_windows_[i]->bounds().size());
497 initial_size_.push_back(initial_size); 522 initial_size_.push_back(initial_size);
498 // If current size is smaller than the min, use the current size as the min. 523 // If current size is smaller than the min, use the current size as the min.
499 // This way we don't snap on resize. 524 // This way we don't snap on resize.
500 int min_size = std::min(initial_size, 525 int min_size = std::min(initial_size,
501 std::max(PrimaryAxisSize(min), kMinOnscreenSize)); 526 std::max(PrimaryAxisSize(min), kMinOnscreenSize));
502 total_min_ += min_size; 527 total_min_ += min_size;
503 total_initial_size_ += initial_size; 528 total_initial_size_ += initial_size;
504 total_available += std::max(min_size, initial_size) - min_size; 529 total_available += std::max(min_size, initial_size) - min_size;
505 } 530 }
531 snap_type_ = GetSnapType(details_.initial_location_in_parent);
506 } 532 }
507 533
508 gfx::Rect WorkspaceWindowResizer::GetFinalBounds( 534 gfx::Rect WorkspaceWindowResizer::GetFinalBounds(
509 const gfx::Rect& bounds) const { 535 const gfx::Rect& bounds) const {
510 if (snap_phantom_window_controller_.get() && 536 if (snap_phantom_window_controller_.get() &&
511 snap_phantom_window_controller_->IsShowing()) { 537 snap_phantom_window_controller_->IsShowing()) {
512 return snap_phantom_window_controller_->bounds_in_screen(); 538 return snap_phantom_window_controller_->bounds_in_screen();
513 } 539 }
514 return bounds; 540 return bounds;
515 } 541 }
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after
848 NOTREACHED(); 874 NOTREACHED();
849 } 875 }
850 return 0; 876 return 0;
851 } 877 }
852 878
853 void WorkspaceWindowResizer::UpdateSnapPhantomWindow(const gfx::Point& location, 879 void WorkspaceWindowResizer::UpdateSnapPhantomWindow(const gfx::Point& location,
854 const gfx::Rect& bounds) { 880 const gfx::Rect& bounds) {
855 if (!did_move_or_resize_ || details_.window_component != HTCAPTION) 881 if (!did_move_or_resize_ || details_.window_component != HTCAPTION)
856 return; 882 return;
857 883
858 if (!wm::CanSnapWindow(window()))
859 return;
860
861 if (window()->type() == aura::client::WINDOW_TYPE_PANEL &&
862 window()->GetProperty(kPanelAttachedKey)) {
863 return;
864 }
865
866 SnapType last_type = snap_type_; 884 SnapType last_type = snap_type_;
867 snap_type_ = GetSnapType(location); 885 snap_type_ = GetSnapType(location);
868 if (snap_type_ == SNAP_NONE || snap_type_ != last_type) { 886 if (snap_type_ == SNAP_NONE || snap_type_ != last_type) {
869 snap_phantom_window_controller_.reset(); 887 snap_phantom_window_controller_.reset();
888 if (snap_type_ == SNAP_NONE && snap_type_ != last_type) {
889 // Create and delete a SnapSizer to maintain docked state.
flackr 2013/09/10 17:59:44 Why do we create a SnapSizer only to delete it? Th
varkha 2013/09/10 21:49:35 This is to keep the awareness about docked state r
flackr 2013/09/11 18:08:50 Yes, I think this is clearer, thanks.
890 snap_sizer_.reset(new SnapSizer(
891 window(),
892 details_.initial_location_in_parent,
893 (last_type == SNAP_LEFT) ?
894 SnapSizer::LEFT_EDGE : SnapSizer::RIGHT_EDGE,
895 internal::SnapSizer::WORKSPACE_DRAG_INPUT));
896 }
870 snap_sizer_.reset(); 897 snap_sizer_.reset();
871 if (snap_type_ == SNAP_NONE) 898 if (snap_type_ == SNAP_NONE)
872 return; 899 return;
873 } 900 }
901 SnapSizer::Edge edge = (snap_type_ == SNAP_LEFT) ?
902 SnapSizer::LEFT_EDGE : SnapSizer::RIGHT_EDGE;
903
874 if (!snap_sizer_) { 904 if (!snap_sizer_) {
875 SnapSizer::Edge edge = (snap_type_ == SNAP_LEFT_EDGE) ?
876 SnapSizer::LEFT_EDGE : SnapSizer::RIGHT_EDGE;
877 snap_sizer_.reset(new SnapSizer(window(), 905 snap_sizer_.reset(new SnapSizer(window(),
878 location, 906 location,
879 edge, 907 edge,
880 internal::SnapSizer::OTHER_INPUT)); 908 internal::SnapSizer::WORKSPACE_DRAG_INPUT));
881 } else { 909 } else {
882 snap_sizer_->Update(location); 910 snap_sizer_->Update(location);
883 } 911 }
912
913 // Update phantom window when it is used for side-maximizing.
914 // In case of docking it will be called directly by the chained resizer.
915 if (!wm::CanSnapWindow(window()) && !SnapSizer::CanDockWindow(window(), edge))
916 return;
917
918 if (snap_sizer_->target_bounds().IsEmpty()) {
919 snap_phantom_window_controller_.reset();
920 return;
921 }
884 if (!snap_phantom_window_controller_) { 922 if (!snap_phantom_window_controller_) {
885 snap_phantom_window_controller_.reset( 923 snap_phantom_window_controller_.reset(
886 new PhantomWindowController(window())); 924 new PhantomWindowController(window()));
887 } 925 }
888 snap_phantom_window_controller_->Show(ScreenAsh::ConvertRectToScreen( 926 snap_phantom_window_controller_->Show(ScreenAsh::ConvertRectToScreen(
889 window()->parent(), snap_sizer_->target_bounds())); 927 window()->parent(), snap_sizer_->target_bounds()));
890 } 928 }
891 929
892 void WorkspaceWindowResizer::RestackWindows() { 930 void WorkspaceWindowResizer::RestackWindows() {
893 if (attached_windows_.empty()) 931 if (attached_windows_.empty())
(...skipping 19 matching lines...) Expand all
913 parent->StackChildAtTop(map.rbegin()->second); 951 parent->StackChildAtTop(map.rbegin()->second);
914 for (IndexToWindowMap::const_reverse_iterator i = map.rbegin(); 952 for (IndexToWindowMap::const_reverse_iterator i = map.rbegin();
915 i != map.rend(); ) { 953 i != map.rend(); ) {
916 aura::Window* window = i->second; 954 aura::Window* window = i->second;
917 ++i; 955 ++i;
918 if (i != map.rend()) 956 if (i != map.rend())
919 parent->StackChildBelow(i->second, window); 957 parent->StackChildBelow(i->second, window);
920 } 958 }
921 } 959 }
922 960
923 WorkspaceWindowResizer::SnapType WorkspaceWindowResizer::GetSnapType( 961 SnapType WorkspaceWindowResizer::GetSnapType(
924 const gfx::Point& location) const { 962 const gfx::Point& location) const {
925 // TODO: this likely only wants total display area, not the area of a single 963 // TODO: this likely only wants total display area, not the area of a single
926 // display. 964 // display.
927 gfx::Rect area(ScreenAsh::GetDisplayBoundsInParent(window())); 965 gfx::Rect area(ScreenAsh::GetDisplayWorkAreaBoundsInParent(window()));
928 if (location.x() <= area.x()) 966 if (location.x() <= area.x())
929 return SNAP_LEFT_EDGE; 967 return SNAP_LEFT;
930 if (location.x() >= area.right() - 1) 968 if (location.x() >= area.right() - 1)
931 return SNAP_RIGHT_EDGE; 969 return SNAP_RIGHT;
932 return SNAP_NONE; 970 return SNAP_NONE;
933 } 971 }
934 972
935 } // namespace internal 973 } // namespace internal
936 } // namespace ash 974 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698