| 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 |