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

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

Powered by Google App Engine
This is Rietveld 408576698