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

Side by Side Diff: ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc

Issue 16271006: Drag on linux (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Further cleanup Created 7 years, 6 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 | Annotate | Revision Log
OLDNEW
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698