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.cpp190
1 files changed, 75 insertions, 115 deletions
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp
index 3fd14a659e..9c7559d514 100644
--- a/src/plugins/platforms/xcb/qxcbclipboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp
@@ -153,114 +153,71 @@ private:
QByteArray format_atoms;
};
-namespace {
-class INCRTransaction;
-typedef QMap<xcb_window_t,INCRTransaction*> TransactionMap;
-static TransactionMap *transactions = 0;
+QXcbClipboardTransaction::QXcbClipboardTransaction(QXcbClipboard *clipboard, xcb_window_t w,
+ xcb_atom_t p, QByteArray d, xcb_atom_t t, int f)
+ : m_clipboard(clipboard), m_window(w), m_property(p), m_data(d), m_target(t), m_format(f)
+{
+ const quint32 values[] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
+ xcb_change_window_attributes(m_clipboard->xcb_connection(), m_window,
+ XCB_CW_EVENT_MASK, values);
-//#define INCR_DEBUG
+ m_abortTimerId = startTimer(m_clipboard->clipboardTimeout());
+}
-class INCRTransaction : public QObject
+QXcbClipboardTransaction::~QXcbClipboardTransaction()
{
- Q_OBJECT
-public:
- INCRTransaction(QXcbConnection *c, xcb_window_t w, xcb_atom_t p,
- QByteArray d, uint i, xcb_atom_t t, int f, int to) :
- conn(c), win(w), property(p), data(d), increment(i),
- target(t), format(f), timeout(to), offset(0)
- {
- const quint32 values[] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
- xcb_change_window_attributes(conn->xcb_connection(), win,
- XCB_CW_EVENT_MASK, values);
- if (!transactions) {
-#ifdef INCR_DEBUG
- qDebug("INCRTransaction: creating the TransactionMap");
-#endif
- transactions = new TransactionMap;
- conn->clipboard()->setProcessIncr(true);
- }
- transactions->insert(win, this);
- abort_timer = startTimer(timeout);
- }
+ if (m_abortTimerId)
+ killTimer(m_abortTimerId);
+ m_abortTimerId = 0;
+ m_clipboard->removeTransaction(m_window);
+}
- ~INCRTransaction()
- {
- if (abort_timer)
- killTimer(abort_timer);
- abort_timer = 0;
- transactions->remove(win);
- if (transactions->isEmpty()) {
-#ifdef INCR_DEBUG
- qDebug("INCRTransaction: no more INCR transactions left in the TransactionMap");
-#endif
- delete transactions;
- transactions = 0;
- conn->clipboard()->setProcessIncr(false);
- }
- }
+bool QXcbClipboardTransaction::updateIncrementalProperty(const xcb_property_notify_event_t *event)
+{
+ if (event->atom != m_property || event->state != XCB_PROPERTY_DELETE)
+ return false;
- void updateIncrProperty(xcb_property_notify_event_t *event, bool &accepted)
- {
- xcb_connection_t *c = conn->xcb_connection();
- if (event->atom == property && event->state == XCB_PROPERTY_DELETE) {
- accepted = true;
- // restart the timer
- if (abort_timer)
- killTimer(abort_timer);
- abort_timer = startTimer(timeout);
-
- unsigned int bytes_left = data.size() - offset;
- if (bytes_left > 0) {
- unsigned int bytes_to_send = qMin(increment, bytes_left);
-#ifdef INCR_DEBUG
- qDebug("INCRTransaction: sending %d bytes, %d remaining (INCR transaction %p)",
- bytes_to_send, bytes_left - bytes_to_send, this);
-#endif
- int dataSize = bytes_to_send / (format / 8);
- xcb_change_property(c, XCB_PROP_MODE_REPLACE, win, property,
- target, format, dataSize, data.constData() + offset);
- offset += bytes_to_send;
- } else {
-#ifdef INCR_DEBUG
- qDebug("INCRTransaction: INCR transaction %p completed", this);
-#endif
- xcb_change_property(c, XCB_PROP_MODE_REPLACE, win, property,
- target, format, 0, (const void *)0);
- const quint32 values[] = { XCB_EVENT_MASK_NO_EVENT };
- xcb_change_window_attributes(conn->xcb_connection(), win,
- XCB_CW_EVENT_MASK, values);
- // self destroy
- delete this;
- }
- }
- }
+ // restart the timer
+ if (m_abortTimerId)
+ killTimer(m_abortTimerId);
+ m_abortTimerId = startTimer(m_clipboard->clipboardTimeout());
-protected:
- void timerEvent(QTimerEvent *ev) override
- {
- if (ev->timerId() == abort_timer) {
- // this can happen when the X client we are sending data
- // to decides to exit (normally or abnormally)
-#ifdef INCR_DEBUG
- qDebug("INCRTransaction: Timed out while sending data to %p", this);
-#endif
- delete this;
- }
+ uint bytes_left = uint(m_data.size()) - m_offset;
+ if (bytes_left > 0) {
+ int increment = m_clipboard->increment();
+ uint bytes_to_send = qMin(uint(increment), bytes_left);
+
+ qCDebug(lcQpaClipboard, "sending %d bytes, %d remaining, transaction: %p)",
+ bytes_to_send, bytes_left - bytes_to_send, this);
+
+ uint32_t dataSize = bytes_to_send / (m_format / 8);
+ xcb_change_property(m_clipboard->xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
+ m_property, m_target, m_format, dataSize, m_data.constData() + m_offset);
+ m_offset += bytes_to_send;
+ } else {
+ qCDebug(lcQpaClipboard, "transaction %p completed", this);
+
+ xcb_change_property(m_clipboard->xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
+ m_property, m_target, m_format, 0, nullptr);
+
+ const quint32 values[] = { XCB_EVENT_MASK_NO_EVENT };
+ xcb_change_window_attributes(m_clipboard->xcb_connection(), m_window,
+ XCB_CW_EVENT_MASK, values);
+ delete this; // self destroy
}
+ return true;
+}
-private:
- QXcbConnection *conn;
- xcb_window_t win;
- xcb_atom_t property;
- QByteArray data;
- uint increment;
- xcb_atom_t target;
- int format;
- int timeout;
- uint offset;
- int abort_timer;
-};
-} // unnamed namespace
+
+void QXcbClipboardTransaction::timerEvent(QTimerEvent *ev)
+{
+ if (ev->timerId() == m_abortTimerId) {
+ // this can happen when the X client we are sending data
+ // to decides to exit (normally or abnormally)
+ qCDebug(lcQpaClipboard, "timed out while sending data to %p", this);
+ delete this; // self destroy
+ }
+}
const int QXcbClipboard::clipboard_timeout = 5000;
@@ -282,6 +239,9 @@ QXcbClipboard::QXcbClipboard(QXcbConnection *c)
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);
}
+
+ // change property protocol request is 24 bytes
+ m_increment = (xcb_get_maximum_request_length(xcb_connection()) * 4) - 24;
}
QXcbClipboard::~QXcbClipboard()
@@ -313,16 +273,17 @@ QXcbClipboard::~QXcbClipboard()
delete m_clientClipboard[QClipboard::Selection];
}
-void QXcbClipboard::incrTransactionPeeker(xcb_generic_event_t *ge, bool &accepted)
+bool QXcbClipboard::handlePropertyNotify(const xcb_generic_event_t *event)
{
- uint response_type = ge->response_type & ~0x80;
- if (response_type == XCB_PROPERTY_NOTIFY) {
- xcb_property_notify_event_t *event = (xcb_property_notify_event_t *)ge;
- TransactionMap::Iterator it = transactions->find(event->window);
- if (it != transactions->end()) {
- (*it)->updateIncrProperty(event, accepted);
- }
- }
+ if (m_transactions.isEmpty() || event->response_type != XCB_PROPERTY_NOTIFY)
+ return false;
+
+ auto propertyNotify = reinterpret_cast<const xcb_property_notify_event_t *>(event);
+ TransactionMap::Iterator it = m_transactions.find(propertyNotify->window);
+ if (it == m_transactions.constEnd())
+ return false;
+
+ return (*it)->updateIncrementalProperty(propertyNotify);
}
xcb_window_t QXcbClipboard::getSelectionOwner(xcb_atom_t atom) const
@@ -522,19 +483,18 @@ xcb_atom_t QXcbClipboard::sendSelection(QMimeData *d, xcb_atom_t target, xcb_win
// This 'bool' can be removed once there is a proper fix for QTBUG-32853
if (m_clipboard_closing)
allow_incr = false;
- // X_ChangeProperty protocol request is 24 bytes
- const int increment = (xcb_get_maximum_request_length(xcb_connection()) * 4) - 24;
- if (data.size() > increment && allow_incr) {
+
+ if (data.size() > m_increment && 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);
- new INCRTransaction(connection(), window, property, data, increment,
- atomFormat, dataFormat, clipboard_timeout);
+ auto transaction = new QXcbClipboardTransaction(this, window, property, data, atomFormat, dataFormat);
+ m_transactions.insert(window, transaction);
return property;
}
// make sure we can perform the XChangeProperty in a single request
- if (data.size() > increment)
+ if (data.size() > m_increment)
return XCB_NONE; // ### perhaps use several XChangeProperty calls w/ PropModeAppend?
int dataSize = data.size() / (dataFormat / 8);
// use a single request to transfer data