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

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

Powered by Google App Engine
This is Rietveld 408576698