From 7a64f12cfe03b673ebb3c5e9e0396c6a504620d8 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Sat, 18 Jun 2011 22:50:30 +0200 Subject: use selection changed events from XFixes properly initialize the XFixes extension and then use the selection changed events to notify Qt apps. Reviewed-by: Samuel --- src/plugins/platforms/xcb/qxcbclipboard.cpp | 50 ++++++++++++++++++---------- src/plugins/platforms/xcb/qxcbclipboard.h | 2 ++ src/plugins/platforms/xcb/qxcbconnection.cpp | 24 ++++++++++--- src/plugins/platforms/xcb/qxcbconnection.h | 4 +++ 4 files changed, 58 insertions(+), 22 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp index ea7cefb972..31f82443de 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.cpp +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -163,6 +163,28 @@ QXcbClipboard::QXcbClipboard(QXcbConnection *c) m_timestamp[QClipboard::Selection] = XCB_CURRENT_TIME; m_screen = connection()->screens().at(connection()->primaryScreen()); + + int x = 0, y = 0, w = 3, h = 3; + + m_owner = xcb_generate_id(xcb_connection()); + Q_XCB_CALL(xcb_create_window(xcb_connection(), + XCB_COPY_FROM_PARENT, // depth -- same as root + m_owner, // window id + m_screen->screen()->root, // parent window id + x, y, w, h, + 0, // border width + XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class + m_screen->screen()->root_visual, // visual + 0, // value mask + 0)); // value list + + if (connection()->hasXFixes()) { + const uint32_t mask = XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER | + XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY | + XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE; + Q_XCB_CALL(xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, XCB_ATOM_PRIMARY, mask)); + Q_XCB_CALL(xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, atom(QXcbAtom::CLIPBOARD), mask)); + } } QXcbClipboard::~QXcbClipboard() @@ -322,24 +344,6 @@ void QXcbClipboard::setRequestor(xcb_window_t window) xcb_window_t QXcbClipboard::owner() const { - if (!m_owner) { - int x = 0, y = 0, w = 3, h = 3; - - xcb_window_t window = xcb_generate_id(xcb_connection()); - Q_XCB_CALL(xcb_create_window(xcb_connection(), - XCB_COPY_FROM_PARENT, // depth -- same as root - window, // window id - m_screen->screen()->root, // parent window id - x, y, w, h, - 0, // border width - XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class - m_screen->screen()->root_visual, // visual - 0, // value mask - 0)); // value list - - QXcbClipboard *that = const_cast(this); - that->m_owner = window; - } return m_owner; } @@ -554,6 +558,16 @@ void QXcbClipboard::handleSelectionRequest(xcb_selection_request_event_t *req) xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event); } +void QXcbClipboard::handleXFixesSelectionRequest(xcb_xfixes_selection_notify_event_t *event) +{ + QClipboard::Mode mode = modeForAtom(event->selection); + if (event->owner != owner() && m_clientClipboard[mode] && m_timestamp[mode] < event->selection_timestamp) { + setMimeData(0, mode); + emitChanged(mode); + } +} + + static inline int maxSelectionIncr(xcb_connection_t *c) { int l = xcb_get_maximum_request_length(c); diff --git a/src/plugins/platforms/xcb/qxcbclipboard.h b/src/plugins/platforms/xcb/qxcbclipboard.h index db31051ee7..d23f93529b 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.h +++ b/src/plugins/platforms/xcb/qxcbclipboard.h @@ -45,6 +45,7 @@ #include #include #include +#include class QXcbConnection; class QXcbScreen; @@ -71,6 +72,7 @@ public: void handleSelectionRequest(xcb_selection_request_event_t *event); 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; QByteArray clipboardReadIncrementalProperty(xcb_window_t win, xcb_atom_t property, int nbytes, bool nullterm); diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index eddc3305d1..d6460339a2 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -90,6 +90,7 @@ QXcbConnection::QXcbConnection(const char *displayName) , m_dri2_support_probed(false) , m_has_support_for_dri2(false) #endif + , xfixes_first_event(0) { m_primaryScreen = 0; @@ -110,6 +111,8 @@ QXcbConnection::QXcbConnection(const char *displayName) m_connection = xcb_connect(m_displayName.constData(), &primaryScreen); #endif //XCB_USE_XLIB + xcb_prefetch_extension_data (m_connection, &xcb_xfixes_id); + m_setup = xcb_get_setup(xcb_connection()); initializeAllAtoms(); @@ -124,14 +127,14 @@ QXcbConnection::QXcbConnection(const char *displayName) xcb_screen_next(&it); } + initializeXFixes(); + initializeXRender(); + m_wmSupport = new QXcbWMSupport(this); m_keyboard = new QXcbKeyboard(this); m_clipboard = new QXcbClipboard(this); m_drag = new QXcbDrag(this); - initializeXFixes(); - initializeXRender(); - #ifdef XCB_USE_DRI2 initializeDri2(); #endif @@ -506,6 +509,15 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) handled = false; break; } + + if (!handled) { + if (response_type == xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) { + setTime(((xcb_xfixes_selection_notify_event_t *)event)->timestamp); + m_clipboard->handleXFixesSelectionRequest((xcb_xfixes_selection_notify_event_t *)event); + handled = true; + } + } + if (handled) printXcbEvent("Handled XCB event", event); else @@ -842,7 +854,9 @@ void QXcbConnection::sync() void QXcbConnection::initializeXFixes() { xcb_generic_error_t *error = 0; - xcb_prefetch_extension_data (m_connection, &xcb_xfixes_id); + const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_xfixes_id); + xfixes_first_event = reply->first_event; + xcb_xfixes_query_version_cookie_t xfixes_query_cookie = xcb_xfixes_query_version(m_connection, XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION); @@ -851,8 +865,10 @@ void QXcbConnection::initializeXFixes() if (!xfixes_query || error || xfixes_query->major_version < 2) { qWarning("Failed to initialize XFixes"); free(error); + xfixes_first_event = 0; } free(xfixes_query); + } void QXcbConnection::initializeXRender() diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 9413b682c3..6cc7e13d02 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -286,6 +286,8 @@ public: inline xcb_timestamp_t time() const { return m_time; } inline void setTime(xcb_timestamp_t t) { if (t > m_time) m_time = t; } + bool hasXFixes() const { return xfixes_first_event > 0; } + private slots: void processXcbEvents(); @@ -347,6 +349,8 @@ private: WindowMapper m_mapper; QVector m_peekFuncs; + + uint32_t xfixes_first_event; }; #define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display())) -- cgit v1.2.3