Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h" | 5 #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h" |
| 6 | 6 |
| 7 #include <X11/Xatom.h> | 7 #include <X11/Xatom.h> |
| 8 | 8 |
| 9 #include "base/event_types.h" | 9 #include "base/event_types.h" |
| 10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
| 11 #include "ui/aura/client/drag_drop_client.h" | 11 #include "ui/aura/client/drag_drop_client.h" |
| 12 #include "ui/aura/client/drag_drop_delegate.h" | 12 #include "ui/aura/client/drag_drop_delegate.h" |
| 13 #include "ui/aura/root_window.h" | 13 #include "ui/aura/root_window.h" |
| 14 #include "ui/aura/window.h" | 14 #include "ui/aura/window.h" |
| 15 #include "ui/base/dragdrop/drag_drop_types.h" | 15 #include "ui/base/dragdrop/drag_drop_types.h" |
| 16 #include "ui/base/dragdrop/os_exchange_data.h" | 16 #include "ui/base/dragdrop/os_exchange_data.h" |
| 17 #include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h" | 17 #include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h" |
| 18 #include "ui/base/events/event.h" | 18 #include "ui/base/events/event.h" |
| 19 #include "ui/base/x/selection_utils.h" | |
| 19 #include "ui/base/x/x11_util.h" | 20 #include "ui/base/x/x11_util.h" |
| 20 #include "ui/views/widget/desktop_aura/desktop_root_window_host_x11.h" | 21 #include "ui/views/widget/desktop_aura/desktop_root_window_host_x11.h" |
| 21 | 22 |
| 22 using aura::client::DragDropDelegate; | 23 using aura::client::DragDropDelegate; |
| 23 using ui::OSExchangeData; | 24 using ui::OSExchangeData; |
| 24 | 25 |
| 25 namespace { | 26 namespace { |
| 26 | 27 |
| 28 const int kMinXdndVersion = 5; | |
| 29 | |
| 27 const char kXdndActionCopy[] = "XdndActionCopy"; | 30 const char kXdndActionCopy[] = "XdndActionCopy"; |
| 28 const char kXdndActionMove[] = "XdndActionMove"; | 31 const char kXdndActionMove[] = "XdndActionMove"; |
| 29 const char kXdndActionLink[] = "XdndActionLink"; | 32 const char kXdndActionLink[] = "XdndActionLink"; |
| 30 | 33 |
| 34 const char kChromiumDragReciever[] = "CHROMIUM_DRAG_RECEIVER"; | |
|
Daniel Erat
2013/06/17 22:09:57
nit: prefix vendor-specific atoms with underscores
| |
| 35 const char kXdndSelection[] = "XdndSelection"; | |
| 36 | |
| 31 const char* kAtomsToCache[] = { | 37 const char* kAtomsToCache[] = { |
| 38 kChromiumDragReciever, | |
| 32 "XdndActionAsk", | 39 "XdndActionAsk", |
| 33 kXdndActionCopy, | 40 kXdndActionCopy, |
| 34 kXdndActionLink, | 41 kXdndActionLink, |
| 35 "XdndActionList", | 42 "XdndActionList", |
| 36 kXdndActionMove, | 43 kXdndActionMove, |
| 37 "XdndActionPrivate", | 44 "XdndActionPrivate", |
| 38 "XdndAware", | 45 "XdndAware", |
| 39 "XdndDrop", | 46 "XdndDrop", |
| 40 "XdndEnter", | 47 "XdndEnter", |
| 41 "XdndFinished", | 48 "XdndFinished", |
| 42 "XdndLeave", | 49 "XdndLeave", |
| 43 "XdndPosition", | 50 "XdndPosition", |
| 44 "XdndProxy", // Proxy windows? | 51 "XdndProxy", // Proxy windows? |
| 45 "XdndSelection", | 52 kXdndSelection, |
| 46 "XdndStatus", | 53 "XdndStatus", |
| 47 "XdndTypeList", | 54 "XdndTypeList", |
| 48 NULL | 55 NULL |
| 49 }; | 56 }; |
| 50 | 57 |
| 58 class DragTargetWindowFinder : public ui::EnumerateWindowsDelegate { | |
|
Daniel Erat
2013/06/17 22:09:57
please add a comment describing what this class do
| |
| 59 public: | |
| 60 DragTargetWindowFinder(XID ignored_icon_window, | |
| 61 gfx::Point screen_loc) | |
| 62 : ignored_icon_window_(ignored_icon_window), | |
| 63 output_window_(None), | |
| 64 screen_loc_(screen_loc) { | |
| 65 ui::EnumerateTopLevelWindows(this); | |
| 66 } | |
| 67 | |
| 68 virtual ~DragTargetWindowFinder() {} | |
| 69 | |
| 70 XID window() const { return output_window_; } | |
| 71 | |
| 72 protected: | |
| 73 virtual bool ShouldStopIterating(XID window) OVERRIDE { | |
| 74 if (window == ignored_icon_window_) | |
| 75 return false; | |
| 76 | |
| 77 if (!ui::IsWindowVisible(window)) | |
| 78 return false; | |
| 79 | |
| 80 if (!ui::WindowContainsPoint(window, screen_loc_)) | |
| 81 return false; | |
| 82 | |
| 83 if (ui::PropertyExists(window, "WM_STATE")) { | |
| 84 output_window_ = window; | |
| 85 return true; | |
| 86 } | |
| 87 | |
| 88 return false; | |
| 89 } | |
| 90 | |
| 91 private: | |
| 92 XID ignored_icon_window_; | |
| 93 XID output_window_; | |
| 94 gfx::Point screen_loc_; | |
| 95 | |
| 96 DISALLOW_COPY_AND_ASSIGN(DragTargetWindowFinder); | |
| 97 }; | |
| 98 | |
| 99 // Returns the topmost X11 window at |screen_point| if it is advertising that | |
| 100 // is supports the Xdnd protocol. Will return the window under the pointer as | |
| 101 // |mouse_window|. If there's a Xdnd aware window, it will be returned in | |
| 102 // |dest_window|. | |
| 103 void FindWindowFor(const gfx::Point& screen_point, | |
| 104 ::Window* mouse_window, ::Window* dest_window) { | |
| 105 DragTargetWindowFinder finder(None, screen_point); | |
| 106 *mouse_window = finder.window(); | |
| 107 | |
| 108 if (finder.window() == None) { | |
| 109 NOTIMPLEMENTED(); | |
|
Daniel Erat
2013/06/17 22:09:57
this NOTIMPLEMENTED() seems weird to me -- what do
Elliot Glaysher
2013/06/18 00:06:39
I wanted a nonfatal log. Deleted.
| |
| 110 *dest_window = None; | |
|
Daniel Erat
2013/06/17 22:09:57
how about clearing dest_window at the beginning of
| |
| 111 return; | |
| 112 } | |
| 113 | |
| 114 // Figure out which window we should test as XdndAware. If mouse_window has | |
| 115 // XdndProxy, it will set that proxy on target, and if not, |target|'s | |
| 116 // original value will remain. | |
| 117 XID target = *mouse_window; | |
| 118 ui::GetXIDProperty(*mouse_window, "XdndProxy", &target); | |
| 119 | |
| 120 int version; | |
| 121 if (ui::GetIntProperty(target, "XdndAware", &version) && | |
| 122 version >= kMinXdndVersion) { | |
| 123 *dest_window = target; | |
| 124 } else { | |
| 125 *dest_window = None; | |
| 126 } | |
| 127 } | |
| 128 | |
| 51 } // namespace | 129 } // namespace |
| 52 | 130 |
| 53 namespace views { | 131 namespace views { |
| 54 | 132 |
| 133 std::map< ::Window, DesktopDragDropClientAuraX11*> | |
| 134 DesktopDragDropClientAuraX11::g_live_client_map; | |
| 135 | |
| 55 class DesktopDragDropClientAuraX11::X11DragContext : | 136 class DesktopDragDropClientAuraX11::X11DragContext : |
| 56 public base::MessageLoop::Dispatcher { | 137 public base::MessageLoop::Dispatcher { |
| 57 public: | 138 public: |
| 58 X11DragContext(ui::X11AtomCache* atom_cache, | 139 X11DragContext(ui::X11AtomCache* atom_cache, |
| 140 ::Window local_window, | |
| 59 const XClientMessageEvent& event); | 141 const XClientMessageEvent& event); |
| 60 virtual ~X11DragContext(); | 142 virtual ~X11DragContext(); |
| 61 | 143 |
| 62 const std::vector<Atom>& targets() { return targets_; } | 144 // When we receive an XdndPosition message, we need to have all the data |
| 145 // copied from the other window before we process the XdndPosition | |
| 146 // message. If we have that data already, dispatch immediately. Otherwise, | |
| 147 // delay dispatching until we do. | |
| 148 void OnStartXdndPositionMessage(DesktopDragDropClientAuraX11* client, | |
| 149 ::Window source_window, | |
| 150 const gfx::Point& screen_point); | |
| 151 | |
| 152 // Called to request the next target from the source window. This is only | |
| 153 // done on the first XdndPosition; after that, we cache the data offered by | |
| 154 // the source window. | |
| 155 void RequestNextTarget(); | |
| 156 | |
| 157 // Called when XSelection data has been copied to our process. | |
| 158 void OnSelectionNotify(const XSelectionEvent& xselection); | |
| 159 | |
| 160 // Clones the fetched targets. | |
| 161 ui::SelectionFormatMap* CloneFetchedTargets() { | |
| 162 DCHECK(fetched_targets_); | |
| 163 return fetched_targets_->Clone(); | |
| 164 } | |
| 63 | 165 |
| 64 // Reads the "XdndActionList" property from |source_window| and copies it | 166 // Reads the "XdndActionList" property from |source_window| and copies it |
| 65 // into |actions|. | 167 // into |actions|. |
| 66 void ReadActions(); | 168 void ReadActions(); |
| 67 | 169 |
| 68 // Creates a ui::DragDropTypes::DragOperation representation of the current | 170 // Creates a ui::DragDropTypes::DragOperation representation of the current |
| 69 // action list. | 171 // action list. |
| 70 int GetDragOperation() const; | 172 int GetDragOperation() const; |
| 71 | 173 |
| 72 private: | 174 private: |
| 73 // Overridden from MessageLoop::Dispatcher: | 175 // Overridden from MessageLoop::Dispatcher: |
| 74 virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE; | 176 virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE; |
| 75 | 177 |
| 76 // The atom cache owned by our parent. | 178 // The atom cache owned by our parent. |
| 77 ui::X11AtomCache* atom_cache_; | 179 ui::X11AtomCache* atom_cache_; |
| 78 | 180 |
| 181 // The XID of our chrome local aura window handling our events. | |
| 182 ::Window local_window_; | |
| 183 | |
| 79 // The XID of the window that's initiated the drag. | 184 // The XID of the window that's initiated the drag. |
| 80 unsigned long source_window_; | 185 unsigned long source_window_; |
| 81 | 186 |
| 82 // targets. | 187 // The client we inform once we're done with requesting data. |
| 83 std::vector<Atom> targets_; | 188 DesktopDragDropClientAuraX11* drag_drop_client_; |
| 189 | |
| 190 // Whether we're blocking the handling of an XdndPosition message by waiting | |
| 191 // for |unfetched_targets_| to be fetched. | |
| 192 bool waiting_to_handle_position_; | |
| 193 | |
| 194 // Where the cursor is on screen | |
|
Daniel Erat
2013/06/17 22:09:57
nit: add trailing period
| |
| 195 gfx::Point screen_point_; | |
| 196 | |
| 197 // A SelectionFormatMap of data that we have in our process. | |
| 198 scoped_ptr<ui::SelectionFormatMap> fetched_targets_; | |
| 199 | |
| 200 // The names of various data types offered by the other window that we | |
| 201 // haven't fetched and put in |fetched_targets_| yet. | |
| 202 std::vector<Atom> unfetched_targets_; | |
| 84 | 203 |
| 85 // supplied actions | 204 // supplied actions |
| 86 std::vector<Atom> actions_; | 205 std::vector<Atom> actions_; |
| 87 | 206 |
| 88 DISALLOW_COPY_AND_ASSIGN(X11DragContext); | 207 DISALLOW_COPY_AND_ASSIGN(X11DragContext); |
| 89 }; | 208 }; |
| 90 | 209 |
| 91 DesktopDragDropClientAuraX11::X11DragContext::X11DragContext( | 210 DesktopDragDropClientAuraX11::X11DragContext::X11DragContext( |
| 92 ui::X11AtomCache* atom_cache, | 211 ui::X11AtomCache* atom_cache, |
| 212 ::Window local_window, | |
| 93 const XClientMessageEvent& event) | 213 const XClientMessageEvent& event) |
| 94 : atom_cache_(atom_cache), | 214 : atom_cache_(atom_cache), |
| 95 source_window_(event.data.l[0]) { | 215 local_window_(local_window), |
| 216 source_window_(event.data.l[0]), | |
| 217 drag_drop_client_(NULL), | |
| 218 waiting_to_handle_position_(false) { | |
| 96 bool get_types = ((event.data.l[1] & 1) != 0); | 219 bool get_types = ((event.data.l[1] & 1) != 0); |
| 97 | 220 |
| 98 if (get_types) { | 221 if (get_types) { |
| 99 if (!ui::GetAtomArrayProperty(source_window_, | 222 if (!ui::GetAtomArrayProperty(source_window_, |
| 100 "XdndTypeList", | 223 "XdndTypeList", |
| 101 &targets_)) { | 224 &unfetched_targets_)) { |
| 102 return; | 225 return; |
| 103 } | 226 } |
| 104 } else { | 227 } else { |
| 105 // data.l[2,3,4] contain the first three types. Unused slots can be None. | 228 // data.l[2,3,4] contain the first three types. Unused slots can be None. |
| 106 for (int i = 0; i < 3; ++i) { | 229 for (int i = 0; i < 3; ++i) { |
| 107 if (event.data.l[2+i] != None) { | 230 if (event.data.l[2+i] != None) { |
| 108 targets_.push_back(event.data.l[2+i]); | 231 unfetched_targets_.push_back(event.data.l[2+i]); |
| 109 } | 232 } |
| 110 } | 233 } |
| 111 } | 234 } |
| 112 | 235 |
| 113 // TODO(erg): If this window is part of our process, don't listen through the | 236 DesktopDragDropClientAuraX11* client = |
| 114 // MessagePump, but instead listen to the DesktopDragDropClientAuraX11 | 237 DesktopDragDropClientAuraX11::GetForWindow(source_window_); |
| 115 // associated with that window. | 238 if (!client) { |
| 116 base::MessagePumpAuraX11::Current()->AddDispatcherForWindow( | 239 // The window doesn't have a DesktopDragDropClientAuraX11, that means its |
|
Daniel Erat
2013/06/17 22:09:57
nit: s/its/it's/
| |
| 117 this, source_window_); | 240 // created by some other process. Listen for messages on it. |
| 118 XSelectInput(base::MessagePumpAuraX11::GetDefaultXDisplay(), | 241 base::MessagePumpAuraX11::Current()->AddDispatcherForWindow( |
| 119 source_window_, PropertyChangeMask); | 242 this, source_window_); |
| 243 XSelectInput(base::MessagePumpAuraX11::GetDefaultXDisplay(), | |
| 244 source_window_, PropertyChangeMask); | |
| 120 | 245 |
| 121 // We must perform a full sync here because we could be racing | 246 // We must perform a full sync here because we could be racing |
| 122 // |source_window_|. | 247 // |source_window_|. |
| 123 XSync(base::MessagePumpAuraX11::GetDefaultXDisplay(), False); | 248 XSync(base::MessagePumpAuraX11::GetDefaultXDisplay(), False); |
| 249 } else { | |
| 250 // This drag originates from an aura window within our process. This means | |
| 251 // that we can shortcut the X11 server and ask the owning SelectionOwner | |
| 252 // for the data its offering. | |
|
Daniel Erat
2013/06/17 22:09:57
nit: s/its/it's/
| |
| 253 fetched_targets_.reset(client->CloneFormatMap()); | |
| 254 unfetched_targets_.clear(); | |
| 255 } | |
| 124 | 256 |
| 125 ReadActions(); | 257 ReadActions(); |
| 126 } | 258 } |
| 127 | 259 |
| 128 DesktopDragDropClientAuraX11::X11DragContext::~X11DragContext() { | 260 DesktopDragDropClientAuraX11::X11DragContext::~X11DragContext() { |
| 129 // Unsubscribe to message events. | 261 DesktopDragDropClientAuraX11* client = |
| 130 base::MessagePumpAuraX11::Current()->RemoveDispatcherForWindow( | 262 DesktopDragDropClientAuraX11::GetForWindow(source_window_); |
| 131 source_window_); | 263 if (!client) { |
| 264 // Unsubscribe to message events. | |
|
Daniel Erat
2013/06/17 22:09:57
nit: s/to/from/
| |
| 265 base::MessagePumpAuraX11::Current()->RemoveDispatcherForWindow( | |
| 266 source_window_); | |
| 267 } | |
| 268 } | |
| 269 | |
| 270 void DesktopDragDropClientAuraX11::X11DragContext::OnStartXdndPositionMessage( | |
| 271 DesktopDragDropClientAuraX11* client, | |
| 272 ::Window source_window, | |
| 273 const gfx::Point& screen_point) { | |
| 274 DCHECK_EQ(source_window_, source_window); | |
| 275 | |
| 276 if (!unfetched_targets_.empty()) { | |
| 277 // We have unfetched targets. That means we need to pause the handling of | |
| 278 // the position message and ask the other window for its data. | |
| 279 screen_point_ = screen_point; | |
| 280 drag_drop_client_ = client; | |
| 281 waiting_to_handle_position_ = true; | |
| 282 | |
| 283 // At this point, we need to start | |
|
Daniel Erat
2013/06/17 22:09:57
fix this comment
| |
| 284 fetched_targets_.reset(new ui::SelectionFormatMap); | |
| 285 RequestNextTarget(); | |
| 286 } else { | |
| 287 client->CompleteXdndPosition(source_window, screen_point); | |
| 288 } | |
| 289 } | |
| 290 | |
| 291 void DesktopDragDropClientAuraX11::X11DragContext::RequestNextTarget() { | |
| 292 ::Atom target = unfetched_targets_.back(); | |
| 293 unfetched_targets_.pop_back(); | |
| 294 | |
| 295 XConvertSelection(base::MessagePumpAuraX11::GetDefaultXDisplay(), | |
| 296 atom_cache_->GetAtom(kXdndSelection), | |
| 297 target, | |
| 298 atom_cache_->GetAtom(kChromiumDragReciever), | |
| 299 local_window_, | |
| 300 CurrentTime); | |
| 301 } | |
| 302 | |
| 303 void DesktopDragDropClientAuraX11::X11DragContext::OnSelectionNotify( | |
| 304 const XSelectionEvent& event) { | |
| 305 DCHECK(waiting_to_handle_position_); | |
| 306 DCHECK(drag_drop_client_); | |
| 307 | |
| 308 unsigned char* data = NULL; | |
| 309 size_t data_bytes = 0; | |
| 310 ::Atom type = None; | |
| 311 if (ui::GetRawBytesOfProperty(local_window_, event.property, | |
| 312 &data, &data_bytes, NULL, &type)) { | |
| 313 char* copied_data = new char[data_bytes]; | |
| 314 memcpy(copied_data, data, data_bytes); | |
| 315 fetched_targets_->Insert(event.target, copied_data, data_bytes); | |
| 316 XFree(data); | |
| 317 } | |
| 318 | |
| 319 if (!unfetched_targets_.empty()) { | |
| 320 RequestNextTarget(); | |
| 321 } else { | |
| 322 waiting_to_handle_position_ = false; | |
| 323 drag_drop_client_->CompleteXdndPosition(source_window_, screen_point_); | |
| 324 drag_drop_client_ = NULL; | |
| 325 } | |
| 132 } | 326 } |
| 133 | 327 |
| 134 void DesktopDragDropClientAuraX11::X11DragContext::ReadActions() { | 328 void DesktopDragDropClientAuraX11::X11DragContext::ReadActions() { |
| 135 std::vector<Atom> atom_array; | 329 DesktopDragDropClientAuraX11* client = |
| 136 | 330 DesktopDragDropClientAuraX11::GetForWindow(source_window_); |
| 137 // TODO(erg): The GTK+ code has a fast path that short circuits talking over | 331 if (!client) { |
| 138 // X11 for local windows. When we become a drop source, we should have a | 332 std::vector<Atom> atom_array; |
| 139 // similar fast path. | 333 if (!ui::GetAtomArrayProperty(source_window_, |
| 140 | 334 "XdndActionList", |
| 141 if (!ui::GetAtomArrayProperty(source_window_, | 335 &atom_array)) { |
| 142 "XdndActionList", | 336 actions_.clear(); |
| 143 &atom_array)) { | 337 } else { |
| 144 actions_.clear(); | 338 actions_.swap(atom_array); |
| 339 } | |
| 145 } else { | 340 } else { |
| 146 actions_.swap(atom_array); | 341 // We have a property notify set up for other windows in case they change |
| 342 // their action list. Thankfully, the views interface is static and you | |
| 343 // can't change the action list after you enter StartDragAndDrop(). | |
| 344 actions_ = client->GetOfferedDragOperations(); | |
| 147 } | 345 } |
| 148 } | 346 } |
| 149 | 347 |
| 150 int DesktopDragDropClientAuraX11::X11DragContext::GetDragOperation() const { | 348 int DesktopDragDropClientAuraX11::X11DragContext::GetDragOperation() const { |
| 151 int drag_operation = ui::DragDropTypes::DRAG_NONE; | 349 int drag_operation = ui::DragDropTypes::DRAG_NONE; |
| 152 for (std::vector<Atom>::const_iterator it = actions_.begin(); | 350 for (std::vector<Atom>::const_iterator it = actions_.begin(); |
| 153 it != actions_.end(); ++it) { | 351 it != actions_.end(); ++it) { |
| 154 if (*it == atom_cache_->GetAtom(kXdndActionCopy)) | 352 if (*it == atom_cache_->GetAtom(kXdndActionCopy)) |
| 155 drag_operation |= ui::DragDropTypes::DRAG_COPY; | 353 drag_operation |= ui::DragDropTypes::DRAG_COPY; |
| 156 else if (*it == atom_cache_->GetAtom(kXdndActionMove)) | 354 else if (*it == atom_cache_->GetAtom(kXdndActionMove)) |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 171 return true; | 369 return true; |
| 172 } | 370 } |
| 173 | 371 |
| 174 /////////////////////////////////////////////////////////////////////////////// | 372 /////////////////////////////////////////////////////////////////////////////// |
| 175 | 373 |
| 176 DesktopDragDropClientAuraX11::DesktopDragDropClientAuraX11( | 374 DesktopDragDropClientAuraX11::DesktopDragDropClientAuraX11( |
| 177 views::DesktopRootWindowHostX11* root_window_host, | 375 views::DesktopRootWindowHostX11* root_window_host, |
| 178 aura::RootWindow* root_window, | 376 aura::RootWindow* root_window, |
| 179 Display* xdisplay, | 377 Display* xdisplay, |
| 180 ::Window xwindow) | 378 ::Window xwindow) |
| 181 : root_window_host_(root_window_host), | 379 : move_loop_(this), |
| 380 root_window_host_(root_window_host), | |
| 182 root_window_(root_window), | 381 root_window_(root_window), |
| 183 xdisplay_(xdisplay), | 382 xdisplay_(xdisplay), |
| 184 xwindow_(xwindow), | 383 xwindow_(xwindow), |
| 185 atom_cache_(xdisplay_, kAtomsToCache), | 384 atom_cache_(xdisplay_, kAtomsToCache), |
| 186 target_window_(NULL), | 385 target_window_(NULL), |
| 386 source_provider_(NULL), | |
| 387 source_current_window_(None), | |
| 187 drag_drop_in_progress_(false), | 388 drag_drop_in_progress_(false), |
| 188 drag_operation_(0) { | 389 drag_operation_(0), |
| 390 resulting_operation_(0) { | |
| 391 DCHECK(g_live_client_map.find(xwindow) == g_live_client_map.end()); | |
|
Daniel Erat
2013/06/17 22:09:57
nit: can you use DCHECK_EQ() here?
Elliot Glaysher
2013/06/18 00:06:39
You can't use DCHECK_EQ with iterators.
| |
| 392 g_live_client_map.insert(std::make_pair(xwindow, this)); | |
| 393 | |
| 189 // Mark that we are aware of drag and drop concepts. | 394 // Mark that we are aware of drag and drop concepts. |
| 190 unsigned long xdnd_version = 5; | 395 unsigned long xdnd_version = kMinXdndVersion; |
| 191 XChangeProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndAware"), | 396 XChangeProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndAware"), |
| 192 XA_ATOM, 32, PropModeReplace, | 397 XA_ATOM, 32, PropModeReplace, |
| 193 reinterpret_cast<unsigned char*>(&xdnd_version), 1); | 398 reinterpret_cast<unsigned char*>(&xdnd_version), 1); |
| 194 } | 399 } |
| 195 | 400 |
| 196 DesktopDragDropClientAuraX11::~DesktopDragDropClientAuraX11() { | 401 DesktopDragDropClientAuraX11::~DesktopDragDropClientAuraX11() { |
| 402 g_live_client_map.erase(xwindow_); | |
| 403 } | |
| 404 | |
| 405 // static | |
| 406 DesktopDragDropClientAuraX11* DesktopDragDropClientAuraX11::GetForWindow( | |
| 407 ::Window window) { | |
| 408 std::map< ::Window, DesktopDragDropClientAuraX11*>::const_iterator it = | |
| 409 g_live_client_map.find(window); | |
| 410 if (it == g_live_client_map.end()) | |
| 411 return NULL; | |
| 412 return it->second; | |
| 197 } | 413 } |
| 198 | 414 |
| 199 void DesktopDragDropClientAuraX11::OnXdndEnter( | 415 void DesktopDragDropClientAuraX11::OnXdndEnter( |
| 200 const XClientMessageEvent& event) { | 416 const XClientMessageEvent& event) { |
| 201 DVLOG(1) << "XdndEnter"; | 417 DVLOG(1) << "XdndEnter"; |
| 202 | 418 |
| 203 int version = (event.data.l[1] & 0xff000000) >> 24; | 419 int version = (event.data.l[1] & 0xff000000) >> 24; |
| 204 if (version < 3) { | 420 if (version < 3) { |
| 205 LOG(ERROR) << "Received old XdndEnter message."; | 421 LOG(ERROR) << "Received old XdndEnter message."; |
| 206 return; | 422 return; |
| 207 } | 423 } |
| 208 | 424 |
| 209 // Make sure that we've run ~X11DragContext() before creating another one. | 425 // Make sure that we've run ~X11DragContext() before creating another one. |
| 210 current_context_.reset(); | 426 target_current_context_.reset(); |
| 211 current_context_.reset(new X11DragContext(&atom_cache_, event)); | 427 target_current_context_.reset( |
| 428 new X11DragContext(&atom_cache_, xwindow_, event)); | |
| 212 | 429 |
| 213 // In the Windows implementation, we immediately call DesktopDropTargetWin:: | 430 // In the Windows implementation, we immediately call DesktopDropTargetWin:: |
| 214 // Translate(). Here, we wait until we receive an XdndPosition message | 431 // Translate(). Here, we wait until we receive an XdndPosition message |
| 215 // because the enter message doesn't convey any positioning | 432 // because the enter message doesn't convey any positioning |
| 216 // information. | 433 // information. |
| 217 } | 434 } |
| 218 | 435 |
| 219 void DesktopDragDropClientAuraX11::OnXdndLeave( | 436 void DesktopDragDropClientAuraX11::OnXdndLeave( |
| 220 const XClientMessageEvent& event) { | 437 const XClientMessageEvent& event) { |
| 438 DVLOG(1) << "XdndLeave"; | |
| 221 NotifyDragLeave(); | 439 NotifyDragLeave(); |
| 222 current_context_.reset(); | 440 target_current_context_.reset(); |
| 223 } | 441 } |
| 224 | 442 |
| 225 void DesktopDragDropClientAuraX11::OnXdndPosition( | 443 void DesktopDragDropClientAuraX11::OnXdndPosition( |
| 226 const XClientMessageEvent& event) { | 444 const XClientMessageEvent& event) { |
| 227 DVLOG(1) << "XdndPosition"; | 445 DVLOG(1) << "XdndPosition"; |
| 228 | 446 |
| 229 unsigned long source_window = event.data.l[0]; | 447 unsigned long source_window = event.data.l[0]; |
| 230 int x_root_window = event.data.l[2] >> 16; | 448 int x_root_window = event.data.l[2] >> 16; |
| 231 int y_root_window = event.data.l[2] & 0xffff; | 449 int y_root_window = event.data.l[2] & 0xffff; |
| 232 | 450 |
| 233 if (!current_context_.get()) { | 451 if (!target_current_context_.get()) { |
| 234 NOTREACHED(); | 452 NOTREACHED(); |
| 235 return; | 453 return; |
| 236 } | 454 } |
| 237 | 455 |
| 238 int drag_operation = ui::DragDropTypes::DRAG_NONE; | 456 // If we already have all the data from this drag, we complete it |
| 239 scoped_ptr<ui::OSExchangeData> data; | 457 // immediately. |
| 240 scoped_ptr<ui::DropTargetEvent> drop_target_event; | 458 target_current_context_->OnStartXdndPositionMessage( |
| 241 DragDropDelegate* delegate; | 459 this, source_window, gfx::Point(x_root_window, y_root_window)); |
| 242 DragTranslate(gfx::Point(x_root_window, y_root_window), | |
| 243 &data, &drop_target_event, &delegate); | |
| 244 if (delegate) | |
| 245 drag_operation = delegate->OnDragUpdated(*drop_target_event); | |
| 246 | |
| 247 // Sends an XdndStatus message back to the source_window. l[2,3] | |
| 248 // theoretically represent an area in the window where the current action is | |
| 249 // the same as what we're returning, but I can't find any implementation that | |
| 250 // actually making use of this. A client can return (0, 0) and/or set the | |
| 251 // first bit of l[1] to disable the feature, and it appears that gtk neither | |
| 252 // sets this nor respects it if set. | |
| 253 XEvent xev; | |
| 254 xev.xclient.type = ClientMessage; | |
| 255 xev.xclient.message_type = atom_cache_.GetAtom("XdndStatus"); | |
| 256 xev.xclient.format = 32; | |
| 257 xev.xclient.window = source_window; | |
| 258 xev.xclient.data.l[0] = xwindow_; | |
| 259 xev.xclient.data.l[1] = (drag_operation != 0) ? (2 | 1) : 0; | |
| 260 xev.xclient.data.l[2] = 0; | |
| 261 xev.xclient.data.l[3] = 0; | |
| 262 xev.xclient.data.l[4] = DragOperationToAtom(drag_operation); | |
| 263 | |
| 264 SendXClientEvent(source_window, &xev); | |
| 265 } | 460 } |
| 266 | 461 |
| 267 void DesktopDragDropClientAuraX11::OnXdndStatus( | 462 void DesktopDragDropClientAuraX11::OnXdndStatus( |
| 268 const XClientMessageEvent& event) { | 463 const XClientMessageEvent& event) { |
| 269 DVLOG(1) << "XdndStatus"; | 464 DVLOG(1) << "XdndStatus"; |
| 465 | |
| 466 unsigned long source_window = event.data.l[0]; | |
| 467 if (event.data.l[1] & 1) | |
| 468 negotiated_operation_[source_window] = event.data.l[4]; | |
| 469 | |
| 470 // TODO(erg): event.data.[2,3] specify a rectangle. It is a request by the | |
|
Daniel Erat
2013/06/17 22:09:57
is this really a TODO, or just a note? sounds like
| |
| 471 // other window to not send further XdndPosition messages while the cursor is | |
| 472 // within it. However, it is considered advisory and (at least according to | |
| 473 // the spec) the other side must handle further position messages within | |
| 474 // it. GTK+ doesn't bother with this, so neither should we. | |
| 475 | |
| 476 waiting_on_status_.erase(source_window); | |
| 477 | |
| 478 // TODO(erg): We should be using the response to try to update the cursor or | |
| 479 // something. | |
| 480 | |
| 481 if (ContainsKey(pending_drop_, source_window)) { | |
| 482 // We were waiting on the status message so we could send the XdndDrop. | |
| 483 SendXdndDrop(source_window); | |
| 484 return; | |
| 485 } | |
| 486 | |
| 487 NextPositionMap::iterator it = next_position_message_.find(source_window); | |
| 488 if (it != next_position_message_.end()) { | |
| 489 // We were waiting on the status message so we could send off the next | |
| 490 // position message we queued up. | |
| 491 gfx::Point p = it->second.first; | |
| 492 unsigned long time = it->second.second; | |
| 493 next_position_message_.erase(it); | |
| 494 | |
| 495 SendXdndPosition(source_window, p, time); | |
| 496 } | |
| 270 } | 497 } |
| 271 | 498 |
| 272 void DesktopDragDropClientAuraX11::OnXdndFinished( | 499 void DesktopDragDropClientAuraX11::OnXdndFinished( |
| 273 const XClientMessageEvent& event) { | 500 const XClientMessageEvent& event) { |
| 274 DVLOG(1) << "XdndFinished"; | 501 DVLOG(1) << "XdndFinished"; |
| 502 resulting_operation_ = AtomToDragOperation( | |
| 503 negotiated_operation_[event.data.l[0]]); | |
| 504 move_loop_.EndMoveLoop(); | |
| 275 } | 505 } |
| 276 | 506 |
| 277 void DesktopDragDropClientAuraX11::OnXdndDrop( | 507 void DesktopDragDropClientAuraX11::OnXdndDrop( |
| 278 const XClientMessageEvent& event) { | 508 const XClientMessageEvent& event) { |
| 279 DVLOG(1) << "XdndDrop"; | 509 DVLOG(1) << "XdndDrop"; |
| 280 | 510 |
| 281 unsigned long source_window = event.data.l[0]; | 511 unsigned long source_window = event.data.l[0]; |
| 282 | 512 |
| 283 int drag_operation = ui::DragDropTypes::DRAG_NONE; | 513 int drag_operation = ui::DragDropTypes::DRAG_NONE; |
| 284 if (target_window_) { | 514 if (target_window_) { |
| 285 aura::client::DragDropDelegate* delegate = | 515 aura::client::DragDropDelegate* delegate = |
| 286 aura::client::GetDragDropDelegate(target_window_); | 516 aura::client::GetDragDropDelegate(target_window_); |
| 287 if (delegate) { | 517 if (delegate) { |
| 288 ui::OSExchangeData data(new ui::OSExchangeDataProviderAuraX11( | 518 ui::OSExchangeData data(new ui::OSExchangeDataProviderAuraX11( |
| 289 root_window_host_, xwindow_, current_context_->targets())); | 519 xwindow_, target_current_context_->CloneFetchedTargets())); |
| 520 | |
| 290 ui::DropTargetEvent event(data, | 521 ui::DropTargetEvent event(data, |
| 291 target_window_location_, | 522 target_window_location_, |
| 292 target_window_root_location_, | 523 target_window_root_location_, |
| 293 current_context_->GetDragOperation()); | 524 target_current_context_->GetDragOperation()); |
| 294 drag_operation = delegate->OnPerformDrop(event); | 525 drag_operation = delegate->OnPerformDrop(event); |
| 295 } | 526 } |
| 296 | 527 |
| 297 target_window_->RemoveObserver(this); | 528 target_window_->RemoveObserver(this); |
| 298 target_window_ = NULL; | 529 target_window_ = NULL; |
| 299 } | 530 } |
| 300 | 531 |
| 301 XEvent xev; | 532 XEvent xev; |
| 302 xev.xclient.type = ClientMessage; | 533 xev.xclient.type = ClientMessage; |
| 303 xev.xclient.message_type = atom_cache_.GetAtom("XdndFinished"); | 534 xev.xclient.message_type = atom_cache_.GetAtom("XdndFinished"); |
| 304 xev.xclient.format = 32; | 535 xev.xclient.format = 32; |
| 305 xev.xclient.window = source_window; | 536 xev.xclient.window = source_window; |
| 306 xev.xclient.data.l[0] = xwindow_; | 537 xev.xclient.data.l[0] = xwindow_; |
| 307 xev.xclient.data.l[1] = (drag_operation != 0) ? 1 : 0; | 538 xev.xclient.data.l[1] = (drag_operation != 0) ? 1 : 0; |
| 308 xev.xclient.data.l[2] = DragOperationToAtom(drag_operation); | 539 xev.xclient.data.l[2] = DragOperationToAtom(drag_operation); |
| 309 | 540 |
| 310 SendXClientEvent(source_window, &xev); | 541 SendXClientEvent(source_window, &xev); |
| 311 } | 542 } |
| 312 | 543 |
| 544 void DesktopDragDropClientAuraX11::OnSelectionNotify( | |
| 545 const XSelectionEvent& xselection) { | |
| 546 if (!target_current_context_) { | |
| 547 NOTIMPLEMENTED(); | |
| 548 return; | |
| 549 } | |
| 550 | |
| 551 target_current_context_->OnSelectionNotify(xselection); | |
| 552 } | |
| 553 | |
| 313 int DesktopDragDropClientAuraX11::StartDragAndDrop( | 554 int DesktopDragDropClientAuraX11::StartDragAndDrop( |
| 314 const ui::OSExchangeData& data, | 555 const ui::OSExchangeData& data, |
| 315 aura::RootWindow* root_window, | 556 aura::RootWindow* root_window, |
| 316 aura::Window* source_window, | 557 aura::Window* source_window, |
| 317 const gfx::Point& root_location, | 558 const gfx::Point& root_location, |
| 318 int operation, | 559 int operation, |
| 319 ui::DragDropTypes::DragEventSource source) { | 560 ui::DragDropTypes::DragEventSource source) { |
| 561 source_current_window_ = None; | |
| 562 drag_drop_in_progress_ = true; | |
| 563 drag_operation_ = operation; | |
| 564 resulting_operation_ = ui::DragDropTypes::DRAG_NONE; | |
| 565 | |
| 566 const ui::OSExchangeData::Provider* provider = &data.provider(); | |
| 567 source_provider_ = static_cast<const ui::OSExchangeDataProviderAuraX11*>( | |
| 568 provider); | |
| 569 | |
| 570 source_provider_->TakeOwnershipOfSelection(); | |
| 571 | |
| 572 std::vector< ::Atom> actions = GetOfferedDragOperations(); | |
| 573 ui::SetAtomArrayProperty(xwindow_, "XdndActionList", "ATOM", actions); | |
| 574 | |
| 320 // Windows has a specific method, DoDragDrop(), which performs the entire | 575 // Windows has a specific method, DoDragDrop(), which performs the entire |
| 321 // drag. We have to emulate this, so we spin off a nested runloop which will | 576 // drag. We have to emulate this, so we spin off a nested runloop which will |
| 322 // track all cursor movement and reroute events to a specific handler. | 577 // track all cursor movement and reroute events to a specific handler. |
| 578 move_loop_.RunMoveLoop(source_window); | |
| 323 | 579 |
| 324 NOTIMPLEMENTED(); | 580 source_provider_ = NULL; |
| 581 drag_drop_in_progress_ = false; | |
| 582 drag_operation_ = 0; | |
| 583 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndActionList")); | |
| 325 | 584 |
| 326 // TODO(erg): Once this is implemented, make sure to reenable the | 585 return resulting_operation_; |
| 327 // NativeTextfieldViewsTest_DragAndDrop* tests. | |
| 328 | |
| 329 return ui::DragDropTypes::DRAG_NONE; | |
| 330 } | 586 } |
| 331 | 587 |
| 332 void DesktopDragDropClientAuraX11::DragUpdate(aura::Window* target, | 588 void DesktopDragDropClientAuraX11::DragUpdate(aura::Window* target, |
| 333 const ui::LocatedEvent& event) { | 589 const ui::LocatedEvent& event) { |
| 334 NOTIMPLEMENTED(); | 590 NOTIMPLEMENTED(); |
| 335 } | 591 } |
| 336 | 592 |
| 337 void DesktopDragDropClientAuraX11::Drop(aura::Window* target, | 593 void DesktopDragDropClientAuraX11::Drop(aura::Window* target, |
| 338 const ui::LocatedEvent& event) { | 594 const ui::LocatedEvent& event) { |
| 339 NOTIMPLEMENTED(); | 595 NOTIMPLEMENTED(); |
| 340 } | 596 } |
| 341 | 597 |
| 342 void DesktopDragDropClientAuraX11::DragCancel() { | 598 void DesktopDragDropClientAuraX11::DragCancel() { |
| 343 NOTIMPLEMENTED(); | 599 move_loop_.EndMoveLoop(); |
| 344 } | 600 } |
| 345 | 601 |
| 346 bool DesktopDragDropClientAuraX11::IsDragDropInProgress() { | 602 bool DesktopDragDropClientAuraX11::IsDragDropInProgress() { |
| 347 return drag_drop_in_progress_; | 603 return drag_drop_in_progress_; |
| 348 } | 604 } |
| 349 | 605 |
| 350 void DesktopDragDropClientAuraX11::OnWindowDestroyed(aura::Window* window) { | 606 void DesktopDragDropClientAuraX11::OnWindowDestroyed(aura::Window* window) { |
| 351 DCHECK_EQ(target_window_, window); | 607 DCHECK_EQ(target_window_, window); |
| 352 target_window_ = NULL; | 608 target_window_ = NULL; |
| 353 } | 609 } |
| 354 | 610 |
| 611 void DesktopDragDropClientAuraX11::OnMouseMovement(XMotionEvent* event) { | |
| 612 gfx::Point screen_point(event->x_root, event->y_root); | |
| 613 | |
| 614 // Find the current window the cursor is over. | |
| 615 ::Window mouse_window = None; | |
| 616 ::Window dest_window = None; | |
| 617 FindWindowFor(screen_point, &mouse_window, &dest_window); | |
| 618 | |
| 619 if (source_current_window_ != dest_window) { | |
| 620 if (source_current_window_ != None) | |
| 621 SendXdndLeave(source_current_window_); | |
| 622 | |
| 623 source_current_window_ = dest_window; | |
| 624 | |
| 625 if (source_current_window_ != None) { | |
| 626 negotiated_operation_.erase(source_current_window_); | |
| 627 SendXdndEnter(source_current_window_); | |
| 628 } | |
| 629 } | |
| 630 | |
| 631 if (source_current_window_ != None) { | |
| 632 if (ContainsKey(waiting_on_status_, dest_window)) { | |
| 633 next_position_message_[dest_window] = | |
| 634 std::make_pair(screen_point, event->time); | |
| 635 } else { | |
| 636 SendXdndPosition(dest_window, screen_point, event->time); | |
| 637 } | |
| 638 } | |
| 639 } | |
| 640 | |
| 641 void DesktopDragDropClientAuraX11::OnMouseReleased() { | |
| 642 if (source_current_window_ != None) { | |
| 643 if (ContainsKey(waiting_on_status_, source_current_window_)) { | |
| 644 // If we are waiting for an XdndStatus message, we need to wait for it to | |
| 645 // complete. | |
| 646 pending_drop_.insert(source_current_window_); | |
| 647 return; | |
| 648 } | |
| 649 | |
| 650 std::map< ::Window, ::Atom>::iterator it = | |
| 651 negotiated_operation_.find(source_current_window_); | |
| 652 if (it != negotiated_operation_.end() && it->second != None) { | |
| 653 // We have negotiated an action with the other end. | |
| 654 SendXdndDrop(source_current_window_); | |
| 655 return; | |
| 656 } | |
| 657 | |
| 658 SendXdndLeave(source_current_window_); | |
| 659 source_current_window_ = None; | |
| 660 } | |
| 661 | |
| 662 move_loop_.EndMoveLoop(); | |
| 663 } | |
| 664 | |
| 665 void DesktopDragDropClientAuraX11::OnMoveLoopEnded() { | |
| 666 target_current_context_.reset(); | |
| 667 } | |
| 668 | |
| 355 void DesktopDragDropClientAuraX11::DragTranslate( | 669 void DesktopDragDropClientAuraX11::DragTranslate( |
| 356 const gfx::Point& root_window_location, | 670 const gfx::Point& root_window_location, |
| 357 scoped_ptr<ui::OSExchangeData>* data, | 671 scoped_ptr<ui::OSExchangeData>* data, |
| 358 scoped_ptr<ui::DropTargetEvent>* event, | 672 scoped_ptr<ui::DropTargetEvent>* event, |
| 359 aura::client::DragDropDelegate** delegate) { | 673 aura::client::DragDropDelegate** delegate) { |
| 360 gfx::Point root_location = root_window_location; | 674 gfx::Point root_location = root_window_location; |
| 361 root_window_->ConvertPointFromNativeScreen(&root_location); | 675 root_window_->ConvertPointFromNativeScreen(&root_location); |
| 362 aura::Window* target_window = | 676 aura::Window* target_window = |
| 363 root_window_->GetEventHandlerForPoint(root_location); | 677 root_window_->GetEventHandlerForPoint(root_location); |
| 364 bool target_window_changed = false; | 678 bool target_window_changed = false; |
| 365 if (target_window != target_window_) { | 679 if (target_window != target_window_) { |
| 366 if (target_window_) | 680 if (target_window_) |
| 367 NotifyDragLeave(); | 681 NotifyDragLeave(); |
| 368 target_window_ = target_window; | 682 target_window_ = target_window; |
| 369 if (target_window_) | 683 if (target_window_) |
| 370 target_window_->AddObserver(this); | 684 target_window_->AddObserver(this); |
| 371 target_window_changed = true; | 685 target_window_changed = true; |
| 372 } | 686 } |
| 373 *delegate = NULL; | 687 *delegate = NULL; |
| 374 if (!target_window_) | 688 if (!target_window_) |
| 375 return; | 689 return; |
| 376 *delegate = aura::client::GetDragDropDelegate(target_window_); | 690 *delegate = aura::client::GetDragDropDelegate(target_window_); |
| 377 if (!*delegate) | 691 if (!*delegate) |
| 378 return; | 692 return; |
| 379 | 693 |
| 380 data->reset(new OSExchangeData(new ui::OSExchangeDataProviderAuraX11( | 694 data->reset(new OSExchangeData(new ui::OSExchangeDataProviderAuraX11( |
| 381 root_window_host_, xwindow_, current_context_->targets()))); | 695 xwindow_, target_current_context_->CloneFetchedTargets()))); |
| 382 gfx::Point location = root_location; | 696 gfx::Point location = root_location; |
| 383 aura::Window::ConvertPointToTarget(root_window_, target_window_, &location); | 697 aura::Window::ConvertPointToTarget(root_window_, target_window_, &location); |
| 384 | 698 |
| 385 target_window_location_ = location; | 699 target_window_location_ = location; |
| 386 target_window_root_location_ = root_location; | 700 target_window_root_location_ = root_location; |
| 387 | 701 |
| 388 event->reset(new ui::DropTargetEvent( | 702 event->reset(new ui::DropTargetEvent( |
| 389 *(data->get()), | 703 *(data->get()), |
| 390 location, | 704 location, |
| 391 root_location, | 705 root_location, |
| 392 current_context_->GetDragOperation())); | 706 target_current_context_->GetDragOperation())); |
| 393 if (target_window_changed) | 707 if (target_window_changed) |
| 394 (*delegate)->OnDragEntered(*event->get()); | 708 (*delegate)->OnDragEntered(*event->get()); |
| 395 } | 709 } |
| 396 | 710 |
| 397 void DesktopDragDropClientAuraX11::NotifyDragLeave() { | 711 void DesktopDragDropClientAuraX11::NotifyDragLeave() { |
| 398 if (!target_window_) | 712 if (!target_window_) |
| 399 return; | 713 return; |
| 400 DragDropDelegate* delegate = | 714 DragDropDelegate* delegate = |
| 401 aura::client::GetDragDropDelegate(target_window_); | 715 aura::client::GetDragDropDelegate(target_window_); |
| 402 if (delegate) | 716 if (delegate) |
| 403 delegate->OnDragExited(); | 717 delegate->OnDragExited(); |
| 404 target_window_->RemoveObserver(this); | 718 target_window_->RemoveObserver(this); |
| 405 target_window_ = NULL; | 719 target_window_ = NULL; |
| 406 } | 720 } |
| 407 | 721 |
| 408 unsigned long DesktopDragDropClientAuraX11::DragOperationToAtom( | 722 ::Atom DesktopDragDropClientAuraX11::DragOperationToAtom( |
| 409 int drag_operation) { | 723 int drag_operation) { |
| 410 if (drag_operation & ui::DragDropTypes::DRAG_COPY) | 724 if (drag_operation & ui::DragDropTypes::DRAG_COPY) |
| 411 return atom_cache_.GetAtom(kXdndActionCopy); | 725 return atom_cache_.GetAtom(kXdndActionCopy); |
| 412 if (drag_operation & ui::DragDropTypes::DRAG_MOVE) | 726 if (drag_operation & ui::DragDropTypes::DRAG_MOVE) |
| 413 return atom_cache_.GetAtom(kXdndActionMove); | 727 return atom_cache_.GetAtom(kXdndActionMove); |
| 414 if (drag_operation & ui::DragDropTypes::DRAG_LINK) | 728 if (drag_operation & ui::DragDropTypes::DRAG_LINK) |
| 415 return atom_cache_.GetAtom(kXdndActionLink); | 729 return atom_cache_.GetAtom(kXdndActionLink); |
| 416 | 730 |
| 417 return None; | 731 return None; |
| 418 } | 732 } |
| 419 | 733 |
| 420 void DesktopDragDropClientAuraX11::SendXClientEvent(unsigned long xid, | 734 int DesktopDragDropClientAuraX11::AtomToDragOperation(::Atom atom) { |
| 735 int drag_operation = ui::DragDropTypes::DRAG_NONE; | |
| 736 if (atom == atom_cache_.GetAtom(kXdndActionCopy)) | |
| 737 drag_operation = ui::DragDropTypes::DRAG_COPY; | |
|
Daniel Erat
2013/06/17 22:09:57
nit: remove drag_operation and just return from ea
| |
| 738 else if (atom == atom_cache_.GetAtom(kXdndActionMove)) | |
| 739 drag_operation = ui::DragDropTypes::DRAG_MOVE; | |
| 740 else if (atom == atom_cache_.GetAtom(kXdndActionLink)) | |
| 741 drag_operation = ui::DragDropTypes::DRAG_LINK; | |
| 742 return drag_operation; | |
| 743 } | |
| 744 | |
| 745 std::vector< ::Atom> DesktopDragDropClientAuraX11::GetOfferedDragOperations() { | |
| 746 std::vector< ::Atom> operations; | |
| 747 if (drag_operation_ & ui::DragDropTypes::DRAG_COPY) | |
| 748 operations.push_back(atom_cache_.GetAtom(kXdndActionCopy)); | |
| 749 if (drag_operation_ & ui::DragDropTypes::DRAG_MOVE) | |
| 750 operations.push_back(atom_cache_.GetAtom(kXdndActionMove)); | |
| 751 if (drag_operation_ & ui::DragDropTypes::DRAG_LINK) | |
| 752 operations.push_back(atom_cache_.GetAtom(kXdndActionLink)); | |
| 753 return operations; | |
| 754 } | |
| 755 | |
| 756 ui::SelectionFormatMap* DesktopDragDropClientAuraX11::CloneFormatMap() const { | |
| 757 return source_provider_ ? source_provider_->CloneFormatMap() : NULL; | |
| 758 } | |
| 759 | |
| 760 void DesktopDragDropClientAuraX11::CompleteXdndPosition( | |
| 761 ::Window source_window, | |
| 762 const gfx::Point& screen_point) { | |
| 763 int drag_operation = ui::DragDropTypes::DRAG_NONE; | |
| 764 scoped_ptr<ui::OSExchangeData> data; | |
| 765 scoped_ptr<ui::DropTargetEvent> drop_target_event; | |
| 766 DragDropDelegate* delegate; | |
|
Daniel Erat
2013/06/17 22:09:57
nit: initialize to NULL
| |
| 767 DragTranslate(screen_point, &data, &drop_target_event, &delegate); | |
| 768 if (delegate) | |
| 769 drag_operation = delegate->OnDragUpdated(*drop_target_event); | |
| 770 | |
| 771 // Sends an XdndStatus message back to the source_window. l[2,3] | |
| 772 // theoretically represent an area in the window where the current action is | |
| 773 // the same as what we're returning, but I can't find any implementation that | |
| 774 // actually making use of this. A client can return (0, 0) and/or set the | |
| 775 // first bit of l[1] to disable the feature, and it appears that gtk neither | |
| 776 // sets this nor respects it if set. | |
| 777 XEvent xev; | |
| 778 xev.xclient.type = ClientMessage; | |
| 779 xev.xclient.message_type = atom_cache_.GetAtom("XdndStatus"); | |
| 780 xev.xclient.format = 32; | |
| 781 xev.xclient.window = source_window; | |
| 782 xev.xclient.data.l[0] = xwindow_; | |
| 783 xev.xclient.data.l[1] = (drag_operation != 0) ? (2 | 1) : 0; | |
|
Daniel Erat
2013/06/17 22:09:57
nit: document what this means in more detail
| |
| 784 xev.xclient.data.l[2] = 0; | |
| 785 xev.xclient.data.l[3] = 0; | |
| 786 xev.xclient.data.l[4] = DragOperationToAtom(drag_operation); | |
| 787 | |
| 788 SendXClientEvent(source_window, &xev); | |
| 789 } | |
| 790 | |
| 791 void DesktopDragDropClientAuraX11::SendXdndEnter(::Window dest_window) { | |
| 792 XEvent xev; | |
| 793 xev.xclient.type = ClientMessage; | |
| 794 xev.xclient.message_type = atom_cache_.GetAtom("XdndEnter"); | |
| 795 xev.xclient.format = 32; | |
| 796 xev.xclient.window = dest_window; | |
| 797 xev.xclient.data.l[0] = xwindow_; | |
| 798 xev.xclient.data.l[1] = (kMinXdndVersion << 24); // The version number. | |
| 799 xev.xclient.data.l[2] = 0; | |
| 800 xev.xclient.data.l[3] = 0; | |
| 801 xev.xclient.data.l[4] = 0; | |
| 802 | |
| 803 std::vector<Atom> targets; | |
| 804 source_provider_->RetrieveTargets(&targets); | |
| 805 | |
| 806 if (targets.size() > 3) { | |
| 807 xev.xclient.data.l[1] |= 1; | |
| 808 ui::SetAtomArrayProperty(xwindow_, "XdndTypeList", "ATOM", targets); | |
| 809 } else { | |
| 810 // Pack the targets into the enter message. | |
| 811 for (size_t i = 0; i < targets.size(); ++i) | |
| 812 xev.xclient.data.l[2 + i] = targets[i]; | |
| 813 } | |
| 814 | |
| 815 SendXClientEvent(dest_window, &xev); | |
| 816 } | |
| 817 | |
| 818 void DesktopDragDropClientAuraX11::SendXdndLeave(::Window dest_window) { | |
| 819 // If we're sending a leave message, don't wait for status messages anymore. | |
| 820 waiting_on_status_.erase(dest_window); | |
| 821 NextPositionMap::iterator it = next_position_message_.find(dest_window); | |
| 822 if (it != next_position_message_.end()) | |
| 823 next_position_message_.erase(it); | |
| 824 | |
| 825 XEvent xev; | |
| 826 xev.xclient.type = ClientMessage; | |
| 827 xev.xclient.message_type = atom_cache_.GetAtom("XdndLeave"); | |
| 828 xev.xclient.format = 32; | |
| 829 xev.xclient.window = dest_window; | |
| 830 xev.xclient.data.l[0] = xwindow_; | |
| 831 xev.xclient.data.l[1] = 0; | |
| 832 xev.xclient.data.l[2] = 0; | |
| 833 xev.xclient.data.l[3] = 0; | |
| 834 xev.xclient.data.l[4] = 0; | |
| 835 SendXClientEvent(dest_window, &xev); | |
| 836 } | |
| 837 | |
| 838 void DesktopDragDropClientAuraX11::SendXdndPosition( | |
| 839 ::Window dest_window, | |
| 840 const gfx::Point& screen_point, | |
| 841 unsigned long time) { | |
| 842 waiting_on_status_.insert(dest_window); | |
| 843 | |
| 844 XEvent xev; | |
| 845 xev.xclient.type = ClientMessage; | |
| 846 xev.xclient.message_type = atom_cache_.GetAtom("XdndPosition"); | |
| 847 xev.xclient.format = 32; | |
| 848 xev.xclient.window = dest_window; | |
| 849 xev.xclient.data.l[0] = xwindow_; | |
| 850 xev.xclient.data.l[1] = 0; | |
| 851 xev.xclient.data.l[2] = (screen_point.x() << 16) | screen_point.y(); | |
| 852 xev.xclient.data.l[3] = time; | |
| 853 xev.xclient.data.l[4] = DragOperationToAtom(drag_operation_); | |
| 854 SendXClientEvent(dest_window, &xev); | |
| 855 } | |
| 856 | |
| 857 void DesktopDragDropClientAuraX11::SendXdndDrop(::Window dest_window) { | |
| 858 XEvent xev; | |
| 859 xev.xclient.type = ClientMessage; | |
| 860 xev.xclient.message_type = atom_cache_.GetAtom("XdndDrop"); | |
| 861 xev.xclient.format = 32; | |
| 862 xev.xclient.window = dest_window; | |
| 863 xev.xclient.data.l[0] = xwindow_; | |
| 864 xev.xclient.data.l[1] = 0; | |
| 865 xev.xclient.data.l[2] = CurrentTime; | |
| 866 xev.xclient.data.l[3] = None; | |
| 867 xev.xclient.data.l[4] = None; | |
| 868 SendXClientEvent(dest_window, &xev); | |
| 869 } | |
| 870 | |
| 871 void DesktopDragDropClientAuraX11::SendXClientEvent(::Window xid, | |
| 421 XEvent* xev) { | 872 XEvent* xev) { |
| 422 DCHECK_EQ(ClientMessage, xev->type); | 873 DCHECK_EQ(ClientMessage, xev->type); |
| 423 | 874 |
| 424 // TODO(erg): When I get drag receiving working, shortcut messages to the X | 875 // Don't send messages to the X11 message queue if we can help it. |
| 425 // server and call the receivers DesktopDragDropClientAuraX11 instance | 876 DesktopDragDropClientAuraX11* short_circuit = GetForWindow(xid); |
| 426 // instead. | 877 if (short_circuit) { |
| 427 // | 878 Atom message_type = xev->xclient.message_type; |
| 879 if (message_type == atom_cache_.GetAtom("XdndEnter")) { | |
| 880 short_circuit->OnXdndEnter(xev->xclient); | |
| 881 return; | |
| 882 } else if (message_type == atom_cache_.GetAtom("XdndLeave")) { | |
| 883 short_circuit->OnXdndLeave(xev->xclient); | |
| 884 return; | |
| 885 } else if (message_type == atom_cache_.GetAtom("XdndPosition")) { | |
| 886 short_circuit->OnXdndPosition(xev->xclient); | |
| 887 return; | |
| 888 } else if (message_type == atom_cache_.GetAtom("XdndStatus")) { | |
| 889 short_circuit->OnXdndStatus(xev->xclient); | |
| 890 return; | |
| 891 } else if (message_type == atom_cache_.GetAtom("XdndFinished")) { | |
| 892 short_circuit->OnXdndFinished(xev->xclient); | |
| 893 return; | |
| 894 } else if (message_type == atom_cache_.GetAtom("XdndDrop")) { | |
| 895 short_circuit->OnXdndDrop(xev->xclient); | |
| 896 return; | |
| 897 } | |
| 898 } | |
| 899 | |
| 428 // I don't understand why the GTK+ code is doing what it's doing here. It | 900 // I don't understand why the GTK+ code is doing what it's doing here. It |
| 429 // goes out of its way to send the XEvent so that it receives a callback on | 901 // goes out of its way to send the XEvent so that it receives a callback on |
| 430 // success or failure, and when it fails, it then sends an internal GdkEvent | 902 // success or failure, and when it fails, it then sends an internal |
| 431 // about the failed drag. (And sending this message doesn't appear to go | 903 // GdkEvent about the failed drag. (And sending this message doesn't appear |
| 432 // through normal xlib machinery, but instead passes through the low level | 904 // to go through normal xlib machinery, but instead passes through the low |
| 433 // xProto (the x11 wire format) that I don't understand. | 905 // level xProto (the x11 wire format) that I don't understand. |
| 434 // | 906 // |
| 435 // I'm unsure if I have to jump through those hoops, or if XSendEvent is | 907 // I'm unsure if I have to jump through those hoops, or if XSendEvent is |
| 436 // sufficient. | 908 // sufficient. |
| 437 | |
| 438 XSendEvent(xdisplay_, xid, False, 0, xev); | 909 XSendEvent(xdisplay_, xid, False, 0, xev); |
| 439 } | 910 } |
| 440 | 911 |
| 441 } // namespace views | 912 } // namespace views |
| OLD | NEW |