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