OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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 "ui/aura_shell/toplevel_window_event_filter.h" | |
6 | |
7 #include "ui/aura/client/aura_constants.h" | |
8 #include "ui/aura/cursor.h" | |
9 #include "ui/aura/event.h" | |
10 #include "ui/aura/root_window.h" | |
11 #include "ui/aura/window.h" | |
12 #include "ui/aura/window_delegate.h" | |
13 #include "ui/aura_shell/window_util.h" | |
14 #include "ui/base/hit_test.h" | |
15 #include "ui/base/ui_base_types.h" | |
16 | |
17 namespace aura_shell { | |
18 | |
19 namespace { | |
20 | |
21 // Identifies the types of bounds change operations performed by a drag to a | |
22 // particular window component. | |
23 const int kBoundsChange_None = 0; | |
24 const int kBoundsChange_Repositions = 1; | |
25 const int kBoundsChange_Resizes = 2; | |
26 | |
27 int GetBoundsChangeForWindowComponent(int window_component) { | |
28 int bounds_change = kBoundsChange_None; | |
29 switch (window_component) { | |
30 case HTTOPLEFT: | |
31 case HTTOP: | |
32 case HTTOPRIGHT: | |
33 case HTLEFT: | |
34 case HTBOTTOMLEFT: | |
35 bounds_change |= kBoundsChange_Repositions | kBoundsChange_Resizes; | |
36 break; | |
37 case HTCAPTION: | |
38 bounds_change |= kBoundsChange_Repositions; | |
39 break; | |
40 case HTRIGHT: | |
41 case HTBOTTOMRIGHT: | |
42 case HTBOTTOM: | |
43 case HTGROWBOX: | |
44 bounds_change |= kBoundsChange_Resizes; | |
45 break; | |
46 default: | |
47 break; | |
48 } | |
49 return bounds_change; | |
50 } | |
51 | |
52 // Possible directions for changing bounds. | |
53 | |
54 const int kBoundsChangeDirection_None = 0; | |
55 const int kBoundsChangeDirection_Horizontal = 1; | |
56 const int kBoundsChangeDirection_Vertical = 2; | |
57 | |
58 int GetPositionChangeDirectionForWindowComponent(int window_component) { | |
59 int pos_change_direction = kBoundsChangeDirection_None; | |
60 switch (window_component) { | |
61 case HTTOPLEFT: | |
62 case HTBOTTOMRIGHT: | |
63 case HTGROWBOX: | |
64 case HTCAPTION: | |
65 pos_change_direction |= | |
66 kBoundsChangeDirection_Horizontal | kBoundsChangeDirection_Vertical; | |
67 break; | |
68 case HTTOP: | |
69 case HTTOPRIGHT: | |
70 case HTBOTTOM: | |
71 pos_change_direction |= kBoundsChangeDirection_Vertical; | |
72 break; | |
73 case HTBOTTOMLEFT: | |
74 case HTRIGHT: | |
75 case HTLEFT: | |
76 pos_change_direction |= kBoundsChangeDirection_Horizontal; | |
77 break; | |
78 default: | |
79 break; | |
80 } | |
81 return pos_change_direction; | |
82 } | |
83 | |
84 int GetSizeChangeDirectionForWindowComponent(int window_component) { | |
85 int size_change_direction = kBoundsChangeDirection_None; | |
86 switch (window_component) { | |
87 case HTTOPLEFT: | |
88 case HTTOPRIGHT: | |
89 case HTBOTTOMLEFT: | |
90 case HTBOTTOMRIGHT: | |
91 case HTGROWBOX: | |
92 case HTCAPTION: | |
93 size_change_direction |= | |
94 kBoundsChangeDirection_Horizontal | kBoundsChangeDirection_Vertical; | |
95 break; | |
96 case HTTOP: | |
97 case HTBOTTOM: | |
98 size_change_direction |= kBoundsChangeDirection_Vertical; | |
99 break; | |
100 case HTRIGHT: | |
101 case HTLEFT: | |
102 size_change_direction |= kBoundsChangeDirection_Horizontal; | |
103 break; | |
104 default: | |
105 break; | |
106 } | |
107 return size_change_direction; | |
108 } | |
109 | |
110 // Returns true for resize components along the right edge, where a drag in | |
111 // positive x will make the window larger. | |
112 bool IsRightEdge(int window_component) { | |
113 return window_component == HTTOPRIGHT || | |
114 window_component == HTRIGHT || | |
115 window_component == HTBOTTOMRIGHT || | |
116 window_component == HTGROWBOX; | |
117 } | |
118 | |
119 // Returns true for resize components in along the bottom edge, where a drag | |
120 // in positive y will make the window larger. | |
121 bool IsBottomEdge(int window_component) { | |
122 return window_component == HTBOTTOMLEFT || | |
123 window_component == HTBOTTOM || | |
124 window_component == HTBOTTOMRIGHT || | |
125 window_component == HTGROWBOX; | |
126 } | |
127 | |
128 void ToggleMaximizedState(aura::Window* window) { | |
129 window->SetIntProperty(aura::client::kShowStateKey, | |
130 IsWindowMaximized(window) ? | |
131 ui::SHOW_STATE_NORMAL : ui::SHOW_STATE_MAXIMIZED); | |
132 } | |
133 | |
134 } // namespace | |
135 | |
136 ToplevelWindowEventFilter::ToplevelWindowEventFilter(aura::Window* owner) | |
137 : EventFilter(owner), | |
138 window_component_(HTNOWHERE) { | |
139 } | |
140 | |
141 ToplevelWindowEventFilter::~ToplevelWindowEventFilter() { | |
142 } | |
143 | |
144 bool ToplevelWindowEventFilter::PreHandleKeyEvent(aura::Window* target, | |
145 aura::KeyEvent* event) { | |
146 return false; | |
147 } | |
148 | |
149 bool ToplevelWindowEventFilter::PreHandleMouseEvent(aura::Window* target, | |
150 aura::MouseEvent* event) { | |
151 // Process EventFilters implementation first so that it processes | |
152 // activation/focus first. | |
153 switch (event->type()) { | |
154 case ui::ET_MOUSE_MOVED: | |
155 UpdateWindowComponentForEvent(target, event); | |
156 break; | |
157 case ui::ET_MOUSE_PRESSED: | |
158 // We also update the current window component here because for the | |
159 // mouse-drag-release-press case, where the mouse is released and | |
160 // pressed without mouse move event. | |
161 UpdateWindowComponentForEvent(target, event); | |
162 if (window_component_ == HTCAPTION && | |
163 event->flags() & ui::EF_IS_DOUBLE_CLICK) { | |
164 ToggleMaximizedState(target); | |
165 } | |
166 UpdateLocationFromEvent(target, event); | |
167 return GetBoundsChangeForWindowComponent(window_component_) != | |
168 kBoundsChange_None; | |
169 case ui::ET_MOUSE_DRAGGED: | |
170 return HandleDrag(target, event); | |
171 case ui::ET_MOUSE_RELEASED: | |
172 window_component_ = HTNOWHERE; | |
173 break; | |
174 default: | |
175 break; | |
176 } | |
177 return false; | |
178 } | |
179 | |
180 ui::TouchStatus ToplevelWindowEventFilter::PreHandleTouchEvent( | |
181 aura::Window* target, | |
182 aura::TouchEvent* event) { | |
183 // Process EventFilters implementation first so that it processes | |
184 // activation/focus first. | |
185 // TODO(sad): Allow resizing/maximizing etc. from touch? | |
186 UpdateWindowComponentForEvent(target, event); | |
187 int bounds_change = GetBoundsChangeForWindowComponent(window_component_); | |
188 if (bounds_change == kBoundsChange_None) | |
189 return ui::TOUCH_STATUS_UNKNOWN; | |
190 | |
191 // Handle touch move by simulate mouse drag with single touch. | |
192 switch (event->type()) { | |
193 case ui::ET_TOUCH_PRESSED: | |
194 UpdateLocationFromEvent(target, event); | |
195 pressed_touch_ids_.insert(event->touch_id()); | |
196 if (pressed_touch_ids_.size() == 1) | |
197 return ui::TOUCH_STATUS_START; | |
198 break; | |
199 case ui::ET_TOUCH_MOVED: | |
200 if (pressed_touch_ids_.size() == 1) { | |
201 if (HandleDrag(target, event)) | |
202 return ui::TOUCH_STATUS_CONTINUE; | |
203 } | |
204 break; | |
205 case ui::ET_TOUCH_RELEASED: | |
206 pressed_touch_ids_.erase(event->touch_id()); | |
207 if (pressed_touch_ids_.empty()) { | |
208 window_component_ = HTNOWHERE; | |
209 return ui::TOUCH_STATUS_END; | |
210 } | |
211 break; | |
212 default: | |
213 break; | |
214 } | |
215 return ui::TOUCH_STATUS_UNKNOWN; | |
216 } | |
217 | |
218 void ToplevelWindowEventFilter::MoveWindowToFront(aura::Window* target) { | |
219 aura::Window* parent = target->parent(); | |
220 aura::Window* child = target; | |
221 while (parent) { | |
222 parent->StackChildAtTop(child); | |
223 if (parent == owner()) | |
224 break; | |
225 parent = parent->parent(); | |
226 child = child->parent(); | |
227 } | |
228 } | |
229 | |
230 bool ToplevelWindowEventFilter::HandleDrag(aura::Window* target, | |
231 aura::LocatedEvent* event) { | |
232 // This function only be triggered to move window | |
233 // by mouse drag or touch move event. | |
234 DCHECK(event->type() == ui::ET_MOUSE_DRAGGED || | |
235 event->type() == ui::ET_TOUCH_MOVED); | |
236 | |
237 int bounds_change = GetBoundsChangeForWindowComponent(window_component_); | |
238 if (bounds_change == kBoundsChange_None) | |
239 return false; | |
240 | |
241 // Only a normal/default window can be moved/resized. | |
242 if (target->GetIntProperty(aura::client::kShowStateKey) != | |
243 ui::SHOW_STATE_NORMAL && | |
244 target->GetIntProperty(aura::client::kShowStateKey) != | |
245 ui::SHOW_STATE_DEFAULT) | |
246 return false; | |
247 | |
248 // Dragging a window moves the local coordinate frame, so do arithmetic | |
249 // in the parent coordinate frame. | |
250 gfx::Point event_location_in_parent(event->location()); | |
251 aura::Window::ConvertPointToWindow(target, target->parent(), | |
252 &event_location_in_parent); | |
253 int delta_x = event_location_in_parent.x() - mouse_down_offset_in_parent_.x(); | |
254 int delta_y = event_location_in_parent.y() - mouse_down_offset_in_parent_.y(); | |
255 | |
256 // The minimize size constraint may limit how much we change the window | |
257 // position. For example, dragging the left edge to the right should stop | |
258 // repositioning the window when the minimize size is reached. | |
259 gfx::Size size = GetSizeForDrag(bounds_change, target, &delta_x, &delta_y); | |
260 gfx::Point origin = GetOriginForDrag(bounds_change, delta_x, delta_y); | |
261 | |
262 target->SetBounds(gfx::Rect(origin, size)); | |
263 return true; | |
264 } | |
265 | |
266 void ToplevelWindowEventFilter::UpdateLocationFromEvent( | |
267 aura::Window* target, | |
268 aura::LocatedEvent* event) { | |
269 mouse_down_bounds_ = target->bounds(); | |
270 mouse_down_offset_in_parent_ = event->location(); | |
271 aura::Window::ConvertPointToWindow(target, target->parent(), | |
272 &mouse_down_offset_in_parent_); | |
273 } | |
274 | |
275 void ToplevelWindowEventFilter::UpdateWindowComponentForEvent( | |
276 aura::Window* target, | |
277 aura::LocatedEvent* event) { | |
278 window_component_ = | |
279 target->delegate()->GetNonClientComponent(event->location()); | |
280 } | |
281 | |
282 gfx::Point ToplevelWindowEventFilter::GetOriginForDrag( | |
283 int bounds_change, | |
284 int delta_x, | |
285 int delta_y) const { | |
286 gfx::Point origin = mouse_down_bounds_.origin(); | |
287 if (bounds_change & kBoundsChange_Repositions) { | |
288 int pos_change_direction = | |
289 GetPositionChangeDirectionForWindowComponent(window_component_); | |
290 if (pos_change_direction & kBoundsChangeDirection_Horizontal) | |
291 origin.Offset(delta_x, 0); | |
292 if (pos_change_direction & kBoundsChangeDirection_Vertical) | |
293 origin.Offset(0, delta_y); | |
294 } | |
295 return origin; | |
296 } | |
297 | |
298 gfx::Size ToplevelWindowEventFilter::GetSizeForDrag( | |
299 int bounds_change, | |
300 aura::Window* target, | |
301 int* delta_x, | |
302 int* delta_y) const { | |
303 gfx::Size size = mouse_down_bounds_.size(); | |
304 if (bounds_change & kBoundsChange_Resizes) { | |
305 gfx::Size min_size = target->delegate()->GetMinimumSize(); | |
306 int size_change_direction = | |
307 GetSizeChangeDirectionForWindowComponent(window_component_); | |
308 size.SetSize( | |
309 GetWidthForDrag(size_change_direction, min_size.width(), delta_x), | |
310 GetHeightForDrag(size_change_direction, min_size.height(), delta_y)); | |
311 } | |
312 return size; | |
313 } | |
314 | |
315 int ToplevelWindowEventFilter::GetWidthForDrag(int size_change_direction, | |
316 int min_width, | |
317 int* delta_x) const { | |
318 int width = mouse_down_bounds_.width(); | |
319 if (size_change_direction & kBoundsChangeDirection_Horizontal) { | |
320 // Along the right edge, positive delta_x increases the window size. | |
321 int x_multiplier = IsRightEdge(window_component_) ? 1 : -1; | |
322 width += x_multiplier * (*delta_x); | |
323 | |
324 // Ensure we don't shrink past the minimum width and clamp delta_x | |
325 // for the window origin computation. | |
326 if (width < min_width) { | |
327 width = min_width; | |
328 *delta_x = -x_multiplier * (mouse_down_bounds_.width() - min_width); | |
329 } | |
330 } | |
331 return width; | |
332 } | |
333 | |
334 int ToplevelWindowEventFilter::GetHeightForDrag(int size_change_direction, | |
335 int min_height, | |
336 int* delta_y) const { | |
337 int height = mouse_down_bounds_.height(); | |
338 if (size_change_direction & kBoundsChangeDirection_Vertical) { | |
339 // Along the bottom edge, positive delta_y increases the window size. | |
340 int y_multiplier = IsBottomEdge(window_component_) ? 1 : -1; | |
341 height += y_multiplier * (*delta_y); | |
342 | |
343 // Ensure we don't shrink past the minimum height and clamp delta_y | |
344 // for the window origin computation. | |
345 if (height < min_height) { | |
346 height = min_height; | |
347 *delta_y = -y_multiplier * (mouse_down_bounds_.height() - min_height); | |
348 } | |
349 } | |
350 return height; | |
351 } | |
352 | |
353 } // namespace aura | |
OLD | NEW |