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>
This commit is contained in:
Gatis Paeglis 2012-10-03 14:53:33 +02:00 committed by The Qt Project
parent befea1d932
commit ce81da52ea
3 changed files with 58 additions and 1 deletions

View File

@ -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();

View File

@ -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();

View File

@ -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();