Add support for wlr-data-control-unstable-v1 protocol
[ChangeLog][Third-Party Code] New protocol synced from wlroots. Change-Id: Ia5f43e62f98e9c95ebd02077ec6dc132e13cf5e0 Reviewed-by: David Edmundson <davidedmundson@kde.org>
This commit is contained in:
parent
207c51371d
commit
92ec75ba8b
18
src/3rdparty/wayland/protocols/wlr-data-control/qt_attribution.json
vendored
Normal file
18
src/3rdparty/wayland/protocols/wlr-data-control/qt_attribution.json
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
[
|
||||
{
|
||||
"Id": "wlr-data-control-unstable-v1-protocol",
|
||||
"Name": "Wlr Data Control Unstable V1 Protocol",
|
||||
"QDocModule": "qtwaylandcompositor",
|
||||
"QtUsage": "Used in the Qt Wayland platform plugin",
|
||||
"Files": "wlr-data-control-unstable-v1.xml",
|
||||
|
||||
"Description": "This protocol allows a privileged client to control data devices.",
|
||||
"Homepage": "https://gitlab.freedesktop.org/wlroots/wlr-protocols/",
|
||||
"Version": "2",
|
||||
"DownloadLocation": "https://gitlab.freedesktop.org/wlroots/wlr-protocols/-/raw/master/unstable/wlr-data-control-unstable-v1.xml",
|
||||
"LicenseId": "MIT",
|
||||
"License": "MIT License",
|
||||
"LicenseFile": "../MIT_LICENSE.txt",
|
||||
"Copyright": "Copyright © 2018 Simon Ser\nCopyright © 2019 Ivan Molodetskikht"
|
||||
}
|
||||
]
|
278
src/3rdparty/wayland/protocols/wlr-data-control/wlr-data-control-unstable-v1.xml
vendored
Normal file
278
src/3rdparty/wayland/protocols/wlr-data-control/wlr-data-control-unstable-v1.xml
vendored
Normal file
@ -0,0 +1,278 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="wlr_data_control_unstable_v1">
|
||||
<copyright>
|
||||
Copyright © 2018 Simon Ser
|
||||
Copyright © 2019 Ivan Molodetskikh
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this
|
||||
software and its documentation for any purpose is hereby granted
|
||||
without fee, provided that the above copyright notice appear in
|
||||
all copies and that both that copyright notice and this permission
|
||||
notice appear in supporting documentation, and that the name of
|
||||
the copyright holders not be used in advertising or publicity
|
||||
pertaining to distribution of the software without specific,
|
||||
written prior permission. The copyright holders make no
|
||||
representations about the suitability of this software for any
|
||||
purpose. It is provided "as is" without express or implied
|
||||
warranty.
|
||||
|
||||
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<description summary="control data devices">
|
||||
This protocol allows a privileged client to control data devices. In
|
||||
particular, the client will be able to manage the current selection and take
|
||||
the role of a clipboard manager.
|
||||
|
||||
Warning! The protocol described in this file is experimental and
|
||||
backward incompatible changes may be made. Backward compatible changes
|
||||
may be added together with the corresponding interface version bump.
|
||||
Backward incompatible changes are done by bumping the version number in
|
||||
the protocol and interface names and resetting the interface version.
|
||||
Once the protocol is to be declared stable, the 'z' prefix and the
|
||||
version number in the protocol and interface names are removed and the
|
||||
interface version number is reset.
|
||||
</description>
|
||||
|
||||
<interface name="zwlr_data_control_manager_v1" version="2">
|
||||
<description summary="manager to control data devices">
|
||||
This interface is a manager that allows creating per-seat data device
|
||||
controls.
|
||||
</description>
|
||||
|
||||
<request name="create_data_source">
|
||||
<description summary="create a new data source">
|
||||
Create a new data source.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="zwlr_data_control_source_v1"
|
||||
summary="data source to create"/>
|
||||
</request>
|
||||
|
||||
<request name="get_data_device">
|
||||
<description summary="get a data device for a seat">
|
||||
Create a data device that can be used to manage a seat's selection.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="zwlr_data_control_device_v1"/>
|
||||
<arg name="seat" type="object" interface="wl_seat"/>
|
||||
</request>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy the manager">
|
||||
All objects created by the manager will still remain valid, until their
|
||||
appropriate destroy request has been called.
|
||||
</description>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="zwlr_data_control_device_v1" version="2">
|
||||
<description summary="manage a data device for a seat">
|
||||
This interface allows a client to manage a seat's selection.
|
||||
|
||||
When the seat is destroyed, this object becomes inert.
|
||||
</description>
|
||||
|
||||
<request name="set_selection">
|
||||
<description summary="copy data to the selection">
|
||||
This request asks the compositor to set the selection to the data from
|
||||
the source on behalf of the client.
|
||||
|
||||
The given source may not be used in any further set_selection or
|
||||
set_primary_selection requests. Attempting to use a previously used
|
||||
source is a protocol error.
|
||||
|
||||
To unset the selection, set the source to NULL.
|
||||
</description>
|
||||
<arg name="source" type="object" interface="zwlr_data_control_source_v1"
|
||||
allow-null="true"/>
|
||||
</request>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy this data device">
|
||||
Destroys the data device object.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<event name="data_offer">
|
||||
<description summary="introduce a new wlr_data_control_offer">
|
||||
The data_offer event introduces a new wlr_data_control_offer object,
|
||||
which will subsequently be used in either the
|
||||
wlr_data_control_device.selection event (for the regular clipboard
|
||||
selections) or the wlr_data_control_device.primary_selection event (for
|
||||
the primary clipboard selections). Immediately following the
|
||||
wlr_data_control_device.data_offer event, the new data_offer object
|
||||
will send out wlr_data_control_offer.offer events to describe the MIME
|
||||
types it offers.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="zwlr_data_control_offer_v1"/>
|
||||
</event>
|
||||
|
||||
<event name="selection">
|
||||
<description summary="advertise new selection">
|
||||
The selection event is sent out to notify the client of a new
|
||||
wlr_data_control_offer for the selection for this device. The
|
||||
wlr_data_control_device.data_offer and the wlr_data_control_offer.offer
|
||||
events are sent out immediately before this event to introduce the data
|
||||
offer object. The selection event is sent to a client when a new
|
||||
selection is set. The wlr_data_control_offer is valid until a new
|
||||
wlr_data_control_offer or NULL is received. The client must destroy the
|
||||
previous selection wlr_data_control_offer, if any, upon receiving this
|
||||
event.
|
||||
|
||||
The first selection event is sent upon binding the
|
||||
wlr_data_control_device object.
|
||||
</description>
|
||||
<arg name="id" type="object" interface="zwlr_data_control_offer_v1"
|
||||
allow-null="true"/>
|
||||
</event>
|
||||
|
||||
<event name="finished">
|
||||
<description summary="this data control is no longer valid">
|
||||
This data control object is no longer valid and should be destroyed by
|
||||
the client.
|
||||
</description>
|
||||
</event>
|
||||
|
||||
<!-- Version 2 additions -->
|
||||
|
||||
<event name="primary_selection" since="2">
|
||||
<description summary="advertise new primary selection">
|
||||
The primary_selection event is sent out to notify the client of a new
|
||||
wlr_data_control_offer for the primary selection for this device. The
|
||||
wlr_data_control_device.data_offer and the wlr_data_control_offer.offer
|
||||
events are sent out immediately before this event to introduce the data
|
||||
offer object. The primary_selection event is sent to a client when a
|
||||
new primary selection is set. The wlr_data_control_offer is valid until
|
||||
a new wlr_data_control_offer or NULL is received. The client must
|
||||
destroy the previous primary selection wlr_data_control_offer, if any,
|
||||
upon receiving this event.
|
||||
|
||||
If the compositor supports primary selection, the first
|
||||
primary_selection event is sent upon binding the
|
||||
wlr_data_control_device object.
|
||||
</description>
|
||||
<arg name="id" type="object" interface="zwlr_data_control_offer_v1"
|
||||
allow-null="true"/>
|
||||
</event>
|
||||
|
||||
<request name="set_primary_selection" since="2">
|
||||
<description summary="copy data to the primary selection">
|
||||
This request asks the compositor to set the primary selection to the
|
||||
data from the source on behalf of the client.
|
||||
|
||||
The given source may not be used in any further set_selection or
|
||||
set_primary_selection requests. Attempting to use a previously used
|
||||
source is a protocol error.
|
||||
|
||||
To unset the primary selection, set the source to NULL.
|
||||
|
||||
The compositor will ignore this request if it does not support primary
|
||||
selection.
|
||||
</description>
|
||||
<arg name="source" type="object" interface="zwlr_data_control_source_v1"
|
||||
allow-null="true"/>
|
||||
</request>
|
||||
|
||||
<enum name="error" since="2">
|
||||
<entry name="used_source" value="1"
|
||||
summary="source given to set_selection or set_primary_selection was already used before"/>
|
||||
</enum>
|
||||
</interface>
|
||||
|
||||
<interface name="zwlr_data_control_source_v1" version="1">
|
||||
<description summary="offer to transfer data">
|
||||
The wlr_data_control_source object is the source side of a
|
||||
wlr_data_control_offer. It is created by the source client in a data
|
||||
transfer and provides a way to describe the offered data and a way to
|
||||
respond to requests to transfer the data.
|
||||
</description>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="invalid_offer" value="1"
|
||||
summary="offer sent after wlr_data_control_device.set_selection"/>
|
||||
</enum>
|
||||
|
||||
<request name="offer">
|
||||
<description summary="add an offered MIME type">
|
||||
This request adds a MIME type to the set of MIME types advertised to
|
||||
targets. Can be called several times to offer multiple types.
|
||||
|
||||
Calling this after wlr_data_control_device.set_selection is a protocol
|
||||
error.
|
||||
</description>
|
||||
<arg name="mime_type" type="string"
|
||||
summary="MIME type offered by the data source"/>
|
||||
</request>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy this source">
|
||||
Destroys the data source object.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<event name="send">
|
||||
<description summary="send the data">
|
||||
Request for data from the client. Send the data as the specified MIME
|
||||
type over the passed file descriptor, then close it.
|
||||
</description>
|
||||
<arg name="mime_type" type="string" summary="MIME type for the data"/>
|
||||
<arg name="fd" type="fd" summary="file descriptor for the data"/>
|
||||
</event>
|
||||
|
||||
<event name="cancelled">
|
||||
<description summary="selection was cancelled">
|
||||
This data source is no longer valid. The data source has been replaced
|
||||
by another data source.
|
||||
|
||||
The client should clean up and destroy this data source.
|
||||
</description>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="zwlr_data_control_offer_v1" version="1">
|
||||
<description summary="offer to transfer data">
|
||||
A wlr_data_control_offer represents a piece of data offered for transfer
|
||||
by another client (the source client). The offer describes the different
|
||||
MIME types that the data can be converted to and provides the mechanism
|
||||
for transferring the data directly from the source client.
|
||||
</description>
|
||||
|
||||
<request name="receive">
|
||||
<description summary="request that the data is transferred">
|
||||
To transfer the offered data, the client issues this request and
|
||||
indicates the MIME type it wants to receive. The transfer happens
|
||||
through the passed file descriptor (typically created with the pipe
|
||||
system call). The source client writes the data in the MIME type
|
||||
representation requested and then closes the file descriptor.
|
||||
|
||||
The receiving client reads from the read end of the pipe until EOF and
|
||||
then closes its end, at which point the transfer is complete.
|
||||
|
||||
This request may happen multiple times for different MIME types.
|
||||
</description>
|
||||
<arg name="mime_type" type="string"
|
||||
summary="MIME type desired by receiver"/>
|
||||
<arg name="fd" type="fd" summary="file descriptor for data transfer"/>
|
||||
</request>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy this offer">
|
||||
Destroys the data offer object.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<event name="offer">
|
||||
<description summary="advertise offered MIME type">
|
||||
Sent immediately after creating the wlr_data_control_offer object.
|
||||
One event per offered MIME type.
|
||||
</description>
|
||||
<arg name="mime_type" type="string" summary="offered MIME type"/>
|
||||
</event>
|
||||
</interface>
|
||||
</protocol>
|
@ -28,6 +28,7 @@ qt_internal_add_module(WaylandClient
|
||||
qwaylandabstractdecoration.cpp qwaylandabstractdecoration_p.h
|
||||
qwaylandappmenu.cpp qwaylandappmenu_p.h
|
||||
qwaylandbuffer.cpp qwaylandbuffer_p.h
|
||||
qwaylanddatacontrolv1.cpp qwaylanddatacontrolv1_p.h
|
||||
qwaylanddecorationfactory.cpp qwaylanddecorationfactory_p.h
|
||||
qwaylanddecorationplugin.cpp qwaylanddecorationplugin_p.h
|
||||
qwaylanddisplay.cpp qwaylanddisplay_p.h
|
||||
@ -92,6 +93,7 @@ qt_internal_add_module(WaylandClient
|
||||
../3rdparty/protocol/fractional-scale
|
||||
../3rdparty/protocol/viewporter
|
||||
../3rdparty/protocol/xdg-shell
|
||||
../3rdparty/protocol/wlr-data-control
|
||||
)
|
||||
|
||||
qt6_generate_wayland_protocol_client_sources(WaylandClient
|
||||
@ -109,6 +111,7 @@ qt6_generate_wayland_protocol_client_sources(WaylandClient
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/xdg-output/xdg-output-unstable-v1.xml
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/fractional-scale/fractional-scale-v1.xml
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/viewporter/viewporter.xml
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/wlr-data-control/wlr-data-control-unstable-v1.xml
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/xdg-shell/xdg-shell.xml
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/xdg-system-bell/xdg-system-bell-v1.xml
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/xdg-toplevel-drag/xdg-toplevel-drag-v1.xml
|
||||
|
@ -1,9 +1,11 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// Copyright (C) 2024 Jie Liu <liujie01@kylinos.cn>
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#include "qwaylandclipboard_p.h"
|
||||
#include "qwaylanddisplay_p.h"
|
||||
#include "qwaylandinputdevice_p.h"
|
||||
#include "qwaylanddatacontrolv1_p.h"
|
||||
#include "qwaylanddataoffer_p.h"
|
||||
#include "qwaylanddatasource_p.h"
|
||||
#include "qwaylanddatadevice_p.h"
|
||||
@ -37,6 +39,12 @@ QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode)
|
||||
|
||||
switch (mode) {
|
||||
case QClipboard::Clipboard:
|
||||
if (auto *dataControlDevice = seat->dataControlDevice()) {
|
||||
if (dataControlDevice->selectionSource())
|
||||
return m_clientClipboard[QClipboard::Clipboard];
|
||||
if (auto *offer = dataControlDevice->selectionOffer())
|
||||
return offer->mimeData();
|
||||
}
|
||||
if (auto *dataDevice = seat->dataDevice()) {
|
||||
if (dataDevice->selectionSource())
|
||||
return m_clientClipboard[QClipboard::Clipboard];
|
||||
@ -45,6 +53,12 @@ QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode)
|
||||
}
|
||||
return &m_emptyData;
|
||||
case QClipboard::Selection:
|
||||
if (auto *dataControlDevice = seat->dataControlDevice()) {
|
||||
if (dataControlDevice->primarySelectionSource())
|
||||
return m_clientClipboard[QClipboard::Selection];
|
||||
if (auto *offer = dataControlDevice->primarySelectionOffer())
|
||||
return offer->mimeData();
|
||||
}
|
||||
#if QT_CONFIG(wayland_client_primary_selection)
|
||||
if (auto *selectionDevice = seat->primarySelectionDevice()) {
|
||||
if (selectionDevice->selectionSource())
|
||||
@ -84,20 +98,28 @@ void QWaylandClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
|
||||
|
||||
switch (mode) {
|
||||
case QClipboard::Clipboard:
|
||||
if (auto *dataDevice = seat->dataDevice()) {
|
||||
if (auto *dataControlDevice = seat->dataControlDevice()) {
|
||||
dataControlDevice->setSelectionSource(data ? new QWaylandDataControlSourceV1(mDisplay->dataControlManager(),
|
||||
m_clientClipboard[QClipboard::Clipboard]) : nullptr);
|
||||
emitChanged(mode);
|
||||
} else if (auto *dataDevice = seat->dataDevice()) {
|
||||
dataDevice->setSelectionSource(data ? new QWaylandDataSource(mDisplay->dndSelectionHandler(),
|
||||
m_clientClipboard[QClipboard::Clipboard]) : nullptr);
|
||||
emitChanged(mode);
|
||||
}
|
||||
break;
|
||||
case QClipboard::Selection:
|
||||
if (auto *dataControlDevice = seat->dataControlDevice()) {
|
||||
dataControlDevice->setPrimarySelectionSource(data ? new QWaylandDataControlSourceV1(mDisplay->dataControlManager(),
|
||||
m_clientClipboard[QClipboard::Selection]) : nullptr);
|
||||
emitChanged(mode);
|
||||
#if QT_CONFIG(wayland_client_primary_selection)
|
||||
if (auto *selectionDevice = seat->primarySelectionDevice()) {
|
||||
} else if (auto *selectionDevice = seat->primarySelectionDevice()) {
|
||||
selectionDevice->setSelectionSource(data ? new QWaylandPrimarySelectionSourceV1(mDisplay->primarySelectionManager(),
|
||||
m_clientClipboard[QClipboard::Selection]) : nullptr);
|
||||
emitChanged(mode);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -106,12 +128,18 @@ void QWaylandClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
|
||||
|
||||
bool QWaylandClipboard::supportsMode(QClipboard::Mode mode) const
|
||||
{
|
||||
#if QT_CONFIG(wayland_client_primary_selection)
|
||||
if (mode == QClipboard::Selection) {
|
||||
auto *seat = mDisplay->currentInputDevice();
|
||||
return seat && seat->primarySelectionDevice();
|
||||
}
|
||||
if (!seat)
|
||||
return false;
|
||||
if (seat->dataControlDevice())
|
||||
return true;
|
||||
#if QT_CONFIG(wayland_client_primary_selection)
|
||||
if (seat->primarySelectionDevice())
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
return mode == QClipboard::Clipboard;
|
||||
}
|
||||
|
||||
@ -124,8 +152,10 @@ bool QWaylandClipboard::ownsMode(QClipboard::Mode mode) const
|
||||
switch (mode) {
|
||||
case QClipboard::Clipboard:
|
||||
return seat->dataDevice() && seat->dataDevice()->selectionSource() != nullptr;
|
||||
#if QT_CONFIG(wayland_client_primary_selection)
|
||||
case QClipboard::Selection:
|
||||
if (seat->dataControlDevice() && seat->dataControlDevice()->primarySelectionSource() != nullptr)
|
||||
return true;
|
||||
#if QT_CONFIG(wayland_client_primary_selection)
|
||||
return seat->primarySelectionDevice() && seat->primarySelectionDevice()->selectionSource() != nullptr;
|
||||
#endif
|
||||
default:
|
||||
|
161
src/plugins/platforms/wayland/qwaylanddatacontrolv1.cpp
Normal file
161
src/plugins/platforms/wayland/qwaylanddatacontrolv1.cpp
Normal file
@ -0,0 +1,161 @@
|
||||
// Copyright (C) 2024 Jie Liu <liujie01@kylinos.cn>
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#include "qwaylanddatacontrolv1_p.h"
|
||||
#include "qwaylandinputdevice_p.h"
|
||||
#include "qwaylanddisplay_p.h"
|
||||
#include "qwaylandmimehelper_p.h"
|
||||
|
||||
#include <QtGui/private/qguiapplication_p.h>
|
||||
|
||||
#include <qpa/qplatformclipboard.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtWaylandClient {
|
||||
|
||||
QWaylandDataControlManagerV1::QWaylandDataControlManagerV1(QWaylandDisplay *display, uint id, uint version)
|
||||
: zwlr_data_control_manager_v1(display->wl_registry(), id, qMin(version, uint(2)))
|
||||
, m_display(display)
|
||||
{
|
||||
}
|
||||
|
||||
QWaylandDataControlDeviceV1 *QWaylandDataControlManagerV1::createDevice(QWaylandInputDevice *seat)
|
||||
{
|
||||
return new QWaylandDataControlDeviceV1(this, seat);
|
||||
}
|
||||
|
||||
QWaylandDataControlOfferV1::QWaylandDataControlOfferV1(QWaylandDisplay *display, ::zwlr_data_control_offer_v1 *offer)
|
||||
: zwlr_data_control_offer_v1(offer)
|
||||
, m_display(display)
|
||||
, m_mimeData(new QWaylandMimeData(this))
|
||||
{}
|
||||
|
||||
void QWaylandDataControlOfferV1::startReceiving(const QString &mimeType, int fd)
|
||||
{
|
||||
receive(mimeType, fd);
|
||||
wl_display_flush(m_display->wl_display());
|
||||
}
|
||||
|
||||
void QWaylandDataControlOfferV1::zwlr_data_control_offer_v1_offer(const QString &mime_type)
|
||||
{
|
||||
m_mimeData->appendFormat(mime_type);
|
||||
}
|
||||
|
||||
QWaylandDataControlDeviceV1::QWaylandDataControlDeviceV1(
|
||||
QWaylandDataControlManagerV1 *manager, QWaylandInputDevice *seat)
|
||||
: QtWayland::zwlr_data_control_device_v1(manager->get_data_device(seat->wl_seat()))
|
||||
, m_display(manager->display())
|
||||
, m_seat(seat)
|
||||
{
|
||||
}
|
||||
|
||||
QWaylandDataControlDeviceV1::~QWaylandDataControlDeviceV1()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
void QWaylandDataControlDeviceV1::invalidateSelectionOffer()
|
||||
{
|
||||
if (!m_selectionOffer)
|
||||
return;
|
||||
|
||||
m_selectionOffer.reset();
|
||||
QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(QClipboard::Selection);
|
||||
}
|
||||
|
||||
void QWaylandDataControlDeviceV1::setSelectionSource(QWaylandDataControlSourceV1 *source)
|
||||
{
|
||||
if (source) {
|
||||
connect(source, &QWaylandDataControlSourceV1::cancelled, this, [this]() {
|
||||
m_selectionSource.reset();
|
||||
QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(QClipboard::Clipboard);
|
||||
});
|
||||
}
|
||||
set_selection(source ? source->object() : nullptr);
|
||||
m_selectionSource.reset(source);
|
||||
}
|
||||
|
||||
void QWaylandDataControlDeviceV1::setPrimarySelectionSource(QWaylandDataControlSourceV1 *source)
|
||||
{
|
||||
if (source) {
|
||||
connect(source, &QWaylandDataControlSourceV1::cancelled, this, [this]() {
|
||||
m_primarySelectionSource.reset();
|
||||
QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(QClipboard::Selection);
|
||||
});
|
||||
}
|
||||
set_primary_selection(source ? source->object() : nullptr);
|
||||
m_primarySelectionSource.reset(source);
|
||||
}
|
||||
|
||||
void QWaylandDataControlDeviceV1::zwlr_data_control_device_v1_data_offer(zwlr_data_control_offer_v1 *offer)
|
||||
{
|
||||
new QWaylandDataControlOfferV1(m_display, offer);
|
||||
}
|
||||
|
||||
void QWaylandDataControlDeviceV1::zwlr_data_control_device_v1_selection(zwlr_data_control_offer_v1 *id)
|
||||
{
|
||||
if (!id)
|
||||
return;
|
||||
m_selectionOffer.reset(static_cast<QWaylandDataControlOfferV1 *>(zwlr_data_control_offer_v1_get_user_data(id)));
|
||||
|
||||
// The selection event may be sent before platfrmIntegration is set.
|
||||
if (auto* integration = QGuiApplicationPrivate::platformIntegration())
|
||||
integration->clipboard()->emitChanged(QClipboard::Selection);
|
||||
}
|
||||
|
||||
void QWaylandDataControlDeviceV1::zwlr_data_control_device_v1_finished()
|
||||
{
|
||||
m_selectionOffer.reset();
|
||||
m_primarySelectionOffer.reset();
|
||||
QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(QClipboard::Selection);
|
||||
}
|
||||
|
||||
void QWaylandDataControlDeviceV1::zwlr_data_control_device_v1_primary_selection(struct ::zwlr_data_control_offer_v1 *id)
|
||||
{
|
||||
if (!id)
|
||||
return;
|
||||
m_primarySelectionOffer.reset(static_cast<QWaylandDataControlOfferV1 *>(zwlr_data_control_offer_v1_get_user_data(id)));
|
||||
|
||||
// The selection event may be sent before platfrmIntegration is set.
|
||||
if (auto* integration = QGuiApplicationPrivate::platformIntegration())
|
||||
integration->clipboard()->emitChanged(QClipboard::Selection);
|
||||
}
|
||||
|
||||
QWaylandDataControlSourceV1::QWaylandDataControlSourceV1(QWaylandDataControlManagerV1 *manager, QMimeData *mimeData)
|
||||
: QtWayland::zwlr_data_control_source_v1(manager->create_data_source())
|
||||
, m_mimeData(mimeData)
|
||||
{
|
||||
if (!mimeData)
|
||||
return;
|
||||
for (auto &format : mimeData->formats())
|
||||
offer(format);
|
||||
}
|
||||
|
||||
QWaylandDataControlSourceV1::~QWaylandDataControlSourceV1()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
void QWaylandDataControlSourceV1::zwlr_data_control_source_v1_send(const QString &mime_type, int32_t fd)
|
||||
{
|
||||
QByteArray content = QWaylandMimeHelper::getByteArray(m_mimeData, mime_type);
|
||||
if (!content.isEmpty()) {
|
||||
// Create a sigpipe handler that does nothing, or clients may be forced to terminate
|
||||
// if the pipe is closed in the other end.
|
||||
struct sigaction action, oldAction;
|
||||
action.sa_handler = SIG_IGN;
|
||||
sigemptyset (&action.sa_mask);
|
||||
action.sa_flags = 0;
|
||||
|
||||
sigaction(SIGPIPE, &action, &oldAction);
|
||||
ssize_t unused = write(fd, content.constData(), size_t(content.size()));
|
||||
Q_UNUSED(unused);
|
||||
sigaction(SIGPIPE, &oldAction, nullptr);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
} // namespace QtWaylandClient
|
||||
|
||||
QT_END_NAMESPACE
|
119
src/plugins/platforms/wayland/qwaylanddatacontrolv1_p.h
Normal file
119
src/plugins/platforms/wayland/qwaylanddatacontrolv1_p.h
Normal file
@ -0,0 +1,119 @@
|
||||
// Copyright (C) 2024 Jie Liu <liujie01@kylinos.cn>
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#ifndef QWAYLANDDATACONTROLV1_H
|
||||
#define QWAYLANDDATACONTROLV1_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <QtWaylandClient/private/qwayland-wlr-data-control-unstable-v1.h>
|
||||
|
||||
#include <QtWaylandClient/private/qtwaylandclientglobal_p.h>
|
||||
#include <QtWaylandClient/private/qwaylanddataoffer_p.h>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
QT_REQUIRE_CONFIG(clipboard);
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QMimeData;
|
||||
|
||||
namespace QtWaylandClient {
|
||||
|
||||
class QWaylandInputDevice;
|
||||
class QWaylandDataControlDeviceV1;
|
||||
|
||||
class QWaylandDataControlManagerV1 : public QtWayland::zwlr_data_control_manager_v1
|
||||
{
|
||||
public:
|
||||
explicit QWaylandDataControlManagerV1(QWaylandDisplay *display, uint id, uint version);
|
||||
QWaylandDataControlDeviceV1 *createDevice(QWaylandInputDevice *seat);
|
||||
QWaylandDisplay *display() const { return m_display; }
|
||||
|
||||
private:
|
||||
QWaylandDisplay *m_display = nullptr;
|
||||
};
|
||||
|
||||
class QWaylandDataControlOfferV1 : public QtWayland::zwlr_data_control_offer_v1, public QWaylandAbstractDataOffer
|
||||
{
|
||||
public:
|
||||
explicit QWaylandDataControlOfferV1(QWaylandDisplay *display, ::zwlr_data_control_offer_v1 *offer);
|
||||
~QWaylandDataControlOfferV1() override { destroy(); }
|
||||
void startReceiving(const QString &mimeType, int fd) override;
|
||||
QMimeData *mimeData() override { return m_mimeData.data(); }
|
||||
|
||||
protected:
|
||||
void zwlr_data_control_offer_v1_offer(const QString &mime_type) override;
|
||||
|
||||
private:
|
||||
QWaylandDisplay *m_display = nullptr;
|
||||
QScopedPointer<QWaylandMimeData> m_mimeData;
|
||||
};
|
||||
|
||||
class Q_WAYLANDCLIENT_EXPORT QWaylandDataControlSourceV1 : public QObject, public QtWayland::zwlr_data_control_source_v1
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QWaylandDataControlSourceV1(QWaylandDataControlManagerV1 *manager, QMimeData *mimeData);
|
||||
~QWaylandDataControlSourceV1() override;
|
||||
|
||||
QMimeData *mimeData() const { return m_mimeData; }
|
||||
|
||||
Q_SIGNALS:
|
||||
void cancelled();
|
||||
|
||||
protected:
|
||||
void zwlr_data_control_source_v1_send(const QString &mime_type, int32_t fd) override;
|
||||
void zwlr_data_control_source_v1_cancelled() override { Q_EMIT cancelled(); }
|
||||
|
||||
private:
|
||||
QWaylandDisplay *m_display = nullptr;
|
||||
QMimeData *m_mimeData = nullptr;
|
||||
};
|
||||
|
||||
class QWaylandDataControlDeviceV1 : public QObject, public QtWayland::zwlr_data_control_device_v1
|
||||
{
|
||||
Q_OBJECT
|
||||
QWaylandDataControlDeviceV1(QWaylandDataControlManagerV1 *manager, QWaylandInputDevice *seat);
|
||||
|
||||
public:
|
||||
~QWaylandDataControlDeviceV1() override;
|
||||
QWaylandDataControlOfferV1 *primarySelectionOffer() const { return m_primarySelectionOffer.data(); }
|
||||
QWaylandDataControlOfferV1 *selectionOffer() const { return m_selectionOffer.data(); }
|
||||
void invalidateSelectionOffer();
|
||||
QWaylandDataControlSourceV1 *selectionSource() const { return m_selectionSource.data(); }
|
||||
QWaylandDataControlSourceV1 *primarySelectionSource() const { return m_primarySelectionSource.data(); }
|
||||
void setSelectionSource(QWaylandDataControlSourceV1 *source);
|
||||
void setPrimarySelectionSource(QWaylandDataControlSourceV1 *source);
|
||||
|
||||
protected:
|
||||
void zwlr_data_control_device_v1_data_offer(struct ::zwlr_data_control_offer_v1 *id) override;
|
||||
void zwlr_data_control_device_v1_selection(struct ::zwlr_data_control_offer_v1 *id) override;
|
||||
void zwlr_data_control_device_v1_finished() override;
|
||||
void zwlr_data_control_device_v1_primary_selection(struct ::zwlr_data_control_offer_v1 *id) override;
|
||||
|
||||
private:
|
||||
QWaylandDisplay *m_display = nullptr;
|
||||
QWaylandInputDevice *m_seat = nullptr;
|
||||
QScopedPointer<QWaylandDataControlOfferV1> m_selectionOffer;
|
||||
QScopedPointer<QWaylandDataControlOfferV1> m_primarySelectionOffer;
|
||||
QScopedPointer<QWaylandDataControlSourceV1> m_selectionSource;
|
||||
QScopedPointer<QWaylandDataControlSourceV1> m_primarySelectionSource;
|
||||
friend class QWaylandDataControlManagerV1;
|
||||
};
|
||||
|
||||
} // namespace QtWaylandClient
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QWAYLANDDATACONTROLV1_H
|
@ -1,4 +1,5 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// Copyright (C) 2024 Jie Liu <liujie01@kylinos.cn>
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#include "qwaylanddisplay_p.h"
|
||||
@ -13,6 +14,7 @@
|
||||
#include "qwaylandinputdevice_p.h"
|
||||
#if QT_CONFIG(clipboard)
|
||||
#include "qwaylandclipboard_p.h"
|
||||
#include "qwaylanddatacontrolv1_p.h"
|
||||
#endif
|
||||
#if QT_CONFIG(wayland_datadevice)
|
||||
#include "qwaylanddatadevicemanager_p.h"
|
||||
@ -53,6 +55,7 @@
|
||||
#include <QtWaylandClient/private/qwayland-cursor-shape-v1.h>
|
||||
#include <QtWaylandClient/private/qwayland-xdg-system-bell-v1.h>
|
||||
#include <QtWaylandClient/private/qwayland-xdg-toplevel-drag-v1.h>
|
||||
#include <QtWaylandClient/private/qwayland-wlr-data-control-unstable-v1.h>
|
||||
|
||||
#include <QtCore/private/qcore_unix_p.h>
|
||||
|
||||
@ -329,6 +332,7 @@ QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration)
|
||||
}
|
||||
|
||||
mWaylandTryReconnect = qEnvironmentVariableIsSet("QT_WAYLAND_RECONNECT");
|
||||
mPreferWlrDataControl = qEnvironmentVariableIntValue("QT_WAYLAND_USE_DATA_CONTROL") > 0;
|
||||
}
|
||||
|
||||
void QWaylandDisplay::setupConnection()
|
||||
@ -787,6 +791,13 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
|
||||
} else if (
|
||||
interface == QLatin1String(QtWayland::org_kde_kwin_appmenu_manager::interface()->name)) {
|
||||
mGlobals.appMenuManager.reset(new QWaylandAppMenuManager(registry, id, 1));
|
||||
#if QT_CONFIG(clipboard)
|
||||
} else if (mPreferWlrDataControl && interface == QLatin1String(QWaylandDataControlManagerV1::interface()->name)) {
|
||||
mGlobals.dataControlManager.reset(new QWaylandDataControlManagerV1(this, id, 2));
|
||||
for (QWaylandInputDevice *inputDevice : std::as_const(mInputDevices)) {
|
||||
inputDevice->setDataControlDevice(mGlobals.dataControlManager->createDevice(inputDevice));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
mRegistryGlobals.append(RegistryGlobal(id, interface, version, registry));
|
||||
@ -851,6 +862,13 @@ void QWaylandDisplay::registry_global_remove(uint32_t id)
|
||||
for (QWaylandInputDevice *inputDevice : std::as_const(mInputDevices))
|
||||
inputDevice->setPrimarySelectionDevice(nullptr);
|
||||
}
|
||||
#endif
|
||||
#if QT_CONFIG(clipboard)
|
||||
if (global.interface == QLatin1String(QtWayland::zwlr_data_control_manager_v1::interface()->name)) {
|
||||
mGlobals.dataControlManager.reset();
|
||||
for (QWaylandInputDevice *inputDevice : std::as_const(mInputDevices))
|
||||
inputDevice->setDataControlDevice(nullptr);
|
||||
}
|
||||
#endif
|
||||
emit globalRemoved(mRegistryGlobals.takeAt(i));
|
||||
break;
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// Copyright (C) 2024 Jie Liu <liujie01@kylinos.cn>
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#ifndef QWAYLANDDISPLAY_H
|
||||
@ -71,6 +72,9 @@ class QWaylandXdgOutputManagerV1;
|
||||
class QWaylandClientBufferIntegration;
|
||||
class QWaylandWindowManagerIntegration;
|
||||
class QWaylandDataDeviceManager;
|
||||
#if QT_CONFIG(clipboard)
|
||||
class QWaylandDataControlManagerV1;
|
||||
#endif
|
||||
#if QT_CONFIG(wayland_client_primary_selection)
|
||||
class QWaylandPrimarySelectionDeviceManagerV1;
|
||||
#endif
|
||||
@ -148,6 +152,12 @@ public:
|
||||
return mGlobals.dndSelectionHandler.get();
|
||||
}
|
||||
#endif
|
||||
#if QT_CONFIG(clipboard)
|
||||
QWaylandDataControlManagerV1 *dataControlManager() const
|
||||
{
|
||||
return mGlobals.dataControlManager.get();
|
||||
}
|
||||
#endif
|
||||
#if QT_CONFIG(wayland_client_primary_selection)
|
||||
QWaylandPrimarySelectionDeviceManagerV1 *primarySelectionManager() const
|
||||
{
|
||||
@ -334,6 +344,9 @@ private:
|
||||
std::unique_ptr<QWaylandTabletManagerV2> tabletManager;
|
||||
#endif
|
||||
std::unique_ptr<QWaylandPointerGestures> pointerGestures;
|
||||
#if QT_CONFIG(clipboard)
|
||||
std::unique_ptr<QWaylandDataControlManagerV1> dataControlManager;
|
||||
#endif
|
||||
#if QT_CONFIG(wayland_client_primary_selection)
|
||||
std::unique_ptr<QWaylandPrimarySelectionDeviceManagerV1> primarySelectionManager;
|
||||
#endif
|
||||
@ -363,6 +376,7 @@ private:
|
||||
struct wl_callback *mSyncCallback = nullptr;
|
||||
static const wl_callback_listener syncCallbackListener;
|
||||
bool mWaylandTryReconnect = false;
|
||||
bool mPreferWlrDataControl = false;
|
||||
|
||||
bool mWaylandInputContextRequested = [] () {
|
||||
const auto requested = QPlatformInputContextFactory::requested();
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// Copyright (C) 2024 Jie Liu <liujie01@kylinos.cn>
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#include "qwaylandinputdevice_p.h"
|
||||
@ -12,6 +13,9 @@
|
||||
#include "qwaylanddatadevice_p.h"
|
||||
#include "qwaylanddatadevicemanager_p.h"
|
||||
#endif
|
||||
#if QT_CONFIG(clipboard)
|
||||
#include "qwaylanddatacontrolv1_p.h"
|
||||
#endif
|
||||
#if QT_CONFIG(wayland_client_primary_selection)
|
||||
#include "qwaylandprimaryselectionv1_p.h"
|
||||
#endif
|
||||
@ -316,6 +320,13 @@ QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version,
|
||||
, mDisplay(display->wl_display())
|
||||
, mId(id)
|
||||
{
|
||||
|
||||
#if QT_CONFIG(clipboard)
|
||||
if (auto *dataControlManager = mQDisplay->dataControlManager()) {
|
||||
setDataControlDevice(dataControlManager->createDevice(this));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if QT_CONFIG(wayland_datadevice)
|
||||
if (mQDisplay->dndSelectionHandler()) {
|
||||
mDataDevice = mQDisplay->dndSelectionHandler()->getDataDevice(this);
|
||||
@ -485,6 +496,18 @@ QWaylandDataDevice *QWaylandInputDevice::dataDevice() const
|
||||
}
|
||||
#endif
|
||||
|
||||
#if QT_CONFIG(clipboard)
|
||||
void QWaylandInputDevice::setDataControlDevice(QWaylandDataControlDeviceV1 *dataControlDevice)
|
||||
{
|
||||
mDataControlDevice.reset(dataControlDevice);
|
||||
}
|
||||
|
||||
QWaylandDataControlDeviceV1 *QWaylandInputDevice::dataControlDevice() const
|
||||
{
|
||||
return mDataControlDevice.data();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if QT_CONFIG(wayland_client_primary_selection)
|
||||
void QWaylandInputDevice::setPrimarySelectionDevice(QWaylandPrimarySelectionDeviceV1 *primarySelectionDevice)
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// Copyright (C) 2024 Jie Liu <liujie01@kylinos.cn>
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#ifndef QWAYLANDINPUTDEVICE_H
|
||||
@ -51,6 +52,9 @@ namespace QtWaylandClient {
|
||||
|
||||
class QWaylandDataDevice;
|
||||
class QWaylandDisplay;
|
||||
#if QT_CONFIG(clipboard)
|
||||
class QWaylandDataControlDeviceV1;
|
||||
#endif
|
||||
#if QT_CONFIG(wayland_client_primary_selection)
|
||||
class QWaylandPrimarySelectionDeviceV1;
|
||||
#endif
|
||||
@ -102,6 +106,11 @@ public:
|
||||
QWaylandDataDevice *dataDevice() const;
|
||||
#endif
|
||||
|
||||
#if QT_CONFIG(clipboard)
|
||||
void setDataControlDevice(QWaylandDataControlDeviceV1 *dataControlDevice);
|
||||
QWaylandDataControlDeviceV1 *dataControlDevice() const;
|
||||
#endif
|
||||
|
||||
#if QT_CONFIG(wayland_client_primary_selection)
|
||||
void setPrimarySelectionDevice(QWaylandPrimarySelectionDeviceV1 *primarySelectionDevice);
|
||||
QWaylandPrimarySelectionDeviceV1 *primarySelectionDevice() const;
|
||||
@ -166,6 +175,10 @@ protected:
|
||||
QWaylandDataDevice *mDataDevice = nullptr;
|
||||
#endif
|
||||
|
||||
#if QT_CONFIG(clipboard)
|
||||
QScopedPointer<QWaylandDataControlDeviceV1> mDataControlDevice;
|
||||
#endif
|
||||
|
||||
#if QT_CONFIG(wayland_client_primary_selection)
|
||||
QScopedPointer<QWaylandPrimarySelectionDeviceV1> mPrimarySelectionDevice;
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user