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 gfx::Display display = gfx::Screen::GetScreenFor(window)->
60 GetDisplayNearestWindow(window);
61 DCHECK(display.is_valid());
62 return display.device_scale_factor();
65 Window* ConsumerToWindow(ui::GestureConsumer* consumer) {
66 return consumer ? static_cast<Window*>(consumer) : NULL;
69 void SetLastMouseLocation(const RootWindow* root_window,
70 const gfx::Point& location_in_root) {
71 client::ScreenPositionClient* client =
72 client::GetScreenPositionClient(root_window);
74 gfx::Point location_in_screen = location_in_root;
75 client->ConvertPointToScreen(root_window, &location_in_screen);
76 Env::GetInstance()->set_last_mouse_location(location_in_screen);
78 Env::GetInstance()->set_last_mouse_location(location_in_root);
82 RootWindowHost* CreateHost(RootWindow* root_window,
83 const RootWindow::CreateParams& params) {
84 RootWindowHost* host = params.host ?
85 params.host : RootWindowHost::Create(params.initial_bounds);
86 host->SetDelegate(root_window);
90 class SimpleRootWindowTransformer : public RootWindowTransformer {
92 SimpleRootWindowTransformer(const RootWindow* root_window,
93 const gfx::Transform& transform)
94 : root_window_(root_window),
95 transform_(transform) {
98 // RootWindowTransformer overrides:
99 virtual gfx::Transform GetTransform() const OVERRIDE {
103 virtual gfx::Transform GetInverseTransform() const OVERRIDE {
104 gfx::Transform invert;
105 if (!transform_.GetInverse(&invert))
110 virtual gfx::Rect GetRootWindowBounds(
111 const gfx::Size& host_size) const OVERRIDE {
112 gfx::Rect bounds(host_size);
113 gfx::RectF new_bounds(ui::ConvertRectToDIP(root_window_->layer(), bounds));
114 transform_.TransformRect(&new_bounds);
115 return gfx::Rect(gfx::ToFlooredSize(new_bounds.size()));
118 virtual gfx::Insets GetHostInsets() const OVERRIDE {
119 return gfx::Insets();
123 virtual ~SimpleRootWindowTransformer() {}
125 const RootWindow* root_window_;
126 const gfx::Transform transform_;
128 DISALLOW_COPY_AND_ASSIGN(SimpleRootWindowTransformer);
133 RootWindow::CreateParams::CreateParams(const gfx::Rect& a_initial_bounds)
134 : initial_bounds(a_initial_bounds),
138 ////////////////////////////////////////////////////////////////////////////////
139 // RootWindow, public:
141 RootWindow::RootWindow(const CreateParams& params)
143 host_(CreateHost(this, params)),
145 last_cursor_(ui::kCursorNull),
146 mouse_pressed_handler_(NULL),
147 mouse_moved_handler_(NULL),
148 event_dispatch_target_(NULL),
149 synthesize_mouse_move_(false),
152 held_event_factory_(this) {
153 set_dispatcher(this);
154 SetName("RootWindow");
156 compositor_.reset(new ui::Compositor(host_->GetAcceleratedWidget()));
157 DCHECK(compositor_.get());
159 prop_.reset(new ui::ViewProp(host_->GetAcceleratedWidget(),
160 kRootWindowForAcceleratedWidget,
162 ui::GestureRecognizer::Get()->AddGestureEventHelper(this);
165 RootWindow::~RootWindow() {
166 TRACE_EVENT0("shutdown", "RootWindow::Destructor");
168 ui::GestureRecognizer::Get()->RemoveGestureEventHelper(this);
170 // Make sure to destroy the compositor before terminating so that state is
171 // cleared and we don't hit asserts.
174 // An observer may have been added by an animation on the RootWindow.
175 layer()->GetAnimator()->RemoveObserver(this);
177 // Destroy child windows while we're still valid. This is also done by
178 // ~Window, but by that time any calls to virtual methods overriden here (such
179 // as GetRootWindow()) result in Window's implementation. By destroying here
180 // we ensure GetRootWindow() still returns this.
181 RemoveOrDestroyChildren();
183 // Destroying/removing child windows may try to access |host_| (eg.
184 // GetAcceleratedWidget())
187 set_dispatcher(NULL);
191 RootWindow* RootWindow::GetForAcceleratedWidget(
192 gfx::AcceleratedWidget widget) {
193 return reinterpret_cast<RootWindow*>(
194 ui::ViewProp::GetValue(widget, kRootWindowForAcceleratedWidget));
197 void RootWindow::Init() {
198 compositor()->SetScaleAndSize(GetDeviceScaleFactorFromDisplay(this),
199 host_->GetBounds().size());
200 Window::Init(ui::LAYER_NOT_DRAWN);
201 compositor()->SetRootLayer(layer());
202 transformer_.reset(new SimpleRootWindowTransformer(this, gfx::Transform()));
203 UpdateRootWindowSize(GetHostSize());
204 Env::GetInstance()->NotifyRootWindowInitialized(this);
208 void RootWindow::ShowRootWindow() {
212 void RootWindow::HideRootWindow() {
216 void RootWindow::PrepareForShutdown() {
217 host_->PrepareForShutdown();
218 // discard synthesize event request as well.
219 synthesize_mouse_move_ = false;
222 void RootWindow::RepostEvent(const ui::LocatedEvent& event) {
223 DCHECK(event.type() == ui::ET_MOUSE_PRESSED ||
224 event.type() == ui::ET_GESTURE_TAP_DOWN);
225 // We allow for only one outstanding repostable event. This is used
226 // in exiting context menus. A dropped repost request is allowed.
227 if (event.type() == ui::ET_MOUSE_PRESSED) {
228 held_repostable_event_.reset(
230 static_cast<const ui::MouseEvent&>(event),
231 static_cast<aura::Window*>(event.target()),
232 static_cast<aura::Window*>(this)));
233 base::MessageLoop::current()->PostTask(
235 base::Bind(&RootWindow::DispatchHeldEvents,
236 weak_factory_.GetWeakPtr()));
238 DCHECK(event.type() == ui::ET_GESTURE_TAP_DOWN);
239 held_repostable_event_.reset();
240 // TODO(rbyers): Reposing of gestures is tricky to get
241 // right, so it's not yet supported. crbug.com/170987.
245 RootWindowHostDelegate* RootWindow::AsRootWindowHostDelegate() {
249 void RootWindow::SetHostSize(const gfx::Size& size_in_pixel) {
250 DispatchHeldEvents();
251 gfx::Rect bounds = host_->GetBounds();
252 bounds.set_size(size_in_pixel);
253 host_->SetBounds(bounds);
255 // Requery the location to constrain it within the new root window size.
257 if (host_->QueryMouseLocation(&point))
258 SetLastMouseLocation(this, ui::ConvertPointToDIP(layer(), point));
260 synthesize_mouse_move_ = false;
263 gfx::Size RootWindow::GetHostSize() const {
264 return host_->GetBounds().size();
267 void RootWindow::SetHostBounds(const gfx::Rect& bounds_in_pixel) {
268 DCHECK(!bounds_in_pixel.IsEmpty());
269 DispatchHeldEvents();
270 host_->SetBounds(bounds_in_pixel);
271 synthesize_mouse_move_ = false;
274 gfx::Point RootWindow::GetHostOrigin() const {
275 return host_->GetBounds().origin();
278 void RootWindow::SetCursor(gfx::NativeCursor cursor) {
279 last_cursor_ = cursor;
280 // A lot of code seems to depend on NULL cursors actually showing an arrow,
281 // so just pass everything along to the host.
282 host_->SetCursor(cursor);
285 void RootWindow::OnCursorVisibilityChanged(bool show) {
286 // Clear any existing mouse hover effects when the cursor becomes invisible.
287 // Note we do not need to dispatch a mouse enter when the cursor becomes
288 // visible because that can only happen in response to a mouse event, which
289 // will trigger its own mouse enter.
291 DispatchMouseExitAtPoint(GetLastMouseLocationInRoot());
293 host_->OnCursorVisibilityChanged(show);
296 void RootWindow::OnMouseEventsEnableStateChanged(bool enabled) {
297 // Send entered / exited so that visual state can be updated to match
298 // mouse events state.
299 PostMouseMoveEventAfterWindowChange();
300 // TODO(mazda): Add code to disable mouse events when |enabled| == false.
303 void RootWindow::MoveCursorTo(const gfx::Point& location_in_dip) {
304 gfx::Point host_location(location_in_dip);
305 ConvertPointToHost(&host_location);
306 MoveCursorToInternal(location_in_dip, host_location);
309 void RootWindow::MoveCursorToHostLocation(const gfx::Point& host_location) {
310 gfx::Point root_location(host_location);
311 ConvertPointFromHost(&root_location);
312 MoveCursorToInternal(root_location, host_location);
315 bool RootWindow::ConfineCursorToWindow() {
316 // We would like to be able to confine the cursor to that window. However,
317 // currently, we do not have such functionality in X. So we just confine
318 // to the root window. This is ok because this option is currently only
319 // being used in fullscreen mode, so root_window bounds = window bounds.
320 return host_->ConfineCursorToRootWindow();
323 void RootWindow::UnConfineCursor() {
324 host_->UnConfineCursor();
327 void RootWindow::ScheduleRedrawRect(const gfx::Rect& damage_rect) {
328 compositor_->ScheduleRedrawRect(damage_rect);
331 Window* RootWindow::GetGestureTarget(ui::GestureEvent* event) {
332 Window* target = client::GetCaptureWindow(this);
334 target = ConsumerToWindow(
335 ui::GestureRecognizer::Get()->GetTargetForGestureEvent(event));
341 bool RootWindow::DispatchGestureEvent(ui::GestureEvent* event) {
342 DispatchHeldEvents();
344 Window* target = GetGestureTarget(event);
346 event->ConvertLocationToTarget(static_cast<Window*>(this), target);
347 ProcessEvent(target, event);
348 return event->handled();
354 void RootWindow::OnWindowDestroying(Window* window) {
355 DispatchMouseExitToHidingWindow(window);
356 OnWindowHidden(window, WINDOW_DESTROYED);
358 if (window->IsVisible() &&
359 window->ContainsPointInRoot(GetLastMouseLocationInRoot())) {
360 PostMouseMoveEventAfterWindowChange();
364 void RootWindow::OnWindowBoundsChanged(Window* window,
365 bool contained_mouse_point) {
366 if (contained_mouse_point ||
367 (window->IsVisible() &&
368 window->ContainsPointInRoot(GetLastMouseLocationInRoot()))) {
369 PostMouseMoveEventAfterWindowChange();
373 void RootWindow::DispatchMouseExitToHidingWindow(Window* window) {
374 // The mouse capture is intentionally ignored. Think that a mouse enters
375 // to a window, the window sets the capture, the mouse exits the window,
376 // and then it releases the capture. In that case OnMouseExited won't
377 // be called. So it is natural not to emit OnMouseExited even though
378 // |window| is the capture window.
379 gfx::Point last_mouse_location = GetLastMouseLocationInRoot();
380 if (window->Contains(mouse_moved_handler_) &&
381 window->ContainsPointInRoot(last_mouse_location))
382 DispatchMouseExitAtPoint(last_mouse_location);
385 void RootWindow::DispatchMouseExitAtPoint(const gfx::Point& point) {
386 ui::MouseEvent event(ui::ET_MOUSE_EXITED, point, point, ui::EF_NONE);
387 DispatchMouseEnterOrExit(event, ui::ET_MOUSE_EXITED);
390 void RootWindow::OnWindowVisibilityChanged(Window* window, bool is_visible) {
392 OnWindowHidden(window, WINDOW_HIDDEN);
394 if (window->ContainsPointInRoot(GetLastMouseLocationInRoot()))
395 PostMouseMoveEventAfterWindowChange();
398 void RootWindow::OnWindowTransformed(Window* window, bool contained_mouse) {
399 if (contained_mouse ||
400 (window->IsVisible() &&
401 window->ContainsPointInRoot(GetLastMouseLocationInRoot()))) {
402 PostMouseMoveEventAfterWindowChange();
406 void RootWindow::OnKeyboardMappingChanged() {
407 FOR_EACH_OBSERVER(RootWindowObserver, observers_,
408 OnKeyboardMappingChanged(this));
411 void RootWindow::OnRootWindowHostCloseRequested() {
412 FOR_EACH_OBSERVER(RootWindowObserver, observers_,
413 OnRootWindowHostCloseRequested(this));
416 void RootWindow::AddRootWindowObserver(RootWindowObserver* observer) {
417 observers_.AddObserver(observer);
420 void RootWindow::RemoveRootWindowObserver(RootWindowObserver* observer) {
421 observers_.RemoveObserver(observer);
424 void RootWindow::PostNativeEvent(const base::NativeEvent& native_event) {
425 host_->PostNativeEvent(native_event);
428 void RootWindow::ConvertPointToNativeScreen(gfx::Point* point) const {
429 ConvertPointToHost(point);
430 gfx::Point location = host_->GetLocationOnNativeScreen();
431 point->Offset(location.x(), location.y());
434 void RootWindow::ConvertPointFromNativeScreen(gfx::Point* point) const {
435 gfx::Point location = host_->GetLocationOnNativeScreen();
436 point->Offset(-location.x(), -location.y());
437 ConvertPointFromHost(point);
440 void RootWindow::ConvertPointToHost(gfx::Point* point) const {
441 gfx::Point3F point_3f(*point);
442 GetRootTransform().TransformPoint(&point_3f);
443 *point = gfx::ToFlooredPoint(point_3f.AsPointF());
446 void RootWindow::ConvertPointFromHost(gfx::Point* point) const {
447 gfx::Point3F point_3f(*point);
448 GetInverseRootTransform().TransformPoint(&point_3f);
449 *point = gfx::ToFlooredPoint(point_3f.AsPointF());
452 void RootWindow::ProcessedTouchEvent(ui::TouchEvent* event,
454 ui::EventResult result) {
455 scoped_ptr<ui::GestureRecognizer::Gestures> gestures;
456 gestures.reset(ui::GestureRecognizer::Get()->
457 ProcessTouchEventForGesture(*event, result, window));
458 ProcessGestures(gestures.get());
461 gfx::AcceleratedWidget RootWindow::GetAcceleratedWidget() {
462 return host_->GetAcceleratedWidget();
465 void RootWindow::ToggleFullScreen() {
466 host_->ToggleFullScreen();
469 void RootWindow::HoldPointerMoves() {
470 if (!move_hold_count_)
471 held_event_factory_.InvalidateWeakPtrs();
473 TRACE_EVENT_ASYNC_BEGIN0("ui", "RootWindow::HoldPointerMoves", this);
476 void RootWindow::ReleasePointerMoves() {
478 DCHECK_GE(move_hold_count_, 0);
479 if (!move_hold_count_ && held_move_event_) {
480 // We don't want to call DispatchHeldEvents directly, because this might be
481 // called from a deep stack while another event, in which case dispatching
482 // another one may not be safe/expected. Instead we post a task, that we
483 // may cancel if HoldPointerMoves is called again before it executes.
484 base::MessageLoop::current()->PostTask(
486 base::Bind(&RootWindow::DispatchHeldEvents,
487 held_event_factory_.GetWeakPtr()));
489 TRACE_EVENT_ASYNC_END0("ui", "RootWindow::HoldPointerMoves", this);
492 void RootWindow::SetFocusWhenShown(bool focused) {
493 host_->SetFocusWhenShown(focused);
496 gfx::Point RootWindow::GetLastMouseLocationInRoot() const {
497 gfx::Point location = Env::GetInstance()->last_mouse_location();
498 client::ScreenPositionClient* client = client::GetScreenPositionClient(this);
500 client->ConvertPointFromScreen(this, &location);
504 bool RootWindow::QueryMouseLocationForTest(gfx::Point* point) const {
505 return host_->QueryMouseLocation(point);
508 void RootWindow::SetRootWindowTransformer(
509 scoped_ptr<RootWindowTransformer> transformer) {
510 transformer_ = transformer.Pass();
511 host_->SetInsets(transformer_->GetHostInsets());
512 Window::SetTransform(transformer_->GetTransform());
513 // If the layer is not animating, then we need to update the root window
515 if (!layer()->GetAnimator()->is_animating())
516 UpdateRootWindowSize(GetHostSize());
519 gfx::Transform RootWindow::GetRootTransform() const {
520 float scale = ui::GetDeviceScaleFactor(layer());
521 gfx::Transform transform;
522 transform.Scale(scale, scale);
523 transform *= transformer_->GetTransform();
527 ////////////////////////////////////////////////////////////////////////////////
528 // RootWindow, Window overrides:
530 Window* RootWindow::GetRootWindow() {
534 const Window* RootWindow::GetRootWindow() const {
538 void RootWindow::SetTransform(const gfx::Transform& transform) {
539 scoped_ptr<RootWindowTransformer> transformer(
540 new SimpleRootWindowTransformer(this, transform));
541 SetRootWindowTransformer(transformer.Pass());
544 bool RootWindow::CanFocus() const {
548 bool RootWindow::CanReceiveEvents() const {
552 ////////////////////////////////////////////////////////////////////////////////
553 // RootWindow, private:
555 void RootWindow::TransformEventForDeviceScaleFactor(ui::LocatedEvent* event) {
556 event->UpdateForRootTransform(GetInverseRootTransform());
559 void RootWindow::MoveCursorToInternal(const gfx::Point& root_location,
560 const gfx::Point& host_location) {
561 host_->MoveCursorTo(host_location);
562 SetLastMouseLocation(this, root_location);
563 client::CursorClient* cursor_client = client::GetCursorClient(this);
565 const gfx::Display& display =
566 gfx::Screen::GetScreenFor(this)->GetDisplayNearestWindow(this);
567 cursor_client->SetDisplay(display);
569 synthesize_mouse_move_ = false;
572 void RootWindow::DispatchMouseEnterOrExit(const ui::MouseEvent& event,
573 ui::EventType type) {
574 if (!mouse_moved_handler_ || !mouse_moved_handler_->delegate())
577 ui::MouseEvent translated_event(event,
578 static_cast<Window*>(this),
579 mouse_moved_handler_,
581 event.flags() | ui::EF_IS_SYNTHESIZED);
582 ProcessEvent(mouse_moved_handler_, &translated_event);
585 void RootWindow::ProcessEvent(Window* target, ui::Event* event) {
586 Window* old_target = event_dispatch_target_;
587 event_dispatch_target_ = target;
588 if (DispatchEvent(target, event))
589 event_dispatch_target_ = old_target;
592 bool RootWindow::ProcessGestures(ui::GestureRecognizer::Gestures* gestures) {
593 if (!gestures || gestures->empty())
596 Window* target = GetGestureTarget(gestures->get().at(0));
597 Window* old_target = event_dispatch_target_;
598 event_dispatch_target_ = target;
600 bool handled = false;
601 for (size_t i = 0; i < gestures->size(); ++i) {
602 ui::GestureEvent* event = gestures->get().at(i);
603 event->ConvertLocationToTarget(static_cast<Window*>(this), target);
604 if (!DispatchEvent(target, event))
605 return false; // |this| has been destroyed.
606 if (event->handled())
608 if (event_dispatch_target_ != target) // |target| has been destroyed.
611 event_dispatch_target_ = old_target;
615 void RootWindow::OnWindowAddedToRootWindow(Window* attached) {
616 if (attached->IsVisible() &&
617 attached->ContainsPointInRoot(GetLastMouseLocationInRoot())) {
618 PostMouseMoveEventAfterWindowChange();
622 void RootWindow::OnWindowRemovedFromRootWindow(Window* detached,
624 DCHECK(aura::client::GetCaptureWindow(this) != this);
626 DispatchMouseExitToHidingWindow(detached);
627 OnWindowHidden(detached, new_root ? WINDOW_MOVING : WINDOW_HIDDEN);
629 if (detached->IsVisible() &&
630 detached->ContainsPointInRoot(GetLastMouseLocationInRoot())) {
631 PostMouseMoveEventAfterWindowChange();
635 void RootWindow::OnWindowHidden(Window* invisible, WindowHiddenReason reason) {
636 // Do not clear the capture, and the |event_dispatch_target_| if the
637 // window is moving across root windows, because the target itself
638 // is actually still visible and clearing them stops further event
639 // processing, which can cause unexpected behaviors. See
641 if (reason != WINDOW_MOVING) {
642 Window* capture_window = aura::client::GetCaptureWindow(this);
643 // If the ancestor of the capture window is hidden,
644 // release the capture.
645 if (invisible->Contains(capture_window) && invisible != this)
646 capture_window->ReleaseCapture();
648 if (invisible->Contains(event_dispatch_target_))
649 event_dispatch_target_ = NULL;
652 // If the ancestor of any event handler windows are invisible, release the
653 // pointer to those windows.
654 if (invisible->Contains(mouse_pressed_handler_))
655 mouse_pressed_handler_ = NULL;
656 if (invisible->Contains(mouse_moved_handler_))
657 mouse_moved_handler_ = NULL;
659 CleanupGestureRecognizerState(invisible);
662 void RootWindow::CleanupGestureRecognizerState(Window* window) {
663 ui::GestureRecognizer::Get()->CleanupStateForConsumer(window);
664 const Windows& windows = window->children();
665 for (Windows::const_iterator iter = windows.begin();
666 iter != windows.end();
668 CleanupGestureRecognizerState(*iter);
672 void RootWindow::UpdateRootWindowSize(const gfx::Size& host_size) {
673 SetBounds(transformer_->GetRootWindowBounds(host_size));
676 ////////////////////////////////////////////////////////////////////////////////
677 // RootWindow, ui::EventTarget implementation:
679 ui::EventTarget* RootWindow::GetParentTarget() {
680 return client::GetEventClient(this) ?
681 client::GetEventClient(this)->GetToplevelEventTarget() :
685 ////////////////////////////////////////////////////////////////////////////////
686 // RootWindow, ui::LayerDelegate implementation:
688 void RootWindow::OnDeviceScaleFactorChanged(
689 float device_scale_factor) {
690 const bool cursor_is_in_bounds =
691 GetBoundsInScreen().Contains(Env::GetInstance()->last_mouse_location());
692 bool cursor_visible = false;
693 client::CursorClient* cursor_client = client::GetCursorClient(this);
694 if (cursor_is_in_bounds && cursor_client) {
695 cursor_visible = cursor_client->IsCursorVisible();
697 cursor_client->HideCursor();
699 host_->OnDeviceScaleFactorChanged(device_scale_factor);
700 Window::OnDeviceScaleFactorChanged(device_scale_factor);
701 // Update the device scale factor of the cursor client only when the last
702 // mouse location is on this root window.
703 if (cursor_is_in_bounds) {
705 const gfx::Display& display =
706 gfx::Screen::GetScreenFor(this)->GetDisplayNearestWindow(this);
707 cursor_client->SetDisplay(display);
710 if (cursor_is_in_bounds && cursor_client && cursor_visible)
711 cursor_client->ShowCursor();
714 ////////////////////////////////////////////////////////////////////////////////
715 // RootWindow, aura::client::CaptureDelegate implementation:
717 void RootWindow::UpdateCapture(Window* old_capture,
718 Window* new_capture) {
719 // |mouse_moved_handler_| may have been set to a Window in a different root
720 // (see below). Clear it here to ensure we don't end up referencing a stale
722 if (mouse_moved_handler_ && !Contains(mouse_moved_handler_))
723 mouse_moved_handler_ = NULL;
725 if (old_capture && old_capture->GetRootWindow() == this &&
726 old_capture->delegate()) {
727 // Send a capture changed event with bogus location data.
728 ui::MouseEvent event(ui::ET_MOUSE_CAPTURE_CHANGED, gfx::Point(),
731 ProcessEvent(old_capture, &event);
733 old_capture->delegate()->OnCaptureLost();
737 // Make all subsequent mouse events go to the capture window. We shouldn't
738 // need to send an event here as OnCaptureLost() should take care of that.
739 if (mouse_moved_handler_ || Env::GetInstance()->IsMouseButtonDown())
740 mouse_moved_handler_ = new_capture;
742 // Make sure mouse_moved_handler gets updated.
743 SynthesizeMouseMoveEvent();
745 mouse_pressed_handler_ = NULL;
748 void RootWindow::OnOtherRootGotCapture() {
749 mouse_moved_handler_ = NULL;
750 mouse_pressed_handler_ = NULL;
753 void RootWindow::SetNativeCapture() {
757 void RootWindow::ReleaseNativeCapture() {
758 host_->ReleaseCapture();
761 ////////////////////////////////////////////////////////////////////////////////
762 // RootWindow, ui::EventDispatcherDelegate implementation:
764 bool RootWindow::CanDispatchToTarget(ui::EventTarget* target) {
765 return event_dispatch_target_ == target;
768 ////////////////////////////////////////////////////////////////////////////////
769 // RootWindow, ui::GestureEventHelper implementation:
771 bool RootWindow::CanDispatchToConsumer(ui::GestureConsumer* consumer) {
772 Window* window = ConsumerToWindow(consumer);;
773 return (window && window->GetRootWindow() == this);
776 void RootWindow::DispatchPostponedGestureEvent(ui::GestureEvent* event) {
777 DispatchGestureEvent(event);
780 void RootWindow::DispatchCancelTouchEvent(ui::TouchEvent* event) {
781 OnHostTouchEvent(event);
784 ////////////////////////////////////////////////////////////////////////////////
785 // RootWindow, ui::LayerAnimationObserver implementation:
787 void RootWindow::OnLayerAnimationEnded(
788 ui::LayerAnimationSequence* animation) {
789 UpdateRootWindowSize(GetHostSize());
792 void RootWindow::OnLayerAnimationScheduled(
793 ui::LayerAnimationSequence* animation) {
796 void RootWindow::OnLayerAnimationAborted(
797 ui::LayerAnimationSequence* animation) {
800 ////////////////////////////////////////////////////////////////////////////////
801 // RootWindow, RootWindowHostDelegate implementation:
803 bool RootWindow::OnHostKeyEvent(ui::KeyEvent* event) {
804 DispatchHeldEvents();
805 if (event->key_code() == ui::VKEY_UNKNOWN)
807 client::EventClient* client = client::GetEventClient(GetRootWindow());
808 Window* focused_window = client::GetFocusClient(this)->GetFocusedWindow();
809 if (client && !client->CanProcessEventsWithinSubtree(focused_window)) {
810 client::GetFocusClient(this)->FocusWindow(NULL);
813 ProcessEvent(focused_window ? focused_window : this, event);
814 return event->handled();
817 bool RootWindow::OnHostMouseEvent(ui::MouseEvent* event) {
818 if (event->type() == ui::ET_MOUSE_DRAGGED ||
819 (event->flags() & ui::EF_IS_SYNTHESIZED)) {
820 if (move_hold_count_) {
821 Window* null_window = static_cast<Window*>(NULL);
822 held_move_event_.reset(
823 new ui::MouseEvent(*event, null_window, null_window));
826 // We may have a held event for a period between the time move_hold_count_
827 // fell to 0 and the DispatchHeldEvents executes. Since we're going to
828 // dispatch the new event directly below, we can reset the old one.
829 held_move_event_.reset();
832 DispatchHeldEvents();
833 return DispatchMouseEventImpl(event);
836 bool RootWindow::OnHostScrollEvent(ui::ScrollEvent* event) {
837 DispatchHeldEvents();
839 TransformEventForDeviceScaleFactor(event);
840 SetLastMouseLocation(this, event->location());
841 synthesize_mouse_move_ = false;
843 Window* target = mouse_pressed_handler_ ?
844 mouse_pressed_handler_ : client::GetCaptureWindow(this);
847 target = GetEventHandlerForPoint(event->location());
852 event->ConvertLocationToTarget(static_cast<Window*>(this), target);
853 int flags = event->flags();
854 if (IsNonClientLocation(target, event->location()))
855 flags |= ui::EF_IS_NON_CLIENT;
856 event->set_flags(flags);
858 ProcessEvent(target, event);
859 return event->handled();
862 bool RootWindow::OnHostTouchEvent(ui::TouchEvent* event) {
863 if ((event->type() == ui::ET_TOUCH_MOVED)) {
864 if (move_hold_count_) {
865 Window* null_window = static_cast<Window*>(NULL);
866 held_move_event_.reset(
867 new ui::TouchEvent(*event, null_window, null_window));
870 // We may have a held event for a period between the time move_hold_count_
871 // fell to 0 and the DispatchHeldEvents executes. Since we're going to
872 // dispatch the new event directly below, we can reset the old one.
873 held_move_event_.reset();
876 DispatchHeldEvents();
877 return DispatchTouchEventImpl(event);
880 void RootWindow::OnHostCancelMode() {
881 ui::CancelModeEvent event;
882 Window* focused_window = client::GetFocusClient(this)->GetFocusedWindow();
883 ProcessEvent(focused_window ? focused_window : this, &event);
886 void RootWindow::OnHostActivated() {
887 Env::GetInstance()->RootWindowActivated(this);
890 void RootWindow::OnHostLostWindowCapture() {
891 Window* capture_window = client::GetCaptureWindow(this);
892 if (capture_window && capture_window->GetRootWindow() == this)
893 capture_window->ReleaseCapture();
896 void RootWindow::OnHostLostMouseGrab() {
897 mouse_pressed_handler_ = NULL;
898 mouse_moved_handler_ = NULL;
901 void RootWindow::OnHostPaint(const gfx::Rect& damage_rect) {
902 compositor_->ScheduleRedrawRect(damage_rect);
905 void RootWindow::OnHostMoved(const gfx::Point& origin) {
906 FOR_EACH_OBSERVER(RootWindowObserver, observers_,
907 OnRootWindowHostMoved(this, origin));
910 void RootWindow::OnHostResized(const gfx::Size& size) {
911 DispatchHeldEvents();
912 // The compositor should have the same size as the native root window host.
913 // Get the latest scale from display because it might have been changed.
914 compositor_->SetScaleAndSize(GetDeviceScaleFactorFromDisplay(this), size);
916 // The layer, and the observers should be notified of the
917 // transformed size of the root window.
918 UpdateRootWindowSize(size);
919 FOR_EACH_OBSERVER(RootWindowObserver, observers_,
920 OnRootWindowHostResized(this));
923 float RootWindow::GetDeviceScaleFactor() {
924 return compositor()->device_scale_factor();
927 RootWindow* RootWindow::AsRootWindow() {
931 ////////////////////////////////////////////////////////////////////////////////
932 // RootWindow, private:
934 bool RootWindow::DispatchMouseEventImpl(ui::MouseEvent* event) {
935 TransformEventForDeviceScaleFactor(event);
936 Window* target = mouse_pressed_handler_ ?
937 mouse_pressed_handler_ : client::GetCaptureWindow(this);
939 target = GetEventHandlerForPoint(event->location());
940 return DispatchMouseEventToTarget(event, target);
943 void RootWindow::DispatchMouseEventRepost(ui::MouseEvent* event) {
944 if (event->type() != ui::ET_MOUSE_PRESSED)
946 Window* target = client::GetCaptureWindow(this);
947 WindowEventDispatcher* dispatcher = this;
949 target = GetEventHandlerForPoint(event->location());
951 dispatcher = target->GetDispatcher();
952 CHECK(dispatcher); // Capture window better be in valid root.
954 dispatcher->mouse_pressed_handler_ = NULL;
955 dispatcher->DispatchMouseEventToTarget(event, target);
958 bool RootWindow::DispatchMouseEventToTarget(ui::MouseEvent* event,
960 client::CursorClient* cursor_client = client::GetCursorClient(this);
962 !cursor_client->IsMouseEventsEnabled() &&
963 (event->flags() & ui::EF_IS_SYNTHESIZED))
966 static const int kMouseButtonFlagMask =
967 ui::EF_LEFT_MOUSE_BUTTON |
968 ui::EF_MIDDLE_MOUSE_BUTTON |
969 ui::EF_RIGHT_MOUSE_BUTTON;
970 // WARNING: because of nested message loops |this| may be deleted after
971 // dispatching any event. Do not use AutoReset or the like here.
972 base::WeakPtr<RootWindow> ref(weak_factory_.GetWeakPtr());
973 SetLastMouseLocation(this, event->location());
974 synthesize_mouse_move_ = false;
975 switch (event->type()) {
976 case ui::ET_MOUSE_EXITED:
978 DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED);
981 mouse_moved_handler_ = NULL;
984 case ui::ET_MOUSE_MOVED:
985 // Send an exit to the current |mouse_moved_handler_| and an enter to
986 // |target|. Take care that both us and |target| aren't destroyed during
988 if (target != mouse_moved_handler_) {
989 aura::Window* old_mouse_moved_handler = mouse_moved_handler_;
990 WindowTracker destroyed_tracker;
992 destroyed_tracker.Add(target);
993 DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED);
996 // If the |mouse_moved_handler_| changes out from under us, assume a
997 // nested message loop ran and we don't need to do anything.
998 if (mouse_moved_handler_ != old_mouse_moved_handler)
1000 if (destroyed_tracker.Contains(target)) {
1001 destroyed_tracker.Remove(target);
1002 mouse_moved_handler_ = target;
1003 DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_ENTERED);
1007 mouse_moved_handler_ = NULL;
1012 case ui::ET_MOUSE_PRESSED:
1013 // Don't set the mouse pressed handler for non client mouse down events.
1014 // These are only sent by Windows and are not always followed with non
1015 // client mouse up events which causes subsequent mouse events to be
1016 // sent to the wrong target.
1017 if (!(event->flags() & ui::EF_IS_NON_CLIENT) && !mouse_pressed_handler_)
1018 mouse_pressed_handler_ = target;
1019 Env::GetInstance()->set_mouse_button_flags(
1020 event->flags() & kMouseButtonFlagMask);
1022 case ui::ET_MOUSE_RELEASED:
1023 mouse_pressed_handler_ = NULL;
1024 Env::GetInstance()->set_mouse_button_flags(event->flags() &
1025 kMouseButtonFlagMask & ~event->changed_button_flags());
1032 event->ConvertLocationToTarget(static_cast<Window*>(this), target);
1033 if (IsNonClientLocation(target, event->location()))
1034 event->set_flags(event->flags() | ui::EF_IS_NON_CLIENT);
1035 ProcessEvent(target, event);
1038 result = event->handled();
1045 bool RootWindow::DispatchTouchEventImpl(ui::TouchEvent* event) {
1046 switch (event->type()) {
1047 case ui::ET_TOUCH_PRESSED:
1048 touch_ids_down_ |= (1 << event->touch_id());
1049 Env::GetInstance()->set_touch_down(touch_ids_down_ != 0);
1052 // Handle ET_TOUCH_CANCELLED only if it has a native event.
1053 case ui::ET_TOUCH_CANCELLED:
1054 if (!event->HasNativeEvent())
1057 case ui::ET_TOUCH_RELEASED:
1058 touch_ids_down_ = (touch_ids_down_ | (1 << event->touch_id())) ^
1059 (1 << event->touch_id());
1060 Env::GetInstance()->set_touch_down(touch_ids_down_ != 0);
1066 TransformEventForDeviceScaleFactor(event);
1067 bool handled = false;
1068 Window* target = client::GetCaptureWindow(this);
1070 target = ConsumerToWindow(
1071 ui::GestureRecognizer::Get()->GetTouchLockedTarget(event));
1073 target = ConsumerToWindow(ui::GestureRecognizer::Get()->
1074 GetTargetForLocation(event->location()));
1078 // The gesture recognizer processes touch events in the system coordinates. So
1079 // keep a copy of the touch event here before possibly converting the event to
1080 // a window's local coordinate system.
1081 ui::TouchEvent event_for_gr(*event);
1083 ui::EventResult result = ui::ER_UNHANDLED;
1084 if (!target && !bounds().Contains(event->location())) {
1085 // If the initial touch is outside the root window, target the root.
1087 ProcessEvent(target ? target : NULL, event);
1088 result = event->result();
1090 // We only come here when the first contact was within the root window.
1092 target = GetEventHandlerForPoint(event->location());
1097 event->ConvertLocationToTarget(static_cast<Window*>(this), target);
1098 ProcessEvent(target, event);
1099 handled = event->handled();
1100 result = event->result();
1103 // Get the list of GestureEvents from GestureRecognizer.
1104 scoped_ptr<ui::GestureRecognizer::Gestures> gestures;
1105 gestures.reset(ui::GestureRecognizer::Get()->
1106 ProcessTouchEventForGesture(event_for_gr, result, target));
1108 return ProcessGestures(gestures.get()) ? true : handled;
1111 void RootWindow::DispatchHeldEvents() {
1112 if (held_repostable_event_) {
1113 base::WeakPtr<RootWindow> ref(weak_factory_.GetWeakPtr());
1114 if (held_repostable_event_->type() == ui::ET_MOUSE_PRESSED) {
1115 scoped_ptr<ui::MouseEvent> mouse_event(
1116 static_cast<ui::MouseEvent*>(held_repostable_event_.release()));
1117 DispatchMouseEventRepost(mouse_event.get());
1119 // TODO(rbyers): GESTURE_TAP_DOWN not yet supported: crbug.com/170987.
1125 if (held_move_event_ && held_move_event_->IsMouseEvent()) {
1126 // If a mouse move has been synthesized, the target location is suspect,
1127 // so drop the held event.
1128 if (!synthesize_mouse_move_)
1129 DispatchMouseEventImpl(
1130 static_cast<ui::MouseEvent*>(held_move_event_.get()));
1131 held_move_event_.reset();
1132 } else if (held_move_event_ && held_move_event_->IsTouchEvent()) {
1133 DispatchTouchEventImpl(
1134 static_cast<ui::TouchEvent*>(held_move_event_.get()));
1135 held_move_event_.reset();
1139 void RootWindow::PostMouseMoveEventAfterWindowChange() {
1140 if (synthesize_mouse_move_)
1142 synthesize_mouse_move_ = true;
1143 base::MessageLoop::current()->PostTask(
1145 base::Bind(&RootWindow::SynthesizeMouseMoveEvent,
1146 weak_factory_.GetWeakPtr()));
1149 void RootWindow::SynthesizeMouseMoveEvent() {
1150 if (!synthesize_mouse_move_)
1152 synthesize_mouse_move_ = false;
1153 gfx::Point root_mouse_location = GetLastMouseLocationInRoot();
1154 if (!bounds().Contains(root_mouse_location))
1156 gfx::Point host_mouse_location = root_mouse_location;
1157 ConvertPointToHost(&host_mouse_location);
1159 ui::MouseEvent event(ui::ET_MOUSE_MOVED,
1160 host_mouse_location,
1161 host_mouse_location,
1162 ui::EF_IS_SYNTHESIZED);
1163 OnHostMouseEvent(&event);
1166 gfx::Transform RootWindow::GetInverseRootTransform() const {
1167 float scale = ui::GetDeviceScaleFactor(layer());
1168 gfx::Transform transform;
1169 transform.Scale(1.0f / scale, 1.0f / scale);
1170 return transformer_->GetInverseTransform() * transform;