11#include <private/qguiapplication_p.h>
12#include <QElapsedTimer>
14#include <QtCore/QDebug>
18#ifndef QT_NO_CLIPBOARD
26 , m_clipboard(clipboard)
30 modeAtom = XCB_ATOM_PRIMARY;
38 qCWarning(lcQpaClipboard,
"QXcbClipboardMime: Internal error: Unsupported clipboard mode");
59 if (!formatList.size()) {
66 if (format_atoms.
size() > 0) {
67 const xcb_atom_t *targets = (
const xcb_atom_t *) format_atoms.
data();
68 int size = format_atoms.
size() /
sizeof(xcb_atom_t);
70 for (
int i = 0;
i <
size; ++
i) {
75 if (!formatList.contains(
format))
76 that->formatList.append(
format);
92 auto requestedType =
type;
99 const xcb_atom_t *targets = (
const xcb_atom_t *) format_atoms.
data();
100 int size = format_atoms.
size() /
sizeof(xcb_atom_t);
105 bool hasUtf8 =
false;
123 : m_clipboard(clipboard), m_window(
w), m_property(
p),
m_data(
d), m_target(
t), m_format(
f)
126 xcb_change_window_attributes(m_clipboard->
xcb_connection(), m_window,
127 XCB_CW_EVENT_MASK,
values);
142 if (
event->atom != m_property ||
event->state != XCB_PROPERTY_DELETE)
151 if (bytes_left > 0) {
155 qCDebug(lcQpaClipboard,
"sending %d bytes, %d remaining, transaction: %p)",
156 bytes_to_send, bytes_left - bytes_to_send,
this);
158 uint32_t
dataSize = bytes_to_send / (m_format / 8);
159 xcb_change_property(m_clipboard->
xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
161 m_offset += bytes_to_send;
163 qCDebug(lcQpaClipboard,
"transaction %p completed",
this);
165 xcb_change_property(m_clipboard->
xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
166 m_property, m_target, m_format, 0,
nullptr);
169 xcb_change_window_attributes(m_clipboard->
xcb_connection(), m_window,
170 XCB_CW_EVENT_MASK,
values);
179 if (ev->
timerId() == m_abortTimerId) {
182 qCDebug(lcQpaClipboard,
"timed out while sending data to %p",
this);
187const int QXcbClipboard::clipboard_timeout = 5000;
200 const uint32_t
mask = XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
201 XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
202 XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE;
204 XCB_ATOM_PRIMARY,
mask);
215 m_clipboard_closing =
true;
231 if (
auto event = waitForClipboardEvent(
connection()->qtSelectionOwner(),
232 XCB_SELECTION_NOTIFY,
true)) {
235 qCWarning(lcQpaClipboard,
"QXcbClipboard: Unable to receive an event from the "
236 "clipboard manager in a reasonable time");
248 if (m_transactions.
isEmpty() ||
event->response_type != XCB_PROPERTY_NOTIFY)
251 auto propertyNotify =
reinterpret_cast<const xcb_property_notify_event_t *
>(
event);
256 return (*it)->updateIncrementalProperty(propertyNotify);
264 return XCB_ATOM_PRIMARY;
270 if (
a == XCB_ATOM_PRIMARY)
285 if (clipboardOwner ==
connection()->qtSelectionOwner()) {
286 return m_clientClipboard[
mode];
288 if (!m_xClipboard[
mode])
303 xClipboard = qobject_cast<QXcbClipboardMime *>(
mimeData(
mode));
310 if (!xClipboard && (m_clientClipboard[
mode] ==
data))
313 xcb_atom_t modeAtom = atomForMode(
mode);
314 xcb_window_t newOwner = XCB_NONE;
316 if (m_clientClipboard[
mode]) {
318 delete m_clientClipboard[
mode];
319 m_clientClipboard[
mode] =
nullptr;
320 m_timestamp[
mode] = XCB_CURRENT_TIME;
335 if (
connection()->selectionOwner(modeAtom) != newOwner) {
336 qCWarning(lcQpaClipboard,
"QXcbClipboard::setMimeData: Cannot set X11 selection owner");
357 return m_timestamp[
mode] != XCB_CURRENT_TIME;
369 if (!m_requestor && platformScreen) {
370 const int x = 0,
y = 0,
w = 3,
h = 3;
375 XCB_COPY_FROM_PARENT,
377 platformScreen->
screen()->root,
380 XCB_WINDOW_CLASS_INPUT_OUTPUT,
381 platformScreen->
screen()->root_visual,
388 uint32_t
mask = XCB_EVENT_MASK_PROPERTY_CHANGE;
398 if (m_requestor != XCB_NONE) {
410 for (
int j = 0;
j < atoms.
size(); ++
j) {
421 32,
types.size(), (
const void *)
types.constData());
427 xcb_atom_t atomFormat =
target;
443 bool allow_incr =
property != motif_clip_temporary;
445 if (m_clipboard_closing)
448 if (
data.size() > m_maxPropertyRequestDataBytes && allow_incr) {
449 long bytes =
data.size();
458 if (
data.size() > m_maxPropertyRequestDataBytes)
475 if (m_timestamp[
mode] != XCB_CURRENT_TIME &&
event->time <= m_timestamp[
mode])
488 if (newOwner != XCB_NONE) {
490 delete m_clientClipboard[
mode];
491 m_clientClipboard[
mode] =
nullptr;
492 m_timestamp[
mode] = XCB_CURRENT_TIME;
499 qCWarning(lcQpaClipboard,
"QXcbClipboard: Selection request should be caught before");
504 event.response_type = XCB_SELECTION_NOTIFY;
505 event.requestor = req->requestor;
506 event.selection = req->selection;
507 event.target = req->target;
508 event.property = XCB_NONE;
509 event.time = req->time;
514 qCWarning(lcQpaClipboard,
"QXcbClipboard: Unknown selection %s",
515 connection()->atomName(req->selection).constData());
516 xcb_send_event(
xcb_connection(),
false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (
const char *)&
event);
520 d = m_clientClipboard[
mode];
523 qCWarning(lcQpaClipboard,
"QXcbClipboard: Cannot transfer data, no data available");
524 xcb_send_event(
xcb_connection(),
false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (
const char *)&
event);
528 if (m_timestamp[
mode] == XCB_CURRENT_TIME
529 || (req->time != XCB_CURRENT_TIME && req->time < m_timestamp[
mode])) {
530 qCDebug(lcQpaClipboard,
"QXcbClipboard: SelectionRequest too old");
531 xcb_send_event(
xcb_connection(),
false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (
const char *)&
event);
539 struct AtomPair { xcb_atom_t
target; xcb_atom_t
property; } *multi =
nullptr;
540 xcb_atom_t multi_type = XCB_NONE;
541 int multi_format = 0;
544 bool multi_writeback =
false;
546 if (req->target == multipleAtom) {
548 if (req->property == XCB_NONE
550 nullptr, &multi_type, &multi_format)
551 || multi_format != 32) {
553 xcb_send_event(
xcb_connection(),
false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (
const char *)&
event);
556 nmulti = multi_data.
size()/
sizeof(*multi);
557 multi =
new AtomPair[nmulti];
558 memcpy(multi,multi_data.
data(),multi_data.
size());
562 for (; imulti < nmulti; ++imulti) {
567 target = multi[imulti].target;
568 property = multi[imulti].property;
571 property = req->property;
576 xcb_atom_t
ret = XCB_NONE;
579 }
else if (
target == timestampAtom) {
580 if (m_timestamp[
mode] != XCB_CURRENT_TIME) {
581 xcb_change_property(
xcb_connection(), XCB_PROP_MODE_REPLACE, req->requestor,
585 qCWarning(lcQpaClipboard,
"QXcbClipboard: Invalid data timestamp");
587 }
else if (
target == targetsAtom) {
588 ret = sendTargetsSelection(
d, req->requestor,
property);
594 if (
ret == XCB_NONE) {
595 multi[imulti].property = XCB_NONE;
596 multi_writeback =
true;
599 event.property =
ret;
605 if (multi_writeback) {
608 xcb_change_property(
xcb_connection(), XCB_PROP_MODE_REPLACE, req->requestor, req->property,
609 multi_type, 32, nmulti*2, (
const void *)multi);
613 event.property = req->property;
617 xcb_send_event(
xcb_connection(),
false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (
const char *)&
event);
630 if (!m_xClipboard[
mode]) {
636 }
else if (
event->subtype == XCB_XFIXES_SELECTION_EVENT_SELECTION_CLIENT_CLOSE ||
637 event->subtype == XCB_XFIXES_SELECTION_EVENT_SELECTION_WINDOW_DESTROY)
643 xcb_atom_t dummy_type;
660 auto bytes_left =
reply->bytes_after;
662 int offset = 0, buffer_offset = 0;
664 int newSize = bytes_left;
667 bool ok = (
buffer->size() == newSize);
676 XCB_GET_PROPERTY_TYPE_ANY,
offset, m_maxPropertyRequestDataBytes / 4);
682 bytes_left =
reply->bytes_after;
683 char *
data = (
char *)xcb_get_property_value(
reply.get());
684 int length = xcb_get_property_value_length(
reply.get());
690 qCWarning(lcQpaClipboard,
"QXcbClipboard: buffer overflow");
710 *
size = buffer_offset;
721xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t
window,
int type,
bool checkManager)
728 if (eventType !=
type)
730 if (eventType == XCB_PROPERTY_NOTIFY) {
731 auto propertyNotify =
reinterpret_cast<xcb_property_notify_event_t *
>(
event);
732 return propertyNotify->window ==
window;
734 if (eventType == XCB_SELECTION_NOTIFY) {
735 auto selectionNotify =
reinterpret_cast<xcb_selection_notify_event_t *
>(
event);
736 return selectionNotify->requestor ==
window;
756 e =
queue->peek([clipboardAtom](xcb_generic_event_t *
event,
int type) {
758 if (
type == XCB_SELECTION_REQUEST)
760 else if (
type == XCB_SELECTION_CLEAR)
772 if (
elapsed < clipboard_timeout)
773 queue->waitForNewEvents(flushedTailNode, clipboard_timeout -
elapsed);
774 }
while (
timer.elapsed() < clipboard_timeout);
783 bool alloc_error =
false;
786 xcb_timestamp_t prev_time = m_incr_receive_time;
792 buf.resize(nbytes+1);
793 alloc_error =
buf.size() != nbytes+1;
800 xcb_generic_event_t *ge = waitForClipboardEvent(
win, XCB_PROPERTY_NOTIFY);
803 xcb_property_notify_event_t *
event = (xcb_property_notify_event_t *)ge;
807 ||
event->state != XCB_PROPERTY_NEW_VALUE
808 ||
event->time < prev_time)
810 prev_time =
event->time;
821 }
else if (!alloc_error) {
836 if (
elapsed > clipboard_timeout)
864 xcb_generic_event_t *ge = waitForClipboardEvent(
win, XCB_SELECTION_NOTIFY);
865 bool no_selection = !ge || ((xcb_selection_notify_event_t *)ge)->property == XCB_NONE;
874 int nbytes =
buf.size() >= 4 ? *((
int*)
buf.data()) : 0;
886#include "moc_qxcbclipboard.cpp"
887#include "qxcbclipboard.moc"
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
Mode
\keyword clipboard mode
QStringList formats() const override
Returns a list of formats supported by the object.
static QStringList formatsHelper(const QMimeData *data)
qsizetype size() const noexcept
const_reference at(qsizetype i) const noexcept
void reserve(qsizetype size)
void append(parameter_type t)
iterator insert(const Key &key, const T &value)
iterator find(const Key &key)
const_iterator constEnd() const
int startTimer(int interval, Qt::TimerType timerType=Qt::CoarseTimer)
This is an overloaded function that will start a timer of type timerType and a timeout of interval mi...
void killTimer(int id)
Kills the timer with timer identifier, id.
T * data() const noexcept
Returns the value of the pointer referenced by this object.
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
\macro QT_RESTRICTED_CAST_FROM_ASCII
int timerId() const
Returns the unique timer identifier, which is the same identifier as returned from QObject::startTime...
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
size_t maxRequestDataBytes(size_t requestSize) const
bool hasFormat_sys(const QString &format) const override
QVariant retrieveData_sys(const QString &fmt, QMetaType type) const override
QXcbClipboardMime(QClipboard::Mode mode, QXcbClipboard *clipboard)
QStringList formats_sys() const override
bool updateIncrementalProperty(const xcb_property_notify_event_t *event)
void timerEvent(QTimerEvent *ev) override
This event handler can be reimplemented in a subclass to receive timer events for the object.
~QXcbClipboardTransaction()
QXcbClipboardTransaction(QXcbClipboard *clipboard, xcb_window_t w, xcb_atom_t p, QByteArray d, xcb_atom_t t, int f)
int clipboardTimeout() const
QByteArray getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t t=0)
bool clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format)
QByteArray getDataInFormat(xcb_atom_t modeAtom, xcb_atom_t fmtatom)
QByteArray clipboardReadIncrementalProperty(xcb_window_t win, xcb_atom_t property, int nbytes, bool nullterm)
void removeTransaction(xcb_window_t window)
void handleSelectionClearRequest(xcb_selection_clear_event_t *event)
bool supportsMode(QClipboard::Mode mode) const override
void setRequestor(xcb_window_t window)
bool handlePropertyNotify(const xcb_generic_event_t *event)
QXcbClipboard(QXcbConnection *connection)
QMimeData * mimeData(QClipboard::Mode mode) override
QXcbScreen * screen() const
bool ownsMode(QClipboard::Mode mode) const override
xcb_window_t requestor() const
void setMimeData(QMimeData *data, QClipboard::Mode mode) override
void handleSelectionRequest(xcb_selection_request_event_t *event)
void handleXFixesSelectionRequest(xcb_xfixes_selection_notify_event_t *event)
xcb_window_t selectionOwner(xcb_atom_t atom) const
void setTime(xcb_timestamp_t t)
xcb_timestamp_t time() const
QXcbScreen * primaryScreen() const
xcb_window_t qtSelectionOwner()
QXcbEventQueue * eventQueue() const
xcb_timestamp_t getTimestamp()
void handleXcbEvent(xcb_generic_event_t *event)
static QVariant mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, const QByteArray &data, const QString &format, QMetaType requestedType, bool hasUtf8)
static QList< xcb_atom_t > mimeAtomsForFormat(QXcbConnection *connection, const QString &format)
static xcb_atom_t mimeAtomForFormat(QXcbConnection *connection, const QString &format, QMetaType requestedType, const QList< xcb_atom_t > &atoms, bool *hasUtf8)
static bool mimeDataForAtom(QXcbConnection *connection, xcb_atom_t a, QMimeData *mimeData, QByteArray *data, xcb_atom_t *atomFormat, int *dataFormat)
static QString mimeAtomToString(QXcbConnection *connection, xcb_atom_t a)
QXcbConnection * connection() const
xcb_connection_t * xcb_connection() const
xcb_atom_t atom(QXcbAtom::Atom atom) const
xcb_screen_t * screen() const
void setWindowTitle(const QString &title) override
Reimplement to set the window title to title.
QSet< QString >::iterator it
Combined button and popup list for selecting options.
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
#define qCWarning(category,...)
#define qCDebug(category,...)
constexpr const T & qMin(const T &a, const T &b)
GLenum GLsizei GLsizei GLint * values
[15]
GLint GLint GLint GLint GLint x
[0]
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLsizei GLenum GLenum * types
GLenum GLuint GLenum GLsizei length
GLenum GLuint GLenum GLsizei const GLchar * buf
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLint GLsizei GLsizei GLenum format
GLfloat GLfloat GLfloat GLfloat h
#define QStringLiteral(str)
static double elapsed(qint64 after, qint64 before)
QVideoFrameFormat::PixelFormat fmt
#define Q_XCB_REPLY(call,...)
QtConcurrent::task([]{ qDebug("Hello, world!");}).spawn(FutureResult void increment(QPromise< int > &promise, int i)
[10]
QItemSelection * selection
[0]
bool contains(const AT &t) const noexcept