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/aura/root_window.h"
10 #include "base/command_line.h"
11 #include "base/debug/trace_event.h"
12 #include "base/logging.h"
13 #include "base/message_loop/message_loop.h"
14 #include "ui/aura/client/capture_client.h"
15 #include "ui/aura/client/cursor_client.h"
16 #include "ui/aura/client/event_client.h"
17 #include "ui/aura/client/focus_client.h"
18 #include "ui/aura/client/screen_position_client.h"
19 #include "ui/aura/env.h"
20 #include "ui/aura/root_window_observer.h"
21 #include "ui/aura/root_window_transformer.h"
22 #include "ui/aura/window.h"
23 #include "ui/aura/window_delegate.h"
24 #include "ui/aura/window_tracker.h"
25 #include "ui/aura/window_tree_host.h"
26 #include "ui/base/hit_test.h"
27 #include "ui/base/view_prop.h"
28 #include "ui/compositor/dip_util.h"
29 #include "ui/compositor/layer.h"
30 #include "ui/compositor/layer_animator.h"
31 #include "ui/events/event.h"
32 #include "ui/events/gestures/gesture_recognizer.h"
33 #include "ui/events/gestures/gesture_types.h"
34 #include "ui/gfx/display.h"
35 #include "ui/gfx/point3_f.h"
36 #include "ui/gfx/point_conversions.h"
37 #include "ui/gfx/screen.h"
38 #include "ui/gfx/size_conversions.h"
42 typedef ui::EventDispatchDetails DispatchDetails
;
48 const char kRootWindowForAcceleratedWidget
[] =
49 "__AURA_ROOT_WINDOW_ACCELERATED_WIDGET__";
51 // Returns true if |target| has a non-client (frame) component at |location|,
52 // in window coordinates.
53 bool IsNonClientLocation(Window
* target
, const gfx::Point
& location
) {
54 if (!target
->delegate())
56 int hit_test_code
= target
->delegate()->GetNonClientComponent(location
);
57 return hit_test_code
!= HTCLIENT
&& hit_test_code
!= HTNOWHERE
;
60 float GetDeviceScaleFactorFromDisplay(Window
* window
) {
61 gfx::Display display
= gfx::Screen::GetScreenFor(window
)->
62 GetDisplayNearestWindow(window
);
63 DCHECK(display
.is_valid());
64 return display
.device_scale_factor();
67 Window
* ConsumerToWindow(ui::GestureConsumer
* consumer
) {
68 return consumer
? static_cast<Window
*>(consumer
) : NULL
;
71 void SetLastMouseLocation(const Window
* root_window
,
72 const gfx::Point
& location_in_root
) {
73 client::ScreenPositionClient
* client
=
74 client::GetScreenPositionClient(root_window
);
76 gfx::Point location_in_screen
= location_in_root
;
77 client
->ConvertPointToScreen(root_window
, &location_in_screen
);
78 Env::GetInstance()->set_last_mouse_location(location_in_screen
);
80 Env::GetInstance()->set_last_mouse_location(location_in_root
);
84 RootWindowHost
* CreateHost(RootWindow
* root_window
,
85 const RootWindow::CreateParams
& params
) {
86 RootWindowHost
* host
= params
.host
?
87 params
.host
: RootWindowHost::Create(params
.initial_bounds
);
88 host
->set_delegate(root_window
);
92 class SimpleRootWindowTransformer
: public RootWindowTransformer
{
94 SimpleRootWindowTransformer(const Window
* root_window
,
95 const gfx::Transform
& transform
)
96 : root_window_(root_window
),
97 transform_(transform
) {
100 // RootWindowTransformer overrides:
101 virtual gfx::Transform
GetTransform() const OVERRIDE
{
105 virtual gfx::Transform
GetInverseTransform() const OVERRIDE
{
106 gfx::Transform invert
;
107 if (!transform_
.GetInverse(&invert
))
112 virtual gfx::Rect
GetRootWindowBounds(
113 const gfx::Size
& host_size
) const OVERRIDE
{
114 gfx::Rect
bounds(host_size
);
115 gfx::RectF
new_bounds(ui::ConvertRectToDIP(root_window_
->layer(), bounds
));
116 transform_
.TransformRect(&new_bounds
);
117 return gfx::Rect(gfx::ToFlooredSize(new_bounds
.size()));
120 virtual gfx::Insets
GetHostInsets() const OVERRIDE
{
121 return gfx::Insets();
125 virtual ~SimpleRootWindowTransformer() {}
127 const Window
* root_window_
;
128 const gfx::Transform transform_
;
130 DISALLOW_COPY_AND_ASSIGN(SimpleRootWindowTransformer
);
135 RootWindow::CreateParams::CreateParams(const gfx::Rect
& a_initial_bounds
)
136 : initial_bounds(a_initial_bounds
),
140 ////////////////////////////////////////////////////////////////////////////////
141 // RootWindow, public:
143 RootWindow::RootWindow(const CreateParams
& params
)
144 : window_(new Window(NULL
)),
145 host_(CreateHost(this, params
)),
147 last_cursor_(ui::kCursorNull
),
148 mouse_pressed_handler_(NULL
),
149 mouse_moved_handler_(NULL
),
150 event_dispatch_target_(NULL
),
151 synthesize_mouse_move_(false),
153 repost_event_factory_(this),
154 held_event_factory_(this) {
155 window()->set_dispatcher(this);
156 window()->SetName("RootWindow");
158 compositor_
.reset(new ui::Compositor(host_
->GetAcceleratedWidget()));
159 DCHECK(compositor_
.get());
161 prop_
.reset(new ui::ViewProp(host_
->GetAcceleratedWidget(),
162 kRootWindowForAcceleratedWidget
,
164 ui::GestureRecognizer::Get()->AddGestureEventHelper(this);
167 RootWindow::~RootWindow() {
168 TRACE_EVENT0("shutdown", "RootWindow::Destructor");
170 ui::GestureRecognizer::Get()->RemoveGestureEventHelper(this);
172 // Make sure to destroy the compositor before terminating so that state is
173 // cleared and we don't hit asserts.
176 // An observer may have been added by an animation on the RootWindow.
177 window()->layer()->GetAnimator()->RemoveObserver(this);
179 // Destroy child windows while we're still valid. This is also done by
180 // ~Window, but by that time any calls to virtual methods overriden here (such
181 // as GetRootWindow()) result in Window's implementation. By destroying here
182 // we ensure GetRootWindow() still returns this.
183 window()->RemoveOrDestroyChildren();
185 // Destroying/removing child windows may try to access |host_| (eg.
186 // GetAcceleratedWidget())
189 window()->set_dispatcher(NULL
);
193 RootWindow
* RootWindow::GetForAcceleratedWidget(
194 gfx::AcceleratedWidget widget
) {
195 return reinterpret_cast<RootWindow
*>(
196 ui::ViewProp::GetValue(widget
, kRootWindowForAcceleratedWidget
));
199 void RootWindow::Init() {
200 compositor()->SetScaleAndSize(GetDeviceScaleFactorFromDisplay(window()),
201 host_
->GetBounds().size());
202 window()->Init(ui::LAYER_NOT_DRAWN
);
203 compositor()->SetRootLayer(window()->layer());
205 new SimpleRootWindowTransformer(window(), gfx::Transform()));
206 UpdateRootWindowSize(host_
->GetBounds().size());
207 Env::GetInstance()->NotifyRootWindowInitialized(this);
211 void RootWindow::PrepareForShutdown() {
212 host_
->PrepareForShutdown();
213 // discard synthesize event request as well.
214 synthesize_mouse_move_
= false;
217 void RootWindow::RepostEvent(const ui::LocatedEvent
& event
) {
218 DCHECK(event
.type() == ui::ET_MOUSE_PRESSED
||
219 event
.type() == ui::ET_GESTURE_TAP_DOWN
);
220 // We allow for only one outstanding repostable event. This is used
221 // in exiting context menus. A dropped repost request is allowed.
222 if (event
.type() == ui::ET_MOUSE_PRESSED
) {
223 held_repostable_event_
.reset(
225 static_cast<const ui::MouseEvent
&>(event
),
226 static_cast<aura::Window
*>(event
.target()),
228 base::MessageLoop::current()->PostTask(
230 base::Bind(&RootWindow::DispatchHeldEventsAsync
,
231 repost_event_factory_
.GetWeakPtr()));
233 DCHECK(event
.type() == ui::ET_GESTURE_TAP_DOWN
);
234 held_repostable_event_
.reset();
235 // TODO(rbyers): Reposing of gestures is tricky to get
236 // right, so it's not yet supported. crbug.com/170987.
240 RootWindowHostDelegate
* RootWindow::AsRootWindowHostDelegate() {
244 void RootWindow::SetHostSize(const gfx::Size
& size_in_pixel
) {
245 DispatchDetails details
= DispatchHeldEvents();
246 if (details
.dispatcher_destroyed
)
248 gfx::Rect bounds
= host_
->GetBounds();
249 bounds
.set_size(size_in_pixel
);
250 host_
->SetBounds(bounds
);
252 // Requery the location to constrain it within the new root window size.
254 if (host_
->QueryMouseLocation(&point
)) {
255 SetLastMouseLocation(window(),
256 ui::ConvertPointToDIP(window()->layer(), point
));
259 synthesize_mouse_move_
= false;
262 void RootWindow::SetHostBounds(const gfx::Rect
& bounds_in_pixel
) {
263 DCHECK(!bounds_in_pixel
.IsEmpty());
264 DispatchDetails details
= DispatchHeldEvents();
265 if (details
.dispatcher_destroyed
)
267 host_
->SetBounds(bounds_in_pixel
);
268 synthesize_mouse_move_
= false;
271 void RootWindow::SetCursor(gfx::NativeCursor cursor
) {
272 last_cursor_
= cursor
;
273 // A lot of code seems to depend on NULL cursors actually showing an arrow,
274 // so just pass everything along to the host.
275 host_
->SetCursor(cursor
);
278 void RootWindow::OnCursorVisibilityChanged(bool show
) {
279 // Clear any existing mouse hover effects when the cursor becomes invisible.
280 // Note we do not need to dispatch a mouse enter when the cursor becomes
281 // visible because that can only happen in response to a mouse event, which
282 // will trigger its own mouse enter.
284 DispatchMouseExitAtPoint(GetLastMouseLocationInRoot());
286 host_
->OnCursorVisibilityChanged(show
);
289 void RootWindow::OnMouseEventsEnableStateChanged(bool enabled
) {
290 // Send entered / exited so that visual state can be updated to match
291 // mouse events state.
292 PostMouseMoveEventAfterWindowChange();
293 // TODO(mazda): Add code to disable mouse events when |enabled| == false.
296 void RootWindow::MoveCursorTo(const gfx::Point
& location_in_dip
) {
297 gfx::Point
host_location(location_in_dip
);
298 ConvertPointToHost(&host_location
);
299 MoveCursorToInternal(location_in_dip
, host_location
);
302 void RootWindow::MoveCursorToHostLocation(const gfx::Point
& host_location
) {
303 gfx::Point
root_location(host_location
);
304 ConvertPointFromHost(&root_location
);
305 MoveCursorToInternal(root_location
, host_location
);
308 void RootWindow::ScheduleRedrawRect(const gfx::Rect
& damage_rect
) {
309 compositor_
->ScheduleRedrawRect(damage_rect
);
312 Window
* RootWindow::GetGestureTarget(ui::GestureEvent
* event
) {
313 Window
* target
= client::GetCaptureWindow(window());
315 target
= ConsumerToWindow(
316 ui::GestureRecognizer::Get()->GetTargetForGestureEvent(event
));
322 void RootWindow::DispatchGestureEvent(ui::GestureEvent
* event
) {
323 DispatchDetails details
= DispatchHeldEvents();
324 if (details
.dispatcher_destroyed
)
327 Window
* target
= GetGestureTarget(event
);
329 event
->ConvertLocationToTarget(window(), target
);
330 DispatchDetails details
= ProcessEvent(target
, event
);
331 if (details
.dispatcher_destroyed
)
336 void RootWindow::OnWindowDestroying(Window
* window
) {
337 DispatchMouseExitToHidingWindow(window
);
338 OnWindowHidden(window
, WINDOW_DESTROYED
);
340 if (window
->IsVisible() &&
341 window
->ContainsPointInRoot(GetLastMouseLocationInRoot())) {
342 PostMouseMoveEventAfterWindowChange();
346 void RootWindow::OnWindowBoundsChanged(Window
* window
,
347 bool contained_mouse_point
) {
348 if (contained_mouse_point
||
349 (window
->IsVisible() &&
350 window
->ContainsPointInRoot(GetLastMouseLocationInRoot()))) {
351 PostMouseMoveEventAfterWindowChange();
355 void RootWindow::DispatchMouseExitToHidingWindow(Window
* window
) {
356 // The mouse capture is intentionally ignored. Think that a mouse enters
357 // to a window, the window sets the capture, the mouse exits the window,
358 // and then it releases the capture. In that case OnMouseExited won't
359 // be called. So it is natural not to emit OnMouseExited even though
360 // |window| is the capture window.
361 gfx::Point last_mouse_location
= GetLastMouseLocationInRoot();
362 if (window
->Contains(mouse_moved_handler_
) &&
363 window
->ContainsPointInRoot(last_mouse_location
))
364 DispatchMouseExitAtPoint(last_mouse_location
);
367 void RootWindow::DispatchMouseExitAtPoint(const gfx::Point
& point
) {
368 ui::MouseEvent
event(ui::ET_MOUSE_EXITED
, point
, point
, ui::EF_NONE
);
369 DispatchDetails details
=
370 DispatchMouseEnterOrExit(event
, ui::ET_MOUSE_EXITED
);
371 if (details
.dispatcher_destroyed
)
375 void RootWindow::OnWindowVisibilityChanged(Window
* window
, bool is_visible
) {
377 OnWindowHidden(window
, WINDOW_HIDDEN
);
379 if (window
->ContainsPointInRoot(GetLastMouseLocationInRoot()))
380 PostMouseMoveEventAfterWindowChange();
383 void RootWindow::OnWindowTransformed(Window
* window
, bool contained_mouse
) {
384 if (contained_mouse
||
385 (window
->IsVisible() &&
386 window
->ContainsPointInRoot(GetLastMouseLocationInRoot()))) {
387 PostMouseMoveEventAfterWindowChange();
391 void RootWindow::OnKeyboardMappingChanged() {
392 FOR_EACH_OBSERVER(RootWindowObserver
, observers_
,
393 OnKeyboardMappingChanged(this));
396 void RootWindow::OnRootWindowHostCloseRequested() {
397 FOR_EACH_OBSERVER(RootWindowObserver
, observers_
,
398 OnRootWindowHostCloseRequested(this));
401 void RootWindow::AddRootWindowObserver(RootWindowObserver
* observer
) {
402 observers_
.AddObserver(observer
);
405 void RootWindow::RemoveRootWindowObserver(RootWindowObserver
* observer
) {
406 observers_
.RemoveObserver(observer
);
409 void RootWindow::ConvertPointToHost(gfx::Point
* point
) const {
410 gfx::Point3F
point_3f(*point
);
411 GetRootTransform().TransformPoint(&point_3f
);
412 *point
= gfx::ToFlooredPoint(point_3f
.AsPointF());
415 void RootWindow::ConvertPointFromHost(gfx::Point
* point
) const {
416 gfx::Point3F
point_3f(*point
);
417 GetInverseRootTransform().TransformPoint(&point_3f
);
418 *point
= gfx::ToFlooredPoint(point_3f
.AsPointF());
421 void RootWindow::ProcessedTouchEvent(ui::TouchEvent
* event
,
423 ui::EventResult result
) {
424 scoped_ptr
<ui::GestureRecognizer::Gestures
> gestures
;
425 gestures
.reset(ui::GestureRecognizer::Get()->
426 ProcessTouchEventForGesture(*event
, result
, window
));
427 DispatchDetails details
= ProcessGestures(gestures
.get());
428 if (details
.dispatcher_destroyed
)
432 void RootWindow::HoldPointerMoves() {
433 if (!move_hold_count_
)
434 held_event_factory_
.InvalidateWeakPtrs();
436 TRACE_EVENT_ASYNC_BEGIN0("ui", "RootWindow::HoldPointerMoves", this);
439 void RootWindow::ReleasePointerMoves() {
441 DCHECK_GE(move_hold_count_
, 0);
442 if (!move_hold_count_
&& held_move_event_
) {
443 // We don't want to call DispatchHeldEvents directly, because this might be
444 // called from a deep stack while another event, in which case dispatching
445 // another one may not be safe/expected. Instead we post a task, that we
446 // may cancel if HoldPointerMoves is called again before it executes.
447 base::MessageLoop::current()->PostTask(
449 base::Bind(&RootWindow::DispatchHeldEventsAsync
,
450 held_event_factory_
.GetWeakPtr()));
452 TRACE_EVENT_ASYNC_END0("ui", "RootWindow::HoldPointerMoves", this);
455 gfx::Point
RootWindow::GetLastMouseLocationInRoot() const {
456 gfx::Point location
= Env::GetInstance()->last_mouse_location();
457 client::ScreenPositionClient
* client
=
458 client::GetScreenPositionClient(window());
460 client
->ConvertPointFromScreen(window(), &location
);
464 void RootWindow::SetRootWindowTransformer(
465 scoped_ptr
<RootWindowTransformer
> transformer
) {
466 transformer_
= transformer
.Pass();
467 host_
->SetInsets(transformer_
->GetHostInsets());
468 window()->SetTransform(transformer_
->GetTransform());
469 // If the layer is not animating, then we need to update the root window
471 if (!window()->layer()->GetAnimator()->is_animating())
472 UpdateRootWindowSize(host_
->GetBounds().size());
475 gfx::Transform
RootWindow::GetRootTransform() const {
476 float scale
= ui::GetDeviceScaleFactor(window()->layer());
477 gfx::Transform transform
;
478 transform
.Scale(scale
, scale
);
479 transform
*= transformer_
->GetTransform();
483 void RootWindow::SetTransform(const gfx::Transform
& transform
) {
484 scoped_ptr
<RootWindowTransformer
> transformer(
485 new SimpleRootWindowTransformer(window(), transform
));
486 SetRootWindowTransformer(transformer
.Pass());
489 ////////////////////////////////////////////////////////////////////////////////
490 // RootWindow, private:
492 void RootWindow::TransformEventForDeviceScaleFactor(ui::LocatedEvent
* event
) {
493 event
->UpdateForRootTransform(GetInverseRootTransform());
496 void RootWindow::MoveCursorToInternal(const gfx::Point
& root_location
,
497 const gfx::Point
& host_location
) {
498 host_
->MoveCursorTo(host_location
);
499 SetLastMouseLocation(window(), root_location
);
500 client::CursorClient
* cursor_client
= client::GetCursorClient(window());
502 const gfx::Display
& display
=
503 gfx::Screen::GetScreenFor(window())->GetDisplayNearestWindow(window());
504 cursor_client
->SetDisplay(display
);
506 synthesize_mouse_move_
= false;
509 ui::EventDispatchDetails
RootWindow::DispatchMouseEnterOrExit(
510 const ui::MouseEvent
& event
,
511 ui::EventType type
) {
512 if (!mouse_moved_handler_
|| !mouse_moved_handler_
->delegate())
513 return DispatchDetails();
515 ui::MouseEvent
translated_event(event
,
517 mouse_moved_handler_
,
519 event
.flags() | ui::EF_IS_SYNTHESIZED
);
520 return ProcessEvent(mouse_moved_handler_
, &translated_event
);
523 ui::EventDispatchDetails
RootWindow::ProcessEvent(Window
* target
,
525 Window
* old_target
= event_dispatch_target_
;
526 event_dispatch_target_
= target
;
527 DispatchDetails details
= DispatchEvent(target
, event
);
528 if (!details
.dispatcher_destroyed
) {
529 if (event_dispatch_target_
!= target
)
530 details
.target_destroyed
= true;
531 event_dispatch_target_
= old_target
;
536 ui::EventDispatchDetails
RootWindow::ProcessGestures(
537 ui::GestureRecognizer::Gestures
* gestures
) {
538 DispatchDetails details
;
539 if (!gestures
|| gestures
->empty())
542 Window
* target
= GetGestureTarget(gestures
->get().at(0));
543 for (size_t i
= 0; i
< gestures
->size(); ++i
) {
544 ui::GestureEvent
* event
= gestures
->get().at(i
);
545 event
->ConvertLocationToTarget(window(), target
);
546 details
= ProcessEvent(target
, event
);
547 if (details
.dispatcher_destroyed
|| details
.target_destroyed
)
553 void RootWindow::OnWindowAddedToRootWindow(Window
* attached
) {
554 if (attached
->IsVisible() &&
555 attached
->ContainsPointInRoot(GetLastMouseLocationInRoot())) {
556 PostMouseMoveEventAfterWindowChange();
560 void RootWindow::OnWindowRemovedFromRootWindow(Window
* detached
,
562 DCHECK(aura::client::GetCaptureWindow(window()) != window());
564 DispatchMouseExitToHidingWindow(detached
);
565 OnWindowHidden(detached
, new_root
? WINDOW_MOVING
: WINDOW_HIDDEN
);
567 if (detached
->IsVisible() &&
568 detached
->ContainsPointInRoot(GetLastMouseLocationInRoot())) {
569 PostMouseMoveEventAfterWindowChange();
573 void RootWindow::OnWindowHidden(Window
* invisible
, WindowHiddenReason reason
) {
574 // Do not clear the capture, and the |event_dispatch_target_| if the
575 // window is moving across root windows, because the target itself
576 // is actually still visible and clearing them stops further event
577 // processing, which can cause unexpected behaviors. See
579 if (reason
!= WINDOW_MOVING
) {
580 Window
* capture_window
= aura::client::GetCaptureWindow(window());
581 // If the ancestor of the capture window is hidden,
582 // release the capture.
583 if (invisible
->Contains(capture_window
) && invisible
!= window())
584 capture_window
->ReleaseCapture();
586 if (invisible
->Contains(event_dispatch_target_
))
587 event_dispatch_target_
= NULL
;
590 // If the ancestor of any event handler windows are invisible, release the
591 // pointer to those windows.
592 if (invisible
->Contains(mouse_pressed_handler_
))
593 mouse_pressed_handler_
= NULL
;
594 if (invisible
->Contains(mouse_moved_handler_
))
595 mouse_moved_handler_
= NULL
;
597 CleanupGestureRecognizerState(invisible
);
600 void RootWindow::CleanupGestureRecognizerState(Window
* window
) {
601 ui::GestureRecognizer::Get()->CleanupStateForConsumer(window
);
602 const Window::Windows
& windows
= window
->children();
603 for (Window::Windows::const_iterator iter
= windows
.begin();
604 iter
!= windows
.end();
606 CleanupGestureRecognizerState(*iter
);
610 void RootWindow::UpdateRootWindowSize(const gfx::Size
& host_size
) {
611 window()->SetBounds(transformer_
->GetRootWindowBounds(host_size
));
614 ////////////////////////////////////////////////////////////////////////////////
615 // RootWindow, aura::client::CaptureDelegate implementation:
617 void RootWindow::UpdateCapture(Window
* old_capture
,
618 Window
* new_capture
) {
619 // |mouse_moved_handler_| may have been set to a Window in a different root
620 // (see below). Clear it here to ensure we don't end up referencing a stale
622 if (mouse_moved_handler_
&& !window()->Contains(mouse_moved_handler_
))
623 mouse_moved_handler_
= NULL
;
625 if (old_capture
&& old_capture
->GetRootWindow() == window() &&
626 old_capture
->delegate()) {
627 // Send a capture changed event with bogus location data.
628 ui::MouseEvent
event(ui::ET_MOUSE_CAPTURE_CHANGED
, gfx::Point(),
631 DispatchDetails details
= ProcessEvent(old_capture
, &event
);
632 if (details
.dispatcher_destroyed
)
635 old_capture
->delegate()->OnCaptureLost();
639 // Make all subsequent mouse events go to the capture window. We shouldn't
640 // need to send an event here as OnCaptureLost() should take care of that.
641 if (mouse_moved_handler_
|| Env::GetInstance()->IsMouseButtonDown())
642 mouse_moved_handler_
= new_capture
;
644 // Make sure mouse_moved_handler gets updated.
645 DispatchDetails details
= SynthesizeMouseMoveEvent();
646 if (details
.dispatcher_destroyed
)
649 mouse_pressed_handler_
= NULL
;
652 void RootWindow::OnOtherRootGotCapture() {
653 mouse_moved_handler_
= NULL
;
654 mouse_pressed_handler_
= NULL
;
657 void RootWindow::SetNativeCapture() {
661 void RootWindow::ReleaseNativeCapture() {
662 host_
->ReleaseCapture();
665 ////////////////////////////////////////////////////////////////////////////////
666 // RootWindow, ui::EventDispatcherDelegate implementation:
668 bool RootWindow::CanDispatchToTarget(ui::EventTarget
* target
) {
669 return event_dispatch_target_
== target
;
672 ////////////////////////////////////////////////////////////////////////////////
673 // RootWindow, ui::GestureEventHelper implementation:
675 bool RootWindow::CanDispatchToConsumer(ui::GestureConsumer
* consumer
) {
676 Window
* consumer_window
= ConsumerToWindow(consumer
);;
677 return (consumer_window
&& consumer_window
->GetRootWindow() == window());
680 void RootWindow::DispatchPostponedGestureEvent(ui::GestureEvent
* event
) {
681 DispatchGestureEvent(event
);
684 void RootWindow::DispatchCancelTouchEvent(ui::TouchEvent
* event
) {
685 OnHostTouchEvent(event
);
688 ////////////////////////////////////////////////////////////////////////////////
689 // RootWindow, ui::LayerAnimationObserver implementation:
691 void RootWindow::OnLayerAnimationEnded(
692 ui::LayerAnimationSequence
* animation
) {
693 UpdateRootWindowSize(host_
->GetBounds().size());
696 void RootWindow::OnLayerAnimationScheduled(
697 ui::LayerAnimationSequence
* animation
) {
700 void RootWindow::OnLayerAnimationAborted(
701 ui::LayerAnimationSequence
* animation
) {
704 ////////////////////////////////////////////////////////////////////////////////
705 // RootWindow, RootWindowHostDelegate implementation:
707 bool RootWindow::OnHostKeyEvent(ui::KeyEvent
* event
) {
708 DispatchDetails details
= DispatchHeldEvents();
709 if (details
.dispatcher_destroyed
)
711 if (event
->key_code() == ui::VKEY_UNKNOWN
)
713 client::EventClient
* client
= client::GetEventClient(window());
714 Window
* focused_window
= client::GetFocusClient(window())->GetFocusedWindow();
715 if (client
&& !client
->CanProcessEventsWithinSubtree(focused_window
)) {
716 client::GetFocusClient(window())->FocusWindow(NULL
);
719 details
= ProcessEvent(focused_window
? focused_window
: window(), event
);
720 if (details
.dispatcher_destroyed
)
722 return event
->handled();
725 bool RootWindow::OnHostMouseEvent(ui::MouseEvent
* event
) {
726 DispatchDetails details
= OnHostMouseEventImpl(event
);
727 return event
->handled() || details
.dispatcher_destroyed
;
730 bool RootWindow::OnHostScrollEvent(ui::ScrollEvent
* event
) {
731 DispatchDetails details
= DispatchHeldEvents();
732 if (details
.dispatcher_destroyed
)
735 TransformEventForDeviceScaleFactor(event
);
736 SetLastMouseLocation(window(), event
->location());
737 synthesize_mouse_move_
= false;
739 Window
* target
= mouse_pressed_handler_
?
740 mouse_pressed_handler_
: client::GetCaptureWindow(window());
743 target
= window()->GetEventHandlerForPoint(event
->location());
748 event
->ConvertLocationToTarget(window(), target
);
749 int flags
= event
->flags();
750 if (IsNonClientLocation(target
, event
->location()))
751 flags
|= ui::EF_IS_NON_CLIENT
;
752 event
->set_flags(flags
);
754 details
= ProcessEvent(target
, event
);
755 if (details
.dispatcher_destroyed
)
757 return event
->handled();
760 bool RootWindow::OnHostTouchEvent(ui::TouchEvent
* event
) {
761 if ((event
->type() == ui::ET_TOUCH_MOVED
)) {
762 if (move_hold_count_
) {
763 Window
* null_window
= static_cast<Window
*>(NULL
);
764 held_move_event_
.reset(
765 new ui::TouchEvent(*event
, null_window
, null_window
));
768 // We may have a held event for a period between the time move_hold_count_
769 // fell to 0 and the DispatchHeldEvents executes. Since we're going to
770 // dispatch the new event directly below, we can reset the old one.
771 held_move_event_
.reset();
774 DispatchDetails details
= DispatchHeldEvents();
775 if (details
.dispatcher_destroyed
)
777 details
= DispatchTouchEventImpl(event
);
778 if (details
.dispatcher_destroyed
)
780 return event
->handled();
783 void RootWindow::OnHostCancelMode() {
784 ui::CancelModeEvent event
;
785 Window
* focused_window
= client::GetFocusClient(window())->GetFocusedWindow();
786 DispatchDetails details
=
787 ProcessEvent(focused_window
? focused_window
: window(), &event
);
788 if (details
.dispatcher_destroyed
)
792 void RootWindow::OnHostActivated() {
793 Env::GetInstance()->RootWindowActivated(this);
796 void RootWindow::OnHostLostWindowCapture() {
797 Window
* capture_window
= client::GetCaptureWindow(window());
798 if (capture_window
&& capture_window
->GetRootWindow() == window())
799 capture_window
->ReleaseCapture();
802 void RootWindow::OnHostLostMouseGrab() {
803 mouse_pressed_handler_
= NULL
;
804 mouse_moved_handler_
= NULL
;
807 void RootWindow::OnHostPaint(const gfx::Rect
& damage_rect
) {
808 compositor_
->ScheduleRedrawRect(damage_rect
);
811 void RootWindow::OnHostMoved(const gfx::Point
& origin
) {
812 TRACE_EVENT1("ui", "RootWindow::OnHostMoved",
813 "origin", origin
.ToString());
815 FOR_EACH_OBSERVER(RootWindowObserver
, observers_
,
816 OnRootWindowHostMoved(this, origin
));
819 void RootWindow::OnHostResized(const gfx::Size
& size
) {
820 TRACE_EVENT1("ui", "RootWindow::OnHostResized",
821 "size", size
.ToString());
823 DispatchDetails details
= DispatchHeldEvents();
824 if (details
.dispatcher_destroyed
)
826 // The compositor should have the same size as the native root window host.
827 // Get the latest scale from display because it might have been changed.
828 compositor_
->SetScaleAndSize(GetDeviceScaleFactorFromDisplay(window()), size
);
830 // The layer, and the observers should be notified of the
831 // transformed size of the root window.
832 UpdateRootWindowSize(size
);
833 FOR_EACH_OBSERVER(RootWindowObserver
, observers_
,
834 OnRootWindowHostResized(this));
837 float RootWindow::GetDeviceScaleFactor() {
838 return compositor()->device_scale_factor();
841 RootWindow
* RootWindow::AsRootWindow() {
845 const RootWindow
* RootWindow::AsRootWindow() const {
849 ////////////////////////////////////////////////////////////////////////////////
850 // RootWindow, private:
852 ui::EventDispatchDetails
RootWindow::OnHostMouseEventImpl(
853 ui::MouseEvent
* event
) {
854 if (event
->type() == ui::ET_MOUSE_DRAGGED
||
855 (event
->flags() & ui::EF_IS_SYNTHESIZED
)) {
856 if (move_hold_count_
) {
857 Window
* null_window
= static_cast<Window
*>(NULL
);
858 held_move_event_
.reset(
859 new ui::MouseEvent(*event
, null_window
, null_window
));
861 return DispatchDetails();
863 // We may have a held event for a period between the time move_hold_count_
864 // fell to 0 and the DispatchHeldEvents executes. Since we're going to
865 // dispatch the new event directly below, we can reset the old one.
866 held_move_event_
.reset();
869 DispatchDetails details
= DispatchHeldEvents();
870 if (details
.dispatcher_destroyed
)
872 return DispatchMouseEventImpl(event
);
875 ui::EventDispatchDetails
RootWindow::DispatchMouseEventImpl(
876 ui::MouseEvent
* event
) {
877 TransformEventForDeviceScaleFactor(event
);
878 Window
* target
= mouse_pressed_handler_
?
879 mouse_pressed_handler_
: client::GetCaptureWindow(window());
881 target
= window()->GetEventHandlerForPoint(event
->location());
882 return DispatchMouseEventToTarget(event
, target
);
885 ui::EventDispatchDetails
RootWindow::DispatchMouseEventRepost(
886 ui::MouseEvent
* event
) {
887 if (event
->type() != ui::ET_MOUSE_PRESSED
)
888 return DispatchDetails();
889 Window
* target
= client::GetCaptureWindow(window());
890 WindowEventDispatcher
* dispatcher
= this;
892 target
= window()->GetEventHandlerForPoint(event
->location());
894 dispatcher
= target
->GetDispatcher();
895 CHECK(dispatcher
); // Capture window better be in valid root.
897 dispatcher
->mouse_pressed_handler_
= NULL
;
898 return dispatcher
->DispatchMouseEventToTarget(event
, target
);
901 ui::EventDispatchDetails
RootWindow::DispatchMouseEventToTarget(
902 ui::MouseEvent
* event
,
904 client::CursorClient
* cursor_client
= client::GetCursorClient(window());
906 !cursor_client
->IsMouseEventsEnabled() &&
907 (event
->flags() & ui::EF_IS_SYNTHESIZED
))
908 return DispatchDetails();
910 static const int kMouseButtonFlagMask
=
911 ui::EF_LEFT_MOUSE_BUTTON
|
912 ui::EF_MIDDLE_MOUSE_BUTTON
|
913 ui::EF_RIGHT_MOUSE_BUTTON
;
914 // WARNING: because of nested message loops |this| may be deleted after
915 // dispatching any event. Do not use AutoReset or the like here.
916 SetLastMouseLocation(window(), event
->location());
917 synthesize_mouse_move_
= false;
918 switch (event
->type()) {
919 case ui::ET_MOUSE_EXITED
:
921 DispatchDetails details
=
922 DispatchMouseEnterOrExit(*event
, ui::ET_MOUSE_EXITED
);
923 if (details
.dispatcher_destroyed
)
925 mouse_moved_handler_
= NULL
;
928 case ui::ET_MOUSE_MOVED
:
929 // Send an exit to the current |mouse_moved_handler_| and an enter to
930 // |target|. Take care that both us and |target| aren't destroyed during
932 if (target
!= mouse_moved_handler_
) {
933 aura::Window
* old_mouse_moved_handler
= mouse_moved_handler_
;
934 WindowTracker destroyed_tracker
;
936 destroyed_tracker
.Add(target
);
937 DispatchDetails details
=
938 DispatchMouseEnterOrExit(*event
, ui::ET_MOUSE_EXITED
);
939 if (details
.dispatcher_destroyed
)
941 // If the |mouse_moved_handler_| changes out from under us, assume a
942 // nested message loop ran and we don't need to do anything.
943 if (mouse_moved_handler_
!= old_mouse_moved_handler
)
944 return DispatchDetails();
945 if (destroyed_tracker
.Contains(target
)) {
946 destroyed_tracker
.Remove(target
);
947 mouse_moved_handler_
= target
;
948 DispatchDetails details
=
949 DispatchMouseEnterOrExit(*event
, ui::ET_MOUSE_ENTERED
);
950 if (details
.dispatcher_destroyed
)
953 mouse_moved_handler_
= NULL
;
954 return DispatchDetails();
958 case ui::ET_MOUSE_PRESSED
:
959 // Don't set the mouse pressed handler for non client mouse down events.
960 // These are only sent by Windows and are not always followed with non
961 // client mouse up events which causes subsequent mouse events to be
962 // sent to the wrong target.
963 if (!(event
->flags() & ui::EF_IS_NON_CLIENT
) && !mouse_pressed_handler_
)
964 mouse_pressed_handler_
= target
;
965 Env::GetInstance()->set_mouse_button_flags(
966 event
->flags() & kMouseButtonFlagMask
);
968 case ui::ET_MOUSE_RELEASED
:
969 mouse_pressed_handler_
= NULL
;
970 Env::GetInstance()->set_mouse_button_flags(event
->flags() &
971 kMouseButtonFlagMask
& ~event
->changed_button_flags());
977 event
->ConvertLocationToTarget(window(), target
);
978 if (IsNonClientLocation(target
, event
->location()))
979 event
->set_flags(event
->flags() | ui::EF_IS_NON_CLIENT
);
980 return ProcessEvent(target
, event
);
982 return DispatchDetails();
985 ui::EventDispatchDetails
RootWindow::DispatchTouchEventImpl(
986 ui::TouchEvent
* event
) {
987 switch (event
->type()) {
988 case ui::ET_TOUCH_PRESSED
:
989 touch_ids_down_
|= (1 << event
->touch_id());
990 Env::GetInstance()->set_touch_down(touch_ids_down_
!= 0);
993 // Handle ET_TOUCH_CANCELLED only if it has a native event.
994 case ui::ET_TOUCH_CANCELLED
:
995 if (!event
->HasNativeEvent())
998 case ui::ET_TOUCH_RELEASED
:
999 touch_ids_down_
= (touch_ids_down_
| (1 << event
->touch_id())) ^
1000 (1 << event
->touch_id());
1001 Env::GetInstance()->set_touch_down(touch_ids_down_
!= 0);
1007 TransformEventForDeviceScaleFactor(event
);
1008 Window
* target
= client::GetCaptureWindow(window());
1010 target
= ConsumerToWindow(
1011 ui::GestureRecognizer::Get()->GetTouchLockedTarget(event
));
1013 target
= ConsumerToWindow(ui::GestureRecognizer::Get()->
1014 GetTargetForLocation(event
->location()));
1018 // The gesture recognizer processes touch events in the system coordinates. So
1019 // keep a copy of the touch event here before possibly converting the event to
1020 // a window's local coordinate system.
1021 ui::TouchEvent
event_for_gr(*event
);
1023 ui::EventResult result
= ui::ER_UNHANDLED
;
1024 if (!target
&& !window()->bounds().Contains(event
->location())) {
1025 // If the initial touch is outside the root window, target the root.
1027 DispatchDetails details
= ProcessEvent(target
? target
: NULL
, event
);
1028 if (details
.dispatcher_destroyed
)
1030 result
= event
->result();
1032 // We only come here when the first contact was within the root window.
1034 target
= window()->GetEventHandlerForPoint(event
->location());
1036 return DispatchDetails();
1039 event
->ConvertLocationToTarget(window(), target
);
1040 DispatchDetails details
= ProcessEvent(target
, event
);
1041 if (details
.dispatcher_destroyed
)
1043 result
= event
->result();
1046 // Get the list of GestureEvents from GestureRecognizer.
1047 scoped_ptr
<ui::GestureRecognizer::Gestures
> gestures
;
1048 gestures
.reset(ui::GestureRecognizer::Get()->
1049 ProcessTouchEventForGesture(event_for_gr
, result
, target
));
1051 return ProcessGestures(gestures
.get());
1054 ui::EventDispatchDetails
RootWindow::DispatchHeldEvents() {
1055 DispatchDetails dispatch_details
;
1056 if (held_repostable_event_
) {
1057 if (held_repostable_event_
->type() == ui::ET_MOUSE_PRESSED
) {
1058 scoped_ptr
<ui::MouseEvent
> mouse_event(
1059 static_cast<ui::MouseEvent
*>(held_repostable_event_
.release()));
1060 dispatch_details
= DispatchMouseEventRepost(mouse_event
.get());
1062 // TODO(rbyers): GESTURE_TAP_DOWN not yet supported: crbug.com/170987.
1065 if (dispatch_details
.dispatcher_destroyed
)
1066 return dispatch_details
;
1069 if (held_move_event_
&& held_move_event_
->IsMouseEvent()) {
1070 // If a mouse move has been synthesized, the target location is suspect,
1071 // so drop the held event.
1072 if (!synthesize_mouse_move_
)
1073 dispatch_details
= DispatchMouseEventImpl(
1074 static_cast<ui::MouseEvent
*>(held_move_event_
.get()));
1075 if (!dispatch_details
.dispatcher_destroyed
)
1076 held_move_event_
.reset();
1077 } else if (held_move_event_
&& held_move_event_
->IsTouchEvent()) {
1078 dispatch_details
= DispatchTouchEventImpl(
1079 static_cast<ui::TouchEvent
*>(held_move_event_
.get()));
1080 if (!dispatch_details
.dispatcher_destroyed
)
1081 held_move_event_
.reset();
1084 return dispatch_details
;
1087 void RootWindow::DispatchHeldEventsAsync() {
1088 DispatchDetails details
= DispatchHeldEvents();
1089 if (details
.dispatcher_destroyed
)
1093 void RootWindow::PostMouseMoveEventAfterWindowChange() {
1094 if (synthesize_mouse_move_
)
1096 synthesize_mouse_move_
= true;
1097 base::MessageLoop::current()->PostTask(
1099 base::Bind(&RootWindow::SynthesizeMouseMoveEventAsync
,
1100 held_event_factory_
.GetWeakPtr()));
1103 ui::EventDispatchDetails
RootWindow::SynthesizeMouseMoveEvent() {
1104 DispatchDetails details
;
1105 if (!synthesize_mouse_move_
)
1107 synthesize_mouse_move_
= false;
1108 gfx::Point root_mouse_location
= GetLastMouseLocationInRoot();
1109 if (!window()->bounds().Contains(root_mouse_location
))
1111 gfx::Point host_mouse_location
= root_mouse_location
;
1112 ConvertPointToHost(&host_mouse_location
);
1114 ui::MouseEvent
event(ui::ET_MOUSE_MOVED
,
1115 host_mouse_location
,
1116 host_mouse_location
,
1117 ui::EF_IS_SYNTHESIZED
);
1118 return OnHostMouseEventImpl(&event
);
1121 void RootWindow::SynthesizeMouseMoveEventAsync() {
1122 DispatchDetails details
= SynthesizeMouseMoveEvent();
1123 if (details
.dispatcher_destroyed
)
1127 gfx::Transform
RootWindow::GetInverseRootTransform() const {
1128 float scale
= ui::GetDeviceScaleFactor(window()->layer());
1129 gfx::Transform transform
;
1130 transform
.Scale(1.0f
/ scale
, 1.0f
/ scale
);
1131 return transformer_
->GetInverseTransform() * transform
;