Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwaylanddatadevice.cpp
Go to the documentation of this file.
1
// Copyright (C) 2016 Klarälvdalens Datakonsult AB (KDAB).
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
6
#
include
"qwaylanddatadevice_p.h"
7
8
#
include
"qwaylanddatadevicemanager_p.h"
9
#
include
"qwaylanddataoffer_p.h"
10
#
include
"qwaylanddatasource_p.h"
11
#
include
"qwaylanddnd_p.h"
12
#
include
"qwaylandinputdevice_p.h"
13
#
include
"qwaylanddisplay_p.h"
14
#
include
"qwaylandabstractdecoration_p.h"
15
#
include
"qwaylandsurface_p.h"
16
17
#
include
<
QtWaylandClient
/
private
/
qwayland
-
xdg
-
toplevel
-
drag
-
v1
.
h
>
18
19
#
include
<
QtCore
/
QMimeData
>
20
#
include
<
QtGui
/
QGuiApplication
>
21
#
include
<
QtGui
/
private
/
qguiapplication_p
.
h
>
22
23
#
if
QT_CONFIG
(
clipboard
)
24
#
include
<
qpa
/
qplatformclipboard
.
h
>
25
#
endif
26
#
include
<
qpa
/
qplatformdrag
.
h
>
27
#
include
<
qpa
/
qwindowsysteminterface
.
h
>
28
29
QT_BEGIN_NAMESPACE
30
31
namespace
QtWaylandClient
{
32
33
using
namespace
Qt
::
StringLiterals
;
34
35
QWaylandDataDevice
::QWaylandDataDevice(QWaylandDataDeviceManager *manager, QWaylandInputDevice *inputDevice)
36
: QObject(inputDevice)
37
, QtWayland::wl_data_device(manager->get_data_device(inputDevice->wl_seat()))
38
, m_display(manager->display())
39
, m_inputDevice(inputDevice)
40
{
41
}
42
43
QWaylandDataDevice
::~
QWaylandDataDevice
()
44
{
45
if
(version() >= WL_DATA_DEVICE_RELEASE_SINCE_VERSION)
46
release();
47
else
48
wl_data_device_destroy(object());
49
}
50
51
QWaylandDataOffer *
QWaylandDataDevice
::
selectionOffer
()
const
52
{
53
return
m_selectionOffer.get();
54
}
55
56
void
QWaylandDataDevice
::
invalidateSelectionOffer
()
57
{
58
if
(!m_selectionOffer)
59
return
;
60
61
m_selectionOffer.reset();
62
63
#
if
QT_CONFIG
(
clipboard
)
64
QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(QClipboard::Clipboard);
65
#
endif
66
}
67
68
QWaylandDataSource *
QWaylandDataDevice
::
selectionSource
()
const
69
{
70
return
m_selectionSource.get();
71
}
72
73
void
QWaylandDataDevice
::
setSelectionSource
(QWaylandDataSource *source)
74
{
75
if
(source)
76
connect(source, &QWaylandDataSource::cancelled,
this
, &QWaylandDataDevice::selectionSourceCancelled);
77
set_selection(source ? source->object() :
nullptr
, m_inputDevice->serial());
78
m_selectionSource.reset(source);
79
}
80
81
#
if
QT_CONFIG
(
draganddrop
)
82
QWaylandDataOffer
*
QWaylandDataDevice
::
dragOffer
()
const
83
{
84
return
m_dragOffer
.
get
();
85
}
86
87
bool
QWaylandDataDevice
::
startDrag
(
QMimeData
*
mimeData
,
Qt
::
DropActions
supportedActions
,
QWaylandWindow
*
icon
)
88
{
89
auto
*
origin
=
m_display
->
lastInputSurface
();
90
91
if
(!
origin
) {
92
qCDebug
(
lcQpaWayland
) <<
"Couldn't start a drag because the origin window could not be found."
;
93
return
false
;
94
}
95
96
// dragging data without mimetypes is a legal operation in Qt terms
97
// but Wayland uses a mimetype to determine if a drag is accepted or not
98
// In this rare case, insert a placeholder
99
if
(
mimeData
->
formats
().
isEmpty
())
100
mimeData
->
setData
(
"application/x-qt-avoid-empty-placeholder"_L1
,
QByteArray
(
"1"
));
101
102
static
const
QString
plain
=
QStringLiteral
(
"text/plain"
);
103
static
const
QString
utf8
=
QStringLiteral
(
"text/plain;charset=utf-8"
);
104
105
if
(
mimeData
->
hasFormat
(
plain
) && !
mimeData
->
hasFormat
(
utf8
))
106
mimeData
->
setData
(
utf8
,
mimeData
->
data
(
plain
));
107
108
m_dragSource
.
reset
(
new
QWaylandDataSource
(
m_display
->
dndSelectionHandler
(),
mimeData
));
109
110
if
(
version
() >= 3)
111
m_dragSource
->
set_actions
(
dropActionsToWl
(
supportedActions
));
112
113
connect
(
m_dragSource
.
get
(), &
QWaylandDataSource
::
cancelled
,
114
this
, &
QWaylandDataDevice
::
dragSourceCancelled
);
115
connect
(
m_dragSource
.
get
(), &
QWaylandDataSource
::
dndResponseUpdated
,
116
this
, [
this
](
bool
accepted
,
Qt
::
DropAction
action
) {
117
auto
drag
=
static_cast
<
QWaylandDrag
*>(
QGuiApplicationPrivate
::
platformIntegration
()->
drag
());
118
if
(!
drag
->
currentDrag
()) {
119
return
;
120
}
121
// in old versions drop action is not set, so we guess
122
if
(
m_dragSource
->
version
() < 3) {
123
drag
->
setResponse
(
accepted
);
124
}
else
{
125
QPlatformDropQtResponse
response
(
accepted
,
action
);
126
drag
->
setResponse
(
response
);
127
}
128
});
129
connect
(
m_dragSource
.
get
(), &
QWaylandDataSource
::
dndDropped
,
130
this
, [
this
](
bool
accepted
,
Qt
::
DropAction
action
) {
131
QPlatformDropQtResponse
response
(
accepted
,
action
);
132
if
(
m_toplevelDrag
) {
133
// If the widget was dropped but the drag not accepted it
134
// should be its own window in the future. To distinguish
135
// from canceling mid-drag the drag is accepted here as the
136
// we know if the widget is over a zone where it can be
137
// incorporated or not
138
response
= {
true
,
Qt
::
MoveAction
};
139
}
140
static_cast
<
QWaylandDrag
*>(
QGuiApplicationPrivate
::
platformIntegration
()->
drag
())
141
->
setDropResponse
(
response
);
142
});
143
connect
(
m_dragSource
.
get
(), &
QWaylandDataSource
::
finished
,
this
, [
this
]() {
144
static_cast
<
QWaylandDrag
*>(
QGuiApplicationPrivate
::
platformIntegration
()->
drag
())->
finishDrag
();
145
if
(
m_toplevelDrag
) {
146
m_toplevelDrag
->
destroy
();
147
m_toplevelDrag
=
nullptr
;
148
}
149
});
150
151
if
(
mimeData
->
hasFormat
(
"application/x-qt-mainwindowdrag-window"_L1
)
152
&&
m_display
->
xdgToplevelDragManager
()) {
153
qintptr
dockWindowPtr
;
154
QPoint
offset
;
155
QDataStream
windowStream
(
mimeData
->
data
(
"application/x-qt-mainwindowdrag-window"_L1
));
156
windowStream
>>
dockWindowPtr
;
157
QWindow
*
dockWindow
=
reinterpret_cast
<
QWindow
*>(
dockWindowPtr
);
158
QDataStream
offsetStream
(
mimeData
->
data
(
"application/x-qt-mainwindowdrag-position"_L1
));
159
offsetStream
>>
offset
;
160
if
(
auto
waylandWindow
=
static_cast
<
QWaylandWindow
*>(
dockWindow
->
handle
())) {
161
if
(
auto
toplevel
=
waylandWindow
->
surfaceRole
<
xdg_toplevel
>()) {
162
m_toplevelDrag
=
new
QtWayland
::
xdg_toplevel_drag_v1
(
163
m_display
->
xdgToplevelDragManager
()->
get_xdg_toplevel_drag
(
164
m_dragSource
->
object
()));
165
m_toplevelDrag
->
attach
(
toplevel
,
offset
.
x
(),
offset
.
y
());
166
}
167
}
168
}
169
170
start_drag
(
m_dragSource
->
object
(),
origin
->
object
(),
icon
->
wlSurface
(),
m_display
->
lastInputSerial
());
171
return
true
;
172
}
173
174
void
QWaylandDataDevice
::
cancelDrag
()
175
{
176
m_dragSource
.
reset
();
177
}
178
#
endif
179
180
void
QWaylandDataDevice
::data_device_data_offer(
struct
::wl_data_offer *id)
181
{
182
new
QWaylandDataOffer(m_display, id);
183
}
184
185
#
if
QT_CONFIG
(
draganddrop
)
186
void
QWaylandDataDevice
::
data_device_drop
()
187
{
188
QDrag
*
drag
=
static_cast
<
QWaylandDrag
*>(
QGuiApplicationPrivate
::
platformIntegration
()->
drag
())->
currentDrag
();
189
190
QMimeData
*
dragData
=
nullptr
;
191
Qt
::
DropActions
supportedActions
;
192
if
(
drag
) {
193
dragData
=
drag
->
mimeData
();
194
supportedActions
=
drag
->
supportedActions
();
195
}
else
if
(
m_dragOffer
) {
196
dragData
=
m_dragOffer
->
mimeData
();
197
supportedActions
=
m_dragOffer
->
supportedActions
();
198
}
else
{
199
return
;
200
}
201
202
QPlatformDropQtResponse
response
=
QWindowSystemInterface
::
handleDrop
(
m_dragWindow
,
dragData
,
m_dragPoint
,
supportedActions
,
203
QGuiApplication
::
mouseButtons
(),
204
m_inputDevice
->
modifiers
());
205
206
// re-evaluate as it could have changed during user code above
207
drag
=
static_cast
<
QWaylandDrag
*>(
QGuiApplicationPrivate
::
platformIntegration
()->
drag
())->
currentDrag
();
208
if
(
drag
) {
209
auto
platformDrag
=
static_cast
<
QWaylandDrag
*>(
QGuiApplicationPrivate
::
platformIntegration
()->
drag
());
210
platformDrag
->
setDropResponse
(
response
);
211
platformDrag
->
finishDrag
();
212
}
else
if
(
m_dragOffer
213
&&
response
.
isAccepted
()
214
&&
m_dragOffer
->
version
() >=
WL_DATA_OFFER_FINISH_SINCE_VERSION
) {
215
m_dragOffer
->
finish
();
216
}
217
}
218
219
void
QWaylandDataDevice
::
data_device_enter
(
uint32_t
serial
,
wl_surface
*
surface
,
wl_fixed_t
x_fixed
,
wl_fixed_t
y_fixed
,
wl_data_offer
*
id
)
220
{
221
const
qreal
x
=
wl_fixed_to_double
(
x_fixed
);
222
const
qreal
y
=
wl_fixed_to_double
(
y_fixed
);
223
224
auto
*
dragWaylandWindow
=
surface
?
QWaylandWindow
::
fromWlSurface
(
surface
) :
nullptr
;
225
if
(!
dragWaylandWindow
)
226
return
;
// Ignore foreign surfaces
227
228
m_dragWindow
=
dragWaylandWindow
->
window
();
229
m_dragPoint
=
calculateDragPosition
(
x
,
y
,
m_dragWindow
);
230
m_enterSerial
=
serial
;
231
232
QMimeData
*
dragData
=
nullptr
;
233
Qt
::
DropActions
supportedActions
;
234
235
m_dragOffer
.
reset
(
static_cast
<
QWaylandDataOffer
*>(
wl_data_offer_get_user_data
(
id
)));
236
QDrag
*
drag
=
static_cast
<
QWaylandDrag
*>(
QGuiApplicationPrivate
::
platformIntegration
()->
drag
())->
currentDrag
();
237
if
(
drag
) {
238
dragData
=
drag
->
mimeData
();
239
supportedActions
=
drag
->
supportedActions
();
240
}
else
if
(
m_dragOffer
) {
241
dragData
=
m_dragOffer
->
mimeData
();
242
supportedActions
=
m_dragOffer
->
supportedActions
();
243
}
244
245
const
QPlatformDragQtResponse
&
response
=
QWindowSystemInterface
::
handleDrag
(
246
m_dragWindow
,
dragData
,
m_dragPoint
,
supportedActions
,
QGuiApplication
::
mouseButtons
(),
247
m_inputDevice
->
modifiers
());
248
if
(
drag
) {
249
static_cast
<
QWaylandDrag
*>(
QGuiApplicationPrivate
::
platformIntegration
()->
drag
())->
setResponse
(
response
);
250
}
251
252
sendResponse
(
supportedActions
,
response
);
253
}
254
255
void
QWaylandDataDevice
::
data_device_leave
()
256
{
257
if
(
m_dragWindow
)
258
QWindowSystemInterface
::
handleDrag
(
m_dragWindow
,
nullptr
,
QPoint
(),
Qt
::
IgnoreAction
,
259
QGuiApplication
::
mouseButtons
(),
260
m_inputDevice
->
modifiers
());
261
262
QDrag
*
drag
=
static_cast
<
QWaylandDrag
*>(
QGuiApplicationPrivate
::
platformIntegration
()->
drag
())->
currentDrag
();
263
if
(!
drag
) {
264
m_dragOffer
.
reset
();
265
}
266
}
267
268
void
QWaylandDataDevice
::
data_device_motion
(
uint32_t
time
,
wl_fixed_t
x_fixed
,
wl_fixed_t
y_fixed
)
269
{
270
Q_UNUSED
(
time
);
271
const
qreal
x
=
wl_fixed_to_double
(
x_fixed
);
272
const
qreal
y
=
wl_fixed_to_double
(
y_fixed
);
273
274
QDrag
*
drag
=
static_cast
<
QWaylandDrag
*>(
QGuiApplicationPrivate
::
platformIntegration
()->
drag
())->
currentDrag
();
275
276
if
(!
drag
&& !
m_dragOffer
)
277
return
;
278
279
if
(!
m_dragWindow
)
280
return
;
281
282
m_dragPoint
=
calculateDragPosition
(
x
,
y
,
m_dragWindow
);
283
284
QMimeData
*
dragData
=
nullptr
;
285
Qt
::
DropActions
supportedActions
;
286
if
(
drag
) {
287
dragData
=
drag
->
mimeData
();
288
supportedActions
=
drag
->
supportedActions
();
289
}
else
{
290
dragData
=
m_dragOffer
->
mimeData
();
291
supportedActions
=
m_dragOffer
->
supportedActions
();
292
}
293
294
const
QPlatformDragQtResponse
response
=
QWindowSystemInterface
::
handleDrag
(
m_dragWindow
,
dragData
,
m_dragPoint
,
supportedActions
,
295
QGuiApplication
::
mouseButtons
(),
296
m_inputDevice
->
modifiers
());
297
298
if
(
drag
) {
299
static_cast
<
QWaylandDrag
*>(
QGuiApplicationPrivate
::
platformIntegration
()->
drag
())->
setResponse
(
response
);
300
}
301
302
sendResponse
(
supportedActions
,
response
);
303
}
304
#
endif
// QT_CONFIG(draganddrop)
305
306
void
QWaylandDataDevice
::data_device_selection(wl_data_offer *id)
307
{
308
if
(id)
309
m_selectionOffer.reset(
static_cast
<QWaylandDataOffer *>(wl_data_offer_get_user_data(id)));
310
else
311
m_selectionOffer.reset();
312
313
#
if
QT_CONFIG
(
clipboard
)
314
QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(QClipboard::Clipboard);
315
#
endif
316
}
317
318
void
QWaylandDataDevice
::selectionSourceCancelled()
319
{
320
m_selectionSource.reset();
321
#
if
QT_CONFIG
(
clipboard
)
322
QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(QClipboard::Clipboard);
323
#
endif
324
}
325
326
#
if
QT_CONFIG
(
draganddrop
)
327
void
QWaylandDataDevice
::
dragSourceCancelled
()
328
{
329
static_cast
<
QWaylandDrag
*>(
QGuiApplicationPrivate
::
platformIntegration
()->
drag
())->
finishDrag
();
330
m_dragSource
.
reset
();
331
if
(
m_toplevelDrag
) {
332
m_toplevelDrag
->
destroy
();
333
m_toplevelDrag
=
nullptr
;
334
}
335
}
336
337
QPoint
QWaylandDataDevice
::
calculateDragPosition
(
qreal
x
,
qreal
y
,
QWindow
*
wnd
)
const
338
{
339
QPoint
pnt
(
x
,
y
);
340
if
(
wnd
) {
341
QWaylandWindow
*
wwnd
=
static_cast
<
QWaylandWindow
*>(
m_dragWindow
->
handle
());
342
if
(
wwnd
&&
wwnd
->
decoration
()) {
343
pnt
-=
QPoint
(
wwnd
->
decoration
()->
margins
().
left
(),
344
wwnd
->
decoration
()->
margins
().
top
());
345
}
346
}
347
return
pnt
;
348
}
349
350
void
QWaylandDataDevice
::
sendResponse
(
Qt
::
DropActions
supportedActions
,
const
QPlatformDragQtResponse
&
response
)
351
{
352
if
(
response
.
isAccepted
()) {
353
if
(
version
() >= 3)
354
m_dragOffer
->
set_actions
(
dropActionsToWl
(
supportedActions
),
dropActionsToWl
(
response
.
acceptedAction
()));
355
356
m_dragOffer
->
accept
(
m_enterSerial
,
m_dragOffer
->
firstFormat
());
357
}
else
{
358
m_dragOffer
->
accept
(
m_enterSerial
,
QString
());
359
}
360
}
361
362
int
QWaylandDataDevice
::
dropActionsToWl
(
Qt
::
DropActions
actions
)
363
{
364
365
int
wlActions
=
WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE
;
366
if
(
actions
&
Qt
::
CopyAction
)
367
wlActions
|=
WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY
;
368
if
(
actions
& (
Qt
::
MoveAction
|
Qt
::
TargetMoveAction
))
369
wlActions
|=
WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE
;
370
371
// wayland does not support LinkAction at the time of writing
372
return
wlActions
;
373
}
374
375
376
#
endif
// QT_CONFIG(draganddrop)
377
378
}
379
380
QT_END_NAMESPACE
381
382
#
include
"moc_qwaylanddatadevice_p.cpp"
QtWaylandClient::QWaylandDataDevice
Definition
qwaylanddatadevice_p.h:51
QtWaylandClient::QWaylandDataDevice::~QWaylandDataDevice
~QWaylandDataDevice() override
Definition
qwaylanddatadevice.cpp:43
QtWaylandClient::QWaylandDataDevice::selectionSource
QWaylandDataSource * selectionSource() const
Definition
qwaylanddatadevice.cpp:68
QtWaylandClient::QWaylandDataDevice::selectionOffer
QWaylandDataOffer * selectionOffer() const
Definition
qwaylanddatadevice.cpp:51
QtWaylandClient::QWaylandDataDevice::setSelectionSource
void setSelectionSource(QWaylandDataSource *source)
Definition
qwaylanddatadevice.cpp:73
QtWaylandClient::QWaylandDataDevice::invalidateSelectionOffer
void invalidateSelectionOffer()
Definition
qwaylanddatadevice.cpp:56
QT_BEGIN_NAMESPACE
Combined button and popup list for selecting options.
Definition
qsequentialanimationgroup.cpp:47
QtWaylandClient
Definition
qwaylandclientextension.h:16
qtbase
src
plugins
platforms
wayland
qwaylanddatadevice.cpp
Generated on
for Qt by
1.16.1