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.
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_
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"
25 class DragDropDelegate;
35 class DropTargetEvent;
37 class OSExchangeDataProviderAuraX11;
38 class SelectionFormatMap;
42 class DesktopNativeCursorManager;
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.
47 class VIEWS_EXPORT DesktopDragDropClientAuraX11
48 : public aura::client::DragDropClient,
49 public aura::WindowObserver,
50 public X11WholeScreenMoveLoopDelegate {
52 DesktopDragDropClientAuraX11(
53 aura::Window* root_window,
54 views::DesktopNativeCursorManager* cursor_manager,
57 virtual ~DesktopDragDropClientAuraX11();
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);
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);
72 // Called when XSelection data has been copied to our process.
73 void OnSelectionNotify(const XSelectionEvent& xselection);
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,
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;
90 // Overridden from aura::WindowObserver:
91 virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
93 // Overridden from X11WholeScreenMoveLoopDelegate:
94 virtual void OnMouseMovement(XMotionEvent* event) OVERRIDE;
95 virtual void OnMouseReleased() OVERRIDE;
96 virtual void OnMoveLoopEnded() OVERRIDE;
99 typedef std::map< ::Window, std::pair<gfx::Point, unsigned long> >
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);
110 // Called when we need to notify the current aura::Window that we're no
111 // longer dragging over it.
112 void NotifyDragLeave();
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);
118 // Converts a single action atom to a drag operation.
119 int AtomToDragOperation(::Atom atom);
121 // During the blocking StartDragAndDrop() call, this converts the views-style
122 // |drag_operation_| bitfield into a vector of Atoms to offer to other
124 std::vector< ::Atom> GetOfferedDragOperations();
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
129 ui::SelectionFormatMap GetFormatMap() const;
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);
137 void SendXdndEnter(::Window dest_window);
138 void SendXdndLeave(::Window dest_window);
139 void SendXdndPosition(::Window dest_window,
140 const gfx::Point& screen_point,
142 void SendXdndDrop(::Window dest_window);
144 // Sends |xev| to |xid|, optionally short circuiting the round trip to the X
146 void SendXClientEvent(::Window xid, XEvent* xev);
148 // A nested message loop that notifies this object of events through the
149 // X11WholeScreenMoveLoopDelegate interface.
150 X11WholeScreenMoveLoop move_loop_;
152 aura::Window* root_window_;
157 ui::X11AtomCache atom_cache_;
159 // Target side information.
160 class X11DragContext;
161 scoped_ptr<X11DragContext> target_current_context_;
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_;
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
173 gfx::Point target_window_location_;
174 gfx::Point target_window_root_location_;
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_;
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_;
184 // Source side information.
185 ui::OSExchangeDataProviderAuraX11 const* source_provider_;
186 ::Window source_current_window_;
188 bool drag_drop_in_progress_;
190 // The operation bitfield as requested by StartDragAndDrop.
193 // The operation performed. Is initialized to None at the start of
194 // StartDragAndDrop(), and is set only during the asynchronous XdndFinished
196 int resulting_operation_;
198 // This window will be receiving a drop as soon as we receive an XdndStatus
200 std::set< ::Window> pending_drop_;
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.
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_;
213 // We use these cursors while dragging.
214 gfx::NativeCursor grab_cursor_;
215 gfx::NativeCursor copy_grab_cursor_;
216 gfx::NativeCursor move_grab_cursor_;
218 static std::map< ::Window, DesktopDragDropClientAuraX11*> g_live_client_map;
220 DISALLOW_COPY_AND_ASSIGN(DesktopDragDropClientAuraX11);
225 #endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DRAG_DROP_CLIENT_AURAX11_H_