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_host.h"
21 #include "ui/aura/root_window_observer.h"
22 #include "ui/aura/root_window_transformer.h"
23 #include "ui/aura/window.h"
24 #include "ui/aura/window_delegate.h"
25 #include "ui/aura/window_tracker.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"
46 const char kRootWindowForAcceleratedWidget
[] =
47 "__AURA_ROOT_WINDOW_ACCELERATED_WIDGET__";
49 // Returns true if |target| has a non-client (frame) component at |location|,
50 // in window coordinates.
51 bool IsNonClientLocation(Window
* target
, const gfx::Point
& location
) {
52 if (!target
->delegate())
54 int hit_test_code
= target
->delegate()->GetNonClientComponent(location
);
55 return hit_test_code
!= HTCLIENT
&& hit_test_code
!= HTNOWHERE
;
58 float GetDeviceScaleFactorFromDisplay(Window
* window
) {
59 return gfx::Screen::GetScreenFor(window
)->
60 GetDisplayNearestWindow(window
).device_scale_factor();
63 Window
* ConsumerToWindow(ui::GestureConsumer
* consumer
) {
64 return consumer
? static_cast<Window
*>(consumer
) : NULL
;
67 void SetLastMouseLocation(const RootWindow
* root_window
,
68 const gfx::Point
& location_in_root
) {
69 client::ScreenPositionClient
* client
=
70 client::GetScreenPositionClient(root_window
);
72 gfx::Point location_in_screen
= location_in_root
;
73 client
->ConvertPointToScreen(root_window
, &location_in_screen
);
74 Env::GetInstance()->set_last_mouse_location(location_in_screen
);
76 Env::GetInstance()->set_last_mouse_location(location_in_root
);
80 RootWindowHost
* CreateHost(RootWindow
* root_window
,
81 const RootWindow::CreateParams
& params
) {
82 RootWindowHost
* host
= params
.host
?
83 params
.host
: RootWindowHost::Create(params
.initial_bounds
);
84 host
->SetDelegate(root_window
);
88 class SimpleRootWindowTransformer
: public RootWindowTransformer
{
90 SimpleRootWindowTransformer(const RootWindow
* root_window
,
91 const gfx::Transform
& transform
)
92 : root_window_(root_window
),
93 transform_(transform
) {
96 // RootWindowTransformer overrides:
97 virtual gfx::Transform
GetTransform() const OVERRIDE
{
101 virtual gfx::Transform
GetInverseTransform() const OVERRIDE
{
102 gfx::Transform invert
;
103 if (!transform_
.GetInverse(&invert
))
108 virtual gfx::Rect
GetRootWindowBounds(
109 const gfx::Size
& host_size
) const OVERRIDE
{
110 gfx::Rect
bounds(host_size
);
111 gfx::RectF
new_bounds(ui::ConvertRectToDIP(root_window_
->layer(), bounds
));
112 transform_
.TransformRect(&new_bounds
);
113 return gfx::Rect(gfx::ToFlooredSize(new_bounds
.size()));
116 virtual gfx::Insets
GetHostInsets() const OVERRIDE
{
117 return gfx::Insets();
121 virtual ~SimpleRootWindowTransformer() {}
123 const RootWindow
* root_window_
;
124 const gfx::Transform transform_
;
126 DISALLOW_COPY_AND_ASSIGN(SimpleRootWindowTransformer
);
131 RootWindow::CreateParams::CreateParams(const gfx::Rect
& a_initial_bounds
)
132 : initial_bounds(a_initial_bounds
),
136 ////////////////////////////////////////////////////////////////////////////////
137 // RootWindow, public:
139 RootWindow::RootWindow(const CreateParams
& params
)
141 host_(CreateHost(this, params
)),
143 last_cursor_(ui::kCursorNull
),
144 mouse_pressed_handler_(NULL
),
145 mouse_moved_handler_(NULL
),
146 event_dispatch_target_(NULL
),
147 synthesize_mouse_move_(false),
149 event_factory_(this),
150 held_event_factory_(this),
151 repostable_event_factory_(this) {
152 SetName("RootWindow");
154 compositor_
.reset(new ui::Compositor(host_
->GetAcceleratedWidget()));
155 DCHECK(compositor_
.get());
157 prop_
.reset(new ui::ViewProp(host_
->GetAcceleratedWidget(),
158 kRootWindowForAcceleratedWidget
,
160 ui::GestureRecognizer::Get()->AddGestureEventHelper(this);
163 RootWindow::~RootWindow() {
164 TRACE_EVENT0("shutdown", "RootWindow::Destructor");
166 ui::GestureRecognizer::Get()->RemoveGestureEventHelper(this);
168 // Make sure to destroy the compositor before terminating so that state is
169 // cleared and we don't hit asserts.
172 // An observer may have been added by an animation on the RootWindow.
173 layer()->GetAnimator()->RemoveObserver(this);
175 // Destroy child windows while we're still valid. This is also done by
176 // ~Window, but by that time any calls to virtual methods overriden here (such
177 // as GetRootWindow()) result in Window's implementation. By destroying here
178 // we ensure GetRootWindow() still returns this.
179 RemoveOrDestroyChildren();
181 // Destroying/removing child windows may try to access |host_| (eg.
182 // GetAcceleratedWidget())
187 RootWindow
* RootWindow::GetForAcceleratedWidget(
188 gfx::AcceleratedWidget widget
) {
189 return reinterpret_cast<RootWindow
*>(
190 ui::ViewProp::GetValue(widget
, kRootWindowForAcceleratedWidget
));
193 void RootWindow::Init() {
194 compositor()->SetScaleAndSize(GetDeviceScaleFactorFromDisplay(this),
195 host_
->GetBounds().size());
196 Window::Init(ui::LAYER_NOT_DRAWN
);
197 compositor()->SetRootLayer(layer());
198 transformer_
.reset(new SimpleRootWindowTransformer(this, gfx::Transform()));
199 UpdateRootWindowSize(GetHostSize());
200 Env::GetInstance()->NotifyRootWindowInitialized(this);
204 void RootWindow::ShowRootWindow() {
208 void RootWindow::HideRootWindow() {
212 void RootWindow::PrepareForShutdown() {
213 host_
->PrepareForShutdown();
214 // discard synthesize event request as well.
215 synthesize_mouse_move_
= false;
218 void RootWindow::RepostEvent(const ui::LocatedEvent
& event
) {
219 DCHECK(event
.type() == ui::ET_MOUSE_PRESSED
||
220 event
.type() == ui::ET_GESTURE_TAP_DOWN
);
221 // We allow for only one outstanding repostable event. This is used
222 // in exiting context menus. A dropped repost request is allowed.
223 if (event
.type() == ui::ET_MOUSE_PRESSED
) {
224 held_repostable_event_
.reset(
226 static_cast<const ui::MouseEvent
&>(event
),
227 static_cast<aura::Window
*>(event
.target()),
228 static_cast<aura::Window
*>(this)));
230 held_repostable_event_
.reset(
231 new ui::GestureEvent(
232 static_cast<const ui::GestureEvent
&>(event
),
233 static_cast<aura::Window
*>(event
.target()),
234 static_cast<aura::Window
*>(this)));
236 base::MessageLoop::current()->PostTask(
238 base::Bind(&RootWindow::DispatchHeldEvents
,
239 repostable_event_factory_
.GetWeakPtr()));
242 RootWindowHostDelegate
* RootWindow::AsRootWindowHostDelegate() {
246 void RootWindow::SetHostSize(const gfx::Size
& size_in_pixel
) {
247 DispatchHeldEvents();
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(this, ui::ConvertPointToDIP(layer(), point
));
257 synthesize_mouse_move_
= false;
260 gfx::Size
RootWindow::GetHostSize() const {
261 return host_
->GetBounds().size();
264 void RootWindow::SetHostBounds(const gfx::Rect
& bounds_in_pixel
) {
265 DCHECK(!bounds_in_pixel
.IsEmpty());
266 DispatchHeldEvents();
267 host_
->SetBounds(bounds_in_pixel
);
268 synthesize_mouse_move_
= false;
271 gfx::Point
RootWindow::GetHostOrigin() const {
272 return host_
->GetBounds().origin();
275 void RootWindow::SetCursor(gfx::NativeCursor cursor
) {
276 last_cursor_
= cursor
;
277 // A lot of code seems to depend on NULL cursors actually showing an arrow,
278 // so just pass everything along to the host.
279 host_
->SetCursor(cursor
);
282 void RootWindow::OnCursorVisibilityChanged(bool show
) {
283 // Clear any existing mouse hover effects when the cursor becomes invisible.
284 // Note we do not need to dispatch a mouse enter when the cursor becomes
285 // visible because that can only happen in response to a mouse event, which
286 // will trigger its own mouse enter.
288 DispatchMouseExitAtPoint(GetLastMouseLocationInRoot());
290 host_
->OnCursorVisibilityChanged(show
);
293 void RootWindow::OnMouseEventsEnableStateChanged(bool enabled
) {
294 // Send entered / exited so that visual state can be updated to match
295 // mouse events state.
296 PostMouseMoveEventAfterWindowChange();
297 // TODO(mazda): Add code to disable mouse events when |enabled| == false.
300 void RootWindow::MoveCursorTo(const gfx::Point
& location_in_dip
) {
301 gfx::Point
host_location(location_in_dip
);
302 ConvertPointToHost(&host_location
);
303 MoveCursorToInternal(location_in_dip
, host_location
);
306 void RootWindow::MoveCursorToHostLocation(const gfx::Point
& host_location
) {
307 gfx::Point
root_location(host_location
);
308 ConvertPointFromHost(&root_location
);
309 MoveCursorToInternal(root_location
, host_location
);
312 bool RootWindow::ConfineCursorToWindow() {
313 // We would like to be able to confine the cursor to that window. However,
314 // currently, we do not have such functionality in X. So we just confine
315 // to the root window. This is ok because this option is currently only
316 // being used in fullscreen mode, so root_window bounds = window bounds.
317 return host_
->ConfineCursorToRootWindow();
320 void RootWindow::ScheduleRedrawRect(const gfx::Rect
& damage_rect
) {
321 compositor_
->ScheduleRedrawRect(damage_rect
);
324 Window
* RootWindow::GetGestureTarget(ui::GestureEvent
* event
) {
325 Window
* target
= client::GetCaptureWindow(this);
327 target
= ConsumerToWindow(
328 ui::GestureRecognizer::Get()->GetTargetForGestureEvent(event
));
334 bool RootWindow::DispatchGestureEvent(ui::GestureEvent
* event
) {
335 DispatchHeldEvents();
337 Window
* target
= GetGestureTarget(event
);
339 event
->ConvertLocationToTarget(static_cast<Window
*>(this), target
);
340 ProcessEvent(target
, event
);
341 return event
->handled();
347 void RootWindow::OnWindowDestroying(Window
* window
) {
348 DispatchMouseExitToHidingWindow(window
);
349 OnWindowHidden(window
, WINDOW_DESTROYED
);
351 if (window
->IsVisible() &&
352 window
->ContainsPointInRoot(GetLastMouseLocationInRoot())) {
353 PostMouseMoveEventAfterWindowChange();
357 void RootWindow::OnWindowBoundsChanged(Window
* window
,
358 bool contained_mouse_point
) {
359 if (contained_mouse_point
||
360 (window
->IsVisible() &&
361 window
->ContainsPointInRoot(GetLastMouseLocationInRoot()))) {
362 PostMouseMoveEventAfterWindowChange();
366 void RootWindow::DispatchMouseExitToHidingWindow(Window
* window
) {
367 // The mouse capture is intentionally ignored. Think that a mouse enters
368 // to a window, the window sets the capture, the mouse exits the window,
369 // and then it releases the capture. In that case OnMouseExited won't
370 // be called. So it is natural not to emit OnMouseExited even though
371 // |window| is the capture window.
372 gfx::Point last_mouse_location
= GetLastMouseLocationInRoot();
373 if (window
->Contains(mouse_moved_handler_
) &&
374 window
->ContainsPointInRoot(last_mouse_location
))
375 DispatchMouseExitAtPoint(last_mouse_location
);
378 void RootWindow::DispatchMouseExitAtPoint(const gfx::Point
& point
) {
379 ui::MouseEvent
event(ui::ET_MOUSE_EXITED
, point
, point
, ui::EF_NONE
);
380 DispatchMouseEnterOrExit(event
, ui::ET_MOUSE_EXITED
);
383 void RootWindow::OnWindowVisibilityChanged(Window
* window
, bool is_visible
) {
385 OnWindowHidden(window
, WINDOW_HIDDEN
);
387 if (window
->ContainsPointInRoot(GetLastMouseLocationInRoot()))
388 PostMouseMoveEventAfterWindowChange();
391 void RootWindow::OnWindowTransformed(Window
* window
, bool contained_mouse
) {
392 if (contained_mouse
||
393 (window
->IsVisible() &&
394 window
->ContainsPointInRoot(GetLastMouseLocationInRoot()))) {
395 PostMouseMoveEventAfterWindowChange();
399 void RootWindow::OnKeyboardMappingChanged() {
400 FOR_EACH_OBSERVER(RootWindowObserver
, observers_
,
401 OnKeyboardMappingChanged(this));
404 void RootWindow::OnRootWindowHostCloseRequested() {
405 FOR_EACH_OBSERVER(RootWindowObserver
, observers_
,
406 OnRootWindowHostCloseRequested(this));
409 void RootWindow::AddRootWindowObserver(RootWindowObserver
* observer
) {
410 observers_
.AddObserver(observer
);
413 void RootWindow::RemoveRootWindowObserver(RootWindowObserver
* observer
) {
414 observers_
.RemoveObserver(observer
);
417 void RootWindow::PostNativeEvent(const base::NativeEvent
& native_event
) {
418 host_
->PostNativeEvent(native_event
);
421 void RootWindow::ConvertPointToNativeScreen(gfx::Point
* point
) const {
422 ConvertPointToHost(point
);
423 gfx::Point location
= host_
->GetLocationOnNativeScreen();
424 point
->Offset(location
.x(), location
.y());
427 void RootWindow::ConvertPointFromNativeScreen(gfx::Point
* point
) const {
428 gfx::Point location
= host_
->GetLocationOnNativeScreen();
429 point
->Offset(-location
.x(), -location
.y());
430 ConvertPointFromHost(point
);
433 void RootWindow::ConvertPointToHost(gfx::Point
* point
) const {
434 gfx::Point3F
point_3f(*point
);
435 GetRootTransform().TransformPoint(&point_3f
);
436 *point
= gfx::ToFlooredPoint(point_3f
.AsPointF());
439 void RootWindow::ConvertPointFromHost(gfx::Point
* point
) const {
440 gfx::Point3F
point_3f(*point
);
441 GetInverseRootTransform().TransformPoint(&point_3f
);
442 *point
= gfx::ToFlooredPoint(point_3f
.AsPointF());
445 void RootWindow::ProcessedTouchEvent(ui::TouchEvent
* event
,
447 ui::EventResult result
) {
448 scoped_ptr
<ui::GestureRecognizer::Gestures
> gestures
;
449 gestures
.reset(ui::GestureRecognizer::Get()->
450 ProcessTouchEventForGesture(*event
, result
, window
));
451 ProcessGestures(gestures
.get());
454 gfx::AcceleratedWidget
RootWindow::GetAcceleratedWidget() {
455 return host_
->GetAcceleratedWidget();
458 void RootWindow::ToggleFullScreen() {
459 host_
->ToggleFullScreen();
462 void RootWindow::HoldPointerMoves() {
463 if (!move_hold_count_
)
464 held_event_factory_
.InvalidateWeakPtrs();
466 TRACE_EVENT_ASYNC_BEGIN0("ui", "RootWindow::HoldPointerMoves", this);
469 void RootWindow::ReleasePointerMoves() {
471 DCHECK_GE(move_hold_count_
, 0);
472 if (!move_hold_count_
&& held_move_event_
) {
473 // We don't want to call DispatchHeldEvents directly, because this might be
474 // called from a deep stack while another event, in which case dispatching
475 // another one may not be safe/expected. Instead we post a task, that we
476 // may cancel if HoldPointerMoves is called again before it executes.
477 base::MessageLoop::current()->PostTask(
479 base::Bind(&RootWindow::DispatchHeldEvents
,
480 held_event_factory_
.GetWeakPtr()));
482 TRACE_EVENT_ASYNC_END0("ui", "RootWindow::HoldPointerMoves", this);
485 void RootWindow::SetFocusWhenShown(bool focused
) {
486 host_
->SetFocusWhenShown(focused
);
489 gfx::Point
RootWindow::GetLastMouseLocationInRoot() const {
490 gfx::Point location
= Env::GetInstance()->last_mouse_location();
491 client::ScreenPositionClient
* client
= client::GetScreenPositionClient(this);
493 client
->ConvertPointFromScreen(this, &location
);
497 bool RootWindow::QueryMouseLocationForTest(gfx::Point
* point
) const {
498 return host_
->QueryMouseLocation(point
);
501 void RootWindow::SetRootWindowTransformer(
502 scoped_ptr
<RootWindowTransformer
> transformer
) {
503 transformer_
= transformer
.Pass();
504 host_
->SetInsets(transformer_
->GetHostInsets());
505 Window::SetTransform(transformer_
->GetTransform());
506 // If the layer is not animating, then we need to update the root window
508 if (!layer()->GetAnimator()->is_animating())
509 UpdateRootWindowSize(GetHostSize());
512 gfx::Transform
RootWindow::GetRootTransform() const {
513 float scale
= ui::GetDeviceScaleFactor(layer());
514 gfx::Transform transform
;
515 transform
.Scale(scale
, scale
);
516 transform
*= transformer_
->GetTransform();
520 ////////////////////////////////////////////////////////////////////////////////
521 // RootWindow, Window overrides:
523 RootWindow
* RootWindow::GetRootWindow() {
527 const RootWindow
* RootWindow::GetRootWindow() const {
531 void RootWindow::SetTransform(const gfx::Transform
& transform
) {
532 scoped_ptr
<RootWindowTransformer
> transformer(
533 new SimpleRootWindowTransformer(this, transform
));
534 SetRootWindowTransformer(transformer
.Pass());
537 bool RootWindow::CanFocus() const {
541 bool RootWindow::CanReceiveEvents() const {
545 ////////////////////////////////////////////////////////////////////////////////
546 // RootWindow, private:
548 void RootWindow::TransformEventForDeviceScaleFactor(ui::LocatedEvent
* event
) {
549 event
->UpdateForRootTransform(GetInverseRootTransform());
552 void RootWindow::MoveCursorToInternal(const gfx::Point
& root_location
,
553 const gfx::Point
& host_location
) {
554 host_
->MoveCursorTo(host_location
);
555 SetLastMouseLocation(this, root_location
);
556 client::CursorClient
* cursor_client
= client::GetCursorClient(this);
558 const gfx::Display
& display
=
559 gfx::Screen::GetScreenFor(this)->GetDisplayNearestWindow(this);
560 cursor_client
->SetDisplay(display
);
562 synthesize_mouse_move_
= false;
565 void RootWindow::DispatchMouseEnterOrExit(const ui::MouseEvent
& event
,
566 ui::EventType type
) {
567 if (!mouse_moved_handler_
|| !mouse_moved_handler_
->delegate())
570 ui::MouseEvent
translated_event(event
,
571 static_cast<Window
*>(this),
572 mouse_moved_handler_
,
574 event
.flags() | ui::EF_IS_SYNTHESIZED
);
575 ProcessEvent(mouse_moved_handler_
, &translated_event
);
578 void RootWindow::ProcessEvent(Window
* target
, ui::Event
* event
) {
579 Window
* old_target
= event_dispatch_target_
;
580 event_dispatch_target_
= target
;
581 if (DispatchEvent(target
, event
))
582 event_dispatch_target_
= old_target
;
585 bool RootWindow::ProcessGestures(ui::GestureRecognizer::Gestures
* gestures
) {
586 if (!gestures
|| gestures
->empty())
589 Window
* target
= GetGestureTarget(gestures
->get().at(0));
590 Window
* old_target
= event_dispatch_target_
;
591 event_dispatch_target_
= target
;
593 bool handled
= false;
594 for (size_t i
= 0; i
< gestures
->size(); ++i
) {
595 ui::GestureEvent
* event
= gestures
->get().at(i
);
596 event
->ConvertLocationToTarget(static_cast<Window
*>(this), target
);
597 if (!DispatchEvent(target
, event
))
598 return false; // |this| has been destroyed.
599 if (event
->handled())
601 if (event_dispatch_target_
!= target
) // |target| has been destroyed.
604 event_dispatch_target_
= old_target
;
608 void RootWindow::OnWindowAddedToRootWindow(Window
* attached
) {
609 if (attached
->IsVisible() &&
610 attached
->ContainsPointInRoot(GetLastMouseLocationInRoot())) {
611 PostMouseMoveEventAfterWindowChange();
615 void RootWindow::OnWindowRemovedFromRootWindow(Window
* detached
,
616 RootWindow
* new_root
) {
617 DCHECK(aura::client::GetCaptureWindow(this) != this);
619 DispatchMouseExitToHidingWindow(detached
);
620 OnWindowHidden(detached
, new_root
? WINDOW_MOVING
: WINDOW_HIDDEN
);
622 if (detached
->IsVisible() &&
623 detached
->ContainsPointInRoot(GetLastMouseLocationInRoot())) {
624 PostMouseMoveEventAfterWindowChange();
628 void RootWindow::OnWindowHidden(Window
* invisible
, WindowHiddenReason reason
) {
629 // Do not clear the capture, and the |event_dispatch_target_| if the
630 // window is moving across root windows, because the target itself
631 // is actually still visible and clearing them stops further event
632 // processing, which can cause unexpected behaviors. See
634 if (reason
!= WINDOW_MOVING
) {
635 Window
* capture_window
= aura::client::GetCaptureWindow(this);
636 // If the ancestor of the capture window is hidden,
637 // release the capture.
638 if (invisible
->Contains(capture_window
) && invisible
!= this)
639 capture_window
->ReleaseCapture();
641 if (invisible
->Contains(event_dispatch_target_
))
642 event_dispatch_target_
= NULL
;
645 // If the ancestor of any event handler windows are invisible, release the
646 // pointer to those windows.
647 if (invisible
->Contains(mouse_pressed_handler_
))
648 mouse_pressed_handler_
= NULL
;
649 if (invisible
->Contains(mouse_moved_handler_
))
650 mouse_moved_handler_
= NULL
;
652 CleanupGestureRecognizerState(invisible
);
655 void RootWindow::CleanupGestureRecognizerState(Window
* window
) {
656 ui::GestureRecognizer::Get()->CleanupStateForConsumer(window
);
657 const Windows
& windows
= window
->children();
658 for (Windows::const_iterator iter
= windows
.begin();
659 iter
!= windows
.end();
661 CleanupGestureRecognizerState(*iter
);
665 void RootWindow::UpdateRootWindowSize(const gfx::Size
& host_size
) {
666 SetBounds(transformer_
->GetRootWindowBounds(host_size
));
669 ////////////////////////////////////////////////////////////////////////////////
670 // RootWindow, ui::EventTarget implementation:
672 ui::EventTarget
* RootWindow::GetParentTarget() {
673 return client::GetEventClient(this) ?
674 client::GetEventClient(this)->GetToplevelEventTarget() :
678 ////////////////////////////////////////////////////////////////////////////////
679 // RootWindow, ui::LayerDelegate implementation:
681 void RootWindow::OnDeviceScaleFactorChanged(
682 float device_scale_factor
) {
683 const bool cursor_is_in_bounds
=
684 GetBoundsInScreen().Contains(Env::GetInstance()->last_mouse_location());
685 bool cursor_visible
= false;
686 client::CursorClient
* cursor_client
= client::GetCursorClient(this);
687 if (cursor_is_in_bounds
&& cursor_client
) {
688 cursor_visible
= cursor_client
->IsCursorVisible();
690 cursor_client
->HideCursor();
692 host_
->OnDeviceScaleFactorChanged(device_scale_factor
);
693 Window::OnDeviceScaleFactorChanged(device_scale_factor
);
694 // Update the device scale factor of the cursor client only when the last
695 // mouse location is on this root window.
696 if (cursor_is_in_bounds
) {
698 const gfx::Display
& display
=
699 gfx::Screen::GetScreenFor(this)->GetDisplayNearestWindow(this);
700 cursor_client
->SetDisplay(display
);
703 if (cursor_is_in_bounds
&& cursor_client
&& cursor_visible
)
704 cursor_client
->ShowCursor();
707 ////////////////////////////////////////////////////////////////////////////////
708 // RootWindow, aura::client::CaptureDelegate implementation:
710 void RootWindow::UpdateCapture(Window
* old_capture
,
711 Window
* new_capture
) {
712 // |mouse_moved_handler_| may have been set to a Window in a different root
713 // (see below). Clear it here to ensure we don't end up referencing a stale
715 if (mouse_moved_handler_
&& !Contains(mouse_moved_handler_
))
716 mouse_moved_handler_
= NULL
;
718 if (old_capture
&& old_capture
->GetRootWindow() == this &&
719 old_capture
->delegate()) {
720 // Send a capture changed event with bogus location data.
721 ui::MouseEvent
event(ui::ET_MOUSE_CAPTURE_CHANGED
, gfx::Point(),
724 ProcessEvent(old_capture
, &event
);
726 old_capture
->delegate()->OnCaptureLost();
730 // Make all subsequent mouse events go to the capture window. We shouldn't
731 // need to send an event here as OnCaptureLost() should take care of that.
732 if (mouse_moved_handler_
|| Env::GetInstance()->IsMouseButtonDown())
733 mouse_moved_handler_
= new_capture
;
735 // Make sure mouse_moved_handler gets updated.
736 SynthesizeMouseMoveEvent();
738 mouse_pressed_handler_
= NULL
;
741 void RootWindow::OnOtherRootGotCapture() {
742 mouse_moved_handler_
= NULL
;
743 mouse_pressed_handler_
= NULL
;
746 void RootWindow::SetNativeCapture() {
750 void RootWindow::ReleaseNativeCapture() {
751 host_
->ReleaseCapture();
754 ////////////////////////////////////////////////////////////////////////////////
755 // RootWindow, ui::EventDispatcherDelegate implementation:
757 bool RootWindow::CanDispatchToTarget(ui::EventTarget
* target
) {
758 return event_dispatch_target_
== target
;
761 ////////////////////////////////////////////////////////////////////////////////
762 // RootWindow, ui::GestureEventHelper implementation:
764 bool RootWindow::CanDispatchToConsumer(ui::GestureConsumer
* consumer
) {
765 Window
* window
= ConsumerToWindow(consumer
);;
766 return (window
&& window
->GetRootWindow() == this);
769 void RootWindow::DispatchPostponedGestureEvent(ui::GestureEvent
* event
) {
770 DispatchGestureEvent(event
);
773 void RootWindow::DispatchCancelTouchEvent(ui::TouchEvent
* event
) {
774 OnHostTouchEvent(event
);
777 ////////////////////////////////////////////////////////////////////////////////
778 // RootWindow, ui::LayerAnimationObserver implementation:
780 void RootWindow::OnLayerAnimationEnded(
781 ui::LayerAnimationSequence
* animation
) {
782 UpdateRootWindowSize(GetHostSize());
785 void RootWindow::OnLayerAnimationScheduled(
786 ui::LayerAnimationSequence
* animation
) {
789 void RootWindow::OnLayerAnimationAborted(
790 ui::LayerAnimationSequence
* animation
) {
793 ////////////////////////////////////////////////////////////////////////////////
794 // RootWindow, RootWindowHostDelegate implementation:
796 bool RootWindow::OnHostKeyEvent(ui::KeyEvent
* event
) {
797 DispatchHeldEvents();
798 if (event
->key_code() == ui::VKEY_UNKNOWN
)
800 client::EventClient
* client
= client::GetEventClient(GetRootWindow());
801 Window
* focused_window
= client::GetFocusClient(this)->GetFocusedWindow();
802 if (client
&& !client
->CanProcessEventsWithinSubtree(focused_window
)) {
803 client::GetFocusClient(this)->FocusWindow(NULL
);
806 ProcessEvent(focused_window
? focused_window
: this, event
);
807 return event
->handled();
810 bool RootWindow::OnHostMouseEvent(ui::MouseEvent
* event
) {
811 if (event
->type() == ui::ET_MOUSE_DRAGGED
||
812 (event
->flags() & ui::EF_IS_SYNTHESIZED
)) {
813 if (move_hold_count_
) {
814 Window
* null_window
= static_cast<Window
*>(NULL
);
815 held_move_event_
.reset(
816 new ui::MouseEvent(*event
, null_window
, null_window
));
819 // We may have a held event for a period between the time move_hold_count_
820 // fell to 0 and the DispatchHeldEvents executes. Since we're going to
821 // dispatch the new event directly below, we can reset the old one.
822 held_move_event_
.reset();
825 DispatchHeldEvents();
826 return DispatchMouseEventImpl(event
);
829 bool RootWindow::OnHostScrollEvent(ui::ScrollEvent
* event
) {
830 DispatchHeldEvents();
832 TransformEventForDeviceScaleFactor(event
);
833 SetLastMouseLocation(this, event
->location());
834 synthesize_mouse_move_
= false;
836 Window
* target
= mouse_pressed_handler_
?
837 mouse_pressed_handler_
: client::GetCaptureWindow(this);
840 target
= GetEventHandlerForPoint(event
->location());
845 event
->ConvertLocationToTarget(static_cast<Window
*>(this), target
);
846 int flags
= event
->flags();
847 if (IsNonClientLocation(target
, event
->location()))
848 flags
|= ui::EF_IS_NON_CLIENT
;
849 event
->set_flags(flags
);
851 ProcessEvent(target
, event
);
852 return event
->handled();
855 bool RootWindow::OnHostTouchEvent(ui::TouchEvent
* event
) {
856 if ((event
->type() == ui::ET_TOUCH_MOVED
)) {
857 if (move_hold_count_
) {
858 Window
* null_window
= static_cast<Window
*>(NULL
);
859 held_move_event_
.reset(
860 new ui::TouchEvent(*event
, null_window
, null_window
));
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 DispatchHeldEvents();
870 return DispatchTouchEventImpl(event
);
873 void RootWindow::OnHostCancelMode() {
874 ui::CancelModeEvent event
;
875 Window
* focused_window
= client::GetFocusClient(this)->GetFocusedWindow();
876 ProcessEvent(focused_window
? focused_window
: this, &event
);
879 void RootWindow::OnHostActivated() {
880 Env::GetInstance()->RootWindowActivated(this);
883 void RootWindow::OnHostLostWindowCapture() {
884 Window
* capture_window
= client::GetCaptureWindow(this);
885 if (capture_window
&& capture_window
->GetRootWindow() == this)
886 capture_window
->ReleaseCapture();
889 void RootWindow::OnHostLostMouseGrab() {
890 mouse_pressed_handler_
= NULL
;
891 mouse_moved_handler_
= NULL
;
894 void RootWindow::OnHostPaint(const gfx::Rect
& damage_rect
) {
895 compositor_
->ScheduleRedrawRect(damage_rect
);
898 void RootWindow::OnHostMoved(const gfx::Point
& origin
) {
899 FOR_EACH_OBSERVER(RootWindowObserver
, observers_
,
900 OnRootWindowHostMoved(this, origin
));
903 void RootWindow::OnHostResized(const gfx::Size
& size
) {
904 DispatchHeldEvents();
905 // The compositor should have the same size as the native root window host.
906 // Get the latest scale from display because it might have been changed.
907 compositor_
->SetScaleAndSize(GetDeviceScaleFactorFromDisplay(this), size
);
909 // The layer, and the observers should be notified of the
910 // transformed size of the root window.
911 UpdateRootWindowSize(size
);
912 FOR_EACH_OBSERVER(RootWindowObserver
, observers_
,
913 OnRootWindowHostResized(this));
916 float RootWindow::GetDeviceScaleFactor() {
917 return compositor()->device_scale_factor();
920 RootWindow
* RootWindow::AsRootWindow() {
924 ////////////////////////////////////////////////////////////////////////////////
925 // RootWindow, private:
927 bool RootWindow::DispatchMouseEventImpl(ui::MouseEvent
* event
) {
928 TransformEventForDeviceScaleFactor(event
);
929 Window
* target
= mouse_pressed_handler_
?
930 mouse_pressed_handler_
: client::GetCaptureWindow(this);
932 target
= GetEventHandlerForPoint(event
->location());
933 return DispatchMouseEventToTarget(event
, target
);
936 void RootWindow::DispatchMouseEventRepost(ui::MouseEvent
* event
) {
937 if (event
->type() != ui::ET_MOUSE_PRESSED
)
939 Window
* target
= client::GetCaptureWindow(this);
940 RootWindow
* root
= this;
942 target
= GetEventHandlerForPoint(event
->location());
944 root
= target
->GetRootWindow();
945 CHECK(root
); // Capture window better be in valid root.
947 root
->mouse_pressed_handler_
= NULL
;
948 root
->DispatchMouseEventToTarget(event
, target
);
951 bool RootWindow::DispatchMouseEventToTarget(ui::MouseEvent
* event
,
953 client::CursorClient
* cursor_client
= client::GetCursorClient(this);
955 !cursor_client
->IsMouseEventsEnabled() &&
956 (event
->flags() & ui::EF_IS_SYNTHESIZED
))
959 static const int kMouseButtonFlagMask
=
960 ui::EF_LEFT_MOUSE_BUTTON
|
961 ui::EF_MIDDLE_MOUSE_BUTTON
|
962 ui::EF_RIGHT_MOUSE_BUTTON
;
963 // WARNING: because of nested message loops |this| may be deleted after
964 // dispatching any event. Do not use AutoReset or the like here.
965 WindowTracker destroyed_tracker
;
966 destroyed_tracker
.Add(this);
967 SetLastMouseLocation(this, event
->location());
968 synthesize_mouse_move_
= false;
969 switch (event
->type()) {
970 case ui::ET_MOUSE_EXITED
:
972 DispatchMouseEnterOrExit(*event
, ui::ET_MOUSE_EXITED
);
973 if (!destroyed_tracker
.Contains(this))
975 mouse_moved_handler_
= NULL
;
978 case ui::ET_MOUSE_MOVED
:
979 // Send an exit to the current |mouse_moved_handler_| and an enter to
980 // |target|. Take care that both us and |target| aren't destroyed during
982 if (target
!= mouse_moved_handler_
) {
983 aura::Window
* old_mouse_moved_handler
= mouse_moved_handler_
;
985 destroyed_tracker
.Add(target
);
986 DispatchMouseEnterOrExit(*event
, ui::ET_MOUSE_EXITED
);
987 if (!destroyed_tracker
.Contains(this))
989 // If the |mouse_moved_handler_| changes out from under us, assume a
990 // nested message loop ran and we don't need to do anything.
991 if (mouse_moved_handler_
!= old_mouse_moved_handler
)
993 if (destroyed_tracker
.Contains(target
)) {
994 destroyed_tracker
.Remove(target
);
995 mouse_moved_handler_
= target
;
996 DispatchMouseEnterOrExit(*event
, ui::ET_MOUSE_ENTERED
);
997 if (!destroyed_tracker
.Contains(this))
1000 mouse_moved_handler_
= NULL
;
1005 case ui::ET_MOUSE_PRESSED
:
1006 // Don't set the mouse pressed handler for non client mouse down events.
1007 // These are only sent by Windows and are not always followed with non
1008 // client mouse up events which causes subsequent mouse events to be
1009 // sent to the wrong target.
1010 if (!(event
->flags() & ui::EF_IS_NON_CLIENT
) && !mouse_pressed_handler_
)
1011 mouse_pressed_handler_
= target
;
1012 Env::GetInstance()->set_mouse_button_flags(
1013 event
->flags() & kMouseButtonFlagMask
);
1015 case ui::ET_MOUSE_RELEASED
:
1016 mouse_pressed_handler_
= NULL
;
1017 Env::GetInstance()->set_mouse_button_flags(event
->flags() &
1018 kMouseButtonFlagMask
& ~event
->changed_button_flags());
1025 event
->ConvertLocationToTarget(static_cast<Window
*>(this), target
);
1026 if (IsNonClientLocation(target
, event
->location()))
1027 event
->set_flags(event
->flags() | ui::EF_IS_NON_CLIENT
);
1028 ProcessEvent(target
, event
);
1029 if (!destroyed_tracker
.Contains(this))
1031 result
= event
->handled();
1038 bool RootWindow::DispatchTouchEventImpl(ui::TouchEvent
* event
) {
1039 switch (event
->type()) {
1040 case ui::ET_TOUCH_PRESSED
:
1041 touch_ids_down_
|= (1 << event
->touch_id());
1042 Env::GetInstance()->set_touch_down(touch_ids_down_
!= 0);
1045 // Handle ET_TOUCH_CANCELLED only if it has a native event.
1046 case ui::ET_TOUCH_CANCELLED
:
1047 if (!event
->HasNativeEvent())
1050 case ui::ET_TOUCH_RELEASED
:
1051 touch_ids_down_
= (touch_ids_down_
| (1 << event
->touch_id())) ^
1052 (1 << event
->touch_id());
1053 Env::GetInstance()->set_touch_down(touch_ids_down_
!= 0);
1059 TransformEventForDeviceScaleFactor(event
);
1060 bool handled
= false;
1061 Window
* target
= client::GetCaptureWindow(this);
1063 target
= ConsumerToWindow(
1064 ui::GestureRecognizer::Get()->GetTouchLockedTarget(event
));
1066 target
= ConsumerToWindow(ui::GestureRecognizer::Get()->
1067 GetTargetForLocation(event
->location()));
1071 // The gesture recognizer processes touch events in the system coordinates. So
1072 // keep a copy of the touch event here before possibly converting the event to
1073 // a window's local coordinate system.
1074 ui::TouchEvent
event_for_gr(*event
);
1076 ui::EventResult result
= ui::ER_UNHANDLED
;
1077 if (!target
&& !bounds().Contains(event
->location())) {
1078 // If the initial touch is outside the root window, target the root.
1080 ProcessEvent(target
? target
: NULL
, event
);
1081 result
= event
->result();
1083 // We only come here when the first contact was within the root window.
1085 target
= GetEventHandlerForPoint(event
->location());
1090 event
->ConvertLocationToTarget(static_cast<Window
*>(this), target
);
1091 ProcessEvent(target
, event
);
1092 handled
= event
->handled();
1093 result
= event
->result();
1096 // Get the list of GestureEvents from GestureRecognizer.
1097 scoped_ptr
<ui::GestureRecognizer::Gestures
> gestures
;
1098 gestures
.reset(ui::GestureRecognizer::Get()->
1099 ProcessTouchEventForGesture(event_for_gr
, result
, target
));
1101 return ProcessGestures(gestures
.get()) ? true : handled
;
1104 bool RootWindow::DispatchGestureEventRepost(ui::GestureEvent
* event
) {
1105 if (event
->type() != ui::ET_GESTURE_TAP_DOWN
)
1108 // Cleanup stale gesture events for the old gesture target.
1109 GestureConsumer
* old_consumer
= GetGestureTarget(event
);
1111 CleanupGestureRecognizerState(static_cast<aura::Window
*>(old_consumer
));
1113 Window
* new_consumer
= GetEventHandlerForPoint(event
->root_location());
1115 ui::GestureEvent
begin_gesture(
1116 ui::ET_GESTURE_BEGIN
,
1120 event
->time_stamp(),
1121 ui::GestureEventDetails(ui::ET_GESTURE_BEGIN
, 0, 0),
1122 event
->touch_ids_bitfield());
1123 ProcessEvent(new_consumer
, &begin_gesture
);
1124 ProcessEvent(new_consumer
, event
);
1125 return event
->handled();
1130 void RootWindow::DispatchHeldEvents() {
1131 if (held_repostable_event_
) {
1132 if (held_repostable_event_
->type() == ui::ET_MOUSE_PRESSED
) {
1133 ui::MouseEvent
mouse_event(
1134 static_cast<const ui::MouseEvent
&>(*held_repostable_event_
.get()));
1135 held_repostable_event_
.reset(); // must be reset before dispatch
1136 DispatchMouseEventRepost(&mouse_event
);
1138 DCHECK(held_repostable_event_
->type() == ui::ET_GESTURE_TAP_DOWN
);
1139 ui::GestureEvent
gesture_event(
1140 static_cast<const ui::GestureEvent
&>(*held_repostable_event_
.get()));
1141 held_repostable_event_
.reset(); // must be reset before dispatch
1142 DispatchGestureEventRepost(&gesture_event
);
1144 held_repostable_event_
.reset();
1146 if (held_move_event_
&& held_move_event_
->IsMouseEvent()) {
1147 // If a mouse move has been synthesized, the target location is suspect,
1148 // so drop the held event.
1149 if (!synthesize_mouse_move_
)
1150 DispatchMouseEventImpl(
1151 static_cast<ui::MouseEvent
*>(held_move_event_
.get()));
1152 held_move_event_
.reset();
1153 } else if (held_move_event_
&& held_move_event_
->IsTouchEvent()) {
1154 DispatchTouchEventImpl(
1155 static_cast<ui::TouchEvent
*>(held_move_event_
.get()));
1156 held_move_event_
.reset();
1160 void RootWindow::PostMouseMoveEventAfterWindowChange() {
1161 if (synthesize_mouse_move_
)
1163 synthesize_mouse_move_
= true;
1164 base::MessageLoop::current()->PostTask(
1166 base::Bind(&RootWindow::SynthesizeMouseMoveEvent
,
1167 event_factory_
.GetWeakPtr()));
1170 void RootWindow::SynthesizeMouseMoveEvent() {
1171 if (!synthesize_mouse_move_
)
1173 synthesize_mouse_move_
= false;
1174 gfx::Point root_mouse_location
= GetLastMouseLocationInRoot();
1175 if (!bounds().Contains(root_mouse_location
))
1177 gfx::Point host_mouse_location
= root_mouse_location
;
1178 ConvertPointToHost(&host_mouse_location
);
1180 ui::MouseEvent
event(ui::ET_MOUSE_MOVED
,
1181 host_mouse_location
,
1182 host_mouse_location
,
1183 ui::EF_IS_SYNTHESIZED
);
1184 OnHostMouseEvent(&event
);
1187 gfx::Transform
RootWindow::GetInverseRootTransform() const {
1188 float scale
= ui::GetDeviceScaleFactor(layer());
1189 gfx::Transform transform
;
1190 transform
.Scale(1.0f
/ scale
, 1.0f
/ scale
);
1191 return transformer_
->GetInverseTransform() * transform
;