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 "ash/shell.h" |
| 8 #include "ash/wm/root_window_event_filter.h" |
7 #include "ash/wm/window_util.h" | 9 #include "ash/wm/window_util.h" |
8 #include "ui/aura/window.h" | 10 #include "ui/aura/window.h" |
9 #include "ui/aura/window_delegate.h" | 11 #include "ui/aura/window_delegate.h" |
10 #include "ui/aura/window_property.h" | 12 #include "ui/aura/window_property.h" |
11 #include "ui/base/hit_test.h" | 13 #include "ui/base/hit_test.h" |
12 #include "ui/gfx/compositor/scoped_layer_animation_settings.h" | 14 #include "ui/gfx/compositor/scoped_layer_animation_settings.h" |
13 #include "ui/gfx/compositor/layer.h" | 15 #include "ui/gfx/compositor/layer.h" |
14 #include "ui/gfx/screen.h" | 16 #include "ui/gfx/screen.h" |
15 #include "ui/gfx/transform.h" | 17 #include "ui/gfx/transform.h" |
16 | 18 |
17 DECLARE_WINDOW_PROPERTY_TYPE(int) | 19 DECLARE_WINDOW_PROPERTY_TYPE(int) |
18 | 20 |
19 namespace ash { | 21 namespace ash { |
20 namespace internal { | 22 namespace internal { |
21 | 23 |
22 namespace { | 24 namespace { |
23 | 25 |
24 const aura::WindowProperty<int> kHeightBeforeObscuredProp = {0}; | 26 const aura::WindowProperty<int> kHeightBeforeObscuredProp = {0}; |
25 const aura::WindowProperty<int>* const kHeightBeforeObscuredKey = | 27 const aura::WindowProperty<int>* const kHeightBeforeObscuredKey = |
26 &kHeightBeforeObscuredProp; | 28 &kHeightBeforeObscuredProp; |
27 | 29 |
| 30 void SetHeightBeforeObscured(aura::Window* window, int height) { |
| 31 window->SetProperty(kHeightBeforeObscuredKey, height); |
| 32 } |
| 33 |
| 34 int GetHeightBeforeObscured(aura::Window* window) { |
| 35 return window->GetProperty(kHeightBeforeObscuredKey); |
| 36 } |
| 37 |
| 38 void ClearHeightBeforeObscured(aura::Window* window) { |
| 39 window->SetProperty(kHeightBeforeObscuredKey, 0); |
| 40 } |
| 41 |
28 } // namespace | 42 } // namespace |
29 | 43 |
30 WorkspaceWindowResizer::WorkspaceWindowResizer(aura::Window* window, | 44 WorkspaceWindowResizer::~WorkspaceWindowResizer() { |
31 const gfx::Point& location, | 45 if (root_filter_) |
32 int window_component, | 46 root_filter_->UnlockCursor(); |
33 int grid_size) | 47 } |
34 : WindowResizer(window, location, window_component, grid_size), | 48 |
35 constrain_size_(wm::IsWindowNormal(window)) { | 49 // static |
36 if (is_resizable() && GetHeightBeforeObscured(window) && | 50 WorkspaceWindowResizer* WorkspaceWindowResizer::Create( |
37 constrain_size_ && | 51 aura::Window* window, |
38 (!WindowTouchesBottomOfScreen() || | 52 const gfx::Point& location, |
39 bounds_change() != kBoundsChange_Repositions)) { | 53 int window_component, |
40 ClearHeightBeforeObscured(window); | 54 int grid_size) { |
| 55 Details details(window, location, window_component, grid_size); |
| 56 return details.is_resizable ? |
| 57 new WorkspaceWindowResizer(details) : NULL; |
| 58 } |
| 59 |
| 60 void WorkspaceWindowResizer::Drag(const gfx::Point& location) { |
| 61 gfx::Rect bounds = CalculateBoundsForDrag(details_, location); |
| 62 if (constrain_size_) |
| 63 AdjustBoundsForMainWindow(&bounds); |
| 64 if (bounds != details_.window->bounds()) { |
| 65 did_move_or_resize_ = true; |
| 66 details_.window->SetBounds(bounds); |
41 } | 67 } |
42 } | 68 } |
43 | 69 |
44 WorkspaceWindowResizer::~WorkspaceWindowResizer() { | 70 void WorkspaceWindowResizer::CompleteDrag() { |
| 71 if (details_.grid_size <= 1 || !did_move_or_resize_ || |
| 72 details_.window_component != HTCAPTION) |
| 73 return; |
| 74 |
| 75 gfx::Rect bounds(AdjustBoundsToGrid(details_)); |
| 76 if (GetHeightBeforeObscured(window()) || constrain_size_) { |
| 77 // Two things can happen: |
| 78 // . We'll snap to the grid, which may result in different bounds. When |
| 79 // dragging we only snap on release. |
| 80 // . If the bounds are different, and the windows height was truncated |
| 81 // because it touched the bottom, than snapping to the grid may cause the |
| 82 // window to no longer touch the bottom. Push it back up. |
| 83 gfx::Rect initial_bounds(window()->bounds()); |
| 84 bool at_bottom = TouchesBottomOfScreen(); |
| 85 if (at_bottom && bounds.y() != initial_bounds.y()) { |
| 86 if (bounds.y() < initial_bounds.y()) { |
| 87 bounds.set_height(bounds.height() + details_.grid_size - |
| 88 (initial_bounds.y() - bounds.y())); |
| 89 } |
| 90 AdjustBoundsForMainWindow(&bounds); |
| 91 } |
| 92 } |
| 93 |
| 94 if (bounds == details_.window->bounds()) |
| 95 return; |
| 96 |
| 97 if (bounds.size() != details_.window->bounds().size()) { |
| 98 // Don't attempt to animate a size change. |
| 99 details_.window->SetBounds(bounds); |
| 100 return; |
| 101 } |
| 102 |
| 103 ui::ScopedLayerAnimationSettings scoped_setter( |
| 104 details_.window->layer()->GetAnimator()); |
| 105 // Use a small duration since the grid is small. |
| 106 scoped_setter.SetTransitionDuration(base::TimeDelta::FromMilliseconds(100)); |
| 107 details_.window->SetBounds(bounds); |
45 } | 108 } |
46 | 109 |
47 gfx::Rect WorkspaceWindowResizer::GetBoundsForDrag(const gfx::Point& location) { | 110 void WorkspaceWindowResizer::RevertDrag() { |
48 if (!is_resizable()) | 111 if (!did_move_or_resize_) |
49 return WindowResizer::GetBoundsForDrag(location); | 112 return; |
50 | 113 |
51 gfx::Rect bounds(WindowResizer::GetBoundsForDrag(location)); | 114 details_.window->SetBounds(details_.initial_bounds); |
52 AdjustBounds(&bounds); | |
53 return bounds; | |
54 } | 115 } |
55 | 116 |
56 gfx::Rect WorkspaceWindowResizer::GetFinalBounds() { | 117 WorkspaceWindowResizer::WorkspaceWindowResizer( |
57 if (grid_size() <= 1 || !GetHeightBeforeObscured(window())) | 118 const Details& details) |
58 return WindowResizer::GetFinalBounds(); | 119 : details_(details), |
| 120 constrain_size_(wm::IsWindowNormal(details.window)), |
| 121 did_move_or_resize_(false), |
| 122 root_filter_(NULL) { |
| 123 DCHECK(details_.is_resizable); |
| 124 root_filter_ = Shell::GetInstance()->root_filter(); |
| 125 if (root_filter_) |
| 126 root_filter_->LockCursor(); |
59 | 127 |
60 gfx::Rect initial_bounds(window()->bounds()); | 128 if (is_resizable() && constrain_size_ && |
61 bool at_bottom = WindowTouchesBottomOfScreen(); | 129 (!TouchesBottomOfScreen() || |
62 gfx::Rect bounds(WindowResizer::GetFinalBounds()); | 130 details_.bounds_change != kBoundsChange_Repositions)) { |
63 if (at_bottom && bounds.y() != initial_bounds.y()) { | 131 ClearCachedHeights(); |
64 if (bounds.y() < initial_bounds.y()) { | |
65 bounds.set_height(bounds.height() + grid_size() - | |
66 (initial_bounds.y() - bounds.y())); | |
67 } | |
68 AdjustBounds(&bounds); | |
69 } | 132 } |
70 return bounds; | |
71 } | 133 } |
72 | 134 |
73 // static | 135 void WorkspaceWindowResizer::AdjustBoundsForMainWindow( |
74 void WorkspaceWindowResizer::SetHeightBeforeObscured(aura::Window* window, | 136 gfx::Rect* bounds) const { |
75 int height) { | 137 gfx::Rect work_area(gfx::Screen::GetMonitorWorkAreaNearestWindow(window())); |
76 window->SetProperty(kHeightBeforeObscuredKey, height); | 138 AdjustBoundsForWindow(work_area, window(), bounds); |
77 } | 139 } |
78 | 140 |
79 // static | 141 void WorkspaceWindowResizer::AdjustBoundsForWindow( |
80 void WorkspaceWindowResizer::ClearHeightBeforeObscured(aura::Window* window) { | 142 const gfx::Rect& work_area, |
81 window->SetProperty(kHeightBeforeObscuredKey, 0); | 143 aura::Window* window, |
82 } | 144 gfx::Rect* bounds) const { |
83 | |
84 // static | |
85 int WorkspaceWindowResizer::GetHeightBeforeObscured(aura::Window* window) { | |
86 return window->GetProperty(kHeightBeforeObscuredKey); | |
87 } | |
88 | |
89 void WorkspaceWindowResizer::AdjustBounds(gfx::Rect* bounds) const { | |
90 if (!constrain_size_) | |
91 return; | |
92 | |
93 gfx::Rect work_area(gfx::Screen::GetMonitorWorkAreaNearestWindow(window())); | |
94 if (bounds->bottom() < work_area.bottom()) { | 145 if (bounds->bottom() < work_area.bottom()) { |
95 int height = GetHeightBeforeObscured(window()); | 146 int height = GetHeightBeforeObscured(window); |
96 if (!height) | 147 if (!height) |
97 return; | 148 return; |
98 height = std::max(bounds->height(), height); | 149 height = std::max(bounds->height(), height); |
99 bounds->set_height(std::min(work_area.bottom() - bounds->y(), height)); | 150 bounds->set_height(std::min(work_area.bottom() - bounds->y(), height)); |
100 return; | 151 return; |
101 } | 152 } |
102 | 153 |
103 if (bounds->bottom() == work_area.bottom()) | 154 if (bounds->bottom() == work_area.bottom()) |
104 return; | 155 return; |
105 | 156 |
106 if (!GetHeightBeforeObscured(window())) | 157 if (!GetHeightBeforeObscured(window)) |
107 SetHeightBeforeObscured(window(), window()->bounds().height()); | 158 SetHeightBeforeObscured(window, window->bounds().height()); |
108 | 159 |
109 gfx::Size min_size = window()->delegate()->GetMinimumSize(); | 160 gfx::Size min_size = window->delegate()->GetMinimumSize(); |
110 bounds->set_height(std::max(0, work_area.bottom() - bounds->y())); | 161 bounds->set_height( |
| 162 std::max(0, work_area.bottom() - bounds->y())); |
111 if (bounds->height() < min_size.height()) { | 163 if (bounds->height() < min_size.height()) { |
112 bounds->set_height(min_size.height()); | 164 bounds->set_height(min_size.height()); |
113 bounds->set_y(work_area.bottom() - min_size.height()); | 165 bounds->set_y(work_area.bottom() - min_size.height()); |
114 } | 166 } |
115 } | 167 } |
116 | 168 |
117 bool WorkspaceWindowResizer::WindowTouchesBottomOfScreen() const { | 169 void WorkspaceWindowResizer::ClearCachedHeights() { |
118 gfx::Rect work_area(gfx::Screen::GetMonitorWorkAreaNearestWindow(window())); | 170 ClearHeightBeforeObscured(details_.window); |
119 return window()->bounds().bottom() == work_area.bottom(); | 171 } |
| 172 |
| 173 bool WorkspaceWindowResizer::TouchesBottomOfScreen() const { |
| 174 gfx::Rect work_area( |
| 175 gfx::Screen::GetMonitorWorkAreaNearestWindow(details_.window)); |
| 176 return details_.window->bounds().bottom() == work_area.bottom(); |
120 } | 177 } |
121 | 178 |
122 } // namespace internal | 179 } // namespace internal |
123 } // namespace ash | 180 } // namespace ash |
OLD | NEW |