summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/xcb
diff options
context:
space:
mode:
authorGatis Paeglis <gatis.paeglis@digia.com>2012-10-03 14:53:33 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2012-10-13 05:51:19 +0200
commitce81da52ea1fffa67188e19eb9dbba66501dd82f (patch)
tree579c8ba02a35252b69b39296cfe79c283e5c1953 /src/plugins/platforms/xcb
parentbefea1d93285bdf2ea8134718fb9c74a89bc551e (diff)
Make sure timestamp is initialized before using it for seting selection owner.
Convention from icccm: Clients attempting to acquire a selection must set the time value of the xcb_set_selection_owner request to the timestamp of the event triggering the acquisition attempt, not to XCB_CURRENT_TIME. In some cases it happened that timestamp was set to XCB_CURRENT_TIME. A zero-length append to a property is a way to obtain a timestamp for this purpose; the timestamp is in the corresponding XCB_PROPERTY_NOTIFY event. We used to have this mechanism in 4.8, it was achieved by XWindowEvent. AFAIK there isn't an equivalent for XWindowEvent in XCB. Therefore i had to introduce a new mechanism in QXcbConnection - getTimestamp. This function blocks until it receives the requested event. Change-Id: Ide46a4fdd44cf026fdd17a79d3c4b17741d1b7d4 Task-number: QTBUG-26783 Reviewed-by: Uli Schlachter <psychon@znc.in> Reviewed-by: Lars Knoll <lars.knoll@digia.com> Reviewed-by: Samuel Rødal <samuel.rodal@digia.com>
Diffstat (limited to 'src/plugins/platforms/xcb')
-rw-r--r--src/plugins/platforms/xcb/qxcbclipboard.cpp3
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp53
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h3
3 files changed, 58 insertions, 1 deletions
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp
index f021ab8b4a..142a8dfcde 100644
--- a/src/plugins/platforms/xcb/qxcbclipboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp
@@ -300,6 +300,9 @@ void QXcbClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
m_timestamp[mode] = XCB_CURRENT_TIME;
}
+ if (connection()->time() == XCB_CURRENT_TIME)
+ connection()->setTime(connection()->getTimestamp());
+
if (data) {
newOwner = owner();
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 401739f7d5..ad9fb1d19c 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -864,6 +864,59 @@ void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom a, uint id)
xcb_flush(xcb_connection());
}
+namespace
+{
+ class PropertyNotifyEvent {
+ public:
+ PropertyNotifyEvent(xcb_window_t win, xcb_atom_t property)
+ : window(win), type(XCB_PROPERTY_NOTIFY), atom(property) {}
+ xcb_window_t window;
+ int type;
+ xcb_atom_t atom;
+ bool checkEvent(xcb_generic_event_t *event) const {
+ if (!event)
+ return false;
+ if ((event->response_type & ~0x80) != type) {
+ return false;
+ } else {
+ xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event;
+ if ((pn->window == window) && (pn->atom == atom))
+ return true;
+ }
+ return false;
+ }
+ };
+}
+
+xcb_timestamp_t QXcbConnection::getTimestamp()
+{
+ // send a dummy event to myself to get the timestamp from X server.
+ xcb_window_t rootWindow = screens().at(primaryScreen())->root();
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_APPEND, rootWindow, atom(QXcbAtom::CLIP_TEMPORARY),
+ XCB_ATOM_INTEGER, 32, 0, NULL);
+
+ connection()->flush();
+ PropertyNotifyEvent checker(rootWindow, atom(QXcbAtom::CLIP_TEMPORARY));
+
+ xcb_generic_event_t *event = 0;
+ // lets keep this inside a loop to avoid a possible race condition, where
+ // reader thread has not yet had the time to acquire the mutex in order
+ // to add the new set of events to its event queue
+ while (true) {
+ connection()->sync();
+ if (event = checkEvent(checker))
+ break;
+ }
+
+ xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event;
+ xcb_timestamp_t timestamp = pn->time;
+ free(event);
+
+ xcb_delete_property(xcb_connection(), rootWindow, atom(QXcbAtom::CLIP_TEMPORARY));
+
+ return timestamp;
+}
+
void QXcbConnection::processXcbEvents()
{
QXcbEventArray *eventqueue = m_reader->lock();
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 08dd304b3d..8a6c418788 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -319,7 +319,6 @@ public:
QByteArray atomName(xcb_atom_t atom);
const char *displayName() const { return m_displayName.constData(); }
-
xcb_connection_t *xcb_connection() const { return m_connection; }
const xcb_setup_t *setup() const { return m_setup; }
const xcb_format_t *formatForDepth(uint8_t depth) const;
@@ -380,6 +379,8 @@ public:
bool hasXRandr() const { return has_randr_extension; }
bool hasInputShape() const { return has_input_shape; }
+ xcb_timestamp_t getTimestamp();
+
private slots:
void processXcbEvents();