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

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: Uploaded for a few comments. Created 4 years, 4 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..90daa8a48bb3da431add5e4e70786934245a17e7
--- /dev/null
+++ b/services/ui/ws/current_drag_operation.cc
@@ -0,0 +1,215 @@
+// 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_delegate.h"
+#include "services/ui/ws/event_dispatcher.h"
+#include "services/ui/ws/server_window.h"
+#include "services/ui/ws/window_server.h"
+#include "services/ui/ws/window_tree.h"
+
+namespace ui {
+namespace ws {
+
+enum DragEventType { TYPE_ENTER, TYPE_OVER, TYPE_LEAVE, TYPE_DROP };
+
+struct CurrentDragOperation::Operation {
+ DragEventType type;
+ uint32_t key_state;
+ gfx::Point position;
+};
+
+// TODO(erg): We need to know when WindowTree gets destroyed, or otherwise put
+// in another layer to communicate back that. This is threaded from the a
+// WindowTree to a WMS to the EventDispatcher to here.
+
+CurrentDragOperation::CurrentDragOperation(
+ CurrentDragOperationDelegate* delegate,
+ uint32_t change_id,
+ WindowTree* source_window_tree,
+ ServerWindow* source_window,
+ mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data,
+ uint32_t drag_operations)
+ : delegate_(delegate),
+ change_id_(change_id),
+ drag_operations_(drag_operations),
+ source_window_tree_(source_window_tree),
+ window_server_(source_window_tree->window_server()),
+ source_window_(source_window),
+ mime_data_(std::move(mime_data)),
+ weak_factory_(this) {
+ source_window_->AddObserver(this);
+}
+
+CurrentDragOperation::~CurrentDragOperation() {
+ source_window_->RemoveObserver(this);
+}
+
+void CurrentDragOperation::DispatchLocatedEvent(
+ const ui::LocatedEvent& event,
+ ServerWindow* current_target,
+ const ClientSpecificId& client_id) {
+ 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
+ // 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;
+ }
+
+ if (event.type() == ET_POINTER_UP) {
+ if (current_target) {
+ auto& window_ops = current_window_state_[current_target];
+ window_ops.push_back({TYPE_DROP, key_state, position});
+ if (window_ops.size() == 1)
+ DispatchFrontOfWindowQueue(current_target, &window_ops);
+ } else {
+ // The pointer was released over no window or a window that doesn't
+ // accept drags.
+ MessageDragCompleted(false);
+ }
+
+ return;
+ }
+
+ if (current_target && current_target == current_target_window_) {
+ // 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.empty()) {
+ // We have no window operations so send it immediately.
+ window_ops.push_back({TYPE_OVER, key_state, position});
+ DispatchFrontOfWindowQueue(current_target, &window_ops);
+ } else 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 {
+ // In all other cases, queue.
+ window_ops.push_back({TYPE_OVER, key_state, position});
+ }
+ } else if (current_target != current_target_window_) {
+ if (current_target_window_) {
+ // TODO(erg): There's probably more clever eliding that we can do by
+ // pulling off DragOver events?
+ auto& window_ops = current_window_state_[current_target_window_];
+ window_ops.push_back({TYPE_LEAVE, key_state, position});
+ if (window_ops.size() == 1)
+ DispatchFrontOfWindowQueue(current_target_window_, &window_ops);
+ }
+
+ if (current_target) {
+ auto& window_ops = current_window_state_[current_target];
+ window_ops.push_back({TYPE_ENTER, key_state, position});
+ if (window_ops.size() == 1)
+ DispatchFrontOfWindowQueue(current_target, &window_ops);
+ }
+
+ current_target_window_ = current_target;
+ }
+}
+
+void CurrentDragOperation::MessageDragCompleted(bool success) {
+ // Message our original caller that this drag is completed.
+ source_window_tree_->OnChangeCompleted(change_id_, success);
+
+ // Deletes the CurrentDragOperation.
+ delegate_->OnDragOver(false);
+}
+
+void CurrentDragOperation::DispatchFrontOfWindowQueue(
+ ServerWindow* target,
+ std::deque<Operation>* queue) {
+ WindowTree* tree = window_server_->GetTreeWithRoot(target);
+
+ DCHECK(!queue->empty());
+ const Operation& op = queue->front();
+ switch (op.type) {
+ case TYPE_ENTER: {
+ tree->PerformOnDragEnter(
+ target, mime_data_.Clone(), op.key_state, op.position,
+ drag_operations_,
+ base::Bind(&CurrentDragOperation::OnDragStatusCompleted,
+ weak_factory_.GetWeakPtr(), target->id()));
+ break;
+ }
+ case TYPE_OVER: {
+ tree->PerformOnDragOver(
+ target, op.key_state, op.position, drag_operations_,
+ base::Bind(&CurrentDragOperation::OnDragStatusCompleted,
+ weak_factory_.GetWeakPtr(), target->id()));
+ break;
+ }
+ case TYPE_LEAVE: {
+ tree->PerformOnDragLeave(target);
+ queue->pop_front();
+ if (!queue->empty())
+ DispatchFrontOfWindowQueue(target, queue);
+ break;
+ }
+ case TYPE_DROP: {
+ tree->PerformOnDragDrop(
+ target, op.key_state, op.position, drag_operations_,
+ base::Bind(&CurrentDragOperation::OnDragDropCompleted,
+ weak_factory_.GetWeakPtr(), target->id()));
+ break;
+ }
+ }
+}
+
+void CurrentDragOperation::OnWindowDestroying(ServerWindow* window) {
+ current_window_state_.erase(window);
+
+ if (current_target_window_ == window)
+ current_target_window_ = nullptr;
+}
+
+void CurrentDragOperation::OnDragStatusCompleted(const WindowId& id,
+ uint32_t bitmask) {
+ ServerWindow* window = window_server_->GetWindow(id);
+ DCHECK(window);
+
+ // We must remove the completed item.
+ auto& window_ops = current_window_state_[window];
+ DCHECK(!window_ops.empty());
+ window_ops.pop_front();
+
+ if (!window_ops.empty()) {
+ // There are queued events here. We should dispatch them.
+ DispatchFrontOfWindowQueue(window, &window_ops);
+ }
+
+ // 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 = window_server_->GetWindow(id);
+ DCHECK(window);
+
+ // We must remove the completed item.
+ auto& window_ops = current_window_state_[window];
+ DCHECK(!window_ops.empty());
+ DCHECK_EQ(TYPE_DROP, window_ops.front().type);
+ window_ops.pop_front();
+ DCHECK(window_ops.empty());
+
+ MessageDragCompleted(bitmask != 0u);
+}
+
+} // namespace ws
+} // namespace ui

Powered by Google App Engine
This is Rietveld 408576698