Add app.window.alphaEnabled() and onAlphaEnabledChanged.
[chromium-blink-merge.git] / ui / views / widget / root_view.cc
blob5d52e8d62c2b18d1e170a1fb4a45e0f2b5b56018
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.
5 #include "ui/views/widget/root_view.h"
7 #include <algorithm>
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/views_switches.h"
24 #include "ui/views/widget/widget.h"
25 #include "ui/views/widget/widget_delegate.h"
27 typedef ui::EventDispatchDetails DispatchDetails;
29 namespace views {
30 namespace internal {
32 namespace {
34 enum EventType {
35 EVENT_ENTER,
36 EVENT_EXIT
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);
50 virtual ~MouseEnterExitEvent() {}
53 } // namespace
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) {
63 virtual ~PreEventDispatchHandler() {}
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;
72 View* v = NULL;
73 if (owner_->GetFocusManager()) // Can be NULL in unittests.
74 v = owner_->GetFocusManager()->GetFocusedView();
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());
87 v->ShowContextMenu(location, ui::MENU_SOURCE_KEYBOARD);
88 event->StopPropagation();
92 View* owner_;
94 DISALLOW_COPY_AND_ASSIGN(PreEventDispatchHandler);
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()) {
105 virtual ~PostEventDispatchHandler() {}
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;
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;
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();
139 bool touch_dnd_enabled_;
141 DISALLOW_COPY_AND_ASSIGN(PostEventDispatchHandler);
144 // static
145 const char RootView::kViewClassName[] = "RootView";
147 ////////////////////////////////////////////////////////////////////////////////
148 // RootView, public:
150 // Creation and lifetime -------------------------------------------------------
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 scroll_gesture_handler_(NULL),
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 ViewTargeter(this)));
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);
182 // Tree operations -------------------------------------------------------------
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);
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();
201 View* RootView::GetContentsView() {
202 return child_count() > 0 ? child_at(0) : NULL;
205 void RootView::NotifyNativeViewHierarchyChanged() {
206 PropagateNativeViewHierarchyChanged();
209 // Focus -----------------------------------------------------------------------
211 void RootView::SetFocusTraversableParent(FocusTraversable* focus_traversable) {
212 DCHECK(focus_traversable != this);
213 focus_traversable_parent_ = focus_traversable;
216 void RootView::SetFocusTraversableParentView(View* view) {
217 focus_traversable_parent_view_ = view;
220 // System events ---------------------------------------------------------------
222 void RootView::ThemeChanged() {
223 View::PropagateThemeChanged();
226 void RootView::LocaleChanged() {
227 View::PropagateLocaleChanged();
230 ////////////////////////////////////////////////////////////////////////////////
231 // RootView, FocusTraversable implementation:
233 FocusSearch* RootView::GetFocusSearch() {
234 return &focus_search_;
237 FocusTraversable* RootView::GetFocusTraversableParent() {
238 return focus_traversable_parent_;
241 View* RootView::GetFocusTraversableParentView() {
242 return focus_traversable_parent_view_;
245 ////////////////////////////////////////////////////////////////////////////////
246 // RootView, ui::EventProcessor overrides:
248 ui::EventTarget* RootView::GetRootTarget() {
249 return this;
252 ui::EventDispatchDetails RootView::OnEventFromSource(ui::Event* event) {
253 // TODO(tdanderson): Replace the calls to Dispatch*Event() with calls to
254 // EventProcessor::OnEventFromSource() once the code for
255 // that event type has been refactored, and then
256 // eventually remove this function altogether. See
257 // crbug.com/348083.
258 if (event->IsKeyEvent())
259 return EventProcessor::OnEventFromSource(event);
260 else if (event->IsScrollEvent())
261 return EventProcessor::OnEventFromSource(event);
262 else if (event->IsTouchEvent())
263 NOTREACHED() << "Touch events should not be sent to RootView.";
264 else if (event->IsGestureEvent())
265 DispatchGestureEvent(event->AsGestureEvent());
266 else if (event->IsMouseEvent())
267 NOTREACHED() << "Should not be called with a MouseEvent.";
268 else
269 NOTREACHED() << "Invalid event type.";
271 return DispatchDetails();
274 ////////////////////////////////////////////////////////////////////////////////
275 // RootView, View overrides:
277 const Widget* RootView::GetWidget() const {
278 return widget_;
281 Widget* RootView::GetWidget() {
282 return const_cast<Widget*>(const_cast<const RootView*>(this)->GetWidget());
285 bool RootView::IsDrawn() const {
286 return visible();
289 void RootView::Layout() {
290 View::Layout();
291 widget_->OnRootViewLayout();
294 const char* RootView::GetClassName() const {
295 return kViewClassName;
298 void RootView::SchedulePaintInRect(const gfx::Rect& rect) {
299 if (layer()) {
300 layer()->SchedulePaint(rect);
301 } else {
302 gfx::Rect xrect = ConvertRectToParent(rect);
303 gfx::Rect invalid_rect = gfx::IntersectRects(GetLocalBounds(), xrect);
304 if (!invalid_rect.IsEmpty())
305 widget_->SchedulePaintInRect(invalid_rect);
309 bool RootView::OnMousePressed(const ui::MouseEvent& event) {
310 UpdateCursor(event);
311 SetMouseLocationAndFlags(event);
313 // If mouse_pressed_handler_ is non null, we are currently processing
314 // a pressed -> drag -> released session. In that case we send the
315 // event to mouse_pressed_handler_
316 if (mouse_pressed_handler_) {
317 ui::MouseEvent mouse_pressed_event(event, static_cast<View*>(this),
318 mouse_pressed_handler_);
319 drag_info_.Reset();
320 ui::EventDispatchDetails dispatch_details =
321 DispatchEvent(mouse_pressed_handler_, &mouse_pressed_event);
322 if (dispatch_details.dispatcher_destroyed)
323 return true;
324 return true;
326 DCHECK(!explicit_mouse_handler_);
328 bool hit_disabled_view = false;
329 // Walk up the tree until we find a view that wants the mouse event.
330 for (mouse_pressed_handler_ = GetEventHandlerForPoint(event.location());
331 mouse_pressed_handler_ && (mouse_pressed_handler_ != this);
332 mouse_pressed_handler_ = mouse_pressed_handler_->parent()) {
333 DVLOG(1) << "OnMousePressed testing "
334 << mouse_pressed_handler_->GetClassName();
335 if (!mouse_pressed_handler_->enabled()) {
336 // Disabled views should eat events instead of propagating them upwards.
337 hit_disabled_view = true;
338 break;
341 // See if this view wants to handle the mouse press.
342 ui::MouseEvent mouse_pressed_event(event, static_cast<View*>(this),
343 mouse_pressed_handler_);
345 // Remove the double-click flag if the handler is different than the
346 // one which got the first click part of the double-click.
347 if (mouse_pressed_handler_ != last_click_handler_)
348 mouse_pressed_event.set_flags(event.flags() & ~ui::EF_IS_DOUBLE_CLICK);
350 drag_info_.Reset();
351 ui::EventDispatchDetails dispatch_details =
352 DispatchEvent(mouse_pressed_handler_, &mouse_pressed_event);
353 if (dispatch_details.dispatcher_destroyed)
354 return mouse_pressed_event.handled();
356 // The view could have removed itself from the tree when handling
357 // OnMousePressed(). In this case, the removal notification will have
358 // reset mouse_pressed_handler_ to NULL out from under us. Detect this
359 // case and stop. (See comments in view.h.)
361 // NOTE: Don't return true here, because we don't want the frame to
362 // forward future events to us when there's no handler.
363 if (!mouse_pressed_handler_)
364 break;
366 // If the view handled the event, leave mouse_pressed_handler_ set and
367 // return true, which will cause subsequent drag/release events to get
368 // forwarded to that view.
369 if (mouse_pressed_event.handled()) {
370 last_click_handler_ = mouse_pressed_handler_;
371 DVLOG(1) << "OnMousePressed handled by "
372 << mouse_pressed_handler_->GetClassName();
373 return true;
377 // Reset mouse_pressed_handler_ to indicate that no processing is occurring.
378 mouse_pressed_handler_ = NULL;
380 // In the event that a double-click is not handled after traversing the
381 // entire hierarchy (even as a single-click when sent to a different view),
382 // it must be marked as handled to avoid anything happening from default
383 // processing if it the first click-part was handled by us.
384 if (last_click_handler_ && (event.flags() & ui::EF_IS_DOUBLE_CLICK))
385 hit_disabled_view = true;
387 last_click_handler_ = NULL;
388 return hit_disabled_view;
391 bool RootView::OnMouseDragged(const ui::MouseEvent& event) {
392 if (mouse_pressed_handler_) {
393 SetMouseLocationAndFlags(event);
395 ui::MouseEvent mouse_event(event, static_cast<View*>(this),
396 mouse_pressed_handler_);
397 ui::EventDispatchDetails dispatch_details =
398 DispatchEvent(mouse_pressed_handler_, &mouse_event);
399 if (dispatch_details.dispatcher_destroyed)
400 return false;
402 return false;
405 void RootView::OnMouseReleased(const ui::MouseEvent& event) {
406 UpdateCursor(event);
408 if (mouse_pressed_handler_) {
409 ui::MouseEvent mouse_released(event, static_cast<View*>(this),
410 mouse_pressed_handler_);
411 // We allow the view to delete us from the event dispatch callback. As such,
412 // configure state such that we're done first, then call View.
413 View* mouse_pressed_handler = mouse_pressed_handler_;
414 SetMouseHandler(NULL);
415 ui::EventDispatchDetails dispatch_details =
416 DispatchEvent(mouse_pressed_handler, &mouse_released);
417 if (dispatch_details.dispatcher_destroyed)
418 return;
422 void RootView::OnMouseCaptureLost() {
423 // TODO: this likely needs to reset touch handler too.
425 if (mouse_pressed_handler_ || gesture_handler_) {
426 // Synthesize a release event for UpdateCursor.
427 if (mouse_pressed_handler_) {
428 gfx::Point last_point(last_mouse_event_x_, last_mouse_event_y_);
429 ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED,
430 last_point, last_point,
431 last_mouse_event_flags_,
433 UpdateCursor(release_event);
435 // We allow the view to delete us from OnMouseCaptureLost. As such,
436 // configure state such that we're done first, then call View.
437 View* mouse_pressed_handler = mouse_pressed_handler_;
438 View* gesture_handler = gesture_handler_;
439 SetMouseHandler(NULL);
440 if (mouse_pressed_handler)
441 mouse_pressed_handler->OnMouseCaptureLost();
442 else
443 gesture_handler->OnMouseCaptureLost();
444 // WARNING: we may have been deleted.
448 void RootView::OnMouseMoved(const ui::MouseEvent& event) {
449 View* v = GetEventHandlerForPoint(event.location());
450 // Find the first enabled view, or the existing move handler, whichever comes
451 // first. The check for the existing handler is because if a view becomes
452 // disabled while handling moves, it's wrong to suddenly send ET_MOUSE_EXITED
453 // and ET_MOUSE_ENTERED events, because the mouse hasn't actually exited yet.
454 while (v && !v->enabled() && (v != mouse_move_handler_))
455 v = v->parent();
456 if (v && v != this) {
457 if (v != mouse_move_handler_) {
458 if (mouse_move_handler_ != NULL &&
459 (!mouse_move_handler_->notify_enter_exit_on_child() ||
460 !mouse_move_handler_->Contains(v))) {
461 MouseEnterExitEvent exit(event, ui::ET_MOUSE_EXITED);
462 exit.ConvertLocationToTarget(static_cast<View*>(this),
463 mouse_move_handler_);
464 ui::EventDispatchDetails dispatch_details =
465 DispatchEvent(mouse_move_handler_, &exit);
466 if (dispatch_details.dispatcher_destroyed)
467 return;
468 NotifyEnterExitOfDescendant(event, ui::ET_MOUSE_EXITED,
469 mouse_move_handler_, v);
471 View* old_handler = mouse_move_handler_;
472 mouse_move_handler_ = v;
473 if (!mouse_move_handler_->notify_enter_exit_on_child() ||
474 !mouse_move_handler_->Contains(old_handler)) {
475 MouseEnterExitEvent entered(event, ui::ET_MOUSE_ENTERED);
476 entered.ConvertLocationToTarget(static_cast<View*>(this),
477 mouse_move_handler_);
478 ui::EventDispatchDetails dispatch_details =
479 DispatchEvent(mouse_move_handler_, &entered);
480 if (dispatch_details.dispatcher_destroyed)
481 return;
482 NotifyEnterExitOfDescendant(event, ui::ET_MOUSE_ENTERED,
483 mouse_move_handler_, old_handler);
486 ui::MouseEvent moved_event(event, static_cast<View*>(this),
487 mouse_move_handler_);
488 mouse_move_handler_->OnMouseMoved(moved_event);
489 // TODO(tdanderson): It may be possible to avoid setting the cursor twice
490 // (once here and once from CompoundEventFilter) on a
491 // mousemove. See crbug.com/351469.
492 if (!(moved_event.flags() & ui::EF_IS_NON_CLIENT))
493 widget_->SetCursor(mouse_move_handler_->GetCursor(moved_event));
494 } else if (mouse_move_handler_ != NULL) {
495 MouseEnterExitEvent exited(event, ui::ET_MOUSE_EXITED);
496 ui::EventDispatchDetails dispatch_details =
497 DispatchEvent(mouse_move_handler_, &exited);
498 if (dispatch_details.dispatcher_destroyed)
499 return;
500 NotifyEnterExitOfDescendant(event, ui::ET_MOUSE_EXITED,
501 mouse_move_handler_, v);
502 // On Aura the non-client area extends slightly outside the root view for
503 // some windows. Let the non-client cursor handling code set the cursor
504 // as we do above.
505 if (!(event.flags() & ui::EF_IS_NON_CLIENT))
506 widget_->SetCursor(gfx::kNullCursor);
507 mouse_move_handler_ = NULL;
511 void RootView::OnMouseExited(const ui::MouseEvent& event) {
512 if (mouse_move_handler_ != NULL) {
513 MouseEnterExitEvent exited(event, ui::ET_MOUSE_EXITED);
514 ui::EventDispatchDetails dispatch_details =
515 DispatchEvent(mouse_move_handler_, &exited);
516 if (dispatch_details.dispatcher_destroyed)
517 return;
518 NotifyEnterExitOfDescendant(event, ui::ET_MOUSE_EXITED,
519 mouse_move_handler_, NULL);
520 mouse_move_handler_ = NULL;
524 bool RootView::OnMouseWheel(const ui::MouseWheelEvent& event) {
525 for (View* v = GetEventHandlerForPoint(event.location());
526 v && v != this && !event.handled(); v = v->parent()) {
527 ui::EventDispatchDetails dispatch_details =
528 DispatchEvent(v, const_cast<ui::MouseWheelEvent*>(&event));
529 if (dispatch_details.dispatcher_destroyed ||
530 dispatch_details.target_destroyed) {
531 return event.handled();
534 return event.handled();
537 void RootView::SetMouseHandler(View* new_mh) {
538 // If we're clearing the mouse handler, clear explicit_mouse_handler_ as well.
539 explicit_mouse_handler_ = (new_mh != NULL);
540 mouse_pressed_handler_ = new_mh;
541 gesture_handler_ = new_mh;
542 scroll_gesture_handler_ = new_mh;
543 drag_info_.Reset();
546 void RootView::GetAccessibleState(ui::AXViewState* state) {
547 state->name = widget_->widget_delegate()->GetAccessibleWindowTitle();
548 state->role = widget_->widget_delegate()->GetAccessibleWindowRole();
551 void RootView::UpdateParentLayer() {
552 if (layer())
553 ReparentLayer(gfx::Vector2d(GetMirroredX(), y()), widget_->GetLayer());
556 ////////////////////////////////////////////////////////////////////////////////
557 // RootView, protected:
559 void RootView::ViewHierarchyChanged(
560 const ViewHierarchyChangedDetails& details) {
561 widget_->ViewHierarchyChanged(details);
563 if (!details.is_add) {
564 if (!explicit_mouse_handler_ && mouse_pressed_handler_ == details.child)
565 mouse_pressed_handler_ = NULL;
566 if (mouse_move_handler_ == details.child)
567 mouse_move_handler_ = NULL;
568 if (gesture_handler_ == details.child)
569 gesture_handler_ = NULL;
570 if (scroll_gesture_handler_ == details.child)
571 scroll_gesture_handler_ = NULL;
572 if (event_dispatch_target_ == details.child)
573 event_dispatch_target_ = NULL;
574 if (old_dispatch_target_ == details.child)
575 old_dispatch_target_ = NULL;
579 void RootView::VisibilityChanged(View* /*starting_from*/, bool is_visible) {
580 if (!is_visible) {
581 // When the root view is being hidden (e.g. when widget is minimized)
582 // handlers are reset, so that after it is reshown, events are not captured
583 // by old handlers.
584 explicit_mouse_handler_ = false;
585 mouse_pressed_handler_ = NULL;
586 mouse_move_handler_ = NULL;
587 gesture_handler_ = NULL;
588 scroll_gesture_handler_ = NULL;
589 event_dispatch_target_ = NULL;
590 old_dispatch_target_ = NULL;
594 void RootView::OnPaint(gfx::Canvas* canvas) {
595 if (!layer() || !layer()->fills_bounds_opaquely())
596 canvas->DrawColor(SK_ColorBLACK, SkXfermode::kClear_Mode);
598 View::OnPaint(canvas);
601 gfx::Vector2d RootView::CalculateOffsetToAncestorWithLayer(
602 ui::Layer** layer_parent) {
603 gfx::Vector2d offset(View::CalculateOffsetToAncestorWithLayer(layer_parent));
604 if (!layer() && layer_parent)
605 *layer_parent = widget_->GetLayer();
606 return offset;
609 View::DragInfo* RootView::GetDragInfo() {
610 return &drag_info_;
613 ////////////////////////////////////////////////////////////////////////////////
614 // RootView, private:
616 // Input -----------------------------------------------------------------------
618 void RootView::DispatchGestureEvent(ui::GestureEvent* event) {
619 if (gesture_handler_) {
620 // |gesture_handler_| (or |scroll_gesture_handler_|) can be deleted during
621 // processing.
622 View* handler = scroll_gesture_handler_ &&
623 (event->IsScrollGestureEvent() || event->IsFlingScrollEvent()) ?
624 scroll_gesture_handler_ : gesture_handler_;
625 ui::GestureEvent handler_event(*event, static_cast<View*>(this), handler);
626 ui::EventDispatchDetails dispatch_details =
627 DispatchEvent(handler, &handler_event);
628 if (dispatch_details.dispatcher_destroyed)
629 return;
631 if (event->type() == ui::ET_GESTURE_END &&
632 event->details().touch_points() <= 1) {
633 // In case a drag was in progress, reset all the handlers. Otherwise, just
634 // reset the gesture handler.
635 if (gesture_handler_ == mouse_pressed_handler_)
636 SetMouseHandler(NULL);
637 else
638 gesture_handler_ = NULL;
641 if (scroll_gesture_handler_ &&
642 (event->type() == ui::ET_GESTURE_SCROLL_END ||
643 event->type() == ui::ET_SCROLL_FLING_START)) {
644 scroll_gesture_handler_ = NULL;
647 if (handler_event.stopped_propagation()) {
648 event->StopPropagation();
649 return;
650 } else if (handler_event.handled()) {
651 event->SetHandled();
652 return;
655 if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN &&
656 !scroll_gesture_handler_) {
657 // Some view started processing gesture events, however it does not
658 // process scroll-gesture events. In such case, we allow the event to
659 // bubble up, and install a different scroll-gesture handler different
660 // from the default gesture handler.
661 for (scroll_gesture_handler_ = gesture_handler_->parent();
662 scroll_gesture_handler_ && scroll_gesture_handler_ != this;
663 scroll_gesture_handler_ = scroll_gesture_handler_->parent()) {
664 ui::GestureEvent gesture_event(*event, static_cast<View*>(this),
665 scroll_gesture_handler_);
666 ui::EventDispatchDetails dispatch_details =
667 DispatchEvent(scroll_gesture_handler_, &gesture_event);
668 if (gesture_event.stopped_propagation()) {
669 event->StopPropagation();
670 return;
671 } else if (gesture_event.handled()) {
672 event->SetHandled();
673 return;
674 } else if (dispatch_details.dispatcher_destroyed ||
675 dispatch_details.target_destroyed) {
676 return;
679 scroll_gesture_handler_ = NULL;
682 return;
685 // If there was no handler for a SCROLL_BEGIN event, then subsequent scroll
686 // events are not dispatched to any views.
687 switch (event->type()) {
688 case ui::ET_GESTURE_SCROLL_UPDATE:
689 case ui::ET_GESTURE_SCROLL_END:
690 case ui::ET_SCROLL_FLING_START:
691 return;
692 default:
693 break;
696 View* gesture_handler = NULL;
697 if (views::switches::IsRectBasedTargetingEnabled() &&
698 !event->details().bounding_box().IsEmpty()) {
699 // TODO(tdanderson): Pass in the bounding box to GetEventHandlerForRect()
700 // once crbug.com/313392 is resolved.
701 gfx::Rect touch_rect(event->details().bounding_box());
702 touch_rect.set_origin(event->location());
703 touch_rect.Offset(-touch_rect.width() / 2, -touch_rect.height() / 2);
704 gesture_handler = GetEventHandlerForRect(touch_rect);
705 } else {
706 gesture_handler = GetEventHandlerForPoint(event->location());
709 // Walk up the tree until we find a view that wants the gesture event.
710 for (gesture_handler_ = gesture_handler;
711 gesture_handler_ && (gesture_handler_ != this);
712 gesture_handler_ = gesture_handler_->parent()) {
713 if (!gesture_handler_->enabled()) {
714 // Disabled views eat events but are treated as not handled.
715 return;
718 // See if this view wants to handle the Gesture.
719 ui::GestureEvent gesture_event(*event, static_cast<View*>(this),
720 gesture_handler_);
721 ui::EventDispatchDetails dispatch_details =
722 DispatchEvent(gesture_handler_, &gesture_event);
723 if (dispatch_details.dispatcher_destroyed)
724 return;
726 // The view could have removed itself from the tree when handling
727 // OnGestureEvent(). So handle as per OnMousePressed. NB: we
728 // assume that the RootView itself cannot be so removed.
729 if (!gesture_handler_)
730 return;
732 if (gesture_event.handled()) {
733 if (gesture_event.type() == ui::ET_GESTURE_SCROLL_BEGIN)
734 scroll_gesture_handler_ = gesture_handler_;
735 if (gesture_event.stopped_propagation())
736 event->StopPropagation();
737 else
738 event->SetHandled();
739 // Last ui::ET_GESTURE_END should not set the gesture_handler_.
740 if (gesture_event.type() == ui::ET_GESTURE_END &&
741 event->details().touch_points() <= 1) {
742 gesture_handler_ = NULL;
744 return;
747 // The gesture event wasn't processed. Go up the view hierarchy and
748 // dispatch the gesture event.
751 gesture_handler_ = NULL;
754 void RootView::UpdateCursor(const ui::MouseEvent& event) {
755 if (!(event.flags() & ui::EF_IS_NON_CLIENT)) {
756 View* v = GetEventHandlerForPoint(event.location());
757 ui::MouseEvent me(event, static_cast<View*>(this), v);
758 widget_->SetCursor(v->GetCursor(me));
762 void RootView::SetMouseLocationAndFlags(const ui::MouseEvent& event) {
763 last_mouse_event_flags_ = event.flags();
764 last_mouse_event_x_ = event.x();
765 last_mouse_event_y_ = event.y();
768 void RootView::NotifyEnterExitOfDescendant(const ui::MouseEvent& event,
769 ui::EventType type,
770 View* view,
771 View* sibling) {
772 for (View* p = view->parent(); p; p = p->parent()) {
773 if (!p->notify_enter_exit_on_child())
774 continue;
775 if (sibling && p->Contains(sibling))
776 break;
777 // It is necessary to recreate the notify-event for each dispatch, since one
778 // of the callbacks can mark the event as handled, and that would cause
779 // incorrect event dispatch.
780 MouseEnterExitEvent notify_event(event, type);
781 ui::EventDispatchDetails dispatch_details = DispatchEvent(p, &notify_event);
782 if (dispatch_details.dispatcher_destroyed ||
783 dispatch_details.target_destroyed) {
784 return;
789 bool RootView::CanDispatchToTarget(ui::EventTarget* target) {
790 return event_dispatch_target_ == target;
793 ui::EventDispatchDetails RootView::PreDispatchEvent(ui::EventTarget* target,
794 ui::Event* event) {
795 old_dispatch_target_ = event_dispatch_target_;
796 event_dispatch_target_ = static_cast<View*>(target);
797 return DispatchDetails();
800 ui::EventDispatchDetails RootView::PostDispatchEvent(ui::EventTarget* target,
801 const ui::Event& event) {
802 DispatchDetails details;
803 if (target != event_dispatch_target_)
804 details.target_destroyed = true;
806 event_dispatch_target_ = old_dispatch_target_;
807 old_dispatch_target_ = NULL;
809 #ifndef NDEBUG
810 DCHECK(!event_dispatch_target_ || Contains(event_dispatch_target_));
811 #endif
813 return details;
816 } // namespace internal
817 } // namespace views