1// Copyright (C) 2019 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 "qwaylandprimaryselectionv1_p.h"
5#include "qwaylandinputdevice_p.h"
6#include "qwaylanddisplay_p.h"
7#include "qwaylandmimehelper_p.h"
8
9#include <QtGui/private/qguiapplication_p.h>
10
11#include <qpa/qplatformclipboard.h>
12
13#include <signal.h>
14#include <unistd.h>
15
16QT_BEGIN_NAMESPACE
17
18namespace QtWaylandClient {
19
20QWaylandPrimarySelectionDeviceManagerV1::QWaylandPrimarySelectionDeviceManagerV1(QWaylandDisplay *display, uint id, uint version)
21 : zwp_primary_selection_device_manager_v1(display->wl_registry(), id, qMin(version, uint(1)))
22 , m_display(display)
23{
24}
25
26QWaylandPrimarySelectionDeviceManagerV1::~QWaylandPrimarySelectionDeviceManagerV1()
27{
28 destroy();
29}
30
31QWaylandPrimarySelectionDeviceV1 *QWaylandPrimarySelectionDeviceManagerV1::createDevice(QWaylandInputDevice *seat)
32{
33 return new QWaylandPrimarySelectionDeviceV1(this, seat);
34}
35
36QWaylandPrimarySelectionOfferV1::QWaylandPrimarySelectionOfferV1(QWaylandDisplay *display, ::zwp_primary_selection_offer_v1 *offer)
37 : zwp_primary_selection_offer_v1(offer)
38 , m_display(display)
39 , m_mimeData(new QWaylandMimeData(this))
40{}
41
42void QWaylandPrimarySelectionOfferV1::startReceiving(const QString &mimeType, int fd)
43{
44 receive(mimeType, fd);
45 wl_display_flush(m_display->wl_display());
46}
47
48void QWaylandPrimarySelectionOfferV1::zwp_primary_selection_offer_v1_offer(const QString &mime_type)
49{
50 m_mimeData->appendFormat(mimeType: mime_type);
51}
52
53QWaylandPrimarySelectionDeviceV1::QWaylandPrimarySelectionDeviceV1(
54 QWaylandPrimarySelectionDeviceManagerV1 *manager, QWaylandInputDevice *seat)
55 : QtWayland::zwp_primary_selection_device_v1(manager->get_device(seat->wl_seat()))
56 , m_display(manager->display())
57 , m_seat(seat)
58{
59}
60
61QWaylandPrimarySelectionDeviceV1::~QWaylandPrimarySelectionDeviceV1()
62{
63 destroy();
64}
65
66void QWaylandPrimarySelectionDeviceV1::invalidateSelectionOffer()
67{
68 if (!m_selectionOffer)
69 return;
70
71 m_selectionOffer.reset();
72 QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(mode: QClipboard::Selection);
73}
74
75void QWaylandPrimarySelectionDeviceV1::setSelectionSource(QWaylandPrimarySelectionSourceV1 *source)
76{
77 if (source) {
78 connect(sender: source, signal: &QWaylandPrimarySelectionSourceV1::cancelled, context: this, slot: [this]() {
79 m_selectionSource.reset();
80 QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(mode: QClipboard::Selection);
81 });
82 }
83 set_selection(source ? source->object() : nullptr, m_seat->serial());
84 m_selectionSource.reset(other: source);
85}
86
87void QWaylandPrimarySelectionDeviceV1::zwp_primary_selection_device_v1_data_offer(zwp_primary_selection_offer_v1 *offer)
88{
89 new QWaylandPrimarySelectionOfferV1(m_display, offer);
90}
91
92void QWaylandPrimarySelectionDeviceV1::zwp_primary_selection_device_v1_selection(zwp_primary_selection_offer_v1 *id)
93{
94
95 if (id)
96 m_selectionOffer.reset(other: static_cast<QWaylandPrimarySelectionOfferV1 *>(zwp_primary_selection_offer_v1_get_user_data(id)));
97 else
98 m_selectionOffer.reset();
99
100 QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(mode: QClipboard::Selection);
101}
102
103QWaylandPrimarySelectionSourceV1::QWaylandPrimarySelectionSourceV1(QWaylandPrimarySelectionDeviceManagerV1 *manager, QMimeData *mimeData)
104 : QtWayland::zwp_primary_selection_source_v1(manager->create_source())
105 , m_mimeData(mimeData)
106{
107 if (!mimeData)
108 return;
109 for (auto &format : mimeData->formats())
110 offer(format);
111}
112
113QWaylandPrimarySelectionSourceV1::~QWaylandPrimarySelectionSourceV1()
114{
115 destroy();
116}
117
118void QWaylandPrimarySelectionSourceV1::zwp_primary_selection_source_v1_send(const QString &mime_type, int32_t fd)
119{
120 QByteArray content = QWaylandMimeHelper::getByteArray(mimeData: m_mimeData, mimeType: mime_type);
121 if (!content.isEmpty()) {
122 // Create a sigpipe handler that does nothing, or clients may be forced to terminate
123 // if the pipe is closed in the other end.
124 struct sigaction action, oldAction;
125 action.sa_handler = SIG_IGN;
126 sigemptyset (set: &action.sa_mask);
127 action.sa_flags = 0;
128
129 sigaction(SIGPIPE, act: &action, oact: &oldAction);
130 ssize_t unused = write(fd: fd, buf: content.constData(), n: size_t(content.size()));
131 Q_UNUSED(unused);
132 sigaction(SIGPIPE, act: &oldAction, oact: nullptr);
133 }
134 close(fd: fd);
135}
136
137} // namespace QtWaylandClient
138
139QT_END_NAMESPACE
140
141#include "moc_qwaylandprimaryselectionv1_p.cpp"
142

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