1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ui/aura/root_window.h" 6 7 #include <vector> 8 9 #include "base/auto_reset.h" 10 #include "base/bind.h" 11 #include "base/command_line.h" 12 #include "base/debug/trace_event.h" 13 #include "base/logging.h" 14 #include "base/message_loop/message_loop.h" 15 #include "ui/aura/client/activation_client.h" 16 #include "ui/aura/client/capture_client.h" 17 #include "ui/aura/client/cursor_client.h" 18 #include "ui/aura/client/event_client.h" 19 #include "ui/aura/client/focus_client.h" 20 #include "ui/aura/client/screen_position_client.h" 21 #include "ui/aura/env.h" 22 #include "ui/aura/root_window_host.h" 23 #include "ui/aura/root_window_observer.h" 24 #include "ui/aura/root_window_transformer.h" 25 #include "ui/aura/window.h" 26 #include "ui/aura/window_delegate.h" 27 #include "ui/aura/window_tracker.h" 28 #include "ui/base/events/event.h" 29 #include "ui/base/gestures/gesture_recognizer.h" 30 #include "ui/base/gestures/gesture_types.h" 31 #include "ui/base/hit_test.h" 32 #include "ui/base/view_prop.h" 33 #include "ui/compositor/compositor.h" 34 #include "ui/compositor/dip_util.h" 35 #include "ui/compositor/layer.h" 36 #include "ui/compositor/layer_animator.h" 37 #include "ui/gfx/display.h" 38 #include "ui/gfx/point3_f.h" 39 #include "ui/gfx/point_conversions.h" 40 #include "ui/gfx/screen.h" 41 #include "ui/gfx/size_conversions.h" 42 43 using std::vector; 44 45 namespace aura { 46 47 namespace { 48 49 const char kRootWindowForAcceleratedWidget[] = 50 "__AURA_ROOT_WINDOW_ACCELERATED_WIDGET__"; 51 52 // Returns true if |target| has a non-client (frame) component at |location|, 53 // in window coordinates. 54 bool IsNonClientLocation(Window* target, const gfx::Point& location) { 55 if (!target->delegate()) 56 return false; 57 int hit_test_code = target->delegate()->GetNonClientComponent(location); 58 return hit_test_code != HTCLIENT && hit_test_code != HTNOWHERE; 59 } 60 61 float GetDeviceScaleFactorFromDisplay(Window* window) { 62 return gfx::Screen::GetScreenFor(window)-> 63 GetDisplayNearestWindow(window).device_scale_factor(); 64 } 65 66 Window* ConsumerToWindow(ui::GestureConsumer* consumer) { 67 return consumer && !consumer->ignores_events() ? 68 static_cast<Window*>(consumer) : NULL; 69 } 70 71 void SetLastMouseLocation(const RootWindow* root_window, 72 const gfx::Point& location_in_root) { 73 client::ScreenPositionClient* client = 74 client::GetScreenPositionClient(root_window); 75 if (client) { 76 gfx::Point location_in_screen = location_in_root; 77 client->ConvertPointToScreen(root_window, &location_in_screen); 78 Env::GetInstance()->set_last_mouse_location(location_in_screen); 79 } else { 80 Env::GetInstance()->set_last_mouse_location(location_in_root); 81 } 82 } 83 84 RootWindowHost* CreateHost(RootWindow* root_window, 85 const RootWindow::CreateParams& params) { 86 RootWindowHost* host = params.host ? 87 params.host : RootWindowHost::Create(params.initial_bounds); 88 host->SetDelegate(root_window); 89 return host; 90 } 91 92 class SimpleRootWindowTransformer : public RootWindowTransformer { 93 public: 94 SimpleRootWindowTransformer(const RootWindow* root_window, 95 const gfx::Transform& transform) 96 : root_window_(root_window), 97 transform_(transform) { 98 } 99 100 // RootWindowTransformer overrides: 101 virtual gfx::Transform GetTransform() const OVERRIDE { 102 return transform_; 103 } 104 105 virtual gfx::Transform GetInverseTransform() const OVERRIDE { 106 gfx::Transform invert; 107 if (!transform_.GetInverse(&invert)) 108 return transform_; 109 return invert; 110 } 111 112 virtual gfx::Rect GetRootWindowBounds( 113 const gfx::Size& host_size) const OVERRIDE { 114 gfx::Rect bounds(host_size); 115 gfx::RectF new_bounds(ui::ConvertRectToDIP(root_window_->layer(), bounds)); 116 transform_.TransformRect(&new_bounds); 117 return gfx::Rect(gfx::ToFlooredSize(new_bounds.size())); 118 } 119 120 virtual gfx::Insets GetHostInsets() const OVERRIDE { 121 return gfx::Insets(); 122 } 123 124 private: 125 virtual ~SimpleRootWindowTransformer() {} 126 127 const RootWindow* root_window_; 128 const gfx::Transform transform_; 129 130 DISALLOW_COPY_AND_ASSIGN(SimpleRootWindowTransformer); 131 }; 132 133 } // namespace 134 135 RootWindow::CreateParams::CreateParams(const gfx::Rect& a_initial_bounds) 136 : initial_bounds(a_initial_bounds), 137 host(NULL) { 138 } 139 140 //////////////////////////////////////////////////////////////////////////////// 141 // RootWindow, public: 142 143 RootWindow::RootWindow(const CreateParams& params) 144 : Window(NULL), 145 host_(CreateHost(this, params)), 146 schedule_paint_factory_(this), 147 event_factory_(this), 148 touch_ids_down_(0), 149 last_cursor_(ui::kCursorNull), 150 mouse_pressed_handler_(NULL), 151 mouse_moved_handler_(NULL), 152 mouse_event_dispatch_target_(NULL), 153 event_dispatch_target_(NULL), 154 gesture_recognizer_(ui::GestureRecognizer::Create(this)), 155 synthesize_mouse_move_(false), 156 waiting_on_compositing_end_(false), 157 draw_on_compositing_end_(false), 158 defer_draw_scheduling_(false), 159 move_hold_count_(0), 160 held_event_factory_(this), 161 repostable_event_factory_(this) { 162 SetName("RootWindow"); 163 164 compositor_.reset(new ui::Compositor(this, host_->GetAcceleratedWidget())); 165 DCHECK(compositor_.get()); 166 compositor_->AddObserver(this); 167 168 prop_.reset(new ui::ViewProp(host_->GetAcceleratedWidget(), 169 kRootWindowForAcceleratedWidget, 170 this)); 171 } 172 173 RootWindow::~RootWindow() { 174 compositor_->RemoveObserver(this); 175 // Make sure to destroy the compositor before terminating so that state is 176 // cleared and we don't hit asserts. 177 compositor_.reset(); 178 179 // Tear down in reverse. Frees any references held by the host. 180 host_.reset(NULL); 181 182 // An observer may have been added by an animation on the RootWindow. 183 layer()->GetAnimator()->RemoveObserver(this); 184 } 185 186 // static 187 RootWindow* RootWindow::GetForAcceleratedWidget( 188 gfx::AcceleratedWidget widget) { 189 return reinterpret_cast<RootWindow*>( 190 ui::ViewProp::GetValue(widget, kRootWindowForAcceleratedWidget)); 191 } 192 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(); 202 } 203 204 void RootWindow::ShowRootWindow() { 205 host_->Show(); 206 } 207 208 void RootWindow::HideRootWindow() { 209 host_->Hide(); 210 } 211 212 void RootWindow::PrepareForShutdown() { 213 host_->PrepareForShutdown(); 214 // discard synthesize event request as well. 215 synthesize_mouse_move_ = false; 216 } 217 218 void RootWindow::RepostEvent(const ui::LocatedEvent& event) { 219 // We allow for only one outstanding repostable event. This is used 220 // in exiting context menus. A dropped repost request is allowed. 221 if (event.type() == ui::ET_MOUSE_PRESSED) { 222 held_repostable_event_.reset( 223 new ui::MouseEvent( 224 static_cast<const ui::MouseEvent&>(event), 225 static_cast<aura::Window*>(event.target()), 226 static_cast<aura::Window*>(this))); 227 base::MessageLoop::current()->PostTask( 228 FROM_HERE, 229 base::Bind(&RootWindow::DispatchHeldEvents, 230 repostable_event_factory_.GetWeakPtr())); 231 } else { 232 DCHECK(event.type() == ui::ET_GESTURE_TAP_DOWN); 233 held_repostable_event_.reset(); 234 // TODO(sschmitz): add similar code for gesture events. 235 } 236 } 237 238 RootWindowHostDelegate* RootWindow::AsRootWindowHostDelegate() { 239 return this; 240 } 241 242 void RootWindow::SetHostSize(const gfx::Size& size_in_pixel) { 243 DispatchHeldEvents(); 244 gfx::Rect bounds = host_->GetBounds(); 245 bounds.set_size(size_in_pixel); 246 host_->SetBounds(bounds); 247 248 // Requery the location to constrain it within the new root window size. 249 gfx::Point point; 250 if (host_->QueryMouseLocation(&point)) 251 SetLastMouseLocation(this, ui::ConvertPointToDIP(layer(), point)); 252 253 synthesize_mouse_move_ = false; 254 } 255 256 gfx::Size RootWindow::GetHostSize() const { 257 return host_->GetBounds().size(); 258 } 259 260 void RootWindow::SetHostBounds(const gfx::Rect& bounds_in_pixel) { 261 DCHECK(!bounds_in_pixel.IsEmpty()); 262 DispatchHeldEvents(); 263 host_->SetBounds(bounds_in_pixel); 264 synthesize_mouse_move_ = false; 265 } 266 267 gfx::Point RootWindow::GetHostOrigin() const { 268 return host_->GetBounds().origin(); 269 } 270 271 void RootWindow::SetCursor(gfx::NativeCursor cursor) { 272 last_cursor_ = cursor; 273 // A lot of code seems to depend on NULL cursors actually showing an arrow, 274 // so just pass everything along to the host. 275 host_->SetCursor(cursor); 276 } 277 278 void RootWindow::OnCursorVisibilityChanged(bool show) { 279 host_->OnCursorVisibilityChanged(show); 280 } 281 282 void RootWindow::OnMouseEventsEnableStateChanged(bool enabled) { 283 // Send entered / exited so that visual state can be updated to match 284 // mouse events state. 285 PostMouseMoveEventAfterWindowChange(); 286 // TODO(mazda): Add code to disable mouse events when |enabled| == false. 287 } 288 289 void RootWindow::MoveCursorTo(const gfx::Point& location_in_dip) { 290 gfx::Point host_location(location_in_dip); 291 ConvertPointToHost(&host_location); 292 MoveCursorToInternal(location_in_dip, host_location); 293 } 294 295 void RootWindow::MoveCursorToHostLocation(const gfx::Point& host_location) { 296 gfx::Point root_location(host_location); 297 ConvertPointFromHost(&root_location); 298 MoveCursorToInternal(root_location, host_location); 299 } 300 301 bool RootWindow::ConfineCursorToWindow() { 302 // We would like to be able to confine the cursor to that window. However, 303 // currently, we do not have such functionality in X. So we just confine 304 // to the root window. This is ok because this option is currently only 305 // being used in fullscreen mode, so root_window bounds = window bounds. 306 return host_->ConfineCursorToRootWindow(); 307 } 308 309 void RootWindow::Draw() { 310 defer_draw_scheduling_ = false; 311 if (waiting_on_compositing_end_) { 312 draw_on_compositing_end_ = true; 313 return; 314 } 315 waiting_on_compositing_end_ = true; 316 317 TRACE_EVENT_ASYNC_BEGIN0("ui", "RootWindow::Draw", 318 compositor_->last_started_frame() + 1); 319 320 compositor_->Draw(); 321 } 322 323 void RootWindow::ScheduleFullRedraw() { 324 compositor_->ScheduleFullRedraw(); 325 } 326 327 void RootWindow::ScheduleRedrawRect(const gfx::Rect& damage_rect) { 328 compositor_->ScheduleRedrawRect(damage_rect); 329 } 330 331 Window* RootWindow::GetGestureTarget(ui::GestureEvent* event) { 332 Window* target = client::GetCaptureWindow(this); 333 if (!target) { 334 target = ConsumerToWindow( 335 gesture_recognizer_->GetTargetForGestureEvent(event)); 336 } 337 338 return target; 339 } 340 341 bool RootWindow::DispatchGestureEvent(ui::GestureEvent* event) { 342 DispatchHeldEvents(); 343 344 Window* target = GetGestureTarget(event); 345 if (target) { 346 event->ConvertLocationToTarget(static_cast<Window*>(this), target); 347 ProcessEvent(target, event); 348 return event->handled(); 349 } 350 351 return false; 352 } 353 354 void RootWindow::OnWindowDestroying(Window* window) { 355 DispatchMouseExitToHidingWindow(window); 356 OnWindowHidden(window, WINDOW_DESTROYED); 357 358 if (window->IsVisible() && 359 window->ContainsPointInRoot(GetLastMouseLocationInRoot())) { 360 PostMouseMoveEventAfterWindowChange(); 361 } 362 } 363 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(); 370 } 371 } 372 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 ui::MouseEvent event(ui::ET_MOUSE_EXITED, 383 last_mouse_location, 384 last_mouse_location, 385 ui::EF_NONE); 386 DispatchMouseEnterOrExit(event, ui::ET_MOUSE_EXITED); 387 } 388 } 389 390 void RootWindow::OnWindowVisibilityChanged(Window* window, bool is_visible) { 391 if (!is_visible) 392 OnWindowHidden(window, WINDOW_HIDDEN); 393 394 if (window->ContainsPointInRoot(GetLastMouseLocationInRoot())) 395 PostMouseMoveEventAfterWindowChange(); 396 } 397 398 void RootWindow::OnWindowTransformed(Window* window, bool contained_mouse) { 399 if (contained_mouse || 400 (window->IsVisible() && 401 window->ContainsPointInRoot(GetLastMouseLocationInRoot()))) { 402 PostMouseMoveEventAfterWindowChange(); 403 } 404 } 405 406 void RootWindow::OnKeyboardMappingChanged() { 407 FOR_EACH_OBSERVER(RootWindowObserver, observers_, 408 OnKeyboardMappingChanged(this)); 409 } 410 411 void RootWindow::OnRootWindowHostCloseRequested() { 412 FOR_EACH_OBSERVER(RootWindowObserver, observers_, 413 OnRootWindowHostCloseRequested(this)); 414 } 415 416 void RootWindow::AddRootWindowObserver(RootWindowObserver* observer) { 417 observers_.AddObserver(observer); 418 } 419 420 void RootWindow::RemoveRootWindowObserver(RootWindowObserver* observer) { 421 observers_.RemoveObserver(observer); 422 } 423 424 void RootWindow::PostNativeEvent(const base::NativeEvent& native_event) { 425 #if !defined(OS_MACOSX) 426 host_->PostNativeEvent(native_event); 427 #endif 428 } 429 430 void RootWindow::ConvertPointToNativeScreen(gfx::Point* point) const { 431 ConvertPointToHost(point); 432 gfx::Point location = host_->GetLocationOnNativeScreen(); 433 point->Offset(location.x(), location.y()); 434 } 435 436 void RootWindow::ConvertPointFromNativeScreen(gfx::Point* point) const { 437 gfx::Point location = host_->GetLocationOnNativeScreen(); 438 point->Offset(-location.x(), -location.y()); 439 ConvertPointFromHost(point); 440 } 441 442 void RootWindow::ConvertPointToHost(gfx::Point* point) const { 443 gfx::Point3F point_3f(*point); 444 GetRootTransform().TransformPoint(point_3f); 445 *point = gfx::ToFlooredPoint(point_3f.AsPointF()); 446 } 447 448 void RootWindow::ConvertPointFromHost(gfx::Point* point) const { 449 gfx::Point3F point_3f(*point); 450 GetInverseRootTransform().TransformPoint(point_3f); 451 *point = gfx::ToFlooredPoint(point_3f.AsPointF()); 452 } 453 454 void RootWindow::ProcessedTouchEvent(ui::TouchEvent* event, 455 Window* window, 456 ui::EventResult result) { 457 scoped_ptr<ui::GestureRecognizer::Gestures> gestures; 458 gestures.reset(gesture_recognizer_->ProcessTouchEventForGesture( 459 *event, result, window)); 460 ProcessGestures(gestures.get()); 461 } 462 463 void RootWindow::SetGestureRecognizerForTesting(ui::GestureRecognizer* gr) { 464 gesture_recognizer_.reset(gr); 465 } 466 467 gfx::AcceleratedWidget RootWindow::GetAcceleratedWidget() { 468 return host_->GetAcceleratedWidget(); 469 } 470 471 void RootWindow::ToggleFullScreen() { 472 host_->ToggleFullScreen(); 473 } 474 475 void RootWindow::HoldPointerMoves() { 476 if (!move_hold_count_) 477 held_event_factory_.InvalidateWeakPtrs(); 478 ++move_hold_count_; 479 TRACE_EVENT_ASYNC_BEGIN0("ui", "RootWindow::HoldPointerMoves", this); 480 } 481 482 void RootWindow::ReleasePointerMoves() { 483 --move_hold_count_; 484 DCHECK_GE(move_hold_count_, 0); 485 if (!move_hold_count_ && held_move_event_) { 486 // We don't want to call DispatchHeldEvents directly, because this might be 487 // called from a deep stack while another event, in which case dispatching 488 // another one may not be safe/expected. Instead we post a task, that we 489 // may cancel if HoldPointerMoves is called again before it executes. 490 base::MessageLoop::current()->PostTask( 491 FROM_HERE, 492 base::Bind(&RootWindow::DispatchHeldEvents, 493 held_event_factory_.GetWeakPtr())); 494 } 495 TRACE_EVENT_ASYNC_END0("ui", "RootWindow::HoldPointerMoves", this); 496 } 497 498 void RootWindow::SetFocusWhenShown(bool focused) { 499 host_->SetFocusWhenShown(focused); 500 } 501 502 bool RootWindow::CopyAreaToSkCanvas(const gfx::Rect& source_bounds, 503 const gfx::Point& dest_offset, 504 SkCanvas* canvas) { 505 DCHECK(canvas); 506 DCHECK(bounds().Contains(source_bounds)); 507 gfx::Rect source_pixels = ui::ConvertRectToPixel(layer(), source_bounds); 508 return host_->CopyAreaToSkCanvas(source_pixels, dest_offset, canvas); 509 } 510 511 gfx::Point RootWindow::GetLastMouseLocationInRoot() const { 512 gfx::Point location = Env::GetInstance()->last_mouse_location(); 513 client::ScreenPositionClient* client = client::GetScreenPositionClient(this); 514 if (client) 515 client->ConvertPointFromScreen(this, &location); 516 return location; 517 } 518 519 //////////////////////////////////////////////////////////////////////////////// 520 // RootWindow, Window overrides: 521 522 RootWindow* RootWindow::GetRootWindow() { 523 return this; 524 } 525 526 const RootWindow* RootWindow::GetRootWindow() const { 527 return this; 528 } 529 530 void RootWindow::SetTransform(const gfx::Transform& transform) { 531 scoped_ptr<RootWindowTransformer> transformer( 532 new SimpleRootWindowTransformer(this, transform)); 533 SetRootWindowTransformer(transformer.Pass()); 534 } 535 536 void RootWindow::SetRootWindowTransformer( 537 scoped_ptr<RootWindowTransformer> transformer) { 538 transformer_ = transformer.Pass(); 539 host_->SetInsets(transformer_->GetHostInsets()); 540 Window::SetTransform(transformer_->GetTransform()); 541 // If the layer is not animating, then we need to update the root window 542 // size immediately. 543 if (!layer()->GetAnimator()->is_animating()) 544 UpdateRootWindowSize(GetHostSize()); 545 } 546 547 gfx::Transform RootWindow::GetRootTransform() const { 548 float scale = ui::GetDeviceScaleFactor(layer()); 549 gfx::Transform transform; 550 transform.Scale(scale, scale); 551 transform *= transformer_->GetTransform(); 552 return transform; 553 } 554 555 //////////////////////////////////////////////////////////////////////////////// 556 // RootWindow, ui::EventTarget implementation: 557 558 ui::EventTarget* RootWindow::GetParentTarget() { 559 return client::GetEventClient(this) ? 560 client::GetEventClient(this)->GetToplevelEventTarget() : 561 Env::GetInstance(); 562 } 563 564 //////////////////////////////////////////////////////////////////////////////// 565 // RootWindow, ui::CompositorDelegate implementation: 566 567 void RootWindow::ScheduleDraw() { 568 DCHECK(!ui::Compositor::WasInitializedWithThread()); 569 if (!defer_draw_scheduling_) { 570 defer_draw_scheduling_ = true; 571 base::MessageLoop::current()->PostTask( 572 FROM_HERE, 573 base::Bind(&RootWindow::Draw, schedule_paint_factory_.GetWeakPtr())); 574 } 575 } 576 577 //////////////////////////////////////////////////////////////////////////////// 578 // RootWindow, ui::CompositorObserver implementation: 579 580 void RootWindow::OnCompositingDidCommit(ui::Compositor*) { 581 } 582 583 void RootWindow::OnCompositingStarted(ui::Compositor*, 584 base::TimeTicks start_time) { 585 } 586 587 void RootWindow::OnCompositingEnded(ui::Compositor*) { 588 TRACE_EVENT_ASYNC_END0("ui", "RootWindow::Draw", 589 compositor_->last_ended_frame()); 590 waiting_on_compositing_end_ = false; 591 if (draw_on_compositing_end_) { 592 draw_on_compositing_end_ = false; 593 594 // Call ScheduleDraw() instead of Draw() in order to allow other 595 // ui::CompositorObservers to be notified before starting another 596 // draw cycle. 597 ScheduleDraw(); 598 } 599 } 600 601 void RootWindow::OnCompositingAborted(ui::Compositor*) { 602 } 603 604 void RootWindow::OnCompositingLockStateChanged(ui::Compositor*) { 605 } 606 607 void RootWindow::OnUpdateVSyncParameters(ui::Compositor* compositor, 608 base::TimeTicks timebase, 609 base::TimeDelta interval) { 610 } 611 612 //////////////////////////////////////////////////////////////////////////////// 613 // RootWindow, ui::LayerDelegate implementation: 614 615 void RootWindow::OnDeviceScaleFactorChanged( 616 float device_scale_factor) { 617 const bool cursor_is_in_bounds = 618 GetBoundsInScreen().Contains(Env::GetInstance()->last_mouse_location()); 619 bool cursor_visible = false; 620 client::CursorClient* cursor_client = client::GetCursorClient(this); 621 if (cursor_is_in_bounds && cursor_client) { 622 cursor_visible = cursor_client->IsCursorVisible(); 623 if (cursor_visible) 624 cursor_client->HideCursor(); 625 } 626 host_->OnDeviceScaleFactorChanged(device_scale_factor); 627 Window::OnDeviceScaleFactorChanged(device_scale_factor); 628 // Update the device scale factor of the cursor client only when the last 629 // mouse location is on this root window. 630 if (cursor_is_in_bounds) { 631 if (cursor_client) { 632 const gfx::Display& display = 633 gfx::Screen::GetScreenFor(this)->GetDisplayNearestWindow(this); 634 cursor_client->SetDisplay(display); 635 } 636 } 637 if (cursor_is_in_bounds && cursor_client && cursor_visible) 638 cursor_client->ShowCursor(); 639 } 640 641 //////////////////////////////////////////////////////////////////////////////// 642 // RootWindow, overridden from aura::Window: 643 644 bool RootWindow::CanFocus() const { 645 return IsVisible(); 646 } 647 648 bool RootWindow::CanReceiveEvents() const { 649 return IsVisible(); 650 } 651 652 //////////////////////////////////////////////////////////////////////////////// 653 // RootWindow, overridden from aura::client::CaptureDelegate: 654 655 void RootWindow::UpdateCapture(Window* old_capture, 656 Window* new_capture) { 657 if (old_capture && old_capture->GetRootWindow() == this && 658 old_capture->delegate()) { 659 // Send a capture changed event with bogus location data. 660 ui::MouseEvent event(ui::ET_MOUSE_CAPTURE_CHANGED, gfx::Point(), 661 gfx::Point(), 0); 662 663 ProcessEvent(old_capture, &event); 664 665 old_capture->delegate()->OnCaptureLost(); 666 } 667 668 // Reset the mouse_moved_handler_ if the mouse_moved_handler_ belongs 669 // to another root window when losing the capture. 670 if (mouse_moved_handler_ && old_capture && 671 old_capture->Contains(mouse_moved_handler_) && 672 old_capture->GetRootWindow() != this) { 673 mouse_moved_handler_ = NULL; 674 } 675 676 if (new_capture) { 677 // Make all subsequent mouse events and touch go to the capture window. We 678 // shouldn't need to send an event here as OnCaptureLost should take care of 679 // that. 680 if (mouse_moved_handler_ || Env::GetInstance()->is_mouse_button_down()) 681 mouse_moved_handler_ = new_capture; 682 } else { 683 // Make sure mouse_moved_handler gets updated. 684 SynthesizeMouseMoveEvent(); 685 } 686 mouse_pressed_handler_ = NULL; 687 } 688 689 void RootWindow::SetNativeCapture() { 690 host_->SetCapture(); 691 } 692 693 void RootWindow::ReleaseNativeCapture() { 694 host_->ReleaseCapture(); 695 } 696 697 bool RootWindow::QueryMouseLocationForTest(gfx::Point* point) const { 698 return host_->QueryMouseLocation(point); 699 } 700 701 void RootWindow::ClearMouseHandlers() { 702 mouse_pressed_handler_ = NULL; 703 mouse_moved_handler_ = NULL; 704 mouse_event_dispatch_target_ = NULL; 705 } 706 707 //////////////////////////////////////////////////////////////////////////////// 708 // RootWindow, private: 709 710 void RootWindow::TransformEventForDeviceScaleFactor(ui::LocatedEvent* event) { 711 event->UpdateForRootTransform(GetInverseRootTransform()); 712 } 713 714 void RootWindow::MoveCursorToInternal(const gfx::Point& root_location, 715 const gfx::Point& host_location) { 716 host_->MoveCursorTo(host_location); 717 SetLastMouseLocation(this, root_location); 718 client::CursorClient* cursor_client = client::GetCursorClient(this); 719 if (cursor_client) { 720 const gfx::Display& display = 721 gfx::Screen::GetScreenFor(this)->GetDisplayNearestWindow(this); 722 cursor_client->SetDisplay(display); 723 } 724 synthesize_mouse_move_ = false; 725 } 726 727 void RootWindow::HandleMouseMoved(const ui::MouseEvent& event, Window* target) { 728 if (target == mouse_moved_handler_) 729 return; 730 731 DispatchMouseEnterOrExit(event, ui::ET_MOUSE_EXITED); 732 733 if (mouse_event_dispatch_target_ != target) { 734 mouse_moved_handler_ = NULL; 735 return; 736 } 737 738 mouse_moved_handler_ = target; 739 740 DispatchMouseEnterOrExit(event, ui::ET_MOUSE_ENTERED); 741 } 742 743 void RootWindow::DispatchMouseEnterOrExit(const ui::MouseEvent& event, 744 ui::EventType type) { 745 if (!mouse_moved_handler_ || !mouse_moved_handler_->delegate()) 746 return; 747 748 ui::MouseEvent translated_event(event, 749 static_cast<Window*>(this), 750 mouse_moved_handler_, 751 type, 752 event.flags() | ui::EF_IS_SYNTHESIZED); 753 ProcessEvent(mouse_moved_handler_, &translated_event); 754 } 755 756 void RootWindow::ProcessEvent(Window* target, ui::Event* event) { 757 Window* old_target = event_dispatch_target_; 758 event_dispatch_target_ = target; 759 if (DispatchEvent(target, event)) 760 event_dispatch_target_ = old_target; 761 } 762 763 bool RootWindow::ProcessGestures(ui::GestureRecognizer::Gestures* gestures) { 764 if (!gestures || gestures->empty()) 765 return false; 766 767 Window* target = GetGestureTarget(gestures->get().at(0)); 768 Window* old_target = event_dispatch_target_; 769 event_dispatch_target_ = target; 770 771 bool handled = false; 772 for (size_t i = 0; i < gestures->size(); ++i) { 773 ui::GestureEvent* event = gestures->get().at(i); 774 event->ConvertLocationToTarget(static_cast<Window*>(this), target); 775 if (!DispatchEvent(target, event)) 776 return false; // |this| has been destroyed. 777 if (event->handled()) 778 handled = true; 779 if (event_dispatch_target_ != target) // |target| has been destroyed. 780 break; 781 } 782 event_dispatch_target_ = old_target; 783 return handled; 784 } 785 786 void RootWindow::OnWindowRemovedFromRootWindow(Window* detached, 787 RootWindow* new_root) { 788 DCHECK(aura::client::GetCaptureWindow(this) != this); 789 790 DispatchMouseExitToHidingWindow(detached); 791 OnWindowHidden(detached, new_root ? WINDOW_MOVING : WINDOW_HIDDEN); 792 793 if (detached->IsVisible() && 794 detached->ContainsPointInRoot(GetLastMouseLocationInRoot())) { 795 PostMouseMoveEventAfterWindowChange(); 796 } 797 } 798 799 void RootWindow::OnWindowHidden(Window* invisible, WindowHiddenReason reason) { 800 // TODO(beng): This should be removed once FocusController is turned on. 801 if (client::GetFocusClient(this)) { 802 client::GetFocusClient(this)->OnWindowHiddenInRootWindow( 803 invisible, this, reason == WINDOW_DESTROYED); 804 } 805 806 // Do not clear the capture, and the |event_dispatch_target_| if the 807 // window is moving across root windows, because the target itself 808 // is actually still visible and clearing them stops further event 809 // processing, which can cause unexpected behaviors. See 810 // crbug.com/157583 811 if (reason != WINDOW_MOVING) { 812 Window* capture_window = aura::client::GetCaptureWindow(this); 813 // If the ancestor of the capture window is hidden, 814 // release the capture. 815 if (invisible->Contains(capture_window) && invisible != this) 816 capture_window->ReleaseCapture(); 817 818 if (invisible->Contains(event_dispatch_target_)) 819 event_dispatch_target_ = NULL; 820 } 821 822 // If the ancestor of any event handler windows are invisible, release the 823 // pointer to those windows. 824 if (invisible->Contains(mouse_pressed_handler_)) 825 mouse_pressed_handler_ = NULL; 826 if (invisible->Contains(mouse_moved_handler_)) 827 mouse_moved_handler_ = NULL; 828 if (invisible->Contains(mouse_event_dispatch_target_)) 829 mouse_event_dispatch_target_ = NULL; 830 831 CleanupGestureRecognizerState(invisible); 832 } 833 834 void RootWindow::CleanupGestureRecognizerState(Window* window) { 835 gesture_recognizer_->CleanupStateForConsumer(window); 836 Windows windows = window->children(); 837 for (Windows::const_iterator iter = windows.begin(); 838 iter != windows.end(); 839 ++iter) { 840 CleanupGestureRecognizerState(*iter); 841 } 842 } 843 844 void RootWindow::UpdateRootWindowSize(const gfx::Size& host_size) { 845 SetBounds(transformer_->GetRootWindowBounds(host_size)); 846 } 847 848 void RootWindow::OnWindowAddedToRootWindow(Window* attached) { 849 if (attached->IsVisible() && 850 attached->ContainsPointInRoot(GetLastMouseLocationInRoot())) 851 PostMouseMoveEventAfterWindowChange(); 852 } 853 854 bool RootWindow::CanDispatchToTarget(ui::EventTarget* target) { 855 return event_dispatch_target_ == target; 856 } 857 858 bool RootWindow::DispatchLongPressGestureEvent(ui::GestureEvent* event) { 859 return DispatchGestureEvent(event); 860 } 861 862 bool RootWindow::DispatchCancelTouchEvent(ui::TouchEvent* event) { 863 return OnHostTouchEvent(event); 864 } 865 866 void RootWindow::OnLayerAnimationEnded( 867 ui::LayerAnimationSequence* animation) { 868 UpdateRootWindowSize(GetHostSize()); 869 } 870 871 void RootWindow::OnLayerAnimationScheduled( 872 ui::LayerAnimationSequence* animation) { 873 } 874 875 void RootWindow::OnLayerAnimationAborted( 876 ui::LayerAnimationSequence* animation) { 877 } 878 879 //////////////////////////////////////////////////////////////////////////////// 880 // RootWindow, RootWindowHostDelegate implementation: 881 882 bool RootWindow::OnHostKeyEvent(ui::KeyEvent* event) { 883 DispatchHeldEvents(); 884 if (event->key_code() == ui::VKEY_UNKNOWN) 885 return false; 886 client::EventClient* client = client::GetEventClient(GetRootWindow()); 887 Window* focused_window = client::GetFocusClient(this)->GetFocusedWindow(); 888 if (client && !client->CanProcessEventsWithinSubtree(focused_window)) { 889 client::GetFocusClient(this)->FocusWindow(NULL); 890 return false; 891 } 892 ProcessEvent(focused_window ? focused_window : this, event); 893 return event->handled(); 894 } 895 896 bool RootWindow::OnHostMouseEvent(ui::MouseEvent* event) { 897 if (event->type() == ui::ET_MOUSE_DRAGGED || 898 (event->flags() & ui::EF_IS_SYNTHESIZED)) { 899 if (move_hold_count_) { 900 Window* null_window = static_cast<Window*>(NULL); 901 held_move_event_.reset( 902 new ui::MouseEvent(*event, null_window, null_window)); 903 return true; 904 } else { 905 // We may have a held event for a period between the time move_hold_count_ 906 // fell to 0 and the DispatchHeldEvents executes. Since we're going to 907 // dispatch the new event directly below, we can reset the old one. 908 held_move_event_.reset(); 909 } 910 } 911 DispatchHeldEvents(); 912 return DispatchMouseEventImpl(event); 913 } 914 915 bool RootWindow::OnHostScrollEvent(ui::ScrollEvent* event) { 916 DispatchHeldEvents(); 917 918 TransformEventForDeviceScaleFactor(event); 919 SetLastMouseLocation(this, event->location()); 920 synthesize_mouse_move_ = false; 921 922 Window* target = mouse_pressed_handler_ ? 923 mouse_pressed_handler_ : client::GetCaptureWindow(this); 924 925 if (!target) 926 target = GetEventHandlerForPoint(event->location()); 927 928 if (!target) 929 target = this; 930 931 event->ConvertLocationToTarget(static_cast<Window*>(this), target); 932 int flags = event->flags(); 933 if (IsNonClientLocation(target, event->location())) 934 flags |= ui::EF_IS_NON_CLIENT; 935 event->set_flags(flags); 936 937 ProcessEvent(target, event); 938 return event->handled(); 939 } 940 941 bool RootWindow::OnHostTouchEvent(ui::TouchEvent* event) { 942 if ((event->type() == ui::ET_TOUCH_MOVED)) { 943 if (move_hold_count_) { 944 Window* null_window = static_cast<Window*>(NULL); 945 held_move_event_.reset( 946 new ui::TouchEvent(*event, null_window, null_window)); 947 return true; 948 } else { 949 // We may have a held event for a period between the time move_hold_count_ 950 // fell to 0 and the DispatchHeldEvents executes. Since we're going to 951 // dispatch the new event directly below, we can reset the old one. 952 held_move_event_.reset(); 953 } 954 } 955 DispatchHeldEvents(); 956 return DispatchTouchEventImpl(event); 957 } 958 959 void RootWindow::OnHostCancelMode() { 960 ui::CancelModeEvent event; 961 Window* focused_window = client::GetFocusClient(this)->GetFocusedWindow(); 962 ProcessEvent(focused_window ? focused_window : this, &event); 963 } 964 965 void RootWindow::OnHostActivated() { 966 Env::GetInstance()->RootWindowActivated(this); 967 } 968 969 void RootWindow::OnHostLostWindowCapture() { 970 Window* capture_window = client::GetCaptureWindow(this); 971 if (capture_window && capture_window->GetRootWindow() == this) 972 capture_window->ReleaseCapture(); 973 } 974 975 void RootWindow::OnHostLostMouseGrab() { 976 ClearMouseHandlers(); 977 } 978 979 void RootWindow::OnHostPaint(const gfx::Rect& damage_rect) { 980 compositor_->ScheduleRedrawRect(damage_rect); 981 } 982 983 void RootWindow::OnHostMoved(const gfx::Point& origin) { 984 FOR_EACH_OBSERVER(RootWindowObserver, observers_, 985 OnRootWindowHostMoved(this, origin)); 986 } 987 988 void RootWindow::OnHostResized(const gfx::Size& size) { 989 DispatchHeldEvents(); 990 // The compositor should have the same size as the native root window host. 991 // Get the latest scale from display because it might have been changed. 992 compositor_->SetScaleAndSize(GetDeviceScaleFactorFromDisplay(this), size); 993 994 // The layer, and the observers should be notified of the 995 // transformed size of the root window. 996 UpdateRootWindowSize(size); 997 FOR_EACH_OBSERVER(RootWindowObserver, observers_, 998 OnRootWindowHostResized(this)); 999 } 1000 1001 float RootWindow::GetDeviceScaleFactor() { 1002 return compositor()->device_scale_factor(); 1003 } 1004 1005 RootWindow* RootWindow::AsRootWindow() { 1006 return this; 1007 } 1008 1009 //////////////////////////////////////////////////////////////////////////////// 1010 // RootWindow, private: 1011 1012 bool RootWindow::DispatchMouseEventImpl(ui::MouseEvent* event) { 1013 TransformEventForDeviceScaleFactor(event); 1014 Window* target = mouse_pressed_handler_ ? 1015 mouse_pressed_handler_ : client::GetCaptureWindow(this); 1016 if (!target) 1017 target = GetEventHandlerForPoint(event->location()); 1018 return DispatchMouseEventToTarget(event, target); 1019 } 1020 1021 bool RootWindow::DispatchMouseEventRepost(ui::MouseEvent* event) { 1022 if (event->type() != ui::ET_MOUSE_PRESSED) 1023 return false; 1024 mouse_pressed_handler_ = NULL; 1025 Window* target = GetEventHandlerForPoint(event->location()); 1026 return DispatchMouseEventToTarget(event, target); 1027 } 1028 1029 bool RootWindow::DispatchMouseEventToTarget(ui::MouseEvent* event, 1030 Window* target) { 1031 client::CursorClient* cursor_client = client::GetCursorClient(this); 1032 if (cursor_client && 1033 !cursor_client->IsMouseEventsEnabled() && 1034 (event->flags() & ui::EF_IS_SYNTHESIZED)) 1035 return false; 1036 1037 static const int kMouseButtonFlagMask = 1038 ui::EF_LEFT_MOUSE_BUTTON | 1039 ui::EF_MIDDLE_MOUSE_BUTTON | 1040 ui::EF_RIGHT_MOUSE_BUTTON; 1041 base::AutoReset<Window*> reset(&mouse_event_dispatch_target_, target); 1042 SetLastMouseLocation(this, event->location()); 1043 synthesize_mouse_move_ = false; 1044 switch (event->type()) { 1045 case ui::ET_MOUSE_EXITED: 1046 if (!target) { 1047 DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED); 1048 mouse_moved_handler_ = NULL; 1049 } 1050 break; 1051 case ui::ET_MOUSE_MOVED: 1052 mouse_event_dispatch_target_ = target; 1053 HandleMouseMoved(*event, target); 1054 if (mouse_event_dispatch_target_ != target) 1055 return false; 1056 break; 1057 case ui::ET_MOUSE_PRESSED: 1058 // Don't set the mouse pressed handler for non client mouse down events. 1059 // These are only sent by Windows and are not always followed with non 1060 // client mouse up events which causes subsequent mouse events to be 1061 // sent to the wrong target. 1062 if (!(event->flags() & ui::EF_IS_NON_CLIENT) && !mouse_pressed_handler_) 1063 mouse_pressed_handler_ = target; 1064 Env::GetInstance()->set_mouse_button_flags( 1065 event->flags() & kMouseButtonFlagMask); 1066 break; 1067 case ui::ET_MOUSE_RELEASED: 1068 mouse_pressed_handler_ = NULL; 1069 Env::GetInstance()->set_mouse_button_flags(event->flags() & 1070 kMouseButtonFlagMask & ~event->changed_button_flags()); 1071 break; 1072 default: 1073 break; 1074 } 1075 if (target) { 1076 event->ConvertLocationToTarget(static_cast<Window*>(this), target); 1077 if (IsNonClientLocation(target, event->location())) 1078 event->set_flags(event->flags() | ui::EF_IS_NON_CLIENT); 1079 ProcessEvent(target, event); 1080 return event->handled(); 1081 } 1082 return false; 1083 } 1084 1085 bool RootWindow::DispatchTouchEventImpl(ui::TouchEvent* event) { 1086 switch (event->type()) { 1087 case ui::ET_TOUCH_PRESSED: 1088 touch_ids_down_ |= (1 << event->touch_id()); 1089 Env::GetInstance()->set_touch_down(touch_ids_down_ != 0); 1090 break; 1091 1092 // Handle ET_TOUCH_CANCELLED only if it has a native event. 1093 case ui::ET_TOUCH_CANCELLED: 1094 if (!event->HasNativeEvent()) 1095 break; 1096 // fallthrough 1097 case ui::ET_TOUCH_RELEASED: 1098 touch_ids_down_ = (touch_ids_down_ | (1 << event->touch_id())) ^ 1099 (1 << event->touch_id()); 1100 Env::GetInstance()->set_touch_down(touch_ids_down_ != 0); 1101 break; 1102 1103 default: 1104 break; 1105 } 1106 TransformEventForDeviceScaleFactor(event); 1107 bool handled = false; 1108 Window* target = client::GetCaptureWindow(this); 1109 if (!target) { 1110 target = ConsumerToWindow( 1111 gesture_recognizer_->GetTouchLockedTarget(event)); 1112 if (!target) { 1113 target = ConsumerToWindow( 1114 gesture_recognizer_->GetTargetForLocation(event->location())); 1115 } 1116 } 1117 1118 // The gesture recognizer processes touch events in the system coordinates. So 1119 // keep a copy of the touch event here before possibly converting the event to 1120 // a window's local coordinate system. 1121 ui::TouchEvent event_for_gr(*event); 1122 1123 ui::EventResult result = ui::ER_UNHANDLED; 1124 if (!target && !bounds().Contains(event->location())) { 1125 // If the initial touch is outside the root window, target the root. 1126 target = this; 1127 ProcessEvent(target ? target : NULL, event); 1128 result = event->result(); 1129 } else { 1130 // We only come here when the first contact was within the root window. 1131 if (!target) { 1132 target = GetEventHandlerForPoint(event->location()); 1133 if (!target) 1134 return false; 1135 } 1136 1137 event->ConvertLocationToTarget(static_cast<Window*>(this), target); 1138 ProcessEvent(target, event); 1139 handled = event->handled(); 1140 result = event->result(); 1141 } 1142 1143 // Get the list of GestureEvents from GestureRecognizer. 1144 scoped_ptr<ui::GestureRecognizer::Gestures> gestures; 1145 gestures.reset(gesture_recognizer_->ProcessTouchEventForGesture( 1146 event_for_gr, result, target)); 1147 1148 return ProcessGestures(gestures.get()) ? true : handled; 1149 } 1150 1151 void RootWindow::DispatchHeldEvents() { 1152 if (held_repostable_event_) { 1153 if (held_repostable_event_->type() == ui::ET_MOUSE_PRESSED) { 1154 ui::MouseEvent mouse_event( 1155 static_cast<const ui::MouseEvent&>(*held_repostable_event_.get())); 1156 held_repostable_event_.reset(); // must be reset before dispatch 1157 DispatchMouseEventRepost(&mouse_event); 1158 } else { 1159 DCHECK(held_repostable_event_->type() == ui::ET_GESTURE_TAP_DOWN); 1160 // TODO(sschmitz): add similar code for gesture events 1161 } 1162 held_repostable_event_.reset(); 1163 } 1164 if (held_move_event_ && held_move_event_->IsMouseEvent()) { 1165 // If a mouse move has been synthesized, the target location is suspect, 1166 // so drop the held event. 1167 if (!synthesize_mouse_move_) 1168 DispatchMouseEventImpl( 1169 static_cast<ui::MouseEvent*>(held_move_event_.get())); 1170 held_move_event_.reset(); 1171 } else if (held_move_event_ && held_move_event_->IsTouchEvent()) { 1172 DispatchTouchEventImpl( 1173 static_cast<ui::TouchEvent*>(held_move_event_.get())); 1174 held_move_event_.reset(); 1175 } 1176 } 1177 1178 void RootWindow::PostMouseMoveEventAfterWindowChange() { 1179 if (synthesize_mouse_move_) 1180 return; 1181 synthesize_mouse_move_ = true; 1182 base::MessageLoop::current()->PostTask( 1183 FROM_HERE, 1184 base::Bind(&RootWindow::SynthesizeMouseMoveEvent, 1185 event_factory_.GetWeakPtr())); 1186 } 1187 1188 void RootWindow::SynthesizeMouseMoveEvent() { 1189 if (!synthesize_mouse_move_) 1190 return; 1191 synthesize_mouse_move_ = false; 1192 gfx::Point root_mouse_location = GetLastMouseLocationInRoot(); 1193 if (!bounds().Contains(root_mouse_location)) 1194 return; 1195 gfx::Point host_mouse_location = root_mouse_location; 1196 ConvertPointToHost(&host_mouse_location); 1197 1198 ui::MouseEvent event(ui::ET_MOUSE_MOVED, 1199 host_mouse_location, 1200 host_mouse_location, 1201 ui::EF_IS_SYNTHESIZED); 1202 OnHostMouseEvent(&event); 1203 } 1204 1205 gfx::Transform RootWindow::GetInverseRootTransform() const { 1206 float scale = ui::GetDeviceScaleFactor(layer()); 1207 gfx::Transform transform; 1208 transform.Scale(1.0f / scale, 1.0f / scale); 1209 return transformer_->GetInverseTransform() * transform; 1210 } 1211 1212 } // namespace aura 1213