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"
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/compositor/layer.h"
15 #include "ui/events/event.h"
16 #include "ui/events/keycodes/keyboard_codes.h"
17 #include "ui/gfx/canvas.h"
18 #include "ui/views/focus/view_storage.h"
19 #include "ui/views/layout/fill_layout.h"
20 #include "ui/views/views_switches.h"
21 #include "ui/views/widget/widget.h"
22 #include "ui/views/widget/widget_delegate.h"
24 typedef ui::EventDispatchDetails DispatchDetails
;
36 class MouseEnterExitEvent
: public ui::MouseEvent
{
38 MouseEnterExitEvent(const ui::MouseEvent
& event
, ui::EventType type
)
39 : ui::MouseEvent(event
,
40 static_cast<View
*>(NULL
),
41 static_cast<View
*>(NULL
)) {
42 DCHECK(type
== ui::ET_MOUSE_ENTERED
||
43 type
== ui::ET_MOUSE_EXITED
);
47 virtual ~MouseEnterExitEvent() {}
53 const char RootView::kViewClassName
[] = "RootView";
55 ////////////////////////////////////////////////////////////////////////////////
58 // Creation and lifetime -------------------------------------------------------
60 RootView::RootView(Widget
* widget
)
62 mouse_pressed_handler_(NULL
),
63 mouse_move_handler_(NULL
),
64 last_click_handler_(NULL
),
65 explicit_mouse_handler_(false),
66 last_mouse_event_flags_(0),
67 last_mouse_event_x_(-1),
68 last_mouse_event_y_(-1),
69 touch_pressed_handler_(NULL
),
70 gesture_handler_(NULL
),
71 scroll_gesture_handler_(NULL
),
72 focus_search_(this, false, false),
73 focus_traversable_parent_(NULL
),
74 focus_traversable_parent_view_(NULL
),
75 event_dispatch_target_(NULL
),
76 old_dispatch_target_(NULL
) {
79 RootView::~RootView() {
80 // If we have children remove them explicitly so to make sure a remove
81 // notification is sent for each one of them.
83 RemoveAllChildViews(true);
86 // Tree operations -------------------------------------------------------------
88 void RootView::SetContentsView(View
* contents_view
) {
89 DCHECK(contents_view
&& GetWidget()->native_widget()) <<
90 "Can't be called until after the native widget is created!";
91 // The ContentsView must be set up _after_ the window is created so that its
92 // Widget pointer is valid.
93 SetLayoutManager(new FillLayout
);
95 RemoveAllChildViews(true);
96 AddChildView(contents_view
);
98 // Force a layout now, since the attached hierarchy won't be ready for the
99 // containing window's bounds. Note that we call Layout directly rather than
100 // calling the widget's size changed handler, since the RootView's bounds may
101 // not have changed, which will cause the Layout not to be done otherwise.
105 View
* RootView::GetContentsView() {
106 return child_count() > 0 ? child_at(0) : NULL
;
109 void RootView::NotifyNativeViewHierarchyChanged() {
110 PropagateNativeViewHierarchyChanged();
113 // Focus -----------------------------------------------------------------------
115 void RootView::SetFocusTraversableParent(FocusTraversable
* focus_traversable
) {
116 DCHECK(focus_traversable
!= this);
117 focus_traversable_parent_
= focus_traversable
;
120 void RootView::SetFocusTraversableParentView(View
* view
) {
121 focus_traversable_parent_view_
= view
;
124 // System events ---------------------------------------------------------------
126 void RootView::ThemeChanged() {
127 View::PropagateThemeChanged();
130 void RootView::LocaleChanged() {
131 View::PropagateLocaleChanged();
134 ////////////////////////////////////////////////////////////////////////////////
135 // RootView, FocusTraversable implementation:
137 FocusSearch
* RootView::GetFocusSearch() {
138 return &focus_search_
;
141 FocusTraversable
* RootView::GetFocusTraversableParent() {
142 return focus_traversable_parent_
;
145 View
* RootView::GetFocusTraversableParentView() {
146 return focus_traversable_parent_view_
;
149 ////////////////////////////////////////////////////////////////////////////////
150 // RootView, ui::EventProcessor overrides:
152 ui::EventTarget
* RootView::GetRootTarget() {
156 ui::EventDispatchDetails
RootView::OnEventFromSource(ui::Event
* event
) {
157 // TODO(tdanderson): Replace the calls to Dispatch*Event() with calls to
158 // EventProcessor::OnEventFromSource() once the code for
159 // that event type has been refactored, and then
160 // eventually remove this function altogether. See
162 if (event
->IsKeyEvent())
163 DispatchKeyEvent(static_cast<ui::KeyEvent
*>(event
));
164 else if (event
->IsScrollEvent())
165 DispatchScrollEvent(static_cast<ui::ScrollEvent
*>(event
));
166 else if (event
->IsTouchEvent())
167 DispatchTouchEvent(static_cast<ui::TouchEvent
*>(event
));
168 else if (event
->IsGestureEvent())
169 DispatchGestureEvent(static_cast<ui::GestureEvent
*>(event
));
170 else if (event
->IsMouseEvent())
171 NOTREACHED() << "Should not be called with a MouseEvent.";
173 NOTREACHED() << "Invalid event type.";
175 return DispatchDetails();
178 ////////////////////////////////////////////////////////////////////////////////
179 // RootView, View overrides:
181 const Widget
* RootView::GetWidget() const {
185 Widget
* RootView::GetWidget() {
186 return const_cast<Widget
*>(const_cast<const RootView
*>(this)->GetWidget());
189 bool RootView::IsDrawn() const {
193 void RootView::Layout() {
195 widget_
->OnRootViewLayout();
198 const char* RootView::GetClassName() const {
199 return kViewClassName
;
202 void RootView::SchedulePaintInRect(const gfx::Rect
& rect
) {
204 layer()->SchedulePaint(rect
);
206 gfx::Rect xrect
= ConvertRectToParent(rect
);
207 gfx::Rect invalid_rect
= gfx::IntersectRects(GetLocalBounds(), xrect
);
208 if (!invalid_rect
.IsEmpty())
209 widget_
->SchedulePaintInRect(invalid_rect
);
213 bool RootView::OnMousePressed(const ui::MouseEvent
& event
) {
215 SetMouseLocationAndFlags(event
);
217 // If mouse_pressed_handler_ is non null, we are currently processing
218 // a pressed -> drag -> released session. In that case we send the
219 // event to mouse_pressed_handler_
220 if (mouse_pressed_handler_
) {
221 ui::MouseEvent
mouse_pressed_event(event
, static_cast<View
*>(this),
222 mouse_pressed_handler_
);
224 ui::EventDispatchDetails dispatch_details
=
225 DispatchEvent(mouse_pressed_handler_
, &mouse_pressed_event
);
226 if (dispatch_details
.dispatcher_destroyed
)
230 DCHECK(!explicit_mouse_handler_
);
232 bool hit_disabled_view
= false;
233 // Walk up the tree until we find a view that wants the mouse event.
234 for (mouse_pressed_handler_
= GetEventHandlerForPoint(event
.location());
235 mouse_pressed_handler_
&& (mouse_pressed_handler_
!= this);
236 mouse_pressed_handler_
= mouse_pressed_handler_
->parent()) {
237 DVLOG(1) << "OnMousePressed testing "
238 << mouse_pressed_handler_
->GetClassName();
239 if (!mouse_pressed_handler_
->enabled()) {
240 // Disabled views should eat events instead of propagating them upwards.
241 hit_disabled_view
= true;
245 // See if this view wants to handle the mouse press.
246 ui::MouseEvent
mouse_pressed_event(event
, static_cast<View
*>(this),
247 mouse_pressed_handler_
);
249 // Remove the double-click flag if the handler is different than the
250 // one which got the first click part of the double-click.
251 if (mouse_pressed_handler_
!= last_click_handler_
)
252 mouse_pressed_event
.set_flags(event
.flags() & ~ui::EF_IS_DOUBLE_CLICK
);
255 ui::EventDispatchDetails dispatch_details
=
256 DispatchEvent(mouse_pressed_handler_
, &mouse_pressed_event
);
257 if (dispatch_details
.dispatcher_destroyed
)
258 return mouse_pressed_event
.handled();
260 // The view could have removed itself from the tree when handling
261 // OnMousePressed(). In this case, the removal notification will have
262 // reset mouse_pressed_handler_ to NULL out from under us. Detect this
263 // case and stop. (See comments in view.h.)
265 // NOTE: Don't return true here, because we don't want the frame to
266 // forward future events to us when there's no handler.
267 if (!mouse_pressed_handler_
)
270 // If the view handled the event, leave mouse_pressed_handler_ set and
271 // return true, which will cause subsequent drag/release events to get
272 // forwarded to that view.
273 if (mouse_pressed_event
.handled()) {
274 last_click_handler_
= mouse_pressed_handler_
;
275 DVLOG(1) << "OnMousePressed handled by "
276 << mouse_pressed_handler_
->GetClassName();
281 // Reset mouse_pressed_handler_ to indicate that no processing is occurring.
282 mouse_pressed_handler_
= NULL
;
284 // In the event that a double-click is not handled after traversing the
285 // entire hierarchy (even as a single-click when sent to a different view),
286 // it must be marked as handled to avoid anything happening from default
287 // processing if it the first click-part was handled by us.
288 if (last_click_handler_
&& (event
.flags() & ui::EF_IS_DOUBLE_CLICK
))
289 hit_disabled_view
= true;
291 last_click_handler_
= NULL
;
292 return hit_disabled_view
;
295 bool RootView::OnMouseDragged(const ui::MouseEvent
& event
) {
296 if (mouse_pressed_handler_
) {
297 SetMouseLocationAndFlags(event
);
299 ui::MouseEvent
mouse_event(event
, static_cast<View
*>(this),
300 mouse_pressed_handler_
);
301 ui::EventDispatchDetails dispatch_details
=
302 DispatchEvent(mouse_pressed_handler_
, &mouse_event
);
303 if (dispatch_details
.dispatcher_destroyed
)
309 void RootView::OnMouseReleased(const ui::MouseEvent
& event
) {
312 if (mouse_pressed_handler_
) {
313 ui::MouseEvent
mouse_released(event
, static_cast<View
*>(this),
314 mouse_pressed_handler_
);
315 // We allow the view to delete us from the event dispatch callback. As such,
316 // configure state such that we're done first, then call View.
317 View
* mouse_pressed_handler
= mouse_pressed_handler_
;
318 SetMouseHandler(NULL
);
319 ui::EventDispatchDetails dispatch_details
=
320 DispatchEvent(mouse_pressed_handler
, &mouse_released
);
321 if (dispatch_details
.dispatcher_destroyed
)
326 void RootView::OnMouseCaptureLost() {
327 // TODO: this likely needs to reset touch handler too.
329 if (mouse_pressed_handler_
|| gesture_handler_
) {
330 // Synthesize a release event for UpdateCursor.
331 if (mouse_pressed_handler_
) {
332 gfx::Point
last_point(last_mouse_event_x_
, last_mouse_event_y_
);
333 ui::MouseEvent
release_event(ui::ET_MOUSE_RELEASED
,
334 last_point
, last_point
,
335 last_mouse_event_flags_
,
337 UpdateCursor(release_event
);
339 // We allow the view to delete us from OnMouseCaptureLost. As such,
340 // configure state such that we're done first, then call View.
341 View
* mouse_pressed_handler
= mouse_pressed_handler_
;
342 View
* gesture_handler
= gesture_handler_
;
343 SetMouseHandler(NULL
);
344 if (mouse_pressed_handler
)
345 mouse_pressed_handler
->OnMouseCaptureLost();
347 gesture_handler
->OnMouseCaptureLost();
348 // WARNING: we may have been deleted.
352 void RootView::OnMouseMoved(const ui::MouseEvent
& event
) {
353 View
* v
= GetEventHandlerForPoint(event
.location());
354 // Find the first enabled view, or the existing move handler, whichever comes
355 // first. The check for the existing handler is because if a view becomes
356 // disabled while handling moves, it's wrong to suddenly send ET_MOUSE_EXITED
357 // and ET_MOUSE_ENTERED events, because the mouse hasn't actually exited yet.
358 while (v
&& !v
->enabled() && (v
!= mouse_move_handler_
))
360 if (v
&& v
!= this) {
361 if (v
!= mouse_move_handler_
) {
362 if (mouse_move_handler_
!= NULL
&&
363 (!mouse_move_handler_
->notify_enter_exit_on_child() ||
364 !mouse_move_handler_
->Contains(v
))) {
365 MouseEnterExitEvent
exit(event
, ui::ET_MOUSE_EXITED
);
366 ui::EventDispatchDetails dispatch_details
=
367 DispatchEvent(mouse_move_handler_
, &exit
);
368 if (dispatch_details
.dispatcher_destroyed
)
370 NotifyEnterExitOfDescendant(event
, ui::ET_MOUSE_EXITED
,
371 mouse_move_handler_
, v
);
373 View
* old_handler
= mouse_move_handler_
;
374 mouse_move_handler_
= v
;
375 if (!mouse_move_handler_
->notify_enter_exit_on_child() ||
376 !mouse_move_handler_
->Contains(old_handler
)) {
377 MouseEnterExitEvent
entered(event
, ui::ET_MOUSE_ENTERED
);
378 entered
.ConvertLocationToTarget(static_cast<View
*>(this),
379 mouse_move_handler_
);
380 ui::EventDispatchDetails dispatch_details
=
381 DispatchEvent(mouse_move_handler_
, &entered
);
382 if (dispatch_details
.dispatcher_destroyed
)
384 NotifyEnterExitOfDescendant(entered
, ui::ET_MOUSE_ENTERED
, v
,
388 ui::MouseEvent
moved_event(event
, static_cast<View
*>(this),
389 mouse_move_handler_
);
390 mouse_move_handler_
->OnMouseMoved(moved_event
);
391 // TODO(tdanderson): It may be possible to avoid setting the cursor twice
392 // (once here and once from CompoundEventFilter) on a
393 // mousemove. See crbug.com/351469.
394 if (!(moved_event
.flags() & ui::EF_IS_NON_CLIENT
))
395 widget_
->SetCursor(mouse_move_handler_
->GetCursor(moved_event
));
396 } else if (mouse_move_handler_
!= NULL
) {
397 MouseEnterExitEvent
exited(event
, ui::ET_MOUSE_EXITED
);
398 ui::EventDispatchDetails dispatch_details
=
399 DispatchEvent(mouse_move_handler_
, &exited
);
400 if (dispatch_details
.dispatcher_destroyed
)
402 NotifyEnterExitOfDescendant(event
, ui::ET_MOUSE_EXITED
,
403 mouse_move_handler_
, v
);
404 // On Aura the non-client area extends slightly outside the root view for
405 // some windows. Let the non-client cursor handling code set the cursor
407 if (!(event
.flags() & ui::EF_IS_NON_CLIENT
))
408 widget_
->SetCursor(gfx::kNullCursor
);
409 mouse_move_handler_
= NULL
;
413 void RootView::OnMouseExited(const ui::MouseEvent
& event
) {
414 if (mouse_move_handler_
!= NULL
) {
415 MouseEnterExitEvent
exited(event
, ui::ET_MOUSE_EXITED
);
416 ui::EventDispatchDetails dispatch_details
=
417 DispatchEvent(mouse_move_handler_
, &exited
);
418 if (dispatch_details
.dispatcher_destroyed
)
420 NotifyEnterExitOfDescendant(event
, ui::ET_MOUSE_EXITED
,
421 mouse_move_handler_
, NULL
);
422 mouse_move_handler_
= NULL
;
426 bool RootView::OnMouseWheel(const ui::MouseWheelEvent
& event
) {
427 for (View
* v
= GetEventHandlerForPoint(event
.location());
428 v
&& v
!= this && !event
.handled(); v
= v
->parent()) {
429 ui::EventDispatchDetails dispatch_details
=
430 DispatchEvent(v
, const_cast<ui::MouseWheelEvent
*>(&event
));
431 if (dispatch_details
.dispatcher_destroyed
||
432 dispatch_details
.target_destroyed
) {
433 return event
.handled();
436 return event
.handled();
439 void RootView::SetMouseHandler(View
* new_mh
) {
440 // If we're clearing the mouse handler, clear explicit_mouse_handler_ as well.
441 explicit_mouse_handler_
= (new_mh
!= NULL
);
442 mouse_pressed_handler_
= new_mh
;
443 gesture_handler_
= new_mh
;
444 scroll_gesture_handler_
= new_mh
;
448 void RootView::GetAccessibleState(ui::AXViewState
* state
) {
449 state
->name
= widget_
->widget_delegate()->GetAccessibleWindowTitle();
450 state
->role
= widget_
->widget_delegate()->GetAccessibleWindowRole();
453 void RootView::UpdateParentLayer() {
455 ReparentLayer(gfx::Vector2d(GetMirroredX(), y()), widget_
->GetLayer());
458 ////////////////////////////////////////////////////////////////////////////////
459 // RootView, protected:
461 void RootView::DispatchGestureEvent(ui::GestureEvent
* event
) {
462 if (gesture_handler_
) {
463 // |gesture_handler_| (or |scroll_gesture_handler_|) can be deleted during
465 View
* handler
= scroll_gesture_handler_
&&
466 (event
->IsScrollGestureEvent() || event
->IsFlingScrollEvent()) ?
467 scroll_gesture_handler_
: gesture_handler_
;
468 ui::GestureEvent
handler_event(*event
, static_cast<View
*>(this), handler
);
469 ui::EventDispatchDetails dispatch_details
=
470 DispatchEvent(handler
, &handler_event
);
471 if (dispatch_details
.dispatcher_destroyed
)
474 if (event
->type() == ui::ET_GESTURE_END
&&
475 event
->details().touch_points() <= 1) {
476 // In case a drag was in progress, reset all the handlers. Otherwise, just
477 // reset the gesture handler.
478 if (gesture_handler_
== mouse_pressed_handler_
)
479 SetMouseHandler(NULL
);
481 gesture_handler_
= NULL
;
484 if (scroll_gesture_handler_
&&
485 (event
->type() == ui::ET_GESTURE_SCROLL_END
||
486 event
->type() == ui::ET_SCROLL_FLING_START
)) {
487 scroll_gesture_handler_
= NULL
;
490 if (handler_event
.stopped_propagation()) {
491 event
->StopPropagation();
493 } else if (handler_event
.handled()) {
498 if (event
->type() == ui::ET_GESTURE_SCROLL_BEGIN
&&
499 !scroll_gesture_handler_
) {
500 // Some view started processing gesture events, however it does not
501 // process scroll-gesture events. In such case, we allow the event to
502 // bubble up, and install a different scroll-gesture handler different
503 // from the default gesture handler.
504 for (scroll_gesture_handler_
= gesture_handler_
->parent();
505 scroll_gesture_handler_
&& scroll_gesture_handler_
!= this;
506 scroll_gesture_handler_
= scroll_gesture_handler_
->parent()) {
507 ui::GestureEvent
gesture_event(*event
, static_cast<View
*>(this),
508 scroll_gesture_handler_
);
509 ui::EventDispatchDetails dispatch_details
=
510 DispatchEvent(scroll_gesture_handler_
, &gesture_event
);
511 if (gesture_event
.stopped_propagation()) {
512 event
->StopPropagation();
514 } else if (gesture_event
.handled()) {
517 } else if (dispatch_details
.dispatcher_destroyed
||
518 dispatch_details
.target_destroyed
) {
522 scroll_gesture_handler_
= NULL
;
528 // If there was no handler for a SCROLL_BEGIN event, then subsequent scroll
529 // events are not dispatched to any views.
530 switch (event
->type()) {
531 case ui::ET_GESTURE_SCROLL_UPDATE
:
532 case ui::ET_GESTURE_SCROLL_END
:
533 case ui::ET_SCROLL_FLING_START
:
539 View
* gesture_handler
= NULL
;
540 if (views::switches::IsRectBasedTargetingEnabled() &&
541 !event
->details().bounding_box().IsEmpty()) {
542 // TODO(tdanderson): Pass in the bounding box to GetEventHandlerForRect()
543 // once crbug.com/313392 is resolved.
544 gfx::Rect
touch_rect(event
->details().bounding_box());
545 touch_rect
.set_origin(event
->location());
546 touch_rect
.Offset(-touch_rect
.width() / 2, -touch_rect
.height() / 2);
547 gesture_handler
= GetEventHandlerForRect(touch_rect
);
549 gesture_handler
= GetEventHandlerForPoint(event
->location());
552 // Walk up the tree until we find a view that wants the gesture event.
553 for (gesture_handler_
= gesture_handler
;
554 gesture_handler_
&& (gesture_handler_
!= this);
555 gesture_handler_
= gesture_handler_
->parent()) {
556 if (!gesture_handler_
->enabled()) {
557 // Disabled views eat events but are treated as not handled.
561 // See if this view wants to handle the Gesture.
562 ui::GestureEvent
gesture_event(*event
, static_cast<View
*>(this),
564 ui::EventDispatchDetails dispatch_details
=
565 DispatchEvent(gesture_handler_
, &gesture_event
);
566 if (dispatch_details
.dispatcher_destroyed
)
569 // The view could have removed itself from the tree when handling
570 // OnGestureEvent(). So handle as per OnMousePressed. NB: we
571 // assume that the RootView itself cannot be so removed.
572 if (!gesture_handler_
)
575 if (gesture_event
.handled()) {
576 if (gesture_event
.type() == ui::ET_GESTURE_SCROLL_BEGIN
)
577 scroll_gesture_handler_
= gesture_handler_
;
578 if (gesture_event
.stopped_propagation())
579 event
->StopPropagation();
582 // Last ui::ET_GESTURE_END should not set the gesture_handler_.
583 if (gesture_event
.type() == ui::ET_GESTURE_END
&&
584 event
->details().touch_points() <= 1) {
585 gesture_handler_
= NULL
;
590 // The gesture event wasn't processed. Go up the view hierarchy and
591 // dispatch the gesture event.
594 gesture_handler_
= NULL
;
597 void RootView::ViewHierarchyChanged(
598 const ViewHierarchyChangedDetails
& details
) {
599 widget_
->ViewHierarchyChanged(details
);
601 if (!details
.is_add
) {
602 if (!explicit_mouse_handler_
&& mouse_pressed_handler_
== details
.child
)
603 mouse_pressed_handler_
= NULL
;
604 if (mouse_move_handler_
== details
.child
)
605 mouse_move_handler_
= NULL
;
606 if (touch_pressed_handler_
== details
.child
)
607 touch_pressed_handler_
= NULL
;
608 if (gesture_handler_
== details
.child
)
609 gesture_handler_
= NULL
;
610 if (scroll_gesture_handler_
== details
.child
)
611 scroll_gesture_handler_
= NULL
;
612 if (event_dispatch_target_
== details
.child
)
613 event_dispatch_target_
= NULL
;
614 if (old_dispatch_target_
== details
.child
)
615 old_dispatch_target_
= NULL
;
619 void RootView::VisibilityChanged(View
* /*starting_from*/, bool is_visible
) {
621 // When the root view is being hidden (e.g. when widget is minimized)
622 // handlers are reset, so that after it is reshown, events are not captured
624 explicit_mouse_handler_
= false;
625 mouse_pressed_handler_
= NULL
;
626 mouse_move_handler_
= NULL
;
627 touch_pressed_handler_
= NULL
;
628 gesture_handler_
= NULL
;
629 scroll_gesture_handler_
= NULL
;
630 event_dispatch_target_
= NULL
;
631 old_dispatch_target_
= NULL
;
635 void RootView::OnPaint(gfx::Canvas
* canvas
) {
636 if (!layer() || !layer()->fills_bounds_opaquely())
637 canvas
->DrawColor(SK_ColorBLACK
, SkXfermode::kClear_Mode
);
639 View::OnPaint(canvas
);
642 gfx::Vector2d
RootView::CalculateOffsetToAncestorWithLayer(
643 ui::Layer
** layer_parent
) {
644 gfx::Vector2d
offset(View::CalculateOffsetToAncestorWithLayer(layer_parent
));
645 if (!layer() && layer_parent
)
646 *layer_parent
= widget_
->GetLayer();
650 View::DragInfo
* RootView::GetDragInfo() {
654 ////////////////////////////////////////////////////////////////////////////////
655 // RootView, private:
657 // Input -----------------------------------------------------------------------
659 void RootView::DispatchKeyEvent(ui::KeyEvent
* event
) {
661 if (GetFocusManager()) // NULL in unittests.
662 v
= GetFocusManager()->GetFocusedView();
663 // Special case to handle keyboard-triggered context menus.
664 if (v
&& v
->enabled() && ((event
->key_code() == ui::VKEY_APPS
) ||
665 (event
->key_code() == ui::VKEY_F10
&& event
->IsShiftDown()))) {
666 // Clamp the menu location within the visible bounds of each ancestor view
667 // to avoid showing the menu over a completely different view or window.
668 gfx::Point location
= v
->GetKeyboardContextMenuLocation();
669 for (View
* parent
= v
->parent(); parent
; parent
= parent
->parent()) {
670 const gfx::Rect
& parent_bounds
= parent
->GetBoundsInScreen();
671 location
.SetToMax(parent_bounds
.origin());
672 location
.SetToMin(parent_bounds
.bottom_right());
674 v
->ShowContextMenu(location
, ui::MENU_SOURCE_KEYBOARD
);
675 event
->StopPropagation();
679 DispatchKeyEventStartAt(v
, event
);
682 void RootView::DispatchScrollEvent(ui::ScrollEvent
* event
) {
683 for (View
* v
= GetEventHandlerForPoint(event
->location());
684 v
&& v
!= this && !event
->stopped_propagation(); v
= v
->parent()) {
685 ui::EventDispatchDetails dispatch_details
= DispatchEvent(v
, event
);
686 if (dispatch_details
.dispatcher_destroyed
||
687 dispatch_details
.target_destroyed
) {
692 if (event
->handled() || event
->type() != ui::ET_SCROLL
)
695 // Convert unprocessed scroll events into mouse-wheel events.
696 ui::MouseWheelEvent
wheel(*event
);
697 if (OnMouseWheel(wheel
))
701 void RootView::DispatchTouchEvent(ui::TouchEvent
* event
) {
702 // TODO: this looks all wrong. On a TOUCH_PRESSED we should figure out the
703 // view and target that view with all touches with the same id until the
704 // release (or keep it if captured).
706 // If touch_pressed_handler_ is non null, we are currently processing
707 // a touch down on the screen situation. In that case we send the
708 // event to touch_pressed_handler_
710 if (touch_pressed_handler_
) {
711 ui::TouchEvent
touch_event(*event
, static_cast<View
*>(this),
712 touch_pressed_handler_
);
713 ui::EventDispatchDetails dispatch_details
=
714 DispatchEvent(touch_pressed_handler_
, &touch_event
);
715 if (touch_event
.handled())
717 if (touch_event
.stopped_propagation())
718 event
->StopPropagation();
719 if (dispatch_details
.dispatcher_destroyed
)
724 // Walk up the tree until we find a view that wants the touch event.
725 for (touch_pressed_handler_
= GetEventHandlerForPoint(event
->location());
726 touch_pressed_handler_
&& (touch_pressed_handler_
!= this);
727 touch_pressed_handler_
= touch_pressed_handler_
->parent()) {
728 if (!touch_pressed_handler_
->enabled()) {
729 // Disabled views eat events but are treated as not handled.
733 // See if this view wants to handle the touch
734 ui::TouchEvent
touch_event(*event
, static_cast<View
*>(this),
735 touch_pressed_handler_
);
736 ui::EventDispatchDetails dispatch_details
=
737 DispatchEvent(touch_pressed_handler_
, &touch_event
);
738 if (touch_event
.handled())
740 if (touch_event
.stopped_propagation())
741 event
->StopPropagation();
742 if (dispatch_details
.dispatcher_destroyed
)
745 // The view could have removed itself from the tree when handling
746 // OnTouchEvent(). So handle as per OnMousePressed. NB: we
747 // assume that the RootView itself cannot be so removed.
748 if (!touch_pressed_handler_
)
751 // The touch event wasn't processed. Go up the view hierarchy and dispatch
753 if (!event
->handled())
756 // If a View consumed the event, that means future touch-events should go to
757 // that View. If the event wasn't consumed, then reset the handler.
758 if (!event
->stopped_propagation())
759 touch_pressed_handler_
= NULL
;
764 // Reset touch_pressed_handler_ to indicate that no processing is occurring.
765 touch_pressed_handler_
= NULL
;
770 void RootView::UpdateCursor(const ui::MouseEvent
& event
) {
771 if (!(event
.flags() & ui::EF_IS_NON_CLIENT
)) {
772 View
* v
= GetEventHandlerForPoint(event
.location());
773 ui::MouseEvent
me(event
, static_cast<View
*>(this), v
);
774 widget_
->SetCursor(v
->GetCursor(me
));
778 void RootView::SetMouseLocationAndFlags(const ui::MouseEvent
& event
) {
779 last_mouse_event_flags_
= event
.flags();
780 last_mouse_event_x_
= event
.x();
781 last_mouse_event_y_
= event
.y();
784 void RootView::NotifyEnterExitOfDescendant(const ui::MouseEvent
& event
,
788 for (View
* p
= view
->parent(); p
; p
= p
->parent()) {
789 if (!p
->notify_enter_exit_on_child())
791 if (sibling
&& p
->Contains(sibling
))
793 // It is necessary to recreate the notify-event for each dispatch, since one
794 // of the callbacks can mark the event as handled, and that would cause
795 // incorrect event dispatch.
796 MouseEnterExitEvent
notify_event(event
, type
);
797 ui::EventDispatchDetails dispatch_details
= DispatchEvent(p
, ¬ify_event
);
798 if (dispatch_details
.dispatcher_destroyed
||
799 dispatch_details
.target_destroyed
) {
805 void RootView::DispatchKeyEventStartAt(View
* view
, ui::KeyEvent
* event
) {
806 for (; view
&& view
!= this && !event
->handled(); view
= view
->parent()) {
807 ui::EventDispatchDetails dispatch_details
= DispatchEvent(view
, event
);
808 if (dispatch_details
.dispatcher_destroyed
||
809 dispatch_details
.target_destroyed
) {
815 bool RootView::CanDispatchToTarget(ui::EventTarget
* target
) {
816 return event_dispatch_target_
== target
;
819 ui::EventDispatchDetails
RootView::PreDispatchEvent(ui::EventTarget
* target
,
821 old_dispatch_target_
= event_dispatch_target_
;
822 event_dispatch_target_
= static_cast<View
*>(target
);
823 return DispatchDetails();
826 ui::EventDispatchDetails
RootView::PostDispatchEvent(ui::EventTarget
* target
,
827 const ui::Event
& event
) {
828 DispatchDetails details
;
829 if (target
!= event_dispatch_target_
)
830 details
.target_destroyed
= true;
832 event_dispatch_target_
= old_dispatch_target_
;
833 old_dispatch_target_
= NULL
;
836 DCHECK(!event_dispatch_target_
|| Contains(event_dispatch_target_
));
842 } // namespace internal