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