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

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: Clear the implicit pointer drags before start. 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 EventType type;
18 uint32_t key_state;
19 gfx::Point screen_position;
20 };
21
22 DragController::DragController(
23 DragSource* source,
24 ServerWindow* window,
25 int32_t drag_pointer,
26 mojo::Map<mojo::String, mojo::Array<uint8_t>> mime_data,
27 uint32_t drag_operations)
28 : source_(source),
29 drag_operations_(drag_operations),
30 drag_pointer_id_(drag_pointer),
31 source_window_(window),
32 mime_data_(std::move(mime_data)),
33 weak_factory_(this) {
34 source_window_->AddObserver(this);
35 }
36
37 DragController::~DragController() {
38 if (source_window_)
39 source_window_->RemoveObserver(this);
40 }
41
42 void DragController::Cancel() {
43 MessageDragCompleted(false);
44 // |this| may be invalid now.
sky 2016/09/08 23:37:20 invalid->deleted?
45 }
46
47 bool DragController::DispatchPointerEvent(const ui::PointerEvent& event,
48 ServerWindow* current_target) {
49 uint32_t key_state = event.flags();
sky 2016/09/08 23:37:20 Naming this key_state, when it's event_flags is mi
50 gfx::Point screen_position = event.location();
51
52 if (waiting_for_final_drop_response_) {
53 // If we're waiting on a target window to respond to the final drag drop
54 // call, don't process any more pointer events.
55 return false;
56 }
57
58 if (event.pointer_id() != drag_pointer_id_)
59 return false;
60
61 // If |current_target| doesn't accept drags, walk its hierarchy up until we
62 // find one that does (or set to nullptr at the top of the tree).
63 while (current_target && !current_target->can_accept_drops())
64 current_target = current_target->parent();
65
66 if (current_target && current_target == current_target_window_ &&
67 event.type() != ET_POINTER_UP) {
68 // We're continuing a drag inside the bounds of
69 // |current_target_window_|. Send a continue message.
70 auto& window_ops = window_operations_[current_target];
71 if (window_ops.size() > 1 && window_ops.back().type == EventType::OVER) {
72 // If we have a queued DragOver which isn't in progress, then just
73 // modify it's data.
74 auto& back = window_ops.back();
75 back.key_state = key_state;
76 back.screen_position = screen_position;
77 } else {
78 QueueEvent(current_target, EventType::OVER, key_state, screen_position);
79 }
80 } else if (current_target != current_target_window_) {
81 if (current_target_window_) {
82 auto& window_ops = window_operations_[current_target_window_];
83 if (window_ops.size() > 1 && window_ops.back().type == EventType::OVER) {
84 // If we have queued DragOver events, we want to replace them.
85 auto& back = window_ops.back();
86 back.type = EventType::LEAVE;
87 back.key_state = key_state;
88 back.screen_position = screen_position;
89 } else {
90 QueueEvent(current_target_window_, EventType::LEAVE, key_state,
91 screen_position);
92 }
93 }
94
95 if (current_target)
96 QueueEvent(current_target, EventType::ENTER, key_state, screen_position);
97
98 current_target_window_ = current_target;
99 }
100
101 if (event.type() == ET_POINTER_UP) {
102 if (current_target) {
103 QueueEvent(current_target, EventType::DROP, key_state, screen_position);
104 waiting_for_final_drop_response_ = true;
105 } else {
106 // The pointer was released over no window or a window that doesn't
107 // accept drags.
108 MessageDragCompleted(false);
109 }
110 }
111
112 return true;
113 }
114
115 void DragController::MessageDragCompleted(bool success) {
116 for (ServerWindow* window : called_on_drag_start_) {
117 DragTargetConnection* connection = source_->GetDragTargetWithRoot(window);
118 if (connection)
119 connection->PerformOnDragFinish(window);
120 }
121 called_on_drag_start_.clear();
122
123 source_->OnDragCompleted(success);
124 // |this| may be invalid now.
125 }
126
127 size_t DragController::GetSizeOfQueueForWindow(ServerWindow* window) {
128 auto it = window_operations_.find(window);
129 if (it == window_operations_.end())
130 return 0u;
131 return it->second.size();
132 }
133
134 void DragController::QueueEvent(ServerWindow* window,
135 EventType type,
136 uint32_t key_state,
137 gfx::Point screen_position) {
138 // If this window doesn't have the mime data, send it a PerformOnDragStart()
139 // message.
140 if (window != source_window_ &&
141 !base::ContainsKey(called_on_drag_start_, window)) {
142 DragTargetConnection* connection = source_->GetDragTargetWithRoot(window);
143 connection->PerformOnDragStart(window, mime_data_.Clone());
144 called_on_drag_start_.insert(window);
145 }
146
147 auto& window_ops = window_operations_[window];
148 if (window_ops.empty() && window != source_window_)
149 window->AddObserver(this);
150 window_ops.push_back({type, key_state, screen_position});
151 if (window_ops.size() == 1) {
152 // The first item in the queue is the item we're waiting for a response
153 // on. If we're the only item, send it.
154 DispatchFrontOfWindowQueue(window, &window_ops);
155 }
156 }
157
158 void DragController::RemoveQueueFront(ServerWindow* window) {
159 auto& window_ops = window_operations_[window];
160 if (window_ops.size() == 1 && window != source_window_) {
161 // This is the last event in queue; stop watching the queue.
162 window->RemoveObserver(this);
163 }
164
165 DCHECK(!window_ops.empty());
166 window_ops.pop_front();
167
168 if (!window_ops.empty())
169 DispatchFrontOfWindowQueue(window, &window_ops);
170 }
171
172 void DragController::DispatchFrontOfWindowQueue(ServerWindow* target,
173 std::deque<Operation>* queue) {
174 DragTargetConnection* connection = source_->GetDragTargetWithRoot(target);
175
176 DCHECK(!queue->empty());
177 const Operation& op = queue->front();
178 switch (op.type) {
179 case EventType::ENTER: {
180 connection->PerformOnDragEnter(
181 target, op.key_state, op.screen_position, drag_operations_,
182 base::Bind(&DragController::OnDragStatusCompleted,
183 weak_factory_.GetWeakPtr(), target->id()));
184 break;
185 }
186 case EventType::OVER: {
187 connection->PerformOnDragOver(
188 target, op.key_state, op.screen_position, drag_operations_,
189 base::Bind(&DragController::OnDragStatusCompleted,
190 weak_factory_.GetWeakPtr(), target->id()));
191 break;
192 }
193 case EventType::LEAVE: {
194 connection->PerformOnDragLeave(target);
195 RemoveQueueFront(target);
196 break;
197 }
198 case EventType::DROP: {
199 connection->PerformOnDragDrop(
200 target, op.key_state, op.screen_position, drag_operations_,
201 base::Bind(&DragController::OnDragDropCompleted,
202 weak_factory_.GetWeakPtr(), target->id()));
203 break;
204 }
205 }
206 }
207
208 void DragController::OnDragStatusCompleted(const WindowId& id,
209 uint32_t bitmask) {
210 ServerWindow* window = source_->GetWindowById(id);
211 if (!window) {
212 // The window has been deleted and its queue is empty.
213 return;
214 }
215
216 // We must remove the completed item.
217 RemoveQueueFront(window);
218
219 // TODO(erg): |bitmask| is the allowed drag actions at the mouse location. We
220 // should use this data to change the cursor.
221 }
222
223 void DragController::OnDragDropCompleted(const WindowId& id, uint32_t bitmask) {
224 ServerWindow* window = source_->GetWindowById(id);
225 if (!window) {
226 // The window has been deleted after we sent the drop message. It's really
227 // hard to recover from this so just signal to the source that our drag
228 // failed.
229 MessageDragCompleted(false);
230 return;
231 }
232
233 // TODO(erg): What happens if there are events behind the drag drop!?
234 RemoveQueueFront(window);
235 MessageDragCompleted(bitmask != 0u);
236 }
237
238 void DragController::OnWindowDestroying(ServerWindow* window) {
239 if (current_target_window_ == window)
sky 2016/09/08 23:37:20 You never add an observer for current_target_windo
240 current_target_window_ = nullptr;
241
242 window_operations_.erase(window);
243 called_on_drag_start_.erase(window);
244
245 if (source_window_ == window) {
246 source_window_ = nullptr;
sky 2016/09/08 23:37:20 RemoveObserver?
Elliot Glaysher 2016/09/13 00:14:19 Did this and also made sure we were unsubscribing
247 // Our source window is being deleted, fail the drag.
248 MessageDragCompleted(false);
249 }
250 }
251
252 } // namespace ws
253 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698