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