1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2024 Jie Liu <liujie01@kylinos.cn>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qwaylandclipboard_p.h"
6#include "qwaylanddisplay_p.h"
7#include "qwaylandinputdevice_p.h"
8#include "qwaylanddatacontrolv1_p.h"
9#include "qwaylanddataoffer_p.h"
10#include "qwaylanddatasource_p.h"
11#include "qwaylanddatadevice_p.h"
12#if QT_CONFIG(wayland_client_primary_selection)
13#include "qwaylandprimaryselectionv1_p.h"
14#endif
15
16QT_BEGIN_NAMESPACE
17
18namespace QtWaylandClient {
19
20QWaylandClipboard::QWaylandClipboard(QWaylandDisplay *display)
21 : mDisplay(display)
22{
23 m_clientClipboard[QClipboard::Clipboard] = nullptr;
24 m_clientClipboard[QClipboard::Selection] = nullptr;
25}
26
27QWaylandClipboard::~QWaylandClipboard()
28{
29 if (m_clientClipboard[QClipboard::Clipboard] != m_clientClipboard[QClipboard::Selection])
30 delete m_clientClipboard[QClipboard::Clipboard];
31 delete m_clientClipboard[QClipboard::Selection];
32}
33
34QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode)
35{
36 auto *seat = mDisplay->currentInputDevice();
37 if (!seat)
38 return &m_emptyData;
39
40 switch (mode) {
41 case QClipboard::Clipboard:
42 if (auto *dataControlDevice = seat->dataControlDevice()) {
43 if (dataControlDevice->selectionSource())
44 return m_clientClipboard[QClipboard::Clipboard];
45 if (auto *offer = dataControlDevice->selectionOffer())
46 return offer->mimeData();
47 }
48 if (auto *dataDevice = seat->dataDevice()) {
49 if (dataDevice->selectionSource())
50 return m_clientClipboard[QClipboard::Clipboard];
51 if (auto *offer = dataDevice->selectionOffer())
52 return offer->mimeData();
53 }
54 return &m_emptyData;
55 case QClipboard::Selection:
56 if (auto *dataControlDevice = seat->dataControlDevice()) {
57 if (dataControlDevice->primarySelectionSource())
58 return m_clientClipboard[QClipboard::Selection];
59 if (auto *offer = dataControlDevice->primarySelectionOffer())
60 return offer->mimeData();
61 }
62#if QT_CONFIG(wayland_client_primary_selection)
63 if (auto *selectionDevice = seat->primarySelectionDevice()) {
64 if (selectionDevice->selectionSource())
65 return m_clientClipboard[QClipboard::Selection];
66 if (auto *offer = selectionDevice->selectionOffer())
67 return offer->mimeData();
68 }
69#endif
70 return &m_emptyData;
71 default:
72 return &m_emptyData;
73 }
74}
75
76void QWaylandClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
77{
78 auto *seat = mDisplay->currentInputDevice();
79 if (!seat) {
80 qCWarning(lcQpaWayland) << "Can't set clipboard contents with no wl_seats available";
81 return;
82 }
83
84 if (data && m_clientClipboard[mode] == data) // Already set before?
85 return;
86
87 static const QString plain = QStringLiteral("text/plain");
88 static const QString utf8 = QStringLiteral("text/plain;charset=utf-8");
89
90 if (data && data->hasFormat(mimetype: plain) && !data->hasFormat(mimetype: utf8))
91 data->setData(mimetype: utf8, data: data->data(mimetype: plain));
92
93 auto oldMimeData = std::exchange(obj&: m_clientClipboard[mode], new_val&: data);
94 const auto otherMode = mode == QClipboard::Clipboard ? QClipboard::Selection
95 : QClipboard::Clipboard;
96 if (oldMimeData != m_clientClipboard[otherMode])
97 delete oldMimeData;
98
99 switch (mode) {
100 case QClipboard::Clipboard:
101 if (auto *dataControlDevice = seat->dataControlDevice()) {
102 dataControlDevice->setSelectionSource(data ? new QWaylandDataControlSourceV1(mDisplay->dataControlManager(),
103 m_clientClipboard[QClipboard::Clipboard]) : nullptr);
104 emitChanged(mode);
105 } else if (auto *dataDevice = seat->dataDevice()) {
106 dataDevice->setSelectionSource(data ? new QWaylandDataSource(mDisplay->dndSelectionHandler(),
107 m_clientClipboard[QClipboard::Clipboard]) : nullptr);
108 emitChanged(mode);
109 }
110 break;
111 case QClipboard::Selection:
112 if (auto *dataControlDevice = seat->dataControlDevice()) {
113 dataControlDevice->setPrimarySelectionSource(data ? new QWaylandDataControlSourceV1(mDisplay->dataControlManager(),
114 m_clientClipboard[QClipboard::Selection]) : nullptr);
115 emitChanged(mode);
116#if QT_CONFIG(wayland_client_primary_selection)
117 } else if (auto *selectionDevice = seat->primarySelectionDevice()) {
118 selectionDevice->setSelectionSource(data ? new QWaylandPrimarySelectionSourceV1(mDisplay->primarySelectionManager(),
119 m_clientClipboard[QClipboard::Selection]) : nullptr);
120 emitChanged(mode);
121#endif
122 }
123 break;
124 default:
125 break;
126 }
127}
128
129bool QWaylandClipboard::supportsMode(QClipboard::Mode mode) const
130{
131 if (mode == QClipboard::Selection) {
132 auto *seat = mDisplay->currentInputDevice();
133 if (!seat)
134 return false;
135 if (seat->dataControlDevice())
136 return true;
137#if QT_CONFIG(wayland_client_primary_selection)
138 if (seat->primarySelectionDevice())
139 return true;
140#endif
141 return false;
142 }
143 return mode == QClipboard::Clipboard;
144}
145
146bool QWaylandClipboard::ownsMode(QClipboard::Mode mode) const
147{
148 QWaylandInputDevice *seat = mDisplay->currentInputDevice();
149 if (!seat)
150 return false;
151
152 switch (mode) {
153 case QClipboard::Clipboard:
154 return seat->dataDevice() && seat->dataDevice()->selectionSource() != nullptr;
155 case QClipboard::Selection:
156 if (seat->dataControlDevice() && seat->dataControlDevice()->primarySelectionSource() != nullptr)
157 return true;
158#if QT_CONFIG(wayland_client_primary_selection)
159 return seat->primarySelectionDevice() && seat->primarySelectionDevice()->selectionSource() != nullptr;
160#endif
161 default:
162 return false;
163 }
164}
165
166}
167
168QT_END_NAMESPACE
169

source code of qtbase/src/plugins/platforms/wayland/qwaylandclipboard.cpp