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 | |
4 | #include "qwaylanddatasource_p.h" |
5 | #include "qwaylanddataoffer_p.h" |
6 | #include "qwaylanddatadevicemanager_p.h" |
7 | #include "qwaylandinputdevice_p.h" |
8 | #include "qwaylandmimehelper_p.h" |
9 | |
10 | #include <QtCore/QFile> |
11 | |
12 | #include <QtCore/QDebug> |
13 | |
14 | #include <unistd.h> |
15 | #include <signal.h> |
16 | #include <fcntl.h> |
17 | |
18 | QT_BEGIN_NAMESPACE |
19 | |
20 | namespace QtWaylandClient { |
21 | |
22 | QWaylandDataSource::QWaylandDataSource(QWaylandDataDeviceManager *dataDeviceManager, QMimeData *mimeData) |
23 | : QtWayland::wl_data_source(dataDeviceManager->create_data_source()) |
24 | , m_mime_data(mimeData) |
25 | { |
26 | if (!mimeData) |
27 | return; |
28 | const auto formats = QInternalMimeData::formatsHelper(data: mimeData); |
29 | for (const QString &format : formats) { |
30 | offer(format); |
31 | } |
32 | } |
33 | |
34 | QWaylandDataSource::~QWaylandDataSource() |
35 | { |
36 | destroy(); |
37 | } |
38 | |
39 | void QWaylandDataSource::data_source_cancelled() |
40 | { |
41 | Q_EMIT cancelled(); |
42 | } |
43 | |
44 | void QWaylandDataSource::data_source_send(const QString &mime_type, int32_t fd) |
45 | { |
46 | QByteArray content = QWaylandMimeHelper::getByteArray(mimeData: m_mime_data, mimeType: mime_type); |
47 | if (!content.isEmpty()) { |
48 | // Create a sigpipe handler that does nothing, or clients may be forced to terminate |
49 | // if the pipe is closed in the other end. |
50 | struct sigaction action, oldAction; |
51 | action.sa_handler = SIG_IGN; |
52 | sigemptyset (set: &action.sa_mask); |
53 | action.sa_flags = 0; |
54 | |
55 | sigaction(SIGPIPE, act: &action, oact: &oldAction); |
56 | // Some compositors (e.g., mutter) make fd with O_NONBLOCK. |
57 | // Since wl_data_source.send describes that fd is closed here, |
58 | // it should be done in a loop and don't have any advantage. |
59 | // Blocking operation will be used. |
60 | // According to fcntl(2), FSETFL ignores O_WRONLY. So this |
61 | // call will just remove O_NONBLOCK. |
62 | fcntl(fd: fd, F_SETFL, O_WRONLY); |
63 | ssize_t unused = write(fd: fd, buf: content.constData(), n: content.size()); |
64 | Q_UNUSED(unused); |
65 | sigaction(SIGPIPE, act: &oldAction, oact: nullptr); |
66 | } |
67 | close(fd: fd); |
68 | } |
69 | |
70 | void QWaylandDataSource::data_source_target(const QString &mime_type) |
71 | { |
72 | m_accepted = !mime_type.isEmpty(); |
73 | Q_EMIT dndResponseUpdated(accepted: m_accepted, action: m_dropAction); |
74 | } |
75 | |
76 | void QWaylandDataSource::data_source_action(uint32_t action) |
77 | { |
78 | Qt::DropAction qtAction = Qt::IgnoreAction; |
79 | |
80 | if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE) |
81 | qtAction = Qt::MoveAction; |
82 | else if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) |
83 | qtAction = Qt::CopyAction; |
84 | |
85 | m_dropAction = qtAction; |
86 | Q_EMIT dndResponseUpdated(accepted: m_accepted, action: m_dropAction); |
87 | } |
88 | |
89 | void QWaylandDataSource::data_source_dnd_finished() |
90 | { |
91 | Q_EMIT finished(); |
92 | } |
93 | |
94 | void QWaylandDataSource::data_source_dnd_drop_performed() |
95 | { |
96 | |
97 | Q_EMIT dndDropped(accepted: m_accepted, action: m_dropAction); |
98 | } |
99 | |
100 | } |
101 | |
102 | QT_END_NAMESPACE |
103 | |
104 | #include "moc_qwaylanddatasource_p.cpp" |
105 | |