summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/xcb/qxcbclipboard.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbclipboard.cpp')
-rw-r--r--src/plugins/platforms/xcb/qxcbclipboard.cpp173
1 files changed, 71 insertions, 102 deletions
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp
index 6d023035f2..40e2f47354 100644
--- a/src/plugins/platforms/xcb/qxcbclipboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbclipboard.h"
@@ -67,11 +31,11 @@ public:
break;
case QClipboard::Clipboard:
- modeAtom = m_clipboard->atom(QXcbAtom::CLIPBOARD);
+ modeAtom = m_clipboard->atom(QXcbAtom::AtomCLIPBOARD);
break;
default:
- qWarning("QXcbClipboardMime: Internal error: Unsupported clipboard mode");
+ qCWarning(lcQpaClipboard, "QXcbClipboardMime: Internal error: Unsupported clipboard mode");
break;
}
}
@@ -83,7 +47,7 @@ public:
bool isEmpty() const
{
- return m_clipboard->getSelectionOwner(modeAtom) == XCB_NONE;
+ return m_clipboard->connection()->selectionOwner(modeAtom) == XCB_NONE;
}
protected:
@@ -92,12 +56,12 @@ protected:
if (isEmpty())
return QStringList();
- if (!formatList.count()) {
+ if (!formatList.size()) {
QXcbClipboardMime *that = const_cast<QXcbClipboardMime *>(this);
// get the list of targets from the current clipboard owner - we do this
// once so that multiple calls to this function don't require multiple
// server round trips...
- that->format_atoms = m_clipboard->getDataInFormat(modeAtom, m_clipboard->atom(QXcbAtom::TARGETS));
+ that->format_atoms = m_clipboard->getDataInFormat(modeAtom, m_clipboard->atom(QXcbAtom::AtomTARGETS));
if (format_atoms.size() > 0) {
const xcb_atom_t *targets = (const xcb_atom_t *) format_atoms.data();
@@ -123,9 +87,9 @@ protected:
return list.contains(format);
}
- QVariant retrieveData_sys(const QString &fmt, QVariant::Type type) const override
+ QVariant retrieveData_sys(const QString &fmt, QMetaType type) const override
{
- auto requestedType = QMetaType::Type(type);
+ auto requestedType = type;
if (fmt.isEmpty() || isEmpty())
return QByteArray();
@@ -162,7 +126,7 @@ QXcbClipboardTransaction::QXcbClipboardTransaction(QXcbClipboard *clipboard, xcb
xcb_change_window_attributes(m_clipboard->xcb_connection(), m_window,
XCB_CW_EVENT_MASK, values);
- m_abortTimerId = startTimer(m_clipboard->clipboardTimeout());
+ m_abortTimerId = startTimer(std::chrono::milliseconds{m_clipboard->clipboardTimeout()});
}
QXcbClipboardTransaction::~QXcbClipboardTransaction()
@@ -181,7 +145,7 @@ bool QXcbClipboardTransaction::updateIncrementalProperty(const xcb_property_noti
// restart the timer
if (m_abortTimerId)
killTimer(m_abortTimerId);
- m_abortTimerId = startTimer(m_clipboard->clipboardTimeout());
+ m_abortTimerId = startTimer(std::chrono::milliseconds{m_clipboard->clipboardTimeout()});
uint bytes_left = uint(m_data.size()) - m_offset;
if (bytes_left > 0) {
@@ -231,14 +195,15 @@ QXcbClipboard::QXcbClipboard(QXcbConnection *c)
m_clientClipboard[QClipboard::Selection] = nullptr;
m_timestamp[QClipboard::Clipboard] = XCB_CURRENT_TIME;
m_timestamp[QClipboard::Selection] = XCB_CURRENT_TIME;
- m_owner = connection()->getQtSelectionOwner();
if (connection()->hasXFixes()) {
const uint32_t mask = XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE;
- xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, XCB_ATOM_PRIMARY, mask);
- xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, atom(QXcbAtom::CLIPBOARD), mask);
+ xcb_xfixes_select_selection_input_checked(xcb_connection(), connection()->qtSelectionOwner(),
+ XCB_ATOM_PRIMARY, mask);
+ xcb_xfixes_select_selection_input_checked(xcb_connection(), connection()->qtSelectionOwner(),
+ atom(QXcbAtom::AtomCLIPBOARD), mask);
}
// xcb_change_property_request_t and xcb_get_property_request_t are the same size
@@ -253,19 +218,21 @@ QXcbClipboard::~QXcbClipboard()
m_timestamp[QClipboard::Selection] != XCB_CURRENT_TIME) {
// First we check if there is a clipboard manager.
- auto reply = Q_XCB_REPLY(xcb_get_selection_owner, xcb_connection(), atom(QXcbAtom::CLIPBOARD_MANAGER));
- if (reply && reply->owner != XCB_NONE) {
+ if (connection()->selectionOwner(atom(QXcbAtom::AtomCLIPBOARD_MANAGER)) != XCB_NONE) {
// we delete the property so the manager saves all TARGETS.
- xcb_delete_property(xcb_connection(), m_owner, atom(QXcbAtom::_QT_SELECTION));
- xcb_convert_selection(xcb_connection(), m_owner, atom(QXcbAtom::CLIPBOARD_MANAGER), atom(QXcbAtom::SAVE_TARGETS),
- atom(QXcbAtom::_QT_SELECTION), connection()->time());
+ xcb_delete_property(xcb_connection(), connection()->qtSelectionOwner(),
+ atom(QXcbAtom::Atom_QT_SELECTION));
+ xcb_convert_selection(xcb_connection(), connection()->qtSelectionOwner(),
+ atom(QXcbAtom::AtomCLIPBOARD_MANAGER), atom(QXcbAtom::AtomSAVE_TARGETS),
+ atom(QXcbAtom::Atom_QT_SELECTION), connection()->time());
connection()->sync();
// waiting until the clipboard manager fetches the content.
- if (auto event = waitForClipboardEvent(m_owner, XCB_SELECTION_NOTIFY, true)) {
+ if (auto event = waitForClipboardEvent(connection()->qtSelectionOwner(),
+ XCB_SELECTION_NOTIFY, true)) {
free(event);
} else {
- qWarning("QXcbClipboard: Unable to receive an event from the "
+ qCWarning(lcQpaClipboard, "QXcbClipboard: Unable to receive an event from the "
"clipboard manager in a reasonable time");
}
}
@@ -289,15 +256,10 @@ bool QXcbClipboard::handlePropertyNotify(const xcb_generic_event_t *event)
return (*it)->updateIncrementalProperty(propertyNotify);
}
-xcb_window_t QXcbClipboard::getSelectionOwner(xcb_atom_t atom) const
-{
- return connection()->getSelectionOwner(atom);
-}
-
xcb_atom_t QXcbClipboard::atomForMode(QClipboard::Mode mode) const
{
if (mode == QClipboard::Clipboard)
- return atom(QXcbAtom::CLIPBOARD);
+ return atom(QXcbAtom::AtomCLIPBOARD);
if (mode == QClipboard::Selection)
return XCB_ATOM_PRIMARY;
return XCB_NONE;
@@ -307,7 +269,7 @@ QClipboard::Mode QXcbClipboard::modeForAtom(xcb_atom_t a) const
{
if (a == XCB_ATOM_PRIMARY)
return QClipboard::Selection;
- if (a == atom(QXcbAtom::CLIPBOARD))
+ if (a == atom(QXcbAtom::AtomCLIPBOARD))
return QClipboard::Clipboard;
// not supported enum value, used to detect errors
return QClipboard::FindBuffer;
@@ -319,8 +281,8 @@ QMimeData * QXcbClipboard::mimeData(QClipboard::Mode mode)
if (mode > QClipboard::Selection)
return nullptr;
- xcb_window_t clipboardOwner = getSelectionOwner(atomForMode(mode));
- if (clipboardOwner == owner()) {
+ xcb_window_t clipboardOwner = connection()->selectionOwner(atomForMode(mode));
+ if (clipboardOwner == connection()->qtSelectionOwner()) {
return m_clientClipboard[mode];
} else {
if (!m_xClipboard[mode])
@@ -362,7 +324,7 @@ void QXcbClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
connection()->setTime(connection()->getTimestamp());
if (data) {
- newOwner = owner();
+ newOwner = connection()->qtSelectionOwner();
m_clientClipboard[mode] = data;
m_timestamp[mode] = connection()->time();
@@ -370,8 +332,8 @@ void QXcbClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
xcb_set_selection_owner(xcb_connection(), newOwner, modeAtom, connection()->time());
- if (getSelectionOwner(modeAtom) != newOwner) {
- qWarning("QXcbClipboard::setMimeData: Cannot set X11 selection owner");
+ if (connection()->selectionOwner(modeAtom) != newOwner) {
+ qCWarning(lcQpaClipboard, "QXcbClipboard::setMimeData: Cannot set X11 selection owner");
}
emitChanged(mode);
@@ -386,10 +348,11 @@ bool QXcbClipboard::supportsMode(QClipboard::Mode mode) const
bool QXcbClipboard::ownsMode(QClipboard::Mode mode) const
{
- if (m_owner == XCB_NONE || mode > QClipboard::Selection)
+ if (connection()->qtSelectionOwner() == XCB_NONE || mode > QClipboard::Selection)
return false;
- Q_ASSERT(m_timestamp[mode] == XCB_CURRENT_TIME || getSelectionOwner(atomForMode(mode)) == m_owner);
+ Q_ASSERT(m_timestamp[mode] == XCB_CURRENT_TIME
+ || connection()->selectionOwner(atomForMode(mode)) == connection()->qtSelectionOwner());
return m_timestamp[mode] != XCB_CURRENT_TIME;
}
@@ -438,11 +401,6 @@ void QXcbClipboard::setRequestor(xcb_window_t window)
m_requestor = window;
}
-xcb_window_t QXcbClipboard::owner() const
-{
- return m_owner;
-}
-
xcb_atom_t QXcbClipboard::sendTargetsSelection(QMimeData *d, xcb_window_t window, xcb_atom_t property)
{
QList<xcb_atom_t> types;
@@ -454,10 +412,10 @@ xcb_atom_t QXcbClipboard::sendTargetsSelection(QMimeData *d, xcb_window_t window
types.append(atoms.at(j));
}
}
- types.append(atom(QXcbAtom::TARGETS));
- types.append(atom(QXcbAtom::MULTIPLE));
- types.append(atom(QXcbAtom::TIMESTAMP));
- types.append(atom(QXcbAtom::SAVE_TARGETS));
+ types.append(atom(QXcbAtom::AtomTARGETS));
+ types.append(atom(QXcbAtom::AtomMULTIPLE));
+ types.append(atom(QXcbAtom::AtomTIMESTAMP));
+ types.append(atom(QXcbAtom::AtomSAVE_TARGETS));
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property, XCB_ATOM_ATOM,
32, types.size(), (const void *)types.constData());
@@ -481,7 +439,7 @@ xcb_atom_t QXcbClipboard::sendSelection(QMimeData *d, xcb_atom_t target, xcb_win
// don't allow INCR transfers when using MULTIPLE or to
// Motif clients (since Motif doesn't support INCR)
- static xcb_atom_t motif_clip_temporary = atom(QXcbAtom::CLIP_TEMPORARY);
+ static xcb_atom_t motif_clip_temporary = atom(QXcbAtom::AtomCLIP_TEMPORARY);
bool allow_incr = property != motif_clip_temporary;
// This 'bool' can be removed once there is a proper fix for QTBUG-32853
if (m_clipboard_closing)
@@ -490,7 +448,7 @@ xcb_atom_t QXcbClipboard::sendSelection(QMimeData *d, xcb_atom_t target, xcb_win
if (data.size() > m_maxPropertyRequestDataBytes && allow_incr) {
long bytes = data.size();
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property,
- atom(QXcbAtom::INCR), 32, 1, (const void *)&bytes);
+ atom(QXcbAtom::AtomINCR), 32, 1, (const void *)&bytes);
auto transaction = new QXcbClipboardTransaction(this, window, property, data, atomFormat, dataFormat);
m_transactions.insert(window, transaction);
return property;
@@ -521,7 +479,7 @@ void QXcbClipboard::handleSelectionClearRequest(xcb_selection_clear_event_t *eve
// XGetSelectionOwner(dpy, XA_PRIMARY),
// xevent->xselectionclear.time, d->timestamp);
- xcb_window_t newOwner = getSelectionOwner(event->selection);
+ xcb_window_t newOwner = connection()->selectionOwner(event->selection);
/* If selection ownership was given up voluntarily from QClipboard::clear(), then we do nothing here
since its already handled in setMimeData. Otherwise, the event must have come from another client
@@ -538,7 +496,7 @@ void QXcbClipboard::handleSelectionClearRequest(xcb_selection_clear_event_t *eve
void QXcbClipboard::handleSelectionRequest(xcb_selection_request_event_t *req)
{
if (requestor() && req->requestor == requestor()) {
- qWarning("QXcbClipboard: Selection request should be caught before");
+ qCWarning(lcQpaClipboard, "QXcbClipboard: Selection request should be caught before");
return;
}
@@ -553,7 +511,8 @@ void QXcbClipboard::handleSelectionRequest(xcb_selection_request_event_t *req)
QMimeData *d;
QClipboard::Mode mode = modeForAtom(req->selection);
if (mode > QClipboard::Selection) {
- qWarning() << "QXcbClipboard: Unknown selection" << connection()->atomName(req->selection);
+ qCWarning(lcQpaClipboard, "QXcbClipboard: Unknown selection %s",
+ connection()->atomName(req->selection).constData());
xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event);
return;
}
@@ -561,21 +520,21 @@ void QXcbClipboard::handleSelectionRequest(xcb_selection_request_event_t *req)
d = m_clientClipboard[mode];
if (!d) {
- qWarning("QXcbClipboard: Cannot transfer data, no data available");
+ qCWarning(lcQpaClipboard, "QXcbClipboard: Cannot transfer data, no data available");
xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event);
return;
}
if (m_timestamp[mode] == XCB_CURRENT_TIME // we don't own the selection anymore
|| (req->time != XCB_CURRENT_TIME && req->time < m_timestamp[mode])) {
- qWarning("QXcbClipboard: SelectionRequest too old");
+ qCDebug(lcQpaClipboard, "QXcbClipboard: SelectionRequest too old");
xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event);
return;
}
- xcb_atom_t targetsAtom = atom(QXcbAtom::TARGETS);
- xcb_atom_t multipleAtom = atom(QXcbAtom::MULTIPLE);
- xcb_atom_t timestampAtom = atom(QXcbAtom::TIMESTAMP);
+ xcb_atom_t targetsAtom = atom(QXcbAtom::AtomTARGETS);
+ xcb_atom_t multipleAtom = atom(QXcbAtom::AtomMULTIPLE);
+ xcb_atom_t timestampAtom = atom(QXcbAtom::AtomTIMESTAMP);
struct AtomPair { xcb_atom_t target; xcb_atom_t property; } *multi = nullptr;
xcb_atom_t multi_type = XCB_NONE;
@@ -623,7 +582,7 @@ void QXcbClipboard::handleSelectionRequest(xcb_selection_request_event_t *req)
property, XCB_ATOM_INTEGER, 32, 1, &m_timestamp[mode]);
ret = property;
} else {
- qWarning("QXcbClipboard: Invalid data timestamp");
+ qCWarning(lcQpaClipboard, "QXcbClipboard: Invalid data timestamp");
}
} else if (target == targetsAtom) {
ret = sendTargetsSelection(d, req->requestor, property);
@@ -667,7 +626,7 @@ void QXcbClipboard::handleXFixesSelectionRequest(xcb_xfixes_selection_notify_eve
// Note1: Here we care only about the xfixes events that come from other processes.
// Note2: If the QClipboard::clear() is issued, event->owner is XCB_NONE,
// so we check selection_timestamp to not handle our own QClipboard::clear().
- if (event->owner != owner() && event->selection_timestamp > m_timestamp[mode]) {
+ if (event->owner != connection()->qtSelectionOwner() && event->selection_timestamp > m_timestamp[mode]) {
if (!m_xClipboard[mode]) {
m_xClipboard[mode].reset(new QXcbClipboardMime(mode, this));
} else {
@@ -728,7 +687,7 @@ bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property,
// recover -- this shouldn't normally happen, but it doesn't
// hurt to be defensive
if ((int)(buffer_offset + length) > buffer->size()) {
- qWarning("QXcbClipboard: buffer overflow");
+ qCWarning(lcQpaClipboard, "QXcbClipboard: buffer overflow");
length = buffer->size() - buffer_offset;
// escape loop
@@ -749,7 +708,7 @@ bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property,
// correct size, not 0-term.
if (size)
*size = buffer_offset;
- if (*type == atom(QXcbAtom::INCR))
+ if (*type == atom(QXcbAtom::AtomINCR))
m_incr_receive_time = connection()->getTimestamp();
if (deleteProperty)
xcb_delete_property(xcb_connection(), win, property);
@@ -781,14 +740,19 @@ xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t window, i
if (e) // found the waited for event
return e;
+ // It is safe to assume here that the pointed to node won't be re-used
+ // while we are holding the pointer to it. The nodes can be recycled
+ // only when they are dequeued, which is done only by
+ // QXcbConnection::processXcbEvents().
+ const QXcbEventNode *flushedTailNode = queue->flushedTail();
+
if (checkManager) {
- auto reply = Q_XCB_REPLY(xcb_get_selection_owner, xcb_connection(), atom(QXcbAtom::CLIPBOARD_MANAGER));
- if (!reply || reply->owner == XCB_NONE)
+ if (connection()->selectionOwner(atom(QXcbAtom::AtomCLIPBOARD_MANAGER)) == XCB_NONE)
return nullptr;
}
// process other clipboard events, since someone is probably requesting data from us
- auto clipboardAtom = atom(QXcbAtom::CLIPBOARD);
+ auto clipboardAtom = atom(QXcbAtom::AtomCLIPBOARD);
e = queue->peek([clipboardAtom](xcb_generic_event_t *event, int type) {
xcb_atom_t selection = XCB_ATOM_NONE;
if (type == XCB_SELECTION_REQUEST)
@@ -806,7 +770,7 @@ xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t window, i
const auto elapsed = timer.elapsed();
if (elapsed < clipboard_timeout)
- queue->waitForNewEvents(clipboard_timeout - elapsed);
+ queue->waitForNewEvents(flushedTailNode, clipboard_timeout - elapsed);
} while (timer.elapsed() < clipboard_timeout);
return nullptr;
@@ -829,6 +793,8 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb
alloc_error = buf.size() != nbytes+1;
}
+ QElapsedTimer timer;
+ timer.start();
for (;;) {
connection()->flush();
xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_PROPERTY_NOTIFY);
@@ -864,9 +830,11 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb
tmp_buf.resize(0);
offset += length;
}
- } else {
- break;
}
+
+ const auto elapsed = timer.elapsed();
+ if (elapsed > clipboard_timeout)
+ break;
}
// timed out ... create a new requestor window, otherwise the requestor
@@ -878,7 +846,7 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb
QByteArray QXcbClipboard::getDataInFormat(xcb_atom_t modeAtom, xcb_atom_t fmtAtom)
{
- return getSelection(modeAtom, fmtAtom, atom(QXcbAtom::_QT_SELECTION));
+ return getSelection(modeAtom, fmtAtom, atom(QXcbAtom::Atom_QT_SELECTION));
}
QByteArray QXcbClipboard::getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t time)
@@ -902,7 +870,7 @@ QByteArray QXcbClipboard::getSelection(xcb_atom_t selection, xcb_atom_t target,
xcb_atom_t type;
if (clipboardReadProperty(win, property, true, &buf, nullptr, &type, nullptr)) {
- if (type == atom(QXcbAtom::INCR)) {
+ if (type == atom(QXcbAtom::AtomINCR)) {
int nbytes = buf.size() >= 4 ? *((int*)buf.data()) : 0;
buf = clipboardReadIncrementalProperty(win, property, nbytes, false);
}
@@ -915,4 +883,5 @@ QByteArray QXcbClipboard::getSelection(xcb_atom_t selection, xcb_atom_t target,
QT_END_NAMESPACE
+#include "moc_qxcbclipboard.cpp"
#include "qxcbclipboard.moc"