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
bb10
Lars Knoll 2011-06-18 22:50:30 +02:00
parent 8ffbdae179
commit 7a64f12cfe
4 changed files with 58 additions and 22 deletions

View File

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

View File

@ -45,6 +45,7 @@
#include <QPlatformClipboard>
#include <qxcbobject.h>
#include <xcb/xcb.h>
#include <xcb/xfixes.h>
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);

View File

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

View File

@ -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<PeekFunc> m_peekFuncs;
uint32_t xfixes_first_event;
};
#define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display()))