summaryrefslogtreecommitdiffstats
path: root/widget/gtk/nsDragService.h
blob: 90c11310618016f6fff0063867e9134752c1aee3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=4 et sw=4 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef nsDragService_h__
#define nsDragService_h__

#include "mozilla/RefPtr.h"
#include "nsBaseDragService.h"
#include "nsIObserver.h"
#include "nsAutoRef.h"
#include <gtk/gtk.h>

class nsWindow;

namespace mozilla {
namespace gfx {
class SourceSurface;
}
}

#ifndef HAVE_NSGOBJECTREFTRAITS
#define HAVE_NSGOBJECTREFTRAITS
template <class T>
class nsGObjectRefTraits : public nsPointerRefTraits<T> {
public:
    static void Release(T *aPtr) { g_object_unref(aPtr); }
    static void AddRef(T *aPtr) { g_object_ref(aPtr); }
};
#endif

#ifndef HAVE_NSAUTOREFTRAITS_GTKWIDGET
#define HAVE_NSAUTOREFTRAITS_GTKWIDGET
template <>
class nsAutoRefTraits<GtkWidget> : public nsGObjectRefTraits<GtkWidget> { };
#endif

#ifndef HAVE_NSAUTOREFTRAITS_GDKDRAGCONTEXT
#define HAVE_NSAUTOREFTRAITS_GDKDRAGCONTEXT
template <>
class nsAutoRefTraits<GdkDragContext> :
    public nsGObjectRefTraits<GdkDragContext> { };
#endif

/**
 * Native GTK DragService wrapper
 */

