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

Side by Side Diff: services/ui/ws/drag_controller.cc

Issue 2266603002: mus: Implement interwindow drag and drop (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove 'window &&' 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/drag_controller.h"
6
7 #include "base/logging.h"
8 #include "services/ui/ws/drag_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 DragController::Operation {
17 OperationType type;
18 uint32_t event_flags;
19 gfx::Point screen_position;
20 };
21
22 struct DragController::WindowState {
sky 2016/09/15 18:10:47 Much easier to understand, and better documented.
23 // Set to true once we've observed
sky 2016/09/15 18:10:47 Did you forget to finish the sentence?
24 bool observed;
25
26 // If we're waiting for a response, this is the type of message. TYPE_NONE
27 // means there's no outstanding
28 OperationType waiting_on_reply;
29
30 // The operation that we'll send off if |waiting_on_reply| isn't TYPE_NONE.
31 Operation queued_operation;
32 };
33
34 DragController::DragController(
35 DragSource* source,
36 ServerWindow* source_window,
37 DragTargetConnection* source_connection,
38 int32_t drag_pointer,
39 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data,
40 uint32_t drag_operations)
41 : source_(source),
42 drag_operations_(drag_operations),
43 drag_pointer_id_(drag_pointer),
44 source_window_(source_window),
45 source_connection_(source_connection),
46 mime_data_(std::move(mime_data)),
47 weak_factory_(this) {
48 EnsureWindowObserved(source_window_);
49 }
50
51 DragController::~DragController() {
52 for (auto& pair : window_state_) {
53 if (pair.second.observed)
54 pair.first->RemoveObserver(this);
55 }
56 }
57
58 void DragController::Cancel() {
59 MessageDragCompleted(false);
60 // |this| may be deleted now.
61 }
62
63 bool DragController::DispatchPointerEvent(const ui::PointerEvent& event,
64 ServerWindow* current_target) {
65 uint32_t event_flags =
66 event.flags() &
67 (ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN);
68 gfx::Point screen_position = event.location();
69
70 if (waiting_for_final_drop_response_) {
71 // If we're waiting on a target window to respond to the final drag drop
72 // call, don't process any more pointer events.
73 return false;
74 }
75
76 if (event.pointer_id() != drag_pointer_id_)
77 return false;
78
79 // If |current_target| doesn't accept drags, walk its hierarchy up until we
80 // find one that does (or set to nullptr at the top of the tree).
81 while (current_target && !current_target->can_accept_drops())
82 current_target = current_target->parent();
83
84 if (current_target) {
85 // If we're non-null, we're about to use |current_target| in some
86 // way. Ensure that we receive notifications that this window has gone
87 // away.
88 EnsureWindowObserved(current_target);
89 }
90
91 if (current_target && current_target == current_target_window_ &&
92 event.type() != ET_POINTER_UP) {
93 QueueOperation(current_target, OperationType::OVER, event_flags,
94 screen_position);
95 } else if (current_target != current_target_window_) {
96 if (current_target_window_) {
97 QueueOperation(current_target_window_, OperationType::LEAVE, event_flags,
98 screen_position);
99 }
100
101 if (current_target) {
102 // TODO(erg): If we have a queued LEAVE operation, does this turn into a
103 // noop?
104 QueueOperation(current_target, OperationType::ENTER, event_flags,
105 screen_position);
106 }
107
108 SetCurrentTargetWindow(current_target);
109 }
110
111 if (event.type() == ET_POINTER_UP) {
112 if (current_target) {
113 QueueOperation(current_target, OperationType::DROP, event_flags,
114 screen_position);
115 waiting_for_final_drop_response_ = true;
116 } else {
117 // The pointer was released over no window or a window that doesn't
118 // accept drags.
119 MessageDragCompleted(false);
120 }
121 }
122
123 return true;
124 }
125
126 void DragController::OnWillDestroyDragTargetConnection(
127 DragTargetConnection* connection) {
128 called_on_drag_mime_types_.erase(connection);
129 }
130
131 void DragController::MessageDragCompleted(bool success) {
132 for (DragTargetConnection* connection : called_on_drag_mime_types_)
133 connection->PerformOnDragDropDone();
134 called_on_drag_mime_types_.clear();
135
136 source_->OnDragCompleted(success);
137 // |this| may be deleted now.
138 }
139
140 size_t DragController::GetSizeOfQueueForWindow(ServerWindow* window) {
sky 2016/09/15 18:10:47 It doesn't seem as though you are using this anymo
Elliot Glaysher 2016/09/15 19:14:33 It's used in the unit tests via the private testin
141 auto it = window_state_.find(window);
142 if (it == window_state_.end())
143 return 0u;
144 if (it->second.waiting_on_reply == OperationType::NONE)
145 return 0u;
146 if (it->second.queued_operation.type == OperationType::NONE)
147 return 1u;
148 return 2u;
149 }
150
151 void DragController::SetCurrentTargetWindow(ServerWindow* current_target) {
152 current_target_window_ = current_target;
153 }
154
155 void DragController::EnsureWindowObserved(ServerWindow* window) {
156 if (!window)
157 return;
158
159 WindowState& state = window_state_[window];
160 if (!state.observed) {
161 state.observed = true;
162 window->AddObserver(this);
163 }
164 }
165
166 void DragController::QueueOperation(ServerWindow* window,
167 OperationType type,
168 uint32_t event_flags,
169 gfx::Point screen_position) {
170 // If this window doesn't have the mime data, send it.
171 DragTargetConnection* connection = source_->GetDragTargetForWindow(window);
172 if (connection != source_connection_ &&
173 !base::ContainsKey(called_on_drag_mime_types_, connection)) {
174 connection->PerformOnDragDropStart(mime_data_.Clone());
175 called_on_drag_mime_types_.insert(connection);
176 }
177
178 WindowState& state = window_state_[window];
179 // Set the queued operation to the incoming.
180 state.queued_operation = {type, event_flags, screen_position};
181
182 if (state.waiting_on_reply == OperationType::NONE) {
183 // Send the operation immediately.
184 DispatchOperation(window, &state);
185 }
186 }
187
188 void DragController::DispatchOperation(ServerWindow* target,
189 WindowState* state) {
190 DragTargetConnection* connection = source_->GetDragTargetForWindow(target);
191
192 DCHECK_EQ(OperationType::NONE, state->waiting_on_reply);
193 Operation& op = state->queued_operation;
194 switch (op.type) {
195 case OperationType::NONE: {
sky 2016/09/15 18:10:47 It is possible to get here with an operation of NO
Elliot Glaysher 2016/09/15 19:14:33 Added a NOTREACHED() to emphasize that this is to
196 break;
197 }
198 case OperationType::ENTER: {
199 connection->PerformOnDragEnter(
200 target, op.event_flags, op.screen_position, drag_operations_,
201 base::Bind(&DragController::OnDragStatusCompleted,
202 weak_factory_.GetWeakPtr(), target->id()));
203 state->waiting_on_reply = OperationType::ENTER;
204 break;
205 }
206 case OperationType::OVER: {
207 connection->PerformOnDragOver(
208 target, op.event_flags, op.screen_position, drag_operations_,
209 base::Bind(&DragController::OnDragStatusCompleted,
210 weak_factory_.GetWeakPtr(), target->id()));
211 state->waiting_on_reply = OperationType::OVER;
212 break;
213 }
214 case OperationType::LEAVE: {
215 connection->PerformOnDragLeave(target);
216 state->waiting_on_reply = OperationType::NONE;
217 break;
218 }
219 case OperationType::DROP: {
220 connection->PerformOnCompleteDrop(
221 target, op.event_flags, op.screen_position, drag_operations_,
222 base::Bind(&DragController::OnDragDropCompleted,
223 weak_factory_.GetWeakPtr(), target->id()));
224 state->waiting_on_reply = OperationType::DROP;
225 break;
226 }
227 }
228
229 state->queued_operation = {OperationType::NONE, 0, gfx::Point()};
230 }
231
232 void DragController::OnRespondToOperation(ServerWindow* window) {
233 WindowState& state = window_state_[window];
234 DCHECK_NE(OperationType::NONE, state.waiting_on_reply);
235 state.waiting_on_reply = OperationType::NONE;
236 if (state.queued_operation.type != OperationType::NONE)
237 DispatchOperation(window, &state);
238 }
239
240 void DragController::OnDragStatusCompleted(const WindowId& id,
241 uint32_t bitmask) {
242 ServerWindow* window = source_->GetWindowById(id);
243 if (!window) {
244 // The window has been deleted and its queue is empty.
245 return;
246 }
247
248 // We must remove the completed item.
249 OnRespondToOperation(window);
250
251 // TODO(erg): |bitmask| is the allowed drag actions at the mouse location. We
252 // should use this data to change the cursor.
253 }
254
255 void DragController::OnDragDropCompleted(const WindowId& id, uint32_t bitmask) {
256 ServerWindow* window = source_->GetWindowById(id);
257 if (!window) {
258 // The window has been deleted after we sent the drop message. It's really
259 // hard to recover from this so just signal to the source that our drag
260 // failed.
261 MessageDragCompleted(false);
262 return;
263 }
264
265 OnRespondToOperation(window);
266 MessageDragCompleted(bitmask != 0u);
267 }
268
269 void DragController::OnWindowDestroying(ServerWindow* window) {
270 auto it = window_state_.find(window);
271 if (it != window_state_.end()) {
272 window->RemoveObserver(this);
273 window_state_.erase(it);
274 }
275
276 if (current_target_window_ == window)
277 current_target_window_ = nullptr;
278
279 if (source_window_ == window) {
280 source_window_ = nullptr;
281 // Our source window is being deleted, fail the drag.
282 MessageDragCompleted(false);
283 }
284 }
285
286 } // namespace ws
287 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698