Adds back logic to reset mouse handlers in other roots on capture
[chromium-blink-merge.git] / ui / aura / root_window.cc
blob6aa65fe4400fc0ad30485841a5e9f2864e8aef0d
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"
7 #include <vector>
9 #include "base/bind.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"
40 using std::vector;
42 namespace aura {
44 namespace {
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())
53 return false;
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);
71 if (client) {
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);
75 } else {
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);
85 return host;
88 class SimpleRootWindowTransformer : public RootWindowTransformer {
89 public:
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 {
98 return transform_;
101 virtual gfx::Transform GetInverseTransform() const OVERRIDE {
102 gfx::Transform invert;
103 if (!transform_.GetInverse(&invert))
104 return transform_;
105 return 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();
120 private:
121 virtual ~SimpleRootWindowTransformer() {}
123 const RootWindow* root_window_;
124 const gfx::Transform transform_;
126 DISALLOW_COPY_AND_ASSIGN(SimpleRootWindowTransformer);
129 } // namespace
131 RootWindow::CreateParams::CreateParams(const gfx::Rect& a_initial_bounds)
132 : initial_bounds(a_initial_bounds),
133 host(NULL) {
136 ////////////////////////////////////////////////////////////////////////////////
137 // RootWindow, public:
139 RootWindow::RootWindow(const CreateParams& params)
140 : Window(NULL),
141 host_(CreateHost(this, params)),
142 touch_ids_down_(0),
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),
148 move_hold_count_(0),
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,
159 this));
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.
170 compositor_.reset();
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())
183 host_.reset(NULL);
186 // static
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);
201 Show();
204 void RootWindow::ShowRootWindow() {
205 host_->Show();
208 void RootWindow::HideRootWindow() {
209 host_->Hide();
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(
225 new ui::MouseEvent(
226 static_cast<const ui::MouseEvent&>(event),
227 static_cast<aura::Window*>(event.target()),
228 static_cast<aura::Window*>(this)));
229 } else {
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(
237 FROM_HERE,
238 base::Bind(&RootWindow::DispatchHeldEvents,
239 repostable_event_factory_.GetWeakPtr()));
242 RootWindowHostDelegate* RootWindow::AsRootWindowHostDelegate() {
243 return this;
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.
253 gfx::Point point;
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.
287 if (!show)
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);
326 if (!target) {
327 target = ConsumerToWindow(
328 ui::GestureRecognizer::Get()->GetTargetForGestureEvent(event));
331 return target;
334 bool RootWindow::DispatchGestureEvent(ui::GestureEvent* event) {
335 DispatchHeldEvents();
337 Window* target = GetGestureTarget(event);
338 if (target) {
339 event->ConvertLocationToTarget(static_cast<Window*>(this), target);
340 ProcessEvent(target, event);
341 return event->handled();
344 return false;
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) {
384 if (!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,
446 Window* window,
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();
465 ++move_hold_count_;
466 TRACE_EVENT_ASYNC_BEGIN0("ui", "RootWindow::HoldPointerMoves", this);
469 void RootWindow::ReleasePointerMoves() {
470 --move_hold_count_;
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(
478 FROM_HERE,
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);
492 if (client)
493 client->ConvertPointFromScreen(this, &location);
494 return 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
507 // size immediately.
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();
517 return transform;
520 ////////////////////////////////////////////////////////////////////////////////
521 // RootWindow, Window overrides:
523 RootWindow* RootWindow::GetRootWindow() {
524 return this;
527 const RootWindow* RootWindow::GetRootWindow() const {
528 return this;
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 {
538 return IsVisible();
541 bool RootWindow::CanReceiveEvents() const {
542 return IsVisible();
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);
557 if (cursor_client) {
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())
568 return;
570 ui::MouseEvent translated_event(event,
571 static_cast<Window*>(this),
572 mouse_moved_handler_,
573 type,
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())
587 return false;
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())
600 handled = true;
601 if (event_dispatch_target_ != target) // |target| has been destroyed.
602 break;
604 event_dispatch_target_ = old_target;
605 return handled;
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
633 // crbug.com/157583
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();
660 ++iter) {
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() :
675 Env::GetInstance();
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();
689 if (cursor_visible)
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) {
697 if (cursor_client) {
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
714 // Window.
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(),
722 gfx::Point(), 0);
724 ProcessEvent(old_capture, &event);
726 old_capture->delegate()->OnCaptureLost();
729 if (new_capture) {
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;
734 } else {
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() {
747 host_->SetCapture();
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)
799 return false;
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);
804 return false;
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));
817 return true;
818 } else {
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);
839 if (!target)
840 target = GetEventHandlerForPoint(event->location());
842 if (!target)
843 target = this;
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));
861 return true;
862 } else {
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() {
921 return this;
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);
931 if (!target)
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)
938 return;
939 Window* target = client::GetCaptureWindow(this);
940 RootWindow* root = this;
941 if (!target) {
942 target = GetEventHandlerForPoint(event->location());
943 } else {
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,
952 Window* target) {
953 client::CursorClient* cursor_client = client::GetCursorClient(this);
954 if (cursor_client &&
955 !cursor_client->IsMouseEventsEnabled() &&
956 (event->flags() & ui::EF_IS_SYNTHESIZED))
957 return false;
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:
971 if (!target) {
972 DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED);
973 if (!destroyed_tracker.Contains(this))
974 return false;
975 mouse_moved_handler_ = NULL;
977 break;
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
981 // dispatch.
982 if (target != mouse_moved_handler_) {
983 aura::Window* old_mouse_moved_handler = mouse_moved_handler_;
984 if (target)
985 destroyed_tracker.Add(target);
986 DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED);
987 if (!destroyed_tracker.Contains(this))
988 return false;
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)
992 return false;
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))
998 return false;
999 } else {
1000 mouse_moved_handler_ = NULL;
1001 return false;
1004 break;
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);
1014 break;
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());
1019 break;
1020 default:
1021 break;
1023 bool result;
1024 if (target) {
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))
1030 return false;
1031 result = event->handled();
1032 } else {
1033 result = false;
1035 return result;
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);
1043 break;
1045 // Handle ET_TOUCH_CANCELLED only if it has a native event.
1046 case ui::ET_TOUCH_CANCELLED:
1047 if (!event->HasNativeEvent())
1048 break;
1049 // fallthrough
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);
1054 break;
1056 default:
1057 break;
1059 TransformEventForDeviceScaleFactor(event);
1060 bool handled = false;
1061 Window* target = client::GetCaptureWindow(this);
1062 if (!target) {
1063 target = ConsumerToWindow(
1064 ui::GestureRecognizer::Get()->GetTouchLockedTarget(event));
1065 if (!target) {
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.
1079 target = this;
1080 ProcessEvent(target ? target : NULL, event);
1081 result = event->result();
1082 } else {
1083 // We only come here when the first contact was within the root window.
1084 if (!target) {
1085 target = GetEventHandlerForPoint(event->location());
1086 if (!target)
1087 return false;
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)
1106 return false;
1108 // Cleanup stale gesture events for the old gesture target.
1109 GestureConsumer* old_consumer = GetGestureTarget(event);
1110 if (old_consumer)
1111 CleanupGestureRecognizerState(static_cast<aura::Window*>(old_consumer));
1113 Window* new_consumer = GetEventHandlerForPoint(event->root_location());
1114 if (new_consumer) {
1115 ui::GestureEvent begin_gesture(
1116 ui::ET_GESTURE_BEGIN,
1117 event->x(),
1118 event->y(),
1119 event->flags(),
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();
1127 return false;
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);
1137 } else {
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_)
1162 return;
1163 synthesize_mouse_move_ = true;
1164 base::MessageLoop::current()->PostTask(
1165 FROM_HERE,
1166 base::Bind(&RootWindow::SynthesizeMouseMoveEvent,
1167 event_factory_.GetWeakPtr()));
1170 void RootWindow::SynthesizeMouseMoveEvent() {
1171 if (!synthesize_mouse_move_)
1172 return;
1173 synthesize_mouse_move_ = false;
1174 gfx::Point root_mouse_location = GetLastMouseLocationInRoot();
1175 if (!bounds().Contains(root_mouse_location))
1176 return;
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;
1194 } // namespace aura