Coverage Report

Created: 2026-10-14 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/gui/kernel/qdrag.cpp
Line
Count
Source
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
// Qt-Security score:significant reason:default
4
5
#include <qdrag.h>
6
#include "private/qguiapplication_p.h"
7
#include "qpa/qplatformintegration.h"
8
#include "qpa/qplatformdrag.h"
9
#include <qpixmap.h>
10
#include <qpoint.h>
11
#include "qdnd_p.h"
12
13
#include <QtCore/qpointer.h>
14
15
QT_BEGIN_NAMESPACE
16
17
/*!
18
    \class QDrag
19
    \inmodule QtGui
20
    \ingroup draganddrop
21
    \brief The QDrag class provides support for MIME-based drag and drop data
22
    transfer.
23
24
    Drag and drop is an intuitive way for users to copy or move data around in an
25
    application, and is used in many desktop environments as a mechanism for copying
26
    data between applications. Drag and drop support in Qt is centered around the
27
    QDrag class that handles most of the details of a drag and drop operation.
28
29
    The data to be transferred by the drag and drop operation is contained in a
30
    QMimeData object. This is specified with the setMimeData() function in the
31
    following way:
32
33
    \snippet dragging/mainwindow.cpp 1
34
35
    Note that setMimeData() assigns ownership of the QMimeData object to the
36
    QDrag object. The QDrag must be constructed on the heap with a parent QObject
37
    to ensure that Qt can clean up after the drag and drop operation has been
38
    completed.
39
40
    A pixmap can be used to represent the data while the drag is in
41
    progress, and will move with the cursor to the drop target. This
42
    pixmap typically shows an icon that represents the MIME type of
43
    the data being transferred, but any pixmap can be set with
44
    setPixmap(). The cursor's hot spot can be given a position
45
    relative to the top-left corner of the pixmap with the
46
    setHotSpot() function. The following code positions the pixmap so
47
    that the cursor's hot spot points to the center of its bottom
48
    edge:
49
50
    \snippet separations/finalwidget.cpp 2
51
52
    \note On X11, the pixmap may not be able to keep up with the mouse
53
    movements if the hot spot causes the pixmap to be displayed
54
    directly under the cursor.
55
56
    The source and target widgets can be found with source() and target().
57
    These functions are often used to determine whether drag and drop operations
58
    started and finished at the same widget, so that special behavior can be
59
    implemented.
60
61
    QDrag only deals with the drag and drop operation itself. It is up to the
62
    developer to decide when a drag operation begins, and how a QDrag object should
63
    be constructed and used. For a given widget, it is often necessary to
64
    reimplement \l{QWidget::mousePressEvent()}{mousePressEvent()} to determine
65
    whether the user has pressed a mouse button, and reimplement
66
    \l{QWidget::mouseMoveEvent()}{mouseMoveEvent()} to check whether a QDrag is
67
    required.
68
69
    \sa {Drag and Drop}, QClipboard, QMimeData, {Draggable Icons Example},
70
        {Draggable Text Example}, {Drop Site Example}
71
*/
72
73
/*!
74
    Constructs a new drag object for the widget specified by \a dragSource.
75
*/
76
QDrag::QDrag(QObject *dragSource)
77
0
    : QObject(*new QDragPrivate, dragSource)
