summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/xcb/qxcbconnection.cpp
diff options
context:
space:
mode:
authorGatis Paeglis <gatis.paeglis@digia.com>2013-03-25 14:44:48 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-05-07 22:43:14 +0200
commit05351b0cde3e80d2d0ae3a838e802ff6086e4b59 (patch)
treedbcbb18247aafe9485e7ccbbbc903c858bb1c75d /src/plugins/platforms/xcb/qxcbconnection.cpp
parent9c1d62cc95ed2579fa25d83901c7a1aa315aa2d3 (diff)
Utilize libxkbcommon API for the keyboard backend on X11
libxkbcommon is a keymap compiler [1] which utilizes xkb keyboard configuration database [2]. xkbcommon simplifies keyboard state handling by providing xkb_state object which holds the current state of all modifiers, groups, LEDs, etc, relating to the provided keymap. Detecting modifier mapping should become simpler once it gets supported in libxkbcommon. Also with xinput2 we could get rid of the XkbStateNotify events, because xinput2 key press/release already include all the mod/group info. [1] http://xkbcommon.org/ [2] http://www.freedesktop.org/wiki/Software/XKeyboardConfig This patch: - Removes a dependency to -lxcb-keysyms - Removes a dependency to XLib call - XLookupString - Enables required functionality to fix QTBUG-27681 Task-number: QTBUG-27680 Change-Id: I10e10f873821ee02f6df72238e215a541150f38f Reviewed-by: Samuel Rødal <samuel.rodal@digia.com>
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbconnection.cpp')
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp118
1 files changed, 105 insertions, 13 deletions
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index a7c60cac84..34508260d9 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -253,11 +253,13 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
#endif
, xfixes_first_event(0)
, xrandr_first_event(0)
+ , xkb_first_event(0)
, has_glx_extension(false)
, has_shape_extension(false)
, has_randr_extension(false)
, has_input_shape(false)
, has_touch_without_mouse_emulation(false)
+ , has_xkb(false)
, m_buttons(0)
, m_focusWindow(0)
{
@@ -297,7 +299,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
}
xcb_extension_t *extensions[] = {
- &xcb_shm_id, &xcb_xfixes_id, &xcb_randr_id, &xcb_shape_id, &xcb_sync_id,
+ &xcb_shm_id, &xcb_xfixes_id, &xcb_randr_id, &xcb_shape_id, &xcb_sync_id, &xcb_xkb_id,
#ifdef XCB_USE_RENDER
&xcb_render_id,
#endif
@@ -336,6 +338,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
initializeXInput2();
#endif
initializeXShape();
+ initializeXKB();
m_wmSupport.reset(new QXcbWMSupport(this));
m_keyboard = new QXcbKeyboard(this);
@@ -479,7 +482,6 @@ void printXcbEvent(const char *message, xcb_generic_event_t *event)
PRINT_XCB_EVENT(XCB_SELECTION_NOTIFY);
PRINT_XCB_EVENT(XCB_COLORMAP_NOTIFY);
PRINT_XCB_EVENT(XCB_CLIENT_MESSAGE);
- PRINT_XCB_EVENT(XCB_MAPPING_NOTIFY);
default:
qDebug("QXcbConnection: %s: unknown event - response_type: %d - sequence: %d", message, int(event->response_type & ~0x80), int(event->sequence));
}
@@ -745,6 +747,21 @@ void QXcbConnection::handleButtonRelease(xcb_generic_event_t *ev)
m_buttons &= ~translateMouseButton(event->detail);
}
+namespace {
+ typedef union {
+ /* All XKB events share these fields. */
+ struct {
+ uint8_t response_type;
+ uint8_t xkbType;
+ uint16_t sequence;
+ xcb_timestamp_t time;
+ uint8_t deviceID;
+ } any;
+ xcb_xkb_map_notify_event_t map_notify;
+ xcb_xkb_state_notify_event_t state_notify;
+ } _xkb_event;
+}
+
void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
{
#ifdef Q_XCB_DEBUG
@@ -797,9 +814,6 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent);
case XCB_KEY_RELEASE:
HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent);
- case XCB_MAPPING_NOTIFY:
- m_keyboard->handleMappingNotifyEvent((xcb_mapping_notify_event_t *)event);
- break;
case XCB_SELECTION_REQUEST:
{
xcb_selection_request_event_t *sr = (xcb_selection_request_event_t *)event;
@@ -862,6 +876,22 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
}
}
handled = true;
+ } else if (response_type == xkb_first_event) { // https://bugs.freedesktop.org/show_bug.cgi?id=51295
+ _xkb_event *xkb_event = reinterpret_cast<_xkb_event *>(event);
+ if (xkb_event->any.deviceID == m_keyboard->coreDeviceId()) {
+ switch (xkb_event->any.xkbType) {
+ case XCB_XKB_STATE_NOTIFY:
+ m_keyboard->updateXKBState(&xkb_event->state_notify);
+ handled = true;
+ break;
+ case XCB_XKB_MAP_NOTIFY:
+ m_keyboard->handleMappingNotifyEvent(&xkb_event->map_notify);
+ handled = true;
+ break;
+ default:
+ break;
+ }
+ }
}
}
@@ -869,7 +899,6 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
if (!handled) {
// Check if a custom XEvent constructor was registered in xlib for this event type, and call it discarding the constructed XEvent if any.
// XESetWireToEvent might be used by libraries to intercept messages from the X server e.g. the OpenGL lib waiting for DRI2 events.
-
Display *xdisplay = (Display *)m_xlib_display;
XLockDisplay(xdisplay);
Bool (*proc)(Display*, XEvent*, xEvent*) = XESetWireToEvent(xdisplay, response_type, 0);
@@ -1017,32 +1046,36 @@ namespace
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_window_t root_win = rootWindow();
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_APPEND, root_win, atom(QXcbAtom::CLIP_TEMPORARY),
XCB_ATOM_INTEGER, 32, 0, NULL);
connection()->flush();
- PropertyNotifyEvent checker(rootWindow, atom(QXcbAtom::CLIP_TEMPORARY));
+ PropertyNotifyEvent checker(root_win, 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) {
+ while (!event) {
connection()->sync();
- if ((event = checkEvent(checker)))
- break;
+ event = checkEvent(checker);
}
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));
+ xcb_delete_property(xcb_connection(), root_win, atom(QXcbAtom::CLIP_TEMPORARY));
return timestamp;
}
+xcb_window_t QXcbConnection::rootWindow()
+{
+ return screens().at(primaryScreen())->root();
+}
+
void QXcbConnection::processXcbEvents()
{
int connection_error = xcb_connection_has_error(xcb_connection());
@@ -1539,6 +1572,65 @@ void QXcbConnection::initializeXShape()
free(shape_query);
}
+void QXcbConnection::initializeXKB()
+{
+ const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_xkb_id);
+ if (!reply || !reply->present) {
+ xkb_first_event = 0;
+ return;
+ }
+ xkb_first_event = reply->first_event;
+
+ xcb_connection_t *c = connection()->xcb_connection();
+ xcb_xkb_use_extension_cookie_t xkb_query_cookie;
+ xcb_xkb_use_extension_reply_t *xkb_query;
+
+ xkb_query_cookie = xcb_xkb_use_extension(c, XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION);
+ xkb_query = xcb_xkb_use_extension_reply(c, xkb_query_cookie, 0);
+
+ if (!xkb_query) {
+ qWarning("Qt: Failed to initialize XKB extension");
+ return;
+ } else if (!xkb_query->supported) {
+ qWarning("Qt: Unsupported XKB version (want %d %d, has %d %d)",
+ XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION,
+ xkb_query->serverMajor, xkb_query->serverMinor);
+ free(xkb_query);
+ return;
+ }
+
+ has_xkb = true;
+ free(xkb_query);
+
+ uint affectMap, map;
+ affectMap = map = XCB_XKB_MAP_PART_KEY_TYPES |
+ XCB_XKB_MAP_PART_KEY_SYMS |
+ XCB_XKB_MAP_PART_MODIFIER_MAP |
+ XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS |
+ XCB_XKB_MAP_PART_KEY_ACTIONS |
+ XCB_XKB_MAP_PART_KEY_BEHAVIORS |
+ XCB_XKB_MAP_PART_VIRTUAL_MODS |
+ XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP;
+
+ // Xkb events are reported to all interested clients without regard
+ // to the current keyboard input focus or grab state
+ xcb_void_cookie_t select = xcb_xkb_select_events_checked(c,
+ XCB_XKB_ID_USE_CORE_KBD,
+ XCB_XKB_EVENT_TYPE_STATE_NOTIFY | XCB_XKB_EVENT_TYPE_MAP_NOTIFY,
+ 0,
+ XCB_XKB_EVENT_TYPE_STATE_NOTIFY | XCB_XKB_EVENT_TYPE_MAP_NOTIFY,
+ affectMap,
+ map,
+ 0);
+
+ xcb_generic_error_t *error = xcb_request_check(c, select);
+ if (error) {
+ free(error);
+ qWarning() << "Qt: failed to select notify events from xcb-xkb";
+ return;
+ }
+}
+
#if defined(XCB_USE_EGL)
bool QXcbConnection::hasEgl() const
{