| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/drag_drop/drag_drop_capture_delegate.h" |
| #include "ash/drag_drop/drag_drop_tracker.h" |
| #include "ui/aura/env.h" |
| #include "ui/aura/window.h" |
| #include "ui/aura/window_delegate.h" |
| #include "ui/aura/window_event_dispatcher.h" |
| #include "ui/aura/window_observer.h" |
| #include "ui/aura/window_tracker.h" |
| #include "ui/base/hit_test.h" |
| #include "ui/events/event.h" |
| #include "ui/events/event_target.h" |
| #include "ui/events/event_utils.h" |
| #include "ui/events/types/event_type.h" |
| |
| namespace ash { |
| namespace { |
| |
| void NotifyWindowOfTouchDispatchGestureEnd(aura::Window* window) { |
| if (!window->delegate()) |
| return; |
| DispatchGestureEndToWindow(window); |
| |
| ui::PointerDetails touch_details(ui::EventPointerType::kTouch, |
| /*pointer_id=*/0, 1.0f, 1.0f, 1.0f); |
| ui::TouchEvent touch_cancel_event(ui::ET_TOUCH_CANCELLED, gfx::Point(), |
| ui::EventTimeForNow(), touch_details); |
| window->delegate()->OnTouchEvent(&touch_cancel_event); |
| } |
| |
| } // namespace |
| |
| void DispatchGestureEndToWindow(aura::Window* window) { |
| DCHECK(window && window->delegate()); |
| ui::GestureEventDetails details(ui::ET_GESTURE_END); |
| details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHSCREEN); |
| ui::GestureEvent gesture_end(0, 0, 0, ui::EventTimeForNow(), details); |
| window->delegate()->OnGestureEvent(&gesture_end); |
| } |
| |
| DragDropCaptureDelegate::DragDropCaptureDelegate() = default; |
| DragDropCaptureDelegate::~DragDropCaptureDelegate() = default; |
| |
| bool DragDropCaptureDelegate::TakeCapture( |
| aura::Window* root_window, |
| aura::Window* source_window, |
| CancelDragDropCallback callback, |
| ui::TransferTouchesBehavior behavior) { |
| drag_drop_tracker_.reset(new DragDropTracker(root_window, callback)); |
| // We need to transfer the current gesture sequence and the GR's touch event |
| // queue to the |drag_drop_tracker_|'s capture window so that when it takes |
| // capture, it still gets a valid gesture state. |
| aura::Window* capture_window = drag_drop_tracker_->capture_window(); |
| aura::WindowTracker tracker({source_window, capture_window}); |
| auto* gesture_recognizer = aura::Env::GetInstance()->gesture_recognizer(); |
| gesture_recognizer->TransferEventsTo( |
| source_window, drag_drop_tracker_->capture_window(), behavior); |
| if (tracker.Contains(source_window)) { |
| // We also send a gesture end and touch cancel to the source window so it |
| // can clear state. TODO(varunjain): Remove this whole block when gesture |
| // sequence transferring is properly done in the GR |
| // (http://crbug.com/160558) |
| NotifyWindowOfTouchDispatchGestureEnd(source_window); |
| } |
| if (!tracker.Contains(capture_window)) { |
| // This means the drag was cancelled during event transfer. |
| // See: crbug.com/1297209. |
| return false; |
| } |
| drag_drop_tracker_->TakeCapture(); |
| return true; |
| } |
| |
| aura::Window* DragDropCaptureDelegate::GetTarget( |
| const ui::LocatedEvent& event) { |
| return drag_drop_tracker_ ? drag_drop_tracker_->GetTarget(event) : nullptr; |
| } |
| |
| std::unique_ptr<ui::LocatedEvent> DragDropCaptureDelegate::ConvertEvent( |
| aura::Window* target, |
| const ui::LocatedEvent& event) { |
| return drag_drop_tracker_ ? drag_drop_tracker_->ConvertEvent(target, event) |
| : nullptr; |
| } |
| |
| aura::Window* DragDropCaptureDelegate::capture_window() { |
| return drag_drop_tracker_ ? drag_drop_tracker_->capture_window() : nullptr; |
| } |
| |
| void DragDropCaptureDelegate::ReleaseCapture() { |
| drag_drop_tracker_.reset(); |
| } |
| |
| } // namespace ash |