1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=4 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef nsDragService_h__
8 #define nsDragService_h__
9 
10 #include "mozilla/RefPtr.h"
11 #include "nsBaseDragService.h"
12 #include "nsIObserver.h"
13 #include <gtk/gtk.h>
14 
15 class nsICookieJarSettings;
16 class nsWindow;
17 class nsWaylandDragContext;
18 
19 namespace mozilla {
20 namespace gfx {
21 class SourceSurface;
22 }
23 }  // namespace mozilla
24 
25 /**
26  * Native GTK DragService wrapper
27  */
28 
29 class nsDragService final : public nsBaseDragService, public nsIObserver {
30  public:
31   nsDragService();
32 
33   NS_DECL_ISUPPORTS_INHERITED
34 
35   NS_DECL_NSIOBSERVER
36 
37   // nsBaseDragService
38   MOZ_CAN_RUN_SCRIPT virtual nsresult InvokeDragSessionImpl(
39       nsIArray* anArrayTransferables,
40       const mozilla::Maybe<mozilla::CSSIntRegion>& aRegion,
41       uint32_t aActionType) override;
42   // nsIDragService
43   MOZ_CAN_RUN_SCRIPT NS_IMETHOD InvokeDragSession(
44       nsINode* aDOMNode, nsIPrincipal* aPrincipal,
45       nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings,
46       nsIArray* anArrayTransferables, uint32_t aActionType,
47       nsContentPolicyType aContentPolicyType) override;
48   NS_IMETHOD StartDragSession() override;
49   MOZ_CAN_RUN_SCRIPT NS_IMETHOD EndDragSession(bool aDoneDrag,
50                                                uint32_t aKeyModifiers) override;
51 
52   // nsIDragSession
53   NS_IMETHOD SetCanDrop(bool aCanDrop) override;
54   NS_IMETHOD GetCanDrop(bool* aCanDrop) override;
55   NS_IMETHOD GetNumDropItems(uint32_t* aNumItems) override;
56   NS_IMETHOD GetData(nsITransferable* aTransferable,
57                      uint32_t aItemIndex) override;
58   NS_IMETHOD IsDataFlavorSupported(const char* aDataFlavor,
59                                    bool* _retval) override;
60 
61   NS_IMETHOD UpdateDragEffect() override;
62 
63   // Methods called from nsWindow to handle responding to GTK drag
64   // destination signals
65 
66   static already_AddRefed<nsDragService> GetInstance();
67 
68   void TargetDataReceived(GtkWidget* aWidget, GdkDragContext* aContext, gint aX,
69                           gint aY, GtkSelectionData* aSelection_data,
70                           guint aInfo, guint32 aTime);
71 
72   gboolean ScheduleMotionEvent(nsWindow* aWindow, GdkDragContext* aDragContext,
73                                nsWaylandDragContext* aPendingWaylandDragContext,
74                                mozilla::LayoutDeviceIntPoint aWindowPoint,
75                                guint aTime);
76   void ScheduleLeaveEvent();
77   gboolean ScheduleDropEvent(nsWindow* aWindow, GdkDragContext* aDragContext,
78                              nsWaylandDragContext* aPendingWaylandDragContext,
79                              mozilla::LayoutDeviceIntPoint aWindowPoint,
80                              guint aTime);
81 
GetMostRecentDestWindow()82   nsWindow* GetMostRecentDestWindow() {
83     return mScheduledTask == eDragTaskNone ? mTargetWindow : mPendingWindow;
84   }
85 
86   //  END PUBLIC API
87 
88   // These methods are public only so that they can be called from functions
89   // with C calling conventions.  They are called for drags started with the
90   // invisible widget.
91   void SourceEndDragSession(GdkDragContext* aContext, gint aResult);
92   void SourceDataGet(GtkWidget* widget, GdkDragContext* context,
93                      GtkSelectionData* selection_data, guint32 aTime);
94 
95   void SourceBeginDrag(GdkDragContext* aContext);
96 
97   // set the drag icon during drag-begin
98   void SetDragIcon(GdkDragContext* aContext);
99 
100  protected:
101   virtual ~nsDragService();
102 
103  private:
104   // mScheduledTask indicates what signal has been received from GTK and
105   // so what needs to be dispatched when the scheduled task is run.  It is
106   // eDragTaskNone when there is no task scheduled (but the
107   // previous task may still not have finished running).
108   enum DragTask {
109     eDragTaskNone,
110     eDragTaskMotion,
111     eDragTaskLeave,
112     eDragTaskDrop,
113     eDragTaskSourceEnd
114   };
115   DragTask mScheduledTask;
116   // mTaskSource is the GSource id for the task that is either scheduled
117   // or currently running.  It is 0 if no task is scheduled or running.
118   guint mTaskSource;
119 
120   // target/destination side vars
121   // These variables keep track of the state of the current drag.
122 
123   // mPendingWindow, mPendingWindowPoint, mPendingDragContext, and
124   // mPendingTime, carry information from the GTK signal that will be used
125   // when the scheduled task is run.  mPendingWindow and mPendingDragContext
126   // will be nullptr if the scheduled task is eDragTaskLeave.
127   RefPtr<nsWindow> mPendingWindow;
128   mozilla::LayoutDeviceIntPoint mPendingWindowPoint;
129   RefPtr<GdkDragContext> mPendingDragContext;
130 
131   // We cache all data for the current drag context,
132   // because waiting for the data in GetTargetDragData can be very slow.
133   nsTHashMap<nsCStringHashKey, nsTArray<uint8_t>> mCachedData;
134 
135 #ifdef MOZ_WAYLAND
136   RefPtr<nsWaylandDragContext> mPendingWaylandDragContext;
137 #endif
138   guint mPendingTime;
139 
140   // mTargetWindow and mTargetWindowPoint record the position of the last
141   // eDragTaskMotion or eDragTaskDrop task that was run or is still running.
142   // mTargetWindow is cleared once the drag has completed or left.
143   RefPtr<nsWindow> mTargetWindow;
144   mozilla::LayoutDeviceIntPoint mTargetWindowPoint;
145   // mTargetWidget and mTargetDragContext are set only while dispatching
146   // motion or drop events.  mTime records the corresponding timestamp.
147   RefPtr<GtkWidget> mTargetWidget;
148   RefPtr<GdkDragContext> mTargetDragContext;
149 #ifdef MOZ_WAYLAND
150   RefPtr<nsWaylandDragContext> mTargetWaylandDragContext;
151 #endif
152   // mTargetDragContextForRemote is set while waiting for a reply from
153   // a child process.
154   RefPtr<GdkDragContext> mTargetDragContextForRemote;
155 #ifdef MOZ_WAYLAND
156   RefPtr<nsWaylandDragContext> mTargetWaylandDragContextForRemote;
157 #endif
158   guint mTargetTime;
159 
160   // is it OK to drop on us?
161   bool mCanDrop;
162 
163   // have we received our drag data?
164   bool mTargetDragDataReceived;
165   // last data received and its length
166   void* mTargetDragData;
167   uint32_t mTargetDragDataLen;
168   // is the current target drag context contain a list?
169   bool IsTargetContextList(void);
170   // this will get the native data from the last target given a
171   // specific flavor
172   void GetTargetDragData(GdkAtom aFlavor);
173   // this will reset all of the target vars
174   void TargetResetData(void);
175 
176   // source side vars
177 
178   // the source of our drags
179   GtkWidget* mHiddenWidget;
180   // our source data items
181   nsCOMPtr<nsIArray> mSourceDataItems;
182 
183   // get a list of the sources in gtk's format
184   GtkTargetList* GetSourceList(void);
185 
186   // attempts to create a semi-transparent drag image. Returns TRUE if
187   // successful, FALSE if not
188   bool SetAlphaPixmap(SourceSurface* aPixbuf, GdkDragContext* aContext,
189                       int32_t aXOffset, int32_t aYOffset,
190                       const mozilla::LayoutDeviceIntRect& dragRect);
191 
192   gboolean Schedule(DragTask aTask, nsWindow* aWindow,
193                     GdkDragContext* aDragContext,
194                     nsWaylandDragContext* aPendingWaylandDragContext,
195                     mozilla::LayoutDeviceIntPoint aWindowPoint, guint aTime);
196 
197   // Callback for g_idle_add_full() to run mScheduledTask.
198   MOZ_CAN_RUN_SCRIPT static gboolean TaskDispatchCallback(gpointer data);
199   MOZ_CAN_RUN_SCRIPT gboolean RunScheduledTask();
200   void UpdateDragAction();
201   MOZ_CAN_RUN_SCRIPT void DispatchMotionEvents();
202   void ReplyToDragMotion(GdkDragContext* aDragContext);
203 #ifdef MOZ_WAYLAND
204   void ReplyToDragMotion(nsWaylandDragContext* aDragContext);
205 #endif
206   gboolean DispatchDropEvent();
207   static uint32_t GetCurrentModifiers();
208 };
209 
210 #endif  // nsDragService_h__
211