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/scoped_ptr.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/timer/timer.h"
15 #include "ui/aura/window_observer.h"
16 #include "ui/base/cursor/cursor.h"
17 #include "ui/base/dragdrop/drag_drop_types.h"
18 #include "ui/gfx/point.h"
19 #include "ui/gfx/x/x11_atom_cache.h"
20 #include "ui/views/views_export.h"
21 #include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h"
22 #include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop_delegate.h"
23 #include "ui/wm/public/drag_drop_client.h"
27 class DragDropDelegate;
37 class DropTargetEvent;
39 class OSExchangeDataProviderAuraX11;
40 class SelectionFormatMap;
44 class DesktopNativeCursorManager;
46 // Implements drag and drop on X11 for aura. On one side, this class takes raw
47 // X11 events forwarded from DesktopWindowTreeHostLinux, while on the other, it
48 // handles the views drag events.
49 class VIEWS_EXPORT DesktopDragDropClientAuraX11
50 : public aura::client::DragDropClient,
51 public aura::WindowObserver,
52 public X11WholeScreenMoveLoopDelegate {
54 DesktopDragDropClientAuraX11(
55 aura::Window* root_window,
56 views::DesktopNativeCursorManager* cursor_manager,
59 virtual ~DesktopDragDropClientAuraX11();
61 // We maintain a mapping of live DesktopDragDropClientAuraX11 objects to
62 // their ::Windows. We do this so that we're able to short circuit sending
63 // X11 messages to windows in our process.
64 static DesktopDragDropClientAuraX11* GetForWindow(::Window window);
66 // These methods handle the various X11 client messages from the platform.
67 void OnXdndEnter(const XClientMessageEvent& event);
68 void OnXdndLeave(const XClientMessageEvent& event);
69 void OnXdndPosition(const XClientMessageEvent& event);
70 void OnXdndStatus(const XClientMessageEvent& event);
71 void OnXdndFinished(const XClientMessageEvent& event);
72 void OnXdndDrop(const XClientMessageEvent& event);
74 // Called when XSelection data has been copied to our process.
75 void OnSelectionNotify(const XSelectionEvent& xselection);
77 // Overridden from aura::client::DragDropClient:
78 virtual int StartDragAndDrop(
79 const ui::OSExchangeData& data,
80 aura::Window* root_window,
81 aura::Window* source_window,
82 const gfx::Point& root_location,
84 ui::DragDropTypes::DragEventSource source) OVERRIDE;
85 virtual void DragUpdate(aura::Window* target,
86 const ui::LocatedEvent& event) OVERRIDE;
87 virtual void Drop(aura::Window* target,
88 const ui::LocatedEvent& event) OVERRIDE;
89 virtual void DragCancel() OVERRIDE;
90 virtual bool IsDragDropInProgress() OVERRIDE;
92 // Overridden from aura::WindowObserver:
93 virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
95 // Overridden from X11WholeScreenMoveLoopDelegate:
96 virtual void OnMouseMovement(XMotionEvent* event) OVERRIDE;
97 virtual void OnMouseReleased() OVERRIDE;
98 virtual void OnMoveLoopEnded() OVERRIDE;
102 // |source_current_window_| will receive a drop once we receive an
103 // XdndStatus from it.
104 SOURCE_STATE_PENDING_DROP,
106 // The move looped will be ended once we receive XdndFinished from
107 // |source_current_window_|. We should not send XdndPosition to
108 // |source_current_window_| while in this state.
109 SOURCE_STATE_DROPPED,
111 // There is no drag in progress or there is a drag in progress and the
112 // user has not yet released the mouse.
116 // Processes a mouse move at |screen_point|.
117 void ProcessMouseMove(const gfx::Point& screen_point,
118 unsigned long event_time);
120 // Start timer to end the move loop if the target is too slow to respond after
121 // the mouse is released.
122 void StartEndMoveLoopTimer();
124 // Ends the move loop.
127 // When we receive an position x11 message, we need to translate that into
128 // the underlying aura::Window representation, as moves internal to the X11
129 // window can cause internal drag leave and enter messages.
130 void DragTranslate(const gfx::Point& root_window_location,
131 scoped_ptr<ui::OSExchangeData>* data,
132 scoped_ptr<ui::DropTargetEvent>* event,
133 aura::client::DragDropDelegate** delegate);
135 // Called when we need to notify the current aura::Window that we're no
136 // longer dragging over it.
137 void NotifyDragLeave();
139 // Converts our bitfield of actions into an Atom that represents what action
140 // we're most likely to take on drop.
141 ::Atom DragOperationToAtom(int drag_operation);
143 // Converts a single action atom to a drag operation.
144 ui::DragDropTypes::DragOperation AtomToDragOperation(::Atom atom);
146 // During the blocking StartDragAndDrop() call, this converts the views-style
147 // |drag_operation_| bitfield into a vector of Atoms to offer to other
149 std::vector< ::Atom> GetOfferedDragOperations();
151 // This returns a representation of the data we're offering in this
152 // drag. This is done to bypass an asynchronous roundtrip with the X11
154 ui::SelectionFormatMap GetFormatMap() const;
156 // Handling XdndPosition can be paused while waiting for more data; this is
157 // called either synchronously from OnXdndPosition, or asynchronously after
158 // we've received data requested from the other window.
159 void CompleteXdndPosition(::Window source_window,
160 const gfx::Point& screen_point);
162 void SendXdndEnter(::Window dest_window);
163 void SendXdndLeave(::Window dest_window);
164 void SendXdndPosition(::Window dest_window,
165 const gfx::Point& screen_point,
166 unsigned long event_time);
167 void SendXdndDrop(::Window dest_window);
169 // Sends |xev| to |xid|, optionally short circuiting the round trip to the X
171 void SendXClientEvent(::Window xid, XEvent* xev);
173 // A nested message loop that notifies this object of events through the
174 // X11WholeScreenMoveLoopDelegate interface.
175 X11WholeScreenMoveLoop move_loop_;
177 aura::Window* root_window_;
182 ui::X11AtomCache atom_cache_;
184 // Target side information.
185 class X11DragContext;
186 scoped_ptr<X11DragContext> target_current_context_;
188 // The Aura window that is currently under the cursor. We need to manually
189 // keep track of this because Windows will only call our drag enter method
190 // once when the user enters the associated X Window. But inside that X
191 // Window there could be multiple aura windows, so we need to generate drag
192 // enter events for them.
193 aura::Window* target_window_;
195 // Because Xdnd messages don't contain the position in messages other than
196 // the XdndPosition message, we must manually keep track of the last position
198 gfx::Point target_window_location_;
199 gfx::Point target_window_root_location_;
201 // In the Xdnd protocol, we aren't supposed to send another XdndPosition
202 // message until we have received a confirming XdndStatus message.
203 bool waiting_on_status_;
205 // If we would send an XdndPosition message while we're waiting for an
206 // XdndStatus response, we need to cache the latest details we'd send.
207 scoped_ptr<std::pair<gfx::Point, unsigned long> > next_position_message_;
209 // Reprocesses the most recent mouse move event if the mouse has not moved
210 // in a while in case the window stacking order has changed and
211 // |source_current_window_| needs to be updated.
212 base::OneShotTimer<DesktopDragDropClientAuraX11> repeat_mouse_move_timer_;
214 // When the mouse is released, we need to wait for the last XdndStatus message
215 // only if we have previously received a status message from
216 // |source_current_window_|.
217 bool status_received_since_enter_;
219 // Source side information.
220 ui::OSExchangeDataProviderAuraX11 const* source_provider_;
221 ::Window source_current_window_;
222 SourceState source_state_;
224 // The current drag-drop client that has an active operation. Since we have
225 // multiple root windows and multiple DesktopDragDropClientAuraX11 instances
226 // it is important to maintain only one drag and drop operation at any time.
227 static DesktopDragDropClientAuraX11* g_current_drag_drop_client;
229 // The operation bitfield as requested by StartDragAndDrop.
232 // We offer the other window a list of possible operations,
233 // XdndActionsList. This is the requested action from the other window. This
234 // is DRAG_NONE if we haven't sent out an XdndPosition message yet, haven't
235 // yet received an XdndStatus or if the other window has told us that there's
236 // no action that we can agree on.
237 ui::DragDropTypes::DragOperation negotiated_operation_;
239 // Ends the move loop if the target is too slow to respond after the mouse is
241 base::OneShotTimer<DesktopDragDropClientAuraX11> end_move_loop_timer_;
243 // We use these cursors while dragging.
244 gfx::NativeCursor grab_cursor_;
245 gfx::NativeCursor copy_grab_cursor_;
246 gfx::NativeCursor move_grab_cursor_;
248 base::WeakPtrFactory<DesktopDragDropClientAuraX11> weak_ptr_factory_;
250 DISALLOW_COPY_AND_ASSIGN(DesktopDragDropClientAuraX11);
255 #endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DRAG_DROP_CLIENT_AURAX11_H_