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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 "services/ui/ws/current_drag_operation.h"
6
7 #include "base/logging.h"
8 #include "services/ui/ws/current_drag_operation_source.h"
9 #include "services/ui/ws/drag_target_connection.h"
10 #include "services/ui/ws/event_dispatcher.h"
11 #include "services/ui/ws/server_window.h"
12
13 namespace ui {
14 namespace ws {
15
16 struct CurrentDragOperation::Operation {
17 DragEventType type;
18 uint32_t key_state;
19 gfx::Point position;
sky 2016/09/06 21:11:27 Document what this is relative to. Screen?
20 };
21
22 CurrentDragOperation::CurrentDragOperation(
23 CurrentDragOperationSource* source,
24 ServerWindow* window,
25 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data,
26 uint32_t drag_operations)
27 : source_(source),
28 drag_operations_(drag_operations),
29 source_window_(window),
30 mime_data_(std::move(mime_data)),
31 weak_factory_(this) {
32 source_window_->AddObserver(this);
33 }
34
35 CurrentDragOperation::~CurrentDragOperation() {
36 if (source_window_)
37 source_window_->RemoveObserver(this);
38 }
39
40 void CurrentDragOperation::DispatchCancel() {
41 MessageDragCompleted(false);
42 }
43
44 void CurrentDragOperation::DispatchLocatedEvent(const ui::LocatedEvent& event,
45 ServerWindow* current_target) {
46 uint32_t key_state = event.flags();
47 gfx::Point position = event.location();
48
49 if (waiting_for_final_drop_response_) {
50 // 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
51 // call, don't process any more mouse events.
52 return;
53 }
54
55 if (current_target && !current_target->can_accept_drags()) {
56 // If the current window over point doesn't accept drops, than don't send
57 // it events.
58 current_target = nullptr;
sky 2016/09/06 21:11:27 Shouldn't this bubble
59 }
60
61 if (current_target && current_target == current_target_window_ &&
62 event.type() != ET_POINTER_UP) {
sky 2016/09/06 21:11:27 Shouldn't you only care about POINTER_UP of the po
63 // We're continuing a drag inside the bounds of
64 // |current_target_window_|. Send a continue message.
65 auto& window_ops = current_window_state_[current_target];
66 if (window_ops.size() > 1 && window_ops.back().type == TYPE_OVER) {
67 // If we have a queued DragOver which isn't in progress, then just
68 // modify it's data.
69 auto& back = window_ops.back();
70 back.key_state = key_state;
71 back.position = position;
72 } else {
73 QueueEvent(current_target, TYPE_OVER, key_state, position);
74 }
75 } else if (current_target != current_target_window_) {
76 if (current_target_window_) {
77 auto& window_ops = current_window_state_[current_target_window_];
78 if (window_ops.size() > 1 && window_ops.back().type == TYPE_OVER) {
79 // If we have queued DragOver events, we want to replace them.
80 auto& back = window_ops.back();
81 back.type = TYPE_LEAVE;
82 back.key_state = key_state;
83 back.position = position;
84 } else {
85 QueueEvent(current_target_window_, TYPE_LEAVE, key_state, position);
86 }
87 }
88
89 if (current_target)
90 QueueEvent(current_target, TYPE_ENTER, key_state, position);
91
92 current_target_window_ = current_target;
93 }
94
95 if (event.type() == ET_POINTER_UP) {
96 if (current_target) {
97 QueueEvent(current_target, TYPE_DROP, key_state, position);
98 waiting_for_final_drop_response_ = true;
99 } else {
100 // The pointer was released over no window or a window that doesn't
101 // accept drags.
102 MessageDragCompleted(false);
103 }
104 }
105 }
106
107 void CurrentDragOperation::MessageDragCompleted(bool success) {
108 for (ServerWindow* window : called_on_drag_start_) {
109 DragTargetConnection* connection = source_->GetDragTargetWithRoot(window);
110 if (connection)
111 connection->PerformOnDragFinish(window);
112 }
113 called_on_drag_start_.clear();
114
115 source_->OnDragOver(success);
116 // |this| may be invalid now.
117 }
118
119 size_t CurrentDragOperation::GetSizeOfQueueForWindow(ServerWindow* window) {
120 auto it = current_window_state_.find(window);
121 if (it == current_window_state_.end())
122 return 0u;
123 return it->second.size();
124 }
125
126 void CurrentDragOperation::QueueEvent(ServerWindow* window,
127 DragEventType type,
128 uint32_t key_state,
129 gfx::Point position) {
130 // If this window doesn't have the mime data, send it a PerformOnDragStart()
131 // message.
132 if (window != source_window_ &&
133 !base::ContainsKey(called_on_drag_start_, window)) {
134 DragTargetConnection* connection = source_->GetDragTargetWithRoot(window);
135 connection->PerformOnDragStart(window, mime_data_.Clone());
136 called_on_drag_start_.insert(window);
137 }
138
139 auto& window_ops = current_window_state_[window];
140 if (window_ops.empty() && window != source_window_)
141 window->AddObserver(this);
142 window_ops.push_back({type, key_state, position});
143 if (window_ops.size() == 1) {
144 // The first item in the queue is the item we're waiting for a response
145 // on. If we're the only item, send it.
146 DispatchFrontOfWindowQueue(window, &window_ops);
147 }
148 }
149
150 void CurrentDragOperation::RemoveQueueFront(ServerWindow* window) {
151 auto& window_ops = current_window_state_[window];
152 if (window_ops.size() == 1 && window != source_window_) {
153 // This is the last event in queue; stop watching the queue.
154 window->RemoveObserver(this);
155 }
156
157 DCHECK(!window_ops.empty());
158 window_ops.pop_front();
159
160 if (!window_ops.empty())
161 DispatchFrontOfWindowQueue(window, &window_ops);
162 }
163
164 void CurrentDragOperation::DispatchFrontOfWindowQueue(
165 ServerWindow* target,
166 std::deque<Operation>* queue) {
167 DragTargetConnection* connection = source_->GetDragTargetWithRoot(target);
168
169 DCHECK(!queue->empty());
170 const Operation& op = queue->front();
171 switch (op.type) {
172 case TYPE_ENTER: {
173 connection->PerformOnDragEnter(
174 target, op.key_state, op.position, drag_operations_,
175 base::Bind(&CurrentDragOperation::OnDragStatusCompleted,
176 weak_factory_.GetWeakPtr(), target->id()));
177 break;
178 }
179 case TYPE_OVER: {
180 connection->PerformOnDragOver(
181 target, op.key_state, op.position, drag_operations_,
182 base::Bind(&CurrentDragOperation::OnDragStatusCompleted,
183 weak_factory_.GetWeakPtr(), target->id()));
184 break;
185 }
186 case TYPE_LEAVE: {
187 connection->PerformOnDragLeave(target);
188 RemoveQueueFront(target);
189 break;
190 }
191 case TYPE_DROP: {
192 connection->PerformOnDragDrop(
193 target, op.key_state, op.position, drag_operations_,
194 base::Bind(&CurrentDragOperation::OnDragDropCompleted,
195 weak_factory_.GetWeakPtr(), target->id()));
196 break;
197 }
198 }
199 }
200
201 void CurrentDragOperation::OnDragStatusCompleted(const WindowId& id,
202 uint32_t bitmask) {
203 ServerWindow* window = source_->GetWindowById(id);
204 if (!window) {
205 // The window has been deleted and its queue is empty.
206 return;
207 }
208
209 // We must remove the completed item.
210 RemoveQueueFront(window);
211
212 // TODO(erg): |bitmask| is the allowed drag actions at the mouse location. We
213 // should use this data to change the cursor.
214 }
215
216 void CurrentDragOperation::OnDragDropCompleted(const WindowId& id,
217 uint32_t bitmask) {
218 ServerWindow* window = source_->GetWindowById(id);
219 if (!window) {
220 // The window has been deleted after we sent the drop message. It's really
221 // hard to recover from this so just signal to the source that our drag
222 // failed.
223 MessageDragCompleted(false);
224 return;
225 }
226
227 // TODO(erg): What happens if there are events behind the drag drop!?
228 RemoveQueueFront(window);
229 MessageDragCompleted(bitmask != 0u);
230 }
231
232 void CurrentDragOperation::OnWindowDestroying(ServerWindow* window) {
233 if (current_target_window_ == window)
234 current_target_window_ = nullptr;
235
236 current_window_state_.erase(window);
237 called_on_drag_start_.erase(window);
238
239 if (source_window_ == window) {
240 source_window_ = nullptr;
241 // Our source window is being deleted, fail the drag.
242 MessageDragCompleted(false);
243 }
244 }
245
246 } // namespace ws
247 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698