From 663c5186e88e86983532b8010688b38221faab72 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Wed, 7 Aug 2013 13:46:21 +0200 Subject: Fix timing issue in incremental data retrieval mechanism Make sure that we are not reading wrong PropertyNotify events. From icccm: Requestors may receive a property of type INCR in response to any target that results in selection data. This indicates that the owner will send the actual data incrementally. The selection requestor: - Waits for the SelectionNotify event. - Loops: + Retrieving data using GetProperty with the delete argument True. + Waiting for a PropertyNotify with the state argument NewValue. - Waits until the property named by the PropertyNotify event is zero-length. - Deletes the zero-length property. The issue with the current approach was that after receiving INCR we simply fetched the first PropertyNotify event from the queue, where timestamp indicates that it was generated before INCR, which is not what need. We need PropertyNotify events with a timestamp older than the one on INCR. Task-number: QTBUG-32045 Change-Id: I3b9a006f7d346f67c51e1a296d67a9dc89efadb1 Reviewed-by: Lars Knoll --- src/plugins/platforms/xcb/qxcbclipboard.cpp | 15 +++++++++++---- src/plugins/platforms/xcb/qxcbclipboard.h | 3 ++- 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp index dab4f443ff..dd292fd2a3 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.cpp +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -272,6 +272,7 @@ QXcbClipboard::QXcbClipboard(QXcbConnection *c) , m_owner(XCB_NONE) , m_incr_active(false) , m_clipboard_closing(false) + , m_incr_receive_time(0) { Q_ASSERT(QClipboard::Clipboard == 0); Q_ASSERT(QClipboard::Selection == 1); @@ -733,7 +734,7 @@ static inline int maxSelectionIncr(xcb_connection_t *c) return (l > 65536 ? 65536*4 : l*4) - 100; } -bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format) const +bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format) { int maxsize = maxSelectionIncr(xcb_connection()); ulong bytes_left; // bytes_after @@ -809,7 +810,8 @@ 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)) + m_incr_receive_time = connection()->getTimestamp(); if (deleteProperty) xcb_delete_property(xcb_connection(), win, property); @@ -913,6 +915,7 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb bool alloc_error = false; int length; int offset = 0; + xcb_timestamp_t prev_time = m_incr_receive_time; if (nbytes > 0) { // Reserve buffer + zero-terminator (for text data) @@ -927,10 +930,14 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_PROPERTY_NOTIFY, clipboard_timeout); if (!ge) break; - xcb_property_notify_event_t *event = (xcb_property_notify_event_t *)ge; - if (event->atom != property || event->state != XCB_PROPERTY_NEW_VALUE) + + if (event->atom != property + || event->state != XCB_PROPERTY_NEW_VALUE + || event->time < prev_time) continue; + prev_time = event->time; + if (clipboardReadProperty(win, property, true, &tmp_buf, &length, 0, 0)) { if (length == 0) { // no more data, we're done if (nullterm) { diff --git a/src/plugins/platforms/xcb/qxcbclipboard.h b/src/plugins/platforms/xcb/qxcbclipboard.h index c94762d80f..03021aa606 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.h +++ b/src/plugins/platforms/xcb/qxcbclipboard.h @@ -78,7 +78,7 @@ public: void handleSelectionClearRequest(xcb_selection_clear_event_t *event); void handleXFixesSelectionRequest(xcb_xfixes_selection_notify_event_t *event); - bool clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format) const; + bool clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format); QByteArray clipboardReadIncrementalProperty(xcb_window_t win, xcb_atom_t property, int nbytes, bool nullterm); QByteArray getDataInFormat(xcb_atom_t modeAtom, xcb_atom_t fmtatom); @@ -113,6 +113,7 @@ private: bool m_incr_active; bool m_clipboard_closing; + xcb_timestamp_t m_incr_receive_time; }; #endif // QT_NO_CLIPBOARD -- cgit v1.2.3