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