78
0
{
79
0
    Q_D(QDrag);
80
0
    d->source = dragSource;
81
0
    d->target = nullptr;
82
0
    d->data = nullptr;
83
0
    d->hotspot = QPoint(-10, -10);
84
0
    d->executed_action = Qt::IgnoreAction;
85
0
    d->supported_actions = Qt::IgnoreAction;
86
0
    d->default_action = Qt::IgnoreAction;
87
0
}
88
89
/*!
90
    Destroys the drag object.
91
*/
92
QDrag::~QDrag()
93
0
{
94
0
    Q_D(QDrag);
95
96
    // As a QObject child of the dragSource, QDrag can be destroyed while
97
    // exec() is still blocked in the platform's nested event loop.
98
    // End the drag while still in existence, to avoid use-after-free later on.
99
0
    if (QDragManager::m_instance && QDragManager::m_instance->object() == this)
100
0
        cancel();
101
0
    delete d->data;
102
0
}
103
104
/*!
105
    Sets the data to be sent to the given MIME \a data. Ownership of the data is
106
    transferred to the QDrag object.
107
*/
108
void QDrag::setMimeData(QMimeData *data)
109
0
{
110
0
    Q_D(QDrag);
111
0
    if (d->data == data)
112
0
        return;
113
0
    if (d->data != nullptr)
114
0
        delete d->data;
115
0
    d->data = data;
116
0
}
117
118
/*!
119
    Returns the MIME data that is encapsulated by the drag object.
120
*/
121
QMimeData *QDrag::mimeData() const
122
0
{
123
0
    Q_D(const QDrag);
124
0
    return d->data;
125
0
}
126
127
/*!
128
    Sets \a pixmap as the pixmap used to represent the data in a drag
129
    and drop operation. You can only set a pixmap before the drag is
130
    started.
131
*/
132
void QDrag::setPixmap(const QPixmap &pixmap)
133
0
{
134
0
    Q_D(QDrag);
135
0
    d->pixmap = pixmap;
136
0
}
137
138
/*!
139
    Returns the pixmap used to represent the data in a drag and drop operation.
140
*/
141
QPixmap QDrag::pixmap() const
142
0
{
143
0
    Q_D(const QDrag);
144
0
    return d->pixmap;
145
0
}
146
147
/*!
148
    Sets the position of the hot spot relative to the top-left corner of the
149
    pixmap used to the point specified by \a hotspot.
150
151
    \b{Note:} on X11, the pixmap may not be able to keep up with the mouse
152
    movements if the hot spot causes the pixmap to be displayed
153
    directly under the cursor.
154
*/
155
void QDrag::setHotSpot(const QPoint& hotspot)
156
0
{
157
0
    Q_D(QDrag);
158
0
    d->hotspot = hotspot;
159
0
}
160
161
/*!
162
    Returns the position of the hot spot relative to the top-left corner of the
163
    cursor.
164
*/
165
QPoint QDrag::hotSpot() const
166
0
{
167
0
    Q_D(const QDrag);
168
0
    return d->hotspot;
169
0
}
170
171
/*!
172
    Returns the source of the drag object. This is the widget where the drag
173
    and drop operation originated.
174
*/
175
QObject *QDrag::source() const
176
0
{
177
0
    Q_D(const QDrag);
178
0
    return d->source;
179
0
}
180
181
/*!
182
    Returns the target of the drag and drop operation. This is the widget where
183
    the drag object was dropped.
184
*/
185
QObject *QDrag::target() const
186
0
{
187
0
    Q_D(const QDrag);
188
0
    return d->target;
189
0
}
190
191
/*!
192
    \since 4.3
193
194
    Starts the drag and drop operation and returns a value indicating the requested
195
    drop action when it is completed. The drop actions that the user can choose
196
    from are specified in \a supportedActions. The default proposed action will be selected
197
    among the allowed actions in the following order: Move, Copy and Link.
198
199
    \b{Note:} On Linux and \macos, the drag and drop operation
200
    can take some time, but this function does not block the event
201
    loop. Other events are still delivered to the application while
202
    the operation is performed. On Windows, the Qt event loop is
203
    blocked during the operation.
204
205
    \sa cancel()
206
*/
207
208
Qt::DropAction QDrag::exec(Qt::DropActions supportedActions)
209
0
{
210
0
    return exec(supportedActions, Qt::IgnoreAction);
211
0
}
212
213
/*!
214
    \since 4.3
215
216
    Starts the drag and drop operation and returns a value indicating the requested
217
    drop action when it is completed. The drop actions that the user can choose
218
    from are specified in \a supportedActions.
219
220
    The \a defaultDropAction determines which action will be proposed when the user performs a
221
    drag without using modifier keys.
222
223
    \b{Note:} On Linux and \macos, the drag and drop operation
224
    can take some time, but this function does not block the event
225
    loop. Other events are still delivered to the application while
226
    the operation is performed. On Windows, the Qt event loop is
227
    blocked during the operation. However, QDrag::exec() on
228
    Windows causes processEvents() to be called frequently to keep the GUI responsive.
229
    If any loops or operations are called while a drag operation is active, it will block the drag operation.
230
*/
231
232
Qt::DropAction QDrag::exec(Qt::DropActions supportedActions, Qt::DropAction defaultDropAction)
233
0
{
234
0
    Q_D(QDrag);
235
0
    if (!d->data) {
236
0
        qWarning("QDrag: No mimedata set before starting the drag");
237
0
        return d->executed_action;
238
0
    }
239
0
    Qt::DropAction transformedDefaultDropAction = Qt::IgnoreAction;
240
241
0
    if (defaultDropAction == Qt::IgnoreAction) {
242
0
        if (supportedActions & Qt::MoveAction) {
243
0
            transformedDefaultDropAction = Qt::MoveAction;
244
0
        } else if (supportedActions & Qt::CopyAction) {
245
0
            transformedDefaultDropAction = Qt::CopyAction;
246
0
        } else if (supportedActions & Qt::LinkAction) {
247
0
            transformedDefaultDropAction = Qt::LinkAction;
248
0
        }
249
0
    } else {
250
0
        transformedDefaultDropAction = defaultDropAction;
251
0
    }
252
0
    d->supported_actions = supportedActions;
253
0
    d->default_action = transformedDefaultDropAction;
254
0
    QPointer<QDrag> self = this;
255
0
    auto executed_action = QDragManager::self()->drag(self.data());
256
0
    if (self.isNull())
257
0
        return Qt::IgnoreAction;
258
0
    d->executed_action = executed_action;
259
0
    return d->executed_action;
260
0
}
261
262
/*!
263
    Sets the drag \a cursor for the \a action. This allows you
264
    to override the default native cursors. To revert to using the
265
    native cursor for \a action pass in a null QPixmap as \a cursor.
266
267
    Note: setting the drag cursor for IgnoreAction may not work on
268
    all platforms. X11 and macOS has been tested to work. Windows
269
    does not support it.
270
*/
271
void QDrag::setDragCursor(const QPixmap &cursor, Qt::DropAction action)
272
0
{
273
0
    Q_D(QDrag);
274
0
    if (cursor.isNull())
275
0
        d->customCursors.remove(action);
276
0
    else
277
0
        d->customCursors[action] = cursor;
278
0
}
279
280
/*!
281
    Returns the drag cursor for the \a action.
282
283
    \since 5.0
284
*/
285
286
QPixmap QDrag::dragCursor(Qt::DropAction action) const
287
0
{
288
0
    typedef QMap<Qt::DropAction, QPixmap>::const_iterator Iterator;
289
290
0
    Q_D(const QDrag);
291
0
    const Iterator it = d->customCursors.constFind(action);
292
0
    if (it != d->customCursors.constEnd())
293
0
        return it.value();
294
295
0
    Qt::CursorShape shape = Qt::ForbiddenCursor;
296
0
    switch (action) {
297
0
    case Qt::MoveAction:
298
0
        shape = Qt::DragMoveCursor;
299
0
        break;
300
0
    case Qt::CopyAction:
301
0
        shape = Qt::DragCopyCursor;
302
0
        break;
303
0
    case Qt::LinkAction:
304
0
        shape = Qt::DragLinkCursor;
305
0
        break;
306
0
    default:
307
0
        shape = Qt::ForbiddenCursor;
308
0
    }
309
0
    return QGuiApplicationPrivate::instance()->getPixmapCursor(shape);
310
0
}
311
312
/*!
313
    Returns the set of possible drop actions for this drag operation.
314
315
    \sa exec(), defaultAction()
316
*/
317
Qt::DropActions QDrag::supportedActions() const
318
0
{
319
0
    Q_D(const QDrag);
320
0
    return d->supported_actions;
321
0
}
322
323
324
/*!
325
    Returns the default proposed drop action for this drag operation.
326
327
    \sa exec(), supportedActions()
328
*/
329
Qt::DropAction QDrag::defaultAction() const
330
0
{
331
0
    Q_D(const QDrag);
332
0
    return d->default_action;
333
0
}
334
335
/*!
336
    Cancels a drag operation initiated by Qt.
337
338
    \note This is currently implemented on Windows and X11.
339
340
    \since 5.7
341
    \sa exec()
342
*/
343
void QDrag::cancel()
344
0
{
345
0
    if (QPlatformDrag *platformDrag = QGuiApplicationPrivate::platformIntegration()->drag())
346
0
        platformDrag->cancelDrag();
347
0
}
348
349
/*!
350
    \fn void QDrag::actionChanged(Qt::DropAction action)
351
352
    This signal is emitted when the \a action associated with the
353
    drag changes.
354
355
    \sa targetChanged()
356
*/
357
358
/*!
359
    \fn void QDrag::targetChanged(QObject *newTarget)
360
361
    This signal is emitted when the target of the drag and drop
362
    operation changes, with \a newTarget the new target.
363
364
    \sa target(), actionChanged()
365
*/
366
367
QT_END_NAMESPACE
368
369
#include "moc_qdrag.cpp"