OLD | NEW |
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/display/display_controller.h" | 12 #include "ash/display/display_controller.h" |
13 #include "ash/display/mouse_cursor_event_filter.h" | |
14 #include "ash/screen_ash.h" | 13 #include "ash/screen_ash.h" |
15 #include "ash/shell.h" | 14 #include "ash/shell.h" |
16 #include "ash/shell_window_ids.h" | 15 #include "ash/shell_window_ids.h" |
17 #include "ash/wm/coordinate_conversion.h" | 16 #include "ash/wm/coordinate_conversion.h" |
18 #include "ash/wm/cursor_manager.h" | 17 #include "ash/wm/cursor_manager.h" |
19 #include "ash/wm/default_window_resizer.h" | 18 #include "ash/wm/default_window_resizer.h" |
20 #include "ash/wm/drag_window_controller.h" | 19 #include "ash/wm/drag_window_resizer.h" |
21 #include "ash/wm/property_util.h" | 20 #include "ash/wm/property_util.h" |
22 #include "ash/wm/window_util.h" | 21 #include "ash/wm/window_util.h" |
23 #include "ash/wm/workspace/phantom_window_controller.h" | 22 #include "ash/wm/workspace/phantom_window_controller.h" |
24 #include "ash/wm/workspace/snap_sizer.h" | 23 #include "ash/wm/workspace/snap_sizer.h" |
25 #include "ui/aura/client/aura_constants.h" | 24 #include "ui/aura/client/aura_constants.h" |
26 #include "ui/aura/root_window.h" | 25 #include "ui/aura/root_window.h" |
27 #include "ui/aura/window.h" | 26 #include "ui/aura/window.h" |
28 #include "ui/aura/window_delegate.h" | 27 #include "ui/aura/window_delegate.h" |
29 #include "ui/base/hit_test.h" | 28 #include "ui/base/hit_test.h" |
30 #include "ui/compositor/layer.h" | 29 #include "ui/compositor/layer.h" |
31 #include "ui/gfx/screen.h" | 30 #include "ui/gfx/screen.h" |
32 #include "ui/gfx/transform.h" | 31 #include "ui/gfx/transform.h" |
33 | 32 |
34 namespace ash { | 33 namespace ash { |
35 | 34 |
36 scoped_ptr<WindowResizer> CreateWindowResizer(aura::Window* window, | 35 scoped_ptr<WindowResizer> CreateWindowResizer(aura::Window* window, |
37 const gfx::Point& point_in_parent, | 36 const gfx::Point& point_in_parent, |
38 int window_component) { | 37 int window_component) { |
39 DCHECK(window); | 38 DCHECK(window); |
40 // No need to return a resizer when the window cannot get resized. | 39 // No need to return a resizer when the window cannot get resized. |
41 if (!wm::CanResizeWindow(window) && window_component != HTCAPTION) | 40 if (!wm::CanResizeWindow(window) && window_component != HTCAPTION) |
42 return scoped_ptr<WindowResizer>(); | 41 return scoped_ptr<WindowResizer>(); |
43 | 42 |
| 43 WindowResizer::Details details(window, point_in_parent, window_component); |
| 44 if (!details.is_resizable) |
| 45 return scoped_ptr<WindowResizer>(); |
| 46 |
| 47 WindowResizer* window_resizer = NULL; |
44 if (window->parent() && | 48 if (window->parent() && |
45 window->parent()->id() == internal::kShellWindowId_WorkspaceContainer) { | 49 window->parent()->id() == internal::kShellWindowId_WorkspaceContainer) { |
46 // Allow dragging maximized windows if it's not tracked by workspace. This | 50 // Allow dragging maximized windows if it's not tracked by workspace. This |
47 // is set by tab dragging code. | 51 // is set by tab dragging code. |
48 if (!wm::IsWindowNormal(window) && | 52 if (!wm::IsWindowNormal(window) && |
49 (window_component != HTCAPTION || GetTrackedByWorkspace(window))) | 53 (window_component != HTCAPTION || GetTrackedByWorkspace(window))) |
50 return scoped_ptr<WindowResizer>(); | 54 return scoped_ptr<WindowResizer>(); |
51 return make_scoped_ptr<WindowResizer>( | 55 window_resizer = new internal::WorkspaceWindowResizer( |
52 internal::WorkspaceWindowResizer::Create(window, | 56 details, std::vector<aura::Window*>()); |
53 point_in_parent, | |
54 window_component, | |
55 std::vector<aura::Window*>())); | |
56 } else if (wm::IsWindowNormal(window)) { | 57 } else if (wm::IsWindowNormal(window)) { |
57 return make_scoped_ptr<WindowResizer>(DefaultWindowResizer::Create( | 58 window_resizer = new DefaultWindowResizer(details); |
58 window, | |
59 point_in_parent, | |
60 window_component)); | |
61 } else { | |
62 return scoped_ptr<WindowResizer>(); | |
63 } | 59 } |
| 60 if (window_resizer) |
| 61 window_resizer = new internal::DragWindowResizer(window_resizer, details); |
| 62 return make_scoped_ptr<WindowResizer>(window_resizer); |
64 } | 63 } |
65 | 64 |
66 namespace internal { | 65 namespace internal { |
67 | 66 |
68 namespace { | 67 namespace { |
69 | 68 |
70 // Duration of the animation when snapping the window into place. | 69 // Duration of the animation when snapping the window into place. |
71 const int kSnapDurationMS = 100; | 70 const int kSnapDurationMS = 100; |
72 | 71 |
73 // The maximum opacity of the drag phantom window. | |
74 const float kMaxOpacity = 0.8f; | |
75 | |
76 // Returns true if should snap to the edge. | 72 // Returns true if should snap to the edge. |
77 bool ShouldSnapToEdge(int distance_from_edge, int grid_size) { | 73 bool ShouldSnapToEdge(int distance_from_edge, int grid_size) { |
78 return distance_from_edge < grid_size && | 74 return distance_from_edge < grid_size && |
79 distance_from_edge > -grid_size * 2; | 75 distance_from_edge > -grid_size * 2; |
80 } | 76 } |
81 | 77 |
82 // Returns true if Ash has more than one root window. | |
83 bool HasSecondaryRootWindow() { | |
84 return Shell::GetAllRootWindows().size() > 1; | |
85 } | |
86 | |
87 // When there are two root windows, returns one of the root windows which is not | |
88 // |root_window|. Returns NULL if only one root window exists. | |
89 aura::RootWindow* GetAnotherRootWindow(aura::RootWindow* root_window) { | |
90 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); | |
91 if (root_windows.size() < 2) | |
92 return NULL; | |
93 DCHECK_EQ(2U, root_windows.size()); | |
94 if (root_windows[0] == root_window) | |
95 return root_windows[1]; | |
96 return root_windows[0]; | |
97 } | |
98 | |
99 // Returns the coordinate along the secondary axis to snap to. | 78 // Returns the coordinate along the secondary axis to snap to. |
100 int CoordinateAlongSecondaryAxis(SecondaryMagnetismEdge edge, | 79 int CoordinateAlongSecondaryAxis(SecondaryMagnetismEdge edge, |
101 int leading, | 80 int leading, |
102 int trailing, | 81 int trailing, |
103 int none) { | 82 int none) { |
104 switch (edge) { | 83 switch (edge) { |
105 case SECONDARY_MAGNETISM_EDGE_LEADING: | 84 case SECONDARY_MAGNETISM_EDGE_LEADING: |
106 return leading; | 85 return leading; |
107 case SECONDARY_MAGNETISM_EDGE_TRAILING: | 86 case SECONDARY_MAGNETISM_EDGE_TRAILING: |
108 return trailing; | 87 return trailing; |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 } | 279 } |
301 | 280 |
302 private: | 281 private: |
303 int size_; | 282 int size_; |
304 int min_; | 283 int min_; |
305 int max_; | 284 int max_; |
306 }; | 285 }; |
307 | 286 |
308 WorkspaceWindowResizer::~WorkspaceWindowResizer() { | 287 WorkspaceWindowResizer::~WorkspaceWindowResizer() { |
309 Shell* shell = Shell::GetInstance(); | 288 Shell* shell = Shell::GetInstance(); |
310 shell->mouse_cursor_filter()->set_mouse_warp_mode( | |
311 MouseCursorEventFilter::WARP_ALWAYS); | |
312 shell->mouse_cursor_filter()->HideSharedEdgeIndicator(); | |
313 shell->cursor_manager()->UnlockCursor(); | 289 shell->cursor_manager()->UnlockCursor(); |
314 | |
315 if (destroyed_) | |
316 *destroyed_ = true; | |
317 } | 290 } |
318 | 291 |
319 // static | 292 // static |
320 WorkspaceWindowResizer* WorkspaceWindowResizer::Create( | 293 WorkspaceWindowResizer* WorkspaceWindowResizer::Create( |
321 aura::Window* window, | 294 aura::Window* window, |
322 const gfx::Point& location_in_parent, | 295 const gfx::Point& location_in_parent, |
323 int window_component, | 296 int window_component, |
324 const std::vector<aura::Window*>& attached_windows) { | 297 const std::vector<aura::Window*>& attached_windows) { |
325 Details details(window, location_in_parent, window_component); | 298 Details details(window, location_in_parent, window_component); |
326 return details.is_resizable ? | 299 return details.is_resizable ? |
(...skipping 28 matching lines...) Expand all Loading... |
355 // Hide a phantom window for snapping if the cursor is in another root window. | 328 // Hide a phantom window for snapping if the cursor is in another root window. |
356 if (in_original_root && wm::CanResizeWindow(window())) { | 329 if (in_original_root && wm::CanResizeWindow(window())) { |
357 UpdateSnapPhantomWindow(location_in_parent, bounds); | 330 UpdateSnapPhantomWindow(location_in_parent, bounds); |
358 } else { | 331 } else { |
359 snap_type_ = SNAP_NONE; | 332 snap_type_ = SNAP_NONE; |
360 snap_phantom_window_controller_.reset(); | 333 snap_phantom_window_controller_.reset(); |
361 } | 334 } |
362 | 335 |
363 if (!attached_windows_.empty()) | 336 if (!attached_windows_.empty()) |
364 LayoutAttachedWindows(&bounds); | 337 LayoutAttachedWindows(&bounds); |
365 if (bounds != window()->bounds()) { | 338 if (bounds != window()->bounds()) |
366 bool destroyed = false; | |
367 destroyed_ = &destroyed; | |
368 window()->SetBounds(bounds); | 339 window()->SetBounds(bounds); |
369 if (destroyed) | |
370 return; | |
371 destroyed_ = NULL; | |
372 } | |
373 // Show a phantom window for dragging in another root window. | |
374 if (HasSecondaryRootWindow()) | |
375 UpdateDragWindow(bounds, in_original_root); | |
376 else | |
377 drag_window_controller_.reset(); | |
378 | |
379 } | 340 } |
380 | 341 |
381 void WorkspaceWindowResizer::CompleteDrag(int event_flags) { | 342 void WorkspaceWindowResizer::CompleteDrag(int event_flags) { |
382 wm::SetUserHasChangedWindowPositionOrSize(details_.window, true); | 343 wm::SetUserHasChangedWindowPositionOrSize(details_.window, true); |
383 window()->layer()->SetOpacity(details_.initial_opacity); | |
384 drag_window_controller_.reset(); | |
385 snap_phantom_window_controller_.reset(); | 344 snap_phantom_window_controller_.reset(); |
386 if (!did_move_or_resize_ || details_.window_component != HTCAPTION) | 345 if (!did_move_or_resize_ || details_.window_component != HTCAPTION) |
387 return; | 346 return; |
388 | 347 |
389 // When the window is not in the normal show state, we do not snap thw window. | 348 // When the window is not in the normal show state, we do not snap thw window. |
390 // This happens when the user minimizes or maximizes the window by keyboard | 349 // This happens when the user minimizes or maximizes the window by keyboard |
391 // shortcut while dragging it. If the window is the result of dragging a tab | 350 // shortcut while dragging it. If the window is the result of dragging a tab |
392 // out of a maximized window, it's already in the normal show state when this | 351 // out of a maximized window, it's already in the normal show state when this |
393 // is called, so it does not matter. | 352 // is called, so it does not matter. |
394 if (wm::IsWindowNormal(window()) && | 353 if (wm::IsWindowNormal(window()) && |
395 (snap_type_ == SNAP_LEFT_EDGE || snap_type_ == SNAP_RIGHT_EDGE)) { | 354 (snap_type_ == SNAP_LEFT_EDGE || snap_type_ == SNAP_RIGHT_EDGE)) { |
396 if (!GetRestoreBoundsInScreen(window())) { | 355 if (!GetRestoreBoundsInScreen(window())) { |
397 gfx::Rect initial_bounds = ScreenAsh::ConvertRectToScreen( | 356 gfx::Rect initial_bounds = ScreenAsh::ConvertRectToScreen( |
398 window()->parent(), details_.initial_bounds_in_parent); | 357 window()->parent(), details_.initial_bounds_in_parent); |
399 SetRestoreBoundsInScreen(window(), details_.restore_bounds.IsEmpty() ? | 358 SetRestoreBoundsInScreen(window(), details_.restore_bounds.IsEmpty() ? |
400 initial_bounds : | 359 initial_bounds : |
401 details_.restore_bounds); | 360 details_.restore_bounds); |
402 } | 361 } |
403 window()->SetBounds(snap_sizer_->target_bounds()); | 362 window()->SetBounds(snap_sizer_->target_bounds()); |
404 return; | 363 return; |
405 } | 364 } |
406 gfx::Rect bounds(GetFinalBounds(window()->bounds())); | |
407 | |
408 // Check if the destination is another display. | |
409 gfx::Point last_mouse_location_in_screen = last_mouse_location_; | |
410 wm::ConvertPointToScreen(window()->parent(), &last_mouse_location_in_screen); | |
411 gfx::Screen* screen = Shell::GetScreen(); | |
412 const gfx::Display dst_display = | |
413 screen->GetDisplayNearestPoint(last_mouse_location_in_screen); | |
414 | |
415 if (dst_display.id() != | |
416 screen->GetDisplayNearestWindow(window()->GetRootWindow()).id()) { | |
417 // Don't animate when moving to another display. | |
418 const gfx::Rect dst_bounds = | |
419 ScreenAsh::ConvertRectToScreen(window()->parent(), bounds); | |
420 window()->SetBoundsInScreen(dst_bounds, dst_display); | |
421 } | |
422 } | 365 } |
423 | 366 |
424 void WorkspaceWindowResizer::RevertDrag() { | 367 void WorkspaceWindowResizer::RevertDrag() { |
425 window()->layer()->SetOpacity(details_.initial_opacity); | |
426 drag_window_controller_.reset(); | |
427 snap_phantom_window_controller_.reset(); | 368 snap_phantom_window_controller_.reset(); |
428 Shell::GetInstance()->mouse_cursor_filter()->HideSharedEdgeIndicator(); | |
429 | 369 |
430 if (!did_move_or_resize_) | 370 if (!did_move_or_resize_) |
431 return; | 371 return; |
432 | 372 |
433 window()->SetBounds(details_.initial_bounds_in_parent); | 373 window()->SetBounds(details_.initial_bounds_in_parent); |
434 if (!details_.restore_bounds.IsEmpty()) | 374 if (!details_.restore_bounds.IsEmpty()) |
435 SetRestoreBoundsInScreen(details_.window, details_.restore_bounds); | 375 SetRestoreBoundsInScreen(details_.window, details_.restore_bounds); |
436 | 376 |
437 if (details_.window_component == HTRIGHT) { | 377 if (details_.window_component == HTRIGHT) { |
438 int last_x = details_.initial_bounds_in_parent.right(); | 378 int last_x = details_.initial_bounds_in_parent.right(); |
(...skipping 23 matching lines...) Expand all Loading... |
462 WorkspaceWindowResizer::WorkspaceWindowResizer( | 402 WorkspaceWindowResizer::WorkspaceWindowResizer( |
463 const Details& details, | 403 const Details& details, |
464 const std::vector<aura::Window*>& attached_windows) | 404 const std::vector<aura::Window*>& attached_windows) |
465 : details_(details), | 405 : details_(details), |
466 attached_windows_(attached_windows), | 406 attached_windows_(attached_windows), |
467 did_move_or_resize_(false), | 407 did_move_or_resize_(false), |
468 total_min_(0), | 408 total_min_(0), |
469 total_initial_size_(0), | 409 total_initial_size_(0), |
470 snap_type_(SNAP_NONE), | 410 snap_type_(SNAP_NONE), |
471 num_mouse_moves_since_bounds_change_(0), | 411 num_mouse_moves_since_bounds_change_(0), |
472 destroyed_(NULL), | |
473 magnetism_window_(NULL) { | 412 magnetism_window_(NULL) { |
474 DCHECK(details_.is_resizable); | 413 DCHECK(details_.is_resizable); |
475 | 414 |
476 Shell* shell = Shell::GetInstance(); | 415 Shell* shell = Shell::GetInstance(); |
477 shell->cursor_manager()->LockCursor(); | 416 shell->cursor_manager()->LockCursor(); |
478 | 417 |
479 // The pointer should be confined in one display during resizing a window | |
480 // because the window cannot span two displays at the same time anyway. The | |
481 // exception is window/tab dragging operation. During that operation, | |
482 // |mouse_warp_mode_| should be set to WARP_DRAG so that the user could move a | |
483 // window/tab to another display. | |
484 MouseCursorEventFilter* mouse_cursor_filter = shell->mouse_cursor_filter(); | |
485 mouse_cursor_filter->set_mouse_warp_mode( | |
486 ShouldAllowMouseWarp() ? | |
487 MouseCursorEventFilter::WARP_DRAG : MouseCursorEventFilter::WARP_NONE); | |
488 if (ShouldAllowMouseWarp()) { | |
489 mouse_cursor_filter->ShowSharedEdgeIndicator( | |
490 details.window->GetRootWindow()); | |
491 } | |
492 | |
493 // Only support attaching to the right/bottom. | 418 // Only support attaching to the right/bottom. |
494 DCHECK(attached_windows_.empty() || | 419 DCHECK(attached_windows_.empty() || |
495 (details.window_component == HTRIGHT || | 420 (details.window_component == HTRIGHT || |
496 details.window_component == HTBOTTOM)); | 421 details.window_component == HTBOTTOM)); |
497 | 422 |
498 // TODO: figure out how to deal with window going off the edge. | 423 // TODO: figure out how to deal with window going off the edge. |
499 | 424 |
500 // Calculate sizes so that we can maintain the ratios if we need to resize. | 425 // Calculate sizes so that we can maintain the ratios if we need to resize. |
501 int total_available = 0; | 426 int total_available = 0; |
502 for (size_t i = 0; i < attached_windows_.size(); ++i) { | 427 for (size_t i = 0; i < attached_windows_.size(); ++i) { |
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
811 case HTRIGHT: | 736 case HTRIGHT: |
812 return x; | 737 return x; |
813 case HTBOTTOM: | 738 case HTBOTTOM: |
814 return y; | 739 return y; |
815 default: | 740 default: |
816 NOTREACHED(); | 741 NOTREACHED(); |
817 } | 742 } |
818 return 0; | 743 return 0; |
819 } | 744 } |
820 | 745 |
821 void WorkspaceWindowResizer::UpdateDragWindow(const gfx::Rect& bounds, | |
822 bool in_original_root) { | |
823 if (!did_move_or_resize_ || details_.window_component != HTCAPTION || | |
824 !ShouldAllowMouseWarp()) { | |
825 return; | |
826 } | |
827 | |
828 // It's available. Show a phantom window on the display if needed. | |
829 aura::RootWindow* another_root = | |
830 GetAnotherRootWindow(window()->GetRootWindow()); | |
831 const gfx::Rect root_bounds_in_screen(another_root->GetBoundsInScreen()); | |
832 const gfx::Rect bounds_in_screen = | |
833 ScreenAsh::ConvertRectToScreen(window()->parent(), bounds); | |
834 gfx::Rect bounds_in_another_root = | |
835 gfx::IntersectRects(root_bounds_in_screen, bounds_in_screen); | |
836 | |
837 const float fraction_in_another_window = | |
838 (bounds_in_another_root.width() * bounds_in_another_root.height()) / | |
839 static_cast<float>(bounds.width() * bounds.height()); | |
840 const float phantom_opacity = | |
841 !in_original_root ? 1 : (kMaxOpacity * fraction_in_another_window); | |
842 const float window_opacity = | |
843 in_original_root ? 1 : (kMaxOpacity * (1 - fraction_in_another_window)); | |
844 | |
845 if (fraction_in_another_window > 0) { | |
846 if (!drag_window_controller_.get()) { | |
847 drag_window_controller_.reset( | |
848 new DragWindowController(window())); | |
849 // Always show the drag phantom on the |another_root| window. | |
850 drag_window_controller_->SetDestinationDisplay( | |
851 Shell::GetScreen()->GetDisplayMatching( | |
852 another_root->GetBoundsInScreen())); | |
853 drag_window_controller_->Show(); | |
854 } else { | |
855 // No animation. | |
856 drag_window_controller_->SetBounds(bounds_in_screen); | |
857 } | |
858 drag_window_controller_->SetOpacity(phantom_opacity); | |
859 window()->layer()->SetOpacity(window_opacity); | |
860 } else { | |
861 drag_window_controller_.reset(); | |
862 window()->layer()->SetOpacity(1.0f); | |
863 } | |
864 } | |
865 | |
866 void WorkspaceWindowResizer::UpdateSnapPhantomWindow(const gfx::Point& location, | 746 void WorkspaceWindowResizer::UpdateSnapPhantomWindow(const gfx::Point& location, |
867 const gfx::Rect& bounds) { | 747 const gfx::Rect& bounds) { |
868 if (!did_move_or_resize_ || details_.window_component != HTCAPTION) | 748 if (!did_move_or_resize_ || details_.window_component != HTCAPTION) |
869 return; | 749 return; |
870 | 750 |
871 if (!wm::CanSnapWindow(window())) | 751 if (!wm::CanSnapWindow(window())) |
872 return; | 752 return; |
873 | 753 |
874 SnapType last_type = snap_type_; | 754 SnapType last_type = snap_type_; |
875 snap_type_ = GetSnapType(location); | 755 snap_type_ = GetSnapType(location); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
933 // TODO: this likely only wants total display area, not the area of a single | 813 // TODO: this likely only wants total display area, not the area of a single |
934 // display. | 814 // display. |
935 gfx::Rect area(ScreenAsh::GetDisplayBoundsInParent(window())); | 815 gfx::Rect area(ScreenAsh::GetDisplayBoundsInParent(window())); |
936 if (location.x() <= area.x()) | 816 if (location.x() <= area.x()) |
937 return SNAP_LEFT_EDGE; | 817 return SNAP_LEFT_EDGE; |
938 if (location.x() >= area.right() - 1) | 818 if (location.x() >= area.right() - 1) |
939 return SNAP_RIGHT_EDGE; | 819 return SNAP_RIGHT_EDGE; |
940 return SNAP_NONE; | 820 return SNAP_NONE; |
941 } | 821 } |
942 | 822 |
943 bool WorkspaceWindowResizer::ShouldAllowMouseWarp() const { | |
944 return (details_.window_component == HTCAPTION) && | |
945 (window()->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_NONE) && | |
946 (window()->type() == aura::client::WINDOW_TYPE_NORMAL); | |
947 } | |
948 | |
949 } // namespace internal | 823 } // namespace internal |
950 } // namespace ash | 824 } // namespace ash |
OLD | NEW |