class nsDragService final : public nsBaseDragService,
                            public nsIObserver
{
public:
    nsDragService();

    NS_DECL_ISUPPORTS_INHERITED

    NS_DECL_NSIOBSERVER

    // nsBaseDragService
    virtual nsresult InvokeDragSessionImpl(nsIArray* anArrayTransferables,
                                           nsIScriptableRegion* aRegion,
                                           uint32_t aActionType) override;
    // nsIDragService
    NS_IMETHOD InvokeDragSession (nsIDOMNode *aDOMNode,
                                  nsIArray * anArrayTransferables,
                                  nsIScriptableRegion * aRegion,
                                  uint32_t aActionType,
                                  nsContentPolicyType aContentPolicyType) override;
    NS_IMETHOD StartDragSession() override;
    NS_IMETHOD EndDragSession(bool aDoneDrag) override;

    // nsIDragSession
    NS_IMETHOD SetCanDrop            (bool             aCanDrop) override;
    NS_IMETHOD GetCanDrop            (bool            *aCanDrop) override;
    NS_IMETHOD GetNumDropItems       (uint32_t * aNumItems) override;
    NS_IMETHOD GetData               (nsITransferable * aTransferable,
                                      uint32_t aItemIndex) override;
    NS_IMETHOD IsDataFlavorSupported (const char *aDataFlavor,
                                      bool *_retval) override;

     NS_IMETHOD UpdateDragEffect() override;

    // Methods called from nsWindow to handle responding to GTK drag
    // destination signals

    static nsDragService* GetInstance();

    void TargetDataReceived          (GtkWidget         *aWidget,
                                      GdkDragContext    *aContext,
                                      gint               aX,
                                      gint               aY,
                                      GtkSelectionData  *aSelection_data,
                                      guint              aInfo,
                                      guint32            aTime);

    gboolean ScheduleMotionEvent(nsWindow *aWindow,
                                 GdkDragContext *aDragContext,
                                 mozilla::LayoutDeviceIntPoint aWindowPoint,
                                 guint aTime);
    void ScheduleLeaveEvent();
    gboolean ScheduleDropEvent(nsWindow *aWindow,
                               GdkDragContext *aDragContext,
                               mozilla::LayoutDeviceIntPoint aWindowPoint,
                               guint aTime);

    nsWindow* GetMostRecentDestWindow()
    {
        return mScheduledTask == eDragTaskNone ? mTargetWindow
            : mPendingWindow;
    }

    //  END PUBLIC API

    // These methods are public only so that they can be called from functions
    // with C calling conventions.  They are called for drags started with the
    // invisible widget.
    void           SourceEndDragSession(GdkDragContext *aContext,
                                        gint            aResult);
    void           SourceDataGet(GtkWidget        *widget,
                                 GdkDragContext   *context,
                                 GtkSelectionData *selection_data,
                                 guint32           aTime);

    // set the drag icon during drag-begin
    void SetDragIcon(GdkDragContext* aContext);

protected:
    virtual ~nsDragService();

private:

    // mScheduledTask indicates what signal has been received from GTK and
    // so what needs to be dispatched when the scheduled task is run.  It is
    // eDragTaskNone when there is no task scheduled (but the
    // previous task may still not have finished running).
    enum DragTask {
        eDragTaskNone,
        eDragTaskMotion,
        eDragTaskLeave,
        eDragTaskDrop,
        eDragTaskSourceEnd
    };
    DragTask mScheduledTask;
    // mTaskSource is the GSource id for the task that is either scheduled
    // or currently running.  It is 0 if no task is scheduled or running.
    guint mTaskSource;

    // target/destination side vars
    // These variables keep track of the state of the current drag.

    // mPendingWindow, mPendingWindowPoint, mPendingDragContext, and
    // mPendingTime, carry information from the GTK signal that will be used
    // when the scheduled task is run.  mPendingWindow and mPendingDragContext
    // will be nullptr if the scheduled task is eDragTaskLeave.
    RefPtr<nsWindow> mPendingWindow;
    mozilla::LayoutDeviceIntPoint mPendingWindowPoint;
    nsCountedRef<GdkDragContext> mPendingDragContext;
    guint mPendingTime;

    // mTargetWindow and mTargetWindowPoint record the position of the last
    // eDragTaskMotion or eDragTaskDrop task that was run or is still running.
    // mTargetWindow is cleared once the drag has completed or left.
    RefPtr<nsWindow> mTargetWindow;
    mozilla::LayoutDeviceIntPoint mTargetWindowPoint;
    // mTargetWidget and mTargetDragContext are set only while dispatching
    // motion or drop events.  mTime records the corresponding timestamp.
    nsCountedRef<GtkWidget> mTargetWidget;
    nsCountedRef<GdkDragContext> mTargetDragContext;
    // mTargetDragContextForRemote is set while waiting for a reply from
    // a child process.
    nsCountedRef<GdkDragContext> mTargetDragContextForRemote;
    guint           mTargetTime;

    // is it OK to drop on us?
    bool            mCanDrop;

    // have we received our drag data?
    bool            mTargetDragDataReceived;
    // last data received and its length
    void           *mTargetDragData;
    uint32_t        mTargetDragDataLen;
    // is the current target drag context contain a list?
    bool           IsTargetContextList(void);
    // this will get the native data from the last target given a
    // specific flavor
    void           GetTargetDragData(GdkAtom aFlavor);
    // this will reset all of the target vars
    void           TargetResetData(void);

    // source side vars

    // the source of our drags
    GtkWidget     *mHiddenWidget;
    // our source data items
    nsCOMPtr<nsIArray> mSourceDataItems;

    nsCOMPtr<nsIScriptableRegion> mSourceRegion;

    // get a list of the sources in gtk's format
    GtkTargetList *GetSourceList(void);

    // attempts to create a semi-transparent drag image. Returns TRUE if
    // successful, FALSE if not
    bool SetAlphaPixmap(SourceSurface *aPixbuf,
                        GdkDragContext  *aContext,
                        int32_t          aXOffset,
                        int32_t          aYOffset,
                        const mozilla::LayoutDeviceIntRect &dragRect);

    gboolean Schedule(DragTask aTask, nsWindow *aWindow,
                      GdkDragContext *aDragContext,
                      mozilla::LayoutDeviceIntPoint aWindowPoint, guint aTime);

    // Callback for g_idle_add_full() to run mScheduledTask.
    static gboolean TaskDispatchCallback(gpointer data);
    gboolean RunScheduledTask();
    void UpdateDragAction();
    void DispatchMotionEvents();
    void ReplyToDragMotion(GdkDragContext* aDragContext);
    gboolean DispatchDropEvent();
};

#endif // nsDragService_h__