Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 | |
| OLD | NEW |