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 3 // found in the LICENSE file. 4 5 #include "ui/views/widget/root_view.h" 6 7 #include <algorithm> 8 9 #include "base/logging.h" 10 #include "base/message_loop/message_loop.h" 11 #include "ui/accessibility/ax_view_state.h" 12 #include "ui/base/cursor/cursor.h" 13 #include "ui/base/dragdrop/drag_drop_types.h" 14 #include "ui/base/ui_base_switches_util.h" 15 #include "ui/compositor/layer.h" 16 #include "ui/events/event.h" 17 #include "ui/events/keycodes/keyboard_codes.h" 18 #include "ui/gfx/canvas.h" 19 #include "ui/views/drag_controller.h" 20 #include "ui/views/focus/view_storage.h" 21 #include "ui/views/layout/fill_layout.h" 22 #include "ui/views/view_targeter.h" 23 #include "ui/views/widget/root_view_targeter.h" 24 #include "ui/views/widget/widget.h" 25 #include "ui/views/widget/widget_delegate.h" 26 27 typedef ui::EventDispatchDetails DispatchDetails; 28 29 namespace views { 30 namespace internal { 31 32 namespace { 33 34 enum EventType { 35 EVENT_ENTER, 36 EVENT_EXIT 37 }; 38 39 class MouseEnterExitEvent : public ui::MouseEvent { 40 public: 41 MouseEnterExitEvent(const ui::MouseEvent& event, ui::EventType type) 42 : ui::MouseEvent(event, 43 static_cast<View*>(NULL), 44 static_cast<View*>(NULL)) { 45 DCHECK(type == ui::ET_MOUSE_ENTERED || 46 type == ui::ET_MOUSE_EXITED); 47 SetType(type); 48 } 49 50 virtual ~MouseEnterExitEvent() {} 51 }; 52 53 } // namespace 54 55 // This event handler receives events in the pre-target phase and takes care of 56 // the following: 57 // - Shows keyboard-triggered context menus. 58 class PreEventDispatchHandler : public ui::EventHandler { 59 public: 60 explicit PreEventDispatchHandler(View* owner) 61 : owner_(owner) { 62 } 63 virtual ~PreEventDispatchHandler() {} 64 65 private: 66 // ui::EventHandler: 67 virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE { 68 CHECK_EQ(ui::EP_PRETARGET, event->phase()); 69 if (event->handled()) 70 return; 71 72 View* v = NULL; 73 if (owner_->GetFocusManager()) // Can be NULL in unittests. 74 v = owner_->GetFocusManager()->GetFocusedView(); 75 76 // Special case to handle keyboard-triggered context menus. 77 if (v && v->enabled() && ((event->key_code() == ui::VKEY_APPS) || 78 (event->key_code() == ui::VKEY_F10 && event->IsShiftDown()))) { 79 // Clamp the menu location within the visible bounds of each ancestor view 80 // to avoid showing the menu over a completely different view or window. 81 gfx::Point location = v->GetKeyboardContextMenuLocation(); 82 for (View* parent = v->parent(); parent; parent = parent->parent()) { 83 const gfx::Rect& parent_bounds = parent->GetBoundsInScreen(); 84 location.SetToMax(parent_bounds.origin()); 85 location.SetToMin(parent_bounds.bottom_right()); 86 } 87 v->ShowContextMenu(location, ui::MENU_SOURCE_KEYBOARD); 88 event->StopPropagation(); 89 } 90 } 91 92 View* owner_; 93 94 DISALLOW_COPY_AND_ASSIGN(PreEventDispatchHandler); 95 }; 96 97 // This event handler receives events in the post-target phase and takes care of 98 // the following: 99 // - Generates context menu, or initiates drag-and-drop, from gesture events. 100 class PostEventDispatchHandler : public ui::EventHandler { 101 public: 102 PostEventDispatchHandler() 103 : touch_dnd_enabled_(::switches::IsTouchDragDropEnabled()) { 104 } 105 virtual ~PostEventDispatchHandler() {} 106 107 private: 108 // Overridden from ui::EventHandler: 109 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { 110 DCHECK_EQ(ui::EP_POSTTARGET, event->phase()); 111 if (event->handled()) 112 return; 113 114 View* target = static_cast<View*>(event->target()); 115 gfx::Point location = event->location(); 116 if (touch_dnd_enabled_ && 117 event->type() == ui::ET_GESTURE_LONG_PRESS && 118 (!target->drag_controller() || 119 target->drag_controller()->CanStartDragForView( 120 target, location, location))) { 121 if (target->DoDrag(*event, location, 122 ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH)) { 123 event->StopPropagation(); 124 return; 125 } 126 } 127 128 if (target->context_menu_controller() && 129 (event->type() == ui::ET_GESTURE_LONG_PRESS || 130 event->type() == ui::ET_GESTURE_LONG_TAP || 131 event->type() == ui::ET_GESTURE_TWO_FINGER_TAP)) { 132 gfx::Point screen_location(location); 133 View::ConvertPointToScreen(target, &screen_location); 134 target->ShowContextMenu(screen_location, ui::MENU_SOURCE_TOUCH); 135 event->StopPropagation(); 136 } 137 } 138 139 bool touch_dnd_enabled_; 140 141 DISALLOW_COPY_AND_ASSIGN(PostEventDispatchHandler); 142 }; 143 144 // static 145 const char RootView::kViewClassName[] = "RootView"; 146 147 //////////////////////////////////////////////////////////////////////////////// 148 // RootView, public: 149 150 // Creation and lifetime ------------------------------------------------------- 151 152 RootView::RootView(Widget* widget) 153 : widget_(widget), 154 mouse_pressed_handler_(NULL), 155 mouse_move_handler_(NULL), 156 last_click_handler_(NULL), 157 explicit_mouse_handler_(false), 158 last_mouse_event_flags_(0), 159 last_mouse_event_x_(-1), 160 last_mouse_event_y_(-1), 161 gesture_handler_(NULL), 162 gesture_handler_set_before_processing_(false), 163 pre_dispatch_handler_(new internal::PreEventDispatchHandler(this)), 164 post_dispatch_handler_(new internal::PostEventDispatchHandler), 165 focus_search_(this, false, false), 166 focus_traversable_parent_(NULL), 167 focus_traversable_parent_view_(NULL), 168 event_dispatch_target_(NULL), 169 old_dispatch_target_(NULL) { 170 AddPreTargetHandler(pre_dispatch_handler_.get()); 171 AddPostTargetHandler(post_dispatch_handler_.get()); 172 SetEventTargeter(scoped_ptr<ViewTargeter>(new RootViewTargeter(this, this))); 173 } 174 175 RootView::~RootView() { 176 // If we have children remove them explicitly so to make sure a remove 177 // notification is sent for each one of them. 178 if (has_children()) 179 RemoveAllChildViews(true); 180 } 181 182 // Tree operations ------------------------------------------------------------- 183 184 void RootView::SetContentsView(View* contents_view) { 185 DCHECK(contents_view && GetWidget()->native_widget()) << 186 "Can't be called until after the native widget is created!"; 187 // The ContentsView must be set up _after_ the window is created so that its 188 // Widget pointer is valid. 189 SetLayoutManager(new FillLayout); 190 if (has_children()) 191 RemoveAllChildViews(true); 192 AddChildView(contents_view); 193 194 // Force a layout now, since the attached hierarchy won't be ready for the 195 // containing window's bounds. Note that we call Layout directly rather than 196 // calling the widget's size changed handler, since the RootView's bounds may 197 // not have changed, which will cause the Layout not to be done otherwise. 198 Layout(); 199 } 200 201 View* RootView::GetContentsView() { 202 return child_count() > 0 ? child_at(0) : NULL; 203 } 204 205 void RootView::NotifyNativeViewHierarchyChanged() { 206 PropagateNativeViewHierarchyChanged(); 207 } 208 209 // Focus ----------------------------------------------------------------------- 210 211 void RootView::SetFocusTraversableParent(FocusTraversable* focus_traversable) { 212 DCHECK(focus_traversable != this); 213 focus_traversable_parent_ = focus_traversable; 214 } 215 216 void RootView::SetFocusTraversableParentView(View* view) { 217 focus_traversable_parent_view_ = view; 218 } 219 220 // System events --------------------------------------------------------------- 221 222 void RootView::ThemeChanged() { 223 View::PropagateThemeChanged(); 224 } 225 226 void RootView::LocaleChanged() { 227 View::PropagateLocaleChanged(); 228 } 229 230 //////////////////////////////////////////////////////////////////////////////// 231 // RootView, FocusTraversable implementation: 232 233 FocusSearch* RootView::GetFocusSearch() { 234 return &focus_search_; 235 } 236 237 FocusTraversable* RootView::GetFocusTraversableParent() { 238 return focus_traversable_parent_; 239 } 240 241 View* RootView::GetFocusTraversableParentView() { 242 return focus_traversable_parent_view_; 243 } 244 245 //////////////////////////////////////////////////////////////////////////////// 246 // RootView, ui::EventProcessor overrides: 247 248 ui::EventTarget* RootView::GetRootTarget() { 249 return this; 250 } 251 252 ui::EventDispatchDetails RootView::OnEventFromSource(ui::Event* event) { 253 if (event->IsKeyEvent()) 254 return EventProcessor::OnEventFromSource(event); 255 256 if (event->IsScrollEvent()) 257 return EventProcessor::OnEventFromSource(event); 258 259 if (event->IsGestureEvent()) { 260 // TODO(tdanderson): Once DispatchGestureEvent() has been removed, move 261 // all of this logic into an override of a new 262 // virtual method 263 // EventProcessor::OnEventProcessingStarted() (which 264 // returns false if no processing should take place). 265 // Also move the implementation of 266 // PrepareEventForDispatch() into this new method. 267 // Then RootView::OnEventFromSource() can be removed. 268 ui::GestureEvent* gesture_event = event->AsGestureEvent(); 269 270 // Do not dispatch ui::ET_GESTURE_BEGIN events. 271 if (gesture_event->type() == ui::ET_GESTURE_BEGIN) 272 return DispatchDetails(); 273 274 // Ignore ui::ET_GESTURE_END events which do not correspond to the 275 // removal of the final touch point. 276 if (gesture_event->type() == ui::ET_GESTURE_END && 277 gesture_event->details().touch_points() > 1) { 278 return DispatchDetails(); 279 } 280 281 // Ignore subsequent gesture scroll events if no handler was set for a 282 // ui::ET_GESTURE_SCROLL_BEGIN event. 283 if (!gesture_handler_ && 284 (gesture_event->type() == ui::ET_GESTURE_SCROLL_UPDATE || 285 gesture_event->type() == ui::ET_GESTURE_SCROLL_END || 286 gesture_event->type() == ui::ET_SCROLL_FLING_START)) { 287 return DispatchDetails(); 288 } 289 290 gesture_handler_set_before_processing_ = !!gesture_handler_; 291 return EventProcessor::OnEventFromSource(event); 292 } 293 294 if (event->IsTouchEvent()) 295 NOTREACHED() << "Touch events should not be sent to RootView."; 296 297 if (event->IsMouseEvent()) 298 NOTREACHED() << "Should not be called with a MouseEvent."; 299 300 return DispatchDetails(); 301 } 302 303 void RootView::OnEventProcessingFinished(ui::Event* event) { 304 // If |event| was not handled and |gesture_handler_| was not set by the 305 // dispatch of a previous gesture event, then no default gesture handler 306 // should be set prior to the next gesture event being received. 307 if (event->IsGestureEvent() && 308 !event->handled() && 309 !gesture_handler_set_before_processing_) { 310 gesture_handler_ = NULL; 311 } 312 } 313 314 //////////////////////////////////////////////////////////////////////////////// 315 // RootView, View overrides: 316 317 const Widget* RootView::GetWidget() const { 318 return widget_; 319 } 320 321 Widget* RootView::GetWidget() { 322 return const_cast<Widget*>(const_cast<const RootView*>(this)->GetWidget()); 323 } 324 325 bool RootView::IsDrawn() const { 326 return visible(); 327 } 328 329 void RootView::Layout() { 330 View::Layout(); 331 widget_->OnRootViewLayout(); 332 } 333 334 const char* RootView::GetClassName() const { 335 return kViewClassName; 336 } 337 338 void RootView::SchedulePaintInRect(const gfx::Rect& rect) { 339 if (layer()) { 340 layer()->SchedulePaint(rect); 341 } else { 342 gfx::Rect xrect = ConvertRectToParent(rect); 343 gfx::Rect invalid_rect = gfx::IntersectRects(GetLocalBounds(), xrect); 344 if (!invalid_rect.IsEmpty()) 345 widget_->SchedulePaintInRect(invalid_rect); 346 } 347 } 348 349 bool RootView::OnMousePressed(const ui::MouseEvent& event) { 350 UpdateCursor(event); 351 SetMouseLocationAndFlags(event); 352 353 // If mouse_pressed_handler_ is non null, we are currently processing 354 // a pressed -> drag -> released session. In that case we send the 355 // event to mouse_pressed_handler_ 356 if (mouse_pressed_handler_) { 357 ui::MouseEvent mouse_pressed_event(event, static_cast<View*>(this), 358 mouse_pressed_handler_); 359 drag_info_.Reset(); 360 ui::EventDispatchDetails dispatch_details = 361 DispatchEvent(mouse_pressed_handler_, &mouse_pressed_event); 362 if (dispatch_details.dispatcher_destroyed) 363 return true; 364 return true; 365 } 366 DCHECK(!explicit_mouse_handler_); 367 368 bool hit_disabled_view = false; 369 // Walk up the tree until we find a view that wants the mouse event. 370 for (mouse_pressed_handler_ = GetEventHandlerForPoint(event.location()); 371 mouse_pressed_handler_ && (mouse_pressed_handler_ != this); 372 mouse_pressed_handler_ = mouse_pressed_handler_->parent()) { 373 DVLOG(1) << "OnMousePressed testing " 374 << mouse_pressed_handler_->GetClassName(); 375 if (!mouse_pressed_handler_->enabled()) { 376 // Disabled views should eat events instead of propagating them upwards. 377 hit_disabled_view = true; 378 break; 379 } 380 381 // See if this view wants to handle the mouse press. 382 ui::MouseEvent mouse_pressed_event(event, static_cast<View*>(this), 383 mouse_pressed_handler_); 384 385 // Remove the double-click flag if the handler is different than the 386 // one which got the first click part of the double-click. 387 if (mouse_pressed_handler_ != last_click_handler_) 388 mouse_pressed_event.set_flags(event.flags() & ~ui::EF_IS_DOUBLE_CLICK); 389 390 drag_info_.Reset(); 391 ui::EventDispatchDetails dispatch_details = 392 DispatchEvent(mouse_pressed_handler_, &mouse_pressed_event); 393 if (dispatch_details.dispatcher_destroyed) 394 return mouse_pressed_event.handled(); 395 396 // The view could have removed itself from the tree when handling 397 // OnMousePressed(). In this case, the removal notification will have 398 // reset mouse_pressed_handler_ to NULL out from under us. Detect this 399 // case and stop. (See comments in view.h.) 400 // 401 // NOTE: Don't return true here, because we don't want the frame to 402 // forward future events to us when there's no handler. 403 if (!mouse_pressed_handler_) 404 break; 405 406 // If the view handled the event, leave mouse_pressed_handler_ set and 407 // return true, which will cause subsequent drag/release events to get 408 // forwarded to that view. 409 if (mouse_pressed_event.handled()) { 410 last_click_handler_ = mouse_pressed_handler_; 411 DVLOG(1) << "OnMousePressed handled by " 412 << mouse_pressed_handler_->GetClassName(); 413 return true; 414 } 415 } 416 417 // Reset mouse_pressed_handler_ to indicate that no processing is occurring. 418 mouse_pressed_handler_ = NULL; 419 420 // In the event that a double-click is not handled after traversing the 421 // entire hierarchy (even as a single-click when sent to a different view), 422 // it must be marked as handled to avoid anything happening from default 423 // processing if it the first click-part was handled by us. 424 if (last_click_handler_ && (event.flags() & ui::EF_IS_DOUBLE_CLICK)) 425 hit_disabled_view = true; 426 427 last_click_handler_ = NULL; 428 return hit_disabled_view; 429 } 430 431 bool RootView::OnMouseDragged(const ui::MouseEvent& event) { 432 if (mouse_pressed_handler_) { 433 SetMouseLocationAndFlags(event); 434 435 ui::MouseEvent mouse_event(event, static_cast<View*>(this), 436 mouse_pressed_handler_); 437 ui::EventDispatchDetails dispatch_details = 438 DispatchEvent(mouse_pressed_handler_, &mouse_event); 439 if (dispatch_details.dispatcher_destroyed) 440 return false; 441 } 442 return false; 443 } 444 445 void RootView::OnMouseReleased(const ui::MouseEvent& event) { 446 UpdateCursor(event); 447 448 if (mouse_pressed_handler_) { 449 ui::MouseEvent mouse_released(event, static_cast<View*>(this), 450 mouse_pressed_handler_); 451 // We allow the view to delete us from the event dispatch callback. As such, 452 // configure state such that we're done first, then call View. 453 View* mouse_pressed_handler = mouse_pressed_handler_; 454 SetMouseHandler(NULL); 455 ui::EventDispatchDetails dispatch_details = 456 DispatchEvent(mouse_pressed_handler, &mouse_released); 457 if (dispatch_details.dispatcher_destroyed) 458 return; 459 } 460 } 461 462 void RootView::OnMouseCaptureLost() { 463 // TODO: this likely needs to reset touch handler too. 464 465 if (mouse_pressed_handler_ || gesture_handler_) { 466 // Synthesize a release event for UpdateCursor. 467 if (mouse_pressed_handler_) { 468 gfx::Point last_point(last_mouse_event_x_, last_mouse_event_y_); 469 ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, 470 last_point, last_point, 471 last_mouse_event_flags_, 472 0); 473 UpdateCursor(release_event); 474 } 475 // We allow the view to delete us from OnMouseCaptureLost. As such, 476 // configure state such that we're done first, then call View. 477 View* mouse_pressed_handler = mouse_pressed_handler_; 478 View* gesture_handler = gesture_handler_; 479 SetMouseHandler(NULL); 480 if (mouse_pressed_handler) 481 mouse_pressed_handler->OnMouseCaptureLost(); 482 else 483 gesture_handler->OnMouseCaptureLost(); 484 // WARNING: we may have been deleted. 485 } 486 } 487 488 void RootView::OnMouseMoved(const ui::MouseEvent& event) { 489 View* v = GetEventHandlerForPoint(event.location()); 490 // Find the first enabled view, or the existing move handler, whichever comes 491 // first. The check for the existing handler is because if a view becomes 492 // disabled while handling moves, it's wrong to suddenly send ET_MOUSE_EXITED 493 // and ET_MOUSE_ENTERED events, because the mouse hasn't actually exited yet. 494 while (v && !v->enabled() && (v != mouse_move_handler_)) 495 v = v->parent(); 496 if (v && v != this) { 497 if (v != mouse_move_handler_) { 498 if (mouse_move_handler_ != NULL && 499 (!mouse_move_handler_->notify_enter_exit_on_child() || 500 !mouse_move_handler_->Contains(v))) { 501 MouseEnterExitEvent exit(event, ui::ET_MOUSE_EXITED); 502 exit.ConvertLocationToTarget(static_cast<View*>(this), 503 mouse_move_handler_); 504 ui::EventDispatchDetails dispatch_details = 505 DispatchEvent(mouse_move_handler_, &exit); 506 if (dispatch_details.dispatcher_destroyed) 507 return; 508 NotifyEnterExitOfDescendant(event, ui::ET_MOUSE_EXITED, 509 mouse_move_handler_, v); 510 } 511 View* old_handler = mouse_move_handler_; 512 mouse_move_handler_ = v; 513 if (!mouse_move_handler_->notify_enter_exit_on_child() || 514 !mouse_move_handler_->Contains(old_handler)) { 515 MouseEnterExitEvent entered(event, ui::ET_MOUSE_ENTERED); 516 entered.ConvertLocationToTarget(static_cast<View*>(this), 517 mouse_move_handler_); 518 ui::EventDispatchDetails dispatch_details = 519 DispatchEvent(mouse_move_handler_, &entered); 520 if (dispatch_details.dispatcher_destroyed) 521 return; 522 NotifyEnterExitOfDescendant(event, ui::ET_MOUSE_ENTERED, 523 mouse_move_handler_, old_handler); 524 } 525 } 526 ui::MouseEvent moved_event(event, static_cast<View*>(this), 527 mouse_move_handler_); 528 mouse_move_handler_->OnMouseMoved(moved_event); 529 // TODO(tdanderson): It may be possible to avoid setting the cursor twice 530 // (once here and once from CompoundEventFilter) on a 531 // mousemove. See crbug.com/351469. 532 if (!(moved_event.flags() & ui::EF_IS_NON_CLIENT)) 533 widget_->SetCursor(mouse_move_handler_->GetCursor(moved_event)); 534 } else if (mouse_move_handler_ != NULL) { 535 MouseEnterExitEvent exited(event, ui::ET_MOUSE_EXITED); 536 ui::EventDispatchDetails dispatch_details = 537 DispatchEvent(mouse_move_handler_, &exited); 538 if (dispatch_details.dispatcher_destroyed) 539 return; 540 NotifyEnterExitOfDescendant(event, ui::ET_MOUSE_EXITED, 541 mouse_move_handler_, v); 542 // On Aura the non-client area extends slightly outside the root view for 543 // some windows. Let the non-client cursor handling code set the cursor 544 // as we do above. 545 if (!(event.flags() & ui::EF_IS_NON_CLIENT)) 546 widget_->SetCursor(gfx::kNullCursor); 547 mouse_move_handler_ = NULL; 548 } 549 } 550 551 void RootView::OnMouseExited(const ui::MouseEvent& event) { 552 if (mouse_move_handler_ != NULL) { 553 MouseEnterExitEvent exited(event, ui::ET_MOUSE_EXITED); 554 ui::EventDispatchDetails dispatch_details = 555 DispatchEvent(mouse_move_handler_, &exited); 556 if (dispatch_details.dispatcher_destroyed) 557 return; 558 NotifyEnterExitOfDescendant(event, ui::ET_MOUSE_EXITED, 559 mouse_move_handler_, NULL); 560 mouse_move_handler_ = NULL; 561 } 562 } 563 564 bool RootView::OnMouseWheel(const ui::MouseWheelEvent& event) { 565 for (View* v = GetEventHandlerForPoint(event.location()); 566 v && v != this && !event.handled(); v = v->parent()) { 567 ui::EventDispatchDetails dispatch_details = 568 DispatchEvent(v, const_cast<ui::MouseWheelEvent*>(&event)); 569 if (dispatch_details.dispatcher_destroyed || 570 dispatch_details.target_destroyed) { 571 return event.handled(); 572 } 573 } 574 return event.handled(); 575 } 576 577 void RootView::SetMouseHandler(View* new_mh) { 578 // If we're clearing the mouse handler, clear explicit_mouse_handler_ as well. 579 explicit_mouse_handler_ = (new_mh != NULL); 580 mouse_pressed_handler_ = new_mh; 581 gesture_handler_ = new_mh; 582 drag_info_.Reset(); 583 } 584 585 void RootView::GetAccessibleState(ui::AXViewState* state) { 586 state->name = widget_->widget_delegate()->GetAccessibleWindowTitle(); 587 state->role = widget_->widget_delegate()->GetAccessibleWindowRole(); 588 } 589 590 void RootView::UpdateParentLayer() { 591 if (layer()) 592 ReparentLayer(gfx::Vector2d(GetMirroredX(), y()), widget_->GetLayer()); 593 } 594 595 //////////////////////////////////////////////////////////////////////////////// 596 // RootView, protected: 597 598 void RootView::ViewHierarchyChanged( 599 const ViewHierarchyChangedDetails& details) { 600 widget_->ViewHierarchyChanged(details); 601 602 if (!details.is_add) { 603 if (!explicit_mouse_handler_ && mouse_pressed_handler_ == details.child) 604 mouse_pressed_handler_ = NULL; 605 if (mouse_move_handler_ == details.child) 606 mouse_move_handler_ = NULL; 607 if (gesture_handler_ == details.child) 608 gesture_handler_ = NULL; 609 if (event_dispatch_target_ == details.child) 610 event_dispatch_target_ = NULL; 611 if (old_dispatch_target_ == details.child) 612 old_dispatch_target_ = NULL; 613 } 614 } 615 616 void RootView::VisibilityChanged(View* /*starting_from*/, bool is_visible) { 617 if (!is_visible) { 618 // When the root view is being hidden (e.g. when widget is minimized) 619 // handlers are reset, so that after it is reshown, events are not captured 620 // by old handlers. 621 explicit_mouse_handler_ = false; 622 mouse_pressed_handler_ = NULL; 623 mouse_move_handler_ = NULL; 624 gesture_handler_ = NULL; 625 event_dispatch_target_ = NULL; 626 old_dispatch_target_ = NULL; 627 } 628 } 629 630 void RootView::OnPaint(gfx::Canvas* canvas) { 631 if (!layer() || !layer()->fills_bounds_opaquely()) 632 canvas->DrawColor(SK_ColorBLACK, SkXfermode::kClear_Mode); 633 634 View::OnPaint(canvas); 635 } 636 637 gfx::Vector2d RootView::CalculateOffsetToAncestorWithLayer( 638 ui::Layer** layer_parent) { 639 gfx::Vector2d offset(View::CalculateOffsetToAncestorWithLayer(layer_parent)); 640 if (!layer() && layer_parent) 641 *layer_parent = widget_->GetLayer(); 642 return offset; 643 } 644 645 View::DragInfo* RootView::GetDragInfo() { 646 return &drag_info_; 647 } 648 649 //////////////////////////////////////////////////////////////////////////////// 650 // RootView, private: 651 652 // Input ----------------------------------------------------------------------- 653 654 void RootView::UpdateCursor(const ui::MouseEvent& event) { 655 if (!(event.flags() & ui::EF_IS_NON_CLIENT)) { 656 View* v = GetEventHandlerForPoint(event.location()); 657 ui::MouseEvent me(event, static_cast<View*>(this), v); 658 widget_->SetCursor(v->GetCursor(me)); 659 } 660 } 661 662 void RootView::SetMouseLocationAndFlags(const ui::MouseEvent& event) { 663 last_mouse_event_flags_ = event.flags(); 664 last_mouse_event_x_ = event.x(); 665 last_mouse_event_y_ = event.y(); 666 } 667 668 void RootView::NotifyEnterExitOfDescendant(const ui::MouseEvent& event, 669 ui::EventType type, 670 View* view, 671 View* sibling) { 672 for (View* p = view->parent(); p; p = p->parent()) { 673 if (!p->notify_enter_exit_on_child()) 674 continue; 675 if (sibling && p->Contains(sibling)) 676 break; 677 // It is necessary to recreate the notify-event for each dispatch, since one 678 // of the callbacks can mark the event as handled, and that would cause 679 // incorrect event dispatch. 680 MouseEnterExitEvent notify_event(event, type); 681 ui::EventDispatchDetails dispatch_details = DispatchEvent(p, ¬ify_event); 682 if (dispatch_details.dispatcher_destroyed || 683 dispatch_details.target_destroyed) { 684 return; 685 } 686 } 687 } 688 689 bool RootView::CanDispatchToTarget(ui::EventTarget* target) { 690 return event_dispatch_target_ == target; 691 } 692 693 ui::EventDispatchDetails RootView::PreDispatchEvent(ui::EventTarget* target, 694 ui::Event* event) { 695 View* view = static_cast<View*>(target); 696 if (event->IsGestureEvent()) { 697 // Update |gesture_handler_| to indicate which View is currently handling 698 // gesture events. 699 // TODO(tdanderson): Look into moving this to PostDispatchEvent() and 700 // using |event_dispatch_target_| instead of 701 // |gesture_handler_| to detect if the view has been 702 // removed from the tree. 703 gesture_handler_ = view; 704 705 // Disabled views are permitted to be targets of gesture events, but 706 // gesture events should never actually be dispatched to them. Prevent 707 // dispatch by marking the event as handled. 708 if (!view->enabled()) 709 event->SetHandled(); 710 } 711 712 old_dispatch_target_ = event_dispatch_target_; 713 event_dispatch_target_ = view; 714 return DispatchDetails(); 715 } 716 717 ui::EventDispatchDetails RootView::PostDispatchEvent(ui::EventTarget* target, 718 const ui::Event& event) { 719 // The GESTURE_END event corresponding to the removal of the final touch 720 // point marks the end of a gesture sequence, so reset |gesture_handler_| 721 // to NULL. 722 if (event.type() == ui::ET_GESTURE_END) { 723 // In case a drag was in progress, reset all the handlers. Otherwise, just 724 // reset the gesture handler. 725 if (gesture_handler_ && gesture_handler_ == mouse_pressed_handler_) 726 SetMouseHandler(NULL); 727 else 728 gesture_handler_ = NULL; 729 } 730 731 DispatchDetails details; 732 if (target != event_dispatch_target_) 733 details.target_destroyed = true; 734 735 event_dispatch_target_ = old_dispatch_target_; 736 old_dispatch_target_ = NULL; 737 738 #ifndef NDEBUG 739 DCHECK(!event_dispatch_target_ || Contains(event_dispatch_target_)); 740 #endif 741 742 return details; 743 } 744 745 } // namespace internal 746 } // namespace views 747