desktop_drag_drop_client_aurax11.h revision f2477e01787aa58f445919b809d89e252beef54f
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
3// found in the LICENSE file.
4
5#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DRAG_DROP_CLIENT_AURAX11_H_
6#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DRAG_DROP_CLIENT_AURAX11_H_
7
8#include <set>
9#include <X11/Xlib.h>
10
11#include "base/compiler_specific.h"
12#include "base/memory/ref_counted.h"
13#include "base/memory/scoped_ptr.h"
14#include "ui/aura/client/drag_drop_client.h"
15#include "ui/aura/window_observer.h"
16#include "ui/base/cursor/cursor.h"
17#include "ui/gfx/point.h"
18#include "ui/gfx/x/x11_atom_cache.h"
19#include "ui/views/views_export.h"
20#include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h"
21#include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop_delegate.h"
22
23namespace aura {
24namespace client {
25class DragDropDelegate;
26}
27}
28
29namespace gfx {
30class Point;
31}
32
33namespace ui {
34class DragSource;
35class DropTargetEvent;
36class OSExchangeData;
37class OSExchangeDataProviderAuraX11;
38class SelectionFormatMap;
39}
40
41namespace views {
42class DesktopNativeCursorManager;
43
44// Implements drag and drop on X11 for aura. On one side, this class takes raw
45// X11 events forwarded from DesktopRootWindowHostLinux, while on the other, it
46// handles the views drag events.
47class VIEWS_EXPORT DesktopDragDropClientAuraX11
48    : public aura::client::DragDropClient,
49      public aura::WindowObserver,
50      public X11WholeScreenMoveLoopDelegate {
51 public:
52  DesktopDragDropClientAuraX11(
53      aura::Window* root_window,
54      views::DesktopNativeCursorManager* cursor_manager,
55      Display* xdisplay,
56      ::Window xwindow);
57  virtual ~DesktopDragDropClientAuraX11();
58
59  // We maintain a mapping of live DesktopDragDropClientAuraX11 objects to
60  // their ::Windows. We do this so that we're able to short circuit sending
61  // X11 messages to windows in our process.
62  static DesktopDragDropClientAuraX11* GetForWindow(::Window window);
63
64  // These methods handle the various X11 client messages from the platform.
65  void OnXdndEnter(const XClientMessageEvent& event);
66  void OnXdndLeave(const XClientMessageEvent& event);
67  void OnXdndPosition(const XClientMessageEvent& event);
68  void OnXdndStatus(const XClientMessageEvent& event);
69  void OnXdndFinished(const XClientMessageEvent& event);
70  void OnXdndDrop(const XClientMessageEvent& event);
71
72  // Called when XSelection data has been copied to our process.
73  void OnSelectionNotify(const XSelectionEvent& xselection);
74
75  // Overridden from aura::client::DragDropClient:
76  virtual int StartDragAndDrop(
77      const ui::OSExchangeData& data,
78      aura::Window* root_window,
79      aura::Window* source_window,
80      const gfx::Point& root_location,
81      int operation,
82      ui::DragDropTypes::DragEventSource source) OVERRIDE;
83  virtual void DragUpdate(aura::Window* target,
84                          const ui::LocatedEvent& event) OVERRIDE;
85  virtual void Drop(aura::Window* target,
86                    const ui::LocatedEvent& event) OVERRIDE;
87  virtual void DragCancel() OVERRIDE;
88  virtual bool IsDragDropInProgress() OVERRIDE;
89
90  // Overridden from aura::WindowObserver:
91  virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
92
93  // Overridden from X11WholeScreenMoveLoopDelegate:
94  virtual void OnMouseMovement(XMotionEvent* event) OVERRIDE;
95  virtual void OnMouseReleased() OVERRIDE;
96  virtual void OnMoveLoopEnded() OVERRIDE;
97
98 private:
99  typedef std::map< ::Window, std::pair<gfx::Point, unsigned long> >
100      NextPositionMap;
101
102  // When we receive an position x11 message, we need to translate that into
103  // the underlying aura::Window representation, as moves internal to the X11
104  // window can cause internal drag leave and enter messages.
105  void DragTranslate(const gfx::Point& root_window_location,
106                     scoped_ptr<ui::OSExchangeData>* data,
107                     scoped_ptr<ui::DropTargetEvent>* event,
108                     aura::client::DragDropDelegate** delegate);
109
110  // Called when we need to notify the current aura::Window that we're no
111  // longer dragging over it.
112  void NotifyDragLeave();
113
114  // Converts our bitfield of actions into an Atom that represents what action
115  // we're most likely to take on drop.
116  ::Atom DragOperationToAtom(int drag_operation);
117
118  // Converts a single action atom to a drag operation.
119  int AtomToDragOperation(::Atom atom);
120
121  // During the blocking StartDragAndDrop() call, this converts the views-style
122  // |drag_operation_| bitfield into a vector of Atoms to offer to other
123  // processes.
124  std::vector< ::Atom> GetOfferedDragOperations();
125
126  // This returns a representation of the data we're offering in this
127  // drag. This is done to bypass an asynchronous roundtrip with the X11
128  // server.
129  ui::SelectionFormatMap GetFormatMap() const;
130
131  // Handling XdndPosition can be paused while waiting for more data; this is
132  // called either synchronously from OnXdndPosition, or asynchronously after
133  // we've received data requested from the other window.
134  void CompleteXdndPosition(::Window source_window,
135                            const gfx::Point& screen_point);
136
137  void SendXdndEnter(::Window dest_window);
138  void SendXdndLeave(::Window dest_window);
139  void SendXdndPosition(::Window dest_window,
140                        const gfx::Point& screen_point,
141                        unsigned long time);
142  void SendXdndDrop(::Window dest_window);
143
144  // Sends |xev| to |xid|, optionally short circuiting the round trip to the X
145  // server.
146  void SendXClientEvent(::Window xid, XEvent* xev);
147
148  // A nested message loop that notifies this object of events through the
149  // X11WholeScreenMoveLoopDelegate interface.
150  X11WholeScreenMoveLoop move_loop_;
151
152  aura::Window* root_window_;
153
154  Display* xdisplay_;
155  ::Window xwindow_;
156
157  ui::X11AtomCache atom_cache_;
158
159  // Target side information.
160  class X11DragContext;
161  scoped_ptr<X11DragContext> target_current_context_;
162
163  // The Aura window that is currently under the cursor. We need to manually
164  // keep track of this because Windows will only call our drag enter method
165  // once when the user enters the associated X Window. But inside that X
166  // Window there could be multiple aura windows, so we need to generate drag
167  // enter events for them.
168  aura::Window* target_window_;
169
170  // Because Xdnd messages don't contain the position in messages other than
171  // the XdndPosition message, we must manually keep track of the last position
172  // change.
173  gfx::Point target_window_location_;
174  gfx::Point target_window_root_location_;
175
176  // In the Xdnd protocol, we aren't supposed to send another XdndPosition
177  // message until we have received a confirming XdndStatus message.
178  std::set< ::Window> waiting_on_status_;
179
180  // If we would send an XdndPosition message while we're waiting for an
181  // XdndStatus response, we need to cache the latest details we'd send.
182  NextPositionMap next_position_message_;
183
184  // Source side information.
185  ui::OSExchangeDataProviderAuraX11 const* source_provider_;
186  ::Window source_current_window_;
187
188  bool drag_drop_in_progress_;
189
190  // The operation bitfield as requested by StartDragAndDrop.
191  int drag_operation_;
192
193  // The operation performed. Is initialized to None at the start of
194  // StartDragAndDrop(), and is set only during the asynchronous XdndFinished
195  // message.
196  int resulting_operation_;
197
198  // This window will be receiving a drop as soon as we receive an XdndStatus
199  // from it.
200  std::set< ::Window> pending_drop_;
201
202  // We offer the other window a list of possible operations,
203  // XdndActionsList. This is the requested action from the other window. This
204  // is None if we haven't sent out an XdndPosition message yet, haven't yet
205  // received an XdndStatus or if the other window has told us that there's no
206  // action that we can agree on.
207  //
208  // This is a map instead of a simple variable because of the case where we
209  // put an XdndLeave in the queue at roughly the same time that the other
210  // window responds to an XdndStatus.
211  std::map< ::Window, ::Atom> negotiated_operation_;
212
213  // We use these cursors while dragging.
214  gfx::NativeCursor grab_cursor_;
215  gfx::NativeCursor copy_grab_cursor_;
216  gfx::NativeCursor move_grab_cursor_;
217
218  DISALLOW_COPY_AND_ASSIGN(DesktopDragDropClientAuraX11);
219};
220
221}  // namespace views
222
223#endif  // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DRAG_DROP_CLIENT_AURAX11_H_
224