Home | History | Annotate | Download | only in desktop_aura
      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