Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1485)

Unified Diff: services/ui/ws/current_drag_operation.cc

Issue 2266603002: mus: Implement interwindow drag and drop (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove stray mark Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: services/ui/ws/current_drag_operation.cc
diff --git a/services/ui/ws/current_drag_operation.cc b/services/ui/ws/current_drag_operation.cc
new file mode 100644
index 0000000000000000000000000000000000000000..1e163d342d9d9a676464547cab6a12558b706e45
--- /dev/null
+++ b/services/ui/ws/current_drag_operation.cc
@@ -0,0 +1,247 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/ui/ws/current_drag_operation.h"
+
+#include "base/logging.h"
+#include "services/ui/ws/current_drag_operation_source.h"
+#include "services/ui/ws/drag_target_connection.h"
+#include "services/ui/ws/event_dispatcher.h"
+#include "services/ui/ws/server_window.h"
+
+namespace ui {
+namespace ws {
+
+struct CurrentDragOperation::Operation {
+ DragEventType type;
+ uint32_t key_state;
+ gfx::Point position;
sky 2016/09/06 21:11:27 Document what this is relative to. Screen?
+};
+
+CurrentDragOperation::CurrentDragOperation(
+ CurrentDragOperationSource* source,
+ ServerWindow* window,
+ mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data,
+ uint32_t drag_operations)
+ : source_(source),
+ drag_operations_(drag_operations),
+ source_window_(window),
+ mime_data_(std::move(mime_data)),
+ weak_factory_(this) {
+ source_window_->AddObserver(this);
+}
+
+CurrentDragOperation::~CurrentDragOperation() {
+ if (source_window_)
+ source_window_->RemoveObserver(this);
+}
+
+void CurrentDragOperation::DispatchCancel() {
+ MessageDragCompleted(false);
+}
+
+void CurrentDragOperation::DispatchLocatedEvent(const ui::LocatedEvent& event,
+ ServerWindow* current_target) {
+ uint32_t key_state = event.flags();
+ gfx::Point position = event.location();
+
+ if (waiting_for_final_drop_response_) {
+ // If we're waiting on a target window to respond to the final drag drop
sky 2016/09/06 21:11:27 If you early return here, does it mean the event i
+ // call, don't process any more mouse events.
+ return;
+ }
+
+ if (current_target && !current_target->can_accept_drags()) {
+ // If the current window over point doesn't accept drops, than don't send
+ // it events.
+ current_target = nullptr;
sky 2016/09/06 21:11:27 Shouldn't this bubble
+ }
+
+ if (current_target && current_target == current_target_window_ &&
+ event.type() != ET_POINTER_UP) {
sky 2016/09/06 21:11:27 Shouldn't you only care about POINTER_UP of the po
+ // We're continuing a drag inside the bounds of
+ // |current_target_window_|. Send a continue message.
+ auto& window_ops = current_window_state_[current_target];
+ if (window_ops.size() > 1 && window_ops.back().type == TYPE_OVER) {
+ // If we have a queued DragOver which isn't in progress, then just
+ // modify it's data.
+ auto& back = window_ops.back();
+ back.key_state = key_state;
+ back.position = position;
+ } else {
+ QueueEvent(current_target, TYPE_OVER, key_state, position);
+ }
+ } else if (current_target != current_target_window_) {
+ if (current_target_window_) {
+ auto& window_ops = current_window_state_[current_target_window_];
+ if (window_ops.size() > 1 && window_ops.back().type == TYPE_OVER) {
+ // If we have queued DragOver events, we want to replace them.
+ auto& back = window_ops.back();
+ back.type = TYPE_LEAVE;
+ back.key_state = key_state;
+ back.position = position;
+ } else {
+ QueueEvent(current_target_window_, TYPE_LEAVE, key_state, position);
+ }
+ }
+
+ if (current_target)
+ QueueEvent(current_target, TYPE_ENTER, key_state, position);
+
+ current_target_window_ = current_target;
+ }
+
+ if (event.type() == ET_POINTER_UP) {
+ if (current_target) {
+ QueueEvent(current_target, TYPE_DROP, key_state, position);
+ waiting_for_final_drop_response_ = true;
+ } else {
+ // The pointer was released over no window or a window that doesn't
+ // accept drags.
+ MessageDragCompleted(false);
+ }
+ }
+}
+
+void CurrentDragOperation::MessageDragCompleted(bool success) {
+ for (ServerWindow* window : called_on_drag_start_) {
+ DragTargetConnection* connection = source_->GetDragTargetWithRoot(window);
+ if (connection)
+ connection->PerformOnDragFinish(window);
+ }
+ called_on_drag_start_.clear();
+
+ source_->OnDragOver(success);
+ // |this| may be invalid now.
+}
+
+size_t CurrentDragOperation::GetSizeOfQueueForWindow(ServerWindow* window) {
+ auto it = current_window_state_.find(window);
+ if (it == current_window_state_.end())
+ return 0u;
+ return it->second.size();
+}
+
+void CurrentDragOperation::QueueEvent(ServerWindow* window,
+ DragEventType type,
+ uint32_t key_state,
+ gfx::Point position) {
+ // If this window doesn't have the mime data, send it a PerformOnDragStart()
+ // message.
+ if (window != source_window_ &&
+ !base::ContainsKey(called_on_drag_start_, window)) {
+ DragTargetConnection* connection = source_->GetDragTargetWithRoot(window);
+ connection->PerformOnDragStart(window, mime_data_.Clone());
+ called_on_drag_start_.insert(window);
+ }
+
+ auto& window_ops = current_window_state_[window];
+ if (window_ops.empty() && window != source_window_)
+ window->AddObserver(this);
+ window_ops.push_back({type, key_state, position});
+ if (window_ops.size() == 1) {
+ // The first item in the queue is the item we're waiting for a response
+ // on. If we're the only item, send it.
+ DispatchFrontOfWindowQueue(window, &window_ops);
+ }
+}
+
+void CurrentDragOperation::RemoveQueueFront(ServerWindow* window) {
+ auto& window_ops = current_window_state_[window];
+ if (window_ops.size() == 1 && window != source_window_) {
+ // This is the last event in queue; stop watching the queue.
+ window->RemoveObserver(this);
+ }
+
+ DCHECK(!window_ops.empty());
+ window_ops.pop_front();
+
+ if (!window_ops.empty())
+ DispatchFrontOfWindowQueue(window, &window_ops);
+}
+
+void CurrentDragOperation::DispatchFrontOfWindowQueue(
+ ServerWindow* target,
+ std::deque<Operation>* queue) {
+ DragTargetConnection* connection = source_->GetDragTargetWithRoot(target);
+
+ DCHECK(!queue->empty());
+ const Operation& op = queue->front();
+ switch (op.type) {
+ case TYPE_ENTER: {
+ connection->PerformOnDragEnter(
+ target, op.key_state, op.position, drag_operations_,
+ base::Bind(&CurrentDragOperation::OnDragStatusCompleted,
+ weak_factory_.GetWeakPtr(), target->id()));
+ break;
+ }
+ case TYPE_OVER: {
+ connection->PerformOnDragOver(
+ target, op.key_state, op.position, drag_operations_,
+ base::Bind(&CurrentDragOperation::OnDragStatusCompleted,
+ weak_factory_.GetWeakPtr(), target->id()));
+ break;
+ }
+ case TYPE_LEAVE: {
+ connection->PerformOnDragLeave(target);
+ RemoveQueueFront(target);
+ break;
+ }
+ case TYPE_DROP: {
+ connection->PerformOnDragDrop(
+ target, op.key_state, op.position, drag_operations_,
+ base::Bind(&CurrentDragOperation::OnDragDropCompleted,
+ weak_factory_.GetWeakPtr(), target->id()));
+ break;
+ }
+ }
+}
+
+void CurrentDragOperation::OnDragStatusCompleted(const WindowId& id,
+ uint32_t bitmask) {
+ ServerWindow* window = source_->GetWindowById(id);
+ if (!window) {
+ // The window has been deleted and its queue is empty.
+ return;
+ }
+
+ // We must remove the completed item.
+ RemoveQueueFront(window);
+
+ // TODO(erg): |bitmask| is the allowed drag actions at the mouse location. We
+ // should use this data to change the cursor.
+}
+
+void CurrentDragOperation::OnDragDropCompleted(const WindowId& id,
+ uint32_t bitmask) {
+ ServerWindow* window = source_->GetWindowById(id);
+ if (!window) {
+ // The window has been deleted after we sent the drop message. It's really
+ // hard to recover from this so just signal to the source that our drag
+ // failed.
+ MessageDragCompleted(false);
+ return;
+ }
+
+ // TODO(erg): What happens if there are events behind the drag drop!?
+ RemoveQueueFront(window);
+ MessageDragCompleted(bitmask != 0u);
+}
+
+void CurrentDragOperation::OnWindowDestroying(ServerWindow* window) {
+ if (current_target_window_ == window)
+ current_target_window_ = nullptr;
+
+ current_window_state_.erase(window);
+ called_on_drag_start_.erase(window);
+
+ if (source_window_ == window) {
+ source_window_ = nullptr;
+ // Our source window is being deleted, fail the drag.
+ MessageDragCompleted(false);
+ }
+}
+
+} // namespace ws
+} // namespace ui

Powered by Google App Engine
This is Rietveld 408576698